Compare commits

..

6 Commits

Author SHA1 Message Date
Serge
02e700c03c Cleanup 2024-02-29 17:03:48 +01:00
Serge
35977d007e GPU Power UI Tweaks 2024-02-29 16:07:11 +01:00
Serge
3b9f8de0ab GPU Power tweaks 2024-02-29 15:54:09 +01:00
Serge
1e3a16ae45 Merge branch 'main' into gpu_tgp 2024-02-28 23:40:57 +01:00
Serge
a520c438da Version bump 2024-02-28 17:15:15 +01:00
Serge
6b45795888 GPU TGP setting for supported models 2024-02-28 15:43:16 +01:00
18 changed files with 1049 additions and 198 deletions

View File

@@ -365,9 +365,9 @@ public static class AppConfig
return ContainsModel("ProArt");
}
public static bool IsVivoZenbook()
public static bool IsVivobook()
{
return ContainsModel("Vivobook") || ContainsModel("Zenbook");
return ContainsModel("Vivobook");
}
// Devices with bugged bios command to change brightness
@@ -514,7 +514,7 @@ public static class AppConfig
try
{
var (bios, model) = GetBiosAndModel();
return (Int32.Parse(bios) == 317 || Int32.Parse(bios) == 316);
return (Int32.Parse(bios) == 317);
}
catch
{
@@ -522,19 +522,9 @@ public static class AppConfig
}
}
public static bool IsResetRequired()
{
return ContainsModel("GA403");
}
public static bool IsFanRequired()
{
return ContainsModel("GA402X") || ContainsModel("G513") || ContainsModel("G713R") || ContainsModel("G713P") || ContainsModel("GU605") || ContainsModel("GA403");
}
public static bool IsAMDLight()
{
return ContainsModel("GA402X") || ContainsModel("GU605") || ContainsModel("GA403") || ContainsModel("FA507N") || ContainsModel("FA507X") || ContainsModel("FA707N") || ContainsModel("FA707X");
return ContainsModel("GA402X") || ContainsModel("G513") || ContainsModel("G713R") || ContainsModel("G713P");
}
public static bool IsPowerRequired()

View File

@@ -294,11 +294,6 @@ public class AsusACPI
MaxGPUPower = 70;
}
if (AppConfig.IsSlash())
{
MaxGPUPower = 25;
}
if (AppConfig.DynamicBoost5())
{
MaxGPUBoost = 5;
@@ -308,14 +303,6 @@ public class AsusACPI
{
MaxGPUBoost = 15;
}
if (AppConfig.IsAMDLight())
{
MaxTotal = 90;
}
}
public void Control(uint dwIoControlCode, byte[] lpInBuffer, byte[] lpOutBuffer)
@@ -429,16 +416,9 @@ public class AsusACPI
{
return null;
}
}
public int SetVivoMode(int mode)
{
if (mode == 1) mode = 2;
else if (mode == 2) mode = 1;
return Program.acpi.DeviceSet(VivoBookMode, mode, "VivoMode");
}
public int SetGPUEco(int eco)
{
int ecoFlag = DeviceGet(GPUEco);
@@ -569,7 +549,7 @@ public class AsusACPI
break;
}
//Logger.WriteLine($"GetFan {device} :" + BitConverter.ToString(result));
Logger.WriteLine($"GetFan {device} :" + BitConverter.ToString(result));
return result;

View File

