From 97d43b29bb1a431d52753728c751a065b10cc97f Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Wed, 16 Oct 2024 19:32:24 -0300 Subject: [PATCH 1/6] feat: Better webkit patching #127 --- assets/core/main.py | 9 ++++ assets/pipx/main.py | 4 +- assets/src/Webkit.ts | 106 +++++++++++++++++++++++++++++++++++++++++++ assets/src/index.tsx | 3 ++ 4 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 assets/src/Webkit.ts diff --git a/assets/core/main.py b/assets/core/main.py index b838c513..c8515dbc 100644 --- a/assets/core/main.py +++ b/assets/core/main.py @@ -20,6 +20,15 @@ from updater.version_control import Updater updater = Updater() + +def inject_webkit_shim(shim_script: str): + # write the contents to a file + with open(os.path.join(Millennium.steam_path(), "steamui", "shim.js"), "w") as f: + f.write(shim_script) + f.close() + + add_browser_js(os.path.join(Millennium.steam_path(), "shim.js")) + def get_load_config(): millennium = configparser.ConfigParser() config_path = os.path.join(Millennium.get_install_path(), "ext", "millennium.ini") diff --git a/assets/pipx/main.py b/assets/pipx/main.py index feffb4e1..f4dd88e6 100644 --- a/assets/pipx/main.py +++ b/assets/pipx/main.py @@ -2,7 +2,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) -import pipx.config as config +import config as config import time import importlib.metadata import dev_tools, pip_setup, package_manager @@ -31,4 +31,4 @@ def main(): elapsed_time_ms = (time.perf_counter() - start_time) * 1000 logger.log(f"Finished in {elapsed_time_ms:.2f} ms") -main() \ No newline at end of file +main() diff --git a/assets/src/Webkit.ts b/assets/src/Webkit.ts new file mode 100644 index 00000000..063d9e1e --- /dev/null +++ b/assets/src/Webkit.ts @@ -0,0 +1,106 @@ +import { Millennium } from "millennium-lib"; +import { ConditionalControlFlowType, Theme, ThemeItem } from "./types"; +import { constructThemePath } from "./patcher/Dispatch"; + +interface WebkitItem { + matchString: string, + targetPath: string, + fileType: ConditionalControlFlowType +} + +const ParseMatchAndTarget = (theme: Theme): WebkitItem[] => { + + let webkitItems: WebkitItem[] = [] + + // Add condition keys into the webkitItems array + for (const item in theme?.Conditions) { + const condition = theme.Conditions[item] + + for (const value in condition?.values) { + const controlFlow = condition.values[value] + + + for (const control in controlFlow?.TargetCss?.affects) { + const matchString = controlFlow.TargetCss.affects[control] + const targetPath = controlFlow.TargetCss.src + + webkitItems.push({ matchString, targetPath, fileType: ConditionalControlFlowType.TargetCss }) + } + + for (const control in controlFlow?.TargetJs?.affects) { + const matchString = controlFlow.TargetJs.affects[control] + const targetPath = controlFlow.TargetJs.src + + webkitItems.push({ matchString, targetPath, fileType: ConditionalControlFlowType.TargetJs }) + } + } + } + + // Add patch keys into the webkitItems array + for (const item in theme?.Patches) { + const patch = theme.Patches[item] + + if (patch.TargetCss) { + if (Array.isArray(patch.TargetCss)) { + for (const target in patch.TargetCss) { + webkitItems.push({ matchString: patch.MatchRegexString, targetPath: patch.TargetCss[target], fileType: ConditionalControlFlowType.TargetCss }) + } + } + else { + webkitItems.push({ matchString: patch.MatchRegexString, targetPath: patch.TargetCss, fileType: ConditionalControlFlowType.TargetCss }) + } + } + + if (patch.TargetJs) { + if (Array.isArray(patch.TargetJs)) { + for (const target in patch.TargetJs) { + webkitItems.push({ matchString: patch.MatchRegexString, targetPath: patch.TargetJs[target], fileType: ConditionalControlFlowType.TargetJs }) + } + } + else { + webkitItems.push({ matchString: patch.MatchRegexString, targetPath: patch.TargetJs, fileType: ConditionalControlFlowType.TargetJs }) + } + } + } + + // Filter out duplicates + webkitItems = webkitItems.filter((item, index, self) => + index === self.findIndex((t) => ( + t.matchString === item.matchString && t.targetPath === item.targetPath + )) + ) + + return webkitItems +} + +const CreateWebkitScript = (themeData: ThemeItem) => { + console.log(themeData) + + let script = ``; + const webkitItems: WebkitItem[] = ParseMatchAndTarget(themeData?.data) + + for (const item in webkitItems) { + const webkitItem = webkitItems[item] + + const cssPath = constructThemePath(themeData?.native, webkitItem.targetPath) + const jsPath = ["https://s.ytimg.com/millennium-virtual", "skins", themeData?.native, webkitItem.targetPath].join('/') + + script += ` + if (RegExp("${webkitItem.matchString}").test(window.location.href)) { + console.log("Matched: ${webkitItem.matchString}, injecting ${webkitItem.fileType === ConditionalControlFlowType.TargetCss ? cssPath : jsPath}"); + ${ + webkitItem.fileType === ConditionalControlFlowType.TargetCss + ? `document.head.appendChild(Object.assign(document.createElement('link'), { rel: 'stylesheet', href: '${cssPath}' }))` + : `document.head.appendChild(Object.assign(document.createElement('script'), { src: '${jsPath}' }))` + } + }\n + ` + } + + console.log(script) + Millennium.callServerMethod("inject_webkit_shim", { shim_script: + `(() => { ${script} })()` + }) +} + +export { CreateWebkitScript } \ No newline at end of file diff --git a/assets/src/index.tsx b/assets/src/index.tsx index 2fcf974b..8eff0445 100644 --- a/assets/src/index.tsx +++ b/assets/src/index.tsx @@ -9,6 +9,7 @@ import { PatchNotification } from "./ui/Notifications"; import { Settings, SettingsStore } from "./Settings"; import { DispatchGlobalColors } from "./patcher/v1/GlobalColors"; import { WatchDog } from "./Events"; +import { CreateWebkitScript } from "./Webkit"; /** * @note crashes steam on silent boot startup @@ -78,6 +79,8 @@ const InitializePatcher = (startTime: number, result: SettingsProps) => { Logger.Log(`Received props in [${(performance.now() - startTime).toFixed(3)}ms]`, result) + CreateWebkitScript(result.active_theme); + const theme: ThemeItem = result.active_theme const systemColors: SystemAccentColor = result.accent_color From 545aa842284812b8a210ce28b720c1ca5dd0fabc Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:33:51 -0300 Subject: [PATCH 2/6] chore: Make artifact CI (#140) --- .github/workflows/artifact.yml | 332 +++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 .github/workflows/artifact.yml diff --git a/.github/workflows/artifact.yml b/.github/workflows/artifact.yml new file mode 100644 index 00000000..7cf7c2c2 --- /dev/null +++ b/.github/workflows/artifact.yml @@ -0,0 +1,332 @@ +name: Build Millennium + +on: + workflow_dispatch: + +jobs: + build-windows: + permissions: + contents: write + issues: write + pull-requests: write + + runs-on: windows-latest + + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + + steps: + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: true + + - name: (Setup) Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: (Setup) Assets Build Environment + run: cd assets && npm install && npm run build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: (Setup) Build Assets + run: . scripts\ci\win32\mk-assets.ps1 + + - name: (Setup) Construct Python Environment + run: . scripts\ci\win32\setup-python.ps1 D:/a/env/ext/data/cache + + - name: (Setup) Semantic Release + run: npm install --save-dev semantic-release @semantic-release/github @semantic-release/exec @semantic-release/changelog @semantic-release/git + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # dry run to get the next version + - name: Bump Version + id: read_version + run: . scripts\ci\win32\version.ps1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up cache for Python source + uses: actions/cache@v3 + id: build-cache + with: + path: Python-3.11.8/PCbuild/win32 + key: ${{ runner.os }}-python-3.11.8-build + restore-keys: ${{ runner.os }}-python-3.11.8-build- + + - name: (Python) Add msbuild to PATH + if: steps.build-cache.outputs.cache-hit != 'true' + uses: microsoft/setup-msbuild@v2 + + - name: (Python) Download 3.11.8 win32 source + if: steps.build-cache.outputs.cache-hit != 'true' + run: . scripts\ci\win32\build-python.ps1 + + - name: Upload Build Artifact + uses: actions/upload-artifact@v4 + with: + name: python 3.11.8 build libraries + path: D:/a/Millennium/Millennium/build/python + + - name: Install prerequisites + uses: msys2/setup-msys2@v2 + with: + msystem: mingw32 + install: >- + mingw-w64-i686-libgcrypt + mingw-w64-i686-gcc + mingw-w64-i686-cmake + mingw-w64-i686-ninja + + - name: (Dependency) Install vcpkg + shell: pwsh + run: ./vendor/vcpkg/bootstrap-vcpkg.bat && ./vendor/vcpkg/vcpkg integrate install + + - name: (Generator) Configure CMake + shell: msys2 {0} + run: cmake --preset=windows-mingw-release -DGITHUB_ACTION_BUILD=ON + + - name: Build Millennium + shell: msys2 {0} + run: | + mkdir D:/a/Millennium/Millennium/build/artifacts + cmake --build build --config Release + cp D:/a/Millennium/Millennium/Python-3.11.8/PCbuild/win32/python311.dll D:/a/env/python311.dll + cp /d/a/Millennium/Millennium/build/user32.dll D:/a/env/user32.dll + mkdir D:/a/env/ext/bin + # Disable Millennium CLI for now, as it keeps get false positive detections for no apparent reason + # cp /d/a/Millennium/Millennium/build/cli/millennium.exe D:/a/env/ext/bin/millennium.exe + + - name: Upload Build Artifact + uses: actions/upload-artifact@v4 + with: + include-hidden-files: true + name: millennium-windows + path: D:/a/env/ + + build-linux: + permissions: + contents: write + issues: write + pull-requests: write + + runs-on: ubuntu-latest + + env: + VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + + steps: + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: true + + - name: (Setup) Node.js + uses: actions/setup-node@v3 + with: + node-version: 20 + + - name: (Setup) Assets Build Environment + run: cd assets && npm install && npm run build + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: (Setup) Build Assets + run: bash scripts/ci/posix/mk-assets.sh + + - name: (Setup) Semantic Release + run: npm install --save-dev semantic-release @semantic-release/github @semantic-release/exec @semantic-release/changelog @semantic-release/git + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # dry run to get the next version + - name: Bump Version + id: read_version + run: bash scripts/ci/posix/version.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Install dependencies + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install -y \ + build-essential \ + zlib1g-dev:i386 \ + libncurses5-dev:i386 \ + libgdbm-dev:i386 \ + libnss3-dev:i386 \ + libssl-dev:i386 \ + libreadline-dev:i386 \ + libffi-dev:i386 \ + wget \ + curl \ + libbz2-dev:i386 \ + libsqlite3-dev:i386 \ + liblzma-dev:i386 \ + gcc-multilib \ + g++-multilib + + - name: Set up cache for Python source + uses: actions/cache@v3 + id: build-cache + with: + path: home/runner/.millennium/ext/data/cache + key: ${{ runner.os }}-python-linux-3.11.8-build + restore-keys: ${{ runner.os }}-python-linux-3.11.8-build- + + - name: Download Python 3.11.8 source + if: steps.build-cache.outputs.cache-hit != 'true' + run: | + wget https://www.python.org/ftp/python/3.11.8/Python-3.11.8.tgz + tar -xf Python-3.11.8.tgz + + - name: Configure and build Python 3.11.8 (32-bit) + if: steps.build-cache.outputs.cache-hit != 'true' + run: | + mkdir -p $HOME/.millennium/ext/data/cache + cd Python-3.11.8 + sudo CFLAGS="-m32" LDFLAGS="-m32" ./configure --prefix=$HOME/.millennium/ext/data/cache --enable-optimizations + sudo make -j$(nproc) + sudo make altinstall + + - name: Setup installation + if: steps.build-cache.outputs.cache-hit != 'true' + run: | + sudo mkdir -p $HOME/.millennium/ext/data/cache/lib/tmp + cd $HOME/.millennium/ext/data/cache/lib/tmp + sudo ar -x ../libpython3.11.a + sudo gcc -m32 -shared -o ../libpython-3.11.8.so *.o + + cd $HOME/.millennium/ext/data/cache/lib + sudo rm -rf tmp + ls + + sudo mkdir -p $HOME/Documents/LibPython/ + cd $HOME/.millennium/ext/data/cache/include/python3.11/ + sudo mv * $HOME/Documents/LibPython/ + + sudo rm -rf $HOME/.millennium/ext/data/cache/lib/python3.11/test/ + sudo rm -rf $HOME/.millennium/ext/data/cache/share + sudo rm -rf $HOME/.millennium/ext/data/cache/include + sudo rm -rf $HOME/.millennium/ext/data/cache/lib/python3.11/__pycache__/ + sudo rm -rf $HOME/.millennium/ext/data/cache/lib/python3.11/config-3.11-x86_64-linux-gnu/ + sudo rm $HOME/.millennium/ext/data/cache/lib/libpython3.11.a + + sudo mv $HOME/.millennium/ext/data/cache/lib/libpython-3.11.8.so $HOME/.millennium/libpython-3.11.8.so + + $HOME/.millennium/ext/data/cache/bin/python3.11 --version + mkdir -p /home/runner/env/ext/data + sudo cp -r $HOME/.millennium/ext/data/cache /home/runner/env/ext/data + + - name: (Generator) Install CMake + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.21.1' + env: + VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + + - name: (Dependency) Install vcpkg & setup environment + run: sudo apt install libgtk-3-dev ninja-build && ./vendor/vcpkg/bootstrap-vcpkg.sh && ./vendor/vcpkg/vcpkg integrate install + env: + VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + + - name: (Generator) Configure CMake + run: cmake --preset=linux -G "Ninja" -DGITHUB_ACTION_BUILD=ON + env: + VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + + + - name: Build Millennium + run: | + # mkdir -p /home/runner/Millennium/build/artifacts + cmake --build build --config Release + + # ls -laR /home/runner/Millennium/build + + mkdir -p /home/runner/env + cp ./build/libMillennium.so /home/runner/env/libMillennium.so + cp ~/.millennium/libpython-3.11.8.so /home/runner/env/libpython-3.11.8.so + cp ./scripts/posix/start.sh /home/runner/env/start.sh + + mkdir -p /home/runner/env/ext/bin + cp ./build/cli/millennium /home/runner/env/ext/bin/millennium + + - name: Upload Build Artifact + uses: actions/upload-artifact@v4 + with: + include-hidden-files: true + name: millennium-linux + path: /home/runner/env/ + + release: + needs: [build-windows, build-linux] + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: true + + - name: Download Windows Artifact + uses: actions/download-artifact@v4 + with: + name: millennium-windows + path: ./artifacts/windows + + - name: Download Linux Artifact + uses: actions/download-artifact@v4 + with: + name: millennium-linux + path: ./artifacts/linux + + - name: Get Version + id: read_version + run: bash scripts/ci/posix/version.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Proccess Artifacts + run: | + mkdir -p ./artifacts/release + + cd ./artifacts/windows + zip -r ../release/millennium-v${{ steps.read_version.outputs.version }}-windows-x86_64.zip . + cd - # return to the original directory + + cd ./artifacts/linux + tar -czvf ../release/millennium-v${{ steps.read_version.outputs.version }}-linux-x86_64.tar.gz . + cd - # return to the original directory + + - name: Upload Windows Artifact + uses: actions/upload-artifact@v4 + with: + include-hidden-files: true + name: millennium-windows + path: ./artifacts/release/millennium-v${{ steps.read_version.outputs.version }}-windows-x86_64.zip + + - name: Upload Linux Artifact + uses: actions/upload-artifact@v4 + with: + include-hidden-files: true + name: millennium-linux + path: ./artifacts/release/millennium-v${{ steps.read_version.outputs.version }}-linux-x86_64.tar.gz + From 38802e8fd05758e14f6f55827d6429bcb85562ff Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Wed, 16 Oct 2024 23:49:46 -0300 Subject: [PATCH 3/6] chore: Linux CLI bug fixes --- cli/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 3615e5a1..43644b18 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -52,6 +52,8 @@ if (WINDRES) add_custom_target(resource-cli DEPENDS ${CMAKE_BINARY_DIR}/version-cli.o) add_dependencies(CLI resource-cli) + + target_link_libraries(CLI PRIVATE ${CMAKE_BINARY_DIR}/version-cli.o) endif() install(TARGETS CLI DESTINATION /usr/local/bin) @@ -62,5 +64,5 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} Wl,--gc-sections -s") endif() -target_link_libraries(CLI PRIVATE CLI11::CLI11 CURL::libcurl ${CMAKE_BINARY_DIR}/version-cli.o) +target_link_libraries(CLI PRIVATE CLI11::CLI11 CURL::libcurl) set_target_properties(CLI PROPERTIES OUTPUT_NAME "millennium") \ No newline at end of file From 662b0536e2ca6ff1c8decbcf58c3ddefb2ce38b2 Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Fri, 25 Oct 2024 15:59:37 -0300 Subject: [PATCH 4/6] chore: Update plugin JSON schema --- src/sys/plugin-schema.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/sys/plugin-schema.json b/src/sys/plugin-schema.json index 0feeb4ad..1e4df428 100644 --- a/src/sys/plugin-schema.json +++ b/src/sys/plugin-schema.json @@ -29,6 +29,18 @@ "frontend": { "type": "string", "markdownDescription": "The relative path to the frontend directory. If not provided, the default folder is `frontend`." + }, + "thumbnail": { + "type": "string", + "markdownDescription": "An absolute path to an image resource, usually hosted on Imgur or GitHub's raw CDN. The image should be 16:9 and a minimum size of 512x288 pixels." + }, + "splash_image": { + "type": "string", + "markdownDescription": "An absolute path to an image resource, usually hosted on Imgur or GitHub's raw CDN. This image is displayed as a backdrop when viewing your plugin page online. The image should be 16:9 and a minimum size of 1920x1080 pixels." + }, + "version": { + "type": "string", + "markdownDescription": "The version of your plugin." } }, "required": [ From 0ba18fa00970692d924dc1a315fd2596d5a5ab70 Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Fri, 25 Oct 2024 22:03:18 -0300 Subject: [PATCH 5/6] chore: Update TODO --- src/TODO.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/TODO.md b/src/TODO.md index 86914efa..29533da9 100644 --- a/src/TODO.md +++ b/src/TODO.md @@ -4,3 +4,8 @@ - hot reload plugin backends - hot reload pipx bootstrapper - figure out how to properly shutdown a python backend + + +- Better webkit patching +- Custom accent color separate from windows +- Auto update themes \ No newline at end of file From ba25d11210bf095026e1f3cf3ba6c425991337bf Mon Sep 17 00:00:00 2001 From: shadow <81448108+shdwmtr@users.noreply.github.com> Date: Fri, 25 Oct 2024 22:03:36 -0300 Subject: [PATCH 6/6] chore: Fix artifact build scripts --- .github/workflows/artifact.yml | 54 ---------------------------------- 1 file changed, 54 deletions(-) diff --git a/.github/workflows/artifact.yml b/.github/workflows/artifact.yml index 7cf7c2c2..3095405b 100644 --- a/.github/workflows/artifact.yml +++ b/.github/workflows/artifact.yml @@ -276,57 +276,3 @@ jobs: include-hidden-files: true name: millennium-linux path: /home/runner/env/ - - release: - needs: [build-windows, build-linux] - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - submodules: true - - - name: Download Windows Artifact - uses: actions/download-artifact@v4 - with: - name: millennium-windows - path: ./artifacts/windows - - - name: Download Linux Artifact - uses: actions/download-artifact@v4 - with: - name: millennium-linux - path: ./artifacts/linux - - - name: Get Version - id: read_version - run: bash scripts/ci/posix/version.sh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Proccess Artifacts - run: | - mkdir -p ./artifacts/release - - cd ./artifacts/windows - zip -r ../release/millennium-v${{ steps.read_version.outputs.version }}-windows-x86_64.zip . - cd - # return to the original directory - - cd ./artifacts/linux - tar -czvf ../release/millennium-v${{ steps.read_version.outputs.version }}-linux-x86_64.tar.gz . - cd - # return to the original directory - - - name: Upload Windows Artifact - uses: actions/upload-artifact@v4 - with: - include-hidden-files: true - name: millennium-windows - path: ./artifacts/release/millennium-v${{ steps.read_version.outputs.version }}-windows-x86_64.zip - - - name: Upload Linux Artifact - uses: actions/upload-artifact@v4 - with: - include-hidden-files: true - name: millennium-linux - path: ./artifacts/release/millennium-v${{ steps.read_version.outputs.version }}-linux-x86_64.tar.gz -