diff --git a/launchers/darwin/CMakeLists.txt b/launchers/darwin/CMakeLists.txt
new file mode 100644
index 0000000000..499fc0440e
--- /dev/null
+++ b/launchers/darwin/CMakeLists.txt
@@ -0,0 +1,104 @@
+cmake_minimum_required(VERSION 3.0)
+project(HQLauncher)
+set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
+set(src_files
+ src/Launcher.h
+ src/Launcher.m
+ src/SplashScreen.h
+ src/SplashScreen.m
+ src/LoginScreen.h
+ src/LoginScreen.m
+ src/DisplayNameScreen.h
+ src/DisplayNameScreen.m
+ src/ProcessScreen.h
+ src/ProcessScreen.m
+ src/Window.h
+ src/Window.m
+ src/DownloadInterface.h
+ src/DownloadInterface.m
+ src/DownloadDomainContent.h
+ src/DownloadDomainContent.m
+ src/DownloadScripts.h
+ src/DownloadScripts.m
+ src/CredentialsRequest.h
+ src/CredentialsRequest.m
+ src/LatestBuildRequest.h
+ src/LatestBuildRequest.m
+ src/OrganizationRequest.m
+ src/OrganizationRequest.h
+ src/ErrorViewController.h
+ src/ErrorViewController.m
+ src/Settings.h
+ src/Settings.m
+ src/LaunchInterface.h
+ src/CustomUI.h
+ src/CustomUI.m
+ src/main.mm
+ nib/Window.xib
+ nib/SplashScreen.xib
+ nib/ErrorScreen.xib
+ nib/LoginScreen.xib
+ nib/ProcessScreen.xib
+ nib/DisplayNameScreen.xib)
+
+set(APP_NAME "HQ Launcher")
+
+set(CMAKE_C_FLAGS "-x objective-c")
+set(CMAKE_CXX_FLAGS "-x objective-c++")
+set(CMAKE_EXE_LINKER_FLAGS "-framework Cocoa -framework AppKit -framework QuartzCore")
+
+set_target_properties(${this_target} PROPERTIES
+ MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)
+
+
+set(MACOSX_BUNDLE_ICON_FILE "interface.icns")
+
+add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${src_files})
+set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${APP_NAME})
+
+
+
+file(GLOB NIB_FILES "nib/*.xib")
+
+find_program(IBTOOL ibtool HINTS "/usr/bin" "${OSX_DEVELOPER_ROOT}/usr/bin")
+foreach (nibFile ${NIB_FILES})
+ get_filename_component(fileWithExtension ${nibFile} NAME)
+ string(REGEX REPLACE "\\.[^.]*$" "" file ${fileWithExtension})
+ add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
+ COMMAND ${IBTOOL} --errors --warnings --notices
+ --output-format human-readable-text
+ --compile
+ "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources/${file}.nib"
+
+ ${CMAKE_CURRENT_SOURCE_DIR}/nib/${file}.xib)
+endforeach()
+
+
+add_custom_command(TARGET ${PROJECT_NAME} PRE_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${CMAKE_SOURCE_DIR}/images "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${APP_NAME}.app/Contents/Resources/")
+
+install(
+ TARGETS HQLauncher
+ BUNDLE DESTINATION "."
+ COMPONENT applications
+)
+
+
+set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR})
+
+include(CPackComponent)
+
+set(CPACK_PACKAGE_NAME "HQ Launcher")
+set(CPACK_PACKAGE_VENDOR "High Fidelity")
+set(CPACK_PACKAGE_VERSION ${BUILD_VERSION})
+set(CPACK_PACKAGE_FILE_NAME "HQ Launcher")
+
+set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
+
+set(DMG_SUBFOLDER_NAME "High Fidelity")
+set(ESCAPED_DMG_SUBFOLDER_NAME "")
+set(DMG_SUBFOLDER_ICON "${CMAKE_SOURCE_DIR}/cmake/installer/install-folder.rsrc")
+
+set(CPACK_GENERATOR "DragNDrop")
+include(CPack)
diff --git a/launchers/darwin/cmake/installer/Thumbs.db b/launchers/darwin/cmake/installer/Thumbs.db
new file mode 100644
index 0000000000..86bc943370
Binary files /dev/null and b/launchers/darwin/cmake/installer/Thumbs.db differ
diff --git a/launchers/darwin/cmake/installer/install-folder.rsrc b/launchers/darwin/cmake/installer/install-folder.rsrc
new file mode 100644
index 0000000000..8ce12afd3f
--- /dev/null
+++ b/launchers/darwin/cmake/installer/install-folder.rsrc
@@ -0,0 +1,1634 @@
+data 'icns' (-16455) {
+ $"6963 6E73 0000 65EB 544F 4320 0000 0018" /* icns..eTOC .... */
+ $"6974 3332 0000 25C3 7438 6D6B 0000 4008" /* it32..%t8mk..@. */
+ $"6974 3332 0000 25C3 0000 0000 FF00 FF00" /* it32..%...... */
+ $"FF00 FF00 FF00 FF00 FF00 FF00 FF00 FF00" /* ........ */
+ $"FF00 FF00 EE00 0005 A008 0007 D500 0309" /* .......... */
+ $"549A BBA0 C102 C0A3 48D2 0003 2FB2 E4E3" /* T.H../ */
+ $"A2DF 03E3 E176 01CF 0002 30C9 DDA5 D502" /* .v...0ݥ. */
+ $"D7DE 61CE 0002 0EB1 D6A7 D002 D2CC 2BCD" /* a...֧.+ */
+ $"0001 5BD4 A9CA 02D1 9A05 CB00 0202 9ACA" /* ..[ԩ.њ.... */
+ $"AAC5 01CC 4FCB 0002 0EAF C1AA BF02 C2AF" /* .O....¯ */
+ $"16CA 0002 14AE BCAA BA03 B9C1 7F02 C900" /* ........ */
+ $"0213 A9B6 ACB4 02BA 6503 C800 0212 A4B1" /* ...e.... */
+ $"ADAF 03B4 803B 26BA 2502 2415 0186 0002" /* .;&%.$.... */
+ $"129F ABAE A902 AEAE AAB9 A905 AAA9 A184" /* ... */
+ $"4003 8400 0211 9AA5 EFA4 04A5 A9AA 740E" /* @.....t. */
+ $"8300 0211 949F 819E EC9D 049E 9EA6 7607" /* ....v. */
+ $"8200 0710 8F9A 9997 9698 9CEA 9F05 9E9A" /* .... */
+ $"9797 A04A 8200 080F 8A94 919C B5CE DDE4" /* J... */
+ $"E9E5 06E2 D5BA 9F94 840B 8100 050F 848F" /* .պ.... */
+ $"B2E1 F9EE FF04 F6D3 A78F 2881 0003 0E80" /* .ӧ(... */
+ $"BEF6 F1FF 03FD DBA3 3881 0002 0BA1 F5F3" /* .ۣ8... */
+ $"FF02 FECD 3C81 0001 16D1 F5FF 01ED 4781" /* .<....G */
+ $"0001 36F1 F5FF 01F9 5281 0001 43F7 F5FF" /* ..6.R..C */
+ $"01FB 5A81 0002 43F6 FFF3 FE02 FFFB 5F81" /* .Z..C._ */
+ $"0002 43F5 FFF3 FD02 FEFA 5F81 0002 43F5" /* ..C._..C */
+ $"FEB5 FC06 FDFE FEFF FEFE FDB4 FC02 FDF9" /* .. */
+ $"5F81 0002 43F5 FEB0 FC00 FD81 FF06 FAF2" /* _..C.. */
+ $"EDEB EEF4 FD81 FF00 FDAF FC02 FDF9 5F81" /* .._ */
+ $"0002 43F4 FDAD FB16 FCFF FFF6 D1A0 704B" /* ..C.ѠpK */
+ $"3222 1A18 1B26 3854 7CAD DDFD FFFF FCAC" /* 2"...&8T| */
+ $"FB02 FCF8 5F81 0002 43F3 FCAB FA06 FCFF" /* ._..C. */
+ $"FAC4 732E 068A 0006 0E3E 89D7 FFFF FBAA" /* s.....> */
+ $"FA02 FBF8 5F81 0002 43F3 FBA9 F905 FAFF" /* ._..C. */
+ $"F3A1 3C02 8300 0608 131B 1D19 1005 8300" /* <........... */
+ $"040C 55BC FDFF A9F9 02FA F75F 8100 0243" /* ..U._..C */
+ $"F3FB A7F9 04F8 FEFB A831 8200 0E26 5C91" /* .1..&\ */
+ $"B9D4 E3EA ECE8 DFCE B083 4D19 8100 0501" /* ΰM.... */
+ $"4DC7 FFFB F8A6 F902 FAF7 5F81 0002 43F2" /* M._..C */
+ $"FAA7 F802 FFD5 4E81 0003 1D6E BFEF 80FF" /* .N...n */
+ $"01FC FB80 FA08 FBFD FFFF FEE6 AC56 0D80" /* ..V. */
+ $"0004 0973 EDFF F7A5 F802 F9F6 5F81 0002" /* ..s._.. */
+ $"43F1 F8A4 F704 F6F8 FE9F 1580 0005 238F" /* C....# */
+ $"E6FF FDF8 8AF7 05F9 FFFE D570 0F80 0002" /* .p... */
+ $"31C6 FFA5 F702 F8F5 5F81 0002 43F0 F7A4" /* 1._..C */
+ $"F602 F9F7 7280 0004 0C7C E8FF F990 F603" /* .r...|. */
+ $"FBFF D357 8000 030F A1FF F7A3 F602 F7F5" /* W.... */
+ $"5F81 0002 43F0 F7A3 F602 F9F2 5880 0003" /* _..C.X.. */
+ $"37C8 FFF9 94F6 09FB FCA4 1900 0003 8AFE" /* 7.... */
+ $"F7A2 F602 F7F5 5F81 0002 43F0 F6A2 F502" /* ._..C. */
+ $"F8F2 5180 0002 63EE FC82 F501 F6F6 91F5" /* Q..c. */
+ $"02FF D539 8000 0186 FDA2 F502 F6F4 5F81" /* .9..._ */
+ $"0002 43EF F5A1 F408 F5F7 5D00 0001 7FFA" /* ..C.].... */
+ $"F781 F405 F5FD F3F4 FDF5 90F4 07FB EA4F" /* ..O */
+ $"0000 0194 FEA1 F402 F5F3 5E81 0002 43EE" /* ....^..C */
+ $"F4A1 F301 FC7D 8000 0286 FCF4 81F3 07F5" /* .}... */
+ $"EF81 3335 88F2 F490 F307 F7F0 5200 0008" /* 35.R... */
+ $"B4FC A0F3 02F4 F25E 8100 0243 EEF3 A0F2" /* .^..C */
+ $"07FB AE04 0000 77FB F382 F201 F86A 8100" /* ....w.j. */
+ $"0177 F991 F207 F6ED 4200 001D DBF7 9FF2" /* .w.B... */
+ $"02F3 F25E 8100 0243 EDF2 9FF1 07F5 DF20" /* .^..C. */
+ $"0000 53F5 F382 F102 F5D8 0D81 0002 15E0" /* ..S..... */
+ $"F486 F101 F2F2 86F1 07F7 DD25 0000 50F5" /* ..%..P */
+ $"F29E F102 F2F1 5E81 0002 43EC F19F F006" /* .^..C. */
+ $"F864 0000 25E1 F483 F002 F5CA 0481 0002" /* d..%.... */
+ $"0AD4 F484 F005 F1F9 F4F5 F8F1 85F0 06F9" /* .. */
+ $"B808 0000 A0F9 9EF0 02F1 F05E 8100 0243" /* ....^..C */
+ $"EBF0 9EEF 06F6 BE06 0004 AEF8 84EF 02F1" /* ..... */
+ $"E92C 8100 0237 EEF0 83EF 07F1 ED88 3E43" /* ,..7.>C */
+ $"99F2 F085 EF06 FA74 0000 25E5 F19D EF02" /* .t..%. */
+ $"F0EF 5E81 0002 43EB F09E EF05 F54B 0000" /* ^..C.K.. */
+ $"59F7 86EF 07F5 BA20 0000 26C3 F584 EF01" /* Y. ..&. */
+ $"F569 8100 0188 F785 EF06 F1E5 2500 0088" /* i...%.. */
+ $"F99D EF02 F0EF 5E81 0002 43EB F09D EF06" /* .^..C. */
+ $"F5BE 0500 0DCC F486 EF07 EEFA B400 13D3" /* ...... */
+ $"F6EE 83EF 02F2 D20A 8100 021E E5F0 84EF" /* .... */
+ $"07EE F898 0000 23E5 F09C EF02 F0EF 5E81" /* ...#.^ */
+ $"0002 43EB EF9D EE06 F760 0000 61F7 ED87" /* ..C.`..a */
+ $"EE05 F4BD 0018 DFEF 84EE 01F3 BF82 0002" /* ...... */
+ $"0FD7 F085 EE07 EFE9 2A00 009D F6ED 9BEE" /* ..*.. */
+ $"02EF EF5E 8100 0243 EAEE 9CED 06EF DB16" /* .^..C.. */
+ $"0006 C0F3 88ED 05F3 BB00 17DD EF84 ED02" /* ...... */
+ $"EFE0 1E81 0000 3988 ED05 F788 0000 46F2" /* ...9...F */
+ $"9CED 02EE EE5E 8100 0243 E9ED 9CEC 05F4" /* .^..C. */
+ $"9D00 003B EE89 EC05 F2BB 0017 DCEE 85EC" /* ..;... */
+ $"07F3 A715 0000 20BF F187 EC06 EFD3 1000" /* .... ... */
+ $"0DD0 EF9B EC02 EDED 5E81 0002 43E9 EC9C" /* ..^..C */
+ $"EB05 F459 0000 86F5 89EB 05F1 BA00 17DB" /* .Y..... */
+ $"ED86 EB05 F7A4 0016 CFF2 89EB 05F1 4900" /* ....I. */
+ $"0096 F49B EB02 ECEC 5E81 0002 43E8 EB9B" /* ..^..C */
+ $"EA06 EBE4 2500 05C2 EF89 EA05 F0B9 0017" /* .%..... */
+ $"DAEC 86EA 05F1 B300 1DE1 EC89 EA05 F48B" /* .... */
+ $"0000 5AF3 9BEA 02EB EC5E 8100 0243 E7EA" /* ..Z.^..C */
+ $"9BE9 06ED C607 0024 E3EA 89E9 05EF B800" /* ...$.. */
+ $"18E1 ED86 E905 F0B0 001C DFEB 89E9 06EE" /* ..... */
+ $"BE04 002D E7EA 9AE9 02EA EB5E 8100 0243" /* ..-.^..C */
+ $"E7EA 9BE9 05F1 A400 004B F08A E907 EFB8" /* ...K. */
+ $"000A 8AE0 F3EC 84E9 05F0 B000 1CDF EB89" /* .... */
+ $"E906 EBDC 1A00 11D3 EC9A E902 EAEB 5E81" /* .....^ */
+ $"0002 43E7 E99B E805 F284 0000 6FF2 8AE8" /* ..C...o */
+ $"01EE B780 0004 2481 D6F2 EC82 E805 EFAF" /* ...$. */
+ $"001C DEEA 89E8 06E9 EA35 0002 BCEE 9AE8" /* ...5.. */
+ $"02E9 EA5E 8100 0243 E6E8 9BE7 05F1 6B00" /* .^..C.k. */
+ $"008A F18A E70B EDB7 0003 0200 0019 70CB" /* ........p */
+ $"F0ED 80E7 05EE AF00 1CDD E98A E705 EF4E" /* ....N */
+ $"0000 A7EF 9AE7 02E8 E95E 8100 0243 E5E7" /* ...^..C */
+ $"9BE6 05EF 5B00 009B EF8A E614 ECB6 0017" /* .[..... */
+ $"A959 0B00 0010 60BF EDED E7ED AE00 1CDC" /* Y....`.. */
+ $"E88A E605 F05F 0000 97EF 9AE6 02E7 E95E" /* ._...^ */
+ $"8100 0243 E4E6 9BE5 05ED 5300 00A3 ED8A" /* ..C.S.. */
+ $"E514 EBB5 0016 DCEF C367 1400 0008 50B1" /* ...g....P */
+ $"E9F4 AE00 1CDB E78A E505 EF68 0000 8FEE" /* ...h.. */
+ $"9AE5 02E6 E85E 8100 0243 E4E5 9BE4 05EC" /* .^..C. */
+ $"5200 00A3 EC8A E414 EAB4 0016 D5E7 E9EE" /* R..... */
+ $"CD76 1D00 0002 42A9 A900 1CDA E68A E405" /* v....B... */
+ $"EF68 0000 8EEE 9AE4 02E5 E75E 8100 0243" /* h...^..C */
+ $"E3E4 9BE3 05EC 5900 009A EC8A E30C E9B3" /* .Y... */
+ $"0016 D4E5 E3E3 E7ED D585 2880 0004 1E00" /* ..Յ(.... */
+ $"1CD9 E58A E305 ED5F 0000 95EC 9AE3 02E4" /* .._... */
+ $"E65E 8100 0243 E3E4 9BE3 05ED 6800 0089" /* ^..C.h.. */
+ $"EC8A E305 E9B3 0016 D4E5 81E3 04E5 EDDC" /* .... */
+ $"9435 8000 021C D9E5 8AE3 05EB 4E00 00A3" /* 5....N.. */
+ $"EA9A E302 E4E6 5E81 0002 43E3 E49B E305" /* .^..C. */
+ $"EC80 0000 6FED 8AE3 05E9 B300 16D4 E583" /* ..o... */
+ $"E308 E4EC E2A4 3B00 1CD9 E58A E305 E536" /* .;...6 */
+ $"0002 B6E8 9AE3 02E4 E65E 8100 0243 E2E3" /* ...^..C */
+ $"9BE2 05EA 9D00 004B E98A E205 E8B3 0016" /* ...K... */
+ $"D3E4 85E2 06E3 EFAF 001B D8E4 89E2 06E4" /* .... */
+ $"D61A 000F CCE5 9AE2 02E3 E65D 8100 0243" /* ....]..C */
+ $"E2E2 9BE1 06E5 BE06 0025 DCE2 89E1 05E7" /* ...%. */
+ $"B200 16D2 E386 E105 E7AA 001B D7E3 89E1" /* ..... */
+ $"06E6 B904 002A DEE2 9AE1 02E2 E55D 8100" /* ...*.]. */
+ $"0243 E1E1 9BE0 06E1 D921 0006 BCE4 89E0" /* .C.!.. */
+ $"05E6 B200 16D3 E286 E005 E6A9 001B D6E2" /* ...... */
+ $"89E0 05E9 8800 0054 E89B E002 E1E4 5D81" /* ...T.] */
+ $"0002 43E0 E09C DF05 E751 0000 83E9 89DF" /* ..C.Q.. */
+ $"05EA A900 12C6 E686 DF05 E5A8 001B D5E1" /* ...... */
+ $"89DF 05E6 4900 008B E89B DF02 E0E3 5D81" /* .I...] */
+ $"0002 43DF DF9C DE05 E691 0000 3BE2 88DE" /* ..Cߜ...; */
+ $"07E4 AF1F 0000 25B7 E385 DE05 E4A8 001B" /* ....%... */
+ $"D4E0 88DE 06E1 C911 000A C1E2 9BDE 02DF" /* .... */
+ $"E35D 8100 0243 DFDE 9CDD 06E0 CA12 0007" /* ]..Cޜ.... */
+ $"B7E2 86DD 02DE D82A 8100 0234 DCDE 84DD" /* .*..4ބ */
+ $"05E3 A700 1BD3 DF88 DD05 E783 0000 3DE1" /* ...߈...= */
+ $"9DDD 01E2 5D81 0002 43DE DD9D DC05 E454" /* .]..Cݝ.T */
+ $"0000 5FE5 86DC 02E1 B904 8100 0209 C3E0" /* .._.... */
+ $"84DC 05E2 A700 1BD3 DE87 DC06 DDDA 2B00" /* ...އ.+. */
+ $"008D E59D DC01 E15D 8100 0243 DEDD 9DDC" /* ..]..Cݝ */
+ $"06E2 AB03 000E C0E0 85DC 02DF C40C 8100" /* ....... */
+ $"0213 CCDE 84DC 05E7 A300 18CE E287 DC06" /* ..ބ.... */
+ $"E592 0000 1DD1 DE9D DC01 E15D 8100 0243" /* ...ޝ.]..C */
+ $"DDDC 9DDB 07DC DF40 0000 57E4 DC84 DB02" /* ܝ.@..W܄. */
+ $"DCE1 5E81 0001 6AE2 84DB 07E1 AF23 0001" /* ^..j.#.. */
+ $"32C1 DF85 DB06 DDD5 2700 0077 E49E DB01" /* 2߅.'..w. */
+ $"E05D 8100 0243 DDDC 9DDB 08DA E1A9 0400" /* ]..Cܝ... */
+ $"05A5 E2DA 83DB 09DA DCD6 712C 2E78 D9DC" /* .ڃq,.x */
+ $"DA82 DB02 DCD4 2881 0001 42DE 84DB 07DA" /* ڂ.(..Bބ. */
+ $"E471 0000 1DCE DD9E DB01 E05D 8100 0243" /* q...ݞ.]..C */
+ $"DDDB 9FDA 07E0 5400 0027 CFDD D983 DA07" /* ۟.T..'ك. */
+ $"D9DB E1D8 D9E1 DBD9 83DA 01DE B182 0002" /* ك.ޱ.. */
+ $"0FC7 DC82 DA08 D9E1 AD0A 0000 8AE2 D99E" /* .܂...ٞ */
+ $"DA01 E05D 8100 0144 DCA0 D907 DCC4 1800" /* .]..Dܠ... */
+ $"0052 DEDA 91D9 02DC B905 8100 0216 CCDA" /* .Rڑ.ܹ.... */
+ $"81D9 07D8 DDCB 2600 0041 DBA0 D901 DF5D" /* .&..A۠.] */
+ $"8100 0144 DBA0 D807 D7E0 9402 0000 72E0" /* ..D۠....r */
+ $"92D8 01DA 4C81 0001 68DE 82D8 07DA D642" /* .L..hނ.B */
+ $"0000 16BE DCA0 D801 DE5D 8100 0144 DBA2" /* ...ܠ.]..Dۢ */
+ $"D707 DE66 0000 027F E0D8 90D7 07D9 CC5E" /* .f....ؐ.^ */
+ $"2024 6ED4 D881 D707 DAD8 5100 0005 98DF" /* $n.Q... */
+ $"A1D7 01DD 5D81 0001 44DA A2D6 08D8 D74A" /* .]..Dڢ.J */
+ $"0000 0279 DDD8 90D6 05D8 DDCF D1DD D781" /* ...yؐ.ׁ */
+ $"D602 DBD2 4E80 0001 7ADE A2D6 01DC 5D81" /* .N..zޢ.] */
+ $"0001 44DA A3D6 02D9 D03F 8000 0260 D4DB" /* ..Dڣ.?..` */
+ $"91D6 01D7 D782 D602 DEC1 3A80 0002 6CDC" /* .ׂ.:..l */
+ $"D7A2 D601 DC5D 8100 0144 D9A4 D502 D9CE" /* ע.]..D٤. */
+ $"4480 0003 38B5 DFD7 94D5 03D9 DC98 1C80" /* D..8ה.ܘ. */
+ $"0002 6FDB D6A3 D501 DC5D 8100 0144 D8A5" /* ..o֣.]..Dإ */
+ $"D402 D8D2 5980 0004 0F75 CDDD D690 D40A" /* .Y...u */
+ $"D7DD BD55 0200 0009 82DB D5A4 D401 DB5D" /* ݽU...Ƃդ.] */
+ $"8100 0144 D8A6 D303 D5D8 7F0D 8000 0526" /* ..Dئ.....& */
+ $"85CA DCD8 D48A D305 D5DA DBBD 6A13 8000" /* Ԋ.۽j.. */
+ $"0323 A2DC D4A5 D301 DA5D 8100 0144 D7A7" /* .#ԥ.]..Dק */
+ $"D203 D3DB AE39 8100 141F 68AB D0DB DAD8" /* .ۮ9...h */
+ $"D5D4 D4D3 D4D4 D6D8 DBD9 C99C 5411 8000" /* ɜT.. */
+ $"0303 57C5 D9A7 D201 D95D 8100 0144 D6A9" /* ..W٧.]..D֩ */
+ $"D103 D7D1 8422 8100 0F04 2859 85A5 B9C5" /* .ф"...(Y */
+ $"CACB C9C3 B59D 7A4B 1C82 0003 389F D8D4" /* õzK...8 */
+ $"A8D1 01D9 5D81 0001 44D6 AAD0 04D1 D9C7" /* .]..D֪. */
+ $"7D2A 8400 060B 161E 201C 1408 8300 0506" /* }*..... ...... */
+ $"3D95 D1D7 D1A9 D001 D85C 8100 0144 D6AC" /* =ѩ.\..D֬ */
+ $"D006 D2D9 CD9B 551F 018A 0006 072A 68AB" /* .͛U.....*h */
+ $"D4D7 D1AB D001 D85C 8100 0144 D6AD D016" /* ѫ.\..D֭. */
+ $"CFD1 D6D8 C8A5 7A52 3521 150F 0D10 1825" /* ȥzR5!.....% */
+ $"3B5C 85AF CED8 D4AE D001 D85C 8100 0144" /* ;\Ԯ.\..D */
+ $"D5B1 CF0F D0D4 D7D7 D1C9 C1BC BABD C3CC" /* ձ. */
+ $"D3D7 D7D3 B1CF 01D7 5C81 0001 44D4 B6CE" /* ӱ.\..DԶ */
+ $"00CF 81D0 01CF CFB5 CE01 D65C 8100 0144" /* .ρ.ϵ.\..D */
+ $"D3F5 CD01 D65C 8100 0144 D3F5 CC01 D55C" /* .\..D.\ */
+ $"8100 0144 D2F5 CB01 D45C 8100 0144 D1F5" /* ..D.\..D */
+ $"CA01 D35C 8100 0144 D1F5 CA01 D35C 8100" /* .\..D.\. */
+ $"0144 D1F5 C901 D35C 8100 0144 D0F5 C801" /* .D.\..D. */
+ $"D25C 8100 0144 CFF5 C801 D15C 8100 0244" /* \..D.\..D */
+ $"C7BA F3BB 02BA C85B 8100 0144 C6F5 BA01" /* Ǻ.[..D. */
+ $"C75B 8100 0144 CAF5 C001 CC5C 8100 0144" /* [..D.\..D */
+ $"CEF5 C501 CF5C 8100 0144 D1F5 CA01 D35C" /* .\..D.\ */
+ $"8100 0144 D5F5 CF01 D75C 8100 0144 D9F5" /* ..D.\..D */
+ $"D401 DB5D 8100 0146 DEF5 DA01 E05E 8100" /* .]..F.^. */
+ $"022A B5B8 F4B7 01BF 5382 0000 07F5 0801" /* .*.S..... */
+ $"0904 FF00 FF00 FF00 FF00 FF00 FF00 FF00" /* ........ */
+ $"FF00 FF00 FF00 FF00 FF00 E700 FF00 FF00" /* ........ */
+ $"FF00 FF00 FF00 FF00 FF00 FF00 FF00 FF00" /* ........ */
+ $"FF00 FF00 EE00 0004 A008 0007 D500 0409" /* .......... */
+ $"5399 BAC1 A0C0 01A2 48D2 0004 2FB1 E3E2" /* S.H../ */
+ $"DFA1 DE03 E2E0 7601 CF00 0230 C9DC A4D5" /* ߡ.v...0ܤ */
+ $"03D4 D6DD 60CE 0002 0EB0 D5A7 CF02 D1CB" /* .`...է. */
+ $"2BCD 0001 5BD3 A9C9 02D0 9905 CB00 0202" /* +..[ө.Й.... */
+ $"99C9 AAC4 01CB 4FCB 0002 0EAE C0AA BE02" /* ɪ.O.... */
+ $"C1AE 16CA 0002 13AD BAAB B802 C07F 02C9" /* ....... */
+ $"0002 13A8 B5AC B302 B964 03C8 0002 12A2" /* ....d.... */
+ $"AFAC AD04 AEB2 7F3B 26BA 2502 2415 0186" /* ..;&%.$.. */
+ $"0002 129D AAAE A801 ADAD BCA8 03A0 8240" /* .....@ */
+ $"0384 0002 1198 A3EF A204 A3A7 A973 0D83" /* .....s. */
+ $"0002 1192 9D81 9CEC 9B04 9C9C A474 0782" /* ....t. */
+ $"0007 108D 9897 9594 969A EA9D 059C 9895" /* .... */
+ $"959E 4982 0008 0F88 928F 9AB4 CDDD E4E9" /* I... */
+ $"E506 E2D5 B99E 9282 0B81 0005 0F82 8DB1" /* .չ.... */
+ $"E1F9 EEFF 04F6 D2A6 8D28 8100 030D 7EBD" /* .Ҧ(...~ */
+ $"F6F1 FF03 FDDB A137 8100 020A A0F6 F3FF" /* .ۡ7.. */
+ $"02FE CD3B 8100 0116 D1F5 FF01 ED46 8100" /* .;....F. */
+ $"0136 F1F5 FF01 F852 8100 0143 F7F5 FF01" /* .6.R..C. */
+ $"FB5A 8100 0243 F6FF F3FE 02FF FB5F 8100" /* Z..C._. */
+ $"0243 F5FF F3FD 02FE FA5F 8100 0243 F5FE" /* .C._..C */
+ $"B6FC 82FD B5FC 02FD F95F 8100 0243 F4FD" /* ._..C */
+ $"B0FB 0FFC FDFF FFFE FBF7 F5F5 F6F8 FBFE" /* . */
+ $"FFFF FDB0 FB02 FCF8 5F81 0002 43F4 FDAE" /* ._..C */
+ $"FB14 FDFF F9EB D8C6 B7AE A8A5 A4A5 A9B0" /* .Ʒ */
+ $"BBCA DDEF FCFF FDAD FB02 FCF8 5F81 0002" /* ._.. */
+ $"43F3 FCAB FA08 FBFE FAE6 C6AC 9D97 9785" /* C.Ƭ */
+ $"9809 9797 98A0 B2CF EDFD FDFB AAFA 02FB" /* Ɨ. */
+ $"F85F 8100 0243 F3FB A9F9 1DFA FDF7 D8B1" /* _..C.ر */
+ $"9B97 9999 9797 9A9E A2A5 A6A5 A19D 9997" /* */
+ $"9899 9897 9FBA E3FB FCA9 F902 FAF7 5F81" /* ._ */
+ $"0002 43F3 FBA7 F922 F8FB FADA AC98 9899" /* ..C"ڬ */
+ $"979B A9BD D1E1 EBF0 F3F4 F2EF E8DD CCB7" /* ̷ */
+ $"A499 989A 979A B7E6 FCFA F8A6 F902 FAF7" /* . */
+ $"5F81 0002 43F2 FAA7 F802 FBEB B780 991C" /* _..C.뷀. */
+ $"98A5 C4E2 F5FB FCFA F9F9 F8F8 F9F9 FAFB" /* */
+ $"FCFA F1DB BB9F 979A 979D C6F4 FAA6 F802" /* ۻ. */
+ $"F9F6 5F81 0002 43F1 F8A6 F70A FAD6 A197" /* _..C֡ */
+ $"9A97 A7D0 F1FB F98B F70B F8FA FAEA C4A0" /* .Ġ */
+ $"989A 97AC E5FA A5F7 02F8 F55F 8100 0243" /* ._..C */
+ $"F0F7 A4F6 0AF7 F6C5 999A 989E C8F1 FAF7" /* ř */
+ $"90F6 09F8 FAE9 BB99 9998 9FD6 F9A4 F602" /* 黙. */
+ $"F7F5 5F81 0002 43F0 F6A3 F509 F6F3 BB97" /* _..C */
+ $"9A97 AEE4 F9F6 94F5 08F7 F7D7 A398 9A9A" /* .ף */
+ $"CEF8 A3F5 02F6 F45F 8100 0243 EFF5 A2F4" /* ._..C */
+ $"08F5 F3B8 979A 98BF F2F7 98F4 07F8 E9AF" /* .. */
+ $"989A 99CC F7A2 F402 F5F3 5E81 0002 43EF" /* .^..C */
+ $"F5A2 F407 F5BD 979A 99C9 F6F5 82F4 03F7" /* .. */
+ $"F4F4 F791 F407 F6F1 B797 9A99 D1F7 A1F4" /* . */
+ $"02F5 F35E 8100 0243 EEF4 A1F3 07F6 C897" /* .^..C.ȗ */
+ $"9A99 CBF6 F481 F305 F4F2 CAAC ADCC 92F3" /* .ʬ̒ */
+ $"07F5 F2B8 989A 9CDC F6A0 F302 F4F2 5E81" /* ..^ */
+ $"0002 43EE F3A0 F206 F5DA 9B9A 98C6 F583" /* ..C.ڛ */
+ $"F207 F4C1 9699 9996 C6F5 91F2 07F3 F0B3" /* .. */
+ $"9899 A5EA F49F F202 F3F2 5E81 0002 43ED" /* .^..C */
+ $"F29F F107 F2EB A699 98B9 F3F2 82F1 09F2" /* .릙 */
+ $"E8A0 9A9B 9B9A A2EB F291 F106 F3EA A799" /* 蠚.꧙ */
+ $"97B8 F39F F102 F2F1 5E81 0002 43EC F19F" /* .^..C */
+ $"F006 F3BF 9799 A8EB F283 F002 F2E3 9C80" /* ..㜀 */
+ $"9B03 9A9F E6F1 84F0 04F1 F3F1 F2F3 86F0" /* .. */
+ $"06F3 DC9C 9A99 D4F4 9EF0 02F1 F05E 8100" /* .ܜ.^. */
+ $"0243 EBF0 9EEF 06F2 DE9C 9A9B D8F3 84EF" /* .C.ޜ */
+ $"09F0 EDAA 989B 9B97 AEEF F083 EF07 F0EF" /* . */
+ $"CBB0 B2D1 F0F0 85EF 06F3 C498 99A8 ECF0" /* ˰.Ę */
+ $"9DEF 02F0 EF5E 8100 0243 EBEF 9EEE 05F0" /* .^..C. */
+ $"B598 98BA F186 EE07 F1DC A59A 9AA7 DFF0" /* .ܥ */
+ $"84EE 07F0 C096 9898 97CB F185 EE06 EFEB" /* .. */
+ $"A899 98CB F29D EE02 EFEF 5E81 0002 43EB" /* .^..C */
+ $"EF9D EE07 F0DD 9C9A 9FE2 EFED 85EE 07ED" /* .ݜ. */
+ $"F1DA 9AA1 E4F0 ED83 EE08 EFE3 9E9A 9B9B" /* ښ.㞚 */
+ $"99A6 EA85 EE06 EDF1 D099 99A7 EA9D EE02" /* .Й. */
+ $"EFEF 5E81 0002 43EA EE9D ED05 F0BC 9798" /* ^..C. */
+ $"BDF0 88ED 05EF DD9A A3E8 EE84 ED01 EFDD" /* .ݚ. */
+ $"819B 039A A0E5 EE86 ED05 EBAA 9998 D1F0" /* ..몙 */
+ $"9CED 02EE EE5E 8100 0243 EAEE 9CED 06EE" /* .^..C. */
+ $"E6A3 9A9C DDEF 88ED 05EF DC9A A3E7 EE85" /* 棚.ܚ */
+ $"ED06 E8A6 989B 9B97 AF88 ED05 F0CA 9898" /* .覘.ʘ */
+ $"B3EE 9CED 02EE EE5E 8100 0243 E9ED 9CEC" /* .^..C */
+ $"05EF D199 99AF ED89 EC05 EEDB 9AA3 E7ED" /* .љ.ۚ */
+ $"85EC 07EE D4A1 9A9A A5DC EE87 EC06 EDE3" /* .ԡ. */
+ $"A09A 9FE2 ED9B EC02 EDED 5E81 0002 43E9" /* .^..C */
+ $"EC9C EB05 EEB9 9898 C9EE 89EB 05ED DA9A" /* ..ښ */
+ $"A3E6 EC86 EB05 EFD2 99A2 E1EE 89EB 05ED" /* .ҙ. */
+ $"B498 98CE EE9B EB02 ECEC 5E81 0002 43E8" /* .^..C */
+ $"EB9C EA05 E8A7 999C DCEC 89EA 05EC D99A" /* .觙.ٚ */
+ $"A3E5 EB86 EA05 ECD8 99A5 E7EB 89EA 05ED" /* .ؙ. */
+ $"CA98 98BA ED9B EA02 EBEC 5E81 0002 43E7" /* ʘ.^..C */
+ $"EA9B E905 EADD 9D99 A7E7 8AE9 05EB D99A" /* .ݝ.ٚ */
+ $"A3E7 EB86 E905 EBD6 99A5 E6EA 89E9 05EB" /* .֙. */
+ $"DA9C 99AA E89B E902 EAEB 5E81 0002 43E7" /* ڜ.^..C */
+ $"E99B E805 EBD1 9998 B4EA 8AE8 07EA D89B" /* .љ.؛ */
+ $"9DC8 E5EB E984 E805 EAD5 99A4 E5E9 89E8" /* .ՙ */
+ $"06E9 E4A4 99A1 E1E9 9AE8 02E9 EA5E 8100" /* .䤙.^. */
+ $"0243 E6E8 9BE7 05EA C698 98C0 EA8A E709" /* .C.Ƙ */
+ $"E9D7 9B9A 98A6 C5E1 EAE8 82E7 05E9 D499" /* כ.ԙ */
+ $"A4E4 E88A E705 E8AC 999C D9E9 9AE7 02E8" /* .謙. */
+ $"E95E 8100 0243 E5E7 9BE6 05E9 BE98 98C8" /* ^..C.龘 */
+ $"E98A E60B E8D6 9B9C 9C97 97A2 BFDD E9E8" /* .֛ */
+ $"80E6 05E8 D499 A4E3 E78A E605 E9B4 9899" /* .ԙ.鴘 */
+ $"D1E9 9AE6 02E7 E95E 8100 0243 E5E7 9BE6" /* .^..C */
+ $"05E9 B998 99CE E98A E614 E8D6 9AA2 D2B8" /* .鹘.֚Ҹ */
+ $"9E97 979F BAD9 E8E8 E6E8 D499 A4E3 E78A" /* ԙ */
+ $"E605 E9BA 9898 CCE9 9AE6 02E7 E95E 8100" /* .麘.^. */
+ $"0243 E4E6 9BE5 05E8 B698 99D0 E88A E514" /* .C.趘. */
+ $"E7D5 9AA2 E2E9 DABC A197 979D B5D4 E7EA" /* ՚ڼ */
+ $"D499 A4E2 E68A E505 E8BD 9898 C9E8 9AE5" /* ԙ.轘 */
+ $"02E6 E85E 8100 0243 E4E5 9BE4 05E7 B698" /* .^..C.綘 */
+ $"99CF E78A E414 E6D5 9AA2 DFE6 E6E8 DDC1" /* .՚ */
+ $"A398 969B AFD1 D299 A4E1 E58A E405 E7BC" /* ҙ. */
+ $"9898 C9E7 9AE4 02E5 E75E 8100 0243 E4E4" /* .^..C */
+ $"9BE3 05E6 B798 99CC E68A E314 E5D5 9AA2" /* .淘.՚ */
+ $"DEE4 E3E3 E5E7 DFC5 A799 979A A49A A4E0" /* ŧ */
+ $"E48A E305 E7B9 9899 CAE6 9AE3 02E4 E65E" /* .繘.^ */
+ $"8100 0243 E3E4 9BE3 05E6 BC98 98C6 E68A" /* ..C.漘 */
+ $"E305 E5D4 9AA2 DEE4 82E3 09E6 E0C9 AB99" /* .Ԛɫ */
+ $"989A A4E0 E48A E305 E5B4 9899 CEE5 9AE3" /* .崘 */
+ $"02E4 E65E 8100 0243 E2E3 9BE2 05E5 C398" /* .^..C.Ø */
+ $"98BD E58A E205 E4D3 9AA2 DDE3 84E2 07E4" /* .Ӛ. */
+ $"E2CE AD99 A4DF E38B E204 AC99 9BD4 E39A" /* έ. */
+ $"E202 E3E6 5D81 0002 43E2 E29B E105 E3CC" /* .]..C. */
+ $"9998 B2E3 8AE1 05E3 D29A A2DC E286 E105" /* .Қ. */
+ $"E5D1 99A3 DEE2 8AE1 05DD A399 A0DA E29A" /* љ.ݣ */
+ $"E102 E2E5 5D81 0002 43E1 E19B E005 E1D5" /* .]..C. */
+ $"9D99 A6DE 8AE0 05E2 D29A A2DB E186 E004" /* ފ.Қ. */
+ $"E2CF 99A3 DD8A E005 E1D4 9C99 A8DF 9BE0" /* ϙ݊.Ԝߛ */
+ $"02E1 E45D 8100 0243 E0E0 9CDF 05DD A599" /* .]..C.ݥ */
+ $"9DD4 E089 DF05 E1D1 9AA2 DBE0 86DF 04E1" /* .њ. */
+ $"CE99 A3DC 8ADF 05E2 C498 98B4 E19B DF02" /* Ι܊.Ę. */
+ $"E0E3 5D81 0002 43DF DF9C DE05 E0B3 9898" /* ]..Cߜ. */
+ $"C2E1 89DE 05E1 CE9A A0D7 E086 DE04 E0CE" /* .Κ. */
+ $"99A3 DB8A DE05 E0B1 9999 C5E1 9BDE 02DF" /* ۊ.ౙ. */
+ $"E35D 8100 0243 DFDF 9CDE 05E1 C799 99AD" /* ]..Cߜ.Ǚ */
+ $"DF88 DE07 E0D0 A39A 9AA5 D2DF 85DE 04E0" /* ߈.У߅. */
+ $"CE99 A3DB 89DE 06DF D8A0 9A9E D5DF 9BDE" /* Ιۉ.ؠߛ */
+ $"02DF E35D 8100 0243 DFDE 9CDD 06DE D7A0" /* .]..Cޜ.נ */
+ $"9A9C D2DF 86DD 07DE DCA7 989B 9B98 AA86" /* ߆.ܧ */
+ $"DD04 DFCD 99A3 DA89 DD05 E0C2 9899 ADDE" /* .͙ډ. */
+ $"9DDD 01E2 5D81 0002 43DE DD9D DC05 DFB4" /* .]..Cݝ.ߴ */
+ $"9898 B7DF 86DC 02DD D29C 809B 039A 9ED5" /* ߆.Ҝ. */
+ $"DD84 DC04 DECC 99A3 DA88 DC06 DDDB A899" /* ݄.̙ڈ.ۨ */
+ $"99C5 DF9D DC01 E15D 8100 0243 DDDC 9DDB" /* ߝ.]..Cܝ */
+ $"06DD CD9B 9A9F D3DD 85DB 09DC D49E 9A9B" /* .͛݅Ԟ */
+ $"9B9A A1D7 DC84 DB05 DFCA 99A2 D7DD 87DB" /* ܄.ʙ݇ */
+ $"06DE C699 9AA3 D8DC 9DDB 01E0 5D81 0002" /* .ƙܝ.].. */
+ $"43DD DB9E DA05 DCAE 9998 B4DD 86DA 07DC" /* C۞.ܮ݆. */
+ $"B697 9999 97BA DC84 DA07 DCCE A49A 9BA9" /* ܄.Τ */
+ $"D3DC 85DA 06DB D8A6 9A98 BEDD 9EDA 01E0" /* ܅.ئݞ. */
+ $"5D81 0002 43DD DB9E DA07 DBCB 9B9A 9BCA" /* ]..C۞.˛ */
+ $"DCD9 85DA 05D8 BBA7 A7BD D985 DA07 D8A6" /* م.ػم.ئ */
+ $"989B 9B98 AEDB 84DA 06D9 DCBB 989A A3D6" /* ۄ.ܻ */
+ $"9FDA 01E0 5D81 0001 44DB A0D9 07DA B398" /* .]..D۠.ڳ */
+ $"99A6 D6D9 D883 D907 D8D9 DBD8 D8DB D9D8" /* . */
+ $"83D9 01DA CD81 9B02 9A9F D383 D908 D8DB" /* .́.Ӄ. */
+ $"CC9D 9A99 C2DB D89E D901 DF5D 8100 0144" /* ̝؞.]..D */
+ $"DBA0 D806 D9D2 A29A 98B2 D992 D802 D9CF" /* ۠.Ңْ. */
+ $"9C80 9B02 9AA1 D483 D805 D9D4 A599 99AD" /* .ԃ.ԥ */
+ $"A1D8 01DE 5D81 0001 44DB A1D7 06D9 C49A" /* .]..Dۡ.Ě */
+ $"9B99 BBD9 92D7 07D8 B097 9A9A 97B8 D982" /* ْ.ذق */
+ $"D707 D8D7 AD99 9AA1 D0D8 A0D7 01DD 5D81" /* .ؠ.] */
+ $"0001 44DB A2D7 06D9 B799 9B9A BED9 91D7" /* ..Dۢ.ٷّ */
+ $"06D8 D4B5 A3A4 B9D6 82D7 07D8 D7B1 989A" /* .Եւ.ױ */
+ $"9BC5 D9A1 D701 DD5D 8100 0144 DAA4 D605" /* ١.]..Dڤ. */
+ $"AF98 9A9B BCD8 92D6 03D8 D4D4 D882 D607" /* ؒ.. */
+ $"D7D5 B099 9B99 BCD8 A2D6 01DC 5D81 0001" /* հآ.].. */
+ $"44D9 A3D5 08D6 D3AC 999A 9AB5 D4D6 98D5" /* D٣.Ӭ֘ */
+ $"07D7 CFAA 999B 99B8 D7A3 D501 DC5D 8100" /* .Ϫף.]. */
+ $"0144 D8A4 D409 D5D2 AD99 9B99 AACB D6D5" /* .Dؤҭ */
+ $"94D4 08D5 D6C4 A299 9A9A B9D5 A4D4 01DB" /* .Ģդ. */
+ $"5D81 0001 44D8 A5D3 0AD4 D2B2 999A 999E" /* ]..DإҲ */
+ $"BAD1 D5D4 90D3 09D4 D5CD B19B 9A9A 9CBD" /* Ԑͱ */
+ $"D5A5 D301 DA5D 8100 0144 D7A6 D20B D3D4" /* ե.]..Dצ. */
+ $"BC9E 999A 99A4 BED0 D5D3 8BD2 0BD3 D4D4" /* Ӌ. */
+ $"CCB6 9F99 9A99 A3C5 D4A6 D201 D95D 8100" /* ̶Ԧ.]. */
+ $"0144 D6A8 D10A D3C8 A999 9A9A 99A3 B6C7" /* .D֨ȩ */
+ $"D180 D384 D280 D30A CFC3 B09F 999A 999B" /* рӄҀð */
+ $"B1CE D3A7 D101 D95D 8100 0144 D6A9 D020" /* ӧ.]..D֩ */
+ $"D2D0 BCA3 999A 9A99 9CA5 B1BD C5CA CDCE" /* м */
+ $"CFCE CDC9 C3BA AEA2 9A99 9A99 9AA9 C3D2" /* ú */
+ $"D1A8 D001 D85C 8100 0144 D6AB D01C D2CE" /* Ѩ.\..D֫. */
+ $"BBA5 9A99 9A9A 9999 9B9E A1A2 A3A2 A09D" /* */
+ $"9A99 999A 9A99 9CAA C1D0 D2AA D001 D85C" /* Ҫ.\ */
+ $"8100 0144 D5AC CF06 D0D2 CFC2 B0A2 9B80" /* ..Dլ.° */
+ $"9984 9A80 9906 9CA5 B5C6 D0D1 D0AB CF01" /* .Ы. */
+ $"D75C 8100 0144 D5AF CF14 D0D1 CDC4 B9AF" /* \..Dկ.Ĺ */
+ $"A8A3 A09F 9E9F A1A4 A9B1 BCC7 CED1 D0AE" /* Ю */
+ $"CF01 D65C 8100 0144 D4B2 CE05 CFD0 D0CE" /* .\..DԲ. */
+ $"CCCA 80C9 05CB CDCF D0D0 CFB1 CE01 D65C" /* ʀ.ϱ.\ */
+ $"8100 0144 D3F5 CD01 D65C 8100 0144 D3F5" /* ..D.\..D */
+ $"CC01 D55C 8100 0144 D2F5 CB01 D45C 8100" /* .\..D.\. */
+ $"0144 D1F5 CA01 D35C 8100 0144 D1F5 C901" /* .D.\..D. */
+ $"D35C 8100 0144 D1F5 C901 D35C 8100 0144" /* \..D.\..D */
+ $"D0F5 C801 D25C 8100 0144 CFF5 C701 D15C" /* .\..D.\ */
+ $"8100 0144 CFF5 C701 D05C 8100 0244 C6B8" /* ..D.\..DƸ */
+ $"F3B9 02B8 C75B 8100 0244 C5B8 F3B9 02B8" /* .[..DŸ. */
+ $"C65B 8100 0144 C9F5 BF01 CB5C 8100 0144" /* [..D.\..D */
+ $"CDF5 C401 CF5C 8100 0144 D1F5 C901 D35C" /* .\..D.\ */
+ $"8100 0144 D4F5 CE01 D65C 8100 0144 D8F5" /* ..D.\..D */
+ $"D301 DA5D 8100 0146 DEF5 D901 E05E 8100" /* .]..F.^. */
+ $"022A B5B7 F4B6 01BE 5382 0000 07F5 0801" /* .*.S..... */
+ $"0904 FF00 FF00 FF00 FF00 FF00 FF00 FF00" /* ........ */
+ $"FF00 FF00 FF00 FF00 FF00 E700 FF00 FF00" /* ........ */
+ $"FF00 FF00 FF00 FF00 FF00 FF00 FF00 FF00" /* ........ */
+ $"FF00 FF00 EE00 0004 A008 0007 D500 0409" /* .......... */
+ $"549A BAC1 9EC0 03C1 C0A3 48D2 0004 2FB2" /* T.H../ */
+ $"E3E3 DFA1 DE03 E2E1 7601 CF00 0230 C9DC" /* ߡ.v...0 */
+ $"A5D5 02D6 DD60 CE00 020E B0D6 A7CF 02D1" /* .`...֧. */
+ $"CB2B CD00 025B D3C9 A7CA 03C9 D09A 05CB" /* +..[ɧ.К. */
+ $"0002 0299 CAAA C401 CB4F CB00 020E AEC1" /* ...ʪ.O... */
+ $"AABE 02C1 AE16 CA00 0213 ADBB ABB9 02C0" /* ...... */
+ $"7F02 C900 0213 A8B5 ACB3 02B9 6503 C800" /* ......e.. */
+ $"0212 A3B0 ADAE 03B3 803B 26BA 2502 2415" /* ...;&%.$. */
+ $"0186 0002 129E AAAE A802 ADAD A9BB A803" /* ...... */
+ $"A083 4003 8400 0211 98A4 AFA2 BDA3 04A4" /* @..... */
+ $"A7A9 730E 8300 0211 939E 819D ED9C 039D" /* s..... */
+ $"A575 0782 0007 108E 9897 9694 969B EA9E" /* u.... */
+ $"059D 9995 959F 4A82 0008 0F89 928F 9AB4" /* .J... */
+ $"CDDD E4E9 E506 E2D5 B99E 9283 0B81 0005" /* .չ... */
+ $"0F82 8EB1 E1F9 EEFF 04F6 D2A7 8E28 8100" /* ..ҧ(. */
+ $"030D 7FBD F6F1 FF03 FDDB A237 8100 020A" /* ....ۢ7.. */
+ $"A0F6 F3FF 02FE CD3B 8100 0116 D1F5 FF01" /* .;.... */
+ $"ED46 8100 0136 F1F5 FF01 F852 8100 0143" /* F..6.R..C */
+ $"F7F5 FF01 FB5A 8100 0243 F6FF F3FE 02FF" /* .Z..C. */
+ $"FB5F 8100 0243 F5FF F3FD 02FE FA5F 8100" /* _..C._. */
+ $"0243 F5FE B6FC 81FD B6FC 02FD F95F 8100" /* .C._. */
+ $"0243 F5FE B1FC 05FD FEFF FEFC FA80 F805" /* .C.. */
+ $"FAFC FEFF FEFD B0FC 02FD F95F 8100 0243" /* ._..C */
+ $"F4FD ADFB 15FC FDFE FAF1 E5D9 D0CA C6C4" /* . */
+ $"C4C5 C7CB D2DC E8F4 FCFE FCAD FB02 FCF8" /* . */
+ $"5F81 0002 43F3 FCAB FA08 FBFD FAED DAC9" /* _..C. */
+ $"BFBC BB86 BC07 BBBC C1CD DFF2 FCFC ABFA" /* . */
+ $"02FB F85F 8100 0243 F3FB A9F9 1DFA FCF8" /* ._..C. */
+ $"E5CC BEBB BCBD BCBC BDC0 C2C4 C5C4 C2BF" /* ̾¿ */
+ $"BDBC BCBD BCBB C1D2 EBFA FBA9 F902 FAF7" /* . */
+ $"5F81 0002 43F3 FBA7 F90F F8FA F9E5 C9BC" /* _..C.ɼ */
+ $"BCBD BCBE C7D3 E0EA F0F3 80F5 0FF3 EEE7" /* . */
+ $"DDD0 C4BD BCBD BCBE D0ED FBF9 F8A6 F902" /* Ľ. */
+ $"FAF7 5F81 0002 43F2 FAA7 F80E FAF0 D0BC" /* _..C.м */
+ $"BCBD BCC4 D7EA F6FA FAF9 F982 F80E F9FA" /* . */
+ $"FAF9 F4E6 D2C1 BCBD BCBF D9F5 F9A6 F802" /* . */
+ $"F9F6 5F81 0002 43F1 F8A6 F70A F8E3 C2BC" /* _..C¼ */
+ $"BDBC C5DE F3F9 F88C F70A F9F9 EFD7 C1BC" /* */
+ $"BDBB C9EC F9A5 F702 F8F5 5F81 0002 43F0" /* ._..C */
+ $"F7A6 F607 D8BD BDBC C0DA F3F8 91F6 09F7" /* .ؽ */
+ $"F8EE D1BD BDBC C1E3 F8A4 F602 F7F5 5F81" /* ѽ._ */
+ $"0002 43F0 F6A3 F509 F6F4 D2BC BEBC CAEB" /* ..CҼ */
+ $"F7F6 94F5 08F6 F7E3 C3BC BDBE DDF7 A3F5" /* .ü */
+ $"02F6 F45F 8100 0243 F0F6 A3F5 07F4 D0BC" /* ._..C.м */
+ $"BEBC D4F3 F698 F507 F7EE CABC BDBD DCF7" /* .ʼ */
+ $"A2F5 02F6 F45F 8100 0243 EFF5 A2F4 07F5" /* ._..C. */
+ $"D2BC BEBD DAF5 F582 F403 F6F4 F4F6 91F4" /* Ҽ. */
+ $"07F5 F2CF BCBE BDDF F6A1 F402 F5F3 5E81" /* .ϼ.^ */
+ $"0002 43EE F4A1 F306 F5D9 BCBE BDDB F583" /* ..C.ټ */
+ $"F304 F2DA C9C9 DC92 F307 F4F2 CFBC BDBF" /* .ܒ.ϼ */
+ $"E5F5 A0F3 02F4 F25E 8100 0243 EEF3 A0F2" /* .^..C */
+ $"06F4 E4BE BEBC D8F4 83F2 07F3 D5BB BDBC" /* .侾.ջ */
+ $"BBD8 F491 F207 F3F1 CCBC BDC4 EDF3 9FF2" /* .̼ */
+ $"02F3 F25E 8100 0243 EDF2 9FF1 07F2 EDC5" /* .^..C. */
+ $"BDBC D0F2 F282 F109 F2EC C1BD BEBE BDC2" /* */
+ $"EEF2 91F1 06F2 EDC5 BDBC CFF2 9FF1 02F2" /* .Ž. */
+ $"F15E 8100 0243 ECF1 9FF0 06F2 D3BC BDC6" /* ^..C.Ӽ */
+ $"EDF1 83F0 02F1 E8BF 81BE 02C0 EAF1 85F0" /* .迁. */
+ $"03F2 F1F1 F286 F006 F2E4 BFBE BDDF F29E" /* ..俾 */
+ $"F002 F1F0 5E81 0002 43EB F09E EF06 F1E5" /* .^..C. */
+ $"BFBE BEE2 F184 EF07 F0EE C7BC BEBE BCC9" /* .Ǽ */
+ $"85EF 06F0 EFDA CACB DEF0 86EF 06F2 D6BC" /* ..ּ */
+ $"BDC6 EDF0 9DEF 02F0 EF5E 8100 0243 EBEF" /* .^..C */
+ $"9EEE 05F0 CDBC BCD0 F086 EE07 F0E4 C4BE" /* .ͼ.ľ */
+ $"BDC5 E5EF 84EE 02F0 D3BB 80BC 01DA F085" /* .ӻ. */
+ $"EE06 EFEC C5BD BCDA F09D EE02 EFEF 5E81" /* .Ž.^ */
+ $"0002 43EB EF9D EE06 EFE4 BEBD C0E7 EF87" /* ..C.侽 */
+ $"EE05 F0E2 BDC2 E9EF 84EE 02EF E8C0 80BE" /* .. */
+ $"02BD C4EC 86EE 05F0 DDBC BDC5 EC9D EE02" /* ..ݼ. */
+ $"EFEF 5E81 0002 43EB EF9D EE05 EFD1 BCBC" /* ^..C.Ѽ */
+ $"D1F0 88EE 04EF E4BD C3EB 85EE 01EF E482" /* .. */
+ $"BE01 C1E9 87EE 05ED C6BD BCDD EF9C EE02" /* ..ƽ. */
+ $"EFEF 5E81 0002 43EA EE9D ED05 E9C2 BDBF" /* ^..C.½ */
+ $"E4EE 88ED 04EE E3BD C3EA 86ED 06EA C4BD" /* ..Ľ */
+ $"BEBE BCC9 88ED 05EF D9BC BCCC EE9C ED02" /* Ɉ.ټ. */
+ $"EEEE 5E81 0002 43E9 ED9C EC04 EEDC BDBD" /* ^..C.ܽ */
+ $"C98A EC04 EDE2 BDC2 E986 EC07 EDDE C1BE" /* Ɋ.. */
+ $"BEC4 E3ED 88EC 04E7 C1BD C1E6 9CEC 02ED" /* .. */
+ $"ED5E 8100 0243 E9EC 9CEB 05ED CFBC BCD8" /* ^..C.ϼ */
+ $"ED89 EB04 ECE2 BDC2 E887 EB05 EDDD BDC2" /* ..ݽ */
+ $"E6EC 89EB 05EC CCBC BCDB ED9B EB02 ECEC" /* .̼. */
+ $"5E81 0002 43E8 EB9C EA05 E9C5 BDBF E2EB" /* ^..C.Ž */
+ $"89EA 04EB E1BD C2E7 87EA 04EB DFBD C3E8" /* ..߽ */
+ $"8AEA 05EC D8BC BCCF EC9B EA02 EBEC 5E81" /* .ؼ.^ */
+ $"0002 43E7 EA9B E905 EAE3 BFBD C5E8 8AE9" /* ..C.㿽 */
+ $"04EA E0BD C2E7 87E9 04EA DEBD C3E7 8AE9" /* .. */
+ $"04EA E1BF BDC6 9CE9 02EA EB5E 8100 0243" /* .´Ɯ.^..C */
+ $"E7E9 9BE8 05E9 DCBD BCCC E98A E807 E9DF" /* .ܽ. */
+ $"BEBF D7E6 EAE9 84E8 04E9 DEBD C3E6 8BE8" /* . */
+ $"05E6 C3BD C1E4 E99A E802 E9EA 5E81 0002" /* .ý.^.. */
+ $"43E6 E89B E705 E9D5 BCBC D2E9 8AE7 09E8" /* C.ռ */
+ $"DEBE BEBD C4D5 E4E9 E882 E704 E8DD BDC3" /* .ݽ */
+ $"E58C E704 C8BD BEDF E89A E702 E8E9 5E81" /* .Ƚ.^ */
+ $"0002 43E6 E89B E705 E9D1 BCBC D7E9 8AE7" /* ..C.Ѽ */
+ $"0BE8 DEBE BFBE BCBC C2D2 E2E9 E880 E704" /* .. */
+ $"E8DD BDC3 E58B E705 E8CC BCBD DCE8 9AE7" /* ݽ.̼ */
+ $"02E8 E95E 8100 0243 E5E7 9BE6 05E8 CEBC" /* .^..C.μ */
+ $"BDD9 E88A E613 E7DE BDC2 DBCD C0BC BCC0" /* . */
+ $"CFDF E7E7 E6E7 DCBD C3E4 8BE6 05E8 CFBC" /* ܽ.ϼ */
+ $"BDD9 E89A E602 E7E9 5E81 0002 43E4 E69B" /* .^..C */
+ $"E505 E6CC BCBD DAE6 8AE5 13E6 DDBD C2E3" /* .̼.ݽ */
+ $"E7DF CFC1 BCBC BFCC DCE6 E8DC BDC3 E38B" /* ܽ */
+ $"E505 E7D0 BCBD D6E7 9AE5 02E6 E85E 8100" /* .м.^. */
+ $"0243 E4E5 9BE4 05E5 CCBC BDD9 E58A E413" /* .C.̼. */
+ $"E5DC BDC2 E1E4 E5E6 E1D2 C3BC BCBE C9DB" /* ܽü */
+ $"DABD C3E2 8BE4 05E7 D0BC BDD6 E69A E402" /* ڽ.м. */
+ $"E5E7 5E81 0002 43E4 E49B E305 E5CD BCBD" /* ^..C.ͼ */
+ $"D7E4 8AE3 04E4 DBBD C2E1 80E3 0BE4 E5E1" /* .۽. */
+ $"D4C4 BDBC BEC3 BDC3 E18B E305 E5CE BCBD" /* Ľý.μ */
+ $"D7E4 9AE3 02E4 E65E 8100 0243 E3E4 9BE3" /* .^..C */
+ $"05E5 CFBC BDD4 E48A E304 E4DB BDC2 E183" /* .ϼ.۽ */
+ $"E308 E4E2 D6C6 BDBC BDC3 E18B E305 E4CB" /* .ƽ. */
+ $"BDBD D8E4 9AE3 02E4 E65E 8100 0243 E2E3" /* .^..C */
+ $"9BE2 05E3 D2BC BCCF E48A E204 E3DA BDC1" /* .Ҽ.ڽ */
+ $"E085 E206 E3E2 D8C7 BDC2 E08C E204 C6BD" /* .ǽ.ƽ */
+ $"BEDB E39A E202 E3E6 5D81 0002 43E2 E29B" /* .]..C */
+ $"E105 E2D6 BDBD CAE2 8AE1 04E2 DABE C1DF" /* .ֽ.ھ */
+ $"87E1 04E3 D9BD C2DF 8BE1 04DF C2BD C0DD" /* .ٽߋ.½ */
+ $"9BE1 02E2 E55D 8100 0243 E1E1 9BE0 05E1" /* .]..C. */
+ $"DBBF BDC4 DF8A E004 E1D9 BEC1 DE87 E004" /* ۿߊ.پއ. */
+ $"E1D8 BDC2 DE8A E004 E1DA BEBD C49C E002" /* ؽފ.ھĜ. */
+ $"E1E4 5D81 0002 43E1 E19C E005 DFC3 BDBF" /* ]..C.ý */
+ $"DAE1 89E0 04E1 D9BE C1DE 87E0 04E1 D8BD" /* .پއ.ؽ */
+ $"C2DE 8AE0 05E1 D3BD BDCB E19B E002 E1E4" /* ފ.ӽ. */
+ $"5D81 0002 43E0 E09C DF05 E0CA BDBD D1E0" /* ]..C.ʽ */
+ $"89DF 05E1 D7BE C0DC E086 DF04 E0D7 BDC2" /* .. */
+ $"DE8A DF05 E0C9 BDBD D3E0 9BDF 02E0 E35D" /* ފ.ɽ.] */
+ $"8100 0243 DFDF 9CDE 05DF D3BD BDC6 DF88" /* ..Cߜ.ӽ߈ */
+ $"DE07 DFD7 C2BE BEC3 D8DF 85DE 04DF D6BD" /* .¾߅.ֽ */
+ $"C2DD 8ADE 05DB C0BD BFDA DF9B DE02 DFE3" /* ݊.ߛ. */
+ $"5D81 0002 43DF DE9D DD05 DAC0 BDBF D8DE" /* ]..Cޝ. */
+ $"88DD 05C4 BDBE BEBD C586 DD04 DED5 BDC2" /* .Ľņ.ս */
+ $"DC89 DD05 DED1 BDBD C6DE 9DDD 01E2 5D81" /* ܉.ѽޝ.] */
+ $"0002 43DE DD9D DC05 DDC9 BDBD CBDD 86DC" /* ..Cݝ.ɽ݆ */
+ $"02DD D7BF 81BE 01BF D985 DC04 DDD5 BDC2" /* ..م.ս */
+ $"DB8A DC04 C4BD BDD1 DD9D DC01 E15D 8100" /* ۊ.Ľݝ.]. */
+ $"0243 DDDC 9DDB 06DC D5BE BEC0 D8DC 85DB" /* .Cܝ.վ܅ */
+ $"02DC D8C0 81BE 01C0 D985 DB05 DDD4 BDC1" /* ..م.Խ */
+ $"DADC 87DB 05DC D1BD BEC2 DA9E DB01 E05D" /* ܇.ѽڞ.] */
+ $"8100 0243 DDDB 9EDA 05DB C6BD BDC9 DB86" /* ..C۞.ƽۆ */
+ $"DA07 DBCA BCBD BDBC CCDB 84DA 07DB D5C2" /* .ʼۄ. */
+ $"BEBE C4D7 DB85 DA06 DBDA C3BD BDCD DC9E" /* ۅ.ýܞ */
+ $"DA01 E05D 8100 0243 DDDA 9ED9 01DA D380" /* .]..Cڞ.Ӏ */
+ $"BE01 D3DA 85D9 07DA D9CC C3C3 CDD9 DA85" /* .څ.څ */
+ $"D906 C3BD BEBE BCC6 DA85 D906 DBCC BDBD" /* .ýڅ.̽ */
+ $"C2D8 DA9E D901 E05D 8100 0244 DCDA 9FD9" /* ڞ.]..Dڟ */
+ $"05DA C8BD BDC3 D887 D903 DAD9 D9DA 85D9" /* .Ƚ؇.څ */
+ $"01DA D482 BE01 C0D7 84D9 06DA D3BF BEBD" /* .Ԃ.ׄ.ӿ */
+ $"CFDA 9FD9 01DF 5D81 0001 44DC A1D9 04D6" /* ڟ.]..Dܡ. */
+ $"C1BE BDC8 94D9 01D5 BF81 BE01 C1D7 84D9" /* Ȕ.տ.ׄ */
+ $"04D7 C3BD BDC6 A1D9 01DF 5D81 0001 44DB" /* .ýơ.]..D */
+ $"A1D8 06D9 D0BE BEBD CCD9 93D8 06C7 BCBE" /* .оٓ.Ǽ */
+ $"BDBC CAD9 83D8 05D7 C6BD BEC0 D5A1 D801" /* ك.ƽա. */
+ $"DE5D 8100 0144 DBA2 D706 D8CA BDBE BECD" /* ]..Dۢ.ʽ */
+ $"D892 D704 D6C9 C1C2 CB85 D705 C7BD BEBE" /* ؒ.˅.ǽ */
+ $"D0D8 A1D7 01DD 5D81 0001 44DA A4D6 05C6" /* ء.]..Dڤ. */
+ $"BDBE BECC D792 D603 D7D5 D5D7 84D6 05C7" /* ג.ׄ. */
+ $"BDBE BDCC D7A2 D601 DC5D 8100 0144 D9A4" /* ע.]..D٤ */
+ $"D505 D4C5 BDBE BDC8 9AD5 07D6 D3C4 BDBE" /* .ŽȚ.Ľ */
+ $"BDCA D6A3 D501 DC5D 8100 0144 D8A5 D407" /* ֣.]..Dإ. */
+ $"D3C5 BDBE BDC4 D1D5 96D4 07D5 CEC1 BDBE" /* ŽՖ. */
+ $"BDC9 D5A4 D401 DB5D 8100 0144 D8A7 D307" /* դ.]..Dا. */
+ $"C7BD BEBD BFCA D2D4 92D3 08D4 D1C6 BEBE" /* ǽԒ.ƾ */
+ $"BDBE CBD4 A5D3 01DA 5D81 0001 44D7 A7D2" /* ԥ.]..Dק */
+ $"0AD3 CABF BDBE BDC1 CBD1 D3D3 8CD2 0AD3" /* ʿӌ */
+ $"D3D0 C8C0 BDBE BDC1 CDD3 A6D2 01D9 5D81" /* Ӧ.] */
+ $"0001 44D7 A8D2 0CD3 CEC3 BDBE BEBD C1C8" /* ..Dר.ý */
+ $"CED2 D3D3 85D2 80D3 0AD1 CDC6 BFBD BEBD" /* ӅҀƿ */
+ $"BEC6 D1D3 A7D2 01D9 5D81 0001 44D6 A9D1" /* ӧ.]..D֩ */
+ $"0ED2 D1CA C1BD BEBE BDBE C2C6 CACD CFD0" /* . */
+ $"80D1 0ED0 CFCD C9C5 C1BE BDBE BDBE C3CD" /* . */
+ $"D2D2 A8D1 01D9 5D81 0001 44D6 AAD0 07D1" /* Ҩ.]..D֪. */
+ $"D1D0 C9C2 BEBD BE80 BD02 BEBF C080 C10C" /* ¾.. */
+ $"C0BF BEBD BDBE BEBD BEC3 CBD1 D1AA D001" /* Ѫ. */
+ $"D85C 8100 0144 D5AC CF06 D0D0 CFCB C5C0" /* \..Dլ. */
+ $"BE80 BD80 BE00 BD80 BE80 BD05 BFC1 C7CC" /* .. */
+ $"D0D0 ACCF 01D7 5C81 0001 44D5 B1CF 06CE" /* Ь.\..Dձ. */
+ $"CBC7 C4C2 C1C0 80BF 06C0 C1C3 C5C8 CCCE" /* . */
+ $"B0CF 01D6 5C81 0001 44D4 B6CE 01CD CD80" /* .\..DԶ.̀ */
+ $"CC01 CDCD B5CE 01D6 5C81 0001 44D3 F5CD" /* .͵.\..D */
+ $"01D6 5C81 0001 44D3 F5CC 01D5 5C81 0001" /* .\..D.\.. */
+ $"44D2 F5CB 01D4 5C81 0001 44D2 F5CB 01D4" /* D.\..D. */
+ $"5C81 0001 44D1 F5CA 01D3 5C81 0001 44D1" /* \..D.\..D */
+ $"F5C9 01D3 5C81 0001 44D0 F5C8 01D2 5C81" /* .\..D.\ */
+ $"0001 44CF F5C7 01D1 5C81 0001 44CF F5C7" /* ..D.\..D */
+ $"01D0 5C81 0002 44C6 B9F3 BA02 B9C7 5B81" /* .\..Dƹ.[ */
+ $"0001 44C5 F5B9 01C7 5B81 0001 44C9 F5BF" /* ..D.[..D */
+ $"01CB 5C81 0001 44CD F5C4 01CF 5C81 0001" /* .\..D.\.. */
+ $"44D1 F5C9 01D3 5C81 0001 44D4 F5CE 01D7" /* D.\..D. */
+ $"5C81 0001 44D8 F5D4 01DB 5D81 0002 46DE" /* \..D.]..F */
+ $"DAF4 D901 E05E 8100 012B B5F5 B701 BF53" /* .^..+.S */
+ $"8200 0007 F508 0109 04FF 00FF 00FF 00FF" /* ......... */
+ $"00FF 00FF 00FF 00FF 00FF 00FF 00FF 00FF" /* ........ */
+ $"00E7 0074 386D 6B00 0040 0800 0000 0000" /* ..t8mk..@...... */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0508 0808 0808 0808 0808 0808" /* ................ */
+ $"0808 0808 0808 0808 0808 0808 0808 0808" /* ................ */
+ $"0808 0808 0808 0808 0700 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"000B 5FAD D3DB DBDB DBDB DBDB DBDB DBDB" /* .._ */
+ $"DBDB DBDB DBDB DBDB DBDB DBDB DBDB DBDB" /* */
+ $"DBDB DBDB DBDB DBDB D9B7 5300 0000 0000" /* ٷS..... */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"37CC FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* 7 */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FF8A 0100 0000" /* .... */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 003A" /* ...............: */
+ $"EDFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF 7400 0000" /* t... */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 11D8" /* ............... */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF F636 0000" /* 6.. */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 73FF" /* ..............s */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFC3 0600" /* .. */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0003 C7FF" /* .............. */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF 6800" /* h. */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0013 E9FF" /* .............. */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF E71D" /* . */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 001B EFFF" /* .............. */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFAF" /* */
+ $"0300 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 001B EFFF" /* .............. */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"8F04 0000 0000 0000 0000 0000 0000 0000" /* ............... */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 001B EFFF" /* .............. */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFBB 5738 3737 3737 3737 3737 3737 3737" /* W8777777777777 */
+ $"3737 3737 3737 3737 3737 3737 3737 3737" /* 7777777777777777 */
+ $"3737 3737 3737 3737 3737 3737 3737 3737" /* 7777777777777777 */
+ $"3737 3737 3737 3737 3737 3737 3737 3737" /* 7777777777777777 */
+ $"3734 1F01 0000 0000 0000 0000 001B EFFF" /* 74............ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFE F2C4 6104 0000 0000 0000 001B EFFF" /* a......... */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFB3 1500 0000 0000 001B EFFF" /* ........ */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF BE0B 0000 0000 001B EFFF" /* ....... */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FF7D 0000 0000 001B EFFF" /* }...... */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFE5 1300 0000 001B EFFF" /* ...... */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 4900 0000 001B EFFF" /* I..... */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 6D00 0000 001A EFFF" /* m..... */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7400 0000 0021 F4FF" /* t....! */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0046 FFFF" /* s....F */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0056 FFFF" /* s....V */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0055 FFFF" /* s....U */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7300 0000 0058 FFFF" /* s....X */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFF" /* */
+ $"FFFF FFFF FFFF FFFF 7500 0000 0034 D6DB" /* u....4 */
+ $"DBDB DBDB DBDB DBDB DBDB DBDB DBDB DBDB" /* */
+ $"DBDB DBDB DBDB DBDB DBDB DBDB DBDB DBDB" /* */
+ $"DBDB DBDB DBDB DBDB DBDB DBDB DBDB DBDB" /* */
+ $"DBDB DBDB DBDB DBDB DBDB DBDB DBDB DBDB" /* */
+ $"DBDB DBDB DBDB DBDB DBDB DBDB DBDB DBDB" /* */
+ $"DBDB DBDB DBDB DBDB DBDB DBDB DBDB DBDB" /* */
+ $"DBDB DBDB DBDB DBDB DBDB DBDB DBDB DBDB" /* */
+ $"DBDB DBDB DBDB DBDB 6300 0000 0000 0708" /* c....... */
+ $"0808 0808 0808 0808 0808 0808 0808 0808" /* ................ */
+ $"0808 0808 0808 0808 0808 0808 0808 0808" /* ................ */
+ $"0808 0808 0808 0808 0808 0808 0808 0808" /* ................ */
+ $"0808 0808 0808 0808 0808 0808 0808 0808" /* ................ */
+ $"0808 0808 0808 0808 0808 0808 0808 0808" /* ................ */
+ $"0808 0808 0808 0808 0808 0808 0808 0808" /* ................ */
+ $"0808 0808 0808 0808 0808 0808 0808 0808" /* ................ */
+ $"0808 0808 0808 0809 0400 0000 0000 0000" /* ............... */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 0000 0000 0000" /* ................ */
+ $"0000 0000 0000 0000 0000 00" /* ........... */
+};
+
diff --git a/launchers/darwin/cmake/installer/installer-header.bmp b/launchers/darwin/cmake/installer/installer-header.bmp
new file mode 100644
index 0000000000..7588a338b1
Binary files /dev/null and b/launchers/darwin/cmake/installer/installer-header.bmp differ
diff --git a/launchers/darwin/cmake/installer/installer.ico b/launchers/darwin/cmake/installer/installer.ico
new file mode 100644
index 0000000000..d42eae96ad
Binary files /dev/null and b/launchers/darwin/cmake/installer/installer.ico differ
diff --git a/launchers/darwin/cmake/installer/uninstaller-header.bmp b/launchers/darwin/cmake/installer/uninstaller-header.bmp
new file mode 100644
index 0000000000..d43166ded3
Binary files /dev/null and b/launchers/darwin/cmake/installer/uninstaller-header.bmp differ
diff --git a/launchers/darwin/cmake/modules/MacOSXBundleInfo.plist.in b/launchers/darwin/cmake/modules/MacOSXBundleInfo.plist.in
new file mode 100644
index 0000000000..62d6856ba9
--- /dev/null
+++ b/launchers/darwin/cmake/modules/MacOSXBundleInfo.plist.in
@@ -0,0 +1,35 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+ CFBundleExecutable
+ ${EXECUTABLE_NAME}
+ CFBundleIconFile
+ ${MACOSX_BUNDLE_ICON_FILE}
+ CFBundleIdentifier
+ com.highfidelity.launcher
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ ${PRODUCT_NAME}
+ CFBundlePackageType
+ APPL
+ CFBundleSignature
+ ????
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
+ CFBundleVersion
+ 1.0
+ NSMainNibFile
+ Window
+ NSPrincipalClass
+ NSApplication
+ CFBundleDisplayName
+ HQ Launcher
+
+
diff --git a/launchers/darwin/images/HiFi_Logo_Large.png b/launchers/darwin/images/HiFi_Logo_Large.png
new file mode 100644
index 0000000000..0a3e3024e3
Binary files /dev/null and b/launchers/darwin/images/HiFi_Logo_Large.png differ
diff --git a/launchers/darwin/images/HiFi_Logo_Small.png b/launchers/darwin/images/HiFi_Logo_Small.png
new file mode 100644
index 0000000000..9182e6b693
Binary files /dev/null and b/launchers/darwin/images/HiFi_Logo_Small.png differ
diff --git a/launchers/darwin/images/HiFi_Voxel.png b/launchers/darwin/images/HiFi_Voxel.png
new file mode 100644
index 0000000000..cd46b96c28
Binary files /dev/null and b/launchers/darwin/images/HiFi_Voxel.png differ
diff --git a/launchers/darwin/images/HiFi_Window.png b/launchers/darwin/images/HiFi_Window.png
new file mode 100644
index 0000000000..f9bf24c0fc
Binary files /dev/null and b/launchers/darwin/images/HiFi_Window.png differ
diff --git a/launchers/darwin/images/Hifi_Logo.svg b/launchers/darwin/images/Hifi_Logo.svg
new file mode 100644
index 0000000000..2dc9b52f8d
--- /dev/null
+++ b/launchers/darwin/images/Hifi_Logo.svg
@@ -0,0 +1,14 @@
+
diff --git a/launchers/darwin/images/hifi_logo_large@2x.png b/launchers/darwin/images/hifi_logo_large@2x.png
new file mode 100644
index 0000000000..d480da86dd
Binary files /dev/null and b/launchers/darwin/images/hifi_logo_large@2x.png differ
diff --git a/launchers/darwin/images/hifi_logo_small@2x.png b/launchers/darwin/images/hifi_logo_small@2x.png
new file mode 100644
index 0000000000..b8782dd226
Binary files /dev/null and b/launchers/darwin/images/hifi_logo_small@2x.png differ
diff --git a/launchers/darwin/images/hifi_window@2x.png b/launchers/darwin/images/hifi_window@2x.png
new file mode 100644
index 0000000000..c7638fb61c
Binary files /dev/null and b/launchers/darwin/images/hifi_window@2x.png differ
diff --git a/launchers/darwin/images/interface.icns b/launchers/darwin/images/interface.icns
new file mode 100644
index 0000000000..4aeb8301ce
Binary files /dev/null and b/launchers/darwin/images/interface.icns differ
diff --git a/launchers/darwin/nib/DisplayNameScreen.xib b/launchers/darwin/nib/DisplayNameScreen.xib
new file mode 100644
index 0000000000..e56f2bf66b
--- /dev/null
+++ b/launchers/darwin/nib/DisplayNameScreen.xib
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launchers/darwin/nib/ErrorScreen.xib b/launchers/darwin/nib/ErrorScreen.xib
new file mode 100644
index 0000000000..37feca60cb
--- /dev/null
+++ b/launchers/darwin/nib/ErrorScreen.xib
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launchers/darwin/nib/LoginScreen.xib b/launchers/darwin/nib/LoginScreen.xib
new file mode 100644
index 0000000000..6784b8eff1
--- /dev/null
+++ b/launchers/darwin/nib/LoginScreen.xib
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NSAllRomanInputSourcesLocaleIdentifier
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launchers/darwin/nib/ProcessScreen.xib b/launchers/darwin/nib/ProcessScreen.xib
new file mode 100644
index 0000000000..c6bd8abbec
--- /dev/null
+++ b/launchers/darwin/nib/ProcessScreen.xib
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launchers/darwin/nib/SplashScreen.xib b/launchers/darwin/nib/SplashScreen.xib
new file mode 100644
index 0000000000..3e2e37c81a
--- /dev/null
+++ b/launchers/darwin/nib/SplashScreen.xib
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launchers/darwin/nib/Window.xib b/launchers/darwin/nib/Window.xib
new file mode 100644
index 0000000000..8260f1d3cd
--- /dev/null
+++ b/launchers/darwin/nib/Window.xib
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launchers/darwin/src/CredentialsRequest.h b/launchers/darwin/src/CredentialsRequest.h
new file mode 100644
index 0000000000..2e0807c5ba
--- /dev/null
+++ b/launchers/darwin/src/CredentialsRequest.h
@@ -0,0 +1,10 @@
+#import
+
+@interface CredentialsRequest : NSObject {
+}
+
+@property (nonatomic, retain) NSMutableData* webData;
+@property (nonatomic, retain) NSString* jsonString;
+
+- (void) confirmCredentials:(NSString*)username :(NSString*)password;
+@end
diff --git a/launchers/darwin/src/CredentialsRequest.m b/launchers/darwin/src/CredentialsRequest.m
new file mode 100644
index 0000000000..966bb8cb31
--- /dev/null
+++ b/launchers/darwin/src/CredentialsRequest.m
@@ -0,0 +1,95 @@
+#import "CredentialsRequest.h"
+#import "Launcher.h"
+#import "Settings.h"
+
+@implementation CredentialsRequest
+
+- (void) confirmCredentials:(NSString*)username :(NSString*)password {
+
+ NSLog(@"web request started");
+ NSString *post = [NSString stringWithFormat:@"grant_type=password&username=%@&password=%@&scope=owner", username, password];
+ NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding];
+ NSString *postLength = [NSString stringWithFormat:@"%ld", (unsigned long)[postData length]];
+
+ NSMutableURLRequest *request = [NSMutableURLRequest new];
+ [request setURL:[NSURL URLWithString:@"https://metaverse.highfidelity.com/oauth/token"]];
+ [request setHTTPMethod:@"POST"];
+ [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
+ [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
+ [request setHTTPBody:postData];
+
+ //NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
+ NSURLSession* session = [NSURLSession sharedSession];
+ NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+
+ NSLog(@"credentials request finished");
+ NSMutableData* webData = [NSMutableData data];
+ [webData appendData:data];
+ NSString* jsonString = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[data length] encoding:NSUTF8StringEncoding];
+ NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
+ id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
+
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ if (json[@"error"] != nil) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [[Settings sharedSettings] login:FALSE];
+ [sharedLauncher setLoginErrorState: CREDENTIALS];
+ [sharedLauncher credentialsAccepted:FALSE];
+ });
+ } else {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [[Settings sharedSettings] login:TRUE];
+ [sharedLauncher setTokenString:jsonString];
+ [sharedLauncher credentialsAccepted:TRUE];
+ });
+ }
+
+ NSLog(@"credentials: connectionDidFinished completed");
+
+ }];
+
+ [dataTask resume];
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
+ [self.webData appendData:data];
+ NSLog(@"credentials connection received data");
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
+ NSLog(@"credentials connection received response");
+ NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
+ if([ne statusCode] == 200) {
+ NSLog(@"connection state is 200 - all okay");
+ } else {
+ NSLog(@"connection state is NOT 200");
+ [[Launcher sharedLauncher] displayErrorPage];
+ }
+}
+
+-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
+ NSLog(@"Conn Err: %@", [error localizedDescription]);
+ [[Launcher sharedLauncher] displayErrorPage];
+}
+
+- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
+ NSLog(@"credentials request finished");
+ NSString* jsonString = [[NSString alloc] initWithBytes: [self.webData mutableBytes] length:[self.webData length] encoding:NSUTF8StringEncoding];
+ NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
+ id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ if (json[@"error"] != nil) {
+ [[Settings sharedSettings] login:FALSE];
+ [sharedLauncher setLoginErrorState: CREDENTIALS];
+ [sharedLauncher credentialsAccepted:FALSE];
+ } else {
+ [[Settings sharedSettings] login:TRUE];
+ [sharedLauncher setTokenString:jsonString];
+ [sharedLauncher credentialsAccepted:TRUE];
+ }
+
+ NSLog(@"credentials: connectionDidFinished completed");
+}
+
+@end
diff --git a/launchers/darwin/src/CustomUI.h b/launchers/darwin/src/CustomUI.h
new file mode 100644
index 0000000000..a9d93d03c7
--- /dev/null
+++ b/launchers/darwin/src/CustomUI.h
@@ -0,0 +1,30 @@
+#import
+#import
+#import
+
+extern NSString* hifiSmallLogoFilename;
+extern NSString* hifiLargeLogoFilename;
+extern NSString* hifiVoxelFilename;
+extern NSString* hifiBackgroundFilename;
+
+@interface TextField : NSTextField {
+}
+@end
+
+
+@interface SecureTextField : NSSecureTextField {
+}
+
+@end
+
+
+@interface HFButton : NSButton
+
+ @property (nonatomic, strong) CATextLayer *titleLayer;
+
+@end
+
+@interface Hyperlink : NSTextField {
+
+}
+@end
diff --git a/launchers/darwin/src/CustomUI.m b/launchers/darwin/src/CustomUI.m
new file mode 100644
index 0000000000..01e666637a
--- /dev/null
+++ b/launchers/darwin/src/CustomUI.m
@@ -0,0 +1,118 @@
+#import "CustomUI.h"
+
+#import
+
+NSString* hifiSmallLogoFilename = @"hifi_logo_small";
+NSString* hifiLargeLogoFilename = @"hifi_logo_large";
+NSString* hifiVoxelFilename = @"HiFi_Voxel";
+NSString* hifiBackgroundFilename = @"hifi_window";
+
+@implementation TextField
+- (void) textDidBeginEditing:(NSNotification *)notification
+{
+ NSColor *insertionPointColor = [NSColor whiteColor];
+ NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
+ forObject:self];
+ fieldEditor.insertionPointColor = insertionPointColor;
+}
+- (void) mouseDown:(NSEvent *)event
+{
+ NSColor *insertionPointColor = [NSColor whiteColor];
+ NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
+ forObject:self];
+ fieldEditor.insertionPointColor = insertionPointColor;
+
+}
+
+-(BOOL)becomeFirstResponder
+{
+ BOOL status = [super becomeFirstResponder];
+ NSColor *insertionPointColor = [NSColor whiteColor];
+ NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
+ forObject:self];
+ fieldEditor.insertionPointColor = insertionPointColor;
+ return status;
+}
+@end
+
+@implementation SecureTextField
+
+- (void) textDidBeginEditing:(NSNotification *)notification
+{
+ NSColor *insertionPointColor = [NSColor whiteColor];
+ NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
+ forObject:self];
+ fieldEditor.insertionPointColor = insertionPointColor;
+}
+- (void) mouseDown:(NSEvent *)event
+{
+ NSColor *insertionPointColor = [NSColor whiteColor];
+ NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
+ forObject:self];
+ fieldEditor.insertionPointColor = insertionPointColor;
+
+}
+
+
+-(BOOL)becomeFirstResponder
+{
+ BOOL status = [super becomeFirstResponder];
+ NSColor *insertionPointColor = [NSColor whiteColor];
+ NSTextView *fieldEditor = (NSTextView*)[self.window fieldEditor:YES
+ forObject:self];
+ fieldEditor.insertionPointColor = insertionPointColor;
+ return status;
+}
+@end
+
+
+@implementation HFButton
+- (void)drawRect:(NSRect)dirtyRect {
+ // The UI layers implemented in awakeFromNib will handle drawing
+}
+
+- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow *)window {
+ return YES;
+}
+
+- (void)awakeFromNib {
+ [super awakeFromNib];
+
+ self.wantsLayer = YES;
+ self.layer.backgroundColor = [NSColor blackColor].CGColor;
+ self.layer.borderColor = [NSColor whiteColor].CGColor;
+ self.layer.borderWidth = 2.0f;
+ self.layer.masksToBounds = YES;
+
+ _titleLayer = [[CATextLayer alloc] init];
+
+ CGSize buttonSize = self.frame.size;
+ CGSize titleSize = [self.title sizeWithAttributes:@{NSFontAttributeName: self.font}];
+ CGFloat x = (buttonSize.width - titleSize.width) / 2.0; // Title's origin x
+ CGFloat y = (buttonSize.height - titleSize.height) / 2.0; // Title's origin y
+
+ self.titleLayer.frame = NSMakeRect(round(x), round(y), ceil(titleSize.width), ceil(titleSize.height));
+ self.titleLayer.string = self.title;
+ self.titleLayer.foregroundColor = [NSColor whiteColor].CGColor;
+
+ // TODO(huffman) Fix this to be dynamic based on screen?
+ self.titleLayer.contentsScale = 2.0;
+
+ self.titleLayer.font = (__bridge CFTypeRef _Nullable)(self.font);
+ self.titleLayer.fontSize = self.font.pointSize;
+ //self.titleLayer.allowsEdgeAntialiasing = YES;
+ //self.titleLayer.allowsFontSubpixelQuantization = YES;
+
+ [self.layer addSublayer:self.titleLayer];
+}
+
+@end
+
+@implementation Hyperlink
+
+- (void) mouseDown:(NSEvent *)event
+{
+ [self sendAction:[self action] to:[self target]];
+}
+
+@end
diff --git a/launchers/darwin/src/DisplayNameScreen.h b/launchers/darwin/src/DisplayNameScreen.h
new file mode 100644
index 0000000000..77c0f4e7f5
--- /dev/null
+++ b/launchers/darwin/src/DisplayNameScreen.h
@@ -0,0 +1,5 @@
+#import
+
+@interface DisplayNameScreen : NSViewController {
+}
+@end
diff --git a/launchers/darwin/src/DisplayNameScreen.m b/launchers/darwin/src/DisplayNameScreen.m
new file mode 100644
index 0000000000..7a402d792b
--- /dev/null
+++ b/launchers/darwin/src/DisplayNameScreen.m
@@ -0,0 +1,34 @@
+#import "DisplayNameScreen.h"
+#import "Launcher.h"
+#import "CustomUI.h"
+
+@interface DisplayNameScreen ()
+@property (nonatomic, assign) IBOutlet NSImageView* backgroundImage;
+@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
+@property (nonatomic, assign) IBOutlet NSTextField* displayName;
+@end
+
+@implementation DisplayNameScreen
+- (void) awakeFromNib {
+ [self.backgroundImage setImage: [NSImage imageNamed:hifiBackgroundFilename]];
+ [self.smallLogo setImage: [NSImage imageNamed:hifiSmallLogoFilename]];
+ NSMutableAttributedString* displayNameString = [[NSMutableAttributedString alloc] initWithString:@"Display Name"];
+
+ [displayNameString addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0, displayNameString.length)];
+ [displayNameString addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,displayNameString.length)];
+
+ [self.displayName setPlaceholderAttributedString:displayNameString];
+ [self.displayName setTarget:self];
+ [self.displayName setAction:@selector(login:)];
+}
+
+- (IBAction)login:(id)sender {
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ [sharedLauncher displayNameEntered: [self.displayName stringValue]];
+}
+
+- (IBAction)hyperLink:(id)sender
+{
+ [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.highfidelity.com/hq-support"]];
+}
+@end
diff --git a/launchers/darwin/src/DownloadDomainContent.h b/launchers/darwin/src/DownloadDomainContent.h
new file mode 100644
index 0000000000..a714b201de
--- /dev/null
+++ b/launchers/darwin/src/DownloadDomainContent.h
@@ -0,0 +1,8 @@
+#import
+
+@interface DownloadDomainContent : NSObject {
+}
+
+- (void) downloadDomainContent:(NSString*) domainContentUrl;
+
+@end
diff --git a/launchers/darwin/src/DownloadDomainContent.m b/launchers/darwin/src/DownloadDomainContent.m
new file mode 100644
index 0000000000..8d1ad715f4
--- /dev/null
+++ b/launchers/darwin/src/DownloadDomainContent.m
@@ -0,0 +1,84 @@
+#import "DownloadDomainContent.h"
+#import "Launcher.h"
+
+@implementation DownloadDomainContent
+
+- (void) downloadDomainContent:(NSString *)domainContentUrl
+{
+ NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:domainContentUrl]
+ cachePolicy:NSURLRequestUseProtocolCachePolicy
+ timeoutInterval:60.0];
+ NSURLDownload* theDownload = [[NSURLDownload alloc] initWithRequest:request delegate:self];
+
+ /*NSURLSession *session = [NSURLSession sharedSession];
+ NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
+ completionHandler:
+ ^(NSURL *location, NSURLResponse *response,NSError *error) {
+ NSString* finalFilePath = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent:[response suggestedFilename]];
+ [[NSFileManager defaultManager] moveItemAtURL:location
+ toURL:[NSURL URLWithString: [finalFilePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]
+ error:nil];
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ [sharedLauncher setDownloadContextFilename:[response suggestedFilename]];
+ NSLog(@"extracting domain content file");
+ [sharedLauncher extractZipFileAtDestination:[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:@"content"] :[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:[sharedLauncher getDownloadContentFilename]]];
+
+ NSLog(@"finished extracting content file");
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [sharedLauncher domainContentDownloadFinished];
+ });
+
+ }];*/
+
+ //[downloadTask resume];
+
+ if (!theDownload) {
+ NSLog(@"Download Failed");
+ [[Launcher sharedLauncher] displayErrorPage];
+ }
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
+ NSLog(@"download domain content: data received");
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
+ NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
+ if([ne statusCode] == 200) {
+ NSLog(@"connection state is 200 - all okay");
+ } else {
+ NSLog(@"connection state is NOT 200");
+ [[Launcher sharedLauncher] displayErrorPage];
+ }
+}
+
+-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
+ NSLog(@"download domain content - Conn Err: %@", [error localizedDescription]);
+ [[Launcher sharedLauncher] displayErrorPage];
+}
+
+- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
+{
+ NSString* finalFilePath = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent:filename];
+ [download setDestination:finalFilePath allowOverwrite:YES];
+
+ [[Launcher sharedLauncher] setDownloadContextFilename:filename];
+}
+
+- (void)downloadDidFinish:(NSURLDownload*)download
+{
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ NSLog(@"extracting domain content file");
+ [sharedLauncher extractZipFileAtDestination:[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:@"content"] :[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:[sharedLauncher getDownloadContentFilename]]];
+
+ NSLog(@"finished extracting content file");
+
+ [sharedLauncher domainContentDownloadFinished];
+}
+
+- (void)download:(NSURLDownload*)download didReceiveResponse:(NSURLResponse*)response
+{
+ NSLog(@"Download content set response");
+}
+
+@end
diff --git a/launchers/darwin/src/DownloadInterface.h b/launchers/darwin/src/DownloadInterface.h
new file mode 100644
index 0000000000..8edb75e8ad
--- /dev/null
+++ b/launchers/darwin/src/DownloadInterface.h
@@ -0,0 +1,8 @@
+#import
+
+@interface DownloadInterface : NSObject {
+}
+@property (nonatomic, assign) NSString* finalFilePath;
+
+- (void) downloadInterface:(NSString*) downloadUrl;
+@end
diff --git a/launchers/darwin/src/DownloadInterface.m b/launchers/darwin/src/DownloadInterface.m
new file mode 100644
index 0000000000..73d8663e48
--- /dev/null
+++ b/launchers/darwin/src/DownloadInterface.m
@@ -0,0 +1,109 @@
+#import "DownloadInterface.h"
+#import "Launcher.h"
+#import "Settings.h"
+
+@implementation DownloadInterface
+
+- (void) downloadInterface:(NSString*) downloadUrl
+{
+ NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:downloadUrl]
+ cachePolicy:NSURLRequestUseProtocolCachePolicy
+ timeoutInterval:60.0];
+
+ NSURLDownload* theDownload = [[NSURLDownload alloc] initWithRequest:request delegate:self];
+
+ /*NSURLSession *session = [NSURLSession sharedSession];
+ NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
+ completionHandler:
+ ^(NSURL *location, NSURLResponse *response,NSError *error) {
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ NSString* finalFilePath = [[sharedLauncher getAppPath] stringByAppendingPathComponent:[response suggestedFilename]];
+ [[Launcher sharedLauncher] setDownloadFilename:[response suggestedFilename]];
+
+ NSLog(@"----------->%@", location);
+ [[NSFileManager defaultManager] moveItemAtURL:location
+ toURL:[NSURL URLWithString: [finalFilePath stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]]
+ error:nil];
+ dispatch_async(dispatch_get_main_queue(), ^{
+
+ NSString* appPath = [sharedLauncher getAppPath];
+ NSString* downloadFileName = [sharedLauncher getDownloadFilename];
+ NSLog(@"!!!!!!%@", downloadFileName);
+ NSLog(@"extract interface zip");
+ [sharedLauncher extractZipFileAtDestination:appPath :[appPath stringByAppendingString:downloadFileName]];
+ NSLog(@"finished extracting interface zip");
+
+ NSLog(@"starting xattr");
+ NSTask* quaratineTask = [[NSTask alloc] init];
+ quaratineTask.launchPath = @"/usr/bin/xattr";
+ quaratineTask.arguments = @[@"-d", @"com.apple.quarantine", [appPath stringByAppendingString:@"interface.app"]];
+
+ [quaratineTask launch];
+ [quaratineTask waitUntilExit];
+ NSLog(@"finished xattr");
+
+ NSString* launcherPath = [appPath stringByAppendingString:@"Launcher"];
+
+ [[Settings sharedSettings] setLauncherPath:launcherPath];
+ [sharedLauncher interfaceFinishedDownloading];
+
+ });
+ }];
+
+ [downloadTask resume];*/
+}
+
+- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
+{
+ self.finalFilePath = [[[Launcher sharedLauncher] getAppPath] stringByAppendingPathComponent:filename];
+ [download setDestination:self.finalFilePath allowOverwrite:YES];
+
+ [[Launcher sharedLauncher] setDownloadFilename:filename];
+}
+
+
+- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
+ NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
+ if([ne statusCode] == 200) {
+ NSLog(@"download interface connection state is 200 - all okay");
+ } else {
+ NSLog(@"download interface connection state is NOT 200");
+ [[Launcher sharedLauncher] displayErrorPage];
+ }
+}
+
+-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
+ NSLog(@"download interface content - Conn Err: %@", [error localizedDescription]);
+ [[Launcher sharedLauncher] displayErrorPage];
+}
+
+- (void)downloadDidFinish:(NSURLDownload*)download
+{
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ NSString* appPath = [sharedLauncher getAppPath];
+ NSString* downloadFileName = [sharedLauncher getDownloadFilename];
+
+ NSLog(@"extract interface zip");
+ [sharedLauncher extractZipFileAtDestination:appPath :[appPath stringByAppendingString:downloadFileName]];
+ NSLog(@"finished extracting interface zip");
+
+ NSLog(@"starting xattr");
+ NSTask* quaratineTask = [[NSTask alloc] init];
+ quaratineTask.launchPath = @"/usr/bin/xattr";
+ quaratineTask.arguments = @[@"-d", @"com.apple.quarantine", [appPath stringByAppendingString:@"interface.app"]];
+
+ [quaratineTask launch];
+ [quaratineTask waitUntilExit];
+ NSLog(@"finished xattr");
+
+ NSString* launcherPath = [appPath stringByAppendingString:@"Launcher"];
+
+ [[Settings sharedSettings] setLauncherPath:launcherPath];
+ [sharedLauncher interfaceFinishedDownloading];
+}
+
+- (void)download:(NSURLDownload*)download didReceiveResponse:(NSURLResponse*)response
+{
+ NSLog(@"Download interface response");
+}
+@end
diff --git a/launchers/darwin/src/DownloadScripts.h b/launchers/darwin/src/DownloadScripts.h
new file mode 100644
index 0000000000..711cf4f8b2
--- /dev/null
+++ b/launchers/darwin/src/DownloadScripts.h
@@ -0,0 +1,8 @@
+#import
+
+@interface DownloadScripts : NSObject {
+}
+@property (nonatomic, assign) NSString* finalFilePath;
+
+- (void) downloadScripts:(NSString*) scriptUrl;
+@end
diff --git a/launchers/darwin/src/DownloadScripts.m b/launchers/darwin/src/DownloadScripts.m
new file mode 100644
index 0000000000..8e5863d159
--- /dev/null
+++ b/launchers/darwin/src/DownloadScripts.m
@@ -0,0 +1,39 @@
+#import "DownloadScripts.h"
+#import "Launcher.h"
+
+@implementation DownloadScripts
+
+- (void) downloadScripts:(NSString*) scriptsUrl
+{
+ /*NSURLRequest* theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:scriptsUrl]
+ cachePolicy:NSURLRequestUseProtocolCachePolicy
+ timeoutInterval:6000.0];
+ NSURLDownload *theDownload = [[NSURLDownload alloc] initWithRequest:theRequest delegate:self];
+
+ if (!theDownload) {
+ NSLog(@"Download Failed");
+ }*/
+}
+
+- (void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
+{
+ NSString* finalFilePath = [[[Launcher sharedLauncher] getDownloadPathForContentAndScripts] stringByAppendingPathComponent:filename];
+ [download setDestination:finalFilePath allowOverwrite:YES];
+
+ [[Launcher sharedLauncher] setDownloadScriptsFilename:filename];
+}
+
+- (void)downloadDidFinish:(NSURLDownload*)download
+{
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ [sharedLauncher extractZipFileAtDestination:[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:@"scripts"] :[[sharedLauncher getDownloadPathForContentAndScripts] stringByAppendingString:[sharedLauncher getDownloadScriptsFilename]]];
+
+ [sharedLauncher domainScriptsDownloadFinished];
+
+}
+
+- (void)download:(NSURLDownload*)download didReceiveResponse:(NSURLResponse*)response
+{
+ NSLog(@"DownloadScripts received a response");
+}
+@end
diff --git a/launchers/darwin/src/ErrorViewController.h b/launchers/darwin/src/ErrorViewController.h
new file mode 100644
index 0000000000..4463edb0e5
--- /dev/null
+++ b/launchers/darwin/src/ErrorViewController.h
@@ -0,0 +1,7 @@
+#import
+
+@interface ErrorViewController : NSViewController {
+}
+
+@end
+
diff --git a/launchers/darwin/src/ErrorViewController.m b/launchers/darwin/src/ErrorViewController.m
new file mode 100644
index 0000000000..0ae321763f
--- /dev/null
+++ b/launchers/darwin/src/ErrorViewController.m
@@ -0,0 +1,26 @@
+#import "ErrorViewController.h"
+#import "Launcher.h"
+#import "CustomUI.h"
+
+@interface ErrorViewController()
+@property (nonatomic, assign) IBOutlet NSImageView* backgroundImage;
+@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
+@property (nonatomic, assign) IBOutlet NSImageView* voxelImage;
+
+@end
+
+@implementation ErrorViewController
+
+- (void) awakeFromNib
+{
+ [self.backgroundImage setImage:[NSImage imageNamed:hifiBackgroundFilename]];
+ [self.smallLogo setImage:[NSImage imageNamed:hifiSmallLogoFilename]];
+ [self.voxelImage setImage:[NSImage imageNamed:hifiVoxelFilename]];
+}
+
+-(IBAction)resartLauncher:(id)sender
+{
+ [[Launcher sharedLauncher] showLoginScreen];
+}
+
+@end
diff --git a/launchers/darwin/src/LatestBuildRequest.h b/launchers/darwin/src/LatestBuildRequest.h
new file mode 100644
index 0000000000..be2a168a21
--- /dev/null
+++ b/launchers/darwin/src/LatestBuildRequest.h
@@ -0,0 +1,10 @@
+#import
+
+@interface LatestBuildRequest : NSObject {
+}
+
+@property (nonatomic, retain) NSMutableData* webData;
+@property (nonatomic, retain) NSString* jsonString;
+
+- (void) requestLatestBuildInfo;
+@end
diff --git a/launchers/darwin/src/LatestBuildRequest.m b/launchers/darwin/src/LatestBuildRequest.m
new file mode 100644
index 0000000000..019637ed55
--- /dev/null
+++ b/launchers/darwin/src/LatestBuildRequest.m
@@ -0,0 +1,104 @@
+#import "LatestBuildRequest.h"
+#import "Launcher.h"
+#import "Settings.h"
+
+@implementation LatestBuildRequest
+
+- (void) requestLatestBuildInfo {
+ NSMutableURLRequest *request = [NSMutableURLRequest new];
+ [request setURL:[NSURL URLWithString:@"https://thunder.highfidelity.com/builds/api/tags/latest?format=json"]];
+ [request setHTTPMethod:@"GET"];
+ [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
+
+
+ NSURLSession* session = [NSURLSession sharedSession];
+ NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ NSLog(@"credentials request finished");
+ NSMutableData* webData = [NSMutableData data];
+ [webData appendData:data];
+ NSString* jsonString = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[data length] encoding:NSUTF8StringEncoding];
+ NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
+ id json = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
+
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+ NSArray *values = [json valueForKey:@"results"];
+ NSDictionary *value = [values objectAtIndex:0];
+
+
+ NSString* buildNumber = [value valueForKey:@"latest_version"];
+ NSDictionary* installers = [value objectForKey:@"installers"];
+ NSDictionary* macInstallerObject = [installers objectForKey:@"mac"];
+ NSString* macInstallerUrl = [macInstallerObject valueForKey:@"zip_url"];
+
+ BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]];
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ Settings* settings = [Settings sharedSettings];
+ NSInteger currentVersion = [settings latestBuildVersion];
+ BOOL latestVersionAvailable = (currentVersion != buildNumber.integerValue);
+ [[Settings sharedSettings] buildVersion:buildNumber.integerValue];
+
+ BOOL shouldDownloadInterface = (latestVersionAvailable || !appDirectoryExist);
+ [sharedLauncher shouldDownloadLatestBuild:shouldDownloadInterface :macInstallerUrl];
+ });
+ }];
+
+ [dataTask resume];
+
+ //NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
+
+ /*if(theConnection) {
+ self.webData = [NSMutableData data];
+ NSLog(@"connection initiated");
+ }*/
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
+ [self.webData appendData:data];
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
+ NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
+ if([ne statusCode] == 200) {
+ NSLog(@"connection state is 200 - all okay");
+ } else {
+ NSLog(@"connection state is NOT 200");
+ [[Launcher sharedLauncher] displayErrorPage];
+ }
+}
+
+-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
+ NSLog(@"Conn Err: %@", [error localizedDescription]);
+ [[Launcher sharedLauncher] displayErrorPage];
+}
+
+- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ self.jsonString = [[NSString alloc] initWithBytes: [self.webData mutableBytes] length:[self.webData length] encoding:NSUTF8StringEncoding];
+ NSData *data = [self.jsonString dataUsingEncoding:NSUTF8StringEncoding];
+ id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+ NSArray *values = [json valueForKey:@"results"];
+ NSDictionary *value = [values objectAtIndex:0];
+
+
+ NSString* buildNumber = [value valueForKey:@"latest_version"];
+ NSDictionary* installers = [value objectForKey:@"installers"];
+ NSDictionary* macInstallerObject = [installers objectForKey:@"mac"];
+ NSString* macInstallerUrl = [macInstallerObject valueForKey:@"zip_url"];
+
+ BOOL appDirectoryExist = [fileManager fileExistsAtPath:[[sharedLauncher getAppPath] stringByAppendingString:@"interface.app"]];
+
+ Settings* settings = [Settings sharedSettings];
+ NSInteger currentVersion = [settings latestBuildVersion];
+ BOOL latestVersionAvailable = (currentVersion != buildNumber.integerValue);
+ [[Settings sharedSettings] buildVersion:buildNumber.integerValue];
+
+ BOOL shouldDownloadInterface = (latestVersionAvailable || !appDirectoryExist);
+ [sharedLauncher shouldDownloadLatestBuild:shouldDownloadInterface :macInstallerUrl];
+}
+
+@end
diff --git a/launchers/darwin/src/LaunchInterface.h b/launchers/darwin/src/LaunchInterface.h
new file mode 100644
index 0000000000..2d6df927d6
--- /dev/null
+++ b/launchers/darwin/src/LaunchInterface.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#include
+void launchInterface() {
+}
diff --git a/launchers/darwin/src/Launcher.h b/launchers/darwin/src/Launcher.h
new file mode 100644
index 0000000000..5838e25a82
--- /dev/null
+++ b/launchers/darwin/src/Launcher.h
@@ -0,0 +1,83 @@
+#import
+#import "DownloadInterface.h"
+#import "CredentialsRequest.h"
+#import "DownloadDomainContent.h"
+#import "LatestBuildRequest.h"
+#import "OrganizationRequest.h"
+#import "DownloadScripts.h"
+
+typedef enum processStateTypes
+{
+ DOWNLOADING_INTERFACE = 0,
+ RUNNING_INTERFACE_AFTER_DOWNLOAD,
+ CHECKING_UPDATE,
+ RUNNING_INTERFACE_AFTER_UPDATE
+} ProcessState;
+
+typedef enum LoginErrorTypes
+{
+ NONE = 0,
+ ORGANIZATION,
+ CREDENTIALS
+} LoginError;
+
+@interface Launcher : NSObject {
+}
+@property (nonatomic, retain) NSString* password;
+@property (nonatomic, retain) NSString* username;
+@property (nonatomic, retain) NSString* organization;
+@property (nonatomic, retain) NSString* userToken;
+@property (nonatomic, retain) NSString* displayName;
+@property (nonatomic, retain) NSString* filename;
+@property (nonatomic, retain) NSString* scriptsFilename;
+@property (nonatomic, retain) NSString* contentFilename;
+@property (nonatomic, retain) NSString* domainURL;
+@property (nonatomic, retain) NSString* domainContentUrl;
+@property (nonatomic, retain) NSString* domainScriptsUrl;
+@property (nonatomic, retain) DownloadInterface* downloadInterface;
+@property (nonatomic, retain) CredentialsRequest* credentialsRequest;
+@property (nonatomic, retain) DownloadDomainContent* downloadDomainContent;
+@property (nonatomic, retain) DownloadScripts* downloadScripts;
+@property (nonatomic, retain) LatestBuildRequest* latestBuildRequest;
+@property (nonatomic, retain) OrganizationRequest* organizationRequest;
+@property (nonatomic) BOOL credentialsAccepted;
+@property (nonatomic) BOOL waitingForCredentialReponse;
+@property (nonatomic) BOOL gotCredentialResponse;
+@property (nonatomic) BOOL waitingForInterfaceToTerminate;
+@property (nonatomic, assign, readwrite) ProcessState processState;
+@property (nonatomic, assign, readwrite) LoginError loginError;
+
+- (void) displayNameEntered:(NSString*)aDisplayName;
+- (void) credentialsEntered:(NSString*)aOrginization :(NSString*)aUsername :(NSString*)aPassword;
+- (void) credentialsAccepted:(BOOL) aCredentialsAccepted;
+- (void) domainContentDownloadFinished;
+- (void) domainScriptsDownloadFinished;
+- (void) setDomainURLInfo:(NSString*) aDomainURL :(NSString*) aDomainContentUrl :(NSString*) aDomainScriptsUrl;
+- (void) organizationRequestFinished:(BOOL) aOriginzationAccepted;
+- (BOOL) loginShouldSetErrorState;
+- (void) displayErrorPage;
+- (void) showLoginScreen;
+- (ProcessState) currentProccessState;
+- (void) setCurrentProcessState:(ProcessState) aProcessState;
+- (void) setLoginErrorState:(LoginError) aLoginError;
+- (LoginError) getLoginErrorState;
+- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl;
+- (void) interfaceFinishedDownloading;
+- (NSString*) getDownloadPathForContentAndScripts;
+- (void) launchInterface;
+- (void) extractZipFileAtDestination:(NSString*) destination :(NSString*) file;
+- (BOOL) isWaitingForInterfaceToTerminate;
+- (void) setDownloadFilename:(NSString*) aFilename;
+- (void) setDownloadContextFilename:(NSString*) aFilename;
+- (void) setDownloadScriptsFilename:(NSString*) aFilename;
+- (void) setTokenString:(NSString*) aToken;
+- (NSString*) getTokenString;
+- (NSString*) getDownloadContentFilename;
+- (NSString*) getDownloadScriptsFilename;
+- (NSString*) getDownloadFilename;
+- (BOOL) isLoadedIn;
+- (NSString*) getAppPath;
+
++ (id) sharedLauncher;
+@end
+
diff --git a/launchers/darwin/src/Launcher.m b/launchers/darwin/src/Launcher.m
new file mode 100644
index 0000000000..07fc8878da
--- /dev/null
+++ b/launchers/darwin/src/Launcher.m
@@ -0,0 +1,364 @@
+#import "Launcher.h"
+#import "Window.h"
+#import "SplashScreen.h"
+#import "LoginScreen.h"
+#import "DisplayNameScreen.h"
+#import "ProcessScreen.h"
+#import "ErrorViewController.h"
+#import "Settings.h"
+
+@interface Launcher ()
+
+@property (strong) IBOutlet Window* window;
+@property (nonatomic, assign) NSString* finalFilePath;
+@property (nonatomic, assign) NSButton* button;
+@end
+
+
+static BOOL const DELETE_ZIP_FILES = TRUE;
+@implementation Launcher
++ (id) sharedLauncher {
+ static Launcher* sharedLauncher = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ sharedLauncher = [[self alloc]init];
+ });
+ return sharedLauncher;
+}
+
+-(id)init {
+ if (self = [super init]) {
+ self.username = [[NSString alloc] initWithString:@"Default Property Value"];
+ self.downloadInterface = [DownloadInterface alloc];
+ self.downloadDomainContent = [DownloadDomainContent alloc];
+ self.credentialsRequest = [CredentialsRequest alloc];
+ self.latestBuildRequest = [LatestBuildRequest alloc];
+ self.organizationRequest = [OrganizationRequest alloc];
+ self.downloadScripts = [DownloadScripts alloc];
+ self.credentialsAccepted = TRUE;
+ self.gotCredentialResponse = FALSE;
+ self.waitingForCredentialReponse = FALSE;
+ self.waitingForInterfaceToTerminate = FALSE;
+ self.userToken = nil;
+ self.processState = DOWNLOADING_INTERFACE;
+ }
+ return self;
+}
+
+-(void)awakeFromNib {
+ [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
+ selector:@selector(didTerminateApp:)
+ name:NSWorkspaceDidTerminateApplicationNotification
+ object:nil];
+
+ SplashScreen* splashScreen = [[SplashScreen alloc] initWithNibName:@"SplashScreen" bundle:nil];
+ [self.window setContentViewController: splashScreen];
+ [self closeInterfaceIfRunning];
+
+ if (!self.waitingForInterfaceToTerminate) {
+ [self checkLoginStatus];
+ }
+}
+
+- (NSString*) getDownloadPathForContentAndScripts
+{
+ NSString* filePath = [[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]
+ stringByAppendingString:@"/Launcher/"];
+
+ if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
+ NSError * error = nil;
+ [[NSFileManager defaultManager] createDirectoryAtPath:filePath withIntermediateDirectories:TRUE attributes:nil error:&error];
+ }
+
+ return filePath;
+}
+
+- (void) extractZipFileAtDestination:(NSString *)destination :(NSString*)file
+{
+ NSTask* task = [[NSTask alloc] init];
+ task.launchPath = @"/usr/bin/unzip";
+ task.arguments = @[@"-o", @"-d", destination, file];
+
+ [task launch];
+ [task waitUntilExit];
+
+ if (DELETE_ZIP_FILES) {
+ NSFileManager* fileManager = [NSFileManager defaultManager];
+ [fileManager removeItemAtPath:file error:NULL];
+ }
+}
+
+- (void) displayErrorPage
+{
+ ErrorViewController* errorPage = [[ErrorViewController alloc] initWithNibName:@"ErrorScreen" bundle:nil];
+ [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: errorPage];
+}
+
+- (void) checkLoginStatus
+{
+ if ([self isLoadedIn]) {
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ [sharedLauncher setCurrentProcessState:CHECKING_UPDATE];
+ ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil];
+ [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen];
+ [self.latestBuildRequest requestLatestBuildInfo];
+ } else {
+ [NSTimer scheduledTimerWithTimeInterval:2.0
+ target:self
+ selector:@selector(onSplashScreenTimerFinished:)
+ userInfo:nil
+ repeats:NO];
+ }
+}
+
+- (void) setDownloadContextFilename:(NSString *)aFilename
+{
+ self.contentFilename = aFilename;
+}
+
+- (void) setDownloadScriptsFilename:(NSString*)aFilename
+{
+ self.scriptsFilename = aFilename;
+}
+
+- (NSString*) getDownloadContentFilename
+{
+ return self.contentFilename;
+}
+
+- (NSString*) getDownloadScriptsFilename
+{
+ return self.scriptsFilename;
+}
+
+- (void)didTerminateApp:(NSNotification *)notification {
+ if (self.waitingForInterfaceToTerminate) {
+ NSString* appName = [notification.userInfo valueForKey:@"NSApplicationName"];
+ if ([appName isEqualToString:@"interface"]) {
+ self.waitingForInterfaceToTerminate = FALSE;
+ [self checkLoginStatus];
+ }
+ }
+}
+
+- (void) closeInterfaceIfRunning
+{
+ NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
+ NSArray* apps = [workspace runningApplications];
+ for (NSRunningApplication* app in apps) {
+ if ([[app bundleIdentifier] isEqualToString:@"com.highfidelity.interface"] ||
+ [[app bundleIdentifier] isEqualToString:@"com.highfidelity.interface-pr"]) {
+ [app terminate];
+ self.waitingForInterfaceToTerminate = true;
+ }
+ }
+}
+
+- (BOOL) isWaitingForInterfaceToTerminate {
+ return self.waitingForInterfaceToTerminate;
+}
+
+- (BOOL) isLoadedIn
+{
+ return [[Settings sharedSettings] isLoggedIn];
+}
+
+- (void) setDomainURLInfo:(NSString *)aDomainURL :(NSString *)aDomainContentUrl :(NSString *)aDomainScriptsUrl
+{
+ self.domainURL = aDomainURL;
+ self.domainContentUrl = aDomainContentUrl;
+ self.domainScriptsUrl = aDomainScriptsUrl;
+
+ [[Settings sharedSettings] setDomainUrl:aDomainURL];
+}
+
+- (NSString*) getAppPath
+{
+ return [[[NSBundle mainBundle] bundlePath] stringByAppendingString:@"/Contents/MacOS/"];
+}
+
+- (BOOL) loginShouldSetErrorState
+{
+ return !self.credentialsAccepted;
+}
+
+- (void) displayNameEntered:(NSString*)aDiplayName
+{
+ self.processState = DOWNLOADING_INTERFACE;
+ ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil];
+ [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen];
+ [self.downloadDomainContent downloadDomainContent:self.domainContentUrl];
+ self.displayName = aDiplayName;
+}
+
+- (void) domainContentDownloadFinished
+{
+ //.[self.downloadScripts downloadScripts:self.domainScriptsUrl];
+ [self.latestBuildRequest requestLatestBuildInfo];
+}
+
+- (void) domainScriptsDownloadFinished
+{
+ [self.latestBuildRequest requestLatestBuildInfo];
+}
+
+- (void) saveCredentialsAccepted:(BOOL)aCredentialsAccepted
+{
+ self.credentialsAccepted = aCredentialsAccepted;
+}
+
+- (void) credentialsAccepted:(BOOL)aCredentialsAccepted
+{
+ self.credentialsAccepted = aCredentialsAccepted;
+ if (aCredentialsAccepted) {
+ DisplayNameScreen* displayNameScreen = [[DisplayNameScreen alloc] initWithNibName:@"DisplayNameScreen" bundle:nil];
+ [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: displayNameScreen];
+ } else {
+ LoginScreen* loginScreen = [[LoginScreen alloc] initWithNibName:@"LoginScreen" bundle:nil];
+ [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: loginScreen];
+ }
+}
+
+- (void) interfaceFinishedDownloading
+{
+ if (self.processState == DOWNLOADING_INTERFACE) {
+ self.processState = RUNNING_INTERFACE_AFTER_DOWNLOAD;
+ } else {
+ self.processState = RUNNING_INTERFACE_AFTER_UPDATE;
+ }
+ ProcessScreen* processScreen = [[ProcessScreen alloc] initWithNibName:@"ProcessScreen" bundle:nil];
+ [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: processScreen];
+ [self launchInterface];
+}
+
+- (void) credentialsEntered:(NSString*)aOrginization :(NSString*)aUsername :(NSString*)aPassword
+{
+ self.organization = aOrginization;
+ self.username = aUsername;
+ self.password = aPassword;
+ [self.organizationRequest confirmOrganization:aOrginization :aUsername];
+}
+
+- (void) organizationRequestFinished:(BOOL)aOriginzationAccepted
+{
+ self.credentialsAccepted = aOriginzationAccepted;
+ if (aOriginzationAccepted) {
+ [self.credentialsRequest confirmCredentials:self.username : self.password];
+ } else {
+ LoginScreen* loginScreen = [[LoginScreen alloc] initWithNibName:@"LoginScreen" bundle:nil];
+ [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: loginScreen];
+ }
+}
+
+- (BOOL)canBecomeKeyWindow
+{
+ return YES;
+}
+
+-(void) showLoginScreen
+{
+ LoginScreen* loginScreen = [[LoginScreen alloc] initWithNibName:@"LoginScreen" bundle:nil];
+ [[[[NSApplication sharedApplication] windows] objectAtIndex:0] setContentViewController: loginScreen];
+}
+
+- (void) shouldDownloadLatestBuild:(BOOL) shouldDownload :(NSString*) downloadUrl
+{
+ if (shouldDownload) {
+ [self.downloadInterface downloadInterface: downloadUrl];
+ return;
+ }
+ [self launchInterface];
+}
+
+-(void)onSplashScreenTimerFinished:(NSTimer *)timer
+{
+ [self showLoginScreen];
+}
+
+-(void)setCurrentProcessState:(ProcessState)aProcessState
+{
+ self.processState = aProcessState;
+}
+
+- (void)applicationWillFinishLaunching:(NSNotification *)notification
+{
+ [self.window makeKeyAndOrderFront:self];
+}
+
+- (void) setDownloadFilename:(NSString *)aFilename
+{
+ self.filename = aFilename;
+}
+
+- (NSString*) getDownloadFilename
+{
+ return self.filename;
+}
+
+- (void) setTokenString:(NSString *)aToken
+{
+ self.userToken = aToken;
+}
+
+- (NSString*) getTokenString
+{
+ return self.userToken;
+}
+
+- (void) setLoginErrorState:(LoginError)aLoginError
+{
+ self.loginError = aLoginError;
+}
+
+- (LoginError) getLoginErrorState
+{
+ return self.loginError;
+}
+
+- (void) launchInterface
+{
+ NSString* launcherPath = [[self getAppPath] stringByAppendingString:@"HQ Launcher"];
+
+ [[Settings sharedSettings] setLauncherPath:launcherPath];
+ [[Settings sharedSettings] save];
+ NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
+ NSURL *url = [NSURL fileURLWithPath:[workspace fullPathForApplication:[[self getAppPath] stringByAppendingString:@"interface.app/Contents/MacOS/interface"]]];
+
+ NSError *error = nil;
+
+ NSString* contentPath = [[self getDownloadPathForContentAndScripts] stringByAppendingString:@"content"];
+ NSString* displayName = [ self displayName];
+ NSString* scriptsPath = [[self getAppPath] stringByAppendingString:@"interface.app/Contents/Resources/scripts/simplifiedUI/"];
+ NSString* domainUrl = [[Settings sharedSettings] getDomainUrl];
+ NSString* userToken = [[Launcher sharedLauncher] getTokenString];
+ NSArray* arguments;
+ if (userToken != nil) {
+ arguments = [NSArray arrayWithObjects:
+ @"--url" , domainUrl ,
+ @"--tokens", userToken,
+ @"--cache", contentPath,
+ @"--displayName", displayName,
+ @"--script", scriptsPath,
+ @"--no-updater",
+ @"--no-launcher", nil];
+ } else {
+ arguments = [NSArray arrayWithObjects:
+ @"--url" , domainUrl,
+ @"--cache", contentPath,
+ @"--script", scriptsPath,
+ @"--no-updater",
+ @"--no-launcher", nil];
+ }
+ [workspace launchApplicationAtURL:url options:NSWorkspaceLaunchNewInstance configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:&error];
+
+ //NSLog(@"arguments %@", [NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments]);
+
+ [NSApp terminate:self];
+}
+
+- (ProcessState) currentProccessState
+{
+ return self.processState;
+}
+
+@end
diff --git a/launchers/darwin/src/LoginScreen.h b/launchers/darwin/src/LoginScreen.h
new file mode 100644
index 0000000000..9b2d3d529c
--- /dev/null
+++ b/launchers/darwin/src/LoginScreen.h
@@ -0,0 +1,5 @@
+#import
+
+@interface LoginScreen : NSViewController {
+}
+@end
diff --git a/launchers/darwin/src/LoginScreen.m b/launchers/darwin/src/LoginScreen.m
new file mode 100644
index 0000000000..4c83558160
--- /dev/null
+++ b/launchers/darwin/src/LoginScreen.m
@@ -0,0 +1,76 @@
+#import "LoginScreen.h"
+#import "Launcher.h"
+#import "CustomUI.h"
+
+@interface LoginScreen ()
+@property (nonatomic, assign) IBOutlet NSImageView* backgroundImage;
+@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
+@property (nonatomic, assign) IBOutlet NSTextField* username;
+@property (nonatomic, assign) IBOutlet NSTextField* password;
+@property (nonatomic, assign) IBOutlet NSTextField* orginization;
+@property (nonatomic, assign) IBOutlet NSTextField* header;
+@property (nonatomic, assign) IBOutlet NSTextField* smallHeader;
+@property (nonatomic, assign) IBOutlet NSTextField* trouble;
+@property (nonatomic, assign) IBOutlet NSButton* button;
+@end
+
+@implementation LoginScreen
+
+- (void) awakeFromNib
+{
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ if ([sharedLauncher loginShouldSetErrorState]) {
+ [self.header setStringValue:@"Uh-oh, we have a problem"];
+ switch ([sharedLauncher getLoginErrorState]) {
+ case CREDENTIALS:
+ [self.smallHeader setStringValue:@"There is a problem with your credentials, please try again"];
+ break;
+ case ORGANIZATION:
+ [self.smallHeader setStringValue:@"There is a problem with your organization name, please try again"];
+ break;
+ case NONE:
+ break;
+ default:
+ break;
+ }
+ [self.button setTitle:@"TRY AGAIN"];
+ }
+
+ [self.backgroundImage setImage:[NSImage imageNamed:hifiBackgroundFilename]];
+ [self.smallLogo setImage:[NSImage imageNamed:hifiSmallLogoFilename]];
+
+ NSMutableAttributedString* usernameString = [[NSMutableAttributedString alloc] initWithString:@"Username"];
+
+ [usernameString addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0,8)];
+ [usernameString addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,8)];
+
+ NSMutableAttributedString* orgName = [[NSMutableAttributedString alloc] initWithString:@"Organization Name"];
+ [orgName addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0,17)];
+ [orgName addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,17)];
+
+ NSMutableAttributedString* passwordString = [[NSMutableAttributedString alloc] initWithString:@"Password"];
+
+ [passwordString addAttribute:NSForegroundColorAttributeName value:[NSColor grayColor] range:NSMakeRange(0,8)];
+ [passwordString addAttribute:NSFontAttributeName value:[NSFont systemFontOfSize:18] range:NSMakeRange(0,8)];
+
+ [self.username setPlaceholderAttributedString:usernameString];
+ [self.orginization setPlaceholderAttributedString:orgName];
+ [self.password setPlaceholderAttributedString:passwordString];
+
+ [self.password setTarget:self];
+ [self.password setAction:@selector(goToLogin:)];
+}
+
+- (IBAction)goToLogin:(id)sender
+{
+ printf("In gotologin");
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ [sharedLauncher credentialsEntered:[self.orginization stringValue] :[self.username stringValue] :[self.password stringValue]];
+}
+
+- (IBAction)havingTrouble:(id)sender
+{
+ [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.highfidelity.com/hq-support"]];
+}
+
+@end
diff --git a/launchers/darwin/src/OrganizationRequest.h b/launchers/darwin/src/OrganizationRequest.h
new file mode 100644
index 0000000000..2f7d2570d6
--- /dev/null
+++ b/launchers/darwin/src/OrganizationRequest.h
@@ -0,0 +1,11 @@
+#import
+
+@interface OrganizationRequest : NSObject {
+}
+
+@property (nonatomic, retain) NSMutableData* webData;
+@property (nonatomic, retain) NSString* jsonString;
+@property (nonatomic, retain) NSString* username;
+
+- (void) confirmOrganization:(NSString*) aOrganization :(NSString*) aUsername;
+@end
diff --git a/launchers/darwin/src/OrganizationRequest.m b/launchers/darwin/src/OrganizationRequest.m
new file mode 100644
index 0000000000..b51de8a19e
--- /dev/null
+++ b/launchers/darwin/src/OrganizationRequest.m
@@ -0,0 +1,96 @@
+#import "OrganizationRequest.h"
+#include
+#include
+#import "Launcher.h"
+
+
+static NSString* const organizationURL = @"https://s3.amazonaws.com/hifi-public/huffman/organizations/";
+
+#define str(s) #s
+#define LAUNCHER_HMAC_SECRET_STRING str(LAUNCHER_HMAC_SECRET)
+
+@implementation OrganizationRequest
+
+- (void) confirmOrganization:(NSString*)aOrganization :(NSString*)aUsername {
+ self.username = aUsername;
+
+ const char *cKey = LAUNCHER_HMAC_SECRET_STRING;
+ const char *cData = [aOrganization cStringUsingEncoding:NSASCIIStringEncoding];
+ unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
+ CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
+ NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
+ const unsigned char *buffer = (const unsigned char *)[HMACData bytes];
+ NSMutableString *hash = [NSMutableString stringWithCapacity:HMACData.length * 2];
+ for (int i = 0; i < HMACData.length; ++i){
+ [hash appendFormat:@"%02x", buffer[i]];
+ }
+
+ NSString* jsonFile = [hash stringByAppendingString:@".json"];
+ NSError *error;
+ NSData *data = [NSData dataWithContentsOfURL: [NSURL URLWithString:[organizationURL stringByAppendingString:jsonFile]]];
+
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ if (data) {
+ NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
+ [sharedLauncher setDomainURLInfo:[json valueForKey:@"domain"] :[json valueForKey:@"content_set_url"] :[json valueForKey:@"scripts_url"]];
+ [sharedLauncher setLoginErrorState: NONE];
+ return [sharedLauncher organizationRequestFinished:TRUE];
+ }
+ NSLog(@"FAAAAILLLLLLLEEEEEEEDDDDDD");
+ [sharedLauncher setLoginErrorState: ORGANIZATION];
+ return [sharedLauncher organizationRequestFinished:FALSE];
+ /*NSLog(@"URL: %@", [organizationURL stringByAppendingString:jsonFile]);
+ NSMutableURLRequest *request = [NSMutableURLRequest new];
+ [request setURL:[NSURL URLWithString: [organizationURL stringByAppendingString:@"High%20Fidelity"]]];
+ [request setHTTPMethod:@"GET"];
+ [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
+
+ NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
+
+ if(theConnection) {
+ self.webData = [NSMutableData data];
+ NSLog(@"connection initiated");
+ }*/
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
+ [self.webData appendData:data];
+}
+
+- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
+ NSHTTPURLResponse *ne = (NSHTTPURLResponse *)response;
+ if([ne statusCode] == 200) {
+ NSLog(@"connection state is 200 - all okay");
+ } else {
+ NSLog(@"connection state is NOT 200");
+ }
+}
+
+-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
+ NSLog(@"Conn Err: %@", [error localizedDescription]);
+}
+
+- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
+ /*NSString* jsonString = [[NSString alloc] initWithBytes: [self.webData mutableBytes] length:[self.webData length] encoding:NSUTF8StringEncoding];
+ NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
+ id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];*/
+
+ /*Launcher* sharedLauncher = [Launcher sharedLauncher];
+ if (json[@"error"] != nil) {
+ NSLog(@"Login in failed");
+ NSString* accessToken = [json objectForKey:@"access_token"];
+ NSLog(@"access token %@", accessToken);
+ [sharedLauncher credentialsAccepted:FALSE];
+ } else {
+ NSLog(@"Login successful");
+ NSString* accessToken = [json objectForKey:@"access_token"];
+ NSLog(@"access token %@", accessToken);
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setValue:accessToken forKey:@"access_token"];
+ [defaults synchronize];
+ [sharedLauncher credentialsAccepted:TRUE];
+ }*/
+ //NSLog(@"OUTPUT:: %@", self.jsonString);
+}
+
+@end
diff --git a/launchers/darwin/src/ProcessScreen.h b/launchers/darwin/src/ProcessScreen.h
new file mode 100644
index 0000000000..156f5428d8
--- /dev/null
+++ b/launchers/darwin/src/ProcessScreen.h
@@ -0,0 +1,7 @@
+#import
+
+@interface ProcessScreen : NSViewController {
+}
+
+@property (nonatomic, assign) NSInteger imageRotation;
+@end
diff --git a/launchers/darwin/src/ProcessScreen.m b/launchers/darwin/src/ProcessScreen.m
new file mode 100644
index 0000000000..0a9d6017d1
--- /dev/null
+++ b/launchers/darwin/src/ProcessScreen.m
@@ -0,0 +1,55 @@
+#import "ProcessScreen.h"
+#import "Launcher.h"
+#import "CustomUI.h"
+
+@interface ProcessScreen ()
+@property (nonatomic, assign) IBOutlet NSImageView* background;
+@property (nonatomic, assign) IBOutlet NSImageView* smallLogo;
+@property (nonatomic, assign) IBOutlet NSImageView* voxelImage;
+@property (nonatomic, assign) IBOutlet NSTextField* boldStatus;
+@property (nonatomic, assign) IBOutlet NSTextField* smallStatus;
+@end
+
+@implementation ProcessScreen
+
+- (void) awakeFromNib {
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ switch ([sharedLauncher currentProccessState]) {
+ case DOWNLOADING_INTERFACE:
+ [self.boldStatus setStringValue:@"We're building your virtual HQ"];
+ [self.smallStatus setStringValue:@"Set up may take several minutes."];
+ break;
+ case RUNNING_INTERFACE_AFTER_DOWNLOAD:
+ [self.boldStatus setStringValue:@"Your new HQ is all setup"];
+ [self.smallStatus setStringValue:@"Thanks for being patient."];
+ break;
+ case CHECKING_UPDATE:
+ [self.boldStatus setStringValue:@"Getting updates..."];
+ [self.smallStatus setStringValue:@"We're getting the lastest and greatest for you, one sec."];
+ break;
+ case RUNNING_INTERFACE_AFTER_UPDATE:
+ [self.boldStatus setStringValue:@"You're good to go!"];
+ [self.smallStatus setStringValue:@"Thanks for being patient."];
+ break;
+ default:
+ break;
+ }
+ [self.background setImage: [NSImage imageNamed:hifiBackgroundFilename]];
+ [self.smallLogo setImage: [NSImage imageNamed:hifiSmallLogoFilename]];
+ [self.voxelImage setImage: [NSImage imageNamed:hifiVoxelFilename]];
+
+ self.imageRotation = 0;
+ //[self.voxelImage setFrameCenterRotation:90];
+
+ [NSTimer scheduledTimerWithTimeInterval:0.016
+ target:self
+ selector:@selector(rotateView:)
+ userInfo:nil
+ repeats:YES];
+}
+
+- (void) rotateView:(NSTimer *)timer{
+ self.imageRotation += 1;
+ [self.voxelImage setFrameCenterRotation:self.imageRotation];
+}
+@end
diff --git a/launchers/darwin/src/Settings.h b/launchers/darwin/src/Settings.h
new file mode 100644
index 0000000000..6a036ca1b1
--- /dev/null
+++ b/launchers/darwin/src/Settings.h
@@ -0,0 +1,20 @@
+#import
+
+
+@interface Settings : NSObject {
+}
+@property (nonatomic, assign) NSInteger build;
+@property (nonatomic, assign) BOOL loggedIn;
+@property (nonatomic, assign) NSString* domain;
+@property (nonatomic, assign) NSString* launcher;
+- (NSInteger) latestBuildVersion;
+- (BOOL) isLoggedIn;
+- (void) login:(BOOL)aLoggedIn;
+- (void) buildVersion:(NSInteger) aBuildVersion;
+- (void) setLauncherPath:(NSString*) aLauncherPath;
+- (NSString*) getLaucnherPath;
+- (void) setDomainUrl:(NSString*) aDomainUrl;
+- (NSString*) getDomainUrl;
+- (void) save;
++ (id) sharedSettings;
+@end
diff --git a/launchers/darwin/src/Settings.m b/launchers/darwin/src/Settings.m
new file mode 100644
index 0000000000..407f869af9
--- /dev/null
+++ b/launchers/darwin/src/Settings.m
@@ -0,0 +1,127 @@
+#import "Settings.h"
+#import "Launcher.h"
+
+
+@implementation Settings
+
++ (id) sharedSettings
+{
+ static Settings* sharedSettings = nil;
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ sharedSettings = [[self alloc]init];
+ });
+ return sharedSettings;
+}
+
+- (NSString*) getFilePath
+{
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ NSString* appPath = [sharedLauncher getAppPath];
+ NSString* filePath = [appPath stringByAppendingString:@"interface.app/Contents/MacOS/"];
+
+ return filePath;
+}
+
+- (void) readDataFromJsonFile
+{
+ NSString* filePath = [self getFilePath];
+ NSString* fileAtPath = [filePath stringByAppendingString:@"config.json"];
+ if ([[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
+ NSString* jsonString = [[NSString alloc] initWithData:[NSData dataWithContentsOfFile:fileAtPath] encoding:NSUTF8StringEncoding];
+ NSError * err;
+ NSData *data =[jsonString dataUsingEncoding:NSUTF8StringEncoding];
+ NSDictionary * json;
+ if(data!=nil){
+ json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];
+
+ self.loggedIn = [[json valueForKey:@"loggedIn"] boolValue];
+ self.build = [[json valueForKey:@"build_version"] integerValue];
+ self.launcher = [json valueForKey:@"luancherPath"];
+ self.domain = [json valueForKey:@"domain"];
+ return;
+ }
+ }
+ self.loggedIn = false;
+ self.build = 0;
+ self.launcher = nil;
+ self.domain = nil;
+}
+
+- (void) writeDataToFile {
+ NSDictionary* json = [[NSDictionary alloc] initWithObjectsAndKeys:
+ [NSString stringWithFormat:@"%ld", self.build], @"build_version",
+ self.loggedIn ? @"TRUE" : @"FALSE", @"loggedIn",
+ self.domain, @"domain",
+ self.launcher, @"launcherPath", nil];
+ NSError * err;
+ NSData * jsonData = [NSJSONSerialization dataWithJSONObject:json options:0 error:&err];
+ NSString * jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+
+ NSString* filePath = [self getFilePath];
+ NSString* fileAtPath = [filePath stringByAppendingString:@"config.json"];
+
+ if (![[NSFileManager defaultManager] fileExistsAtPath:fileAtPath]) {
+ NSError * error = nil;
+ [[NSFileManager defaultManager] createDirectoryAtPath:filePath withIntermediateDirectories:FALSE attributes:nil error:&error];
+ [[NSFileManager defaultManager] createFileAtPath:fileAtPath contents:nil attributes:nil];
+
+ }
+ [[jsonString dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileAtPath atomically:NO];
+
+}
+
+-(id)init
+{
+ if (self = [super init]) {
+ [self readDataFromJsonFile];
+ }
+ return self;
+}
+
+- (BOOL) isLoggedIn
+{
+ return self.loggedIn;
+}
+
+- (NSInteger) latestBuildVersion
+{
+ return self.build;
+}
+
+- (void) buildVersion:(NSInteger)aBuildVersion
+{
+ self.build = aBuildVersion;
+}
+
+- (void) login:(BOOL)aLoggedIn
+{
+ self.loggedIn = aLoggedIn;
+}
+
+- (void) setLauncherPath:(NSString *)aLauncherPath
+{
+ self.launcher = aLauncherPath;
+}
+
+- (void) setDomainUrl:(NSString *)aDomainUrl
+{
+ self.domain = aDomainUrl;
+}
+
+- (NSString*) getDomainUrl
+{
+ return self.domain;
+}
+
+- (NSString*) getLaucnherPath
+{
+ return self.launcher;
+}
+
+- (void) save
+{
+ [self writeDataToFile];
+}
+
+@end
diff --git a/launchers/darwin/src/SplashScreen.h b/launchers/darwin/src/SplashScreen.h
new file mode 100644
index 0000000000..a2e2356682
--- /dev/null
+++ b/launchers/darwin/src/SplashScreen.h
@@ -0,0 +1,6 @@
+#import
+#import "LoginScreen.h"
+@interface SplashScreen: NSViewController {
+}
+
+@end
diff --git a/launchers/darwin/src/SplashScreen.m b/launchers/darwin/src/SplashScreen.m
new file mode 100644
index 0000000000..a1f726c1df
--- /dev/null
+++ b/launchers/darwin/src/SplashScreen.m
@@ -0,0 +1,19 @@
+#import "SplashScreen.h"
+#import "Launcher.h"
+#import "CustomUI.h"
+
+@interface SplashScreen ()
+@property (nonatomic, assign) IBOutlet NSImageView* imageView;
+@property (nonatomic, assign) IBOutlet NSImageView* logoImage;
+@property (nonatomic, assign) IBOutlet NSButton* button;
+@end
+
+@implementation SplashScreen
+- (void) viewDidLoad {
+}
+
+-(void)awakeFromNib {
+ [self.imageView setImage:[NSImage imageNamed:hifiBackgroundFilename]];
+ [self.logoImage setImage:[NSImage imageNamed:hifiLargeLogoFilename]];
+}
+@end
diff --git a/launchers/darwin/src/Window.h b/launchers/darwin/src/Window.h
new file mode 100644
index 0000000000..05e1a7e09e
--- /dev/null
+++ b/launchers/darwin/src/Window.h
@@ -0,0 +1,6 @@
+#import
+
+@interface Window : NSWindow {
+
+}
+@end
diff --git a/launchers/darwin/src/Window.m b/launchers/darwin/src/Window.m
new file mode 100644
index 0000000000..fc54e095e7
--- /dev/null
+++ b/launchers/darwin/src/Window.m
@@ -0,0 +1,7 @@
+#import "Window.h"
+
+@implementation Window
+-(BOOL)canBecomeKeyWindow {
+ return YES;
+}
+@end
diff --git a/launchers/darwin/src/main.mm b/launchers/darwin/src/main.mm
new file mode 100644
index 0000000000..41e2986af7
--- /dev/null
+++ b/launchers/darwin/src/main.mm
@@ -0,0 +1,45 @@
+#import "Launcher.h"
+#import "Settings.h"
+
+void redirectLogToDocuments()
+{
+ NSString* filePath = [[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0]
+ stringByAppendingString:@"/Launcher/"];
+
+ if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
+ NSError * error = nil;
+ [[NSFileManager defaultManager] createDirectoryAtPath:filePath withIntermediateDirectories:TRUE attributes:nil error:&error];
+ }
+ NSString *pathForLog = [filePath stringByAppendingPathComponent:@"log.txt"];
+
+ freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding],"a+",stderr);
+}
+
+int main(int argc, const char* argv[]) {
+ //NSApp.appearance = [NSAppearance appearanceNamed: NSAppearanceNameAqua];
+ //redirectLogToDocuments();
+ NSArray* apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.highfidelity.launcher"];
+ if ([apps count] > 1) {
+ NSLog(@"launcher is already running");
+ return 0;
+ }
+
+ [NSApplication sharedApplication];
+ Launcher* sharedLauncher = [Launcher sharedLauncher];
+ [Settings sharedSettings];
+ [NSApp setDelegate: sharedLauncher];
+
+ // Referenced from https://stackoverflow.com/questions/9155015/handle-cmd-q-in-cocoa-application-and-menu-item-quit-application-programmatic
+ id menubar = [[NSMenu new] autorelease];
+ id appMenuItem = [[NSMenuItem new] autorelease];
+ [menubar addItem:appMenuItem];
+ [NSApp setMainMenu:menubar];
+ id appMenu = [[NSMenu new] autorelease];
+ id appName = [[NSProcessInfo processInfo] processName];
+ id quitTitle = [@"Quit " stringByAppendingString:appName];
+ id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle action:@selector(terminate:) keyEquivalent:@"q"] autorelease];
+ [appMenu addItem:quitMenuItem];
+ [appMenuItem setSubmenu:appMenu];
+
+ return NSApplicationMain(argc, argv);
+}
diff --git a/launchers/win32/BUILD.md b/launchers/win32/BUILD.md
new file mode 100644
index 0000000000..dbaa407dfd
--- /dev/null
+++ b/launchers/win32/BUILD.md
@@ -0,0 +1,33 @@
+## Windows Build Guide
+
+To build the launcher we need:
+
+- Visual Studio Community 2017.
+- CMake.
+
+
+### Installing Visual Studio 2017
+
+If you don’t have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/).
+
+When selecting components, check "Desktop development with C++". Also on the right on the Summary toolbar, check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)".
+
+If you already have Visual Studio installed and need to add python, open the "Add or remove programs" control panel and find the "Microsoft Visual Studio Installer".
+
+### Installing CMake
+
+Download and install the latest version of CMake 3.9.
+
+Download the file named win64-x64 Installer from the [CMake Website](https://cmake.org/download/). You can access the installer on this [3.9 Version page](https://cmake.org/files/v3.9/). During installation, make sure to check "Add CMake to system PATH for all users" when prompted.
+
+### Running CMake to Generate Build Files
+
+Run Command Prompt from Start and run the following commands:
+```
+cd "%LAUNCHER_DIR%"
+mkdir build
+cd build
+cmake .. -G "Visual Studio 15 Win64" -T v140
+```
+
+Where `%LAUNCHER_DIR%` is the directory for the PC light launcher repository.
diff --git a/launchers/win32/CMakeLists.txt b/launchers/win32/CMakeLists.txt
new file mode 100644
index 0000000000..4d2618c9bf
--- /dev/null
+++ b/launchers/win32/CMakeLists.txt
@@ -0,0 +1,68 @@
+cmake_minimum_required(VERSION 3.9.2)
+
+project(HQLauncher)
+
+set(CMAKE_CONFIGURATION_TYPES "Debug;Release"
+ CACHE STRING "Configuration types" FORCE)
+
+# Use of MFC
+set(CMAKE_MFC_FLAG 1)
+
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
+
+add_executable(HQLauncher
+ WIN32
+ libs/json/json.h
+ libs/json/json-forwards.h
+ libs/jsoncpp.cpp
+ LauncherApp.cpp
+ LauncherApp.h
+ Launcher.rc
+ LauncherDlg.cpp
+ LauncherDlg.h
+ LauncherManager.cpp
+ LauncherManager.h
+ LauncherUtils.cpp
+ LauncherUtils.h
+ libs/miniz.cpp
+ libs/miniz.h
+ res/HiFi_Logo_Large.png
+ res/HiFi_Logo_Small.png
+ res/HiFi_Voxel.png
+ res/HiFi_Window.png
+ res/interface.ico
+ res/Launcher.rc2
+ Resource.h
+ stdafx.cpp
+ stdafx.h
+ targetver.h
+)
+
+target_compile_definitions(HQLauncher PRIVATE LAUNCHER_HMAC_SECRET=$ENV{LAUNCHER_HMAC_SECRET})
+
+# Preprocessor definitions
+target_compile_definitions(HQLauncher PRIVATE
+ $<$:_UNICODE;_WINDOWS;_DEBUG>
+ $<$:_UNICODE;_WINDOWS;NDEBUG>
+)
+
+# Minimal rebuild
+if (MSVC)
+ target_compile_options(HQLauncher PRIVATE
+ "$<$:/Gm->"
+ "$<$:/Gm->"
+ )
+endif ()
+
+# Precompiled header files
+if (MSVC)
+ target_compile_options(HQLauncher PRIVATE
+ "$<$:/Yu>"
+ "$<$:/Yu>"
+ )
+ set_property(SOURCE stdafx.cpp
+ APPEND_STRING PROPERTY COMPILE_FLAGS
+ "$<$:/Yc> \
+ $<$:/Yc>")
+endif ()
diff --git a/launchers/win32/Launcher.rc b/launchers/win32/Launcher.rc
new file mode 100644
index 0000000000..49f3ca53c5
--- /dev/null
+++ b/launchers/win32/Launcher.rc
@@ -0,0 +1,214 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#ifndef APSTUDIO_INVOKED
+#include "targetver.h"
+#endif
+#include "afxres.h"
+#include "verrsrc.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#ifndef APSTUDIO_INVOKED\r\n"
+ "#include ""targetver.h""\r\n"
+ "#endif\r\n"
+ "#include ""afxres.h""\r\n"
+ "#include ""verrsrc.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#include ""res\\Launcher.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "#endif\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON "res\\interface.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// BINARY
+//
+
+IDR_FONT_REGULAR BINARY "res\\Graphikregular.ttf"
+
+IDR_FONT_BOLD BINARY "res\\Graphikbold.ttf"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_LAUNCHER_DIALOG DIALOGEX 0, 0, 300, 196
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_APPWINDOW
+FONT 10, "MS Shell Dlg", 400, 0, 0x0
+BEGIN
+ CONTROL "",IDC_VOXEL,"Static",SS_BLACKRECT,65,27,174,123
+ EDITTEXT IDC_ORGNAME,44,68,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
+ EDITTEXT IDC_USERNAME,44,95,219,12,ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
+ EDITTEXT IDC_PASSWORD,44,122,219,12,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE | NOT WS_BORDER
+ LTEXT "Organization name",IDC_ORGNAME_BANNER,48,68,219,12,NOT WS_VISIBLE
+ LTEXT "Username",IDC_USERNAME_BANNER,48,95,219,12,NOT WS_VISIBLE
+ LTEXT "Password",IDC_PASSWORD_BANNER,48,122,219,12,NOT WS_VISIBLE
+ CTEXT "",IDC_MESSAGE_LABEL,5,39,299,23,NOT WS_VISIBLE
+ CTEXT "",IDC_ACTION_LABEL,10,15,286,25,NOT WS_VISIBLE
+ CTEXT "",IDC_MESSAGE2_LABEL,35,172,239,15,NOT WS_VISIBLE
+ CTEXT "",IDC_ACTION2_LABEL,15,147,278,25,NOT WS_VISIBLE
+ RTEXT "",IDC_TERMS,15,172,180,15,NOT WS_VISIBLE
+ LTEXT "",IDC_TERMS2,197,172,80,15,NOT WS_VISIBLE
+ CTEXT "",IDC_TROUBLE,65,203,174,15,NOT WS_VISIBLE
+ CONTROL "NEXT",IDC_BUTTON_NEXT,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,107,158,94,16
+ CONTROL "Having Trouble?",IDC_TROUBLE_LINK,"Button",BS_OWNERDRAW | BS_FLAT | NOT WS_VISIBLE | WS_TABSTOP,126,203,56,11
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0"
+ BEGIN
+ VALUE "CompanyName", "High Fidelity Inc."
+ VALUE "FileDescription", "HQ Launcher"
+ VALUE "FileVersion", "1.0.0.1"
+ VALUE "InternalName", "HQ Launcher"
+ VALUE "LegalCopyright", "High Fidelity Inc. All rights reserved."
+ VALUE "OriginalFilename", "HQ Launcher.exe"
+ VALUE "ProductName", "HQ Launcher"
+ VALUE "ProductVersion", "0.0.8.5"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_LAUNCHER_DIALOG, DIALOG
+ BEGIN
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// AFX_DIALOG_LAYOUT
+//
+
+IDD_LAUNCHER_DIALOG AFX_DIALOG_LAYOUT
+BEGIN
+ 0
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PNG
+//
+
+IDB_PNG1 PNG "res\\HiFi_Window.png"
+
+IDB_PNG2 PNG "res\\HiFi_Logo_Large.png"
+
+IDB_PNG4 PNG "res\\HiFi_Voxel.png"
+
+IDB_PNG5 PNG "res\\HiFi_Logo_Small.png"
+
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#include "res\Launcher.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/launchers/win32/LauncherApp.cpp b/launchers/win32/LauncherApp.cpp
new file mode 100644
index 0000000000..a8c69de166
--- /dev/null
+++ b/launchers/win32/LauncherApp.cpp
@@ -0,0 +1,91 @@
+//
+// LauncherApp.cpp
+//
+// Created by Luis Cuenca on 6/5/2019.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "stdafx.h"
+#include "LauncherApp.h"
+#include "LauncherDlg.h"
+#include "LauncherManager.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+// CLauncherApp
+
+BEGIN_MESSAGE_MAP(CLauncherApp, CWinApp)
+ ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+CLauncherApp::CLauncherApp(){}
+
+// The one and only CLauncherApp object
+
+CLauncherApp theApp;
+
+// CLauncherApp initialization
+
+BOOL CLauncherApp::InitInstance() {
+ // don't launch if already running
+ CreateMutex(NULL, TRUE, _T("HQ_Launcher_Mutex"));
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ return FALSE;
+ }
+ int iNumOfArgs;
+ LPWSTR* pArgs = CommandLineToArgvW(GetCommandLine(), &iNumOfArgs);
+ if (iNumOfArgs > 1 && CString(pArgs[1]).Compare(_T("--uninstall")) == 0) {
+ _manager.uninstall();
+ } else {
+ _manager.init();
+ }
+ if (!_manager.installLauncher()) {
+ return FALSE;
+ }
+ installFont(IDR_FONT_REGULAR);
+ installFont(IDR_FONT_BOLD);
+ CWinApp::InitInstance();
+
+ SetRegistryKey(_T("HQ High Fidelity"));
+
+ CLauncherDlg dlg;
+ m_pMainWnd = &dlg;
+ INT_PTR nResponse = dlg.DoModal();
+
+#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
+ ControlBarCleanUp();
+#endif
+
+ // Since the dialog has been closed, return FALSE so that we exit the
+ // application, rather than start the application's message pump.
+ return FALSE;
+}
+
+
+
+BOOL CLauncherApp::installFont(int fontID) {
+ HINSTANCE hResInstance = AfxGetResourceHandle();
+ HRSRC res = FindResource(hResInstance,
+ MAKEINTRESOURCE(fontID), L"BINARY");
+ if (res) {
+ HGLOBAL mem = LoadResource(hResInstance, res);
+ void *data = LockResource(mem);
+ DWORD len = (DWORD)SizeofResource(hResInstance, res);
+
+ DWORD nFonts;
+ auto m_fonthandle = AddFontMemResourceEx(
+ data, // font resource
+ len, // number of bytes in font resource
+ NULL, // Reserved. Must be 0.
+ &nFonts // number of fonts installed
+ );
+
+ return (m_fonthandle != 0);
+ }
+ return FALSE;
+}
diff --git a/launchers/win32/LauncherApp.h b/launchers/win32/LauncherApp.h
new file mode 100644
index 0000000000..8232acb249
--- /dev/null
+++ b/launchers/win32/LauncherApp.h
@@ -0,0 +1,32 @@
+//
+// LauncherApp.h
+//
+// Created by Luis Cuenca on 6/5/2019.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+
+#ifndef __AFXWIN_H__
+ #error "include 'stdafx.h' before including this file for PCH"
+#endif
+
+#include "resource.h" // main symbols
+#include "LauncherManager.h"
+
+class CLauncherApp : public CWinApp
+{
+public:
+ CLauncherApp();
+ virtual BOOL InitInstance();
+ void setDialogOnFront() { SetWindowPos(m_pMainWnd->GetSafeHwnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); }
+ LauncherManager _manager;
+private:
+ BOOL installFont(int fontID);
+ DECLARE_MESSAGE_MAP()
+};
+
+extern CLauncherApp theApp;
diff --git a/launchers/win32/LauncherDlg.cpp b/launchers/win32/LauncherDlg.cpp
new file mode 100644
index 0000000000..f6acbce014
--- /dev/null
+++ b/launchers/win32/LauncherDlg.cpp
@@ -0,0 +1,624 @@
+//
+// LauncherDlg.cpp
+//
+// Created by Luis Cuenca on 6/5/2019.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "stdafx.h"
+#include "LauncherApp.h"
+#include "LauncherDlg.h"
+
+#include
+#pragma comment(lib, "d2d1")
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+static int ACTION_FONT_SIZE = 40;
+static int MESSAGE_FONT_SIZE = 19;
+static int FIELDS_FONT_SIZE = 24;
+static int BUTTON_FONT_SIZE = 25;
+static int TERMS_FONT_SIZE = 17;
+static int TROUBLE_FONT_SIZE = 14;
+
+static COLORREF COLOR_GREY = RGB(120, 120, 120);
+static COLORREF COLOR_BLACK= RGB(0, 0, 0);
+static COLORREF COLOR_WHITE = RGB(255, 255, 255);
+static COLORREF COLOR_LIGHTER_GREY = RGB(230, 230, 230);
+static COLORREF COLOR_LIGHT_GREY = RGB(200, 200, 200);
+static COLORREF COLOR_BLUE = RGB(50, 160, 200);
+
+static CString GRAPHIK_REGULAR = _T("Graphik-Regular");
+static CString GRAPHIK_SEMIBOLD = _T("Graphik-Semibold");
+
+static CString TROUBLE_URL = _T("https://www.highfidelity.com/hq-support");
+
+
+CLauncherDlg::CLauncherDlg(CWnd* pParent)
+ : CDialog(IDD_LAUNCHER_DIALOG, pParent)
+{
+ m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+ EnableD2DSupport();
+}
+
+void CLauncherDlg::DoDataExchange(CDataExchange* pDX)
+{
+ DDX_Control(pDX, IDC_BUTTON_NEXT, m_btnNext);
+ DDX_Control(pDX, IDC_TROUBLE_LINK, m_trouble_link);
+ DDX_Control(pDX, IDC_ORGNAME, m_orgname);
+ DDX_Control(pDX, IDC_USERNAME, m_username);
+ DDX_Control(pDX, IDC_PASSWORD, m_password);
+ CDialog::DoDataExchange(pDX);
+}
+
+BEGIN_MESSAGE_MAP(CLauncherDlg, CDialog)
+ ON_WM_PAINT()
+ ON_WM_QUERYDRAGICON()
+ ON_WM_TIMER()
+ ON_EN_SETFOCUS(IDC_ORGNAME, &CLauncherDlg::OnOrgEditChangeFocus)
+ ON_EN_SETFOCUS(IDC_USERNAME, &CLauncherDlg::OnUserEditChangeFocus)
+ ON_EN_SETFOCUS(IDC_PASSWORD, &CLauncherDlg::OnPassEditChangeFocus)
+ ON_BN_CLICKED(IDC_BUTTON_NEXT, &CLauncherDlg::OnNextClicked)
+ ON_BN_CLICKED(IDC_TROUBLE_LINK, &CLauncherDlg::OnTroubleClicked)
+ ON_WM_CTLCOLOR()
+ ON_WM_DRAWITEM()
+ ON_WM_SETCURSOR()
+END_MESSAGE_MAP()
+
+// CLauncherDlg message handlers
+
+BOOL CLauncherDlg::OnInitDialog() {
+ CDialog::OnInitDialog();
+
+ SetIcon(m_hIcon, TRUE); // Set big icon
+ SetIcon(m_hIcon, FALSE); // Set small icon
+
+ CFont editFont;
+ if (LauncherUtils::getFont(GRAPHIK_REGULAR, FIELDS_FONT_SIZE, true, editFont)) {
+ m_orgname.SetFont(&editFont);
+ m_username.SetFont(&editFont);
+ m_password.SetFont(&editFont);
+ }
+ CFont buttonFont;
+ if (LauncherUtils::getFont(_T("Graphik-Bold"), BUTTON_FONT_SIZE, true, buttonFont)) {
+ m_btnNext.SetFont(&editFont);
+ }
+
+ m_message_label = (CStatic *)GetDlgItem(IDC_MESSAGE_LABEL);
+ m_action_label = (CStatic *)GetDlgItem(IDC_ACTION_LABEL);
+ m_message2_label = (CStatic *)GetDlgItem(IDC_MESSAGE2_LABEL);
+ m_action2_label = (CStatic *)GetDlgItem(IDC_ACTION2_LABEL);
+
+ m_orgname_banner = (CStatic *)GetDlgItem(IDC_ORGNAME_BANNER);
+ m_username_banner = (CStatic *)GetDlgItem(IDC_USERNAME_BANNER);
+ m_password_banner = (CStatic *)GetDlgItem(IDC_PASSWORD_BANNER);
+
+ m_terms = (CStatic *)GetDlgItem(IDC_TERMS);
+ m_terms2 = (CStatic *)GetDlgItem(IDC_TERMS2);
+ m_trouble = (CStatic *)GetDlgItem(IDC_TROUBLE);
+
+ m_voxel = (CStatic *)GetDlgItem(IDC_VOXEL);
+
+ m_voxel->EnableD2DSupport();
+
+ m_pRenderTarget = GetRenderTarget();
+
+ SetTimer(1, 2, NULL);
+
+ return TRUE;
+}
+
+BOOL CLauncherDlg::PreTranslateMessage(MSG* pMsg) {
+ if ((pMsg->message == WM_KEYDOWN))
+ {
+ if (pMsg->wParam == VK_RETURN)
+ {
+ OnNextClicked();
+ return TRUE;
+ }
+ }
+ return CDialog::PreTranslateMessage(pMsg);
+}
+
+void CLauncherDlg::setCustomDialog() {
+
+ LONG lStyle = GetWindowLong(GetSafeHwnd(), GWL_STYLE);
+ lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SYSMENU);
+ SetWindowLong(GetSafeHwnd(), GWL_STYLE, lStyle);
+
+ LONG lExStyle = GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);
+ lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
+ SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, lExStyle);
+
+ SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
+ // theApp.setDialogOnFront();
+}
+
+void CLauncherDlg::OnPaint()
+{
+ CPaintDC dc(this);
+ setCustomDialog();
+ CDialog::OnPaint();
+}
+
+// The system calls this function to obtain the cursor to display while the user drags
+// the minimized window.
+HCURSOR CLauncherDlg::OnQueryDragIcon()
+{
+ return static_cast(m_hIcon);
+}
+
+void CLauncherDlg::startProcess() {
+ if (theApp._manager.needsUpdate()) {
+ setDrawDialog(DrawStep::DrawProcessUpdate);
+ } else {
+ setDrawDialog(DrawStep::DrawProcessSetup);
+ }
+
+ CString installDir;
+ theApp._manager.getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installDir);
+ CString interfaceExe = installDir += "\\interface.exe";
+ if (!theApp._manager.isLoggedIn()) {
+ theApp._manager.downloadContent();
+ } else {
+ theApp._manager.downloadApplication();
+ }
+}
+
+#define str(s) #s
+#define LAUNCHER_HMAC_SECRET_STRING str(LAUNCHER_HMAC_SECRET)
+
+BOOL CLauncherDlg::getHQInfo(const CString& orgname) {
+ CString hash;
+ LauncherUtils::hMac256(orgname, LAUNCHER_HMAC_SECRET_STRING, hash);
+ return theApp._manager.readOrganizationJSON(hash) == LauncherUtils::ResponseError::NoError;
+}
+
+afx_msg void CLauncherDlg::OnTroubleClicked() {
+ ShellExecute(0, NULL, TROUBLE_URL, NULL, NULL, SW_SHOWDEFAULT);
+}
+
+afx_msg void CLauncherDlg::OnNextClicked() {
+ if (_drawStep != DrawStep::DrawChoose) {
+ CString token;
+ CString username, password, orgname;
+ m_orgname.GetWindowTextW(orgname);
+ m_username.GetWindowTextW(username);
+ m_password.GetWindowTextW(password);
+ LauncherUtils::ResponseError error;
+ if (orgname.GetLength() > 0 && username.GetLength() > 0 && password.GetLength() > 0) {
+ if (getHQInfo(orgname)) {
+ error = theApp._manager.getAccessTokenForCredentials(username, password);
+ if (error == LauncherUtils::ResponseError::NoError) {
+ setDrawDialog(DrawStep::DrawChoose);
+ } else if (error == LauncherUtils::ResponseError::BadCredentials) {
+ setDrawDialog(DrawStep::DrawLoginErrorCred);
+ } else {
+ MessageBox(L"Error Reading or retreaving response.", L"Network Error", MB_OK | MB_ICONERROR);
+ }
+ } else {
+ setDrawDialog(DrawStep::DrawLoginErrorOrg);
+ }
+ }
+ } else {
+ CString displayName;
+ m_username.GetWindowTextW(displayName);
+ theApp._manager.setDisplayName(displayName);
+ startProcess();
+ }
+}
+
+void CLauncherDlg::drawBackground(CHwndRenderTarget* pRenderTarget) {
+ CD2DBitmap m_pBitmamBackground(pRenderTarget, IDB_PNG1, _T("PNG"));
+ auto size = pRenderTarget->GetSize();
+ CD2DRectF backRec(0.0f, 0.0f, size.width, size.height);
+ pRenderTarget->DrawBitmap(&m_pBitmamBackground, backRec);
+}
+
+void CLauncherDlg::drawLogo(CHwndRenderTarget* pRenderTarget) {
+ CD2DBitmap m_pBitmamLogo(pRenderTarget, IDB_PNG2, _T("PNG"));
+ auto size = pRenderTarget->GetSize();
+ int logoWidth = 231;
+ int logoHeight = 181;
+ float logoPosX = 0.5f * (size.width - logoWidth);
+ float logoPosY = 0.95f * (size.height - logoHeight);
+ CD2DRectF logoRec(logoPosX, logoPosY, logoPosX + logoWidth, logoPosY + logoHeight);
+ pRenderTarget->DrawBitmap(&m_pBitmamLogo, logoRec);
+}
+
+void CLauncherDlg::drawSmallLogo(CHwndRenderTarget* pRenderTarget) {
+ CD2DBitmap m_pBitmamLogo(pRenderTarget, IDB_PNG5, _T("PNG"));
+ auto size = pRenderTarget->GetSize();
+ int padding = 6;
+ int logoWidth = 100;
+ int logoHeight = 18;
+ float logoPosX = size.width - logoWidth - padding;
+ float logoPosY = size.height - logoHeight - padding;
+ CD2DRectF logoRec(logoPosX, logoPosY, logoPosX + logoWidth, logoPosY + logoHeight);
+ pRenderTarget->DrawBitmap(&m_pBitmamLogo, logoRec);
+}
+
+void CLauncherDlg::drawVoxel(CHwndRenderTarget* pRenderTarget) {
+ CD2DBitmap m_pBitmamVoxel(pRenderTarget, IDB_PNG4, _T("PNG"));
+ auto size = pRenderTarget->GetSize();
+ int logoWidth = 132;
+ int logoHeight = 134;
+ float voxelPosX = 0.5f * (size.width - logoWidth);
+ float voxelPosY = 0.5f * (size.height - logoHeight);
+ CD2DRectF voxelRec(voxelPosX, voxelPosY, voxelPosX + logoWidth, voxelPosY + logoHeight);
+ auto midPoint = D2D1::Point2F(0.5f * size.width, 0.5f * size.height);
+ _logoRotation += 2.0f;
+ CD2DSolidColorBrush brush(pRenderTarget, D2D1::ColorF(0.0f, 0.0f, 0.0f));
+ pRenderTarget->SetTransform(D2D1::Matrix3x2F::Rotation(_logoRotation - 2.0f, midPoint));
+ pRenderTarget->FillRectangle(voxelRec, &brush);
+ pRenderTarget->SetTransform(D2D1::Matrix3x2F::Rotation(_logoRotation, midPoint));
+ pRenderTarget->DrawBitmap(&m_pBitmamVoxel, voxelRec);
+ pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
+}
+
+
+void CLauncherDlg::showWindows(std::vector windows, bool show) {
+ for (auto window : windows) {
+ window->ShowWindow(show ? SW_SHOW : SW_HIDE);
+ }
+}
+
+void CLauncherDlg::prepareLogin(DrawStep step) {
+ m_voxel->ShowWindow(SW_HIDE);
+ m_orgname_banner->SetWindowTextW(_T("Organization Name"));
+ m_username_banner->SetWindowTextW(_T("Username"));
+ m_password_banner->SetWindowTextW(_T("Password"));
+ CString editText;
+ m_orgname.GetWindowTextW(editText);
+ m_orgname_banner->ShowWindow(editText.GetLength() == 0 ? SW_SHOW : SW_HIDE);
+ m_username.GetWindowTextW(editText);
+ m_username_banner->ShowWindow(editText.GetLength() == 0 ? SW_SHOW : SW_HIDE);
+ m_password.GetWindowTextW(editText);
+ m_password_banner->ShowWindow(editText.GetLength() == 0 ? SW_SHOW : SW_HIDE);
+ m_orgname.ShowWindow(SW_SHOW);
+ m_username.ShowWindow(SW_SHOW);
+ m_password.ShowWindow(SW_SHOW);
+ CString actionText = step == DrawStep::DrawLoginLogin ? _T("Please log in") : _T("Uh-oh, we have a problem");
+ CString messageText = step == DrawStep::DrawLoginLogin ? _T("Be sure you've uploaded your Avatar before signing in.") :
+ step == DrawStep::DrawLoginErrorCred ? _T("There is a problem with your credentials\n please try again.") : _T("There is a problem with your Organization name\n please try again.");
+ m_action_label->SetWindowTextW(actionText);
+ m_message_label->SetWindowTextW(messageText);
+ m_action_label->ShowWindow(SW_SHOW);
+ m_message_label->ShowWindow(SW_SHOW);
+ m_btnNext.ShowWindow(SW_SHOW);
+ m_trouble->SetWindowTextW(_T("Having Trouble?"));
+ m_trouble->ShowWindow(SW_SHOW);
+ m_trouble_link.ShowWindow(SW_SHOW);
+
+}
+
+
+void CLauncherDlg::prepareChoose() {
+ m_orgname.ShowWindow(SW_HIDE);
+ m_username.SetWindowTextW(_T(""));
+ m_username_banner->SetWindowTextW(_T("Display Name"));
+ CString editText;
+ m_username.GetWindowTextW(editText);
+ m_username_banner->ShowWindow(editText.GetLength() == 0 ? SW_SHOW : SW_HIDE);
+ m_password.ShowWindow(SW_HIDE);
+ m_orgname_banner->ShowWindow(SW_HIDE);
+ m_password_banner->ShowWindow(SW_HIDE);
+ m_action_label->SetWindowTextW(_T("Choose a display name"));
+ m_message_label->SetWindowTextW(_T("This is the name that your teammates will see."));
+ m_terms->ShowWindow(SW_SHOW);
+ m_terms2->ShowWindow(SW_SHOW);
+ m_terms->SetWindowTextW(_T("By signing in, you agree to the High Fidelity"));
+ m_terms2->SetWindowTextW(_T("Terms of Service"));
+ CRect rec;
+ m_btnNext.GetWindowRect(&rec);
+ ScreenToClient(&rec);
+ if (rec.top > 281) {
+ rec.bottom -= 35;
+ rec.top -= 35;
+ m_btnNext.MoveWindow(rec, FALSE);
+ }
+ m_btnNext.ShowWindow(SW_SHOW);
+}
+
+void CLauncherDlg::prepareProcess(DrawStep step) {
+ m_trouble->ShowWindow(SW_HIDE);
+ m_trouble_link.ShowWindow(SW_HIDE);
+ m_terms->ShowWindow(SW_HIDE);
+ m_terms2->ShowWindow(SW_HIDE);
+ m_orgname_banner->ShowWindow(SW_HIDE);
+ m_username_banner->ShowWindow(SW_HIDE);
+ m_password_banner->ShowWindow(SW_HIDE);
+ m_orgname.ShowWindow(SW_HIDE);
+ m_username.ShowWindow(SW_HIDE);
+ m_password.ShowWindow(SW_HIDE);
+ m_action_label->SetWindowTextW(_T(""));
+ m_message_label->SetWindowTextW(_T(""));
+ m_btnNext.ShowWindow(SW_HIDE);
+ m_action_label->ShowWindow(SW_HIDE);
+ m_message_label->ShowWindow(SW_HIDE);
+ m_voxel->ShowWindow(SW_SHOW);
+ CString actionText = _T("");
+ CString messageText = _T("");
+ switch (step) {
+ case DrawStep::DrawProcessSetup:
+ actionText = _T("We're building your virtual HQ");
+ messageText = _T("Set up may take several minutes.");
+ break;
+ case DrawStep::DrawProcessUpdate:
+ actionText = _T("Getting updates...");
+ messageText = _T("We're getting the latest and greatest for you, one sec.");
+ break;
+ case DrawStep::DrawProcessFinishHq:
+ actionText = _T("Your new HQ is all setup");
+ messageText = _T("Thanks for being patient.");
+ break;
+ case DrawStep::DrawProcessFinishUpdate:
+ actionText = _T("You're good to go!");
+ messageText = _T("Thanks for being patient.");
+ break;
+ case DrawStep::DrawProcessUninstall:
+ actionText = _T("Uninstalling...");
+ messageText = _T("It'll take one sec.");
+ break;
+ }
+ m_action2_label->SetWindowTextW(actionText);
+ m_message2_label->SetWindowTextW(messageText);
+ m_action2_label->ShowWindow(SW_SHOW);
+ m_message2_label->ShowWindow(SW_SHOW);
+}
+
+void CLauncherDlg::prepareError() {
+}
+
+BOOL CLauncherDlg::getTextFormat(int resID, TextFormat& formatOut) {
+ // Set default values for message
+ BOOL isText = TRUE;
+ formatOut.color = COLOR_LIGHT_GREY;
+ formatOut.isBold = false;
+ formatOut.isButton = false;
+ formatOut.size = MESSAGE_FONT_SIZE;
+ formatOut.underlined = false;
+
+ switch (resID) {
+ case IDC_VOXEL:
+ case IDD_LAUNCHER_DIALOG:
+ isText = FALSE;
+ case IDC_MESSAGE_LABEL:
+ case IDC_MESSAGE2_LABEL:
+ // Default values
+ break;
+ case IDC_ACTION_LABEL:
+ case IDC_ACTION2_LABEL:
+ formatOut.size = ACTION_FONT_SIZE;
+ formatOut.isBold = true;
+ formatOut.color = COLOR_LIGHTER_GREY;
+ break;
+ case IDC_USERNAME:
+ case IDC_PASSWORD:
+ case IDC_ORGNAME:
+ formatOut.color = COLOR_WHITE;
+ formatOut.size = FIELDS_FONT_SIZE;
+ formatOut.underlined = true;
+ break;
+ case IDC_USERNAME_BANNER:
+ case IDC_PASSWORD_BANNER:
+ case IDC_ORGNAME_BANNER:
+ formatOut.size = FIELDS_FONT_SIZE;
+ formatOut.color = COLOR_GREY;
+ break;
+ case IDC_TERMS:
+ formatOut.size = TERMS_FONT_SIZE;
+ break;
+ case IDC_TERMS2:
+ formatOut.size = TERMS_FONT_SIZE;
+ formatOut.isBold = true;
+ break;
+ case IDC_TROUBLE:
+ formatOut.size = TROUBLE_FONT_SIZE;
+ formatOut.color = COLOR_BLUE;
+ break;
+ }
+ return isText;
+}
+
+HBRUSH CLauncherDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+
+ HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
+ TextFormat textFormat;
+ int resId = pWnd->GetDlgCtrlID();
+ if (getTextFormat(resId, textFormat)) {
+ pDC->SetTextColor(textFormat.color);
+ pDC->SetBkMode(TRANSPARENT);
+ CFont textFont;
+ CString fontFamily = textFormat.isBold ? GRAPHIK_SEMIBOLD : GRAPHIK_REGULAR;
+ if (LauncherUtils::getFont(fontFamily, textFormat.size, textFormat.isBold, textFont)) {
+ pDC->SelectObject(&textFont);
+ }
+ if (textFormat.underlined) {
+ CRect rect;
+ pWnd->GetClientRect(&rect);
+ int borderThick = 1;
+ int padding = 4;
+ CRect lineRect = CRect(rect.left + padding, rect.bottom, rect.right - padding, rect.bottom + borderThick);
+ lineRect.MoveToY(lineRect.bottom + 1);
+ pDC->FillSolidRect(lineRect, COLOR_GREY);
+ }
+ }
+ return (HBRUSH)GetStockObject(BLACK_BRUSH);
+}
+
+void CLauncherDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
+{
+ CDC dc;
+ dc.Attach(lpDrawItemStruct->hDC);
+ CRect rect = lpDrawItemStruct->rcItem;
+ CRect defrect = rect;
+ CString btnName = _T("");
+ int xpan = 0;
+ if (nIDCtl == IDC_BUTTON_NEXT) {
+ if (_drawStep == DrawStep::DrawChoose || _drawStep == DrawStep::DrawLoginLogin) {
+ btnName += _drawStep == DrawStep::DrawLoginLogin ? _T("NEXT") : _T("LOG IN");
+ int xpan = -20;
+ defrect = CRect(rect.left - xpan, rect.top, rect.right + xpan, rect.bottom);
+ } else {
+ btnName += _T("TRY AGAIN");
+ }
+ int borderThick = 2;
+ dc.FillSolidRect(rect, COLOR_BLACK);
+ dc.FillSolidRect(defrect, COLOR_WHITE);
+ defrect.DeflateRect(borderThick, borderThick, borderThick, borderThick);
+ dc.FillSolidRect(defrect, COLOR_BLACK);
+ UINT state = lpDrawItemStruct->itemState;
+ dc.SetTextColor(COLOR_WHITE);
+
+ CFont buttonFont;
+ if (LauncherUtils::getFont(GRAPHIK_SEMIBOLD, BUTTON_FONT_SIZE, true, buttonFont)) {
+ dc.SelectObject(buttonFont);
+ }
+ dc.DrawText(btnName, CRect(rect.left, rect.top + 4, rect.right, rect.bottom - 8), DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+ dc.Detach();
+ } else if (nIDCtl == IDC_TROUBLE_LINK) {
+ dc.FillSolidRect(rect, COLOR_BLACK);
+ dc.SetTextColor(COLOR_BLUE);
+ CFont buttonFont;
+ if (LauncherUtils::getFont(GRAPHIK_SEMIBOLD, TROUBLE_FONT_SIZE, true, buttonFont)) {
+ dc.SelectObject(buttonFont);
+ }
+ dc.DrawText(_T("Having Trouble"), CRect(rect.left, rect.top, rect.right, rect.bottom), DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+ }
+
+}
+
+void CLauncherDlg::redrawBanner(const CEdit& edit, CStatic* banner) {
+ CString editText;
+ edit.GetWindowTextW(editText);
+ if (editText.GetLength() == 0) {
+ banner->Invalidate();
+ }
+}
+
+void CLauncherDlg::OnOrgEditChangeFocus() {
+ redrawBanner(m_username, m_username_banner);
+ redrawBanner(m_password, m_password_banner);
+}
+
+void CLauncherDlg::OnUserEditChangeFocus() {
+ redrawBanner(m_orgname, m_orgname_banner);
+ redrawBanner(m_password, m_password_banner);
+}
+
+void CLauncherDlg::OnPassEditChangeFocus() {
+ redrawBanner(m_orgname, m_orgname_banner);
+ redrawBanner(m_username, m_username_banner);
+}
+BOOL CLauncherDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+ if (pWnd->IsKindOf(RUNTIME_CLASS(CButton))) {
+ ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_HAND));
+ return TRUE;
+ }
+ return CDialog::OnSetCursor(pWnd, nHitTest, message);
+}
+
+void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
+ const int CONSOLE_MAX_SHUTDOWN_TRY_COUNT = 10;
+ const int CONSOLE_DELTATIME_BETWEEN_TRYS = 10;
+ if (_drawStep == DrawStep::DrawProcessSetup ||
+ _drawStep == DrawStep::DrawProcessUpdate ||
+ _drawStep == DrawStep::DrawProcessUninstall) {
+ // Refresh
+ setDrawDialog(_drawStep, true);
+ }
+ if (_showSplash) {
+ if (_splashStep == 0){
+ if (theApp._manager.needsUninstall()) {
+ setDrawDialog(DrawStep::DrawProcessUninstall);
+ } else {
+ setDrawDialog(DrawStep::DrawLogo);
+ }
+ } else if (_splashStep > 100) {
+ _showSplash = false;
+ if (theApp._manager.shouldShutDown()) {
+ if (LauncherUtils::IsProcessRunning(L"interface.exe")) {
+ exit(0);
+ }
+ } else if (theApp._manager.needsUpdate()) {
+ startProcess();
+ } else if (theApp._manager.needsUninstall()) {
+ theApp._manager.uninstallApplication();
+ exit(0);
+ } else {
+ setDrawDialog(DrawStep::DrawLoginLogin);
+ }
+ }
+ _splashStep++;
+ } else if (theApp._manager.shouldShutDown()) {
+ if (LauncherUtils::IsProcessRunning(L"interface.exe")) {
+ exit(0);
+ }
+ }
+}
+
+void CLauncherDlg::setDrawDialog(DrawStep step, BOOL isUpdate) {
+ _drawStep = step;
+ auto m_pRenderTarget = GetRenderTarget();
+ auto m_voxelRenderTarget = m_voxel->GetRenderTarget();
+ switch (_drawStep) {
+ case DrawStep::DrawLogo:
+ m_pRenderTarget->BeginDraw();
+ drawBackground(m_pRenderTarget);
+ m_pRenderTarget->EndDraw();
+ m_voxelRenderTarget->BeginDraw();
+ drawLogo(m_voxelRenderTarget);
+ m_voxelRenderTarget->EndDraw();
+ break;
+ case DrawStep::DrawLoginLogin:
+ case DrawStep::DrawLoginErrorOrg:
+ case DrawStep::DrawLoginErrorCred:
+ prepareLogin(_drawStep);
+ m_pRenderTarget->BeginDraw();
+ drawBackground(m_pRenderTarget);
+ drawSmallLogo(m_pRenderTarget);
+ m_pRenderTarget->EndDraw();
+ RedrawWindow();
+ break;
+ case DrawStep::DrawChoose:
+ prepareChoose();
+ m_pRenderTarget->BeginDraw();
+ drawBackground(m_pRenderTarget);
+ drawSmallLogo(m_pRenderTarget);
+ m_pRenderTarget->EndDraw();
+ RedrawWindow();
+ break;
+ case DrawStep::DrawProcessFinishHq:
+ case DrawStep::DrawProcessFinishUpdate:
+ case DrawStep::DrawProcessUpdate:
+ case DrawStep::DrawProcessUninstall:
+ case DrawStep::DrawProcessSetup:
+ if (!isUpdate) {
+ m_voxelRenderTarget->BeginDraw();
+ m_voxelRenderTarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 1.0f));
+ m_voxelRenderTarget->EndDraw();
+ m_pRenderTarget->BeginDraw();
+ prepareProcess(_drawStep);
+ drawBackground(m_pRenderTarget);
+ drawSmallLogo(m_pRenderTarget);
+ m_pRenderTarget->EndDraw();
+ RedrawWindow();
+ }
+ m_voxelRenderTarget->BeginDraw();
+ drawVoxel(m_voxelRenderTarget);
+ m_voxelRenderTarget->EndDraw();
+ break;
+ default:
+ break;
+ }
+}
+
+
diff --git a/launchers/win32/LauncherDlg.h b/launchers/win32/LauncherDlg.h
new file mode 100644
index 0000000000..55bc97f205
--- /dev/null
+++ b/launchers/win32/LauncherDlg.h
@@ -0,0 +1,120 @@
+//
+// LauncherDlg.h
+//
+// Created by Luis Cuenca on 6/5/2019.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+
+// CLauncherDlg dialog
+class CLauncherDlg : public CDialog
+{
+ // Construction
+public:
+ enum DrawStep {
+ DrawLogo = 0,
+ DrawLoginLogin,
+ DrawLoginErrorOrg,
+ DrawLoginErrorCred,
+ DrawChoose,
+ DrawProcessSetup,
+ DrawProcessUpdate,
+ DrawProcessFinishHq,
+ DrawProcessFinishUpdate,
+ DrawProcessUninstall,
+ DrawError
+ };
+
+ struct TextFormat {
+ int size;
+ COLORREF color;
+ bool isButton;
+ bool isBold;
+ bool underlined;
+ };
+
+ CLauncherDlg(CWnd* pParent = nullptr);
+ virtual BOOL PreTranslateMessage(MSG* pMsg);
+
+ void setDrawDialog(DrawStep step, BOOL isUpdate = FALSE);
+
+
+// Dialog Data
+#ifdef AFX_DESIGN_TIME
+ enum { IDD = IDD_LAUNCHER_DIALOG };
+#endif
+
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ void startProcess();
+ void setCustomDialog();
+
+// Implementation
+protected:
+
+ BOOL getHQInfo(const CString& orgname);
+ DrawStep _drawStep { DrawStep::DrawLogo };
+ BOOL getTextFormat(int ResID, TextFormat& formatOut);
+ void showWindows(std::vector windows, bool show);
+
+ bool _isConsoleRunning{ false };
+ bool _isInstalling{ false };
+ bool _isFirstDraw{ false };
+ bool _showSplash{ true };
+ int _splashStep{ 0 };
+ float _logoRotation { 0.0f };
+
+ HICON m_hIcon;
+ CButton m_btnNext;
+ CButton m_trouble_link;
+
+ CStatic* m_message_label;
+ CStatic* m_action_label;
+ CStatic* m_message2_label;
+ CStatic* m_action2_label;
+ CStatic* m_terms;
+ CStatic* m_terms2;
+ CStatic* m_trouble;
+ CStatic* m_voxel;
+
+ CEdit m_orgname;
+ CEdit m_username;
+ CEdit m_password;
+
+ CStatic* m_orgname_banner;
+ CStatic* m_username_banner;
+ CStatic* m_password_banner;
+
+ void drawBackground(CHwndRenderTarget* pRenderTarget);
+ void drawLogo(CHwndRenderTarget* pRenderTarget);
+ void drawSmallLogo(CHwndRenderTarget* pRenderTarget);
+ void drawVoxel(CHwndRenderTarget* pRenderTarget);
+
+ void prepareLogin(DrawStep step);
+ void prepareProcess(DrawStep step);
+ void prepareChoose();
+ void prepareError();
+
+ void redrawBanner(const CEdit& edit, CStatic* banner);
+
+ // Generated message map functions
+ virtual BOOL OnInitDialog();
+ afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+ afx_msg void OnPaint();
+ afx_msg HCURSOR OnQueryDragIcon();
+ afx_msg void OnNextClicked();
+ afx_msg void OnTroubleClicked();
+ afx_msg void OnOrgEditChangeFocus();
+ afx_msg void OnUserEditChangeFocus();
+ afx_msg void OnPassEditChangeFocus();
+ afx_msg void OnTimer(UINT_PTR nIDEvent);
+ DECLARE_MESSAGE_MAP()
+
+public:
+ afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
+ afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+};
diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp
new file mode 100644
index 0000000000..94a659a4d7
--- /dev/null
+++ b/launchers/win32/LauncherManager.cpp
@@ -0,0 +1,422 @@
+//
+// LauncherManager.cpp
+//
+// Created by Luis Cuenca on 6/5/2019.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "stdafx.h"
+#include
+
+#include "LauncherManager.h"
+
+
+LauncherManager::LauncherManager()
+{
+}
+
+
+LauncherManager::~LauncherManager()
+{
+}
+
+void LauncherManager::init() {
+ getMostRecentBuild(_latestApplicationURL, _latestVersion);
+ CString currentVersion;
+ if (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn) {
+ if (_latestVersion.Compare(currentVersion) == 0) {
+ launchApplication();
+ _shouldShutdown = TRUE;
+ } else {
+ _shouldUpdate = TRUE;
+ }
+ }
+}
+
+BOOL LauncherManager::installLauncher() {
+ CString appPath;
+ BOOL result = getAndCreatePaths(PathType::Running_Path, appPath);
+ if (!result) {
+ MessageBox(NULL, L"Error getting app directory", L"Path Error", MB_OK | MB_ICONERROR);
+ }
+ CString installDirectory;
+ CString appDirectory = appPath.Left(appPath.ReverseFind('\\') + 1);
+ result = getAndCreatePaths(PathType::Launcher_Directory, installDirectory);
+ if (!result) {
+ MessageBox(NULL, L"Error getting app desired directory", L"Path Error", MB_OK | MB_ICONERROR);
+ }
+
+ CString instalationPath = installDirectory + LAUNCHER_EXE_FILENAME;
+ if (!installDirectory.Compare(appDirectory) == 0) {
+ if (!_shouldUninstall) {
+ // The installer is not running on the desired location and has to be installed
+ // Kill of running before self-copy
+ if (LauncherUtils::IsProcessRunning(LAUNCHER_EXE_FILENAME)) {
+ ::ShellExecute(NULL, NULL, L"taskkill", L"/F /T /IM " + LAUNCHER_EXE_FILENAME, NULL, SW_HIDE);
+ }
+ CopyFile(appPath, instalationPath, FALSE);
+ }
+ } else if (_shouldUninstall) {
+ CString tempPath;
+ if (getAndCreatePaths(PathType::Temp_Directory, tempPath)) {
+ tempPath += _T("\\HQ_uninstaller_tmp.exe");
+ CopyFile(instalationPath, tempPath, false);
+ LauncherUtils::launchApplication(tempPath, _T(" --uninstall"));
+ exit(0);
+ }
+ }
+ return TRUE;
+}
+
+BOOL LauncherManager::createShortcuts() {
+ CString desktopLnkPath;
+ getAndCreatePaths(PathType::Desktop_Directory, desktopLnkPath);
+ desktopLnkPath += _T("\\HQ Launcher.lnk");
+ CString installDir;
+ getAndCreatePaths(PathType::Launcher_Directory, installDir);
+ CString installPath = installDir + LAUNCHER_EXE_FILENAME;
+ if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(desktopLnkPath), _T("CLick to Setup and Launch HQ."))) {
+ return FALSE;
+ }
+ CString startLinkPath;
+ getAndCreatePaths(PathType::StartMenu_Directory, startLinkPath);
+ CString appStartLinkPath = startLinkPath + _T("HQ Launcher.lnk");
+ CString uniStartLinkPath = startLinkPath + _T("Uninstall HQ.lnk");
+ CString uniLinkPath = installDir + _T("Uninstall HQ.lnk");
+ if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(appStartLinkPath), _T("CLick to Setup and Launch HQ."))) {
+ return FALSE;
+ }
+ if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(uniStartLinkPath), _T("CLick to Uninstall HQ."), _T("--uninstall"))) {
+ return FALSE;
+ }
+ if (!LauncherUtils::CreateLink(installPath, (LPCSTR)CStringA(uniLinkPath), _T("CLick to Uninstall HQ."), _T("--uninstall"))) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL LauncherManager::deleteShortcuts() {
+ CString desktopLnkPath;
+ getAndCreatePaths(PathType::Desktop_Directory, desktopLnkPath);
+ desktopLnkPath += _T("\\HQ Launcher.lnk");
+ BOOL success = LauncherUtils::deleteFileOrDirectory(desktopLnkPath);
+ CString startLinkPath;
+ getAndCreatePaths(PathType::StartMenu_Directory, startLinkPath);
+ return success && LauncherUtils::deleteFileOrDirectory(startLinkPath);
+}
+
+BOOL LauncherManager::isApplicationInstalled(CString& version, CString& domain,
+ CString& content, bool& loggedIn) {
+ CString applicationDir;
+ getAndCreatePaths(PathType::Launcher_Directory, applicationDir);
+ CString applicationPath = applicationDir + "interface\\interface.exe";
+ BOOL isApplicationInstalled = PathFileExistsW(applicationPath);
+ BOOL configFileExist = PathFileExistsW(applicationDir + _T("interface\\config.json"));
+ if (isApplicationInstalled && configFileExist) {
+ LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn);
+ return status == LauncherUtils::ResponseError::NoError;
+ }
+ return FALSE;
+}
+
+BOOL LauncherManager::getAndCreatePaths(PathType type, CString& outPath) {
+
+ if (type == PathType::Running_Path) {
+ char appPath[MAX_PATH];
+ DWORD size = GetModuleFileNameA(NULL, appPath, MAX_PATH);
+ if (size) {
+ outPath = CString(appPath);
+ return TRUE;
+ }
+ } else if (type == PathType::Desktop_Directory) {
+ TCHAR desktopPath[MAX_PATH];
+ auto success = SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath));
+ outPath = CString(desktopPath);
+ return success;
+ } else if (type == PathType::Temp_Directory) {
+ TCHAR tempPath[MAX_PATH];
+ auto success = GetTempPath(MAX_PATH, tempPath);
+ outPath = CString(tempPath);
+ return success;
+ } else {
+ TCHAR localDataPath[MAX_PATH];
+ if (type == PathType::StartMenu_Directory) {
+ TCHAR startMenuPath[MAX_PATH];
+ auto success = SUCCEEDED(SHGetFolderPath(NULL, CSIDL_STARTMENU, NULL, 0, startMenuPath));
+ outPath = CString(startMenuPath) + _T("\\Programs\\HQ\\");
+ success = SHCreateDirectoryEx(NULL, outPath, NULL) || ERROR_ALREADY_EXISTS == GetLastError();
+ return success;
+ } else if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, localDataPath))) {
+ _tcscat_s(localDataPath, _T("\\") + DIRECTORY_NAME_APP + _T("\\"));
+ outPath = CString(localDataPath);
+ if (type == PathType::Download_Directory) {
+ outPath += DIRECTORY_NAME_DOWNLOADS + _T("\\");
+ } else if (type == PathType::Interface_Directory) {
+ outPath += DIRECTORY_NAME_INTERFACE;
+ } else if (type == PathType::Content_Directory) {
+ outPath += DIRECTORY_NAME_CONTENT;
+ }
+ return (CreateDirectory(outPath, NULL) || ERROR_ALREADY_EXISTS == GetLastError());
+ }
+ }
+ return FALSE;
+}
+
+BOOL LauncherManager::getInstalledVersion(const CString& path, CString& version) {
+ CStdioFile cfile;
+ BOOL success = cfile.Open(path, CFile::modeRead);
+ if (success) {
+ cfile.ReadString(version);
+ cfile.Close();
+ }
+ return success;
+}
+
+
+BOOL LauncherManager::launchApplication(const CString& tokensJSON) {
+ CString installDir;
+ LauncherManager::getAndCreatePaths(PathType::Interface_Directory, installDir);
+ CString interfaceExe = installDir + _T("\\interface.exe");
+ CString params1 = _T("--url \"") + _domainURL + ("\" ");
+ CString cacheDir;
+ LauncherManager::getAndCreatePaths(PathType::Content_Directory, cacheDir);
+ CString params3 = _T("--cache \"") + cacheDir + ("\" ");
+ CString params4 = !_displayName.IsEmpty() ? _T("--displayName \"") + _displayName + ("\" ") : _T("");
+ CString parsedTokens = tokensJSON;
+ parsedTokens.Replace(_T("\""), _T("\\\""));
+ CString params5 = !tokensJSON.IsEmpty() ? _T("--tokens \"") + parsedTokens + ("\"") : _T("");
+ CString params = params1 + params3 + params4 + params5 + EXTRA_PARAMETERS;
+ auto rs = ShellExecute(NULL, L"open", interfaceExe, params, NULL, SW_SHOW);
+ return (rs != NULL);
+}
+
+BOOL LauncherManager::createConfigJSON() {
+ CString configPath;
+ LauncherManager::getAndCreatePaths(PathType::Interface_Directory, configPath);
+ configPath += "\\config.json";
+ std::ofstream configFile(configPath, std::ofstream::binary);
+ if (configFile.fail()) {
+ return FALSE;
+ }
+ Json::Value config;
+ CString applicationPath;
+ LauncherManager::getAndCreatePaths(PathType::Launcher_Directory, applicationPath);
+ applicationPath += LAUNCHER_EXE_FILENAME;
+ config["loggedIn"] = _loggedIn;
+ config["launcherPath"] = LauncherUtils::cStringToStd(applicationPath);
+ config["version"] = LauncherUtils::cStringToStd(_latestVersion);
+ config["domain"] = LauncherUtils::cStringToStd(_domainURL);
+ CString content;
+ getAndCreatePaths(PathType::Content_Directory, content);
+ config["content"] = LauncherUtils::cStringToStd(content);
+ configFile << config;
+ configFile.close();
+ return TRUE;
+}
+
+LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain, CString& content, bool& loggedIn) {
+ CString configPath;
+ getAndCreatePaths(PathType::Interface_Directory, configPath);
+ configPath += "\\config.json";
+ std::ifstream configFile(configPath, std::ifstream::binary);
+ if (configFile.fail()) {
+ return LauncherUtils::ResponseError::Open;
+ }
+ Json::Value config;
+ configFile >> config;
+ if (config["version"].isString() && config["domain"].isString() &&
+ config["content"].isString()) {
+ loggedIn = config["loggedIn"].asBool();
+ version = config["version"].asCString();
+ domain = config["domain"].asCString();
+ content = config["content"].asCString();
+ configFile.close();
+ return LauncherUtils::ResponseError::NoError;
+ }
+ configFile.close();
+ return LauncherUtils::ResponseError::ParsingJSON;
+}
+
+LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString& hash) {
+ CString contentTypeJson = L"content-type:application/json";
+ CString response;
+ CString url = _T("/hifi-public/huffman/organizations/") + hash + _T(".json");
+ LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"s3.amazonaws.com", url,
+ contentTypeJson, CStringA(), response, false);
+ if (error != LauncherUtils::ResponseError::NoError) {
+ return error;
+ }
+ Json::Value json;
+ if (LauncherUtils::parseJSON(response, json)) {
+ if (json["content_set_url"].isString() && json["domain"].isString()) {
+ _contentURL = json["content_set_url"].asCString();
+ _domainURL = json["domain"].asCString();
+ return LauncherUtils::ResponseError::NoError;
+ }
+ }
+ return LauncherUtils::ResponseError::ParsingJSON;
+}
+
+LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut) {
+ CString contentTypeJson = L"content-type:application/json";
+ CString response;
+ LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"thunder.highfidelity.com", L"/builds/api/tags/latest?format=json",
+ contentTypeJson, CStringA(), response, false);
+ if (error != LauncherUtils::ResponseError::NoError) {
+ return error;
+ }
+ Json::Value json;
+ if (LauncherUtils::parseJSON(response, json)) {
+ int count = json["count"].isInt() ? json["count"].asInt() : 0;
+ if (count > 0 && json["results"].isArray()) {
+ for (int i = 0; i < count; i++) {
+ if (json["results"][i].isObject()) {
+ Json::Value result = json["results"][i];
+ if (result["latest_version"].isInt()) {
+ std::string version = std::to_string(result["latest_version"].asInt());
+ versionOut = CString(version.c_str());
+ }
+ if (result["installers"].isObject() &&
+ result["installers"]["windows"].isObject() &&
+ result["installers"]["windows"]["zip_url"].isString()) {
+ urlOut = result["installers"]["windows"]["zip_url"].asCString();
+ return LauncherUtils::ResponseError::NoError;
+ }
+ }
+ }
+ }
+ }
+ return LauncherUtils::ResponseError::ParsingJSON;
+}
+
+LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username, const CString& password) {
+ CStringA post = "grant_type=password&username=";
+ post += username;
+ post += "&password=";
+ post += password;
+ post += "&scope=owner";
+
+ CString contentTypeText = L"content-type:application/x-www-form-urlencoded";
+ CString response;
+ LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", L"metaverse.highfidelity.com", L"/oauth/token",
+ contentTypeText, post, response, true);
+ if (error != LauncherUtils::ResponseError::NoError) {
+ return error;
+ }
+ Json::Value json;
+ if (LauncherUtils::parseJSON(response, json)) {
+ if (json["error"].isString()) {
+ return LauncherUtils::ResponseError::BadCredentials;
+ } else if (json["access_token"].isString()) {
+ _tokensJSON = response;
+ return LauncherUtils::ResponseError::NoError;
+ }
+ }
+ return LauncherUtils::ResponseError::ParsingJSON;
+}
+
+BOOL LauncherManager::createApplicationRegistryKeys(int size) {
+ const std::string REGISTRY_PATH = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\HQ";
+ BOOL success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "DisplayName", "HQ");
+ CString installDir;
+ getAndCreatePaths(PathType::Launcher_Directory, installDir);
+ success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "InstallLocation", LauncherUtils::cStringToStd(installDir));
+ std::string applicationExe = LauncherUtils::cStringToStd(installDir + LAUNCHER_EXE_FILENAME);
+ std::string uninstallPath = '"' + applicationExe + '"' + " --uninstall";
+ success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "UninstallString", uninstallPath);
+ success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "DisplayVersion", LauncherUtils::cStringToStd(_latestVersion));
+ success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "DisplayIcon", applicationExe);
+ success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "Publisher", "High Fidelity");
+ success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "InstallDate", LauncherUtils::cStringToStd(CTime::GetCurrentTime().Format("%Y%m%d")));
+ success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "EstimatedSize", (DWORD)size);
+ success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "NoModify", (DWORD)1);
+ success = LauncherUtils::insertRegistryKey(REGISTRY_PATH, "NoRepair", (DWORD)1);
+ return success;
+}
+
+BOOL LauncherManager::deleteApplicationRegistryKeys() {
+ const CString REGISTRY_PATH = _T("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\HQ");
+ return LauncherUtils::deleteRegistryKey(REGISTRY_PATH);
+}
+
+BOOL LauncherManager::uninstallApplication() {
+ CString installDir;
+ getAndCreatePaths(PathType::Launcher_Directory, installDir);
+ BOOL success = LauncherUtils::deleteFileOrDirectory(installDir);
+ success = success && (deleteShortcuts());
+ success = success && (deleteApplicationRegistryKeys());
+ return success;
+}
+
+void LauncherManager::onZipExtracted(ZipType type, int size) {
+ if (type == ZipType::ZipContent) {
+ downloadApplication();
+ } else if (type == ZipType::ZipApplication) {
+ createShortcuts();
+ CString versionPath;
+ getAndCreatePaths(LauncherManager::PathType::Launcher_Directory, versionPath);
+ createConfigJSON();
+ launchApplication(_tokensJSON);
+ createApplicationRegistryKeys(size);
+ _shouldShutdown = TRUE;
+ }
+}
+
+BOOL LauncherManager::extractApplication() {
+ CString installPath;
+ getAndCreatePaths(LauncherManager::PathType::Interface_Directory, installPath);
+ BOOL success = LauncherUtils::unzipFileOnThread(ZipType::ZipApplication, LauncherUtils::cStringToStd(_applicationZipPath),
+ LauncherUtils::cStringToStd(installPath), [&](int type, int size) {
+ onZipExtracted((ZipType)type, size);
+ });
+ return success;
+}
+
+void LauncherManager::onFileDownloaded(DownloadType type) {
+ if (type == DownloadType::DownloadContent) {
+ installContent();
+ } else if (type == DownloadType::DownloadApplication) {
+ extractApplication();
+ }
+}
+
+
+BOOL LauncherManager::installContent() {
+ std::string contentZipFile = LauncherUtils::cStringToStd(_contentZipPath);
+ CString contentPath;
+ getAndCreatePaths(LauncherManager::PathType::Content_Directory, contentPath);
+ BOOL success = LauncherUtils::unzipFileOnThread(ZipType::ZipContent, contentZipFile,
+ LauncherUtils::cStringToStd(contentPath), [&](int type, int size) {
+ onZipExtracted((ZipType)type, size);
+ });
+ return success;
+}
+
+
+BOOL LauncherManager::downloadFile(DownloadType type, const CString& url, CString& outPath) {
+ CString fileName = url.Mid(url.ReverseFind('/') + 1);
+ CString downloadDirectory;
+ BOOL success = getAndCreatePaths(LauncherManager::PathType::Download_Directory, downloadDirectory);
+ outPath = downloadDirectory + fileName;
+ if (success) {
+ if (!LauncherUtils::downloadFileOnThread(type, url, outPath, [&](int type) {
+ onFileDownloaded((DownloadType)type);
+ })) {
+ success = FALSE;
+ }
+ }
+ return success;
+}
+
+BOOL LauncherManager::downloadContent() {
+ CString contentURL = getContentURL();
+ return downloadFile(DownloadType::DownloadContent, contentURL, _contentZipPath);
+}
+
+BOOL LauncherManager::downloadApplication() {
+ CString applicationURL = getLatestInterfaceURL();
+ return downloadFile(DownloadType::DownloadApplication, applicationURL, _applicationZipPath);
+}
diff --git a/launchers/win32/LauncherManager.h b/launchers/win32/LauncherManager.h
new file mode 100644
index 0000000000..3ad21694f6
--- /dev/null
+++ b/launchers/win32/LauncherManager.h
@@ -0,0 +1,109 @@
+//
+// LauncherManager.h
+//
+// Created by Luis Cuenca on 6/5/2019.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+
+#include "LauncherUtils.h"
+
+const CString DIRECTORY_NAME_APP = _T("HQ");
+const CString DIRECTORY_NAME_DOWNLOADS = _T("downloads");
+const CString DIRECTORY_NAME_INTERFACE = _T("interface");
+const CString DIRECTORY_NAME_CONTENT = _T("content");
+const CString EXTRA_PARAMETERS = _T(" --suppress-settings-reset --no-launcher --no-updater");
+const CString LAUNCHER_EXE_FILENAME = _T("HQ Launcher.exe");
+const bool INSTALL_ZIP = true;
+
+class LauncherManager
+{
+public:
+ enum PathType {
+ Running_Path = 0,
+ Launcher_Directory,
+ Download_Directory,
+ Interface_Directory,
+ Desktop_Directory,
+ Content_Directory,
+ StartMenu_Directory,
+ Temp_Directory
+ };
+ enum ZipType {
+ ZipContent = 0,
+ ZipApplication
+ };
+ enum DownloadType {
+ DownloadContent = 0,
+ DownloadApplication
+ };
+ enum ErrorType {
+ ErrorNetworkAuth,
+ ErrorNetworkUpdate,
+ ErrorNetworkHq,
+ ErrorDownloading,
+ ErrorUpdating,
+ ErrorInstall,
+ ErrorIOFiles
+ };
+ LauncherManager();
+ ~LauncherManager();
+ void init();
+ BOOL getAndCreatePaths(PathType type, CString& outPath);
+ BOOL getInstalledVersion(const CString& path, CString& version);
+ BOOL isApplicationInstalled(CString& version, CString& domain,
+ CString& content, bool& loggedIn);
+ LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password);
+ LauncherUtils::ResponseError getMostRecentBuild(CString& urlOut, CString& versionOut);
+ LauncherUtils::ResponseError readOrganizationJSON(const CString& hash);
+ LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain,
+ CString& content, bool& loggedIn);
+ BOOL createConfigJSON();
+ BOOL createApplicationRegistryKeys(int size);
+ BOOL deleteApplicationRegistryKeys();
+ BOOL createShortcuts();
+ BOOL deleteShortcuts();
+ BOOL launchApplication(const CString& tokensJSON = _T(""));
+ BOOL uninstallApplication();
+ BOOL installLauncher();
+
+ // getters
+ const CString& getContentURL() const { return _contentURL; }
+ const CString& getdomainURL() const { return _domainURL; }
+ const CString& getVersion() const { return _version; }
+ BOOL shouldShutDown() const { return _shouldShutdown; }
+ BOOL needsUpdate() { return _shouldUpdate; }
+ BOOL needsUninstall() { return _shouldUninstall; }
+ void setDisplayName(const CString& displayName) { _displayName = displayName; }
+ bool isLoggedIn() { return _loggedIn; }
+ const CString& getLatestInterfaceURL() const { return _latestApplicationURL; }
+ void uninstall() { _shouldUninstall = true; };
+
+ BOOL downloadFile(DownloadType type, const CString& url, CString& localPath);
+ BOOL downloadContent();
+ BOOL downloadApplication();
+ BOOL installContent();
+ BOOL extractApplication();
+ void onZipExtracted(ZipType type, int size);
+ void onFileDownloaded(DownloadType type);
+
+private:
+ CString _latestApplicationURL;
+ CString _latestVersion;
+ CString _contentURL;
+ CString _domainURL;
+ CString _version;
+ CString _displayName;
+ CString _tokensJSON;
+ CString _applicationZipPath;
+ CString _contentZipPath;
+ bool _loggedIn{ false };
+ BOOL _shouldUpdate{ FALSE };
+ BOOL _shouldUninstall{ FALSE };
+ BOOL _shouldShutdown{ FALSE };
+};
+
diff --git a/launchers/win32/LauncherUtils.cpp b/launchers/win32/LauncherUtils.cpp
new file mode 100644
index 0000000000..8a75747e9b
--- /dev/null
+++ b/launchers/win32/LauncherUtils.cpp
@@ -0,0 +1,405 @@
+//
+// LauncherUtils.cpp
+//
+// Created by Luis Cuenca on 6/5/2019.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#include "stdafx.h"
+#include
+#include
+#include
+#include
+#pragma comment(lib, "winhttp")
+
+#include "LauncherUtils.h"
+
+BOOL LauncherUtils::IsProcessRunning(const wchar_t *processName) {
+ bool exists = false;
+ PROCESSENTRY32 entry;
+ entry.dwSize = sizeof(PROCESSENTRY32);
+
+ HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
+
+ if (Process32First(snapshot, &entry)) {
+ while (Process32Next(snapshot, &entry)) {
+ if (!_wcsicmp(entry.szExeFile, processName)) {
+ exists = true;
+ break;
+ }
+ }
+ }
+ CloseHandle(snapshot);
+ return exists;
+}
+
+HRESULT LauncherUtils::CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszArgs) {
+ IShellLink* psl;
+
+ // Get a pointer to the IShellLink interface. It is assumed that CoInitialize
+ // has already been called.
+ CoInitialize(NULL);
+ HRESULT hres = E_INVALIDARG;
+ if ((lpszPathObj != NULL) && (wcslen(lpszPathObj) > 0) &&
+ (lpszDesc != NULL) &&
+ (lpszPathLink != NULL) && (strlen(lpszPathLink) > 0)) {
+ hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
+ if (SUCCEEDED(hres)) {
+ IPersistFile* ppf;
+
+ // Set the path to the shortcut target and add the description.
+ psl->SetPath(lpszPathObj);
+ psl->SetDescription(lpszDesc);
+ psl->SetArguments(lpszArgs);
+
+ // Query IShellLink for the IPersistFile interface, used for saving the
+ // shortcut in persistent storage.
+ hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
+
+ if (SUCCEEDED(hres)) {
+ WCHAR wsz[MAX_PATH];
+
+ // Ensure that the string is Unicode.
+ MultiByteToWideChar(CP_ACP, 0, lpszPathLink, -1, wsz, MAX_PATH);
+
+ // Add code here to check return value from MultiByteWideChar
+ // for success.
+
+ // Save the link by calling IPersistFile::Save.
+ hres = ppf->Save(wsz, TRUE);
+ ppf->Release();
+ }
+ psl->Release();
+ }
+ }
+ CoUninitialize();
+ return SUCCEEDED(hres);
+}
+
+std::string LauncherUtils::cStringToStd(CString cstring) {
+ CT2CA convertedString(cstring);
+ std::string strStd(convertedString);
+ return strStd;
+}
+
+BOOL LauncherUtils::launchApplication(LPCWSTR lpApplicationName, LPTSTR cmdArgs) {
+ // additional information
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ // set the size of the structures
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ ZeroMemory(&pi, sizeof(pi));
+
+ // start the program up
+ BOOL success = CreateProcess(
+ lpApplicationName, // the path
+ cmdArgs, // Command line
+ NULL, // Process handle not inheritable
+ NULL, // Thread handle not inheritable
+ FALSE, // Set handle inheritance to FALSE
+ CREATE_NEW_CONSOLE, // Opens file in a separate console
+ NULL, // Use parent's environment block
+ NULL, // Use parent's starting directory
+ &si, // Pointer to STARTUPINFO structure
+ &pi // Pointer to PROCESS_INFORMATION structure
+ );
+ // Close process and thread handles.
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return success;
+}
+
+BOOL LauncherUtils::deleteRegistryKey(const CString& registryPath) {
+ TCHAR szDelKey[MAX_PATH * 2];
+ StringCchCopy(szDelKey, MAX_PATH * 2, registryPath);
+ auto status = RegDeleteKey(HKEY_CURRENT_USER, szDelKey);
+ if (status == ERROR_SUCCESS) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+LauncherUtils::ResponseError LauncherUtils::makeHTTPCall(const CString& callerName,
+ const CString& mainUrl, const CString& dirUrl,
+ const CString& contentType, CStringA& postData,
+ CString& response, bool isPost = false) {
+
+ HINTERNET hopen = WinHttpOpen(callerName, WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+ WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
+ if (!hopen) {
+ return ResponseError::Open;
+ }
+ HINTERNET hconnect = WinHttpConnect(hopen, mainUrl, INTERNET_DEFAULT_HTTPS_PORT, 0);
+ if (!hconnect) {
+ return ResponseError::Connect;
+ }
+ HINTERNET hrequest = WinHttpOpenRequest(hconnect, isPost ? L"POST" : L"GET", dirUrl,
+ NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
+ if (!hrequest) {
+ return ResponseError::OpenRequest;
+ }
+ if (isPost) {
+ if (!WinHttpSendRequest(hrequest, contentType, -1,
+ postData.GetBuffer(postData.GetLength()), (DWORD)strlen(postData), (DWORD)strlen(postData), NULL)) {
+ return ResponseError::SendRequest;
+ }
+ } else {
+ if (!WinHttpSendRequest(hrequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0)) {
+ return ResponseError::SendRequest;
+ }
+ }
+ if (!WinHttpReceiveResponse(hrequest, 0)) {
+ return ResponseError::ReceiveRequest;
+ }
+ // query remote file size, set haveContentLength on success and dwContentLength to the length
+ wchar_t szContentLength[32];
+ DWORD bufferBytes = 4096;
+ DWORD dwHeaderIndex = WINHTTP_NO_HEADER_INDEX;
+
+ BOOL haveContentLength = WinHttpQueryHeaders(hrequest, WINHTTP_QUERY_CONTENT_LENGTH, NULL,
+ &szContentLength, &bufferBytes, &dwHeaderIndex);
+
+ DWORD dwContentLength;
+ if (haveContentLength) {
+ dwContentLength = _wtoi(szContentLength);
+ }
+ byte p[4096];
+ if (!WinHttpQueryDataAvailable(hrequest, &bufferBytes)) {
+ return ResponseError::ReadResponse;
+ }
+ WinHttpReadData(hrequest, p, bufferBytes, &bufferBytes);
+ response = CString((const char*)p, (int)bufferBytes);
+ return ResponseError::NoError;
+}
+
+BOOL LauncherUtils::parseJSON(const CString& jsonTxt, Json::Value& root) {
+ Json::CharReaderBuilder CharBuilder;
+ std::string jsonString = cStringToStd(jsonTxt);
+ std::string errs;
+ Json::CharReader* nreader = CharBuilder.newCharReader();
+ bool parsingSuccessful = false;
+ if (nreader != NULL) {
+ parsingSuccessful = nreader->parse(jsonString.c_str(), jsonString.c_str() + jsonString.length(), &root, &errs);
+ delete nreader;
+ }
+ return parsingSuccessful;
+}
+
+BOOL LauncherUtils::getFont(const CString& fontName, int fontSize, bool isBold, CFont& fontOut) {
+ LOGFONT lf;
+ memset(&lf, 0, sizeof(lf));
+ lf.lfHeight = fontSize;
+ lf.lfWeight = isBold ? FW_BOLD : FW_NORMAL;
+ lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
+ lf.lfQuality = ANTIALIASED_QUALITY;
+
+ wcscpy_s(lf.lfFaceName, fontName);
+ if (!fontOut.CreateFontIndirect(&lf)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+uint64_t LauncherUtils::extractZip(const std::string& zipFile, const std::string& path, std::vector& files) {
+ mz_zip_archive zip_archive;
+ memset(&zip_archive, 0, sizeof(zip_archive));
+
+ auto status = mz_zip_reader_init_file(&zip_archive, zipFile.c_str(), 0);
+
+ if (!status) return 0;
+ int fileCount = (int)mz_zip_reader_get_num_files(&zip_archive);
+ if (fileCount == 0) {
+ mz_zip_reader_end(&zip_archive);
+ return 0;
+ }
+ mz_zip_archive_file_stat file_stat;
+ if (!mz_zip_reader_file_stat(&zip_archive, 0, &file_stat)) {
+ mz_zip_reader_end(&zip_archive);
+ return 0;
+ }
+ // Get root folder
+ CString lastDir = _T("");
+ uint64_t totalSize = 0;
+ for (int i = 0; i < fileCount; i++) {
+ if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) continue;
+ std::string filename = file_stat.m_filename;
+ std::replace(filename.begin(), filename.end(), '/', '\\');
+ CString fullFilename = CString(path.c_str()) + "\\" + CString(filename.c_str());
+ if (mz_zip_reader_is_file_a_directory(&zip_archive, i)) {
+ if (SHCreateDirectoryEx(NULL, fullFilename, NULL) || ERROR_ALREADY_EXISTS == GetLastError()) {
+ break;
+ } else {
+ continue;
+ }
+ }
+ CT2A destFile(fullFilename);
+ if (mz_zip_reader_extract_to_file(&zip_archive, i, destFile, 0)) {
+ totalSize += (uint64_t)file_stat.m_uncomp_size;
+ files.emplace_back(destFile);
+ }
+ }
+
+ // Close the archive, freeing any resources it was using
+ mz_zip_reader_end(&zip_archive);
+ return totalSize;
+}
+
+BOOL LauncherUtils::insertRegistryKey(const std::string& regPath, const std::string& name, const std::string& value) {
+ HKEY key;
+ auto status = RegCreateKeyExA(HKEY_CURRENT_USER, regPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &key, NULL);
+ if (status == ERROR_SUCCESS) {
+ status = RegSetValueExA(key, name.c_str(), 0, REG_SZ, (const BYTE*)value.c_str(), (DWORD)(value.size() + 1));
+ return status == ERROR_SUCCESS;
+ }
+ RegCloseKey(key);
+ return FALSE;
+}
+
+BOOL LauncherUtils::insertRegistryKey(const std::string& regPath, const std::string& name, DWORD value) {
+ HKEY key;
+ auto status = RegCreateKeyExA(HKEY_CURRENT_USER, regPath.c_str(), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &key, NULL);
+ if (status == ERROR_SUCCESS) {
+ status = RegSetValueExA(key, name.c_str(), 0, REG_DWORD, (const BYTE*)&value, sizeof(value));
+ return TRUE;
+ }
+ RegCloseKey(key);
+ return FALSE;
+}
+
+BOOL LauncherUtils::deleteFileOrDirectory(const CString& dirPath, bool noRecycleBin) {
+ CString dir = dirPath;
+ // Add extra null to string
+ dir.AppendChar(0);
+ SHFILEOPSTRUCT fileop;
+ fileop.hwnd = NULL; // no status display
+ fileop.wFunc = FO_DELETE; // delete operation
+ fileop.pFrom = dir; // source file name as double null terminated string
+ fileop.pTo = NULL; // no destination needed
+ fileop.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; // do not prompt the user
+
+ if (!noRecycleBin) {
+ fileop.fFlags |= FOF_ALLOWUNDO;
+ }
+
+ fileop.fAnyOperationsAborted = FALSE;
+ fileop.lpszProgressTitle = NULL;
+ fileop.hNameMappings = NULL;
+
+ int ret = SHFileOperation(&fileop);
+ return (ret == 0);
+}
+
+BOOL LauncherUtils::hMac256(const CString& cmessage, const char* keystr, CString& hashOut) {
+ char message[256];
+ strcpy_s(message, CStringA(cmessage).GetString());
+ char key[256];
+ strcpy_s(key, keystr);
+ HCRYPTPROV hProv = 0;
+ HCRYPTHASH hHash = 0;
+ HCRYPTKEY hKey = 0;
+ HCRYPTHASH hHmacHash = 0;
+ BYTE pbHash[32];
+ HMAC_INFO HmacInfo;
+ int err = 0;
+ typedef struct blob {
+ BLOBHEADER header;
+ DWORD len;
+ BYTE key[1];
+ } m_blob;
+
+ ZeroMemory(&HmacInfo, sizeof(HmacInfo));
+ HmacInfo.HashAlgid = CALG_SHA_256;
+ ZeroMemory(&pbHash, 32);
+ m_blob* kb = NULL;
+ DWORD kbSize = DWORD(sizeof(m_blob) + strlen(key));
+
+ kb = (m_blob*)malloc(kbSize);
+ kb->header.bType = PLAINTEXTKEYBLOB;
+ kb->header.bVersion = CUR_BLOB_VERSION;
+ kb->header.reserved = 0;
+ kb->header.aiKeyAlg = CALG_RC2;
+ memcpy(&kb->key, key, strlen(key));
+ kb->len = (DWORD)strlen(key);
+ BOOL success = false;
+ DWORD datalen = (DWORD)32;
+ if (CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET)
+ && CryptImportKey(hProv, (BYTE*)kb, kbSize, 0, CRYPT_IPSEC_HMAC_KEY, &hKey)
+ && CryptCreateHash(hProv, CALG_HMAC, hKey, 0, &hHmacHash)
+ && CryptSetHashParam(hHmacHash, HP_HMAC_INFO, (BYTE*)&HmacInfo, 0)
+ && CryptHashData(hHmacHash, (BYTE*)message, (DWORD)strlen(message), 0)
+ && CryptGetHashParam(hHmacHash, HP_HASHVAL, pbHash, &datalen, 0)) {
+ char *Hex = "0123456789abcdef";
+ char HashString[65] = { 0 };
+ for (int Count = 0; Count < 32; Count++)
+ {
+ HashString[Count * 2] = Hex[pbHash[Count] >> 4];
+ HashString[(Count * 2) + 1] = Hex[pbHash[Count] & 0xF];
+ }
+ hashOut = CString(HashString);
+ success = true;
+ }
+
+ free(kb);
+ if (hHmacHash)
+ CryptDestroyHash(hHmacHash);
+ if (hKey)
+ CryptDestroyKey(hKey);
+ if (hHash)
+ CryptDestroyHash(hHash);
+ if (hProv)
+ CryptReleaseContext(hProv, 0);
+ return success;
+}
+
+
+DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) {
+ UnzipThreadData& data = *((UnzipThreadData*)lpParameter);
+ uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector());
+ int mb_size = (int)(size * 0.001f);
+ data.callback(data._type, mb_size);
+ delete &data;
+ return 0;
+}
+
+DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter)
+{
+ DownloadThreadData& data = *((DownloadThreadData*)lpParameter);
+ auto hr = URLDownloadToFile(0, data._url, data._file, 0, NULL);
+ data.callback(data._type);
+ return 0;
+}
+
+BOOL LauncherUtils::unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function callback) {
+ DWORD myThreadID;
+ UnzipThreadData* unzipThreadData = new UnzipThreadData();
+ unzipThreadData->_type = type;
+ unzipThreadData->_zipFile = zipFile;
+ unzipThreadData->_path = path;
+ unzipThreadData->setCallback(callback);
+ HANDLE myHandle = CreateThread(0, 0, unzipThread, unzipThreadData, 0, &myThreadID);
+ if (myHandle) {
+ CloseHandle(myHandle);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL LauncherUtils::downloadFileOnThread(int type, const CString& url, const CString& file, std::function callback) {
+ DWORD myThreadID;
+ DownloadThreadData* downloadThreadData = new DownloadThreadData();
+ downloadThreadData->_type = type;
+ downloadThreadData->_url = url;
+ downloadThreadData->_file = file;
+ downloadThreadData->setCallback(callback);
+ HANDLE myHandle = CreateThread(0, 0, downloadThread, downloadThreadData, 0, &myThreadID);
+ if (myHandle) {
+ CloseHandle(myHandle);
+ return TRUE;
+ }
+ return FALSE;
+}
\ No newline at end of file
diff --git a/launchers/win32/LauncherUtils.h b/launchers/win32/LauncherUtils.h
new file mode 100644
index 0000000000..3e9f18d892
--- /dev/null
+++ b/launchers/win32/LauncherUtils.h
@@ -0,0 +1,77 @@
+//
+// LauncherUtils.h
+//
+// Created by Luis Cuenca on 6/5/2019.
+// Copyright 2019 High Fidelity, Inc.
+//
+// Distributed under the Apache License, Version 2.0.
+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+#pragma once
+
+#include
+
+#include "libs/json/json.h"
+#include "libs/miniz.h"
+
+class LauncherUtils
+{
+public:
+ enum ResponseError {
+ Open = 0,
+ Connect,
+ OpenRequest,
+ SendRequest,
+ ReceiveRequest,
+ ReadResponse,
+ ParsingJSON,
+ BadCredentials,
+ NoError
+ };
+
+ struct DownloadThreadData {
+ int _type;
+ CString _url;
+ CString _file;
+ std::function callback;
+ // function(type)
+ void setCallback(std::function fn) {
+ callback = std::bind(fn, std::placeholders::_1);
+ }
+ };
+
+ struct UnzipThreadData {
+ int _type;
+ std::string _zipFile;
+ std::string _path;
+ // function(type, size)
+ std::function callback;
+ void setCallback(std::function fn) {
+ callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
+ }
+ };
+
+ static BOOL parseJSON(const CString& jsonTxt, Json::Value& jsonObject);
+ static ResponseError makeHTTPCall(const CString& callerName, const CString& mainUrl,
+ const CString& dirUrl, const CString& contentType,
+ CStringA& postData, CString& response, bool isPost);
+ static std::string cStringToStd(CString cstring);
+ static BOOL getFont(const CString& fontName, int fontSize, bool isBold, CFont& fontOut);
+ static BOOL launchApplication(LPCWSTR lpApplicationName, LPTSTR cmdArgs = _T(""));
+ static BOOL IsProcessRunning(const wchar_t *processName);
+ static BOOL insertRegistryKey(const std::string& regPath, const std::string& name, const std::string& value);
+ static BOOL insertRegistryKey(const std::string& regPath, const std::string& name, DWORD value);
+ static BOOL deleteFileOrDirectory(const CString& dirPath, bool noRecycleBin = true);
+ static HRESULT CreateLink(LPCWSTR lpszPathObj, LPCSTR lpszPathLink, LPCWSTR lpszDesc, LPCWSTR lpszArgs = _T(""));
+ static BOOL hMac256(const CString& message, const char* key, CString& hashOut);
+ static uint64_t extractZip(const std::string& zipFile, const std::string& path, std::vector& files);
+ static BOOL deleteRegistryKey(const CString& registryPath);
+ static BOOL unzipFileOnThread(int type, const std::string& zipFile, const std::string& path, std::function callback);
+ static BOOL downloadFileOnThread(int type, const CString& url, const CString& file, std::function callback);
+
+private:
+ // Threads
+ static DWORD WINAPI unzipThread(LPVOID lpParameter);
+ static DWORD WINAPI downloadThread(LPVOID lpParameter);
+};
\ No newline at end of file
diff --git a/launchers/win32/libs/json/json-forwards.h b/launchers/win32/libs/json/json-forwards.h
new file mode 100644
index 0000000000..dd9a9bf356
--- /dev/null
+++ b/launchers/win32/libs/json/json-forwards.h
@@ -0,0 +1,320 @@
+/// Json-cpp amalgamated forward header (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json-forwards.h"
+/// This header provides forward declaration for all JsonCpp types.
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
+The JsonCpp Authors, and is released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+ http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+
+Permission 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:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE 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.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED
+# define JSON_FORWARD_AMALGAMATED_H_INCLUDED
+/// If defined, indicates that the source file is amalgamated
+/// to prevent private header inclusion.
+#define JSON_IS_AMALGAMATION
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//# define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//# define JSON_USE_CPPTL_SMALLMAP 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgamated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgamated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#elif defined(__GNUC__) || defined(__clang__)
+#define JSON_API __attribute__((visibility("default")))
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#error \
+ "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+// As recommended at
+// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
+extern JSON_API int
+msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...);
+#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
+#else
+#define jsoncpp_snprintf std::snprintf
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
+// C++11 should be used directly in JSONCPP.
+#define JSONCPP_OVERRIDE override
+
+#if __cplusplus >= 201103L
+#define JSONCPP_NOEXCEPT noexcept
+#define JSONCPP_OP_EXPLICIT explicit
+#elif defined(_MSC_VER) && _MSC_VER < 1900
+#define JSONCPP_NOEXCEPT throw()
+#define JSONCPP_OP_EXPLICIT explicit
+#elif defined(_MSC_VER) && _MSC_VER >= 1900
+#define JSONCPP_NOEXCEPT noexcept
+#define JSONCPP_OP_EXPLICIT explicit
+#else
+#define JSONCPP_NOEXCEPT throw()
+#define JSONCPP_OP_EXPLICIT
+#endif
+
+#ifdef __clang__
+#if __has_extension(attribute_deprecated_with_message)
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
+#endif
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
+#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
+#endif // GNUC version
+#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates MSVC)
+#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#endif // __clang__ || __GNUC__ || _MSC_VER
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+#if __GNUC__ >= 6
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+#endif
+
+#if !defined(JSON_IS_AMALGAMATION)
+
+#include "allocator.h"
+#include "version.h"
+
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else // if defined(_MSC_VER) // Other platforms, use long long
+typedef int64_t Int64;
+typedef uint64_t UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+
+template
+using Allocator = typename std::conditional,
+ std::allocator>::type;
+using String = std::basic_string, Allocator>;
+using IStringStream = std::basic_istringstream;
+using OStringStream = std::basic_ostringstream;
+using IStream = std::istream;
+using OStream = std::ostream;
+} // namespace Json
+
+// Legacy names (formerly macros).
+using JSONCPP_STRING = Json::String;
+using JSONCPP_ISTRINGSTREAM = Json::IStringStream;
+using JSONCPP_OSTRINGSTREAM = Json::OStringStream;
+using JSONCPP_ISTREAM = Json::IStream;
+using JSONCPP_OSTREAM = Json::OStream;
+
+#endif // JSON_CONFIG_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#endif //ifndef JSON_FORWARD_AMALGAMATED_H_INCLUDED
diff --git a/launchers/win32/libs/json/json.h b/launchers/win32/libs/json/json.h
new file mode 100644
index 0000000000..c596384322
--- /dev/null
+++ b/launchers/win32/libs/json/json.h
@@ -0,0 +1,2346 @@
+/// Json-cpp amalgamated header (http://jsoncpp.sourceforge.net/).
+/// It is intended to be used with #include "json/json.h"
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+/*
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+Baptiste Lepilleur and The JsonCpp Authors explicitly disclaim copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur and
+The JsonCpp Authors, and is released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+ http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+
+Permission 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:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE 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.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
+
+*/
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: LICENSE
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+#ifndef JSON_AMALGAMATED_H_INCLUDED
+# define JSON_AMALGAMATED_H_INCLUDED
+/// If defined, indicates that the source file is amalgamated
+/// to prevent private header inclusion.
+#define JSON_IS_AMALGAMATION
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+// DO NOT EDIT. This file (and "version") is generated by CMake.
+// Run CMake configure step to update it.
+#ifndef JSON_VERSION_H_INCLUDED
+#define JSON_VERSION_H_INCLUDED
+
+#define JSONCPP_VERSION_STRING "1.8.4"
+#define JSONCPP_VERSION_MAJOR 1
+#define JSONCPP_VERSION_MINOR 8
+#define JSONCPP_VERSION_PATCH 4
+#define JSONCPP_VERSION_QUALIFIER
+#define JSONCPP_VERSION_HEXA \
+ ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | \
+ (JSONCPP_VERSION_PATCH << 8))
+
+#ifdef JSONCPP_USING_SECURE_MEMORY
+#undef JSONCPP_USING_SECURE_MEMORY
+#endif
+#define JSONCPP_USING_SECURE_MEMORY 0
+// If non-zero, the library zeroes any memory that it has allocated before
+// it frees its memory.
+
+#endif // JSON_VERSION_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/version.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/allocator.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_ALLOCATOR_H_INCLUDED
+#define CPPTL_JSON_ALLOCATOR_H_INCLUDED
+
+#include
+#include
+
+#pragma pack(push, 8)
+
+namespace Json {
+template class SecureAllocator {
+public:
+ // Type definitions
+ using value_type = T;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = T&;
+ using const_reference = const T&;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+
+ /**
+ * Allocate memory for N items using the standard allocator.
+ */
+ pointer allocate(size_type n) {
+ // allocate using "global operator new"
+ return static_cast(::operator new(n * sizeof(T)));
+ }
+
+ /**
+ * Release memory which was allocated for N items at pointer P.
+ *
+ * The memory block is filled with zeroes before being released.
+ * The pointer argument is tagged as "volatile" to prevent the
+ * compiler optimizing out this critical step.
+ */
+ void deallocate(volatile pointer p, size_type n) {
+ std::memset(p, 0, n * sizeof(T));
+ // free using "global operator delete"
+ ::operator delete(p);
+ }
+
+ /**
+ * Construct an item in-place at pointer P.
+ */
+ template void construct(pointer p, Args&&... args) {
+ // construct using "placement new" and "perfect forwarding"
+ ::new (static_cast(p)) T(std::forward(args)...);
+ }
+
+ size_type max_size() const { return size_t(-1) / sizeof(T); }
+
+ pointer address(reference x) const { return std::addressof(x); }
+
+ const_pointer address(const_reference x) const { return std::addressof(x); }
+
+ /**
+ * Destroy an item in-place at pointer P.
+ */
+ void destroy(pointer p) {
+ // destroy using "explicit destructor"
+ p->~T();
+ }
+
+ // Boilerplate
+ SecureAllocator() {}
+ template SecureAllocator(const SecureAllocator&) {}
+ template struct rebind { using other = SecureAllocator; };
+};
+
+template
+bool operator==(const SecureAllocator&, const SecureAllocator&) {
+ return true;
+}
+
+template
+bool operator!=(const SecureAllocator&, const SecureAllocator&) {
+ return false;
+}
+
+} // namespace Json
+
+#pragma pack(pop)
+
+#endif // CPPTL_JSON_ALLOCATOR_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/allocator.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//# define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//# define JSON_USE_CPPTL_SMALLMAP 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgamated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgamated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#elif defined(__GNUC__) || defined(__clang__)
+#define JSON_API __attribute__((visibility("default")))
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#error \
+ "ERROR: Visual Studio 12 (2013) with _MSC_VER=1800 is the oldest supported compiler with sufficient C++11 capabilities"
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+// As recommended at
+// https://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
+extern JSON_API int
+msvc_pre1900_c99_snprintf(char* outBuf, size_t size, const char* format, ...);
+#define jsoncpp_snprintf msvc_pre1900_c99_snprintf
+#else
+#define jsoncpp_snprintf std::snprintf
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+// JSONCPP_OVERRIDE is maintained for backwards compatibility of external tools.
+// C++11 should be used directly in JSONCPP.
+#define JSONCPP_OVERRIDE override
+
+#if __cplusplus >= 201103L
+#define JSONCPP_NOEXCEPT noexcept
+#define JSONCPP_OP_EXPLICIT explicit
+#elif defined(_MSC_VER) && _MSC_VER < 1900
+#define JSONCPP_NOEXCEPT throw()
+#define JSONCPP_OP_EXPLICIT explicit
+#elif defined(_MSC_VER) && _MSC_VER >= 1900
+#define JSONCPP_NOEXCEPT noexcept
+#define JSONCPP_OP_EXPLICIT explicit
+#else
+#define JSONCPP_NOEXCEPT throw()
+#define JSONCPP_OP_EXPLICIT
+#endif
+
+#ifdef __clang__
+#if __has_extension(attribute_deprecated_with_message)
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
+#endif
+#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc)
+#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+#define JSONCPP_DEPRECATED(message) __attribute__((deprecated(message)))
+#elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
+#define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__))
+#endif // GNUC version
+#elif defined(_MSC_VER) // MSVC (after clang because clang on Windows emulates MSVC)
+#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#endif // __clang__ || __GNUC__ || _MSC_VER
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+#if __GNUC__ >= 6
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+#endif
+
+#if !defined(JSON_IS_AMALGAMATION)
+
+#include "allocator.h"
+#include "version.h"
+
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else // if defined(_MSC_VER) // Other platforms, use long long
+typedef int64_t Int64;
+typedef uint64_t UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+
+template
+using Allocator = typename std::conditional,
+ std::allocator>::type;
+using String = std::basic_string, Allocator>;
+using IStringStream = std::basic_istringstream;
+using OStringStream = std::basic_ostringstream;
+using IStream = std::istream;
+using OStream = std::ostream;
+} // namespace Json
+
+// Legacy names (formerly macros).
+using JSONCPP_STRING = Json::String;
+using JSONCPP_ISTRINGSTREAM = Json::IStringStream;
+using JSONCPP_OSTRINGSTREAM = Json::OStringStream;
+using JSONCPP_ISTREAM = Json::IStream;
+using JSONCPP_OSTREAM = Json::OStream;
+
+#endif // JSON_CONFIG_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/config.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/forwards.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+#define CPPTL_JSON_FEATURES_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+#pragma pack(push, 8)
+
+namespace Json {
+
+/** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+class JSON_API Features {
+public:
+ /** \brief A configuration that allows all features and assumes all strings
+ * are UTF-8.
+ * - C & C++ comments are allowed
+ * - Root object can be any JSON value
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features all();
+
+ /** \brief A configuration that is strictly compatible with the JSON
+ * specification.
+ * - Comments are forbidden.
+ * - Root object must be either an array or an object value.
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features strictMode();
+
+ /** \brief Initialize the configuration like JsonConfig::allFeatures;
+ */
+ Features();
+
+ /// \c true if comments are allowed. Default: \c true.
+ bool allowComments_{true};
+
+ /// \c true if root must be either an array or an object value. Default: \c
+ /// false.
+ bool strictRoot_{false};
+
+ /// \c true if dropped null placeholders are allowed. Default: \c false.
+ bool allowDroppedNullPlaceholders_{false};
+
+ /// \c true if numeric object key are allowed. Default: \c false.
+ bool allowNumericKeys_{false};
+};
+
+} // namespace Json
+
+#pragma pack(pop)
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
+
+// //////////////////////////////////////////////////////////////////////
+// End of content of file: include/json/features.h
+// //////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+// //////////////////////////////////////////////////////////////////////
+// Beginning of content of file: include/json/value.h
+// //////////////////////////////////////////////////////////////////////
+
+// Copyright 2007-2010 Baptiste Lepilleur and The JsonCpp Authors
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_H_INCLUDED
+#define CPPTL_JSON_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include
+#include
+#include
+#include
+#include
+
+#ifndef JSON_USE_CPPTL_SMALLMAP
+#include