@@ -24,17 +24,29 @@ namespace GHelper.Display
}
}
public void SetBrightness(int brightness = -1)
public void SaveGamma()
{
if (!AppConfig.IsOLED()) return;
var screenName = ScreenNative.FindLaptopScreen();
if (screenName is null) return;
if (brightness >= 0) AppConfig.Set("brightness", brightness);
else brightness = AppConfig.Get("brightness");
if (brightness >= 0) SetGamma(brightness);
try
{
var handle = ScreenNative.CreateDC(screenName, screenName, null, IntPtr.Zero);
var gammaRamp = new GammaRamp();
if (ScreenNative.GetDeviceGammaRamp(handle, ref gammaRamp))
{
var gamma = new DisplayGammaRamp(gammaRamp);
Logger.WriteLine("Gamma R: " + string.Join("-", gamma.Red));
Logger.WriteLine("Gamma G: " + string.Join("-", gamma.Green));
Logger.WriteLine("Gamma B: " + string.Join("-", gamma.Blue));
}
}
catch (Exception ex)
{
Logger.WriteLine(ex.ToString());
}
}
public void SetGamma(int brightness = 100)
{
var bright = Math.Round((float)brightness / 200 + 0.5, 2);
@@ -51,15 +63,15 @@ namespace GHelper.Display
if (ScreenNative.GetDeviceGammaRamp(handle, ref gammaDump))
{
gammaRamp = new DisplayGammaRamp(gammaDump);
//Logger.WriteLine("Gamma R: " + string.Join("-", gammaRamp.Red));
//Logger.WriteLine("Gamma G: " + string.Join("-", gammaRamp.Green));
//Logger.WriteLine("Gamma B: " + string.Join("-", gammaRamp.Blue));
Logger.WriteLine("Gamma R: " + string.Join("-", gammaRamp.Red));
Logger.WriteLine("Gamma G: " + string.Join("-", gammaRamp.Green));
Logger.WriteLine("Gamma B: " + string.Join("-", gammaRamp.Blue));
}
}
if (gammaRamp is null || !gammaRamp.IsOriginal())
{
Logger.WriteLine("Not default Gamma");
Logger.WriteLine("Default Gamma");
gammaRamp = new DisplayGammaRamp();
}

View File

@@ -9,7 +9,7 @@ namespace GHelper.Fan
public const int XGM_FAN_MAX = 72;
public const int INADEQUATE_MAX = 104;
public const int INADEQUATE_MAX = 92;
const int FAN_COUNT = 3;

View File

@@ -762,10 +762,7 @@ namespace GHelper
private void TrackPower_MouseUp(object? sender, MouseEventArgs e)
{
Task.Run(() =>
{
modeControl.AutoPower(true);
});
modeControl.AutoPower();
}
@@ -1008,7 +1005,7 @@ namespace GHelper
try
{
if (chartCount > 2)
Size = MinimumSize = new Size(Size.Width, Math.Max(MinimumSize.Height, (int)(ControlHelper.GetDpiScale(this).Value * (chartCount * 200 + 100))));
Size = MinimumSize = new Size(Size.Width, (int)(ControlHelper.GetDpiScale(this).Value * (chartCount * 200 + 100)));
}
catch (Exception ex)
{
@@ -1115,7 +1112,6 @@ namespace GHelper
if (gpuVisible)
{
int gpuPowerVar = Program.acpi.DeviceGet(AsusACPI.GPU_POWER);
Logger.WriteLine("Default GPU Power: " + gpuPowerVar);
trackGPUClockLimit.Value = NvidiaGpuControl.MaxClockLimit;
trackGPUCore.Value = 0;
@@ -1123,7 +1119,7 @@ namespace GHelper
trackGPUBoost.Value = AsusACPI.MaxGPUBoost;
trackGPUTemp.Value = AsusACPI.MaxGPUTemp;
trackGPUPower.Value = Math.Max(Math.Min((gpuPowerVar >= 0) ? gpuPowerVar : AsusACPI.MaxGPUPower, AsusACPI.MaxGPUPower), AsusACPI.MinGPUPower);
trackGPUPower.Value = (gpuPowerVar >= 0) ? gpuPowerVar : AsusACPI.MaxGPUPower;
AppConfig.SetMode("gpu_boost", trackGPUBoost.Value);
AppConfig.SetMode("gpu_temp", trackGPUTemp.Value);

View File

@@ -101,8 +101,6 @@ namespace GHelper.Helpers
if (Program.settingsForm.Visible)
Program.screenControl.InitScreen();
Program.screenControl.SetBrightness();
}
private static int CheckAndSaveLidAction()

View File

@@ -85,7 +85,7 @@ namespace GHelper.Input
InitBacklightTimer();
if (AppConfig.IsVivoZenbook()) Program.acpi.DeviceSet(AsusACPI.FnLock, AppConfig.Is("fn_lock") ? 1 : 0, "FnLock");
if (AppConfig.ContainsModel("VivoBook")) Program.acpi.DeviceSet(AsusACPI.FnLock, AppConfig.Is("fn_lock") ? 1 : 0, "FnLock");
}
@@ -151,7 +151,7 @@ namespace GHelper.Input
// FN-Lock group
if (AppConfig.Is("fn_lock") && !AppConfig.IsVivoZenbook())
if (AppConfig.Is("fn_lock") && !AppConfig.ContainsModel("VivoBook"))
for (Keys i = Keys.F1; i <= Keys.F11; i++) hook.RegisterHotKey(ModifierKeys.None, i);
// Arrow-lock group
@@ -500,7 +500,7 @@ namespace GHelper.Input
case "micmute":
bool muteStatus = Audio.ToggleMute();
Program.toast.RunToast(muteStatus ? "Muted" : "Unmuted", muteStatus ? ToastIcon.MicrophoneMute : ToastIcon.Microphone);
if (AppConfig.IsVivoZenbook()) Program.acpi.DeviceSet(AsusACPI.MicMuteLed, muteStatus ? 1 : 0, "MicmuteLed");
if (AppConfig.IsVivobook()) Program.acpi.DeviceSet(AsusACPI.MicMuteLed, muteStatus ? 1 : 0, "MicmuteLed");
break;
case "brightness_up":
SetBrightness(+10);
@@ -568,7 +568,7 @@ namespace GHelper.Input
int fnLock = AppConfig.Is("fn_lock") ? 0 : 1;
AppConfig.Set("fn_lock", fnLock);
if (AppConfig.IsVivoZenbook())
if (AppConfig.ContainsModel("VivoBook"))
Program.acpi.DeviceSet(AsusACPI.FnLock, fnLock == 1 ? 1 : 0, "FnLock");
else
Program.settingsForm.BeginInvoke(Program.inputDispatcher.RegisterKeys);

