├── README.md ├── Misc ├── AllignmentTemplates.h ├── ImSorryForTheQualityOfThis.h └── Types.h ├── VALORANT.vcxproj.user ├── VALORANT ├── VALORANT.h └── FNamePool.h ├── VALORANT.vcxproj.filters ├── VALORANT.sln ├── dllmain.cpp └── VALORANT.vcxproj /README.md: -------------------------------------------------------------------------------- 1 | # VALORANT 2 | 3 | Iterate And Decrypt FNamePool->Entries To A Log On VALORANT 4 | 5 | The output text will be located in the games directory 6 | -------------------------------------------------------------------------------- /Misc/AllignmentTemplates.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | FORCEINLINE constexpr T Align(T Val, uint64 Alignment) 5 | { 6 | return (T)(((uint64)Val + Alignment - 1) & ~(Alignment - 1)); 7 | } 8 | -------------------------------------------------------------------------------- /VALORANT.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | -------------------------------------------------------------------------------- /VALORANT/VALORANT.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | uint64 BaseAddress = NULL; 10 | class FNamePool* NamePoolData = nullptr; 11 | 12 | #define FileName "\\FNamePool_Entries_Log.txt" 13 | 14 | #define DecryptWideOffset 0x3C09E00 15 | #define DecryptNonWideOffset 0x3C09D90 16 | #define NamePoolDataOffset 0xA050A00 17 | 18 | #include 19 | -------------------------------------------------------------------------------- /Misc/ImSorryForTheQualityOfThis.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | class ImSorryForTheQualityOfThis { 7 | public: 8 | ImSorryForTheQualityOfThis(std::string FileName, bool Append = false) 9 | { 10 | std::filesystem::path Path = std::filesystem::current_path(); 11 | Path += FileName; 12 | LogFile.open(Path, Append ? std::fstream::out : std::fstream::out | std::fstream::app); 13 | } 14 | 15 | inline void CloseLog() 16 | { 17 | LogFile.close(); 18 | } 19 | 20 | void LogToFile(std::string ToLog) 21 | { 22 | LogFile << ToLog << std::endl; 23 | } 24 | 25 | void LogToFile(std::string ToLog, void* Pointer) 26 | { 27 | LogFile << ToLog << "0x" << std::hex << Pointer << std::endl; 28 | } 29 | 30 | void LogToFile(std::string ToLog, uint64 Pointer) 31 | { 32 | LogFile << ToLog << "0x" << std::hex << reinterpret_cast(Pointer) << std::endl; 33 | } 34 | 35 | private: 36 | std::ofstream LogFile; 37 | }; 38 | 39 | 40 | -------------------------------------------------------------------------------- /VALORANT.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 6 | 7 | 8 | 9 | 10 | 11 | 12 | Misc 13 | 14 | 15 | Misc 16 | 17 | 18 | VALORANT 19 | 20 | 21 | Misc 22 | 23 | 24 | VALORANT 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /VALORANT.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32616.157 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VALORANT", "VALORANT.vcxproj", "{0DF87F4D-16D8-4835-B552-9F5C4A0D2044}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {0DF87F4D-16D8-4835-B552-9F5C4A0D2044}.Debug|x64.ActiveCfg = Debug|x64 17 | {0DF87F4D-16D8-4835-B552-9F5C4A0D2044}.Debug|x64.Build.0 = Debug|x64 18 | {0DF87F4D-16D8-4835-B552-9F5C4A0D2044}.Debug|x86.ActiveCfg = Debug|Win32 19 | {0DF87F4D-16D8-4835-B552-9F5C4A0D2044}.Debug|x86.Build.0 = Debug|Win32 20 | {0DF87F4D-16D8-4835-B552-9F5C4A0D2044}.Release|x64.ActiveCfg = Release|x64 21 | {0DF87F4D-16D8-4835-B552-9F5C4A0D2044}.Release|x64.Build.0 = Release|x64 22 | {0DF87F4D-16D8-4835-B552-9F5C4A0D2044}.Release|x86.ActiveCfg = Release|Win32 23 | {0DF87F4D-16D8-4835-B552-9F5C4A0D2044}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {ECE949B5-DEBC-404E-BD21-FB63B5C1604E} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Misc/Types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //~ Unsigned base types 4 | 5 | // 8-bit unsigned integer 6 | typedef unsigned char uint8; 7 | 8 | // 16-bit unsigned integer 9 | typedef unsigned short int uint16; 10 | 11 | // 32-bit unsigned integer 12 | typedef unsigned int uint32; 13 | 14 | // 64-bit unsigned integer 15 | typedef unsigned long long uint64; 16 | 17 | //~ Signed base types. 18 | 19 | // 8-bit signed integer 20 | typedef signed char int8; 21 | 22 | // 16-bit signed integer 23 | typedef signed short int int16; 24 | 25 | // 32-bit signed integer 26 | typedef signed int int32; 27 | 28 | // 64-bit signed integer 29 | typedef signed long long int64; 30 | 31 | 32 | //~ Character types 33 | 34 | // An ANSI character. 8-bit fixed-width representation of 7-bit characters. 35 | typedef char ANSICHAR; 36 | 37 | // A wide character. In-memory only. ?-bit fixed-width representation of the platform's natural wide character set. Could be different sizes on different platforms. 38 | typedef wchar_t WIDECHAR; 39 | 40 | // An 8-bit character type. In-memory only. 8-bit representation. Should really be char8_t but making this the generic option is easier for compilers which don't fully support C++11 yet (i.e. MSVC). 41 | typedef uint8 CHAR8; 42 | 43 | // A 16-bit character type. In-memory only. 16-bit representation. Should really be char16_t but making this the generic option is easier for compilers which don't fully support C++11 yet (i.e. MSVC). 44 | typedef uint16 CHAR16; 45 | 46 | // A 32-bit character type. In-memory only. 32-bit representation. Should really be char32_t but making this the generic option is easier for compilers which don't fully support C++11 yet (i.e. MSVC). 47 | typedef uint32 CHAR32; 48 | 49 | // A switchable character. In-memory only. Either ANSICHAR or WIDECHAR, depending on a licensee's requirements. 50 | typedef WIDECHAR TCHAR; 51 | -------------------------------------------------------------------------------- /dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | 5 | this art only showing up properly on vs not on github lol im too lazy to fix fuck off 6 | 7 | '."""""""""""""""""`. 8 | `. ... `. 9 | `. / `. `. 10 | .'"":_ :"""""".'| 11 | .'//)/) ` (/)/)).' | 12 | .'/)_/"" __ ""\.' | 13 | |"""(((""""((("""| | 14 | || | "" "" | | 15 | || | | ' 16 | _|| | BANANAESSZ | .' ME :D <-----------------------------> VALORANT E-GIRLS <3 17 | /__3 | | .' 18 | / /|| YOU | |' _______________ |*\_/*|________ 19 | / / // .--. """"""""""""""""" | ___________ | .-. .-. ||_/-\_|______ | 20 | \ \// / (OO) | | C:\>_ | | .****. .****. | | | | 21 | \// |( _ ) | | 0 0 | | .*****.*****. | | 0 0 | | 22 | // \__/`-'\__ Hopefully some monkey finds this useful. | | - | | .*********. | | - | | 23 | // \__ _ \ | | \___/ | | .*******. | | \___/ | | 24 | _.-'/ | ._._.|\ \ I'm so sleepy. | |___ ___| | .*****. | |___________| | 25 | (_.-' | \ \ \ |_____|\_/|_____| .***. |_______________| 26 | .-._ / o ) / / I go to sleep now, goodnight. _|__|/ \|_|_.............*.............._|________|_ 27 | /_ \ \ / \__/ / / / ********** \ / ********** \ 28 | \ \_/ / / |_/ / ************ \ / ************ \ 29 | \ / / -------------------- -------------------- 30 | `-._/-' 31 | 32 | */ 33 | 34 | 35 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) 36 | { 37 | if (ul_reason_for_call != DLL_PROCESS_ATTACH) return FALSE; 38 | 39 | BaseAddress = reinterpret_cast(GetModuleHandleA(NULL)); 40 | if (!BaseAddress) return FALSE; 41 | 42 | NamePoolData = reinterpret_cast(BaseAddress + NamePoolDataOffset); 43 | 44 | FName NoneFName(0); 45 | 46 | std::string None = NoneFName.GetName(); 47 | 48 | if (None != "None") return FALSE; 49 | 50 | ImSorryForTheQualityOfThis LOG(FileName); 51 | 52 | FNameEntryAllocator Entries = NamePoolData->Entries; 53 | 54 | LOG.LogToFile("[ (*^-^*) Kinda Sorta Some Information ]\n"); 55 | 56 | LOG.LogToFile("Base Address ", BaseAddress); 57 | LOG.LogToFile("FNamePool* NamePoolData ", NamePoolData); 58 | LOG.LogToFile("Entries.CurrentBlock " + std::to_string(Entries.CurrentBlock)); 59 | LOG.LogToFile("Entries.CurrentByteCursor " + std::to_string(Entries.CurrentByteCursor)); 60 | LOG.LogToFile("Entries.Blocks ", Entries.Blocks); 61 | 62 | LOG.LogToFile("\n[ End Of Kinda Sorta Some Information `(°.°)` ]\n"); 63 | 64 | NamePoolData->Entries.Log(LOG); 65 | 66 | return TRUE; 67 | } 68 | -------------------------------------------------------------------------------- /VALORANT/FNamePool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | static constexpr uint32 FNameMaxBlockBits = 13; 4 | static constexpr uint32 FNameBlockOffsetBits = 16; 5 | static constexpr uint32 FNameMaxBlocks = 1 << FNameMaxBlockBits; 6 | static constexpr uint32 FNameBlockOffsets = 1 << FNameBlockOffsetBits; 7 | 8 | struct FNameEntryId 9 | { 10 | FNameEntryId() : Value(0) {} 11 | 12 | FNameEntryId(uint32 Id) : Value(Id) {} 13 | 14 | explicit operator bool() const { return Value != 0; } 15 | 16 | FORCEINLINE bool operator==(FNameEntryId Other) const 17 | { 18 | return Value == Other.Value; 19 | } 20 | 21 | FORCEINLINE static FNameEntryId FromUnstableInt(uint32 UnstableInt) 22 | { 23 | FNameEntryId Id; 24 | Id.Value = UnstableInt; 25 | return Id; 26 | } 27 | 28 | FORCEINLINE uint32 ToUnstableInt() const { 29 | return Value; 30 | } 31 | 32 | uint32 Value; 33 | }; 34 | 35 | struct FNameEntryHandle 36 | { 37 | uint32 Block = 0; 38 | uint32 Offset = 0; 39 | 40 | FNameEntryHandle(uint32 InBlock, uint32 InOffset) 41 | : Block(InBlock) 42 | , Offset(InOffset) 43 | {} 44 | 45 | FNameEntryHandle(FNameEntryId Id) 46 | : Block(Id.ToUnstableInt() >> FNameBlockOffsetBits) 47 | , Offset(Id.ToUnstableInt()& (FNameBlockOffsets - 1)) 48 | {} 49 | 50 | operator FNameEntryId() const 51 | { 52 | return FNameEntryId::FromUnstableInt(Block << FNameBlockOffsetBits | Offset); 53 | } 54 | 55 | explicit operator bool() const { return Block | Offset; } 56 | }; 57 | 58 | struct FNameEntryHeader 59 | { 60 | uint16 bIsWide : 1; 61 | uint16 Len : 15; 62 | }; 63 | 64 | struct FNameEntry { 65 | enum { NAME_SIZE = 1024 }; 66 | public: 67 | FORCEINLINE bool IsWide() const 68 | { 69 | return Header.bIsWide; 70 | } 71 | 72 | FORCEINLINE int32 GetNameLength() const 73 | { 74 | return Header.Len; 75 | } 76 | 77 | FORCEINLINE FNameEntryHeader GetEntryHeader() const 78 | { 79 | return Header; 80 | } 81 | 82 | static int32 GetSize(int32 Length, bool bIsPureAnsi); 83 | 84 | char* DecryptNonWide(); 85 | 86 | wchar_t* DecryptWide(); 87 | 88 | FORCEINLINE void CopyUnterminatedName(ANSICHAR* Out) 89 | { 90 | memcpy(Out, DecryptNonWide(), sizeof(ANSICHAR) * Header.Len); 91 | } 92 | 93 | FORCEINLINE void CopyUnterminatedName(WIDECHAR* Out) 94 | { 95 | memcpy(Out, DecryptWide(), sizeof(WIDECHAR) * Header.Len); 96 | } 97 | 98 | FORCEINLINE static int32 GetDataOffset() 99 | { 100 | return offsetof(FNameEntry, AnsiName); 101 | } 102 | 103 | void GetAnsiName(ANSICHAR(&Out)[NAME_SIZE]); 104 | 105 | void GetWideName(WIDECHAR(&Out)[NAME_SIZE]); 106 | 107 | std::string String(); 108 | 109 | FNameEntryId ComparisonId; 110 | 111 | FNameEntryHeader Header; 112 | 113 | union 114 | { 115 | ANSICHAR AnsiName[NAME_SIZE]; 116 | WIDECHAR WideName[NAME_SIZE]; 117 | }; 118 | 119 | }; 120 | 121 | void FNameEntry::GetAnsiName(ANSICHAR(&Out)[NAME_SIZE]) 122 | { 123 | if (!IsWide()) 124 | { 125 | CopyUnterminatedName(Out); 126 | Out[Header.Len] = '\0'; 127 | } 128 | } 129 | 130 | void FNameEntry::GetWideName(WIDECHAR(&Out)[NAME_SIZE]) 131 | { 132 | if (IsWide()) 133 | { 134 | CopyUnterminatedName(Out); 135 | Out[Header.Len] = '\0'; 136 | } 137 | } 138 | 139 | class FNameEntryAllocator 140 | { 141 | public: 142 | enum { Stride = alignof(FNameEntry) }; 143 | enum { BlockSizeBytes = Stride * FNameBlockOffsets }; 144 | 145 | void* FRWLock; 146 | uint32 CurrentBlock = 0; 147 | uint32 CurrentByteCursor = 0; 148 | uint8* Blocks[FNameMaxBlocks] = {}; 149 | 150 | FORCEINLINE uint32 NumBlocks() const 151 | { 152 | return CurrentBlock + 1; 153 | } 154 | 155 | FORCEINLINE FNameEntry& Resolve(FNameEntryHandle Handle) const 156 | { 157 | if (Handle.Offset < 0 && Handle.Block > NumBlocks() && Handle.Offset * Stride < FNameBlockOffsets) 158 | return *reinterpret_cast(Blocks[0] + Stride * 0); 159 | 160 | return *reinterpret_cast(Blocks[Handle.Block] + Stride * Handle.Offset); 161 | } 162 | 163 | void LogBlock(uint8* It, uint32 BlockSize, ImSorryForTheQualityOfThis& LOG); 164 | 165 | void Log(ImSorryForTheQualityOfThis& LOG); 166 | }; 167 | 168 | wchar_t* FNameEntry::DecryptWide() 169 | { 170 | 171 | auto _DecryptWideEntry = (__int64(__fastcall*)(FNameEntry * Entry, wchar_t* Buffer))(BaseAddress + DecryptWideOffset); 172 | 173 | wchar_t Buffer[1024]; 174 | 175 | __int64 Result = _DecryptWideEntry(this, Buffer); 176 | 177 | return Buffer; 178 | } 179 | 180 | char* FNameEntry::DecryptNonWide() 181 | { 182 | auto _DecryptNonWideEntry = (__int64(__fastcall*)(FNameEntry * Entry, char* Buffer))(BaseAddress + DecryptNonWideOffset); 183 | 184 | char Buffer[1024]; 185 | 186 | __int64 Result = _DecryptNonWideEntry(this, Buffer); 187 | 188 | return Buffer; 189 | } 190 | 191 | std::string FNameEntry::String() 192 | { 193 | if (IsWide()) { 194 | WCHAR* DecryptedName = DecryptWide(); 195 | std::wstring Wide(DecryptedName, Header.Len); 196 | return std::string(Wide.begin(), Wide.end()); 197 | } 198 | 199 | char* DecryptedName = DecryptNonWide(); 200 | return std::string(DecryptedName, Header.Len); 201 | } 202 | 203 | int32 FNameEntry::GetSize(int32 Length, bool bIsPureAnsi) 204 | { 205 | int32 Bytes = GetDataOffset() + Length * (bIsPureAnsi ? sizeof(ANSICHAR) : sizeof(WIDECHAR)); 206 | return Align(Bytes, alignof(FNameEntry)); 207 | } 208 | 209 | void FNameEntryAllocator::LogBlock(uint8* It, uint32 BlockSize, ImSorryForTheQualityOfThis& LOG) 210 | { 211 | uint8* End = It + BlockSize - FNameEntry::GetDataOffset(); 212 | while (It < End) 213 | { 214 | FNameEntry* Entry = reinterpret_cast(It); 215 | 216 | if (uint32 Len = Entry->GetEntryHeader().Len) 217 | { 218 | LOG.LogToFile("[" + std::to_string(Entry->ComparisonId.Value) + "] " + Entry->String()); 219 | It += FNameEntry::GetSize(Len, !Entry->IsWide()); 220 | } 221 | else 222 | { 223 | break; 224 | } 225 | } 226 | } 227 | 228 | void FNameEntryAllocator::Log(ImSorryForTheQualityOfThis& LOG) 229 | { 230 | LOG.LogToFile("Logging FNamePool->Entries...\n"); 231 | 232 | for (uint32 BlockIdx = 0; BlockIdx < CurrentBlock; ++BlockIdx) 233 | { 234 | LogBlock(Blocks[BlockIdx], BlockSizeBytes, LOG); 235 | } 236 | 237 | LogBlock(Blocks[CurrentBlock], CurrentByteCursor, LOG); 238 | 239 | LOG.LogToFile("\nFNamePool->Entries log has completed."); 240 | 241 | LOG.CloseLog(); 242 | } 243 | 244 | class FNamePool 245 | { 246 | public: 247 | enum { MaxENames = 512 }; 248 | FNameEntryAllocator Entries; 249 | /* 250 | * Not interested in other members. 251 | */ 252 | }; 253 | 254 | struct FName { 255 | FNameEntryId ComparisonIndex; 256 | 257 | FNameEntryId DisplayIndex; 258 | 259 | uint32 Number; 260 | 261 | FORCEINLINE FNameEntryId GetComparisonIndex() const 262 | { 263 | return ComparisonIndex; 264 | } 265 | 266 | FORCEINLINE FNameEntryId GetDisplayIndex() const 267 | { 268 | return DisplayIndex; 269 | } 270 | 271 | FORCEINLINE bool operator==(FName Other) const 272 | { 273 | return (ComparisonIndex == Other.ComparisonIndex) && (GetNumber() == Other.GetNumber()); 274 | } 275 | 276 | FORCEINLINE bool operator!=(FName Other) const 277 | { 278 | return !(*this == Other); 279 | } 280 | 281 | FORCEINLINE int32 GetNumber() const 282 | { 283 | return Number; 284 | } 285 | 286 | FName() : 287 | ComparisonIndex(FNameEntryId()), 288 | Number(0) 289 | { } 290 | 291 | FName(int32 i, int32 n = 0) : 292 | ComparisonIndex(FNameEntryId(i)), 293 | Number(n) 294 | { } 295 | 296 | const FNameEntry* GetDisplayNameEntry() const; 297 | 298 | std::string GetName(); 299 | }; 300 | 301 | const FNameEntry* FName::GetDisplayNameEntry() const 302 | { 303 | return &NamePoolData->Entries.Resolve(GetDisplayIndex()); 304 | } 305 | 306 | std::string FName::GetName() 307 | { 308 | FNameEntry Entry = NamePoolData->Entries.Resolve(GetDisplayIndex()); 309 | 310 | std::string Name = Entry.String(); 311 | 312 | if (Number > 0) Name += '_' + std::to_string(Number); 313 | 314 | std::size_t Pos = Name.rfind('/'); 315 | 316 | if (Pos != std::string::npos) Name = Name.substr(Pos + 1); 317 | 318 | return Name; 319 | } -------------------------------------------------------------------------------- /VALORANT.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | ValorantFNamePool 25 | 10.0 26 | VALORANT 27 | {0DF87F4D-16D8-4835-B552-9F5C4A0D2044} 28 | 29 | 30 | 31 | DynamicLibrary 32 | true 33 | v143 34 | Unicode 35 | 36 | 37 | DynamicLibrary 38 | false 39 | v143 40 | true 41 | Unicode 42 | 43 | 44 | DynamicLibrary 45 | true 46 | v143 47 | Unicode 48 | 49 | 50 | DynamicLibrary 51 | false 52 | v143 53 | true 54 | Unicode 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | $(ProjectDir);$(IncludePath) 76 | $(SolutionDir)\Output 77 | 78 | 79 | 80 | Level3 81 | true 82 | WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 83 | true 84 | Use 85 | pch.h 86 | 87 | 88 | Windows 89 | true 90 | false 91 | 92 | 93 | 94 | 95 | Level3 96 | true 97 | true 98 | true 99 | WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 100 | true 101 | Use 102 | pch.h 103 | 104 | 105 | Windows 106 | true 107 | true 108 | true 109 | false 110 | 111 | 112 | 113 | 114 | Level3 115 | true 116 | _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) 117 | true 118 | Use 119 | pch.h 120 | 121 | 122 | Windows 123 | true 124 | false 125 | 126 | 127 | 128 | 129 | Level3 130 | true 131 | true 132 | true 133 | NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 134 | true 135 | NotUsing 136 | pch.h 137 | MultiThreaded 138 | stdcpp17 139 | 140 | 141 | Windows 142 | true 143 | true 144 | true 145 | false 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | --------------------------------------------------------------------------------