diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f16d882..95ae038 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -17,13 +17,11 @@ on: pull_request: # The branches below must be a subset of the branches above branches: [ master ] - schedule: - - cron: '19 2 * * 5' jobs: analyze: name: Analyze - runs-on: windows-2019 + runs-on: windows-2022 permissions: actions: read contents: read diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ba5e6aa..dc5ef9d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,7 +1,6 @@ -# This is a basic workflow to help you get started with Actions name: CI -# Controls when the workflow will run + on: # Triggers the workflow on push or pull request events but only for the master branch push: @@ -10,92 +9,276 @@ on: # Allows you to run this workflow manually from the Actions tab workflow_dispatch: -# A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: - # The type of runner that the job will run on - runs-on: windows-2019 + permissions: + contents: write + runs-on: windows-2025-vs2026 # Steps represent a sequence of tasks that will be executed as part of the job steps: - - name: Check Commit and Install 7Zip PowerShell Module + # Step to check if the commit message contains #GITBUILD + - name: Check Commit Message shell: powershell run: | - # cancel early, if not build commit - $strVal ='${{ github.event.commits[0].message }}' + # Get the commit message + $strVal ='${{ github.event. head_commit.message }}' # Convert commit message to a single line if multiline $singleLineStrVal = $strVal -replace "`r`n", " " -replace "`n", " " - if($singleLineStrVal -match '#GITBUILD') - { - Write-Host 'True' + if ($singleLineStrVal -match '#GITBUILD') { + Write-Host 'Build commit detected. Proceeding with build...' + echo "build_trigger=true" >> $env:GITHUB_ENV } else { - Write-Host 'False' - exit(1) + Write-Host 'No build commit. Skipping build steps...' + echo "build_trigger=false" >> $env:GITHUB_ENV } - Install-Module 7Zip4PowerShell -Force -Verbose - - uses: actions/checkout@v2 + # Step to ensure the repository is checked out + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + fetch-tags: true + + # Inform if build steps are skipped + - name: Inform Skipped Build Steps + if: env.build_trigger != 'true' + shell: powershell + run: | + Write-Host "Skipping build steps because the commit message does not contain #GITBUILD." + + # Install 7Zip PowerShell module + - name: Install 7Zip PowerShell Module + if: env.build_trigger == 'true' + shell: powershell + run: Install-Module 7Zip4PowerShell -Force -Verbose + # Restore NuGet packages - name: Restore NuGet packages + if: env.build_trigger == 'true' run: nuget restore UnityLauncherPro.sln - + + # Build the binary - name: Build Binary + if: env.build_trigger == 'true' shell: cmd run: call .\Build.cmd - + + # Build the artifact - name: Build Artifact + if: env.build_trigger == 'true' shell: cmd run: call .\ArtifactBuild.cmd - - name: Get current date and time - id: datetime + # Check that output exists + - name: Validate UnityLauncherPro.exe exists + if: env.build_trigger == 'true' + shell: cmd + run: | + if not exist "UnityLauncherPro\bin\Release\UnityLauncherPro.exe" ( + echo ERROR: UnityLauncherPro.exe not found. + exit /b 1 + ) + echo Found UnityLauncherPro.exe + + # 1) Compute a wrapped major.minor.build from the run number + - name: Compute installer version + if: env.build_trigger == 'true' + shell: bash + run: | + TOTAL=${{ github.run_number }} + BUILD=$(( TOTAL % 65536 )) + MINOR_TOTAL=$(( TOTAL / 65536 )) + MINOR=$(( MINOR_TOTAL % 256 )) + MAJOR=$(( MINOR_TOTAL / 256 )) + echo "INSTALLER_MAJOR=$MAJOR" >> $GITHUB_ENV + echo "INSTALLER_MINOR=$MINOR" >> $GITHUB_ENV + echo "INSTALLER_BUILD=$BUILD" >> $GITHUB_ENV + echo "INSTALLER_VER=$MAJOR.$MINOR.$BUILD" >> $GITHUB_ENV + echo "Computed installer version → $MAJOR.$MINOR.$BUILD (run #${{ github.run_number }})" + + # 2) Patch your .vdproj in place (inject ProductVersion and a new GUID) + - name: Patch .vdproj ProductVersion & ProductCode + if: env.build_trigger == 'true' + shell: pwsh + run: | + $proj = 'UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj' + $ver = "${{ env.INSTALLER_VER }}" # e.g. 0.0.118 + $guid = [Guid]::NewGuid().ToString("B").ToUpper() # e.g. {E821A3F5-1F84-4A4B-BE9D-115D93E9E6F0} + + # Read & rewrite line-by-line + $fixed = Get-Content $proj | ForEach-Object { + if ($_ -match '^(\s*)"ProductVersion"') { + # preserve indentation, then inject exactly one pair of braces + "$($Matches[1])""ProductVersion"" = ""8:$ver""" + } + elseif ($_ -match '^(\s*)"ProductCode"') { + "$($Matches[1])""ProductCode"" = ""8:$guid""" + } + else { + $_ + } + } + + # Overwrite the project + Set-Content -Path $proj -Value $fixed + + Write-Host "→ ProductVersion patched to 8:$ver" + Write-Host "→ ProductCode patched to 8:$guid" + + + # 3) **DEBUG**: print out the patched .vdproj so you can inspect it + - name: Show patched .vdproj + if: env.build_trigger == 'true' + shell: pwsh + run: | + $proj = 'UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj' + Write-Host "=== BEGIN .vdproj CONTENT ===" + Get-Content $proj + Write-Host "=== END .vdproj CONTENT ===" + + # locate VS 2026 + - name: Locate Visual Studio 2026 + id: vswhere + shell: pwsh + run: | + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vswhere)) { + throw "Could not find vswhere.exe at $vswhere" + } + + $installPath = & $vswhere -latest -products * -version "[18.0,19.0)" ` + -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + + if (-not $installPath) { + Write-Host 'VS 2026 (major 18) not found on runner. Falling back to VS 2022 (major 17).' + $installPath = & $vswhere -latest -products * -version "[17.0,18.0)" ` + -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + } + + if (-not $installPath) { + throw "Could not find a Visual Studio installation" + } + + "VS=$installPath" >> $env:GITHUB_ENV + "installPath=$installPath" >> $env:GITHUB_OUTPUT + + # download vs installer builder (v2.0.1) + - name: Download Installer-Projects VSIX + shell: pwsh run: | - echo "current_datetime=$(date +'%d/%m/%Y %H:%M')" >> $GITHUB_ENV + $vsixUrl = "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/VisualStudioClient/vsextensions/MicrosoftVisualStudio2026InstallerProjects/2.0.1/vspackage" + $fallbackUrl = "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/VisualStudioClient/vsextensions/MicrosoftVisualStudio2022InstallerProjects/2.0.1/vspackage" + try { + Invoke-WebRequest $vsixUrl -OutFile installerprojects.vsix -ErrorAction Stop + } catch { + Write-Host "VS2026 Installer Projects package not found, falling back to VS2022 feed." + Invoke-WebRequest $fallbackUrl -OutFile installerprojects.vsix -ErrorAction Stop + } - # Step to get previous tag and commits - - name: Get commits since last release + # install vs installer builder + - name: Install Installer-Projects extension + shell: pwsh + run: | + $vsixInstaller = Join-Path "${{ steps.vswhere.outputs.installPath }}" 'Common7\IDE\VSIXInstaller.exe' + Write-Host "Running: $vsixInstaller installerprojects.vsix /quiet" + & $vsixInstaller installerprojects.vsix /quiet + + # Build MSI installer project using Visual Studio 2026 workaround + - name: Build Installer MSI + if: env.build_trigger == 'true' + shell: cmd + run: | + setlocal EnableDelayedExpansion + echo === Running BuildInstaller.bat === + call .\BuildInstaller.bat || echo WARNING: BuildInstaller.bat exited with %ERRORLEVEL%, continuing... + set "ec=!ERRORLEVEL!" + if not "!ec!"=="0" echo WARNING: BuildInstaller.bat exited with !ec!, continuing... + echo === Verifying MSI === + if exist "UnityLauncherProInstaller\Release\UnityLauncherPro-Installer.msi" ( + echo Success: MSI found at UnityLauncherProInstaller\Release\UnityLauncherPro-Installer.msi + exit /b 0 + ) else ( + echo ERROR: MSI not found in UnityLauncherProInstaller\Release + exit /b 1 + ) + + # Get the current date and time + - name: Get current date and time (Helsinki) + if: env.build_trigger == 'true' + shell: pwsh + run: | + $nowUtc = Get-Date -AsUTC + $tz = [TimeZoneInfo]::FindSystemTimeZoneById('FLE Standard Time') # Europe/Helsinki + $now = [TimeZoneInfo]::ConvertTimeFromUtc($nowUtc, $tz) + + "current_datetime=$($now.ToString('dd/MM/yyyy HH:mm'))" >> $env:GITHUB_ENV + "build_timestamp=$($now.ToString('HH:mm:ss - dd/MM/yyyy'))" >> $env:GITHUB_ENV + - name: Echo timestamp (debug) + if: env.build_trigger == 'true' + shell: pwsh + run: echo "build_timestamp=${env:build_timestamp}" + + # Get commits since last build + - name: Get commits since last numeric CI tag id: get_commits + if: env.build_trigger == 'true' shell: bash run: | - # Get the most recent tag - PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none") - if [ "$PREV_TAG" = "none" ]; then - echo "No previous tag found, listing all commits" - COMMITS=$(git log --pretty=format:"* %s" --no-merges) + set -euo pipefail + + # Defensive: fetch tags + git fetch --tags --force + + # Collect numeric-only tags (e.g., 145, 143...) and sort ascending numerically + mapfile -t NUM_TAGS < <(git tag --list '[0-9]*' | sort -n) + + PREV_TAG="" + # Walk from newest to oldest and pick the newest tag that is an ancestor of HEAD + for (( idx=${#NUM_TAGS[@]}-1 ; idx>=0 ; idx-- )); do + t="${NUM_TAGS[$idx]}" + if git merge-base --is-ancestor "$t" HEAD; then + PREV_TAG="$t" + break + fi + done + + if [ -z "$PREV_TAG" ]; then + echo "No previous numeric CI tag reachable from HEAD → listing all commits" + RANGE="--all" else - echo "Previous tag: $PREV_TAG" - # List commits since last tag - COMMITS=$(git log $PREV_TAG..HEAD --pretty=format:"* %s" --no-merges) + echo "Previous CI tag: $PREV_TAG" + RANGE="$PREV_TAG..HEAD" fi - echo "Commits since last release: $COMMITS" - - # Save commits to environment file for later use - echo "commits=$COMMITS" >> $GITHUB_ENV - - - name: Create Release - id: create_release - uses: actions/create-release@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Nicely formatted bullets; add --date=short if you want dates + COMMITS=$(git log $RANGE --no-merges --pretty='* %h %s (by %an)') + + if [ -z "$COMMITS" ]; then + COMMITS="* No code changes since last CI tag." + fi + + { + echo 'commits<> "$GITHUB_OUTPUT" + + - name: Create GitHub Release + Upload Assets + if: env.build_trigger == 'true' + uses: softprops/action-gh-release@v2 with: - tag_name: ${{github.run_number}} - release_name: ${{ env.current_datetime }} (${{ github.run_number }}) + tag_name: ${{ github.run_number }} + name: ${{ env.current_datetime }} (${{ github.run_number }}) body: | - Automated Release by GitHub Action CI - - ### Commits in this release: - ${{ env.commits }} + Automated Release by GitHub Action CI. + **Build time:** ${{ env.build_timestamp }} + NOTE: Installer is experimental (and it loses settings from previous version) + + ### Commits in this release + ${{ steps.get_commits.outputs.commits }} draft: false - prerelease: false - - - name: Upload Release Asset - id: upload-release-asset - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_path: ./UnityLauncherPro.zip - asset_name: UnityLauncherPro.zip - asset_content_type: application/zip + prerelease: false + files: | + ./UnityLauncherPro.zip + ./UnityLauncherProInstaller/Release/UnityLauncherPro-Installer.msi diff --git a/Build.cmd b/Build.cmd index 96f1597..817a945 100644 --- a/Build.cmd +++ b/Build.cmd @@ -1,10 +1,13 @@ @echo off REM Default VS paths to check if no Paths.cmd file exists -set VISUAL_STUDIO_PATH_0="%programfiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe" -set VISUAL_STUDIO_PATH_1="%programfiles(x86)%\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" -set VISUAL_STUDIO_PATH_2="%programfiles(x86)%\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe" -set VISUAL_STUDIO_PATH_3="%programfiles(x86)%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_0="%programfiles%\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_1="%programfiles%\Microsoft Visual Studio\18\Professional\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_2="%programfiles%\Microsoft Visual Studio\18\Enterprise\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_3="%programfiles%\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_4="%programfiles%\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_5="%programfiles(x86)%\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin\msbuild.exe" +set VISUAL_STUDIO_PATH_6="%programfiles(x86)%\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin\msbuild.exe" pushd "%~dp0" if exist Debug rd /s /q Debug @@ -37,6 +40,21 @@ set VISUAL_STUDIO_PATH=%VISUAL_STUDIO_PATH_3% goto build ) +if exist %VISUAL_STUDIO_PATH_4% ( +set VISUAL_STUDIO_PATH=%VISUAL_STUDIO_PATH_4% +goto build +) + +if exist %VISUAL_STUDIO_PATH_5% ( +set VISUAL_STUDIO_PATH=%VISUAL_STUDIO_PATH_5% +goto build +) + +if exist %VISUAL_STUDIO_PATH_6% ( +set VISUAL_STUDIO_PATH=%VISUAL_STUDIO_PATH_6% +goto build +) + REM No default path found. Let the user know what to do. echo No Visual Studio installation found. Please configure it manually. echo 1. Copy 'Paths.cmd.template'. diff --git a/BuildInstaller.bat b/BuildInstaller.bat new file mode 100644 index 0000000..b00a9ec --- /dev/null +++ b/BuildInstaller.bat @@ -0,0 +1,83 @@ +@ECHO OFF +SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION + +ECHO: +ECHO === Starting Installer Build Workaround === + +REM Store current directory +SET "current_path=%CD%" + +SET "vs_base_path=%ProgramFiles%\Microsoft Visual Studio\18" +FOR %%E IN (Community Professional Enterprise) DO ( + IF EXIST "%vs_base_path%\%%E\Common7\IDE\CommonExtensions\Microsoft\VSI\DisableOutOfProcBuild\DisableOutOfProcBuild.exe" ( + SET "buildfix_path=%vs_base_path%\%%E\Common7\IDE\CommonExtensions\Microsoft\VSI\DisableOutOfProcBuild" + SET "devenv_path=%vs_base_path%\%%E\Common7\IDE\devenv.exe" + SET "vs_edition=%%E" + GOTO :FoundEdition + ) +) + + +ECHO [ERROR] Could not find DisableOutOfProcBuild.exe in any known VS2026 edition. +EXIT /B 1 + +:FoundEdition +ECHO Found Visual Studio 2026 Edition: %vs_edition% +CD /D "%buildfix_path%" +CALL DisableOutOfProcBuild.exe + +REM Restore previous directory +CD /D "%current_path%" + +REM === Validate required files === +ECHO: +ECHO === Checking required files === + +SET "error=0" + +IF NOT EXIST "UnityLauncherPro\bin\Release\UnityLauncherPro.exe" ( + ECHO [ERROR] Missing file: UnityLauncherPro\bin\Release\UnityLauncherPro.exe + SET "error=1" +) +IF NOT EXIST "UnityLauncherPro\Images\icon.ico" ( + ECHO [ERROR] Missing file: UnityLauncherPro\Images\icon.ico + SET "error=1" +) + +IF %error% NEQ 0 ( + ECHO [ERROR] Required files are missing. Aborting installer build. + EXIT /B 1 +) + + +ECHO: +ECHO === Building Installer === +ECHO Current dir: %CD% + +IF NOT EXIST "UnityLauncherPro.sln" ( + ECHO [ERROR] Solution file not found: UnityLauncherPro.sln + EXIT /B 1 +) + +SET "installer_project=UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj" + +IF NOT EXIST "%installer_project%" ( + ECHO [ERROR] Installer project not found: %installer_project% + EXIT /B 1 +) + +ECHO Running: +ECHO "%devenv_path%" "UnityLauncherPro.sln" /Rebuild "Release" /Project "%installer_project%" + +"%devenv_path%" "UnityLauncherPro.sln" /Rebuild "Release" /Project "%installer_project%" > build_output.log 2>&1 +SET "exitCode=%ERRORLEVEL%" + + +ECHO: +ECHO === Build Complete === + +REM Optional cleanup: disable workaround +REG DELETE "HKCU\Software\Microsoft\VisualStudio\Setup" /v VSDisableOutOfProcBuild /f >NUL 2>&1 + +ENDLOCAL +EXIT /B %exitCode% diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6b201eb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# Contributing to UnityLauncherPro + +Thanks for your interest in contributing! +Here’s how you can help: + +## How to Contribute + +0. **Open Issue** Describe your idea first (if its useful, it might get accepted) OR check existing issues and comment there +1. **Fork** the repository +2. **Clone** your fork: `git clone https://github.com/YOURUSERNAME/UnityLauncherPro.git` +3. Optional: **Create a new branch**: `git checkout -b feature-name` +4. **Make your changes** +5. **Commit**: `git commit -m "Add feature XYZ"` +6. **Push**: `git push origin feature-name` +7. **Open a Pull Request** from your fork + +## Reporting Bugs + +- Use the **Issues** tab +- Include **steps to reproduce**, screenshots, and error messages + +## Suggesting Features + +- Open an issue with `[Feature]` in the title +- Describe the problem your feature solves +- Note: Not all features get merged! *i'd like to keep workflows and UI something close to my own preferences (Sorry!), but you can of course make your own forks with additional features! + +## Code Style & External Libraries + +- Style is not enforced +- Simple code is good and functions can be as long as they need, to do the task (but can extract commonly used parts/methods into Tools or other helper libraries) +- Avoid using external packages/nugets/dependencies (to keep this as a small single exe build) +- Try to keep main features fast (or even improve existing features to make this more lightweight and faster to start etc.) + +## Need Help? + +Feel free to open an issue or post in discussion. + +--- + +Thanks for contributing! diff --git a/README.md b/README.md index 22ec5bb..45f2a03 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ -# UnityLauncherPro -[![Build Status](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/main.yml/badge.svg)](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [![Downloads](https://img.shields.io/github/downloads/unitycoder/unitylauncherpro/total)](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [![GitHub license](https://img.shields.io/github/license/unitycoder/UnityLauncherPro)](https://github.com/unitycoder/UnityLauncherPro/blob/master/LICENSE) [](https://discord.gg/cXT97hU) [![VirusTotal scan now](https://img.shields.io/static/v1?label=VirusTotal&message=Scan)](https://www.virustotal.com/gui/url/e123b616cf4cbe3d3f7ba13b0d88cf5fff4638f72d5b9461088d0b11e9a41de3?nocache=1) [![CodeQL](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml/badge.svg)](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml) +# Disclaimer +This is un-official, alternative Project launcher for Unity Editor. +These materials are not sponsored by or affiliated with Unity Technologies or its affiliates. “Unity” is a trademark or registered trademark of Unity Technologies or its affiliates in the U.S. and elsewhere. +# Project Launcher For Unity +[![Build Status](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/main.yml/badge.svg)](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [![Downloads](https://img.shields.io/github/downloads/unitycoder/unitylauncherpro/total)](https://github.com/unitycoder/UnityLauncherPro/releases/latest/download/UnityLauncherPro.zip) [![GitHub license](https://img.shields.io/github/license/unitycoder/UnityLauncherPro)](https://github.com/unitycoder/UnityLauncherPro/blob/master/LICENSE) [](https://discord.gg/cXT97hU) [![VirusTotal scan now](https://img.shields.io/static/v1?label=VirusTotal&message=Scan)](https://www.virustotal.com/gui/url/e123b616cf4cbe3d3f7ba13b0d88cf5fff4638f72d5b9461088d0b11e9a41de3?nocache=1) [![CodeQL](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml/badge.svg)](https://github.com/unitycoder/UnityLauncherPro/actions/workflows/codeql.yml) Handle all your Unity versions and Projects easily! @@ -27,6 +30,9 @@ Handle all your Unity versions and Projects easily! - Select template for new project (template based on selected unity version) - And more: https://github.com/unitycoder/UnityLauncherPro/wiki/Launcher-Comparison +### Powered by +[![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSourceSupport) + ### Forum Thread https://forum.unity.com/threads/unity-launcher-launch-correct-unity-versions-for-each-project-automatically.488718/ @@ -37,17 +43,20 @@ https://github.com/unitycoder/UnityLauncherPro/wiki See DEV branch for latest commits https://github.com/unitycoder/UnityLauncherPro/tree/dev
Pre-releases are sometimes available from dev branch: https://github.com/unitycoder/UnityLauncherPro/releases +### Contributing +See https://github.com/unitycoder/UnityLauncherPro/blob/master/CONTRIBUTING.md + ### Screenshots -![image](https://user-images.githubusercontent.com/5438317/71485879-184b3a00-281c-11ea-97db-73c5dfa9bb4e.png) +image -![image](https://github.com/unitycoder/UnityLauncherPro/assets/5438317/21eb1fcd-3cb1-4dea-8133-9ce440de77d8) +image -![image](https://github.com/unitycoder/UnityLauncherPro/assets/5438317/2942c1d7-2006-4dee-8b68-e1f6f2e0fbf4) +image -![image](https://github.com/unitycoder/UnityLauncherPro/assets/5438317/6f8dce07-c640-42db-a1ef-d8bcc7a80cc2) +image -![image](https://user-images.githubusercontent.com/5438317/206923022-4b4bb8ed-0351-408f-b1d3-82bd6eefbc45.png) +image ### Perform tasks on selected project ![image](https://github.com/unitycoder/UnityLauncherPro/assets/5438317/a0b468ba-e3a6-420b-8155-78bc32814752) @@ -64,9 +73,12 @@ Pre-releases are sometimes available from dev branch: https://github.com/unityco ### View and Select current platform ![unitylauncherpro_platform](https://user-images.githubusercontent.com/5438317/132997691-5ed50f1d-e285-4c83-b356-46c1e3f431e4.gif) -### Rename Project title -![pro-rename](https://user-images.githubusercontent.com/5438317/193453048-aa5527c6-a345-4f93-b934-f68ac2524cac.gif) -
Old (winforms) version is here: https://github.com/unitycoder/UnityLauncher + + + + + + diff --git a/UnityLauncherPro.sln b/UnityLauncherPro.sln index 63fd938..d5fe6c9 100644 --- a/UnityLauncherPro.sln +++ b/UnityLauncherPro.sln @@ -1,14 +1,13 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.539 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.00000.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityLauncherPro", "UnityLauncherPro\UnityLauncherPro.csproj", "{EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}" EndProject +Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "UnityLauncherProInstaller", "UnityLauncherProInstaller\UnityLauncherProInstaller.vdproj", "{249180EF-BFC1-9DD7-48CC-E2B9253A64E0}" +EndProject Global - GlobalSection(Performance) = preSolution - HasPerformanceSessions = true - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU @@ -18,6 +17,9 @@ Global {EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}.Debug|Any CPU.Build.0 = Debug|Any CPU {EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}.Release|Any CPU.ActiveCfg = Release|Any CPU {EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}.Release|Any CPU.Build.0 = Release|Any CPU + {249180EF-BFC1-9DD7-48CC-E2B9253A64E0}.Debug|Any CPU.ActiveCfg = Debug + {249180EF-BFC1-9DD7-48CC-E2B9253A64E0}.Release|Any CPU.ActiveCfg = Release + {249180EF-BFC1-9DD7-48CC-E2B9253A64E0}.Release|Any CPU.Build.0 = Release EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -28,4 +30,7 @@ Global GlobalSection(Performance) = preSolution HasPerformanceSessions = true EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal diff --git a/UnityLauncherPro/App.xaml b/UnityLauncherPro/App.xaml index 1d882de..aebdd7d 100644 --- a/UnityLauncherPro/App.xaml +++ b/UnityLauncherPro/App.xaml @@ -136,7 +136,7 @@ - + @@ -257,6 +257,7 @@ + @@ -452,6 +453,10 @@ + + + + @@ -530,9 +535,6 @@ - - - diff --git a/UnityLauncherPro/App.xaml.cs b/UnityLauncherPro/App.xaml.cs index 180b5f2..d14e416 100644 --- a/UnityLauncherPro/App.xaml.cs +++ b/UnityLauncherPro/App.xaml.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; namespace UnityLauncherPro { diff --git a/UnityLauncherPro/Controls/SearchBoxControl.xaml b/UnityLauncherPro/Controls/SearchBoxControl.xaml new file mode 100644 index 0000000..c9d0fb6 --- /dev/null +++ b/UnityLauncherPro/Controls/SearchBoxControl.xaml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + diff --git a/UnityLauncherPro/Controls/SearchBoxControl.xaml.cs b/UnityLauncherPro/Controls/SearchBoxControl.xaml.cs new file mode 100644 index 0000000..97ab6d4 --- /dev/null +++ b/UnityLauncherPro/Controls/SearchBoxControl.xaml.cs @@ -0,0 +1,52 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; + +namespace UnityLauncherPro.Controls +{ + public partial class SearchBoxControl : UserControl + { + public event TextChangedEventHandler SearchTextChanged; + public event RoutedEventHandler SearchCleared; + + public event KeyEventHandler SearchKeyDown; + + public SearchBoxControl() + { + InitializeComponent(); + } + + public string SearchText + { + get { return txtSearchBox.Text; } + set { txtSearchBox.Text = value; } + } + + public new void Focus() + { + txtSearchBox.Focus(); + txtSearchBox.Select(txtSearchBox.Text.Length, 0); + } + + public void Clear() + { + txtSearchBox.Text = ""; + } + + private void TxtSearchBox_PreviewKeyDown(object sender, KeyEventArgs e) + { + SearchKeyDown?.Invoke(this, e); + } + + private void TxtSearchBox_TextChanged(object sender, TextChangedEventArgs e) + { + SearchTextChanged?.Invoke(this, e); + } + + private void OnClearSearchClick(object sender, RoutedEventArgs e) + { + Clear(); + SearchCleared?.Invoke(this, e); + } + } +} diff --git a/UnityLauncherPro/Converters/LastModifiedConverter.cs b/UnityLauncherPro/Converters/LastModifiedConverter.cs index 710dd14..a0f2b45 100644 --- a/UnityLauncherPro/Converters/LastModifiedConverter.cs +++ b/UnityLauncherPro/Converters/LastModifiedConverter.cs @@ -23,5 +23,23 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu return DateTime.ParseExact((string)value, MainWindow.currentDateFormat, culture); } + } + + // just for tooltip + [ValueConversion(typeof(DateTime), typeof(String))] + public class LastModifiedConverterTooltip : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) return null; + DateTime date = (DateTime)value; + return date.ToString(MainWindow.currentDateFormat); + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return DateTime.ParseExact((string)value, MainWindow.currentDateFormat, culture); + } + } } diff --git a/UnityLauncherPro/Converters/ThumbnailConverter.cs b/UnityLauncherPro/Converters/ThumbnailConverter.cs new file mode 100644 index 0000000..955194b --- /dev/null +++ b/UnityLauncherPro/Converters/ThumbnailConverter.cs @@ -0,0 +1,83 @@ +using System; +using System.Globalization; +using System.IO; +using System.Windows; +using System.Windows.Data; +using System.Windows.Media.Imaging; + +namespace UnityLauncherPro.Converters +{ + public class ThumbnailConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + // Return UnsetValue if no project is selected + if (value == null) + { + return DependencyProperty.UnsetValue; + } + + if (value is Project project) + { + if (!string.IsNullOrEmpty(project.Path)) + { + string thumbnailPath = Path.Combine(project.Path, "ProjectSettings", "icon.png"); + + if (File.Exists(thumbnailPath)) + { + try + { + // Check if this is for Width/Height parameter + if (parameter != null && (parameter.ToString() == "Width" || parameter.ToString() == "Height")) + { + return 64.0; // Return default dimension + } + + // For Source binding, load the bitmap + var bitmap = new BitmapImage(); + bitmap.BeginInit(); + bitmap.CacheOption = BitmapCacheOption.OnLoad; + bitmap.CreateOptions = BitmapCreateOptions.IgnoreImageCache; + bitmap.UriSource = new Uri(thumbnailPath, UriKind.Absolute); + bitmap.DecodePixelWidth = 64; // Match your display size + bitmap.DecodePixelHeight = 64; + + bitmap.EndInit(); + + // Freeze for cross-thread access + if (bitmap.CanFreeze) + { + bitmap.Freeze(); + } + + return bitmap; + } + catch + { + // Ignore and fall back to UnsetValue for Source, or 64.0 for dimensions + if (parameter != null && (parameter.ToString() == "Width" || parameter.ToString() == "Height")) + { + return 1.0; + } + return DependencyProperty.UnsetValue; + } + } + } + + // Project path doesn't exist or no thumbnail found + if (parameter != null && (parameter.ToString() == "Width" || parameter.ToString() == "Height")) + { + return 1.0; // Return default dimension + } + return DependencyProperty.UnsetValue; + } + + return DependencyProperty.UnsetValue; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/UnityLauncherPro/Data/OnlineTemplateItem.cs b/UnityLauncherPro/Data/OnlineTemplateItem.cs new file mode 100644 index 0000000..6fe485f --- /dev/null +++ b/UnityLauncherPro/Data/OnlineTemplateItem.cs @@ -0,0 +1,38 @@ +using System.ComponentModel; +using System.Windows.Media.Imaging; + +namespace UnityLauncherPro.Data +{ + public class OnlineTemplateItem : INotifyPropertyChanged + { + private bool _isDownloaded; + + public string Name { get; set; } + public string Description { get; set; } + public string RenderPipeline { get; set; } + public string Type { get; set; } // Core, Learning, Sample, + public string PreviewImageURL { get; set; } + public BitmapImage PreviewImage { get; set; } + public string TarBallURL { get; set; } + + public bool IsDownloaded + { + get { return _isDownloaded; } + set + { + if (_isDownloaded != value) + { + _isDownloaded = value; + OnPropertyChanged(nameof(IsDownloaded)); + } + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + protected virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/UnityLauncherPro/Data/Project.cs b/UnityLauncherPro/Data/Project.cs index 5f422d3..7b221ee 100644 --- a/UnityLauncherPro/Data/Project.cs +++ b/UnityLauncherPro/Data/Project.cs @@ -1,10 +1,11 @@ using System; +using System.ComponentModel; using System.Globalization; using System.Windows.Data; namespace UnityLauncherPro { - public class Project : IValueConverter + public class Project : IValueConverter, INotifyPropertyChanged { public string Title { set; get; } public string Version { set; get; } @@ -18,6 +19,19 @@ public class Project : IValueConverter public bool folderExists { set; get; } public string SRP { set; get; } // Scriptable Render Pipeline, TODO add version info? + //public string InfoLabel { set; get; } // this is additional info from Releases API (like vulnerabilities..) + private string _infoLabel; + public string InfoLabel + { + get => _infoLabel; + set + { + if (_infoLabel == value) return; + _infoLabel = value; + OnPropertyChanged(nameof(InfoLabel)); + } + } + // WPF keeps calling this method from AppendFormatHelper, GetNameCore..? not sure if need to return something else or default would be faster? public override string ToString() { @@ -41,5 +55,8 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu { throw new NotSupportedException(); } + + public event PropertyChangedEventHandler PropertyChanged; + protected void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } } \ No newline at end of file diff --git a/UnityLauncherPro/Data/TemplateGraphQLResponse.cs b/UnityLauncherPro/Data/TemplateGraphQLResponse.cs new file mode 100644 index 0000000..32bdd91 --- /dev/null +++ b/UnityLauncherPro/Data/TemplateGraphQLResponse.cs @@ -0,0 +1,49 @@ +namespace UnityLauncherPro.Data +{ + public class TemplateGraphQLResponse + { + public TemplateData data { get; set; } + } + + public class TemplateData + { + public GetTemplates getTemplates { get; set; } + } + + public class GetTemplates + { + public TemplateEdge[] edges { get; set; } + } + + public class TemplateEdge + { + public TemplateNode node { get; set; } + } + + public class TemplateNode + { + public string name { get; set; } + public string packageName { get; set; } + public string description { get; set; } + public string type { get; set; } + public string renderPipeline { get; set; } + public PreviewImage previewImage { get; set; } + public TemplateVersion[] versions { get; set; } + } + + public class PreviewImage + { + public string url { get; set; } + } + + public class TemplateVersion + { + public string name { get; set; } + public Tarball tarball { get; set; } + } + + public class Tarball + { + public string url { get; set; } + } +} \ No newline at end of file diff --git a/UnityLauncherPro/Data/ThemeColor.cs b/UnityLauncherPro/Data/ThemeColor.cs index 24a6232..2dcbd02 100644 --- a/UnityLauncherPro/Data/ThemeColor.cs +++ b/UnityLauncherPro/Data/ThemeColor.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel; using System.Globalization; using System.Windows.Data; using System.Windows.Media; diff --git a/UnityLauncherPro/Data/UnityInstallation.cs b/UnityLauncherPro/Data/UnityInstallation.cs index c43d7f8..5f5d320 100644 --- a/UnityLauncherPro/Data/UnityInstallation.cs +++ b/UnityLauncherPro/Data/UnityInstallation.cs @@ -1,9 +1,10 @@ using System; +using System.ComponentModel; using System.Windows.Data; namespace UnityLauncherPro { - public class UnityInstallation : IValueConverter + public class UnityInstallation : IValueConverter, INotifyPropertyChanged { public string Version { set; get; } public long VersionCode { set; get; } // version as number, cached for sorting @@ -15,12 +16,45 @@ public class UnityInstallation : IValueConverter public bool IsPreferred { set; get; } public string ReleaseType { set; get; } // Alpha, Beta, LTS.. TODO could be enum + //public string InfoLabel { set; get; } // this is additional info from Releases API (like vulnerabilities..) + + private string _infoLabel; + public string InfoLabel + { + get => _infoLabel; + set + { + if (_infoLabel == value) return; + _infoLabel = value; + OnPropertyChanged(nameof(InfoLabel)); + } + } + // https://stackoverflow.com/a/5551986/5452781 public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { string version = value as string; if (string.IsNullOrEmpty(version)) return null; - return MainWindow.unityInstalledVersions.ContainsKey(version); + + bool checkInfoLabel = true; + + if (MainWindow.unityInstalledVersions.ContainsKey(version)) + { + //Console.WriteLine("checking version: "+version); + if (checkInfoLabel && string.IsNullOrEmpty(InfoLabel) == false) + { + Console.WriteLine("Contains warning: " + version); + return -1; // has warning + } + else + { + return 1; // normal + } + } + else + { + return 0; // not installed + } } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) @@ -28,5 +62,9 @@ public object ConvertBack(object value, Type targetType, object parameter, Syste throw new NotSupportedException(); } + // status label results are ready + public event PropertyChangedEventHandler PropertyChanged; + protected void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); + } } diff --git a/UnityLauncherPro/GetProjects.cs b/UnityLauncherPro/GetProjects.cs index caabb2e..1fbfa8e 100644 --- a/UnityLauncherPro/GetProjects.cs +++ b/UnityLauncherPro/GetProjects.cs @@ -13,12 +13,90 @@ public static class GetProjects static readonly string[] registryPathsToCheck = new string[] { @"SOFTWARE\Unity Technologies\Unity Editor 5.x", @"SOFTWARE\Unity Technologies\Unity Editor 4.x" }; // convert target platform name into valid buildtarget platform name, NOTE this depends on unity version, now only 2019 and later are supported - public static Dictionary remapPlatformNames = new Dictionary { { "StandaloneWindows64", "Win64" }, { "StandaloneWindows", "Win" }, { "Android", "Android" }, { "WebGL", "WebGL" } }; + public static Dictionary remapPlatformNames = new Dictionary { + { "StandaloneWindows64", "Win64" }, + { "StandaloneWindows", "Win" }, + { "Android", "Android" }, + { "WebGL", "WebGL" } }; - public static List Scan(bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, StringCollection AllProjectPaths = null, bool searchGitbranchRecursivly = false, bool showSRP = false) + public static List Scan(bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, StringCollection AllProjectPaths = null, bool searchGitbranchRecursively = false, bool showSRP = false) { List projectsFound = new List(); + // first, scan projects from unity hub json file + VisitProjectsInUnityHubJson + ( + getGitBranch, getPlasticBranch, getArguments, + showMissingFolders, showTargetPlatform , searchGitbranchRecursively , showSRP, + project => + { + if (!projectsFound.ContainsProjectWithPath(project.Path)) + projectsFound.Add(project); + + // add found projects to history also (gets added only if its not already there) + Tools.AddProjectToHistory(project.Path); + }); + + // then scan projects from registry + VisitProjectsInRegistry + ( + getGitBranch, getPlasticBranch, getArguments, + showMissingFolders, showTargetPlatform , searchGitbranchRecursively , showSRP, + project => + { + if (!projectsFound.ContainsProjectWithPath(project.Path)) + projectsFound.Add(project); + + // TODO FIXME, this gets called everytime for same projects? + // add found projects to history also (gets added only if its not already there) + Tools.AddProjectToHistory(project.Path); + }); + + // NOTE those 40 projects should be added to custom list, otherwise they will disappear (since last item is not yet added to our list, until its launched once, so need to launch many projects, to start collecting history..) + // but then we would have to loop here again..? or add in the loop above..if doesnt exists on list, and the remove extra items from the end + + // scan info for custom folders (if not already on the list) + if (AllProjectPaths != null) + { + // iterate custom full projects history + foreach (var projectPath in AllProjectPaths) + { + // check if registry list contains this path already + // if not found from registry, add to recent projects list + if (!projectsFound.ContainsProjectWithPath(projectPath)) + { + var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursively, showSRP); + if (p != null) projectsFound.Add(p); + } + } + } + + // sometimes projects are in wrong order, seems to be related to messing up your unity registry, the keys are received in created order (so if you had removed/modified them manually, it might return wrong order instead of 0 - 40) + // sort by modified date, projects without modified date are put to last, NOTE: this would remove projects without modified date (if they become last items, before trimming list on next step) + projectsFound.Sort((x, y) => + { + if (x.Modified == null && y.Modified == null) return 0; // cannot be -1, https://stackoverflow.com/a/42821992/5452781 + if (x.Modified == null) return 1; + if (y.Modified == null) return -1; + return y.Modified.Value.CompareTo(x.Modified.Value); + //return x.Modified.Value.CompareTo(y.Modified.Value); // BUG this breaks something, so that last item platform is wrong (for project that is missing from disk) ? + }); + + // trim list to max amount (older ones are dropped) + if (projectsFound.Count > MainWindow.maxProjectCount) + { + //Console.WriteLine("Trimming projects list to " + MainWindow.maxProjectCount + " projects"); + projectsFound.RemoveRange(MainWindow.maxProjectCount, projectsFound.Count - MainWindow.maxProjectCount); + } + return projectsFound; + } // Scan() + + // visits each project stored in the Unity registry, invoking the visitor for each one + private static void VisitProjectsInRegistry( + bool getGitBranch, bool getPlasticBranch, bool getArguments, + bool showMissingFolders, bool showTargetPlatform , bool searchGitbranchRecursively , bool showSRP, + Action visitor) + { var hklm = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); // check each version path @@ -53,74 +131,112 @@ public static List Scan(bool getGitBranch = false, bool getPlasticBranc projectPath = (string)key.GetValue(valueName); } - var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursivly, showSRP); + var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursively, showSRP); //Console.WriteLine(projectPath+" "+p.TargetPlatform); // if want to hide project and folder path for screenshot - //p.Title = "Example Project "; - //p.Path = "C:/Projects/ExamplePath/MyProj"; - + //p.Title = "Example Project"; + //p.Path = "C:/Projects/MyProj"; if (p != null) { - projectsFound.Add(p); - - // add found projects to history also (gets added only if its not already there) - Tools.AddProjectToHistory(p.Path); + visitor(p); } } // valid key } // each key } // for each registry root + } // VisitProjectsInRegistry() - // NOTE those 40 projects should be added to custom list, otherwise they will disappear (since last item is not yet added to our list, until its launched once, so need to launch many projects, to start collecting history..) - // but then we would have to loop here again..? or add in the loop above..if doesnt exists on list, and the remove extra items from the end + private static void VisitProjectsInUnityHubJson( + bool getGitBranch, bool getPlasticBranch, bool getArguments, + bool showMissingFolders, bool showTargetPlatform , bool searchGitbranchRecursively , bool showSRP, + Action visitor) + { + string hubProjectsFile = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "UnityHub", "projects-v1.json"); - // scan info for custom folders (if not already on the list) - if (AllProjectPaths != null) + if (!File.Exists(hubProjectsFile)) + return; + + string json; + try { json = File.ReadAllText(hubProjectsFile); } + catch { return; } + + int dataIndex = json.IndexOf("\"data\":"); + if (dataIndex == -1) return; + + // find the opening { of the data object + int dataStart = json.IndexOf('{', dataIndex + 7); + if (dataStart == -1) return; + + int searchFrom = dataStart + 1; + while (true) { - // iterate custom full projects history - foreach (var projectPath in AllProjectPaths) + // find the start of the next project entry object + int entryStart = json.IndexOf('{', searchFrom); + if (entryStart == -1) break; + + // find the matching closing } + int entryEnd = JsonParser.FindMatchingBrace(json, entryStart); + if (entryEnd == -1) break; + + string entry = json.Substring(entryStart, entryEnd - entryStart + 1); + + string projectPath = JsonParser.GetStringValue(entry, "path"); + if (!string.IsNullOrEmpty(projectPath)) { - // check if registry list contains this path already, then skip it - bool found = false; - for (int i = 0, len = projectsFound.Count; i < len; i++) + // unescape JSON backslashes and convert to normal path separators + projectPath = projectPath.Replace(@"\\", @"/"); + + // collect project info from disk, but override with hub json data where its more authoritative + // todo: an optimization could be to only get data from disk that is missing from json, + // instead of getting all data and then overriding. + var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursively, showSRP); + if (p != null) { - if (projectsFound[i].Path == projectPath) + string title = JsonParser.GetStringValue(entry, "title"); + if (!string.IsNullOrEmpty(title)) p.Title = title; + + // NOTE: this has changed in newer hub versions? (not checking from folder anymore?) + // lastModified is a Unix millisecond timestamp + string lastModifiedStr = JsonParser.GetNumberValue(entry, "lastModified"); + if (long.TryParse(lastModifiedStr, out long lastModifiedMs)) + p.Modified = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(lastModifiedMs).ToLocalTime(); + + string version = JsonParser.GetStringValue(entry, "version"); + if (!string.IsNullOrEmpty(version)) p.Version = version; + + if (showTargetPlatform) { - found = true; - break; + string buildTarget = JsonParser.GetStringValue(entry, "buildTarget"); + p.TargetPlatform = Tools.GetTargetPlatformFromRaw(buildTarget); } - } - // if not found from registry, add to recent projects list - if (found == false) - { - var p = GetProjectInfo(projectPath, getGitBranch, getPlasticBranch, getArguments, showMissingFolders, showTargetPlatform, searchGitbranchRecursivly, showSRP); - if (p != null) projectsFound.Add(p); + if (showSRP) + { + string renderPipeline = JsonParser.GetStringValue(entry, "renderPipeline"); + if (!string.IsNullOrEmpty(renderPipeline)) p.SRP = renderPipeline; + } + + visitor(p); } } - } - // sometimes projects are in wrong order, seems to be related to messing up your unity registry, the keys are received in created order (so if you had removed/modified them manually, it might return wrong order instead of 0 - 40) - // sort by modified date, projects without modified date are put to last, NOTE: this would remove projects without modified date (if they become last items, before trimming list on next step) - projectsFound.Sort((x, y) => - { - if (x.Modified == null && y.Modified == null) return 0; // cannot be -1, https://stackoverflow.com/a/42821992/5452781 - if (x.Modified == null) return 1; - if (y.Modified == null) return -1; - return y.Modified.Value.CompareTo(x.Modified.Value); - //return x.Modified.Value.CompareTo(y.Modified.Value); // BUG this breaks something, so that last item platform is wrong (for project that is missing from disk) ? - }); + searchFrom = entryEnd + 1; + } + } - // trim list to max amount (older ones are dropped) - if (projectsFound.Count > MainWindow.maxProjectCount) + private static bool ContainsProjectWithPath(this List projects, string projectPath) + { + foreach (var p in projects) { - //Console.WriteLine("Trimming projects list to " + MainWindow.maxProjectCount + " projects"); - projectsFound.RemoveRange(MainWindow.maxProjectCount, projectsFound.Count - MainWindow.maxProjectCount); + if (string.Equals(p.Path, projectPath, StringComparison.OrdinalIgnoreCase)) + return true; } - return projectsFound; - } // Scan() + return false; + } - static Project GetProjectInfo(string projectPath, bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, bool searchGitbranchRecursivly = false, bool showSRP = false) + static Project GetProjectInfo(string projectPath, bool getGitBranch = false, bool getPlasticBranch = false, bool getArguments = false, bool showMissingFolders = false, bool showTargetPlatform = false, bool searchGitbranchRecursively = false, bool showSRP = false) { bool folderExists = Directory.Exists(projectPath); @@ -165,11 +281,12 @@ static Project GetProjectInfo(string projectPath, bool getGitBranch = false, boo string gitBranch = ""; if (getGitBranch == true) { - gitBranch = folderExists ? Tools.ReadGitBranchInfo(projectPath, searchGitbranchRecursivly) : null; + gitBranch = folderExists ? Tools.ReadGitBranchInfo(projectPath, searchGitbranchRecursively) : null; + // check for plastic, if enabled if (getPlasticBranch == true && gitBranch == null) { - gitBranch = folderExists ? Tools.ReadPlasticBranchInfo(projectPath) : null; + gitBranch = folderExists ? Tools.ReadPlasticBranchInfo(projectPath, searchGitbranchRecursively) : null; } } @@ -219,6 +336,12 @@ public static bool RemoveRecentProject(string projectPathToRemove) { bool result = false; + if (RemoveProjectFromUnityHubJson(projectPathToRemove)) + { + //Console.WriteLine("Deleted Unity Hub project item: " + projectPathToRemove); + result = true; + } + var hklm = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64); // check each version path @@ -280,10 +403,115 @@ public static bool RemoveRecentProject(string projectPathToRemove) result = true; } - return result; } // RemoveRecentProject() + private static bool RemoveProjectFromUnityHubJson(string projectPathToRemove) + { + string hubProjectsFile = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), + "UnityHub", "projects-v1.json"); + + if (!File.Exists(hubProjectsFile)) + return false; + + string json; + + try + { + json = File.ReadAllText(hubProjectsFile); + } + catch + { + return false; + } + + string wantedPath = NormalizeProjectPath(projectPathToRemove); + + int dataIndex = json.IndexOf("\"data\":"); + if (dataIndex == -1) + return false; + + int dataStart = json.IndexOf('{', dataIndex + 7); + if (dataStart == -1) + return false; + + int searchFrom = dataStart + 1; + + while (true) + { + int entryStart = json.IndexOf('{', searchFrom); + if (entryStart == -1) + break; + + int entryEnd = JsonParser.FindMatchingBrace(json, entryStart); + if (entryEnd == -1) + break; + + string entry = json.Substring(entryStart, entryEnd - entryStart + 1); + string projectPath = JsonParser.GetStringValue(entry, "path"); + + if (!string.IsNullOrEmpty(projectPath)) + { + projectPath = NormalizeProjectPath(projectPath); + + if (string.Equals(projectPath, wantedPath, StringComparison.OrdinalIgnoreCase)) + { + int removeStart = entryStart; + int removeEnd = entryEnd + 1; + + // Prefer removing comma after this object. + int i = removeEnd; + while (i < json.Length && char.IsWhiteSpace(json[i])) + i++; + + if (i < json.Length && json[i] == ',') + { + removeEnd = i + 1; + } + else + { + // Otherwise remove comma before this object. + i = removeStart - 1; + while (i >= 0 && char.IsWhiteSpace(json[i])) + i--; + + if (i >= 0 && json[i] == ',') + removeStart = i; + } + + json = json.Remove(removeStart, removeEnd - removeStart); + + try + { + File.WriteAllText(hubProjectsFile, json); + return true; + } + catch + { + return false; + } + } + } + + searchFrom = entryEnd + 1; + } + + return false; + } + + private static string NormalizeProjectPath(string path) + { + if (string.IsNullOrEmpty(path)) + return ""; + + return path + .Replace(@"\\", "/") + .Replace("\\", "/") + .Trim() + .TrimEnd('/'); + } + } // class } // namespace diff --git a/UnityLauncherPro/GetUnityInstallations.cs b/UnityLauncherPro/GetUnityInstallations.cs index f12bc77..28a0a31 100644 --- a/UnityLauncherPro/GetUnityInstallations.cs +++ b/UnityLauncherPro/GetUnityInstallations.cs @@ -11,7 +11,6 @@ public static class GetUnityInstallations { static Dictionary platformNames = new Dictionary { { "androidplayer", "Android" }, { "windowsstandalonesupport", "Win" }, { "linuxstandalonesupport", "Linux" }, { "LinuxStandalone", "Linux" }, { "OSXStandalone", "OSX" }, { "webglsupport", "WebGL" }, { "metrosupport", "UWP" }, { "iossupport", "iOS" } }; - // returns unity installations public static List Scan() { @@ -49,7 +48,23 @@ public static List Scan() var haveUninstaller = File.Exists(uninstallExe); var exePath = Path.Combine(editorFolder, "Unity.exe"); - if (File.Exists(exePath) == false) continue; + +// bool supportTuanjie = true; + if (File.Exists(exePath) == false) + { + //if (supportTuanjie == false) + { + continue; + } + //else + //{ + // exePath = Path.Combine(editorFolder, "Tuanjie.exe"); + // if (File.Exists(exePath) == false) + // { + // continue; + // } + //} + } // get full version number from uninstaller (or try exe, if no uninstaller) var version = Tools.GetFileVersionData(haveUninstaller ? uninstallExe : exePath); @@ -65,6 +80,9 @@ public static List Scan() unity.IsPreferred = (version == MainWindow.preferredVersion); unity.ProjectCount = GetProjectCountForUnityVersion(version); + // TODO here need to check for vulnerabilities from CACHED data, BUT if its cached, then it might be old + unity.InfoLabel = null; + if (Tools.IsAlpha(version)) { unity.ReleaseType = "Alpha"; diff --git a/UnityLauncherPro/GetUnityUpdates.cs b/UnityLauncherPro/GetUnityUpdates.cs index 0cdf33e..692dcef 100644 --- a/UnityLauncherPro/GetUnityUpdates.cs +++ b/UnityLauncherPro/GetUnityUpdates.cs @@ -16,6 +16,7 @@ public static class GetUnityUpdates private const int DelayBetweenBatches = 1000; // 1 second in milliseconds private const string CacheFileName = "UnityVersionCache.json"; private static readonly HttpClient Client = new HttpClient(); + public static string unofficalReleasesURL = "https://raw.githubusercontent.com/unitycoder/UnofficialUnityReleasesWatcher/refs/heads/main/unity-releases.md"; static Dictionary unofficialReleaseURLs = new Dictionary(); @@ -30,23 +31,28 @@ public static async Task> FetchAll(bool useUnofficialList = f { var unofficialVersions = await FetchUnofficialVersions(cachedVersions); unofficialReleaseURLs.Clear(); - // TODO modify FetchUnofficialVersions to put items in this dictionary directlys + + // TODO modify FetchUnofficialVersions to put items in this dictionary directly foreach (var version in unofficialVersions) { - //Console.WriteLine("unofficial: " + version.Version + " , " + version.directURL); + Console.WriteLine("version in unofficials: " + version); + // add only if not there yet if (unofficialReleaseURLs.ContainsKey(version.Version) == false) { + Console.WriteLine("added unofficial: " + version.Version + " , " + version.directURL); unofficialReleaseURLs.Add(version.Version, version.directURL); } } + // combine allVersions = unofficialVersions.Concat(allVersions).ToList(); } - if (newVersions.Count > 0) + if (newVersions.Count > 0 || (useUnofficialList && unofficialReleaseURLs.Count > 0)) { SaveCachedVersions(allVersions); } + return allVersions; } @@ -57,23 +63,28 @@ public static async Task> FetchUnofficialVersions(List FetchDownloadUrl(string unityVersion) } } - static string ParseHashCodeFromURL(string url) - { - // https://beta.unity3d.com/download/330fbefc18b7/download.html#6000.1.0a8 > 330fbefc18b7 - - int hashStart = url.IndexOf("download/") + 9; - int hashEnd = url.IndexOf("/download.html", hashStart); - return url.Substring(hashStart, hashEnd - hashStart); - } - private static async Task ExtractDownloadUrlAsync(string json, string unityVersion) { //Console.WriteLine("json: " + json + " vers: " + unityVersion); if (json.Contains("\"results\":[]")) { - Console.WriteLine("No results found from releases API, checking unofficial list (if enabled)"); + Console.WriteLine("No results found from releases API, checking unofficial list (if enabled), v=" + unityVersion); + + // print unofficialReleaseURLs + foreach (var kvp in unofficialReleaseURLs) + { + Console.WriteLine($"Unofficial: {kvp.Key} => {kvp.Value}"); + } if (unofficialReleaseURLs.ContainsKey(unityVersion)) { - Console.WriteLine("Unofficial release found in the list."); + Console.WriteLine("Unofficial release found in the list: "); - string unityHash = ParseHashCodeFromURL(unofficialReleaseURLs[unityVersion]); + string unityHash = Tools.ParseHashCodeFromURL(unofficialReleaseURLs[unityVersion]); // Console.WriteLine(unityHash); string downloadURL = Tools.ParseDownloadURLFromWebpage(unityVersion, unityHash, false, true); // Console.WriteLine("direct download url: "+downloadURL); @@ -377,15 +385,54 @@ private static string GetStringValue(string source, string propertyName) private static List LoadCachedVersions() { - string configFilePath = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).FilePath; + string configFilePath = ConfigurationManager + .OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal) + .FilePath; + string configDirectory = Path.GetDirectoryName(configFilePath); - if (configDirectory == null) return new List(); + if (string.IsNullOrEmpty(configDirectory)) + return new List(); + + Directory.CreateDirectory(configDirectory); string cacheFilePath = Path.Combine(configDirectory, CacheFileName); - if (!File.Exists(cacheFilePath)) return new List(); - string json = File.ReadAllText(cacheFilePath); - return ParseCachedUnityVersions(json); + // copy from embedded resource on first run + if (!File.Exists(cacheFilePath)) + { + try + { + string resourceName = $"{typeof(GetUnityUpdates).Namespace}.Resources.{CacheFileName}"; + using (var stream = typeof(GetUnityUpdates).Assembly.GetManifestResourceStream(resourceName)) + { + if (stream != null) + { + using (var fileStream = File.Create(cacheFilePath)) + { + stream.CopyTo(fileStream); + } + } + else + { + return new List(); + } + } + } + catch + { + return new List(); + } + } + + try + { + string json = File.ReadAllText(cacheFilePath); + return ParseCachedUnityVersions(json); + } + catch + { + return new List(); + } } private static void SaveCachedVersions(List versions) @@ -405,5 +452,27 @@ private static void SaveCachedVersions(List versions) //Console.WriteLine("Saving cachedrelease: " + cacheFilePath); File.WriteAllText(cacheFilePath, json); } + + internal static async Task CheckUnofficialVersionList(string version) + { + // fetch md page from unofficalReleasesURL + var content = await Client.GetStringAsync(unofficalReleasesURL); + // parse lines + var lines = content.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + if (line.StartsWith("- ")) // Identify Markdown list items + { + var urlPart = line.Substring(4).Trim(); // bug in server, has double - + var foundVersion = ExtractVersionFromUrl(urlPart); + if (foundVersion == version) + { + Console.WriteLine("Found unofficial version in the list: " + foundVersion + " , " + urlPart); + return urlPart; + } + } + } + return null; + } } } diff --git a/UnityLauncherPro/Helpers/Github.cs b/UnityLauncherPro/Helpers/Github.cs new file mode 100644 index 0000000..b81410b --- /dev/null +++ b/UnityLauncherPro/Helpers/Github.cs @@ -0,0 +1,487 @@ +using System; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; +using System.Security.Cryptography; +using System.Diagnostics; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace UnityLauncherPro.Helpers +{ + public class GitHubTokenValidationResult + { + public bool IsValid { get; set; } + public string Login { get; set; } + public string Name { get; set; } + public string Error { get; set; } + public HttpStatusCode StatusCode { get; set; } + } + + public class GitHubCreateRepoResult + { + public bool Success { get; set; } + public string Name { get; set; } + //public string FullName { get; set; } + //public string HtmlUrl { get; set; } + //public string CloneUrl { get; set; } + //public string SshUrl { get; set; } + public string Error { get; set; } + public HttpStatusCode StatusCode { get; set; } + } + + public static class GithubActions + { + + public static async Task CreateRepositoryAsync(string token, string repoName, string description = "", bool isPrivate = true, bool autoInit = false, string organization = null) + { + if (string.IsNullOrWhiteSpace(token)) + { + return new GitHubCreateRepoResult + { + Success = false, + Error = "Token is empty." + }; + } + + if (string.IsNullOrWhiteSpace(repoName)) + { + return new GitHubCreateRepoResult + { + Success = false, + Error = "Repository name is empty." + }; + } + + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + + using (var client = new HttpClient()) + { + client.DefaultRequestHeaders.UserAgent.ParseAdd(MainWindow.appName); + client.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("Bearer", token.Trim()); + + client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github+json"); + client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); + + var json = ('{' + + $"\"name\": \"{repoName}\"," + + $"\"description\": \"{description ?? ""}\"," + + $"\"private\": {isPrivate.ToString().ToLower()}," + + $"\"auto_init\": {autoInit.ToString().ToLower()}" + + '}'); + + using (var content = new StringContent(json, Encoding.UTF8, "application/json")) + { + HttpResponseMessage response; + var endpoint = string.IsNullOrWhiteSpace(organization) + ? "https://api.github.com/user/repos" + : "https://api.github.com/orgs/" + Uri.EscapeDataString(organization.Trim()) + "/repos"; + + try + { + response = await client.PostAsync(endpoint, content); + } + catch (Exception ex) + { + return new GitHubCreateRepoResult + { + Success = false, + Error = "Request failed: " + ex.Message + }; + } + + string responseText = await response.Content.ReadAsStringAsync(); + + if (response.IsSuccessStatusCode) + { + return new GitHubCreateRepoResult + { + Success = true, + StatusCode = response.StatusCode + //Name = (string)result["name"], + //FullName = (string)result["full_name"], + //HtmlUrl = (string)result["html_url"], + //CloneUrl = (string)result["clone_url"], + //SshUrl = (string)result["ssh_url"] + }; + } + + return new GitHubCreateRepoResult + { + Success = false, + StatusCode = response.StatusCode, + Error = "GitHub API error: " + + (int)response.StatusCode + " " + + response.ReasonPhrase + "\n" + + responseText + }; + } + } + } + + public static async Task> GetUserOrganizationsAsync(string token) + { + var organizations = new List(); + + if (string.IsNullOrWhiteSpace(token)) return organizations; + + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + + using (var client = new HttpClient()) + { + client.DefaultRequestHeaders.UserAgent.ParseAdd(MainWindow.appName); + client.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("Bearer", token.Trim()); + + client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github+json"); + client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); + + HttpResponseMessage response; + + try + { + response = await client.GetAsync("https://api.github.com/user/orgs"); + } + catch + { + return organizations; + } + + if (!response.IsSuccessStatusCode) return organizations; + + string responseText = await response.Content.ReadAsStringAsync(); + var matches = Regex.Matches(responseText, "\"login\"\\s*:\\s*\"([^\"]+)\""); + + for (int i = 0; i < matches.Count; i++) + { + organizations.Add(matches[i].Groups[1].Value); + } + } + + return organizations; + } + + public static async Task InitRepositoryAsync(string baseDir, string projectName, bool initGitLfs = false, string defaultBranch = "main") + { + string projectPath = string.IsNullOrWhiteSpace(projectName) + ? Path.GetFullPath(baseDir) + : Path.GetFullPath(Path.Combine(baseDir, projectName)); + + if (!Directory.Exists(projectPath)) Directory.CreateDirectory(projectPath); + + // Git 2.28+ supports --initial-branch + await RunGitAsync(projectPath, "init --initial-branch=\"" + defaultBranch + "\""); + + string gitignorePath = Path.Combine(projectPath, ".gitignore"); + + if (initGitLfs) + { + try + { + // Local repo setup. Requires Git LFS to be installed on the user's machine. + await RunGitAsync(projectPath, "lfs install --local"); + } + catch + { + // Git repo is still valid even if LFS init fails. + // Log this in your app if you have a logger. + } + } + + return projectPath; + } + + public static async Task RunGitAsync(string workingDirectory, string arguments) + { + await Task.Run(delegate + { + var startInfo = new ProcessStartInfo + { + FileName = "git", + Arguments = arguments, + WorkingDirectory = workingDirectory, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + Console.WriteLine("run " + startInfo.FileName + " " + startInfo.Arguments); + + using (var process = new Process()) + { + process.StartInfo = startInfo; + + process.Start(); + + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + + process.WaitForExit(); + + if (process.ExitCode != 0) + { + Console.WriteLine("failed to run git command: " + error); + throw new Exception( + "Git command failed:\n" + + "git " + arguments + "\n\n" + + "Output:\n" + output + "\n\n" + + "Error:\n" + error); + } + } + }); + } + + + + + // checks if repo is valid and if it already exists in the user's account. Returns null if valid, otherwise an error message. + public static async Task ValidateRepoName(string repoName, string userName) + { + // validate string locally + if (string.IsNullOrEmpty(repoName)) return "Repository name cannot be empty."; + + // regex "The repository name can only contain ASCII letters, digits, and the characters ., -, and _." + if (!System.Text.RegularExpressions.Regex.IsMatch(repoName, @"^[a-zA-Z0-9._-]+$")) return "Repository name can only contain letters, digits, ., -, and _."; + + // check if repo already exists in user's account + var token = GitHubTokenStore.LoadToken(); + if (string.IsNullOrWhiteSpace(token)) return "No GitHub token found. Please set a token first."; + + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + + using (var client = new HttpClient()) + { + client.DefaultRequestHeaders.UserAgent.ParseAdd(MainWindow.appName); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Trim()); + client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github+json"); + client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); + + HttpResponseMessage response; + try + { + response = await client.GetAsync($"https://api.github.com/repos/{userName}/{repoName}"); + } + catch (Exception ex) + { + return "Request failed: " + ex.Message; + } + + if (response.StatusCode == HttpStatusCode.OK) + return $"Repository '{repoName}' already exists in your account."; + + if (response.StatusCode == HttpStatusCode.NotFound) + return null; // repo does not exist, name is available + + string responseText = await response.Content.ReadAsStringAsync(); + return $"Unexpected GitHub response: {(int)response.StatusCode} {response.ReasonPhrase}\n{responseText}"; + } + } + + + } // GithubActions class + + public static class GitHubAuth + { + public static async Task ValidateTokenAsync(string token) + { + if (string.IsNullOrWhiteSpace(token)) + { + return new GitHubTokenValidationResult + { + IsValid = false, + Error = "Token is empty" + }; + } + + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + + using (var client = new HttpClient()) + { + client.DefaultRequestHeaders.UserAgent.ParseAdd(MainWindow.appName); + client.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue("Bearer", token.Trim()); + + client.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github+json"); + client.DefaultRequestHeaders.Add("X-GitHub-Api-Version", "2022-11-28"); + + HttpResponseMessage response; + + try + { + response = await client.GetAsync("https://api.github.com/user"); + } + catch (Exception ex) + { + return new GitHubTokenValidationResult + { + IsValid = false, + Error = "Request failed: " + ex.Message + }; + } + + string responseText = await response.Content.ReadAsStringAsync(); + + if (response.StatusCode == HttpStatusCode.OK) + { + return new GitHubTokenValidationResult + { + IsValid = true, + Login = JsonParser.GetStringValue(responseText, "login"), + Name = JsonParser.GetStringValue(responseText, "name"), + StatusCode = response.StatusCode + }; + } + + if (response.StatusCode == HttpStatusCode.Unauthorized) + { + return new GitHubTokenValidationResult + { + IsValid = false, + StatusCode = response.StatusCode, + Error = "Invalid, expired, or revoked GitHub token" + }; + } + + if (response.StatusCode == HttpStatusCode.Forbidden) + { + return new GitHubTokenValidationResult + { + IsValid = false, + StatusCode = response.StatusCode, + Error = "GitHub rejected the request. This may be a rate limit or permission issue." + }; + } + + return new GitHubTokenValidationResult + { + IsValid = false, + StatusCode = response.StatusCode, + Error = "Unexpected GitHub response: " + (int)response.StatusCode + " " + response.ReasonPhrase + "\n" + responseText + }; + } + } + } // GitHubAuth class + + + public static class GitHubTokenStore + { + private static readonly string FolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), MainWindow.appName); + private static readonly string FilePath = Path.Combine(FolderPath, MainWindow.appName + ".dat"); + + public static void SaveToken(string token, string username) + { + if (string.IsNullOrWhiteSpace(token)) throw new ArgumentException("Token is empty.", "token"); + + if (!Directory.Exists(FolderPath)) Directory.CreateDirectory(FolderPath); + + string payload = BuildPayload(token, username); + byte[] plainBytes = Encoding.UTF8.GetBytes(payload); + byte[] encryptedBytes = ProtectedData.Protect(plainBytes, null, DataProtectionScope.CurrentUser); + File.WriteAllBytes(FilePath, encryptedBytes); + } + + public static string LoadToken() + { + return LoadValue("token"); + } + + public static string LoadUsername() + { + return LoadValue("username"); + } + + private static string LoadValue(string key) + { + string payload = LoadPayload(); + if (string.IsNullOrWhiteSpace(payload)) return null; + + return ReadValue(payload, key); + } + + private static string LoadPayload() + { + if (!File.Exists(FilePath)) + return null; + + try + { + byte[] encryptedBytes = File.ReadAllBytes(FilePath); + + byte[] plainBytes = ProtectedData.Unprotect(encryptedBytes, null, DataProtectionScope.CurrentUser); + return Encoding.UTF8.GetString(plainBytes); + } + catch + { + return null; + } + } + + private static string BuildPayload(string token, string username) + { + return "token=" + EscapeValue(token) + "\nusername=" + EscapeValue(username); + } + + private static string ReadValue(string payload, string key) + { + string prefix = key + "="; + string[] lines = payload.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + + for (int i = 0; i < lines.Length; i++) + { + string line = lines[i]; + if (!line.StartsWith(prefix, StringComparison.Ordinal)) continue; + return UnescapeValue(line.Substring(prefix.Length)); + } + + return null; + } + + private static string EscapeValue(string value) + { + if (value == null) return string.Empty; + return value.Replace("\\", "\\\\").Replace("\r", "\\r").Replace("\n", "\\n"); + } + + private static string UnescapeValue(string value) + { + if (string.IsNullOrEmpty(value)) return value; + + var builder = new StringBuilder(value.Length); + for (int i = 0; i < value.Length; i++) + { + char c = value[i]; + if (c == '\\' && i + 1 < value.Length) + { + i++; + char next = value[i]; + if (next == 'r') builder.Append('\r'); + else if (next == 'n') builder.Append('\n'); + else builder.Append(next); + } + else + { + builder.Append(c); + } + } + + return builder.ToString(); + } + + public static void DeleteToken() + { + if (File.Exists(FilePath)) + File.Delete(FilePath); + } + + public static bool HasToken() + { + return !string.IsNullOrWhiteSpace(LoadToken()); + } + } + +} // namespace diff --git a/UnityLauncherPro/Helpers/JsonParser.cs b/UnityLauncherPro/Helpers/JsonParser.cs new file mode 100644 index 0000000..7ea3c35 --- /dev/null +++ b/UnityLauncherPro/Helpers/JsonParser.cs @@ -0,0 +1,72 @@ +namespace UnityLauncherPro +{ + internal static class JsonParser + { + // finds the index of the closing } matching the opening { at startIndex + internal static int FindMatchingBrace(string json, int startIndex) + { + int depth = 0; + for (int i = startIndex; i < json.Length; i++) + { + if (json[i] == '{') depth++; + else if (json[i] == '}') { depth--; if (depth == 0) return i; } + } + return -1; + } + + // extracts a JSON string value for the given key + internal static string GetStringValue(string json, string key) + { + int keyIndex = json.IndexOf("\"" + key + "\":"); + if (keyIndex == -1) return null; + int valueStart = json.IndexOf('"', keyIndex + key.Length + 2) + 1; + if (valueStart == 0) return null; + int valueEnd = json.IndexOf('"', valueStart); + if (valueEnd == -1) return null; + return json.Substring(valueStart, valueEnd - valueStart); + } + + // extracts a JSON number value for the given key (returned as string for flexibility) + internal static string GetNumberValue(string json, string key) + { + int keyIndex = json.IndexOf("\"" + key + "\":"); + if (keyIndex == -1) return null; + int valueStart = keyIndex + key.Length + 3; // skip past "key": + while (valueStart < json.Length && json[valueStart] == ' ') valueStart++; + int valueEnd = valueStart; + while (valueEnd < json.Length && (char.IsDigit(json[valueEnd]) || json[valueEnd] == '-')) valueEnd++; + return valueEnd > valueStart ? json.Substring(valueStart, valueEnd - valueStart) : null; + } + + internal static string ExtractJsonString(string json, string key) + { + int keyIndex = json.IndexOf(key + ":"); + if (keyIndex == -1) return null; + + int valueStart = json.IndexOf("\"", keyIndex + key.Length + 1); + if (valueStart == -1) return null; + + int valueEnd = json.IndexOf("\"", valueStart + 1); + if (valueEnd == -1) return null; + + return json.Substring(valueStart + 1, valueEnd - valueStart - 1); + } + + internal static string ExtractNestedJsonString(string json, string parentKey, string childKey) + { + int parentIndex = json.IndexOf(parentKey + ":"); + if (parentIndex == -1) return null; + + // Find the object after parentKey + int objectStart = json.IndexOf("{", parentIndex); + if (objectStart == -1) return null; + + int objectEnd = JsonParser.FindMatchingBrace(json, objectStart); + if (objectEnd == -1) return null; + + string nestedJson = json.Substring(objectStart, objectEnd - objectStart + 1); + return ExtractJsonString(nestedJson, childKey); + } + + } // class +} // namespace diff --git a/UnityLauncherPro/Helpers/ProcessHandler.cs b/UnityLauncherPro/Helpers/ProcessHandler.cs index 8728e4d..d350a7a 100644 --- a/UnityLauncherPro/Helpers/ProcessHandler.cs +++ b/UnityLauncherPro/Helpers/ProcessHandler.cs @@ -11,7 +11,7 @@ namespace UnityLauncherPro.Helpers { public static class ProcessHandler { - static Dictionary processes = new Dictionary(); + static Dictionary processes = new Dictionary(); public static void Add(Project proj, Process proc) { @@ -21,11 +21,11 @@ public static void Add(Project proj, Process proc) if (processes.ContainsKey(key)) { // already in the list, maybe trying to launch same project twice? only overwrite if previous process has closed - if (processes[key] == null) processes[key] = proc; + if (processes[key].Item1 == null) processes[key] = (proc, proj); } else { - processes.Add(key, proc); + processes.Add(key, (proc, proj)); } // subscribe to process exit here, so that can update proj details row (if it was changed in Unity) @@ -45,13 +45,35 @@ public static void Add(Project proj, Process proc) public static Process Get(string key) { - if (processes.ContainsKey(key)) return processes[key]; + if (processes.ContainsKey(key) && (processes[key].Item1 != null)) + { + return processes[key].Item1; + } return null; } + // return project for given key + //public static Project GetProject(string key) + //{ + // if (processes.ContainsKey(key) && (processes[key].Item2 != null)) + // { + // return processes[key].Item2; + // } + // return null; + //} + public static bool IsRunning(string key) { - return processes.ContainsKey(key) && (processes[key] != null); + return processes.ContainsKey(key) && (processes[key].Item1 != null); + } + + public static Project GetSingleRunning() + { + if (processes.Count != 1) return null; + var enumerator = processes.Values.GetEnumerator(); + enumerator.MoveNext(); + var entry = enumerator.Current; + return entry.Item1 != null ? entry.Item2 : null; } public static void Remove(string key) diff --git a/UnityLauncherPro/Libraries/ExtractTarGz.cs b/UnityLauncherPro/Libraries/ExtractTarGz.cs index 04517d1..e55e44a 100644 --- a/UnityLauncherPro/Libraries/ExtractTarGz.cs +++ b/UnityLauncherPro/Libraries/ExtractTarGz.cs @@ -1,6 +1,3 @@ -// source https://gist.github.com/Su-s/438be493ae692318c73e30367cbc5c2a -// updated source https://gist.github.com/Matheos96/da8990030dfe3e27b0a48722042d9c0b - using System; using System.IO; using System.IO.Compression; @@ -11,10 +8,8 @@ namespace TarLib public class Tar { /// - /// Extracts a .tar.gz archive to the specified directory. + /// Extracts a .tar.gz archive to the specified directory. /// - /// The .tar.gz to decompress and extract. - /// Output directory to write the files. public static void ExtractTarGz(string filename, string outputDir) { using (var stream = File.OpenRead(filename)) @@ -24,39 +19,29 @@ public static void ExtractTarGz(string filename, string outputDir) } /// - /// Extracts a .tar.gz archive stream to the specified directory. + /// Extracts a .tar.gz archive stream to the specified directory. /// - /// The .tar.gz to decompress and extract. - /// Output directory to write the files. public static void ExtractTarGz(Stream stream, string outputDir) { - int read; - const int chunk = 4096; + const int chunk = 4096*4; var buffer = new byte[chunk]; - // A GZipStream is not seekable, so copy it first to a MemoryStream using (var gzipStream = new GZipStream(stream, CompressionMode.Decompress)) + using (var memStream = new MemoryStream()) { - using (var memStream = new MemoryStream()) + int read; + while ((read = gzipStream.Read(buffer, 0, buffer.Length)) > 0) { - //For .NET 6+ - while ((read = gzipStream.Read(buffer, 0, buffer.Length)) > 0) - { - memStream.Write(buffer, 0, read); - } - memStream.Seek(0, SeekOrigin.Begin); - - //ExtractTar(gzip, outputDir); - ExtractTar(memStream, outputDir); + memStream.Write(buffer, 0, read); } + memStream.Seek(0, SeekOrigin.Begin); + ExtractTar(memStream, outputDir); } } /// - /// Extractes a tar archive to the specified directory. + /// Extracts a tar archive file. /// - /// The .tar to extract. - /// Output directory to write the files. public static void ExtractTar(string filename, string outputDir) { using (var stream = File.OpenRead(filename)) @@ -66,85 +51,206 @@ public static void ExtractTar(string filename, string outputDir) } /// - /// Extractes a tar archive to the specified directory. + /// Extracts a tar archive stream. + /// Fixes path loss caused by ignoring the POSIX 'prefix' field and wrong header offsets. /// - /// The .tar to extract. - /// Output directory to write the files. public static void ExtractTar(Stream stream, string outputDir) { - var buffer = new byte[100]; - var longFileName = string.Empty; + // Tar header constants + const int HeaderSize = 512; + byte[] header = new byte[HeaderSize]; + + string pendingLongName = null; // For GNU long name ('L') entries + while (true) { - stream.Read(buffer, 0, 100); - string name = string.IsNullOrEmpty(longFileName) ? Encoding.ASCII.GetString(buffer).Trim('\0') : longFileName; //Use longFileName if we have one read - - if (String.IsNullOrWhiteSpace(name)) break; - stream.Seek(24, SeekOrigin.Current); - stream.Read(buffer, 0, 12); - var size = Convert.ToInt64(Encoding.UTF8.GetString(buffer, 0, 12).Trim('\0').Trim(), 8); - stream.Seek(20, SeekOrigin.Current); //Move head to typeTag byte - var typeTag = stream.ReadByte(); - stream.Seek(355L, SeekOrigin.Current); //Move head to beginning of data (byte 512) - - if (typeTag == 'L') + int bytesRead = ReadExact(stream, header, 0, HeaderSize); + if (bytesRead == 0) break; // End of stream + if (bytesRead < HeaderSize) throw new EndOfStreamException("Unexpected end of tar stream."); + + // Detect two consecutive zero blocks (end of archive) + bool allZero = IsAllZero(header); + if (allZero) + { + // Peek next block; if also zero -> end + bytesRead = ReadExact(stream, header, 0, HeaderSize); + if (bytesRead == 0 || IsAllZero(header)) break; + if (bytesRead < HeaderSize) throw new EndOfStreamException("Unexpected end of tar stream."); + } + + // Parse fields (POSIX ustar) + string name = GetString(header, 0, 100); + string mode = GetString(header, 100, 8); + string uid = GetString(header, 108, 8); + string gid = GetString(header, 116, 8); + string sizeOctal = GetString(header, 124, 12); + string mtime = GetString(header, 136, 12); + string checksum = GetString(header, 148, 8); + char typeFlag = (char)header[156]; + string linkName = GetString(header, 157, 100); + string magic = GetString(header, 257, 6); // "ustar\0" or "ustar " + string version = GetString(header, 263, 2); + string uname = GetString(header, 265, 32); + string gname = GetString(header, 297, 32); + string prefix = GetString(header, 345, 155); + + // Compose full name using prefix (if present and not using GNU long name override) + if (!string.IsNullOrEmpty(prefix)) + { + name = prefix + "/" + name; + } + + // If we previously read a GNU long name block, override current name + if (!string.IsNullOrEmpty(pendingLongName)) { - //If Type Tag is 'L' we have a filename that is longer than the 100 bytes reserved for it in the header. - //We read it here and save it temporarily as it will be the file name of the next block where the actual data is - var buf = new byte[size]; - stream.Read(buf, 0, buf.Length); - longFileName = Encoding.ASCII.GetString(buf).Trim('\0'); + name = pendingLongName; + pendingLongName = null; } - else + + long size = ParseOctal(sizeOctal); + + // Handle GNU long name extension block: the data of this entry is the filename of next entry. + if (typeFlag == 'L') { - longFileName = string.Empty; //Reset longFileName if current entry is not indicating one + byte[] longNameData = new byte[size]; + ReadExact(stream, longNameData, 0, (int)size); + pendingLongName = Encoding.ASCII.GetString(longNameData).Trim('\0', '\r', '\n'); + SkipPadding(stream, size); + continue; // Move to next header + } + + // Skip PAX extended header (type 'x') - metadata only + if (typeFlag == 'x') + { + SkipData(stream, size); + SkipPadding(stream, size); + continue; + } + + // Normalize name + if (string.IsNullOrWhiteSpace(name)) continue; - var output = Path.Combine(outputDir, name); + // Directory? + bool isDirectory = typeFlag == '5' || name.EndsWith("/"); - // only include these folders - var include = (output.IndexOf("package/ProjectData~/Assets/") > -1); - include |= (output.IndexOf("package/ProjectData~/ProjectSettings/") > -1); - include |= (output.IndexOf("package/ProjectData~/Packages/") > -1); + // Inclusion filter (original logic) + string originalName = name; + bool include = + originalName.IndexOf("package/ProjectData~/Assets/", StringComparison.Ordinal) > -1 || + originalName.IndexOf("package/ProjectData~/ProjectSettings/", StringComparison.Ordinal) > -1 || + originalName.IndexOf("package/ProjectData~/Library/", StringComparison.Ordinal) > -1 || + originalName.IndexOf("package/ProjectData~/Packages/", StringComparison.Ordinal) > -1; - // rename output path from "package/ProjectData~/Assets/" into "Assets/" - output = output.Replace("package/ProjectData~/", ""); + // Strip leading prefix. + string cleanedName = originalName.StartsWith("package/ProjectData~/", StringComparison.Ordinal) + ? originalName.Substring("package/ProjectData~/".Length) + : originalName; + + string finalPath = Path.Combine(outputDir, cleanedName.Replace('/', Path.DirectorySeparatorChar)); + + if (isDirectory) + { + if (include && !Directory.Exists(finalPath)) + Directory.CreateDirectory(finalPath); + // No data to read for directory; continue to next header + SkipData(stream, size); // size should be 0 + SkipPadding(stream, size); + continue; + } + + // Ensure directory exists + if (include) + { + string dir = Path.GetDirectoryName(finalPath); + if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) + Directory.CreateDirectory(dir); + } - if (include == true && !Directory.Exists(Path.GetDirectoryName(output))) Directory.CreateDirectory(Path.GetDirectoryName(output)); + // Read file data (always advance stream even if not included) + byte[] fileData = new byte[size]; + ReadExact(stream, fileData, 0, (int)size); - // not folder - //if (name.Equals("./", StringComparison.InvariantCulture) == false) - if (name.EndsWith("/") == false) //Directories are zero size and don't need anything written + if (include) + { + using (var fs = File.Open(finalPath, FileMode.Create, FileAccess.Write)) { - if (include == true) - { - //Console.WriteLine("output=" + output); - using (var str = File.Open(output, FileMode.OpenOrCreate, FileAccess.ReadWrite)) - { - var buf = new byte[size]; - stream.Read(buf, 0, buf.Length); - // take only data from this folder - str.Write(buf, 0, buf.Length); - } - } - else - { - var buf = new byte[size]; - stream.Read(buf, 0, buf.Length); - } + fs.Write(fileData, 0, fileData.Length); } } - //Move head to next 512 byte block - var pos = stream.Position; - var offset = 512 - (pos % 512); - if (offset == 512) offset = 0; + // Skip padding to 512 boundary + SkipPadding(stream, size); + } + } - stream.Seek(offset, SeekOrigin.Current); + private static string GetString(byte[] buffer, int offset, int length) + { + var s = Encoding.ASCII.GetString(buffer, offset, length); + int nullIndex = s.IndexOf('\0'); + if (nullIndex >= 0) s = s.Substring(0, nullIndex); + return s.Trim(); + } + + private static long ParseOctal(string s) + { + s = s.Trim(); + if (string.IsNullOrEmpty(s)) return 0; + try + { + return Convert.ToInt64(s, 8); + } + catch + { + // Fallback: treat as decimal if malformed + long val; + return long.TryParse(s, out val) ? val : 0; } } - } // class Tar -} // namespace TarLib + private static bool IsAllZero(byte[] buffer) + { + for (int i = 0; i < buffer.Length; i++) + if (buffer[i] != 0) return false; + return true; + } + + private static int ReadExact(Stream stream, byte[] buffer, int offset, int count) + { + int total = 0; + while (total < count) + { + int read = stream.Read(buffer, offset + total, count - total); + if (read <= 0) break; + total += read; + } + return total; + } + + private static void SkipData(Stream stream, long size) + { + if (size <= 0) return; + const int chunk = 8192; + byte[] tmp = new byte[Math.Min(chunk, (int)size)]; + long remaining = size; + while (remaining > 0) + { + int toRead = (int)Math.Min(tmp.Length, remaining); + int read = stream.Read(tmp, 0, toRead); + if (read <= 0) throw new EndOfStreamException("Unexpected end while skipping data."); + remaining -= read; + } + } + + private static void SkipPadding(Stream stream, long size) + { + long padding = (512 - (size % 512)) % 512; + if (padding > 0) + { + stream.Seek(padding, SeekOrigin.Current); + } + } + } +} /* This software is available under 2 licenses-- choose whichever you prefer. @@ -184,4 +290,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 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. -*/ +*/ \ No newline at end of file diff --git a/UnityLauncherPro/MainWindow.xaml b/UnityLauncherPro/MainWindow.xaml index 54de073..1d02730 100644 --- a/UnityLauncherPro/MainWindow.xaml +++ b/UnityLauncherPro/MainWindow.xaml @@ -5,12 +5,18 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:UnityLauncherPro" xmlns:System="clr-namespace:System;assembly=mscorlib" + xmlns:controls="clr-namespace:UnityLauncherPro.Controls" xmlns:converters="clr-namespace:UnityLauncherPro.Converters" x:Class="UnityLauncherPro.MainWindow" mc:Ignorable="d" - Title="UnityLauncherPro" Height="650" Width="880" WindowStartupLocation="CenterScreen" Background="{DynamicResource ThemeDarkestBackground}" MinWidth="780" MinHeight="650" AllowsTransparency="True" WindowStyle="None" Margin="0" KeyDown="OnWindowKeyDown" Closing="Window_Closing" SizeChanged="Window_SizeChanged" Icon="Images/icon.ico" SourceInitialized="Window_SourceInitialized" MouseDown="Window_MouseDown"> + Title="UnityLauncherPro" Height="670" Width="880" WindowStartupLocation="CenterScreen" Background="{DynamicResource ThemeDarkestBackground}" MinWidth="780" MinHeight="650" AllowsTransparency="True" WindowStyle="None" Margin="0" KeyDown="OnWindowKeyDown" Closing="Window_Closing" SizeChanged="Window_SizeChanged" Icon="Images/icon.ico" SourceInitialized="Window_SourceInitialized" MouseDown="Window_MouseDown"> + + + + + @@ -48,89 +54,65 @@ - - - - - - - - - - - - - - - - - + - - - - - @@ -286,39 +287,9 @@ - - - - - - - - - + - - - - - @@ -413,37 +397,7 @@ - - - - - - - - - + @@ -455,7 +409,7 @@ - - - - - @@ -547,28 +506,28 @@ @@ -577,15 +536,18 @@ @@ -596,48 +558,16 @@ + diff --git a/UnityLauncherPro/NewProject.xaml.cs b/UnityLauncherPro/NewProject.xaml.cs index 138fba8..0b6921c 100644 --- a/UnityLauncherPro/NewProject.xaml.cs +++ b/UnityLauncherPro/NewProject.xaml.cs @@ -1,10 +1,18 @@ using System; using System.Collections.Generic; using System.IO; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using System.Windows.Media.Imaging; +using UnityLauncherPro.Data; +using UnityLauncherPro.Helpers; +using UnityLauncherPro.Properties; namespace UnityLauncherPro { @@ -15,21 +23,38 @@ public partial class NewProject : Window public static string newName = null; public static string templateZipPath = null; public static string selectedPlatform = null; + public static bool forceDX11 = false; public static string[] platformsForThisUnity = null; bool isInitializing = true; // to keep OnChangeEvent from firing too early int previousSelectedTemplateIndex = -1; int previousSelectedModuleIndex = -1; + bool loadOnlineTemplates = true; - static string targetFolder = null; + public static string targetFolder { get; private set; } = null; + private CancellationTokenSource _templateLoadCancellation; - public NewProject(string unityVersion, string suggestedName, string targetFolder, bool nameIsLocked = false) + const string githubTokenCreationURL = "https://github.com/settings/tokens/new?description=UnityLauncherPro+Setup+Project+Access&default_expires_at=90&scopes=repo#Remember_to_Copy_Token!"; + + void UpdateOrgUiState() + { + bool orgsEnabled = chkEnableOrgs.IsChecked == true; + btnCreateNewProjectAndRepo.Content = orgsEnabled ? "New Project+Repo at Org" : "New Project+Repo"; + } + + + public NewProject(string unityVersion, string suggestedName, string targetFolder, bool nameIsLocked = false, bool fetchOnlineTemplates = false) { isInitializing = true; InitializeComponent(); + loadOnlineTemplates = fetchOnlineTemplates; + btnFetchTemplates.Visibility = fetchOnlineTemplates ? Visibility.Collapsed : Visibility.Visible; + NewProject.targetFolder = targetFolder; + LoadSettings(); + // get version newVersion = unityVersion; newName = suggestedName; @@ -37,30 +62,55 @@ public NewProject(string unityVersion, string suggestedName, string targetFolder txtNewProjectName.IsEnabled = !nameIsLocked; txtNewProjectName.Text = newName; - lblNewProjectFolder.Content = targetFolder; - //// fill available versions - if (gridAvailableVersions.ItemsSource == null) + // git + txtRepoName.Text = newName; + + txtNewProjectFolder.Text = targetFolder; + + UpdateCreateButtonsEnabledState(); + + if (MainWindow.unityInstallationsSource.Count == 0) + { + Tools.SetStatus("No Unity installations found! Please add Unity installations first."); + isInitializing = false; + btnCreateNewProject.IsEnabled = false; + btnCreateNewProjectAndRepo.IsEnabled = false; + txtNewProjectStatus.Text = "No Unity installations found! Please add Unity installations first."; + return; + } + + // fill available versions, only replace if it's a different collection instance + if (!ReferenceEquals(gridAvailableVersions.ItemsSource, MainWindow.unityInstallationsSource)) { gridAvailableVersions.ItemsSource = MainWindow.unityInstallationsSource; } - + // we have that version installed if (MainWindow.unityInstalledVersions.ContainsKey(unityVersion) == true) { // find this unity version, TODO theres probably easier way than looping all - for (int i = 0; i < MainWindow.unityInstallationsSource.Count; i++) + if (MainWindow.unityInstallationsSource != null) { - if (MainWindow.unityInstallationsSource[i].Version == newVersion) + for (int i = 0; i < MainWindow.unityInstallationsSource.Count; i++) { - gridAvailableVersions.SelectedIndex = i; - gridAvailableVersions.ScrollIntoView(gridAvailableVersions.SelectedItem); - break; + if (MainWindow.unityInstallationsSource[i].Version == newVersion) + { + gridAvailableVersions.SelectedIndex = i; + gridAvailableVersions.ScrollIntoView(gridAvailableVersions.SelectedItem); + + string baseVersion = Tools.GetBaseVersion(newVersion); + if (fetchOnlineTemplates) _ = LoadOnlineTemplatesAsync(baseVersion); + break; + } } } - UpdateTemplatesDropDown((gridAvailableVersions.SelectedItem as UnityInstallation).Path); - UpdateModulesDropdown(newVersion); + if (gridAvailableVersions.SelectedItem != null) + { + UpdateTemplatesDropDown((gridAvailableVersions.SelectedItem as UnityInstallation).Path); + UpdateModulesDropdown(newVersion); + } } else // we dont have requested unity version, select first item then { @@ -71,13 +121,64 @@ public NewProject(string unityVersion, string suggestedName, string targetFolder } // select projectname text so can overwrite if needed - txtNewProjectName.Focus(); - txtNewProjectName.SelectAll(); newProjectName = txtNewProjectName.Text; + if (nameIsLocked) + { + Tools.SetFocusToGrid(gridAvailableVersions); + } + else + { + txtNewProjectName.Focus(); + txtNewProjectName.SelectAll(); + } + isInitializing = false; } // NewProject + private async void LoadSettings() + { + chkEnableVersionControl.IsChecked = Settings.Default.gitEnableVersionControl; + + chkForceDX11.IsChecked = Settings.Default.forceDX11; + chkEnableLfs.IsChecked = Settings.Default.gitIEnableLFS; + chkEnableLfs.IsEnabled = chkEnableVersionControl.IsChecked == true; + chkInitialCommit.IsChecked = Settings.Default.gitInitialCommit; + chkInitialCommit.IsEnabled = chkEnableVersionControl.IsChecked == true; + chkAddReadme.IsChecked = Settings.Default.gitAddReadme; + chkAddUnityGitIgnore.IsChecked = Settings.Default.gitAddIgnore; + chkEnableOrgs.IsChecked = Settings.Default.gitEnableOrgs; + UpdateOrgUiState(); + + expVersionControl.IsExpanded = Settings.Default.gitPanelExpanded || chkEnableVersionControl.IsChecked == true; + + string token = GitHubTokenStore.LoadToken(); + string username = GitHubTokenStore.LoadUsername(); + + if (string.IsNullOrWhiteSpace(token)) + { + ShowGitAuthorizedUI(false); + return; + } + + + // TODO no need to validate on every load.. + GitHubTokenValidationResult result = await GitHubAuth.ValidateTokenAsync(token); + + if (result.IsValid) + { + ShowGitAuthorizedUI(true); + await LoadGithubOrgsAsync(token); + } + else + { + GitHubTokenStore.DeleteToken(); + Settings.Default.Save(); + ShowGitAuthorizedUI(false); + } + + } // LoadSettings + void UpdateTemplatesDropDown(string unityPath) { // scan available templates, TODO could cache this at least per session? @@ -86,7 +187,6 @@ void UpdateTemplatesDropDown(string unityPath) lblTemplateTitleAndCount.Content = "Templates: (" + (cmbNewProjectTemplate.Items.Count - 1) + ")"; } - void UpdateModulesDropdown(string version) { // get modules and stick into combobox, NOTE we already have this info from GetProjects.Scan, so could access it @@ -124,35 +224,271 @@ void UpdateModulesDropdown(string version) } } - private void BtnCreateNewProject_Click(object sender, RoutedEventArgs e) + bool isCreatingProject = false; + private async void BtnCreateNewProject_Click(object sender, RoutedEventArgs e) { - // check if projectname already exists (only if should be automatically created name) - var targetPath = Path.Combine(targetFolder, txtNewProjectName.Text); - if (txtNewProjectName.IsEnabled == true && Directory.Exists(targetPath) == true) + await CreateNewProject(withRepo: false); + } + + private async void btnCreateNewProjectAndRepo_Click(object sender, RoutedEventArgs e) + { + await CreateNewProject(withRepo: true); + } + + private async Task CreateNewProject(bool withRepo) + { + if (isCreatingProject) return; + isCreatingProject = true; + + btnCreateNewProject.IsEnabled = false; + btnCreateNewProjectAndRepo.IsEnabled = false; + + try { - System.Console.WriteLine("Project already exists"); - return; - } + // check if projectname already exists (only if should be automatically created name) + var targetPath = Path.Combine(targetFolder, txtNewProjectName.Text); + if (txtNewProjectName.IsEnabled == true && Directory.Exists(targetPath) == true) + { + Tools.SetStatus("Project already exists: " + txtNewProjectName.Text); + isCreatingProject = false; + return; + } + + // Check if online template is selected + if (listOnlineTemplates.SelectedItem is OnlineTemplateItem selectedOnlineTemplate) + { + // Use online template path + string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + string templatesPath = Path.Combine(appDataPath, "UnityHub", "Templates"); + + if (!string.IsNullOrEmpty(selectedOnlineTemplate.TarBallURL)) + { + string fileName = Path.GetFileName(new Uri(selectedOnlineTemplate.TarBallURL).LocalPath); + if (string.IsNullOrEmpty(fileName)) + { + string safeFileName = string.Join("_", selectedOnlineTemplate.Name.Split(Path.GetInvalidFileNameChars())); + fileName = $"{safeFileName}.tgz"; + } - templateZipPath = ((KeyValuePair)cmbNewProjectTemplate.SelectedValue).Value; - selectedPlatform = cmbNewProjectPlatform.SelectedValue.ToString(); - UpdateSelectedVersion(); + templateZipPath = Path.Combine(templatesPath, fileName); - // save last used value for platform - Properties.Settings.Default.newProjectPlatform = cmbNewProjectPlatform.SelectedValue.ToString(); - Properties.Settings.Default.Save(); + // Verify the file exists + if (!File.Exists(templateZipPath)) + { + Tools.SetStatus("Selected online template is not downloaded. Please download it first."); + isCreatingProject = false; + return; + } + } + else + { + Tools.SetStatus("Invalid online template URL"); + isCreatingProject = false; + return; + } + } + else + { + // Use built-in template from dropdown + if (cmbNewProjectTemplate.SelectedValue != null) templateZipPath = ((KeyValuePair)cmbNewProjectTemplate.SelectedValue).Value; + } + + if (cmbNewProjectTemplate.SelectedValue != null) + { + selectedPlatform = cmbNewProjectPlatform.SelectedValue.ToString(); + UpdateSelectedVersion(); + + // save last used value for platform + Settings.Default.newProjectPlatform = cmbNewProjectPlatform.SelectedValue.ToString(); + Settings.Default.Save(); + } + + var repoOwner = GitHubTokenStore.LoadUsername(); + + if (withRepo && chkEnableVersionControl.IsChecked == true) + { + + // setup local git + try + { + string projectPath = await GithubActions.InitRepositoryAsync(baseDir: txtNewProjectFolder.Text, projectName: txtNewProjectName.Text, initGitLfs: (chkEnableLfs.IsChecked == true), defaultBranch: "main"); + + txtNewProjectStatus.Text = "Git repository initialized at: " + projectPath; + } + catch (Exception ex) + { + txtNewProjectStatus.Text = "Git init failed: " + ex.Message; + } + + // create online repo + try + { + string token = GitHubTokenStore.LoadToken(); + + // if invalid repo, add DDMMYYY_HHMMSS + if (lblRepoNameInvalid.Visibility == Visibility.Visible) + { + txtRepoName.Text += "_" + DateTime.Now.ToString("ddMMyyyy_HHmmss"); + } + + string selectedOrg = null; + if (chkEnableOrgs.IsChecked == true) + { + selectedOrg = cmbGithubOrgs.SelectedItem as string; + if (string.IsNullOrWhiteSpace(selectedOrg)) selectedOrg = null; + } + + repoOwner = selectedOrg ?? repoOwner; + + GitHubCreateRepoResult result = await GithubActions.CreateRepositoryAsync(token: token, repoName: txtRepoName.Text, description: txtRepoDescription.Text, isPrivate: rbPrivate.IsChecked == true, autoInit: false, organization: selectedOrg); + + if (result.Success) + { + Console.WriteLine("Created repo successfully."); + + string remoteUrl = $"https://github.com/{repoOwner}/{txtRepoName.Text}.git"; + await GithubActions.RunGitAsync(Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text), $"remote add origin {remoteUrl}"); + } + else + { + Console.WriteLine("Failed to create repo.."); + txtNewProjectStatus.Text = "GitHub repo creation failed: " + (string.IsNullOrWhiteSpace(result.Error) ? "Unknown GitHub error." : result.Error); + } + } + catch (Exception ex) + { + txtNewProjectStatus.Text += " | GitHub repo creation failed: " + ex.Message; + } + + // create .gitattributes if LFS enabled? + if (chkEnableLfs.IsChecked == true) + { + //var gitAttributesUrl = "https://raw.githubusercontent.com/gitattributes/gitattributes/refs/heads/master/Unity.gitattributes"; + + // load from resources + try + { + var assembly = typeof(NewProject).Assembly; + var resourceName = $"{typeof(NewProject).Namespace}.Resources..gitattributes"; + + using var stream = assembly.GetManifestResourceStream(resourceName); + if (stream == null) return; + + var gitattributesPath = Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text, ".gitattributes"); + using var fileStream = File.Create(gitattributesPath); + stream.CopyTo(fileStream); + } + catch + { + Tools.SetStatus("Failed to create .gitattributes file for this project."); + } + } + } // if version control enabled + + // create readme if enabled + if (withRepo && chkAddReadme.IsChecked == true) + { + var readmePath = Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text, "README.md"); + try + { + if (Directory.Exists(Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text)) == false) + { + Directory.CreateDirectory(Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text)); + } + File.WriteAllText(readmePath, "# " + txtRepoName.Text + "\n\n" + txtRepoDescription.Text); + } + catch (Exception ex) + { + Tools.SetStatus("Failed to create README file for this project: " + ex.Message); + } + } + + // download .gitignore if enabled + if (withRepo && chkAddUnityGitIgnore.IsChecked == true) + { + //var gitIgnoreUrl = "https://raw.githubusercontent.com/github/gitignore/refs/heads/main/Unity.gitignore"; + + // load from resources + try + { + var assembly = typeof(NewProject).Assembly; + var resourceName = $"{typeof(NewProject).Namespace}.Resources..gitignore"; + + using var stream = assembly.GetManifestResourceStream(resourceName); + if (stream == null) return; + + var gitignorePath = Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text, ".gitignore"); + using var fileStream = File.Create(gitignorePath); + stream.CopyTo(fileStream); + } + catch + { + Tools.SetStatus("Failed to create .gitignore file for this project."); + } + } // if add gitignore + + if (withRepo && chkEnableVersionControl.IsChecked == true) + { + if (chkInitialCommit.IsChecked == true) + { + try + { + await GithubActions.RunGitAsync(Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text), "add ."); + await GithubActions.RunGitAsync(Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text), "commit -m \"Initial commit from " + MainWindow.appName + "\""); + await GithubActions.RunGitAsync(Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text), "push -u origin main"); + + Console.WriteLine(Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text) + " add ."); + Console.WriteLine(Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text) + " commit -m \"Initial commit from " + MainWindow.appName + "\""); + + txtNewProjectStatus.Text += " | Initial commit created"; + } + catch (Exception ex) + { + txtNewProjectStatus.Text += " | Initial commit failed: " + ex.Message; + Console.WriteLine("failed commit"); + } + } + + Tools.OpenURL("https://github.com/" + repoOwner + "/" + txtRepoName.Text); + + } // if version control enabled + + } + finally + { + isCreatingProject = false; + UpdateCreateButtonsEnabledState(); + } DialogResult = true; } + private void UpdateCreateButtonsEnabledState() + { + bool folderExists = Directory.Exists(txtNewProjectFolder.Text); + bool projectNameAvailable = txtNewProjectName.IsEnabled==false || (!string.IsNullOrWhiteSpace(txtNewProjectName.Text) && !Directory.Exists(Path.Combine(targetFolder, txtNewProjectName.Text))); + bool onlineTemplateReady = !(listOnlineTemplates.SelectedItem is OnlineTemplateItem selectedOnlineTemplate) || selectedOnlineTemplate.IsDownloaded; + bool versionControlEnabled = chkEnableVersionControl.IsChecked == true; + bool gitFolderExists = Directory.Exists(Path.Combine(txtNewProjectFolder.Text, txtNewProjectName.Text, ".git")); + + btnCreateNewProject.IsEnabled = folderExists && projectNameAvailable && onlineTemplateReady && !isCreatingProject; + btnCreateNewProjectAndRepo.IsEnabled = btnCreateNewProject.IsEnabled && versionControlEnabled && !gitFolderExists; + + if (folderExists == false) txtNewProjectStatus.Text = "Folder does not exist."; + if (projectNameAvailable == false && txtNewProjectName.IsEnabled == true) txtNewProjectStatus.Text = "Project name is empty or already exists."; + if (onlineTemplateReady == false) txtNewProjectStatus.Text = "Selected online template is not downloaded."; + if (gitFolderExists == true) txtNewProjectStatus.Text = "Git repository already exists in the project folder."; + } + + private void BtnCancelNewProject_Click(object sender, RoutedEventArgs e) { DialogResult = false; } - private void Window_PreviewKeyDown(object sender, KeyEventArgs e) + private async void Window_PreviewKeyDown(object sender, KeyEventArgs e) { switch (e.Key) { @@ -178,7 +514,7 @@ private void Window_PreviewKeyDown(object sender, KeyEventArgs e) e.Handled = true; // override writing to textbox break; case Key.Enter: // enter, create proj - BtnCreateNewProject_Click(null, null); + await CreateNewProject(withRepo: false); e.Handled = true; break; case Key.Escape: // esc cancel @@ -241,18 +577,19 @@ private void TxtNewProjectName_TextChanged(object sender, TextChangedEventArgs e System.Console.WriteLine("Project already exists"); txtNewProjectName.BorderBrush = Brushes.Red; // not visible if focused txtNewProjectName.ToolTip = "Project folder already exists"; - btnCreateNewProject.IsEnabled = false; } else { txtNewProjectName.BorderBrush = null; - btnCreateNewProject.IsEnabled = true; txtNewProjectName.ToolTip = ""; } + UpdateCreateButtonsEnabledState(); + //System.Console.WriteLine("newProjectName: " + txtNewProjectName.Text); newProjectName = txtNewProjectName.Text; + if (chkEnableVersionControl.IsChecked == true) txtRepoName.Text = newProjectName; } private void TxtNewProjectName_PreviewKeyDown(object sender, KeyEventArgs e) @@ -272,7 +609,7 @@ private void TxtNewProjectName_PreviewKeyDown(object sender, KeyEventArgs e) void GenerateNewName() { - var newProj = Tools.GetSuggestedProjectName(newVersion, lblNewProjectFolder.Content.ToString()); + var newProj = Tools.GetSuggestedProjectName(newVersion, txtNewProjectFolder.Text.ToString()); txtNewProjectName.Text = newProj; } @@ -289,6 +626,22 @@ private void GridAvailableVersions_SelectionChanged(object sender, SelectionChan // update templates list for selected unity version UpdateTemplatesDropDown(k.Path); UpdateModulesDropdown(k.Version); + + // hide forceDX11 checkbox if version is below 6000 + bool is6000 = k.Version.Contains("6000"); + lblOverride.Visibility = chkForceDX11.Visibility = is6000 ? Visibility.Visible : Visibility.Collapsed; + //chkForceDX11.IsChecked = chkForceDX11.Visibility == Visibility.Visible ? forceDX11 : false; + forceDX11 = Settings.Default.forceDX11 && is6000; + + listOnlineTemplates.ItemsSource = null; // clear previous items + if (loadOnlineTemplates) + { + string baseVersion = Tools.GetBaseVersion(k.Version); + // Cancel previous request + _templateLoadCancellation?.Cancel(); + _templateLoadCancellation = new CancellationTokenSource(); + _ = LoadOnlineTemplatesAsync(baseVersion, _templateLoadCancellation.Token); + } } private void GridAvailableVersions_Loaded(object sender, RoutedEventArgs e) @@ -313,15 +666,689 @@ private void CmbNewProjectPlatform_DropDownOpened(object sender, System.EventArg previousSelectedModuleIndex = cmbNewProjectPlatform.SelectedIndex; } - private void gridAvailableVersions_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e) + private async void gridAvailableVersions_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e) { // check that we clicked actually on a row var src = VisualTreeHelper.GetParent((DependencyObject)e.OriginalSource); var srcType = src.GetType(); if (srcType == typeof(ContentPresenter)) { - BtnCreateNewProject_Click(null, null); + await CreateNewProject(withRepo: false); + } + } + + private void chkForceDX11_Checked(object sender, RoutedEventArgs e) + { + if (isInitializing) return; // Don't save during initialization + + Settings.Default.forceDX11 = forceDX11; + Settings.Default.Save(); + } + + private void chkEnableVersionControl_Checked(object sender, RoutedEventArgs e) + { + bool state = chkEnableVersionControl.IsChecked == true; + + UpdateCreateButtonsEnabledState(); + + if (isInitializing) return; + + // lock controls + rbPrivate.IsEnabled = state; + rbPublic.IsEnabled = state; + txtRepoName.IsEnabled = state; + txtRepoDescription.IsEnabled = state; + chkEnableLfs.IsEnabled = state; + chkInitialCommit.IsEnabled = state; + //chkAddUnityGitIgnore.IsEnabled = state; + //chkAddReadme.IsEnabled = state; + + Settings.Default.gitEnableVersionControl = state; + Settings.Default.Save(); + } + + private void btnBrowseForProjectFolder_Click(object sender, RoutedEventArgs e) + { + string defaultFolder = null; + if (txtNewProjectFolder.Text != null) + { + if (Directory.Exists(txtNewProjectFolder.Text) == true) + { + defaultFolder = txtNewProjectFolder.Text; + } + else + { + // find closest existing parent folder + var dir = new DirectoryInfo(txtNewProjectFolder.Text); + while (dir.Parent != null) + { + dir = dir.Parent; + if (Directory.Exists(dir.FullName) == true) + { + defaultFolder = dir.FullName; + break; + } + } + } + } + + var folder = Tools.BrowseForOutputFolder("Select New Project folder", defaultFolder); + if (string.IsNullOrEmpty(folder) == false && Directory.Exists(folder) == true) + { + txtNewProjectFolder.Text = folder; + } + + } + + private void txtNewProjectFolder_TextChanged(object sender, TextChangedEventArgs e) + { + // validate that folder exists + if (Directory.Exists(txtNewProjectFolder.Text) == false) + { + txtNewProjectFolder.BorderBrush = Brushes.Red; // not visible if focused + btnCreateMissingFolder.IsEnabled = true; + } + else + { + txtNewProjectFolder.BorderBrush = null; + targetFolder = txtNewProjectFolder.Text; + btnCreateMissingFolder.IsEnabled = false; + } + + UpdateCreateButtonsEnabledState(); + } + + private void btnCreateMissingFolder_Click(object sender, RoutedEventArgs e) + { + try + { + Directory.CreateDirectory(txtNewProjectFolder.Text); + txtNewProjectFolder.BorderBrush = null; + btnCreateNewProject.IsEnabled = true; + targetFolder = txtNewProjectFolder.Text; + } + catch (Exception ex) + { + Tools.SetStatus("Failed to create folder: " + ex.Message); + } + } + + private static readonly HttpClient _httpClient = new HttpClient(); + + private async Task LoadGithubOrgsAsync(string token) + { + cmbGithubOrgs.IsEnabled = chkEnableOrgs.IsChecked == true; + if (chkEnableOrgs.IsChecked != true) return; + + var orgs = await GithubActions.GetUserOrganizationsAsync(token); + cmbGithubOrgs.ItemsSource = orgs; + + var lastOrg = Settings.Default.gitLastOrg; + if (!string.IsNullOrWhiteSpace(lastOrg) && orgs.Contains(lastOrg)) + { + cmbGithubOrgs.SelectedItem = lastOrg; + } + else if (orgs.Count > 0) + { + cmbGithubOrgs.SelectedIndex = 0; + } + else + { + cmbGithubOrgs.SelectedIndex = -1; + } + } + + private void cmbGithubOrgs_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (isInitializing) return; + + var selectedOrg = cmbGithubOrgs.SelectedItem as string; + if (string.IsNullOrWhiteSpace(selectedOrg)) return; + + Settings.Default.gitLastOrg = selectedOrg; + Settings.Default.Save(); + } + + private async Task LoadOnlineTemplatesAsync(string baseVersion, CancellationToken cancellationToken = default) + { + try + { + _httpClient.DefaultRequestHeaders.Remove("Accept"); + _httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); + + var graphqlJson = "{\"query\":\"fragment TemplateEntity on Template { __typename name packageName description type buildPlatforms renderPipeline previewImage { url } versions { name tarball { url } } } query HUB__getTemplates($limit: Int! $skip: Int! $orderBy: TemplateOrder! $supportedUnityEditorVersions: [String!]!) { getTemplates(limit: $limit skip: $skip orderBy: $orderBy supportedUnityEditorVersions: $supportedUnityEditorVersions) { edges { node { ...TemplateEntity } } } }\",\"variables\":{\"limit\":40,\"skip\":0,\"orderBy\":\"WEIGHTED_DESC\",\"supportedUnityEditorVersions\":[\"" + baseVersion + "\"]}}"; + + var content = new StringContent(graphqlJson, Encoding.UTF8, "application/json"); + + // Check for cancellation before making request + if (cancellationToken.IsCancellationRequested) return; + + var response = await _httpClient.PostAsync("https://live-platform-api.prd.ld.unity3d.com/graphql", content, cancellationToken); + + // Check for cancellation after request + if (cancellationToken.IsCancellationRequested) return; + + if (response.IsSuccessStatusCode) + { + var responseString = await response.Content.ReadAsStringAsync(); + + // Check for cancellation before parsing + if (cancellationToken.IsCancellationRequested) return; + + var templates = ParseTemplatesFromJson(responseString); + + // Download preview images to bypass WPF's ClickOnce security check on HTTPS URIs + foreach (var template in templates) + { + if (cancellationToken.IsCancellationRequested) return; + + try + { + if (!string.IsNullOrEmpty(template.PreviewImageURL) && !template.PreviewImageURL.StartsWith("pack://")) + { + var imageData = await _httpClient.GetByteArrayAsync(template.PreviewImageURL); + var bitmap = new BitmapImage(); + bitmap.BeginInit(); + bitmap.CacheOption = BitmapCacheOption.OnLoad; + bitmap.StreamSource = new MemoryStream(imageData); + bitmap.EndInit(); + if (bitmap.CanFreeze) bitmap.Freeze(); + template.PreviewImage = bitmap; + } + } + catch + { + // Failed to download preview image, leave PreviewImage as null + } + } + + // Update UI on dispatcher thread only if not cancelled + if (!cancellationToken.IsCancellationRequested) + { + Dispatcher.Invoke(() => + { + // Only set ItemsSource, don't touch Items + listOnlineTemplates.ItemsSource = templates; + }); + } + } + else + { + Console.WriteLine($"GraphQL request failed: {response.StatusCode}"); + } + } + catch (OperationCanceledException) + { + // Request was cancelled, this is expected + Console.WriteLine("Template loading cancelled"); + } + catch (Exception ex) + { + if (!cancellationToken.IsCancellationRequested) + { + Console.WriteLine($"Error loading online templates: {ex.Message}"); + } + } + } + + private void LoadFallbackTemplates() + { + var templates = new List + { + new OnlineTemplateItem + { + Name = "3D Template", + Description = "A great starting point for 3D projects using the Universal Render Pipeline (URP).", + PreviewImageURL = "pack://application:,,,/Images/icon.png", + Type = "CORE", + RenderPipeline = "URP" + } + }; + + Dispatcher.Invoke(() => + { + // Only set ItemsSource, don't use Items.Clear() + listOnlineTemplates.ItemsSource = templates; + }); + } + + private List ParseTemplatesFromJson(string json) + { + var templates = new List(); + + try + { + // Get templates directory path + string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + string templatesPath = Path.Combine(appDataPath, "UnityHub", "Templates"); + + // Find the edges array + int edgesStart = json.IndexOf("\"edges\":"); + if (edgesStart == -1) return templates; + + // Find all node objects + int currentPos = edgesStart; + while (true) + { + int nodeStart = json.IndexOf("{\"__typename\":\"Template\"", currentPos); + if (nodeStart == -1) break; + + // Find the end of this node object (simplified - find matching brace) + int nodeEnd = JsonParser.FindMatchingBrace(json, nodeStart); + if (nodeEnd == -1) break; + + string nodeJson = json.Substring(nodeStart, nodeEnd - nodeStart + 1); + + // Parse individual fields + var tarballUrl = JsonParser.ExtractNestedJsonString(nodeJson, "\"tarball\"", "\"url\""); + var rawDescription = JsonParser.ExtractJsonString(nodeJson, "\"description\""); + var splitDescription = Tools.SplitTextToRows(rawDescription, 3); + + var template = new OnlineTemplateItem + { + Name = JsonParser.ExtractJsonString(nodeJson, "\"name\""), + Description = splitDescription, + Type = JsonParser.ExtractJsonString(nodeJson, "\"type\""), + RenderPipeline = JsonParser.ExtractJsonString(nodeJson, "\"renderPipeline\""), + PreviewImageURL = JsonParser.ExtractNestedJsonString(nodeJson, "\"previewImage\"", "\"url\"") ?? "pack://application:,,,/Images/icon.png", + TarBallURL = tarballUrl, + IsDownloaded = false + }; + + // Check if template file already exists + if (!string.IsNullOrEmpty(tarballUrl) && Directory.Exists(templatesPath)) + { + try + { + string fileName = Path.GetFileName(new Uri(tarballUrl).LocalPath); + if (!string.IsNullOrEmpty(fileName)) + { + string filePath = Path.Combine(templatesPath, fileName); + template.IsDownloaded = File.Exists(filePath); + } + } + catch + { + // If URL parsing fails, keep IsDownloaded as false + } + } + + templates.Add(template); + currentPos = nodeEnd + 1; + } + } + catch (Exception ex) + { + Console.WriteLine($"Error parsing templates: {ex.Message}"); } + + return templates; } - } -} + + private void listOnlineTemplates_PreviewMouseDown(object sender, MouseButtonEventArgs e) + { + // Get the item that was clicked + var listBox = sender as ListBox; + if (listBox == null) return; + + // Find the ListBoxItem that was clicked + var clickedElement = e.OriginalSource as DependencyObject; + while (clickedElement != null && clickedElement != listBox) + { + if (clickedElement is ListBoxItem) + { + var clickedItem = clickedElement as ListBoxItem; + + // If the clicked item is already selected, deselect it + if (clickedItem.IsSelected) + { + listBox.SelectedItem = null; + e.Handled = true; + return; + } + break; + } + clickedElement = VisualTreeHelper.GetParent(clickedElement); + } + } + + private void listOnlineTemplates_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (listOnlineTemplates.SelectedItem is OnlineTemplateItem selectedTemplate) + { + lblSelectedTemplate.Content = selectedTemplate.Name; + lblSelectedTemplate.BorderThickness = new Thickness(1); + + // Disable built-in template dropdown when online template is selected + cmbNewProjectTemplate.IsEnabled = false; + cmbNewProjectTemplate.SelectedIndex = 0; // Reset to default + + btnCreateNewProject.Content = selectedTemplate.IsDownloaded ? "Create Project" : "Download Template First >"; + } + else + { + lblSelectedTemplate.Content = "None"; + lblSelectedTemplate.BorderThickness = new Thickness(0); + + // Re-enable built-in template dropdown when no online template is selected + cmbNewProjectTemplate.IsEnabled = true; + + // enable create button + btnCreateNewProject.Content = "Create Project"; + } + + UpdateCreateButtonsEnabledState(); + } + + private async void btnDownloadTemplate_Click(object sender, RoutedEventArgs e) + { + var button = sender as Button; + if (button?.Tag is OnlineTemplateItem template) + { + if (string.IsNullOrEmpty(template.TarBallURL)) + { + Tools.SetStatus("No download URL available for this template"); + return; + } + + try + { + // Disable button during download + button.IsEnabled = false; + button.Content = "⏳"; + + // Create templates directory in %APPDATA%\UnityHub\Templates + string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + string templatesPath = Path.Combine(appDataPath, "UnityHub", "Templates"); + + if (!Directory.Exists(templatesPath)) + { + Directory.CreateDirectory(templatesPath); + } + + // Extract original filename from URL + string fileName = Path.GetFileName(new Uri(template.TarBallURL).LocalPath); + if (string.IsNullOrEmpty(fileName)) + { + // Fallback to sanitized template name if URL doesn't have a filename + string safeFileName = string.Join("_", template.Name.Split(Path.GetInvalidFileNameChars())); + fileName = $"{safeFileName}.tgz"; + } + + string targetFilePath = Path.Combine(templatesPath, fileName); + + // Download the template (overwrite if exists) + using (var client = new HttpClient()) + { + var response = await client.GetAsync(template.TarBallURL); + response.EnsureSuccessStatusCode(); + + var fileBytes = await response.Content.ReadAsByteArrayAsync(); + File.WriteAllBytes(targetFilePath, fileBytes); + + // Mark as downloaded + template.IsDownloaded = true; + + Tools.SetStatus($"Template downloaded: {template.Name}"); + + // Refresh no longer needed with INotifyPropertyChanged + // listOnlineTemplates.Items.Refresh(); + } + } + catch (Exception ex) + { + Tools.SetStatus($"Download failed: {ex.Message}"); + Console.WriteLine($"Error downloading template: {ex.Message}"); + } + finally + { + // Re-enable button + button.IsEnabled = true; + button.Content = "⬇"; + } + } + } + + private void btnFetchTemplates_Click(object sender, RoutedEventArgs e) + { + if (gridAvailableVersions.SelectedItem is UnityInstallation selectedInstallation) + { + string baseVersion = Tools.GetBaseVersion(selectedInstallation.Version); + _templateLoadCancellation?.Cancel(); + _templateLoadCancellation = new CancellationTokenSource(); + _ = LoadOnlineTemplatesAsync(baseVersion, _templateLoadCancellation.Token); + } + } + + private void btnCreateToken_Click(object sender, RoutedEventArgs e) + { + string tokenUrl = githubTokenCreationURL; + if (chkEnableOrgs.IsChecked == true) + { + tokenUrl = tokenUrl.Replace("scopes=repo", "scopes=repo,read:org"); + } + Tools.OpenURL(tokenUrl); + } + + + + private void ShowGitAuthorizedUI(bool show) + { + txtTokenInput.Password = null; + + if (show) + { + var username = GitHubTokenStore.LoadUsername(); + + lblGithubUsername.Content = username; + + chkEnableVersionControl.IsChecked = true; + chkEnableVersionControl.IsEnabled = true; + + txtTokenInput.Visibility = Visibility.Collapsed; + btnAuthorizeToken.Visibility = Visibility.Collapsed; + btnDisconnectToken.Visibility = Visibility.Visible; + lblConnected.Visibility = Visibility.Visible; + lblNotConnected.Visibility = Visibility.Collapsed; + btnCreateToken.Visibility = Visibility.Collapsed; + + btnCreateToken.IsEnabled = false; + btnDisconnectToken.IsEnabled = true; + btnAuthorizeToken.IsEnabled = false; + } + else + { + lblGithubUsername.Content = string.Empty; + + chkEnableVersionControl.IsChecked = false; + chkEnableVersionControl.IsEnabled = false; + + txtTokenInput.Visibility = Visibility.Visible; + btnAuthorizeToken.Visibility = Visibility.Visible; + btnDisconnectToken.Visibility = Visibility.Collapsed; + lblConnected.Visibility = Visibility.Collapsed; + lblNotConnected.Visibility = Visibility.Visible; + btnCreateToken.Visibility = Visibility.Visible; + + btnDisconnectToken.IsEnabled = false; + btnAuthorizeToken.IsEnabled = true; + btnCreateToken.IsEnabled = true; + } + } + + private async void btnAuthorizeToken_Click(object sender, RoutedEventArgs e) + { + string token = txtTokenInput.Password.Trim(); + + btnAuthorizeToken.IsEnabled = false; + btnDisconnectToken.IsEnabled = true; + + txtNewProjectStatus.Text = "Validating token..."; + + lblConnected.Visibility = Visibility.Collapsed; + lblNotConnected.Visibility = Visibility.Visible; + + try + { + GitHubTokenValidationResult result = await GitHubAuth.ValidateTokenAsync(token); + + if (result.IsValid) + { + GitHubTokenStore.SaveToken(token, result.Login); + txtNewProjectStatus.Text = "Token valid. Logged in as " + result.Login + "."; + lblGithubUsername.Content = result.Login; + ShowGitAuthorizedUI(true); + await LoadGithubOrgsAsync(token); + } + else + { + txtNewProjectStatus.Text = result.Error; + ShowGitAuthorizedUI(false); + } + } + finally + { + btnAuthorizeToken.IsEnabled = true; + } + + Settings.Default.Save(); + } + + private void chkEnableLfs_Checked(object sender, RoutedEventArgs e) + { + if (isInitializing) return; + + Settings.Default.gitIEnableLFS = chkEnableLfs.IsChecked == true; + Settings.Default.Save(); + } + + private void chkInitialCommit_Checked(object sender, RoutedEventArgs e) + { + if (isInitializing) return; + + Settings.Default.gitInitialCommit = chkInitialCommit.IsChecked == true; + Settings.Default.Save(); + } + + private void chkAddReadme_Checked(object sender, RoutedEventArgs e) + { + if (isInitializing) return; + + Settings.Default.gitAddReadme = chkAddReadme.IsChecked == true; + Settings.Default.Save(); + } + + private void chkAddUnityGitIgnore_Checked(object sender, RoutedEventArgs e) + { + if (isInitializing) return; + + Settings.Default.gitAddIgnore = chkAddUnityGitIgnore.IsChecked == true; + Settings.Default.Save(); + } + + private async void chkEnableOrgs_Checked(object sender, RoutedEventArgs e) + { + if (isInitializing) return; + + Settings.Default.gitEnableOrgs = chkEnableOrgs.IsChecked == true; + Settings.Default.Save(); + UpdateOrgUiState(); + + var enabled = chkEnableOrgs.IsChecked == true; + cmbGithubOrgs.IsEnabled = enabled; + + if (!enabled) + { + var selectedOrg = cmbGithubOrgs.SelectedItem as string; + if (!string.IsNullOrWhiteSpace(selectedOrg)) + { + Settings.Default.gitLastOrg = selectedOrg; + Settings.Default.Save(); + } + + cmbGithubOrgs.ItemsSource = null; + cmbGithubOrgs.SelectedIndex = -1; + return; + } + + var token = GitHubTokenStore.LoadToken(); + if (string.IsNullOrWhiteSpace(token)) return; + + await LoadGithubOrgsAsync(token); + } + + private CancellationTokenSource _repoNameCts; + + private async void txtRepoName_TextChanged(object sender, TextChangedEventArgs e) + { + _repoNameCts?.Cancel(); + _repoNameCts = new CancellationTokenSource(); + var token = _repoNameCts.Token; + lblRepoNameValid.Visibility = Visibility.Collapsed; + lblRepoNameInvalid.Visibility = Visibility.Visible; + + await Task.Delay(750); + + if (token.IsCancellationRequested) return; + + var username = GitHubTokenStore.LoadUsername(); + var res = await GithubActions.ValidateRepoName(txtRepoName.Text, username); + + if (token.IsCancellationRequested) return; + + if (res != null) + { + txtNewProjectStatus.Text = res; + lblRepoNameValid.Visibility = Visibility.Collapsed; + lblRepoNameInvalid.Visibility = Visibility.Visible; + lblRepoNameInvalid.ToolTip = res; + } + else + { + lblRepoNameValid.Visibility = Visibility.Visible; + lblRepoNameInvalid.Visibility = Visibility.Collapsed; + lblRepoNameInvalid.ToolTip = ""; + } + } + + private void expVersionControl_Collapsed(object sender, RoutedEventArgs e) + { + if (isInitializing) return; + + Settings.Default.gitPanelExpanded = expVersionControl.IsExpanded; + Settings.Default.Save(); + } + + private void btnDisconnectToken_Click(object sender, RoutedEventArgs e) + { + GitHubTokenStore.DeleteToken(); + cmbGithubOrgs.ItemsSource = null; + cmbGithubOrgs.SelectedIndex = -1; + Settings.Default.Save(); + ShowGitAuthorizedUI(false); + } + + private void txtTokenInput_PasswordChanged(object sender, RoutedEventArgs e) + { + bool tokenSeemsOK = false; + + if (string.IsNullOrWhiteSpace(txtTokenInput.Password)) return; + + if (txtTokenInput.Password.StartsWith("ghp_") && txtTokenInput.Password.Length == 40) + { + btnAuthorizeToken.IsEnabled = true; + txtTokenInput.BorderBrush = Brushes.Green; + tokenSeemsOK = true; + } + else + { + btnAuthorizeToken.IsEnabled = false; + txtTokenInput.BorderBrush = Brushes.Red; + } + + btnAuthorizeToken.IsEnabled = tokenSeemsOK; + } + + + } // class NewProject +} // namespace UnityLauncherPro diff --git a/UnityLauncherPro/Properties/AssemblyInfo.cs b/UnityLauncherPro/Properties/AssemblyInfo.cs index b280a55..6fe6e89 100644 --- a/UnityLauncherPro/Properties/AssemblyInfo.cs +++ b/UnityLauncherPro/Properties/AssemblyInfo.cs @@ -12,7 +12,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("UnityCoder.com")] [assembly: AssemblyProduct("UnityLauncherPro")] -[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyCopyright("Copyright © 2025")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/UnityLauncherPro/Properties/Settings.Designer.cs b/UnityLauncherPro/Properties/Settings.Designer.cs index f024741..c107c1f 100644 --- a/UnityLauncherPro/Properties/Settings.Designer.cs +++ b/UnityLauncherPro/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace UnityLauncherPro.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.11.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "18.6.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -613,5 +613,161 @@ public bool disableUnityHubLaunch { this["disableUnityHubLaunch"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool registerExplorerMenuAPK { + get { + return ((bool)(this["registerExplorerMenuAPK"])); + } + set { + this["registerExplorerMenuAPK"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool fetchAdditionalInfo { + get { + return ((bool)(this["fetchAdditionalInfo"])); + } + set { + this["fetchAdditionalInfo"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool forceDX11 { + get { + return ((bool)(this["forceDX11"])); + } + set { + this["forceDX11"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool fetchOnlineTemplates { + get { + return ((bool)(this["fetchOnlineTemplates"])); + } + set { + this["fetchOnlineTemplates"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool gitIEnableLFS { + get { + return ((bool)(this["gitIEnableLFS"])); + } + set { + this["gitIEnableLFS"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool gitInitialCommit { + get { + return ((bool)(this["gitInitialCommit"])); + } + set { + this["gitInitialCommit"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool gitAddReadme { + get { + return ((bool)(this["gitAddReadme"])); + } + set { + this["gitAddReadme"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool gitPanelExpanded { + get { + return ((bool)(this["gitPanelExpanded"])); + } + set { + this["gitPanelExpanded"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool gitEnableVersionControl { + get { + return ((bool)(this["gitEnableVersionControl"])); + } + set { + this["gitEnableVersionControl"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool showRecoveredScenePopup { + get { + return ((bool)(this["showRecoveredScenePopup"])); + } + set { + this["showRecoveredScenePopup"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool gitAddIgnore { + get { + return ((bool)(this["gitAddIgnore"])); + } + set { + this["gitAddIgnore"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool gitEnableOrgs { + get { + return ((bool)(this["gitEnableOrgs"])); + } + set { + this["gitEnableOrgs"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string gitLastOrg { + get { + return ((string)(this["gitLastOrg"])); + } + set { + this["gitLastOrg"] = value; + } + } } } diff --git a/UnityLauncherPro/Properties/Settings.settings b/UnityLauncherPro/Properties/Settings.settings index 918912e..dfa2553 100644 --- a/UnityLauncherPro/Properties/Settings.settings +++ b/UnityLauncherPro/Properties/Settings.settings @@ -154,5 +154,44 @@ False + + False + + + False + + + False + + + True + + + True + + + False + + + False + + + False + + + False + + + True + + + True + + + False + + + + \ No newline at end of file diff --git a/UnityLauncherPro/Resources/.gitattributes b/UnityLauncherPro/Resources/.gitattributes new file mode 100644 index 0000000..859c559 --- /dev/null +++ b/UnityLauncherPro/Resources/.gitattributes @@ -0,0 +1,163 @@ +# Define macros (only works in top-level gitattributes files) +[attr]lfs filter=lfs diff=lfs merge=lfs -text +[attr]unity-json eol=lf linguist-language=json +[attr]unity-yaml merge=unityyamlmerge eol=lf linguist-language=yaml + +# Optionally collapse Unity YAML files on GitHub diffs +# [attr]unity-yaml merge=unityyamlmerge text linguist-language=yaml linguist-generated + +# Unity source files +*.cginc text +*.compute text linguist-language=hlsl +*.cs text diff=csharp +*.hlsl text linguist-language=hlsl +*.raytrace text linguist-language=hlsl +*.shader text + +# Unity JSON files +*.asmdef unity-json +*.asmref unity-json +*.index unity-json +*.inputactions unity-json +*.shadergraph unity-json +*.shadersubgraph unity-json + +# Unity UI Toolkit files +*.tss text diff=css linguist-language=css +*.uss text diff=css linguist-language=css +*.uxml text linguist-language=xml linguist-detectable + +# Unity YAML files +*.anim unity-yaml +*.asset unity-yaml +*.brush unity-yaml +*.controller unity-yaml +*.flare unity-yaml +*.fontsettings unity-yaml +*.giparams unity-yaml +*.guiskin unity-yaml +*.lighting unity-yaml +*.mask unity-yaml +*.mat unity-yaml +*.meta unity-yaml +*.mixer unity-yaml +*.overrideController unity-yaml +*.playable unity-yaml +*.prefab unity-yaml +*.preset unity-yaml +*.renderTexture unity-yaml +*.scenetemplate unity-yaml +*.shadervariants unity-yaml +*.signal unity-yaml +*.spriteatlas unity-yaml +*.spriteatlasv2 unity-yaml +*.terrainlayer unity-yaml +*.unity unity-yaml + +# "physic" for 3D but "physics" for 2D +*.physicMaterial unity-yaml +*.physicsMaterial2D unity-yaml + +# Exclude from GitHub stats and diffs: third-party plugins, packages lock file +Assets/Plugins/** linguist-generated +Packages/packages-lock.json linguist-generated + +# Unity LFS +*.cubemap lfs +*.unitypackage lfs + +# 3D models +*.3dm lfs +*.3ds lfs +*.blend lfs +*.blend1 lfs +*.c4d lfs +*.collada lfs +*.dae lfs +*.dxf lfs +*.FBX lfs +*.fbx lfs +*.jas lfs +*.lws lfs +*.lxo lfs +*.ma lfs +*.max lfs +*.mb lfs +*.obj lfs +*.ply lfs +*.skp lfs +*.stl lfs +*.ztl lfs + +# Audio +*.aif lfs +*.aiff lfs +*.it lfs +*.mod lfs +*.mp3 lfs +*.ogg lfs +*.s3m lfs +*.wav lfs +*.xm lfs + +# Video +*.asf lfs +*.avi lfs +*.flv lfs +*.mov lfs +*.mp4 lfs +*.mpeg lfs +*.mpg lfs +*.ogv lfs +*.wmv lfs + +# Images +*.bmp lfs +*.exr lfs +*.gif lfs +*.hdr lfs +*.iff lfs +*.jpeg lfs +*.jpg lfs +*.pict lfs +*.png lfs +*.psd lfs +*.tga lfs +*.tif lfs +*.tiff lfs +*.webp lfs + +# Compressed Archive +*.7z lfs +*.bz2 lfs +*.gz lfs +*.rar lfs +*.tar lfs +*.zip lfs + +# Compiled Dynamic Library +*.dll lfs +*.pdb lfs +*.so lfs + +# Fonts +*.otf lfs +*.ttf lfs + +# Executable/Installer +*.apk lfs +*.exe lfs + +# Documents +*.pdf lfs + +# ETC +*.a lfs +*.reason lfs +*.rns lfs + +# Spine export file for Unity +*.skel.bytes lfs + +# Exceptions for .asset files such as lightning pre-baking +LightingData.asset binary diff --git a/UnityLauncherPro/Resources/.gitignore b/UnityLauncherPro/Resources/.gitignore new file mode 100644 index 0000000..3c335ae --- /dev/null +++ b/UnityLauncherPro/Resources/.gitignore @@ -0,0 +1,106 @@ +# This .gitignore file should be placed at the root of your Unity project directory +# +# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore +# +# Recommended: add any editor/OS/tool-specific ignore rules from the Global/ templates as needed. +# See: https://github.com/github/gitignore/tree/main/Global +# +.utmp/ +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/[Ll]ogs/ +/[Uu]ser[Ss]ettings/ +*.log + +# By default unity supports Blender asset imports, *.blend1 blender files do not need to be commited to version control. +*.blend1 +*.blend1.meta + +# MemoryCaptures can get excessive in size. +# They also could contain extremely sensitive data +/[Mm]emoryCaptures/ + +# Recordings can get excessive in size +/[Rr]ecordings/ + +# Uncomment this line if you wish to ignore the asset store tools plugin +# /[Aa]ssets/AssetStoreTools* + +# Autogenerated Jetbrains Rider plugin +/[Aa]ssets/Plugins/Editor/JetBrains* +# Jetbrains Rider personal-layer settings +*.DotSettings.user + +# Visual Studio cache directory +.vs/ + +# Gradle cache directory +.gradle/ + +# Autogenerated VS/MD/Consulo solution and project files +ExportedObj/ +.consulo/ +*.csproj +*.unityproj +*.sln +*.slnx +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb +*.mdb +*.opendb +*.VC.db + +# Unity3D generated meta files +*.pidb.meta +*.pdb.meta +*.mdb.meta + +# Unity3D generated file on crash reports +sysinfo.txt + +# Mono auto generated files +mono_crash.* + +# Builds +*.apk +*.aab +*.unitypackage +*.unitypackage.meta +*.app + +# Crashlytics generated file +crashlytics-build.properties + +# TestRunner generated files +InitTestScene*.unity* + +# Addressables default ignores, before user customizations +/ServerData +/[Aa]ssets/StreamingAssets/aa* +/[Aa]ssets/AddressableAssetsData/link.xml* +/[Aa]ssets/Addressables_Temp* +# By default, Addressables content builds will generate addressables_content_state.bin +# files in platform-specific subfolders, for example: +# /Assets/AddressableAssetsData/OSX/addressables_content_state.bin +/[Aa]ssets/AddressableAssetsData/*/*.bin* + +# Visual Scripting auto-generated files +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db.meta +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers.meta + +# Auto-generated scenes by play mode tests +/[Aa]ssets/[Ii]nit[Tt]est[Ss]cene*.unity* + +# Auto-generated cache in Assets folder +/[Aa]ssets/[Ss]ceneDependencyCache* diff --git a/UnityLauncherPro/Resources/UnityVersionCache.json b/UnityLauncherPro/Resources/UnityVersionCache.json index 02fd89e..709f738 100644 --- a/UnityLauncherPro/Resources/UnityVersionCache.json +++ b/UnityLauncherPro/Resources/UnityVersionCache.json @@ -1 +1 @@ -[{"version":"6000.0.27f1","releaseDate":"2024-11-14T09:07:52.6160000+02:00","stream":"Tech"},{"version":"6000.1.0a4","releaseDate":"2024-11-14T08:21:53.5470000+02:00","stream":"Tech"},{"version":"6000.1.0a3","releaseDate":"2024-10-31T02:09:14.4710000+02:00","stream":"Tech"},{"version":"6000.0.26f1","releaseDate":"2024-11-07T05:58:16.8120000+02:00","stream":"Tech"},{"version":"2022.3.52f1","releaseDate":"2024-11-06T08:44:56.0460000+02:00","stream":"Tech"},{"version":"6000.0.25f1","releaseDate":"2024-10-31T02:08:57.1640000+02:00","stream":"LTS"},{"version":"6000.1.0a2","releaseDate":"2024-10-31T01:18:23.1720000+02:00","stream":"Alpha"},{"version":"6000.0.24f1","releaseDate":"2024-10-24T07:50:49.7030000+03:00","stream":"LTS"},{"version":"2022.3.51f1","releaseDate":"2024-10-22T19:55:03.7950000+03:00","stream":"LTS"},{"version":"6000.0.23f1","releaseDate":"2024-10-17T02:50:12.5800000+03:00","stream":"LTS"},{"version":"2021.3.45f1","releaseDate":"2024-10-16T11:39:15.9770000+03:00","stream":"LTS"},{"version":"2022.3.50f1","releaseDate":"2024-10-09T12:22:48.6100000+03:00","stream":"LTS"},{"version":"6000.0.22f1","releaseDate":"2024-10-02T22:04:27.2050000+03:00","stream":"Tech"},{"version":"2022.3.49f1","releaseDate":"2024-10-01T17:05:21.8390000+03:00","stream":"LTS"},{"version":"2022.3.48f1","releaseDate":"2024-09-26T21:38:03.7600000+03:00","stream":"LTS"},{"version":"6000.0.21f1","releaseDate":"2024-09-24T19:11:20.5860000+03:00","stream":"Tech"},{"version":"2021.3.44f1","releaseDate":"2024-09-23T17:46:08.5310000+03:00","stream":"LTS"},{"version":"6000.0.20f1","releaseDate":"2024-09-19T18:22:09.9610000+03:00","stream":"Tech"},{"version":"2022.3.47f1","releaseDate":"2024-09-18T09:44:50.2140000+03:00","stream":"LTS"},{"version":"6000.0.19f1","releaseDate":"2024-09-12T04:29:34.6560000+03:00","stream":"Tech"},{"version":"2022.3.46f1","releaseDate":"2024-09-10T19:41:40.2330000+03:00","stream":"LTS"},{"version":"6000.0.18f1","releaseDate":"2024-09-04T09:08:14.6900000+03:00","stream":"Tech"},{"version":"2022.3.45f1","releaseDate":"2024-09-04T01:44:17.3580000+03:00","stream":"LTS"},{"version":"6000.0.17f1","releaseDate":"2024-08-27T19:52:36.7630000+03:00","stream":"Tech"},{"version":"2022.3.44f1","releaseDate":"2024-08-23T09:10:50.9750000+03:00","stream":"LTS"},{"version":"6000.0.16f1","releaseDate":"2024-08-22T21:12:19.7750000+03:00","stream":"Tech"},{"version":"2021.3.43f1","releaseDate":"2024-08-22T13:10:30.8490000+03:00","stream":"LTS"},{"version":"2022.3.43f1","releaseDate":"2024-08-21T17:11:42.7280000+03:00","stream":"LTS"},{"version":"6000.0.15f1","releaseDate":"2024-08-13T21:03:16.7920000+03:00","stream":"Tech"},{"version":"2022.3.42f1","releaseDate":"2024-08-13T12:26:14.2690000+03:00","stream":"LTS"},{"version":"6000.0.14f1","releaseDate":"2024-08-07T08:59:10.6590000+03:00","stream":"Tech"},{"version":"2022.3.41f1","releaseDate":"2024-08-06T13:07:06.8530000+03:00","stream":"LTS"},{"version":"2021.3.42f1","releaseDate":"2024-08-06T12:30:24.6020000+03:00","stream":"LTS"},{"version":"6000.0.13f1","releaseDate":"2024-07-31T21:30:12.3520000+03:00","stream":"Tech"},{"version":"2022.3.40f1","releaseDate":"2024-07-30T17:14:27.5360000+03:00","stream":"LTS"},{"version":"6000.0.12f1","releaseDate":"2024-07-25T19:59:55.9270000+03:00","stream":"Tech"},{"version":"2022.3.39f1","releaseDate":"2024-07-23T19:04:16.2020000+03:00","stream":"LTS"},{"version":"2021.3.41f1","releaseDate":"2024-07-23T17:54:58.7980000+03:00","stream":"LTS"},{"version":"6000.0.11f1","releaseDate":"2024-07-17T13:16:09.0230000+03:00","stream":"Tech"},{"version":"2022.3.38f1","releaseDate":"2024-07-16T16:52:35.9940000+03:00","stream":"LTS"},{"version":"6000.0.10f1","releaseDate":"2024-07-10T19:45:22.4880000+03:00","stream":"Tech"},{"version":"2022.3.37f1","releaseDate":"2024-07-09T15:05:40.0740000+03:00","stream":"LTS"},{"version":"6000.0.9f1","releaseDate":"2024-07-03T17:22:27.3520000+03:00","stream":"Tech"},{"version":"2022.3.36f1","releaseDate":"2024-07-02T20:23:09.1240000+03:00","stream":"LTS"},{"version":"6000.0.8f1","releaseDate":"2024-06-28T18:36:42.0980000+03:00","stream":"Tech"},{"version":"2022.3.35f1","releaseDate":"2024-06-27T20:06:27.0820000+03:00","stream":"LTS"},{"version":"2021.3.40f1","releaseDate":"2024-06-27T05:15:04.4950000+03:00","stream":"LTS"},{"version":"6000.0.7f1","releaseDate":"2024-06-20T19:04:46.2760000+03:00","stream":"Tech"},{"version":"2022.3.34f1","releaseDate":"2024-06-18T14:27:05.7060000+03:00","stream":"LTS"},{"version":"2022.3.33f1","releaseDate":"2024-06-12T09:22:11.9550000+03:00","stream":"LTS"},{"version":"6000.0.5f1","releaseDate":"2024-06-04T21:54:20.5720000+03:00","stream":"Tech"},{"version":"2022.3.32f1","releaseDate":"2024-06-04T20:45:52.3580000+03:00","stream":"LTS"},{"version":"6000.0.4f1","releaseDate":"2024-05-29T19:49:19.3410000+03:00","stream":"Tech"},{"version":"2022.3.31f1","releaseDate":"2024-05-28T20:19:07.2650000+03:00","stream":"LTS"},{"version":"2021.3.39f1","releaseDate":"2024-05-28T19:13:34.5600000+03:00","stream":"LTS"},{"version":"6000.0.3f1","releaseDate":"2024-05-21T19:15:54.9330000+03:00","stream":"Tech"},{"version":"2022.3.30f1","releaseDate":"2024-05-21T15:05:13.7390000+03:00","stream":"LTS"},{"version":"6000.0.2f1","releaseDate":"2024-05-14T22:54:04.4270000+03:00","stream":"Tech"},{"version":"2022.3.29f1","releaseDate":"2024-05-14T18:20:52.9280000+03:00","stream":"LTS"},{"version":"6000.0.1f1","releaseDate":"2024-05-08T18:11:21.9000000+03:00","stream":"Tech"},{"version":"2022.3.28f1","releaseDate":"2024-05-07T18:20:10.5920000+03:00","stream":"LTS"},{"version":"2021.3.38f1","releaseDate":"2024-05-02T21:42:56.7610000+03:00","stream":"LTS"},{"version":"2022.3.27f1","releaseDate":"2024-04-30T20:28:32.4380000+03:00","stream":"LTS"},{"version":"6000.0.0f1","releaseDate":"2024-04-29T21:37:33.4220000+03:00","stream":"Tech"},{"version":"2023.2.20f1","releaseDate":"2024-04-25T22:29:55.5280000+03:00","stream":"Tech"},{"version":"2022.3.26f1","releaseDate":"2024-04-23T20:47:02.1750000+03:00","stream":"LTS"},{"version":"6000.0.0b16","releaseDate":"2024-04-19T18:47:47.0120000+03:00","stream":"Beta"},{"version":"2023.2.19f1","releaseDate":"2024-04-18T11:21:36.2640000+03:00","stream":"Tech"},{"version":"2022.3.25f1","releaseDate":"2024-04-16T15:56:01.9400000+03:00","stream":"LTS"},{"version":"6000.0.0b15","releaseDate":"2024-04-13T03:46:31.3090000+03:00","stream":"Beta"},{"version":"2023.2.18f1","releaseDate":"2024-04-10T00:11:33.7860000+03:00","stream":"Tech"},{"version":"2022.3.24f1","releaseDate":"2024-04-09T14:12:12.5040000+03:00","stream":"LTS"},{"version":"2023.2.17f1","releaseDate":"2024-04-04T04:45:09.5450000+03:00","stream":"Tech"},{"version":"2022.3.23f1","releaseDate":"2024-04-02T18:24:02.3240000+03:00","stream":"LTS"},{"version":"2021.3.37f1","releaseDate":"2024-04-02T16:12:43.5310000+03:00","stream":"LTS"},{"version":"6000.0.0b13","releaseDate":"2024-03-27T03:28:00.3900000+02:00","stream":"Beta"},{"version":"2023.2.16f1","releaseDate":"2024-03-27T03:03:51.3150000+02:00","stream":"Tech"},{"version":"2023.2.15f1","releaseDate":"2024-03-19T23:07:34.0340000+02:00","stream":"Tech"},{"version":"6000.0.0b12","releaseDate":"2024-03-19T21:32:02.8890000+02:00","stream":"Beta"},{"version":"2022.3.22f1","releaseDate":"2024-03-19T13:06:29.3290000+02:00","stream":"LTS"},{"version":"6000.0.0b11","releaseDate":"2024-03-13T23:20:06.4030000+02:00","stream":"Beta"},{"version":"2023.2.14f1","releaseDate":"2024-03-12T20:27:41.7580000+02:00","stream":"Tech"},{"version":"2023.2.13f1","releaseDate":"2024-03-05T22:41:13.8390000+02:00","stream":"Tech"},{"version":"2023.3.0b10","releaseDate":"2024-03-05T21:08:01.4850000+02:00","stream":"Beta"},{"version":"2021.3.36f1","releaseDate":"2024-03-05T20:42:24.1710000+02:00","stream":"LTS"},{"version":"2022.3.21f1","releaseDate":"2024-03-05T18:04:04.8580000+02:00","stream":"LTS"},{"version":"2023.2.12f1","releaseDate":"2024-02-29T01:06:57.2790000+02:00","stream":"Tech"},{"version":"2023.3.0b9","releaseDate":"2024-02-28T23:32:42.6980000+02:00","stream":"Beta"},{"version":"2023.2.11f1","releaseDate":"2024-02-20T23:17:45.0260000+02:00","stream":"Tech"},{"version":"2023.3.0b8","releaseDate":"2024-02-20T21:40:27.1710000+02:00","stream":"Beta"},{"version":"2023.2.10f1","releaseDate":"2024-02-14T21:39:19.8910000+02:00","stream":"Tech"},{"version":"2022.3.20f1","releaseDate":"2024-02-14T13:25:56.5410000+02:00","stream":"LTS"},{"version":"2023.3.0b7","releaseDate":"2024-02-13T21:59:14.7140000+02:00","stream":"Beta"},{"version":"2023.3.0b6","releaseDate":"2024-02-07T09:24:40.2320000+02:00","stream":"Beta"},{"version":"2023.2.9f1","releaseDate":"2024-02-07T08:56:57.6470000+02:00","stream":"Tech"},{"version":"2021.3.35f1","releaseDate":"2024-02-06T17:40:15.5830000+02:00","stream":"LTS"},{"version":"2022.3.19f1","releaseDate":"2024-01-31T13:56:51.6340000+02:00","stream":"LTS"},{"version":"2023.3.0b5","releaseDate":"2024-01-31T02:28:33.7000000+02:00","stream":"Beta"},{"version":"2023.2.8f1","releaseDate":"2024-01-31T02:02:00.5870000+02:00","stream":"Tech"},{"version":"2023.2.7f1","releaseDate":"2024-01-23T22:43:04.8780000+02:00","stream":"Tech"},{"version":"2023.3.0b4","releaseDate":"2024-01-23T21:12:34.8720000+02:00","stream":"Beta"},{"version":"2022.3.18f1","releaseDate":"2024-01-20T18:00:12.2100000+02:00","stream":"LTS"},{"version":"2023.2.6f1","releaseDate":"2024-01-17T07:22:12.1160000+02:00","stream":"Tech"},{"version":"2023.3.0b3","releaseDate":"2024-01-15T07:07:54.4010000+02:00","stream":"Beta"},{"version":"2023.3.0b2","releaseDate":"2024-01-09T23:10:15.9440000+02:00","stream":"Beta"},{"version":"2021.3.34f1","releaseDate":"2024-01-09T17:33:57.0130000+02:00","stream":"LTS"},{"version":"2022.3.17f1","releaseDate":"2024-01-09T15:24:21.3090000+02:00","stream":"LTS"},{"version":"2023.2.5f1","releaseDate":"2024-01-09T10:49:30.8570000+02:00","stream":"Tech"},{"version":"2023.3.0b1","releaseDate":"2024-01-03T04:06:01.1860000+02:00","stream":"Beta"},{"version":"2023.2.4f1","releaseDate":"2023-12-22T13:24:31.4620000+02:00","stream":"Tech"},{"version":"2022.3.16f1","releaseDate":"2023-12-19T12:05:11.7210000+02:00","stream":"LTS"},{"version":"2023.3.0a18","releaseDate":"2023-12-13T23:40:57.5080000+02:00","stream":"Alpha"},{"version":"2023.2.3f1","releaseDate":"2023-12-06T00:03:42.7620000+02:00","stream":"Tech"},{"version":"2023.3.0a17","releaseDate":"2023-12-05T22:29:50.0710000+02:00","stream":"Alpha"},{"version":"2022.3.15f1","releaseDate":"2023-12-05T18:41:51.6760000+02:00","stream":"LTS"},{"version":"2023.2.2f1","releaseDate":"2023-11-28T22:28:30.9510000+02:00","stream":"Tech"},{"version":"2023.3.0a16","releaseDate":"2023-11-28T20:53:03.1050000+02:00","stream":"Alpha"},{"version":"2021.3.33f1","releaseDate":"2023-11-28T17:21:35.6330000+02:00","stream":"LTS"},{"version":"2023.2.1f1","releaseDate":"2023-11-22T00:09:38.4850000+02:00","stream":"Tech"},{"version":"2022.3.14f1","releaseDate":"2023-11-21T22:07:15.6700000+02:00","stream":"LTS"},{"version":"2023.3.0a15","releaseDate":"2023-11-21T19:46:47.0020000+02:00","stream":"Alpha"},{"version":"2023.2.0f1","releaseDate":"2023-11-15T01:22:44.2930000+02:00","stream":"Tech"},{"version":"2023.3.0a14","releaseDate":"2023-11-14T23:47:34.4680000+02:00","stream":"Alpha"},{"version":"2023.1.20f1","releaseDate":"2023-11-09T13:37:53.0800000+02:00","stream":"Tech"},{"version":"2022.3.13f1","releaseDate":"2023-11-07T19:33:11.8460000+02:00","stream":"LTS"},{"version":"2023.3.0a13","releaseDate":"2023-11-07T15:03:31.6360000+02:00","stream":"Alpha"},{"version":"2023.2.0b17","releaseDate":"2023-11-07T03:15:49.7360000+02:00","stream":"Beta"},{"version":"2021.3.32f1","releaseDate":"2023-11-01T17:47:25.8010000+02:00","stream":"LTS"},{"version":"2023.2.0b16","releaseDate":"2023-11-01T09:07:29.0190000+02:00","stream":"Beta"},{"version":"2023.3.0a12","releaseDate":"2023-10-31T22:54:47.4610000+02:00","stream":"Alpha"},{"version":"2023.1.19f1","releaseDate":"2023-10-31T16:12:27.1350000+02:00","stream":"Tech"},{"version":"2023.3.0a11","releaseDate":"2023-10-26T23:42:38.0140000+03:00","stream":"Alpha"},{"version":"2023.2.0b15","releaseDate":"2023-10-26T22:42:17.8000000+03:00","stream":"Beta"},{"version":"2022.3.12f1","releaseDate":"2023-10-26T17:00:14.6020000+03:00","stream":"LTS"},{"version":"2023.1.18f1","releaseDate":"2023-10-24T19:38:46.5580000+03:00","stream":"Tech"},{"version":"2023.1.17f1","releaseDate":"2023-10-17T16:06:27.2150000+03:00","stream":"Tech"},{"version":"2023.2.0b14","releaseDate":"2023-10-16T19:49:19.2110000+03:00","stream":"Beta"},{"version":"2023.3.0a10","releaseDate":"2023-10-16T18:53:09.4090000+03:00","stream":"Alpha"},{"version":"2023.2.0b13","releaseDate":"2023-10-11T02:43:50.4180000+03:00","stream":"Beta"},{"version":"2022.3.11f1","releaseDate":"2023-10-10T18:27:45.5750000+03:00","stream":"LTS"},{"version":"2023.2.0b12","releaseDate":"2023-10-05T08:35:01.2590000+03:00","stream":"Beta"},{"version":"2023.3.0a8","releaseDate":"2023-10-05T07:37:32.5410000+03:00","stream":"Alpha"},{"version":"2023.1.16f1","releaseDate":"2023-10-03T20:51:07.9240000+03:00","stream":"Tech"},{"version":"2021.3.31f1","releaseDate":"2023-10-03T18:50:59.1880000+03:00","stream":"LTS"},{"version":"2023.2.0b11","releaseDate":"2023-09-27T22:03:28.2830000+03:00","stream":"Beta"},{"version":"2023.1.15f1","releaseDate":"2023-09-26T16:26:57.1220000+03:00","stream":"Tech"},{"version":"2023.3.0a6","releaseDate":"2023-09-21T22:57:30.1720000+03:00","stream":"Alpha"},{"version":"2023.2.0b10","releaseDate":"2023-09-21T03:25:39.0680000+03:00","stream":"Beta"},{"version":"2023.3.0a7","releaseDate":"2023-09-21T02:32:03.4860000+03:00","stream":"Alpha"},{"version":"2023.1.14f1","releaseDate":"2023-09-19T16:45:02.8020000+03:00","stream":"Tech"},{"version":"2022.3.10f1","releaseDate":"2023-09-19T14:09:17.9240000+03:00","stream":"LTS"},{"version":"2023.2.0b9","releaseDate":"2023-09-13T19:47:50.2650000+03:00","stream":"Beta"},{"version":"2023.3.0a5","releaseDate":"2023-09-13T11:39:30.3420000+03:00","stream":"Alpha"},{"version":"2023.1.13f1","releaseDate":"2023-09-12T19:45:26.5060000+03:00","stream":"Tech"},{"version":"2023.2.0b8","releaseDate":"2023-09-07T03:06:06.6190000+03:00","stream":"Beta"},{"version":"2023.3.0a4","releaseDate":"2023-09-07T02:09:51.7610000+03:00","stream":"Alpha"},{"version":"2023.1.12f1","releaseDate":"2023-09-05T16:19:07.6000000+03:00","stream":"Tech"},{"version":"2022.3.9f1","releaseDate":"2023-09-05T14:20:42.5520000+03:00","stream":"LTS"},{"version":"2023.3.0a3","releaseDate":"2023-08-30T02:57:28.4560000+03:00","stream":"Alpha"},{"version":"2023.1.11f1","releaseDate":"2023-08-30T02:34:23.2510000+03:00","stream":"Tech"},{"version":"2023.2.0b7","releaseDate":"2023-08-30T01:05:40.2550000+03:00","stream":"Beta"},{"version":"2021.3.30f1","releaseDate":"2023-08-30T01:00:32.9160000+03:00","stream":"LTS"},{"version":"2023.2.0b6","releaseDate":"2023-08-23T19:37:08.1570000+03:00","stream":"Beta"},{"version":"2022.3.8f1","releaseDate":"2023-08-22T19:08:57.6900000+03:00","stream":"LTS"},{"version":"2023.1.10f1","releaseDate":"2023-08-22T12:04:56.8560000+03:00","stream":"Tech"},{"version":"2023.2.0b5","releaseDate":"2023-08-15T22:46:13.9610000+03:00","stream":"Beta"},{"version":"2023.1.9f1","releaseDate":"2023-08-15T11:51:07.4310000+03:00","stream":"Tech"},{"version":"2023.2.0b4","releaseDate":"2023-08-10T19:28:52.9540000+03:00","stream":"Beta"},{"version":"2023.1.8f1","releaseDate":"2023-08-08T13:46:36.3470000+03:00","stream":"Tech"},{"version":"2022.3.7f1","releaseDate":"2023-08-08T12:39:39.2500000+03:00","stream":"LTS"},{"version":"2023.2.0b3","releaseDate":"2023-08-02T00:20:07.9800000+03:00","stream":"Beta"},{"version":"2023.1.7f1","releaseDate":"2023-08-01T14:52:30.6880000+03:00","stream":"Tech"},{"version":"2022.3.6f1","releaseDate":"2023-07-31T21:44:28.3130000+03:00","stream":"LTS"},{"version":"2023.2.0b2","releaseDate":"2023-07-26T18:36:17.0900000+03:00","stream":"Beta"},{"version":"2023.1.6f1","releaseDate":"2023-07-25T17:07:19.6790000+03:00","stream":"Tech"},{"version":"2021.3.29f1","releaseDate":"2023-07-25T15:13:45.7210000+03:00","stream":"LTS"},{"version":"2023.2.0b1","releaseDate":"2023-07-19T20:48:18.0780000+03:00","stream":"Beta"},{"version":"2023.1.5f1","releaseDate":"2023-07-18T12:47:39.8830000+03:00","stream":"Tech"},{"version":"2022.3.5f1","releaseDate":"2023-07-13T19:12:49.1180000+03:00","stream":"LTS"},{"version":"2023.1.4f1","releaseDate":"2023-07-13T12:22:35.2840000+03:00","stream":"Tech"},{"version":"2023.2.0a22","releaseDate":"2023-07-10T13:49:24.5250000+03:00","stream":"Alpha"},{"version":"2023.1.3f1","releaseDate":"2023-07-05T13:38:33.7830000+03:00","stream":"Tech"},{"version":"2021.3.28f1","releaseDate":"2023-07-04T22:41:02.2050000+03:00","stream":"LTS"},{"version":"2023.1.2f1","releaseDate":"2023-06-26T20:35:53.2890000+03:00","stream":"Tech"},{"version":"2022.3.4f1","releaseDate":"2023-06-26T19:47:18.7050000+03:00","stream":"LTS"},{"version":"2023.2.0a20","releaseDate":"2023-06-21T22:58:23.5890000+03:00","stream":"Alpha"},{"version":"2022.3.3f1","releaseDate":"2023-06-21T18:21:19.0310000+03:00","stream":"LTS"},{"version":"2023.1.1f1","releaseDate":"2023-06-21T17:44:26.6940000+03:00","stream":"Tech"},{"version":"2023.2.0a19","releaseDate":"2023-06-13T20:56:46.9020000+03:00","stream":"Alpha"},{"version":"2022.3.2f1","releaseDate":"2023-06-13T20:35:17.0320000+03:00","stream":"LTS"},{"version":"2023.1.0f1","releaseDate":"2023-06-12T23:09:17.9400000+03:00","stream":"Tech"},{"version":"2021.3.27f1","releaseDate":"2023-06-07T19:35:21.2420000+03:00","stream":"LTS"},{"version":"2023.2.0a18","releaseDate":"2023-06-07T18:05:43.8610000+03:00","stream":"Alpha"},{"version":"2023.1.0b20","releaseDate":"2023-06-07T17:07:58.1050000+03:00","stream":"Beta"},{"version":"2022.3.1f1","releaseDate":"2023-06-07T14:44:18.6430000+03:00","stream":"LTS"},{"version":"2023.1.0b19","releaseDate":"2023-06-01T00:22:40.7160000+03:00","stream":"Beta"},{"version":"2023.2.0a17","releaseDate":"2023-05-31T22:36:57.5850000+03:00","stream":"Alpha"},{"version":"2022.3.0f1","releaseDate":"2023-05-30T13:40:13.8580000+03:00","stream":"LTS"},{"version":"2021.3.26f1","releaseDate":"2023-05-25T14:47:02.1500000+03:00","stream":"LTS"},{"version":"2023.2.0a16","releaseDate":"2023-05-24T23:32:01.9930000+03:00","stream":"Alpha"},{"version":"2023.1.0b18","releaseDate":"2023-05-24T17:12:55.4530000+03:00","stream":"Beta"},{"version":"2022.2.21f1","releaseDate":"2023-05-24T14:15:23.9850000+03:00","stream":"Tech"},{"version":"2022.2.20f1","releaseDate":"2023-05-18T12:58:25.7740000+03:00","stream":"Tech"},{"version":"2023.2.0a15","releaseDate":"2023-05-17T23:05:43.2150000+03:00","stream":"Alpha"},{"version":"2020.3.48f1","releaseDate":"2023-05-17T20:23:52.7840000+03:00","stream":"LTS"},{"version":"2023.1.0b17","releaseDate":"2023-05-17T19:32:57.0910000+03:00","stream":"Beta"},{"version":"2021.3.25f1","releaseDate":"2023-05-11T16:55:39.0570000+03:00","stream":"LTS"},{"version":"2022.2.19f1","releaseDate":"2023-05-11T15:02:51.9390000+03:00","stream":"Tech"},{"version":"2023.1.0b16","releaseDate":"2023-05-11T04:23:47.7980000+03:00","stream":"Beta"},{"version":"2023.2.0a14","releaseDate":"2023-05-10T22:50:11.4440000+03:00","stream":"Alpha"},{"version":"2023.1.0b15","releaseDate":"2023-05-04T18:09:21.8720000+03:00","stream":"Beta"},{"version":"2022.2.18f1","releaseDate":"2023-05-04T17:54:59.9510000+03:00","stream":"Tech"},{"version":"2023.2.0a13","releaseDate":"2023-05-03T22:08:00.7610000+03:00","stream":"Alpha"},{"version":"2022.2.17f1","releaseDate":"2023-04-27T20:55:43.2970000+03:00","stream":"Tech"},{"version":"2021.3.24f1","releaseDate":"2023-04-27T20:16:27.5610000+03:00","stream":"LTS"},{"version":"2023.2.0a12","releaseDate":"2023-04-27T17:39:10.7740000+03:00","stream":"Alpha"},{"version":"2023.1.0b14","releaseDate":"2023-04-26T20:38:33.8280000+03:00","stream":"Beta"},{"version":"2023.2.0a11","releaseDate":"2023-04-20T02:11:25.8420000+03:00","stream":"Alpha"},{"version":"2023.1.0b13","releaseDate":"2023-04-19T18:38:30.4380000+03:00","stream":"Beta"},{"version":"2022.2.16f1","releaseDate":"2023-04-19T17:00:29.7910000+03:00","stream":"Tech"},{"version":"2021.3.23f1","releaseDate":"2023-04-14T06:05:53.4110000+03:00","stream":"LTS"},{"version":"2022.2.15f1","releaseDate":"2023-04-13T16:56:06.9490000+03:00","stream":"Tech"},{"version":"2023.2.0a10","releaseDate":"2023-04-12T20:57:27.3950000+03:00","stream":"Alpha"},{"version":"2023.1.0b12","releaseDate":"2023-04-12T19:58:27.1750000+03:00","stream":"Beta"},{"version":"2022.2.14f1","releaseDate":"2023-04-06T01:20:20.9000000+03:00","stream":"Tech"},{"version":"2023.2.0a9","releaseDate":"2023-04-05T20:17:10.3830000+03:00","stream":"Alpha"},{"version":"2020.3.47f1","releaseDate":"2023-04-05T19:12:43.4140000+03:00","stream":"LTS"},{"version":"2023.1.0b11","releaseDate":"2023-04-05T00:58:08.4100000+03:00","stream":"Beta"},{"version":"2022.2.13f1","releaseDate":"2023-03-31T17:48:28.3060000+03:00","stream":"Tech"},{"version":"2021.3.22f1","releaseDate":"2023-03-29T23:44:06.1310000+03:00","stream":"LTS"},{"version":"2023.1.0b10","releaseDate":"2023-03-29T22:31:31.4270000+03:00","stream":"Beta"},{"version":"2023.2.0a8","releaseDate":"2023-03-29T20:45:36.7180000+03:00","stream":"Alpha"},{"version":"2023.2.0a7","releaseDate":"2023-03-22T23:21:49.2770000+02:00","stream":"Alpha"},{"version":"2022.2.12f1","releaseDate":"2023-03-22T21:38:11.7020000+02:00","stream":"Tech"},{"version":"2023.1.0b9","releaseDate":"2023-03-22T19:34:30.5930000+02:00","stream":"Beta"},{"version":"2023.2.0a6","releaseDate":"2023-03-15T19:05:39.9400000+02:00","stream":"Alpha"},{"version":"2023.1.0b8","releaseDate":"2023-03-15T17:20:07.0490000+02:00","stream":"Beta"},{"version":"2021.3.21f1","releaseDate":"2023-03-15T05:07:29.3970000+02:00","stream":"LTS"},{"version":"2022.2.11f1","releaseDate":"2023-03-15T04:33:37.4390000+02:00","stream":"Tech"},{"version":"2022.2.10f1","releaseDate":"2023-03-09T03:37:14.1860000+02:00","stream":"Tech"},{"version":"2020.3.46f1","releaseDate":"2023-03-08T18:13:10.8010000+02:00","stream":"LTS"},{"version":"2023.1.0b7","releaseDate":"2023-03-07T19:21:08.1180000+02:00","stream":"Beta"},{"version":"2022.2.9f1","releaseDate":"2023-03-03T03:54:20.1620000+02:00","stream":"Tech"},{"version":"2021.3.20f1","releaseDate":"2023-03-03T01:34:21.4780000+02:00","stream":"LTS"},{"version":"2023.1.0b6","releaseDate":"2023-03-02T19:05:36.6970000+02:00","stream":"Beta"},{"version":"2022.2.8f1","releaseDate":"2023-02-23T17:21:52.5810000+02:00","stream":"Tech"},{"version":"2023.1.0b5","releaseDate":"2023-02-22T16:43:31.6520000+02:00","stream":"Beta"},{"version":"2021.3.19f1","releaseDate":"2023-02-17T17:24:45.3250000+02:00","stream":"LTS"},{"version":"2023.1.0b4","releaseDate":"2023-02-16T18:12:27.2890000+02:00","stream":"Beta"},{"version":"2022.2.7f1","releaseDate":"2023-02-15T22:59:18.6940000+02:00","stream":"Tech"},{"version":"2020.3.45f1","releaseDate":"2023-02-14T23:48:56.7970000+02:00","stream":"LTS"},{"version":"2022.2.6f1","releaseDate":"2023-02-10T03:46:54.4290000+02:00","stream":"Tech"},{"version":"2023.1.0b3","releaseDate":"2023-02-08T18:02:45.1480000+02:00","stream":"Beta"},{"version":"2021.3.18f1","releaseDate":"2023-02-01T22:10:11.4750000+02:00","stream":"LTS"},{"version":"2023.1.0b2","releaseDate":"2023-02-01T16:26:56.9800000+02:00","stream":"Beta"},{"version":"2022.2.5f1","releaseDate":"2023-01-31T22:58:08.2060000+02:00","stream":"Tech"},{"version":"2022.2.4f1","releaseDate":"2023-01-27T16:41:48.2250000+02:00","stream":"Tech"},{"version":"2023.1.0b1","releaseDate":"2023-01-24T18:35:43.4020000+02:00","stream":"Beta"},{"version":"2021.3.17f1","releaseDate":"2023-01-24T18:26:13.7420000+02:00","stream":"LTS"},{"version":"2022.2.3f1","releaseDate":"2023-01-23T21:50:52.1750000+02:00","stream":"Tech"},{"version":"2023.1.0a26","releaseDate":"2023-01-18T19:32:21.5630000+02:00","stream":"Alpha"},{"version":"2020.3.44f1","releaseDate":"2023-01-18T19:25:53.1090000+02:00","stream":"LTS"},{"version":"2023.1.0a25","releaseDate":"2023-01-11T21:23:37.6860000+02:00","stream":"Alpha"},{"version":"2022.2.2f1","releaseDate":"2023-01-10T05:21:01.4250000+02:00","stream":"Tech"},{"version":"2023.1.0a24","releaseDate":"2022-12-22T03:56:32.4480000+02:00","stream":"Alpha"},{"version":"2020.3.43f1","releaseDate":"2022-12-16T00:02:25.8850000+02:00","stream":"LTS"},{"version":"2021.3.16f1","releaseDate":"2022-12-15T18:05:52.9180000+02:00","stream":"LTS"},{"version":"2023.1.0a23","releaseDate":"2022-12-14T20:58:53.9770000+02:00","stream":"Alpha"},{"version":"2022.2.1f1","releaseDate":"2022-12-12T17:26:11.2260000+02:00","stream":"Tech"},{"version":"2023.1.0a22","releaseDate":"2022-12-07T23:25:31.9420000+02:00","stream":"Alpha"},{"version":"2022.2.0f1","releaseDate":"2022-12-07T16:29:04.8310000+02:00","stream":"Tech"},{"version":"2022.1.24f1","releaseDate":"2022-12-06T20:33:08.7300000+02:00","stream":"Tech"},{"version":"2021.3.15f1","releaseDate":"2022-12-01T19:20:58.3010000+02:00","stream":"LTS"},{"version":"2023.1.0a21","releaseDate":"2022-11-30T17:35:08.6520000+02:00","stream":"Alpha"},{"version":"2023.1.0a20","releaseDate":"2022-11-24T16:54:00.0950000+02:00","stream":"Alpha"},{"version":"2022.2.0b16","releaseDate":"2022-11-18T17:21:52.7500000+02:00","stream":"Beta"},{"version":"2023.1.0a19","releaseDate":"2022-11-17T23:40:42.6370000+02:00","stream":"Alpha"},{"version":"2021.3.14f1","releaseDate":"2022-11-17T19:28:01.6800000+02:00","stream":"LTS"},{"version":"2020.3.42f1","releaseDate":"2022-11-17T18:42:55.7160000+02:00","stream":"LTS"},{"version":"2022.1.23f1","releaseDate":"2022-11-16T13:07:08.5870000+02:00","stream":"Tech"},{"version":"2022.2.0b15","releaseDate":"2022-11-16T11:42:02.4260000+02:00","stream":"Beta"},{"version":"2023.1.0a18","releaseDate":"2022-11-10T17:10:57.7810000+02:00","stream":"Alpha"},{"version":"2022.1.22f1","releaseDate":"2022-11-09T14:42:48.4520000+02:00","stream":"Tech"},{"version":"2022.2.0b14","releaseDate":"2022-11-07T16:57:36.8080000+02:00","stream":"Beta"},{"version":"2021.3.13f1","releaseDate":"2022-11-04T18:42:23.1680000+02:00","stream":"LTS"},{"version":"2023.1.0a17","releaseDate":"2022-11-04T17:52:07.0070000+02:00","stream":"Alpha"},{"version":"2023.1.0a16","releaseDate":"2022-10-27T18:51:25.6730000+03:00","stream":"Alpha"},{"version":"2022.1.21f1","releaseDate":"2022-10-27T17:14:42.0510000+03:00","stream":"Tech"},{"version":"2022.2.0b13","releaseDate":"2022-10-26T23:13:31.6270000+03:00","stream":"Beta"},{"version":"2021.3.12f1","releaseDate":"2022-10-25T18:16:10.9510000+03:00","stream":"LTS"},{"version":"2023.1.0a15","releaseDate":"2022-10-21T18:12:32.3200000+03:00","stream":"Alpha"},{"version":"2020.3.41f1","releaseDate":"2022-10-21T17:22:52.5630000+03:00","stream":"LTS"},{"version":"2022.2.0b12","releaseDate":"2022-10-20T18:21:30.9490000+03:00","stream":"Beta"},{"version":"2022.2.0b11","releaseDate":"2022-10-17T22:47:44.2460000+03:00","stream":"Beta"},{"version":"2023.1.0a14","releaseDate":"2022-10-13T22:56:48.3590000+03:00","stream":"Alpha"},{"version":"2022.1.20f1","releaseDate":"2022-10-12T14:42:58.6240000+03:00","stream":"Tech"},{"version":"2023.1.0a13","releaseDate":"2022-10-06T22:12:22.6230000+03:00","stream":"Alpha"},{"version":"2022.2.0b10","releaseDate":"2022-10-06T18:22:41.4710000+03:00","stream":"Beta"},{"version":"2022.1.19f1","releaseDate":"2022-10-05T15:57:27.6550000+03:00","stream":"Tech"},{"version":"2022.1.18f1","releaseDate":"2022-09-29T17:37:44.5850000+03:00","stream":"Tech"},{"version":"2021.3.11f1","releaseDate":"2022-09-29T13:18:44.5050000+03:00","stream":"LTS"},{"version":"2022.2.0b9","releaseDate":"2022-09-29T06:03:40.7910000+03:00","stream":"Beta"},{"version":"2023.1.0a12","releaseDate":"2022-09-28T22:55:37.0920000+03:00","stream":"Alpha"},{"version":"2020.3.40f1","releaseDate":"2022-09-27T13:08:51.4880000+03:00","stream":"LTS"},{"version":"2023.1.0a11","releaseDate":"2022-09-21T17:43:10.2830000+03:00","stream":"Alpha"},{"version":"2022.1.17f1","releaseDate":"2022-09-21T14:47:30.1360000+03:00","stream":"Tech"},{"version":"2021.3.10f1","releaseDate":"2022-09-16T18:49:10.5930000+03:00","stream":"LTS"},{"version":"2020.3.39f1","releaseDate":"2022-09-15T00:53:29.6050000+03:00","stream":"LTS"},{"version":"2023.1.0a10","releaseDate":"2022-09-12T21:11:46.9380000+03:00","stream":"Alpha"},{"version":"2022.2.0b8","releaseDate":"2022-09-09T19:13:00.3470000+03:00","stream":"Beta"},{"version":"2022.1.16f1","releaseDate":"2022-09-08T16:08:35.0830000+03:00","stream":"Tech"},{"version":"2023.1.0a9","releaseDate":"2022-09-06T21:57:38.9710000+03:00","stream":"Alpha"},{"version":"2021.3.9f1","releaseDate":"2022-09-01T19:32:11.5790000+03:00","stream":"LTS"},{"version":"2022.2.0b7","releaseDate":"2022-09-01T17:23:07.2070000+03:00","stream":"Beta"},{"version":"2022.1.15f1","releaseDate":"2022-09-01T13:40:40.3950000+03:00","stream":"Tech"},{"version":"2022.2.0b6","releaseDate":"2022-08-26T01:40:10.3100000+03:00","stream":"Beta"},{"version":"2022.2.0b5","releaseDate":"2022-08-22T16:46:29.2740000+03:00","stream":"Beta"},{"version":"2022.1.14f1","releaseDate":"2022-08-22T11:56:08.0450000+03:00","stream":"Tech"},{"version":"2023.1.0a6","releaseDate":"2022-08-18T19:45:55.0300000+03:00","stream":"Alpha"},{"version":"2020.3.38f1","releaseDate":"2022-08-17T16:37:37.9830000+03:00","stream":"LTS"},{"version":"2023.1.0a5","releaseDate":"2022-08-11T19:35:17.2190000+03:00","stream":"Alpha"},{"version":"2022.1.13f1","releaseDate":"2022-08-11T10:43:08.2790000+03:00","stream":"Tech"},{"version":"2021.3.8f1","releaseDate":"2022-08-08T18:26:36.9290000+03:00","stream":"LTS"},{"version":"2022.1.12f1","releaseDate":"2022-08-05T13:30:50.9200000+03:00","stream":"Tech"},{"version":"2022.2.0b4","releaseDate":"2022-08-05T05:14:17.7170000+03:00","stream":"Beta"},{"version":"2022.2.0b3","releaseDate":"2022-07-28T20:18:44.5910000+03:00","stream":"Beta"},{"version":"2021.3.7f1","releaseDate":"2022-07-28T12:50:46.7670000+03:00","stream":"LTS"},{"version":"2022.1.11f1","releaseDate":"2022-07-27T15:20:14.4870000+03:00","stream":"Tech"},{"version":"2023.1.0a4","releaseDate":"2022-07-26T19:55:38.5590000+03:00","stream":"Alpha"},{"version":"2022.2.0b2","releaseDate":"2022-07-22T16:54:37.0230000+03:00","stream":"Beta"},{"version":"2020.3.37f1","releaseDate":"2022-07-21T12:53:36.2240000+03:00","stream":"LTS"},{"version":"2022.1.10f1","releaseDate":"2022-07-20T14:35:58.8890000+03:00","stream":"Tech"},{"version":"2022.1.9f1","releaseDate":"2022-07-14T14:39:28.8090000+03:00","stream":"Tech"},{"version":"2022.2.0b1","releaseDate":"2022-07-13T02:24:29.9080000+03:00","stream":"Beta"},{"version":"2021.3.6f1","releaseDate":"2022-07-08T12:48:54.7110000+03:00","stream":"LTS"},{"version":"2022.1.8f1","releaseDate":"2022-07-07T18:05:53.6420000+03:00","stream":"Tech"},{"version":"2022.2.0a18","releaseDate":"2022-07-04T19:35:28.1410000+03:00","stream":"Alpha"},{"version":"2022.1.7f1","releaseDate":"2022-06-29T15:39:55.5870000+03:00","stream":"Tech"},{"version":"2022.1.6f1","releaseDate":"2022-06-23T14:07:14.8560000+03:00","stream":"Tech"},{"version":"2021.3.5f1","releaseDate":"2022-06-22T20:32:31.1470000+03:00","stream":"LTS"},{"version":"2019.4.40f1","releaseDate":"2022-06-16T23:44:08.7430000+03:00","stream":"LTS"},{"version":"2022.2.0a17","releaseDate":"2022-06-16T22:20:11.1080000+03:00","stream":"Alpha"},{"version":"2020.3.36f1","releaseDate":"2022-06-16T18:04:11.6550000+03:00","stream":"LTS"},{"version":"2022.1.5f1","releaseDate":"2022-06-15T19:47:55.4610000+03:00","stream":"Tech"},{"version":"2022.2.0a16","releaseDate":"2022-06-08T23:20:40.3790000+03:00","stream":"Alpha"},{"version":"2022.1.4f1","releaseDate":"2022-06-08T18:53:22.1510000+03:00","stream":"Tech"},{"version":"2022.1.3f1","releaseDate":"2022-05-31T19:42:45.9740000+03:00","stream":"Tech"},{"version":"2021.3.4f1","releaseDate":"2022-05-31T18:14:15.5590000+03:00","stream":"LTS"},{"version":"2020.3.35f1","releaseDate":"2022-05-27T02:30:47.9620000+03:00","stream":"LTS"},{"version":"2022.1.2f1","releaseDate":"2022-05-25T17:32:41.9670000+03:00","stream":"Tech"},{"version":"2021.3.3f1","releaseDate":"2022-05-19T13:01:53.9560000+03:00","stream":"LTS"},{"version":"2022.1.1f1","releaseDate":"2022-05-18T23:43:29.7780000+03:00","stream":"Tech"},{"version":"2022.2.0a13","releaseDate":"2022-05-13T01:47:12.2000000+03:00","stream":"Alpha"},{"version":"2019.4.39f1","releaseDate":"2022-05-12T01:31:15.5880000+03:00","stream":"LTS"},{"version":"2022.1.0f1","releaseDate":"2022-05-09T19:53:20.7220000+03:00","stream":"Tech"},{"version":"2022.2.0a12","releaseDate":"2022-05-05T15:15:24.2770000+03:00","stream":"Alpha"},{"version":"2021.3.2f1","releaseDate":"2022-05-05T13:42:14.7170000+03:00","stream":"LTS"},{"version":"2020.3.34f1","releaseDate":"2022-05-04T17:33:40.9940000+03:00","stream":"LTS"},{"version":"2022.2.0a11","releaseDate":"2022-04-25T17:28:41.0660000+03:00","stream":"Alpha"},{"version":"2021.3.1f1","releaseDate":"2022-04-21T21:19:43.4030000+03:00","stream":"LTS"},{"version":"2022.2.0a10","releaseDate":"2022-04-14T16:22:59.4940000+03:00","stream":"Alpha"},{"version":"2019.4.38f1","releaseDate":"2022-04-13T18:24:10.4100000+03:00","stream":"LTS"},{"version":"2022.1.0b16","releaseDate":"2022-04-12T21:11:34.7660000+03:00","stream":"Beta"},{"version":"2021.3.0f1","releaseDate":"2022-04-11T21:46:28.6540000+03:00","stream":"LTS"},{"version":"2020.3.33f1","releaseDate":"2022-04-07T16:58:00.7880000+03:00","stream":"LTS"},{"version":"2022.1.0b15","releaseDate":"2022-04-07T10:56:08.2280000+03:00","stream":"Beta"},{"version":"2021.2.19f1","releaseDate":"2022-04-05T20:15:08.0160000+03:00","stream":"Tech"},{"version":"2022.2.0a9","releaseDate":"2022-04-01T13:23:18.7140000+03:00","stream":"Alpha"},{"version":"2021.2.18f1","releaseDate":"2022-04-01T10:28:41.0490000+03:00","stream":"Tech"},{"version":"2022.1.0b14","releaseDate":"2022-03-30T12:56:12.7250000+03:00","stream":"Beta"},{"version":"2021.2.17f1","releaseDate":"2022-03-24T23:31:28.9800000+02:00","stream":"Tech"},{"version":"2020.3.32f1","releaseDate":"2022-03-23T17:39:23.9120000+02:00","stream":"LTS"},{"version":"2019.4.37f1","releaseDate":"2022-03-22T20:47:13.8460000+02:00","stream":"LTS"},{"version":"2022.1.0b13","releaseDate":"2022-03-22T19:02:39.2100000+02:00","stream":"Beta"},{"version":"2020.3.31f1","releaseDate":"2022-03-17T20:06:28.2220000+02:00","stream":"LTS"},{"version":"2021.2.16f1","releaseDate":"2022-03-17T19:27:16.4280000+02:00","stream":"Tech"},{"version":"2022.1.0b12","releaseDate":"2022-03-17T17:03:20.4980000+02:00","stream":"Beta"},{"version":"2021.2.15f1","releaseDate":"2022-03-11T19:03:49.6680000+02:00","stream":"Tech"},{"version":"2022.1.0b11","releaseDate":"2022-03-09T09:19:01.6160000+02:00","stream":"Beta"},{"version":"2021.2.14f1","releaseDate":"2022-03-03T19:20:56.9220000+02:00","stream":"Tech"},{"version":"2022.1.0b10","releaseDate":"2022-03-02T14:36:18.0430000+02:00","stream":"Beta"},{"version":"2020.3.30f1","releaseDate":"2022-02-24T19:26:14.6130000+02:00","stream":"LTS"},{"version":"2021.2.13f1","releaseDate":"2022-02-23T21:42:33.3400000+02:00","stream":"Tech"},{"version":"2022.1.0b9","releaseDate":"2022-02-23T15:13:56.5370000+02:00","stream":"Beta"},{"version":"2021.2.12f1","releaseDate":"2022-02-17T22:43:34.6210000+02:00","stream":"Tech"},{"version":"2019.4.36f1","releaseDate":"2022-02-17T18:41:01.3940000+02:00","stream":"LTS"},{"version":"2020.3.29f1","releaseDate":"2022-02-17T17:59:07.5210000+02:00","stream":"LTS"},{"version":"2022.1.0b8","releaseDate":"2022-02-16T13:35:02.2220000+02:00","stream":"Beta"},{"version":"2021.2.11f1","releaseDate":"2022-02-10T19:24:35.6120000+02:00","stream":"Tech"},{"version":"2020.3.28f1","releaseDate":"2022-02-09T23:48:58.6840000+02:00","stream":"LTS"},{"version":"2022.1.0b7","releaseDate":"2022-02-08T13:39:17.9160000+02:00","stream":"Beta"},{"version":"2022.1.0b6","releaseDate":"2022-02-02T10:30:32.4120000+02:00","stream":"Beta"},{"version":"2021.2.10f1","releaseDate":"2022-02-02T00:07:17.8640000+02:00","stream":"Tech"},{"version":"2020.3.27f1","releaseDate":"2022-02-01T01:06:41.6490000+02:00","stream":"LTS"},{"version":"2019.4.35f1","releaseDate":"2022-01-28T16:26:18.8910000+02:00","stream":"LTS"},{"version":"2022.1.0b5","releaseDate":"2022-01-27T19:44:54.5310000+02:00","stream":"Beta"},{"version":"2021.2.9f1","releaseDate":"2022-01-27T19:09:54.1410000+02:00","stream":"Tech"},{"version":"2022.1.0b4","releaseDate":"2022-01-19T13:50:18.8200000+02:00","stream":"Beta"},{"version":"2020.3.26f1","releaseDate":"2022-01-13T22:29:30.1460000+02:00","stream":"LTS"},{"version":"2021.2.8f1","releaseDate":"2022-01-13T18:36:04.5530000+02:00","stream":"Tech"},{"version":"2022.1.0b3","releaseDate":"2022-01-12T14:14:48.4210000+02:00","stream":"Beta"},{"version":"2020.3.25f1","releaseDate":"2021-12-16T20:21:47.6100000+02:00","stream":"LTS"},{"version":"2021.2.7f1","releaseDate":"2021-12-16T19:44:39.8370000+02:00","stream":"Tech"},{"version":"2019.4.34f1","releaseDate":"2021-12-15T19:52:49.4210000+02:00","stream":"LTS"},{"version":"2022.1.0b2","releaseDate":"2021-12-14T20:43:17.2160000+02:00","stream":"Beta"},{"version":"2021.2.6f1","releaseDate":"2021-12-10T18:38:19.6320000+02:00","stream":"Tech"},{"version":"2022.1.0b1","releaseDate":"2021-12-08T21:49:54.8000000+02:00","stream":"Beta"},{"version":"2020.3.24f1","releaseDate":"2021-12-02T22:30:57.1110000+02:00","stream":"LTS"},{"version":"2021.2.5f1","releaseDate":"2021-12-01T18:54:28.0590000+02:00","stream":"Tech"},{"version":"2022.1.0a16","releaseDate":"2021-11-29T14:23:09.8130000+02:00","stream":"Alpha"},{"version":"2019.4.33f1","releaseDate":"2021-11-25T20:53:15.4390000+02:00","stream":"LTS"},{"version":"2021.2.4f1","releaseDate":"2021-11-25T15:45:23.5490000+02:00","stream":"Tech"},{"version":"2020.3.23f1","releaseDate":"2021-11-19T22:08:31.1420000+02:00","stream":"LTS"},{"version":"2022.1.0a15","releaseDate":"2021-11-18T14:23:33.3050000+02:00","stream":"Alpha"},{"version":"2021.2.3f1","releaseDate":"2021-11-18T13:49:58.4170000+02:00","stream":"Tech"},{"version":"2021.2.2f1","releaseDate":"2021-11-11T13:54:38.2890000+02:00","stream":"Tech"},{"version":"2020.3.22f1","releaseDate":"2021-11-05T21:35:33.6640000+02:00","stream":"LTS"},{"version":"2021.1.28f1","releaseDate":"2021-11-04T21:43:00.6120000+02:00","stream":"Tech"},{"version":"2021.2.1f1","releaseDate":"2021-11-04T14:14:00.1790000+02:00","stream":"Tech"},{"version":"2019.4.32f1","releaseDate":"2021-10-28T19:49:13.4530000+03:00","stream":"LTS"},{"version":"2022.1.0a13","releaseDate":"2021-10-28T17:30:14.4590000+03:00","stream":"Alpha"},{"version":"2021.1.27f1","releaseDate":"2021-10-25T22:24:00.3960000+03:00","stream":"Tech"},{"version":"2021.2.0f1","releaseDate":"2021-10-25T17:52:13.0340000+03:00","stream":"Tech"},{"version":"2020.3.21f1","releaseDate":"2021-10-21T19:33:29.3350000+03:00","stream":"LTS"},{"version":"2021.1.26f1","releaseDate":"2021-10-20T18:42:50.4910000+03:00","stream":"Tech"},{"version":"2021.1.25f1","releaseDate":"2021-10-15T00:35:29.3880000+03:00","stream":"Tech"},{"version":"2022.1.0a12","releaseDate":"2021-10-13T22:34:46.2550000+03:00","stream":"Alpha"},{"version":"2021.2.0b16","releaseDate":"2021-10-12T19:42:06.0710000+03:00","stream":"Beta"},{"version":"2020.3.20f1","releaseDate":"2021-10-08T19:38:35.5420000+03:00","stream":"LTS"},{"version":"2021.1.24f1","releaseDate":"2021-10-06T21:29:11.4340000+03:00","stream":"Tech"},{"version":"2022.1.0a11","releaseDate":"2021-10-06T18:14:18.1140000+03:00","stream":"Alpha"},{"version":"2021.2.0b15","releaseDate":"2021-10-06T12:13:13.6910000+03:00","stream":"Beta"},{"version":"2022.1.0a10","releaseDate":"2021-10-01T22:35:39.3300000+03:00","stream":"Alpha"},{"version":"2021.2.0b14","releaseDate":"2021-10-01T14:27:08.4200000+03:00","stream":"Beta"},{"version":"2021.1.23f1","releaseDate":"2021-09-30T20:01:27.1780000+03:00","stream":"Tech"},{"version":"2019.4.31f1","releaseDate":"2021-09-30T19:11:12.7000000+03:00","stream":"LTS"},{"version":"2022.1.0a9","releaseDate":"2021-09-23T19:24:52.9250000+03:00","stream":"Alpha"},{"version":"2020.3.19f1","releaseDate":"2021-09-23T00:58:37.4230000+03:00","stream":"LTS"},{"version":"2021.2.0b13","releaseDate":"2021-09-22T16:58:46.5710000+03:00","stream":"Beta"},{"version":"2021.1.22f1","releaseDate":"2021-09-21T03:25:04.5570000+03:00","stream":"Tech"},{"version":"2021.2.0b12","releaseDate":"2021-09-16T14:41:11.3370000+03:00","stream":"Beta"},{"version":"2022.1.0a8","releaseDate":"2021-09-15T17:02:16.5010000+03:00","stream":"Alpha"},{"version":"2021.1.21f1","releaseDate":"2021-09-15T00:44:40.4000000+03:00","stream":"Tech"},{"version":"2020.3.18f1","releaseDate":"2021-09-09T12:35:05.2550000+03:00","stream":"LTS"},{"version":"2021.1.20f1","releaseDate":"2021-09-08T16:15:22.7130000+03:00","stream":"Tech"},{"version":"2021.2.0b11","releaseDate":"2021-09-07T14:45:52.4140000+03:00","stream":"Beta"},{"version":"2022.1.0a7","releaseDate":"2021-09-06T14:16:46.3500000+03:00","stream":"Alpha"},{"version":"2021.2.0b10","releaseDate":"2021-09-04T04:54:50.1580000+03:00","stream":"Beta"},{"version":"2019.4.30f1","releaseDate":"2021-09-04T01:17:29.3740000+03:00","stream":"LTS"},{"version":"2021.1.19f1","releaseDate":"2021-09-01T13:51:04.9530000+03:00","stream":"Tech"},{"version":"2020.3.17f1","releaseDate":"2021-08-25T21:28:14.2230000+03:00","stream":"LTS"},{"version":"2021.1.18f1","releaseDate":"2021-08-25T20:26:42.2380000+03:00","stream":"Tech"},{"version":"2021.2.0b9","releaseDate":"2021-08-25T14:31:02.2950000+03:00","stream":"Beta"},{"version":"2021.2.0b8","releaseDate":"2021-08-19T12:59:27.4650000+03:00","stream":"Beta"},{"version":"2021.1.17f1","releaseDate":"2021-08-13T21:37:59.3900000+03:00","stream":"Tech"},{"version":"2020.3.16f1","releaseDate":"2021-08-12T18:55:22.6880000+03:00","stream":"LTS"},{"version":"2021.2.0b7","releaseDate":"2021-08-10T13:33:56.9150000+03:00","stream":"Beta"},{"version":"2021.2.0b6","releaseDate":"2021-08-04T16:24:08.9160000+03:00","stream":"Beta"},{"version":"2021.2.0b5","releaseDate":"2021-08-02T18:15:23.1620000+03:00","stream":"Beta"},{"version":"2021.1.16f1","releaseDate":"2021-08-02T17:27:00.4890000+03:00","stream":"Tech"},{"version":"2020.3.15f2","releaseDate":"2021-07-30T19:23:30.2390000+03:00","stream":"LTS"},{"version":"2019.4.29f1","releaseDate":"2021-07-30T18:19:33.1520000+03:00","stream":"LTS"},{"version":"2021.2.0b4","releaseDate":"2021-07-15T13:53:43.7390000+03:00","stream":"Beta"},{"version":"2021.1.15f1","releaseDate":"2021-07-14T14:13:58.1820000+03:00","stream":"Tech"},{"version":"2020.3.14f1","releaseDate":"2021-07-13T19:58:10.4910000+03:00","stream":"LTS"},{"version":"2021.2.0b3","releaseDate":"2021-07-08T13:47:42.2000000+03:00","stream":"Beta"},{"version":"2021.1.14f1","releaseDate":"2021-07-07T04:08:43.8360000+03:00","stream":"Tech"},{"version":"2021.2.0b2","releaseDate":"2021-07-02T16:15:04.4120000+03:00","stream":"Beta"},{"version":"2020.3.13f1","releaseDate":"2021-06-30T21:40:12.8800000+03:00","stream":"LTS"},{"version":"2021.1.13f1","releaseDate":"2021-06-30T08:59:29.1870000+03:00","stream":"Tech"},{"version":"2021.2.0b1","releaseDate":"2021-06-18T22:27:35.5390000+03:00","stream":"Beta"},{"version":"2018.4.36f1","releaseDate":"2021-06-17T19:13:54.0080000+03:00","stream":"LTS"},{"version":"2021.1.12f1","releaseDate":"2021-06-17T18:00:50.5720000+03:00","stream":"Tech"},{"version":"2020.3.12f1","releaseDate":"2021-06-15T21:58:12.2770000+03:00","stream":"LTS"},{"version":"2021.2.0a21","releaseDate":"2021-06-15T19:37:53.0380000+03:00","stream":"Alpha"},{"version":"2021.1.11f1","releaseDate":"2021-06-10T13:04:24.2960000+03:00","stream":"Tech"},{"version":"2021.2.0a20","releaseDate":"2021-06-09T20:17:01.4260000+03:00","stream":"Alpha"},{"version":"2019.4.28f1","releaseDate":"2021-06-03T20:50:56.4390000+03:00","stream":"LTS"},{"version":"2021.1.10f1","releaseDate":"2021-06-03T19:53:09.2760000+03:00","stream":"Tech"},{"version":"2021.2.0a19","releaseDate":"2021-06-03T18:19:41.9870000+03:00","stream":"Alpha"},{"version":"2020.3.11f1","releaseDate":"2021-06-01T20:44:03.0610000+03:00","stream":"LTS"},{"version":"2021.1.9f1","releaseDate":"2021-05-28T15:13:35.9700000+03:00","stream":"Tech"},{"version":"2020.3.10f1","releaseDate":"2021-05-26T21:08:15.2460000+03:00","stream":"LTS"},{"version":"2019.4.27f1","releaseDate":"2021-05-20T16:45:43.0950000+03:00","stream":"LTS"},{"version":"2020.3.9f1","releaseDate":"2021-05-19T20:45:38.0840000+03:00","stream":"LTS"},{"version":"2021.1.7f1","releaseDate":"2021-05-13T17:00:02.5350000+03:00","stream":"Tech"},{"version":"2020.3.8f1","releaseDate":"2021-05-12T23:50:34.7750000+03:00","stream":"LTS"},{"version":"2021.2.0a17","releaseDate":"2021-05-12T21:15:13.4370000+03:00","stream":"Alpha"},{"version":"2018.4.35f1","releaseDate":"2021-05-12T18:16:04.9960000+03:00","stream":"LTS"},{"version":"2021.1.6f1","releaseDate":"2021-05-06T09:42:44.3860000+03:00","stream":"Tech"},{"version":"2019.4.26f1","releaseDate":"2021-05-05T21:28:43.0280000+03:00","stream":"LTS"},{"version":"2020.3.7f1","releaseDate":"2021-05-05T20:05:58.3680000+03:00","stream":"LTS"},{"version":"2021.2.0a16","releaseDate":"2021-05-05T18:00:27.2340000+03:00","stream":"Alpha"},{"version":"2020.3.6f1","releaseDate":"2021-04-28T21:33:45.0410000+03:00","stream":"LTS"},{"version":"2021.2.0a15","releaseDate":"2021-04-28T19:51:06.5220000+03:00","stream":"Alpha"},{"version":"2021.1.5f1","releaseDate":"2021-04-28T14:57:22.3140000+03:00","stream":"Tech"},{"version":"2019.4.25f1","releaseDate":"2021-04-22T21:56:19.4680000+03:00","stream":"LTS"},{"version":"2021.1.4f1","releaseDate":"2021-04-22T11:14:16.9190000+03:00","stream":"Tech"},{"version":"2021.2.0a14","releaseDate":"2021-04-21T19:58:34.0620000+03:00","stream":"Alpha"},{"version":"2020.3.5f1","releaseDate":"2021-04-21T18:58:44.8310000+03:00","stream":"LTS"},{"version":"2018.4.34f1","releaseDate":"2021-04-15T13:28:39.0470000+03:00","stream":"LTS"},{"version":"2021.2.0a13","releaseDate":"2021-04-14T19:07:25.9350000+03:00","stream":"Alpha"},{"version":"2020.3.4f1","releaseDate":"2021-04-13T20:59:16.5940000+03:00","stream":"LTS"},{"version":"2021.1.3f1","releaseDate":"2021-04-13T14:23:53.3800000+03:00","stream":"Tech"},{"version":"2019.4.24f1","releaseDate":"2021-04-09T02:33:06.9090000+03:00","stream":"LTS"},{"version":"2020.3.3f1","releaseDate":"2021-04-07T19:37:40.6130000+03:00","stream":"LTS"},{"version":"2021.1.2f1","releaseDate":"2021-04-07T17:35:36.8280000+03:00","stream":"Tech"},{"version":"2021.2.0a12","releaseDate":"2021-04-06T19:40:54.7470000+03:00","stream":"Alpha"},{"version":"2021.2.0a11","releaseDate":"2021-03-31T20:48:42.9770000+03:00","stream":"Alpha"},{"version":"2021.1.1f1","releaseDate":"2021-03-31T17:04:08.0250000+03:00","stream":"Tech"},{"version":"2020.3.2f1","releaseDate":"2021-03-29T21:24:30.6840000+03:00","stream":"LTS"},{"version":"2021.2.0a10","releaseDate":"2021-03-24T22:41:29.4570000+02:00","stream":"Alpha"},{"version":"2018.4.33f1","releaseDate":"2021-03-24T19:48:21.9510000+02:00","stream":"LTS"},{"version":"2019.4.23f1","releaseDate":"2021-03-24T18:44:56.5610000+02:00","stream":"LTS"},{"version":"2020.3.1f1","releaseDate":"2021-03-22T20:05:51.7280000+02:00","stream":"LTS"},{"version":"2021.1.0f1","releaseDate":"2021-03-22T13:13:57.9050000+02:00","stream":"Tech"},{"version":"2021.2.0a9","releaseDate":"2021-03-17T20:02:06.9710000+02:00","stream":"Alpha"},{"version":"2021.1.0b12","releaseDate":"2021-03-17T13:21:39.6870000+02:00","stream":"Beta"},{"version":"2020.3.0f1","releaseDate":"2021-03-11T01:09:00.0190000+02:00","stream":"LTS"},{"version":"2021.1.0b11","releaseDate":"2021-03-10T20:19:22.0910000+02:00","stream":"Beta"},{"version":"2019.4.22f1","releaseDate":"2021-03-10T18:07:28.3010000+02:00","stream":"LTS"},{"version":"2021.2.0a8","releaseDate":"2021-03-09T17:39:33.3380000+02:00","stream":"Alpha"},{"version":"2021.1.0b10","releaseDate":"2021-03-04T19:23:44.8170000+02:00","stream":"Beta"},{"version":"2020.2.7f1","releaseDate":"2021-03-04T18:43:17.8170000+02:00","stream":"LTS"},{"version":"2021.2.0a6","releaseDate":"2021-02-24T20:59:57.2080000+02:00","stream":"Alpha"},{"version":"2021.1.0b8","releaseDate":"2021-02-24T19:47:25.5060000+02:00","stream":"Beta"},{"version":"2019.4.21f1","releaseDate":"2021-02-24T19:14:33.4900000+02:00","stream":"LTS"},{"version":"2020.2.6f1","releaseDate":"2021-02-24T02:10:19.4960000+02:00","stream":"LTS"},{"version":"2020.2.5f1","releaseDate":"2021-02-19T01:17:13.0170000+02:00","stream":"LTS"},{"version":"2018.4.32f1","releaseDate":"2021-02-18T14:18:22.1450000+02:00","stream":"LTS"},{"version":"2021.2.0a5","releaseDate":"2021-02-17T18:45:52.4040000+02:00","stream":"Alpha"},{"version":"2021.1.0b7","releaseDate":"2021-02-17T17:33:40.3340000+02:00","stream":"Beta"},{"version":"2020.2.4f1","releaseDate":"2021-02-12T22:14:18.5720000+02:00","stream":"LTS"},{"version":"2019.4.20f1","releaseDate":"2021-02-10T19:06:33.6840000+02:00","stream":"LTS"},{"version":"2021.1.0b6","releaseDate":"2021-02-10T17:26:16.3810000+02:00","stream":"Beta"},{"version":"2020.2.3f1","releaseDate":"2021-02-03T22:51:44.0220000+02:00","stream":"LTS"},{"version":"2021.1.0b5","releaseDate":"2021-02-03T13:02:09.2570000+02:00","stream":"Beta"},{"version":"2019.4.19f1","releaseDate":"2021-02-01T19:49:54.7260000+02:00","stream":"LTS"},{"version":"2021.1.0b4","releaseDate":"2021-01-27T14:14:30.6700000+02:00","stream":"Beta"},{"version":"2018.4.31f1","releaseDate":"2021-01-22T16:08:18.4010000+02:00","stream":"LTS"},{"version":"2020.2.2f1","releaseDate":"2021-01-21T22:41:55.7470000+02:00","stream":"LTS"},{"version":"2021.1.0b3","releaseDate":"2021-01-20T18:49:58.0860000+02:00","stream":"Beta"},{"version":"2021.1.0b2","releaseDate":"2021-01-13T17:48:52.7690000+02:00","stream":"Beta"},{"version":"2019.4.18f1","releaseDate":"2021-01-13T17:13:41.1610000+02:00","stream":"LTS"},{"version":"2020.2.1f1","releaseDate":"2020-12-23T19:32:56.7940000+02:00","stream":"LTS"},{"version":"2021.1.0b1","releaseDate":"2020-12-23T17:53:59.2550000+02:00","stream":"Beta"},{"version":"2019.4.17f1","releaseDate":"2020-12-22T17:05:02.0370000+02:00","stream":"LTS"},{"version":"2020.2.0f1","releaseDate":"2020-12-14T22:24:28.6530000+02:00","stream":"LTS"},{"version":"2021.1.0a9","releaseDate":"2020-12-11T11:34:06.1400000+02:00","stream":"Alpha"},{"version":"2020.1.17f1","releaseDate":"2020-12-09T13:39:40.0550000+02:00","stream":"LTS"},{"version":"2020.2.0b14","releaseDate":"2020-12-02T19:45:40.0260000+02:00","stream":"Beta"},{"version":"2021.1.0a8","releaseDate":"2020-12-02T19:15:19.2560000+02:00","stream":"Alpha"},{"version":"2019.4.16f1","releaseDate":"2020-12-02T18:12:41.3440000+02:00","stream":"LTS"},{"version":"2018.4.30f1","releaseDate":"2020-12-01T22:09:28.0830000+02:00","stream":"LTS"},{"version":"2020.1.16f1","releaseDate":"2020-12-01T21:04:30.3740000+02:00","stream":"LTS"},{"version":"2021.1.0a7","releaseDate":"2020-11-25T20:59:24.1580000+02:00","stream":"Alpha"},{"version":"2020.2.0b13","releaseDate":"2020-11-25T19:57:21.5630000+02:00","stream":"Beta"},{"version":"2020.1.15f1","releaseDate":"2020-11-25T13:32:56.2470000+02:00","stream":"LTS"},{"version":"2020.2.0b12","releaseDate":"2020-11-19T20:01:22.4320000+02:00","stream":"Beta"},{"version":"2020.1.14f1","releaseDate":"2020-11-18T21:08:42.0520000+02:00","stream":"LTS"},{"version":"2019.4.15f1","releaseDate":"2020-11-18T20:02:15.0550000+02:00","stream":"LTS"},{"version":"2021.1.0a5","releaseDate":"2020-11-16T10:29:13.8620000+02:00","stream":"Alpha"},{"version":"2021.1.0a6","releaseDate":"2020-11-12T15:53:12.8280000+02:00","stream":"Alpha"},{"version":"2020.2.0b11","releaseDate":"2020-11-11T21:36:00.6590000+02:00","stream":"Beta"},{"version":"2018.4.29f1","releaseDate":"2020-11-11T12:56:28.8090000+02:00","stream":"LTS"},{"version":"2020.1.13f1","releaseDate":"2020-11-11T11:59:32.6030000+02:00","stream":"LTS"},{"version":"2019.4.14f1","releaseDate":"2020-11-05T19:37:50.1760000+02:00","stream":"LTS"},{"version":"2020.2.0b10","releaseDate":"2020-11-04T19:18:58.3930000+02:00","stream":"Beta"},{"version":"2021.1.0a4","releaseDate":"2020-11-04T13:36:41.3270000+02:00","stream":"Alpha"},{"version":"2020.1.12f1","releaseDate":"2020-11-04T13:19:05.1340000+02:00","stream":"LTS"},{"version":"2020.2.0b9","releaseDate":"2020-10-28T18:33:57.6480000+02:00","stream":"Beta"},{"version":"2020.1.11f1","releaseDate":"2020-10-28T13:19:45.3420000+02:00","stream":"LTS"},{"version":"2020.2.0b8","releaseDate":"2020-10-22T18:53:30.1610000+03:00","stream":"Beta"},{"version":"2021.1.0a2","releaseDate":"2020-10-22T13:37:27.7270000+03:00","stream":"Alpha"},{"version":"2019.4.13f1","releaseDate":"2020-10-21T17:49:14.4000000+03:00","stream":"LTS"},{"version":"2020.1.10f1","releaseDate":"2020-10-21T12:46:16.1030000+03:00","stream":"LTS"},{"version":"2020.2.0b7","releaseDate":"2020-10-15T23:12:00.7850000+03:00","stream":"Beta"},{"version":"2020.1.9f1","releaseDate":"2020-10-13T20:07:55.6420000+03:00","stream":"LTS"},{"version":"2020.2.0b6","releaseDate":"2020-10-08T20:11:41.8220000+03:00","stream":"Beta"},{"version":"2019.4.12f1","releaseDate":"2020-10-07T19:30:31.4100000+03:00","stream":"LTS"},{"version":"2020.1.8f1","releaseDate":"2020-10-06T13:51:55.4870000+03:00","stream":"LTS"},{"version":"2018.4.28f1","releaseDate":"2020-10-06T12:51:51.3680000+03:00","stream":"LTS"},{"version":"2020.2.0b5","releaseDate":"2020-10-01T20:28:10.4460000+03:00","stream":"Beta"},{"version":"2020.1.7f1","releaseDate":"2020-09-30T12:51:21.0060000+03:00","stream":"LTS"},{"version":"2020.2.0b4","releaseDate":"2020-09-28T18:04:05.0940000+03:00","stream":"Beta"},{"version":"2019.4.11f1","releaseDate":"2020-09-23T17:50:07.5230000+03:00","stream":"LTS"},{"version":"2020.1.6f1","releaseDate":"2020-09-16T13:37:08.4180000+03:00","stream":"LTS"},{"version":"2019.4.10f1","releaseDate":"2020-09-10T18:00:59.3550000+03:00","stream":"LTS"},{"version":"2020.1.5f1","releaseDate":"2020-09-10T15:29:36.7490000+03:00","stream":"LTS"},{"version":"2020.2.0b2","releaseDate":"2020-09-09T20:06:38.9020000+03:00","stream":"Beta"},{"version":"2018.4.27f1","releaseDate":"2020-09-09T12:04:26.6260000+03:00","stream":"LTS"},{"version":"2020.2.0b1","releaseDate":"2020-09-03T06:50:06.9580000+03:00","stream":"Beta"},{"version":"2020.1.4f1","releaseDate":"2020-08-27T16:54:15.2610000+03:00","stream":"LTS"},{"version":"2019.4.9f1","releaseDate":"2020-08-26T18:12:20.1780000+03:00","stream":"LTS"},{"version":"2020.1.3f1","releaseDate":"2020-08-21T20:25:52.4300000+03:00","stream":"LTS"},{"version":"2020.2.0a21","releaseDate":"2020-08-20T19:08:48.0150000+03:00","stream":"Alpha"},{"version":"2019.4.8f1","releaseDate":"2020-08-12T16:18:43.9270000+03:00","stream":"LTS"},{"version":"2018.4.26f1","releaseDate":"2020-08-12T14:59:47.8120000+03:00","stream":"LTS"},{"version":"2020.1.2f1","releaseDate":"2020-08-12T14:11:53.6620000+03:00","stream":"LTS"},{"version":"2019.4.7f1","releaseDate":"2020-08-05T18:02:13.5720000+03:00","stream":"LTS"},{"version":"2020.1.1f1","releaseDate":"2020-08-05T12:04:55.1630000+03:00","stream":"LTS"},{"version":"2019.4.6f1","releaseDate":"2020-07-30T23:31:02.8270000+03:00","stream":"LTS"},{"version":"2020.2.0a19","releaseDate":"2020-07-28T20:12:37.1260000+03:00","stream":"Alpha"},{"version":"2019.4.5f1","releaseDate":"2020-07-23T11:08:58.2940000+03:00","stream":"LTS"},{"version":"2020.1.0f1","releaseDate":"2020-07-20T13:15:38.9490000+03:00","stream":"LTS"},{"version":"2020.2.0a18","releaseDate":"2020-07-15T18:09:32.2040000+03:00","stream":"Alpha"},{"version":"2019.4.4f1","releaseDate":"2020-07-15T17:33:21.3420000+03:00","stream":"LTS"},{"version":"2018.4.25f1","releaseDate":"2020-07-14T18:59:51.1720000+03:00","stream":"LTS"},{"version":"2020.1.0b16","releaseDate":"2020-07-14T14:16:19.7360000+03:00","stream":"Beta"},{"version":"2019.4.3f1","releaseDate":"2020-07-08T20:17:30.7430000+03:00","stream":"LTS"},{"version":"2020.1.0b15","releaseDate":"2020-07-08T16:16:36.1440000+03:00","stream":"Beta"},{"version":"2020.2.0a17","releaseDate":"2020-07-07T20:13:29.0870000+03:00","stream":"Alpha"},{"version":"2018.4.24f1","releaseDate":"2020-07-02T15:50:59.9690000+03:00","stream":"LTS"},{"version":"2019.4.2f1","releaseDate":"2020-07-01T17:31:49.6530000+03:00","stream":"LTS"},{"version":"2020.2.0a16","releaseDate":"2020-06-30T20:30:06.4050000+03:00","stream":"Alpha"},{"version":"2020.1.0b14","releaseDate":"2020-06-30T16:03:30.1650000+03:00","stream":"Beta"},{"version":"2019.4.1f1","releaseDate":"2020-06-18T17:26:11.2500000+03:00","stream":"LTS"},{"version":"2020.2.0a15","releaseDate":"2020-06-17T01:26:34.6240000+03:00","stream":"Alpha"},{"version":"2020.1.0b13","releaseDate":"2020-06-16T18:13:24.1630000+03:00","stream":"Beta"},{"version":"2020.1.0b12","releaseDate":"2020-06-09T18:59:47.8410000+03:00","stream":"Beta"},{"version":"2019.4.0f1","releaseDate":"2020-06-07T19:09:39.2440000+03:00","stream":"LTS"},{"version":"2020.1.0b11","releaseDate":"2020-06-03T11:04:41.2780000+03:00","stream":"Beta"},{"version":"2020.2.0a13","releaseDate":"2020-06-02T21:22:41.6660000+03:00","stream":"Alpha"},{"version":"2019.3.15f1","releaseDate":"2020-05-28T18:28:05.9350000+03:00","stream":"LTS"},{"version":"2020.1.0b10","releaseDate":"2020-05-27T18:18:15.7610000+03:00","stream":"Beta"},{"version":"2020.2.0a12","releaseDate":"2020-05-27T04:46:13.7030000+03:00","stream":"Alpha"},{"version":"2020.1.0b9","releaseDate":"2020-05-18T22:30:07.6160000+03:00","stream":"Beta"},{"version":"2019.3.14f1","releaseDate":"2020-05-18T22:09:15.4130000+03:00","stream":"LTS"},{"version":"2020.2.0a11","releaseDate":"2020-05-18T20:28:51.3580000+03:00","stream":"Alpha"},{"version":"2018.4.23f1","releaseDate":"2020-05-18T19:26:44.5050000+03:00","stream":"LTS"},{"version":"2017.4.40f1","releaseDate":"2020-05-18T18:54:47.5130000+03:00","stream":"LTS"},{"version":"2019.3.13f1","releaseDate":"2020-05-06T19:28:06.4310000+03:00","stream":"LTS"},{"version":"2020.2.0a10","releaseDate":"2020-05-06T17:34:37.9180000+03:00","stream":"Alpha"},{"version":"2020.1.0b8","releaseDate":"2020-05-05T19:50:03.1040000+03:00","stream":"Beta"},{"version":"2019.3.12f1","releaseDate":"2020-04-29T20:04:13.3180000+03:00","stream":"LTS"},{"version":"2020.2.0a9","releaseDate":"2020-04-28T16:42:11.9750000+03:00","stream":"Alpha"},{"version":"2020.1.0b7","releaseDate":"2020-04-28T13:12:51.1350000+03:00","stream":"Beta"},{"version":"2018.4.22f1","releaseDate":"2020-04-24T14:56:23.0650000+03:00","stream":"LTS"},{"version":"2020.1.0b6","releaseDate":"2020-04-24T00:32:23.4180000+03:00","stream":"Beta"},{"version":"2020.2.0a8","releaseDate":"2020-04-23T23:39:25.3310000+03:00","stream":"Alpha"},{"version":"2019.3.11f1","releaseDate":"2020-04-23T23:12:30.9100000+03:00","stream":"LTS"},{"version":"2019.3.10f1","releaseDate":"2020-04-16T17:51:49.2210000+03:00","stream":"LTS"},{"version":"2020.2.0a7","releaseDate":"2020-04-14T17:50:07.5570000+03:00","stream":"Alpha"},{"version":"2018.4.21f1","releaseDate":"2020-04-09T13:24:27.7520000+03:00","stream":"LTS"},{"version":"2020.1.0b5","releaseDate":"2020-04-09T12:02:00.1780000+03:00","stream":"Beta"},{"version":"2019.3.9f1","releaseDate":"2020-04-08T20:27:11.2330000+03:00","stream":"LTS"},{"version":"2019.3.8f1","releaseDate":"2020-04-06T16:35:43.6360000+03:00","stream":"LTS"},{"version":"2017.4.39f1","releaseDate":"2020-04-03T11:51:34.4000000+03:00","stream":"LTS"},{"version":"2020.1.0b4","releaseDate":"2020-04-01T12:27:53.0680000+03:00","stream":"Beta"},{"version":"2019.3.7f1","releaseDate":"2020-03-26T15:25:09.7460000+02:00","stream":"LTS"},{"version":"2018.4.20f1","releaseDate":"2020-03-26T14:30:57.8620000+02:00","stream":"LTS"},{"version":"2020.1.0b3","releaseDate":"2020-03-26T10:40:28.9370000+02:00","stream":"Beta"},{"version":"2017.4.38f1","releaseDate":"2020-03-20T12:06:20.6150000+02:00","stream":"LTS"},{"version":"2019.3.6f1","releaseDate":"2020-03-19T15:48:25.4900000+02:00","stream":"LTS"},{"version":"2020.1.0b2","releaseDate":"2020-03-18T13:35:10.1890000+02:00","stream":"Beta"},{"version":"2018.4.19f1","releaseDate":"2020-03-13T12:43:07.0330000+02:00","stream":"LTS"},{"version":"2019.3.5f1","releaseDate":"2020-03-12T15:37:50.3680000+02:00","stream":"LTS"},{"version":"2020.1.0b1","releaseDate":"2020-03-11T14:36:55.5980000+02:00","stream":"Beta"},{"version":"2019.3.4f1","releaseDate":"2020-03-06T12:05:37.8940000+02:00","stream":"LTS"},{"version":"2020.1.0a25","releaseDate":"2020-02-27T14:18:33.9680000+02:00","stream":"Alpha"},{"version":"2018.4.18f1","releaseDate":"2020-02-27T13:32:09.7550000+02:00","stream":"LTS"},{"version":"2019.3.3f1","releaseDate":"2020-02-26T15:41:18.4700000+02:00","stream":"LTS"},{"version":"2020.1.0a24","releaseDate":"2020-02-21T12:47:26.5020000+02:00","stream":"Alpha"},{"version":"2019.3.2f1","releaseDate":"2020-02-19T18:29:42.6760000+02:00","stream":"LTS"},{"version":"2017.4.37f1","releaseDate":"2020-02-18T18:24:58.6090000+02:00","stream":"LTS"},{"version":"2020.1.0a23","releaseDate":"2020-02-12T17:20:34.1120000+02:00","stream":"Alpha"},{"version":"2019.3.1f1","releaseDate":"2020-02-12T15:41:59.0190000+02:00","stream":"LTS"},{"version":"2018.4.17f1","releaseDate":"2020-02-11T13:48:12.9240000+02:00","stream":"LTS"},{"version":"2019.2.21f1","releaseDate":"2020-02-08T01:29:05.9630000+02:00","stream":"LTS"},{"version":"2020.1.0a22","releaseDate":"2020-02-05T12:35:10.0980000+02:00","stream":"Alpha"},{"version":"2019.2.20f1","releaseDate":"2020-01-31T15:52:30.5640000+02:00","stream":"LTS"},{"version":"2020.1.0a21","releaseDate":"2020-01-30T13:45:07.1640000+02:00","stream":"Alpha"},{"version":"2018.4.16f1","releaseDate":"2020-01-27T16:58:33.6030000+02:00","stream":"LTS"},{"version":"2019.3.0f6","releaseDate":"2020-01-27T14:06:56.5750000+02:00","stream":"LTS"},{"version":"2020.1.0a20","releaseDate":"2020-01-23T12:37:53.2280000+02:00","stream":"Alpha"},{"version":"2019.2.19f1","releaseDate":"2020-01-22T21:01:38.0230000+02:00","stream":"LTS"},{"version":"2020.1.0a19","releaseDate":"2020-01-16T13:54:15.4740000+02:00","stream":"Alpha"},{"version":"2019.2.18f1","releaseDate":"2020-01-16T01:24:20.6510000+02:00","stream":"LTS"},{"version":"2019.3.0f5","releaseDate":"2020-01-13T19:38:10.2010000+02:00","stream":"LTS"},{"version":"2017.4.36f1","releaseDate":"2020-01-09T16:49:31.0200000+02:00","stream":"LTS"},{"version":"2018.4.15f1","releaseDate":"2020-01-09T16:09:30.0590000+02:00","stream":"LTS"},{"version":"2020.1.0a18","releaseDate":"2020-01-08T13:28:04.1620000+02:00","stream":"Alpha"},{"version":"2020.1.0a17","releaseDate":"2019-12-19T12:21:05.7530000+02:00","stream":"Alpha"},{"version":"2019.2.17f1","releaseDate":"2019-12-18T21:20:41.5950000+02:00","stream":"LTS"},{"version":"2019.2.16f1","releaseDate":"2019-12-13T20:41:32.6580000+02:00","stream":"LTS"},{"version":"2020.1.0a16","releaseDate":"2019-12-12T16:47:22.9460000+02:00","stream":"Alpha"},{"version":"2019.3.0f3","releaseDate":"2019-12-11T22:34:41.7010000+02:00","stream":"LTS"},{"version":"2018.4.14f1","releaseDate":"2019-12-10T13:15:45.5800000+02:00","stream":"LTS"},{"version":"2017.4.35f1","releaseDate":"2019-12-06T16:49:43.1000000+02:00","stream":"LTS"},{"version":"2020.1.0a15","releaseDate":"2019-12-06T12:23:44.0090000+02:00","stream":"Alpha"},{"version":"2019.2.15f1","releaseDate":"2019-12-04T21:50:05.0710000+02:00","stream":"LTS"},{"version":"2019.2.14f1","releaseDate":"2019-11-27T20:40:20.1350000+02:00","stream":"LTS"},{"version":"2019.3.0f1","releaseDate":"2019-11-27T18:46:18.6920000+02:00","stream":"LTS"},{"version":"2019.3.0b12","releaseDate":"2019-11-21T22:46:51.9600000+02:00","stream":"Beta"},{"version":"2020.1.0a14","releaseDate":"2019-11-21T19:18:32.5570000+02:00","stream":"Alpha"},{"version":"2018.4.13f1","releaseDate":"2019-11-21T17:42:03.5440000+02:00","stream":"LTS"},{"version":"2019.2.13f1","releaseDate":"2019-11-20T19:22:07.1550000+02:00","stream":"LTS"},{"version":"2020.1.0a13","releaseDate":"2019-11-15T14:47:40.5570000+02:00","stream":"Alpha"},{"version":"2019.3.0b11","releaseDate":"2019-11-14T23:50:47.1120000+02:00","stream":"Beta"},{"version":"2019.2.12f1","releaseDate":"2019-11-11T20:38:24.9000000+02:00","stream":"LTS"},{"version":"2020.1.0a12","releaseDate":"2019-11-08T12:46:31.2520000+02:00","stream":"Alpha"},{"version":"2019.3.0b10","releaseDate":"2019-11-06T19:42:42.1640000+02:00","stream":"Beta"},{"version":"2019.3.0b9","releaseDate":"2019-11-01T18:37:43.0620000+02:00","stream":"Beta"},{"version":"2019.2.11f1","releaseDate":"2019-11-01T14:01:07.4740000+02:00","stream":"LTS"},{"version":"2020.1.0a11","releaseDate":"2019-10-31T18:32:46.5520000+02:00","stream":"Alpha"},{"version":"2017.4.34f1","releaseDate":"2019-10-30T19:20:05.4810000+02:00","stream":"LTS"},{"version":"2018.4.12f1","releaseDate":"2019-10-28T13:35:32.8840000+02:00","stream":"LTS"},{"version":"2019.2.10f1","releaseDate":"2019-10-24T00:46:43.5750000+03:00","stream":"LTS"},{"version":"2019.3.0b8","releaseDate":"2019-10-23T20:20:42.4990000+03:00","stream":"Beta"},{"version":"2020.1.0a9","releaseDate":"2019-10-17T13:21:00.0530000+03:00","stream":"Alpha"},{"version":"2019.3.0b7","releaseDate":"2019-10-14T20:32:52.8980000+03:00","stream":"Beta"},{"version":"2019.2.9f1","releaseDate":"2019-10-11T21:05:30.4520000+03:00","stream":"LTS"},{"version":"2018.4.11f1","releaseDate":"2019-10-10T16:08:52.3110000+03:00","stream":"LTS"},{"version":"2020.1.0a8","releaseDate":"2019-10-10T12:24:32.0630000+03:00","stream":"Alpha"},{"version":"2017.4.33f1","releaseDate":"2019-10-07T11:27:32.7430000+03:00","stream":"LTS"},{"version":"2019.3.0b6","releaseDate":"2019-10-04T19:50:37.4470000+03:00","stream":"Beta"},{"version":"2019.2.8f1","releaseDate":"2019-10-04T01:11:03.8390000+03:00","stream":"LTS"},{"version":"2020.1.0a7","releaseDate":"2019-10-01T19:22:34.3760000+03:00","stream":"Alpha"},{"version":"2018.4.10f1","releaseDate":"2019-10-01T15:06:54.8160000+03:00","stream":"LTS"},{"version":"2019.2.7f2","releaseDate":"2019-09-30T21:04:28.7120000+03:00","stream":"LTS"},{"version":"2019.3.0b5","releaseDate":"2019-09-30T17:32:45.4310000+03:00","stream":"Beta"},{"version":"2020.1.0a5","releaseDate":"2019-09-25T17:28:57.7470000+03:00","stream":"Alpha"},{"version":"2019.3.0b4","releaseDate":"2019-09-20T18:43:52.3750000+03:00","stream":"Beta"},{"version":"2019.2.6f1","releaseDate":"2019-09-17T22:29:14.5200000+03:00","stream":"LTS"},{"version":"2018.4.9f1","releaseDate":"2019-09-13T15:05:02.2970000+03:00","stream":"LTS"},{"version":"2019.2.5f1","releaseDate":"2019-09-12T18:37:27.5480000+03:00","stream":"LTS"},{"version":"2019.3.0b3","releaseDate":"2019-09-10T19:31:30.3650000+03:00","stream":"Beta"},{"version":"2019.3.0b2","releaseDate":"2019-09-06T20:16:21.5300000+03:00","stream":"Beta"},{"version":"2020.1.0a3","releaseDate":"2019-09-05T18:08:44.2560000+03:00","stream":"Alpha"},{"version":"2019.2.4f1","releaseDate":"2019-09-05T17:17:26.6680000+03:00","stream":"LTS"},{"version":"2017.4.32f1","releaseDate":"2019-09-05T14:50:38.8620000+03:00","stream":"LTS"},{"version":"2018.4.8f1","releaseDate":"2019-08-30T12:24:35.8910000+03:00","stream":"LTS"},{"version":"2019.2.3f1","releaseDate":"2019-08-28T15:57:33.7170000+03:00","stream":"LTS"},{"version":"2019.3.0b1","releaseDate":"2019-08-26T18:03:03.4490000+03:00","stream":"Beta"},{"version":"2019.2.2f1","releaseDate":"2019-08-21T13:42:41.1150000+03:00","stream":"LTS"},{"version":"2018.4.7f1","releaseDate":"2019-08-19T13:07:37.5940000+03:00","stream":"LTS"},{"version":"2019.2.1f1","releaseDate":"2019-08-14T17:28:59.0190000+03:00","stream":"LTS"},{"version":"2019.3.0a12","releaseDate":"2019-08-13T17:24:35.2560000+03:00","stream":"Alpha"},{"version":"2018.4.6f1","releaseDate":"2019-08-08T12:30:29.8390000+03:00","stream":"LTS"},{"version":"2019.1.14f1","releaseDate":"2019-08-08T12:01:21.7260000+03:00","stream":"LTS"},{"version":"2017.4.31f1","releaseDate":"2019-08-02T13:02:34.0640000+03:00","stream":"LTS"},{"version":"2019.1.13f1","releaseDate":"2019-08-01T14:12:43.9510000+03:00","stream":"LTS"},{"version":"2019.3.0a11","releaseDate":"2019-07-31T21:32:46.9870000+03:00","stream":"Alpha"},{"version":"2019.2.0f1","releaseDate":"2019-07-29T13:48:07.1340000+03:00","stream":"LTS"},{"version":"2019.1.12f1","releaseDate":"2019-07-26T16:28:16.0830000+03:00","stream":"LTS"},{"version":"2018.4.5f1","releaseDate":"2019-07-26T14:33:58.8310000+03:00","stream":"LTS"},{"version":"2019.3.0a10","releaseDate":"2019-07-22T21:03:08.9830000+03:00","stream":"Alpha"},{"version":"2019.2.0b10","releaseDate":"2019-07-18T18:39:34.1320000+03:00","stream":"Beta"},{"version":"2019.1.11f1","releaseDate":"2019-07-18T15:29:11.3370000+03:00","stream":"LTS"},{"version":"2018.4.4f1","releaseDate":"2019-07-12T19:20:22.9020000+03:00","stream":"LTS"},{"version":"2019.1.10f1","releaseDate":"2019-07-12T18:54:54.0030000+03:00","stream":"LTS"},{"version":"2019.2.0b9","releaseDate":"2019-07-11T21:56:49.6310000+03:00","stream":"Beta"},{"version":"2017.4.30f1","releaseDate":"2019-07-05T17:27:47.0610000+03:00","stream":"LTS"},{"version":"2019.1.9f1","releaseDate":"2019-07-05T14:47:29.6410000+03:00","stream":"LTS"},{"version":"2019.3.0a8","releaseDate":"2019-07-03T20:30:44.9800000+03:00","stream":"Alpha"},{"version":"2018.4.3f1","releaseDate":"2019-06-28T16:03:41.3670000+03:00","stream":"LTS"},{"version":"2019.3.0a7","releaseDate":"2019-06-26T20:12:40.6830000+03:00","stream":"Alpha"},{"version":"2019.2.0b7","releaseDate":"2019-06-25T23:47:11.2540000+03:00","stream":"Beta"},{"version":"2019.1.8f1","releaseDate":"2019-06-22T11:48:33.7900000+03:00","stream":"LTS"},{"version":"2019.3.0a6","releaseDate":"2019-06-19T06:02:44.0090000+03:00","stream":"Alpha"},{"version":"2019.1.7f1","releaseDate":"2019-06-14T18:44:01.6130000+03:00","stream":"LTS"},{"version":"2019.2.0b6","releaseDate":"2019-06-12T12:40:00.7880000+03:00","stream":"Beta"},{"version":"2017.4.29f1","releaseDate":"2019-06-08T22:03:51.2520000+03:00","stream":"LTS"},{"version":"2018.4.2f1","releaseDate":"2019-06-08T21:07:32.0460000+03:00","stream":"LTS"},{"version":"2019.1.6f1","releaseDate":"2019-06-08T19:58:35.5350000+03:00","stream":"LTS"},{"version":"2019.3.0a5","releaseDate":"2019-06-06T15:22:57.5620000+03:00","stream":"Alpha"},{"version":"2019.2.0b5","releaseDate":"2019-06-05T17:32:16.2730000+03:00","stream":"Beta"},{"version":"2019.1.5f1","releaseDate":"2019-06-03T14:40:25.5010000+03:00","stream":"LTS"},{"version":"2017.4.28f1","releaseDate":"2019-05-30T20:27:14.6810000+03:00","stream":"LTS"},{"version":"2019.3.0a4","releaseDate":"2019-05-30T17:15:42.7070000+03:00","stream":"Alpha"},{"version":"2019.2.0b4","releaseDate":"2019-05-29T20:12:13.2450000+03:00","stream":"Beta"},{"version":"2018.4.1f1","releaseDate":"2019-05-28T19:24:03.8580000+03:00","stream":"LTS"},{"version":"2019.1.4f1","releaseDate":"2019-05-24T20:57:10.7780000+03:00","stream":"LTS"},{"version":"2019.2.0b3","releaseDate":"2019-05-22T17:03:19.4450000+03:00","stream":"Beta"},{"version":"2019.3.0a3","releaseDate":"2019-05-22T14:46:55.0550000+03:00","stream":"Alpha"},{"version":"2019.1.3f1","releaseDate":"2019-05-16T17:47:53.8260000+03:00","stream":"LTS"},{"version":"2019.2.0b2","releaseDate":"2019-05-15T18:44:17.7590000+03:00","stream":"Beta"},{"version":"2019.3.0a2","releaseDate":"2019-05-10T23:36:39.2540000+03:00","stream":"Alpha"},{"version":"2019.1.2f1","releaseDate":"2019-05-10T18:59:18.5200000+03:00","stream":"LTS"},{"version":"2017.4.27f1","releaseDate":"2019-05-10T16:21:41.1350000+03:00","stream":"LTS"},{"version":"2018.4.0f1","releaseDate":"2019-05-10T14:43:31.4210000+03:00","stream":"LTS"},{"version":"2019.2.0b1","releaseDate":"2019-05-09T12:44:58.3510000+03:00","stream":"Beta"},{"version":"2019.1.1f1","releaseDate":"2019-05-03T17:43:43.5970000+03:00","stream":"LTS"},{"version":"2019.2.0a14","releaseDate":"2019-05-01T20:59:12.6880000+03:00","stream":"Alpha"},{"version":"2018.3.14f1","releaseDate":"2019-04-26T14:50:27.0450000+03:00","stream":"LTS"},{"version":"2019.2.0a13","releaseDate":"2019-04-24T20:50:21.0670000+03:00","stream":"Alpha"},{"version":"2017.4.26f1","releaseDate":"2019-04-23T12:36:49.5910000+03:00","stream":"LTS"},{"version":"2018.3.13f1","releaseDate":"2019-04-18T12:14:47.6950000+03:00","stream":"LTS"},{"version":"2019.1.0f2","releaseDate":"2019-04-15T16:28:01.4440000+03:00","stream":"LTS"},{"version":"2019.2.0a11","releaseDate":"2019-04-11T19:48:43.1840000+03:00","stream":"Alpha"},{"version":"2019.1.0f1","releaseDate":"2019-04-08T21:51:36.4080000+03:00","stream":"LTS"},{"version":"2018.3.12f1","releaseDate":"2019-04-08T17:36:53.3460000+03:00","stream":"LTS"},{"version":"2017.4.25f1","releaseDate":"2019-04-08T16:39:05.1910000+03:00","stream":"LTS"},{"version":"2019.1.0b10","releaseDate":"2019-04-03T17:15:22.3850000+03:00","stream":"Beta"},{"version":"2018.3.11f1","releaseDate":"2019-03-29T14:15:27.9350000+02:00","stream":"LTS"},{"version":"2019.1.0b9","releaseDate":"2019-03-26T18:57:04.8470000+02:00","stream":"Beta"},{"version":"2018.3.10f1","releaseDate":"2019-03-25T19:27:03.0350000+02:00","stream":"LTS"},{"version":"2017.4.24f1","releaseDate":"2019-03-22T11:39:13.6670000+02:00","stream":"LTS"},{"version":"2019.2.0a9","releaseDate":"2019-03-20T17:45:22.3090000+02:00","stream":"Alpha"},{"version":"2019.1.0b8","releaseDate":"2019-03-18T19:17:39.0930000+02:00","stream":"Beta"},{"version":"2018.3.9f1","releaseDate":"2019-03-18T14:14:09.6120000+02:00","stream":"LTS"},{"version":"2019.1.0b7","releaseDate":"2019-03-13T18:10:13.3900000+02:00","stream":"Beta"},{"version":"2019.2.0a8","releaseDate":"2019-03-13T16:22:24.9240000+02:00","stream":"Alpha"},{"version":"2017.4.23f1","releaseDate":"2019-03-08T19:28:16.4670000+02:00","stream":"LTS"},{"version":"2019.1.0b6","releaseDate":"2019-03-08T18:41:08.1330000+02:00","stream":"Beta"},{"version":"2018.3.8f1","releaseDate":"2019-03-08T18:15:08.8060000+02:00","stream":"LTS"},{"version":"2019.2.0a7","releaseDate":"2019-03-04T15:52:19.7100000+02:00","stream":"Alpha"},{"version":"2019.1.0b5","releaseDate":"2019-03-01T18:44:15.4080000+02:00","stream":"Beta"},{"version":"5.6.7f1","releaseDate":"2019-02-28T20:35:23.8950000+02:00","stream":"LTS"},{"version":"2018.2.21f1","releaseDate":"2019-02-28T19:57:55.3450000+02:00","stream":"LTS"},{"version":"2017.4.22f1","releaseDate":"2019-02-28T19:01:39.7560000+02:00","stream":"LTS"},{"version":"2018.3.7f1","releaseDate":"2019-02-28T18:07:09.1890000+02:00","stream":"LTS"},{"version":"2019.2.0a6","releaseDate":"2019-02-27T09:50:11.0870000+02:00","stream":"Alpha"},{"version":"2017.4.21f1","releaseDate":"2019-02-21T17:15:49.2140000+02:00","stream":"LTS"},{"version":"2019.1.0b4","releaseDate":"2019-02-19T18:30:33.2540000+02:00","stream":"Beta"},{"version":"2018.3.6f1","releaseDate":"2019-02-15T18:45:14.6840000+02:00","stream":"LTS"},{"version":"2019.1.0b3","releaseDate":"2019-02-11T17:22:34.4640000+02:00","stream":"Beta"},{"version":"2017.4.20f2","releaseDate":"2019-02-11T12:07:10.8110000+02:00","stream":"LTS"},{"version":"2018.3.5f1","releaseDate":"2019-02-08T17:27:29.3790000+02:00","stream":"LTS"},{"version":"2019.2.0a4","releaseDate":"2019-02-06T16:46:04.4100000+02:00","stream":"Alpha"},{"version":"2019.1.0b2","releaseDate":"2019-02-04T15:55:05.8000000+02:00","stream":"Beta"},{"version":"2018.3.4f1","releaseDate":"2019-02-01T18:49:54.5170000+02:00","stream":"LTS"},{"version":"2019.1.0b1","releaseDate":"2019-01-28T17:21:41.6220000+02:00","stream":"Beta"},{"version":"2017.4.19f1","releaseDate":"2019-01-28T16:49:20.9630000+02:00","stream":"LTS"},{"version":"2018.3.3f1","releaseDate":"2019-01-25T16:37:01.8620000+02:00","stream":"LTS"},{"version":"2018.3.2f1","releaseDate":"2019-01-17T11:18:26.5460000+02:00","stream":"LTS"},{"version":"2019.1.0a14","releaseDate":"2019-01-15T20:45:50.0540000+02:00","stream":"Alpha"},{"version":"2018.3.1f1","releaseDate":"2019-01-10T14:42:52.5380000+02:00","stream":"LTS"},{"version":"2017.4.18f1","releaseDate":"2019-01-10T13:37:33.9090000+02:00","stream":"LTS"},{"version":"2019.1.0a13","releaseDate":"2019-01-03T03:39:26.4790000+02:00","stream":"Alpha"},{"version":"2019.1.0a12","releaseDate":"2018-12-14T20:20:29.2790000+02:00","stream":"Alpha"},{"version":"2018.2.20f1","releaseDate":"2018-12-14T13:15:42.9470000+02:00","stream":"LTS"},{"version":"2018.3.0f2","releaseDate":"2018-12-12T14:02:30.5550000+02:00","stream":"LTS"},{"version":"2018.3.0f1","releaseDate":"2018-12-11T17:41:14.3820000+02:00","stream":"LTS"},{"version":"2017.2.5f1","releaseDate":"2018-12-07T20:04:37.5790000+02:00","stream":"LTS"},{"version":"2018.2.19f1","releaseDate":"2018-12-07T18:44:08.5920000+02:00","stream":"LTS"},{"version":"2017.4.17f1","releaseDate":"2018-12-07T17:51:37.3080000+02:00","stream":"LTS"},{"version":"2019.1.0a11","releaseDate":"2018-12-04T22:58:06.1280000+02:00","stream":"Alpha"},{"version":"2018.2.18f1","releaseDate":"2018-11-30T17:10:33.2730000+02:00","stream":"LTS"},{"version":"2018.3.0b12","releaseDate":"2018-11-28T14:03:56.2160000+02:00","stream":"Beta"},{"version":"2019.1.0a10","releaseDate":"2018-11-23T18:56:21.7430000+02:00","stream":"Alpha"},{"version":"2017.4.16f1","releaseDate":"2018-11-23T12:14:00.4550000+02:00","stream":"LTS"},{"version":"2018.2.17f1","releaseDate":"2018-11-21T17:28:51.6180000+02:00","stream":"LTS"},{"version":"2018.3.0b11","releaseDate":"2018-11-21T15:58:06.3430000+02:00","stream":"Beta"},{"version":"2017.2.4p1","releaseDate":"2018-11-16T12:22:37.6740000+02:00","stream":"Tech"},{"version":"2018.2.16f1","releaseDate":"2018-11-15T13:01:20.6050000+02:00","stream":"LTS"},{"version":"2019.1.0a9","releaseDate":"2018-11-14T18:08:29.5040000+02:00","stream":"Alpha"},{"version":"2018.3.0b10","releaseDate":"2018-11-14T15:35:56.4560000+02:00","stream":"Beta"},{"version":"2017.4.15f1","releaseDate":"2018-11-12T16:08:59.6070000+02:00","stream":"LTS"},{"version":"2018.2.15f1","releaseDate":"2018-11-09T12:10:19.0780000+02:00","stream":"LTS"},{"version":"2018.3.0b9","releaseDate":"2018-11-07T13:26:23.7790000+02:00","stream":"Beta"},{"version":"2019.1.0a8","releaseDate":"2018-11-07T01:07:14.7810000+02:00","stream":"Alpha"},{"version":"2019.1.0a7","releaseDate":"2018-10-31T18:36:10.7410000+02:00","stream":"Alpha"},{"version":"2018.3.0b8","releaseDate":"2018-10-31T12:43:25.5420000+02:00","stream":"Beta"},{"version":"2018.2.14f1","releaseDate":"2018-10-26T18:36:58.3850000+03:00","stream":"LTS"},{"version":"2017.4.14f1","releaseDate":"2018-10-26T14:46:14.9670000+03:00","stream":"LTS"},{"version":"2018.3.0b7","releaseDate":"2018-10-24T12:18:44.7430000+03:00","stream":"Beta"},{"version":"2018.2.13f1","releaseDate":"2018-10-18T13:04:17.7440000+03:00","stream":"LTS"},{"version":"2018.3.0b6","releaseDate":"2018-10-18T10:28:58.7650000+03:00","stream":"Beta"},{"version":"2018.2.12f1","releaseDate":"2018-10-12T17:40:28.9550000+03:00","stream":"LTS"},{"version":"2017.4.13f1","releaseDate":"2018-10-12T15:12:23.4990000+03:00","stream":"LTS"},{"version":"2018.3.0b5","releaseDate":"2018-10-10T11:17:14.4800000+03:00","stream":"Beta"},{"version":"2018.2.11f1","releaseDate":"2018-10-04T13:36:18.2630000+03:00","stream":"LTS"},{"version":"2018.3.0b4","releaseDate":"2018-10-03T14:09:35.4250000+03:00","stream":"Beta"},{"version":"2017.2.4f1","releaseDate":"2018-10-03T13:10:22.6970000+03:00","stream":"LTS"},{"version":"2017.4.12f1","releaseDate":"2018-09-27T13:54:38.6660000+03:00","stream":"LTS"},{"version":"2018.2.10f1","releaseDate":"2018-09-26T17:32:56.4460000+03:00","stream":"LTS"},{"version":"2018.3.0b3","releaseDate":"2018-09-26T16:21:30.9390000+03:00","stream":"Beta"},{"version":"2018.2.9f1","releaseDate":"2018-09-21T15:47:59.5780000+03:00","stream":"LTS"},{"version":"2018.3.0b2","releaseDate":"2018-09-20T12:44:45.6210000+03:00","stream":"Beta"},{"version":"2018.2.8f1","releaseDate":"2018-09-14T13:03:11.1630000+03:00","stream":"LTS"},{"version":"2017.4.11f1","releaseDate":"2018-09-13T12:35:24.1460000+03:00","stream":"LTS"},{"version":"2018.3.0b1","releaseDate":"2018-09-11T16:07:05.2700000+03:00","stream":"Beta"},{"version":"2018.2.7f1","releaseDate":"2018-09-06T19:34:51.1710000+03:00","stream":"LTS"},{"version":"2018.2.6f1","releaseDate":"2018-08-30T14:26:23.2890000+03:00","stream":"LTS"},{"version":"2017.2.3p4","releaseDate":"2018-08-29T16:24:14.6370000+03:00","stream":"Tech"},{"version":"2018.1.9f2","releaseDate":"2018-08-29T13:25:53.0360000+03:00","stream":"LTS"},{"version":"2017.4.10f1","releaseDate":"2018-08-24T16:44:21.5260000+03:00","stream":"LTS"},{"version":"2018.2.5f1","releaseDate":"2018-08-22T18:12:22.7900000+03:00","stream":"LTS"},{"version":"2018.2.4f1","releaseDate":"2018-08-17T17:17:08.6950000+03:00","stream":"LTS"},{"version":"2018.2.3f1","releaseDate":"2018-08-10T19:45:34.0780000+03:00","stream":"LTS"},{"version":"2017.4.9f1","releaseDate":"2018-08-10T17:27:28.1310000+03:00","stream":"LTS"},{"version":"2017.2.3p3","releaseDate":"2018-08-03T17:58:35.3170000+03:00","stream":"Tech"},{"version":"2018.2.2f1","releaseDate":"2018-08-03T16:32:08.8780000+03:00","stream":"LTS"},{"version":"2017.4.8f1","releaseDate":"2018-07-26T14:30:32.4430000+03:00","stream":"LTS"},{"version":"2018.2.1f1","releaseDate":"2018-07-26T13:43:51.5190000+03:00","stream":"LTS"},{"version":"2017.1.5f1","releaseDate":"2018-07-23T19:24:20.2750000+03:00","stream":"LTS"},{"version":"2018.1.8f1","releaseDate":"2018-07-13T16:52:59.7910000+03:00","stream":"LTS"},{"version":"2017.4.7f1","releaseDate":"2018-07-13T13:22:49.0920000+03:00","stream":"LTS"},{"version":"2018.2.0f2","releaseDate":"2018-07-09T19:46:12.1340000+03:00","stream":"LTS"},{"version":"2018.2.0f1","releaseDate":"2018-07-06T18:20:59.9000000+03:00","stream":"LTS"},{"version":"2017.2.3p2","releaseDate":"2018-07-05T17:38:35.9270000+03:00","stream":"Tech"},{"version":"2018.1.7f1","releaseDate":"2018-07-05T17:17:37.5460000+03:00","stream":"LTS"},{"version":"2018.2.0b11","releaseDate":"2018-07-03T16:34:59.1560000+03:00","stream":"Beta"},{"version":"2018.2.0b10","releaseDate":"2018-06-26T16:53:45.0430000+03:00","stream":"Beta"},{"version":"2017.4.6f1","releaseDate":"2018-06-22T11:23:54.2190000+03:00","stream":"LTS"},{"version":"2018.1.6f1","releaseDate":"2018-06-21T18:02:57.3560000+03:00","stream":"LTS"},{"version":"2017.1.4p2","releaseDate":"2018-06-20T12:46:38.0700000+03:00","stream":"Tech"},{"version":"2018.2.0b9","releaseDate":"2018-06-19T16:54:09.0660000+03:00","stream":"Beta"},{"version":"2018.1.5f1","releaseDate":"2018-06-15T15:35:07.6220000+03:00","stream":"LTS"},{"version":"2018.2.0b8","releaseDate":"2018-06-13T16:54:30.1710000+03:00","stream":"Beta"},{"version":"2017.1.4p1","releaseDate":"2018-06-13T16:31:38.3930000+03:00","stream":"Tech"},{"version":"2018.1.4f1","releaseDate":"2018-06-11T17:59:27.4260000+03:00","stream":"LTS"},{"version":"2017.4.5f1","releaseDate":"2018-06-07T12:24:13.1100000+03:00","stream":"LTS"},{"version":"2018.2.0b7","releaseDate":"2018-06-06T20:13:56.2500000+03:00","stream":"Beta"},{"version":"2018.1.3f1","releaseDate":"2018-06-04T12:52:38.3090000+03:00","stream":"LTS"},{"version":"2017.2.3p1","releaseDate":"2018-05-31T13:04:31.7460000+03:00","stream":"Tech"},{"version":"2018.2.0b6","releaseDate":"2018-05-29T17:49:22.1680000+03:00","stream":"Beta"},{"version":"2018.1.2f1","releaseDate":"2018-05-25T18:39:42.9360000+03:00","stream":"LTS"},{"version":"2018.2.0b5","releaseDate":"2018-05-24T10:21:44.1020000+03:00","stream":"Beta"},{"version":"2017.1.4f1","releaseDate":"2018-05-23T18:53:36.9910000+03:00","stream":"LTS"},{"version":"2017.4.4f1","releaseDate":"2018-05-23T18:20:18.8730000+03:00","stream":"LTS"},{"version":"2017.2.3f1","releaseDate":"2018-05-18T16:26:34.7630000+03:00","stream":"LTS"},{"version":"2018.1.1f1","releaseDate":"2018-05-18T12:56:06.0720000+03:00","stream":"LTS"},{"version":"2018.2.0b4","releaseDate":"2018-05-11T22:14:37.6770000+03:00","stream":"Beta"},{"version":"2017.4.3f1","releaseDate":"2018-05-11T17:44:04.8180000+03:00","stream":"LTS"},{"version":"5.6.6f2","releaseDate":"2018-05-08T12:03:55.4790000+03:00","stream":"LTS"},{"version":"2017.1.3p4","releaseDate":"2018-05-06T13:03:23.7480000+03:00","stream":"Tech"},{"version":"2018.2.0b3","releaseDate":"2018-05-04T03:29:00.7830000+03:00","stream":"Beta"},{"version":"2018.1.0f2","releaseDate":"2018-05-02T12:32:53.1810000+03:00","stream":"LTS"},{"version":"2017.4.2f2","releaseDate":"2018-04-30T12:57:20.7740000+03:00","stream":"LTS"},{"version":"2017.2.2p4","releaseDate":"2018-04-27T11:09:34.6590000+03:00","stream":"Tech"},{"version":"2018.1.0f1","releaseDate":"2018-04-26T17:34:43.9320000+03:00","stream":"LTS"},{"version":"2018.2.0b2","releaseDate":"2018-04-25T18:46:41.7020000+03:00","stream":"Beta"},{"version":"2018.2.0b1","releaseDate":"2018-04-18T04:14:08.2100000+03:00","stream":"Beta"},{"version":"2017.4.1f1","releaseDate":"2018-04-12T15:46:45.4370000+03:00","stream":"LTS"},{"version":"5.6.5p4","releaseDate":"2018-04-12T13:47:59.7170000+03:00","stream":"Tech"},{"version":"2017.1.3p3","releaseDate":"2018-04-06T13:32:38.6350000+03:00","stream":"Tech"},{"version":"2017.2.2p3","releaseDate":"2018-04-05T13:16:10.2630000+03:00","stream":"Tech"},{"version":"2018.1.0b13","releaseDate":"2018-03-30T13:12:24.9220000+03:00","stream":"Beta"},{"version":"2017.2.2p2","releaseDate":"2018-03-23T15:33:23.0760000+02:00","stream":"Tech"},{"version":"2018.1.0b12","releaseDate":"2018-03-23T10:03:45.3420000+02:00","stream":"Beta"},{"version":"2017.4.0f1","releaseDate":"2018-03-19T13:40:15.8330000+02:00","stream":"LTS"},{"version":"2018.1.0b11","releaseDate":"2018-03-16T15:01:57.6520000+02:00","stream":"Beta"},{"version":"5.6.5p3","releaseDate":"2018-03-16T11:45:19.3630000+02:00","stream":"Tech"},{"version":"2017.3.1p4","releaseDate":"2018-03-13T13:06:06.2160000+02:00","stream":"Tech"},{"version":"2017.2.2p1","releaseDate":"2018-03-09T17:01:16.6870000+02:00","stream":"Tech"},{"version":"2018.1.0b10","releaseDate":"2018-03-08T17:30:14.4980000+02:00","stream":"Beta"},{"version":"2017.3.1p3","releaseDate":"2018-03-06T15:00:52.2380000+02:00","stream":"Tech"},{"version":"2017.1.3p2","releaseDate":"2018-03-02T13:14:31.1230000+02:00","stream":"Tech"},{"version":"2018.1.0b9","releaseDate":"2018-02-27T22:03:39.0920000+02:00","stream":"Beta"},{"version":"2017.3.1p2","releaseDate":"2018-02-26T13:20:31.2290000+02:00","stream":"Tech"},{"version":"2017.2.2f1","releaseDate":"2018-02-26T12:56:15.2980000+02:00","stream":"LTS"},{"version":"2018.1.0b8","releaseDate":"2018-02-21T01:19:54.4560000+02:00","stream":"Beta"},{"version":"5.6.5p2","releaseDate":"2018-02-15T12:54:22.5920000+02:00","stream":"Tech"},{"version":"2017.3.1p1","releaseDate":"2018-02-14T18:32:07.5630000+02:00","stream":"Tech"},{"version":"2018.1.0b7","releaseDate":"2018-02-14T13:12:33.8400000+02:00","stream":"Beta"},{"version":"2017.2.1p4","releaseDate":"2018-02-12T15:46:02.9250000+02:00","stream":"Tech"},{"version":"2018.1.0b6","releaseDate":"2018-02-08T01:26:06.8280000+02:00","stream":"Beta"},{"version":"2017.3.1f1","releaseDate":"2018-02-05T17:31:22.3830000+02:00","stream":"LTS"},{"version":"2017.1.3p1","releaseDate":"2018-02-02T18:03:25.9430000+02:00","stream":"Tech"},{"version":"2018.1.0b5","releaseDate":"2018-01-31T14:56:51.0850000+02:00","stream":"Beta"},{"version":"2017.2.1p3","releaseDate":"2018-01-30T18:14:38.4790000+02:00","stream":"Tech"},{"version":"2017.3.0p4","releaseDate":"2018-01-29T14:43:13.4400000+02:00","stream":"Tech"},{"version":"2018.1.0b4","releaseDate":"2018-01-22T21:10:28.0890000+02:00","stream":"Beta"},{"version":"5.6.5p1","releaseDate":"2018-01-22T12:15:55.2200000+02:00","stream":"Tech"},{"version":"2017.3.0p3","releaseDate":"2018-01-18T18:39:06.6310000+02:00","stream":"Tech"},{"version":"2018.1.0b3","releaseDate":"2018-01-17T14:06:15.8980000+02:00","stream":"Beta"},{"version":"2017.3.0p2","releaseDate":"2018-01-12T20:16:05.8470000+02:00","stream":"Tech"},{"version":"5.5.6f1","releaseDate":"2018-01-12T19:52:32.0940000+02:00","stream":"LTS"},{"version":"2017.2.1p2","releaseDate":"2018-01-12T12:39:16.7060000+02:00","stream":"Tech"},{"version":"2018.1.0b2","releaseDate":"2018-01-09T17:44:00.8450000+02:00","stream":"Beta"},{"version":"2017.1.3f1","releaseDate":"2018-01-04T19:14:40.6550000+02:00","stream":"LTS"},{"version":"2017.3.0p1","releaseDate":"2017-12-22T13:42:56.1700000+02:00","stream":"Tech"},{"version":"5.6.5f1","releaseDate":"2017-12-21T13:08:15.3130000+02:00","stream":"LTS"},{"version":"2017.2.1p1","releaseDate":"2017-12-20T15:53:25.0250000+02:00","stream":"Tech"},{"version":"2017.3.0f3","releaseDate":"2017-12-18T18:24:06.3520000+02:00","stream":"LTS"},{"version":"2017.2.1f1","releaseDate":"2017-12-11T17:44:05.8030000+02:00","stream":"LTS"},{"version":"2017.3.0f2","releaseDate":"2017-12-08T18:45:52.2440000+02:00","stream":"LTS"},{"version":"2017.1.2p4","releaseDate":"2017-12-08T17:51:33.8740000+02:00","stream":"Tech"},{"version":"5.6.4p4","releaseDate":"2017-12-07T14:26:50.5400000+02:00","stream":"Tech"},{"version":"2017.2.0p4","releaseDate":"2017-12-04T12:45:02.9910000+02:00","stream":"Tech"},{"version":"2017.3.0f1","releaseDate":"2017-12-01T20:31:55.9230000+02:00","stream":"LTS"},{"version":"5.5.5p2","releaseDate":"2017-11-28T18:57:54.6100000+02:00","stream":"Tech"},{"version":"2017.3.0b11","releaseDate":"2017-11-28T17:29:29.2860000+02:00","stream":"Beta"},{"version":"2017.2.0p3","releaseDate":"2017-11-27T15:27:46.2180000+02:00","stream":"Tech"},{"version":"2017.1.2p3","releaseDate":"2017-11-21T17:57:28.2100000+02:00","stream":"Tech"},{"version":"2017.3.0b10","releaseDate":"2017-11-20T17:18:14.5740000+02:00","stream":"Beta"},{"version":"5.6.4p3","releaseDate":"2017-11-20T15:49:56.7630000+02:00","stream":"Tech"},{"version":"2017.2.0p2","releaseDate":"2017-11-15T16:24:53.1850000+02:00","stream":"Tech"},{"version":"5.6.4p2","releaseDate":"2017-11-12T21:00:26.6870000+02:00","stream":"Tech"},{"version":"2017.3.0b9","releaseDate":"2017-11-10T19:33:11.8540000+02:00","stream":"Beta"},{"version":"2017.2.0p1","releaseDate":"2017-11-06T19:18:19.4960000+02:00","stream":"Tech"},{"version":"2017.3.0b8","releaseDate":"2017-11-03T17:21:00.7540000+02:00","stream":"Beta"},{"version":"2017.3.0b7","releaseDate":"2017-10-31T17:40:56.2350000+02:00","stream":"Beta"},{"version":"2017.1.2p2","releaseDate":"2017-10-27T14:03:41.0290000+03:00","stream":"Tech"},{"version":"2017.3.0b6","releaseDate":"2017-10-24T19:13:05.0440000+03:00","stream":"Beta"},{"version":"5.6.4p1","releaseDate":"2017-10-20T11:55:09.4280000+03:00","stream":"Tech"},{"version":"2017.3.0b5","releaseDate":"2017-10-17T17:14:21.2300000+03:00","stream":"Beta"},{"version":"5.6.4f1","releaseDate":"2017-10-16T00:45:41.6100000+03:00","stream":"LTS"},{"version":"5.5.5p1","releaseDate":"2017-10-13T18:41:22.6040000+03:00","stream":"Tech"},{"version":"2017.1.2p1","releaseDate":"2017-10-13T17:36:45.0300000+03:00","stream":"Tech"},{"version":"2017.2.0f3","releaseDate":"2017-10-11T20:12:25.4710000+03:00","stream":"LTS"},{"version":"2017.1.1p4","releaseDate":"2017-10-11T01:24:40.4590000+03:00","stream":"Tech"},{"version":"2017.3.0b4","releaseDate":"2017-10-10T18:09:12.8770000+03:00","stream":"Beta"},{"version":"2017.1.2f1","releaseDate":"2017-10-06T15:44:00.5700000+03:00","stream":"LTS"},{"version":"2017.3.0b3","releaseDate":"2017-10-05T17:33:00.3650000+03:00","stream":"Beta"},{"version":"5.5.5f1","releaseDate":"2017-10-03T21:12:06.1320000+03:00","stream":"LTS"},{"version":"2017.2.0f2","releaseDate":"2017-10-02T20:53:40.3960000+03:00","stream":"LTS"},{"version":"2017.3.0b2","releaseDate":"2017-09-26T17:46:30.1710000+03:00","stream":"Beta"},{"version":"2017.1.1p3","releaseDate":"2017-09-22T19:41:25.5110000+03:00","stream":"Tech"},{"version":"2017.2.0f1","releaseDate":"2017-09-22T18:33:23.3090000+03:00","stream":"LTS"},{"version":"5.6.3p4","releaseDate":"2017-09-22T16:54:29.4830000+03:00","stream":"Tech"},{"version":"2017.3.0b1","releaseDate":"2017-09-21T16:38:59.5970000+03:00","stream":"Beta"},{"version":"5.4.6f3","releaseDate":"2017-09-20T11:37:58.9140000+03:00","stream":"LTS"},{"version":"2017.1.1p2","releaseDate":"2017-09-15T13:24:31.5570000+03:00","stream":"Tech"},{"version":"5.5.4p5","releaseDate":"2017-09-14T17:25:05.9100000+03:00","stream":"Tech"},{"version":"2017.2.0b11","releaseDate":"2017-09-12T16:31:58.6150000+03:00","stream":"Beta"},{"version":"2017.1.1p1","releaseDate":"2017-09-08T19:32:50.0560000+03:00","stream":"Tech"},{"version":"5.6.3p3","releaseDate":"2017-09-08T16:29:05.0680000+03:00","stream":"Tech"},{"version":"2017.2.0b10","releaseDate":"2017-09-04T23:19:12.8220000+03:00","stream":"Beta"},{"version":"2017.1.1f1","releaseDate":"2017-09-04T14:34:13.9350000+03:00","stream":"LTS"},{"version":"5.6.3p2","releaseDate":"2017-09-01T19:44:02.7640000+03:00","stream":"Tech"},{"version":"5.5.4p4","releaseDate":"2017-08-31T20:24:23.0240000+03:00","stream":"Tech"},{"version":"2017.2.0b9","releaseDate":"2017-08-29T18:59:23.8640000+03:00","stream":"Beta"},{"version":"2017.1.0p5","releaseDate":"2017-08-25T14:26:12.4730000+03:00","stream":"Tech"},{"version":"2017.2.0b8","releaseDate":"2017-08-18T17:33:35.1850000+03:00","stream":"Beta"},{"version":"5.3.8p2","releaseDate":"2017-08-18T13:53:50.1590000+03:00","stream":"Tech"},{"version":"5.4.5p5","releaseDate":"2017-08-18T03:06:42.9010000+03:00","stream":"Tech"},{"version":"5.5.4p3","releaseDate":"2017-08-18T00:45:42.7300000+03:00","stream":"Tech"},{"version":"5.6.3p1","releaseDate":"2017-08-17T23:56:53.9060000+03:00","stream":"Tech"},{"version":"2017.1.0p4","releaseDate":"2017-08-17T10:16:35.4780000+03:00","stream":"Tech"},{"version":"2017.2.0b7","releaseDate":"2017-08-15T20:42:22.6120000+03:00","stream":"Beta"},{"version":"2017.1.0p3","releaseDate":"2017-08-11T17:09:22.9780000+03:00","stream":"Tech"},{"version":"2017.2.0b6","releaseDate":"2017-08-09T00:09:18.9660000+03:00","stream":"Beta"},{"version":"5.6.3f1","releaseDate":"2017-08-01T20:03:58.0440000+03:00","stream":"LTS"},{"version":"2017.2.0b5","releaseDate":"2017-08-01T12:24:10.5780000+03:00","stream":"Beta"},{"version":"2017.1.0p2","releaseDate":"2017-07-27T15:04:31.4330000+03:00","stream":"Tech"},{"version":"5.5.4p2","releaseDate":"2017-07-26T14:06:59.7850000+03:00","stream":"Tech"},{"version":"5.6.2p4","releaseDate":"2017-07-21T20:06:22.5790000+03:00","stream":"Tech"},{"version":"2017.1.0p1","releaseDate":"2017-07-21T19:18:52.6830000+03:00","stream":"Tech"},{"version":"2017.2.0b4","releaseDate":"2017-07-20T19:07:24.3140000+03:00","stream":"Beta"},{"version":"5.6.2p3","releaseDate":"2017-07-17T17:54:07.4300000+03:00","stream":"Tech"},{"version":"2017.2.0b3","releaseDate":"2017-07-14T16:58:24.2490000+03:00","stream":"Beta"},{"version":"2017.1.0f3","releaseDate":"2017-07-10T14:29:48.3440000+03:00","stream":"LTS"},{"version":"2017.2.0b2","releaseDate":"2017-07-06T17:42:46.1050000+03:00","stream":"Beta"},{"version":"5.6.2p2","releaseDate":"2017-07-06T15:05:04.2550000+03:00","stream":"Tech"},{"version":"2017.1.0f2","releaseDate":"2017-07-05T21:06:25.7100000+03:00","stream":"LTS"},{"version":"5.6.2p1","releaseDate":"2017-06-29T17:08:51.3150000+03:00","stream":"Tech"},{"version":"5.4.5p4","releaseDate":"2017-06-28T14:33:16.4010000+03:00","stream":"Tech"},{"version":"2017.1.0f1","releaseDate":"2017-06-26T21:35:00.1560000+03:00","stream":"LTS"},{"version":"5.5.4p1","releaseDate":"2017-06-22T17:02:21.4330000+03:00","stream":"Tech"},{"version":"5.6.2f1","releaseDate":"2017-06-21T16:10:00.3850000+03:00","stream":"LTS"},{"version":"2017.1.0b10","releaseDate":"2017-06-19T18:48:58.2720000+03:00","stream":"Beta"},{"version":"5.6.1p4","releaseDate":"2017-06-16T18:05:31.4130000+03:00","stream":"Tech"},{"version":"5.3.8f2","releaseDate":"2017-06-13T14:42:19.0780000+03:00","stream":"LTS"},{"version":"2017.1.0b9","releaseDate":"2017-06-09T22:19:53.7480000+03:00","stream":"Beta"},{"version":"5.4.5p3","releaseDate":"2017-06-09T22:08:09.9090000+03:00","stream":"Tech"},{"version":"5.6.1p3","releaseDate":"2017-06-09T20:34:47.4540000+03:00","stream":"Tech"},{"version":"5.5.4f1","releaseDate":"2017-06-06T19:31:53.0570000+03:00","stream":"LTS"},{"version":"2017.1.0b8","releaseDate":"2017-06-02T18:43:21.3940000+03:00","stream":"Beta"},{"version":"5.6.1p2","releaseDate":"2017-06-02T13:52:12.6100000+03:00","stream":"Tech"},{"version":"5.4.5p2","releaseDate":"2017-05-29T11:25:58.9590000+03:00","stream":"Tech"},{"version":"2017.1.0b7","releaseDate":"2017-05-26T19:22:45.2060000+03:00","stream":"Beta"},{"version":"5.5.3p4","releaseDate":"2017-05-24T19:03:02.5850000+03:00","stream":"Tech"},{"version":"2017.1.0b6","releaseDate":"2017-05-19T14:33:20.6370000+03:00","stream":"Beta"},{"version":"5.6.1p1","releaseDate":"2017-05-18T15:38:02.4330000+03:00","stream":"Tech"},{"version":"2017.1.0b5","releaseDate":"2017-05-11T15:55:57.6670000+03:00","stream":"Beta"},{"version":"5.6.1f1","releaseDate":"2017-05-11T13:42:26.0420000+03:00","stream":"LTS"},{"version":"5.5.3p3","releaseDate":"2017-05-10T18:53:39.6190000+03:00","stream":"Tech"},{"version":"2017.1.0b4","releaseDate":"2017-05-08T17:47:09.7280000+03:00","stream":"Beta"},{"version":"5.6.0p4","releaseDate":"2017-05-08T15:16:30.1560000+03:00","stream":"Tech"},{"version":"2017.1.0b3","releaseDate":"2017-05-03T16:29:05.2510000+03:00","stream":"Beta"},{"version":"5.6.0p3","releaseDate":"2017-04-27T22:02:39.4410000+03:00","stream":"Tech"},{"version":"2017.1.0b2","releaseDate":"2017-04-26T16:56:42.4410000+03:00","stream":"Beta"},{"version":"5.5.3p2","releaseDate":"2017-04-25T17:57:56.6830000+03:00","stream":"Tech"},{"version":"5.6.0p2","releaseDate":"2017-04-21T23:03:49.1450000+03:00","stream":"Tech"},{"version":"5.6.0p1","releaseDate":"2017-04-18T16:49:03.9820000+03:00","stream":"Tech"},{"version":"5.5.3p1","releaseDate":"2017-04-13T18:11:15.6120000+03:00","stream":"Tech"},{"version":"2017.1.0b1","releaseDate":"2017-04-11T17:05:40.0040000+03:00","stream":"Beta"},{"version":"5.6.0f3","releaseDate":"2017-03-31T18:00:22.4860000+03:00","stream":"LTS"},{"version":"5.5.3f1","releaseDate":"2017-03-31T13:51:39.1560000+03:00","stream":"LTS"},{"version":"5.4.5p1","releaseDate":"2017-03-30T17:45:22.1890000+03:00","stream":"Tech"},{"version":"5.6.0f2","releaseDate":"2017-03-27T19:28:45.6580000+03:00","stream":"LTS"},{"version":"5.5.2p4","releaseDate":"2017-03-23T12:35:50.2430000+02:00","stream":"Tech"},{"version":"5.5.2p3","releaseDate":"2017-03-17T20:58:40.1640000+02:00","stream":"Tech"},{"version":"5.6.0f1","releaseDate":"2017-03-17T18:41:48.6380000+02:00","stream":"LTS"},{"version":"5.4.5f1","releaseDate":"2017-03-10T16:21:03.7460000+02:00","stream":"LTS"},{"version":"5.6.0b11","releaseDate":"2017-03-08T19:05:35.2990000+02:00","stream":"Beta"},{"version":"5.5.2p2","releaseDate":"2017-03-08T18:29:03.3490000+02:00","stream":"Tech"},{"version":"5.5.2p1","releaseDate":"2017-03-03T14:06:12.3730000+02:00","stream":"Tech"},{"version":"5.6.0b10","releaseDate":"2017-03-02T19:57:00.6420000+02:00","stream":"Beta"},{"version":"5.4.4p4","releaseDate":"2017-03-01T13:11:30.9140000+02:00","stream":"Tech"},{"version":"5.5.2f1","releaseDate":"2017-02-24T11:54:27.4260000+02:00","stream":"LTS"},{"version":"5.5.1p4","releaseDate":"2017-02-17T18:08:36.9750000+02:00","stream":"Tech"},{"version":"5.6.0b9","releaseDate":"2017-02-17T16:41:26.8530000+02:00","stream":"Beta"},{"version":"5.6.0b8","releaseDate":"2017-02-13T17:54:50.1120000+02:00","stream":"Beta"},{"version":"5.5.1p3","releaseDate":"2017-02-09T14:22:29.2650000+02:00","stream":"Tech"},{"version":"5.4.4p3","releaseDate":"2017-02-08T19:25:47.9670000+02:00","stream":"Tech"},{"version":"5.3.7p4","releaseDate":"2017-02-07T19:01:05.9100000+02:00","stream":"Tech"},{"version":"5.6.0b7","releaseDate":"2017-02-07T17:05:04.8950000+02:00","stream":"Beta"},{"version":"5.5.1p2","releaseDate":"2017-02-03T15:27:39.9140000+02:00","stream":"Tech"},{"version":"5.6.0b6","releaseDate":"2017-02-01T17:38:41.3800000+02:00","stream":"Beta"},{"version":"5.5.1p1","releaseDate":"2017-02-01T16:22:21.4140000+02:00","stream":"Tech"},{"version":"5.6.0b5","releaseDate":"2017-01-26T11:26:16.7750000+02:00","stream":"Beta"},{"version":"5.4.4p2","releaseDate":"2017-01-25T17:10:44.2950000+02:00","stream":"Tech"},{"version":"5.5.1f1","releaseDate":"2017-01-24T12:32:21.5040000+02:00","stream":"LTS"},{"version":"5.6.0b4","releaseDate":"2017-01-17T22:17:27.6580000+02:00","stream":"Beta"},{"version":"5.4.4p1","releaseDate":"2017-01-13T18:46:40.7580000+02:00","stream":"Tech"},{"version":"5.5.0p4","releaseDate":"2017-01-11T18:18:53.9900000+02:00","stream":"Tech"},{"version":"5.4.4f1","releaseDate":"2017-01-05T17:53:15.0500000+02:00","stream":"LTS"},{"version":"5.5.0p3","releaseDate":"2017-01-05T11:04:18.8540000+02:00","stream":"Tech"},{"version":"5.6.0b3","releaseDate":"2016-12-23T19:38:00.2460000+02:00","stream":"Beta"},{"version":"5.3.7p3","releaseDate":"2016-12-21T18:13:38.5020000+02:00","stream":"Tech"},{"version":"5.6.0b2","releaseDate":"2016-12-20T15:32:52.8740000+02:00","stream":"Beta"},{"version":"5.5.0p2","releaseDate":"2016-12-16T22:23:56.1000000+02:00","stream":"Tech"},{"version":"5.4.3p4","releaseDate":"2016-12-16T15:59:43.9270000+02:00","stream":"Tech"},{"version":"5.6.0b1","releaseDate":"2016-12-13T12:35:25.7510000+02:00","stream":"Beta"},{"version":"5.4.3p3","releaseDate":"2016-12-07T18:18:47.8600000+02:00","stream":"Tech"},{"version":"5.5.0p1","releaseDate":"2016-12-07T17:25:41.5570000+02:00","stream":"Tech"},{"version":"5.4.3p2","releaseDate":"2016-12-01T15:54:47.9540000+02:00","stream":"Tech"},{"version":"5.5.0f3","releaseDate":"2016-11-30T13:49:48.4400000+02:00","stream":"LTS"},{"version":"5.3.7p2","releaseDate":"2016-11-28T18:06:22.4430000+02:00","stream":"Tech"},{"version":"5.4.3p1","releaseDate":"2016-11-28T12:09:25.4130000+02:00","stream":"Tech"},{"version":"5.5.0f2","releaseDate":"2016-11-25T12:16:50.2830000+02:00","stream":"LTS"},{"version":"5.5.0f1","releaseDate":"2016-11-22T18:14:01.1850000+02:00","stream":"LTS"},{"version":"5.4.3f1","releaseDate":"2016-11-17T14:51:02.0260000+02:00","stream":"LTS"},{"version":"5.3.7p1","releaseDate":"2016-11-11T17:32:03.0220000+02:00","stream":"Tech"},{"version":"5.5.0b11","releaseDate":"2016-11-09T20:04:57.2170000+02:00","stream":"Beta"},{"version":"5.5.0b10","releaseDate":"2016-11-09T17:40:05.1770000+02:00","stream":"Beta"},{"version":"5.4.2p4","releaseDate":"2016-11-09T14:35:14.5410000+02:00","stream":"Tech"},{"version":"5.3.7f1","releaseDate":"2016-11-08T15:22:26.8980000+02:00","stream":"LTS"},{"version":"5.4.2p3","releaseDate":"2016-11-02T17:35:46.0380000+02:00","stream":"Tech"},{"version":"5.4.2p2","releaseDate":"2016-10-28T15:33:11.6310000+03:00","stream":"Tech"},{"version":"5.4.2p1","releaseDate":"2016-10-24T18:58:28.0140000+03:00","stream":"Tech"},{"version":"5.5.0b9","releaseDate":"2016-10-24T18:06:57.1480000+03:00","stream":"Beta"},{"version":"5.3.6p8","releaseDate":"2016-10-24T17:31:38.0530000+03:00","stream":"Tech"},{"version":"5.4.2f2","releaseDate":"2016-10-21T12:41:39.1710000+03:00","stream":"LTS"},{"version":"5.5.0b8","releaseDate":"2016-10-20T16:10:07.3480000+03:00","stream":"Beta"},{"version":"5.5.0b7","releaseDate":"2016-10-11T17:19:07.1390000+03:00","stream":"Beta"},{"version":"5.3.6p7","releaseDate":"2016-10-07T15:14:33.7940000+03:00","stream":"Tech"},{"version":"5.4.1p4","releaseDate":"2016-10-05T19:04:22.6090000+03:00","stream":"Tech"},{"version":"5.5.0b6","releaseDate":"2016-10-03T19:33:15.7800000+03:00","stream":"Beta"},{"version":"5.4.1p3","releaseDate":"2016-09-28T17:50:34.1120000+03:00","stream":"Tech"},{"version":"5.5.0b5","releaseDate":"2016-09-27T11:31:35.7680000+03:00","stream":"Beta"},{"version":"5.3.6p6","releaseDate":"2016-09-23T13:03:44.0380000+03:00","stream":"Tech"},{"version":"5.4.1p2","releaseDate":"2016-09-22T21:37:12.2160000+03:00","stream":"Tech"},{"version":"5.5.0b4","releaseDate":"2016-09-19T18:28:43.2030000+03:00","stream":"Beta"},{"version":"5.3.6p5","releaseDate":"2016-09-16T10:03:24.6470000+03:00","stream":"Tech"},{"version":"5.4.1p1","releaseDate":"2016-09-15T14:18:34.2100000+03:00","stream":"Tech"},{"version":"5.5.0b3","releaseDate":"2016-09-12T16:01:26.0040000+03:00","stream":"Beta"},{"version":"5.4.1f1","releaseDate":"2016-09-07T14:02:30.4590000+03:00","stream":"LTS"},{"version":"5.5.0b2","releaseDate":"2016-09-05T17:30:09.8380000+03:00","stream":"Beta"},{"version":"5.3.6p4","releaseDate":"2016-09-02T17:39:02.8790000+03:00","stream":"Tech"},{"version":"5.4.0p4","releaseDate":"2016-08-31T18:12:19.9330000+03:00","stream":"Tech"},{"version":"5.5.0b1","releaseDate":"2016-08-30T01:26:28.1480000+03:00","stream":"Beta"},{"version":"5.4.0p3","releaseDate":"2016-08-25T19:23:33.9710000+03:00","stream":"Tech"},{"version":"5.3.6p3","releaseDate":"2016-08-23T18:52:41.7170000+03:00","stream":"Tech"},{"version":"5.4.0p2","releaseDate":"2016-08-18T18:13:53.4540000+03:00","stream":"Tech"},{"version":"5.4.0p1","releaseDate":"2016-08-11T19:41:23.0620000+03:00","stream":"Tech"},{"version":"5.3.6p2","releaseDate":"2016-08-03T16:49:58.6420000+03:00","stream":"Tech"},{"version":"5.4.0f3","releaseDate":"2016-07-27T18:33:32.0650000+03:00","stream":"LTS"},{"version":"5.3.6p1","releaseDate":"2016-07-27T16:49:40.4080000+03:00","stream":"Tech"},{"version":"5.4.0f2","releaseDate":"2016-07-21T17:37:50.4920000+03:00","stream":"LTS"},{"version":"5.3.6f1","releaseDate":"2016-07-20T12:42:16.5870000+03:00","stream":"LTS"},{"version":"5.4.0f1","releaseDate":"2016-07-14T17:14:28.9480000+03:00","stream":"LTS"},{"version":"5.3.5p8","releaseDate":"2016-07-13T15:31:43.9130000+03:00","stream":"Tech"},{"version":"5.4.0b25","releaseDate":"2016-07-11T17:27:32.5710000+03:00","stream":"Beta"},{"version":"5.3.5p7","releaseDate":"2016-07-08T12:46:28.2840000+03:00","stream":"Tech"},{"version":"5.4.0b24","releaseDate":"2016-07-01T18:47:18.2330000+03:00","stream":"Beta"},{"version":"5.3.5p6","releaseDate":"2016-06-29T19:20:44.0350000+03:00","stream":"Tech"},{"version":"5.4.0b23","releaseDate":"2016-06-28T14:35:44.6560000+03:00","stream":"Beta"},{"version":"5.4.0b22","releaseDate":"2016-06-20T12:50:01.9180000+03:00","stream":"Beta"},{"version":"5.3.5p5","releaseDate":"2016-06-20T11:56:54.1950000+03:00","stream":"Tech"},{"version":"5.3.5p4","releaseDate":"2016-06-20T11:17:44.2570000+03:00","stream":"Tech"},{"version":"5.3.5p3","releaseDate":"2016-06-10T12:28:48.9900000+03:00","stream":"Tech"},{"version":"5.4.0b21","releaseDate":"2016-06-09T13:10:18.5030000+03:00","stream":"Beta"},{"version":"5.1.5f1","releaseDate":"2016-06-06T14:04:12.1990000+03:00","stream":"LTS"},{"version":"5.3.5p2","releaseDate":"2016-06-03T17:52:11.1590000+03:00","stream":"Tech"},{"version":"5.4.0b20","releaseDate":"2016-06-03T16:53:41.3450000+03:00","stream":"Beta"},{"version":"5.2.5f1","releaseDate":"2016-06-01T14:51:51.5940000+03:00","stream":"LTS"},{"version":"5.3.5p1","releaseDate":"2016-05-31T10:40:56.6820000+03:00","stream":"Tech"},{"version":"5.4.0b19","releaseDate":"2016-05-25T12:23:12.8120000+03:00","stream":"Beta"},{"version":"5.4.0b18","releaseDate":"2016-05-19T18:44:13.0190000+03:00","stream":"Beta"},{"version":"5.3.5f1","releaseDate":"2016-05-19T18:29:29.7780000+03:00","stream":"LTS"},{"version":"5.3.4p6","releaseDate":"2016-05-06T18:28:15.3400000+03:00","stream":"Tech"},{"version":"5.4.0b17","releaseDate":"2016-05-04T01:24:49.7340000+03:00","stream":"Beta"},{"version":"5.3.4p5","releaseDate":"2016-04-27T18:20:06.9680000+03:00","stream":"Tech"},{"version":"5.4.0b16","releaseDate":"2016-04-27T14:25:25.9450000+03:00","stream":"Beta"},{"version":"5.3.4p4","releaseDate":"2016-04-20T13:50:41.9420000+03:00","stream":"Tech"},{"version":"5.4.0b15","releaseDate":"2016-04-18T13:10:26.2100000+03:00","stream":"Beta"},{"version":"5.3.4p3","releaseDate":"2016-04-13T13:24:45.5350000+03:00","stream":"Tech"},{"version":"5.4.0b14","releaseDate":"2016-04-11T14:55:25.2850000+03:00","stream":"Beta"},{"version":"5.3.4p2","releaseDate":"2016-04-08T16:41:06.6810000+03:00","stream":"Tech"},{"version":"5.4.0b13","releaseDate":"2016-04-04T12:27:37.0640000+03:00","stream":"Beta"},{"version":"5.4.0b12","releaseDate":"2016-03-29T19:39:18.7120000+03:00","stream":"Beta"},{"version":"5.3.4p1","releaseDate":"2016-03-24T00:30:26.0740000+02:00","stream":"Tech"},{"version":"5.4.0b11","releaseDate":"2016-03-21T13:52:03.7650000+02:00","stream":"Beta"},{"version":"5.4.0b10","releaseDate":"2016-03-15T15:45:23.9730000+02:00","stream":"Beta"},{"version":"5.3.4f1","releaseDate":"2016-03-15T15:33:58.4510000+02:00","stream":"LTS"},{"version":"5.3.3p3","releaseDate":"2016-03-14T19:48:02.2170000+02:00","stream":"Tech"},{"version":"5.4.0b9","releaseDate":"2016-03-08T12:03:52.2650000+02:00","stream":"Beta"},{"version":"5.3.3p2","releaseDate":"2016-03-04T18:05:49.8740000+02:00","stream":"Tech"},{"version":"5.4.0b8","releaseDate":"2016-03-02T14:14:56.5970000+02:00","stream":"Beta"},{"version":"5.3.3p1","releaseDate":"2016-02-24T18:53:39.5190000+02:00","stream":"Tech"},{"version":"5.3.3f1","releaseDate":"2016-02-23T14:53:03.4530000+02:00","stream":"LTS"},{"version":"5.4.0b7","releaseDate":"2016-02-22T16:29:51.4670000+02:00","stream":"Beta"},{"version":"5.3.2p4","releaseDate":"2016-02-20T21:48:43.6160000+02:00","stream":"Tech"},{"version":"5.4.0b6","releaseDate":"2016-02-15T18:11:52.0550000+02:00","stream":"Beta"},{"version":"5.3.2p3","releaseDate":"2016-02-12T11:22:27.9230000+02:00","stream":"Tech"},{"version":"5.4.0b5","releaseDate":"2016-02-09T18:00:54.0100000+02:00","stream":"Beta"},{"version":"5.3.2p2","releaseDate":"2016-02-03T20:16:50.7640000+02:00","stream":"Tech"},{"version":"5.4.0b4","releaseDate":"2016-01-30T16:05:07.6350000+02:00","stream":"Beta"},{"version":"5.3.2p1","releaseDate":"2016-01-28T18:05:44.7130000+02:00","stream":"Tech"},{"version":"5.3.2f1","releaseDate":"2016-01-27T17:27:25.9430000+02:00","stream":"LTS"},{"version":"5.3.1p4","releaseDate":"2016-01-23T14:12:30.0740000+02:00","stream":"Tech"},{"version":"5.4.0b3","releaseDate":"2016-01-22T19:00:02.9810000+02:00","stream":"Beta"},{"version":"5.4.0b2","releaseDate":"2016-01-15T13:09:43.6900000+02:00","stream":"Beta"},{"version":"5.3.1p3","releaseDate":"2016-01-14T19:48:48.7310000+02:00","stream":"Tech"},{"version":"5.4.0b1","releaseDate":"2016-01-13T00:10:16.2620000+02:00","stream":"Beta"},{"version":"5.3.1p2","releaseDate":"2016-01-08T14:16:04.4350000+02:00","stream":"Tech"},{"version":"5.3.1p1","releaseDate":"2016-01-08T14:10:16.3210000+02:00","stream":"Tech"},{"version":"5.3.1f1","releaseDate":"2015-12-18T16:23:10.2740000+02:00","stream":"LTS"},{"version":"5.2.4f1","releaseDate":"2015-12-15T18:37:45.1050000+02:00","stream":"LTS"},{"version":"5.2.3p3","releaseDate":"2015-12-10T12:23:24.9490000+02:00","stream":"Tech"},{"version":"5.3.0f4","releaseDate":"2015-12-08T00:12:35.0350000+02:00","stream":"LTS"},{"version":"5.2.3p2","releaseDate":"2015-12-03T14:16:45.5710000+02:00","stream":"Tech"},{"version":"5.2.3p1","releaseDate":"2015-11-27T17:42:46.6020000+02:00","stream":"Tech"},{"version":"5.3.0f2","releaseDate":"2015-11-23T17:08:26.3310000+02:00","stream":"LTS"},{"version":"5.2.3f1","releaseDate":"2015-11-19T12:38:36.6940000+02:00","stream":"LTS"},{"version":"5.2.2p4","releaseDate":"2015-11-18T13:12:41.1430000+02:00","stream":"Tech"},{"version":"5.3.0f1","releaseDate":"2015-11-14T17:28:15.8630000+02:00","stream":"LTS"},{"version":"5.2.2p3","releaseDate":"2015-11-10T18:44:28.0350000+02:00","stream":"Tech"},{"version":"5.3.0b6","releaseDate":"2015-11-09T17:44:01.7640000+02:00","stream":"Beta"},{"version":"5.3.0b5","releaseDate":"2015-11-02T19:19:46.6150000+02:00","stream":"Beta"},{"version":"5.2.2p2","releaseDate":"2015-10-30T18:26:48.9590000+02:00","stream":"Tech"},{"version":"5.2.2p1","releaseDate":"2015-10-24T20:00:34.5130000+03:00","stream":"Tech"},{"version":"5.3.0b4","releaseDate":"2015-10-23T15:11:59.0160000+03:00","stream":"Beta"},{"version":"5.2.2f1","releaseDate":"2015-10-21T16:11:59.7920000+03:00","stream":"LTS"},{"version":"5.3.0b3","releaseDate":"2015-10-16T23:48:22.9780000+03:00","stream":"Beta"},{"version":"5.2.1p4","releaseDate":"2015-10-15T09:00:51.3200000+03:00","stream":"Tech"},{"version":"5.3.0b2","releaseDate":"2015-10-10T16:11:44.6410000+03:00","stream":"Beta"},{"version":"5.2.1p3","releaseDate":"2015-10-09T17:49:17.0510000+03:00","stream":"Tech"},{"version":"5.1.4f1","releaseDate":"2015-10-06T11:17:42.7590000+03:00","stream":"LTS"},{"version":"5.3.0b1","releaseDate":"2015-10-02T22:38:07.8510000+03:00","stream":"Beta"},{"version":"5.2.1p2","releaseDate":"2015-10-01T16:15:11.2250000+03:00","stream":"Tech"},{"version":"5.2.1p1","releaseDate":"2015-09-25T16:13:16.8560000+03:00","stream":"Tech"},{"version":"5.2.1f1","releaseDate":"2015-09-22T15:24:32.4680000+03:00","stream":"LTS"},{"version":"5.2.0p1","releaseDate":"2015-09-18T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.1.3p3","releaseDate":"2015-09-11T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.1.3p2","releaseDate":"2015-09-04T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.2.0f3","releaseDate":"2015-09-03T12:33:57.1480000+03:00","stream":"LTS"},{"version":"5.1.3p1","releaseDate":"2015-08-27T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.1.3f1","releaseDate":"2015-08-24T12:50:04.1790000+03:00","stream":"LTS"},{"version":"5.2.0f2","releaseDate":"2015-08-21T18:46:49.9960000+03:00","stream":"LTS"},{"version":"5.2.0f1","releaseDate":"2015-08-16T18:50:39.4690000+03:00","stream":"LTS"},{"version":"5.2.0b6","releaseDate":"2015-08-07T22:27:28.2000000+03:00","stream":"Beta"},{"version":"5.1.2p3","releaseDate":"2015-08-06T18:11:03.9900000+03:00","stream":"Tech"},{"version":"5.2.0b5","releaseDate":"2015-07-31T13:58:16.6300000+03:00","stream":"Beta"},{"version":"5.1.2p2","releaseDate":"2015-07-30T19:04:41.2110000+03:00","stream":"Tech"},{"version":"5.2.0b4","releaseDate":"2015-07-23T18:55:44.2700000+03:00","stream":"Beta"},{"version":"5.1.2p1","releaseDate":"2015-07-23T18:20:51.9840000+03:00","stream":"Tech"},{"version":"5.2.0b3","releaseDate":"2015-07-17T22:58:20.5700000+03:00","stream":"Beta"},{"version":"5.1.2f1","releaseDate":"2015-07-16T11:54:11.0960000+03:00","stream":"LTS"},{"version":"5.2.0b2","releaseDate":"2015-07-10T21:37:49.5390000+03:00","stream":"Beta"},{"version":"5.1.1p4","releaseDate":"2015-07-10T12:08:40.1750000+03:00","stream":"Tech"},{"version":"5.0.4f1","releaseDate":"2015-07-06T15:10:34.2300000+03:00","stream":"LTS"},{"version":"5.1.1p3","releaseDate":"2015-07-03T19:18:12.6150000+03:00","stream":"Tech"},{"version":"5.2.0b1","releaseDate":"2015-07-01T19:26:20.9210000+03:00","stream":"Beta"},{"version":"5.1.1p2","releaseDate":"2015-06-26T00:27:14.0670000+03:00","stream":"Tech"},{"version":"5.0.3p3","releaseDate":"2015-06-24T18:55:13.6440000+03:00","stream":"Tech"},{"version":"5.1.1p1","releaseDate":"2015-06-23T18:05:55.5660000+03:00","stream":"Tech"},{"version":"5.1.1f1","releaseDate":"2015-06-18T13:20:02.2470000+03:00","stream":"LTS"},{"version":"5.0.3p2","releaseDate":"2015-06-18T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.1.0p1","releaseDate":"2015-06-12T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.3p1","releaseDate":"2015-06-11T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.3f2","releaseDate":"2015-06-09T18:36:46.8690000+03:00","stream":"LTS"},{"version":"5.1.0f3","releaseDate":"2015-06-04T00:31:28.2170000+03:00","stream":"LTS"},{"version":"5.0.2p4","releaseDate":"2015-06-03T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.2p3","releaseDate":"2015-05-28T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.2p2","releaseDate":"2015-05-20T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.2p1","releaseDate":"2015-05-15T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.2f1","releaseDate":"2015-05-13T17:05:42.7910000+03:00","stream":"LTS"},{"version":"5.0.1p4","releaseDate":"2015-05-08T13:25:56.9760000+03:00","stream":"Tech"},{"version":"5.0.1p3","releaseDate":"2015-04-29T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.1p2","releaseDate":"2015-04-24T17:14:44.9700000+03:00","stream":"Tech"},{"version":"5.0.1p1","releaseDate":"2015-04-16T11:21:07.0000000+03:00","stream":"Tech"},{"version":"5.0.1f1","releaseDate":"2015-03-31T19:55:08.3760000+03:00","stream":"LTS"},{"version":"5.0.0p3","releaseDate":"2015-03-26T14:03:56.0680000+02:00","stream":"Tech"},{"version":"5.0.0p2","releaseDate":"2015-03-20T18:38:49.5150000+02:00","stream":"Tech"},{"version":"5.0.0p1","releaseDate":"2015-03-16T17:20:13.6040000+02:00","stream":"Tech"},{"version":"5.0.0f4","releaseDate":"2015-02-25T17:49:05.8350000+02:00","stream":"LTS"}] \ No newline at end of file +[{"version":"6000.5.0b8","releaseDate":"2026-05-14T15:39:34.7510000+03:00","stream":"Tech"},{"version":"6000.6.0a5","releaseDate":"2026-05-13T17:25:34.1410000+03:00","stream":"Tech"},{"version":"6000.4.7f1","releaseDate":"2026-05-13T17:24:18.1390000+03:00","stream":"Tech"},{"version":"6000.0.75f1","releaseDate":"2026-05-13T17:51:23.6980000+03:00","stream":"Tech"},{"version":"6000.3.15f1","releaseDate":"2026-05-08T08:39:58.4930000+03:00","stream":"Tech"},{"version":"6000.5.0b7","releaseDate":"2026-05-07T17:14:10.6130000+03:00","stream":"Tech"},{"version":"6000.4.6f1","releaseDate":"2026-05-05T22:06:48.6370000+03:00","stream":"Tech"},{"version":"6000.5.0b6","releaseDate":"2026-04-30T13:10:20.3860000+03:00","stream":"Tech"},{"version":"6000.0.74f1","releaseDate":"2026-04-29T13:05:57.6210000+03:00","stream":"Tech"},{"version":"6000.4.5f1","releaseDate":"2026-04-28T19:38:39.7340000+03:00","stream":"Tech"},{"version":"6000.5.0b5","releaseDate":"2026-04-23T14:17:03.0940000+03:00","stream":"Tech"},{"version":"6000.4.4f1","releaseDate":"2026-04-22T20:33:26.0390000+03:00","stream":"Tech"},{"version":"6000.3.14f1","releaseDate":"2026-04-22T15:21:09.8230000+03:00","stream":"Tech"},{"version":"6000.5.0b4","releaseDate":"2026-04-16T09:32:17.8570000+03:00","stream":"Tech"},{"version":"6000.6.0a3","releaseDate":"2026-04-15T16:42:23.9000000+03:00","stream":"Tech"},{"version":"6000.4.3f1","releaseDate":"2026-04-15T14:05:46.3300000+03:00","stream":"Tech"},{"version":"6000.0.73f1","releaseDate":"2026-04-15T11:22:53.0260000+03:00","stream":"Tech"},{"version":"6000.4.2f1","releaseDate":"2026-04-09T19:40:36.0250000+03:00","stream":"Tech"},{"version":"6000.5.0b3","releaseDate":"2026-04-09T12:53:13.0050000+03:00","stream":"Tech"},{"version":"6000.3.13f1","releaseDate":"2026-04-08T12:59:17.4520000+03:00","stream":"Tech"},{"version":"6000.6.0a2","releaseDate":"2026-04-02T16:34:26.4310000+03:00","stream":"Tech"},{"version":"6000.5.0b2","releaseDate":"2026-04-02T11:36:24.3840000+03:00","stream":"Tech"},{"version":"6000.0.72f1","releaseDate":"2026-04-01T12:38:47.0550000+03:00","stream":"Tech"},{"version":"6000.4.1f1","releaseDate":"2026-03-18T20:39:00.8960000+02:00","stream":"Tech"},{"version":"6000.5.0b1","releaseDate":"2026-03-26T12:10:36.0990000+02:00","stream":"Tech"},{"version":"6000.3.12f1","releaseDate":"2026-03-25T13:55:21.4130000+02:00","stream":"Tech"},{"version":"6000.5.0a9","releaseDate":"2026-03-19T12:10:12.0660000+02:00","stream":"Tech"},{"version":"6000.4.0f1","releaseDate":"2026-03-18T20:43:57.5310000+02:00","stream":"Tech"},{"version":"6000.0.71f1","releaseDate":"2026-03-18T09:40:01.2100000+02:00","stream":"Tech"},{"version":"6000.3.11f1","releaseDate":"2026-03-11T16:52:35.7710000+02:00","stream":"Tech"},{"version":"6000.0.70f1","releaseDate":"2026-03-10T11:16:20.8440000+02:00","stream":"Tech"},{"version":"6000.4.0b11","releaseDate":"2026-03-04T04:30:38.3620000+02:00","stream":"Tech"},{"version":"6000.5.0a8","releaseDate":"2026-03-05T12:01:52.5860000+02:00","stream":"Tech"},{"version":"6000.0.69f1","releaseDate":"2026-03-04T11:50:56.2280000+02:00","stream":"Tech"},{"version":"6000.4.0b10","releaseDate":"2026-02-25T20:07:42.7910000+02:00","stream":"Tech"},{"version":"6000.3.10f1","releaseDate":"2026-02-25T16:01:36.9330000+02:00","stream":"Tech"},{"version":"6000.4.0b8","releaseDate":"2026-02-19T22:56:42.2560000+02:00","stream":"Tech"},{"version":"6000.4.0b9","releaseDate":"2026-02-19T20:25:29.3970000+02:00","stream":"Tech"},{"version":"6000.5.0a7","releaseDate":"2026-02-19T12:32:55.5120000+02:00","stream":"Tech"},{"version":"6000.0.68f1","releaseDate":"2026-02-18T16:49:24.6650000+02:00","stream":"Tech"},{"version":"6000.3.9f1","releaseDate":"2026-02-18T13:29:51.8010000+02:00","stream":"Tech"},{"version":"6000.3.8f1","releaseDate":"2026-02-11T12:40:25.7840000+02:00","stream":"Tech"},{"version":"6000.5.0a6","releaseDate":"2026-02-04T18:26:46.3460000+02:00","stream":"Tech"},{"version":"6000.3.7f1","releaseDate":"2026-02-05T09:53:48.4870000+02:00","stream":"Tech"},{"version":"6000.0.67f1","releaseDate":"2026-02-04T13:53:51.0940000+02:00","stream":"Tech"},{"version":"6000.4.0b7","releaseDate":"2026-02-03T21:49:13.9010000+02:00","stream":"Tech"},{"version":"6000.3.6f1","releaseDate":"2026-01-29T12:44:38.7000000+02:00","stream":"Tech"},{"version":"6000.4.0b6","releaseDate":"2026-01-27T19:40:09.1180000+02:00","stream":"Tech"},{"version":"6000.0.66f2","releaseDate":"2026-01-26T16:47:46.0650000+02:00","stream":"Tech"},{"version":"6000.3.5f2","releaseDate":"2026-01-26T16:40:28.1430000+02:00","stream":"Tech"},{"version":"6000.5.0a5","releaseDate":"2026-01-22T12:38:59.9750000+02:00","stream":"Tech"},{"version":"6000.0.66f1","releaseDate":"2026-01-21T18:47:35.7870000+02:00","stream":"Tech"},{"version":"6000.3.5f1","releaseDate":"2026-01-21T11:47:57.8450000+02:00","stream":"Tech"},{"version":"6000.4.0b5","releaseDate":"2026-01-15T22:51:28.6186105+02:00","stream":"Beta"},{"version":"6000.3.4f1","releaseDate":"2026-01-14T14:54:12.1540000+02:00","stream":"Tech"},{"version":"6000.4.0b4","releaseDate":"2026-01-09T23:27:01.0380215+02:00","stream":"Beta"},{"version":"6000.5.0a4","releaseDate":"2026-01-08T11:11:41.8800000+02:00","stream":"Tech"},{"version":"6000.3.3f1","releaseDate":"2026-01-08T09:54:44.9680000+02:00","stream":"Tech"},{"version":"6000.4.0b3","releaseDate":"2026-01-07T23:47:44.7500000+02:00","stream":"Tech"},{"version":"6000.0.65f1","releaseDate":"2026-01-07T10:41:15.3920000+02:00","stream":"Tech"},{"version":"6000.5.0a3","releaseDate":"2025-12-16T06:44:25.8440000+02:00","stream":"Tech"},{"version":"6000.4.0b2","releaseDate":"2025-12-17T02:22:00.9030000+02:00","stream":"Tech"},{"version":"6000.3.2f1","releaseDate":"2025-12-17T00:09:49.3130000+02:00","stream":"Tech"},{"version":"6000.4.0b1","releaseDate":"2025-12-11T13:25:29.5920000+02:00","stream":"Tech"},{"version":"6000.0.64f1","releaseDate":"2025-12-10T11:19:20.6760000+02:00","stream":"Tech"},{"version":"6000.3.1f1","releaseDate":"2025-12-09T19:55:30.3660000+02:00","stream":"Tech"},{"version":"6000.3.0f1","releaseDate":"2025-12-03T18:52:53.2470000+02:00","stream":"Tech"},{"version":"6000.2.15f1","releaseDate":"2025-12-03T13:49:37.6290000+02:00","stream":"Tech"},{"version":"6000.0.63f1","releaseDate":"2025-11-28T08:25:46.3120000+02:00","stream":"Tech"},{"version":"6000.2.14f1","releaseDate":"2025-11-26T16:26:46.7190000+02:00","stream":"Tech"},{"version":"6000.2.13f1","releaseDate":"2025-11-19T15:11:47.7500000+02:00","stream":"Tech"},{"version":"6000.3.0b10","releaseDate":"2025-11-12T07:27:36.1380000+02:00","stream":"Tech"},{"version":"6000.4.0a5","releaseDate":"2025-11-12T22:12:35.8588381+02:00","stream":"Alpha"},{"version":"6000.2.12f1","releaseDate":"2025-11-12T16:28:37.9120000+02:00","stream":"Tech"},{"version":"6000.3.0b9","releaseDate":"2025-11-06T17:16:36.1760000+02:00","stream":"Tech"},{"version":"6000.2.11f1","releaseDate":"2025-11-05T13:01:47.1570000+02:00","stream":"Tech"},{"version":"6000.4.0a4","releaseDate":"2025-11-05T17:12:05.4680000+02:00","stream":"Tech"},{"version":"6000.0.62f1","releaseDate":"2025-11-05T10:33:28.1580000+02:00","stream":"Tech"},{"version":"6000.0.61f1","releaseDate":"2025-10-30T08:44:03.1510000+02:00","stream":"Tech"},{"version":"6000.2.10f1","releaseDate":"2025-10-29T11:40:31.0020000+02:00","stream":"Tech"},{"version":"2022.3.62f3","releaseDate":"2025-10-28T12:40:42.8600000+02:00","stream":"Tech"},{"version":"6000.3.0b7","releaseDate":"2025-10-22T18:22:20.7580000+03:00","stream":"Tech"},{"version":"6000.3.0b8","releaseDate":"2025-10-23T18:22:23.0845430+03:00","stream":"Beta"},{"version":"6000.2.9f1","releaseDate":"2025-10-22T16:53:40.3120000+03:00","stream":"Tech"},{"version":"6000.0.60f1","releaseDate":"2025-10-16T12:20:46.6530000+03:00","stream":"Tech"},{"version":"6000.4.0a2","releaseDate":"2025-10-16T12:11:25.3990000+03:00","stream":"Tech"},{"version":"2019.4.41f2","releaseDate":"2025-10-15T16:26:35.7050000+03:00","stream":"Tech"},{"version":"6000.2.8f1","releaseDate":"2025-10-15T11:31:36.2450000+03:00","stream":"Tech"},{"version":"6000.3.0b6","releaseDate":"2025-10-09T23:59:53.2387953+03:00","stream":"Beta"},{"version":"6000.3.0b5","releaseDate":"2025-10-09T18:33:40.7540000+03:00","stream":"Tech"},{"version":"6000.2.7f2","releaseDate":"2025-10-08T12:37:04.9950000+03:00","stream":"Tech"},{"version":"6000.0.59f2","releaseDate":"2025-10-08T12:29:47.7630000+03:00","stream":"Tech"},{"version":"6000.1.17f1","releaseDate":"2025-10-03T07:54:02.0830000+03:00","stream":"Tech"},{"version":"2019.1.15f1","releaseDate":"2025-10-03T07:17:50.8610000+03:00","stream":"Tech"},{"version":"2019.2.23f1","releaseDate":"2025-10-03T07:17:32.1480000+03:00","stream":"Tech"},{"version":"2019.3.17f1","releaseDate":"2025-10-03T07:17:11.9430000+03:00","stream":"Tech"},{"version":"2019.4.41f1","releaseDate":"2025-10-03T07:16:52.7010000+03:00","stream":"Tech"},{"version":"2020.1.18f1","releaseDate":"2025-10-03T07:16:32.0710000+03:00","stream":"Tech"},{"version":"2020.2.8f1","releaseDate":"2025-10-03T07:16:16.5430000+03:00","stream":"Tech"},{"version":"2020.3.49f1","releaseDate":"2025-10-03T07:15:57.2050000+03:00","stream":"Tech"},{"version":"2021.1.29f1","releaseDate":"2025-10-03T07:15:36.7810000+03:00","stream":"Tech"},{"version":"2021.2.20f1","releaseDate":"2025-10-03T07:15:18.8740000+03:00","stream":"Tech"},{"version":"2021.3.45f2","releaseDate":"2025-10-03T07:14:55.9440000+03:00","stream":"Tech"},{"version":"2022.1.25f1","releaseDate":"2025-10-03T07:14:10.0200000+03:00","stream":"Tech"},{"version":"2022.2.23f1","releaseDate":"2025-10-03T07:13:47.6470000+03:00","stream":"Tech"},{"version":"2022.3.62f2","releaseDate":"2025-10-03T07:13:21.9340000+03:00","stream":"Tech"},{"version":"2023.1.22f1","releaseDate":"2025-10-03T07:12:29.6750000+03:00","stream":"Tech"},{"version":"2023.2.22f1","releaseDate":"2025-10-03T07:12:10.1900000+03:00","stream":"Tech"},{"version":"6000.0.58f2","releaseDate":"2025-10-03T07:11:47.3060000+03:00","stream":"Tech"},{"version":"6000.2.6f2","releaseDate":"2025-10-03T07:11:06.2630000+03:00","stream":"Tech"},{"version":"6000.3.0b3","releaseDate":"2025-09-30T21:20:55.2365253+03:00","stream":"Beta"},{"version":"6000.3.0b4","releaseDate":"2025-09-30T21:20:55.2365253+03:00","stream":"Beta"},{"version":"6000.3.0b3","releaseDate":"2025-09-25T12:32:28.8700000+03:00","stream":"Tech"},{"version":"6000.2.6f1","releaseDate":"2025-09-25T12:31:26.1340000+03:00","stream":"Tech"},{"version":"6000.3.0b2","releaseDate":"2025-09-17T14:13:50.6420000+03:00","stream":"Tech"},{"version":"6000.2.5f1","releaseDate":"2025-09-17T08:28:37.0430000+03:00","stream":"Tech"},{"version":"6000.0.58f1","releaseDate":"2025-09-17T08:27:16.4870000+03:00","stream":"Tech"},{"version":"6000.2.4f1","releaseDate":"2025-09-12T12:50:41.4540000+03:00","stream":"Tech"},{"version":"6000.3.0b1","releaseDate":"2025-09-09T19:50:04.5110000+03:00","stream":"Tech"},{"version":"6000.2.3f1","releaseDate":"2025-09-04T18:48:31.8630000+03:00","stream":"Tech"},{"version":"6000.0.57f1","releaseDate":"2025-09-03T12:18:47.7990000+03:00","stream":"Tech"},{"version":"6000.2.2f1","releaseDate":"2025-08-26T23:57:12.7490000+03:00","stream":"Tech"},{"version":"6000.3.0a5","releaseDate":"2025-08-21T12:46:22.7360000+03:00","stream":"Tech"},{"version":"6000.2.1f1","releaseDate":"2025-08-20T21:26:03.3440000+03:00","stream":"Tech"},{"version":"6000.0.56f1","releaseDate":"2025-08-20T10:31:57.0100000+03:00","stream":"Tech"},{"version":"6000.1.16f1","releaseDate":"2025-08-13T13:01:50.9500000+03:00","stream":"Tech"},{"version":"6000.2.0f1","releaseDate":"2025-08-12T21:26:22.1900000+03:00","stream":"Tech"},{"version":"6000.2.0b13","releaseDate":"2025-08-08T01:59:59.6800000+03:00","stream":"Tech"},{"version":"6000.1.15f1","releaseDate":"2025-08-05T17:09:59.1050000+03:00","stream":"Tech"},{"version":"6000.0.55f1","releaseDate":"2025-08-05T16:33:24.7270000+03:00","stream":"Tech"},{"version":"6000.1.14f1","releaseDate":"2025-07-30T11:28:59.4950000+03:00","stream":"Tech"},{"version":"6000.2.0b12","releaseDate":"2025-07-29T20:28:17.2950000+03:00","stream":"Tech"},{"version":"6000.2.0b11","releaseDate":"2025-07-24T18:28:42.3790000+03:00","stream":"Tech"},{"version":"6000.3.0a3","releaseDate":"2025-07-23T18:26:41.8870000+03:00","stream":"Tech"},{"version":"6000.0.54f1","releaseDate":"2025-07-23T14:28:35.7140000+03:00","stream":"Tech"},{"version":"6000.1.13f1","releaseDate":"2025-07-23T09:54:37.0260000+03:00","stream":"Tech"},{"version":"6000.3.0a2","releaseDate":"2025-07-17T13:48:27.7620000+03:00","stream":"Tech"},{"version":"6000.2.0b10","releaseDate":"2025-07-16T16:54:47.1060000+03:00","stream":"Tech"},{"version":"6000.1.12f1","releaseDate":"2025-07-15T17:19:15.7530000+03:00","stream":"Tech"},{"version":"6000.2.0b9","releaseDate":"2025-07-09T19:49:32.8200000+03:00","stream":"Tech"},{"version":"6000.1.11f1","releaseDate":"2025-07-09T13:28:05.7180000+03:00","stream":"Tech"},{"version":"6000.0.53f1","releaseDate":"2025-07-09T09:34:27.5310000+03:00","stream":"Tech"},{"version":"6000.1.10f1","releaseDate":"2025-07-02T20:01:29.6990000+03:00","stream":"Tech"},{"version":"6000.2.0b8","releaseDate":"2025-07-02T19:48:35.9940000+03:00","stream":"Tech"},{"version":"6000.0.52f1","releaseDate":"2025-07-02T08:11:11.7010000+03:00","stream":"Tech"},{"version":"6000.2.0b7","releaseDate":"2025-06-24T18:49:01.1870000+03:00","stream":"Tech"},{"version":"6000.1.9f1","releaseDate":"2025-06-24T16:56:32.8380000+03:00","stream":"Tech"},{"version":"6000.1.8f1","releaseDate":"2025-06-18T08:09:52.6810000+03:00","stream":"Tech"},{"version":"6000.2.0b6","releaseDate":"2025-06-14T00:10:42.6505176+03:00","stream":"Beta"},{"version":"6000.1.7f1","releaseDate":"2025-06-11T16:28:11.0210000+03:00","stream":"Tech"},{"version":"6000.0.51f1","releaseDate":"2025-06-11T12:43:13.5700000+03:00","stream":"Tech"},{"version":"6000.2.0b5","releaseDate":"2025-06-05T21:43:56.6458275+03:00","stream":"Beta"},{"version":"6000.1.6f1","releaseDate":"2025-06-05T12:52:49.5640000+03:00","stream":"Tech"},{"version":"6000.2.0b4","releaseDate":"2025-06-04T08:33:17.6990000+03:00","stream":"Tech"},{"version":"6000.0.50f1","releaseDate":"2025-05-28T18:00:23.5230000+03:00","stream":"Tech"},{"version":"6000.1.5f1","releaseDate":"2025-05-28T17:09:19.2710000+03:00","stream":"Tech"},{"version":"6000.2.0b3","releaseDate":"2025-05-23T10:48:51.3054783+03:00","stream":"Beta"},{"version":"6000.1.4f1","releaseDate":"2025-05-21T12:38:18.0710000+03:00","stream":"Tech"},{"version":"6000.2.0b2","releaseDate":"2025-05-20T17:11:12.0840000+03:00","stream":"Tech"},{"version":"6000.2.0b1","releaseDate":"2025-05-15T12:05:37.2680000+03:00","stream":"Tech"},{"version":"6000.0.49f1","releaseDate":"2025-05-14T06:30:14.3260000+03:00","stream":"Tech"},{"version":"6000.1.3f1","releaseDate":"2025-05-14T06:29:42.5580000+03:00","stream":"Tech"},{"version":"2022.3.62f1","releaseDate":"2025-05-07T09:24:12.5330000+03:00","stream":"Tech"},{"version":"6000.1.2f1","releaseDate":"2025-05-06T20:34:03.1050000+03:00","stream":"Tech"},{"version":"6000.2.0a10","releaseDate":"2025-05-01T12:14:47.8870000+03:00","stream":"Tech"},{"version":"6000.1.1f1","releaseDate":"2025-04-29T19:39:51.9700000+03:00","stream":"Tech"},{"version":"6000.0.48f1","releaseDate":"2025-04-29T17:35:44.5230000+03:00","stream":"Tech"},{"version":"6000.1.0f1","releaseDate":"2025-04-23T19:39:14.5990000+03:00","stream":"Tech"},{"version":"6000.0.47f1","releaseDate":"2025-04-16T06:29:12.0920000+03:00","stream":"Tech"},{"version":"6000.1.0b15","releaseDate":"2025-04-16T06:28:31.9490000+03:00","stream":"Tech"},{"version":"6000.1.0b14","releaseDate":"2025-04-10T21:26:49.7290000+03:00","stream":"Tech"},{"version":"6000.0.46f1","releaseDate":"2025-04-10T05:59:39.0190000+03:00","stream":"Tech"},{"version":"6000.2.0a9","releaseDate":"2025-04-10T21:54:23.9518927+03:00","stream":"Alpha"},{"version":"2022.3.61f1","releaseDate":"2025-04-10T11:38:43.5390000+03:00","stream":"Tech"},{"version":"6000.1.0b13","releaseDate":"2025-04-03T17:02:05.1710000+03:00","stream":"Tech"},{"version":"6000.2.0a8","releaseDate":"2025-04-03T14:42:33.5640000+03:00","stream":"Tech"},{"version":"6000.0.45f1","releaseDate":"2025-04-02T20:28:25.2630000+03:00","stream":"Tech"},{"version":"6000.2.0a7","releaseDate":"2025-04-03T00:29:12.5673679+03:00","stream":"Alpha"},{"version":"6000.0.44f1","releaseDate":"2025-03-28T17:42:02.3830000+02:00","stream":"Tech"},{"version":"6000.1.0b12","releaseDate":"2025-03-28T17:41:15.4510000+02:00","stream":"Tech"},{"version":"6000.0.43f1","releaseDate":"2025-03-18T19:24:00.4850000+02:00","stream":"Tech"},{"version":"6000.1.0b11","releaseDate":"2025-03-13T23:12:53.3749487+02:00","stream":"Beta"},{"version":"6000.0.42f1","releaseDate":"2025-03-11T15:58:50.1000000+02:00","stream":"Tech"},{"version":"2022.3.60f1","releaseDate":"2025-03-12T12:34:20.8620000+02:00","stream":"Tech"},{"version":"6000.1.0b10","releaseDate":"2025-03-09T21:03:55.9859232+02:00","stream":"Beta"},{"version":"6000.2.0a6","releaseDate":"2025-03-05T12:38:42.7350000+02:00","stream":"Tech"},{"version":"6000.0.41f1","releaseDate":"2025-03-03T23:59:40.0490000+02:00","stream":"Tech"},{"version":"6000.1.0b9","releaseDate":"2025-02-26T20:38:37.1430029+02:00","stream":"Beta"},{"version":"2022.3.59f1","releaseDate":"2025-02-26T08:46:36.6070000+02:00","stream":"Tech"},{"version":"6000.0.40f1","releaseDate":"2025-02-25T18:31:05.0170000+02:00","stream":"Tech"},{"version":"6000.1.0b8","releaseDate":"2025-02-22T23:05:50.9086693+02:00","stream":"Beta"},{"version":"6000.2.0a4","releaseDate":"2025-02-19T16:48:33.1920000+02:00","stream":"Tech"},{"version":"6000.0.39f1","releaseDate":"2025-02-19T09:25:26.3610000+02:00","stream":"Tech"},{"version":"6000.1.0b7","releaseDate":"2025-02-19T09:25:03.6480000+02:00","stream":"Tech"},{"version":"2022.3.58f1","releaseDate":"2025-02-12T09:38:47.9230000+02:00","stream":"Tech"},{"version":"6000.1.0b6","releaseDate":"2025-02-11T17:27:26.4890000+02:00","stream":"Tech"},{"version":"6000.0.38f1","releaseDate":"2025-02-11T17:26:47.9610000+02:00","stream":"Tech"},{"version":"6000.1.0b5","releaseDate":"2025-02-04T18:57:33.9900000+02:00","stream":"Tech"},{"version":"6000.0.37f1","releaseDate":"2025-02-04T18:57:15.7990000+02:00","stream":"Tech"},{"version":"6000.2.0a1","releaseDate":"2025-01-29T12:20:51.8410000+02:00","stream":"Tech"},{"version":"2022.3.57f1","releaseDate":"2025-01-29T11:35:20.0040000+02:00","stream":"Tech"},{"version":"6000.1.0b4","releaseDate":"2025-01-28T20:18:53.6020000+02:00","stream":"Tech"},{"version":"6000.0.36f1","releaseDate":"2025-01-28T20:18:05.4190000+02:00","stream":"Tech"},{"version":"6000.0.35f1","releaseDate":"2025-01-22T20:20:41.5350000+02:00","stream":"Tech"},{"version":"6000.1.0b3","releaseDate":"2025-01-22T20:18:42.6480000+02:00","stream":"Tech"},{"version":"6000.1.0b2","releaseDate":"2025-01-16T14:57:55.2590000+02:00","stream":"Tech"},{"version":"6000.0.34f1","releaseDate":"2025-01-15T15:46:28.7450000+02:00","stream":"Tech"},{"version":"2022.3.56f1","releaseDate":"2025-01-15T09:37:15.3380000+02:00","stream":"Tech"},{"version":"6000.0.33f1","releaseDate":"2025-01-08T12:15:44.6480000+02:00","stream":"Tech"},{"version":"6000.1.0b1","releaseDate":"2025-01-07T23:50:17.2740000+02:00","stream":"Tech"},{"version":"6000.0.32f1","releaseDate":"2024-12-19T17:34:00.0720000+02:00","stream":"Tech"},{"version":"6000.1.0a9","releaseDate":"2024-12-18T10:40:10.1340000+02:00","stream":"Tech"},{"version":"2022.3.55f1","releaseDate":"2024-12-17T18:21:09.4100000+02:00","stream":"Tech"},{"version":"6000.1.0a8","releaseDate":"2024-12-15T18:28:59.7430639+02:00","stream":"Alpha"},{"version":"6000.0.31f1","releaseDate":"2024-12-10T22:18:02.5280000+02:00","stream":"Tech"},{"version":"6000.1.0a8","releaseDate":"2024-12-10T22:17:32.5920000+02:00","stream":"Tech"},{"version":"6000.1.0a7","releaseDate":"2024-12-05T08:33:50.3480000+02:00","stream":"Tech"},{"version":"6000.0.30f1","releaseDate":"2024-12-04T16:36:24.5510000+02:00","stream":"Tech"},{"version":"2022.3.54f1","releaseDate":"2024-12-04T16:24:52.8920000+02:00","stream":"Tech"},{"version":"6000.1.0a6","releaseDate":"2024-11-28T13:20:00.3060000+02:00","stream":"Tech"},{"version":"6000.0.29f1","releaseDate":"2024-11-28T11:51:13.4500000+02:00","stream":"Tech"},{"version":"6000.0.28f1","releaseDate":"2024-11-20T17:26:35.0740000+02:00","stream":"Tech"},{"version":"6000.1.0a5","releaseDate":"2024-11-20T06:47:45.8140000+02:00","stream":"Tech"},{"version":"2022.3.53f1","releaseDate":"2024-11-19T18:19:05.9770000+02:00","stream":"Tech"},{"version":"6000.0.27f1","releaseDate":"2024-11-14T09:07:52.6160000+02:00","stream":"Tech"},{"version":"6000.1.0a4","releaseDate":"2024-11-14T08:21:53.5470000+02:00","stream":"Tech"},{"version":"6000.1.0a3","releaseDate":"2024-10-31T02:09:14.4710000+02:00","stream":"Tech"},{"version":"6000.0.26f1","releaseDate":"2024-11-07T05:58:16.8120000+02:00","stream":"Tech"},{"version":"2022.3.52f1","releaseDate":"2024-11-06T08:44:56.0460000+02:00","stream":"Tech"},{"version":"6000.0.25f1","releaseDate":"2024-10-31T02:08:57.1640000+02:00","stream":"LTS"},{"version":"6000.1.0a2","releaseDate":"2024-10-31T01:18:23.1720000+02:00","stream":"Alpha"},{"version":"6000.0.24f1","releaseDate":"2024-10-24T07:50:49.7030000+03:00","stream":"LTS"},{"version":"2022.3.51f1","releaseDate":"2024-10-22T19:55:03.7950000+03:00","stream":"LTS"},{"version":"6000.0.23f1","releaseDate":"2024-10-17T02:50:12.5800000+03:00","stream":"LTS"},{"version":"2021.3.45f1","releaseDate":"2024-10-16T11:39:15.9770000+03:00","stream":"LTS"},{"version":"2022.3.50f1","releaseDate":"2024-10-09T12:22:48.6100000+03:00","stream":"LTS"},{"version":"6000.0.22f1","releaseDate":"2024-10-02T22:04:27.2050000+03:00","stream":"Tech"},{"version":"2022.3.49f1","releaseDate":"2024-10-01T17:05:21.8390000+03:00","stream":"LTS"},{"version":"2022.3.48f1","releaseDate":"2024-09-26T21:38:03.7600000+03:00","stream":"LTS"},{"version":"6000.0.21f1","releaseDate":"2024-09-24T19:11:20.5860000+03:00","stream":"Tech"},{"version":"2021.3.44f1","releaseDate":"2024-09-23T17:46:08.5310000+03:00","stream":"LTS"},{"version":"6000.0.20f1","releaseDate":"2024-09-19T18:22:09.9610000+03:00","stream":"Tech"},{"version":"2022.3.47f1","releaseDate":"2024-09-18T09:44:50.2140000+03:00","stream":"LTS"},{"version":"6000.0.19f1","releaseDate":"2024-09-12T04:29:34.6560000+03:00","stream":"Tech"},{"version":"2022.3.46f1","releaseDate":"2024-09-10T19:41:40.2330000+03:00","stream":"LTS"},{"version":"6000.0.18f1","releaseDate":"2024-09-04T09:08:14.6900000+03:00","stream":"Tech"},{"version":"2022.3.45f1","releaseDate":"2024-09-04T01:44:17.3580000+03:00","stream":"LTS"},{"version":"6000.0.17f1","releaseDate":"2024-08-27T19:52:36.7630000+03:00","stream":"Tech"},{"version":"2022.3.44f1","releaseDate":"2024-08-23T09:10:50.9750000+03:00","stream":"LTS"},{"version":"6000.0.16f1","releaseDate":"2024-08-22T21:12:19.7750000+03:00","stream":"Tech"},{"version":"2021.3.43f1","releaseDate":"2024-08-22T13:10:30.8490000+03:00","stream":"LTS"},{"version":"2022.3.43f1","releaseDate":"2024-08-21T17:11:42.7280000+03:00","stream":"LTS"},{"version":"6000.0.15f1","releaseDate":"2024-08-13T21:03:16.7920000+03:00","stream":"Tech"},{"version":"2022.3.42f1","releaseDate":"2024-08-13T12:26:14.2690000+03:00","stream":"LTS"},{"version":"6000.0.14f1","releaseDate":"2024-08-07T08:59:10.6590000+03:00","stream":"Tech"},{"version":"2022.3.41f1","releaseDate":"2024-08-06T13:07:06.8530000+03:00","stream":"LTS"},{"version":"2021.3.42f1","releaseDate":"2024-08-06T12:30:24.6020000+03:00","stream":"LTS"},{"version":"6000.0.13f1","releaseDate":"2024-07-31T21:30:12.3520000+03:00","stream":"Tech"},{"version":"2022.3.40f1","releaseDate":"2024-07-30T17:14:27.5360000+03:00","stream":"LTS"},{"version":"6000.0.12f1","releaseDate":"2024-07-25T19:59:55.9270000+03:00","stream":"Tech"},{"version":"2022.3.39f1","releaseDate":"2024-07-23T19:04:16.2020000+03:00","stream":"LTS"},{"version":"2021.3.41f1","releaseDate":"2024-07-23T17:54:58.7980000+03:00","stream":"LTS"},{"version":"6000.0.11f1","releaseDate":"2024-07-17T13:16:09.0230000+03:00","stream":"Tech"},{"version":"2022.3.38f1","releaseDate":"2024-07-16T16:52:35.9940000+03:00","stream":"LTS"},{"version":"6000.0.10f1","releaseDate":"2024-07-10T19:45:22.4880000+03:00","stream":"Tech"},{"version":"2022.3.37f1","releaseDate":"2024-07-09T15:05:40.0740000+03:00","stream":"LTS"},{"version":"6000.0.9f1","releaseDate":"2024-07-03T17:22:27.3520000+03:00","stream":"Tech"},{"version":"2022.3.36f1","releaseDate":"2024-07-02T20:23:09.1240000+03:00","stream":"LTS"},{"version":"6000.0.8f1","releaseDate":"2024-06-28T18:36:42.0980000+03:00","stream":"Tech"},{"version":"2022.3.35f1","releaseDate":"2024-06-27T20:06:27.0820000+03:00","stream":"LTS"},{"version":"2021.3.40f1","releaseDate":"2024-06-27T05:15:04.4950000+03:00","stream":"LTS"},{"version":"6000.0.7f1","releaseDate":"2024-06-20T19:04:46.2760000+03:00","stream":"Tech"},{"version":"2022.3.34f1","releaseDate":"2024-06-18T14:27:05.7060000+03:00","stream":"LTS"},{"version":"2022.3.33f1","releaseDate":"2024-06-12T09:22:11.9550000+03:00","stream":"LTS"},{"version":"6000.0.5f1","releaseDate":"2024-06-04T21:54:20.5720000+03:00","stream":"Tech"},{"version":"2022.3.32f1","releaseDate":"2024-06-04T20:45:52.3580000+03:00","stream":"LTS"},{"version":"6000.0.4f1","releaseDate":"2024-05-29T19:49:19.3410000+03:00","stream":"Tech"},{"version":"2022.3.31f1","releaseDate":"2024-05-28T20:19:07.2650000+03:00","stream":"LTS"},{"version":"2021.3.39f1","releaseDate":"2024-05-28T19:13:34.5600000+03:00","stream":"LTS"},{"version":"6000.0.3f1","releaseDate":"2024-05-21T19:15:54.9330000+03:00","stream":"Tech"},{"version":"2022.3.30f1","releaseDate":"2024-05-21T15:05:13.7390000+03:00","stream":"LTS"},{"version":"6000.0.2f1","releaseDate":"2024-05-14T22:54:04.4270000+03:00","stream":"Tech"},{"version":"2022.3.29f1","releaseDate":"2024-05-14T18:20:52.9280000+03:00","stream":"LTS"},{"version":"6000.0.1f1","releaseDate":"2024-05-08T18:11:21.9000000+03:00","stream":"Tech"},{"version":"2022.3.28f1","releaseDate":"2024-05-07T18:20:10.5920000+03:00","stream":"LTS"},{"version":"2021.3.38f1","releaseDate":"2024-05-02T21:42:56.7610000+03:00","stream":"LTS"},{"version":"2022.3.27f1","releaseDate":"2024-04-30T20:28:32.4380000+03:00","stream":"LTS"},{"version":"6000.0.0f1","releaseDate":"2024-04-29T21:37:33.4220000+03:00","stream":"Tech"},{"version":"2023.2.20f1","releaseDate":"2024-04-25T22:29:55.5280000+03:00","stream":"Tech"},{"version":"2022.3.26f1","releaseDate":"2024-04-23T20:47:02.1750000+03:00","stream":"LTS"},{"version":"6000.0.0b16","releaseDate":"2024-04-19T18:47:47.0120000+03:00","stream":"Beta"},{"version":"2023.2.19f1","releaseDate":"2024-04-18T11:21:36.2640000+03:00","stream":"Tech"},{"version":"2022.3.25f1","releaseDate":"2024-04-16T15:56:01.9400000+03:00","stream":"LTS"},{"version":"6000.0.0b15","releaseDate":"2024-04-13T03:46:31.3090000+03:00","stream":"Beta"},{"version":"2023.2.18f1","releaseDate":"2024-04-10T00:11:33.7860000+03:00","stream":"Tech"},{"version":"2022.3.24f1","releaseDate":"2024-04-09T14:12:12.5040000+03:00","stream":"LTS"},{"version":"2023.2.17f1","releaseDate":"2024-04-04T04:45:09.5450000+03:00","stream":"Tech"},{"version":"2022.3.23f1","releaseDate":"2024-04-02T18:24:02.3240000+03:00","stream":"LTS"},{"version":"2021.3.37f1","releaseDate":"2024-04-02T16:12:43.5310000+03:00","stream":"LTS"},{"version":"6000.0.0b13","releaseDate":"2024-03-27T03:28:00.3900000+02:00","stream":"Beta"},{"version":"2023.2.16f1","releaseDate":"2024-03-27T03:03:51.3150000+02:00","stream":"Tech"},{"version":"2023.2.15f1","releaseDate":"2024-03-19T23:07:34.0340000+02:00","stream":"Tech"},{"version":"6000.0.0b12","releaseDate":"2024-03-19T21:32:02.8890000+02:00","stream":"Beta"},{"version":"2022.3.22f1","releaseDate":"2024-03-19T13:06:29.3290000+02:00","stream":"LTS"},{"version":"6000.0.0b11","releaseDate":"2024-03-13T23:20:06.4030000+02:00","stream":"Beta"},{"version":"2023.2.14f1","releaseDate":"2024-03-12T20:27:41.7580000+02:00","stream":"Tech"},{"version":"2023.2.13f1","releaseDate":"2024-03-05T22:41:13.8390000+02:00","stream":"Tech"},{"version":"2023.3.0b10","releaseDate":"2024-03-05T21:08:01.4850000+02:00","stream":"Beta"},{"version":"2021.3.36f1","releaseDate":"2024-03-05T20:42:24.1710000+02:00","stream":"LTS"},{"version":"2022.3.21f1","releaseDate":"2024-03-05T18:04:04.8580000+02:00","stream":"LTS"},{"version":"2023.2.12f1","releaseDate":"2024-02-29T01:06:57.2790000+02:00","stream":"Tech"},{"version":"2023.3.0b9","releaseDate":"2024-02-28T23:32:42.6980000+02:00","stream":"Beta"},{"version":"2023.2.11f1","releaseDate":"2024-02-20T23:17:45.0260000+02:00","stream":"Tech"},{"version":"2023.3.0b8","releaseDate":"2024-02-20T21:40:27.1710000+02:00","stream":"Beta"},{"version":"2023.2.10f1","releaseDate":"2024-02-14T21:39:19.8910000+02:00","stream":"Tech"},{"version":"2022.3.20f1","releaseDate":"2024-02-14T13:25:56.5410000+02:00","stream":"LTS"},{"version":"2023.3.0b7","releaseDate":"2024-02-13T21:59:14.7140000+02:00","stream":"Beta"},{"version":"2023.3.0b6","releaseDate":"2024-02-07T09:24:40.2320000+02:00","stream":"Beta"},{"version":"2023.2.9f1","releaseDate":"2024-02-07T08:56:57.6470000+02:00","stream":"Tech"},{"version":"2021.3.35f1","releaseDate":"2024-02-06T17:40:15.5830000+02:00","stream":"LTS"},{"version":"2022.3.19f1","releaseDate":"2024-01-31T13:56:51.6340000+02:00","stream":"LTS"},{"version":"2023.3.0b5","releaseDate":"2024-01-31T02:28:33.7000000+02:00","stream":"Beta"},{"version":"2023.2.8f1","releaseDate":"2024-01-31T02:02:00.5870000+02:00","stream":"Tech"},{"version":"2023.2.7f1","releaseDate":"2024-01-23T22:43:04.8780000+02:00","stream":"Tech"},{"version":"2023.3.0b4","releaseDate":"2024-01-23T21:12:34.8720000+02:00","stream":"Beta"},{"version":"2022.3.18f1","releaseDate":"2024-01-20T18:00:12.2100000+02:00","stream":"LTS"},{"version":"2023.2.6f1","releaseDate":"2024-01-17T07:22:12.1160000+02:00","stream":"Tech"},{"version":"2023.3.0b3","releaseDate":"2024-01-15T07:07:54.4010000+02:00","stream":"Beta"},{"version":"2023.3.0b2","releaseDate":"2024-01-09T23:10:15.9440000+02:00","stream":"Beta"},{"version":"2021.3.34f1","releaseDate":"2024-01-09T17:33:57.0130000+02:00","stream":"LTS"},{"version":"2022.3.17f1","releaseDate":"2024-01-09T15:24:21.3090000+02:00","stream":"LTS"},{"version":"2023.2.5f1","releaseDate":"2024-01-09T10:49:30.8570000+02:00","stream":"Tech"},{"version":"2023.3.0b1","releaseDate":"2024-01-03T04:06:01.1860000+02:00","stream":"Beta"},{"version":"2023.2.4f1","releaseDate":"2023-12-22T13:24:31.4620000+02:00","stream":"Tech"},{"version":"2022.3.16f1","releaseDate":"2023-12-19T12:05:11.7210000+02:00","stream":"LTS"},{"version":"2023.3.0a18","releaseDate":"2023-12-13T23:40:57.5080000+02:00","stream":"Alpha"},{"version":"2023.2.3f1","releaseDate":"2023-12-06T00:03:42.7620000+02:00","stream":"Tech"},{"version":"2023.3.0a17","releaseDate":"2023-12-05T22:29:50.0710000+02:00","stream":"Alpha"},{"version":"2022.3.15f1","releaseDate":"2023-12-05T18:41:51.6760000+02:00","stream":"LTS"},{"version":"2023.2.2f1","releaseDate":"2023-11-28T22:28:30.9510000+02:00","stream":"Tech"},{"version":"2023.3.0a16","releaseDate":"2023-11-28T20:53:03.1050000+02:00","stream":"Alpha"},{"version":"2021.3.33f1","releaseDate":"2023-11-28T17:21:35.6330000+02:00","stream":"LTS"},{"version":"2023.2.1f1","releaseDate":"2023-11-22T00:09:38.4850000+02:00","stream":"Tech"},{"version":"2022.3.14f1","releaseDate":"2023-11-21T22:07:15.6700000+02:00","stream":"LTS"},{"version":"2023.3.0a15","releaseDate":"2023-11-21T19:46:47.0020000+02:00","stream":"Alpha"},{"version":"2023.2.0f1","releaseDate":"2023-11-15T01:22:44.2930000+02:00","stream":"Tech"},{"version":"2023.3.0a14","releaseDate":"2023-11-14T23:47:34.4680000+02:00","stream":"Alpha"},{"version":"2023.1.20f1","releaseDate":"2023-11-09T13:37:53.0800000+02:00","stream":"Tech"},{"version":"2022.3.13f1","releaseDate":"2023-11-07T19:33:11.8460000+02:00","stream":"LTS"},{"version":"2023.3.0a13","releaseDate":"2023-11-07T15:03:31.6360000+02:00","stream":"Alpha"},{"version":"2023.2.0b17","releaseDate":"2023-11-07T03:15:49.7360000+02:00","stream":"Beta"},{"version":"2021.3.32f1","releaseDate":"2023-11-01T17:47:25.8010000+02:00","stream":"LTS"},{"version":"2023.2.0b16","releaseDate":"2023-11-01T09:07:29.0190000+02:00","stream":"Beta"},{"version":"2023.3.0a12","releaseDate":"2023-10-31T22:54:47.4610000+02:00","stream":"Alpha"},{"version":"2023.1.19f1","releaseDate":"2023-10-31T16:12:27.1350000+02:00","stream":"Tech"},{"version":"2023.3.0a11","releaseDate":"2023-10-26T23:42:38.0140000+03:00","stream":"Alpha"},{"version":"2023.2.0b15","releaseDate":"2023-10-26T22:42:17.8000000+03:00","stream":"Beta"},{"version":"2022.3.12f1","releaseDate":"2023-10-26T17:00:14.6020000+03:00","stream":"LTS"},{"version":"2023.1.18f1","releaseDate":"2023-10-24T19:38:46.5580000+03:00","stream":"Tech"},{"version":"2023.1.17f1","releaseDate":"2023-10-17T16:06:27.2150000+03:00","stream":"Tech"},{"version":"2023.2.0b14","releaseDate":"2023-10-16T19:49:19.2110000+03:00","stream":"Beta"},{"version":"2023.3.0a10","releaseDate":"2023-10-16T18:53:09.4090000+03:00","stream":"Alpha"},{"version":"2023.2.0b13","releaseDate":"2023-10-11T02:43:50.4180000+03:00","stream":"Beta"},{"version":"2022.3.11f1","releaseDate":"2023-10-10T18:27:45.5750000+03:00","stream":"LTS"},{"version":"2023.2.0b12","releaseDate":"2023-10-05T08:35:01.2590000+03:00","stream":"Beta"},{"version":"2023.3.0a8","releaseDate":"2023-10-05T07:37:32.5410000+03:00","stream":"Alpha"},{"version":"2023.1.16f1","releaseDate":"2023-10-03T20:51:07.9240000+03:00","stream":"Tech"},{"version":"2021.3.31f1","releaseDate":"2023-10-03T18:50:59.1880000+03:00","stream":"LTS"},{"version":"2023.2.0b11","releaseDate":"2023-09-27T22:03:28.2830000+03:00","stream":"Beta"},{"version":"2023.1.15f1","releaseDate":"2023-09-26T16:26:57.1220000+03:00","stream":"Tech"},{"version":"2023.3.0a6","releaseDate":"2023-09-21T22:57:30.1720000+03:00","stream":"Alpha"},{"version":"2023.2.0b10","releaseDate":"2023-09-21T03:25:39.0680000+03:00","stream":"Beta"},{"version":"2023.3.0a7","releaseDate":"2023-09-21T02:32:03.4860000+03:00","stream":"Alpha"},{"version":"2023.1.14f1","releaseDate":"2023-09-19T16:45:02.8020000+03:00","stream":"Tech"},{"version":"2022.3.10f1","releaseDate":"2023-09-19T14:09:17.9240000+03:00","stream":"LTS"},{"version":"2023.2.0b9","releaseDate":"2023-09-13T19:47:50.2650000+03:00","stream":"Beta"},{"version":"2023.3.0a5","releaseDate":"2023-09-13T11:39:30.3420000+03:00","stream":"Alpha"},{"version":"2023.1.13f1","releaseDate":"2023-09-12T19:45:26.5060000+03:00","stream":"Tech"},{"version":"2023.2.0b8","releaseDate":"2023-09-07T03:06:06.6190000+03:00","stream":"Beta"},{"version":"2023.3.0a4","releaseDate":"2023-09-07T02:09:51.7610000+03:00","stream":"Alpha"},{"version":"2023.1.12f1","releaseDate":"2023-09-05T16:19:07.6000000+03:00","stream":"Tech"},{"version":"2022.3.9f1","releaseDate":"2023-09-05T14:20:42.5520000+03:00","stream":"LTS"},{"version":"2023.3.0a3","releaseDate":"2023-08-30T02:57:28.4560000+03:00","stream":"Alpha"},{"version":"2023.1.11f1","releaseDate":"2023-08-30T02:34:23.2510000+03:00","stream":"Tech"},{"version":"2023.2.0b7","releaseDate":"2023-08-30T01:05:40.2550000+03:00","stream":"Beta"},{"version":"2021.3.30f1","releaseDate":"2023-08-30T01:00:32.9160000+03:00","stream":"LTS"},{"version":"2023.2.0b6","releaseDate":"2023-08-23T19:37:08.1570000+03:00","stream":"Beta"},{"version":"2022.3.8f1","releaseDate":"2023-08-22T19:08:57.6900000+03:00","stream":"LTS"},{"version":"2023.1.10f1","releaseDate":"2023-08-22T12:04:56.8560000+03:00","stream":"Tech"},{"version":"2023.2.0b5","releaseDate":"2023-08-15T22:46:13.9610000+03:00","stream":"Beta"},{"version":"2023.1.9f1","releaseDate":"2023-08-15T11:51:07.4310000+03:00","stream":"Tech"},{"version":"2023.2.0b4","releaseDate":"2023-08-10T19:28:52.9540000+03:00","stream":"Beta"},{"version":"2023.1.8f1","releaseDate":"2023-08-08T13:46:36.3470000+03:00","stream":"Tech"},{"version":"2022.3.7f1","releaseDate":"2023-08-08T12:39:39.2500000+03:00","stream":"LTS"},{"version":"2023.2.0b3","releaseDate":"2023-08-02T00:20:07.9800000+03:00","stream":"Beta"},{"version":"2023.1.7f1","releaseDate":"2023-08-01T14:52:30.6880000+03:00","stream":"Tech"},{"version":"2022.3.6f1","releaseDate":"2023-07-31T21:44:28.3130000+03:00","stream":"LTS"},{"version":"2023.2.0b2","releaseDate":"2023-07-26T18:36:17.0900000+03:00","stream":"Beta"},{"version":"2023.1.6f1","releaseDate":"2023-07-25T17:07:19.6790000+03:00","stream":"Tech"},{"version":"2021.3.29f1","releaseDate":"2023-07-25T15:13:45.7210000+03:00","stream":"LTS"},{"version":"2023.2.0b1","releaseDate":"2023-07-19T20:48:18.0780000+03:00","stream":"Beta"},{"version":"2023.1.5f1","releaseDate":"2023-07-18T12:47:39.8830000+03:00","stream":"Tech"},{"version":"2022.3.5f1","releaseDate":"2023-07-13T19:12:49.1180000+03:00","stream":"LTS"},{"version":"2023.1.4f1","releaseDate":"2023-07-13T12:22:35.2840000+03:00","stream":"Tech"},{"version":"2023.2.0a22","releaseDate":"2023-07-10T13:49:24.5250000+03:00","stream":"Alpha"},{"version":"2023.1.3f1","releaseDate":"2023-07-05T13:38:33.7830000+03:00","stream":"Tech"},{"version":"2021.3.28f1","releaseDate":"2023-07-04T22:41:02.2050000+03:00","stream":"LTS"},{"version":"2023.1.2f1","releaseDate":"2023-06-26T20:35:53.2890000+03:00","stream":"Tech"},{"version":"2022.3.4f1","releaseDate":"2023-06-26T19:47:18.7050000+03:00","stream":"LTS"},{"version":"2023.2.0a20","releaseDate":"2023-06-21T22:58:23.5890000+03:00","stream":"Alpha"},{"version":"2022.3.3f1","releaseDate":"2023-06-21T18:21:19.0310000+03:00","stream":"LTS"},{"version":"2023.1.1f1","releaseDate":"2023-06-21T17:44:26.6940000+03:00","stream":"Tech"},{"version":"2023.2.0a19","releaseDate":"2023-06-13T20:56:46.9020000+03:00","stream":"Alpha"},{"version":"2022.3.2f1","releaseDate":"2023-06-13T20:35:17.0320000+03:00","stream":"LTS"},{"version":"2023.1.0f1","releaseDate":"2023-06-12T23:09:17.9400000+03:00","stream":"Tech"},{"version":"2021.3.27f1","releaseDate":"2023-06-07T19:35:21.2420000+03:00","stream":"LTS"},{"version":"2023.2.0a18","releaseDate":"2023-06-07T18:05:43.8610000+03:00","stream":"Alpha"},{"version":"2023.1.0b20","releaseDate":"2023-06-07T17:07:58.1050000+03:00","stream":"Beta"},{"version":"2022.3.1f1","releaseDate":"2023-06-07T14:44:18.6430000+03:00","stream":"LTS"},{"version":"2023.1.0b19","releaseDate":"2023-06-01T00:22:40.7160000+03:00","stream":"Beta"},{"version":"2023.2.0a17","releaseDate":"2023-05-31T22:36:57.5850000+03:00","stream":"Alpha"},{"version":"2022.3.0f1","releaseDate":"2023-05-30T13:40:13.8580000+03:00","stream":"LTS"},{"version":"2021.3.26f1","releaseDate":"2023-05-25T14:47:02.1500000+03:00","stream":"LTS"},{"version":"2023.2.0a16","releaseDate":"2023-05-24T23:32:01.9930000+03:00","stream":"Alpha"},{"version":"2023.1.0b18","releaseDate":"2023-05-24T17:12:55.4530000+03:00","stream":"Beta"},{"version":"2022.2.21f1","releaseDate":"2023-05-24T14:15:23.9850000+03:00","stream":"Tech"},{"version":"2022.2.20f1","releaseDate":"2023-05-18T12:58:25.7740000+03:00","stream":"Tech"},{"version":"2023.2.0a15","releaseDate":"2023-05-17T23:05:43.2150000+03:00","stream":"Alpha"},{"version":"2020.3.48f1","releaseDate":"2023-05-17T20:23:52.7840000+03:00","stream":"LTS"},{"version":"2023.1.0b17","releaseDate":"2023-05-17T19:32:57.0910000+03:00","stream":"Beta"},{"version":"2021.3.25f1","releaseDate":"2023-05-11T16:55:39.0570000+03:00","stream":"LTS"},{"version":"2022.2.19f1","releaseDate":"2023-05-11T15:02:51.9390000+03:00","stream":"Tech"},{"version":"2023.1.0b16","releaseDate":"2023-05-11T04:23:47.7980000+03:00","stream":"Beta"},{"version":"2023.2.0a14","releaseDate":"2023-05-10T22:50:11.4440000+03:00","stream":"Alpha"},{"version":"2023.1.0b15","releaseDate":"2023-05-04T18:09:21.8720000+03:00","stream":"Beta"},{"version":"2022.2.18f1","releaseDate":"2023-05-04T17:54:59.9510000+03:00","stream":"Tech"},{"version":"2023.2.0a13","releaseDate":"2023-05-03T22:08:00.7610000+03:00","stream":"Alpha"},{"version":"2022.2.17f1","releaseDate":"2023-04-27T20:55:43.2970000+03:00","stream":"Tech"},{"version":"2021.3.24f1","releaseDate":"2023-04-27T20:16:27.5610000+03:00","stream":"LTS"},{"version":"2023.2.0a12","releaseDate":"2023-04-27T17:39:10.7740000+03:00","stream":"Alpha"},{"version":"2023.1.0b14","releaseDate":"2023-04-26T20:38:33.8280000+03:00","stream":"Beta"},{"version":"2023.2.0a11","releaseDate":"2023-04-20T02:11:25.8420000+03:00","stream":"Alpha"},{"version":"2023.1.0b13","releaseDate":"2023-04-19T18:38:30.4380000+03:00","stream":"Beta"},{"version":"2022.2.16f1","releaseDate":"2023-04-19T17:00:29.7910000+03:00","stream":"Tech"},{"version":"2021.3.23f1","releaseDate":"2023-04-14T06:05:53.4110000+03:00","stream":"LTS"},{"version":"2022.2.15f1","releaseDate":"2023-04-13T16:56:06.9490000+03:00","stream":"Tech"},{"version":"2023.2.0a10","releaseDate":"2023-04-12T20:57:27.3950000+03:00","stream":"Alpha"},{"version":"2023.1.0b12","releaseDate":"2023-04-12T19:58:27.1750000+03:00","stream":"Beta"},{"version":"2022.2.14f1","releaseDate":"2023-04-06T01:20:20.9000000+03:00","stream":"Tech"},{"version":"2023.2.0a9","releaseDate":"2023-04-05T20:17:10.3830000+03:00","stream":"Alpha"},{"version":"2020.3.47f1","releaseDate":"2023-04-05T19:12:43.4140000+03:00","stream":"LTS"},{"version":"2023.1.0b11","releaseDate":"2023-04-05T00:58:08.4100000+03:00","stream":"Beta"},{"version":"2022.2.13f1","releaseDate":"2023-03-31T17:48:28.3060000+03:00","stream":"Tech"},{"version":"2021.3.22f1","releaseDate":"2023-03-29T23:44:06.1310000+03:00","stream":"LTS"},{"version":"2023.1.0b10","releaseDate":"2023-03-29T22:31:31.4270000+03:00","stream":"Beta"},{"version":"2023.2.0a8","releaseDate":"2023-03-29T20:45:36.7180000+03:00","stream":"Alpha"},{"version":"2023.2.0a7","releaseDate":"2023-03-22T23:21:49.2770000+02:00","stream":"Alpha"},{"version":"2022.2.12f1","releaseDate":"2023-03-22T21:38:11.7020000+02:00","stream":"Tech"},{"version":"2023.1.0b9","releaseDate":"2023-03-22T19:34:30.5930000+02:00","stream":"Beta"},{"version":"2023.2.0a6","releaseDate":"2023-03-15T19:05:39.9400000+02:00","stream":"Alpha"},{"version":"2023.1.0b8","releaseDate":"2023-03-15T17:20:07.0490000+02:00","stream":"Beta"},{"version":"2021.3.21f1","releaseDate":"2023-03-15T05:07:29.3970000+02:00","stream":"LTS"},{"version":"2022.2.11f1","releaseDate":"2023-03-15T04:33:37.4390000+02:00","stream":"Tech"},{"version":"2022.2.10f1","releaseDate":"2023-03-09T03:37:14.1860000+02:00","stream":"Tech"},{"version":"2020.3.46f1","releaseDate":"2023-03-08T18:13:10.8010000+02:00","stream":"LTS"},{"version":"2023.1.0b7","releaseDate":"2023-03-07T19:21:08.1180000+02:00","stream":"Beta"},{"version":"2022.2.9f1","releaseDate":"2023-03-03T03:54:20.1620000+02:00","stream":"Tech"},{"version":"2021.3.20f1","releaseDate":"2023-03-03T01:34:21.4780000+02:00","stream":"LTS"},{"version":"2023.1.0b6","releaseDate":"2023-03-02T19:05:36.6970000+02:00","stream":"Beta"},{"version":"2022.2.8f1","releaseDate":"2023-02-23T17:21:52.5810000+02:00","stream":"Tech"},{"version":"2023.1.0b5","releaseDate":"2023-02-22T16:43:31.6520000+02:00","stream":"Beta"},{"version":"2021.3.19f1","releaseDate":"2023-02-17T17:24:45.3250000+02:00","stream":"LTS"},{"version":"2023.1.0b4","releaseDate":"2023-02-16T18:12:27.2890000+02:00","stream":"Beta"},{"version":"2022.2.7f1","releaseDate":"2023-02-15T22:59:18.6940000+02:00","stream":"Tech"},{"version":"2020.3.45f1","releaseDate":"2023-02-14T23:48:56.7970000+02:00","stream":"LTS"},{"version":"2022.2.6f1","releaseDate":"2023-02-10T03:46:54.4290000+02:00","stream":"Tech"},{"version":"2023.1.0b3","releaseDate":"2023-02-08T18:02:45.1480000+02:00","stream":"Beta"},{"version":"2021.3.18f1","releaseDate":"2023-02-01T22:10:11.4750000+02:00","stream":"LTS"},{"version":"2023.1.0b2","releaseDate":"2023-02-01T16:26:56.9800000+02:00","stream":"Beta"},{"version":"2022.2.5f1","releaseDate":"2023-01-31T22:58:08.2060000+02:00","stream":"Tech"},{"version":"2022.2.4f1","releaseDate":"2023-01-27T16:41:48.2250000+02:00","stream":"Tech"},{"version":"2023.1.0b1","releaseDate":"2023-01-24T18:35:43.4020000+02:00","stream":"Beta"},{"version":"2021.3.17f1","releaseDate":"2023-01-24T18:26:13.7420000+02:00","stream":"LTS"},{"version":"2022.2.3f1","releaseDate":"2023-01-23T21:50:52.1750000+02:00","stream":"Tech"},{"version":"2023.1.0a26","releaseDate":"2023-01-18T19:32:21.5630000+02:00","stream":"Alpha"},{"version":"2020.3.44f1","releaseDate":"2023-01-18T19:25:53.1090000+02:00","stream":"LTS"},{"version":"2023.1.0a25","releaseDate":"2023-01-11T21:23:37.6860000+02:00","stream":"Alpha"},{"version":"2022.2.2f1","releaseDate":"2023-01-10T05:21:01.4250000+02:00","stream":"Tech"},{"version":"2023.1.0a24","releaseDate":"2022-12-22T03:56:32.4480000+02:00","stream":"Alpha"},{"version":"2020.3.43f1","releaseDate":"2022-12-16T00:02:25.8850000+02:00","stream":"LTS"},{"version":"2021.3.16f1","releaseDate":"2022-12-15T18:05:52.9180000+02:00","stream":"LTS"},{"version":"2023.1.0a23","releaseDate":"2022-12-14T20:58:53.9770000+02:00","stream":"Alpha"},{"version":"2022.2.1f1","releaseDate":"2022-12-12T17:26:11.2260000+02:00","stream":"Tech"},{"version":"2023.1.0a22","releaseDate":"2022-12-07T23:25:31.9420000+02:00","stream":"Alpha"},{"version":"2022.2.0f1","releaseDate":"2022-12-07T16:29:04.8310000+02:00","stream":"Tech"},{"version":"2022.1.24f1","releaseDate":"2022-12-06T20:33:08.7300000+02:00","stream":"Tech"},{"version":"2021.3.15f1","releaseDate":"2022-12-01T19:20:58.3010000+02:00","stream":"LTS"},{"version":"2023.1.0a21","releaseDate":"2022-11-30T17:35:08.6520000+02:00","stream":"Alpha"},{"version":"2023.1.0a20","releaseDate":"2022-11-24T16:54:00.0950000+02:00","stream":"Alpha"},{"version":"2022.2.0b16","releaseDate":"2022-11-18T17:21:52.7500000+02:00","stream":"Beta"},{"version":"2023.1.0a19","releaseDate":"2022-11-17T23:40:42.6370000+02:00","stream":"Alpha"},{"version":"2021.3.14f1","releaseDate":"2022-11-17T19:28:01.6800000+02:00","stream":"LTS"},{"version":"2020.3.42f1","releaseDate":"2022-11-17T18:42:55.7160000+02:00","stream":"LTS"},{"version":"2022.1.23f1","releaseDate":"2022-11-16T13:07:08.5870000+02:00","stream":"Tech"},{"version":"2022.2.0b15","releaseDate":"2022-11-16T11:42:02.4260000+02:00","stream":"Beta"},{"version":"2023.1.0a18","releaseDate":"2022-11-10T17:10:57.7810000+02:00","stream":"Alpha"},{"version":"2022.1.22f1","releaseDate":"2022-11-09T14:42:48.4520000+02:00","stream":"Tech"},{"version":"2022.2.0b14","releaseDate":"2022-11-07T16:57:36.8080000+02:00","stream":"Beta"},{"version":"2021.3.13f1","releaseDate":"2022-11-04T18:42:23.1680000+02:00","stream":"LTS"},{"version":"2023.1.0a17","releaseDate":"2022-11-04T17:52:07.0070000+02:00","stream":"Alpha"},{"version":"2023.1.0a16","releaseDate":"2022-10-27T18:51:25.6730000+03:00","stream":"Alpha"},{"version":"2022.1.21f1","releaseDate":"2022-10-27T17:14:42.0510000+03:00","stream":"Tech"},{"version":"2022.2.0b13","releaseDate":"2022-10-26T23:13:31.6270000+03:00","stream":"Beta"},{"version":"2021.3.12f1","releaseDate":"2022-10-25T18:16:10.9510000+03:00","stream":"LTS"},{"version":"2023.1.0a15","releaseDate":"2022-10-21T18:12:32.3200000+03:00","stream":"Alpha"},{"version":"2020.3.41f1","releaseDate":"2022-10-21T17:22:52.5630000+03:00","stream":"LTS"},{"version":"2022.2.0b12","releaseDate":"2022-10-20T18:21:30.9490000+03:00","stream":"Beta"},{"version":"2022.2.0b11","releaseDate":"2022-10-17T22:47:44.2460000+03:00","stream":"Beta"},{"version":"2023.1.0a14","releaseDate":"2022-10-13T22:56:48.3590000+03:00","stream":"Alpha"},{"version":"2022.1.20f1","releaseDate":"2022-10-12T14:42:58.6240000+03:00","stream":"Tech"},{"version":"2023.1.0a13","releaseDate":"2022-10-06T22:12:22.6230000+03:00","stream":"Alpha"},{"version":"2022.2.0b10","releaseDate":"2022-10-06T18:22:41.4710000+03:00","stream":"Beta"},{"version":"2022.1.19f1","releaseDate":"2022-10-05T15:57:27.6550000+03:00","stream":"Tech"},{"version":"2022.1.18f1","releaseDate":"2022-09-29T17:37:44.5850000+03:00","stream":"Tech"},{"version":"2021.3.11f1","releaseDate":"2022-09-29T13:18:44.5050000+03:00","stream":"LTS"},{"version":"2022.2.0b9","releaseDate":"2022-09-29T06:03:40.7910000+03:00","stream":"Beta"},{"version":"2023.1.0a12","releaseDate":"2022-09-28T22:55:37.0920000+03:00","stream":"Alpha"},{"version":"2020.3.40f1","releaseDate":"2022-09-27T13:08:51.4880000+03:00","stream":"LTS"},{"version":"2023.1.0a11","releaseDate":"2022-09-21T17:43:10.2830000+03:00","stream":"Alpha"},{"version":"2022.1.17f1","releaseDate":"2022-09-21T14:47:30.1360000+03:00","stream":"Tech"},{"version":"2021.3.10f1","releaseDate":"2022-09-16T18:49:10.5930000+03:00","stream":"LTS"},{"version":"2020.3.39f1","releaseDate":"2022-09-15T00:53:29.6050000+03:00","stream":"LTS"},{"version":"2023.1.0a10","releaseDate":"2022-09-12T21:11:46.9380000+03:00","stream":"Alpha"},{"version":"2022.2.0b8","releaseDate":"2022-09-09T19:13:00.3470000+03:00","stream":"Beta"},{"version":"2022.1.16f1","releaseDate":"2022-09-08T16:08:35.0830000+03:00","stream":"Tech"},{"version":"2023.1.0a9","releaseDate":"2022-09-06T21:57:38.9710000+03:00","stream":"Alpha"},{"version":"2021.3.9f1","releaseDate":"2022-09-01T19:32:11.5790000+03:00","stream":"LTS"},{"version":"2022.2.0b7","releaseDate":"2022-09-01T17:23:07.2070000+03:00","stream":"Beta"},{"version":"2022.1.15f1","releaseDate":"2022-09-01T13:40:40.3950000+03:00","stream":"Tech"},{"version":"2022.2.0b6","releaseDate":"2022-08-26T01:40:10.3100000+03:00","stream":"Beta"},{"version":"2022.2.0b5","releaseDate":"2022-08-22T16:46:29.2740000+03:00","stream":"Beta"},{"version":"2022.1.14f1","releaseDate":"2022-08-22T11:56:08.0450000+03:00","stream":"Tech"},{"version":"2023.1.0a6","releaseDate":"2022-08-18T19:45:55.0300000+03:00","stream":"Alpha"},{"version":"2020.3.38f1","releaseDate":"2022-08-17T16:37:37.9830000+03:00","stream":"LTS"},{"version":"2023.1.0a5","releaseDate":"2022-08-11T19:35:17.2190000+03:00","stream":"Alpha"},{"version":"2022.1.13f1","releaseDate":"2022-08-11T10:43:08.2790000+03:00","stream":"Tech"},{"version":"2021.3.8f1","releaseDate":"2022-08-08T18:26:36.9290000+03:00","stream":"LTS"},{"version":"2022.1.12f1","releaseDate":"2022-08-05T13:30:50.9200000+03:00","stream":"Tech"},{"version":"2022.2.0b4","releaseDate":"2022-08-05T05:14:17.7170000+03:00","stream":"Beta"},{"version":"2022.2.0b3","releaseDate":"2022-07-28T20:18:44.5910000+03:00","stream":"Beta"},{"version":"2021.3.7f1","releaseDate":"2022-07-28T12:50:46.7670000+03:00","stream":"LTS"},{"version":"2022.1.11f1","releaseDate":"2022-07-27T15:20:14.4870000+03:00","stream":"Tech"},{"version":"2023.1.0a4","releaseDate":"2022-07-26T19:55:38.5590000+03:00","stream":"Alpha"},{"version":"2022.2.0b2","releaseDate":"2022-07-22T16:54:37.0230000+03:00","stream":"Beta"},{"version":"2020.3.37f1","releaseDate":"2022-07-21T12:53:36.2240000+03:00","stream":"LTS"},{"version":"2022.1.10f1","releaseDate":"2022-07-20T14:35:58.8890000+03:00","stream":"Tech"},{"version":"2022.1.9f1","releaseDate":"2022-07-14T14:39:28.8090000+03:00","stream":"Tech"},{"version":"2022.2.0b1","releaseDate":"2022-07-13T02:24:29.9080000+03:00","stream":"Beta"},{"version":"2021.3.6f1","releaseDate":"2022-07-08T12:48:54.7110000+03:00","stream":"LTS"},{"version":"2022.1.8f1","releaseDate":"2022-07-07T18:05:53.6420000+03:00","stream":"Tech"},{"version":"2022.2.0a18","releaseDate":"2022-07-04T19:35:28.1410000+03:00","stream":"Alpha"},{"version":"2022.1.7f1","releaseDate":"2022-06-29T15:39:55.5870000+03:00","stream":"Tech"},{"version":"2022.1.6f1","releaseDate":"2022-06-23T14:07:14.8560000+03:00","stream":"Tech"},{"version":"2021.3.5f1","releaseDate":"2022-06-22T20:32:31.1470000+03:00","stream":"LTS"},{"version":"2019.4.40f1","releaseDate":"2022-06-16T23:44:08.7430000+03:00","stream":"LTS"},{"version":"2022.2.0a17","releaseDate":"2022-06-16T22:20:11.1080000+03:00","stream":"Alpha"},{"version":"2020.3.36f1","releaseDate":"2022-06-16T18:04:11.6550000+03:00","stream":"LTS"},{"version":"2022.1.5f1","releaseDate":"2022-06-15T19:47:55.4610000+03:00","stream":"Tech"},{"version":"2022.2.0a16","releaseDate":"2022-06-08T23:20:40.3790000+03:00","stream":"Alpha"},{"version":"2022.1.4f1","releaseDate":"2022-06-08T18:53:22.1510000+03:00","stream":"Tech"},{"version":"2022.1.3f1","releaseDate":"2022-05-31T19:42:45.9740000+03:00","stream":"Tech"},{"version":"2021.3.4f1","releaseDate":"2022-05-31T18:14:15.5590000+03:00","stream":"LTS"},{"version":"2020.3.35f1","releaseDate":"2022-05-27T02:30:47.9620000+03:00","stream":"LTS"},{"version":"2022.1.2f1","releaseDate":"2022-05-25T17:32:41.9670000+03:00","stream":"Tech"},{"version":"2021.3.3f1","releaseDate":"2022-05-19T13:01:53.9560000+03:00","stream":"LTS"},{"version":"2022.1.1f1","releaseDate":"2022-05-18T23:43:29.7780000+03:00","stream":"Tech"},{"version":"2022.2.0a13","releaseDate":"2022-05-13T01:47:12.2000000+03:00","stream":"Alpha"},{"version":"2019.4.39f1","releaseDate":"2022-05-12T01:31:15.5880000+03:00","stream":"LTS"},{"version":"2022.1.0f1","releaseDate":"2022-05-09T19:53:20.7220000+03:00","stream":"Tech"},{"version":"2022.2.0a12","releaseDate":"2022-05-05T15:15:24.2770000+03:00","stream":"Alpha"},{"version":"2021.3.2f1","releaseDate":"2022-05-05T13:42:14.7170000+03:00","stream":"LTS"},{"version":"2020.3.34f1","releaseDate":"2022-05-04T17:33:40.9940000+03:00","stream":"LTS"},{"version":"2022.2.0a11","releaseDate":"2022-04-25T17:28:41.0660000+03:00","stream":"Alpha"},{"version":"2021.3.1f1","releaseDate":"2022-04-21T21:19:43.4030000+03:00","stream":"LTS"},{"version":"2022.2.0a10","releaseDate":"2022-04-14T16:22:59.4940000+03:00","stream":"Alpha"},{"version":"2019.4.38f1","releaseDate":"2022-04-13T18:24:10.4100000+03:00","stream":"LTS"},{"version":"2022.1.0b16","releaseDate":"2022-04-12T21:11:34.7660000+03:00","stream":"Beta"},{"version":"2021.3.0f1","releaseDate":"2022-04-11T21:46:28.6540000+03:00","stream":"LTS"},{"version":"2020.3.33f1","releaseDate":"2022-04-07T16:58:00.7880000+03:00","stream":"LTS"},{"version":"2022.1.0b15","releaseDate":"2022-04-07T10:56:08.2280000+03:00","stream":"Beta"},{"version":"2021.2.19f1","releaseDate":"2022-04-05T20:15:08.0160000+03:00","stream":"Tech"},{"version":"2022.2.0a9","releaseDate":"2022-04-01T13:23:18.7140000+03:00","stream":"Alpha"},{"version":"2021.2.18f1","releaseDate":"2022-04-01T10:28:41.0490000+03:00","stream":"Tech"},{"version":"2022.1.0b14","releaseDate":"2022-03-30T12:56:12.7250000+03:00","stream":"Beta"},{"version":"2021.2.17f1","releaseDate":"2022-03-24T23:31:28.9800000+02:00","stream":"Tech"},{"version":"2020.3.32f1","releaseDate":"2022-03-23T17:39:23.9120000+02:00","stream":"LTS"},{"version":"2019.4.37f1","releaseDate":"2022-03-22T20:47:13.8460000+02:00","stream":"LTS"},{"version":"2022.1.0b13","releaseDate":"2022-03-22T19:02:39.2100000+02:00","stream":"Beta"},{"version":"2020.3.31f1","releaseDate":"2022-03-17T20:06:28.2220000+02:00","stream":"LTS"},{"version":"2021.2.16f1","releaseDate":"2022-03-17T19:27:16.4280000+02:00","stream":"Tech"},{"version":"2022.1.0b12","releaseDate":"2022-03-17T17:03:20.4980000+02:00","stream":"Beta"},{"version":"2021.2.15f1","releaseDate":"2022-03-11T19:03:49.6680000+02:00","stream":"Tech"},{"version":"2022.1.0b11","releaseDate":"2022-03-09T09:19:01.6160000+02:00","stream":"Beta"},{"version":"2021.2.14f1","releaseDate":"2022-03-03T19:20:56.9220000+02:00","stream":"Tech"},{"version":"2022.1.0b10","releaseDate":"2022-03-02T14:36:18.0430000+02:00","stream":"Beta"},{"version":"2020.3.30f1","releaseDate":"2022-02-24T19:26:14.6130000+02:00","stream":"LTS"},{"version":"2021.2.13f1","releaseDate":"2022-02-23T21:42:33.3400000+02:00","stream":"Tech"},{"version":"2022.1.0b9","releaseDate":"2022-02-23T15:13:56.5370000+02:00","stream":"Beta"},{"version":"2021.2.12f1","releaseDate":"2022-02-17T22:43:34.6210000+02:00","stream":"Tech"},{"version":"2019.4.36f1","releaseDate":"2022-02-17T18:41:01.3940000+02:00","stream":"LTS"},{"version":"2020.3.29f1","releaseDate":"2022-02-17T17:59:07.5210000+02:00","stream":"LTS"},{"version":"2022.1.0b8","releaseDate":"2022-02-16T13:35:02.2220000+02:00","stream":"Beta"},{"version":"2021.2.11f1","releaseDate":"2022-02-10T19:24:35.6120000+02:00","stream":"Tech"},{"version":"2020.3.28f1","releaseDate":"2022-02-09T23:48:58.6840000+02:00","stream":"LTS"},{"version":"2022.1.0b7","releaseDate":"2022-02-08T13:39:17.9160000+02:00","stream":"Beta"},{"version":"2022.1.0b6","releaseDate":"2022-02-02T10:30:32.4120000+02:00","stream":"Beta"},{"version":"2021.2.10f1","releaseDate":"2022-02-02T00:07:17.8640000+02:00","stream":"Tech"},{"version":"2020.3.27f1","releaseDate":"2022-02-01T01:06:41.6490000+02:00","stream":"LTS"},{"version":"2019.4.35f1","releaseDate":"2022-01-28T16:26:18.8910000+02:00","stream":"LTS"},{"version":"2022.1.0b5","releaseDate":"2022-01-27T19:44:54.5310000+02:00","stream":"Beta"},{"version":"2021.2.9f1","releaseDate":"2022-01-27T19:09:54.1410000+02:00","stream":"Tech"},{"version":"2022.1.0b4","releaseDate":"2022-01-19T13:50:18.8200000+02:00","stream":"Beta"},{"version":"2020.3.26f1","releaseDate":"2022-01-13T22:29:30.1460000+02:00","stream":"LTS"},{"version":"2021.2.8f1","releaseDate":"2022-01-13T18:36:04.5530000+02:00","stream":"Tech"},{"version":"2022.1.0b3","releaseDate":"2022-01-12T14:14:48.4210000+02:00","stream":"Beta"},{"version":"2020.3.25f1","releaseDate":"2021-12-16T20:21:47.6100000+02:00","stream":"LTS"},{"version":"2021.2.7f1","releaseDate":"2021-12-16T19:44:39.8370000+02:00","stream":"Tech"},{"version":"2019.4.34f1","releaseDate":"2021-12-15T19:52:49.4210000+02:00","stream":"LTS"},{"version":"2022.1.0b2","releaseDate":"2021-12-14T20:43:17.2160000+02:00","stream":"Beta"},{"version":"2021.2.6f1","releaseDate":"2021-12-10T18:38:19.6320000+02:00","stream":"Tech"},{"version":"2022.1.0b1","releaseDate":"2021-12-08T21:49:54.8000000+02:00","stream":"Beta"},{"version":"2020.3.24f1","releaseDate":"2021-12-02T22:30:57.1110000+02:00","stream":"LTS"},{"version":"2021.2.5f1","releaseDate":"2021-12-01T18:54:28.0590000+02:00","stream":"Tech"},{"version":"2022.1.0a16","releaseDate":"2021-11-29T14:23:09.8130000+02:00","stream":"Alpha"},{"version":"2019.4.33f1","releaseDate":"2021-11-25T20:53:15.4390000+02:00","stream":"LTS"},{"version":"2021.2.4f1","releaseDate":"2021-11-25T15:45:23.5490000+02:00","stream":"Tech"},{"version":"2020.3.23f1","releaseDate":"2021-11-19T22:08:31.1420000+02:00","stream":"LTS"},{"version":"2022.1.0a15","releaseDate":"2021-11-18T14:23:33.3050000+02:00","stream":"Alpha"},{"version":"2021.2.3f1","releaseDate":"2021-11-18T13:49:58.4170000+02:00","stream":"Tech"},{"version":"2021.2.2f1","releaseDate":"2021-11-11T13:54:38.2890000+02:00","stream":"Tech"},{"version":"2020.3.22f1","releaseDate":"2021-11-05T21:35:33.6640000+02:00","stream":"LTS"},{"version":"2021.1.28f1","releaseDate":"2021-11-04T21:43:00.6120000+02:00","stream":"Tech"},{"version":"2021.2.1f1","releaseDate":"2021-11-04T14:14:00.1790000+02:00","stream":"Tech"},{"version":"2019.4.32f1","releaseDate":"2021-10-28T19:49:13.4530000+03:00","stream":"LTS"},{"version":"2022.1.0a13","releaseDate":"2021-10-28T17:30:14.4590000+03:00","stream":"Alpha"},{"version":"2021.1.27f1","releaseDate":"2021-10-25T22:24:00.3960000+03:00","stream":"Tech"},{"version":"2021.2.0f1","releaseDate":"2021-10-25T17:52:13.0340000+03:00","stream":"Tech"},{"version":"2020.3.21f1","releaseDate":"2021-10-21T19:33:29.3350000+03:00","stream":"LTS"},{"version":"2021.1.26f1","releaseDate":"2021-10-20T18:42:50.4910000+03:00","stream":"Tech"},{"version":"2021.1.25f1","releaseDate":"2021-10-15T00:35:29.3880000+03:00","stream":"Tech"},{"version":"2022.1.0a12","releaseDate":"2021-10-13T22:34:46.2550000+03:00","stream":"Alpha"},{"version":"2021.2.0b16","releaseDate":"2021-10-12T19:42:06.0710000+03:00","stream":"Beta"},{"version":"2020.3.20f1","releaseDate":"2021-10-08T19:38:35.5420000+03:00","stream":"LTS"},{"version":"2021.1.24f1","releaseDate":"2021-10-06T21:29:11.4340000+03:00","stream":"Tech"},{"version":"2022.1.0a11","releaseDate":"2021-10-06T18:14:18.1140000+03:00","stream":"Alpha"},{"version":"2021.2.0b15","releaseDate":"2021-10-06T12:13:13.6910000+03:00","stream":"Beta"},{"version":"2022.1.0a10","releaseDate":"2021-10-01T22:35:39.3300000+03:00","stream":"Alpha"},{"version":"2021.2.0b14","releaseDate":"2021-10-01T14:27:08.4200000+03:00","stream":"Beta"},{"version":"2021.1.23f1","releaseDate":"2021-09-30T20:01:27.1780000+03:00","stream":"Tech"},{"version":"2019.4.31f1","releaseDate":"2021-09-30T19:11:12.7000000+03:00","stream":"LTS"},{"version":"2022.1.0a9","releaseDate":"2021-09-23T19:24:52.9250000+03:00","stream":"Alpha"},{"version":"2020.3.19f1","releaseDate":"2021-09-23T00:58:37.4230000+03:00","stream":"LTS"},{"version":"2021.2.0b13","releaseDate":"2021-09-22T16:58:46.5710000+03:00","stream":"Beta"},{"version":"2021.1.22f1","releaseDate":"2021-09-21T03:25:04.5570000+03:00","stream":"Tech"},{"version":"2021.2.0b12","releaseDate":"2021-09-16T14:41:11.3370000+03:00","stream":"Beta"},{"version":"2022.1.0a8","releaseDate":"2021-09-15T17:02:16.5010000+03:00","stream":"Alpha"},{"version":"2021.1.21f1","releaseDate":"2021-09-15T00:44:40.4000000+03:00","stream":"Tech"},{"version":"2020.3.18f1","releaseDate":"2021-09-09T12:35:05.2550000+03:00","stream":"LTS"},{"version":"2021.1.20f1","releaseDate":"2021-09-08T16:15:22.7130000+03:00","stream":"Tech"},{"version":"2021.2.0b11","releaseDate":"2021-09-07T14:45:52.4140000+03:00","stream":"Beta"},{"version":"2022.1.0a7","releaseDate":"2021-09-06T14:16:46.3500000+03:00","stream":"Alpha"},{"version":"2021.2.0b10","releaseDate":"2021-09-04T04:54:50.1580000+03:00","stream":"Beta"},{"version":"2019.4.30f1","releaseDate":"2021-09-04T01:17:29.3740000+03:00","stream":"LTS"},{"version":"2021.1.19f1","releaseDate":"2021-09-01T13:51:04.9530000+03:00","stream":"Tech"},{"version":"2020.3.17f1","releaseDate":"2021-08-25T21:28:14.2230000+03:00","stream":"LTS"},{"version":"2021.1.18f1","releaseDate":"2021-08-25T20:26:42.2380000+03:00","stream":"Tech"},{"version":"2021.2.0b9","releaseDate":"2021-08-25T14:31:02.2950000+03:00","stream":"Beta"},{"version":"2021.2.0b8","releaseDate":"2021-08-19T12:59:27.4650000+03:00","stream":"Beta"},{"version":"2021.1.17f1","releaseDate":"2021-08-13T21:37:59.3900000+03:00","stream":"Tech"},{"version":"2020.3.16f1","releaseDate":"2021-08-12T18:55:22.6880000+03:00","stream":"LTS"},{"version":"2021.2.0b7","releaseDate":"2021-08-10T13:33:56.9150000+03:00","stream":"Beta"},{"version":"2021.2.0b6","releaseDate":"2021-08-04T16:24:08.9160000+03:00","stream":"Beta"},{"version":"2021.2.0b5","releaseDate":"2021-08-02T18:15:23.1620000+03:00","stream":"Beta"},{"version":"2021.1.16f1","releaseDate":"2021-08-02T17:27:00.4890000+03:00","stream":"Tech"},{"version":"2020.3.15f2","releaseDate":"2021-07-30T19:23:30.2390000+03:00","stream":"LTS"},{"version":"2019.4.29f1","releaseDate":"2021-07-30T18:19:33.1520000+03:00","stream":"LTS"},{"version":"2021.2.0b4","releaseDate":"2021-07-15T13:53:43.7390000+03:00","stream":"Beta"},{"version":"2021.1.15f1","releaseDate":"2021-07-14T14:13:58.1820000+03:00","stream":"Tech"},{"version":"2020.3.14f1","releaseDate":"2021-07-13T19:58:10.4910000+03:00","stream":"LTS"},{"version":"2021.2.0b3","releaseDate":"2021-07-08T13:47:42.2000000+03:00","stream":"Beta"},{"version":"2021.1.14f1","releaseDate":"2021-07-07T04:08:43.8360000+03:00","stream":"Tech"},{"version":"2021.2.0b2","releaseDate":"2021-07-02T16:15:04.4120000+03:00","stream":"Beta"},{"version":"2020.3.13f1","releaseDate":"2021-06-30T21:40:12.8800000+03:00","stream":"LTS"},{"version":"2021.1.13f1","releaseDate":"2021-06-30T08:59:29.1870000+03:00","stream":"Tech"},{"version":"2021.2.0b1","releaseDate":"2021-06-18T22:27:35.5390000+03:00","stream":"Beta"},{"version":"2018.4.36f1","releaseDate":"2021-06-17T19:13:54.0080000+03:00","stream":"LTS"},{"version":"2021.1.12f1","releaseDate":"2021-06-17T18:00:50.5720000+03:00","stream":"Tech"},{"version":"2020.3.12f1","releaseDate":"2021-06-15T21:58:12.2770000+03:00","stream":"LTS"},{"version":"2021.2.0a21","releaseDate":"2021-06-15T19:37:53.0380000+03:00","stream":"Alpha"},{"version":"2021.1.11f1","releaseDate":"2021-06-10T13:04:24.2960000+03:00","stream":"Tech"},{"version":"2021.2.0a20","releaseDate":"2021-06-09T20:17:01.4260000+03:00","stream":"Alpha"},{"version":"2019.4.28f1","releaseDate":"2021-06-03T20:50:56.4390000+03:00","stream":"LTS"},{"version":"2021.1.10f1","releaseDate":"2021-06-03T19:53:09.2760000+03:00","stream":"Tech"},{"version":"2021.2.0a19","releaseDate":"2021-06-03T18:19:41.9870000+03:00","stream":"Alpha"},{"version":"2020.3.11f1","releaseDate":"2021-06-01T20:44:03.0610000+03:00","stream":"LTS"},{"version":"2021.1.9f1","releaseDate":"2021-05-28T15:13:35.9700000+03:00","stream":"Tech"},{"version":"2020.3.10f1","releaseDate":"2021-05-26T21:08:15.2460000+03:00","stream":"LTS"},{"version":"2019.4.27f1","releaseDate":"2021-05-20T16:45:43.0950000+03:00","stream":"LTS"},{"version":"2020.3.9f1","releaseDate":"2021-05-19T20:45:38.0840000+03:00","stream":"LTS"},{"version":"2021.1.7f1","releaseDate":"2021-05-13T17:00:02.5350000+03:00","stream":"Tech"},{"version":"2020.3.8f1","releaseDate":"2021-05-12T23:50:34.7750000+03:00","stream":"LTS"},{"version":"2021.2.0a17","releaseDate":"2021-05-12T21:15:13.4370000+03:00","stream":"Alpha"},{"version":"2018.4.35f1","releaseDate":"2021-05-12T18:16:04.9960000+03:00","stream":"LTS"},{"version":"2021.1.6f1","releaseDate":"2021-05-06T09:42:44.3860000+03:00","stream":"Tech"},{"version":"2019.4.26f1","releaseDate":"2021-05-05T21:28:43.0280000+03:00","stream":"LTS"},{"version":"2020.3.7f1","releaseDate":"2021-05-05T20:05:58.3680000+03:00","stream":"LTS"},{"version":"2021.2.0a16","releaseDate":"2021-05-05T18:00:27.2340000+03:00","stream":"Alpha"},{"version":"2020.3.6f1","releaseDate":"2021-04-28T21:33:45.0410000+03:00","stream":"LTS"},{"version":"2021.2.0a15","releaseDate":"2021-04-28T19:51:06.5220000+03:00","stream":"Alpha"},{"version":"2021.1.5f1","releaseDate":"2021-04-28T14:57:22.3140000+03:00","stream":"Tech"},{"version":"2019.4.25f1","releaseDate":"2021-04-22T21:56:19.4680000+03:00","stream":"LTS"},{"version":"2021.1.4f1","releaseDate":"2021-04-22T11:14:16.9190000+03:00","stream":"Tech"},{"version":"2021.2.0a14","releaseDate":"2021-04-21T19:58:34.0620000+03:00","stream":"Alpha"},{"version":"2020.3.5f1","releaseDate":"2021-04-21T18:58:44.8310000+03:00","stream":"LTS"},{"version":"2018.4.34f1","releaseDate":"2021-04-15T13:28:39.0470000+03:00","stream":"LTS"},{"version":"2021.2.0a13","releaseDate":"2021-04-14T19:07:25.9350000+03:00","stream":"Alpha"},{"version":"2020.3.4f1","releaseDate":"2021-04-13T20:59:16.5940000+03:00","stream":"LTS"},{"version":"2021.1.3f1","releaseDate":"2021-04-13T14:23:53.3800000+03:00","stream":"Tech"},{"version":"2019.4.24f1","releaseDate":"2021-04-09T02:33:06.9090000+03:00","stream":"LTS"},{"version":"2020.3.3f1","releaseDate":"2021-04-07T19:37:40.6130000+03:00","stream":"LTS"},{"version":"2021.1.2f1","releaseDate":"2021-04-07T17:35:36.8280000+03:00","stream":"Tech"},{"version":"2021.2.0a12","releaseDate":"2021-04-06T19:40:54.7470000+03:00","stream":"Alpha"},{"version":"2021.2.0a11","releaseDate":"2021-03-31T20:48:42.9770000+03:00","stream":"Alpha"},{"version":"2021.1.1f1","releaseDate":"2021-03-31T17:04:08.0250000+03:00","stream":"Tech"},{"version":"2020.3.2f1","releaseDate":"2021-03-29T21:24:30.6840000+03:00","stream":"LTS"},{"version":"2021.2.0a10","releaseDate":"2021-03-24T22:41:29.4570000+02:00","stream":"Alpha"},{"version":"2018.4.33f1","releaseDate":"2021-03-24T19:48:21.9510000+02:00","stream":"LTS"},{"version":"2019.4.23f1","releaseDate":"2021-03-24T18:44:56.5610000+02:00","stream":"LTS"},{"version":"2020.3.1f1","releaseDate":"2021-03-22T20:05:51.7280000+02:00","stream":"LTS"},{"version":"2021.1.0f1","releaseDate":"2021-03-22T13:13:57.9050000+02:00","stream":"Tech"},{"version":"2021.2.0a9","releaseDate":"2021-03-17T20:02:06.9710000+02:00","stream":"Alpha"},{"version":"2021.1.0b12","releaseDate":"2021-03-17T13:21:39.6870000+02:00","stream":"Beta"},{"version":"2020.3.0f1","releaseDate":"2021-03-11T01:09:00.0190000+02:00","stream":"LTS"},{"version":"2021.1.0b11","releaseDate":"2021-03-10T20:19:22.0910000+02:00","stream":"Beta"},{"version":"2019.4.22f1","releaseDate":"2021-03-10T18:07:28.3010000+02:00","stream":"LTS"},{"version":"2021.2.0a8","releaseDate":"2021-03-09T17:39:33.3380000+02:00","stream":"Alpha"},{"version":"2021.1.0b10","releaseDate":"2021-03-04T19:23:44.8170000+02:00","stream":"Beta"},{"version":"2020.2.7f1","releaseDate":"2021-03-04T18:43:17.8170000+02:00","stream":"LTS"},{"version":"2021.2.0a6","releaseDate":"2021-02-24T20:59:57.2080000+02:00","stream":"Alpha"},{"version":"2021.1.0b8","releaseDate":"2021-02-24T19:47:25.5060000+02:00","stream":"Beta"},{"version":"2019.4.21f1","releaseDate":"2021-02-24T19:14:33.4900000+02:00","stream":"LTS"},{"version":"2020.2.6f1","releaseDate":"2021-02-24T02:10:19.4960000+02:00","stream":"LTS"},{"version":"2020.2.5f1","releaseDate":"2021-02-19T01:17:13.0170000+02:00","stream":"LTS"},{"version":"2018.4.32f1","releaseDate":"2021-02-18T14:18:22.1450000+02:00","stream":"LTS"},{"version":"2021.2.0a5","releaseDate":"2021-02-17T18:45:52.4040000+02:00","stream":"Alpha"},{"version":"2021.1.0b7","releaseDate":"2021-02-17T17:33:40.3340000+02:00","stream":"Beta"},{"version":"2020.2.4f1","releaseDate":"2021-02-12T22:14:18.5720000+02:00","stream":"LTS"},{"version":"2019.4.20f1","releaseDate":"2021-02-10T19:06:33.6840000+02:00","stream":"LTS"},{"version":"2021.1.0b6","releaseDate":"2021-02-10T17:26:16.3810000+02:00","stream":"Beta"},{"version":"2020.2.3f1","releaseDate":"2021-02-03T22:51:44.0220000+02:00","stream":"LTS"},{"version":"2021.1.0b5","releaseDate":"2021-02-03T13:02:09.2570000+02:00","stream":"Beta"},{"version":"2019.4.19f1","releaseDate":"2021-02-01T19:49:54.7260000+02:00","stream":"LTS"},{"version":"2021.1.0b4","releaseDate":"2021-01-27T14:14:30.6700000+02:00","stream":"Beta"},{"version":"2018.4.31f1","releaseDate":"2021-01-22T16:08:18.4010000+02:00","stream":"LTS"},{"version":"2020.2.2f1","releaseDate":"2021-01-21T22:41:55.7470000+02:00","stream":"LTS"},{"version":"2021.1.0b3","releaseDate":"2021-01-20T18:49:58.0860000+02:00","stream":"Beta"},{"version":"2021.1.0b2","releaseDate":"2021-01-13T17:48:52.7690000+02:00","stream":"Beta"},{"version":"2019.4.18f1","releaseDate":"2021-01-13T17:13:41.1610000+02:00","stream":"LTS"},{"version":"2020.2.1f1","releaseDate":"2020-12-23T19:32:56.7940000+02:00","stream":"LTS"},{"version":"2021.1.0b1","releaseDate":"2020-12-23T17:53:59.2550000+02:00","stream":"Beta"},{"version":"2019.4.17f1","releaseDate":"2020-12-22T17:05:02.0370000+02:00","stream":"LTS"},{"version":"2020.2.0f1","releaseDate":"2020-12-14T22:24:28.6530000+02:00","stream":"LTS"},{"version":"2021.1.0a9","releaseDate":"2020-12-11T11:34:06.1400000+02:00","stream":"Alpha"},{"version":"2020.1.17f1","releaseDate":"2020-12-09T13:39:40.0550000+02:00","stream":"LTS"},{"version":"2020.2.0b14","releaseDate":"2020-12-02T19:45:40.0260000+02:00","stream":"Beta"},{"version":"2021.1.0a8","releaseDate":"2020-12-02T19:15:19.2560000+02:00","stream":"Alpha"},{"version":"2019.4.16f1","releaseDate":"2020-12-02T18:12:41.3440000+02:00","stream":"LTS"},{"version":"2018.4.30f1","releaseDate":"2020-12-01T22:09:28.0830000+02:00","stream":"LTS"},{"version":"2020.1.16f1","releaseDate":"2020-12-01T21:04:30.3740000+02:00","stream":"LTS"},{"version":"2021.1.0a7","releaseDate":"2020-11-25T20:59:24.1580000+02:00","stream":"Alpha"},{"version":"2020.2.0b13","releaseDate":"2020-11-25T19:57:21.5630000+02:00","stream":"Beta"},{"version":"2020.1.15f1","releaseDate":"2020-11-25T13:32:56.2470000+02:00","stream":"LTS"},{"version":"2020.2.0b12","releaseDate":"2020-11-19T20:01:22.4320000+02:00","stream":"Beta"},{"version":"2020.1.14f1","releaseDate":"2020-11-18T21:08:42.0520000+02:00","stream":"LTS"},{"version":"2019.4.15f1","releaseDate":"2020-11-18T20:02:15.0550000+02:00","stream":"LTS"},{"version":"2021.1.0a5","releaseDate":"2020-11-16T10:29:13.8620000+02:00","stream":"Alpha"},{"version":"2021.1.0a6","releaseDate":"2020-11-12T15:53:12.8280000+02:00","stream":"Alpha"},{"version":"2020.2.0b11","releaseDate":"2020-11-11T21:36:00.6590000+02:00","stream":"Beta"},{"version":"2018.4.29f1","releaseDate":"2020-11-11T12:56:28.8090000+02:00","stream":"LTS"},{"version":"2020.1.13f1","releaseDate":"2020-11-11T11:59:32.6030000+02:00","stream":"LTS"},{"version":"2019.4.14f1","releaseDate":"2020-11-05T19:37:50.1760000+02:00","stream":"LTS"},{"version":"2020.2.0b10","releaseDate":"2020-11-04T19:18:58.3930000+02:00","stream":"Beta"},{"version":"2021.1.0a4","releaseDate":"2020-11-04T13:36:41.3270000+02:00","stream":"Alpha"},{"version":"2020.1.12f1","releaseDate":"2020-11-04T13:19:05.1340000+02:00","stream":"LTS"},{"version":"2020.2.0b9","releaseDate":"2020-10-28T18:33:57.6480000+02:00","stream":"Beta"},{"version":"2020.1.11f1","releaseDate":"2020-10-28T13:19:45.3420000+02:00","stream":"LTS"},{"version":"2020.2.0b8","releaseDate":"2020-10-22T18:53:30.1610000+03:00","stream":"Beta"},{"version":"2021.1.0a2","releaseDate":"2020-10-22T13:37:27.7270000+03:00","stream":"Alpha"},{"version":"2019.4.13f1","releaseDate":"2020-10-21T17:49:14.4000000+03:00","stream":"LTS"},{"version":"2020.1.10f1","releaseDate":"2020-10-21T12:46:16.1030000+03:00","stream":"LTS"},{"version":"2020.2.0b7","releaseDate":"2020-10-15T23:12:00.7850000+03:00","stream":"Beta"},{"version":"2020.1.9f1","releaseDate":"2020-10-13T20:07:55.6420000+03:00","stream":"LTS"},{"version":"2020.2.0b6","releaseDate":"2020-10-08T20:11:41.8220000+03:00","stream":"Beta"},{"version":"2019.4.12f1","releaseDate":"2020-10-07T19:30:31.4100000+03:00","stream":"LTS"},{"version":"2020.1.8f1","releaseDate":"2020-10-06T13:51:55.4870000+03:00","stream":"LTS"},{"version":"2018.4.28f1","releaseDate":"2020-10-06T12:51:51.3680000+03:00","stream":"LTS"},{"version":"2020.2.0b5","releaseDate":"2020-10-01T20:28:10.4460000+03:00","stream":"Beta"},{"version":"2020.1.7f1","releaseDate":"2020-09-30T12:51:21.0060000+03:00","stream":"LTS"},{"version":"2020.2.0b4","releaseDate":"2020-09-28T18:04:05.0940000+03:00","stream":"Beta"},{"version":"2019.4.11f1","releaseDate":"2020-09-23T17:50:07.5230000+03:00","stream":"LTS"},{"version":"2020.1.6f1","releaseDate":"2020-09-16T13:37:08.4180000+03:00","stream":"LTS"},{"version":"2019.4.10f1","releaseDate":"2020-09-10T18:00:59.3550000+03:00","stream":"LTS"},{"version":"2020.1.5f1","releaseDate":"2020-09-10T15:29:36.7490000+03:00","stream":"LTS"},{"version":"2020.2.0b2","releaseDate":"2020-09-09T20:06:38.9020000+03:00","stream":"Beta"},{"version":"2018.4.27f1","releaseDate":"2020-09-09T12:04:26.6260000+03:00","stream":"LTS"},{"version":"2020.2.0b1","releaseDate":"2020-09-03T06:50:06.9580000+03:00","stream":"Beta"},{"version":"2020.1.4f1","releaseDate":"2020-08-27T16:54:15.2610000+03:00","stream":"LTS"},{"version":"2019.4.9f1","releaseDate":"2020-08-26T18:12:20.1780000+03:00","stream":"LTS"},{"version":"2020.1.3f1","releaseDate":"2020-08-21T20:25:52.4300000+03:00","stream":"LTS"},{"version":"2020.2.0a21","releaseDate":"2020-08-20T19:08:48.0150000+03:00","stream":"Alpha"},{"version":"2019.4.8f1","releaseDate":"2020-08-12T16:18:43.9270000+03:00","stream":"LTS"},{"version":"2018.4.26f1","releaseDate":"2020-08-12T14:59:47.8120000+03:00","stream":"LTS"},{"version":"2020.1.2f1","releaseDate":"2020-08-12T14:11:53.6620000+03:00","stream":"LTS"},{"version":"2019.4.7f1","releaseDate":"2020-08-05T18:02:13.5720000+03:00","stream":"LTS"},{"version":"2020.1.1f1","releaseDate":"2020-08-05T12:04:55.1630000+03:00","stream":"LTS"},{"version":"2019.4.6f1","releaseDate":"2020-07-30T23:31:02.8270000+03:00","stream":"LTS"},{"version":"2020.2.0a19","releaseDate":"2020-07-28T20:12:37.1260000+03:00","stream":"Alpha"},{"version":"2019.4.5f1","releaseDate":"2020-07-23T11:08:58.2940000+03:00","stream":"LTS"},{"version":"2020.1.0f1","releaseDate":"2020-07-20T13:15:38.9490000+03:00","stream":"LTS"},{"version":"2020.2.0a18","releaseDate":"2020-07-15T18:09:32.2040000+03:00","stream":"Alpha"},{"version":"2019.4.4f1","releaseDate":"2020-07-15T17:33:21.3420000+03:00","stream":"LTS"},{"version":"2018.4.25f1","releaseDate":"2020-07-14T18:59:51.1720000+03:00","stream":"LTS"},{"version":"2020.1.0b16","releaseDate":"2020-07-14T14:16:19.7360000+03:00","stream":"Beta"},{"version":"2019.4.3f1","releaseDate":"2020-07-08T20:17:30.7430000+03:00","stream":"LTS"},{"version":"2020.1.0b15","releaseDate":"2020-07-08T16:16:36.1440000+03:00","stream":"Beta"},{"version":"2020.2.0a17","releaseDate":"2020-07-07T20:13:29.0870000+03:00","stream":"Alpha"},{"version":"2018.4.24f1","releaseDate":"2020-07-02T15:50:59.9690000+03:00","stream":"LTS"},{"version":"2019.4.2f1","releaseDate":"2020-07-01T17:31:49.6530000+03:00","stream":"LTS"},{"version":"2020.2.0a16","releaseDate":"2020-06-30T20:30:06.4050000+03:00","stream":"Alpha"},{"version":"2020.1.0b14","releaseDate":"2020-06-30T16:03:30.1650000+03:00","stream":"Beta"},{"version":"2019.4.1f1","releaseDate":"2020-06-18T17:26:11.2500000+03:00","stream":"LTS"},{"version":"2020.2.0a15","releaseDate":"2020-06-17T01:26:34.6240000+03:00","stream":"Alpha"},{"version":"2020.1.0b13","releaseDate":"2020-06-16T18:13:24.1630000+03:00","stream":"Beta"},{"version":"2020.1.0b12","releaseDate":"2020-06-09T18:59:47.8410000+03:00","stream":"Beta"},{"version":"2019.4.0f1","releaseDate":"2020-06-07T19:09:39.2440000+03:00","stream":"LTS"},{"version":"2020.1.0b11","releaseDate":"2020-06-03T11:04:41.2780000+03:00","stream":"Beta"},{"version":"2020.2.0a13","releaseDate":"2020-06-02T21:22:41.6660000+03:00","stream":"Alpha"},{"version":"2019.3.15f1","releaseDate":"2020-05-28T18:28:05.9350000+03:00","stream":"LTS"},{"version":"2020.1.0b10","releaseDate":"2020-05-27T18:18:15.7610000+03:00","stream":"Beta"},{"version":"2020.2.0a12","releaseDate":"2020-05-27T04:46:13.7030000+03:00","stream":"Alpha"},{"version":"2020.1.0b9","releaseDate":"2020-05-18T22:30:07.6160000+03:00","stream":"Beta"},{"version":"2019.3.14f1","releaseDate":"2020-05-18T22:09:15.4130000+03:00","stream":"LTS"},{"version":"2020.2.0a11","releaseDate":"2020-05-18T20:28:51.3580000+03:00","stream":"Alpha"},{"version":"2018.4.23f1","releaseDate":"2020-05-18T19:26:44.5050000+03:00","stream":"LTS"},{"version":"2017.4.40f1","releaseDate":"2020-05-18T18:54:47.5130000+03:00","stream":"LTS"},{"version":"2019.3.13f1","releaseDate":"2020-05-06T19:28:06.4310000+03:00","stream":"LTS"},{"version":"2020.2.0a10","releaseDate":"2020-05-06T17:34:37.9180000+03:00","stream":"Alpha"},{"version":"2020.1.0b8","releaseDate":"2020-05-05T19:50:03.1040000+03:00","stream":"Beta"},{"version":"2019.3.12f1","releaseDate":"2020-04-29T20:04:13.3180000+03:00","stream":"LTS"},{"version":"2020.2.0a9","releaseDate":"2020-04-28T16:42:11.9750000+03:00","stream":"Alpha"},{"version":"2020.1.0b7","releaseDate":"2020-04-28T13:12:51.1350000+03:00","stream":"Beta"},{"version":"2018.4.22f1","releaseDate":"2020-04-24T14:56:23.0650000+03:00","stream":"LTS"},{"version":"2020.1.0b6","releaseDate":"2020-04-24T00:32:23.4180000+03:00","stream":"Beta"},{"version":"2020.2.0a8","releaseDate":"2020-04-23T23:39:25.3310000+03:00","stream":"Alpha"},{"version":"2019.3.11f1","releaseDate":"2020-04-23T23:12:30.9100000+03:00","stream":"LTS"},{"version":"2019.3.10f1","releaseDate":"2020-04-16T17:51:49.2210000+03:00","stream":"LTS"},{"version":"2020.2.0a7","releaseDate":"2020-04-14T17:50:07.5570000+03:00","stream":"Alpha"},{"version":"2018.4.21f1","releaseDate":"2020-04-09T13:24:27.7520000+03:00","stream":"LTS"},{"version":"2020.1.0b5","releaseDate":"2020-04-09T12:02:00.1780000+03:00","stream":"Beta"},{"version":"2019.3.9f1","releaseDate":"2020-04-08T20:27:11.2330000+03:00","stream":"LTS"},{"version":"2019.3.8f1","releaseDate":"2020-04-06T16:35:43.6360000+03:00","stream":"LTS"},{"version":"2017.4.39f1","releaseDate":"2020-04-03T11:51:34.4000000+03:00","stream":"LTS"},{"version":"2020.1.0b4","releaseDate":"2020-04-01T12:27:53.0680000+03:00","stream":"Beta"},{"version":"2019.3.7f1","releaseDate":"2020-03-26T15:25:09.7460000+02:00","stream":"LTS"},{"version":"2018.4.20f1","releaseDate":"2020-03-26T14:30:57.8620000+02:00","stream":"LTS"},{"version":"2020.1.0b3","releaseDate":"2020-03-26T10:40:28.9370000+02:00","stream":"Beta"},{"version":"2017.4.38f1","releaseDate":"2020-03-20T12:06:20.6150000+02:00","stream":"LTS"},{"version":"2019.3.6f1","releaseDate":"2020-03-19T15:48:25.4900000+02:00","stream":"LTS"},{"version":"2020.1.0b2","releaseDate":"2020-03-18T13:35:10.1890000+02:00","stream":"Beta"},{"version":"2018.4.19f1","releaseDate":"2020-03-13T12:43:07.0330000+02:00","stream":"LTS"},{"version":"2019.3.5f1","releaseDate":"2020-03-12T15:37:50.3680000+02:00","stream":"LTS"},{"version":"2020.1.0b1","releaseDate":"2020-03-11T14:36:55.5980000+02:00","stream":"Beta"},{"version":"2019.3.4f1","releaseDate":"2020-03-06T12:05:37.8940000+02:00","stream":"LTS"},{"version":"2020.1.0a25","releaseDate":"2020-02-27T14:18:33.9680000+02:00","stream":"Alpha"},{"version":"2018.4.18f1","releaseDate":"2020-02-27T13:32:09.7550000+02:00","stream":"LTS"},{"version":"2019.3.3f1","releaseDate":"2020-02-26T15:41:18.4700000+02:00","stream":"LTS"},{"version":"2020.1.0a24","releaseDate":"2020-02-21T12:47:26.5020000+02:00","stream":"Alpha"},{"version":"2019.3.2f1","releaseDate":"2020-02-19T18:29:42.6760000+02:00","stream":"LTS"},{"version":"2017.4.37f1","releaseDate":"2020-02-18T18:24:58.6090000+02:00","stream":"LTS"},{"version":"2020.1.0a23","releaseDate":"2020-02-12T17:20:34.1120000+02:00","stream":"Alpha"},{"version":"2019.3.1f1","releaseDate":"2020-02-12T15:41:59.0190000+02:00","stream":"LTS"},{"version":"2018.4.17f1","releaseDate":"2020-02-11T13:48:12.9240000+02:00","stream":"LTS"},{"version":"2019.2.21f1","releaseDate":"2020-02-08T01:29:05.9630000+02:00","stream":"LTS"},{"version":"2020.1.0a22","releaseDate":"2020-02-05T12:35:10.0980000+02:00","stream":"Alpha"},{"version":"2019.2.20f1","releaseDate":"2020-01-31T15:52:30.5640000+02:00","stream":"LTS"},{"version":"2020.1.0a21","releaseDate":"2020-01-30T13:45:07.1640000+02:00","stream":"Alpha"},{"version":"2018.4.16f1","releaseDate":"2020-01-27T16:58:33.6030000+02:00","stream":"LTS"},{"version":"2019.3.0f6","releaseDate":"2020-01-27T14:06:56.5750000+02:00","stream":"LTS"},{"version":"2020.1.0a20","releaseDate":"2020-01-23T12:37:53.2280000+02:00","stream":"Alpha"},{"version":"2019.2.19f1","releaseDate":"2020-01-22T21:01:38.0230000+02:00","stream":"LTS"},{"version":"2020.1.0a19","releaseDate":"2020-01-16T13:54:15.4740000+02:00","stream":"Alpha"},{"version":"2019.2.18f1","releaseDate":"2020-01-16T01:24:20.6510000+02:00","stream":"LTS"},{"version":"2019.3.0f5","releaseDate":"2020-01-13T19:38:10.2010000+02:00","stream":"LTS"},{"version":"2017.4.36f1","releaseDate":"2020-01-09T16:49:31.0200000+02:00","stream":"LTS"},{"version":"2018.4.15f1","releaseDate":"2020-01-09T16:09:30.0590000+02:00","stream":"LTS"},{"version":"2020.1.0a18","releaseDate":"2020-01-08T13:28:04.1620000+02:00","stream":"Alpha"},{"version":"2020.1.0a17","releaseDate":"2019-12-19T12:21:05.7530000+02:00","stream":"Alpha"},{"version":"2019.2.17f1","releaseDate":"2019-12-18T21:20:41.5950000+02:00","stream":"LTS"},{"version":"2019.2.16f1","releaseDate":"2019-12-13T20:41:32.6580000+02:00","stream":"LTS"},{"version":"2020.1.0a16","releaseDate":"2019-12-12T16:47:22.9460000+02:00","stream":"Alpha"},{"version":"2019.3.0f3","releaseDate":"2019-12-11T22:34:41.7010000+02:00","stream":"LTS"},{"version":"2018.4.14f1","releaseDate":"2019-12-10T13:15:45.5800000+02:00","stream":"LTS"},{"version":"2017.4.35f1","releaseDate":"2019-12-06T16:49:43.1000000+02:00","stream":"LTS"},{"version":"2020.1.0a15","releaseDate":"2019-12-06T12:23:44.0090000+02:00","stream":"Alpha"},{"version":"2019.2.15f1","releaseDate":"2019-12-04T21:50:05.0710000+02:00","stream":"LTS"},{"version":"2019.2.14f1","releaseDate":"2019-11-27T20:40:20.1350000+02:00","stream":"LTS"},{"version":"2019.3.0f1","releaseDate":"2019-11-27T18:46:18.6920000+02:00","stream":"LTS"},{"version":"2019.3.0b12","releaseDate":"2019-11-21T22:46:51.9600000+02:00","stream":"Beta"},{"version":"2020.1.0a14","releaseDate":"2019-11-21T19:18:32.5570000+02:00","stream":"Alpha"},{"version":"2018.4.13f1","releaseDate":"2019-11-21T17:42:03.5440000+02:00","stream":"LTS"},{"version":"2019.2.13f1","releaseDate":"2019-11-20T19:22:07.1550000+02:00","stream":"LTS"},{"version":"2020.1.0a13","releaseDate":"2019-11-15T14:47:40.5570000+02:00","stream":"Alpha"},{"version":"2019.3.0b11","releaseDate":"2019-11-14T23:50:47.1120000+02:00","stream":"Beta"},{"version":"2019.2.12f1","releaseDate":"2019-11-11T20:38:24.9000000+02:00","stream":"LTS"},{"version":"2020.1.0a12","releaseDate":"2019-11-08T12:46:31.2520000+02:00","stream":"Alpha"},{"version":"2019.3.0b10","releaseDate":"2019-11-06T19:42:42.1640000+02:00","stream":"Beta"},{"version":"2019.3.0b9","releaseDate":"2019-11-01T18:37:43.0620000+02:00","stream":"Beta"},{"version":"2019.2.11f1","releaseDate":"2019-11-01T14:01:07.4740000+02:00","stream":"LTS"},{"version":"2020.1.0a11","releaseDate":"2019-10-31T18:32:46.5520000+02:00","stream":"Alpha"},{"version":"2017.4.34f1","releaseDate":"2019-10-30T19:20:05.4810000+02:00","stream":"LTS"},{"version":"2018.4.12f1","releaseDate":"2019-10-28T13:35:32.8840000+02:00","stream":"LTS"},{"version":"2019.2.10f1","releaseDate":"2019-10-24T00:46:43.5750000+03:00","stream":"LTS"},{"version":"2019.3.0b8","releaseDate":"2019-10-23T20:20:42.4990000+03:00","stream":"Beta"},{"version":"2020.1.0a9","releaseDate":"2019-10-17T13:21:00.0530000+03:00","stream":"Alpha"},{"version":"2019.3.0b7","releaseDate":"2019-10-14T20:32:52.8980000+03:00","stream":"Beta"},{"version":"2019.2.9f1","releaseDate":"2019-10-11T21:05:30.4520000+03:00","stream":"LTS"},{"version":"2018.4.11f1","releaseDate":"2019-10-10T16:08:52.3110000+03:00","stream":"LTS"},{"version":"2020.1.0a8","releaseDate":"2019-10-10T12:24:32.0630000+03:00","stream":"Alpha"},{"version":"2017.4.33f1","releaseDate":"2019-10-07T11:27:32.7430000+03:00","stream":"LTS"},{"version":"2019.3.0b6","releaseDate":"2019-10-04T19:50:37.4470000+03:00","stream":"Beta"},{"version":"2019.2.8f1","releaseDate":"2019-10-04T01:11:03.8390000+03:00","stream":"LTS"},{"version":"2020.1.0a7","releaseDate":"2019-10-01T19:22:34.3760000+03:00","stream":"Alpha"},{"version":"2018.4.10f1","releaseDate":"2019-10-01T15:06:54.8160000+03:00","stream":"LTS"},{"version":"2019.2.7f2","releaseDate":"2019-09-30T21:04:28.7120000+03:00","stream":"LTS"},{"version":"2019.3.0b5","releaseDate":"2019-09-30T17:32:45.4310000+03:00","stream":"Beta"},{"version":"2020.1.0a5","releaseDate":"2019-09-25T17:28:57.7470000+03:00","stream":"Alpha"},{"version":"2019.3.0b4","releaseDate":"2019-09-20T18:43:52.3750000+03:00","stream":"Beta"},{"version":"2019.2.6f1","releaseDate":"2019-09-17T22:29:14.5200000+03:00","stream":"LTS"},{"version":"2018.4.9f1","releaseDate":"2019-09-13T15:05:02.2970000+03:00","stream":"LTS"},{"version":"2019.2.5f1","releaseDate":"2019-09-12T18:37:27.5480000+03:00","stream":"LTS"},{"version":"2019.3.0b3","releaseDate":"2019-09-10T19:31:30.3650000+03:00","stream":"Beta"},{"version":"2019.3.0b2","releaseDate":"2019-09-06T20:16:21.5300000+03:00","stream":"Beta"},{"version":"2020.1.0a3","releaseDate":"2019-09-05T18:08:44.2560000+03:00","stream":"Alpha"},{"version":"2019.2.4f1","releaseDate":"2019-09-05T17:17:26.6680000+03:00","stream":"LTS"},{"version":"2017.4.32f1","releaseDate":"2019-09-05T14:50:38.8620000+03:00","stream":"LTS"},{"version":"2018.4.8f1","releaseDate":"2019-08-30T12:24:35.8910000+03:00","stream":"LTS"},{"version":"2019.2.3f1","releaseDate":"2019-08-28T15:57:33.7170000+03:00","stream":"LTS"},{"version":"2019.3.0b1","releaseDate":"2019-08-26T18:03:03.4490000+03:00","stream":"Beta"},{"version":"2019.2.2f1","releaseDate":"2019-08-21T13:42:41.1150000+03:00","stream":"LTS"},{"version":"2018.4.7f1","releaseDate":"2019-08-19T13:07:37.5940000+03:00","stream":"LTS"},{"version":"2019.2.1f1","releaseDate":"2019-08-14T17:28:59.0190000+03:00","stream":"LTS"},{"version":"2019.3.0a12","releaseDate":"2019-08-13T17:24:35.2560000+03:00","stream":"Alpha"},{"version":"2018.4.6f1","releaseDate":"2019-08-08T12:30:29.8390000+03:00","stream":"LTS"},{"version":"2019.1.14f1","releaseDate":"2019-08-08T12:01:21.7260000+03:00","stream":"LTS"},{"version":"2017.4.31f1","releaseDate":"2019-08-02T13:02:34.0640000+03:00","stream":"LTS"},{"version":"2019.1.13f1","releaseDate":"2019-08-01T14:12:43.9510000+03:00","stream":"LTS"},{"version":"2019.3.0a11","releaseDate":"2019-07-31T21:32:46.9870000+03:00","stream":"Alpha"},{"version":"2019.2.0f1","releaseDate":"2019-07-29T13:48:07.1340000+03:00","stream":"LTS"},{"version":"2019.1.12f1","releaseDate":"2019-07-26T16:28:16.0830000+03:00","stream":"LTS"},{"version":"2018.4.5f1","releaseDate":"2019-07-26T14:33:58.8310000+03:00","stream":"LTS"},{"version":"2019.3.0a10","releaseDate":"2019-07-22T21:03:08.9830000+03:00","stream":"Alpha"},{"version":"2019.2.0b10","releaseDate":"2019-07-18T18:39:34.1320000+03:00","stream":"Beta"},{"version":"2019.1.11f1","releaseDate":"2019-07-18T15:29:11.3370000+03:00","stream":"LTS"},{"version":"2018.4.4f1","releaseDate":"2019-07-12T19:20:22.9020000+03:00","stream":"LTS"},{"version":"2019.1.10f1","releaseDate":"2019-07-12T18:54:54.0030000+03:00","stream":"LTS"},{"version":"2019.2.0b9","releaseDate":"2019-07-11T21:56:49.6310000+03:00","stream":"Beta"},{"version":"2017.4.30f1","releaseDate":"2019-07-05T17:27:47.0610000+03:00","stream":"LTS"},{"version":"2019.1.9f1","releaseDate":"2019-07-05T14:47:29.6410000+03:00","stream":"LTS"},{"version":"2019.3.0a8","releaseDate":"2019-07-03T20:30:44.9800000+03:00","stream":"Alpha"},{"version":"2018.4.3f1","releaseDate":"2019-06-28T16:03:41.3670000+03:00","stream":"LTS"},{"version":"2019.3.0a7","releaseDate":"2019-06-26T20:12:40.6830000+03:00","stream":"Alpha"},{"version":"2019.2.0b7","releaseDate":"2019-06-25T23:47:11.2540000+03:00","stream":"Beta"},{"version":"2019.1.8f1","releaseDate":"2019-06-22T11:48:33.7900000+03:00","stream":"LTS"},{"version":"2019.3.0a6","releaseDate":"2019-06-19T06:02:44.0090000+03:00","stream":"Alpha"},{"version":"2019.1.7f1","releaseDate":"2019-06-14T18:44:01.6130000+03:00","stream":"LTS"},{"version":"2019.2.0b6","releaseDate":"2019-06-12T12:40:00.7880000+03:00","stream":"Beta"},{"version":"2017.4.29f1","releaseDate":"2019-06-08T22:03:51.2520000+03:00","stream":"LTS"},{"version":"2018.4.2f1","releaseDate":"2019-06-08T21:07:32.0460000+03:00","stream":"LTS"},{"version":"2019.1.6f1","releaseDate":"2019-06-08T19:58:35.5350000+03:00","stream":"LTS"},{"version":"2019.3.0a5","releaseDate":"2019-06-06T15:22:57.5620000+03:00","stream":"Alpha"},{"version":"2019.2.0b5","releaseDate":"2019-06-05T17:32:16.2730000+03:00","stream":"Beta"},{"version":"2019.1.5f1","releaseDate":"2019-06-03T14:40:25.5010000+03:00","stream":"LTS"},{"version":"2017.4.28f1","releaseDate":"2019-05-30T20:27:14.6810000+03:00","stream":"LTS"},{"version":"2019.3.0a4","releaseDate":"2019-05-30T17:15:42.7070000+03:00","stream":"Alpha"},{"version":"2019.2.0b4","releaseDate":"2019-05-29T20:12:13.2450000+03:00","stream":"Beta"},{"version":"2018.4.1f1","releaseDate":"2019-05-28T19:24:03.8580000+03:00","stream":"LTS"},{"version":"2019.1.4f1","releaseDate":"2019-05-24T20:57:10.7780000+03:00","stream":"LTS"},{"version":"2019.2.0b3","releaseDate":"2019-05-22T17:03:19.4450000+03:00","stream":"Beta"},{"version":"2019.3.0a3","releaseDate":"2019-05-22T14:46:55.0550000+03:00","stream":"Alpha"},{"version":"2019.1.3f1","releaseDate":"2019-05-16T17:47:53.8260000+03:00","stream":"LTS"},{"version":"2019.2.0b2","releaseDate":"2019-05-15T18:44:17.7590000+03:00","stream":"Beta"},{"version":"2019.3.0a2","releaseDate":"2019-05-10T23:36:39.2540000+03:00","stream":"Alpha"},{"version":"2019.1.2f1","releaseDate":"2019-05-10T18:59:18.5200000+03:00","stream":"LTS"},{"version":"2017.4.27f1","releaseDate":"2019-05-10T16:21:41.1350000+03:00","stream":"LTS"},{"version":"2018.4.0f1","releaseDate":"2019-05-10T14:43:31.4210000+03:00","stream":"LTS"},{"version":"2019.2.0b1","releaseDate":"2019-05-09T12:44:58.3510000+03:00","stream":"Beta"},{"version":"2019.1.1f1","releaseDate":"2019-05-03T17:43:43.5970000+03:00","stream":"LTS"},{"version":"2019.2.0a14","releaseDate":"2019-05-01T20:59:12.6880000+03:00","stream":"Alpha"},{"version":"2018.3.14f1","releaseDate":"2019-04-26T14:50:27.0450000+03:00","stream":"LTS"},{"version":"2019.2.0a13","releaseDate":"2019-04-24T20:50:21.0670000+03:00","stream":"Alpha"},{"version":"2017.4.26f1","releaseDate":"2019-04-23T12:36:49.5910000+03:00","stream":"LTS"},{"version":"2018.3.13f1","releaseDate":"2019-04-18T12:14:47.6950000+03:00","stream":"LTS"},{"version":"2019.1.0f2","releaseDate":"2019-04-15T16:28:01.4440000+03:00","stream":"LTS"},{"version":"2019.2.0a11","releaseDate":"2019-04-11T19:48:43.1840000+03:00","stream":"Alpha"},{"version":"2019.1.0f1","releaseDate":"2019-04-08T21:51:36.4080000+03:00","stream":"LTS"},{"version":"2018.3.12f1","releaseDate":"2019-04-08T17:36:53.3460000+03:00","stream":"LTS"},{"version":"2017.4.25f1","releaseDate":"2019-04-08T16:39:05.1910000+03:00","stream":"LTS"},{"version":"2019.1.0b10","releaseDate":"2019-04-03T17:15:22.3850000+03:00","stream":"Beta"},{"version":"2018.3.11f1","releaseDate":"2019-03-29T14:15:27.9350000+02:00","stream":"LTS"},{"version":"2019.1.0b9","releaseDate":"2019-03-26T18:57:04.8470000+02:00","stream":"Beta"},{"version":"2018.3.10f1","releaseDate":"2019-03-25T19:27:03.0350000+02:00","stream":"LTS"},{"version":"2017.4.24f1","releaseDate":"2019-03-22T11:39:13.6670000+02:00","stream":"LTS"},{"version":"2019.2.0a9","releaseDate":"2019-03-20T17:45:22.3090000+02:00","stream":"Alpha"},{"version":"2019.1.0b8","releaseDate":"2019-03-18T19:17:39.0930000+02:00","stream":"Beta"},{"version":"2018.3.9f1","releaseDate":"2019-03-18T14:14:09.6120000+02:00","stream":"LTS"},{"version":"2019.1.0b7","releaseDate":"2019-03-13T18:10:13.3900000+02:00","stream":"Beta"},{"version":"2019.2.0a8","releaseDate":"2019-03-13T16:22:24.9240000+02:00","stream":"Alpha"},{"version":"2017.4.23f1","releaseDate":"2019-03-08T19:28:16.4670000+02:00","stream":"LTS"},{"version":"2019.1.0b6","releaseDate":"2019-03-08T18:41:08.1330000+02:00","stream":"Beta"},{"version":"2018.3.8f1","releaseDate":"2019-03-08T18:15:08.8060000+02:00","stream":"LTS"},{"version":"2019.2.0a7","releaseDate":"2019-03-04T15:52:19.7100000+02:00","stream":"Alpha"},{"version":"2019.1.0b5","releaseDate":"2019-03-01T18:44:15.4080000+02:00","stream":"Beta"},{"version":"5.6.7f1","releaseDate":"2019-02-28T20:35:23.8950000+02:00","stream":"LTS"},{"version":"2018.2.21f1","releaseDate":"2019-02-28T19:57:55.3450000+02:00","stream":"LTS"},{"version":"2017.4.22f1","releaseDate":"2019-02-28T19:01:39.7560000+02:00","stream":"LTS"},{"version":"2018.3.7f1","releaseDate":"2019-02-28T18:07:09.1890000+02:00","stream":"LTS"},{"version":"2019.2.0a6","releaseDate":"2019-02-27T09:50:11.0870000+02:00","stream":"Alpha"},{"version":"2017.4.21f1","releaseDate":"2019-02-21T17:15:49.2140000+02:00","stream":"LTS"},{"version":"2019.1.0b4","releaseDate":"2019-02-19T18:30:33.2540000+02:00","stream":"Beta"},{"version":"2018.3.6f1","releaseDate":"2019-02-15T18:45:14.6840000+02:00","stream":"LTS"},{"version":"2019.1.0b3","releaseDate":"2019-02-11T17:22:34.4640000+02:00","stream":"Beta"},{"version":"2017.4.20f2","releaseDate":"2019-02-11T12:07:10.8110000+02:00","stream":"LTS"},{"version":"2018.3.5f1","releaseDate":"2019-02-08T17:27:29.3790000+02:00","stream":"LTS"},{"version":"2019.2.0a4","releaseDate":"2019-02-06T16:46:04.4100000+02:00","stream":"Alpha"},{"version":"2019.1.0b2","releaseDate":"2019-02-04T15:55:05.8000000+02:00","stream":"Beta"},{"version":"2018.3.4f1","releaseDate":"2019-02-01T18:49:54.5170000+02:00","stream":"LTS"},{"version":"2019.1.0b1","releaseDate":"2019-01-28T17:21:41.6220000+02:00","stream":"Beta"},{"version":"2017.4.19f1","releaseDate":"2019-01-28T16:49:20.9630000+02:00","stream":"LTS"},{"version":"2018.3.3f1","releaseDate":"2019-01-25T16:37:01.8620000+02:00","stream":"LTS"},{"version":"2018.3.2f1","releaseDate":"2019-01-17T11:18:26.5460000+02:00","stream":"LTS"},{"version":"2019.1.0a14","releaseDate":"2019-01-15T20:45:50.0540000+02:00","stream":"Alpha"},{"version":"2018.3.1f1","releaseDate":"2019-01-10T14:42:52.5380000+02:00","stream":"LTS"},{"version":"2017.4.18f1","releaseDate":"2019-01-10T13:37:33.9090000+02:00","stream":"LTS"},{"version":"2019.1.0a13","releaseDate":"2019-01-03T03:39:26.4790000+02:00","stream":"Alpha"},{"version":"2019.1.0a12","releaseDate":"2018-12-14T20:20:29.2790000+02:00","stream":"Alpha"},{"version":"2018.2.20f1","releaseDate":"2018-12-14T13:15:42.9470000+02:00","stream":"LTS"},{"version":"2018.3.0f2","releaseDate":"2018-12-12T14:02:30.5550000+02:00","stream":"LTS"},{"version":"2018.3.0f1","releaseDate":"2018-12-11T17:41:14.3820000+02:00","stream":"LTS"},{"version":"2017.2.5f1","releaseDate":"2018-12-07T20:04:37.5790000+02:00","stream":"LTS"},{"version":"2018.2.19f1","releaseDate":"2018-12-07T18:44:08.5920000+02:00","stream":"LTS"},{"version":"2017.4.17f1","releaseDate":"2018-12-07T17:51:37.3080000+02:00","stream":"LTS"},{"version":"2019.1.0a11","releaseDate":"2018-12-04T22:58:06.1280000+02:00","stream":"Alpha"},{"version":"2018.2.18f1","releaseDate":"2018-11-30T17:10:33.2730000+02:00","stream":"LTS"},{"version":"2018.3.0b12","releaseDate":"2018-11-28T14:03:56.2160000+02:00","stream":"Beta"},{"version":"2019.1.0a10","releaseDate":"2018-11-23T18:56:21.7430000+02:00","stream":"Alpha"},{"version":"2017.4.16f1","releaseDate":"2018-11-23T12:14:00.4550000+02:00","stream":"LTS"},{"version":"2018.2.17f1","releaseDate":"2018-11-21T17:28:51.6180000+02:00","stream":"LTS"},{"version":"2018.3.0b11","releaseDate":"2018-11-21T15:58:06.3430000+02:00","stream":"Beta"},{"version":"2017.2.4p1","releaseDate":"2018-11-16T12:22:37.6740000+02:00","stream":"Tech"},{"version":"2018.2.16f1","releaseDate":"2018-11-15T13:01:20.6050000+02:00","stream":"LTS"},{"version":"2019.1.0a9","releaseDate":"2018-11-14T18:08:29.5040000+02:00","stream":"Alpha"},{"version":"2018.3.0b10","releaseDate":"2018-11-14T15:35:56.4560000+02:00","stream":"Beta"},{"version":"2017.4.15f1","releaseDate":"2018-11-12T16:08:59.6070000+02:00","stream":"LTS"},{"version":"2018.2.15f1","releaseDate":"2018-11-09T12:10:19.0780000+02:00","stream":"LTS"},{"version":"2018.3.0b9","releaseDate":"2018-11-07T13:26:23.7790000+02:00","stream":"Beta"},{"version":"2019.1.0a8","releaseDate":"2018-11-07T01:07:14.7810000+02:00","stream":"Alpha"},{"version":"2019.1.0a7","releaseDate":"2018-10-31T18:36:10.7410000+02:00","stream":"Alpha"},{"version":"2018.3.0b8","releaseDate":"2018-10-31T12:43:25.5420000+02:00","stream":"Beta"},{"version":"2018.2.14f1","releaseDate":"2018-10-26T18:36:58.3850000+03:00","stream":"LTS"},{"version":"2017.4.14f1","releaseDate":"2018-10-26T14:46:14.9670000+03:00","stream":"LTS"},{"version":"2018.3.0b7","releaseDate":"2018-10-24T12:18:44.7430000+03:00","stream":"Beta"},{"version":"2018.2.13f1","releaseDate":"2018-10-18T13:04:17.7440000+03:00","stream":"LTS"},{"version":"2018.3.0b6","releaseDate":"2018-10-18T10:28:58.7650000+03:00","stream":"Beta"},{"version":"2018.2.12f1","releaseDate":"2018-10-12T17:40:28.9550000+03:00","stream":"LTS"},{"version":"2017.4.13f1","releaseDate":"2018-10-12T15:12:23.4990000+03:00","stream":"LTS"},{"version":"2018.3.0b5","releaseDate":"2018-10-10T11:17:14.4800000+03:00","stream":"Beta"},{"version":"2018.2.11f1","releaseDate":"2018-10-04T13:36:18.2630000+03:00","stream":"LTS"},{"version":"2018.3.0b4","releaseDate":"2018-10-03T14:09:35.4250000+03:00","stream":"Beta"},{"version":"2017.2.4f1","releaseDate":"2018-10-03T13:10:22.6970000+03:00","stream":"LTS"},{"version":"2017.4.12f1","releaseDate":"2018-09-27T13:54:38.6660000+03:00","stream":"LTS"},{"version":"2018.2.10f1","releaseDate":"2018-09-26T17:32:56.4460000+03:00","stream":"LTS"},{"version":"2018.3.0b3","releaseDate":"2018-09-26T16:21:30.9390000+03:00","stream":"Beta"},{"version":"2018.2.9f1","releaseDate":"2018-09-21T15:47:59.5780000+03:00","stream":"LTS"},{"version":"2018.3.0b2","releaseDate":"2018-09-20T12:44:45.6210000+03:00","stream":"Beta"},{"version":"2018.2.8f1","releaseDate":"2018-09-14T13:03:11.1630000+03:00","stream":"LTS"},{"version":"2017.4.11f1","releaseDate":"2018-09-13T12:35:24.1460000+03:00","stream":"LTS"},{"version":"2018.3.0b1","releaseDate":"2018-09-11T16:07:05.2700000+03:00","stream":"Beta"},{"version":"2018.2.7f1","releaseDate":"2018-09-06T19:34:51.1710000+03:00","stream":"LTS"},{"version":"2018.2.6f1","releaseDate":"2018-08-30T14:26:23.2890000+03:00","stream":"LTS"},{"version":"2017.2.3p4","releaseDate":"2018-08-29T16:24:14.6370000+03:00","stream":"Tech"},{"version":"2018.1.9f2","releaseDate":"2018-08-29T13:25:53.0360000+03:00","stream":"LTS"},{"version":"2017.4.10f1","releaseDate":"2018-08-24T16:44:21.5260000+03:00","stream":"LTS"},{"version":"2018.2.5f1","releaseDate":"2018-08-22T18:12:22.7900000+03:00","stream":"LTS"},{"version":"2018.2.4f1","releaseDate":"2018-08-17T17:17:08.6950000+03:00","stream":"LTS"},{"version":"2018.2.3f1","releaseDate":"2018-08-10T19:45:34.0780000+03:00","stream":"LTS"},{"version":"2017.4.9f1","releaseDate":"2018-08-10T17:27:28.1310000+03:00","stream":"LTS"},{"version":"2017.2.3p3","releaseDate":"2018-08-03T17:58:35.3170000+03:00","stream":"Tech"},{"version":"2018.2.2f1","releaseDate":"2018-08-03T16:32:08.8780000+03:00","stream":"LTS"},{"version":"2017.4.8f1","releaseDate":"2018-07-26T14:30:32.4430000+03:00","stream":"LTS"},{"version":"2018.2.1f1","releaseDate":"2018-07-26T13:43:51.5190000+03:00","stream":"LTS"},{"version":"2017.1.5f1","releaseDate":"2018-07-23T19:24:20.2750000+03:00","stream":"LTS"},{"version":"2018.1.8f1","releaseDate":"2018-07-13T16:52:59.7910000+03:00","stream":"LTS"},{"version":"2017.4.7f1","releaseDate":"2018-07-13T13:22:49.0920000+03:00","stream":"LTS"},{"version":"2018.2.0f2","releaseDate":"2018-07-09T19:46:12.1340000+03:00","stream":"LTS"},{"version":"2018.2.0f1","releaseDate":"2018-07-06T18:20:59.9000000+03:00","stream":"LTS"},{"version":"2017.2.3p2","releaseDate":"2018-07-05T17:38:35.9270000+03:00","stream":"Tech"},{"version":"2018.1.7f1","releaseDate":"2018-07-05T17:17:37.5460000+03:00","stream":"LTS"},{"version":"2018.2.0b11","releaseDate":"2018-07-03T16:34:59.1560000+03:00","stream":"Beta"},{"version":"2018.2.0b10","releaseDate":"2018-06-26T16:53:45.0430000+03:00","stream":"Beta"},{"version":"2017.4.6f1","releaseDate":"2018-06-22T11:23:54.2190000+03:00","stream":"LTS"},{"version":"2018.1.6f1","releaseDate":"2018-06-21T18:02:57.3560000+03:00","stream":"LTS"},{"version":"2017.1.4p2","releaseDate":"2018-06-20T12:46:38.0700000+03:00","stream":"Tech"},{"version":"2018.2.0b9","releaseDate":"2018-06-19T16:54:09.0660000+03:00","stream":"Beta"},{"version":"2018.1.5f1","releaseDate":"2018-06-15T15:35:07.6220000+03:00","stream":"LTS"},{"version":"2018.2.0b8","releaseDate":"2018-06-13T16:54:30.1710000+03:00","stream":"Beta"},{"version":"2017.1.4p1","releaseDate":"2018-06-13T16:31:38.3930000+03:00","stream":"Tech"},{"version":"2018.1.4f1","releaseDate":"2018-06-11T17:59:27.4260000+03:00","stream":"LTS"},{"version":"2017.4.5f1","releaseDate":"2018-06-07T12:24:13.1100000+03:00","stream":"LTS"},{"version":"2018.2.0b7","releaseDate":"2018-06-06T20:13:56.2500000+03:00","stream":"Beta"},{"version":"2018.1.3f1","releaseDate":"2018-06-04T12:52:38.3090000+03:00","stream":"LTS"},{"version":"2017.2.3p1","releaseDate":"2018-05-31T13:04:31.7460000+03:00","stream":"Tech"},{"version":"2018.2.0b6","releaseDate":"2018-05-29T17:49:22.1680000+03:00","stream":"Beta"},{"version":"2018.1.2f1","releaseDate":"2018-05-25T18:39:42.9360000+03:00","stream":"LTS"},{"version":"2018.2.0b5","releaseDate":"2018-05-24T10:21:44.1020000+03:00","stream":"Beta"},{"version":"2017.1.4f1","releaseDate":"2018-05-23T18:53:36.9910000+03:00","stream":"LTS"},{"version":"2017.4.4f1","releaseDate":"2018-05-23T18:20:18.8730000+03:00","stream":"LTS"},{"version":"2017.2.3f1","releaseDate":"2018-05-18T16:26:34.7630000+03:00","stream":"LTS"},{"version":"2018.1.1f1","releaseDate":"2018-05-18T12:56:06.0720000+03:00","stream":"LTS"},{"version":"2018.2.0b4","releaseDate":"2018-05-11T22:14:37.6770000+03:00","stream":"Beta"},{"version":"2017.4.3f1","releaseDate":"2018-05-11T17:44:04.8180000+03:00","stream":"LTS"},{"version":"5.6.6f2","releaseDate":"2018-05-08T12:03:55.4790000+03:00","stream":"LTS"},{"version":"2017.1.3p4","releaseDate":"2018-05-06T13:03:23.7480000+03:00","stream":"Tech"},{"version":"2018.2.0b3","releaseDate":"2018-05-04T03:29:00.7830000+03:00","stream":"Beta"},{"version":"2018.1.0f2","releaseDate":"2018-05-02T12:32:53.1810000+03:00","stream":"LTS"},{"version":"2017.4.2f2","releaseDate":"2018-04-30T12:57:20.7740000+03:00","stream":"LTS"},{"version":"2017.2.2p4","releaseDate":"2018-04-27T11:09:34.6590000+03:00","stream":"Tech"},{"version":"2018.1.0f1","releaseDate":"2018-04-26T17:34:43.9320000+03:00","stream":"LTS"},{"version":"2018.2.0b2","releaseDate":"2018-04-25T18:46:41.7020000+03:00","stream":"Beta"},{"version":"2018.2.0b1","releaseDate":"2018-04-18T04:14:08.2100000+03:00","stream":"Beta"},{"version":"2017.4.1f1","releaseDate":"2018-04-12T15:46:45.4370000+03:00","stream":"LTS"},{"version":"5.6.5p4","releaseDate":"2018-04-12T13:47:59.7170000+03:00","stream":"Tech"},{"version":"2017.1.3p3","releaseDate":"2018-04-06T13:32:38.6350000+03:00","stream":"Tech"},{"version":"2017.2.2p3","releaseDate":"2018-04-05T13:16:10.2630000+03:00","stream":"Tech"},{"version":"2018.1.0b13","releaseDate":"2018-03-30T13:12:24.9220000+03:00","stream":"Beta"},{"version":"2017.2.2p2","releaseDate":"2018-03-23T15:33:23.0760000+02:00","stream":"Tech"},{"version":"2018.1.0b12","releaseDate":"2018-03-23T10:03:45.3420000+02:00","stream":"Beta"},{"version":"2017.4.0f1","releaseDate":"2018-03-19T13:40:15.8330000+02:00","stream":"LTS"},{"version":"2018.1.0b11","releaseDate":"2018-03-16T15:01:57.6520000+02:00","stream":"Beta"},{"version":"5.6.5p3","releaseDate":"2018-03-16T11:45:19.3630000+02:00","stream":"Tech"},{"version":"2017.3.1p4","releaseDate":"2018-03-13T13:06:06.2160000+02:00","stream":"Tech"},{"version":"2017.2.2p1","releaseDate":"2018-03-09T17:01:16.6870000+02:00","stream":"Tech"},{"version":"2018.1.0b10","releaseDate":"2018-03-08T17:30:14.4980000+02:00","stream":"Beta"},{"version":"2017.3.1p3","releaseDate":"2018-03-06T15:00:52.2380000+02:00","stream":"Tech"},{"version":"2017.1.3p2","releaseDate":"2018-03-02T13:14:31.1230000+02:00","stream":"Tech"},{"version":"2018.1.0b9","releaseDate":"2018-02-27T22:03:39.0920000+02:00","stream":"Beta"},{"version":"2017.3.1p2","releaseDate":"2018-02-26T13:20:31.2290000+02:00","stream":"Tech"},{"version":"2017.2.2f1","releaseDate":"2018-02-26T12:56:15.2980000+02:00","stream":"LTS"},{"version":"2018.1.0b8","releaseDate":"2018-02-21T01:19:54.4560000+02:00","stream":"Beta"},{"version":"5.6.5p2","releaseDate":"2018-02-15T12:54:22.5920000+02:00","stream":"Tech"},{"version":"2017.3.1p1","releaseDate":"2018-02-14T18:32:07.5630000+02:00","stream":"Tech"},{"version":"2018.1.0b7","releaseDate":"2018-02-14T13:12:33.8400000+02:00","stream":"Beta"},{"version":"2017.2.1p4","releaseDate":"2018-02-12T15:46:02.9250000+02:00","stream":"Tech"},{"version":"2018.1.0b6","releaseDate":"2018-02-08T01:26:06.8280000+02:00","stream":"Beta"},{"version":"2017.3.1f1","releaseDate":"2018-02-05T17:31:22.3830000+02:00","stream":"LTS"},{"version":"2017.1.3p1","releaseDate":"2018-02-02T18:03:25.9430000+02:00","stream":"Tech"},{"version":"2018.1.0b5","releaseDate":"2018-01-31T14:56:51.0850000+02:00","stream":"Beta"},{"version":"2017.2.1p3","releaseDate":"2018-01-30T18:14:38.4790000+02:00","stream":"Tech"},{"version":"2017.3.0p4","releaseDate":"2018-01-29T14:43:13.4400000+02:00","stream":"Tech"},{"version":"2018.1.0b4","releaseDate":"2018-01-22T21:10:28.0890000+02:00","stream":"Beta"},{"version":"5.6.5p1","releaseDate":"2018-01-22T12:15:55.2200000+02:00","stream":"Tech"},{"version":"2017.3.0p3","releaseDate":"2018-01-18T18:39:06.6310000+02:00","stream":"Tech"},{"version":"2018.1.0b3","releaseDate":"2018-01-17T14:06:15.8980000+02:00","stream":"Beta"},{"version":"2017.3.0p2","releaseDate":"2018-01-12T20:16:05.8470000+02:00","stream":"Tech"},{"version":"5.5.6f1","releaseDate":"2018-01-12T19:52:32.0940000+02:00","stream":"LTS"},{"version":"2017.2.1p2","releaseDate":"2018-01-12T12:39:16.7060000+02:00","stream":"Tech"},{"version":"2018.1.0b2","releaseDate":"2018-01-09T17:44:00.8450000+02:00","stream":"Beta"},{"version":"2017.1.3f1","releaseDate":"2018-01-04T19:14:40.6550000+02:00","stream":"LTS"},{"version":"2017.3.0p1","releaseDate":"2017-12-22T13:42:56.1700000+02:00","stream":"Tech"},{"version":"5.6.5f1","releaseDate":"2017-12-21T13:08:15.3130000+02:00","stream":"LTS"},{"version":"2017.2.1p1","releaseDate":"2017-12-20T15:53:25.0250000+02:00","stream":"Tech"},{"version":"2017.3.0f3","releaseDate":"2017-12-18T18:24:06.3520000+02:00","stream":"LTS"},{"version":"2017.2.1f1","releaseDate":"2017-12-11T17:44:05.8030000+02:00","stream":"LTS"},{"version":"2017.3.0f2","releaseDate":"2017-12-08T18:45:52.2440000+02:00","stream":"LTS"},{"version":"2017.1.2p4","releaseDate":"2017-12-08T17:51:33.8740000+02:00","stream":"Tech"},{"version":"5.6.4p4","releaseDate":"2017-12-07T14:26:50.5400000+02:00","stream":"Tech"},{"version":"2017.2.0p4","releaseDate":"2017-12-04T12:45:02.9910000+02:00","stream":"Tech"},{"version":"2017.3.0f1","releaseDate":"2017-12-01T20:31:55.9230000+02:00","stream":"LTS"},{"version":"5.5.5p2","releaseDate":"2017-11-28T18:57:54.6100000+02:00","stream":"Tech"},{"version":"2017.3.0b11","releaseDate":"2017-11-28T17:29:29.2860000+02:00","stream":"Beta"},{"version":"2017.2.0p3","releaseDate":"2017-11-27T15:27:46.2180000+02:00","stream":"Tech"},{"version":"2017.1.2p3","releaseDate":"2017-11-21T17:57:28.2100000+02:00","stream":"Tech"},{"version":"2017.3.0b10","releaseDate":"2017-11-20T17:18:14.5740000+02:00","stream":"Beta"},{"version":"5.6.4p3","releaseDate":"2017-11-20T15:49:56.7630000+02:00","stream":"Tech"},{"version":"2017.2.0p2","releaseDate":"2017-11-15T16:24:53.1850000+02:00","stream":"Tech"},{"version":"5.6.4p2","releaseDate":"2017-11-12T21:00:26.6870000+02:00","stream":"Tech"},{"version":"2017.3.0b9","releaseDate":"2017-11-10T19:33:11.8540000+02:00","stream":"Beta"},{"version":"2017.2.0p1","releaseDate":"2017-11-06T19:18:19.4960000+02:00","stream":"Tech"},{"version":"2017.3.0b8","releaseDate":"2017-11-03T17:21:00.7540000+02:00","stream":"Beta"},{"version":"2017.3.0b7","releaseDate":"2017-10-31T17:40:56.2350000+02:00","stream":"Beta"},{"version":"2017.1.2p2","releaseDate":"2017-10-27T14:03:41.0290000+03:00","stream":"Tech"},{"version":"2017.3.0b6","releaseDate":"2017-10-24T19:13:05.0440000+03:00","stream":"Beta"},{"version":"5.6.4p1","releaseDate":"2017-10-20T11:55:09.4280000+03:00","stream":"Tech"},{"version":"2017.3.0b5","releaseDate":"2017-10-17T17:14:21.2300000+03:00","stream":"Beta"},{"version":"5.6.4f1","releaseDate":"2017-10-16T00:45:41.6100000+03:00","stream":"LTS"},{"version":"5.5.5p1","releaseDate":"2017-10-13T18:41:22.6040000+03:00","stream":"Tech"},{"version":"2017.1.2p1","releaseDate":"2017-10-13T17:36:45.0300000+03:00","stream":"Tech"},{"version":"2017.2.0f3","releaseDate":"2017-10-11T20:12:25.4710000+03:00","stream":"LTS"},{"version":"2017.1.1p4","releaseDate":"2017-10-11T01:24:40.4590000+03:00","stream":"Tech"},{"version":"2017.3.0b4","releaseDate":"2017-10-10T18:09:12.8770000+03:00","stream":"Beta"},{"version":"2017.1.2f1","releaseDate":"2017-10-06T15:44:00.5700000+03:00","stream":"LTS"},{"version":"2017.3.0b3","releaseDate":"2017-10-05T17:33:00.3650000+03:00","stream":"Beta"},{"version":"5.5.5f1","releaseDate":"2017-10-03T21:12:06.1320000+03:00","stream":"LTS"},{"version":"2017.2.0f2","releaseDate":"2017-10-02T20:53:40.3960000+03:00","stream":"LTS"},{"version":"2017.3.0b2","releaseDate":"2017-09-26T17:46:30.1710000+03:00","stream":"Beta"},{"version":"2017.1.1p3","releaseDate":"2017-09-22T19:41:25.5110000+03:00","stream":"Tech"},{"version":"2017.2.0f1","releaseDate":"2017-09-22T18:33:23.3090000+03:00","stream":"LTS"},{"version":"5.6.3p4","releaseDate":"2017-09-22T16:54:29.4830000+03:00","stream":"Tech"},{"version":"2017.3.0b1","releaseDate":"2017-09-21T16:38:59.5970000+03:00","stream":"Beta"},{"version":"5.4.6f3","releaseDate":"2017-09-20T11:37:58.9140000+03:00","stream":"LTS"},{"version":"2017.1.1p2","releaseDate":"2017-09-15T13:24:31.5570000+03:00","stream":"Tech"},{"version":"5.5.4p5","releaseDate":"2017-09-14T17:25:05.9100000+03:00","stream":"Tech"},{"version":"2017.2.0b11","releaseDate":"2017-09-12T16:31:58.6150000+03:00","stream":"Beta"},{"version":"2017.1.1p1","releaseDate":"2017-09-08T19:32:50.0560000+03:00","stream":"Tech"},{"version":"5.6.3p3","releaseDate":"2017-09-08T16:29:05.0680000+03:00","stream":"Tech"},{"version":"2017.2.0b10","releaseDate":"2017-09-04T23:19:12.8220000+03:00","stream":"Beta"},{"version":"2017.1.1f1","releaseDate":"2017-09-04T14:34:13.9350000+03:00","stream":"LTS"},{"version":"5.6.3p2","releaseDate":"2017-09-01T19:44:02.7640000+03:00","stream":"Tech"},{"version":"5.5.4p4","releaseDate":"2017-08-31T20:24:23.0240000+03:00","stream":"Tech"},{"version":"2017.2.0b9","releaseDate":"2017-08-29T18:59:23.8640000+03:00","stream":"Beta"},{"version":"2017.1.0p5","releaseDate":"2017-08-25T14:26:12.4730000+03:00","stream":"Tech"},{"version":"2017.2.0b8","releaseDate":"2017-08-18T17:33:35.1850000+03:00","stream":"Beta"},{"version":"5.3.8p2","releaseDate":"2017-08-18T13:53:50.1590000+03:00","stream":"Tech"},{"version":"5.4.5p5","releaseDate":"2017-08-18T03:06:42.9010000+03:00","stream":"Tech"},{"version":"5.5.4p3","releaseDate":"2017-08-18T00:45:42.7300000+03:00","stream":"Tech"},{"version":"5.6.3p1","releaseDate":"2017-08-17T23:56:53.9060000+03:00","stream":"Tech"},{"version":"2017.1.0p4","releaseDate":"2017-08-17T10:16:35.4780000+03:00","stream":"Tech"},{"version":"2017.2.0b7","releaseDate":"2017-08-15T20:42:22.6120000+03:00","stream":"Beta"},{"version":"2017.1.0p3","releaseDate":"2017-08-11T17:09:22.9780000+03:00","stream":"Tech"},{"version":"2017.2.0b6","releaseDate":"2017-08-09T00:09:18.9660000+03:00","stream":"Beta"},{"version":"5.6.3f1","releaseDate":"2017-08-01T20:03:58.0440000+03:00","stream":"LTS"},{"version":"2017.2.0b5","releaseDate":"2017-08-01T12:24:10.5780000+03:00","stream":"Beta"},{"version":"2017.1.0p2","releaseDate":"2017-07-27T15:04:31.4330000+03:00","stream":"Tech"},{"version":"5.5.4p2","releaseDate":"2017-07-26T14:06:59.7850000+03:00","stream":"Tech"},{"version":"5.6.2p4","releaseDate":"2017-07-21T20:06:22.5790000+03:00","stream":"Tech"},{"version":"2017.1.0p1","releaseDate":"2017-07-21T19:18:52.6830000+03:00","stream":"Tech"},{"version":"2017.2.0b4","releaseDate":"2017-07-20T19:07:24.3140000+03:00","stream":"Beta"},{"version":"5.6.2p3","releaseDate":"2017-07-17T17:54:07.4300000+03:00","stream":"Tech"},{"version":"2017.2.0b3","releaseDate":"2017-07-14T16:58:24.2490000+03:00","stream":"Beta"},{"version":"2017.1.0f3","releaseDate":"2017-07-10T14:29:48.3440000+03:00","stream":"LTS"},{"version":"2017.2.0b2","releaseDate":"2017-07-06T17:42:46.1050000+03:00","stream":"Beta"},{"version":"5.6.2p2","releaseDate":"2017-07-06T15:05:04.2550000+03:00","stream":"Tech"},{"version":"2017.1.0f2","releaseDate":"2017-07-05T21:06:25.7100000+03:00","stream":"LTS"},{"version":"5.6.2p1","releaseDate":"2017-06-29T17:08:51.3150000+03:00","stream":"Tech"},{"version":"5.4.5p4","releaseDate":"2017-06-28T14:33:16.4010000+03:00","stream":"Tech"},{"version":"2017.1.0f1","releaseDate":"2017-06-26T21:35:00.1560000+03:00","stream":"LTS"},{"version":"5.5.4p1","releaseDate":"2017-06-22T17:02:21.4330000+03:00","stream":"Tech"},{"version":"5.6.2f1","releaseDate":"2017-06-21T16:10:00.3850000+03:00","stream":"LTS"},{"version":"2017.1.0b10","releaseDate":"2017-06-19T18:48:58.2720000+03:00","stream":"Beta"},{"version":"5.6.1p4","releaseDate":"2017-06-16T18:05:31.4130000+03:00","stream":"Tech"},{"version":"5.3.8f2","releaseDate":"2017-06-13T14:42:19.0780000+03:00","stream":"LTS"},{"version":"2017.1.0b9","releaseDate":"2017-06-09T22:19:53.7480000+03:00","stream":"Beta"},{"version":"5.4.5p3","releaseDate":"2017-06-09T22:08:09.9090000+03:00","stream":"Tech"},{"version":"5.6.1p3","releaseDate":"2017-06-09T20:34:47.4540000+03:00","stream":"Tech"},{"version":"5.5.4f1","releaseDate":"2017-06-06T19:31:53.0570000+03:00","stream":"LTS"},{"version":"2017.1.0b8","releaseDate":"2017-06-02T18:43:21.3940000+03:00","stream":"Beta"},{"version":"5.6.1p2","releaseDate":"2017-06-02T13:52:12.6100000+03:00","stream":"Tech"},{"version":"5.4.5p2","releaseDate":"2017-05-29T11:25:58.9590000+03:00","stream":"Tech"},{"version":"2017.1.0b7","releaseDate":"2017-05-26T19:22:45.2060000+03:00","stream":"Beta"},{"version":"5.5.3p4","releaseDate":"2017-05-24T19:03:02.5850000+03:00","stream":"Tech"},{"version":"2017.1.0b6","releaseDate":"2017-05-19T14:33:20.6370000+03:00","stream":"Beta"},{"version":"5.6.1p1","releaseDate":"2017-05-18T15:38:02.4330000+03:00","stream":"Tech"},{"version":"2017.1.0b5","releaseDate":"2017-05-11T15:55:57.6670000+03:00","stream":"Beta"},{"version":"5.6.1f1","releaseDate":"2017-05-11T13:42:26.0420000+03:00","stream":"LTS"},{"version":"5.5.3p3","releaseDate":"2017-05-10T18:53:39.6190000+03:00","stream":"Tech"},{"version":"2017.1.0b4","releaseDate":"2017-05-08T17:47:09.7280000+03:00","stream":"Beta"},{"version":"5.6.0p4","releaseDate":"2017-05-08T15:16:30.1560000+03:00","stream":"Tech"},{"version":"2017.1.0b3","releaseDate":"2017-05-03T16:29:05.2510000+03:00","stream":"Beta"},{"version":"5.6.0p3","releaseDate":"2017-04-27T22:02:39.4410000+03:00","stream":"Tech"},{"version":"2017.1.0b2","releaseDate":"2017-04-26T16:56:42.4410000+03:00","stream":"Beta"},{"version":"5.5.3p2","releaseDate":"2017-04-25T17:57:56.6830000+03:00","stream":"Tech"},{"version":"5.6.0p2","releaseDate":"2017-04-21T23:03:49.1450000+03:00","stream":"Tech"},{"version":"5.6.0p1","releaseDate":"2017-04-18T16:49:03.9820000+03:00","stream":"Tech"},{"version":"5.5.3p1","releaseDate":"2017-04-13T18:11:15.6120000+03:00","stream":"Tech"},{"version":"2017.1.0b1","releaseDate":"2017-04-11T17:05:40.0040000+03:00","stream":"Beta"},{"version":"5.6.0f3","releaseDate":"2017-03-31T18:00:22.4860000+03:00","stream":"LTS"},{"version":"5.5.3f1","releaseDate":"2017-03-31T13:51:39.1560000+03:00","stream":"LTS"},{"version":"5.4.5p1","releaseDate":"2017-03-30T17:45:22.1890000+03:00","stream":"Tech"},{"version":"5.6.0f2","releaseDate":"2017-03-27T19:28:45.6580000+03:00","stream":"LTS"},{"version":"5.5.2p4","releaseDate":"2017-03-23T12:35:50.2430000+02:00","stream":"Tech"},{"version":"5.5.2p3","releaseDate":"2017-03-17T20:58:40.1640000+02:00","stream":"Tech"},{"version":"5.6.0f1","releaseDate":"2017-03-17T18:41:48.6380000+02:00","stream":"LTS"},{"version":"5.4.5f1","releaseDate":"2017-03-10T16:21:03.7460000+02:00","stream":"LTS"},{"version":"5.6.0b11","releaseDate":"2017-03-08T19:05:35.2990000+02:00","stream":"Beta"},{"version":"5.5.2p2","releaseDate":"2017-03-08T18:29:03.3490000+02:00","stream":"Tech"},{"version":"5.5.2p1","releaseDate":"2017-03-03T14:06:12.3730000+02:00","stream":"Tech"},{"version":"5.6.0b10","releaseDate":"2017-03-02T19:57:00.6420000+02:00","stream":"Beta"},{"version":"5.4.4p4","releaseDate":"2017-03-01T13:11:30.9140000+02:00","stream":"Tech"},{"version":"5.5.2f1","releaseDate":"2017-02-24T11:54:27.4260000+02:00","stream":"LTS"},{"version":"5.5.1p4","releaseDate":"2017-02-17T18:08:36.9750000+02:00","stream":"Tech"},{"version":"5.6.0b9","releaseDate":"2017-02-17T16:41:26.8530000+02:00","stream":"Beta"},{"version":"5.6.0b8","releaseDate":"2017-02-13T17:54:50.1120000+02:00","stream":"Beta"},{"version":"5.5.1p3","releaseDate":"2017-02-09T14:22:29.2650000+02:00","stream":"Tech"},{"version":"5.4.4p3","releaseDate":"2017-02-08T19:25:47.9670000+02:00","stream":"Tech"},{"version":"5.3.7p4","releaseDate":"2017-02-07T19:01:05.9100000+02:00","stream":"Tech"},{"version":"5.6.0b7","releaseDate":"2017-02-07T17:05:04.8950000+02:00","stream":"Beta"},{"version":"5.5.1p2","releaseDate":"2017-02-03T15:27:39.9140000+02:00","stream":"Tech"},{"version":"5.6.0b6","releaseDate":"2017-02-01T17:38:41.3800000+02:00","stream":"Beta"},{"version":"5.5.1p1","releaseDate":"2017-02-01T16:22:21.4140000+02:00","stream":"Tech"},{"version":"5.6.0b5","releaseDate":"2017-01-26T11:26:16.7750000+02:00","stream":"Beta"},{"version":"5.4.4p2","releaseDate":"2017-01-25T17:10:44.2950000+02:00","stream":"Tech"},{"version":"5.5.1f1","releaseDate":"2017-01-24T12:32:21.5040000+02:00","stream":"LTS"},{"version":"5.6.0b4","releaseDate":"2017-01-17T22:17:27.6580000+02:00","stream":"Beta"},{"version":"5.4.4p1","releaseDate":"2017-01-13T18:46:40.7580000+02:00","stream":"Tech"},{"version":"5.5.0p4","releaseDate":"2017-01-11T18:18:53.9900000+02:00","stream":"Tech"},{"version":"5.4.4f1","releaseDate":"2017-01-05T17:53:15.0500000+02:00","stream":"LTS"},{"version":"5.5.0p3","releaseDate":"2017-01-05T11:04:18.8540000+02:00","stream":"Tech"},{"version":"5.6.0b3","releaseDate":"2016-12-23T19:38:00.2460000+02:00","stream":"Beta"},{"version":"5.3.7p3","releaseDate":"2016-12-21T18:13:38.5020000+02:00","stream":"Tech"},{"version":"5.6.0b2","releaseDate":"2016-12-20T15:32:52.8740000+02:00","stream":"Beta"},{"version":"5.5.0p2","releaseDate":"2016-12-16T22:23:56.1000000+02:00","stream":"Tech"},{"version":"5.4.3p4","releaseDate":"2016-12-16T15:59:43.9270000+02:00","stream":"Tech"},{"version":"5.6.0b1","releaseDate":"2016-12-13T12:35:25.7510000+02:00","stream":"Beta"},{"version":"5.4.3p3","releaseDate":"2016-12-07T18:18:47.8600000+02:00","stream":"Tech"},{"version":"5.5.0p1","releaseDate":"2016-12-07T17:25:41.5570000+02:00","stream":"Tech"},{"version":"5.4.3p2","releaseDate":"2016-12-01T15:54:47.9540000+02:00","stream":"Tech"},{"version":"5.5.0f3","releaseDate":"2016-11-30T13:49:48.4400000+02:00","stream":"LTS"},{"version":"5.3.7p2","releaseDate":"2016-11-28T18:06:22.4430000+02:00","stream":"Tech"},{"version":"5.4.3p1","releaseDate":"2016-11-28T12:09:25.4130000+02:00","stream":"Tech"},{"version":"5.5.0f2","releaseDate":"2016-11-25T12:16:50.2830000+02:00","stream":"LTS"},{"version":"5.5.0f1","releaseDate":"2016-11-22T18:14:01.1850000+02:00","stream":"LTS"},{"version":"5.4.3f1","releaseDate":"2016-11-17T14:51:02.0260000+02:00","stream":"LTS"},{"version":"5.3.7p1","releaseDate":"2016-11-11T17:32:03.0220000+02:00","stream":"Tech"},{"version":"5.5.0b11","releaseDate":"2016-11-09T20:04:57.2170000+02:00","stream":"Beta"},{"version":"5.5.0b10","releaseDate":"2016-11-09T17:40:05.1770000+02:00","stream":"Beta"},{"version":"5.4.2p4","releaseDate":"2016-11-09T14:35:14.5410000+02:00","stream":"Tech"},{"version":"5.3.7f1","releaseDate":"2016-11-08T15:22:26.8980000+02:00","stream":"LTS"},{"version":"5.4.2p3","releaseDate":"2016-11-02T17:35:46.0380000+02:00","stream":"Tech"},{"version":"5.4.2p2","releaseDate":"2016-10-28T15:33:11.6310000+03:00","stream":"Tech"},{"version":"5.4.2p1","releaseDate":"2016-10-24T18:58:28.0140000+03:00","stream":"Tech"},{"version":"5.5.0b9","releaseDate":"2016-10-24T18:06:57.1480000+03:00","stream":"Beta"},{"version":"5.3.6p8","releaseDate":"2016-10-24T17:31:38.0530000+03:00","stream":"Tech"},{"version":"5.4.2f2","releaseDate":"2016-10-21T12:41:39.1710000+03:00","stream":"LTS"},{"version":"5.5.0b8","releaseDate":"2016-10-20T16:10:07.3480000+03:00","stream":"Beta"},{"version":"5.5.0b7","releaseDate":"2016-10-11T17:19:07.1390000+03:00","stream":"Beta"},{"version":"5.3.6p7","releaseDate":"2016-10-07T15:14:33.7940000+03:00","stream":"Tech"},{"version":"5.4.1p4","releaseDate":"2016-10-05T19:04:22.6090000+03:00","stream":"Tech"},{"version":"5.5.0b6","releaseDate":"2016-10-03T19:33:15.7800000+03:00","stream":"Beta"},{"version":"5.4.1p3","releaseDate":"2016-09-28T17:50:34.1120000+03:00","stream":"Tech"},{"version":"5.5.0b5","releaseDate":"2016-09-27T11:31:35.7680000+03:00","stream":"Beta"},{"version":"5.3.6p6","releaseDate":"2016-09-23T13:03:44.0380000+03:00","stream":"Tech"},{"version":"5.4.1p2","releaseDate":"2016-09-22T21:37:12.2160000+03:00","stream":"Tech"},{"version":"5.5.0b4","releaseDate":"2016-09-19T18:28:43.2030000+03:00","stream":"Beta"},{"version":"5.3.6p5","releaseDate":"2016-09-16T10:03:24.6470000+03:00","stream":"Tech"},{"version":"5.4.1p1","releaseDate":"2016-09-15T14:18:34.2100000+03:00","stream":"Tech"},{"version":"5.5.0b3","releaseDate":"2016-09-12T16:01:26.0040000+03:00","stream":"Beta"},{"version":"5.4.1f1","releaseDate":"2016-09-07T14:02:30.4590000+03:00","stream":"LTS"},{"version":"5.5.0b2","releaseDate":"2016-09-05T17:30:09.8380000+03:00","stream":"Beta"},{"version":"5.3.6p4","releaseDate":"2016-09-02T17:39:02.8790000+03:00","stream":"Tech"},{"version":"5.4.0p4","releaseDate":"2016-08-31T18:12:19.9330000+03:00","stream":"Tech"},{"version":"5.5.0b1","releaseDate":"2016-08-30T01:26:28.1480000+03:00","stream":"Beta"},{"version":"5.4.0p3","releaseDate":"2016-08-25T19:23:33.9710000+03:00","stream":"Tech"},{"version":"5.3.6p3","releaseDate":"2016-08-23T18:52:41.7170000+03:00","stream":"Tech"},{"version":"5.4.0p2","releaseDate":"2016-08-18T18:13:53.4540000+03:00","stream":"Tech"},{"version":"5.4.0p1","releaseDate":"2016-08-11T19:41:23.0620000+03:00","stream":"Tech"},{"version":"5.3.6p2","releaseDate":"2016-08-03T16:49:58.6420000+03:00","stream":"Tech"},{"version":"5.4.0f3","releaseDate":"2016-07-27T18:33:32.0650000+03:00","stream":"LTS"},{"version":"5.3.6p1","releaseDate":"2016-07-27T16:49:40.4080000+03:00","stream":"Tech"},{"version":"5.4.0f2","releaseDate":"2016-07-21T17:37:50.4920000+03:00","stream":"LTS"},{"version":"5.3.6f1","releaseDate":"2016-07-20T12:42:16.5870000+03:00","stream":"LTS"},{"version":"5.4.0f1","releaseDate":"2016-07-14T17:14:28.9480000+03:00","stream":"LTS"},{"version":"5.3.5p8","releaseDate":"2016-07-13T15:31:43.9130000+03:00","stream":"Tech"},{"version":"5.4.0b25","releaseDate":"2016-07-11T17:27:32.5710000+03:00","stream":"Beta"},{"version":"5.3.5p7","releaseDate":"2016-07-08T12:46:28.2840000+03:00","stream":"Tech"},{"version":"5.4.0b24","releaseDate":"2016-07-01T18:47:18.2330000+03:00","stream":"Beta"},{"version":"5.3.5p6","releaseDate":"2016-06-29T19:20:44.0350000+03:00","stream":"Tech"},{"version":"5.4.0b23","releaseDate":"2016-06-28T14:35:44.6560000+03:00","stream":"Beta"},{"version":"5.4.0b22","releaseDate":"2016-06-20T12:50:01.9180000+03:00","stream":"Beta"},{"version":"5.3.5p5","releaseDate":"2016-06-20T11:56:54.1950000+03:00","stream":"Tech"},{"version":"5.3.5p4","releaseDate":"2016-06-20T11:17:44.2570000+03:00","stream":"Tech"},{"version":"5.3.5p3","releaseDate":"2016-06-10T12:28:48.9900000+03:00","stream":"Tech"},{"version":"5.4.0b21","releaseDate":"2016-06-09T13:10:18.5030000+03:00","stream":"Beta"},{"version":"5.1.5f1","releaseDate":"2016-06-06T14:04:12.1990000+03:00","stream":"LTS"},{"version":"5.3.5p2","releaseDate":"2016-06-03T17:52:11.1590000+03:00","stream":"Tech"},{"version":"5.4.0b20","releaseDate":"2016-06-03T16:53:41.3450000+03:00","stream":"Beta"},{"version":"5.2.5f1","releaseDate":"2016-06-01T14:51:51.5940000+03:00","stream":"LTS"},{"version":"5.3.5p1","releaseDate":"2016-05-31T10:40:56.6820000+03:00","stream":"Tech"},{"version":"5.4.0b19","releaseDate":"2016-05-25T12:23:12.8120000+03:00","stream":"Beta"},{"version":"5.4.0b18","releaseDate":"2016-05-19T18:44:13.0190000+03:00","stream":"Beta"},{"version":"5.3.5f1","releaseDate":"2016-05-19T18:29:29.7780000+03:00","stream":"LTS"},{"version":"5.3.4p6","releaseDate":"2016-05-06T18:28:15.3400000+03:00","stream":"Tech"},{"version":"5.4.0b17","releaseDate":"2016-05-04T01:24:49.7340000+03:00","stream":"Beta"},{"version":"5.3.4p5","releaseDate":"2016-04-27T18:20:06.9680000+03:00","stream":"Tech"},{"version":"5.4.0b16","releaseDate":"2016-04-27T14:25:25.9450000+03:00","stream":"Beta"},{"version":"5.3.4p4","releaseDate":"2016-04-20T13:50:41.9420000+03:00","stream":"Tech"},{"version":"5.4.0b15","releaseDate":"2016-04-18T13:10:26.2100000+03:00","stream":"Beta"},{"version":"5.3.4p3","releaseDate":"2016-04-13T13:24:45.5350000+03:00","stream":"Tech"},{"version":"5.4.0b14","releaseDate":"2016-04-11T14:55:25.2850000+03:00","stream":"Beta"},{"version":"5.3.4p2","releaseDate":"2016-04-08T16:41:06.6810000+03:00","stream":"Tech"},{"version":"5.4.0b13","releaseDate":"2016-04-04T12:27:37.0640000+03:00","stream":"Beta"},{"version":"5.4.0b12","releaseDate":"2016-03-29T19:39:18.7120000+03:00","stream":"Beta"},{"version":"5.3.4p1","releaseDate":"2016-03-24T00:30:26.0740000+02:00","stream":"Tech"},{"version":"5.4.0b11","releaseDate":"2016-03-21T13:52:03.7650000+02:00","stream":"Beta"},{"version":"5.4.0b10","releaseDate":"2016-03-15T15:45:23.9730000+02:00","stream":"Beta"},{"version":"5.3.4f1","releaseDate":"2016-03-15T15:33:58.4510000+02:00","stream":"LTS"},{"version":"5.3.3p3","releaseDate":"2016-03-14T19:48:02.2170000+02:00","stream":"Tech"},{"version":"5.4.0b9","releaseDate":"2016-03-08T12:03:52.2650000+02:00","stream":"Beta"},{"version":"5.3.3p2","releaseDate":"2016-03-04T18:05:49.8740000+02:00","stream":"Tech"},{"version":"5.4.0b8","releaseDate":"2016-03-02T14:14:56.5970000+02:00","stream":"Beta"},{"version":"5.3.3p1","releaseDate":"2016-02-24T18:53:39.5190000+02:00","stream":"Tech"},{"version":"5.3.3f1","releaseDate":"2016-02-23T14:53:03.4530000+02:00","stream":"LTS"},{"version":"5.4.0b7","releaseDate":"2016-02-22T16:29:51.4670000+02:00","stream":"Beta"},{"version":"5.3.2p4","releaseDate":"2016-02-20T21:48:43.6160000+02:00","stream":"Tech"},{"version":"5.4.0b6","releaseDate":"2016-02-15T18:11:52.0550000+02:00","stream":"Beta"},{"version":"5.3.2p3","releaseDate":"2016-02-12T11:22:27.9230000+02:00","stream":"Tech"},{"version":"5.4.0b5","releaseDate":"2016-02-09T18:00:54.0100000+02:00","stream":"Beta"},{"version":"5.3.2p2","releaseDate":"2016-02-03T20:16:50.7640000+02:00","stream":"Tech"},{"version":"5.4.0b4","releaseDate":"2016-01-30T16:05:07.6350000+02:00","stream":"Beta"},{"version":"5.3.2p1","releaseDate":"2016-01-28T18:05:44.7130000+02:00","stream":"Tech"},{"version":"5.3.2f1","releaseDate":"2016-01-27T17:27:25.9430000+02:00","stream":"LTS"},{"version":"5.3.1p4","releaseDate":"2016-01-23T14:12:30.0740000+02:00","stream":"Tech"},{"version":"5.4.0b3","releaseDate":"2016-01-22T19:00:02.9810000+02:00","stream":"Beta"},{"version":"5.4.0b2","releaseDate":"2016-01-15T13:09:43.6900000+02:00","stream":"Beta"},{"version":"5.3.1p3","releaseDate":"2016-01-14T19:48:48.7310000+02:00","stream":"Tech"},{"version":"5.4.0b1","releaseDate":"2016-01-13T00:10:16.2620000+02:00","stream":"Beta"},{"version":"5.3.1p2","releaseDate":"2016-01-08T14:16:04.4350000+02:00","stream":"Tech"},{"version":"5.3.1p1","releaseDate":"2016-01-08T14:10:16.3210000+02:00","stream":"Tech"},{"version":"5.3.1f1","releaseDate":"2015-12-18T16:23:10.2740000+02:00","stream":"LTS"},{"version":"5.2.4f1","releaseDate":"2015-12-15T18:37:45.1050000+02:00","stream":"LTS"},{"version":"5.2.3p3","releaseDate":"2015-12-10T12:23:24.9490000+02:00","stream":"Tech"},{"version":"5.3.0f4","releaseDate":"2015-12-08T00:12:35.0350000+02:00","stream":"LTS"},{"version":"5.2.3p2","releaseDate":"2015-12-03T14:16:45.5710000+02:00","stream":"Tech"},{"version":"5.2.3p1","releaseDate":"2015-11-27T17:42:46.6020000+02:00","stream":"Tech"},{"version":"5.3.0f2","releaseDate":"2015-11-23T17:08:26.3310000+02:00","stream":"LTS"},{"version":"5.2.3f1","releaseDate":"2015-11-19T12:38:36.6940000+02:00","stream":"LTS"},{"version":"5.2.2p4","releaseDate":"2015-11-18T13:12:41.1430000+02:00","stream":"Tech"},{"version":"5.3.0f1","releaseDate":"2015-11-14T17:28:15.8630000+02:00","stream":"LTS"},{"version":"5.2.2p3","releaseDate":"2015-11-10T18:44:28.0350000+02:00","stream":"Tech"},{"version":"5.3.0b6","releaseDate":"2015-11-09T17:44:01.7640000+02:00","stream":"Beta"},{"version":"5.3.0b5","releaseDate":"2015-11-02T19:19:46.6150000+02:00","stream":"Beta"},{"version":"5.2.2p2","releaseDate":"2015-10-30T18:26:48.9590000+02:00","stream":"Tech"},{"version":"5.2.2p1","releaseDate":"2015-10-24T20:00:34.5130000+03:00","stream":"Tech"},{"version":"5.3.0b4","releaseDate":"2015-10-23T15:11:59.0160000+03:00","stream":"Beta"},{"version":"5.2.2f1","releaseDate":"2015-10-21T16:11:59.7920000+03:00","stream":"LTS"},{"version":"5.3.0b3","releaseDate":"2015-10-16T23:48:22.9780000+03:00","stream":"Beta"},{"version":"5.2.1p4","releaseDate":"2015-10-15T09:00:51.3200000+03:00","stream":"Tech"},{"version":"5.3.0b2","releaseDate":"2015-10-10T16:11:44.6410000+03:00","stream":"Beta"},{"version":"5.2.1p3","releaseDate":"2015-10-09T17:49:17.0510000+03:00","stream":"Tech"},{"version":"5.1.4f1","releaseDate":"2015-10-06T11:17:42.7590000+03:00","stream":"LTS"},{"version":"5.3.0b1","releaseDate":"2015-10-02T22:38:07.8510000+03:00","stream":"Beta"},{"version":"5.2.1p2","releaseDate":"2015-10-01T16:15:11.2250000+03:00","stream":"Tech"},{"version":"5.2.1p1","releaseDate":"2015-09-25T16:13:16.8560000+03:00","stream":"Tech"},{"version":"5.2.1f1","releaseDate":"2015-09-22T15:24:32.4680000+03:00","stream":"LTS"},{"version":"5.2.0p1","releaseDate":"2015-09-18T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.1.3p3","releaseDate":"2015-09-11T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.1.3p2","releaseDate":"2015-09-04T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.2.0f3","releaseDate":"2015-09-03T12:33:57.1480000+03:00","stream":"LTS"},{"version":"5.1.3p1","releaseDate":"2015-08-27T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.1.3f1","releaseDate":"2015-08-24T12:50:04.1790000+03:00","stream":"LTS"},{"version":"5.2.0f2","releaseDate":"2015-08-21T18:46:49.9960000+03:00","stream":"LTS"},{"version":"5.2.0f1","releaseDate":"2015-08-16T18:50:39.4690000+03:00","stream":"LTS"},{"version":"5.2.0b6","releaseDate":"2015-08-07T22:27:28.2000000+03:00","stream":"Beta"},{"version":"5.1.2p3","releaseDate":"2015-08-06T18:11:03.9900000+03:00","stream":"Tech"},{"version":"5.2.0b5","releaseDate":"2015-07-31T13:58:16.6300000+03:00","stream":"Beta"},{"version":"5.1.2p2","releaseDate":"2015-07-30T19:04:41.2110000+03:00","stream":"Tech"},{"version":"5.2.0b4","releaseDate":"2015-07-23T18:55:44.2700000+03:00","stream":"Beta"},{"version":"5.1.2p1","releaseDate":"2015-07-23T18:20:51.9840000+03:00","stream":"Tech"},{"version":"5.2.0b3","releaseDate":"2015-07-17T22:58:20.5700000+03:00","stream":"Beta"},{"version":"5.1.2f1","releaseDate":"2015-07-16T11:54:11.0960000+03:00","stream":"LTS"},{"version":"5.2.0b2","releaseDate":"2015-07-10T21:37:49.5390000+03:00","stream":"Beta"},{"version":"5.1.1p4","releaseDate":"2015-07-10T12:08:40.1750000+03:00","stream":"Tech"},{"version":"5.0.4f1","releaseDate":"2015-07-06T15:10:34.2300000+03:00","stream":"LTS"},{"version":"5.1.1p3","releaseDate":"2015-07-03T19:18:12.6150000+03:00","stream":"Tech"},{"version":"5.2.0b1","releaseDate":"2015-07-01T19:26:20.9210000+03:00","stream":"Beta"},{"version":"5.1.1p2","releaseDate":"2015-06-26T00:27:14.0670000+03:00","stream":"Tech"},{"version":"5.0.3p3","releaseDate":"2015-06-24T18:55:13.6440000+03:00","stream":"Tech"},{"version":"5.1.1p1","releaseDate":"2015-06-23T18:05:55.5660000+03:00","stream":"Tech"},{"version":"5.1.1f1","releaseDate":"2015-06-18T13:20:02.2470000+03:00","stream":"LTS"},{"version":"5.0.3p2","releaseDate":"2015-06-18T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.1.0p1","releaseDate":"2015-06-12T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.3p1","releaseDate":"2015-06-11T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.3f2","releaseDate":"2015-06-09T18:36:46.8690000+03:00","stream":"LTS"},{"version":"5.1.0f3","releaseDate":"2015-06-04T00:31:28.2170000+03:00","stream":"LTS"},{"version":"5.0.2p4","releaseDate":"2015-06-03T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.2p3","releaseDate":"2015-05-28T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.2p2","releaseDate":"2015-05-20T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.2p1","releaseDate":"2015-05-15T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.2f1","releaseDate":"2015-05-13T17:05:42.7910000+03:00","stream":"LTS"},{"version":"5.0.1p4","releaseDate":"2015-05-08T13:25:56.9760000+03:00","stream":"Tech"},{"version":"5.0.1p3","releaseDate":"2015-04-29T03:00:00.0000000+03:00","stream":"Tech"},{"version":"5.0.1p2","releaseDate":"2015-04-24T17:14:44.9700000+03:00","stream":"Tech"},{"version":"5.0.1p1","releaseDate":"2015-04-16T11:21:07.0000000+03:00","stream":"Tech"},{"version":"5.0.1f1","releaseDate":"2015-03-31T19:55:08.3760000+03:00","stream":"LTS"},{"version":"5.0.0p3","releaseDate":"2015-03-26T14:03:56.0680000+02:00","stream":"Tech"},{"version":"5.0.0p2","releaseDate":"2015-03-20T18:38:49.5150000+02:00","stream":"Tech"},{"version":"5.0.0p1","releaseDate":"2015-03-16T17:20:13.6040000+02:00","stream":"Tech"},{"version":"5.0.0f4","releaseDate":"2015-02-25T17:49:05.8350000+02:00","stream":"LTS"}] \ No newline at end of file diff --git a/UnityLauncherPro/ThemeEditor.xaml.cs b/UnityLauncherPro/ThemeEditor.xaml.cs index a5da45a..a6b6686 100644 --- a/UnityLauncherPro/ThemeEditor.xaml.cs +++ b/UnityLauncherPro/ThemeEditor.xaml.cs @@ -109,35 +109,47 @@ private void GridThemeColors_SelectionChanged(object sender, SelectionChangedEve private void BtnSaveTheme_Click(object sender, RoutedEventArgs e) { - var themeFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Themes"); - - if (Directory.Exists(themeFolder) == false) Directory.CreateDirectory(themeFolder); - - SaveFileDialog saveFileDialog = new SaveFileDialog(); - if (string.IsNullOrEmpty(previousSaveFileName)) - { - saveFileDialog.FileName = "custom"; - } - else + // 1) Determine the default filename (with .ini) + string defaultName = string.IsNullOrEmpty(previousSaveFileName) + ? "custom.ini" + : previousSaveFileName + ".ini"; + + // 2) Ask the helper for a safe full path + string initialFullPath = Tools.GetSafeFilePath("Themes", defaultName); + string initialDir = Path.GetDirectoryName(initialFullPath); + string initialFile = Path.GetFileNameWithoutExtension(initialFullPath); + + // 3) Configure the save dialog + var saveFileDialog = new SaveFileDialog { - saveFileDialog.FileName = previousSaveFileName; - } - saveFileDialog.DefaultExt = ".ini"; - saveFileDialog.Filter = "Theme files (.ini)|*.ini"; - saveFileDialog.InitialDirectory = themeFolder; - saveFileDialog.RestoreDirectory = true; - + FileName = initialFile, // no extension here + DefaultExt = ".ini", + Filter = "Theme files (.ini)|*.ini", + InitialDirectory = initialDir, + RestoreDirectory = true + }; + + // 4) Show and, if confirmed, write out the INI if (saveFileDialog.ShowDialog() == true) { - List iniRows = new List(); - iniRows.Add("# Created with UnityLauncherPro built-in theme editor " + DateTime.Now.ToString("dd/MM/yyyy")); + // Build INI lines + var iniRows = new List + { + "# Created with UnityLauncherPro built-in theme editor " + + DateTime.Now.ToString("dd/MM/yyyy") + }; + // original-style loop for (int i = 0; i < themeColors.Count; i++) { iniRows.Add(themeColors[i].Key + "=" + themeColors[i].Brush.ToString()); } - var themePath = saveFileDialog.FileName; + // Get the chosen path & ensure its folder exists + string themePath = saveFileDialog.FileName; previousSaveFileName = Path.GetFileNameWithoutExtension(themePath); + Directory.CreateDirectory(Path.GetDirectoryName(themePath)); + + // Write out File.WriteAllLines(themePath, iniRows); Console.WriteLine("Saved theme: " + themePath); } diff --git a/UnityLauncherPro/Tools.cs b/UnityLauncherPro/Tools.cs index 3dd3954..ff9142b 100644 --- a/UnityLauncherPro/Tools.cs +++ b/UnityLauncherPro/Tools.cs @@ -1,6 +1,7 @@ using Microsoft.Win32; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -16,7 +17,10 @@ using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; +using System.Windows.Threading; +using UnityLauncherPro.Data; using UnityLauncherPro.Helpers; +using UnityLauncherPro.Properties; namespace UnityLauncherPro { @@ -24,6 +28,8 @@ public static class Tools { const int SW_RESTORE = 9; + static readonly string initFileDefaultURL = "https://raw.githubusercontent.com/unitycoder/UnityInitializeProject/main/Assets/Editor/InitializeProject.cs"; + [DllImport("user32", CharSet = CharSet.Unicode)] static extern IntPtr FindWindow(string cls, string win); [DllImport("user32")] @@ -224,7 +230,7 @@ public static void AddProjectToHistory(string projectPath) } // NOTE holding alt key (when using alt+o) brings up unity project selector - public static Process LaunchProject(Project proj, DataGrid dataGridRef = null, bool useInitScript = false, bool upgrade = false) + public static Process LaunchProject(Project proj, DataGrid dataGridRef = null, bool useInitScript = false, bool upgrade = false, bool cloneFromTemplate = false) { if (proj == null) return null; @@ -256,13 +262,6 @@ public static Process LaunchProject(Project proj, DataGrid dataGridRef = null, b Directory.CreateDirectory(assetsFolder); } - // when opening project, check for crashed backup scene first - var cancelLaunch = CheckCrashBackupScene(proj.Path); - if (cancelLaunch == true) - { - return null; - } - // if its upgrade, we dont want to check current version if (upgrade == false) { @@ -279,17 +278,31 @@ public static Process LaunchProject(Project proj, DataGrid dataGridRef = null, b var unityExePath = GetUnityExePath(proj.Version); if (unityExePath == null) { + // if no editors installed, show message + if (MainWindow.unityInstallationsSource.Count == 0) + { + MessageBox.Show($"No Unity versions installed. Please run {MainWindow.appName} first to setup root folders.", MainWindow.appName, MessageBoxButton.OK, MessageBoxImage.Warning); + return null; + } + DisplayUpgradeDialog(proj, null, useInitScript); return null; } + // when opening project, check for crashed backup scene first + var cancelLaunch = CheckCrashBackupScene(proj.Path); + if (cancelLaunch == true) + { + return null; + } + Process newProcess = new Process(); try { var cmd = "\"" + unityExePath + "\""; newProcess.StartInfo.FileName = cmd; - var unitycommandlineparameters = " -projectPath " + "\"" + proj.Path + "\""; + string unitycommandlineparameters = (cloneFromTemplate ? " -createproject " : " -projectPath ") + "\"" + proj.Path + "\""; string customArguments = proj.Arguments; if (string.IsNullOrEmpty(customArguments) == false) @@ -399,30 +412,54 @@ static bool CheckCrashBackupScene(string projectPath) var recoveryFile = Path.Combine(projectPath, "Temp", "__Backupscenes", "0.backup"); if (File.Exists(recoveryFile)) { - var result = MessageBox.Show("Crash recovery scene found, do you want to copy it into Assets/_Recovery/-folder?", "UnityLauncherPro - Scene Recovery", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (result == MessageBoxResult.Yes) + if (Settings.Default.showRecoveredScenePopup) { - var restoreFolder = Path.Combine(projectPath, "Assets", "_Recovery"); - if (Directory.Exists(restoreFolder) == false) + var result = MessageBox.Show("Crash recovery scene found, do you want to MOVE it into Assets/_Recovery/-folder?", "UnityLauncherPro - Scene Recovery", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result == MessageBoxResult.Yes) { - Directory.CreateDirectory(restoreFolder); - } - if (Directory.Exists(restoreFolder) == true) - { - Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; - var uniqueFileName = "Recovered_Scene" + unixTimestamp + ".unity"; - File.Copy(recoveryFile, Path.Combine(restoreFolder, uniqueFileName)); - Console.WriteLine("Recovered crashed scene into: " + restoreFolder); + var restoreFolder = Path.Combine(projectPath, "Assets", "_Recovery"); + if (Directory.Exists(restoreFolder) == false) + { + Directory.CreateDirectory(restoreFolder); + } + + if (Directory.Exists(restoreFolder) == true) + { + Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; + var uniqueFileName = "Recovered_Scene" + unixTimestamp + ".unity"; + + try + { + File.Move(recoveryFile, Path.Combine(restoreFolder, uniqueFileName)); + // remove folder, otherwise unity 6000.2 asks for recovery + Directory.Delete(Path.Combine(projectPath, "Temp", "__Backupscenes"), true); + + Console.WriteLine("moved file to " + uniqueFileName); + } + catch (IOException) + { + // if move failed, try copy + File.Copy(recoveryFile, Path.Combine(restoreFolder, uniqueFileName)); + Console.WriteLine("copied file"); + } + + Console.WriteLine("Recovered crashed scene into: " + restoreFolder); + } + else + { + Console.WriteLine("Error: Failed to create restore folder: " + restoreFolder); + cancelRunningUnity = true; + } } - else + else if (result == MessageBoxResult.Cancel) // dont do restore, but run Unity { - Console.WriteLine("Error: Failed to create restore folder: " + restoreFolder); cancelRunningUnity = true; } } - else if (result == MessageBoxResult.Cancel) // dont do restore, but run Unity + else { - cancelRunningUnity = true; + File.Delete(recoveryFile); + Directory.Delete(Path.GetDirectoryName(recoveryFile)); } } return cancelRunningUnity; @@ -438,6 +475,8 @@ public static string GetUnityExePath(string version) // opens Explorer to target folder public static bool LaunchExplorer(string folder) { + if (folder == null || folder.Length < 1) return false; + if (Directory.Exists(folder) == true) { Process.Start(folder); @@ -677,7 +716,15 @@ public static async void DownloadInBrowser(string version, bool preferFullInstal // https://beta.unity3d.com/download/330fbefc18b7/UnityDownloadAssistant-6000.1.0a8.exe if (exeURL == null) { - Console.WriteLine("TODO DownloadInBrowser"); + // exe url not found, try unofficial list (TODO this is hack to avoid null url, because unofficial list items have been cached to local json, without download url..) + Console.WriteLine("Fixing null in DownloadInBrowser ,v=" + version); + var downloadURL = await GetUnityUpdates.CheckUnofficialVersionList(version); + if (string.IsNullOrEmpty(downloadURL) == false) + { + string unityHash = ParseHashCodeFromURL(downloadURL); + exeURL = ParseDownloadURLFromWebpage(version, unityHash, false, true); + } + return; } if (preferFullInstaller == true) @@ -702,12 +749,25 @@ public static async void DownloadInBrowser(string version, bool preferFullInstal public static async void DownloadAndInstall(string version) { + string exeURL = await GetUnityUpdates.FetchDownloadUrl(version); + if (version == null) { Console.WriteLine("Error> Cannot download and install null version"); return; } - string exeURL = await GetUnityUpdates.FetchDownloadUrl(version); + + if (string.IsNullOrEmpty(exeURL) == true) + { + // exe url not found, try unofficial list (TODO this is hack to avoid null url, because unofficial list items have been cached to local json, without download url..) + Console.WriteLine("Fixing null in DownloadInBrowser ,v=" + version); + var downloadURL = await GetUnityUpdates.CheckUnofficialVersionList(version); + if (string.IsNullOrEmpty(downloadURL) == false) + { + string unityHash = ParseHashCodeFromURL(downloadURL); + exeURL = ParseDownloadURLFromWebpage(version, unityHash, false, true); + } + } Console.WriteLine("download exeURL= (" + exeURL + ")"); @@ -732,6 +792,28 @@ public static async void DownloadAndInstall(string version) string outputVersionFolder = version.Split('.')[0] + "_" + version.Split('.')[1]; string targetPathArgs = " /D=" + lastRootFolder + outputVersionFolder; ; + // NOTE cannot enable same modules as the previously installed version, because it requires elevated permissions.. + // GetPlatformsForUnityVersion.. + //var previousVersion = Tools.FindNearestVersion(version, MainWindow.unityInstalledVersions.Keys.ToList(), true); + //if (previousVersion != null) + //{ + // string[] previousModules = GetPlatformsForUnityVersion(previousVersion); + // if (previousModules != null && previousModules.Length > 0) + // { + // // find registry Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Unity Technologies\Installer + // // then enable dword 1, for example key: "Select_Android", if my modules has "Android" etc. + + // foreach (var module in previousModules) + // { + // Console.WriteLine(previousVersion + " has modules: " + module); + // // 6000.0.66f2 has modules: Android + // // 6000.0.66f2 has modules: iOS + // // 6000.0.66f2 has modules: Win + // // 6000.0.66f2 has modules: Win64 + // } + // } + //} + // if user clicks NO to UAC, this fails (so added try-catch) try { @@ -739,14 +821,23 @@ public static async void DownloadAndInstall(string version) process.StartInfo.FileName = tempFile; process.StartInfo.Arguments = targetPathArgs; process.EnableRaisingEvents = true; - process.Exited += (sender, e) => DeleteTempFile(tempFile); + process.Exited += (sender, e) => InstallationCompleted(tempFile); process.Start(); } - catch (Exception) + catch (Win32Exception ex) when (ex.NativeErrorCode == 1223) // ERROR_CANCELLED { - Console.WriteLine("Failed to run exe: " + tempFile); - DeleteTempFile(tempFile); + // User declined the UAC prompt + Console.WriteLine("User cancelled elevation (UAC)."); + SetStatus("Installation cancelled by user."); + InstallationCompleted(tempFile); } + catch (Exception ex) + { + Console.WriteLine("Failed to run exe: " + tempFile + " - " + ex.Message); + SetStatus("Failed to run installer: " + ex.Message); + InstallationCompleted(tempFile); + } + // TODO refresh upgrade dialog after installer finished } } @@ -755,14 +846,15 @@ public static async void DownloadAndInstall(string version) //SetStatus("Error> Cannot find installer executable ... opening website instead"); var url = "https://unity3d.com/get-unity/download/archive"; Process.Start(url + "#installer-not-found---version-" + version); + SetStatus("Error> Cannot find installer executable for version " + version); } - } + } // DownloadAndInstall - static readonly string initFileDefaultURL = "https://raw.githubusercontent.com/unitycoder/UnityInitializeProject/main/Assets/Editor/InitializeProject.cs"; public static async Task DownloadInitScript(string currentInitScriptFullPath, string currentInitScriptLocationOrURL) { string currentInitScriptFolder = Path.GetDirectoryName(currentInitScriptFullPath); + string currentInitScriptFile = Path.GetFileName(currentInitScriptFullPath); string tempFile = Path.Combine(Path.GetTempPath(), currentInitScriptFile); bool isLocalFile = false; @@ -816,29 +908,40 @@ public static async Task DownloadInitScript(string currentInitScriptFullPath, st { File.Move(tempFile, currentInitScriptFullPath); } + SetStatus("Downloaded latest init script."); } else { Console.WriteLine("Invalid c# init file..(missing correct Namespace, Class or Method)"); + SetStatus("Invalid c# init file..(missing correct Namespace, Class or Method)"); } } catch (Exception e) { Console.WriteLine("File exception: " + e.Message); + SetStatus("File exception: " + e.Message); } } else { Console.WriteLine("Failed to download init script from: " + currentInitScriptLocationOrURL); + SetStatus("Failed to download init script from: " + currentInitScriptLocationOrURL); } } - static void DeleteTempFile(string path) + static void InstallationCompleted(string path) { if (File.Exists(path) == true) { - Console.WriteLine("DeleteTempFile: " + path); + // delete temp installer file File.Delete(path); + + // refresh installed versions list + mainWindow.Dispatcher.Invoke(() => + { + mainWindow.UpdateUnityInstallationsList(); + mainWindow.CallGetUnityUpdates(); + }); } } @@ -868,19 +971,21 @@ public static string CleanVersionNumber(string version) var split = version.Split('.'); float parsedVersion = float.Parse($"{split[0]}.{split[1]}"); - // 2023.3 and newer Alpha releases, no replace - if (IsAlpha(version) && parsedVersion >= 2023.3) + + // For 2023.3 and newer pre-release (alpha or beta) versions, do not clean. + if ((IsAlpha(version) || version.Contains("b")) && parsedVersion >= 2023.3) { - // do nothing + // Do nothing; leave version unchanged. } else { - // note old patch versions still contains p## in the end - version = Regex.Replace(version, @"[f|a|b][0-9]{1,2}", "", RegexOptions.IgnoreCase); + // Remove the trailing patch/build indicator. + version = Regex.Replace(version, @"[fab][0-9]{1,2}", "", RegexOptions.IgnoreCase); } return version; } + // TODO only hash version is used, cleanup the rest public static string ParseDownloadURLFromWebpage(string version, string hash = null, bool preferFullInstaller = false, bool useHash = false) { @@ -1107,8 +1212,7 @@ public static string FindNearestVersion(string currentVersion, List allA string result = null; // add current version to list, to sort it with others - if (!allAvailable.Contains(currentVersion)) - allAvailable.Add(currentVersion); + if (!allAvailable.Contains(currentVersion)) allAvailable.Add(currentVersion); // sort list if (checkBelow) @@ -1158,6 +1262,7 @@ public static long VersionAsLong(string version) multiplier *= 50; } } + return result; } @@ -1230,7 +1335,7 @@ public static void DisplayUpgradeDialog(Project proj, MainWindow owner, bool use // get selected version to upgrade for Console.WriteLine("Upgrade to " + upgradeToVersion); - // inject new version for this item, TODO inject version to ProjectSettings file, so then no alert from unity wrong version dialog + // inject new version for this item proj.Version = upgradeToVersion; SaveProjectVersion(proj); var proc = LaunchProject(proj, dataGridRef: null, useInitScript: false, upgrade: true); @@ -1278,6 +1383,56 @@ public static void AddContextMenuRegistry(string contextRegRoot) } } + public static void AddContextMenuRegistryAPKInstall(string contextRegRoot) + { + // Define the registry key path for .apk file association + string apkFileTypeRegPath = @"Software\Classes\.apk"; + + // Open or create the registry key for .apk files + RegistryKey apkKey = Registry.CurrentUser.OpenSubKey(apkFileTypeRegPath, true); + + if (apkKey == null) + { + apkKey = Registry.CurrentUser.CreateSubKey(apkFileTypeRegPath); + } + + if (apkKey != null) + { + // Create or open the Shell subkey for context menu options + RegistryKey shellKey = apkKey.CreateSubKey("shell", true); + + if (shellKey != null) + { + var appName = "UnityLauncherPro"; + // Create a subkey for the app's context menu item + RegistryKey appKey = shellKey.CreateSubKey(appName, true); + + if (appKey != null) + { + appKey.SetValue("", "Install with " + appName); // Display name in context menu + appKey.SetValue("Icon", "\"" + Process.GetCurrentProcess().MainModule.FileName + "\""); + appKey.SetValue("Position", "Bottom"); // Set position to adjust order + + // Create the command subkey to specify the action + RegistryKey commandKey = appKey.CreateSubKey("command", true); + + if (commandKey != null) + { + // Build the command string to launch with -install argument + var executeString = "\"" + Process.GetCurrentProcess().MainModule.FileName + "\" -install \"%1\""; + commandKey.SetValue("", executeString); + } + } + } + } + else + { + Console.WriteLine("Error> Cannot create or access registry key for .apk file association: " + apkFileTypeRegPath); + } + } + + + /// /// uninstall context menu item from registry /// @@ -1305,128 +1460,189 @@ public static void RemoveContextMenuRegistry(string contextRegRoot) } } + public static void RemoveContextMenuRegistryAPKInstall(string contextRegRoot) + { + // Define the registry key path for .apk file association + string apkFileTypeRegPath = @"Software\Classes\.apk\shell"; + + // Open the registry key for the shell context menu + RegistryKey shellKey = Registry.CurrentUser.OpenSubKey(apkFileTypeRegPath, true); + + if (shellKey != null) + { + var appName = "UnityLauncherPro"; + + // Check if the app's context menu key exists + RegistryKey appKey = shellKey.OpenSubKey(appName, false); + if (appKey != null) + { + // Delete the app's context menu key + shellKey.DeleteSubKeyTree(appName); + Console.WriteLine("Removed context menu for .apk files."); + } + else + { + Console.WriteLine("No context menu found for .apk files."); + } + } + else + { + Console.WriteLine("Error> Cannot find registry key for .apk shell context: " + apkFileTypeRegPath); + } + } + /// /// reads .git/HEAD file from the project to get current branch name /// /// + /// /// public static string ReadGitBranchInfo(string projectPath, bool searchParentFolders) { - string results = null; - - if (searchParentFolders) + DirectoryInfo directoryInfo = new DirectoryInfo(projectPath); + while (directoryInfo != null) { - DirectoryInfo directoryInfo = new DirectoryInfo(projectPath); + string gitDir = Path.Combine(directoryInfo.FullName, ".git"); + string headFile = Path.Combine(gitDir, "HEAD"); - while (directoryInfo != null) + if (Directory.Exists(gitDir) && File.Exists(headFile)) { - string dirName = Path.Combine(directoryInfo.FullName, ".git"); + string headContent = File.ReadAllText(headFile).Trim(); + int pos = headContent.LastIndexOf('/') + 1; + return (pos < headContent.Length) ? headContent.Substring(pos) : headContent; + } - if (Directory.Exists(dirName)) - { - string branchFile = Path.Combine(dirName, "HEAD"); - if (File.Exists(branchFile)) - { - // removes extra end of line - results = string.Join(" ", File.ReadAllLines(branchFile)); - // get branch only - int pos = results.LastIndexOf("/") + 1; - results = results.Substring(pos, results.Length - pos); - return results; - } - } - directoryInfo = directoryInfo.Parent; + if (!searchParentFolders) + { + break; } + directoryInfo = directoryInfo.Parent; } - else - { - string dirName = Path.Combine(projectPath, ".git"); - if (Directory.Exists(dirName)) + return null; + } - { - string branchFile = Path.Combine(dirName, "HEAD"); - if (File.Exists(branchFile)) - { - // removes extra end of line - results = string.Join(" ", File.ReadAllLines(branchFile)); - // get branch only - int pos = results.LastIndexOf("/") + 1; - results = results.Substring(pos, results.Length - pos); + public static string ReadPlasticBranchInfo(string projectPath, bool searchParentFolders) + { + string branchName = null; + DirectoryInfo directoryInfo = new DirectoryInfo(projectPath); + while (directoryInfo != null) + { + string plasticSelectorPath = Path.Combine(directoryInfo.FullName, ".plastic", "plastic.selector"); + if (File.Exists(plasticSelectorPath)) + { + branchName = ExtractPlasticBranch(plasticSelectorPath); + if (!string.IsNullOrEmpty(branchName)) + { + return branchName; } + } + if (!searchParentFolders) + { + break; } + + directoryInfo = directoryInfo.Parent; } - return results; + + return branchName; } - public static string ReadPlasticBranchInfo(string projectPath) + private static string ExtractPlasticBranch(string plasticSelectorPath) { - string results = null; - string dirName = Path.Combine(projectPath, ".plastic"); - if (Directory.Exists(dirName)) + string[] lines = File.ReadAllLines(plasticSelectorPath); + foreach (string line in lines) { - string branchFile = Path.Combine(dirName, "plastic.selector"); - if (File.Exists(branchFile)) + string trimmedLine = line.Trim(); + if (trimmedLine.StartsWith("br ") || trimmedLine.StartsWith("smartbranch ")) { - // removes extra end of line - results = string.Join(" ", File.ReadAllText(branchFile)); - // get branch only - int pos = results.LastIndexOf("\"/") + 1; - // -1 to remove last " - results = results.Substring(pos, results.Length - pos - 1); + // Extract the first quoted string + var match = Regex.Match(trimmedLine, "\"([^\"]+)\""); + if (match.Success) + { + string branchName = match.Groups[1].Value; + // Remove leading slash if present (e.g., "/main" becomes "main") + if (branchName.StartsWith("/")) + { + branchName = branchName.Substring(1); + } + return branchName; + } } } - return results; + return null; } - //public static Platform GetTargetPlatform(string projectPath) static string GetTargetPlatformRaw(string projectPath) { string results = null; - //Platform results = Platform.Unknown; // get buildtarget from .csproj // StandaloneWindows64:19 // get main csproj file var csproj = Path.Combine(projectPath, "Assembly-CSharp.csproj"); + // TODO check projname also, if no assembly-.., NOTE already checked above - //var csproj = Path.Combine(projectPath, projectName + ".csproj"); + // var csproj = Path.Combine(projectPath, projectName + ".csproj"); + if (File.Exists(csproj)) { - var csprojtxt = File.ReadAllText(csproj); - var csprojsplit = csprojtxt.Split(new[] { "" }, StringSplitOptions.None); - if (csprojsplit != null && csprojsplit.Length > 1) + // Read the file line by line for performance + using (var reader = new StreamReader(csproj)) { - var endrow = csprojsplit[1].IndexOf(":"); - if (endrow > -1) + string line; + while ((line = reader.ReadLine()) != null) { - //Console.WriteLine("build target: " + csprojsplit[1].Substring(0, endrow)); - // 5.6 : win32, win64, osx, linux, linux64, ios, android, web, webstreamed, webgl, xboxone, ps4, psp2, wsaplayer, tizen, samsungtv - // 2017: standalone, Win, Win64, OSXUniversal, Linux, Linux64, LinuxUniversal, iOS, Android, Web, WebStreamed, WebGL, XboxOne, PS4, PSP2, WindowsStoreApps, Switch, WiiU, N3DS, tvOS, PSM - // 2018: standalone, Win, Win64, OSXUniversal, Linux, Linux64, LinuxUniversal, iOS, Android, Web, WebStreamed, WebGL, XboxOne, PS4, WindowsStoreApps, Switch, N3DS, tvOS - // 2019: Standalone, Win, Win64, OSXUniversal, Linux64, iOS, Android, WebGL, XboxOne, PS4, WindowsStoreApps, Switch, tvOS - // 2020: Standalone, Win, Win64, OSXUniversal, Linux64, iOS, Android, WebGL, XboxOne, PS4, WindowsStoreApps, Switch, tvOS - // 2021: Standalone, Win, Win64, OSXUniversal, Linux64, iOS, Android, WebGL, XboxOne, PS4, WindowsStoreApps, Switch, tvOS - results = csprojsplit[1].Substring(0, endrow); - //results = (Platform)Enum.Parse(typeof(Platform), csprojsplit[1].Substring(0, endrow)); + const string tagStart = ""; + const string tagEnd = ""; + + int startIdx = line.IndexOf(tagStart); + if (startIdx >= 0) + { + int endIdx = line.IndexOf(tagEnd, startIdx); + if (endIdx > startIdx) + { + string inner = line.Substring(startIdx + tagStart.Length, endIdx - startIdx - tagStart.Length); + int colonIndex = inner.IndexOf(':'); + if (colonIndex > -1) + { + //Console.WriteLine("build target: " + inner.Substring(0, colonIndex)); + // 5.6 : win32, win64, osx, linux, linux64, ios, android, web, webstreamed, webgl, xboxone, ps4, psp2, wsaplayer, tizen, samsungtv + // 2017: standalone, Win, Win64, OSXUniversal, Linux, Linux64, LinuxUniversal, iOS, Android, Web, WebStreamed, WebGL, XboxOne, PS4, PSP2, WindowsStoreApps, Switch, WiiU, N3DS, tvOS, PSM + // 2018: standalone, Win, Win64, OSXUniversal, Linux, Linux64, LinuxUniversal, iOS, Android, Web, WebStreamed, WebGL, XboxOne, PS4, WindowsStoreApps, Switch, N3DS, tvOS + // 2019: Standalone, Win, Win64, OSXUniversal, Linux64, iOS, Android, WebGL, XboxOne, PS4, WindowsStoreApps, Switch, tvOS + // 2020: Standalone, Win, Win64, OSXUniversal, Linux64, iOS, Android, WebGL, XboxOne, PS4, WindowsStoreApps, Switch, tvOS + // 2021: Standalone, Win, Win64, OSXUniversal, Linux64, iOS, Android, WebGL, XboxOne, PS4, WindowsStoreApps, Switch, tvOS + results = inner.Substring(0, colonIndex); + //results = (Platform)Enum.Parse(typeof(Platform), inner.Substring(0, colonIndex)); + break; // we found it, exit early + } + } + } } } } else { - //Console.WriteLine("Missing csproj, cannot parse target platform: "+ projectPath); + //Console.WriteLine("Missing csproj, cannot parse target platform: " + projectPath); } return results; } + public static string GetTargetPlatform(string projectPath) { var rawPlatformName = GetTargetPlatformRaw(projectPath); + return GetTargetPlatformFromRaw(rawPlatformName); + } + + public static string GetTargetPlatformFromRaw(string rawPlatformName) + { if (string.IsNullOrEmpty(rawPlatformName) == false && GetProjects.remapPlatformNames.ContainsKey(rawPlatformName)) { return GetProjects.remapPlatformNames[rawPlatformName]; @@ -1440,19 +1656,31 @@ public static string GetTargetPlatform(string projectPath) public static string ReadCustomProjectData(string projectPath, string customFile) { - string results = null; - customFile = Path.Combine(projectPath, "ProjectSettings", customFile); - if (File.Exists(customFile) == true) + // ProjectSettings is the old deprecated location (and current location from Hub 3.15.x, but later they will use UserSettings first too) + string[] directories = { "UserSettings", "ProjectSettings" }; + + foreach (var directory in directories) { - results = string.Join(" ", File.ReadAllLines(customFile)); + string filePath = Path.Combine(projectPath, directory, customFile); + if (File.Exists(filePath)) + { + return string.Join(" ", File.ReadAllLines(filePath)); + } } - return results; + + return null; } public static bool SaveCustomProjectData(string projectPath, string customFile, string data) { - customFile = Path.Combine(projectPath, "ProjectSettings", customFile); + // NOTE: now saving into UserSettings folder only (there might be old custom data is in ProjectSettings/ still..) + var customPath = Path.Combine(projectPath, "UserSettings"); + if (!Directory.Exists(customPath)) + { + Directory.CreateDirectory(customPath); + } + customFile = Path.Combine(customPath, customFile); try { File.WriteAllText(customFile, data); @@ -1460,6 +1688,7 @@ public static bool SaveCustomProjectData(string projectPath, string customFile, } catch (Exception) { + SetStatus("Failed to save custom project data to: " + customFile); } return false; @@ -1481,47 +1710,42 @@ public static bool HasFocus(DependencyObject obj, Control control, bool checkChi public static void SetFocusToGrid(DataGrid targetGrid, int index = -1) { - // set main component focus - //targetGrid.Focus(); - //Keyboard.Focus(targetGrid); - - // no items if (targetGrid.Items.Count < 1) return; - // keep current row selected if (index == -1 && targetGrid.SelectedIndex > -1) index = targetGrid.SelectedIndex; - - // if no item selected, pick first if (index == -1) index = 0; targetGrid.SelectedIndex = index; - // set full focus + // Try get the row, if not realized yet, defer DataGridRow row = (DataGridRow)targetGrid.ItemContainerGenerator.ContainerFromIndex(index); if (row == null) { - targetGrid.UpdateLayout(); - if (index < targetGrid.Items.Count) - { - // scroll selected into view - targetGrid.ScrollIntoView(targetGrid.Items[index]); - row = (DataGridRow)targetGrid.ItemContainerGenerator.ContainerFromIndex(index); - } - else + // clamp to max items + if (index >= targetGrid.Items.Count) index = targetGrid.Items.Count - 1; + + targetGrid.ScrollIntoView(targetGrid.Items[index]); + // Defer the focus once row is generated + targetGrid.Dispatcher.InvokeAsync(() => { - Console.WriteLine("selected row out of bounds: " + index); - } + var newRow = (DataGridRow)targetGrid.ItemContainerGenerator.ContainerFromIndex(index); + if (newRow != null) + { + newRow.MoveFocus(new TraversalRequest(FocusNavigationDirection.Up)); + newRow.Focus(); + Keyboard.Focus(newRow); + } + }, DispatcherPriority.Background); } - // NOTE does this causes move below? - //row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next)); - if (row != null) + else { - row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Up)); // works better than Up + row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Up)); row.Focus(); Keyboard.Focus(row); } } + public static string BrowseForOutputFolder(string title, string initialDirectory = null) { // https://stackoverflow.com/a/50261723/5452781 @@ -1548,26 +1772,27 @@ public static string BrowseForOutputFolder(string title, string initialDirectory } // TODO too many params.. - public static Project FastCreateProject(string version, string baseFolder, string projectName = null, string templateZipPath = null, string[] platformsForThisUnity = null, string platform = null, bool useInitScript = false, string initScriptPath = null) + public static Project FastCreateProject(string version, string baseFolder, string projectName = null, string templateZipPath = null, string[] platformsForThisUnity = null, string platform = null, bool useInitScript = false, string initScriptPath = null, bool forceDX11 = false) { // check for base folders in settings tab if (string.IsNullOrEmpty(baseFolder) == true) { - Console.WriteLine("Missing baseFolder value"); + SetStatus("Missing baseFolder value"); return null; } // check if base folder exists if (Directory.Exists(baseFolder) == false) { - Console.WriteLine("Missing baseFolder: " + baseFolder); + // TODO add streaming filter + SetStatus("Missing baseFolder: " + baseFolder); return null; } // check selected unity version if (string.IsNullOrEmpty(version) == true) { - Console.WriteLine("Missing unity version string"); + SetStatus("Missing unity version string"); return null; } @@ -1584,27 +1809,43 @@ public static Project FastCreateProject(string version, string baseFolder, strin // create folder CreateEmptyProjectFolder(newPath, version); - // unzip template, if any + bool cloneFromTemplate = false; + // unzip or copy template if (templateZipPath != null) { - TarLib.Tar.ExtractTarGz(templateZipPath, newPath); - } + // Console.WriteLine(templateZipPath); - // copy init file into project - if (useInitScript == true) - { - if (File.Exists(initScriptPath) == true) + if (File.Exists(templateZipPath)) { - var editorTargetFolder = Path.Combine(baseFolder, projectName, "Assets", "Editor"); - if (Directory.Exists(editorTargetFolder) == false) Directory.CreateDirectory(editorTargetFolder); - var targetScriptFile = Path.Combine(editorTargetFolder, Path.GetFileName(initScriptPath)); - // TODO overwrite old file, there shouldnt be anything here - if (File.Exists(targetScriptFile) == false) File.Copy(initScriptPath, targetScriptFile); + cloneFromTemplate = true; + try + { + // NOTE no need to extract, unity can handle it with -cloneFromTemplate + //TarLib.Tar.ExtractTarGz(templateZipPath, newPath); + } + catch (Exception ex) + { + SetStatus("Error extract template file:" + ex.Message); + } + } + else if (Directory.Exists(templateZipPath)) + { + // this is for folder templates, copy files + try + { + CopyDirectory(templateZipPath, newPath); + } + catch (Exception ex) + { + SetStatus("Error copying template folder: " + ex.Message); + } } + } // launch empty project var proj = new Project(); + proj.Title = projectName; proj.Path = Path.Combine(baseFolder, newPath).Replace("\\", "/"); proj.Version = version; @@ -1612,10 +1853,53 @@ public static Project FastCreateProject(string version, string baseFolder, strin proj.TargetPlatform = platform; proj.Modified = DateTime.Now; proj.folderExists = true; // have to set this value, so item is green on list + proj.Arguments = version.Contains("6000") ? (forceDX11 ? "-force-d3d11" : null) : null; // this gets erased later, since its not saved? would be nice to not add it at all though + + var origArgs = proj.Arguments; + if (cloneFromTemplate == true) + { + proj.Arguments += " -cloneFromTemplate \"" + templateZipPath + "\""; + } + var proc = LaunchProject(proj, null, useInitScript, false, cloneFromTemplate); + + if (cloneFromTemplate == true) + { + // remove the -cloneFromTemplate argument, since its not needed in the recent list + proj.Arguments = origArgs; + } - var proc = LaunchProject(proj, null, useInitScript); ProcessHandler.Add(proj, proc); + // copy init file into project + if (useInitScript == true) + { + Action copyInitScript = () => + { + if (File.Exists(initScriptPath) == true) + { + var editorTargetFolder = Path.Combine(baseFolder, projectName, "Assets", "Editor"); + if (Directory.Exists(editorTargetFolder) == false) Directory.CreateDirectory(editorTargetFolder); + var targetScriptFile = Path.Combine(editorTargetFolder, Path.GetFileName(initScriptPath)); + // TODO overwrite old file, there shouldnt be anything here + if (File.Exists(targetScriptFile) == false) File.Copy(initScriptPath, targetScriptFile); + } + }; + + if (cloneFromTemplate == true) + { + // need to copy later, because cloning overwrites the folder? + _ = Task.Run(async () => + { + await Task.Delay(7500); + copyInitScript(); + }); + } + else + { + copyInitScript(); + } + } + return proj; } // FastCreateProject @@ -1653,6 +1937,8 @@ public static string GetSuggestedProjectName(string version, string baseFolder) static void CreateEmptyProjectFolder(string path, string version) { Console.WriteLine("Create new project folder: " + path); + // TODO add streaming filter + SetStatus("Creating new project folder: " + path); Directory.CreateDirectory(path); // create project version file, to avoid wrong version warning @@ -1662,11 +1948,43 @@ static void CreateEmptyProjectFolder(string path, string version) File.WriteAllText(settingsFile, "m_EditorVersion: " + version); } - public static string GetEditorLogsFolder() + public static string GetGlobalEditorLogsFolder() { + // NOTE this is pre 6.5 unity (in 6.5 and later its inside project: MyProj/Logs/Editor.log) return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Unity", "Editor"); } + public static void OpenEditorLogForProject(Project proj) + { + // if version is 6000.5 or higher, then log file is in Proj/Logs, otherwise in Appdata/LocalLow + if (proj.Version != null && Tools.IsVersionAtLeast(proj.Version, "6000.5") == true) + { + var logFolder = Path.Combine(proj.Path, "Logs"); + var logFile = Path.Combine(logFolder, "Editor.log"); + if (File.Exists(logFile) == true) + { + Tools.LaunchExe(logFile); + } + else + { + SetStatus("Log file not found: " + logFile, MessageType.Warning); + } + } + else + { + var logFolder = Tools.GetGlobalEditorLogsFolder(); + var logFile = Path.Combine(logFolder, "Editor.log"); + if (File.Exists(logFile) == true) + { + Tools.LaunchExe(logFile); + } + else + { + SetStatus("Log file not found: " + logFile, MessageType.Warning); + } + } + } + public static string[] GetPlatformsForUnityVersion(string version) { // get platforms array for this unity version @@ -1707,24 +2025,38 @@ public static Dictionary ScanTemplates(string unityInstallPath) var templateFolder = Path.Combine(unityPath, "Data/Resources/PackageManager/ProjectTemplates/"); if (Directory.Exists(templateFolder) == false) return items; + // get all files in template folder var fileEntries = Directory.GetFiles(templateFolder).ToList(); // process found files - for (int i = fileEntries.Count - 1; i > -1; i--) + for (int i = 0; i < fileEntries.Count; i++) { + //Console.WriteLine(fileEntries[i]); // check if its tgz - if (fileEntries[i].IndexOf(".tgz") == -1) - { - fileEntries.RemoveAt(i); - } - else + if (fileEntries[i].ToLower().IndexOf(".tgz") > -1) { - // cleanup name + // cleanup displayed name var name = Path.GetFileName(fileEntries[i]).Replace("com.unity.template.", "").Replace(".tgz", ""); items.Add(name, fileEntries[i]); } } + // 2018.4 has folders instead of tgz files + // BUT do this for all versions, in case user has added custom template folders (that contain Assets/ folder) + var dirEntries = Directory.GetDirectories(templateFolder).ToList(); + for (int i = 0; i < dirEntries.Count; i++) + { + //Console.WriteLine(dirEntries[i]); + // if it has com.unity.template. prefix, then its a template + // if that directory contains Assets/ folder, then its a template + if (Directory.Exists(Path.Combine(dirEntries[i], "Assets")) == true) + { + //Console.WriteLine(dirEntries[i]); + var name = Path.GetFileName(dirEntries[i]).Replace("com.unity.template.", ""); + items.Add(name, dirEntries[i]); + } + } + return items; } @@ -1784,6 +2116,7 @@ public static bool ValidateDateFormat(string format) // https://stackoverflow.com/a/37724335/5452781 public static void BringProcessToFront(Process process) { + if (process == null) return; IntPtr handle = process.MainWindowHandle; if (IsIconic(handle)) { @@ -1950,6 +2283,33 @@ static string[] GetScenes() } + public static void BuildProjectCustom(Project proj) + { + Console.WriteLine("Building " + proj.Title + " (custom)"); + SetStatus("Build process started: " + DateTime.Now.ToString("HH:mm:ss")); + + // get selected project unity exe path + var unityExePath = Tools.GetUnityExePath(proj.Version); + if (unityExePath == null) return; + + // create commandline string for building and launch it + //var buildcmd = $"\"{unityExePath}\" -quit -batchmode -nographics -projectPath \"{proj.Path}\" -executeMethod \"Builder.BuildAndroid\" -buildTarget android -logFile -"; + // TODO test without nographics : https://forum.unity.com/threads/batch-build-one-scene-is-black-works-in-normal-file-build.1282823/#post-9456524 + var buildParams = $" -quit -batchmode -nographics -projectPath \"{proj.Path}\" -executeMethod \"UnityLauncherProToolsCustom.BuildCustom\""; + Console.WriteLine("buildcmd= " + buildParams); + + // launch build + var proc = Tools.LaunchExe(unityExePath, buildParams); + + // wait for process exit then open output folder + proc.Exited += (o, i) => + { + SetStatus("Build process finished: " + DateTime.Now.ToString("HH:mm:ss")); + // TODO set color based on results + SetBuildStatus(Colors.Green); + }; + } + // runs unity SimpleWebServer.exe and launches default Browser into project build/ folder' public static void LaunchWebGL(Project proj, string relativeFolder) { @@ -2013,7 +2373,7 @@ public static void LaunchWebGL(Project proj, string relativeFolder) if (objEndPoints[i].Port == port) { port++; - if (port > 65534) + if (port > 65535) { Console.WriteLine("Failed to find open port.."); isAvailable = false; @@ -2268,9 +2628,9 @@ internal static string GetBytesReadable(long i) public static MainWindow mainWindow; // set status bar in main thread - public static void SetStatus(string text) + public static void SetStatus(string text, MessageType messageType = MessageType.Info) { - mainWindow.Dispatcher.Invoke(() => { mainWindow.SetStatus(text); }); + mainWindow.Dispatcher.Invoke(() => { mainWindow.SetStatus(text, messageType); }); } public static void SetBuildStatus(Color color) @@ -2426,13 +2786,21 @@ internal static void OpenCustomAssetPath() } } - private static async Task DownloadFileAsync(string fileUrl, string destinationPath) + public static async Task DownloadFileAsync(string fileUrl, string destinationPath) { var cancellationTokenSource = new CancellationTokenSource(); var fileName = Path.GetFileName(fileUrl); var progressWindow = new DownloadProgressWindow(fileName, () => cancellationTokenSource.Cancel()); progressWindow.Show(); var result = false; + + // create destination folder, if not exists + var outputFolderPath = Path.GetDirectoryName(destinationPath); + if (Directory.Exists(outputFolderPath) == false) + { + Directory.CreateDirectory(outputFolderPath); + } + try { using (var client = new HttpClient()) @@ -2445,8 +2813,7 @@ private static async Task DownloadFileAsync(string fileUrl, string destina var totalRead = 0; using (var contentStream = await response.Content.ReadAsStreamAsync()) - using (var fileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, - FileShare.None, buffer.Length, true)) + using (var fileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write, FileShare.None, buffer.Length, true)) { int bytesRead; while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length, cancellationTokenSource.Token)) > 0) @@ -2471,7 +2838,7 @@ private static async Task DownloadFileAsync(string fileUrl, string destina { if (!result) { - DeleteTempFile(destinationPath); + InstallationCompleted(destinationPath); } progressWindow.Close(); } @@ -2480,31 +2847,536 @@ private static async Task DownloadFileAsync(string fileUrl, string destina internal static string GetSRP(string projectPath) { - // read projectsettings/graphicsettings file, look for m_SRPDefaultSettings: value var settingsFile = Path.Combine(projectPath, "ProjectSettings", "GraphicsSettings.asset"); - if (File.Exists(settingsFile) == false) return null; + if (!File.Exists(settingsFile)) return null; - var allText = File.ReadAllText(settingsFile); - var srpIndex = allText.IndexOf("m_SRPDefaultSettings:"); - if (srpIndex == -1) return null; // BIRP + bool srpSectionFound = false; - // urp = UnityEngine.Rendering.Universal.UniversalRenderPipeline - // hdrp = UnityEngine.Rendering.HighDefinition.HDRenderPipeline + using (var reader = new StreamReader(settingsFile)) + { + string line; + while ((line = reader.ReadLine()) != null) + { + if (!srpSectionFound) + { + if (line.Contains("m_SRPDefaultSettings:") || line.Contains("m_RenderPipelineGlobalSettingsMap:")) + { + srpSectionFound = true; + } + continue; + } + + if (line.Contains("UniversalRenderPipeline")) + { + return "URP"; + } + else if (line.Contains("HDRenderPipeline")) + { + return "HDRP"; + } + } + } + return null; // BIRP or unknown + } + + internal static void InstallAPK(string ApkPath) + { + try + { + var cmd = "cmd.exe"; + var pars = $"/C adb install -r \"{ApkPath}\""; // Use /C to execute and close the window after finishing + + var processStartInfo = new ProcessStartInfo + { + FileName = cmd, + Arguments = pars, + RedirectStandardOutput = true, // Capture output to wait for completion + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = false + }; + + string installOutput = null; + string installError = null; + + using (var installProcess = Process.Start(processStartInfo)) + { + installOutput = installProcess.StandardOutput.ReadToEnd(); + installError = installProcess.StandardError.ReadToEnd(); + installProcess.WaitForExit(); + + if (installProcess.ExitCode != 0 || !string.IsNullOrEmpty(installError)) + { + SetStatus($"Error installing APK: {installError.Trim()}\n{installOutput.Trim()}"); + return; + } + } + + // Attempt to extract package name using aapt + var aaptCmd = $"aapt dump badging \"{ApkPath}\" | findstr package:"; + var aaptProcessStartInfo = new ProcessStartInfo + { + FileName = "cmd.exe", + Arguments = $"/C {aaptCmd}", + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true + }; + + string packageName = null; + using (var process = Process.Start(aaptProcessStartInfo)) + { + var output = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + + var match = System.Text.RegularExpressions.Regex.Match(output, "package: name='(.*?)'"); + if (match.Success) + { + packageName = match.Groups[1].Value; + } + } + + if (!string.IsNullOrEmpty(packageName)) + { + // Run the application using adb + var runPars = $"/C adb shell monkey -p {packageName} 1"; + var runProcessStartInfo = new ProcessStartInfo + { + FileName = cmd, + Arguments = runPars, + UseShellExecute = true, + CreateNoWindow = false, + WindowStyle = ProcessWindowStyle.Normal + }; + Process.Start(runProcessStartInfo); + + SetStatus($"Installed and launched APK with package name: {packageName}"); + } + else + { + SetStatus("ADB install completed, but failed to extract package name. Application not launched."); + } + } + catch (Win32Exception ex) + { + // Handle case where adb or aapt is not found + SetStatus($"Error: Required tool not found. Ensure adb and aapt are installed and added to PATH. Details: {ex.Message}"); + } + catch (Exception ex) + { + // Handle other unexpected exceptions + SetStatus($"An unexpected error occurred: {ex.Message}"); + } + } - if (allText.IndexOf("UnityEngine.Rendering.Universal.UniversalRenderPipeline", srpIndex) > -1) + // exclude folders from windows defender + internal static bool RunExclusionElevated(IEnumerable paths, bool silent = false) + { + var escapedPaths = new List(); + foreach (var rawPath in paths) { - return "URP"; + var path = rawPath.Trim(); + string safePath = path.Replace("'", "''"); + escapedPaths.Add($"'{safePath}'"); } - else if (allText.IndexOf("UnityEngine.Rendering.HighDefinition.HDRenderPipeline", srpIndex) > -1) + + string joinedPaths = string.Join(", ", escapedPaths); + string psCommand = $"Add-MpPreference -ExclusionPath {joinedPaths}"; + + string fullCommand; + + if (silent) { - return "HDRP"; + // No output, just run the command silently + fullCommand = psCommand; } else { - return null; // BIRP + // Show command and keep window open + var quotedPathsForDisplay = string.Join(", ", escapedPaths.ConvertAll(p => $"'{p.Trim('\'')}'")); + string displayCommand = $"Add-MpPreference -ExclusionPath {quotedPathsForDisplay}"; + fullCommand = $"Write-Host 'Running: {displayCommand}'; {psCommand}; Write-Host ''; Write-Host 'Done. Press any key to exit...'; pause"; } + var startInfo = new ProcessStartInfo + { + FileName = "powershell.exe", + Arguments = silent + ? $"-WindowStyle Hidden -Command \"{fullCommand}\"" + : $"-NoExit -Command \"{fullCommand}\"", + UseShellExecute = true, + Verb = "runas", // Requires admin rights + WindowStyle = silent ? ProcessWindowStyle.Hidden : ProcessWindowStyle.Normal + }; + + try + { + Process.Start(startInfo); + } + catch (Win32Exception) + { + if (!silent) + { + MessageBox.Show("Operation cancelled or failed due to insufficient privileges.", "Cancelled", MessageBoxButton.OK, MessageBoxImage.Warning); + } + return false; + } + catch (Exception ex) + { + MessageBox.Show("Error: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); + return false; + } + + return true; } + + /// + /// Returns a full file path under either the application's install folder + /// or, if that isn't writable, under LocalAppData\UnityLauncherPro\. + /// + /// e.g. "Themes", "Scripts" + /// e.g. "custom.ini", "InitializeProject.cs" + public static string GetSafeFilePath(string subfolder, string fileName) + { + // 1) Preferred: under the app folder + string preferredDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, subfolder); + // 2) Fallback: in LocalAppData + string fallbackDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "UnityLauncherPro", subfolder); + + try + { + // Safe even if it already exists + Directory.CreateDirectory(preferredDir); + return Path.Combine(preferredDir, fileName); + } + catch (UnauthorizedAccessException) + { + // no write access under Program Files + } + catch (Exception ex) + { + // optional: log unexpected errors + Console.WriteLine($"Warning: couldn’t create {preferredDir}: {ex.Message}"); + } + + // Ensure fallback always exists + Directory.CreateDirectory(fallbackDir); + return Path.Combine(fallbackDir, fileName); + } + + // copy directory structure (for template folder) + public static void CopyDirectory(string sourceDir, string targetDir) + { + // Create the target directory if it doesn't exist + Directory.CreateDirectory(targetDir); + + // Copy all files + foreach (var file in Directory.GetFiles(sourceDir)) + { + var destFile = Path.Combine(targetDir, Path.GetFileName(file)); + File.Copy(file, destFile, overwrite: false); + } + + // Recursively copy subdirectories + foreach (var directory in Directory.GetDirectories(sourceDir)) + { + var destDir = Path.Combine(targetDir, Path.GetFileName(directory)); + CopyDirectory(directory, destDir); + } + } + + + + // test fetching + + // Reuse a single HttpClient + private static readonly HttpClient _http = new HttpClient + { + Timeout = TimeSpan.FromSeconds(15) + }; + + /// + /// Fire-and-forget entry; returns immediately. Keeps your UI thread free. + /// + internal static void FetchAdditionalInfoForEditors() + { + _ = FetchImplAsync(); // don't await -> no UI hang + } + + private static async Task FetchImplAsync() + { + try + { + foreach (var version in MainWindow.unityInstalledVersions.Keys) + { + //Console.WriteLine("******** Fetching " + version); + + var url = $"https://services.api.unity.com/unity/editor/release/v1/releases?order=RELEASE_DATE_DESC&limit=1&version={Uri.EscapeDataString(version)}"; + + string json; + try + { + json = await _http.GetStringAsync(url).ConfigureAwait(false); + } + catch (Exception ex) + { + Debug.WriteLine($"[FetchAdditionalInfo] {version}: HTTP error: {ex.Message}"); + continue; + } + + try + { + //Console.WriteLine("received: " + json); + UnityEditorInfoLabel label = ExtractLabelText(json); + if (label != null) + { + + // feed this info back to main window + if (string.IsNullOrEmpty(label.labelText) == false) + { + //Console.WriteLine(label.description); + + var u = MainWindow.unityInstallationsSource.FirstOrDefault(x => x.Version == version); + + string infoText = label.labelText + "\n" + label.description; ; + + u.InfoLabel = infoText; + + int index = MainWindow.unityInstallationsSource.IndexOf(u); + if (index >= 0) + { + MainWindow.unityInstallationsSource[index] = u; + } + + // update all projectsSource items with this version too + foreach (var p in MainWindow.projectsSource) + { + if (p.Version == version) + { + p.InfoLabel = infoText; + } + } + + + + //SetStatus($"Info for {version}: {label.labelText}"); + //Console.WriteLine("got infolabel for " + version); + } + } + + } + catch (Exception ex) + { + Debug.WriteLine($"[FetchAdditionalInfo] {version}: JSON parse error: {ex.Message}"); + } + + // delay + await Task.Delay(500).ConfigureAwait(false); + + } // foreach version + } + catch (Exception ex) + { + // Last-resort catch so fire-and-forget exceptions aren’t unobserved + Debug.WriteLine($"[FetchAdditionalInfo] Fatal: {ex}"); + } + } // FetchImplAsync() + + public class UnityEditorInfoLabel + { + public string description; // may contain HTML + public string labelText; + public string icon; + public string color; + } + + private static UnityEditorInfoLabel ExtractLabelText(string json) + { + var label = new UnityEditorInfoLabel(); + if (string.IsNullOrEmpty(json) || json.Contains("\"results\":[]")) return label; + + int resultsIndex = json.IndexOf("\"results\":", StringComparison.Ordinal); + if (resultsIndex == -1) return label; + + // Use the LAST "label": in the payload (the editor-level one) + int labelIndex = json.LastIndexOf("\"label\":", StringComparison.Ordinal); + if (labelIndex == -1 || labelIndex < resultsIndex) return label; + + // labelText + int ltIndex = json.IndexOf("\"labelText\":", labelIndex, StringComparison.Ordinal); + if (ltIndex != -1) + { + int vStart = json.IndexOf('\"', ltIndex + 12) + 1; // "labelText": => +12 + if (vStart > 0) + { + int vEnd = json.IndexOf('\"', vStart); + if (vEnd > vStart) label.labelText = json.Substring(vStart, vEnd - vStart); + } + } + + // icon + int iconIndex = json.IndexOf("\"icon\":", labelIndex, StringComparison.Ordinal); + if (iconIndex != -1) + { + int vStart = json.IndexOf('\"', iconIndex + 7) + 1; // "icon": => +7 + if (vStart > 0) + { + int vEnd = json.IndexOf('\"', vStart); + if (vEnd > vStart) label.icon = json.Substring(vStart, vEnd - vStart); + } + } + + // color + int colorIndex = json.IndexOf("\"color\":", labelIndex, StringComparison.Ordinal); + if (colorIndex != -1) + { + int vStart = json.IndexOf('\"', colorIndex + 8) + 1; // "color": => +8 + if (vStart > 0) + { + int vEnd = json.IndexOf('\"', vStart); + if (vEnd > vStart) label.color = json.Substring(vStart, vEnd - vStart); + } + } + + // description (may contain escaped quotes) + int descIndex = json.IndexOf("\"description\":", labelIndex, StringComparison.Ordinal); + if (descIndex != -1) + { + int qStart = json.IndexOf('\"', descIndex + 14) + 1; // "description": => +14 + if (qStart > 0) + { + int i = qStart; + for (; i < json.Length; i++) + if (json[i] == '\"' && json[i - 1] != '\\') break; + + if (i > qStart) + { + label.description = json.Substring(qStart, i - qStart).Replace("\\\"", "\"").Replace("\\n", "\n").Replace("\\r", "\r").Replace("\\t", "\t"); + // strip HTML tags for now + label.description = System.Text.RegularExpressions.Regex.Replace(label.description, "<.*?>", string.Empty); + } + } + } + + return label; + } + + public static string ParseHashCodeFromURL(string url) + { + // https://beta.unity3d.com/download/330fbefc18b7/download.html#6000.1.0a8 > 330fbefc18b7 + + int hashStart = url.IndexOf("download/") + 9; + int hashEnd = url.IndexOf("/download.html", hashStart); + return url.Substring(hashStart, hashEnd - hashStart); + } + + internal static void OpenReleasesApiForVersion(string version) + { + string url = $"https://services.api.unity.com/unity/editor/release/v1/releases?limit=1&version={version}"; + LaunchBrowser(url); + } + + private static void LaunchBrowser(string url) + { + try + { + Process.Start(new ProcessStartInfo + { + FileName = url, + UseShellExecute = true + }); + } + catch (Exception ex) + { + MessageBox.Show("Failed to open URL: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + + internal static bool IsVersionAtLeast(string version, string v) + { + if (string.IsNullOrEmpty(version) || string.IsNullOrEmpty(v)) return false; + + try + { + var versionParts = version.Split('.'); + var vParts = v.Split('.'); + + int versionMajor = 0; + int vMajor = 0; + int versionMinor = 0; + int vMinor = 0; + + if (versionParts.Length > 0) + { + int i = 0; + while (i < versionParts[0].Length && char.IsDigit(versionParts[0][i])) i++; + int.TryParse(versionParts[0].Substring(0, i), out versionMajor); + } + + if (vParts.Length > 0) + { + int i = 0; + while (i < vParts[0].Length && char.IsDigit(vParts[0][i])) i++; + int.TryParse(vParts[0].Substring(0, i), out vMajor); + } + + if (versionMajor != vMajor) + { + return versionMajor > vMajor; + } + + if (versionParts.Length > 1) + { + int i = 0; + while (i < versionParts[1].Length && char.IsDigit(versionParts[1][i])) i++; + int.TryParse(versionParts[1].Substring(0, i), out versionMinor); + } + + if (vParts.Length > 1) + { + int i = 0; + while (i < vParts[1].Length && char.IsDigit(vParts[1][i])) i++; + int.TryParse(vParts[1].Substring(0, i), out vMinor); + } + + return versionMinor >= vMinor; + } + catch + { + return false; + } + } + + public static string GetBaseVersion(string version) + { + // e.g. 2020.3.15f1 -> 2020.3 + var parts = version.Split('.'); + if (parts.Length >= 2) + { + return parts[0] + "." + parts[1]; + } + return version; + } + + + public static string SplitTextToRows(string description, int rows) + { + if (rows < 2) return description; + if (string.IsNullOrEmpty(description)) return description; + + int len = description.Length; + if (len <= rows) return description; // too short to split meaningfully + + int firstCut = (len / rows); + int secondCut = (len * 2) / rows; + + string part1 = description.Substring(0, firstCut).Trim(); + string part2 = description.Substring(firstCut, secondCut - firstCut).Trim(); + string part3 = description.Substring(secondCut).Trim(); + + return part1 + Environment.NewLine + part2 + Environment.NewLine + part3; + } + } // class } // namespace diff --git a/UnityLauncherPro/UnityLauncherPro.csproj b/UnityLauncherPro/UnityLauncherPro.csproj index 5fe024b..5883d18 100644 --- a/UnityLauncherPro/UnityLauncherPro.csproj +++ b/UnityLauncherPro/UnityLauncherPro.csproj @@ -9,6 +9,7 @@ UnityLauncherPro UnityLauncherPro v4.8 + 8.0 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 @@ -64,6 +65,7 @@ + @@ -83,14 +85,20 @@ MSBuild:Compile Designer + + SearchBoxControl.xaml + + + + @@ -101,6 +109,8 @@ + + @@ -119,6 +129,9 @@ UpgradeWindow.xaml + + MSBuild:Compile + Designer @@ -177,6 +190,8 @@ SettingsSingleFileGenerator Settings.Designer.cs + + diff --git a/UnityLauncherPro/UpgradeWindow.xaml.cs b/UnityLauncherPro/UpgradeWindow.xaml.cs index bc2ef62..0ce7708 100644 --- a/UnityLauncherPro/UpgradeWindow.xaml.cs +++ b/UnityLauncherPro/UpgradeWindow.xaml.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -21,37 +19,42 @@ public UpgradeWindow(string currentVersion, string projectPath, string commandLi txtCurrentVersion.Text = currentVersion; txtCurrentPlatform.Text = Tools.GetTargetPlatform(projectPath); - if (gridAvailableVersions.ItemsSource == null) + if (!ReferenceEquals(gridAvailableVersions.ItemsSource, MainWindow.unityInstallationsSource)) { gridAvailableVersions.ItemsSource = MainWindow.unityInstallationsSource; } gridAvailableVersions.SelectedItem = null; - // we have current version info in project - // enable release and dl buttons - btnOpenReleasePage.IsEnabled = true; - btnDownload.IsEnabled = true; - // if dont have exact version, show red outline - if (MainWindow.unityInstalledVersions.ContainsKey(currentVersion) == false) + if (currentVersion == null || MainWindow.unityInstalledVersions.ContainsKey(currentVersion) == false) { txtCurrentVersion.BorderBrush = Brushes.Red; txtCurrentVersion.BorderThickness = new Thickness(1); } - // find nearest version - string nearestVersion = Tools.FindNearestVersion(currentVersion, MainWindow.unityInstalledVersions.Keys.ToList()); - if (nearestVersion != null) + if (currentVersion != null) { - // select nearest version - for (int i = 0; i < MainWindow.unityInstallationsSource.Count; i++) + // we know the version, enable buttons + btnOpenReleasePage.IsEnabled = true; + btnDownload.IsEnabled = true; + + // remove china c1 from version, NOTE not used anymore.. its Tuanjie + if (currentVersion.Contains("c")) currentVersion = currentVersion.Replace("c1", ""); + // find nearest version + string nearestVersion = Tools.FindNearestVersion(currentVersion, MainWindow.unityInstalledVersions.Keys.ToList()); + + if (nearestVersion != null && MainWindow.unityInstallationsSource != null) { - if (MainWindow.unityInstallationsSource[i].Version == nearestVersion) + // select nearest version + for (int i = 0; i < MainWindow.unityInstallationsSource.Count; i++) { - gridAvailableVersions.SelectedIndex = i; - gridAvailableVersions.ScrollIntoView(gridAvailableVersions.SelectedItem); - break; + if (MainWindow.unityInstallationsSource[i].Version == nearestVersion) + { + gridAvailableVersions.SelectedIndex = i; + gridAvailableVersions.ScrollIntoView(gridAvailableVersions.SelectedItem); + break; + } } } } @@ -75,7 +78,7 @@ private void BtnOpenReleasePage_Click(object sender, RoutedEventArgs e) Tools.OpenReleaseNotes(txtCurrentVersion.Text); } - + private void BtnDownloadEditor_Click(object sender, RoutedEventArgs e) { Tools.DownloadInBrowser(txtCurrentVersion.Text); @@ -146,6 +149,13 @@ private void GridAvailableVersions_PreviewMouseDoubleClick(object sender, MouseB void Upgrade() { var k = (UnityInstallation)gridAvailableVersions.SelectedItem; + + if (k == null) + { + DialogResult = false; + return; + } + upgradeVersion = k.Version; DialogResult = true; } diff --git a/UnityLauncherProInstaller/UnityLauncherProInstaller.vdproj b/UnityLauncherProInstaller/UnityLauncherProInstaller.vdproj new file mode 100644 index 0000000..1faa96f --- /dev/null +++ b/UnityLauncherProInstaller/UnityLauncherProInstaller.vdproj @@ -0,0 +1,835 @@ +"DeployProject" +{ +"VSVersion" = "3:800" +"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" +"IsWebType" = "8:FALSE" +"ProjectName" = "8:UnityLauncherProInstaller" +"LanguageId" = "3:1033" +"CodePage" = "3:1252" +"UILanguageId" = "3:1033" +"SccProjectName" = "8:" +"SccLocalPath" = "8:" +"SccAuxPath" = "8:" +"SccProvider" = "8:" + "Hierarchy" + { + "Entry" + { + "MsmKey" = "8:_56C1F622109E4E31983910358EA5BCB3" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_7E1343CBA8EB43B8864B8A7BBEB62BCA" + "OwnerKey" = "8:_UNDEFINED" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_B4800275BE183C6B5A0394F826FCA770" + "OwnerKey" = "8:_7E1343CBA8EB43B8864B8A7BBEB62BCA" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_UNDEFINED" + "OwnerKey" = "8:_7E1343CBA8EB43B8864B8A7BBEB62BCA" + "MsmSig" = "8:_UNDEFINED" + } + "Entry" + { + "MsmKey" = "8:_UNDEFINED" + "OwnerKey" = "8:_B4800275BE183C6B5A0394F826FCA770" + "MsmSig" = "8:_UNDEFINED" + } + } + "Configurations" + { + "Debug" + { + "DisplayName" = "8:Debug" + "IsDebugOnly" = "11:TRUE" + "IsReleaseOnly" = "11:FALSE" + "OutputFilename" = "8:Debug\\UnityLauncherProInstaller.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:2" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:1" + "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" + { + "Enabled" = "11:TRUE" + "PromptEnabled" = "11:TRUE" + "PrerequisitesLocation" = "2:1" + "Url" = "8:" + "ComponentsUrl" = "8:" + "Items" + { + "{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:{88EC2DC6-E1F3-4355-B2F4-CF0345A0D5AF}" + { + "Name" = "8:Microsoft .NET Framework 4.7.2 (x86 and x64)" + "ProductCode" = "8:{88EC2DC6-E1F3-4355-B2F4-CF0345A0D5AF}" + } + } + } + } + "Release" + { + "DisplayName" = "8:Release" + "IsDebugOnly" = "11:FALSE" + "IsReleaseOnly" = "11:TRUE" + "OutputFilename" = "8:Release\\UnityLauncherPro-Installer.msi" + "PackageFilesAs" = "3:2" + "PackageFileSize" = "3:-2147483648" + "CabType" = "3:1" + "Compression" = "3:2" + "SignOutput" = "11:FALSE" + "CertificateFile" = "8:" + "PrivateKeyFile" = "8:" + "TimeStampServer" = "8:" + "InstallerBootstrapper" = "3:1" + "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" + { + "Enabled" = "11:FALSE" + "PromptEnabled" = "11:TRUE" + "PrerequisitesLocation" = "2:1" + "Url" = "8:" + "ComponentsUrl" = "8:" + "Items" + { + } + } + } + } + "Deployable" + { + "CustomAction" + { + } + "DefaultFeature" + { + "Name" = "8:DefaultFeature" + "Title" = "8:" + "Description" = "8:" + } + "ExternalPersistence" + { + "LaunchCondition" + { + "{A06ECF26-33A3-4562-8140-9B0E340D4F24}:_C6DAFA7E7FB6480FB6A878EC2AE20521" + { + "Name" = "8:.NET Framework" + "Message" = "8:[VSDNETMSG]" + "FrameworkVersion" = "8:.NETFramework,Version=v4.8" + "AllowLaterVersions" = "11:FALSE" + "InstallUrl" = "8:http://go.microsoft.com/fwlink/?LinkId=863262" + } + } + } + "File" + { + "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_56C1F622109E4E31983910358EA5BCB3" + { + "SourcePath" = "8:..\\UnityLauncherPro\\Images\\icon.ico" + "TargetName" = "8:icon.ico" + "Tag" = "8:" + "Folder" = "8:_68B52FAF3D0E46A7BB2DA063CB0BC570" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + } + "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_B4800275BE183C6B5A0394F826FCA770" + { + "AssemblyRegister" = "3:1" + "AssemblyIsInGAC" = "11:FALSE" + "AssemblyAsmDisplayName" = "8:System.Net.Http, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" + "ScatterAssemblies" + { + "_B4800275BE183C6B5A0394F826FCA770" + { + "Name" = "8:System.Net.Http.dll" + "Attributes" = "3:512" + } + } + "SourcePath" = "8:System.Net.Http.dll" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_68B52FAF3D0E46A7BB2DA063CB0BC570" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:TRUE" + "IsDependency" = "11:TRUE" + "IsolateTo" = "8:" + } + } + "FileType" + { + } + "Folder" + { + "{1525181F-901A-416C-8A58-119130FE478E}:_19ED9D0C790D4F4D9166B197E25DE46F" + { + "Name" = "8:#1919" + "AlwaysCreate" = "11:TRUE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:ProgramMenuFolder" + "Folders" + { + } + } + "{1525181F-901A-416C-8A58-119130FE478E}:_2963B7ED2A0A442D83028448A89C2E88" + { + "Name" = "8:#1916" + "AlwaysCreate" = "11:TRUE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:DesktopFolder" + "Folders" + { + } + } + "{3C67513D-01DD-4637-8A68-80971EB9504F}:_68B52FAF3D0E46A7BB2DA063CB0BC570" + { + "DefaultLocation" = "8:[ProgramFilesFolder][Manufacturer]\\[ProductName]" + "Name" = "8:#1925" + "AlwaysCreate" = "11:TRUE" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Property" = "8:TARGETDIR" + "Folders" + { + } + } + } + "LaunchCondition" + { + } + "Locator" + { + } + "MsiBootstrapper" + { + "LangId" = "3:1033" + "RequiresElevation" = "11:FALSE" + } + "Product" + { + "Name" = "8:Microsoft Visual Studio" + "ProductName" = "8:UnityLauncherPro" + "ProductCode" = "8:{904A3434-1B2D-42CB-AC64-C311F3956044}" + "PackageCode" = "8:{1E8EE2AB-7275-4599-9F22-E57650F33D2B}" + "UpgradeCode" = "8:{4F3ACBAF-4673-4808-9A4F-50ED1E82F59F}" + "AspNetVersion" = "8:2.0.50727.0" + "RestartWWWService" = "11:FALSE" + "RemovePreviousVersions" = "11:TRUE" + "DetectNewerInstalledVersion" = "11:TRUE" + "InstallAllUsers" = "11:FALSE" + "ProductVersion" = "8:0.0.2" + "Manufacturer" = "8:unitycoder.com" + "ARPHELPTELEPHONE" = "8:" + "ARPHELPLINK" = "8:https://github.com/unitycoder/UnityLauncherPro" + "Title" = "8:UnityLauncherPro" + "Subject" = "8:" + "ARPCONTACT" = "8:unitycoder.com" + "Keywords" = "8:unity" + "ARPCOMMENTS" = "8:Custom Unity Project Launcher" + "ARPURLINFOABOUT" = "8:" + "ARPPRODUCTICON" = "8:" + "ARPIconIndex" = "3:0" + "SearchPath" = "8:" + "UseSystemSearchPath" = "11:TRUE" + "TargetPlatform" = "3:0" + "PreBuildEvent" = "8:" + "PostBuildEvent" = "8:" + "RunPostBuildEvent" = "3:0" + } + "Registry" + { + "HKLM" + { + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_BBC8E7EDED764786B28BA436E2F2E3FA" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_53F28CB8B5D5476E83FCE79B61696A5A" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCU" + { + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_7C8A921E5D854F9293E898B1E5D7903E" + { + "Name" = "8:Software" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + "{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_00642DD831ED49BF966A3921B4EE13E6" + { + "Name" = "8:[Manufacturer]" + "Condition" = "8:" + "AlwaysCreate" = "11:FALSE" + "DeleteAtUninstall" = "11:FALSE" + "Transitive" = "11:FALSE" + "Keys" + { + } + "Values" + { + } + } + } + "Values" + { + } + } + } + } + "HKCR" + { + "Keys" + { + } + } + "HKU" + { + "Keys" + { + } + } + "HKPU" + { + "Keys" + { + } + } + } + "Sequences" + { + } + "Shortcut" + { + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_43C0E1ACE07D4DBEA0C42EC6C9AD587A" + { + "Name" = "8:UnityLauncherPro" + "Arguments" = "8:" + "Description" = "8:" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_7E1343CBA8EB43B8864B8A7BBEB62BCA" + "Folder" = "8:_19ED9D0C790D4F4D9166B197E25DE46F" + "WorkingFolder" = "8:_68B52FAF3D0E46A7BB2DA063CB0BC570" + "Icon" = "8:_56C1F622109E4E31983910358EA5BCB3" + "Feature" = "8:" + } + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_C0602FC78BDC49EEBC2B8D63BF602DB2" + { + "Name" = "8:UnityLauncherPro" + "Arguments" = "8:" + "Description" = "8:" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_68B52FAF3D0E46A7BB2DA063CB0BC570" + "Folder" = "8:_68B52FAF3D0E46A7BB2DA063CB0BC570" + "WorkingFolder" = "8:_19ED9D0C790D4F4D9166B197E25DE46F" + "Icon" = "8:_56C1F622109E4E31983910358EA5BCB3" + "Feature" = "8:" + } + "{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_DC1220A510594DA78B14B2A948B17BB5" + { + "Name" = "8:UnityLauncherPro" + "Arguments" = "8:" + "Description" = "8:" + "ShowCmd" = "3:1" + "IconIndex" = "3:0" + "Transitive" = "11:FALSE" + "Target" = "8:_7E1343CBA8EB43B8864B8A7BBEB62BCA" + "Folder" = "8:_2963B7ED2A0A442D83028448A89C2E88" + "WorkingFolder" = "8:_68B52FAF3D0E46A7BB2DA063CB0BC570" + "Icon" = "8:_56C1F622109E4E31983910358EA5BCB3" + "Feature" = "8:" + } + } + "UserInterface" + { + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_03C4E4CC62D94357B185E5414076DE3C" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdBasicDialogs.wim" + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_147ABB7D36884065B2CC6D33E436F4F1" + { + "Name" = "8:#1900" + "Sequence" = "3:1" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_2E594B7DED8F49399108B61F7333A382" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "InstallAllUsersVisible" + { + "Name" = "8:InstallAllUsersVisible" + "DisplayName" = "8:#1059" + "Description" = "8:#1159" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:0" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_AE9BBF03F4254EC78B72E1DA3A342CD2" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8:This is open-source application from https://github.com/unitycoder/UnityLauncherPro" + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_C6CB2BBAEA624833A4382BCB39FA64B4" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_6FD98948481641629052D2D3CAF5F3EC" + { + "Name" = "8:#1901" + "Sequence" = "3:2" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_452D9579D991490E998DC755F1371F7B" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_A6508805A9374BCB8029A844ED81291A" + { + "UseDynamicProperties" = "11:FALSE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdUserInterface.wim" + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_BA4BFC6354F84AF4B5DAA3D1002FD75E" + { + "Name" = "8:#1900" + "Sequence" = "3:2" + "Attributes" = "3:1" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_ACD96EE1DEDB42B59E67289A08B39190" + { + "Sequence" = "3:200" + "DisplayName" = "8:Installation Folder" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFolderDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_AEF9C7C83C86472088534BF4856BB7AB" + { + "Sequence" = "3:300" + "DisplayName" = "8:Confirm Installation" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_DA356B2059B947B59EFF4A9037C11614" + { + "Sequence" = "3:100" + "DisplayName" = "8:Welcome" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "CopyrightWarning" + { + "Name" = "8:CopyrightWarning" + "DisplayName" = "8:#1002" + "Description" = "8:#1102" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8:This is open-source application from https://github.com/unitycoder/UnityLauncherPro" + "DefaultValue" = "8:#1202" + "UsePlugInResources" = "11:TRUE" + } + "Welcome" + { + "Name" = "8:Welcome" + "DisplayName" = "8:#1003" + "Description" = "8:#1103" + "Type" = "3:3" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:1" + "Value" = "8:#1203" + "DefaultValue" = "8:#1203" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_D76F1CBBB8244A92B7828779EDBE19E0" + { + "Name" = "8:#1901" + "Sequence" = "3:1" + "Attributes" = "3:2" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_C84B873F85C44D4FA8E3AA32E8FB9A36" + { + "Sequence" = "3:100" + "DisplayName" = "8:Progress" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdProgressDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "ShowProgress" + { + "Name" = "8:ShowProgress" + "DisplayName" = "8:#1009" + "Description" = "8:#1109" + "Type" = "3:5" + "ContextData" = "8:1;True=1;False=0" + "Attributes" = "3:0" + "Setting" = "3:0" + "Value" = "3:1" + "DefaultValue" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_DABCB1736D1B4216B9E2922C80D06DC6" + { + "Name" = "8:#1902" + "Sequence" = "3:1" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_E782EE25F33D462DAC7BFBC248F22B2A" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + "UpdateText" + { + "Name" = "8:UpdateText" + "DisplayName" = "8:#1058" + "Description" = "8:#1158" + "Type" = "3:15" + "ContextData" = "8:" + "Attributes" = "3:0" + "Setting" = "3:2" + "Value" = "8:Please use Windows Update to check for any critical updates to the .NET 4.8 Framework." + "DefaultValue" = "8:#1258" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_EA095038010E4A17BE1470B74EBD21B7" + { + "Name" = "8:#1902" + "Sequence" = "3:2" + "Attributes" = "3:3" + "Dialogs" + { + "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_E429B6085A7046E699D077EBC15B0E34" + { + "Sequence" = "3:100" + "DisplayName" = "8:Finished" + "UseDynamicProperties" = "11:TRUE" + "IsDependency" = "11:FALSE" + "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" + "Properties" + { + "BannerBitmap" + { + "Name" = "8:BannerBitmap" + "DisplayName" = "8:#1001" + "Description" = "8:#1101" + "Type" = "3:8" + "ContextData" = "8:Bitmap" + "Attributes" = "3:4" + "Setting" = "3:1" + "UsePlugInResources" = "11:TRUE" + } + } + } + } + } + } + "MergeModule" + { + } + "ProjectOutput" + { + "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_7E1343CBA8EB43B8864B8A7BBEB62BCA" + { + "SourcePath" = "8:..\\UnityLauncherPro\\bin\\Release\\UnityLauncherPro.exe" + "TargetName" = "8:" + "Tag" = "8:" + "Folder" = "8:_68B52FAF3D0E46A7BB2DA063CB0BC570" + "Condition" = "8:" + "Transitive" = "11:FALSE" + "Vital" = "11:TRUE" + "ReadOnly" = "11:FALSE" + "Hidden" = "11:FALSE" + "System" = "11:FALSE" + "Permanent" = "11:FALSE" + "SharedLegacy" = "11:FALSE" + "PackageAs" = "3:1" + "Register" = "3:1" + "Exclude" = "11:FALSE" + "IsDependency" = "11:FALSE" + "IsolateTo" = "8:" + "ProjectOutputGroupRegister" = "3:1" + "OutputConfiguration" = "8:" + "OutputGroupCanonicalName" = "8:Built" + "OutputProjectGuid" = "8:{EC78D91A-3E63-4CAA-8BC3-9673A30FDA45}" + "ShowKeyOutput" = "11:TRUE" + "ExcludeFilters" + { + } + } + } + } +}