View File

@@ -62,46 +62,33 @@ namespace GHelper.Mode
if (!Modes.Exists(mode)) mode = 0;
customFans = false;
customPower = 0;
settings.ShowMode(mode);
SetModeLabel();
Modes.SetCurrent(mode);
int status = Program.acpi.DeviceSet(AsusACPI.PerformanceMode, AppConfig.IsManualModeRequired() ? AsusACPI.PerformanceManual : Modes.GetBase(mode), "Mode");
Task.Run(async () =>
// Vivobook fallback
if (status != 1)
{
bool reset = AppConfig.IsResetRequired() && (Modes.GetBase(oldMode) == Modes.GetBase(mode)) && customPower > 0;
customFans = false;
customPower = 0;
SetModeLabel();
// Workaround for not properly resetting limits on G14 2024
if (reset)
{
Program.acpi.DeviceSet(AsusACPI.PerformanceMode, (Modes.GetBase(oldMode) != 1) ? AsusACPI.PerformanceTurbo : AsusACPI.PerformanceBalanced, "Reset");
await Task.Delay(TimeSpan.FromMilliseconds(1500));
}
int status = Program.acpi.DeviceSet(AsusACPI.PerformanceMode, AppConfig.IsManualModeRequired() ? AsusACPI.PerformanceManual : Modes.GetBase(mode), "Mode");
// Vivobook fallback
if (status != 1) Program.acpi.SetVivoMode(Modes.GetBase(mode));
SetGPUClocks();
AutoFans();
await Task.Delay(TimeSpan.FromMilliseconds(1000));
AutoPower();
});
int vivoMode = Modes.GetBase(mode);
if (vivoMode == 1) vivoMode = 2;
else if (vivoMode == 2) vivoMode = 1;
Program.acpi.DeviceSet(AsusACPI.VivoBookMode, vivoMode, "VivoMode");
}
if (AppConfig.Is("xgm_fan") && Program.acpi.IsXGConnected()) XGM.Reset();
if (notify)
Program.toast.RunToast(Modes.GetCurrentName(), SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online ? ToastIcon.Charger : ToastIcon.Battery);
SetGPUClocks();
AutoFans();
AutoPower(1000);
// Power plan from config or defaulting to balanced
if (AppConfig.GetModeString("scheme") is not null)
@@ -158,17 +145,18 @@ namespace GHelper.Mode
Program.acpi.SetFanCurve(AsusFan.Mid, AppConfig.GetFanConfig(AsusFan.Mid));
// Alternative way to set fan curve
// something went wrong, resetting to default profile
if (cpuResult != 1 || gpuResult != 1)
{
cpuResult = Program.acpi.SetFanRange(AsusFan.CPU, AppConfig.GetFanConfig(AsusFan.CPU));
gpuResult = Program.acpi.SetFanRange(AsusFan.GPU, AppConfig.GetFanConfig(AsusFan.GPU));
// Something went wrong, resetting to default profile
if (cpuResult != 1 || gpuResult != 1)
{
Program.acpi.DeviceSet(AsusACPI.PerformanceMode, Modes.GetCurrentBase(), "Reset Mode");
settings.LabelFansResult("Model doesn't support custom fan curves");
int mode = Modes.GetCurrentBase();
Logger.WriteLine("ASUS BIOS rejected fan curve, resetting mode to " + mode);
Program.acpi.DeviceSet(AsusACPI.PerformanceMode, mode, "Reset Mode");
settings.LabelFansResult("ASUS BIOS rejected fan curve");
}
}
else
@@ -194,25 +182,52 @@ namespace GHelper.Mode
}
public void AutoPower(bool launchAsAdmin = false)
public void AutoPower(int delay = 0)
{
customPower = 0;
bool applyPower = AppConfig.IsMode("auto_apply_power");
bool applyFans = AppConfig.IsMode("auto_apply");
//bool applyGPU = true;
if (applyPower && !applyFans && (AppConfig.IsFanRequired() || AppConfig.IsManualModeRequired()))
if (applyPower && !applyFans)
{
AutoFans(true);
Thread.Sleep(500);
// force fan curve for misbehaving bios PPTs on some models
if (AppConfig.IsFanRequired())
{
delay = 500;
AutoFans(true);
}
// Fix for models that don't support PPT settings in all modes, setting a "manual" mode for them
if (AppConfig.IsManualModeRequired())
{
AutoFans(true);
}
}
if (applyPower) SetPower(launchAsAdmin);
if (delay > 0)
{
var timer = new System.Timers.Timer(delay);
timer.Elapsed += delegate
{
timer.Stop();
timer.Dispose();
Thread.Sleep(500);
SetGPUPower();
AutoRyzen();
if (applyPower) SetPower();
Thread.Sleep(500);
SetGPUPower();
AutoRyzen();
};
timer.Start();
}
else
{
if (applyPower) SetPower(true);
SetGPUPower();
AutoRyzen();
}
}

