From 39a8d9c8a26391997f0172dbb2f85412d5ef7ad6 Mon Sep 17 00:00:00 2001 From: JustArchi Date: Wed, 15 Mar 2017 11:56:20 +0100 Subject: [PATCH] SteamUserPermissions revolution This is needed for defining multiple operators and/or masters, as well as eventual further enhancements --- ArchiSteamFarm/Bot.cs | 139 ++++++++++++------ ArchiSteamFarm/BotConfig.cs | 17 ++- .../Localization/Strings.Designer.cs | 11 +- ArchiSteamFarm/Localization/Strings.resx | 5 +- ArchiSteamFarm/Trading.cs | 2 +- ArchiSteamFarm/config/example.json | 3 +- ConfigGenerator/BotConfig.cs | 21 ++- ConfigGenerator/ConfigGenerator.csproj | 3 + ConfigGenerator/packages.config | 10 +- .../GenDictEdit.1.1.0/GenDictEdit.1.1.0.nupkg | Bin 0 -> 8973 bytes .../lib/net20/GenericDictionaryEditor.dll | Bin 0 -> 14336 bytes 11 files changed, 141 insertions(+), 70 deletions(-) create mode 100644 packages/GenDictEdit.1.1.0/GenDictEdit.1.1.0.nupkg create mode 100644 packages/GenDictEdit.1.1.0/lib/net20/GenericDictionaryEditor.dll diff --git a/ArchiSteamFarm/Bot.cs b/ArchiSteamFarm/Bot.cs index e6b8503a7..0c570a6c0 100755 --- a/ArchiSteamFarm/Bot.cs +++ b/ArchiSteamFarm/Bot.cs @@ -62,7 +62,7 @@ namespace ArchiSteamFarm { internal bool CanReceiveSteamCards => !IsAccountLimited && !IsAccountLocked; internal bool HasMobileAuthenticator => BotDatabase?.MobileAuthenticator != null; - internal bool IsConnectedAndLoggedOn => (SteamClient?.IsConnected == true) && (SteamClient.SteamID != null); + internal bool IsConnectedAndLoggedOn => SteamID != 0; internal bool IsPlayingPossible => !PlayingBlocked && (LibraryLockedBySteamID == 0); [JsonProperty] @@ -459,12 +459,30 @@ namespace ArchiSteamFarm { } } + internal bool IsMaster(ulong steamID) { + if (steamID == 0) { + ArchiLogger.LogNullError(nameof(steamID)); + return false; + } + + if (IsOwner(steamID)) { + return true; + } + + return GetSteamUserPermission(steamID) >= BotConfig.EPermission.Master; + } + internal async Task LootIfNeeded() { - if (!BotConfig.SendOnFarmingFinished || (BotConfig.SteamMasterID == 0) || !IsConnectedAndLoggedOn || (BotConfig.SteamMasterID == SteamClient.SteamID)) { + if (!IsConnectedAndLoggedOn || !BotConfig.SendOnFarmingFinished) { return; } - await ResponseLoot(BotConfig.SteamMasterID).ConfigureAwait(false); + ulong steamMasterID = GetFirstSteamMasterID(); + if (steamMasterID == 0) { + return; + } + + await ResponseLoot(steamMasterID).ConfigureAwait(false); } internal async Task OnFarmingFinished(bool farmedSomething) { @@ -549,7 +567,7 @@ namespace ArchiSteamFarm { return false; } - if (await ArchiWebHandler.Init(SteamClient.SteamID, SteamClient.ConnectedUniverse, callback.Nonce, BotConfig.SteamParentalPIN).ConfigureAwait(false)) { + if (await ArchiWebHandler.Init(SteamID, SteamClient.ConnectedUniverse, callback.Nonce, BotConfig.SteamParentalPIN).ConfigureAwait(false)) { return true; } @@ -866,6 +884,18 @@ namespace ArchiSteamFarm { return result; } + private ulong GetFirstSteamMasterID() => BotConfig.SteamUserPermissions.Where(kv => (kv.Key != SteamID) && (kv.Value == BotConfig.EPermission.Master)).Select(kv => kv.Key).OrderBy(steamID => steamID).FirstOrDefault(); + + private BotConfig.EPermission GetSteamUserPermission(ulong steamID) { + if (steamID == 0) { + ArchiLogger.LogNullError(nameof(steamID)); + return BotConfig.EPermission.None; + } + + BotConfig.EPermission permission; + return BotConfig.SteamUserPermissions.TryGetValue(steamID, out permission) ? permission : BotConfig.EPermission.None; + } + private void HandleCallbacks() { TimeSpan timeSpan = TimeSpan.FromMilliseconds(CallbackSleep); while (KeepRunning || SteamClient.IsConnected) { @@ -1021,24 +1051,29 @@ namespace ArchiSteamFarm { private void InitModules() { CardsFarmer.SetInitialState(BotConfig.Paused); - if ((BotConfig.SendTradePeriod > 0) && (BotConfig.SteamMasterID != 0)) { - TimeSpan delay = TimeSpan.FromHours(BotConfig.SendTradePeriod) + TimeSpan.FromMinutes(Bots.Count); - TimeSpan period = TimeSpan.FromHours(BotConfig.SendTradePeriod); - - if (SendItemsTimer == null) { - SendItemsTimer = new Timer( - async e => await ResponseLoot(BotConfig.SteamMasterID).ConfigureAwait(false), - null, - delay, // Delay - period // Period - ); - } else { - SendItemsTimer.Change(delay, period); - } - } else if (SendItemsTimer != null) { + if (SendItemsTimer != null) { SendItemsTimer.Dispose(); SendItemsTimer = null; } + + if (BotConfig.SendTradePeriod == 0) { + return; + } + + ulong steamMasterID = BotConfig.SteamUserPermissions.Where(kv => kv.Value == BotConfig.EPermission.Master).Select(kv => kv.Key).FirstOrDefault(); + if (steamMasterID == 0) { + return; + } + + TimeSpan delay = TimeSpan.FromHours(BotConfig.SendTradePeriod) + TimeSpan.FromMinutes(Bots.Count); + TimeSpan period = TimeSpan.FromHours(BotConfig.SendTradePeriod); + + SendItemsTimer = new Timer( + async e => await ResponseLoot(steamMasterID).ConfigureAwait(false), + null, + delay, // Delay + period // Period + ); } private void InitPermanentConnectionFailure() { @@ -1061,22 +1096,17 @@ namespace ArchiSteamFarm { await Start().ConfigureAwait(false); } - private bool IsMaster(ulong steamID) { - if (steamID != 0) { - return (steamID == BotConfig.SteamMasterID) || IsOwner(steamID); + private bool IsFamilySharing(ulong steamID) { + if (steamID == 0) { + ArchiLogger.LogNullError(nameof(steamID)); + return false; } - ArchiLogger.LogNullError(nameof(steamID)); - return false; - } - - private bool IsOperator(ulong steamID) { - if (steamID != 0) { - return (steamID == BotConfig.SteamOperatorID) || IsMaster(steamID); + if (IsOwner(steamID)) { + return true; } - ArchiLogger.LogNullError(nameof(steamID)); - return false; + return SteamFamilySharingIDs.Contains(steamID) || (GetSteamUserPermission(steamID) >= BotConfig.EPermission.FamilySharing); } private bool IsMasterClanID(ulong steamID) { @@ -1088,6 +1118,19 @@ namespace ArchiSteamFarm { return false; } + private bool IsOperator(ulong steamID) { + if (steamID == 0) { + ArchiLogger.LogNullError(nameof(steamID)); + return false; + } + + if (IsOwner(steamID)) { + return true; + } + + return GetSteamUserPermission(steamID) >= BotConfig.EPermission.Operator; + } + private static bool IsOwner(ulong steamID) { if (steamID != 0) { return (steamID == Program.GlobalConfig.SteamOwnerID) || (Debugging.IsDebugBuild && (steamID == SharedInfo.ArchiSteamID)); @@ -1706,7 +1749,7 @@ namespace ArchiSteamFarm { return; } - if (callback.FriendID == SteamClient.SteamID) { + if (callback.FriendID == SteamID) { Events.OnPersonaState(this, callback); Statistics?.OnPersonaState(callback).Forget(); } else if ((callback.FriendID == LibraryLockedBySteamID) && (callback.GameID == 0)) { @@ -1749,13 +1792,13 @@ namespace ArchiSteamFarm { // Ignore no status updates if (LibraryLockedBySteamID == 0) { - if ((callback.LibraryLockedBySteamID == 0) || (callback.LibraryLockedBySteamID == SteamClient.SteamID)) { + if ((callback.LibraryLockedBySteamID == 0) || (callback.LibraryLockedBySteamID == SteamID)) { return; } LibraryLockedBySteamID = callback.LibraryLockedBySteamID; } else { - if ((callback.LibraryLockedBySteamID != 0) && (callback.LibraryLockedBySteamID != SteamClient.SteamID)) { + if ((callback.LibraryLockedBySteamID != 0) && (callback.LibraryLockedBySteamID != SteamID)) { return; } @@ -2096,7 +2139,7 @@ namespace ArchiSteamFarm { private string ResponseHelp(ulong steamID) { if (steamID != 0) { - return IsOperator(steamID) ? FormatBotResponse("https://github.com/" + SharedInfo.GithubRepo + "/wiki/Commands") : null; + return IsFamilySharing(steamID) ? FormatBotResponse("https://github.com/" + SharedInfo.GithubRepo + "/wiki/Commands") : null; } ArchiLogger.LogNullError(nameof(steamID)); @@ -2175,11 +2218,12 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.BotLootingTemporarilyDisabled); } - if (BotConfig.SteamMasterID == 0) { + ulong targetSteamMasterID = GetFirstSteamMasterID(); + if (targetSteamMasterID == 0) { return FormatBotResponse(Strings.BotLootingMasterNotDefined); } - if (BotConfig.SteamMasterID == SteamClient.SteamID) { + if (targetSteamMasterID == SteamID) { return FormatBotResponse(Strings.BotLootingYourself); } @@ -2198,12 +2242,12 @@ namespace ArchiSteamFarm { return FormatBotResponse(Strings.BotLootingFailed); } - if (!await ArchiWebHandler.SendTradeOffer(inventory, BotConfig.SteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) { + if (!await ArchiWebHandler.SendTradeOffer(inventory, targetSteamMasterID, BotConfig.SteamTradeToken).ConfigureAwait(false)) { return FormatBotResponse(Strings.BotLootingFailed); } await Task.Delay(3000).ConfigureAwait(false); // Sometimes we can be too fast for Steam servers to generate confirmations, wait a short moment - await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, BotConfig.SteamMasterID).ConfigureAwait(false); + await AcceptConfirmations(true, Steam.ConfirmationDetails.EType.Trade, targetSteamMasterID).ConfigureAwait(false); return FormatBotResponse(Strings.BotLootingSuccess); } @@ -2299,7 +2343,7 @@ namespace ArchiSteamFarm { Dictionary ownedGames; if (await ArchiWebHandler.HasValidApiKey().ConfigureAwait(false)) { - ownedGames = await ArchiWebHandler.GetOwnedGames(SteamClient.SteamID).ConfigureAwait(false); + ownedGames = await ArchiWebHandler.GetOwnedGames(SteamID).ConfigureAwait(false); } else { ownedGames = await ArchiWebHandler.GetMyOwnedGames().ConfigureAwait(false); } @@ -2423,10 +2467,13 @@ namespace ArchiSteamFarm { return null; } - if (!IsMaster(steamID)) { - if (sticky || !SteamFamilySharingIDs.Contains(steamID)) { - return null; - } + BotConfig.EPermission permission = GetSteamUserPermission(steamID); + if (permission < BotConfig.EPermission.FamilySharing) { + return null; + } + + if (sticky && (permission < BotConfig.EPermission.Master)) { + return FormatBotResponse(Strings.ErrorAccessDenied); } if (!IsConnectedAndLoggedOn) { @@ -2439,7 +2486,7 @@ namespace ArchiSteamFarm { await CardsFarmer.Pause(sticky).ConfigureAwait(false); - if (!SteamFamilySharingIDs.Contains(steamID)) { + if (permission >= BotConfig.EPermission.Master) { return FormatBotResponse(Strings.BotAutomaticIdlingNowPaused); } @@ -2913,7 +2960,7 @@ namespace ArchiSteamFarm { return null; } - if (!IsOperator(steamID)) { + if (!IsFamilySharing(steamID)) { return null; } diff --git a/ArchiSteamFarm/BotConfig.cs b/ArchiSteamFarm/BotConfig.cs index 6d2dc0469..2399aa96c 100644 --- a/ArchiSteamFarm/BotConfig.cs +++ b/ArchiSteamFarm/BotConfig.cs @@ -97,15 +97,13 @@ namespace ArchiSteamFarm { [JsonProperty(Required = Required.DisallowNull)] internal readonly ulong SteamMasterClanID = 0; - [JsonProperty(Required = Required.DisallowNull)] - internal readonly ulong SteamMasterID = 0; - - [JsonProperty(Required = Required.DisallowNull)] - internal readonly ulong SteamOperatorID = 0; - [JsonProperty] internal readonly string SteamTradeToken = null; + [SuppressMessage("ReSharper", "CollectionNeverUpdated.Global")] + [JsonProperty(Required = Required.DisallowNull)] + internal readonly Dictionary SteamUserPermissions = new Dictionary(); + [JsonProperty(Required = Required.DisallowNull)] internal readonly ETradingPreferences TradingPreferences = ETradingPreferences.None; @@ -178,6 +176,13 @@ namespace ArchiSteamFarm { NamesDescending } + internal enum EPermission : byte { + None, + FamilySharing, + Operator, + Master + } + [Flags] internal enum ERedeemingPreferences : byte { None = 0, diff --git a/ArchiSteamFarm/Localization/Strings.Designer.cs b/ArchiSteamFarm/Localization/Strings.Designer.cs index 34736ebe2..24fa7756d 100644 --- a/ArchiSteamFarm/Localization/Strings.Designer.cs +++ b/ArchiSteamFarm/Localization/Strings.Designer.cs @@ -376,7 +376,7 @@ namespace ArchiSteamFarm.Localization { } /// - /// Wyszukuje zlokalizowany ciąg podobny do ciągu Trade couldn't be sent because SteamMasterID is not defined!. + /// Wyszukuje zlokalizowany ciąg podobny do ciągu Trade couldn't be sent because there is no master user defined!. /// internal static string BotLootingMasterNotDefined { get { @@ -718,6 +718,15 @@ namespace ArchiSteamFarm.Localization { } } + /// + /// Wyszukuje zlokalizowany ciąg podobny do ciągu Access denied!. + /// + internal static string ErrorAccessDenied { + get { + return ResourceManager.GetString("ErrorAccessDenied", resourceCulture); + } + } + /// /// Wyszukuje zlokalizowany ciąg podobny do ciągu Your bot config is invalid. Please verify content of {0} and try again!. /// diff --git a/ArchiSteamFarm/Localization/Strings.resx b/ArchiSteamFarm/Localization/Strings.resx index 14cfdcaa8..2fd83da2f 100644 --- a/ArchiSteamFarm/Localization/Strings.resx +++ b/ArchiSteamFarm/Localization/Strings.resx @@ -549,7 +549,7 @@ StackTrace: Trade offer failed! - Trade couldn't be sent because SteamMasterID is not defined! + Trade couldn't be sent because there is no master user defined! SteamMasterID is name of bot config property, it should not be translated @@ -714,4 +714,7 @@ StackTrace: Owned already: {0} {0} will be replaced by game's ID (number), {1} will be replaced by game's name + + Access denied! + \ No newline at end of file diff --git a/ArchiSteamFarm/Trading.cs b/ArchiSteamFarm/Trading.cs index 137261ca9..47aa00685 100644 --- a/ArchiSteamFarm/Trading.cs +++ b/ArchiSteamFarm/Trading.cs @@ -178,7 +178,7 @@ namespace ArchiSteamFarm { } // Always accept trades from SteamMasterID - if ((tradeOffer.OtherSteamID64 != 0) && ((tradeOffer.OtherSteamID64 == Bot.BotConfig.SteamMasterID) || (tradeOffer.OtherSteamID64 == Program.GlobalConfig.SteamOwnerID))) { + if ((tradeOffer.OtherSteamID64 != 0) && Bot.IsMaster(tradeOffer.OtherSteamID64)) { return new ParseTradeResult(tradeOffer.TradeOfferID, tradeOffer.ItemsToGive.Count > 0 ? ParseTradeResult.EResult.AcceptedWithItemLose : ParseTradeResult.EResult.AcceptedWithoutItemLose); } diff --git a/ArchiSteamFarm/config/example.json b/ArchiSteamFarm/config/example.json index 67d75cfdf..6ea3822a2 100644 --- a/ArchiSteamFarm/config/example.json +++ b/ArchiSteamFarm/config/example.json @@ -23,10 +23,9 @@ "ShutdownOnFarmingFinished": false, "SteamLogin": null, "SteamMasterClanID": 0, - "SteamMasterID": 0, - "SteamOperatorID": 0, "SteamParentalPIN": "0", "SteamPassword": null, "SteamTradeToken": null, + "SteamUserPermissions": {}, "TradingPreferences": 0 } diff --git a/ConfigGenerator/BotConfig.cs b/ConfigGenerator/BotConfig.cs index 597d9df31..27b3e0a69 100644 --- a/ConfigGenerator/BotConfig.cs +++ b/ConfigGenerator/BotConfig.cs @@ -30,6 +30,7 @@ using System.Drawing.Design; using System.IO; using ConfigGenerator.JSON; using Newtonsoft.Json; +using Wexman.Design; namespace ConfigGenerator { [SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")] @@ -112,14 +113,6 @@ namespace ConfigGenerator { [JsonProperty(Required = Required.DisallowNull)] public ulong SteamMasterClanID { get; set; } = 0; - [LocalizedCategory("Access")] - [JsonProperty(Required = Required.DisallowNull)] - public ulong SteamMasterID { get; set; } = 0; - - [LocalizedCategory("Access")] - [JsonProperty(Required = Required.DisallowNull)] - public ulong SteamOperatorID { get; set; } = 0; - [LocalizedCategory("Access")] [JsonProperty] public string SteamParentalPIN { get; set; } = "0"; @@ -133,6 +126,11 @@ namespace ConfigGenerator { [JsonProperty] public string SteamTradeToken { get; set; } = null; + [LocalizedCategory("Access")] + [Editor(typeof(GenericDictionaryEditor), typeof(UITypeEditor))] + [JsonProperty(Required = Required.DisallowNull)] + public Dictionary SteamUserPermissions { get; set; } = new Dictionary(); + [LocalizedCategory("Advanced")] [Editor(typeof(FlagEnumUiEditor), typeof(UITypeEditor))] [JsonProperty(Required = Required.DisallowNull)] @@ -195,6 +193,13 @@ namespace ConfigGenerator { NamesDescending } + internal enum EPermission : byte { + None, + FamilySharing, + Operator, + Master + } + [Flags] internal enum ERedeemingPreferences : byte { None = 0, diff --git a/ConfigGenerator/ConfigGenerator.csproj b/ConfigGenerator/ConfigGenerator.csproj index d23a7b9b1..2f6f44013 100644 --- a/ConfigGenerator/ConfigGenerator.csproj +++ b/ConfigGenerator/ConfigGenerator.csproj @@ -46,6 +46,9 @@ OnOutputUpdated + + ..\packages\GenDictEdit.1.1.0\lib\net20\GenericDictionaryEditor.dll + ..\packages\Newtonsoft.Json.10.0.1-beta1\lib\net45\Newtonsoft.Json.dll diff --git a/ConfigGenerator/packages.config b/ConfigGenerator/packages.config index 7a1a7c996..0f22ba522 100644 --- a/ConfigGenerator/packages.config +++ b/ConfigGenerator/packages.config @@ -1,8 +1,8 @@  - - - - - + + + + + \ No newline at end of file diff --git a/packages/GenDictEdit.1.1.0/GenDictEdit.1.1.0.nupkg b/packages/GenDictEdit.1.1.0/GenDictEdit.1.1.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..1292a93e353684917ef60f258404d442dab20bf9 GIT binary patch literal 8973 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 v&pZFmCe_&R{`c>Jzqvy)zSu z5sbBVrAn!_+PdmWsjXsdwbpm*1Ep59TCDE2cDEK=+i$70uG`hs+Uow!x%bXYLa^KJ z_wCnjzuqvv`#+EW`Jey!Kkm5?)}QxTauJamzYjhjdH`oWngu@`Mj;N)cqmBs_@1qK zKw0-}P4@+{RCv%d2Fz$8+!swIjdZwI51W}}IF<~zZRiRojDEc#5b)2kO?R#)TBo?^ z`fD%wYfJ*arl^bE<-VHDAuE{4aO5 zNoL`Abv@A*E^H;*!GRcmj1m=rcgH%Ss`0W9qr*hrJh>P28F_R=THlcd-PQnrO!^AH z^N%pRYA{n~ADH6XRus6S3-QZ4nlW4rrXDw-$iC7jer)R${PK=wqE&gM6vG@>9PFD) z1>~JebjwU4pKyu(eGXBDf_R24vo`yLr@I4Ryht#h z`u?4FeWatIdGCR1ryqId)zN2ezkJ#=H^2Sp+e0&hS3EL&u5sU?PgHF9{`U&rI^)%= zdy*}a-YD+5>tBXG_gdTKU!3p$-7DR*UVG^0t9PvE{l@IqPF?#}W$n#ZoYnElMX$X1 z_|HqbMXI(m7jf9B&wWSMGYK50@z2pdBTBH0z{m zj+MAD3LnXig3Fi>Jp+4;|A+^HmZ3KqL1virYjx{YZ72Jpj)+H7;7EPBMI6DlWChB= zG|+5~Fl(%{HDJWnz>sP4mZ+)8IOiFh&<4AbS50-f3nEzV{@R8ksw1)Hhl~2rFART4 zo_~==>_0nKCazf!%1Du>y>L^`P?#_H&h%P*akE za0z4VB8)4cFC}ica!J+|SEg_x|5n11yQm^CZrdj~TDu8eD zIRT&dGqHvLtnpkbpfzX*eJ*ijxEdzO;s~}Gzj-CvoMQFaQ=y5is}Q1T`#qC2v3V88 zbiXIk2JKp`gw=c=QX^||R%KO35N%C0c^yVDtu@{s&~dkHHc|k??=YkQ20CbINCAu@ zham+p0uDn8U?6B#6)AvG>@cJN1_EqpNCAuzham+pu*q5)QUC+ntHqGQedysC+%wls zY`AXKy%YPb8yg=sR<{~-@5EZbxnL(2m76;%=Tp=X)^-`~9Gry~Wt_=GR&-XrXk9+B zevDoRQ>WSn-NuG7!cL~HQ%BgTI;N4RfwRo2xpvh)Lq#7Ihdnz-pngVGhabf5g6xkYaz7%+|zG7f)ibh zU%YELmDUptoAi{CG5hpXwzNr)_UmR{IFafz%y_J~F1%ScQ!yjCVqwDq{;LbOX5#6L zsjo=tnY0;=*M&PXz42JzS^99dv0YED=v}%rx}Tmh-{Y<}$-?Fu&QxZRuV$?@%f@z=uZWP>MT8)h{Mrm+N>XuR* z`g|yp*Xl{#jPC zY=Ymx`5i2knO$i!mK;d2#yz;qSHbU@XLr#NTy3#%Xy)3p+p*l~DCk32{xes_jb2v9 zfo>{Ws`vYRutmS0y@)WmxZ4;r$-OXygbj(XC(wELaabG~OcCZ7os1v*%Jpy^7<0y0 z+r81~kMuV7ZMX6^c=gI;B}fUSQ_*ObaIOHyPd5NHx>Go<>SU#qzKtgR^edEMLFKv$ zFPDGsJ?7PDp0C2E(U8C2uhAaC+XW8`{#@`q!HPoGX%vhVo>{2TPQfdMbBo}?LiX@S zg>1Q~=-t8*3Zr8hZ77;wq>&-`l_J)8Rq##0_k>>&VE)=bUBFM91Cx~yT^kq;X!O+p zxBD%@??cB=uR*F&L9j0HZK}fFr_mCWH99xQ77|h(5!^4F2L+!8R!~{-`$0c771tDN z)LHy4_oBGp@28uJIePa2F#vYNc^+Mg8E`T!!?-Y|K)ME$4`mmAlc-B%Zq9)~>7WA0 zQCNEtT@0!OSF>W&n?%=vDo0Ho@kw+)s7flM2BDs&7g48@P9sfwN|{cZM~^5qz!!lE z`P9w8OVk~}&#M<_IZvzCqP(%-S>UkX4T28|zA6~hSh`TKOYjoyd2p^1yif2J&riX* z&BK}x2!2=ar=I8Gzuz}QDWRplnGzYICkyVutWxMm7_QSNr#!Aq#jO6ZP){m9QRai1 zQ^T@PiOfawEz0{#H}pBsErl{E9(%Qi*4C7^*mg; zKWS6*)gDlLgnE*;syZV4#VnP;Y`Neh_T@=RswSxILa}FisgTk_9ir#e>#+il+L}Sv zKY}`dWE|_Arnqj!2tHs_jjlUDaf;5eX4l;q%R@HR?s@?6s+(=eHn|?9Qraby6^Sys z(W1Oj*es)4Z0cgyUQl1RsV_iQPWRf>9gvmNBQ|vqvI=_Are1)of_`9Azl3Zu{m7WpW>d={n?i5e)VYvV(z`Y_2w5emyd}}6ynhebRPx)@4UkQxQk%LH zvS~EUrk;ar8qKn)*WHJ3mtAL5|K)xP)DoLg3Jy^Ov8g$bO{WfbXcq0UD0*OJ|Wa)vI6GORYG0kUF(|z*)ulv5nmmsAKKJ_uMyNwY%1kjs?@={LJuNeQ0NiC zLwWc#=Mlsl7d@B9e_6`M1g*NiL0P5$1iD0Dp+AaLL++^%qh&|2rTMM=Wo2$%rAe^t zqUk_4%>@?F=|F|fnh+fyEa};zbI5loJ+3@Oy9KWnyk782f(Hb@Dfpn^L14RbSjx`} zz9jgH@Q+FPO<;$jD32@MiVrvydj?|*-Cy)R_MyW?@1Xn=uu^%g=y|G98eN(?S2W9H zA1;%9xKe7B5$|MW#CujFbe=+)ckD{+MhVP&%YH}TR%%i7z+APAcn7PZbl^1LjzE*z z4xQ808sJ{4k-eyncyF&0JMGF%fv4clV}ZX@H!2&v1M0c-V&FnGrtnN_qCW&KMqS>s z*w5?K#l(B?a=|j#T!-W;6ns!^qdCEcRZzhf)NbOvxSM#_T}Pe4cWAew2d5(8+6^od zX_-j7VPT%DU%VZry}>%AQn@>LrmKc{e>;HwMqP8EGnE>FpKvwGT5Kd=7Q~ZJJB}g^57d!uK{ED#p8t6*e?{1)(vIFyzSf@sCrt&qlmS!qn zR=?t!DV!F;sNki7UlKeh_==#SiUq+I!KmN?^#wKHJ}gKs)(HzX3vLx072GHInBY-C za*MuTv*1?2QNewJj|m8tT>Rjp{LVk*nMFdl%!wv z$~!FrfrIf}We+lORcH$o zdR+=*d2b)b^V2FZGgfbu?{~)7^V1v1#jS%YJcBzcKD^|U`hF@@xZtNrLKoR|5$O3; z#O9Z;H~KSieI=dX_O78n9;cQx?$&xUX}!}lhGMw2r7il7L^RpZrl(>9Nov!#MR7lS zb}BlcJA|XUwUPKnG1?o~adW#l8qesR(U`e);fY#2u_WsTIhN3VpBWqE+fe5|xN)p+ z4e(=7H`6gaMb7OwS@+Vkq4#5YUz%1YGYM?W-7res;-Ib2&}t+GjijDTBS?CjS~ID% zk?0;C)brZ4@5}8-*womHPMBJacpMGl?%BR|&UMK4ayZX$R+y_s+&1Et&dO5M(8s+W z;<)zoaA3&l0<`R5p#eSJ!-AB3X4+C>j#WzZSUzPfORe!d)*sJ1-t|0(;YHp6E~t#iQfc4|*i{mY_YEN=K7@G8QaK5gxx-1@y5kmKuylhr9VT z6~`K#w1)z*ko6;`?BSS5WY>bDLzug|nXf;VX=_@+$ydwc*gDyvoyd!cgJsx$FZ{Q zj@Pq-lUJE%^aSxZZZ@;tm>5i`k?Z<|;t9KXyyl5U@C2HF!Y#4(VUCHy|IjrVgya1f z8~)?vAt*+vAwtF(cO%rY7{;+EOPNR!cC}7@2rK_SaZ69=k}FKFQT9+YPakqtKc)5W>&)Cq-jicCN?LZk|tL{K*;3 zGc*42c{X2IA59`_G0C)_;)8ZB|7-Egnca`_B^y_Nd1Bw5+=i#)wzAC=pAiOm4d57* zh+1`Izsc7AW6GdRBu)%QleuM_Z3}+)XZmuPQ&!Mw3=W&IfeR)Ob(?sPlZcwz zCuqkS*_^=XrS(>(p&cm(GEY0hND_mY!0us_Ee`COT^N#AzfBvdrDG!>s1r2P7J1psRjA>P?S?<$9ZWLIb;4% zm;;#v(*BN2JidBIpFSuXfZh3AZkcMZJ*IWBR2nxrwp+5%Ig^-MlAP4pqo}37pSq0} z(~J%~0o@Wy_8S+b8aRdJxsptqM%>C$IEi$s%HFdIx|}P=qj-IW79An2GK{#6-HSuv zF!Q`vk0qy@c?<~|wg7Cg&MQ6Kdoj1wz&Oc$k&bnS9-tWxrA^_2CA)=vA15_3rip;j zdSgiMV3*r@-!@V_n`8?&QabbU8fwo45}|8_>!#JXWy;wF+c_pt?xl6-X_2{GQn~5O z&9H2#J8Hr)i4fvxZE8-q+sx>N2;n%=xlKD;ZWrvUQFhS#^)@3RcZ59S5fR+K@T_UY z!pJsiuOZ#+Fp_7dbaSk5lfF$yl=}45AJ0VNsq79U-FB8g$J&{(vYoFoF*C-lO3Syb zpeqeWPI%j!eJkCF58doH)kHJ&yjQ&~c;%ax*TTJ&K}p94A!h-Hi3&GU6mM`d%$wbc z7sGM<>C^`;>&3D2$~a2BBBA0wd7;c!c0h|totE+}6%OUB7LVWqzMXi=GJ>ZuJBe0r zk(vo;B=L-~4O9wk4G7f)a-QO&`VsziPu3dlc z(ZlmM?tSDE^4@>Z`I{>jAKmS}>-3&WO8&`zsuos4)u9?!m=sm>y0nraezA=A!~n=j z35+lvQ5A$05L{HGsQAJzFiMqBl}ig%K@h59L8!_Di?gdk<;J z3|zAHYfybI>(2FtT~(p_P@@>Dk(!LvRaIJ8t*WX9UkO&h(;x~;5cO(QEy$K?ToF9O z)64n71vR@4m?yra%)Q%s!)9Zl7lQ{_;qqDzsNCI>oov@Tx(`qA$UTY&h#WV590ht)S4$(FZOWsxC#paC-J>V} zFbdjb zo13Pcvgw_hCQbUUGk!91)>&yD|w=ohibI)&?IhHPKw)u34~am=xFV(+u$vmm0c4xV82X)*XjLW_ z$Ae7IV(Wt(ep9AmxnRgbqsO=#aP$}lx(UlD7!0kjoP5)(*iT^b#mb34i7AlBt@yAZ zl+7-~j~@t!7cOYT-ZWRCS^7eK+u|j9Z+&l5@3Q*EOP8Kf-?VJow)$mDmMvZw?OzmK z8r_CZRPda?v7wQDgopBQ*{@K6o~+N{(;4`J@9A(%XGynOvBiuI;>wdvS-LOaYlrv( zE$2INUT6Hh%~R{}!^aSty4t$FaQNQOO@H^LGjBU~{$=fldZbSOspq#D=?*=8{)Rz4 z*(EnO=bs=)J0aib{n+_P1$EpEoJgl(u)mjk@z;11b>zHi;Bq)e=a-ys!Si`UNTkfR zczk^{mb4x|>$*HoXRQxr!xn$)^ta>xMFjZkBf^_4*~9XBWW5o>@*T}%qG+v3eCSE% zY{j&~)zUe_uEi*BrY?Nxy&0e6Z9=J?Hc$uXcHkP6`FPm<#{1S~(z4~ed*W~3_;BOL zYd!yH1EIhwf9|&iSrzAU?Z~XQA*aW3Wu>v|yH{5U+&XKMW%Zf2tnB^Ve}STi=j2ul(z9=Wky8-$vlS0iyt= AlmGw# literal 0 HcmV?d00001