From 19f16b4f64939eea510bec932ea0e4e71d006c95 Mon Sep 17 00:00:00 2001 From: flashwave Date: Fri, 26 Aug 2022 02:01:04 +0200 Subject: [PATCH] v1.6.0 - 2021-07-09 --- README.md | 2 + TopMostFriend/AboutWindow.cs | 9 +- TopMostFriend/ActionTimeout.cs | 35 ++ TopMostFriend/BlacklistWindow.cs | 39 +- TopMostFriend/FirstRunWindow.cs | 357 ++++++++++++++ TopMostFriend/Languages/Language.cs | 22 + TopMostFriend/Languages/LanguageInfo.cs | 21 + TopMostFriend/Languages/LanguageString.cs | 19 + TopMostFriend/Languages/en-GB.xml | 109 +++++ TopMostFriend/Languages/nl-NL.xml | 109 +++++ TopMostFriend/Locale.cs | 89 ++++ TopMostFriend/Program.cs | 219 +++++---- TopMostFriend/Properties/AssemblyInfo.cs | 4 +- .../Properties/Resources.Designer.cs | 10 + TopMostFriend/Properties/Resources.resx | 3 + TopMostFriend/Resources/firstrun.png | Bin 0 -> 17917 bytes TopMostFriend/Settings.cs | 4 +- TopMostFriend/SettingsWindow.cs | 435 ++++++++++++------ TopMostFriend/TopMostFriend.csproj | 24 + TopMostFriend/UAC.cs | 81 ++++ TopMostFriend/Win32.cs | 10 +- TopMostFriend/WindowInfo.cs | 31 +- firstrun.psd | Bin 0 -> 161897 bytes 23 files changed, 1342 insertions(+), 290 deletions(-) create mode 100644 TopMostFriend/ActionTimeout.cs create mode 100644 TopMostFriend/FirstRunWindow.cs create mode 100644 TopMostFriend/Languages/Language.cs create mode 100644 TopMostFriend/Languages/LanguageInfo.cs create mode 100644 TopMostFriend/Languages/LanguageString.cs create mode 100644 TopMostFriend/Languages/en-GB.xml create mode 100644 TopMostFriend/Languages/nl-NL.xml create mode 100644 TopMostFriend/Locale.cs create mode 100644 TopMostFriend/Resources/firstrun.png create mode 100644 TopMostFriend/UAC.cs create mode 100644 firstrun.psd diff --git a/README.md b/README.md index 122171e..04fb36e 100644 --- a/README.md +++ b/README.md @@ -3,3 +3,5 @@ utility that lets you quickly force any program to be always on top should work on any version of windows that supports .net framework 4.0 + +[Click here to download!](https://github.com/flashwave/topmostfriend/releases/latest) diff --git a/TopMostFriend/AboutWindow.cs b/TopMostFriend/AboutWindow.cs index f50ab16..a14a4f7 100644 --- a/TopMostFriend/AboutWindow.cs +++ b/TopMostFriend/AboutWindow.cs @@ -15,7 +15,7 @@ namespace TopMostFriend { } public AboutWindow() { - Text = @"About Top Most Friend"; + Text = Locale.String(@"AboutTitle"); Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath); BackgroundImage = Properties.Resources.about; StartPosition = FormStartPosition.CenterScreen; @@ -24,11 +24,12 @@ namespace TopMostFriend { ClientSize = Properties.Resources.about.Size; MaximizeBox = MinimizeBox = false; MaximumSize = MinimumSize = Size; + TopMost = true; int tabIndex = 0; Button closeButton = new Button { - Text = @"Close", + Text = Locale.String(@"AboutClose"), Size = new Size(BUTTON_WIDTH, BUTTON_HEIGHT), TabIndex = ++tabIndex, }; @@ -37,7 +38,7 @@ namespace TopMostFriend { Controls.Add(closeButton); Button websiteButton = new Button { - Text = @"Website", + Text = Locale.String(@"AboutWebsite"), Size = new Size(BUTTON_WIDTH, BUTTON_HEIGHT), TabIndex = ++tabIndex, }; @@ -46,7 +47,7 @@ namespace TopMostFriend { Controls.Add(websiteButton); Button donateButton = new Button { - Text = @"Donate", + Text = Locale.String(@"AboutDonate"), Size = new Size(BUTTON_WIDTH, BUTTON_HEIGHT), TabIndex = ++tabIndex, }; diff --git a/TopMostFriend/ActionTimeout.cs b/TopMostFriend/ActionTimeout.cs new file mode 100644 index 0000000..cf2b542 --- /dev/null +++ b/TopMostFriend/ActionTimeout.cs @@ -0,0 +1,35 @@ +using System; +using System.Threading; + +namespace TopMostFriend { + public class ActionTimeout { + private readonly Action Action; + private bool Continue = true; + private int Remaining = 0; + private const int STEP = 500; + + public ActionTimeout(Action action, int timeout) { + Action = action ?? throw new ArgumentNullException(nameof(action)); + if(timeout < 1) + throw new ArgumentException(@"Timeout must be a positive integer.", nameof(timeout)); + Remaining = timeout; + new Thread(ThreadBody) { IsBackground = true }.Start(); + } + + private void ThreadBody() { + do { + Thread.Sleep(STEP); + Remaining -= STEP; + + if(!Continue) + return; + } while(Remaining > 0); + + Action.Invoke(); + } + + public void Cancel() { + Continue = false; + } + } +} diff --git a/TopMostFriend/BlacklistWindow.cs b/TopMostFriend/BlacklistWindow.cs index 91dcc16..605900e 100644 --- a/TopMostFriend/BlacklistWindow.cs +++ b/TopMostFriend/BlacklistWindow.cs @@ -35,26 +35,27 @@ namespace TopMostFriend { MinimizeBox = MaximizeBox = false; MinimumSize = Size; DialogResult = DialogResult.Cancel; + TopMost = true; BlacklistView = new ListBox { TabIndex = 101, IntegralHeight = false, Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, - Location = new Point(BUTTON_WIDTH + (SPACING * 2), SPACING), + Location = new Point(SPACING, SPACING), ClientSize = new Size(ClientSize.Width - BUTTON_WIDTH - (int)(SPACING * 3.5), ClientSize.Height - (int)(SPACING * 2.5)), }; BlacklistView.SelectedIndexChanged += BlacklistView_SelectedIndexChanged; BlacklistView.MouseDoubleClick += BlacklistView_MouseDoubleClick; AddButton = new Button { - Anchor = AnchorStyles.Top | AnchorStyles.Left, - Text = @"Add", + Anchor = AnchorStyles.Top | AnchorStyles.Right, + Text = Locale.String(@"BlacklistAdd"), ClientSize = new Size(BUTTON_WIDTH, BUTTON_HEIGHT), - Location = new Point(SPACING, SPACING), + Location = new Point(BlacklistView.Width + (SPACING * 2), SPACING), TabIndex = 201, }; EditButton = new Button { - Text = @"Edit", + Text = Locale.String(@"BlacklistEdit"), Location = new Point(AddButton.Location.X, AddButton.Location.Y + AddButton.Height + SPACING), Enabled = false, Anchor = AddButton.Anchor, @@ -62,7 +63,7 @@ namespace TopMostFriend { TabIndex = 202, }; RemoveButton = new Button { - Text = @"Remove", + Text = Locale.String(@"BlacklistRemove"), Location = new Point(AddButton.Location.X, EditButton.Location.Y + AddButton.Height + SPACING), Enabled = false, Anchor = AddButton.Anchor, @@ -75,16 +76,16 @@ namespace TopMostFriend { RemoveButton.Click += RemoveButton_Click; CancelButton = new Button { - Anchor = AnchorStyles.Bottom | AnchorStyles.Left, - Text = @"Cancel", - Location = new Point(SPACING, ClientSize.Height - AddButton.ClientSize.Height - SPACING), + Anchor = AnchorStyles.Bottom | AnchorStyles.Right, + Text = Locale.String(@"BlacklistCancel"), + Location = new Point(AddButton.Location.X, ClientSize.Height - AddButton.ClientSize.Height - SPACING), ClientSize = AddButton.ClientSize, TabIndex = 10001, }; Button acceptButton = new Button { - Anchor = AnchorStyles.Bottom | AnchorStyles.Left, - Text = @"Done", - Location = new Point(SPACING, ClientSize.Height - ((AddButton.ClientSize.Height + SPACING) * 2)), + Anchor = AnchorStyles.Bottom | AnchorStyles.Right, + Text = Locale.String(@"BlacklistDone"), + Location = new Point(AddButton.Location.X, ClientSize.Height - ((AddButton.ClientSize.Height + SPACING) * 2)), ClientSize = AddButton.ClientSize, TabIndex = 10002, }; @@ -106,16 +107,18 @@ namespace TopMostFriend { public string Original { get; } public string String { get => TextBox.Text; } - private TextBox TextBox; + private readonly TextBox TextBox; public BlacklistEditorWindow(string original = null) { Original = original ?? string.Empty; - Text = original == null ? @"Adding new entry..." : $@"Editing {original}..."; + Text = Locale.String(original == null ? @"BlacklistEditorAdding" : @"BlacklistEditorEditing", original); + Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath); StartPosition = FormStartPosition.CenterParent; - FormBorderStyle = FormBorderStyle.FixedToolWindow; + FormBorderStyle = FormBorderStyle.FixedSingle; ClientSize = new Size(500, 39); MaximizeBox = MinimizeBox = false; MaximumSize = MinimumSize = Size; + TopMost = true; Button cancelButton = new Button { Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right, @@ -123,7 +126,7 @@ namespace TopMostFriend { Name = @"cancelButton", Size = new Size(75, 23), TabIndex = 102, - Text = @"Cancel", + Text = Locale.String(@"BlacklistEditorCancel"), }; cancelButton.Click += (s, e) => { DialogResult = DialogResult.Cancel; Close(); }; @@ -133,14 +136,14 @@ namespace TopMostFriend { Name = @"saveButton", Size = new Size(75, 23), TabIndex = 101, - Text = @"Save", + Text = Locale.String(@"BlacklistEditorSave"), }; saveButton.Click += (s, e) => { DialogResult = DialogResult.OK; Close(); }; TextBox = new TextBox { Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right, Location = new Point(8, 9), - Name = @"deviceSelection", + Name = @"deviceSelection", // ?????? Size = new Size(ClientSize.Width - 8 - cancelButton.Width - saveButton.Width - 19, 23), TabIndex = 100, Text = Original, diff --git a/TopMostFriend/FirstRunWindow.cs b/TopMostFriend/FirstRunWindow.cs new file mode 100644 index 0000000..1648281 --- /dev/null +++ b/TopMostFriend/FirstRunWindow.cs @@ -0,0 +1,357 @@ +using System; +using System.Diagnostics; +using System.Drawing; +using System.Threading; +using System.Windows.Forms; + +namespace TopMostFriend { + public class FirstRunWindow : Form { + public static void Display() { + using(FirstRunWindow firstRun = new FirstRunWindow()) + firstRun.ShowDialog(); + } + + private bool CanClose = false; + private bool IsClosing = false; + private bool IsSizing = false; + + private Button NextBtn { get; } + private Button PrevBtn { get; } + + private Action NextAct = null; + private Action PrevAct = null; + + private bool NextVisible { get => NextBtn.Visible; set => NextBtn.Visible = value; } + private bool PrevVisible { get => PrevBtn.Visible; set => PrevBtn.Visible = value; } + + private Panel WorkArea { get; } + + public FirstRunWindow() { + Text = Program.TITLE + @" v" + Application.ProductVersion.Substring(0, Application.ProductVersion.Length - 2); + Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath); + StartPosition = FormStartPosition.CenterScreen; + FormBorderStyle = FormBorderStyle.FixedSingle; + AutoScaleMode = AutoScaleMode.Dpi; + MaximizeBox = MinimizeBox = false; + TopMost = true; + ClientSize = new Size(410, 80); + + Controls.Add(new PictureBox { + Image = Properties.Resources.firstrun, + Size = Properties.Resources.firstrun.Size, + Location = new Point(0, 0), + }); + + NextBtn = new Button { + Text = Locale.String(@"FirstRunNext"), + Anchor = AnchorStyles.Right | AnchorStyles.Bottom, + Visible = false, + Location = new Point(ClientSize.Width - 81, ClientSize.Height - 29), + }; + NextBtn.Click += NextBtn_Click; + Controls.Add(NextBtn); + + PrevBtn = new Button { + Text = Locale.String(@"FirstRunPrev"), + Anchor = AnchorStyles.Left | AnchorStyles.Bottom, + Visible = false, + Location = new Point(6, ClientSize.Height - 29), + }; + PrevBtn.Click += PrevBtn_Click; + Controls.Add(PrevBtn); + + WorkArea = new Panel { + Dock = DockStyle.Fill, + }; + Controls.Add(WorkArea); + } + + private void PrevBtn_Click(object sender, EventArgs e) { + if(!PrevVisible) + return; + WorkArea.Controls.Clear(); + if(PrevAct == null) + Close(); + else + Invoke(PrevAct); + } + + private void NextBtn_Click(object sender, EventArgs e) { + if(!NextVisible) + return; + WorkArea.Controls.Clear(); + if(NextAct == null) + Close(); + else + Invoke(NextAct); + } + + protected override void OnShown(EventArgs e) { + base.OnShown(e); + Update(); + Thread.Sleep(500); + ShowPageIntro(); + } + + protected override void OnFormClosing(FormClosingEventArgs e) { + if(e.CloseReason == CloseReason.UserClosing && !CanClose) { + e.Cancel = true; + + if(!IsClosing) { + IsClosing = true; + + SetHeight(80, new Action(() => { + CanClose = true; + Thread.Sleep(100); + Close(); + })); + } + return; + } + + base.OnFormClosing(e); + } + + public void SetHeight(int height, Action onFinish = null) { + if(height < 80) + throw new ArgumentException(@"target height must be more than or equal to 80.", nameof(height)); + + if(IsSizing) + return; + IsSizing = true; + + const int timeout = 1000 / 60; + double time = 0; + double period = timeout / 400d; + + int currentHeight = ClientSize.Height; + int currentY = Location.Y; + int diffHeight = height - currentHeight; + int diffY = diffHeight / 2; + + Action setHeight = new Action(() => { + int newHeight = currentHeight + (int)Math.Ceiling(time * diffHeight); + int newY = currentY - (int)Math.Ceiling(time * diffY); + ClientSize = new Size(ClientSize.Width, newHeight); + Location = new Point(Location.X, newY); + }); + + new Thread(() => { + Stopwatch sw = new Stopwatch(); + + try { + do { + sw.Restart(); + + Invoke(setHeight); + time += period; + + int delay = timeout - (int)sw.ElapsedMilliseconds; + if(delay > 1) + Thread.Sleep(delay); + } while(time < 1d + period); + } finally { + sw.Stop(); + if(onFinish != null) + Invoke(onFinish); + IsSizing = false; + } + }) { + IsBackground = true, + Priority = ThreadPriority.AboveNormal, + }.Start(); + } + + public void ShowPageIntro() { + Text = Locale.String(@"FirstRunWelcomeTitle"); + PrevVisible = false; + NextVisible = true; + NextAct = ShowPageHotKey; + + SetHeight(190, new Action(() => { + WorkArea.Controls.Add(new Label { + Text = Locale.String(@"FirstRunWelcomeIntro"), + Location = new Point(10, 90), + Size = new Size(ClientSize.Width - 20, 200), + }); + })); + } + + public void ShowPageHotKey() { + Text = Locale.String(@"FirstRunHotKeyTitle"); + PrevVisible = NextVisible = true; + PrevAct = ShowPageIntro; + NextAct = () => { + Program.SetForegroundHotKey(Settings.Get(Program.FOREGROUND_HOTKEY_SETTING, 0)); + ShowPageElevation(); + }; + + SetHeight(230, new Action(() => { + WorkArea.Controls.Add(new Label { + Text = Locale.String(@"FirstRunHotKeyExplain"), + Location = new Point(10, 90), + Size = new Size(ClientSize.Width - 20, 40), + }); + + SettingsWindow.CreateHotKeyInput( + WorkArea, + () => Settings.Get(Program.FOREGROUND_HOTKEY_SETTING, 0), + keyCode => Settings.Set(Program.FOREGROUND_HOTKEY_SETTING, keyCode), + 0, + 110 + ); + + CheckBox flShowNotification = new CheckBox { + Text = Locale.String(@"FirstRunHotKeyNotify"), + Location = new Point(12, 170), + Checked = Settings.Get(Program.TOGGLE_BALLOON_SETTING, Program.ToggleBalloonDefault), + AutoSize = true, + TabIndex = 201, + }; + flShowNotification.CheckedChanged += (s, e) => { + Settings.Set(Program.TOGGLE_BALLOON_SETTING, flShowNotification.Checked); + }; + WorkArea.Controls.Add(flShowNotification); + })); + } + + public void ShowPageElevation() { + Text = Locale.String(@"FirstRunAdminTitle"); + PrevVisible = NextVisible = true; + PrevAct = ShowPageHotKey; + NextAct = ShowPageThanks; + + SetHeight(280, () => { + WorkArea.Controls.Add(new Label { + Text = Locale.String(@"FirstRunAdminExplain"), + Location = new Point(10, 90), + Size = new Size(ClientSize.Width - 20, 40), + }); + + bool alwaysAdmin = Settings.Get(Program.ALWAYS_ADMIN_SETTING, false); + bool implicitAdmin = Settings.Get(Program.ALWAYS_RETRY_ELEVATED, false); + + RadioButton rdAsk = new RadioButton { + Text = Locale.String(@"FirstRunAdminOptionAsk"), + Location = new Point(10, 140), + Size = new Size(ClientSize.Width - 20, 30), + Appearance = Appearance.Button, + Checked = !alwaysAdmin && !implicitAdmin, + }; + rdAsk.CheckedChanged += (s, e) => { + if(rdAsk.Checked) { + Settings.Set(Program.ALWAYS_ADMIN_SETTING, false); + Settings.Set(Program.ALWAYS_RETRY_ELEVATED, false); + } + }; + WorkArea.Controls.Add(rdAsk); + + RadioButton rdImplicit = new RadioButton { + Text = Locale.String(@"FirstRunAdminOptionImplicit"), + Location = new Point(rdAsk.Location.X, rdAsk.Location.Y + 36), + Size = rdAsk.Size, + Appearance = rdAsk.Appearance, + Checked = implicitAdmin && !alwaysAdmin, + }; + rdImplicit.CheckedChanged += (s, e) => { + if(rdImplicit.Checked) { + Settings.Set(Program.ALWAYS_ADMIN_SETTING, false); + Settings.Set(Program.ALWAYS_RETRY_ELEVATED, true); + } + }; + WorkArea.Controls.Add(rdImplicit); + + RadioButton rdAlways = new RadioButton { + Text = Locale.String(@"FirstRunAdminOptionAlways"), + Location = new Point(rdAsk.Location.X, rdImplicit.Location.Y + 36), + Size = rdAsk.Size, + Appearance = rdAsk.Appearance, + Checked = alwaysAdmin, + }; + rdAlways.CheckedChanged += (s, e) => { + if(rdAlways.Checked) { + Settings.Set(Program.ALWAYS_ADMIN_SETTING, true); + Settings.Set(Program.ALWAYS_RETRY_ELEVATED, false); + } + }; + WorkArea.Controls.Add(rdAlways); + }); + } + + public void ShowPageThanks() { + Text = Locale.String(@"FirstRunThanksTitle"); + PrevVisible = NextVisible = true; + PrevAct = ShowPageElevation; + NextAct = CheckRestartNeeded; + + SetHeight(270, () => { + Label thankYou = new Label { + Text = Locale.String(@"FirstRunThanksThank"), + Location = new Point(10, 90), + Size = new Size(ClientSize.Width - 20, 20), + }; + WorkArea.Controls.Add(thankYou); + + string updateLinkString = Locale.String(@"FirstRunThanksUpdate"); + + int websiteStart = updateLinkString.IndexOf(@"[WEB]"); + updateLinkString = updateLinkString.Substring(0, websiteStart) + updateLinkString.Substring(websiteStart + 5); + int websiteEnd = updateLinkString.IndexOf(@"[/WEB]"); + updateLinkString = updateLinkString.Substring(0, websiteEnd) + updateLinkString.Substring(websiteEnd + 6); + + int changelogStart = updateLinkString.IndexOf(@"[CHANGELOG]"); + updateLinkString = updateLinkString.Substring(0, changelogStart) + updateLinkString.Substring(changelogStart + 11); + int changelogEnd = updateLinkString.IndexOf(@"[/CHANGELOG]"); + updateLinkString = updateLinkString.Substring(0, changelogEnd) + updateLinkString.Substring(changelogEnd + 12); + + LinkLabel updateLink; + WorkArea.Controls.Add(updateLink = new LinkLabel { + Text = updateLinkString, + Location = new Point(10, 120), + Size = new Size(ClientSize.Width - 20, 34), + Font = thankYou.Font, + Links = { + new LinkLabel.Link(websiteStart, websiteEnd - websiteStart, @"https://flash.moe/topmostfriend"), + new LinkLabel.Link(changelogStart, changelogEnd - changelogStart, @"https://flash.moe/topmostfriend/changelog.php"), + }, + }); + updateLink.LinkClicked += (s, e) => { + Process.Start((string)e.Link.LinkData); + }; + + string settingsLinkString = Locale.String(@"FirstRunThanksSettings"); + + int settingsStart = settingsLinkString.IndexOf(@"[SETTINGS]"); + settingsLinkString = settingsLinkString.Substring(0, settingsStart) + settingsLinkString.Substring(settingsStart + 10); + int settingsEnd = settingsLinkString.IndexOf(@"[/SETTINGS]"); + settingsLinkString = settingsLinkString.Substring(0, settingsEnd) + settingsLinkString.Substring(settingsEnd + 11); + + LinkLabel settingsLink; + WorkArea.Controls.Add(settingsLink = new LinkLabel { + Text = settingsLinkString, + Location = new Point(10, 160), + Size = new Size(ClientSize.Width - 20, 30), + Font = thankYou.Font, + Links = { + new LinkLabel.Link(settingsStart, settingsEnd - settingsStart), + }, + }); + settingsLink.LinkClicked += (s, e) => { + SettingsWindow.Display(); + }; + + WorkArea.Controls.Add(new Label { + Text = Locale.String(@"FirstRunThanksAdmin"), + Location = new Point(10, 200), + Size = new Size(ClientSize.Width - 20, 80), + }); + }); + } + + public void CheckRestartNeeded() { + if(Settings.Get(Program.ALWAYS_ADMIN_SETTING, false)) + UAC.RestartElevated(); + Close(); + } + } +} diff --git a/TopMostFriend/Languages/Language.cs b/TopMostFriend/Languages/Language.cs new file mode 100644 index 0000000..0c89bfd --- /dev/null +++ b/TopMostFriend/Languages/Language.cs @@ -0,0 +1,22 @@ +using System; +using System.Linq; +using System.Xml; +using System.Xml.Serialization; + +namespace TopMostFriend.Languages { + [XmlRoot(@"Language")] + public class Language { + [XmlElement(@"Info")] + public LanguageInfo Info { get; set; } + + [XmlArray(@"Strings")] + [XmlArrayItem(@"String", Type = typeof(LanguageString))] + public LanguageString[] Strings { get; set; } + + public LanguageString GetString(string name) { + if(name == null) + throw new ArgumentNullException(nameof(name)); + return Strings.FirstOrDefault(s => name.Equals(s.Name)); + } + } +} diff --git a/TopMostFriend/Languages/LanguageInfo.cs b/TopMostFriend/Languages/LanguageInfo.cs new file mode 100644 index 0000000..e1bc766 --- /dev/null +++ b/TopMostFriend/Languages/LanguageInfo.cs @@ -0,0 +1,21 @@ +using System.Xml.Serialization; + +namespace TopMostFriend.Languages { + public class LanguageInfo { + [XmlElement(@"Id")] + public string Id { get; set; } + + [XmlElement(@"NameNative")] + public string NameNative { get; set; } + + [XmlElement(@"NameEnglish")] + public string NameEnglish { get; set; } + + [XmlElement(@"TargetVersion")] + public string TargetVersion { get; set; } + + public override string ToString() { + return $@"{NameNative} / {NameEnglish} ({Id})"; + } + } +} diff --git a/TopMostFriend/Languages/LanguageString.cs b/TopMostFriend/Languages/LanguageString.cs new file mode 100644 index 0000000..8511cd9 --- /dev/null +++ b/TopMostFriend/Languages/LanguageString.cs @@ -0,0 +1,19 @@ +using System.Xml.Serialization; + +namespace TopMostFriend.Languages { + public class LanguageString { + [XmlAttribute(@"name")] + public string Name { get; set; } + + [XmlText] + public string Value { get; set; } + + public string Format(params object[] args) { + return string.Format(Value, args); + } + + public override string ToString() { + return $@"{Name}: {Value}"; + } + } +} diff --git a/TopMostFriend/Languages/en-GB.xml b/TopMostFriend/Languages/en-GB.xml new file mode 100644 index 0000000..781735f --- /dev/null +++ b/TopMostFriend/Languages/en-GB.xml @@ -0,0 +1,109 @@ + + + + en-GB + British English + British English + 1.6.0 + + + An instance of {0} is already running. + + &Refresh + &Settings + &About + &Quit + + Now always on top + No longer always on top + Window has no title. + + Wasn't able to change always on top status on this window. + Do you want to try again as an Administrator? A User Account Control dialog will pop up after selecting Yes. + {0} was still unable to change always on top status for the window. It might be protected by Windows. + + About {0} + Close + Website + Donate + + {0} Settings + Apply + Cancel + OK + + Hot Keys + Reset + Toggle always on top status on active window + + Options + Show notification when using toggle hot key + Show icon of window affected by hot key + Always retry changing always on top status as Administrator on first failure + SHIFT+CLICK items in the tray area list to add to the title blacklist + Revert status to before {0} altered them on exit + Show list of open windows in the tray area menu + Always run as Administrator + + Language + You should restart {0} for the language change to fully take effect. A lot of text will still appear in the previously selected language. + + Other + Manage Blacklist... + Title Blacklist + Start with Windows... + +Should {0} start with Windows? +Clicking Yes will create a shortcut to the {0} in your Start-up folder, clicking No will delete the shortcut. +Make sure you've placed your {0} executable in a permanent location before clicking Yes. + + Reset All Settings... + +This will reset all {0} settings and restart the application. +Are you absolutely sure? + + + Add + Edit + Remove + Cancel + Done + + Adding new entry... + Editing {0}... + Cancel + Save + + Next + Previous + + Welcome to {0}! + +{0} is a utility that lets you manage the always-on-top state of windows from programs you have open. + +You will now be taken through a few steps to configure {0} to your liking! + + + Selecting a hot key + +Select a global hot key for toggling the always on top status of whatever window is currently in the foreground. +If you don't wish to specify one just hit Reset followed by Next. + + Show a notification when the hot key has been used + + Administrator actions + +Sometimes {0} is not able to change the always on top state for certain windows without having administrative privileges. +{0} provides multiple options for this situation: + + Ask me what to do when it's required. + Ask for administrative privileges automatically when required. + Always run {0} as Administrator (not recommended). + + Thank you! + Thank you for using {0}! + Be sure to check the {0} [WEB]website[/WEB] and [CHANGELOG]changelog[/CHANGELOG] for updates from time to time. + There are more options you may be interested in taking a look at in the [SETTINGS]Settings[/SETTINGS] window. + If you have chosen to always run {0} as Administrator, you will receive a User Account Control prompt after hitting next. + + diff --git a/TopMostFriend/Languages/nl-NL.xml b/TopMostFriend/Languages/nl-NL.xml new file mode 100644 index 0000000..c1fa96d --- /dev/null +++ b/TopMostFriend/Languages/nl-NL.xml @@ -0,0 +1,109 @@ + + + + nl-NL + Nederlands + Dutch + 1.6.0 + + + {0} is al gestart. + + &Verversen + &Instellingen + &Over + &Sluiten + + Nu altijd op voorgrond + Niet langer altijd op voorgrond + Venster heeft geen titel. + + Het was niet mogelijk om de altijd op voorgrond status van dit venster te veranderen. + Wil je het opnieuw proberen als Administrator? Een Gebruikersaccountbeheer dialoog zal verschijnen als je op Ja klikt. + {0} kon nog steeds niet de altijd op voorgrond status van dit venster veranderen. Het wordt mogelijk beschermd door Windows. + + Over {0} + Sluiten + Website + Doneer + + {0} Instellingen + Toepassen + Annuleren + OK + + Sneltoetsen + Herstel + Schakel altijd op voorgrond status op actief venster + + Opties + Toon notificatie als de sneltoets gebruikt is + Toon icoon van venster dat beïnvloed was door de sneltoets + Probeer altijd opnieuw als Administrator bij de eerste mislukking van het veranderen van de status + SHIFT+CLICK items in de systeemvak lijst om ze toe te voegen aan de titel blacklist + Herstel status naar voordat {0} ze heeft aangepast tijdens het sluiten + Geef lijst met open venster weer in het systeemvak menu + Start altijd als Administrator + + Taal (Language) + Je moet {0} opnieuw starten om de verandering van de taal volledig effect te laten nemen. Veel tekst zal nog steeds verschijnen in de voorheen geselecteerde taal. + + Overig + Beheer Blacklist... + Titel Blacklist + Start met Windows... + +Moet {0} tegelijkertijd met Windows starten? +Als je op Ja klikt zal een een snelkoppeling aangemaakt worden in de Opstarten map van het start menu, als je op Nee klikt wordt de snelkoppeling verwijderd. +Zorg ervoor dat je het EXE bestand voor {0} in een permanente locatie hebt voordat je op Ja klikt. + + Herstel alle instellingen... + +Dit zal alle instellingen verwijderen en het programma opnieuw opstarten. +Weet je het absoluut zeker? + + + Toevoegen + Bewerken + Verwijderen + Annuleren + Klaar + + Nieuw item toevoegen... + {0} bewerken... + Annuleren + Opslaan + + Volgende + Vorige + + Welkom bij {0}! + +{0} is een hulpprogramma dat jou controle geeft over de altijd-op-voorgrond status van programma's die je open hebt. + +Je zal nu door een aantal stappen genomen worden om {0} naar jouw wens te configureren! + + + Sneltoets selecteren + +Selecteer een globale sneltoets voor het wijzigen van de altijd op voorgrond status van het venster dat op dat moment in de voorgrond staat. +Als je geen sneltoets toe wil wijzen, druk op Herstel en vervolgens op Volgende. + + Toon een melding wanneer de sneltoets is gebruikt + + Administrator acties + +Soms kan {0} niet de altijd op voorgrond status van bepaalde vensters aanpassen omdat daar administratieve rechten voor nodig zijn. +{0} geeft je de volgende opties voor deze situatie: + + Vraag mij wat te doen wanneer het nodig is. + Vraag mij automatisch om administratieve rechten wanneer het nodig is. + Start {0} altijd als Administrator (niet aanbevolen). + + Bedankt! + Bedankt voor het gebruiken van {0}! + Controlleer de {0} [WEB]website[/WEB] en [CHANGELOG]changelog[/CHANGELOG] eens in de zoveel tijd om te kijken of er updates zijn. + Naast de opties die je al gekregen hebt, zijn er nog meer beschikbaar in het [SETTINGS]Instellingen[/SETTINGS] venster als je daarin geïnteresseerd bent. + Als je gekozen hebt om {0} altijd als Administrator te starten, zal je een Gebruikersaccountbeheer dialoog zien nadat je op volgende klikt. + + diff --git a/TopMostFriend/Locale.cs b/TopMostFriend/Locale.cs new file mode 100644 index 0000000..9c50742 --- /dev/null +++ b/TopMostFriend/Locale.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Xml; +using System.Xml.Serialization; +using TopMostFriend.Languages; + +namespace TopMostFriend { + public static class Locale { + public const string DEFAULT = @"en-GB"; + private static XmlSerializer Serializer { get; } + private static Dictionary Languages { get; } + private static Language ActiveLanguage { get; set; } + + static Locale() { + Serializer = new XmlSerializer(typeof(Language)); + Languages = new Dictionary(); + Assembly currentAsm = Assembly.GetExecutingAssembly(); + string[] resources = currentAsm.GetManifestResourceNames(); + + foreach(string resource in resources) + if(resource.StartsWith(@"TopMostFriend.Languages.") && resource.EndsWith(@".xml")) + using(Stream resourceStream = currentAsm.GetManifestResourceStream(resource)) + LoadLanguage(resourceStream); + } + + public static string LoadLanguage(Stream stream) { + Language lang = (Language)Serializer.Deserialize(stream); + foreach(LanguageString ls in lang.Strings) + ls.Value = ls.Value.Trim(); + + Languages.Add(lang.Info.Id, lang); + if(ActiveLanguage == null && DEFAULT.Equals(lang.Info.Id)) + ActiveLanguage = lang; + +#if DEBUG + Debug.WriteLine(@" =========="); + Debug.WriteLine(lang.Info); + foreach(LanguageString str in lang.Strings) + Debug.WriteLine(str); + Debug.WriteLine(string.Empty); +#endif + + return lang.Info.Id; + } + + public static LanguageInfo GetCurrentLanguage() { + return ActiveLanguage.Info; + } + + public static LanguageInfo[] GetAvailableLanguages() { + return Languages.Values.Select(l => l.Info).ToArray(); + } + + public static string GetPreferredLanguage() { + return Settings.Has(Program.LANGUAGE) + ? Settings.Get(Program.LANGUAGE, DEFAULT) + : CultureInfo.InstalledUICulture.Name; + } + + public static void SetLanguage(string langId) { + if(!Languages.ContainsKey(langId)) + langId = DEFAULT; + ActiveLanguage = Languages[langId]; + } + + public static void SetLanguage(LanguageInfo langInfo) { + SetLanguage(langInfo.Id); + } + + public static string String(string name, params object[] args) { + LanguageString str = ActiveLanguage.GetString(name); + if(str == null) + return name; + + List rargs = new List { Program.TITLE }; + rargs.AddRange(args); + + return str.Format(rargs.ToArray()); + } + + public static void Meow() { + Debug.WriteLine(@"meow"); + } + } +} diff --git a/TopMostFriend/Program.cs b/TopMostFriend/Program.cs index 996c64c..d9fbb36 100644 --- a/TopMostFriend/Program.cs +++ b/TopMostFriend/Program.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; -using System.Security.Principal; using System.Text; using System.Threading; using System.Windows.Forms; @@ -17,6 +16,8 @@ namespace TopMostFriend { private static HotKeyWindow HotKeys; private static Icon OriginalIcon; + public const string TITLE = @"Top Most Friend"; + private const string GUID = #if DEBUG @"{1A22D9CA-2AA9-48F2-B007-3A48CF205CDD}"; @@ -25,6 +26,8 @@ namespace TopMostFriend { #endif private static readonly Mutex GlobalMutex = new Mutex(true, GUID); + private const string CUSTOM_LANGUAGE = @"TopMostFriendLanguage.xml"; + public const string FOREGROUND_HOTKEY_ATOM = @"{86795D64-770D-4BD6-AA26-FA638FBAABCF}"; #if DEBUG public const string FOREGROUND_HOTKEY_SETTING = @"ForegroundHotKey_DEBUG"; @@ -44,6 +47,10 @@ namespace TopMostFriend { public const string TITLE_BLACKLIST = @"TitleBlacklist"; public const string SHOW_HOTKEY_ICON = @"ShowHotkeyIcon"; public const string SHOW_WINDOW_LIST = @"ShowWindowList"; + public const string LAST_VERSION = @"LastVersion"; + public const string ALWAYS_RETRY_ELEVATED = @"AlwaysRetryElevated"; + public const string REVERT_ON_EXIT = @"RevertOnExit"; + public const string LANGUAGE = @"Language"; private static ToolStripItem RefreshButton; private static ToolStripItem LastSelectedItem = null; @@ -53,8 +60,39 @@ namespace TopMostFriend { private static ToolStripItem[] ListActionItems; private static ToolStripItem[] AppActionItems; + private static readonly Dictionary OriginalStates = new Dictionary(); + [STAThread] - public static void Main(string[] args) { + public static int Main(string[] args) { + Settings.Set(LAST_VERSION, Application.ProductVersion); + + IEnumerable cliToggleNew = args.Where(a => a.StartsWith(@"--toggle=")).Select(a => a.Substring(9)); + if(cliToggleNew.Any()) { + bool is32bit = IntPtr.Size == 4; + + foreach(string hwndStr in cliToggleNew) { + IntPtr hwnd; + if(is32bit) { + if(int.TryParse(hwndStr, out int hwnd32)) + hwnd = new IntPtr(hwnd32); + else + return 1; + } else { + if(long.TryParse(hwndStr, out long hwnd64)) + hwnd = new IntPtr(hwnd64); + else + return 1; + } + + // pass 0 to skip implicit FindOwnerId call + WindowInfo wi = new WindowInfo(hwnd, 0); + if(!wi.ToggleTopMost(!args.Contains($@"--background={hwndStr}"))) + return 2; + } + + return 0; + } + if(Environment.OSVersion.Version.Major >= 6) Win32.SetProcessDPIAware(); @@ -64,26 +102,53 @@ namespace TopMostFriend { if(args.Contains(@"--reset-admin")) Settings.Remove(ALWAYS_ADMIN_SETTING); - string cliToggle = args.FirstOrDefault(x => x.StartsWith(@"--hwnd=")); - if(!string.IsNullOrEmpty(cliToggle) && int.TryParse(cliToggle.Substring(7), out int cliToggleHWnd)) { - WindowInfo cliWindow = new WindowInfo(cliToggleHWnd); - if(!cliWindow.ToggleTopMost()) - TopMostFailed(cliWindow); + string cliToggleOld = args.FirstOrDefault(a => a.StartsWith(@"--hwnd="))?.Substring(7); + if(!string.IsNullOrEmpty(cliToggleOld)) { + IntPtr cliToggleHWnd = IntPtr.Zero; + if(IntPtr.Size == 4) { + if(int.TryParse(cliToggleOld, out int hwnd32)) + cliToggleHWnd = new IntPtr(hwnd32); + } else { + if(long.TryParse(cliToggleOld, out long hwnd64)) + cliToggleHWnd = new IntPtr(hwnd64); + } + + if(cliToggleHWnd != IntPtr.Zero) { + WindowInfo cliWindow = new WindowInfo(cliToggleHWnd); + if(!cliWindow.ToggleTopMost()) + TopMostFailed(cliWindow); + } } if(args.Contains(@"--stop")) - return; + return 0; + + if(File.Exists(CUSTOM_LANGUAGE)) { + string customLanguage; + using(Stream s = File.OpenRead(CUSTOM_LANGUAGE)) + try { + customLanguage = Locale.LoadLanguage(s); + } catch { + customLanguage = Locale.DEFAULT; + } + Locale.SetLanguage(customLanguage); + } else + Locale.SetLanguage(Locale.GetPreferredLanguage()); if(!GlobalMutex.WaitOne(0, true)) { - MessageBox.Show(@"An instance of Top Most Friend is already running.", @"Top Most Friend"); - return; + MessageBox.Show(Locale.String(@"AlreadyRunning"), TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information); + return -1; } + bool isFirstRun = !Settings.Has(FOREGROUND_HOTKEY_SETTING); + Settings.SetDefault(FOREGROUND_HOTKEY_SETTING, 0); Settings.SetDefault(ALWAYS_ADMIN_SETTING, false); Settings.SetDefault(SHIFT_CLICK_BLACKLIST, true); Settings.SetDefault(SHOW_HOTKEY_ICON, true); Settings.SetDefault(SHOW_WINDOW_LIST, true); + Settings.SetDefault(ALWAYS_RETRY_ELEVATED, false); + Settings.SetDefault(REVERT_ON_EXIT, false); // Defaulting to false on Windows 10 because it uses the stupid, annoying and intrusive new Android style notification system // This would fucking piledrive the notification history and also just be annoying in general because intrusive Settings.SetDefault(TOGGLE_BALLOON_SETTING, ToggleBalloonDefault); @@ -102,9 +167,9 @@ namespace TopMostFriend { Settings.Set(TITLE_BLACKLIST, titles.ToArray()); } - if(Settings.Get(ALWAYS_ADMIN_SETTING) && !IsElevated()) { - Elevate(); - return; + if(Settings.Get(ALWAYS_ADMIN_SETTING) && !UAC.IsElevated) { + UAC.RestartElevated(); + return -2; } TitleBlacklist.Clear(); @@ -134,19 +199,19 @@ namespace TopMostFriend { CtxMenu.ItemClicked += CtxMenu_ItemClicked; ListActionItems = new ToolStripItem[] { new ToolStripSeparator(), - RefreshButton = new ToolStripMenuItem(@"&Refresh", Properties.Resources.arrow_refresh, new EventHandler((s, e) => RefreshWindowList())), + RefreshButton = new ToolStripMenuItem(Locale.String(@"TrayRefresh"), Properties.Resources.arrow_refresh, new EventHandler((s, e) => RefreshWindowList())), }; AppActionItems = new ToolStripItem[] { - new ToolStripMenuItem(@"&Settings", Properties.Resources.cog, new EventHandler((s, e) => SettingsWindow.Display())), - new ToolStripMenuItem(@"&About", Properties.Resources.help, new EventHandler((s, e) => AboutWindow.Display())), - new ToolStripMenuItem(@"&Quit", Properties.Resources.door_in, new EventHandler((s, e) => Application.Exit())), + new ToolStripMenuItem(Locale.String(@"TraySettings"), Properties.Resources.cog, new EventHandler((s, e) => SettingsWindow.Display())), + new ToolStripMenuItem(Locale.String(@"TrayAbout"), Properties.Resources.help, new EventHandler((s, e) => AboutWindow.Display())), + new ToolStripMenuItem(Locale.String(@"TrayQuit"), Properties.Resources.door_in, new EventHandler((s, e) => Application.Exit())), }; CtxMenu.Items.AddRange(AppActionItems); SysIcon = new NotifyIcon { Visible = true, Icon = OriginalIcon, - Text = @"Top Most Application Manager", + Text = TITLE, }; SysIcon.ContextMenuStrip = CtxMenu; SysIcon.MouseDown += SysIcon_MouseDown; @@ -154,9 +219,26 @@ namespace TopMostFriend { HotKeys = new HotKeyWindow(); SetForegroundHotKey(Settings.Get(FOREGROUND_HOTKEY_SETTING)); + if(isFirstRun) + FirstRunWindow.Display(); + Application.Run(); + if(Settings.Get(REVERT_ON_EXIT, false)) + RevertTopMostStatus(); + Shutdown(); + + return 0; + } + + public static void RevertTopMostStatus() { + foreach(KeyValuePair originalState in OriginalStates) { + WindowInfo wi = new WindowInfo(originalState.Key); + if(wi.IsTopMost != originalState.Value) + if(!wi.ToggleTopMost(false)) + TopMostFailed(wi, false); + } } public static void AddBlacklistedTitle(string title) { @@ -192,33 +274,6 @@ namespace TopMostFriend { GlobalMutex.ReleaseMutex(); } - private static bool? IsElevatedValue; - - public static bool IsElevated() { - if(!IsElevatedValue.HasValue) { - using(WindowsIdentity identity = WindowsIdentity.GetCurrent()) - IsElevatedValue = identity != null && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); - } - - return IsElevatedValue.Value; - } - - public static void Elevate(string args = null) { - if(IsElevated()) - return; - - Shutdown(); - - Process.Start(new ProcessStartInfo { - UseShellExecute = true, - FileName = Application.ExecutablePath, - WorkingDirectory = Environment.CurrentDirectory, - Arguments = args ?? string.Empty, - Verb = @"runas", - }); - Application.Exit(); - } - public static void SetForegroundHotKey(int keyCode) { SetForegroundHotKey((Win32ModKeys)(keyCode & 0xFFFF), (Keys)((keyCode & 0xFFFF0000) >> 16)); } @@ -270,8 +325,13 @@ namespace TopMostFriend { if(Settings.Get(SHIFT_CLICK_BLACKLIST, true) && Control.ModifierKeys.HasFlag(Keys.Shift)) { AddBlacklistedTitle(title); SaveBlacklistedTitles(); - } else if(!window.ToggleTopMost()) - TopMostFailed(window); + } else { + if(window.ToggleTopMost()) { + if(!OriginalStates.ContainsKey(window.Handle)) + OriginalStates[window.Handle] = !window.IsTopMost; + } else + TopMostFailed(window); + } })) { CheckOnClick = true, Checked = window.IsTopMost, @@ -287,50 +347,29 @@ namespace TopMostFriend { CtxMenu.Items.AddRange(items.ToArray()); } - private static void TopMostFailed(WindowInfo window) { - MessageBoxButtons buttons = MessageBoxButtons.OK; - StringBuilder sb = new StringBuilder(); - sb.AppendLine(@"Wasn't able to change topmost status on this window."); + private static void TopMostFailed(WindowInfo window, bool switchWindow = true) { + bool retryElevated = Settings.Get(ALWAYS_RETRY_ELEVATED, false), + isElevated = UAC.IsElevated; - if(!IsElevated()) { - sb.AppendLine(@"Do you want to restart Top Most Friend as administrator and try again?"); - buttons = MessageBoxButtons.YesNo; + if(!retryElevated) { + MessageBoxButtons buttons = MessageBoxButtons.OK; + StringBuilder sb = new StringBuilder(); + sb.AppendLine(Locale.String(@"ErrUnableAlterStatus1")); + + if(!isElevated) { + sb.AppendLine(Locale.String(@"ErrUnableAlterStatus2")); + buttons = MessageBoxButtons.YesNo; + } + + retryElevated = MessageBox.Show(sb.ToString(), TITLE, buttons, MessageBoxIcon.Error) == DialogResult.Yes; } - DialogResult result = MessageBox.Show(sb.ToString(), @"Top Most Friend", buttons, MessageBoxIcon.Error); - - if(result == DialogResult.Yes) - Elevate($@"--hwnd={window.Handle}"); - } - - private class ActionTimeout { - private readonly Action Action; - private bool Continue = true; - private int Remaining = 0; - private const int STEP = 500; - - public ActionTimeout(Action action, int timeout) { - Action = action ?? throw new ArgumentNullException(nameof(action)); - if(timeout < 1) - throw new ArgumentException(@"Timeout must be a positive integer.", nameof(timeout)); - Remaining = timeout; - new Thread(ThreadBody) { IsBackground = true }.Start(); - } - - private void ThreadBody() { - do { - Thread.Sleep(STEP); - Remaining -= STEP; - - if(!Continue) - return; - } while(Remaining > 0); - - Action.Invoke(); - } - - public void Cancel() { - Continue = false; + if(retryElevated) { + if(window.ToggleTopMostElevated(switchWindow)) { + if(!OriginalStates.ContainsKey(window.Handle)) + OriginalStates[window.Handle] = !window.IsTopMost; + } else + MessageBox.Show(Locale.String(@"ErrUnableAlterStatusProtected"), TITLE, MessageBoxButtons.OK, MessageBoxIcon.Error); } } @@ -343,8 +382,8 @@ namespace TopMostFriend { if(Settings.Get(TOGGLE_BALLOON_SETTING, false)) { string title = window.Title; SysIcon?.ShowBalloonTip( - 2000, window.IsTopMost ? @"Always on top" : @"No longer always on top", - string.IsNullOrEmpty(title) ? @"Window has no title." : title, + 2000, Locale.String(window.IsTopMost ? @"NotifyOnTop" : @"NotifyNoLonger"), + string.IsNullOrEmpty(title) ? Locale.String(@"NotifyNoTitle") : title, ToolTipIcon.Info ); } diff --git a/TopMostFriend/Properties/AssemblyInfo.cs b/TopMostFriend/Properties/AssemblyInfo.cs index a2c6bb1..e19f006 100644 --- a/TopMostFriend/Properties/AssemblyInfo.cs +++ b/TopMostFriend/Properties/AssemblyInfo.cs @@ -29,5 +29,5 @@ using System.Runtime.InteropServices; // Build Number // Revision // -[assembly: AssemblyVersion("1.5.1.0")] -[assembly: AssemblyFileVersion("1.5.1.0")] +[assembly: AssemblyVersion("1.6.0.0")] +[assembly: AssemblyFileVersion("1.6.0.0")] diff --git a/TopMostFriend/Properties/Resources.Designer.cs b/TopMostFriend/Properties/Resources.Designer.cs index fb8717c..ab9867c 100644 --- a/TopMostFriend/Properties/Resources.Designer.cs +++ b/TopMostFriend/Properties/Resources.Designer.cs @@ -100,6 +100,16 @@ namespace TopMostFriend.Properties { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap firstrun { + get { + object obj = ResourceManager.GetObject("firstrun", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/TopMostFriend/Properties/Resources.resx b/TopMostFriend/Properties/Resources.resx index 5aecbd4..6ba3e5a 100644 --- a/TopMostFriend/Properties/Resources.resx +++ b/TopMostFriend/Properties/Resources.resx @@ -130,6 +130,9 @@ ..\Resources\door_in.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\firstrun.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\help.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/TopMostFriend/Resources/firstrun.png b/TopMostFriend/Resources/firstrun.png new file mode 100644 index 0000000000000000000000000000000000000000..f83fdefee2239a2af798d5a3f55eeb530d13d2d9 GIT binary patch literal 17917 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 IM6N<$f||Ep%>V!Z literal 0 HcmV?d00001 diff --git a/TopMostFriend/Settings.cs b/TopMostFriend/Settings.cs index 2921408..b1ab304 100644 --- a/TopMostFriend/Settings.cs +++ b/TopMostFriend/Settings.cs @@ -26,9 +26,7 @@ namespace TopMostFriend { } public static string[] Get(string name, string[] fallback = null) { - byte[] buffer = GetRoot().GetValue(name, null) as byte[]; - - if (buffer == null) + if(!(GetRoot().GetValue(name, null) is byte[] buffer)) return fallback; List strings = new List(); diff --git a/TopMostFriend/SettingsWindow.cs b/TopMostFriend/SettingsWindow.cs index 600cf92..062c42d 100644 --- a/TopMostFriend/SettingsWindow.cs +++ b/TopMostFriend/SettingsWindow.cs @@ -1,6 +1,9 @@ using System; +using System.Diagnostics; using System.Drawing; +using System.IO; using System.Windows.Forms; +using TopMostFriend.Languages; namespace TopMostFriend { public class SettingsWindow : Form { @@ -29,184 +32,172 @@ namespace TopMostFriend { public readonly CheckBox FlShiftClickBlacklist; public readonly CheckBox FlShowHotkeyIcon; public readonly CheckBox FlShowWindowList; + public readonly CheckBox FlAlwaysRetryAsAdmin; + public readonly CheckBox FlRevertOnExit; + + public readonly ComboBox LangSelect; public SettingsWindow() { - Text = @"Top Most Friend Settings"; + Text = Locale.String(@"SettingsTitle"); Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath); StartPosition = FormStartPosition.CenterScreen; FormBorderStyle = FormBorderStyle.FixedSingle; AutoScaleMode = AutoScaleMode.Dpi; - ClientSize = new Size(430, 298); + ClientSize = new Size(430, 407); MinimizeBox = MaximizeBox = false; - MinimumSize = MaximumSize = Size; + TopMost = true; KeyCode = Settings.Get(Program.FOREGROUND_HOTKEY_SETTING, 0); Button applyButton = new Button { - Text = @"Apply", + Text = Locale.String(@"SettingsApply"), Size = new Size(75, 23), Location = new Point(ClientSize.Width - 81, ClientSize.Height - 30), TabIndex = 10003, + Anchor = AnchorStyles.Bottom | AnchorStyles.Right, }; applyButton.Click += ApplyButton_Click; Button cancelButton = new Button { - Text = @"Cancel", + Text = Locale.String(@"SettingsCancel"), Size = applyButton.Size, Location = new Point(ClientSize.Width - 162, applyButton.Location.Y), TabIndex = 10002, + Anchor = applyButton.Anchor, }; cancelButton.Click += CancelButton_Click; Button okButton = new Button { - Text = @"OK", + Text = Locale.String(@"SettingsOk"), Size = applyButton.Size, Location = new Point(ClientSize.Width - 243, applyButton.Location.Y), TabIndex = 10001, + Anchor = applyButton.Anchor, }; okButton.Click += OkButton_Click; GroupBox hotKeyGroup = new GroupBox { - Text = @"Hotkeys", + Text = Locale.String(@"SettingsHotKeysTitle"), Location = new Point(6, 6), Size = new Size(Width - 18, 70), + Anchor = AnchorStyles.Left | AnchorStyles.Right, }; - GroupBox flagsGroup = new GroupBox { - Text = @"Flags", - Location = new Point(6, 76), - Size = new Size(Width - 18, 130), + Text = Locale.String(@"SettingsOptionsTitle"), + Location = new Point(6, 80), + Size = new Size(Width - 18, 170), + Anchor = hotKeyGroup.Anchor, }; - - GroupBox blackListGroup = new GroupBox { - Text = @"Blacklist", - Location = new Point(6, 206), + GroupBox langGroup = new GroupBox { + Text = Locale.String(@"SettingsLanguageTitle"), + Location = new Point(6, 254), Size = new Size(Width - 18, 55), + Anchor = hotKeyGroup.Anchor, + }; + GroupBox otherGroup = new GroupBox { + Text = Locale.String(@"SettingsOtherTitle"), + Location = new Point(6, 313), + Size = new Size(Width - 18, 55), + Anchor = hotKeyGroup.Anchor, }; Controls.AddRange(new Control[] { applyButton, cancelButton, okButton, - hotKeyGroup, flagsGroup, blackListGroup, + hotKeyGroup, flagsGroup, langGroup, otherGroup, }); - Label toggleForegroundLabel = new Label { + hotKeyGroup.Controls.Add(new Label { AutoSize = true, - Text = @"Toggle always on top status on active window", + Text = Locale.String(@"SettingsHotKeysToggle"), Location = new Point(8, 17), - }; - - const int mod_x = 120; - const int mod_y = 34; - - Button fgReset = new Button { - Text = @"Reset", - Location = new Point(hotKeyGroup.Width - 85, mod_y), - TabIndex = 105, - }; - fgReset.Click += FgReset_Click; - - FgKey = new TextBox { - Text = ((Keys)(KeyCode >> 16)).ToString(), - Location = new Point(12, mod_y + 2), - TabIndex = 101, - }; - FgKey.KeyDown += FgKey_KeyDown; - - FgModCtrl = new CheckBox { - Text = @"CTRL", - Location = new Point(mod_x, mod_y), - Checked = (KeyCode & (int)Win32ModKeys.MOD_CONTROL) > 0, - Appearance = Appearance.Button, - Size = new Size(50, 23), - TextAlign = ContentAlignment.MiddleCenter, - TabIndex = 102, - }; - FgModCtrl.Click += FgModCtrl_Click; - - FgModAlt = new CheckBox { - Text = @"ALT", - Location = new Point(mod_x + 50, mod_y), - Checked = (KeyCode & (int)Win32ModKeys.MOD_ALT) > 0, - Appearance = FgModCtrl.Appearance, - Size = FgModCtrl.Size, - TextAlign = FgModCtrl.TextAlign, - TabIndex = 103, - }; - FgModAlt.Click += FgModAlt_Click; - - FgModShift = new CheckBox { - Text = @"SHIFT", - Location = new Point(mod_x + 100, mod_y), - Checked = (KeyCode & (int)Win32ModKeys.MOD_SHIFT) > 0, - Appearance = FgModCtrl.Appearance, - Size = FgModCtrl.Size, - TextAlign = FgModCtrl.TextAlign, - TabIndex = 104, - }; - FgModShift.Click += FgModShift_Click; - - FgModWindows = new CheckBox { - Text = @"WIN", - Location = new Point(mod_x + 150, mod_y), - Checked = (KeyCode & (int)Win32ModKeys.MOD_WIN) > 0, - Appearance = FgModCtrl.Appearance, - Size = FgModCtrl.Size, - TextAlign = FgModCtrl.TextAlign, - TabIndex = 105, - }; - FgModWindows.Click += FgModWindows_Click; - - hotKeyGroup.Controls.AddRange(new Control[] { - toggleForegroundLabel, FgModCtrl, FgModAlt, FgModShift, FgModWindows, fgReset, FgKey, }); - FlAlwaysAdmin = new CheckBox { - Text = @"Always run as administrator", + CreateHotKeyInput( + hotKeyGroup, + () => KeyCode, + keyCode => KeyCode = keyCode + ); + + FlToggleNotification = new CheckBox { + Text = Locale.String(@"SettingsOptionsToggleNotify"), Location = new Point(10, 20), - Checked = Settings.Get(Program.ALWAYS_ADMIN_SETTING, false), + Checked = Settings.Get(Program.TOGGLE_BALLOON_SETTING, Program.ToggleBalloonDefault), AutoSize = true, TabIndex = 201, }; - FlToggleNotification = new CheckBox { - Text = @"Show notification when using toggle hotkey", + FlShowHotkeyIcon = new CheckBox { + Text = Locale.String(@"SettingsOptionsToggleNotifyIcon"), Location = new Point(10, 40), - Checked = Settings.Get(Program.TOGGLE_BALLOON_SETTING, Program.ToggleBalloonDefault), + Checked = Settings.Get(Program.SHOW_HOTKEY_ICON, true), AutoSize = true, TabIndex = 202, }; - FlShiftClickBlacklist = new CheckBox { - Text = @"SHIFT+CLICK items in the list to add to the title blacklist", + FlAlwaysRetryAsAdmin = new CheckBox { + Text = Locale.String(@"SettingsOptionsElevatedRetry"), Location = new Point(10, 60), - Checked = Settings.Get(Program.SHIFT_CLICK_BLACKLIST, true), + Checked = Settings.Get(Program.ALWAYS_RETRY_ELEVATED, false), AutoSize = true, TabIndex = 203, }; - FlShowHotkeyIcon = new CheckBox { - Text = @"Show icon of window affected by hotkey", + FlShiftClickBlacklist = new CheckBox { + Text = Locale.String(@"SettingsOptionsShiftBlacklist"), Location = new Point(10, 80), - Checked = Settings.Get(Program.SHOW_HOTKEY_ICON, true), + Checked = Settings.Get(Program.SHIFT_CLICK_BLACKLIST, true), AutoSize = true, TabIndex = 204, }; - FlShowWindowList = new CheckBox { - Text = @"Show list of open windows in the task bar context menu", + FlRevertOnExit = new CheckBox { + Text = Locale.String(@"SettingsOptionsRevertOnExit"), Location = new Point(10, 100), - Checked = Settings.Get(Program.SHOW_WINDOW_LIST, true), + Checked = Settings.Get(Program.REVERT_ON_EXIT, false), AutoSize = true, TabIndex = 205, }; + FlShowWindowList = new CheckBox { + Text = Locale.String(@"SettingsOptionsShowTrayList"), + Location = new Point(10, 120), + Checked = Settings.Get(Program.SHOW_WINDOW_LIST, true), + AutoSize = true, + TabIndex = 206, + }; + FlAlwaysAdmin = new CheckBox { + Text = Locale.String(@"SettingsOptionsAlwaysAdmin"), + Location = new Point(10, 140), + Checked = Settings.Get(Program.ALWAYS_ADMIN_SETTING, false), + AutoSize = true, + TabIndex = 207, + }; - flagsGroup.Controls.AddRange(new[] { + CheckBox[] options = new[] { FlAlwaysAdmin, FlToggleNotification, FlShiftClickBlacklist, - FlShowHotkeyIcon, FlShowWindowList, - }); + FlShowHotkeyIcon, FlShowWindowList, FlAlwaysRetryAsAdmin, + FlRevertOnExit, + }; + + flagsGroup.Controls.AddRange(options); + + foreach(CheckBox option in options) + if((option.Width + (option.Left * 2)) > flagsGroup.ClientSize.Width) + ClientSize = new Size(option.Width + 30, ClientSize.Height); + + LangSelect = new ComboBox { + Anchor = AnchorStyles.Left | AnchorStyles.Right, + DropDownStyle = ComboBoxStyle.DropDownList, + Size = new Size(langGroup.Width - 24, 21), + Location = new Point(12, 22), + }; + LangSelect.Items.AddRange(Locale.GetAvailableLanguages()); + LangSelect.SelectedItem = Locale.GetCurrentLanguage(); + langGroup.Controls.Add(LangSelect); Button titleBlacklist = new Button { Size = new Size(120, 23), Location = new Point(10, 20), - Text = @"Manage...", + Text = Locale.String(@"SettingsOtherBlacklistButton"), TabIndex = 301, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowOnly, }; titleBlacklist.Click += (s, e) => { - string[] newList = BlacklistWindow.Display(@"Title Blacklist", Program.GetBlacklistedTitles()); + string[] newList = BlacklistWindow.Display(Locale.String(@"SettingsOtherBlacklistWindowTitle"), Program.GetBlacklistedTitles()); if(newList != null) { Program.ApplyBlacklistedTitles(newList); @@ -214,22 +205,207 @@ namespace TopMostFriend { } }; - blackListGroup.Controls.AddRange(new[] { titleBlacklist }); + Button startWithWindows = new Button { + Size = new Size(120, 23), + Location = new Point(134, 20), + Text = Locale.String(@"SettingsOtherStartupButton"), + TabIndex = 302, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowOnly, + }; + startWithWindows.Click += (s, e) => { + DialogResult dr = MessageBox.Show(Locale.String(@"SettingsOtherStartupConfirm"), Program.TITLE, MessageBoxButtons.YesNo, MessageBoxIcon.Question); + + string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), @"TopMostFriend.lnk"); + + if(File.Exists(path)) + File.Delete(path); + + if(dr == DialogResult.Yes) { + IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell(); + IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(path); + shortcut.TargetPath = Application.ExecutablePath; + shortcut.Save(); + } + }; + + Button resetSettings = new Button { + Size = new Size(120, 23), + Location = new Point(258, 20), + Text = Locale.String(@"SettingsOtherResetButton"), + TabIndex = 303, + AutoSize = true, + AutoSizeMode = AutoSizeMode.GrowOnly, + }; + resetSettings.Click += (s, e) => { + DialogResult dr = MessageBox.Show(Locale.String(@"SettingsOtherResetConfirm"), Program.TITLE, MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation); + + if(dr == DialogResult.Yes) { + Settings.Remove(Program.FOREGROUND_HOTKEY_SETTING); + Settings.Remove(Program.PROCESS_SEPARATOR_SETTING); + Settings.Remove(Program.LIST_SELF_SETTING); + Settings.Remove(Program.LIST_BACKGROUND_PATH_SETTING); + Settings.Remove(Program.LIST_BACKGROUND_LAYOUT_SETTING); + Settings.Remove(Program.ALWAYS_ADMIN_SETTING); + Settings.Remove(Program.TOGGLE_BALLOON_SETTING); + Settings.Remove(Program.SHIFT_CLICK_BLACKLIST); + Settings.Remove(Program.TITLE_BLACKLIST); + Settings.Remove(Program.SHOW_HOTKEY_ICON); + Settings.Remove(Program.SHOW_WINDOW_LIST); + Settings.Remove(Program.LAST_VERSION); + Settings.Remove(Program.ALWAYS_RETRY_ELEVATED); + Settings.Remove(Program.REVERT_ON_EXIT); + Program.Shutdown(); + Process.Start(Application.ExecutablePath); + Application.Exit(); + } + }; + + Button[] otherButtons = new[] { titleBlacklist, startWithWindows, resetSettings }; + + otherGroup.Controls.AddRange(otherButtons); } - private void FgReset_Click(object sender, EventArgs e) { - FgModCtrl.Checked = FgModAlt.Checked = FgModShift.Checked = false; - FgKey.Text = string.Empty; - KeyCode = 0; + public static void CreateHotKeyInput( + Control target, + Func getKeyCode, + Action setKeyCode, + int offsetX = 0, + int offsetY = 0 + ) { + int modX = 120 + offsetX; + int modY = 34 + offsetY; + int keyCode = getKeyCode(); + + Button fgReset = new Button { + Text = Locale.String(@"SettingsHotKeysReset"), + Location = new Point(target.Width - 85 + offsetX, modY), + TabIndex = 105, + }; + + TextBox fgKey = new TextBox { + Text = ((Keys)(keyCode >> 16)).ToString(), + Location = new Point(12 + offsetX, modY + 2), + TabIndex = 101, + }; + + CheckBox fgModCtrl = new CheckBox { + Text = @"CTRL", + Location = new Point(modX, modY), + Checked = (keyCode & (int)Win32ModKeys.MOD_CONTROL) > 0, + Appearance = Appearance.Button, + Size = new Size(50, 23), + TextAlign = ContentAlignment.MiddleCenter, + TabIndex = 102, + }; + + CheckBox fgModWindows = new CheckBox { + Text = @"WIN", + Location = new Point(modX + 50, modY), + Checked = (keyCode & (int)Win32ModKeys.MOD_WIN) > 0, + Appearance = fgModCtrl.Appearance, + Size = fgModCtrl.Size, + TextAlign = fgModCtrl.TextAlign, + TabIndex = 103, + }; + + CheckBox fgModAlt = new CheckBox { + Text = @"ALT", + Location = new Point(modX + 100, modY), + Checked = (keyCode & (int)Win32ModKeys.MOD_ALT) > 0, + Appearance = fgModCtrl.Appearance, + Size = fgModCtrl.Size, + TextAlign = fgModCtrl.TextAlign, + TabIndex = 104, + }; + + CheckBox fgModShift = new CheckBox { + Text = @"SHIFT", + Location = new Point(modX + 150, modY), + Checked = (keyCode & (int)Win32ModKeys.MOD_SHIFT) > 0, + Appearance = fgModCtrl.Appearance, + Size = fgModCtrl.Size, + TextAlign = fgModCtrl.TextAlign, + TabIndex = 105, + }; + + fgReset.Click += (s, e) => { + fgModCtrl.Checked = fgModAlt.Checked = fgModShift.Checked = false; + fgKey.Text = ((Keys)0).ToString(); + setKeyCode(0); + }; + fgModCtrl.Click += (s, e) => { + if(s is CheckBox cb) { + if(cb.Checked) + keyCode |= (int)Win32ModKeys.MOD_CONTROL; + else + keyCode &= ~(int)Win32ModKeys.MOD_CONTROL; + setKeyCode(keyCode); + } + }; + fgModAlt.Click += (s, e) => { + if(s is CheckBox cb) { + if(cb.Checked) + keyCode |= (int)Win32ModKeys.MOD_ALT; + else + keyCode &= ~(int)Win32ModKeys.MOD_ALT; + setKeyCode(keyCode); + } + }; + fgModShift.Click += (s, e) => { + if(s is CheckBox cb) { + if(cb.Checked) + keyCode |= (int)Win32ModKeys.MOD_SHIFT; + else + keyCode &= ~(int)Win32ModKeys.MOD_SHIFT; + setKeyCode(keyCode); + } + }; + fgModWindows.Click += (s, e) => { + if(s is CheckBox cb) { + if(cb.Checked) + keyCode |= (int)Win32ModKeys.MOD_WIN; + else + keyCode &= ~(int)Win32ModKeys.MOD_WIN; + setKeyCode(keyCode); + } + }; + fgKey.KeyDown += (s, e) => { + if(!(s is TextBox textBox)) + return; + e.Handled = e.SuppressKeyPress = true; + textBox.Text = e.KeyCode.ToString(); + keyCode &= 0xFFFF; + keyCode |= (int)e.KeyCode << 16; + setKeyCode(keyCode); + }; + + target.Controls.AddRange(new Control[] { + fgModCtrl, fgModAlt, fgModShift, fgModWindows, fgReset, fgKey, + }); } public void Apply() { + if(LangSelect.SelectedItem is LanguageInfo li) { + if(li != Locale.GetCurrentLanguage()) { + if(Locale.GetPreferredLanguage() == li.Id) + Settings.Remove(Program.LANGUAGE); + else + Settings.Set(Program.LANGUAGE, li.Id); + + Locale.SetLanguage(li); + MessageBox.Show(Locale.String(@"SettingsLanguageChangedInfo"), Program.TITLE, MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + Settings.Set(Program.FOREGROUND_HOTKEY_SETTING, KeyCode); Settings.Set(Program.ALWAYS_ADMIN_SETTING, FlAlwaysAdmin.Checked); Settings.Set(Program.TOGGLE_BALLOON_SETTING, FlToggleNotification.Checked); Settings.Set(Program.SHIFT_CLICK_BLACKLIST, FlShiftClickBlacklist.Checked); Settings.Set(Program.SHOW_HOTKEY_ICON, FlShowHotkeyIcon.Checked); Settings.Set(Program.SHOW_WINDOW_LIST, FlShowWindowList.Checked); + Settings.Set(Program.ALWAYS_RETRY_ELEVATED, FlAlwaysRetryAsAdmin.Checked); + Settings.Set(Program.REVERT_ON_EXIT, FlRevertOnExit.Checked); Program.SetForegroundHotKey(KeyCode); } @@ -244,49 +420,6 @@ namespace TopMostFriend { Apply(); } - private void FgModCtrl_Click(object sender, EventArgs e) { - if(sender is CheckBox cb) { - if (cb.Checked) - KeyCode |= (int)Win32ModKeys.MOD_CONTROL; - else - KeyCode &= ~(int)Win32ModKeys.MOD_CONTROL; - } - } - private void FgModAlt_Click(object sender, EventArgs e) { - if (sender is CheckBox cb) { - if (cb.Checked) - KeyCode |= (int)Win32ModKeys.MOD_ALT; - else - KeyCode &= ~(int)Win32ModKeys.MOD_ALT; - } - } - private void FgModShift_Click(object sender, EventArgs e) { - if (sender is CheckBox cb) { - if (cb.Checked) - KeyCode |= (int)Win32ModKeys.MOD_SHIFT; - else - KeyCode &= ~(int)Win32ModKeys.MOD_SHIFT; - } - } - - private void FgModWindows_Click(object sender, EventArgs e) { - if(sender is CheckBox cb) { - if(cb.Checked) - KeyCode |= (int)Win32ModKeys.MOD_WIN; - else - KeyCode &= ~(int)Win32ModKeys.MOD_WIN; - } - } - - private void FgKey_KeyDown(object sender, KeyEventArgs e) { - if (!(sender is TextBox textBox)) - return; - e.Handled = e.SuppressKeyPress = true; - textBox.Text = e.KeyCode.ToString(); - KeyCode &= 0xFFFF; - KeyCode |= (int)e.KeyCode << 16; - } - protected override void OnFormClosed(FormClosedEventArgs e) { base.OnFormClosed(e); Instance.Dispose(); diff --git a/TopMostFriend/TopMostFriend.csproj b/TopMostFriend/TopMostFriend.csproj index 3201bbf..aeb5065 100644 --- a/TopMostFriend/TopMostFriend.csproj +++ b/TopMostFriend/TopMostFriend.csproj @@ -44,12 +44,20 @@ Form + Form + + Form + Form + + + + @@ -61,10 +69,12 @@ Form + + @@ -80,6 +90,9 @@ + + + @@ -88,5 +101,16 @@ Resources.Designer.cs + + + {F935DC20-1CF0-11D0-ADB9-00C04FD58A0B} + 1 + 0 + 0 + tlbimp + False + True + + \ No newline at end of file diff --git a/TopMostFriend/UAC.cs b/TopMostFriend/UAC.cs new file mode 100644 index 0000000..9c98a55 --- /dev/null +++ b/TopMostFriend/UAC.cs @@ -0,0 +1,81 @@ +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Security.Principal; +using System.Windows.Forms; + +namespace TopMostFriend { + public static class UAC { + private static bool? IsElevatedValue; + private static string ExecutablePathValue; + + static UAC() { + ExecutablePath = null; + } + + public static bool IsElevated { + get { + if(!IsElevatedValue.HasValue) + using(WindowsIdentity identity = WindowsIdentity.GetCurrent()) + IsElevatedValue = identity != null && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator); + + return IsElevatedValue.Value; + } + } + + public static string ExecutablePath { + get => ExecutablePathValue; + set { + ExecutablePathValue = string.IsNullOrWhiteSpace(value) || !File.Exists(value) + ? Assembly.GetEntryAssembly().Location + : value; + } + } + + public static int RunElevatedTask(string args) { + if(string.IsNullOrWhiteSpace(args)) + throw new ArgumentException(@"No arguments provided.", nameof(args)); + + try { + Process process = Process.Start(new ProcessStartInfo { + UseShellExecute = true, + FileName = ExecutablePath, + WorkingDirectory = Environment.CurrentDirectory, + Arguments = args, + Verb = @"runas", + }); + + process.WaitForExit(); + + return process.ExitCode; + } catch(Win32Exception ex) { + return ex.ErrorCode; + } + } + + public static int ToggleWindowTopMost(WindowInfo window, bool switchWindow) + => ToggleWindowTopMost(window.Handle, switchWindow); + + public static int ToggleWindowTopMost(IntPtr handle, bool switchWindow) + => RunElevatedTask(switchWindow ? $@"--toggle={handle}" : $@"--toggle={handle} --background={handle}"); + + public static void RestartElevated() { + if(IsElevated) + return; + + Program.Shutdown(); + + Process.Start(new ProcessStartInfo { + UseShellExecute = true, + FileName = ExecutablePath, + WorkingDirectory = Environment.CurrentDirectory, + Arguments = string.Join(@" ", Environment.GetCommandLineArgs()), + Verb = @"runas", + }); + + Application.Exit(); + } + } +} diff --git a/TopMostFriend/Win32.cs b/TopMostFriend/Win32.cs index 3cb94f0..fb516ad 100644 --- a/TopMostFriend/Win32.cs +++ b/TopMostFriend/Win32.cs @@ -52,12 +52,10 @@ namespace TopMostFriend { public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); [DllImport(@"user32", SetLastError = true)] - public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); + public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex) { - if (IntPtr.Size == 8) - return GetWindowLongPtr64(hWnd, nIndex); - return new IntPtr(GetWindowLong32(hWnd, nIndex)); + return IntPtr.Size == 8 ? GetWindowLongPtr64(hWnd, nIndex) : new IntPtr(GetWindowLong32(hWnd, nIndex)); } [DllImport(@"user32", EntryPoint = "GetWindowLong")] @@ -84,9 +82,7 @@ namespace TopMostFriend { } public static IntPtr GetClassLongPtr(IntPtr hWnd, int nIndex) { - if (IntPtr.Size > 4) - return GetClassLongPtr64(hWnd, nIndex); - return new IntPtr(GetClassLongPtr32(hWnd, nIndex)); + return IntPtr.Size > 4 ? GetClassLongPtr64(hWnd, nIndex) : new IntPtr(GetClassLongPtr32(hWnd, nIndex)); } [DllImport(@"user32", EntryPoint = "GetClassLong")] diff --git a/TopMostFriend/WindowInfo.cs b/TopMostFriend/WindowInfo.cs index 8d86c6c..0e01873 100644 --- a/TopMostFriend/WindowInfo.cs +++ b/TopMostFriend/WindowInfo.cs @@ -3,18 +3,18 @@ using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Linq; -using System.Text; namespace TopMostFriend { public class WindowInfo { public IntPtr Handle { get; } - public Process Owner { get; } + public int ProcessId { get; } + + public Process Owner => Process.GetProcessById(ProcessId); public string Title => Win32.GetWindowTextString(Handle); - public long Flags => Win32.GetWindowLongPtr(Handle, Win32.GWL_EXSTYLE).ToInt32(); public bool IsTopMost { - get => (Flags & Win32.WS_EX_TOPMOST) > 0; + get => (Win32.GetWindowLongPtr(Handle, Win32.GWL_EXSTYLE).ToInt32() & Win32.WS_EX_TOPMOST) > 0; set { Win32.SetWindowPos( Handle, new IntPtr(value ? Win32.HWND_TOPMOST : Win32.HWND_NOTOPMOST), @@ -52,33 +52,34 @@ namespace TopMostFriend { public Image IconBitmap => Icon?.ToBitmap(); - public WindowInfo(int handle) - : this(new IntPtr(handle)) {} - public WindowInfo(IntPtr handle) - : this(handle, FindOwner(handle)) {} + : this(handle, FindOwnerId(handle)) { } - public WindowInfo(IntPtr handle, Process owner) { + public WindowInfo(IntPtr handle, int processId) { Handle = handle; - Owner = owner ?? throw new ArgumentNullException(nameof(owner)); + ProcessId = processId; } public void SwitchTo() { Win32.SwitchToThisWindow(Handle, false); } - public bool ToggleTopMost() { + public bool ToggleTopMost(bool switchWindow = true) { bool expected = !IsTopMost; IsTopMost = expected; bool success = IsTopMost == expected; - if(expected && success) + if(switchWindow && expected && success) SwitchTo(); return success; } - public static Process FindOwner(IntPtr hWnd) { - Win32.GetWindowThreadProcessId(hWnd, out uint procId); - return Process.GetProcessById((int)procId); + public bool ToggleTopMostElevated(bool switchWindow = true) { + return UAC.ToggleWindowTopMost(this, switchWindow) == 0; + } + + public static int FindOwnerId(IntPtr hWnd) { + Win32.GetWindowThreadProcessId(hWnd, out int procId); + return procId; } public static WindowInfo GetForegroundWindow() { diff --git a/firstrun.psd b/firstrun.psd new file mode 100644 index 0000000000000000000000000000000000000000..e8089b94ee6a34398a9f58a41f549822c6ec5d1c GIT binary patch literal 161897 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

iwVpPU4Tb924xkjIg7~1P zt%7yM-X2;lg+>!Z1AHtt&oG|2Rb?u-uOQ}`1c-A~yH}uCA5y7oLoDcu`~y*st6FK$ zsBj9EHgW{NE(971bu$(Ar~|)72$E=Oz9G$Q5cSdNR0J!f20R-OdsNuGK_FUzDNE4E z<5v_F7ePXS5F|NK)w0S463SZa-NIVrD4+J4`UF-UR3OTNU&UN` za5R_C7FcXzji?hPG&z1vG$u;q0nn*W4Bt_|!pv3MS3rVK3nVSJ)C-EH+HnyyZH*%l zNzMM3Za`B%m|?E_57iM}X%a26N+Yx#M8mleG|Gv%GU|EIFQmwNK+&K|l@7cUv1>-5 zqnPeSL?JelN3D!;z$NsG$_N;TRM(6a{NBQIFLDCXcM!i9k&|?lT1FpYYdzB0hjB)- zYxE3DbZ`K!aWs}NnPBE{LP{wkMzche6i}-`lw**ME^@fi0gV!Cjj!0NK3rihBd-Eo zE6_W5i!NS3#=xZ)z6ByFC8F|Re{MM2M*FRLLdUR=6_TW`WgOc)OhmK+Ky)2lGcHDw zkf^I+kIXWMlnzGJ{5W5 zD*IU{Cxrtf>FNXJ{Ucx+oc0hHE8`}{*ASc$Wa#hdB8pVW^zsonzx;6D2}04eTAHG><|l1xm;h?!~BrpROU*T7aC?Di`#s$S1kgH`>vn|*sh{SJjbp*uW{Us1vKwL%-3iMy;&Z!xj$q)C?ate~Qi3H8LbE@lF zR&C61=QTjKk$ZWW2sg&nfoN-Sm4RzW;F4n{@H;`igsmIrSj85(WrM8%+Xx@i1dp^C za&w&tt`@kuJFoInqZ!mzcYXsp(LzBAsmw-RCY`$bv`MRUD(3nJE38AV9S!R)CL3vD zqH;_-37ZlX%rVWxl|NA5Kf1r5cGJQmFQ5e_G#f${9i0Tn^|TE z^S+FEAK;o3%Zk7NVoC}GkP{3Q7z&K)fc&K&2r%4%fDRnRB#H$l;_QJ_z^E=F&W26- zt_wSV2iw(;f?*%4MzS7Q`q-(W!J+sp;rRN2!+xv{ayPG zeayf><=%BIibEA;_CC$03M_50gkWFVNk9c6P$Aj|5SA}VsX=2#S3R826eN}gP>Tcy zJ**~987xC+VqtDAmehC{(x~e_ut)&aC%L3UjJ3oZ?YcC<(xa@3%Rq>2aoLKx43;i` z(YtK0$mb~Mi5fh1VlBxjEd%&O;61^Fs)gDQBGjzmlVvgKqw{NukMvd-r-z7ck2J;9 zC*din#dr5mpn*RF5Y)StP$tp>WF0gvgF8VgEi#yK5*^&(;S< zI6D!QBu>`C*HX#mSwVhDakfD;h$57Tt`U4AA(+KBzcmjA2cuo@AvGnMrs<}jv8xY8 zyWY+LsN$vsHbHCfRQnc@ADXe`mlg6eBuO#XM6N-UH+>9)-fGW=-MgSs1lW=BmUQN? zlN$6vVWgq^w3!M0W9|P`z(~wrqJI z2hSqra1{^jT4Y-NhQFa(CQd1IvM!KEVX}VU8nVshg4z z4(W*WKzNPft)XTo><`qz^7L(K@4347B52B8zY7}Y0^r}SeAi{rP;9}9ZP>A$5X!=f zs5t(FVw8JHaNDNkskL_v~CDHLl^<3&a!Q=%F{ zFZF1VbOk-yGYTC%54AE1F!C?1#xm=!^ZaGong$2jL77?Y09PHjNIH?B>cEh(2z(sx z#I}M}D4PQ2U{css11W=t1y1Rd$*0&1F1y6!37h8;8`?%Is=w#T-Yoiu*V%Uon)RV) z1}+B-lq<_9OrSKl2+IhRq?a~fIAb7E&JLlMm_`Q%$i3ank|BZADudF2DYsDrM171N^S7#U90RY#Nx1 zYLu*1O6l<^QGjWnl+Rdnf@{cnL3}ho&PQmVW%(Kpqdn(pkPJ&BLkqoF(0*i7V(Le2 zauw5MxZMF$hw`(Lk^?fNeGynjOAB04@(Elyk|hU|9vX^kIor^xCSocARY}A&z%C?I z@^6eP@sGk5s0_dR4-`;})CE+Lq7xw|N?k?T^?o@CI@unwG)856OW(H^RTR=2R8q?x z^bkEHZNh3QQx(zE5K2MAD2UlSGCD{yMY2Hyr@&T;DJRd9QoRP#0+_mRZvku7f>Pz~ z7H5|ZmN1NCZLO^0TIFJzvP#q%<0|(rgG>Dz!NEi;8!Lq5O^lFmrRXx@%FsP=X|3QV zmLk=;b5bR}oJ~mU(Tjo5F1slKaTIn`Pu0QZ4nfIW9D2}4GJ1_aNW3(vB2j{B*2T3C zwNqsWj9`Xy9pr2f)JrIxe=w4fdh1aZ#0`B?P)DL{c_ftDO>%Nj_CaY;c$tWJg#zgi zy4fT$deAS>`{!!v7;& z>MA&#Z_Of6?gqvV_?#CJU*91jkcrQzq5z*mDZ|Jf7L`71m=kpHIXr*^P&pX2Y6+u} z4zeCP(ceD=TQ-|pjy+gMYT8FD^xGt_H^EnfZv?&yi`Krsf`)B59TqKzN*xMgIrz*V zR;YX|fz39PRdu3LQs#t@ra1WW7>c3|3O);76mjsd37@uP0DmL4nZ1N&BwUt@$MY@b z7Gv$OJT|g1HbK_XTY=0tf${;`P%xiJ2@Yhm+mS+%F&sn-))K@3xiea{8JdH)6@HEV zCaAO|oI9vS#1*K95nB}d+D&ArUYJ9f8Q6^((k{1{)e3I5kT|n zU1m7pB$Xq|8#Y6TE1*ftkHUTZrZpW4CKkWPxQtuHr8gK^!U|lYh%6E=GoRGp981|q zE)vs^z*WTzXFc7AUNvQ7+caWpH`uBNndpqjzS#L2A&2-~D7VNqw&%Nn$p$_H3_+`u z|BwsgH^oHmGkcN5eZzrS;?x{F!jMUfCnQ`RO?uU~9*I+HG_->qapK9QtC_f?0JKgc zO15Vh-K=7E>HrDHFd*3* zr7ajrnaGtwpH*0+2fCPD2XO6(JAW{w)-TDN5rgUcIE!$eaN43@>O3*Ei4*52A&MH3 zYR3{lF9%5LmN7{gNvyLZq+;~)Nk9N;X#oR5U8{m%{y2W;1d&A3y@<}rtwBZ)bPnY9 z31k@?Lr^R+79`G^-(t^2%mr2Dz(wZ>5jRNzJHk~{O}3XqWhtt@76HX(0+JZY*$Bz=>`{--1~bEEP<(rV3D~@FfmL8CdPolL^($F-0?nr zoiJ3263Ba)3j@zKYD|h9BEO18@v;Omn9XLd&vihfJGVE{et1NZ<~*o9eT7ED3Qc0> zvbdiKlKZx7av$A&`8tEZA_B`^2=}t zgO16v4ABlsb!bM?Q-b>pt?%qcJ(Lb=;7J9HF&-0b@u-SHtGTO4RUcYeT~prMfyOBz zlLiwH=OpNuOkaUUNd+0XM$R=|5z>H&FbvltA_EO4EtlY~J=HE0qChf1Bj<4NL7lPd zAsq|qWOJjrZ#y{0zo=npO(j$ru(a>OO8FLXGrp0ye!4|;Up>&B&WME4SccVVtRiY= zlTwRsWoS8UacWeK5P+I!X~bBA(~i!%e*nZG^?IAjV~FNRDas&sg<$>JY%ZUx5AsUP zKY*3SXV&5Khg-z_R+P*`s4YfTYo1+9w?o`(TRX7H=$Zm7LqFP9t4R#$#&xZPx{bIl z^8(ZY^1jcO)-)WUNT|%U6X6^hFJ=Y@re@K>Y_6E=k!lY~M4UEBHe#scM{n2LF$~{V zf#po5FHJ9np=WF%cyt|U7E~VPPzMFHO-`UO3riCr3NAao0jVUOlh=e($hyIG9bs$& z)xl!bb7cfMrjpK^h-ic^_QGN%GSRz<#FqJZ%sj^afdvYZOprjPgvb`V$%QvJIOJ*y z&frEMqlnAieaLm4V%=}^*IHC2xy-~h45Ujj)74giszVT)5?sqTHF{VuQJw6lu0`RY zZycq`3zTSeg-%ye*T=>?!AE2f1nfGs|mV>fou?NQF@gR522SGOv8T5t_fMT^*TPM(*#_WXRcwt zwTlTCB|$l{1BtzP2#2)ExK2P5{rbqfSO;_tL#IGOI~buLy=Xn-VCxFO zjbXk@ABAIZ*!2}x6CXf9I!w|k&P zD4j)V$EYHCqco$QZoe_2AYMSb23vDX#Uj{vH^F9~OZ~7&;Be3)NmIgQ!WK6ufvcGA zFu`VG;HN!))E{NeCWrh@<(~SXjLhuv3iDyrim*iGW;7u& zAjX(wyqQG6jqESX$%cuF)HAIHF137oLK-=c(Y9jCXj^;F!H}bnFEQ^mge*d4`~b*Q zgj7BTLS*L{a?NzNkR3mj5ix!WR-@rGGj89sHvd9#90fLm;K*V2QhuT>PB;@;tts@F z(Q@ji4{6I8>irR{#l2{Ox1#!MrAoXpcDr>E)HTBC%?{4oTcuh>Yb{X%Qwiou6Vj{T zP}LT>TJ{BDM^xLVwgpHoLBL4Ns%;+29RdVrLmmaU8?%ZEBqj4@plATvA= zfTAPQB-rNwXJ}v3h#G4Lo&mra;s13aC7Wipiv?J0ZA1QyexR{lr0*e_b}VJW7@?_h z(wvy-*xv^sr4JDHusjwTm|@29R1G?k-q4#K=tw@dE-`axk-@9>c9Vq6bBN4XH{HOv zVfP;9K*U#q&v?|*rPozrM=etHu>sCp=R52n>bMVGRjQMMglvw)7!<5Jx+1C{B_K2EGTCe! zs9k~r$8=I>(9F#Ei8eMF_Xrl1+cKaU{+76jF-x*Ymj(bDm`D*!_IF(bs_9imoa7jR zy+mO;3(1f@zq!4N+NLAR8uJw{TIQyH%vw@f8yqpPYn3ve=|ya3h+Z(zvF5+y>dr}+hSY~R@t}I8CRqh4svUm#8)VSh+h%;caETlP>0}H zmdTGd))_7*2W_RsWMVk8d?2&Zh4Qu$L5Bu%tV_ZeH9jyp9*s+N)B1iQEx1Di%=rJ#t&Tf$?c#WwPml1|TZtSrO;{?hc>7A+4vTSX z?R5O>W?1S6F08{r$QU+49MVK1){ROob-lomH#kz)!aIZ=>@fK0?ED=tq?n=Pc9Asx z(&Fq_;QhO##9b_bHbY8yd*$lcshDZ7Le{J?TA}g=p4B?2V?#9sml70CS$P|*+GX#A z8yrHa>|KhayYsg}V#H98?&`M-#&C=>=;*+i_eh2l7Ils|#8S)ym(V4hl@6*IWQQ7J zF-03t|4TBPLlHx9Cm6(n?W7aHP0JH3SQKR{!s!8W5cOVeEV8h&qO^cxi3HBy++1aa zj^nquk55#TDxi*Xayhh{jF@=DtI$CvL@P1YsGM{u_t+s64aF$X^yv*IG~P|_t!dhV zF&b|?Ct*T?o;2~^htkrh%(3-p0g z@u`c{ipKtpXt>pc5XKQ8w4D&fTVlOoZWWF52OI?nzCdVVdYMyna;D`Q)C!#d>e08c z(@mupPC1owW!l?eVb&7t^9Fkj3pX1Eh!TWkp|hv9BE4IT@f4U9pmJ^&DWWQ12cA^V zx_lvQwmd`}~H>z;PIs3O)Tm zCpsLabllFH&-Ay-TebCf(CGMd8U#L7Q2SY z-WkGmvGI)gt-~_J<`D!pA!d&BAn9OH8np`vix!h-VC=Yp6}I#z7UP=^x4{o&6}F(m z)})Rg@pc#j@323sXnGO7q!|zkycgFYsi@(Mi#B5v6)3pLlH)DK)R!3mqpUkF(;uO( zg)VooE`6vXcf5^JD{Z0KvYlgyVo4gP*BoxW+E7L;W<=iDB2%lddh_lNJ#V% zQytvu5}_#O%9QjrWlfkEl}37;RkDCX`5QG0rNe*QeI(&VqN_cBgy4QR{{UxgL2zwO zO7Wj}eFC8|xJ95-0e3iPD*I&~w&Fh@K^|5z1Y(4exAR40L=f$@xRJrV}73R-SaQ=*Dtf(&u4#^ z-~SY(p4+o{uK$hCekI<2mB+-SGk=xueRRw}itTuuOn$mP)#t~@I9)tmo>(|pohnaO zCw!!<59RXdRX)7dH7ZLU^;6B)&y>epEucEtJyoAB&-9<|oGG8JKT$o$vLrmNuzJCj z3i@ZOm+BX*7wYF-lB#&NI#ZmkP7P0vPI*RFy*=TBv-_N>;>^X#Sc{cUIwuPr_@1Bm zfGw9!kIoFAU1mSgb&vCysN*d01j2&-(pt7YbjkZxfw%f_vEnmt(TfW4@!NFNR2eo;?)d(6ECs)AOIk5=FK0jitPt@>830OHk;P}<4>w(n= zttwRsr+gM?|HL&U1DOe_WW8V>tezH$sprdQ;<0laqXjiCpYg$W)pJ8110L80FLl9` zXeXv2w7Uu(7UelvgKcVc?O!6?j~Ab`_70rtc$%Y}MfL>2Tt4 z*(Yhn{%W!j}=IphHB$RZ@(byQtbGeau}FZExVdJ$pIF&+w0^=$Xd@N^qtAF|^z zu&w}SfRLl)D9{jL&rV%Nc*@huC{co=Ss5PhBfKT7%}=y~IAcgY9+KycHpEeUBu?kl z;Iw99)R+p)1fURRK)GUBdKOpbFI%vmAsb?y*uwr%k zJRW8%%#x*cgjqb7u_Tm_Q|_M{pgARyH400?3i8Mb(s}%2$5>4GDk!DZJFrtDRG;pk zKrS(&*;VCwoVftykb{T-g9S>IZr-QM)jS>7H7?RK19PsYz%dl3m(J7(b`8J*;54@h zoR7hmtDT_V=+q+A8HD(hCt}&jFzkz*t>8@WgQ~*BmY`zMY=plBu1cDNOC>9gx7kvh zC8oiJtyRP!&p|BWdFA4AVNld54En;EY=SE-g*(Q@UmAN1UP}U|9r8l!;8imR?Uo|IEv&j&S^Fj*OtDpB2%Z4x4$zQ;B=iJ+7V z0I?ESfMv zBdx4fJYiRa)iIAhLI?XNyEu0Fy?kcrv`g41OQU1UtTgC$kaNba+ZYU)dC8flK^MibpP)ofVMsPOZdaH1b zHSVh)yyU!43`>eM;x3?A%^E^|Y;B9DZQ_=o7J(jD)JKvlY(({J*-)$hViCxS2{Ik8 zXqFAbIEN^49h{?oJULz;>C;@U&qR>Dg4n|R}<=CZ@H2| zbA^jMZIq`}KJB7cKGodoRii47BHiVyNR_w_9L-)_z+J`zeZE#OW!$!xJ57iuNFV`KcACuO0EnRftM7S3Y;qqCQtRK&#Y`B_3c}!Xpe{NUQJQ#sX6hiuscVpINDc074{EtQBEmfsN}R5d)};_B7V*eK6~fmU*VA zIHZk1PjRe;9YSN!pbjA%x`z%H#uYF0U+lB2Rz;{ffRnDFN{|K)Em{{&_Mp!Q9QARQ zkdEiodOX*}HN0L5-`>G4nY^r=QWq9Oy5Q}xiw0!q&9YBl1y4HypEfknQWV4itkH`! zrKOr(6SdE(S#4}SPtI>}yvz9wM&$=9nX)=3OKx*bqhnXFMZ@Foa;)~`yjt~w^S0u= zD{Icny1mGU=Pgh7h>k|sZeto&$j=08eBQc zz8B9efvI@WRc!mQI&h+gct&R~s8#U03M}zdS?Ix|ypJt4)=+8ftiwUj1HuxyE;wjpz4a(4OA_wD&wqk%OUnsRLcgNM~3VH0Z(;@8NTf?;12RibOyW zo?tuR5!tv@;@k50B@9${f(OY$gbgQ-V`lmRD;a$kT@ls*NGzSg?u$UW2&96gNeE*2 zG2qhp_?&9o1&b9ZDs9BJ4ruw=>gC?q0=DUpWm);`%9-T}EW_M_Z=9#|Rc zL!0z2hsdxlYLrEYSipt-BK}}iW!7X{F|~^Y?8~#Q23L*6Wz7a+w;|$^3Mr)GcqT8o ze0q8QJl57#a*W3$AW;BTE<+UcET*UBsU;Z4`U&Xw62xj@-3n0kK*iGQP>TgR@pkIBN{3Lee9sD+ zg$x0ye0lgv*+9}rb}+|2rkfgBgGV-1;Bi^xA?)C>;q&hzAQekXvEpNcg^G^)6Icpz zW)^>8uO)ue@jB`TEU*i%A#79x+U%{f>Q1m3ZghfR30(!j`k+JmljDkoUrg3yrNL1c zJMauZwt*EKyYoZn_M6YROt!T!EC4|eSv+jC8kbXR8^T82_;9`p8Xwp_0v`+2fW{i1 zp^TJLsCw8SL}X&PVdzEXikfiE$f8=iYUgkD4|ATn*z4OsmeJne$QL#)DYJu`q- zWtd-rauB(s%}Rt$Qzs*zcBLER9pXGZtpyDhPem^M$&OtCpm~_Zz%f9hZnd$E2TcIA z-GF-~dv(-+w7}89NZ@$^Xm%t({e@ zL4z!ZsX3a$#c(-n1*$&8v`iu@>H(Nemg@{utbZP4!_$JQe5H6bf2DXCal>@wkWSNO zrf1e|recngP-Wz^IeJ;6Sw?&29Lt!qIA@%zI<-vfF`$Hs{eUVX3|~fpl4qGeL;Zu- z?mA>H#fz>xGo}}|mBJQLM}Cim1<5-%cdt~+&s%(ji8SPV;MtwpgnYgxcW^eIS^y?mFQE_ID>VmWx8F%sY z)I3SIOGS@Zdb^EPA`NLmq3X=_)5B9ephdz!NTbcDfrKW-#r5!)V{oRoRDuCVslesv zh!3b}1FQg80Wgd#g)1~R7-{NBLPNTqD*h?KbIB|o#*df{a87-+w1r?(wZ?+VM8feP zn(0CtbZx9_hV7tm1(7bJ5GyETvWf%3Q)}OnZj7!^^|Sqa3uh#{`fLrl9_R+3GXxi% z&N7un!180%fmuFR4;nFQx`H;mQbjGX;TK5l@>5r!oo=7f zDU`|sBPl%?FN9GUiIa5OLJ=jOkh~GttoeUC_+EPHEYerMvJAe(m+OcTrK4$$_y!Sw z8Wn5G2xCZRM|750G&hoinj}*BD==LvxB<&XA|$D{FbN0fY;c8^wk*mGz%o4X{_%@Y zdjvw$APWKmwi2K0y`aE4c(44s8}5B1qyu=OxM9Q zdbxTf;|C3fx2C75CXciderbL`4z^>+pDW$F>=;XQVN#Yc!6rBZY{??>L-=@lNOfLZ z1A8~{a)@NLD0p2Vabr>C;H_b&sD{MlbRsZv6{tEBR28nOeyxR(D~OEr_TxTOP1aF7 z+lz#mr3V{SF5H5wfy%`!4NJR|+cKtd5^@F0VLvqoxL1 z;^U3j%2!ITt$-~>ZMg~Cgkp62D63K<=Ul7!YHUctXRn6Enq6!&tjXYn{U_)^u}4ks z)1%1XqC8v(d#vLdp120egtljN7nWp|ZY+Qu5+=41y0ya1Cz>TG>*2E2W1?gNCYH30 zZVihvhZ8l2GZVC+WoSPNx+(uGs~nc71vl-bc0<0z_6_)o`~^SDNUE``A!S8_s(7_} zE#s#PG9yV-f7}^vtN4VSoSP#{i;EiT653|Bz$VZ}`S?UAx{G6*gBTi63Hv{d$J zSlF3liv=`haH62xn&Ukzos1}eA(iMdoe5ea6y766uwZ5IR=qNMb?UWO`>*8zwrKJM zeXQ$jT18E6jCd!MHHn_9QPJH&{H!+&06hYGD^qneaag%)%P=-z9iSL;{mSNkxZ&mteR(p7)L z<)v0pr z)Mlz}cFl7ENe5I_GMFsJ>Lp7D61MkRufc~&Br;BwI0J<0^v7BL>O{B!O`rRhl&)X_HUK@vn^^h8yiygWhG zwO0s@tO%D;BeSEq0+sFK^!Nm1I0@D~S6whG<}?*Cdig@j=p4=!&`DH=c0sc>s2sCc zPpj0U8?ZvtQgl)}xGgbVBVS0A>L5Wn6(eZ!2c&%od@Vyy_|~VciHTDVpjHJ&Ylz0e zw$~l>Xjy`}0hc*FID=ZQ#a$rv26jrlJTyhsc|k4uuZtklp|%5=GG!$gqlU5LH)&*s z>BDWDd=F%8_NE_mvJXxRSR0O?2)DueCQ7%_o{&)-0~ylPPz=3%Ih!DJ-Et{b2eP!> zTZFTb){ATbK3ZMuaOD=vY6IUj=*G4B%Sc*IMOwpYE!_&Wb)p)S*TFq(5E?>DI}sYt zIV5A%H5DD;=c}F9hDci{Xh## z108_~g6HUkgA39vp>wWDy3vd`u!wS!3?00tBIJ>|Vp^cvDmt?U&A7&c@+>(G3;GhD zCx(hlh8oG)$anGK3PWN$a(Mb1sD-X>1qb2iO&X>dp8SBnZ3ai7cnv~bmg61;O}_To zjOjXqqCu!?K`AbOc^LKje$?x;DByU$F+$g76`_j-n?a}u1{#B6$@7n<3bHpsmkrU}1I}&<2&Z@XZJf zHpOGK%ydo+C^^Yx!F?@GCjkqZmA$j%(*z>}w4?^(i1IPJC+W zC~2a0CD~=ecWSG!)cDubuLaBnVkf%1T%rj+Rm_0c1704LPs!+5qh;+xMl2Z#qu#88 zx@hNe;0<3ZUL8_=vNSwu;28xdNQs2Plhs)y*etpWwjPl{!nFu96RsLu6}arkwq>Lq zi^L(;)&x}_#v2_lE*GL`D*$DL;Pyer*xHPES`-^L*hZ9iw8uH@P3^0jVWS`78ulRT zl9DB4&Y+pF*iY>sgbN7YVpMH=P|I{EO^&28lWiztP@58zQz$~2f~Oj!2&JC&#PY>9 zQE>gTX>5nIu|!dNkvYKjMwN}BR;i}|y1siEtILm~qng@=j?%7h#x9CHWD>v_on}fX zwGlC+cXAcuk}x_^qH^7c&!WE+9OE-@5MTS%EV$bTUy1J!pT(0^d@7;E6AU4uw}jkT zRk!4?6L58P6T&{2oC6Zy0Do4VWCjRann~v&n2o}~w4k>GpsC2GQdqk-hEnPZy5_cQ z@UE|1Lm>u%sd}+}117m3Ce0tY)eWfB1f$+AGC#nSTji!Lh%*=lca5tGl#@~--e27y z`{R>7dstMt8M>sh{pfLNTCS06S&X$1(1{#km11LbmBtx#c-vU8+9jc#9B`6wNYu;J zBiT$YU*V=%i^Yuv%!*yP5iz=jCh`X;sEjh6X=y-X1Bd$*X@{U!gI1}i2{aPLki2Z3 zb1mY%Rh&le=7i)UVfv(E!s+tbto+Tw+N?Q@?qXNSFWytWPHCuf$`2ReuKAa}5=P4d z7qo?T*SQ{fz4ReW4nEsp8i8pPn3jUG!=RnhgH>b|(l6mkuEQRt^vj5!T&}z3XN2r^ z$S|Z~|M)U4(3ze#_@rO)>?N*C!&{#Cb*!3tsb*iGka!I{r>+=DC5cP83=2jyztL4n zupM}6zn4#GjHSramU6V$INK_w5qesZhZz^^&RQ}1V--Ry&YNC=R%zmcGA8|pn)0WX z)@Zl@JF6U1!DtZ`Bg^p6*wfa$HjaVM2&BYSp`k5YgKcq~FdZ-EfXE`ov@)_2m&3Ts zb3m`+=+sjfx*T{8csSV6jyjT6MEo5;4mF)8)wgPAmyyMX=?!#4oi!#sDvBcl<7xsh z63ZI^=4bmaXArLaY8%4U_}9Ft{l_G7q&gDM(3XKF)YVyPy{sTtC_yYy7;$vN306g_ zeNsbArIW(Q0@0LJJ7c_|OUGBo7l5gi)2?*b1uKHxl!n|Ku!e?OlN>!T7sKwt*|vq) z2ml<4c9M$rCjiqNngDIaxB_wkIQ>L_LO$ny7a)z4~&$$tP>9Dg^>$k9jZ zM;0ckA$=;#);5h-C62ZTsLU!L+$-Yhg^e3wMeH@LfXPfE5zWBFBQX^gm^x265$L>* zT|xYoVGEMvEamX@wLs*p4D`S7#ais**ak|=wu&vjYBL!Arx>Z-K+7h`q*v0>3VPKb zTfuI$L*~ZF>}T3CAG6aV85m=KS;cxKkfpKoF321UXUZ~=U1u+&5SzyxdYx%fNQOI9 zQ*a!HIf7PWL^lmEOyY*_dDms^#Oq3FrD` zkd73r;z@L}ds%>|kF7{}x>43ocyeZry={Z|j^i5Q8*4ZnQa^o#x@sOYvit0H_lRj$ z_?>3HE$nOEotGUVQ>pg4a{L<{qYEzQ7{_SLn=|x^1_#s`fTje^fas@yLSsa>21j&M zv0sfJa;jI0m?9v2`O^zTXf^WWY^BqXQpq-&^NY?MCv-VY8WRm_HJB>r1&L4KqK&4S zzw6__1rHg3h#+2+TG*5jQXUVKBgc)_pzKG4OEMO9hY`a^T7Q$7G><0*pcoan-qRWO zA*v#v;ua!}B?z5nwOPtkAsKZ+i;F2-D5xjzqZh8BZWX(S7B4U)@;mVfo#Y#Ee*D=_ zeBwEDAl))lFz-_Y&VpF7j7IC!OCfShkUc+qZWU?@4G7I}p4rm`l1IA}sLq0U_leUf zOsZ)#gV8v3^DZv4IN=~*8fxm(9b0A?;(afPW;fZ#gyG}dItz$8tK#em5bI#L5Y1&q zp%OBD5aoSusaVCw^a!ToH^WCcn&fE6b=d2WxovtnB%m??PpB+ik06}6w<8Ht&oFV| zjZQ5fGv7gV%GKVj?xl=jOhb9?c*{}%?9pNppb4RKtBHUE>~BJh$Px(wOA4rbJ#nIRu0n>SQKMdYk;)SxMtB+3>sGRmm#2YBu0vby^NrS2xYFf z<)r%!B)pEk7gs>#pZ#pkE~=T7ats-I;JZCtYj(YKmPPQQ%uGDLQFHI!E8D2-A>L&j38|uz*lgz zI%mVw6al1R=3Yo=kIBN4B#F5JB%ww^8Ea!$MP;{yHdgioTmcvZw|rc`l9P}Le29cn zeW3x>4s+!B6aY(aqP_%)y}^Szkbwt%ey1W-))Y=IG3K2RR)miJgmAglQej2g=H zmWV($!s*)h87JCxV=SGZ7$KUlJ?a${8KXJjln29pq+*(HS!nE*ih>E*aul?kJ}`Kp z|7MrJK~^*V@0enmnoP)+p1zLAR0Jj@t>K0fqH$$HM9DB#RC?M3DAxiBb+cfuV(6fi zNRpE1HuL$eW}4#`jIujum2MU(y^W_qBuBj=p<@v?LanPH)dgio+tD7QN6Ha8q0R;f z42vPWV=jIe*+M7@wZ>?4*;a~ie$bf!s3f|K4!C;On>-UY5{`2Y{Xd87@2d4PFE~qUep|Km(mcVD@lb2_G+Bm z7}=mfmBuoa_S7ip1g$IsSv6%=5ewgEe$jrv%^X?)5e_L=mUbL&bpoeN1uj2rYsr}Y zDiR>7A*h_6fzr-Evc3Cgo+DhJpkl@V*P9a5WpW4Va~NeN5hA&9K2wTygJLFf-rKgq zITAL5b4J8DlcQa2v{A?JEOHgNxT&n6mPk86>GJ6Tjyhv6lcNG@Na#wA;Efik@j9*) zTO46n93!_(>Xp$dA;%#dG_Xsz`edZRF*FW3=AVx*!U566jVp#9q^I6gBtkXQ0Xfor zJg6uQL;5j-#+|Jpaaa=!vd+TEDA9gEGYAeqLC1)-h&7xr$S~C(!r!rDGu6+r9xE@m zuw|4^VphVSxa1yg(ol?W4+IMw!C^~~Y02U|E1{|C8B<{xYG*hjgy9_AJ!=joLXKeA zo?%}jbcwxfYg{0s$Yz_6R7=vw z+IFFhUfp6u7L&c{zThgXX^!LU#@t5F0p;V~$l(|=ck_bIct&~ix@-qsq%lNd(jZG^ zF&jc-9w%h-xHM;dxknj?+IBN%Qqt02MW(*uR6$h-DsM@Yir&N`st(jM6*ZcQR$-uG zRsvLNK;r5Mu3iF__5>RzvXDF*XyYz`1txD5EGQe2sJ=XiLPSDkIj$t-B#|WCb!5TY zV7;H;5psE2fv&@EEB_h%bf$|IEL620VnU(TT9>8-7s%2y)G9KquQFF3|M)TIk))er z2XVi2G@cAby{XG`Nh*`j#*Rr7OE;FTh9ERu7&ugc4HqHyiK`aj5QHJ^9G4q^IsR3B z>GA6}p3D%PDYXM^Oy|6=HyaCZfn2T*@`a0l@HmuEE|r&__arl8XqnujI1BM$Dvf}3 z0F8vqXKJcwSpG&j>)H(T~V`c(~rByMdR)M=2YbTaI?gK6eoU-<7+DGV;i11 zc5I1bs$eU~ljt-9o6-!!U--R(tQK zx5`-TN HH)n5n?h`?!80eeeDo^|_+=_q^dg(yBxTKW9b`5TzjC~JHyFF>0eutKl zH{0Vj8f4u0O!KUwxmTD~Ky7Q^R=7pyowL>q2XU8^&ABnUVN4v<(dzO62~bK+35r$7 zkfWG3(yC(@gOe(}vo!Sa!OWfRa*=bi2|*U1m)#ETvJD;%tYkzZv_^Yc%7Ryl>+s$X zZro^4b*aKhvkFw!->3^jPhUPdsX^0^;7cCXAWAv1x}6Z&+O>j20syKdu&%^a$9;?3 zN#jr`bU>4x^2XRQC2kYcssCDwag^z7+_A&O%9vUiEj;gZg=)^r--vGrKb=Gu9}lg- zL75oq1TQ&;c|0Lg%B><11YwZh;mFKq!8=1wEBoFVZPKE7)Ajq%1cy5PaiYSRg)Si= zRTQj68ppOh%eWn5yVjWsuyJ2wL%SRYYJJK3D-*Vg4w}6KYYXvU39?}EDfy#gA3Kf> zrw@#{n7256oO$slnV*KBmY6zWsh1rBq7di&b4l)!$mblYhRu2QqA_TS&&8WUOC>p> zY050Ab`cp>!Sa_kKD4+UoV(D>1|o_uoAR;;+%a|qCdRyAGM8MAH^177G1oEYa+snD zY?MJE-WZ!^&0(HsAqF;Y!E`t-sVOcXOotDiFvHVJ)wIsIF`9FDyOTGA+dd6XO!-5|C1`bn>1z5_F9a|W$!c8W){K_%t%1!%R3N5c;jVWXwq zXnKTUt)bNd;%_qrJsbOz5Q=p-ITwRp}7x3Y6{ad=}ZB2N6p622%|t^0yFsMN3BsB4|X8K!nRpq!a$F#iTp)78I{7MQRBX)4yPH;3wVa z%%s8izp3oo@8I9Zv-STrWUK!^&i?DaO@ED#`$x0%Z~S-j`%+fd?_}xqN;a&|XX*7? z)~+vQ>2)DnsIO(|bt$`4FJJL+ zpFI1Q@l$61qV}iG{(1cTvwHQPpZwqThWE2(o3hy_Z;mm{{uSr*=k2;1KXvwRK$Bkc z>^JL`EWP%#I)4w$`l|9J6@#n0j8{fIlct4NfzCY0X z+mfY!9^ZeQ^Aa?9r%ta|cwa-k^Y!YxYw5GE*S}iArS*R;#CP4Vmt5`I_e=44{dJBu z$Lp^S*zs z`U-p1^;hc5Gv@W}zU!~KraZ1G?OVb{Fb9e|*=Bf?>y4`bLHQN0g`=OS(VE}|M_#4N z&9=)Y+x0mD-1{WIxgz%~KgpGS#P?-<4=tqpudY%=YIZ^5G45m==qMk8=PO@drH#ko ziauF?w*I8}?r1BogZx7Qh0`qA5b z1&)hmB0Xzq6<5mfIMy9+SHD@aZBPkmRH8g$P(ZpRbRHAxan`%ox+{hc(=8p7quu^{ z>@E8bL!LkrvLNMiEbXnniR+GUk)F?j)$RFFo|SL+`|vlz<{PiO{(5ltM7nZy>h|Aq zM2@QL1vbv59^dp+Y@46=zY_LBiZ=AcX58kxy!kHwN=Qk_a*aK|)#v?Ydn^lR_|ZCH z0dMtrd%XQ;J^lg~Ea9x1znA!X74tPL>H5E~@pr;@1q;3U{u1vKhD%uZ)%WLlf1ysV zAK`iQK4TA~=h5q|^*nl@Z$-~D$8{r1$nILtv+mP%{sm8kgxC6k8$8dtZ*K2fZvXAr zyCC6T37xvB@45N66VJjGU?;dPB&x9$+6j1zbcKcZIzIQ7+pO~{&6VBEtK8{!ALU&> z>ie;0fm?Ure{R2()=?|q_1}R9y8TuhDeQ0fGbJOPd(}sWjZ(YsV#{x)2Ws%#fe*UV zE$_y!{72=5=5FbQZusW*e&+Vy-qhdR^FrB`b)M%gywLY$-#5u)ZuCNWB)yRNkng`m zy%1LU>tXBH_@K3){d;<#UrBa9qKohW>vEr)d^_<#SlioppqqX>@h*4`JP;o2HXi6U z+uYQ%{0dR;nkdzX_fEH)c$lx;kpJNSjix^8`-um_E0>}kpAH5CHd!oX+>}Nu$ zxK870vEK2PH}yPF8qam7`Ohu3#w!2Emj58Px5#-tcTP+ zeQon<-P6}DuifUg&-*qtM_-4$t~9SX?>SbyTE|+*(yP|*8oKCfLUJV|-?J+CJ^ZsO zsF(Hq_@7llKeJ9~CDMwd|E%*$1FknJ9~s)YwsP{>n}0gCpkqC*-~8|==4laYuhaGN z&0BuHY5}8;flYpMja6LzOpL2F3%0>3-SA0V#iT}&zZtc>HB}2gS+9@zn|PFU8tNzG z%0vFDp43Gz3ICRX3Y zIr2BDxvqW3v8mI>Ijq;_Z(7gwHGlI;{M?g{h#7)HkpZsB5E|*Y;gb)`!iPV(CmkQM z9cv?xRok)d(+^vU4}W5OjSk-sCxq>|`RDg+$9hY$YB5&dt+g1$a*Y-FXxp*2?>P1w ze^`Eh`_E=SoBd;a?O&*Ww*Dt|cJJLi8r+kEd%Ex~ZV!^xYI;Do%5naHex9!V-s?RI z{K2EZJ&pc@$J2XP^oN-O_cZzsGxzUZ`yV_Cghu~isgI1W^Io0gTRbDYSHZehySrDv zys?Ixybl(8W86>SywTol8~^@t_CI8QCi^GZ|H=B{zrZ@{&e8G}%)BNUgSsiO8&p5^}R&~kyHv4j{bUgNGc4xCKMaC(nM``!flW%)#Bo0@s2Ur#N4D$lBV>h*Jjdg`5-R`zZ4b-nbdcSiNcmOeHA&aj^P+Lk<< z+H$T}XI~y>*_RpNucyv!DYH1tOow|>vabOn?N)fek^^RMae^(JX=>^9$qBMAk2vew zqk2QV6 zyESBrGqU}bci8?Hi>y_%2j^O%Q_XoceCpiWobT=OTn4)A9Pi&5oh#Xszm|$RKbQIa zJDhq30ez=9$LmsYE?eT$*V*RFX^;4Op1(g;)f<-1o#S|J@m7^_hIgu(J)p>j*VEam zbLk;E`R7Oz3}v2%6(HXI1TvDsO;_O{$+ z`&J;F`Z6LQ)Tv+e%@&RWZ9mR_?;s8C;NPBm!%UX(F1BDxK52AiUKYmzDwK5^iJI)A z*xqn*_%fe12ylpLHnYSBH=sVpLER3Sb8G(Mgh1w%L-NW4pPCbSobl!j)+$T8eF$gl z*lTw5Fyqs3WuA@``C10$&gE*XB={zSLu5Gh8uI-fV2Spd3QPWe>jC>zQkvr2)YoA6 zN0Kd>IkoK;-25hz4dDt4lVJ^S4-Cul`vVCe7+XBu*^iR^-#17wZJI}H%u68+{Ou`K z)m_Zt?+g2ScWfh;e?O$@TMSNP0q@+9-Wie3-r$oo(^E@ocJfFF$&KdyMqdztuG!Fmf zUg$&ao?~u!C*1uzjpTod-*I$~5O(OMSl=0*+ptutDQ+`yNMjd2b#93WV2K#v7m0n( zP2!;3_~q=)u{9x41UF4gWTZt z-#araq2=ot=?NnsjBu`r2zkHd7d_6+QN%vPY6NF%iQ!4XUK7h8FMKy$%x5#B2$SXQ z)LYqbo}>V~ldO+nNHsqRbBSzuh#I@}nq4{j7QRPH+$Y@-^wc@s&;x6>RtKJ_8@ zb+%!8e*U*OS@zaHBw-n4|AF4WmCdK)XLt6{f;(zS|19GNBYys1zTTtMo$~b_rS6zg z8UHn<_e;TZ3vsbeh zvez0iPl)hi!P(iH@HBY0x4E_-lka1W2d=c^+^u%xe1C>>zroL!;@#`nACxsmGq)6gBuaOF)VUjvdhlj!y4$19-gwlxZ^ls%+<4Rjw?68h zf}1}T^iu-Akevzc{#5$(E{<~=5lpi21|0gC?5>V`o2&k)IXWOg`v zI{UHgzsY`i`unE;`1GHcp4s}bt=};-HM3#n+h)FF=DTLTbLPI8@1FT%GtbN%pE)^m zdgj@gAD{UPGkKTtna|Je9?vmf1){RqYJzmxsF=^vQ>p_xC* z2{+Dcp4l?qTgzBOB`ykF@V#N|~(yJcl z!)9VVp=xH`!^M0bm%&Bc!6mGb(;F}09xsVEv$4rVse*vGnV4Ow0Z!(l-ZYn%^9Y1J3%@fw_3q0_{J*5qLcm zua7m`KHePtz!T&1&CX2T9hkhEz?z-lnmsuA_R-0^Lz8!pP2N2|c{e%798kH$$?@kV z$Df-Ve{OR8xkrf~_s;>`E1!ET{)#J~F#W?z{4{Ra=mcX6zP zhX{Z7AA|_J#*q#_G5tso_R*Q~n*)CP=mgoL>3D|4um0puzy7(;oc;7qu8oSNIpLHC z5$E_PBm<+i|Iy@7e((Dy=~~_Y*yld;`JedA7qyuCA3Zddk_p`(9kce)3E2-#2z4kf z?obfw&|H$GLkFi1O5j6dNjt>lpcaQ7Ykmiz4h6{{3kE)RVEQ1U$Wh$yF=Q=%PZ;;u zL@*wk2*zWNHAo*D<9qChP=nPAyES1Y?wG(6!ahE^s>kE19-p0_6UXCo&F=}G$3p`i zPinV%zT-dhr8mCt)2BZ3={J7ni=PQ{K8||L#Kk<`puDA9S{n>VJg;T4@okMtvKeC= zaHlq7Y-2bVSL<~)%+ zr+th7>`R1XKaSx(8^PG8$#B2OyVtWngAu>S5WUr{7=pw95ANN9$Bkbb8l?cG-@5F2uAV$Z*OrZv>h|8{@>J0W8+j?y$9N?THL+HVD84L%^jG!aph^P zsY_J~Jx#dZc=1rFB6W~YwO@%_6SK;jWIU7Sm|^b}YNb~r%%4J6zerm86a0KO5-Q)n z7)kbL_(pwxp4Tr?taz25KNt0^*U;)e9f8?65xKMDeiB>oI%oPKN7Y()q+!^-|enwobBJ)xjuYFcXO_Y>yU*zJJ&II z|GD7u8@J_2R0Bf7BA!bJ4=GP?@4Cn^2~@^a*0p$byc6+NaHkQ!C?sT5kR})BH=8Ek z9J=9~@0ffuv;LduAKg3o>e2OIWgolMH#6Dfn;Rkgqscdv;wD-cQCGP1IYI@(E)sbn z1b#o-{7ncEe?K<852rk~(MAem@}_H^{vl2f<&)_@!MmsrO#cAy4w^Pj|M4}K5aG5T zy5Wtxu;ER130h0Ze>mPH`=`9S-C4qS-Q6x2|KQ*B{o}L5Ri(51-~<>~HQ}z|Rb1em z?_%&4sr1dR<%!8zo?LSlD4))9=R_v*y7gIZ&KJ_7yWNFY^sbTNAntyju>jnSn2jai zF62!Af47t-+`jvL#zJs6*nSUEK$xGf-G$;1f8F&yqzMfT?pzN@D(-%ti5%R;c_wnO zy3a?MDDs*QVO!m2)fB8XYh*#Uq1(+Bn^dVe&z)%W%xRyy&-+ z?<(Ct65E)+cZ2OF{Qb!DjQM-B^JGWHjwn02hNsl)?wZzA_HIqz%!1mQiSDRHf~?1it*F@ zHt(4xGcpshdG`|$UXIVPe&5Lv;O2OXh=MIftE&9Z2{}J+ZdcV>e;}k_T>J{=raI2- zxR810<<|Apri5qmx*k|UnsAISGGcqHR1L{244ysir3S*ZnIE3wDx>ZhHDq&E59Bwm zcq!}t{Lm)Pvoq=J+|0g5pLl|jstkQ%-{Vg_K^-)>Wir0{wSSGj2HV=BzZ(0dYk=m~ z{{*|r`!v&GR{Y59p+o!To|v6UErKy`R*{~**|}GDT7%$G4o5MR=>Bo)#M6{oefyZ7 zQ8(ZNO6reIQv;^_N=5jfbwA64Yarb6>P!S~y4``t_RT)_1ZCSbKw!aI{zdW;rTr*O z2ZKTkgQ(CaT{Q7xQ_h@SLuHGe<3n4eY(ydUzuikZ!Fa+VOvb(TO?0j9wQp9d;p*@t z`F}K7&eg8Nz4lFV9KT=f8$!8cHzN9wH(E}A-Rqn{7);vly$*czXftzo>V+@;6mK_j z|1C4>@!u??n@?v?FO+DFh}?a{yxrM&r`8|kbv56u1NQ{OlB+|&zGr}_Kn)FV>|rk^ef`1--e<|)7{e`LT=B!7jo?)u`Urhb6sZa3l*wo>v zC#Lp*0KR-PJ)#my9B>Ri>xwyI?&i-un-(`Od`u)$`z4}YwI{<}_WP`wW zX6g+1o(}rW@cA4_5AknX)`8N8dH3MdcV_=7|9*^rKOS`alhE-KT>10-dy(Hq`FRG^ zEQbk(r@{Gn`BZtNI6Qo^I$S(iKGA#f`r+b8b@;oUc>J+L2M->Y+4u0?-4`~sHZN?h z@2fZetNX5Ret*-_rnfgPZpt_Q?xstd%BPAW<>Aqj#o=r?P0O1vZGJm; zUS#K`P2G(juyet=%ftDTIXhQRRA9*Xsh_-dxI9uH-uUF&qf{HOa+Hgk|KIzr0bzlo ztZZs;ybwnbaq;AcpZbaV$@dP|N46Y3a`^C*k9!ew=_0C)*EcP)|Gy3t3!8p*W4YdxT-`{WZ!&mCxXxV)*e`JK)G7LXU%;U8?w zH`N<^>@)=AN`M?5Sp?*FKXv2?*C>VNX4B3&SJU78yPWO)%`2e%-#2EPMjHp4vW-)+ zV89Ws9qx0=@<{K-Bh2i7nCl#Igu&((tX||O=Q+y4roXkZ+Ei{VH(uLRJyjnqILN}` z#Uld_P;(s{8w6?p;l@ks-`QNS|Gx!Ai~axF#sbP`Pvu7yl{UPo-8X9;83CkvYReI? zBwfeaqjWdtQ0>?5dv9}l)8eN8r8&wdj?z0kh$A33NAjoYgyPY;*|h%v6vNHE%_E5T zYxljoxr@O5)!3hJY;Xzo9ZF?NZ?c7ee|gY#7z!zZS&%N)s_wSZP~I2nAL;z z1Ij3%c(BDI#kvE{jnQ0&Cf&{DeOERw-8a~>90yt6^j88=FAh>4-hjADjgKGE`tn3w zRupO<8H}$DDUPG<8X$Rt&EMF(d|z+N5=ZK7@<^SHolRYi)CEFZSz3{ZztLR7>2N{kIfB&j2-(vfqX!C);i`i9k^Y)XQkB*nV&%TpmTUK2*xa8SqK-oh8yFs< z{Zw_7k;6t%#zz=(8U4+_z1bsN!LDTYU0rh&R;y*7yg3Sw7-mTaA4blS8Cm|+=!WB= zpu2|1caP(>?pxXN0c`JYYH#{-T-1vR$Eu$4JZrJ79_tc9oNsR5x5V)l zn&Wjhwl@t~AGtpvGRIr9Wa41$(GG@Eg6!(1F2*mvujFWpTi!=C27#`(v9)OcI*=V5 zGj09x@}uAT^wFn}j`icw8xA>waIO0m;*diQxv;VNu54reUH^FFhRs{PxBC7K-@9dV zwXu(#?6F#GDI?(P%~x%7IbL8SHa#{z(+D>8HecR+<-Y4%-UIlEvvf9o7f1j8ANavP z{sZ6tJ@;)Ieb;c~|5x05$H`S)*}|pjP`Pg9oMTtV>YTf)s*_?X3zUU2!C(VpY_J)7 z07)h~5fsVB;2Do+-g~xT{A_SQ!q3>_nQ_8KC?cWUxhsEbpIg;IYJtT3e&75dsP3+_ z?>_79bM85Nue;7HC6`ePRZ7gMa)sL93YCRi2DL&ikJC(#lUP6Ty6y6|W=z)k>+&-h zUH7c&2zQBHcSNq>v=(1QU1MWSncJw6CuB*vgwvXwZkJWBQoJjdEA^iG-uXRs9zCZ} z2ox##d0c&zT^;9&U2)=yy0e4EJw0Xe7fxXUoTXG{)U#B$U#FF4xR20razLm+CsngJ zWl}LJS1NVRs_4>nn>VeT*XT7Un>t#nTn6r4c>!k$@5*G0c7?4f1*UHS zPRT`h0RL!cHr6JV! zPmpZ*VVzw?UKOb94KHT01%K@HX@4)z;_+6X_Qv+Yv%N8|ny}(e6qa_qgaU*i9nIWS5oY!guFnZRH@SH0$s50xhc0S!%k|? zV{+L6MZeL#`LkuqmM)!grwED<6-7$5v0@>DwCLsKjXs-Ef{B#V7%Wb&FXfkcU3Q~R z&8c-pnFrUb2}^swNkEB>&@1TP3UlWGG5N( zB!jr)3d|r5w>RS}2-GimX$ov~3VOCP8^JN{xoE#;=u`%8$EMd{>$T4?O6$t!*9A?!MW5 z-O<*DhUQLuoZZ{i8unZDYK`6+sBVe%rutMpk){fdNvl$6jPCNLNH>lf7xzS)tGs4| zDJbmu4B!***xuh(<2P%R33-vq;E!&7mGHY`QFE!?Wc5|nH#W7jM`O{pnxNI>tc=X= zY4jOXYNMy3sk1BHQ{EkGuM64roZ8^7sBda+X^(XE^mNBM(F=o0q12dtRjtvU-rk;` z#W%z9#8i=rjz>3fKY~j~{Hb_}J6f!}q^{@lo{FYcD=|f2%8K zHrOj;E1ulD|G)9dZ!k)>bTvp;o!+qe7P1x*2yMr#T* zFSvL2zVrd{{@uG4x0N_Ob;7T{@~2ET`)cvC-@K1zARwr9);;zzd|UX|s|OxmR_-fV zu=9yKHgA1q@4mfHZt4uV{EfRFe{^e^MQ18$TfA%czWw|6?ccZeshelly7dNE?T*L4 zyk+a7yZ7Pud!PB@d_b+%SW7#XKDjr&zhK|t)uQ?T;z>GJfY%m zd~YzGmHhQHk)Xv|+I`3I(X8axH?{z5U+b!0k7bLF-_}`P)+vDbf_uu%TtY6?2O?ux z$$zy}Htd3x*YWf%8h@doG&~n0_w^Q!#ou|`adP0tOY0og(%zf{WYuFZg}T3X2Jf-Q z>1OAjF^OoBb(?=CUv`dJ{v79JX@RV@rI}VOx&3*8&f8AC{$WwQFVOz&_;9x9oq6TH z>SY7jg6CraLz2s?3bd}4Z=TMI&Tg;w`kKFp?}+}owA$gQS$<|DTX=SROKq3n2)eeT z(!zHwHkK_s++N-O^^t7BhRWuZnQZZ!Jt0r+wgH&`{oGP_)zZPN=*-e8ho@ynd}y*0 z*;s-m5Zt}%>;?j?;pLNOfyddCCy#%yzp%f5o5jS*bhhZ;#$e5gI3$ry3hFgsl>OqVj$okkAMuMgn&TSm=`X)!9{9QsPA?f zAg?`e%ktiOmCs$X;$${^cIOwiu3dZ6?K>!lc1KDo7yTfUm7Lvu&$jjJHviqu!&p&l zXtXA{B9+G8c+Lziyy2F=|3)UO{^h)y`sJ`U`1LPtTet3} z+aLN@*!#uoii)|v#1~)q`&-tn-THT5C)8qPN#&A% zA;6#c{Fb$Ax8Dyd>RgNYfw`%-CgfI`9CfR4wUb|1-ceWAG-oS4zYg>SOZx6Xj}G0vw4+73lZy|ec zFRZCq_%^<{bK8PQXW#N$0OpUH{XSvqCIa*CSGHFK9e7v+Or^$FPwq)x-5AA#-d24B zz9D;c``p&X`bxjW-O7VmUA^!iTK>b@u7-w|dE2Nz`@2d?=f8|!9=daJTWxK0^#gF{ z?f%-PmE_Jn%i3$}TKjJY+7n5}mE6eI!w$k3u!SO>&np&B?ZJhy&#lhPH$1=fCzLa46&f>5Gdsn^M z-onFJQ?r;FetAV(Wo1p*O$6h!-6f$uv=kp&)95mpN_xnfgNy20)==-ZwEIkEXYC61 z&D`E#JeK`5FlMm&y*RPac&^W{Q7TnRGmqlhIZsXj!F^Mb0n4KRC$mez)8C@R^| zUcY(!_I2|c@uU-$FCoL*TWtv-SfKLuUwO@i_)dPcYbng}C_8k}|zqZlj1*A6neN-_EtQCWS&1m;;0-;&3b`j6(R0j*G;4 zY1-kIznMICO0#7%?W|TTn~X%Hk}q8&f}XaU3Bjcm(-5R}XCA>@+MTK#g3rwk=sq67 z>e2{%o+M5dzrXK>R^K(D$DowSl|Xd8fbnw@=C~_k?9&5=fnI5I zRCV9@mA&Z$!k1pd+*R=NzM%Ef0hh^+ofIAa;GS~3|N6j7;>nPSW$7gHtDc0*-FgcT zS$;)7h}`hUjLQ5hK8e`!s);$RfI=+(DI!dDh?erzk$H>z=gsMxz3jG~KCD(%76^jzpp(WM+imoL$F7Iot3s-ln z{0fjew7A?ZET>1N=yN?KMuS$(Wv&7r8>wkoLH?n@hAN@AX>Phh+8OCYQp2d58NP`n zi3weM1=HLMvjZARqo!$@980pm!!DX%(M=r3nqAGUT6yCQw2kD~bb08!-N?ihy|%fp zw$!6C=NHDyIif=^H~1oK%+T0#(%er+N z@7T%j(L8Rp42i#X@3sxOJz635XxH*oXlT5AkEZ&??5fJXqu41u__Xuq6S zViA_m@=p5v{o9t$MurCo?5o4arDQ@&^ENnsXi-(g9JCW+hn86*Tf1T7y-#;n*$vY} zZ#!Ge)i*4|s*>%{)^5D>32Zfs{$)wIf#4g93b9JVVvYqLmTyx|^v$keq1VyIhh9xJ zCBAs@>`mW2?com0zW<%#XXYH?r8 zLrdS#f?wgw_<^u8H*SROU(K%w@o9kgNpU>;dS}4or6%HEA&BI1OB3Y^-tMoinw!f8 z2;#_L#8-rk1kosM7p@hcQ1BA!vxS_gy#GHSrg*rh4LfSe@)RS>V|KRPJeVz{G!Gkr zq1lKt(VBX@%E*6wD&p0t?DcDqzj>>#JUEg1arxVJ#aZg7-mWXK)owYH$QB)L^I`;0 ztT@}BME{?}idZh!272B^|DSAkQ2$NUD=8P$UE;3UHh{d(E2U;PeOdfwPe3b|n`>6l zrFzSPtvloJY-ttiaW*oJKF4!?#>V|O(+}zutj!=aG9B_Mk->MoNU3u*u6PFmj_((@ z1YCSpPt3AXHyB^uK&~H%6vZ~O8SJL=qQVopbrQ6bW3SWV#{B^W2pc3zY1WWmG3#S)_oE~VPwENkrO?u|BA zirq#nUyexjNxLbHZ`7z5Tm^^jUO6{kj4*1(R6&i=RbJmv6R;q!K_8pyN>HUxY0duX zhPpDUVp#lPR*B&9l?b)o7OZZiQb(>3q2-h+l&Ddj=@%t5DVd5xsi7uZV$~{D_=GYkTEri%2~Pm7FR=^-xd-GRi`#muix%^qJ;_xzNJ1 zDvhG4P_5#IRI}8YjCPhro#sD@P$WeiRHbG{(p&)<;A^Kzt`Npq{gu9xR%Vo_bK-L9 z0;-&*k)fHTP-eJUN|5o2@fW31A&<*u$rTwTC||Uo1fJLm&>u1r-%a5Y&t*s}3Sdr^ zQfE=Q6aZ`jBE?F7nd<`sCGLwz2&O>08ky)e5-sE0agZidCsE5yqXeG?rR*d5N3vt` zW4IQT7>9G$N$#eD-x=U^`1_i44(@yrooIMx5unK{uW$ksos&v|@)As+mK|lx!hudf z2Y)xG8&0pzUT&HZ?|9QA%27B^X)P>4%i;V9cz!~8QE>)_52LztN|EUt=z!m|_(8=E zKA$|$do_<9g~?P_$r;SrNl?IG+}5}b#(zFHWQYTq55d2>s5mP>C3}xC1224x=`2Pw zAAwhzW}sWD7QysSB7S{>JEl4X(*p3a&cgG*z&Oz-i8%#|S0@DFSfFS5Bga>dvA~{c z_9HAelFBjVFefnv+J5xL>pQ9)+643XB*KKuekA)7Zg`e41GAt+fm?Tl;c?;=f!hPq z6XdZerggTG#`e}~Ojk*mCXX|qvz?KD2sj21(nK5_ZU;jOF)}$QldDHR-mF@0ar?Xu zl;cy}X|SV?W28{neJJ}Y%qHXskXOkps@okj=BJuYA#UjRmwSC$J_10%jpRgXjZUxA z60_kH0`Dk{4=PT>_}^eW&WvY3DWrenAXTO5pMVd-lX;<)k&pMv38OWRDJAYhBT(;x#VcCDd1^nBT{48$SAp9Ric%=|t z+4kYf+m{9d`SwRZUi%Q!*N7sncnQ2MOab8X3R(tQN7@A7d8R?71ZQ-*h01bRxBw3l z@ZcysIE|inNjKrg@kAZ7`^^$-I61fDK@Yq|#`En{G+UqtIs z8svza%Ucg&ZXCxm=`Y~vQY>Da@Sg5L20Zmd3$6|?GT_+GY-1SHAKCZ=h*qaC(OiIy z=WrJU^3z~HWxOd*${lxQ+$mSuIqEv+&UjRAkH_uyxLr<%!)~)$OvaSxui~`$RmuC} zLGgD)W8#D;B|at2c$1#AJK;*X(^qe6NQ(X@&WL|6$x7ct`vLJwXgelKqkS6JPP>z? zB-&@38TbG}dw14#)}8eT;X~RjVJ=vSBpMeT7H45*TzZ6=`KCyKpVOlA;uOq~`w9Gm zFsbWkt~r?!Qx|gWKM)Hfzn6@l{bBJX@i#?r(M7aPqHP9U7;zm#*Xgnux76jFXg4N0 zF3zCckTfevNk7W99Tg3Vlg#}r+K!@aI@flV%b9T$@z)#`ofN0h_N?>_+FcZXOEfGR zX6=UE~@DIV3{Np!EsqDamO>(gjhn z_*HgIT!&d0b&s>whzL*GEA)818F=i>TQCfXPBU#m39^7F${}SKh7WX0j!REU&WeZN!&vb@iq4CY;&J9df_Xsg&wJwDtVc$p zAP+O&_&+2^(fAx1UlPqK7L62tpS2(JrP1H4TZplf@)UbLo;*z>4Lp)w6?(&N+7xqy zCYd`SIWHcDxxt*RQP>&+0<0%Uaqt%Mc+jBW?>m1#{!?;9dR%frJOT@sivO8;GlJfX zf~H3nh(I6rj4&+OfMPK-+4h*^B5QlG_y?@*kS{Z>t-y2PvbG}#?2P2UB=5s>YI_ma z{Q@ zNGI(KVA6}j&e(O@`Ge#Sm^TC%mb|SC#Ur9j@w+0iM5a`0)JmBoBN`HoFx%*avSZ$)ykTx0bG zeO8TJEXrM#0`23jn(@u@&j2-l;diAMap4j1kO&)ogQEm54^{?jS{a5^MkJ9cbrx)$ zRWk9rBDq9m4@di=VY^BqVv}IpKgc?pqy*k>R#;e$JPgVUbXx>|ij=Hd?Bb_yqkc?u zR!qH-&5}won8^Pm`G3+&xVliB`(;`@EK*81OKE%ms+%^f=&N<8C8NbMkyvT+*R?d3 zS=G{aMFmnr*$(7Wca#~VBGHIwNId2r{&+vodntPq@>BXa{E$hNTBFIRRZ7KTIC4lj zC>e%JVi~71nvhbEX2c_+VzI(pKKr==FzLThW|WQ;OQkx0$M@fOeS5iCPM%mADNX&& zMhiTl$H}li&OG5mop6c2iH$5UNrPCEev|R&FL&mgST0c-+~whNw?Qc(Zw|tn5wSoj zR+;>j;WCF-PTmws)ZVUt1UvEngw3*%;sU9;2DFKSKeRfP@I_{C-wj`Ox7%eRQAPxv zYtaRb9+QyMb1rlTU ztDw#QuW|wha5TIQhmLf*IdaGm-4BNj#GG<5EffO7em+X+m8QuNd^smQPnq|6@XVOv zQGv`@^)=Z0T9r{Y#UrKA-tc2oDSCri=8@FW{1lR|2Os$C>e+QpjfC7XRr5GG7*5mO zN(Dx)*R5PUn+)SvxD-kh_Esdki=J$Aax$4fnwAtuK~2DGB61mi5J;2Qb%4Y!7s{lP zVW|MGs$>;uWwAmI>W2cK3XqnPC8Y&ugq5~XA(zG_g)o7?$we}$RDu9i34Ptjx)+2^%SD)^B+`UT2rFqU zwvzY?veo!0Au7PAlOi#sbjPU7m%mTRz^I>QFuF^ZQ@yo$mOO3_JyO}CY#eb`B#~=F z^Ph*A7Z=xHyDh<_D8>6f7KbzCk~yqK4Spd*V$PH?3$1pn6N@Poh`DoA8kDPaMzh6i z0aM=XcG}DagULo8L1o84M1N(>64q#(%Wl?jazvz5PA|kb(=IW+6vN4+a-%T39MwM2 z9eriEoLmwY!6{wof|tPZer0`UiCwP(QQu%R7%j*Kn)RGqWvz(L>1jZOi!m9PtoD>c zhO4XP5|Ko%(i<}-q1kHBI5@k-sKI0mFflu@Ulq8*3yHFn2Q3>+Uo&h@9=0*8T#IBH zN6Uuq!q9hbU));dmKZoWXY^Dyb;QzLnpkH`wco5pQrJ;eQ{T|o(h<#ciDDg1m0skB z$E77QmC;*S*U;G97U}BlinKLUSJ$=RV|T2hq0DLEWOB~nDsOXO zq>|dUNG#JOj<(g8+I1?eTNt?+*ohz9GOw}HrIRB%;F_y_<0}N-XXe-Y%{rsAw7Ryg zp}D=Yy|Kb=&{{%m-O*a7Mkd$VLv?MP>1cVRqdDv|tE6&`EmU1s-_YFF8I49dT9G(c z%fu3e-dWbr7QwF~3${|H^XR36nLwNc9cD|$-Nb5XH$QJ86cLC-`^r%dS?J|391#tO zixj5vFFl9BQS|0_pZnH*4drgV+Em)HG!+8y);s8QOn~}sa)@!zw?RPH*J1;cV?ex&r`RrS-s&&eB|~%vtvP%-vEkTuyx^% zXZEJ>tEay(r`DyFD|GJqx%WK1C%sQh-)i)lZB@eiU;ZOV^4~2!@bxd&I#h(A(h`2; zMYtAt^Ob#%E-7((=RWk8vw*WV z9tL6jq2h9@sigaB17N9-|I@;1iz(QRdfJ;Oh$jDVUzt%Emx>jps-2A9P9*u)UnP?K zdpEaw^ag+DXNV;K&a!&DTH{2C4t2C++gpNx7Dkf4JE)T+L_(Fj4J7&hY$&bSkRU0(9e@&>y`=ZowhlKeQ`>&ehb1~RPY z{3G{cX!5=(a~9ukM>7%S|94Tf)7|{daWL5r^#vW}3qh2BuEVX4OA8d1`mci~e`a&o z?ySED-w?eA{;0WfF|pOoY;LIRV4Zs~q~|-=0h;{#%@xg$gP658RJR;6_RpeTTjeH3 zlkW}K$`*nq|IxxSv%TTLagL8c)UIaS-KCFrxgxqB1=?Cbu-~L)szNBrHURjbzB`XI&8)2-gn z{O_Zvd-mzOH?3Z^;d2kZkHy5=8be%KC^y!u1$ABYyGL(bzu~hF(Z@eNe#eG2Tkm@u ztOxMY!;4{V@bP;#tzNzE)_))>_0Pc;?)?S6`0SUrtzNb1&c_I}_E4E{_FZg#{lfbB z9iAjXK8CVT-U>R z*T0%qQ8Ay`91m`u+t%8(cpH%XVV%<I!dmY2_kJ+SLLYib($Hlsn&-cD~|Hc0E@gLf=ws;X+g@vCs> zS97cCR**Y)FKVs|H_W>gP){H^78C|RXSo)Rd^Ca;tdr&53LBr^WG^i!w;1$VPG+j-5#;ZP_}(RrrKOdf>j=U95wEZ7 zIYMw{tyQPO7S=Vb zrkk-kY>-No?r!3|9_+6yqrt3XgL%zOTehs8Q{zx;gbW_xmIfo+aq#;b$^NKaT3oF3 z6X3D~F$Z?7STP!=L-)Yu`O#?i(%T7;{ZWr63a`Zn`-3Wx$kYgs)dv^UG^`{?R#xf6 zVuhQS^V6XNca&cvUAaQy%cg3c7(ZwBMEDucA{ldS@YxyxhvZ;?iJIUe#HPasETuX4 z4s^SfSA&mk#=-t_KmYVdoGAX=o~4aW%~hcTS~=(n_5sIKv2Z$Y*;k66+p}lii?7i9 zhndDhTTAi51p!VZGSc|I47jPGg1sk;xlaL{;d0<4SBblBx1Hi>GVcBxz!e|tFLUxs zjDMUHGH9&NY53GnOIGOSR(;Wx_Hi`AjUWyo1!?*DI$ zLDj+jQj@K`wQs?^**#s|i*9}pDEw-k-}q_45^eeB_`v#}bW65P+**$$C^s`~ zY^AXgD-E5wV&ThpK0Md$R#3)qGrY zchQtpZWJpFn&}VSy|}eH+%%u01!$Fv1==S-R@*Rbk^9|DR`siS;NZTW%^qFV+gw{0 zUHuP$?CtphqtHJO)4KR8H@21eLGhD}UlV5h0#^;pnp>c#(B9TmeihKFa|_(X%~e(P zeJmIA;v64$t)TJC+B|47TiY`L?FV1ozO1KC<#ANyHdz}dHd)WK*=-E8_^V&oyms}5 zJ0HqzvOXEK>Y8bLEG)%UKkqILbsfP@=O1q0fZfl%w8#2IpI0yRu$|Jg_ibL%4T`Aj z+Cby?S8D99ZoF~jse51uWo_Li|d``HBBv)7ufO#?3AmBV0k?fo8S8I4kU)R0&TUUqM4;p#qln0N`ZV|yMH0?hyOgK4 zH@K~QCQeM5II9XBM=tDrMr~)QIP_oTY(lj~)EClAa~~fLn-x-hs1Lt=y~%B!l9JOJ z0)_Eqk>Aot_p($AgKM_F!$qn zo8H;7orvwfX>)7M^mXx%8*B=ZNE6_bcMg+3y7LSX+cDc0b_Fza^HYH|OFdjC9H#(> zOa`v_?9V^7XYZ4b-fbo!k!eZY?Y&`#R>5{}g@+z`asOWAZg+os8B6MpOWTyjl1;lF zc?jDzes&>>o^vJGFB_>TSr%Nf~eS4n1hqAg57%FLBjJ$C!tJ~z$ zqcA7ec^c;3^YmW0aaXBHJ}xp!G%i*eb7@cqmFayq?RsR#Jf~WmDpo11RS$e^=S@Dn zQtN4)|IpKWl6$>-p8RU8%*<)g=#gDF`SlcM*6@Q5@4U%xP#J@5bj8d*`QF`6Z`pj` zqYs8{Y#z=+CMb)%_>7G0g#t=?@*$K@F)+*|a*ZWe+tP`|en?`|Dkq8wGAbq@4X==y zX@{pg^tly%C=_(j>trYw*te7CQSFSg5@~|3mqKF=1yN}l z6gB=jg{<^BDw-vhWTdmGU?~7yWtJFhp;;pSQ@XeSNft?(s+gz=iZc^m25TbMEF&sH zofDAaq@dpT}VJf;a zHrs$-;G2x+Z7mi3PLa6Cw*Ts4qnb#(Qjeu0+7Vb z0);RGEw{@}#(nfOP=cApYC}0*85zAONlHaf%Y@pVT=rY(2a-`{@^`@RlxUPFUO;ce zhlfp`N8UdMW0Mpwo}xyk1|&aa?Z?C)iT=I#ztDaJ#JpjjU`pH3=}aTO@d@N^ha~?O zjYq`e;!~o(6bmr%{|5|Y-J>vZ2>>CZNekwFVxHyLWsDVR(4PQ^0?80Aenc`PPKu9< z-UBfyTl{;pPk|Si^bTCTy(!;*7}q}q&QS(zqm=jXqm*7&!OeiRym3xYc+~1jiS|Q$w!#bKEU;;)d)zR=e;Lz zm8qP>i3Ve=0mzZ!!=iH_ehnA@4vmJ{rN(iehS5;LR?0m45Dia)c9xNhOMZeY5u@rH z8vhkMzGSZPpnHV)gZKxAF!d5Q8we9Qmf0}D#)q(xhK>IV{vqE!4umts z_i0!lcIVXASgfNp97O9l?$1%Q&WQhvdvhVzGUXa(Ez`b)chr{whjo_Ak+By|Z~1eK z!n2q-e=bV1p-p!-=}Lq6n_yhj^DIoqF)En_=cI+xh%CDHFJR%!goSwVzr#X;v5*JA zBqiqTAjpOS#zvE|83CCka{dhFgtR0910UkakjBl*ir+#9GI+?4krCGgx4;vJfngZP z!hpiX&j1q!5Kqj&DX?#|;(rq*ih+PQ$r_J=3w;qh(oru)DDHyNO#~NANQiB^{8?O{ zZ%veBf%tWBY4fc!pg|{GxHMbvUp0l^jd4d{<2<_&!7 z1X{X#J#O92)kdUq%=o0G6JD-pb_W(20uxgn_7(G-XvIyL}wO# z{2N-$ioj+0w1#77nBd;SrA|Xj`-1Y@chwvIHwNFPc;T2rIJ$00KdsJ~6SN{vHeuBG*aQK#D7;Q&!sAQ!05z#B4zS0?5Eh*#vsVJsONCMbalvBXEC6o>4lVx;jmg%628L1I0n{s_Ph zD~FV)!7t=3i~y8T0wHH18Kql&xrNh+#y`VCLVX(Vv5Y|5AHpKAFaY`Xp{`79JZB*b zA3)b2KCoaUHY*Ce^QP)qV2>d}$kdQ(49I& za0FL*XiV`D1|@In7zQS}^$}j|`zLnG2Vg53h3pOm%rw?15tQSfVDBgf9@)byg7WXP z5KMHBca2`RwZEXJqv|6Np60C$%6|eqZ^lK0cyI=kHtPiUX!#W+e08IdrBQ{&G4~0}QUP4sho!boFH|8)g)2q?$P(g0&!iCAG5#o@JIouAO&<3?12>i2P!0bPAqf!DCDejFa$R9ohO(nuW4 zR|)7ME|1#=&cnM3FcQ5GX78={8t}69m|{T5doYCl(OpV10w6+Xg8oN$YWjVrM@IrN zRLowmCNb)x&~3}$^{PwElem(-h)u%nDZHIh?;!&1B95NMlhYgy|8SWSJL-{ zTmq*Wi1EI;9eD+1P`4-wxYUW8ef!p_I@?8tv5%4f*71`!@2b-)?h5 zA^enbtb3Gs#1o+irudc2az(Tg6UP*%&M3i?rj}W5td^S6&$bPw71!{ZUBf$I7dWVMG`jELb zgqPJxY=2Udz1+lHQ@J|8wih4TargQK&3+>{0_plZT0Y(HiPoK$uwqJ%SfKO_cW1B5 z!O0t$1a5_#)*E4p>`-@6s|5&q=mThS`T%KemP(z10DDT8B}IWzC<6!}K9JR=^@TdE zMx#yYpxmxeCshS#q)q6A&}q-$&1E5sB(;zpfFc2>GV+S-#cP@zq%$x^Lh$}xVyV1( z+rpMgpIM7B1vz#V z`5-4D%L!93rHPDdmdBS06#3l{{!))ahhB^994Vx`eSttQ7=U=Y-RVsQ6jQ|5VJ8t# zdLdW=i7tqnKq7+l+QokQl}4?#Pe`$cVOGnQJ@am?n3NHv#1~d5OHYeV_ zWK!&&+TQ-Tt#k$f6e{d)yg(((sjict2J(19C+V(pUKb2PtW?2-DLmMP7X%xYV*E`2 zmhDaVj9wdLEfZ^2K&CeOIyb)tL$BSrB3d65+w>ZUlhn3%CHvGl;S;99j*=lMr_UDk zb$8U2IEh;WJ3#*gEcu4!me%%YHze1)IvdMy%!m@Ffiz>T*8V(!JT9afThHO}wm>elt1ogrUXC6oNU0TuW1a%@6#vj_Uhgd<(`P z!~WF$ZQ`KC=&0(t;i__=R= zsTs0508i(tf1Cu^0}x<;VtIu>)W7SA&u-bq1lTushTMUsT~9o^t=y_NhnN6+YQK8# z)3?m2^B4^7x*bnIe*LjM`!f3t`<{XByWgnM@-jOlEx+%Dozt;P_av?ZyD70(p!c>B z$9h+BjoVQ%Rf4@@HVRrlXA%@5mkag|u-`~(5^m93DaCEZKXX!=Z~qCCP2uvb8U zT_H3Cqa?uITGcp3fW5J_dLHUmZ?t-?0Wj2g0rq;QtrSHvrT{PbHCZ*2C{td5eKKZJ zJ!#f&{-JvrDSI~_!Xyeq671MHv`!s!1$tixFT&p74|Y766Jht)kO=z=T>&G6ShVie zyac|uZ9g5!+F&5N*?)aFFk&*8y5 zxGZcz$26|CnKanTE9d;0Z^^jjPj>`^yk>4*gT1@HeX0g~DKyv-<(}3VG}up`Bn|e4 z3Z}vSc7IhVm2Iz7hL2;+KHm{4&#SJ1TRsU&s^`kZ0@EALEftbXPKwTDkVU4zGLF?@ zk;WXFeLI^`AGl>jUxUi;sl9;&@OFLyis^ZEzi6mxG589Sb9=t94Ws_=b{z&&ydy8b&IHp%FMQ>e_3O5M z9^?VY)>l>M1lV_eY15*vup0vGiXx4rbRJ1BOJ4oz=J_q5ATPlFrzh^(wrTGj?V(Wn zcHnYoadp)^l={U_d}-UHYJ5kiYC?d0-MX9q9#+(l6|7_OexxtIZp-IiAXxJ_j$>ZE z4jen!D5;0J5!&k{4R3E)#c2u2Kq;aZOX>IjP zacfNc#~0?77}PHMK0(;Np2Bc_y;Y^s1=u?PlcMW1oHuOQzJ2`y zXz`hZ6-;#f=2m+OC(Y&5YbE?~2YU7bfb2Qa#D$8N(l#Bw9orZ8_RhKCP6FlG-jWhh z1&8Q5$#B{!RHw*>lbXCXI2ZU%fiKyIMG{SZAm_6^(-jM(Y5ejVm*>NqU&XP1^>;<(7SANC+NL?^xE=+_ zG=+$}s{_~TRi&o@M~5Yl=z1h@-C$+<5-ikaWKUyl&dPyIZVw@cJ+orfjR-de7$txH zCjf)ydewyHdYi{`jetROJs)T}yuRM-30`k-T_0YYK+N!(*u`8z0{*`_Jac36+K1<) z8{(&Dgv${J)VJFTU9DWhfQ&n)k?9h@52mb(-e6F{|WYlRO^ZD^XX3ZU-!=L;D zsqlGFS&u|Jk+d-31`PJ`oTK&%5M$6R$J^47hXL)4m>X#O7GlDjGP)Y0Mi(l2- zi*f?%>*jVeHTSN6h(IH4`Z8J)OCDGg4VQY5zqvYSQ%{jt%%3_$ppm|M6ldpEUj?QIuUnVXRi7WS^1AAh z7w+G_Voq}q2Mb;`)TW`vAABXmzALjK* zqsEqMY;Kz_s;*tXZtdDNt7BBn0(sW$N+5tS3N>Wk{Cr*G^#FPByC@|$>BbqO!4UhmQ|sJvZx z*+R0fi;jBLhx+lx1F5Rh)Xxj1PadwuRMp?;44Qq^MErJt2+J~SGbn9PRj&!p{VQX+ z<19B)RllLy#1{mxH)VTyn*XnY5ufYBUMe>t3svTdoUVF%X^16mir>MhG_LkrKs=|+ zO^S{dHI=esOV>6yAT_~0P8C+4T~U%x=+sOKt2a3GIbrp}!)+i4Q?R&ly6P?g}~FX467mxWoMk*7nSr;x27 z+{NBP=+223ug|W_uFZBSV$sWcUc~9$O*j0S39GjT-F&W&39Gve=smJ!ys$b;)-e!_ zfsQw@=~+-^MIM)Z%t@<*vnP6^J>blrn}`J4q_jFtR5WVx(&~lpw|E&6{BgLFM`~>l z#nyUQorh%BfrO!S4(#PmP$XsbNYLb<({sgdw0a=WZ!DWj7i{%AN_!ukP*$G}y$a09 zg6?z=<$kXX6->}m$IPfwrZ)PUNML|m|JcXsgt>-o$t z0Tk3bDz`oI_^u|uNlhQ~66;1^s`@Vi0&A>~nKeac7vp4tP zgwBvv3)yWbtS=;mb+}OF&?0b*oH4MFPBx|kUKMIf>1JGp)YemS70ISQ0@?J5gEy1= zz5AYdurKV;o6zX-NAM?#Hg`RwN4AvN;6!veP87`?kni8S`{wQUKe40U!zSh|pv(4V z0Ns_8>dgAgI;12JNYfxY3p#>~BZ+i~ocG0As-zy1j;}TJ^<`$u`nn?xWiF#u%}`Um zbN8xwIL|d-Zb%YnP)M(+Z>$aAd{_F|(9BD%>nwqqhWc`}r9)p?xq(Bufj{+?wAO3d zx>EUS10G;F-3%p&=131oy}Oam0cuLEB@nI)2P|4tSvVX`UE2^Q*>#`>3H8d_YRIW` zbl@vW4ar__H;M{4NEMB$8*1s~S3qs_LTMfP>lz(-5yLUF@?Hq}|w2TJ`= zBF0A-ue7ewo9rN~!xZVS^Cc~Ix-e23^b7A~Necx!fW;pn55P1q?w*k zNT_gyk`}n{Nx6!uQ@ofu$*-fHl?0a=#~`D0g`aJ_wmRTNZOcxjaE{5wQ#niS^YV&b z^j!?iOm`CL^{evG??|u1u$>-bv~W6u1-b~8e-tq_YG|!z_%dh)2ToH-Gp!P`;3{|r z+2}N13{9%W)w49(jBb`zlSWxIJwg%*ahLC!k*JTF-KKIoW|0$b4NE@|U)M5oNcS<>Y9Vq0A zD`!9+%W%WoSiZYB;mSCSn)L~Ao}hmY63mD44;Y^=2@I2{jn70#Pp%W7Hjw7W@noI; zBc#MK+z=>zIWWok2(x~SSw8~->Gwf-Kv}zc_$rpuRF99zF+p5zco0JLLMN@f3l1)> zfZ>Z^031W9{gU!54F8q-2HpBo%5z;;VWh94PGzoc+}^kz#(y!d)HurMDaU~`Z~Q&t z(18$lUJ3d_Y~(5z$gWLKUV@Ij2kb;QIt{8$nggLjCA5YY;}SoK1`K1WA@$z?dpdWC zzYw1XGRZi~y=yQw-jywy#!bibcf$J_O+#nB{YU@y#*P}NjyHV*HTMDK8Hj8D1-piE zXgFU~4$NRU)0N7>0uEZ<=Mvs$!d!wmuc@Q022<5IU^xuTQ=pQ41jBzOA{nD34#en& zPGPLCO?07rL}=sb$jpMpRhBbL5r|XHtscM6X`(XwAlM~GVV3x1$KY=~XO@_H;5x>H zU9lMGZ__RSA{Jd>f+j|swX%{^#O>rpK%x<8w0eVHr%{io1`sJnnE6vMe;9MY7-JEQ zL=*5EPy0NNeeGzMusb%%7h~+gywOo;%wJL;Q+<%LbX0x>{U1_X0BtoJ8H>gl21#}f zL2@mEu}m45tEIfSu!v{q&)N>?9!%eIEZ!fnykt4WO$za{F51I8Aht{J}v6 zyd63k;ez@&?#DRJ1~>_U`YiZxM?gxws5nRTRGgQShz(xF7BMI3erEr;kE( zntBQ0f3RG#I4mO_J&zZ_rrF7nF=w`uQ2rH+x)Inp3Jd2HIFUe^?i>T9@_g(R@5uy* zlJD1uGQ}l9GQPy7w-IGR`5q+9e*<)tfY3NL-BLC0%P=gZ zxWlk?5;VvmWm5S(ti<5~D3Xd)=Sbuu*hqp>N$s;yMV=E{JA;8!92mSXfSZl*Ny0#q zoy?GooJO=~0Pk4WtXPhoN@tVvM$UnaD?o53;mP}8$q2xM{180IOUjh;S$LDeAWyS? z5zRLZ8uKOMLw1d0$mh*rXO}m3o_NGun)@qO1US5db?g$JS^EJl)Xg!KLT_C;1kx|Y zAc(hV{GUxr%rPd|o^$L1EG1y+J?#53AP^k`&+{TI?V}q6hj~kvIzNJip;#OWg{0-z z3F_^nHy1HCflbc+FGl~(DEH*3$63}PlK&q9H#-Y1IM}?nQ3Ns<>73cf4-t14ARqs2 z%&1wwi!(JqXTOMu8$sj}w=>fzXO~AkjNPD1MBc;YU&kbLZc57p+Fe4_k4|rgXy@Av U&;x