View File

@@ -37,12 +37,7 @@
}
public override int DPIIncrements()
{
return 50;
}
public override int MinDPI()
{
return 50;
return 100;
}
public override bool HasDebounceSetting()

View File

@@ -7,10 +7,6 @@
{
}
public StrixImpactII(ushort pid) : base(0x0B05, pid, "mi_00", false)
{
}
public override int DPIProfileCount()
{
return 4;
@@ -178,19 +174,4 @@
}
}
}
public class StrixImpactIIElectroPunk : StrixImpactII
{
public StrixImpactIIElectroPunk() : base(0x1956)
{
}
public override string GetDisplayName()
{
return "ROG Strix Impact II Electro Punk";
}
}
}

View File

@@ -209,7 +209,6 @@ namespace GHelper.Peripherals
DetectMouse(new PugioII());
DetectMouse(new PugioIIWired());
DetectMouse(new StrixImpactII());
DetectMouse(new StrixImpactIIElectroPunk());
DetectMouse(new Chakram());
DetectMouse(new ChakramWired());
DetectMouse(new ChakramCore());

View File

@@ -124,10 +124,10 @@
<value>Verbindung zu ASUS ACPI fehlgeschlagen. G-Helper kann nicht ausgeführt werden. Bitte installiere ASUS System Control Interface.</value>
</data>
<data name="AlertAPUMemoryRestart" xml:space="preserve">
<value>Gerät neu starten, um Änderungen anzuwenden</value>
<value>Restart your device to apply changes</value>
</data>
<data name="AlertAPUMemoryRestartTitle" xml:space="preserve">
<value>Jetzt neu starten?</value>
<value>Restart now?</value>
</data>
<data name="AlertDGPU" xml:space="preserve">
<value>Die GPU wird gerade verwendet. Trotzdem deaktivieren?</value>
@@ -250,7 +250,7 @@
<value>Im Betrieb</value>
</data>
<data name="BacklightTimeout" xml:space="preserve">
<value>Timeout angeschlossen / bei Akku (0 = An)</value>
<value>Timeout angeschlossen / bei Akku (0 - AN)</value>
</data>
<data name="BacklightTimeoutBattery" xml:space="preserve">
<value>Backlight Timeout when on battery</value>
@@ -289,7 +289,7 @@
<value>Hochfahren</value>
</data>
<data name="BootSound" xml:space="preserve">
<value>Boot-Sound</value>
<value>Boot Sound</value>
</data>
<data name="Brightness" xml:space="preserve">
<value>Helligkeit</value>
@@ -310,7 +310,7 @@
<value>Farbe</value>
</data>
<data name="Contrast" xml:space="preserve">
<value>Kontrast</value>
<value>Contrast</value>
</data>
<data name="Controller" xml:space="preserve">
<value>Controller</value>
@@ -328,7 +328,7 @@
<value>Standard</value>
</data>
<data name="DisableController" xml:space="preserve">
<value>Controller deaktivieren</value>
<value>Disable Controller</value>
</data>
<data name="DisableOnLidClose" xml:space="preserve">
<value>Disable on lid close</value>
@@ -352,7 +352,7 @@
<value>Eco</value>
</data>
<data name="EnableGPUOnShutdown" xml:space="preserve">
<value>Aktiviere GPU beim Herunterfahren (verhindert Problem im Eco-Modus)</value>
<value>Enable GPU on shutdown (prevents issue with Eco mode)</value>
</data>
<data name="EnableOptimusText" xml:space="preserve">
<value>Die dGPU zu deaktivieren, indem Sie in den Eco-Modus wechseln während der Anzeigemodus nicht auf Optimus eingestellt ist, kann zu Problemen mit der Helligkeitseinstellung führen.
@@ -366,7 +366,7 @@ Trotzdem fortfahren?</value>
<value>Energieeinstellungen</value>
</data>
<data name="Export" xml:space="preserve">
<value>Profil exportieren</value>
<value>Export Profile</value>
</data>
<data name="Extra" xml:space="preserve">
<value>Extra</value>
@@ -441,10 +441,10 @@ Trotzdem fortfahren?</value>
<value>Hoch</value>
</data>
<data name="ImageRotation" xml:space="preserve">
<value>Bilddrehung</value>
<value>Image Rotation</value>
</data>
<data name="Import" xml:space="preserve">
<value>Profil importieren</value>
<value>Import Profile</value>
</data>
<data name="KeyBindings" xml:space="preserve">
<value>Tastenbelegung</value>
@@ -534,7 +534,7 @@ Trotzdem fortfahren?</value>
<value>Tastenreaktionsgeschwindigkeit</value>
</data>
<data name="MouseImportFailed" xml:space="preserve">
<value>Import fehlgeschlagen. Die ausgewählte Datei ist kein gültiges Mausprofil oder beschädigt.</value>
<value>Import failed. Selected file is not a valid mouse profile or corrutpted.</value>
</data>
<data name="MouseLiftOffDistance" xml:space="preserve">
<value>Lift Off Distance</value>
@@ -621,7 +621,7 @@ Trotzdem fortfahren?</value>
<value>Schließen</value>
</data>
<data name="Reset" xml:space="preserve">
<value>Zurücksetzen</value>
<value>Reset</value>
</data>
<data name="RestartGPU" xml:space="preserve">
<value>Ein Prozess verhindert den Wechsel in den Eco-Modus. dGPU neu starten? Fortfahren auf eigene Gefahr.</value>
@@ -639,7 +639,7 @@ Trotzdem fortfahren?</value>
<value>Beim Start ausführen</value>
</data>
<data name="ScalingQuality" xml:space="preserve">
<value>Skalierungsqualität</value>
<value>Scaling Quality</value>
</data>
<data name="ScreenPadDown" xml:space="preserve">
<value>Screenpad Helligkeit verringern</value>
@@ -720,7 +720,7 @@ Trotzdem fortfahren?</value>
<value>Version</value>
</data>
<data name="VibrationStrength" xml:space="preserve">
<value>Vibrationsstärke</value>
<value>Vibration Strength</value>
</data>
<data name="VolumeDown" xml:space="preserve">
<value>Lautstärke verringern</value>

