From 84a806bf75040868b345ce85e1ed2954388170b3 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 3 Mar 2022 13:59:43 +1100 Subject: [PATCH] Release 1.9.3 (#1052) ## Bug fixes - Addresses the issue where WindowsSettings plugin results appear higher than other results #1020 - Fixed an issue where full screen mode does not disable hotkey when enabled #1037 - Fixed some potential issues when loading plugins that use shared assembly #1036 - Sorted out a race condition issue causing image loading on some results to fail #1040 - Revised ttf/otf support #935 - Resolved the issue where WebSearch plugin would crash if not connected to internet #977 - Fixed incorrect text for "New Tab" and "New Window" buttons under Settings' default browser section #951 - Fixed typos in plugin title and WindowsSettings name inside the context menu #1056 --- .../Plugin/PluginAssemblyLoader.cs | 24 +------ .../Image/ImageCache.cs | 2 +- Flow.Launcher/Helper/HotKeyMapper.cs | 2 +- Flow.Launcher/Languages/en.xaml | 4 +- Flow.Launcher/Languages/ko.xaml | 4 +- Flow.Launcher/Languages/pt-pt.xaml | 4 +- Flow.Launcher/Languages/sk.xaml | 4 +- Flow.Launcher/ReportWindow.xaml.cs | 4 +- Flow.Launcher/SelectBrowserWindow.xaml | 2 +- Flow.Launcher/SettingWindow.xaml.cs | 2 +- Flow.Launcher/ViewModel/ResultViewModel.cs | 31 ++++++++-- .../PluginsManager.cs | 4 +- .../Flow.Launcher.Plugin.WebSearch/Main.cs | 62 +++++++++---------- .../SuggestionSources/Baidu.cs | 4 +- .../SuggestionSources/Bing.cs | 4 +- .../SuggestionSources/Google.cs | 4 +- .../SuggestionSources/SuggestionSource.cs | 2 +- .../Helper/ResultHelper.cs | 15 ++--- .../plugin.json | 2 +- appveyor.yml | 2 +- 20 files changed, 92 insertions(+), 90 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs b/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs index 515b0bedc..9d76b6be0 100644 --- a/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs +++ b/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs @@ -15,20 +15,6 @@ namespace Flow.Launcher.Core.Plugin private readonly AssemblyName assemblyName; - private static readonly ConcurrentDictionary loadedAssembly; - - static PluginAssemblyLoader() - { - var currentAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - loadedAssembly = new ConcurrentDictionary( - currentAssemblies.Select(x => new KeyValuePair(x.FullName, default))); - - AppDomain.CurrentDomain.AssemblyLoad += (sender, args) => - { - loadedAssembly[args.LoadedAssembly.FullName] = default; - }; - } - internal PluginAssemblyLoader(string assemblyFilePath) { dependencyResolver = new AssemblyDependencyResolver(assemblyFilePath); @@ -47,10 +33,9 @@ namespace Flow.Launcher.Core.Plugin // When resolving dependencies, ignore assembly depenedencies that already exits with Flow.Launcher // Otherwise duplicate assembly will be loaded and some weird behavior will occur, such as WinRT.Runtime.dll // will fail due to loading multiple versions in process, each with their own static instance of registration state - if (assemblyPath == null || ExistsInReferencedPackage(assemblyName)) - return null; + var existAssembly = Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName); - return LoadFromAssemblyPath(assemblyPath); + return existAssembly ?? (assemblyPath == null ? null : LoadFromAssemblyPath(assemblyPath)); } internal Type FromAssemblyGetTypeOfInterface(Assembly assembly, Type type) @@ -58,10 +43,5 @@ namespace Flow.Launcher.Core.Plugin var allTypes = assembly.ExportedTypes; return allTypes.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Any(t => t == type)); } - - internal bool ExistsInReferencedPackage(AssemblyName assemblyName) - { - return loadedAssembly.ContainsKey(assemblyName.FullName); - } } } \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 13277c7d9..04e11bf1a 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -74,7 +74,7 @@ namespace Flow.Launcher.Infrastructure.Image // To delete the images from the data dictionary based on the resizing of the Usage Dictionary // Double Check to avoid concurrent remove if (Data.Count > permissibleFactor * MaxCached) - foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key).ToArray()) + foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) Data.TryRemove(key, out _); semaphore.Release(); } diff --git a/Flow.Launcher/Helper/HotKeyMapper.cs b/Flow.Launcher/Helper/HotKeyMapper.cs index 98327d8da..a3ad20f77 100644 --- a/Flow.Launcher/Helper/HotKeyMapper.cs +++ b/Flow.Launcher/Helper/HotKeyMapper.cs @@ -25,7 +25,7 @@ namespace Flow.Launcher.Helper internal static void OnToggleHotkey(object sender, HotkeyEventArgs args) { - if (!mainViewModel.GameModeStatus) + if (!mainViewModel.ShouldIgnoreHotkeys() && !mainViewModel.GameModeStatus) mainViewModel.ToggleFlowLauncher(); } diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 4b0f4933c..ec355a0ac 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -176,8 +176,8 @@ Browser Browser Name Browser Path - New Window - New Tab + New Window + New Tab Private Mode diff --git a/Flow.Launcher/Languages/ko.xaml b/Flow.Launcher/Languages/ko.xaml index 59485e1f1..7184bef34 100644 --- a/Flow.Launcher/Languages/ko.xaml +++ b/Flow.Launcher/Languages/ko.xaml @@ -175,8 +175,8 @@ 브라우저 브라우저 이름 브라우저 경로 - 새 창 - 새 탭 + 새 창 + 새 탭 프라이빗 모드 diff --git a/Flow.Launcher/Languages/pt-pt.xaml b/Flow.Launcher/Languages/pt-pt.xaml index b641f0e86..764ba542b 100644 --- a/Flow.Launcher/Languages/pt-pt.xaml +++ b/Flow.Launcher/Languages/pt-pt.xaml @@ -176,8 +176,8 @@ Navegador Nome do navegador Caminho do navegador - Nova janela - Novo separador + Nova janela + Novo separador Modo privado diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml index 385eef658..dac746d0f 100644 --- a/Flow.Launcher/Languages/sk.xaml +++ b/Flow.Launcher/Languages/sk.xaml @@ -174,8 +174,8 @@ Prehliadač Názov prehliadača Cesta k prehliadaču - Nové okno - Nová karta + Nové okno + Nová karta Privátny režim diff --git a/Flow.Launcher/ReportWindow.xaml.cs b/Flow.Launcher/ReportWindow.xaml.cs index 7318fe4cd..6a9fd60e0 100644 --- a/Flow.Launcher/ReportWindow.xaml.cs +++ b/Flow.Launcher/ReportWindow.xaml.cs @@ -52,8 +52,8 @@ namespace Flow.Launcher var link = new Hyperlink { IsEnabled = true }; link.Inlines.Add(url); link.NavigateUri = new Uri(url); - link.RequestNavigate += (s, e) => SearchWeb.NewTabInBrowser(e.Uri.ToString()); - link.Click += (s, e) => SearchWeb.NewTabInBrowser(url); + link.RequestNavigate += (s, e) => SearchWeb.OpenInBrowserTab(e.Uri.ToString()); + link.Click += (s, e) => SearchWeb.OpenInBrowserTab(url); paragraph.Inlines.Add(textBeforeUrl); paragraph.Inlines.Add(link); diff --git a/Flow.Launcher/SelectBrowserWindow.xaml b/Flow.Launcher/SelectBrowserWindow.xaml index 79e27e63f..98bc391dd 100644 --- a/Flow.Launcher/SelectBrowserWindow.xaml +++ b/Flow.Launcher/SelectBrowserWindow.xaml @@ -196,7 +196,7 @@ VerticalAlignment="Center" Orientation="Horizontal"> + Content="{DynamicResource defaultBrowser_newTab}"> diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 338b96406..15babee8b 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -232,7 +232,7 @@ namespace Flow.Launcher var uri = new Uri(website); if (Uri.CheckSchemeName(uri.Scheme)) { - website.NewTabInBrowser(); + website.OpenInBrowserTab(); } } } diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 908de0c09..4d32d792d 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -7,11 +7,16 @@ using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using System.IO; +using System.Drawing.Text; +using System.Collections.Generic; namespace Flow.Launcher.ViewModel { public class ResultViewModel : BaseModel { + private static PrivateFontCollection fontCollection = new(); + private static Dictionary fonts = new(); + public ResultViewModel(Result result, Settings settings) { if (result != null) @@ -23,13 +28,29 @@ namespace Flow.Launcher.ViewModel // Checks if it's a system installed font, which does not require path to be provided. if (glyph.FontFamily.EndsWith(".ttf") || glyph.FontFamily.EndsWith(".otf")) { - var fontPath = Result.Glyph.FontFamily; - Glyph = Path.IsPathRooted(fontPath) - ? Result.Glyph - : Result.Glyph with + string fontFamilyPath = glyph.FontFamily; + + if (!Path.IsPathRooted(fontFamilyPath)) + { + fontFamilyPath = Path.Combine(Result.PluginDirectory, fontFamilyPath); + } + + if (fonts.ContainsKey(fontFamilyPath)) + { + Glyph = glyph with { - FontFamily = Path.Combine(Result.PluginDirectory, fontPath) + FontFamily = fonts[fontFamilyPath] }; + } + else + { + fontCollection.AddFontFile(fontFamilyPath); + fonts[fontFamilyPath] = $"{Path.GetDirectoryName(fontFamilyPath)}/#{fontCollection.Families[^1].Name}"; + Glyph = glyph with + { + FontFamily = fonts[fontFamilyPath] + }; + } } else { diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 8d4177c2b..53e994d34 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -333,7 +333,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { if (e.SpecialKeyState.CtrlPressed) { - SearchWeb.NewTabInBrowser(plugin.UrlDownload); + SearchWeb.OpenInBrowserTab(plugin.UrlDownload); return ShouldHideWindow; } @@ -397,7 +397,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { if (e.SpecialKeyState.CtrlPressed) { - SearchWeb.NewTabInBrowser(x.Website); + SearchWeb.OpenInBrowserTab(x.Website); return ShouldHideWindow; } diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs index 31d56c108..2ed412130 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs @@ -41,8 +41,8 @@ namespace Flow.Launcher.Plugin.WebSearch var results = new List(); foreach (SearchSource searchSource in _settings.SearchSources.Where(o => (o.ActionKeyword == query.ActionKeyword || - o.ActionKeyword == SearchSourceGlobalPluginWildCardSign) - && o.Enabled)) + o.ActionKeyword == SearchSourceGlobalPluginWildCardSign) + && o.Enabled)) { string keyword = string.Empty; keyword = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? query.ToString() : query.Search; @@ -105,11 +105,11 @@ namespace Flow.Launcher.Plugin.WebSearch if (_settings.EnableSuggestion) { var suggestions = await SuggestionsAsync(keyword, subtitle, searchSource, token).ConfigureAwait(false); - if (token.IsCancellationRequested || !suggestions.Any()) + var enumerable = suggestions?.ToList(); + if (token.IsCancellationRequested || enumerable is not { Count: > 0 }) return; - - - results.AddRange(suggestions); + + results.AddRange(enumerable); token.ThrowIfCancellationRequested(); } @@ -118,32 +118,32 @@ namespace Flow.Launcher.Plugin.WebSearch private async Task> SuggestionsAsync(string keyword, string subtitle, SearchSource searchSource, CancellationToken token) { var source = _settings.SelectedSuggestion; - if (source != null) + if (source == null) { - //Suggestions appear below actual result, and appear above global action keyword match if non-global; - var score = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? scoreSuggestions : scoreSuggestions + 1; - - var suggestions = await source.Suggestions(keyword, token).ConfigureAwait(false); - - token.ThrowIfCancellationRequested(); - - var resultsFromSuggestion = suggestions?.Select(o => new Result - { - Title = o, - SubTitle = subtitle, - Score = score, - IcoPath = searchSource.IconPath, - ActionKeywordAssigned = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? string.Empty : searchSource.ActionKeyword, - Action = c => - { - _context.API.OpenUrl(searchSource.Url.Replace("{q}", Uri.EscapeDataString(o))); - - return true; - } - }); - return resultsFromSuggestion; + return new List(); } - return new List(); + //Suggestions appear below actual result, and appear above global action keyword match if non-global; + var score = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? scoreSuggestions : scoreSuggestions + 1; + + var suggestions = await source.SuggestionsAsync(keyword, token).ConfigureAwait(false); + + token.ThrowIfCancellationRequested(); + + var resultsFromSuggestion = suggestions?.Select(o => new Result + { + Title = o, + SubTitle = subtitle, + Score = score, + IcoPath = searchSource.IconPath, + ActionKeywordAssigned = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? string.Empty : searchSource.ActionKeyword, + Action = c => + { + _context.API.OpenUrl(searchSource.Url.Replace("{q}", Uri.EscapeDataString(o))); + + return true; + } + }); + return resultsFromSuggestion; } public Task InitAsync(PluginInitContext context) @@ -191,4 +191,4 @@ namespace Flow.Launcher.Plugin.WebSearch public event ResultUpdatedEventHandler ResultsUpdated; } -} +} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs index ccb5b20d7..d1fbd4ac5 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs @@ -16,7 +16,7 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { private readonly Regex _reg = new Regex("window.baidu.sug\\((.*)\\)"); - public override async Task> Suggestions(string query, CancellationToken token) + public override async Task> SuggestionsAsync(string query, CancellationToken token) { string result; @@ -25,7 +25,7 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources const string api = "http://suggestion.baidu.com/su?json=1&wd="; result = await Http.GetAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false); } - catch (Exception e) when (e is HttpRequestException || e.InnerException is TimeoutException) + catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException}) { Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); return null; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs index 38c5fb4a0..971fc079c 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs @@ -15,7 +15,7 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { class Bing : SuggestionSource { - public override async Task> Suggestions(string query, CancellationToken token) + public override async Task> SuggestionsAsync(string query, CancellationToken token) { try @@ -40,7 +40,7 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources } - catch (Exception e) when (e is HttpRequestException || e.InnerException is TimeoutException) + catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException}) { Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); return null; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index c5f43d081..a6c18b1ef 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -14,7 +14,7 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { public class Google : SuggestionSource { - public override async Task> Suggestions(string query, CancellationToken token) + public override async Task> SuggestionsAsync(string query, CancellationToken token) { try { @@ -32,7 +32,7 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources return results.EnumerateArray().Select(o => o.GetString()).ToList(); } - catch (Exception e) when (e is HttpRequestException || e.InnerException is TimeoutException) + catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException}) { Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); return null; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs index c58e61141..e89addee9 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs @@ -6,6 +6,6 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { public abstract class SuggestionSource { - public abstract Task> Suggestions(string query, CancellationToken token); + public abstract Task> SuggestionsAsync(string query, CancellationToken token); } } diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Helper/ResultHelper.cs b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Helper/ResultHelper.cs index 3005567c4..c693331e9 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Helper/ResultHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Helper/ResultHelper.cs @@ -34,8 +34,9 @@ namespace Flow.Launcher.Plugin.WindowsSettings.Helper var resultList = new List(); foreach (var entry in list) { - const int highScore = 20; - const int midScore = 10; + // Adjust the score to lower the order of many irrelevant matches from area strings + // that may only be for description. + const int nonNameMatchScoreAdj = 10; Result? result; Debug.Assert(_api != null, nameof(_api) + " != null"); @@ -44,7 +45,7 @@ namespace Flow.Launcher.Plugin.WindowsSettings.Helper if (nameMatch.IsSearchPrecisionScoreMet()) { - var settingResult = NewSettingResult(nameMatch.Score + highScore, entry.Type); + var settingResult = NewSettingResult(nameMatch.Score, entry.Type); settingResult.TitleHighlightData = nameMatch.MatchData; result = settingResult; } @@ -53,7 +54,7 @@ namespace Flow.Launcher.Plugin.WindowsSettings.Helper var areaMatch = _api.FuzzySearch(query.Search, entry.Area); if (areaMatch.IsSearchPrecisionScoreMet()) { - var settingResult = NewSettingResult(areaMatch.Score + midScore, entry.Type); + var settingResult = NewSettingResult(areaMatch.Score - nonNameMatchScoreAdj, entry.Type); result = settingResult; } else @@ -61,7 +62,7 @@ namespace Flow.Launcher.Plugin.WindowsSettings.Helper result = entry.AltNames? .Select(altName => _api.FuzzySearch(query.Search, altName)) .Where(match => match.IsSearchPrecisionScoreMet()) - .Select(altNameMatch => NewSettingResult(altNameMatch.Score + midScore, entry.Type)) + .Select(altNameMatch => NewSettingResult(altNameMatch.Score - nonNameMatchScoreAdj, entry.Type)) .FirstOrDefault(); } @@ -75,7 +76,7 @@ namespace Flow.Launcher.Plugin.WindowsSettings.Helper .SelectMany(x => x) .Contains(x, StringComparer.CurrentCultureIgnoreCase)) ) - result = NewSettingResult(midScore, entry.Type); + result = NewSettingResult(nonNameMatchScoreAdj, entry.Type); } } @@ -115,7 +116,7 @@ namespace Flow.Launcher.Plugin.WindowsSettings.Helper private static void AddOptionalToolTip(WindowsSetting entry, Result result) { var toolTipText = new StringBuilder(); - + var settingType = entry.Type == "AppSettingsApp" ? "System settings" : "Control Panel"; toolTipText.AppendLine($"{Resources.Application}: {settingType}"); diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json index f5211e9da..61336db67 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json @@ -4,7 +4,7 @@ "Description": "Search settings inside Control Panel and Settings App", "Name": "Windows Settings", "Author": "TobiasSekan", - "Version": "2.0.1", + "Version": "2.0.2", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.WindowsSettings.dll", diff --git a/appveyor.yml b/appveyor.yml index df9f4e668..ea1dcb22a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.9.2.{build}' +version: '1.9.3.{build}' init: - ps: |