View File

@@ -13,7 +13,7 @@ namespace Ryzen
internal class RyzenControl
{
public static int MinCPUUV => AppConfig.Get("min_uv", -40);
public static int MinCPUUV => AppConfig.Get("min_uv", -30);
public const int MaxCPUUV = 0;
public const int MinIGPUUV = -20;

File diff suppressed because it is too large Load Diff

View File

@@ -254,28 +254,16 @@ namespace GHelper
VisualiseFnLock();
buttonFnLock.Click += ButtonFnLock_Click;
panelPerformance.Focus();
InitBrightness();
}
public void InitBrightness()
{
if (!AppConfig.IsOLED()) return;
panelGamma.Visible = true;
int brightness = AppConfig.Get("brightness");
if (brightness >= 0) sliderGamma.Value = brightness;
panelGamma.Visible = AppConfig.IsOLED();
sliderGamma.ValueChanged += SliderGamma_ValueChanged;
labelGamma.Text = sliderGamma.Value + "%";
}
labelGamma.Text = "100%";
panelPerformance.Focus();
}
private void SliderGamma_ValueChanged(object? sender, EventArgs e)
{
screenControl.SetBrightness(sliderGamma.Value);
screenControl.SetGamma(sliderGamma.Value);
labelGamma.Text = sliderGamma.Value + "%";
}

View File

@@ -79,7 +79,7 @@ namespace GHelper.USB
public static Color Color1 = Color.White;
public static Color Color2 = Color.Black;
static bool isACPI = AppConfig.IsTUF() || AppConfig.IsVivoZenbook() || AppConfig.IsProArt();
static bool isACPI = AppConfig.IsTUF() || AppConfig.IsVivobook() || AppConfig.IsProArt();
static bool isStrix = AppConfig.IsStrix() && !AppConfig.IsNoDirectRGB();
static bool isStrix4Zone = AppConfig.IsStrixLimitedRGB();

View File

@@ -36,7 +36,7 @@ namespace GHelper
(bios, model) = AppConfig.GetBiosAndModel();
buttonRefresh.TabStop = false;
updatesCount = 0;
labelUpdates.ForeColor = colorEco;
labelUpdates.Text = Properties.Strings.NoNewUpdates;
@@ -161,36 +161,24 @@ namespace GHelper
});
}
private void _VisualiseNewDriver(int position, int newer, TableLayoutPanel table)
public void VisualiseNewDriver(int position, int newer, TableLayoutPanel table)
{
var label = table.GetControlFromPosition(3, position) as LinkLabel;
if (label != null)
{
if (newer == DRIVER_NEWER)
{
label.AccessibleName = label.AccessibleName + Properties.Strings.NewUpdates;
label.Font = new Font(label.Font, FontStyle.Underline | FontStyle.Bold);
label.LinkColor = colorTurbo;
}
if (newer == DRIVER_NOT_FOUND) label.LinkColor = Color.Gray;
}
}
public void VisualiseNewDriver(int position, int newer, TableLayoutPanel table)
{
if (InvokeRequired)
{
Invoke(delegate
{
_VisualiseNewDriver(position, newer, table);
});
} else
{
_VisualiseNewDriver(position, newer, table);
}
if (newer == DRIVER_NEWER)
{
label.AccessibleName = label.AccessibleName + Properties.Strings.NewUpdates;
label.Font = new Font(label.Font, FontStyle.Underline | FontStyle.Bold);
label.LinkColor = colorTurbo;
}
if (newer == DRIVER_NOT_FOUND) label.LinkColor = Color.Gray;
});
}
}
public void VisualiseNewCount(int updatesCount, TableLayoutPanel table)
@@ -206,7 +194,7 @@ namespace GHelper
});
}
public async void DriversAsync(string url, int type, TableLayoutPanel table)
public async void DriversAsync(string url, int type, TableLayoutPanel table)
{
try
@@ -279,7 +267,7 @@ namespace GHelper
foreach (var localVersion in localVersions)
{
newer = Math.Min(newer, new Version(driver.version).CompareTo(new Version(localVersion)));
Logger.WriteLine(driver.title + " " + deviceID + " " + driver.version + " vs " + localVersion + " = " + newer);
Logger.WriteLine(driver.title + " " + deviceID + " "+ driver.version + " vs " + localVersion + " = " + newer);
}
}

View File

@@ -1,5 +1,5 @@
{
"sdk": {
"version": "7.0.406"
"version": "7.0.400"
}
}