From f5b89bc51cdebc254334ea05a172560cf7de9edf Mon Sep 17 00:00:00 2001 From: panthernet Date: Fri, 12 Jan 2018 17:07:07 +0100 Subject: [PATCH] Release 2.3.7 --- .gitignore | 1 + Documents/AIV.cs | 4 +- Documents/CHANGELOG.txt | 5 +- .../METRO.SimpleGraph.csproj | 230 - .../METRO.SimpleGraph_TemporaryKey.pfx | Bin 2460 -> 0 bytes .../METRO.SimpleGraph/Package.appxmanifest | 37 - .../Properties/AssemblyInfo.cs | 16 - Examples/METRO.SimpleGraph/packages.config | 4 - .../App.xaml | 2 +- .../App.xaml.cs | 2 +- .../Assets/100.png | Bin .../Assets/150.png | Bin .../Assets/300.png | Bin .../Assets/44.png | Bin .../Assets/50.png | Bin .../Assets/88.png | Bin .../Assets/Logo.png | Bin .../Assets/Logo.scale-100.png | Bin .../Assets/Logo.scale-200.png | Bin .../Assets/MidLogo.png | Bin .../Assets/SmallLogo.png | Bin .../Assets/SplashScreen.png | Bin .../Assets/SplashScreen.scale-100.png | Bin .../Assets/SplashScreen.scale-200.png | Bin .../Assets/StoreLogo.png | Bin .../Assets/newlogo_big.png | Bin .../Assets/play.png | Bin .../Assets/refresh.png | Bin .../Assets/tr_grren.png | Bin .../Assets/tr_red.png | Bin .../Common/StandardStyles.xaml | 0 .../Common/templates.xaml | 0 .../Common/templates2.xaml | 0 .../MainPage.xaml | 9 +- .../MainPage.xaml.cs | 4 +- .../MainPageDebug.xaml | 5 +- .../MainPageDebug.xaml.cs | 6 +- .../Models/CurvedEr.cs | 4 +- .../Models/CurvedErParameters.cs | 2 +- .../Models/DataEdge.cs | 3 +- .../Models/DataVertex.cs | 3 +- .../Models/DebugItems.cs | 2 +- .../Models/GXLogicCoreExample.cs | 2 +- .../Models/GraphAreaExample.cs | 3 +- .../Models/GraphExample.cs | 2 +- .../Models/MouseOverScaleAnimation.cs | 7 +- .../Package.appxmanifest | 6 +- .../Properties/AssemblyInfo.cs | 0 .../Properties/Default.rd.xml | 0 .../UAP.SimpleGraph.csproj} | 118 +- .../UAP.SimpleGraph.nuget.props | 21 + .../UAP.SimpleGraph.nuget.targets | 12 + .../project.json | 4 +- Examples/UAP.SimpleGraph/project.lock.json | 25886 ++++++++++++++++ Examples/UWA.SimpleGraph/App.xaml | 14 - Examples/UWA.SimpleGraph/App.xaml.cs | 96 - .../UWA.SimpleGraph_TemporaryKey.pfx | Bin 2460 -> 0 bytes Examples/UWA.SimpleGraph/project.lock.json | 14870 --------- GraphX for .NET.sln | 68 +- GraphX.Controls/Behaviours/DragBehaviour.cs | 4 +- GraphX.Controls/Controls/EdgeControlBase.cs | 17 +- .../EdgePointers/DefaultEdgePointer.cs | 29 +- GraphX.Controls/Controls/GraphArea.cs | 2 +- GraphX.Controls/Controls/GraphAreaBase.cs | 6 + GraphX.Controls/Controls/VertexControlBase.cs | 1 + .../GraphX.METRO.Controls.csproj | 89 +- .../Converters/DoubleToLog10Converter.cs | 26 + .../Converters/EqualityToBooleanConverter.cs | 22 + .../Converters/RoundedValueConverter.cs | 64 + .../Converters/VisibilityToBoolConverter.cs | 55 + .../ZoomControl/Helpers/DoubleHelper.cs | 94 + .../ZoomControl/Helpers/PointHelper.cs | 42 + .../ZoomControl/Helpers/VisualTreeHelperEx.cs | 157 + .../SupportClasses/AreaSelectedEventArgs.cs | 19 + .../AreaSelectedEventHandler.cs | 4 + .../ContentSizeChangedHandler.cs | 6 + .../SupportClasses/MouseWheelZoomingMode.cs | 8 + .../SupportClasses/ZoomControlModes.cs | 20 + .../SupportClasses/ZoomViewModifierMode.cs | 30 + .../ZoomControl/ZoomContentPresenter.cs | 71 + .../Controls/ZoomControl/ZoomControl.cs | 911 + .../DesignerExampleData/EdgeDataExample.cs | 20 + .../DesignerExampleData/VertexDataExample.cs | 21 + GraphX.UAP.Controls/DpExtensions.cs | 70 + .../GraphX.UAP.Controls.csproj | 370 + GraphX.UAP.Controls/Images/cross-icon.png | Bin 0 -> 50642 bytes GraphX.UAP.Controls/Images/help_black.png | Bin 0 -> 5460 bytes GraphX.UAP.Controls/Images/round1.png | Bin 0 -> 22705 bytes GraphX.UAP.Controls/Images/round2.png | Bin 0 -> 34574 bytes GraphX.UAP.Controls/Models/AnimationHelper.cs | 33 + GraphX.UAP.Controls/Models/DelegateCommand.cs | 81 + .../Models/DispatcherHelper.cs | 19 + .../Models/EdgeSelectedEventArgs.cs | 29 + .../Models/FileServiceProviderMETRO.cs | 39 + GraphX.UAP.Controls/Models/ModifierKeys.cs | 11 + .../Models/MouseButtonEventArgs.cs | 6 + .../Models/VertexMovedEventArgs.cs | 16 + .../Models/VertexSelectedEventArgs.cs | 16 + .../Models/XamlTypes/ViewModelBase.cs | 68 + .../Models/XamlTypes/ViewModelXamlMember.cs | 69 + .../ViewModelXamlMetadataProvider.cs | 28 + .../Models/XamlTypes/ViewModelXamlType.cs | 117 + .../Models/XamlTypes/XamlSystemType.cs | 105 + .../Models/XamlTypes/XamlTypeProvider.cs | 70 + GraphX.UAP.Controls/PrintHelper.cs | 142 + .../Properties/AssemblyInfo.cs | 29 + .../Properties/GraphX.UAP.Controls.rd.xml | 33 + GraphX.UAP.Controls/Themes/Generic.xaml | 262 + GraphX.UAP.Controls/uap_graphx.controls.pfx | Bin 0 -> 1709 bytes 109 files changed, 29294 insertions(+), 15485 deletions(-) delete mode 100644 Examples/METRO.SimpleGraph/METRO.SimpleGraph.csproj delete mode 100644 Examples/METRO.SimpleGraph/METRO.SimpleGraph_TemporaryKey.pfx delete mode 100644 Examples/METRO.SimpleGraph/Package.appxmanifest delete mode 100644 Examples/METRO.SimpleGraph/Properties/AssemblyInfo.cs delete mode 100644 Examples/METRO.SimpleGraph/packages.config rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/App.xaml (95%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/App.xaml.cs (99%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/100.png (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/150.png (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/300.png (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/44.png (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/50.png (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/88.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/Logo.png (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/Logo.scale-100.png (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/Logo.scale-200.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/MidLogo.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/SmallLogo.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/SplashScreen.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/SplashScreen.scale-100.png (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/SplashScreen.scale-200.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/StoreLogo.png (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Assets/newlogo_big.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/play.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/refresh.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/tr_grren.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Assets/tr_red.png (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Common/StandardStyles.xaml (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Common/templates.xaml (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Common/templates2.xaml (100%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/MainPage.xaml (90%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/MainPage.xaml.cs (99%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/MainPageDebug.xaml (94%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/MainPageDebug.xaml.cs (98%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Models/CurvedEr.cs (97%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Models/CurvedErParameters.cs (90%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Models/DataEdge.cs (98%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Models/DataVertex.cs (98%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Models/DebugItems.cs (73%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Models/GXLogicCoreExample.cs (89%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Models/GraphAreaExample.cs (92%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Models/GraphExample.cs (94%) rename Examples/{METRO.SimpleGraph => UAP.SimpleGraph}/Models/MouseOverScaleAnimation.cs (98%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Package.appxmanifest (87%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Properties/AssemblyInfo.cs (100%) rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/Properties/Default.rd.xml (100%) rename Examples/{UWA.SimpleGraph/UWA.SimpleGraph.csproj => UAP.SimpleGraph/UAP.SimpleGraph.csproj} (67%) create mode 100644 Examples/UAP.SimpleGraph/UAP.SimpleGraph.nuget.props create mode 100644 Examples/UAP.SimpleGraph/UAP.SimpleGraph.nuget.targets rename Examples/{UWA.SimpleGraph => UAP.SimpleGraph}/project.json (74%) create mode 100644 Examples/UAP.SimpleGraph/project.lock.json delete mode 100644 Examples/UWA.SimpleGraph/App.xaml delete mode 100644 Examples/UWA.SimpleGraph/App.xaml.cs delete mode 100644 Examples/UWA.SimpleGraph/UWA.SimpleGraph_TemporaryKey.pfx delete mode 100644 Examples/UWA.SimpleGraph/project.lock.json create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/Converters/DoubleToLog10Converter.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/Converters/EqualityToBooleanConverter.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/Converters/RoundedValueConverter.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/Converters/VisibilityToBoolConverter.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/Helpers/DoubleHelper.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/Helpers/PointHelper.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/Helpers/VisualTreeHelperEx.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/AreaSelectedEventArgs.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/AreaSelectedEventHandler.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ContentSizeChangedHandler.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/MouseWheelZoomingMode.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ZoomControlModes.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ZoomViewModifierMode.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/ZoomContentPresenter.cs create mode 100644 GraphX.UAP.Controls/Controls/ZoomControl/ZoomControl.cs create mode 100644 GraphX.UAP.Controls/DesignerExampleData/EdgeDataExample.cs create mode 100644 GraphX.UAP.Controls/DesignerExampleData/VertexDataExample.cs create mode 100644 GraphX.UAP.Controls/DpExtensions.cs create mode 100644 GraphX.UAP.Controls/GraphX.UAP.Controls.csproj create mode 100644 GraphX.UAP.Controls/Images/cross-icon.png create mode 100644 GraphX.UAP.Controls/Images/help_black.png create mode 100644 GraphX.UAP.Controls/Images/round1.png create mode 100644 GraphX.UAP.Controls/Images/round2.png create mode 100644 GraphX.UAP.Controls/Models/AnimationHelper.cs create mode 100644 GraphX.UAP.Controls/Models/DelegateCommand.cs create mode 100644 GraphX.UAP.Controls/Models/DispatcherHelper.cs create mode 100644 GraphX.UAP.Controls/Models/EdgeSelectedEventArgs.cs create mode 100644 GraphX.UAP.Controls/Models/FileServiceProviderMETRO.cs create mode 100644 GraphX.UAP.Controls/Models/ModifierKeys.cs create mode 100644 GraphX.UAP.Controls/Models/MouseButtonEventArgs.cs create mode 100644 GraphX.UAP.Controls/Models/VertexMovedEventArgs.cs create mode 100644 GraphX.UAP.Controls/Models/VertexSelectedEventArgs.cs create mode 100644 GraphX.UAP.Controls/Models/XamlTypes/ViewModelBase.cs create mode 100644 GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlMember.cs create mode 100644 GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlMetadataProvider.cs create mode 100644 GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlType.cs create mode 100644 GraphX.UAP.Controls/Models/XamlTypes/XamlSystemType.cs create mode 100644 GraphX.UAP.Controls/Models/XamlTypes/XamlTypeProvider.cs create mode 100644 GraphX.UAP.Controls/PrintHelper.cs create mode 100644 GraphX.UAP.Controls/Properties/AssemblyInfo.cs create mode 100644 GraphX.UAP.Controls/Properties/GraphX.UAP.Controls.rd.xml create mode 100644 GraphX.UAP.Controls/Themes/Generic.xaml create mode 100644 GraphX.UAP.Controls/uap_graphx.controls.pfx diff --git a/.gitignore b/.gitignore index af27fba5..13184f4d 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,4 @@ UpgradeLog*.XML #LocalHistory VS plugin .localhistory/ .settings/launch.json +/.vs/GraphX for .NET/v15/Server/sqlite3 diff --git a/Documents/AIV.cs b/Documents/AIV.cs index 2445cffa..888f72e7 100644 --- a/Documents/AIV.cs +++ b/Documents/AIV.cs @@ -8,5 +8,5 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("2.3.6.0")] -[assembly: AssemblyFileVersion("2.3.6.0")] +[assembly: AssemblyVersion("2.3.7.0")] +[assembly: AssemblyFileVersion("2.3.7.0")] diff --git a/Documents/CHANGELOG.txt b/Documents/CHANGELOG.txt index edc9c6c3..c72629db 100644 --- a/Documents/CHANGELOG.txt +++ b/Documents/CHANGELOG.txt @@ -1,8 +1,11 @@ -WIP 2.3.7 +RELEASE 2.3.7 - Added edge drag functionality to be able to reattach edge to another vertex (thanks to LaborJos) - Fixed SimpleTreeLayout vertex sizes supplement (thanks to edgardozoppi) - Fixed and improved parallel edge handling (thanks to perturbare) - Fixed RemoveEdge() method were not removing edges from data graph (thanks to perturbare) +- Removed METRO support and example +- Added UAP (UWP) support for Windows 10+ platform (VS2017) +- Minor bugfixes RELEASE 2.3.6 DETAILED CHANGELOG: diff --git a/Examples/METRO.SimpleGraph/METRO.SimpleGraph.csproj b/Examples/METRO.SimpleGraph/METRO.SimpleGraph.csproj deleted file mode 100644 index 59c00309..00000000 --- a/Examples/METRO.SimpleGraph/METRO.SimpleGraph.csproj +++ /dev/null @@ -1,230 +0,0 @@ - - - - - Debug - AnyCPU - {44841666-C547-4874-9BC9-B34D2A1FA6D8} - appcontainerexe - Properties - METRO.SimpleGraph - METRO.SimpleGraph - en-US - 512 - {BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - METRO.SimpleGraph_TemporaryKey.pfx - 8.1 - 12 - - 0E531EEE26E7E3F2FBD6A8E1E9F889D31225622F - ..\..\ - true - - - AnyCPU - true - full - false - bin\Debug\ - TRACE;DEBUG;NETFX_CORE, METRO - prompt - 4 - true - 1591 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE;NETFX_CORE - prompt - 4 - 1591 - - - true - bin\ARM\Debug\ - DEBUG;TRACE;NETFX_CORE - ;2008 - full - ARM - false - prompt - true - - - bin\ARM\Release\ - TRACE;NETFX_CORE - true - ;2008 - pdbonly - ARM - false - prompt - true - - - true - bin\x64\Debug\ - DEBUG;TRACE;NETFX_CORE - ;2008 - full - x64 - false - prompt - true - - - bin\x64\Release\ - TRACE;NETFX_CORE - true - ;2008 - pdbonly - x64 - false - prompt - true - - - true - bin\x86\Debug\ - DEBUG;TRACE;NETFX_CORE - ;2008 - full - x86 - false - prompt - true - - - bin\x86\Release\ - TRACE;NETFX_CORE - true - ;2008 - pdbonly - x86 - false - prompt - true - - - - - {66f33708-c1c7-4385-8235-7201784d184c} - GraphX.METRO.Controls - - - {3644d44b-dec0-4b65-bba0-c68e34821aae} - GraphX.PCL.Common - - - {a30d218b-aaa4-483a-99f7-eaeb1b8b4610} - GraphX.PCL.Logic - - - - - App.xaml - - - MainPageDebug.xaml - - - MainPage.xaml - - - - - - - - - - - - - - - Designer - - - - - - - - - - - - - - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - PreserveNewest - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - PreserveNewest - - - - - ..\..\packages\QuickGraphPCL.3.6.61114.2\lib\portable-win+net4+sl5+wp8+win8+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\QuickGraph.dll - True - - - ..\..\packages\QuickGraphPCL.3.6.61114.2\lib\portable-win+net4+sl5+wp8+win8+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\QuickGraph.Graphviz.dll - True - - - - 12.0 - - - - - - true - - - METRO.SimpleGraph_TemporaryKey.pfx - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Examples/METRO.SimpleGraph/METRO.SimpleGraph_TemporaryKey.pfx b/Examples/METRO.SimpleGraph/METRO.SimpleGraph_TemporaryKey.pfx deleted file mode 100644 index 338d6daef6dfd835d732c97236efa9c380f0faf7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2460 zcmZ`*2{=^m8b7lbW|(PgrNv~cB*qzxZL%b5D9WT7gt7M6MnaK4N26?6!XO$c{gEZ5 zg(MUv6e`@ZB!$S5iMFxa!*g%9`#kra^StNz{eIv3e((3Z=lkAsKnRNe{Qnvf`hbRn-obJ|Y<(Efe?^Jm5Xb@u{SAcBd~gc} z_iq`VoPZXQ!fX#;O1rWSi4^WaL+GxV+A8DjJ_2Mo824BH559B=2+FzErv%1t-4CSPzP}8nkglD|?oHw00TFdqul~^h^Zr-%fXorBadC9Iq70s5C8mOXf)s3eaTcW235Cd+fVk zsSlXk^`!I7c@ID4#Hz5g#YBmZ9KU^5ws10^o{x)o5b|WVxTcij(8^Ib=mv_qMjpPFrC!ZutTC%#g zJj0qxD)gU7!he>&b)sXDzZ@~5;{PJ^RfL3>)79Y(x~-S1v))(#IFUNU#w!l|`f=n{ zh|)BAw(#o#pVqDzrT&i#-|NGt_E_t9$kfUBxQJR2OLXkV-+14`)oO@8)ew}fG}s)m zK8nj&ysnU4(IL`#i5s@rGorXdbK8sj2H_hm$_mNJTXs+t);CCIM+syd#yiDiN(oO` zqMTg!+}2RRgDVHi%L`~5J*v&aNkM=AVsI}Sj`5zOA%~tYU4zP=fDE4MO_yD`q5JnL zz$`;%P0R5F!AQHgA=a^KH|tChA}7i1w(iM2?`;;1W)EhTKb;+QnN*?dO+IzXyFK8+ z%3}KVjWy)npI(-scPUc2^f^7ttnTVzy8v~KJ0_frW+N@DA^oj<3RmnB;Ty-gq*y0r zr6fppj7STw5mh=U&Kd-EQ;HiM!x-$5&I?<|g&!5k-z@KwwMvT2??!w&!v5O;c|Bnx zR&%SDplR92%zph}#WQVFl_MXf0*bOHl|q&!G*Nu-d|YC5Wrv(c-gMr%znpl_gL(xK zxA^i@H|9p>N|Opy${yH}K9Ei(0LM(JR@ZKxISEOFIKIoy$p)4Bvy}M|687 zHnC!(hxFRAVvW0*gHG|;@#oq2dZ(T^f(?)o9W=H%Vj8_NVcF^6_kEKvW<(@yY2q~s z&$#O#O|ur9IFVz^EvTRy82L+Wv)auea;oT&{1)ng-oEK%g%5p5bG_l*_8Ws7htWM* zk``L}@~i`jg^Z}OYi=^H`JrZ*fzyiFpH>Z|0dRN%?FM6j-4V8RdwO^`>-X1&;?=xFo za+)le z?dga+d!0ij?K76Qub#VdH>B6B?9qHg9kcy=Q0PA8vnm{MU(|T$C-vCY;6vYLwJa*K zQ+TeNXSz4$aPLzVXq1@epycm1iIt{c&}akz0HEW4L@CNXk|m%4xC0cx6Yv6UfE!GXt1f4P1T^Ix!0qKY%D0Za% zfGyw)I|c)Rz)9G=fDk|qI0Qdel>opSW_w|L8VG{5K$r)^69xf3Yf*B5-I`x0%vKWz zgAj`Ld*!Pi1e7WoLMg+t5^QpRc70R9+$YEF?03pQF0u&N~ zL=tUdK~;SP_uOht)v*?<5FOApn%7NP^-R6djF{#09wpg!p&{2Y7~nqz!nA zHmFO{qktL|4ZUM9)mfw3YxMtxK?sFE6Ci{D6ogm@!0W*wAp`;_RQhCkE5by9zwtt9 z%*(k8D37NJ_b&DLbGBOG7JYX1j%jqc|Lli?b&>-cHW>xf=f15;icFlUJ&N^ZXwtBC zXTJ20aVI0ss&>s?8aN-K9H?id%t0F1yb@8`bn98=s#|Z1Z-${m{DcrvB7k=nH-SVKr9) zwdYVG1pOo7MeDu%5TFVGCkp%CMVjwk(IDqX@RV;npnugjo4DP-|d00RFaj<9{0ND{haWT z!s+8lObk<^r$t-FHMB|5IMZp->~Zj2Vl=yhwr-g+v@WU^W5-c@B@it1zG$wlT*tmv zDf(#Z`%bK@ - - - - METRO.SimpleGraph - panth_000 - Assets\StoreLogo.png - - - 6.3.0 - 6.3.0 - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Examples/METRO.SimpleGraph/Properties/AssemblyInfo.cs b/Examples/METRO.SimpleGraph/Properties/AssemblyInfo.cs deleted file mode 100644 index 9affc518..00000000 --- a/Examples/METRO.SimpleGraph/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("METRO.SimpleGraph")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("METRO.SimpleGraph")] -[assembly: AssemblyCopyright("Copyright © 2014")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] \ No newline at end of file diff --git a/Examples/METRO.SimpleGraph/packages.config b/Examples/METRO.SimpleGraph/packages.config deleted file mode 100644 index a3f91dfd..00000000 --- a/Examples/METRO.SimpleGraph/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Examples/METRO.SimpleGraph/App.xaml b/Examples/UAP.SimpleGraph/App.xaml similarity index 95% rename from Examples/METRO.SimpleGraph/App.xaml rename to Examples/UAP.SimpleGraph/App.xaml index 276b3134..f485eac4 100644 --- a/Examples/METRO.SimpleGraph/App.xaml +++ b/Examples/UAP.SimpleGraph/App.xaml @@ -1,5 +1,5 @@  diff --git a/Examples/METRO.SimpleGraph/App.xaml.cs b/Examples/UAP.SimpleGraph/App.xaml.cs similarity index 99% rename from Examples/METRO.SimpleGraph/App.xaml.cs rename to Examples/UAP.SimpleGraph/App.xaml.cs index 055debd2..6674dcb8 100644 --- a/Examples/METRO.SimpleGraph/App.xaml.cs +++ b/Examples/UAP.SimpleGraph/App.xaml.cs @@ -6,7 +6,7 @@ // The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227 -namespace METRO.SimpleGraph +namespace UAP.SimpleGraph { /// /// Provides application-specific behavior to supplement the default Application class. diff --git a/Examples/UWA.SimpleGraph/Assets/100.png b/Examples/UAP.SimpleGraph/Assets/100.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/100.png rename to Examples/UAP.SimpleGraph/Assets/100.png diff --git a/Examples/UWA.SimpleGraph/Assets/150.png b/Examples/UAP.SimpleGraph/Assets/150.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/150.png rename to Examples/UAP.SimpleGraph/Assets/150.png diff --git a/Examples/UWA.SimpleGraph/Assets/300.png b/Examples/UAP.SimpleGraph/Assets/300.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/300.png rename to Examples/UAP.SimpleGraph/Assets/300.png diff --git a/Examples/UWA.SimpleGraph/Assets/44.png b/Examples/UAP.SimpleGraph/Assets/44.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/44.png rename to Examples/UAP.SimpleGraph/Assets/44.png diff --git a/Examples/UWA.SimpleGraph/Assets/50.png b/Examples/UAP.SimpleGraph/Assets/50.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/50.png rename to Examples/UAP.SimpleGraph/Assets/50.png diff --git a/Examples/UWA.SimpleGraph/Assets/88.png b/Examples/UAP.SimpleGraph/Assets/88.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/88.png rename to Examples/UAP.SimpleGraph/Assets/88.png diff --git a/Examples/METRO.SimpleGraph/Assets/Logo.png b/Examples/UAP.SimpleGraph/Assets/Logo.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/Logo.png rename to Examples/UAP.SimpleGraph/Assets/Logo.png diff --git a/Examples/UWA.SimpleGraph/Assets/Logo.scale-100.png b/Examples/UAP.SimpleGraph/Assets/Logo.scale-100.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/Logo.scale-100.png rename to Examples/UAP.SimpleGraph/Assets/Logo.scale-100.png diff --git a/Examples/UWA.SimpleGraph/Assets/Logo.scale-200.png b/Examples/UAP.SimpleGraph/Assets/Logo.scale-200.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/Logo.scale-200.png rename to Examples/UAP.SimpleGraph/Assets/Logo.scale-200.png diff --git a/Examples/METRO.SimpleGraph/Assets/MidLogo.png b/Examples/UAP.SimpleGraph/Assets/MidLogo.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/MidLogo.png rename to Examples/UAP.SimpleGraph/Assets/MidLogo.png diff --git a/Examples/METRO.SimpleGraph/Assets/SmallLogo.png b/Examples/UAP.SimpleGraph/Assets/SmallLogo.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/SmallLogo.png rename to Examples/UAP.SimpleGraph/Assets/SmallLogo.png diff --git a/Examples/METRO.SimpleGraph/Assets/SplashScreen.png b/Examples/UAP.SimpleGraph/Assets/SplashScreen.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/SplashScreen.png rename to Examples/UAP.SimpleGraph/Assets/SplashScreen.png diff --git a/Examples/METRO.SimpleGraph/Assets/SplashScreen.scale-100.png b/Examples/UAP.SimpleGraph/Assets/SplashScreen.scale-100.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/SplashScreen.scale-100.png rename to Examples/UAP.SimpleGraph/Assets/SplashScreen.scale-100.png diff --git a/Examples/UWA.SimpleGraph/Assets/SplashScreen.scale-200.png b/Examples/UAP.SimpleGraph/Assets/SplashScreen.scale-200.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/SplashScreen.scale-200.png rename to Examples/UAP.SimpleGraph/Assets/SplashScreen.scale-200.png diff --git a/Examples/METRO.SimpleGraph/Assets/StoreLogo.png b/Examples/UAP.SimpleGraph/Assets/StoreLogo.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/StoreLogo.png rename to Examples/UAP.SimpleGraph/Assets/StoreLogo.png diff --git a/Examples/UWA.SimpleGraph/Assets/newlogo_big.png b/Examples/UAP.SimpleGraph/Assets/newlogo_big.png similarity index 100% rename from Examples/UWA.SimpleGraph/Assets/newlogo_big.png rename to Examples/UAP.SimpleGraph/Assets/newlogo_big.png diff --git a/Examples/METRO.SimpleGraph/Assets/play.png b/Examples/UAP.SimpleGraph/Assets/play.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/play.png rename to Examples/UAP.SimpleGraph/Assets/play.png diff --git a/Examples/METRO.SimpleGraph/Assets/refresh.png b/Examples/UAP.SimpleGraph/Assets/refresh.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/refresh.png rename to Examples/UAP.SimpleGraph/Assets/refresh.png diff --git a/Examples/METRO.SimpleGraph/Assets/tr_grren.png b/Examples/UAP.SimpleGraph/Assets/tr_grren.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/tr_grren.png rename to Examples/UAP.SimpleGraph/Assets/tr_grren.png diff --git a/Examples/METRO.SimpleGraph/Assets/tr_red.png b/Examples/UAP.SimpleGraph/Assets/tr_red.png similarity index 100% rename from Examples/METRO.SimpleGraph/Assets/tr_red.png rename to Examples/UAP.SimpleGraph/Assets/tr_red.png diff --git a/Examples/METRO.SimpleGraph/Common/StandardStyles.xaml b/Examples/UAP.SimpleGraph/Common/StandardStyles.xaml similarity index 100% rename from Examples/METRO.SimpleGraph/Common/StandardStyles.xaml rename to Examples/UAP.SimpleGraph/Common/StandardStyles.xaml diff --git a/Examples/METRO.SimpleGraph/Common/templates.xaml b/Examples/UAP.SimpleGraph/Common/templates.xaml similarity index 100% rename from Examples/METRO.SimpleGraph/Common/templates.xaml rename to Examples/UAP.SimpleGraph/Common/templates.xaml diff --git a/Examples/METRO.SimpleGraph/Common/templates2.xaml b/Examples/UAP.SimpleGraph/Common/templates2.xaml similarity index 100% rename from Examples/METRO.SimpleGraph/Common/templates2.xaml rename to Examples/UAP.SimpleGraph/Common/templates2.xaml diff --git a/Examples/METRO.SimpleGraph/MainPage.xaml b/Examples/UAP.SimpleGraph/MainPage.xaml similarity index 90% rename from Examples/METRO.SimpleGraph/MainPage.xaml rename to Examples/UAP.SimpleGraph/MainPage.xaml index 32e6496e..d4be275b 100644 --- a/Examples/METRO.SimpleGraph/MainPage.xaml +++ b/Examples/UAP.SimpleGraph/MainPage.xaml @@ -1,16 +1,15 @@  - + @@ -18,7 +17,7 @@ - + diff --git a/Examples/METRO.SimpleGraph/MainPage.xaml.cs b/Examples/UAP.SimpleGraph/MainPage.xaml.cs similarity index 99% rename from Examples/METRO.SimpleGraph/MainPage.xaml.cs rename to Examples/UAP.SimpleGraph/MainPage.xaml.cs index bbb1ce4c..6200cb3a 100644 --- a/Examples/METRO.SimpleGraph/MainPage.xaml.cs +++ b/Examples/UAP.SimpleGraph/MainPage.xaml.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; @@ -12,10 +11,11 @@ using GraphX.PCL.Common.Enums; using GraphX.PCL.Logic.Algorithms.LayoutAlgorithms; using GraphX.PCL.Logic.Algorithms.OverlapRemoval; +using UAP.SimpleGraph.Models; // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 -namespace METRO.SimpleGraph +namespace UAP.SimpleGraph { /// /// An empty page that can be used on its own or navigated to within a Frame. diff --git a/Examples/METRO.SimpleGraph/MainPageDebug.xaml b/Examples/UAP.SimpleGraph/MainPageDebug.xaml similarity index 94% rename from Examples/METRO.SimpleGraph/MainPageDebug.xaml rename to Examples/UAP.SimpleGraph/MainPageDebug.xaml index b542e457..abbf9eff 100644 --- a/Examples/METRO.SimpleGraph/MainPageDebug.xaml +++ b/Examples/UAP.SimpleGraph/MainPageDebug.xaml @@ -1,11 +1,12 @@  @@ -16,7 +17,7 @@ - + diff --git a/Examples/METRO.SimpleGraph/MainPageDebug.xaml.cs b/Examples/UAP.SimpleGraph/MainPageDebug.xaml.cs similarity index 98% rename from Examples/METRO.SimpleGraph/MainPageDebug.xaml.cs rename to Examples/UAP.SimpleGraph/MainPageDebug.xaml.cs index c7a821e1..91199cee 100644 --- a/Examples/METRO.SimpleGraph/MainPageDebug.xaml.cs +++ b/Examples/UAP.SimpleGraph/MainPageDebug.xaml.cs @@ -4,19 +4,17 @@ using System.Linq; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Input; using Windows.UI.Xaml.Navigation; -using GraphX.Controls; using GraphX.Controls.Animations; using GraphX.Controls.Models; using GraphX.PCL.Common.Enums; using GraphX.PCL.Logic.Algorithms.LayoutAlgorithms; using GraphX.PCL.Logic.Algorithms.OverlapRemoval; -using METRO.SimpleGraph.Models; +using UAP.SimpleGraph.Models; // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238 -namespace METRO.SimpleGraph +namespace UAP.SimpleGraph { /// /// An empty page that can be used on its own or navigated to within a Frame. diff --git a/Examples/METRO.SimpleGraph/Models/CurvedEr.cs b/Examples/UAP.SimpleGraph/Models/CurvedEr.cs similarity index 97% rename from Examples/METRO.SimpleGraph/Models/CurvedEr.cs rename to Examples/UAP.SimpleGraph/Models/CurvedEr.cs index 00a5552f..af4a1488 100644 --- a/Examples/METRO.SimpleGraph/Models/CurvedEr.cs +++ b/Examples/UAP.SimpleGraph/Models/CurvedEr.cs @@ -1,13 +1,11 @@ using System; using System.Collections.Generic; using System.Threading; -using GraphX; using GraphX.Measure; using GraphX.PCL.Common.Interfaces; using GraphX.PCL.Logic.Algorithms.EdgeRouting; -using METRO.SimpleGraph; -namespace InteractiveGraph.Models +namespace UAP.SimpleGraph.Models { public class CurvedEr: EdgeRoutingAlgorithmBase { diff --git a/Examples/METRO.SimpleGraph/Models/CurvedErParameters.cs b/Examples/UAP.SimpleGraph/Models/CurvedErParameters.cs similarity index 90% rename from Examples/METRO.SimpleGraph/Models/CurvedErParameters.cs rename to Examples/UAP.SimpleGraph/Models/CurvedErParameters.cs index 13e620ff..d211ce51 100644 --- a/Examples/METRO.SimpleGraph/Models/CurvedErParameters.cs +++ b/Examples/UAP.SimpleGraph/Models/CurvedErParameters.cs @@ -1,6 +1,6 @@ using GraphX.PCL.Logic.Algorithms.EdgeRouting; -namespace InteractiveGraph.Models +namespace UAP.SimpleGraph.Models { public class CurvedErParameters: EdgeRoutingParameters { diff --git a/Examples/METRO.SimpleGraph/Models/DataEdge.cs b/Examples/UAP.SimpleGraph/Models/DataEdge.cs similarity index 98% rename from Examples/METRO.SimpleGraph/Models/DataEdge.cs rename to Examples/UAP.SimpleGraph/Models/DataEdge.cs index bf164fa9..08599a7e 100644 --- a/Examples/METRO.SimpleGraph/Models/DataEdge.cs +++ b/Examples/UAP.SimpleGraph/Models/DataEdge.cs @@ -1,8 +1,7 @@ using System.ComponentModel; -using GraphX; using GraphX.PCL.Common.Models; -namespace METRO.SimpleGraph +namespace UAP.SimpleGraph.Models { /* DataEdge is the data class for the edges. It contains all custom edge data specified by the user. * This class also must be derived from EdgeBase class that provides properties and methods mandatory for diff --git a/Examples/METRO.SimpleGraph/Models/DataVertex.cs b/Examples/UAP.SimpleGraph/Models/DataVertex.cs similarity index 98% rename from Examples/METRO.SimpleGraph/Models/DataVertex.cs rename to Examples/UAP.SimpleGraph/Models/DataVertex.cs index 550b30a5..ac95b667 100644 --- a/Examples/METRO.SimpleGraph/Models/DataVertex.cs +++ b/Examples/UAP.SimpleGraph/Models/DataVertex.cs @@ -1,8 +1,7 @@ using System.ComponentModel; -using GraphX; using GraphX.PCL.Common.Models; -namespace METRO.SimpleGraph +namespace UAP.SimpleGraph.Models { /* DataVertex is the data class for the vertices. It contains all custom vertex data specified by the user. * This class also must be derived from VertexBase that provides properties and methods mandatory for diff --git a/Examples/METRO.SimpleGraph/Models/DebugItems.cs b/Examples/UAP.SimpleGraph/Models/DebugItems.cs similarity index 73% rename from Examples/METRO.SimpleGraph/Models/DebugItems.cs rename to Examples/UAP.SimpleGraph/Models/DebugItems.cs index 9c419706..1f77b8bb 100644 --- a/Examples/METRO.SimpleGraph/Models/DebugItems.cs +++ b/Examples/UAP.SimpleGraph/Models/DebugItems.cs @@ -1,4 +1,4 @@ -namespace METRO.SimpleGraph.Models +namespace UAP.SimpleGraph.Models { public enum DebugItems { diff --git a/Examples/METRO.SimpleGraph/Models/GXLogicCoreExample.cs b/Examples/UAP.SimpleGraph/Models/GXLogicCoreExample.cs similarity index 89% rename from Examples/METRO.SimpleGraph/Models/GXLogicCoreExample.cs rename to Examples/UAP.SimpleGraph/Models/GXLogicCoreExample.cs index 33bdd289..7d4b8328 100644 --- a/Examples/METRO.SimpleGraph/Models/GXLogicCoreExample.cs +++ b/Examples/UAP.SimpleGraph/Models/GXLogicCoreExample.cs @@ -1,7 +1,7 @@ using GraphX.PCL.Logic.Models; using QuickGraph; -namespace METRO.SimpleGraph +namespace UAP.SimpleGraph.Models { /// /// Logics core object which contains all algorithms and logic settings diff --git a/Examples/METRO.SimpleGraph/Models/GraphAreaExample.cs b/Examples/UAP.SimpleGraph/Models/GraphAreaExample.cs similarity index 92% rename from Examples/METRO.SimpleGraph/Models/GraphAreaExample.cs rename to Examples/UAP.SimpleGraph/Models/GraphAreaExample.cs index e3152815..6ad022e9 100644 --- a/Examples/METRO.SimpleGraph/Models/GraphAreaExample.cs +++ b/Examples/UAP.SimpleGraph/Models/GraphAreaExample.cs @@ -1,8 +1,7 @@ -using GraphX; using GraphX.Controls; using QuickGraph; -namespace METRO.SimpleGraph +namespace UAP.SimpleGraph.Models { /// /// This is custom GraphArea representation using custom data types. diff --git a/Examples/METRO.SimpleGraph/Models/GraphExample.cs b/Examples/UAP.SimpleGraph/Models/GraphExample.cs similarity index 94% rename from Examples/METRO.SimpleGraph/Models/GraphExample.cs rename to Examples/UAP.SimpleGraph/Models/GraphExample.cs index 8fc216ae..376f3977 100644 --- a/Examples/METRO.SimpleGraph/Models/GraphExample.cs +++ b/Examples/UAP.SimpleGraph/Models/GraphExample.cs @@ -1,6 +1,6 @@ using QuickGraph; -namespace METRO.SimpleGraph +namespace UAP.SimpleGraph.Models { /// /// This is our custom data graph derived from BidirectionalGraph class using custom data types. diff --git a/Examples/METRO.SimpleGraph/Models/MouseOverScaleAnimation.cs b/Examples/UAP.SimpleGraph/Models/MouseOverScaleAnimation.cs similarity index 98% rename from Examples/METRO.SimpleGraph/Models/MouseOverScaleAnimation.cs rename to Examples/UAP.SimpleGraph/Models/MouseOverScaleAnimation.cs index 6fb03090..16477580 100644 --- a/Examples/METRO.SimpleGraph/Models/MouseOverScaleAnimation.cs +++ b/Examples/UAP.SimpleGraph/Models/MouseOverScaleAnimation.cs @@ -1,13 +1,12 @@ -using Windows.Foundation; +using System; +using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Animation; -using GraphX; -using System; using GraphX.Controls; using GraphX.Controls.Animations; -namespace METRO.SimpleGraph +namespace UAP.SimpleGraph.Models { public sealed class MouseOverAnimation : IBidirectionalControlAnimation { diff --git a/Examples/UWA.SimpleGraph/Package.appxmanifest b/Examples/UAP.SimpleGraph/Package.appxmanifest similarity index 87% rename from Examples/UWA.SimpleGraph/Package.appxmanifest rename to Examples/UAP.SimpleGraph/Package.appxmanifest index 72e87f45..d9e4dafb 100644 --- a/Examples/UWA.SimpleGraph/Package.appxmanifest +++ b/Examples/UAP.SimpleGraph/Package.appxmanifest @@ -3,7 +3,7 @@ - UWA.SimpleGraph + UAP.SimpleGraph panth Assets/50.png @@ -14,8 +14,8 @@ - - + + diff --git a/Examples/UWA.SimpleGraph/Properties/AssemblyInfo.cs b/Examples/UAP.SimpleGraph/Properties/AssemblyInfo.cs similarity index 100% rename from Examples/UWA.SimpleGraph/Properties/AssemblyInfo.cs rename to Examples/UAP.SimpleGraph/Properties/AssemblyInfo.cs diff --git a/Examples/UWA.SimpleGraph/Properties/Default.rd.xml b/Examples/UAP.SimpleGraph/Properties/Default.rd.xml similarity index 100% rename from Examples/UWA.SimpleGraph/Properties/Default.rd.xml rename to Examples/UAP.SimpleGraph/Properties/Default.rd.xml diff --git a/Examples/UWA.SimpleGraph/UWA.SimpleGraph.csproj b/Examples/UAP.SimpleGraph/UAP.SimpleGraph.csproj similarity index 67% rename from Examples/UWA.SimpleGraph/UWA.SimpleGraph.csproj rename to Examples/UAP.SimpleGraph/UAP.SimpleGraph.csproj index 1c809225..54f4c03e 100644 --- a/Examples/UWA.SimpleGraph/UWA.SimpleGraph.csproj +++ b/Examples/UAP.SimpleGraph/UAP.SimpleGraph.csproj @@ -7,11 +7,11 @@ {51C7122B-AAD1-4C49-B2E9-1B09B367952F} AppContainerExe Properties - METRO.SimpleGraph - UWA.SimpleGraph + UAP.SimpleGraph + UAP.SimpleGraph en-US UAP - 10.0.10586.0 + 10.0.14393.0 10.0.10586.0 14 512 @@ -91,47 +91,26 @@ - - - MainPage.xaml.cs + + App.xaml + + MainPage.xaml - - MainPageDebug.xaml.cs + MainPageDebug.xaml - - Models\CurvedEr.cs - - - Models\CurvedErParameters.cs - - - Models\DataEdge.cs - - - Models\DataVertex.cs - - - Models\DebugItems.cs - - - Models\GraphAreaExample.cs - - - Models\GraphExample.cs - - - Models\GXLogicCoreExample.cs - - - Models\MouseOverScaleAnimation.cs - - - App.xaml - + + + + + + + + + @@ -140,37 +119,20 @@ - - Assets\Logo.png - - - Assets\MidLogo.png - - - Assets\play.png - - - Assets\refresh.png - - - Assets\SmallLogo.png - - - Assets\SplashScreen.png - - - Assets\StoreLogo.png - - - Assets\tr_grren.png - - - Assets\tr_red.png - + + + + + + + + + + @@ -178,37 +140,28 @@ MSBuild:Compile Designer - - Common\StandardStyles.xaml + MSBuild:Compile Designer - - Common\templates.xaml + MSBuild:Compile Designer - - Common\templates2.xaml + MSBuild:Compile Designer - - MainPage.xaml + MSBuild:Compile Designer - - MainPageDebug.xaml + MSBuild:Compile Designer - - {66f33708-c1c7-4385-8235-7201784d184c} - GraphX.METRO.Controls - {3644d44b-dec0-4b65-bba0-c68e34821aae} GraphX.PCL.Common @@ -217,6 +170,10 @@ {a30d218b-aaa4-483a-99f7-eaeb1b8b4610} GraphX.PCL.Logic + + {4bebc41e-2710-4613-80b1-198e08d10619} + GraphX.UAP.Controls + @@ -226,7 +183,8 @@ true - UWA.SimpleGraph_TemporaryKey.pfx + + @@ -352,8 +353,8 @@ True - - 12.0 + + 14.0 true diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/Converters/DoubleToLog10Converter.cs b/GraphX.UAP.Controls/Controls/ZoomControl/Converters/DoubleToLog10Converter.cs new file mode 100644 index 00000000..4088bde2 --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/Converters/DoubleToLog10Converter.cs @@ -0,0 +1,26 @@ +using System; +using Windows.UI.Xaml.Data; + +namespace GraphX.Controls +{ + public sealed class DoubleToLog10Converter : IValueConverter + { + #region IValueConverter Members + + public object Convert(object value, Type targetType, object parameter, string language) + { + var val = Math.Log10((double)value); + return double.IsNegativeInfinity(val) ? 0 : val; + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + var val = Math.Pow(10, (double)value); + return double.IsNegativeInfinity(val) ? 0 : val; + } + + #endregion + + + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/Converters/EqualityToBooleanConverter.cs b/GraphX.UAP.Controls/Controls/ZoomControl/Converters/EqualityToBooleanConverter.cs new file mode 100644 index 00000000..15969238 --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/Converters/EqualityToBooleanConverter.cs @@ -0,0 +1,22 @@ +using System; +using Windows.UI.Xaml.Data; + +namespace GraphX.Controls +{ + public sealed class EqualityToBooleanConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string language) + { + return Equals(value, parameter); + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + if ((bool)value) + return parameter; + + //it's false, so don't bind it back + return null; + } + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/Converters/RoundedValueConverter.cs b/GraphX.UAP.Controls/Controls/ZoomControl/Converters/RoundedValueConverter.cs new file mode 100644 index 00000000..25d796c3 --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/Converters/RoundedValueConverter.cs @@ -0,0 +1,64 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using Windows.Foundation; +using Windows.UI.Xaml.Data; + +namespace GraphX.Controls +{ + public class RoundedValueConverter : IValueConverter + { + #region Precision Property + + public int Precision + { + get + { + return _precision; + } + set + { + _precision = value; + } + } + + private int _precision = 0; + + #endregion + + public object Convert(object value, Type targetType, object parameter, string language) + { + if( value is double ) + { + return Math.Round( ( double )value, _precision ); + } + else if( value is Point ) + { + return new Point( Math.Round( ( ( Point )value ).X, _precision ), Math.Round( ( ( Point )value ).Y, _precision ) ); + } + else + { + return value; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + return value; + } + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/Converters/VisibilityToBoolConverter.cs b/GraphX.UAP.Controls/Controls/ZoomControl/Converters/VisibilityToBoolConverter.cs new file mode 100644 index 00000000..ce7a4720 --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/Converters/VisibilityToBoolConverter.cs @@ -0,0 +1,55 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Data; + +namespace GraphX.Controls + { + [Bindable] + public sealed class VisibilityToBoolConverter : IValueConverter + { + public bool Inverted { get; set; } + public bool Not { get; set; } + + public object Convert(object value, Type targetType, object parameter, string language) + { + return this.Inverted ? this.BoolToVisibility( value ) : this.VisibilityToBool( value ); + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + return this.Inverted ? this.VisibilityToBool( value ) : this.BoolToVisibility( value ); + } + + private object VisibilityToBool( object value ) + { + if( !( value is Visibility ) ) + throw new InvalidOperationException( "SuppliedValueWasNotVisibility" ); + + return ( ( ( Visibility )value ) == Visibility.Visible ) ^ Not; + } + + private object BoolToVisibility( object value ) + { + if( !( value is bool ) ) + throw new InvalidOperationException( "SuppliedValueWasNotBool" ); + + return ( ( bool )value ^ Not ) ? Visibility.Visible : Visibility.Collapsed; + } + } + } diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/Helpers/DoubleHelper.cs b/GraphX.UAP.Controls/Controls/ZoomControl/Helpers/DoubleHelper.cs new file mode 100644 index 00000000..88c8ad16 --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/Helpers/DoubleHelper.cs @@ -0,0 +1,94 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Runtime.InteropServices; +using GraphX.Measure; +using Point = Windows.Foundation.Point; +using Rect = Windows.Foundation.Rect; +using Size = Windows.Foundation.Size; + +namespace GraphX.Controls +{ + internal static class DoubleHelper + { + public static bool AreVirtuallyEqual( double d1, double d2 ) + { + if( double.IsPositiveInfinity( d1 ) ) + return double.IsPositiveInfinity( d2 ); + + if( double.IsNegativeInfinity( d1 ) ) + return double.IsNegativeInfinity( d2 ); + + if( IsNaN( d1 ) ) + return IsNaN( d2 ); + + var n = d1 - d2; + var d = ( Math.Abs( d1 ) + Math.Abs( d2 ) + 10 ) * 1.0e-15; + return ( -d < n ) && ( d > n ); + } + + public static bool AreVirtuallyEqual( Size s1, Size s2 ) + { + return ( AreVirtuallyEqual( s1.Width, s2.Width ) + && AreVirtuallyEqual( s1.Height, s2.Height ) ); + } + + public static bool AreVirtuallyEqual( Point p1, Point p2 ) + { + return ( AreVirtuallyEqual( p1.X, p2.X ) + && AreVirtuallyEqual( p1.Y, p2.Y ) ); + } + + public static bool AreVirtuallyEqual( Rect r1, Rect r2 ) + { + return ( AreVirtuallyEqual( r1.TopLeft(), r2.TopLeft() ) + && AreVirtuallyEqual( r1.BottomRight(), r2.BottomRight() ) ); + } + + public static bool AreVirtuallyEqual( Vector v1, Vector v2 ) + { + return ( AreVirtuallyEqual( v1.X, v2.X ) + && AreVirtuallyEqual( v1.Y, v2.Y ) ); + } + + + public static bool IsNaN( double value ) + { + // used reflector to borrow the high performance IsNan function + // from the WPF MS.Internal namespace + var t = new NanUnion {DoubleValue = value}; + + var exp = t.UintValue & 0xfff0000000000000; + var man = t.UintValue & 0x000fffffffffffff; + + return ( exp == 0x7ff0000000000000 || exp == 0xfff0000000000000 ) && ( man != 0 ); + } + + #region NanUnion Nested Types + + [StructLayout( LayoutKind.Explicit )] + private struct NanUnion + { + [FieldOffset( 0 )] + internal double DoubleValue; + [FieldOffset( 0 )] + internal UInt64 UintValue; + } + + #endregion + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/Helpers/PointHelper.cs b/GraphX.UAP.Controls/Controls/ZoomControl/Helpers/PointHelper.cs new file mode 100644 index 00000000..147a1408 --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/Helpers/PointHelper.cs @@ -0,0 +1,42 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using Windows.Foundation; + +namespace GraphX.Controls +{ + internal static class PointHelper + { + public static double DistanceBetween( Point p1, Point p2 ) + { + return Math.Sqrt( Math.Pow( p1.X - p2.X, 2 ) + Math.Pow( p1.Y - p2.Y, 2 ) ); + } + + public static Point Empty + { + get + { + return new Point( double.NaN, double.NaN ); + } + } + + public static bool IsEmpty( Point point ) + { + return DoubleHelper.IsNaN( point.X ) && DoubleHelper.IsNaN( point.Y ); + } + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/Helpers/VisualTreeHelperEx.cs b/GraphX.UAP.Controls/Controls/ZoomControl/Helpers/VisualTreeHelperEx.cs new file mode 100644 index 00000000..2ed5b64e --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/Helpers/VisualTreeHelperEx.cs @@ -0,0 +1,157 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Collections.Generic; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; + +namespace GraphX.Controls +{ + public static class VisualTreeHelperEx + { + public static DependencyObject FindAncestorByType(DependencyObject element, Type type, bool specificTypeOnly) + { + if (element == null) + return null; + + if (element.GetType() == type) + return element; + + return FindAncestorByType(VisualTreeHelper.GetParent(element), type, specificTypeOnly); + } + + public static T FindAncestorByType(DependencyObject depObj) where T : DependencyObject + { + if (depObj == null) + { + return default(T); + } + if (depObj is T) + { + return (T) depObj; + } + + T parent = default(T); + + parent = FindAncestorByType(VisualTreeHelper.GetParent(depObj)); + + return parent; + } + + public static UIElement FindDescendantByName(UIElement element, string name) + { + if (element != null && (element is FrameworkElement) && (element as FrameworkElement).Name == name) + return element; + + UIElement foundElement = null; + if (element is FrameworkElement) + (element as FrameworkElement).InvalidateArrange(); + + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) + { + var visual = VisualTreeHelper.GetChild(element, i) as UIElement; + foundElement = FindDescendantByName(visual, name); + if (foundElement != null) + break; + } + + return foundElement; + } + + public static UIElement FindDescendantByType(UIElement element, Type type) + { + return FindDescendantByType(element, type, true); + } + + public static UIElement FindDescendantByType(UIElement element, Type type, bool specificTypeOnly) + { + if (element == null) + return null; + + if (element.GetType() == type) + return element; + + UIElement foundElement = null; + if (element is FrameworkElement) + (element as FrameworkElement).InvalidateArrange(); + + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) + { + var visual = VisualTreeHelper.GetChild(element, i) as UIElement; + foundElement = FindDescendantByType(visual, type, specificTypeOnly); + if (foundElement != null) + break; + } + + return foundElement; + } + + public static T FindDescendantByType(UIElement element) where T : UIElement + { + UIElement temp = FindDescendantByType(element, typeof (T)); + + return (T) temp; + } + + public static UIElement FindDescendantWithPropertyValue(UIElement element, + DependencyProperty dp, object value) + { + if (element == null) + return null; + + if (element.GetValue(dp).Equals(value)) + return element; + + UIElement foundElement = null; + if (element is FrameworkElement) + (element as FrameworkElement).InvalidateArrange(); + + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) + { + var visual = VisualTreeHelper.GetChild(element, i) as UIElement; + foundElement = FindDescendantWithPropertyValue(visual, dp, value); + if (foundElement != null) + break; + } + + return foundElement; + } + + #region Find descendants of type + + public static IEnumerable FindDescendantsOfType(this UIElement element) where T : class + { + if (element == null) yield break; + if (element is T) + yield return element as T; + + var frameworkElement = element as FrameworkElement; + if (frameworkElement != null) + frameworkElement.InvalidateArrange(); + + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) + { + var visual = VisualTreeHelper.GetChild(element, i) as UIElement; + if (visual == null) continue; + foreach (var item in visual.FindDescendantsOfType()) + yield return item; + } + } + + #endregion + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/AreaSelectedEventArgs.cs b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/AreaSelectedEventArgs.cs new file mode 100644 index 00000000..ee26582a --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/AreaSelectedEventArgs.cs @@ -0,0 +1,19 @@ +using System; +using Windows.Foundation; + +namespace GraphX.Controls +{ + public class AreaSelectedEventArgs : EventArgs + { + /// + /// Rectangle data in coordinates of content object + /// + public Rect Rectangle { get; set; } + + public AreaSelectedEventArgs(Rect rec) + : base() + { + Rectangle = rec; + } + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/AreaSelectedEventHandler.cs b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/AreaSelectedEventHandler.cs new file mode 100644 index 00000000..3fefb99c --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/AreaSelectedEventHandler.cs @@ -0,0 +1,4 @@ +namespace GraphX.Controls +{ + public delegate void AreaSelectedEventHandler(object sender, AreaSelectedEventArgs args); +} \ No newline at end of file diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ContentSizeChangedHandler.cs b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ContentSizeChangedHandler.cs new file mode 100644 index 00000000..d4b0f59e --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ContentSizeChangedHandler.cs @@ -0,0 +1,6 @@ +using Windows.Foundation; + +namespace GraphX.Controls +{ + public delegate void ContentSizeChangedHandler(object sender, Size newSize); +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/MouseWheelZoomingMode.cs b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/MouseWheelZoomingMode.cs new file mode 100644 index 00000000..ff8de5b0 --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/MouseWheelZoomingMode.cs @@ -0,0 +1,8 @@ +namespace GraphX.Controls +{ + public enum MouseWheelZoomingMode + { + Positional = 0, + Absolute + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ZoomControlModes.cs b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ZoomControlModes.cs new file mode 100644 index 00000000..4700483f --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ZoomControlModes.cs @@ -0,0 +1,20 @@ +namespace GraphX.Controls +{ + public enum ZoomControlModes + { + /// + /// The content should fill the given space. + /// + Fill, + + /// + /// The content will be represented in its original size. + /// + Original, + + /// + /// The content will be zoomed with a custom percent. + /// + Custom + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ZoomViewModifierMode.cs b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ZoomViewModifierMode.cs new file mode 100644 index 00000000..36db13c5 --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/SupportClasses/ZoomViewModifierMode.cs @@ -0,0 +1,30 @@ +namespace GraphX.Controls +{ + public enum ZoomViewModifierMode + { + /// + /// It does nothing at all. + /// + None, + + /// + /// You can pan the view with the mouse in this mode. + /// + Pan, + + /// + /// You can zoom in with the mouse in this mode. + /// + ZoomIn, + + /// + /// You can zoom out with the mouse in this mode. + /// + ZoomOut, + + /// + /// Zooming after the user has been selected the zooming box. + /// + ZoomBox + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/ZoomContentPresenter.cs b/GraphX.UAP.Controls/Controls/ZoomControl/ZoomContentPresenter.cs new file mode 100644 index 00000000..3ff94303 --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/ZoomContentPresenter.cs @@ -0,0 +1,71 @@ +using System.ComponentModel; +using Windows.Foundation; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Media; + +namespace GraphX.Controls +{ + [Bindable] + public sealed class ZCP : ContentPresenter, INotifyPropertyChanged + { + public event ContentSizeChangedHandler ContentSizeChanged; + + private Size _contentSize; + + /* public Point ContentTopLeft { get; private set; } + public Point ContentBottomRight { get; private set; } + public Point ContentActualSize { get; private set; } + */ + public Size ContentSize + { + get { return _contentSize; } + private set { + if (value == _contentSize) + return; + + _contentSize = value; + if (ContentSizeChanged != null) + ContentSizeChanged(this, _contentSize); + } + } + + protected override Size MeasureOverride(Size constraint) + { + base.MeasureOverride(new Size(double.PositiveInfinity, double.PositiveInfinity)); + var max = 1000000000; + var x = double.IsInfinity(constraint.Width) ? max : constraint.Width; + var y = double.IsInfinity(constraint.Height) ? max : constraint.Height; + return new Size(x, y); + } + + protected override Size ArrangeOverride(Size arrangeBounds) + { + UIElement child = Content != null + ? VisualTreeHelper.GetChild(this, 0) as UIElement + : null; + if (child == null) + return arrangeBounds; + + //set the ContentSize + ContentSize = child.DesiredSize; + child.Arrange(new Rect(new Point(),child.DesiredSize)); + /* if (child is GraphAreaBase) + { + ContentBottomRight = (child as GraphAreaBase).BottomRight; + ContentTopLeft = (child as GraphAreaBase).TopLeft; + ContentActualSize = new Point((child as GraphAreaBase).ActualWidth, (child as GraphAreaBase).ActualHeight); + }*/ + + return arrangeBounds; + } + + public event PropertyChangedEventHandler PropertyChanged; + public void OnPropertyChanged(string name) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(name)); + } + } +} diff --git a/GraphX.UAP.Controls/Controls/ZoomControl/ZoomControl.cs b/GraphX.UAP.Controls/Controls/ZoomControl/ZoomControl.cs new file mode 100644 index 00000000..904aa92f --- /dev/null +++ b/GraphX.UAP.Controls/Controls/ZoomControl/ZoomControl.cs @@ -0,0 +1,911 @@ +using System; +using System.ComponentModel; +using Windows.ApplicationModel; +using Windows.System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Animation; +using GraphX.Measure; +using GraphX.Controls.Models; +using Point = Windows.Foundation.Point; +using Rect = Windows.Foundation.Rect; +using Thickness = Windows.UI.Xaml.Thickness; + +namespace GraphX.Controls +{ + [TemplatePart(Name = PART_PRESENTER, Type = typeof(ZCP))] + public class ZoomControl : ContentControl, IZoomControl, INotifyPropertyChanged + { + + #region Properties + + #region ViewFinderVisibility Attached Property + + public static readonly DependencyProperty ViewFinderVisibilityProperty = + DependencyProperty.RegisterAttached("ViewFinderVisibility", typeof(Visibility), typeof(ZoomControl), + new PropertyMetadata(Visibility.Visible)); + + public static Visibility GetViewFinderVisibility(DependencyObject d) + { + return (Visibility)(d.GetValue(ViewFinderVisibilityProperty)); + } + + public static void SetViewFinderVisibility(DependencyObject d, Visibility value) + { + d.SetValue(ViewFinderVisibilityProperty, value); + } + + #endregion + + public DelegateCommand ZoomToFillCommand { get { return new DelegateCommand((o) => ZoomToFill());} } + + public DelegateCommand CenterToContentCommand { get { return new DelegateCommand((o) => CenterContent());} } + + /// + /// Gets or sets if animation should be disabled + /// + public bool IsAnimationDisabled { get; set; } + + /// + /// Use Ctrl key to zoom with mouse wheel or without it + /// + public bool UseCtrlForMouseWheel { get; set; } + + /// + /// Gets or sets absolute zooming on mouse wheel which doesn't depend on mouse position + /// + public MouseWheelZoomingMode MouseWheelZoomingMode { get; set; } + + /// + /// Fires when area has been selected using SelectionModifiers + /// + public event AreaSelectedEventHandler AreaSelected; + + private void OnAreaSelected(Rect selection) + { + if (AreaSelected != null) + AreaSelected(this, new AreaSelectedEventArgs(selection)); + } + + private const string PART_PRESENTER = "PART_Presenter"; + + public static readonly DependencyProperty HideZoomProperty = + DependencyProperty.Register("HideZoom", typeof(Visibility), typeof(ZoomControl), + new PropertyMetadata(Visibility.Visible)); + + public static readonly DependencyProperty AnimationLengthProperty = + DependencyProperty.Register("AnimationLength", typeof(TimeSpan), typeof(ZoomControl), + new PropertyMetadata(TimeSpan.FromMilliseconds(500))); + + public static readonly DependencyProperty MaximumZoomStepProperty = + DependencyProperty.Register("MaximumZoomStep", typeof(double), typeof(ZoomControl), + new PropertyMetadata(5.0)); + + public static readonly DependencyProperty MaxZoomProperty = + DependencyProperty.Register("MaxZoom", typeof(double), typeof(ZoomControl), new PropertyMetadata(100.0)); + + public static readonly DependencyProperty MinZoomProperty = + DependencyProperty.Register("MinZoom", typeof(double), typeof(ZoomControl), new PropertyMetadata(0.01)); + + public static readonly DependencyProperty ModeProperty = + DependencyProperty.Register("Mode", typeof(ZoomControlModes), typeof(ZoomControl), + new PropertyMetadata(ZoomControlModes.Custom, Mode_PropertyChanged)); + + private static void Mode_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var zc = (ZoomControl)d; + var mode = (ZoomControlModes)e.NewValue; + switch (mode) + { + case ZoomControlModes.Fill: + zc.DoZoomToFill(); + break; + case ZoomControlModes.Original: + zc.DoZoomToOriginal(); + break; + case ZoomControlModes.Custom: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + public static readonly DependencyProperty ModifierModeProperty = + DependencyProperty.Register("ModifierMode", typeof(ZoomViewModifierMode), typeof(ZoomControl), + new PropertyMetadata(ZoomViewModifierMode.None)); + + #region TranslateX TranslateY + public static readonly DependencyProperty TranslateXProperty = + DependencyProperty.Register("TranslateX", typeof(double), typeof(ZoomControl), + new PropertyMetadata(0.0, TranslateX_PropertyChanged)); + + public static readonly DependencyProperty TranslateYProperty = + DependencyProperty.Register("TranslateY", typeof(double), typeof(ZoomControl), + new PropertyMetadata(0.0, TranslateY_PropertyChanged)); + + + private static void TranslateX_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var zc = (ZoomControl)d; + if (zc._translateTransform == null) + return; + zc._translateTransform.X = (double)e.NewValue; + if (!zc._isZooming) + zc.Mode = ZoomControlModes.Custom; + zc.OnPropertyChanged("Presenter"); + zc.Presenter.OnPropertyChanged("RenderTransform"); + } + + private static void TranslateY_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var zc = (ZoomControl)d; + if (zc._translateTransform == null) + return; + zc._translateTransform.Y = (double)e.NewValue; + if (!zc._isZooming) + zc.Mode = ZoomControlModes.Custom; + zc.OnPropertyChanged("Presenter"); + zc.Presenter.OnPropertyChanged("RenderTransform"); + + } + + #endregion + + public static readonly DependencyProperty ZoomBoxBackgroundProperty = + DependencyProperty.Register("ZoomBoxBackground", typeof(Brush), typeof(ZoomControl), + new PropertyMetadata(null)); + + + public static readonly DependencyProperty ZoomBoxBorderBrushProperty = + DependencyProperty.Register("ZoomBoxBorderBrush", typeof(Brush), typeof(ZoomControl), + new PropertyMetadata(null)); + + + public static readonly DependencyProperty ZoomBoxBorderThicknessProperty = + DependencyProperty.Register("ZoomBoxBorderThickness", typeof(Thickness), typeof(ZoomControl), + new PropertyMetadata(null)); + + + public static readonly DependencyProperty ZoomBoxOpacityProperty = + DependencyProperty.Register("ZoomBoxOpacity", typeof(double), typeof(ZoomControl), + new PropertyMetadata(0.5)); + + + public static readonly DependencyProperty ZoomBoxProperty = + DependencyProperty.Register("ZoomBox", typeof(Rect), typeof(ZoomControl), + new PropertyMetadata(new Rect())); + + public static readonly DependencyProperty ZoomSensitivityProperty = + DependencyProperty.Register("ZoomSensitivity", typeof(double), typeof(ZoomControl), + new PropertyMetadata(100.0)); + + #region Zoom + public static readonly DependencyProperty ZoomProperty = + DependencyProperty.Register("Zoom", typeof(double), typeof(ZoomControl), + new PropertyMetadata(1.0, Zoom_PropertyChanged)); + + private static void Zoom_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var zc = (ZoomControl)d; + + if (zc._scaleTransform == null) + return; + + var zoom = (double)e.NewValue; + zc._scaleTransform.ScaleX = zoom; + zc._scaleTransform.ScaleY = zoom; + /* if (!zc._isZooming) + { + var delta = (double)e.NewValue / (double)e.OldValue; + zc.TranslateX *= delta; + zc.TranslateY *= delta; + zc.Mode = ZoomControlModes.Custom; + }*/ + zc.OnPropertyChanged("Presenter"); + zc.Presenter.OnPropertyChanged("RenderTransform"); + zc.OnPropertyChanged("Zoom"); + + //VF zc.UpdateViewport(); + } + #endregion + + private Point _mouseDownPos; + private ZCP _presenter; + + /// + /// Applied to the presenter. + /// + private ScaleTransform _scaleTransform; + private Vector _startTranslate; + private TransformGroup _transformGroup; + + /// + /// Applied to the scrollviewer. + /// + private TranslateTransform _translateTransform; + + private Storyboard _currentZoomAnimation; + + private bool _isZooming; + + public Brush ZoomBoxBackground + { + get { return (Brush)GetValue(ZoomBoxBackgroundProperty); } + set { SetValue(ZoomBoxBackgroundProperty, value); } + } + + public Brush ZoomBoxBorderBrush + { + get { return (Brush)GetValue(ZoomBoxBorderBrushProperty); } + set { SetValue(ZoomBoxBorderBrushProperty, value); } + } + + public Thickness ZoomBoxBorderThickness + { + get { return (Thickness)GetValue(ZoomBoxBorderThicknessProperty); } + set { SetValue(ZoomBoxBorderThicknessProperty, value); } + } + + public double ZoomBoxOpacity + { + get { return (double)GetValue(ZoomBoxOpacityProperty); } + set { SetValue(ZoomBoxOpacityProperty, value); } + } + + public Rect ZoomBox + { + get { return (Rect)GetValue(ZoomBoxProperty); } + set { SetValue(ZoomBoxProperty, value); } + } + + public Point OrigoPosition + { + get { return new Point(ActualWidth / 2, ActualHeight / 2); } + } + + private Storyboard _lastTranslateXAnimation; + public double TranslateX + { + get + { + var value = (double)GetValue(TranslateXProperty); + return double.IsNaN(value) ? 0 : value; + } + set + { + if (_lastTranslateXAnimation != null) + { + //_lastTranslateXAnimation.SkipToFill(); + _lastTranslateXAnimation.Stop(); + //SetValue(TranslateXProperty, TranslateX); + } + _lastTranslateXAnimation = AnimationHelper.CreateDoubleAnimation(TranslateX, value, 0, "TranslateX", this, null, (o, e) => SetValue(TranslateXProperty, value)); + // ((DoubleAnimation)_lastTranslateXAnimation.Children[0]).EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseOut }; + _lastTranslateXAnimation.Begin(); + //SetValue(TranslateXProperty, value); + } + } + + private Storyboard _lastTranslateYAnimation; + public double TranslateY + { + get { + var value = (double)GetValue(TranslateYProperty); + return double.IsNaN(value) ? 0 : value; + } + set + { + if (_lastTranslateYAnimation != null) + { + //_lastTranslateYAnimation.SkipToFill(); + _lastTranslateYAnimation.Stop(); + //SetValue(TranslateYProperty, TranslateY); + } + + _lastTranslateYAnimation = AnimationHelper.CreateDoubleAnimation(TranslateY, value, 0, "TranslateY", this, null, (o, e) => SetValue(TranslateYProperty, value)); + //((DoubleAnimation)_lastTranslateYAnimation.Children[0]).EasingFunction = new ExponentialEase { EasingMode = EasingMode.EaseOut }; + _lastTranslateYAnimation.Begin(); + //SetValue(TranslateYProperty, value); + } + } + + public TimeSpan AnimationLength + { + get { return (TimeSpan)GetValue(AnimationLengthProperty); } + set { SetValue(AnimationLengthProperty, value); } + } + + public double MinZoom + { + get { return (double)GetValue(MinZoomProperty); } + set { SetValue(MinZoomProperty, value); } + } + + public double MaxZoom + { + get { return (double)GetValue(MaxZoomProperty); } + set { SetValue(MaxZoomProperty, value); } + } + + public double MaximumZoomStep + { + get { return (double)GetValue(MaximumZoomStepProperty); } + set { SetValue(MaximumZoomStepProperty, value); } + } + + public double ZoomSensitivity + { + get { return (double)GetValue(ZoomSensitivityProperty); } + set { SetValue(ZoomSensitivityProperty, value); } + } + + public double Zoom + { + get { return (double)GetValue(ZoomProperty); } + set + { + if (value == (double)GetValue(ZoomProperty)) + return; + //TODO BeginAnimation(ZoomProperty, null); + SetValue(ZoomProperty, value); + } + } + + /// + /// Gets content object as UIElement + /// + public UIElement ContentVisual + { + get + { + return Content as UIElement; + } + } + /// + /// Gets content as ITrackableContent like GraphArea + /// + public ITrackableContent TrackableContent + { + get + { + return Content as ITrackableContent; + } + } + + bool _isga; + /// + /// Is loaded content represents ITrackableContent object + /// + public bool IsContentTrackable + { + get { return _isga; } + } + + + public ZCP Presenter + { + get { return _presenter; } + set + { + _presenter = value; + if (_presenter == null) + return; + + //add the ScaleTransform to the presenter + _transformGroup = new TransformGroup(); + _scaleTransform = new ScaleTransform(); + _translateTransform = new TranslateTransform(); + _transformGroup.Children.Add(_scaleTransform); + _transformGroup.Children.Add(_translateTransform); + _presenter.RenderTransform = _transformGroup; + _presenter.RenderTransformOrigin = new Point(0.5, 0.5); + } + } + + public UIElement PresenterVisual + { + get { return Presenter; } + } + + /// + /// Gets or sets the active modifier mode. + /// + public ZoomViewModifierMode ModifierMode + { + get { return (ZoomViewModifierMode)GetValue(ModifierModeProperty); } + set { SetValue(ModifierModeProperty, value); } + } + + /// + /// Gets or sets the mode of the zoom control. + /// + public ZoomControlModes Mode + { + get { return (ZoomControlModes)GetValue(ModeProperty); } + set { SetValue(ModeProperty, value); } + } + + #endregion + + public ZoomControl() + { + DefaultStyleKey = typeof (ZoomControl); + if (DesignMode.DesignModeEnabled) + { + //Mode = ZoomControlModes.Fill; + + Loaded += ZoomControl_DesignerLoaded; + } + else + { + PointerWheelChanged += ZoomControl_MouseWheel; + PointerPressed += ZoomControl_PreviewMouseDown; + PointerReleased += ZoomControl_MouseUp; + UseCtrlForMouseWheel = true; + Loaded += ZoomControl_Loaded; + } + + } + + void ZoomControl_Loaded(object sender, RoutedEventArgs e) + { + SetValue(ZoomProperty, Zoom); + } + + void ZoomControl_DesignerLoaded(object sender, RoutedEventArgs e) + { + Zoom = 1.0; + } + + #region ContentChanged + protected override void OnContentChanged(object oldContent, object newContent) + { + if (oldContent != null) + { + var old = oldContent as ITrackableContent; + if (old != null) old.ContentSizeChanged -= Content_ContentSizeChanged; + } + if (newContent != null) + { + //VF UpdateViewFinderDisplayContentBounds(); + //VF UpdateViewport(); + var newc = newContent as ITrackableContent; + if (newc != null) + { + _isga = true; + newc.ContentSizeChanged += Content_ContentSizeChanged; + } + else _isga = false; + } + + base.OnContentChanged(oldContent, newContent); + } + + void Content_ContentSizeChanged(object sender, ContentSizeChangedEventArgs e) + { + //VF UpdateViewFinderDisplayContentBounds(); + //VF UpdateViewport(); + } + #endregion + + #region Mouse controls + + /// + /// Converts screen rectangle area to rectangle in content coordinate space according to scale and translation + /// + /// Screen rectangle data + public Rect ToContentRectangle(Rect screenRectangle) + { + var transformer = TransformToVisual(ContentVisual); + var tl = transformer.TransformPoint(new Point(screenRectangle.X, screenRectangle.Y)); + var br = transformer.TransformPoint(new Point(screenRectangle.Right, screenRectangle.Bottom)); + return new Rect(tl.X, tl.Y, Math.Abs(Math.Abs(br.X) - Math.Abs(tl.X)), Math.Abs(Math.Abs(br.Y) - Math.Abs(tl.Y))); + } + + private void ZoomControl_MouseWheel(object sender, PointerRoutedEventArgs e) + { + + var handle = (e.KeyModifiers == VirtualKeyModifiers.Control && ModifierMode == ZoomViewModifierMode.None) || UseCtrlForMouseWheel; + if (!handle) return; + + e.Handled = true; + //var origoPosition = new Point(ActualWidth / 2, ActualHeight / 2); + //var mousePosition = e.GetCurrentPoint(this).Position; + MouseWheelAction(e.GetCurrentPoint(this).Properties.MouseWheelDelta, e.GetCurrentPoint(this).Position); + } + + /// + /// Defines action on mousewheel + /// + /// + /// + protected virtual void MouseWheelAction(int delta, Point mousePosition) + { + var origoPosition = OrigoPosition; + + DoZoom( + Math.Max(1 / MaximumZoomStep, Math.Min(MaximumZoomStep, (Math.Abs(delta) / 10000.0 * ZoomSensitivity + 1))), + delta < 0 ? -1 : 1, + origoPosition, + MouseWheelZoomingMode == MouseWheelZoomingMode.Absolute ? OrigoPosition : mousePosition, + MouseWheelZoomingMode == MouseWheelZoomingMode.Absolute ? OrigoPosition : mousePosition); + } + + + private void ZoomControl_MouseUp(object sender, PointerRoutedEventArgs e) + { + switch (ModifierMode) + { + case ZoomViewModifierMode.None: + return; + case ZoomViewModifierMode.Pan: + break; + case ZoomViewModifierMode.ZoomIn: + break; + case ZoomViewModifierMode.ZoomOut: + break; + case ZoomViewModifierMode.ZoomBox: + if (_startedAsAreaSelection) + { + _startedAsAreaSelection = false; + + OnAreaSelected(ToContentRectangle(ZoomBox)); + ZoomBox = Rect.Empty; + } + else ZoomToInternal(ZoomBox); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + ModifierMode = ZoomViewModifierMode.None; + PointerMoved -= ZoomControl_PreviewMouseMove; + ReleasePointerCapture(e.Pointer); + } + + private void ZoomControl_PreviewMouseMove(object sender, PointerRoutedEventArgs e) + { + var pos = e.GetCurrentPoint(this).Position; + switch (ModifierMode) + { + case ZoomViewModifierMode.None: + return; + case ZoomViewModifierMode.Pan: + var pps = pos.Subtract(_mouseDownPos); + var translatex = _startTranslate.X + pps.X; + var translatey = _startTranslate.Y + pps.Y; + TranslateX = translatex; + TranslateY = translatey; + //VF UpdateViewport(); + break; + case ZoomViewModifierMode.ZoomIn: + break; + case ZoomViewModifierMode.ZoomOut: + break; + case ZoomViewModifierMode.ZoomBox: + var x = Math.Min(_mouseDownPos.X, pos.X); + var y = Math.Min(_mouseDownPos.Y, pos.Y); + var sizeX = Math.Abs(_mouseDownPos.X - pos.X); + var sizeY = Math.Abs(_mouseDownPos.Y - pos.Y); + ZoomBox = new Rect(x, y, sizeX, sizeY); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + /* private void ZoomControl_MouseDown(object sender, PointerRoutedEventArgs e) + { + OnMouseDown(e, false); + }*/ + + private void ZoomControl_PreviewMouseDown(object sender, PointerRoutedEventArgs e) + { + OnMouseDown(e, false); + e.Handled = false; + } + + private bool _startedAsAreaSelection; + private void OnMouseDown(PointerRoutedEventArgs e, bool isPreview) + { + if (ModifierMode != ZoomViewModifierMode.None) + return; + _startedAsAreaSelection = false; + switch (e.KeyModifiers) + { + case VirtualKeyModifiers.None: + if (!isPreview) + ModifierMode = ZoomViewModifierMode.Pan; + break; + case VirtualKeyModifiers.Windows | VirtualKeyModifiers.Control: + _startedAsAreaSelection = true; + ModifierMode = ZoomViewModifierMode.ZoomBox; + break; + case VirtualKeyModifiers.Windows: + ModifierMode = ZoomViewModifierMode.ZoomBox; + break; + case VirtualKeyModifiers.Control: + break; + case VirtualKeyModifiers.Shift: + ModifierMode = ZoomViewModifierMode.Pan; + break; + default: + return; + } + + if (ModifierMode == ZoomViewModifierMode.None) + return; + + _mouseDownPos = e.GetCurrentPoint(this).Position; + _startTranslate = new Vector(TranslateX, TranslateY); + CapturePointer(e.Pointer); + PointerMoved += ZoomControl_PreviewMouseMove; + } + #endregion + + #region Animation + + public event EventHandler ZoomAnimationCompleted; + + private void OnZoomAnimationCompleted() + { + if (ZoomAnimationCompleted != null) + ZoomAnimationCompleted(this, EventArgs.Empty); + } + + + + + private void DoZoomAnimation(double targetZoom, double transformX, double transformY, bool isZooming = true) + { + if (targetZoom == 0d && double.IsNaN(transformX) && double.IsNaN(transformY)) return; + _isZooming = isZooming; + var duration = !IsAnimationDisabled ? new Duration(AnimationLength) : new Duration(new TimeSpan(0,0,0,0,100)); + var value = (double)GetValue(TranslateXProperty); + if (double.IsNaN(value) || double.IsInfinity(value)) SetValue(TranslateXProperty, 0d); + value = (double)GetValue(TranslateYProperty); + if (double.IsNaN(value) || double.IsInfinity(value)) SetValue(TranslateYProperty, 0d); + StartAnimation(TranslateXProperty, "TranslateX", transformX, duration); + if (double.IsNaN(transformY) || double.IsInfinity(transformY)) transformY = 0; + StartAnimation(TranslateYProperty, "TranslateY", transformY, duration); + if (double.IsNaN(targetZoom) || double.IsInfinity(targetZoom)) targetZoom = 1; + StartAnimation(ZoomProperty, "Zoom", targetZoom, duration); + } + + private void StartAnimation(DependencyProperty dp, string dpName, double toValue, Duration duration) + { + if (double.IsNaN(toValue) || double.IsInfinity(toValue)) + { + if (dp == ZoomProperty) + { + _isZooming = false; + } + return; + } + + _currentZoomAnimation = AnimationHelper.CreateDoubleAnimation(null, toValue, duration.TimeSpan.TotalMilliseconds, dpName, this); + if (dp == ZoomProperty) + { + _zoomAnimCount++; + _currentZoomAnimation.Completed += (s, args) => + { + _zoomAnimCount--; + if (_zoomAnimCount > 0 && _currentZoomAnimation != s) + return; + var zoom = Zoom; + SetValue(ZoomProperty, zoom); + _isZooming = false; + //VF UpdateViewport(); + OnZoomAnimationCompleted(); + }; + } + _currentZoomAnimation.Begin(); + } + + private int _zoomAnimCount; + + + #endregion + + /// + /// Zoom to rectangle area (MAY BE DEPRECATED). Use ZoomToContent method instead. + /// + /// + /// + public void ZoomTo(Rect rect, bool setDelta = false) + { + ZoomToInternal(rect, setDelta); + //VF UpdateViewFinderDisplayContentBounds(); + //VF UpdateViewport(); + } + + /// + /// Zoom to rectangle area of the content + /// + /// Rectangle area + /// Sets if content coordinates or screen coordinates was specified + public void ZoomToContent(Rect rectangle, bool usingContentCoordinates = true) + { + //if content isn't UIElement - return + if (ContentVisual == null) return; + // translate the region from the coordinate space of the content + // to the coordinate space of the content presenter + var transformer = ContentVisual.TransformToVisual(_presenter); + var region = usingContentCoordinates ? + new Rect( + transformer.TransformPoint(new Point(rectangle.Top, rectangle.Left)), + transformer.TransformPoint(new Point(rectangle.Bottom, rectangle.Right))) : rectangle; + + // calculate actual zoom, which must fit the entire selection + // while maintaining a 1:1 ratio + var aspectX = ActualWidth / region.Width; + var aspectY = ActualHeight / region.Height; + var newRelativeScale = aspectX < aspectY ? aspectX : aspectY; + // ensure that the scale value alls within the valid range + if (newRelativeScale > MaxZoom) + newRelativeScale = MaxZoom; + else if (newRelativeScale < MinZoom) + newRelativeScale = MinZoom; + + var center = new Point(rectangle.X + rectangle.Width / 2, rectangle.Y + rectangle.Height / 2); + var newRelativePosition = new Point((ActualWidth / 2 - center.X) * Zoom, (ActualHeight / 2 - center.Y) * Zoom); + + TranslateX = newRelativePosition.X; + TranslateY = newRelativePosition.Y; + Zoom = newRelativeScale; + } + + /// + /// Zoom to original size + /// + public void ZoomToOriginal() + { + if (Mode == ZoomControlModes.Original) + DoZoomToOriginal(); + else Mode = ZoomControlModes.Original; + } + + /// + /// Centers content on the screen + /// + public void CenterContent() + { + if (_presenter == null) + return; + + var initialTranslate = GetTrackableTranslate(); + DoZoomAnimation(Zoom, initialTranslate.X*Zoom, initialTranslate.Y*Zoom); + } + + /// + /// Zoom to fill screen area with the content + /// + public void ZoomToFill() + { + if(Mode == ZoomControlModes.Fill) + DoZoomToFill(); + else Mode = ZoomControlModes.Fill; + } + + private void ZoomToInternal(Rect rect, bool setDelta = false) + { + var deltaZoom = Math.Min(ActualWidth / rect.Width, ActualHeight / rect.Height); + var startHandlePosition = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); + DoZoom(deltaZoom, 1, OrigoPosition, startHandlePosition, OrigoPosition, setDelta); + ZoomBox = new Rect(); + } + + /// + /// Returns initial translate depending on container graph settings (to deal with optinal new coord system) + /// + private Vector GetTrackableTranslate() + { + if (!IsContentTrackable) return new Vector(); + return DesignMode.DesignModeEnabled ? GetInitialTranslate(200,100) : GetInitialTranslate(TrackableContent.ContentSize.Width, TrackableContent.ContentSize.Height, TrackableContent.ContentSize.X, TrackableContent.ContentSize.Y); + } + + private void DoZoomToOriginal() + { + if (_presenter == null) + return; + + var initialTranslate = GetTrackableTranslate(); + DoZoomAnimation(1.0, initialTranslate.X, initialTranslate.Y); + } + + private Vector GetInitialTranslate(double contentWidth, double contentHeight, double offsetX = 0, double offsetY = 0) + { + if (_presenter == null) + return new Vector(0.0, 0.0); + var w = contentWidth - ActualWidth; + var h = contentHeight - ActualHeight; + var tX = -(w / 2.0 + offsetX); + var tY = -(h / 2.0 + offsetY); + + return new Vector(tX, tY); + } + + private void DoZoomToFill() + { + if (_presenter == null) + return; + var c = IsContentTrackable ? TrackableContent.ContentSize.Size() : ContentVisual.DesiredSize; + var deltaZoom = Math.Min(MaxZoom,Math.Min( ActualWidth / (c.Width), ActualHeight / (c.Height))); + var initialTranslate = IsContentTrackable ? GetTrackableTranslate() : GetInitialTranslate(c.Width, c.Height); + DoZoomAnimation(deltaZoom, initialTranslate.X * deltaZoom, initialTranslate.Y * deltaZoom); + } + + private double GetCoercedTranslate(double baseValue) + { + return _presenter == null ? 0.0 : baseValue; + } + + private void DoZoom(double deltaZoom, int mod, Point origoPosition, Point startHandlePosition, Point targetHandlePosition, bool setDelta = false) + { + var startZoom = Zoom; + var currentZoom = setDelta ? deltaZoom : (mod == -1 ? (startZoom / deltaZoom) : (startZoom * deltaZoom)); + currentZoom = Math.Max(MinZoom, Math.Min(MaxZoom, currentZoom)); + + var startTranslate = new Point(TranslateX, TranslateY); + + var v = startHandlePosition.Subtract(origoPosition); + var vTarget = targetHandlePosition.Subtract(origoPosition); + + var targetPoint = v.Subtract(startTranslate).Div(startZoom); + var zoomedTargetPointPos = targetPoint.Mul(currentZoom).Sum(startTranslate); + var endTranslate = vTarget.Subtract(zoomedTargetPointPos); + + + if (setDelta) + { + var transformX = GetCoercedTranslate(endTranslate.X); + var transformY = GetCoercedTranslate(endTranslate.Y); + DoZoomAnimation(currentZoom, transformX, transformY); + } + else + { + var transformX = GetCoercedTranslate(TranslateX + endTranslate.X); + var transformY = GetCoercedTranslate(TranslateY + endTranslate.Y); + DoZoomAnimation(currentZoom, transformX, transformY); + } + Mode = ZoomControlModes.Custom; + } + + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + //VF AttachToVisualTree(); + + //get the presenter, and initialize + Presenter = GetTemplateChild(PART_PRESENTER) as ZCP; + if (Presenter != null) + { + Presenter.SizeChanged += (s, a) => + { + //VF UpdateViewport(); + if (Mode == ZoomControlModes.Fill) + DoZoomToFill(); + }; + Presenter.ContentSizeChanged += (s, a) => + { + //UpdateViewFinderDisplayContentBounds(); + if (Mode == ZoomControlModes.Fill) + { + DoZoomToFill(); + //IsAnimationDisabled = false; + } + }; + } + ZoomToFill(); + } + + public event PropertyChangedEventHandler PropertyChanged; + public void OnPropertyChanged(string name) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(name)); + } + } +} diff --git a/GraphX.UAP.Controls/DesignerExampleData/EdgeDataExample.cs b/GraphX.UAP.Controls/DesignerExampleData/EdgeDataExample.cs new file mode 100644 index 00000000..d0e74f35 --- /dev/null +++ b/GraphX.UAP.Controls/DesignerExampleData/EdgeDataExample.cs @@ -0,0 +1,20 @@ +using GraphX.PCL.Common.Models; + +namespace GraphX.Controls.DesignerExampleData +{ + internal sealed class EdgeDataExample : EdgeBase + { + public EdgeDataExample(TVertex source, TVertex target) + : base(source, target) + { + + } + public EdgeDataExample(TVertex source, TVertex target, double weight) + : base(source, target, weight) + { + + } + + public string Text { get; set; } + } +} diff --git a/GraphX.UAP.Controls/DesignerExampleData/VertexDataExample.cs b/GraphX.UAP.Controls/DesignerExampleData/VertexDataExample.cs new file mode 100644 index 00000000..a02587ba --- /dev/null +++ b/GraphX.UAP.Controls/DesignerExampleData/VertexDataExample.cs @@ -0,0 +1,21 @@ +using GraphX.PCL.Common.Models; + +namespace GraphX.Controls.DesignerExampleData +{ + internal sealed class VertexDataExample : VertexBase + { + public VertexDataExample(int id, string name) + { + ID = id; Name = name; + //DataImage = new BitmapImage(new Uri(@"pack://application:,,,/GraphX.Controls;component/Images/help_black.png", UriKind.Absolute)); + } + + public string Name { get; set; } + //public ImageSource DataImage{ get; set; } + + public override string ToString() + { + return Name; + } + } +} diff --git a/GraphX.UAP.Controls/DpExtensions.cs b/GraphX.UAP.Controls/DpExtensions.cs new file mode 100644 index 00000000..1bb119d6 --- /dev/null +++ b/GraphX.UAP.Controls/DpExtensions.cs @@ -0,0 +1,70 @@ +using System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Data; + +namespace GraphX.Controls +{ + public static class DependencyObjectExtensions + { + public static IDisposable WatchProperty(this DependencyObject target, + string propertyPath, + DependencyPropertyChangedEventHandler handler) + { + return new DependencyPropertyWatcher(target, propertyPath, handler); + } + + private class DependencyPropertyWatcher : DependencyObject, IDisposable + { + private DependencyPropertyChangedEventHandler _handler; + + public DependencyPropertyWatcher(DependencyObject target, + string propertyPath, + DependencyPropertyChangedEventHandler handler) + { + if (target == null) throw new ArgumentNullException("target"); + if (propertyPath == null) throw new ArgumentNullException("propertyPath"); + if (handler == null) throw new ArgumentNullException("handler"); + + _handler = handler; + + var binding = new Binding + { + Source = target, + Path = new PropertyPath(propertyPath), + Mode = BindingMode.OneWay, + }; + BindingOperations.SetBinding(this, ValueProperty, binding); + } + + private static readonly DependencyProperty ValueProperty = + DependencyProperty.Register( + "Value", + typeof (object), + typeof (DependencyPropertyWatcher), + new PropertyMetadata(null, ValuePropertyChanged)); + + private static void ValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var watcher = d as DependencyPropertyWatcher; + if (watcher == null) + return; + + watcher.OnValueChanged(e); + } + + private void OnValueChanged(DependencyPropertyChangedEventArgs e) + { + var handler = _handler; + if (handler != null) + handler(this, e); + } + + public void Dispose() + { + _handler = null; + // There is no ClearBinding method, so set a dummy binding instead + BindingOperations.SetBinding(this, ValueProperty, new Binding()); + } + } + } +} diff --git a/GraphX.UAP.Controls/GraphX.UAP.Controls.csproj b/GraphX.UAP.Controls/GraphX.UAP.Controls.csproj new file mode 100644 index 00000000..ca66aebe --- /dev/null +++ b/GraphX.UAP.Controls/GraphX.UAP.Controls.csproj @@ -0,0 +1,370 @@ + + + + + Debug + AnyCPU + {4BEBC41E-2710-4613-80B1-198E08D10619} + Library + Properties + GraphX.UAP.Controls + GraphX.UAP.Controls + ru-RU + UAP + 10.0.14393.0 + 10.0.10586.0 + 14 + 512 + {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + AnyCPU + true + full + false + bin\Debug\ + TRACE;DEBUG;NETFX_CORE;WINDOWS_UWP;METRO + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP;METRO + prompt + 4 + + + x86 + true + bin\x86\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x86 + false + prompt + + + x86 + bin\x86\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x86 + false + prompt + + + ARM + true + bin\ARM\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + ARM + false + prompt + + + ARM + bin\ARM\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + ARM + false + prompt + + + x64 + true + bin\x64\Debug\ + DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP + ;2008 + full + x64 + false + prompt + + + x64 + bin\x64\Release\ + TRACE;NETFX_CORE;WINDOWS_UWP + true + ;2008 + pdbonly + x64 + false + prompt + + + PackageReference + + + + Animations\DeleteFadeAnimation.cs + + + Animations\DeleteShrinkAnimation.cs + + + Animations\Enum\DeleteAnimation.cs + + + Animations\Enum\MouseOverAnimation.cs + + + Animations\Enum\MoveAnimation.cs + + + Animations\Interfaces\IBidirectionalControlAnimation.cs + + + Animations\Interfaces\IOneWayControlAnimation.cs + + + Animations\MouseOverScaleAnimation.cs + + + Animations\MoveAnimationBase.cs + + + Animations\MoveFadeAnimation.cs + + + Animations\MoveSimpleAnimation.cs + + + Behaviours\DragBehaviour.cs + + + Behaviours\HighlightBehaviour.cs + + + Controls\EdgeControl.cs + + + Controls\EdgeControlBase.cs + + + Controls\EdgeLabels\AttachableEdgeLabelControl.cs + + + Controls\EdgeLabels\EdgeLabelControl.cs + + + Controls\EdgePointers\DefaultEdgePointer.cs + + + Controls\GraphArea.cs + + + Controls\GraphAreaBase.cs + + + Controls\Misc\ControlDrawOrder.cs + + + Controls\Misc\EdgeDashStyle.cs + + + Controls\Misc\IEdgeLabelControl.cs + + + Controls\Misc\IEdgePointer.cs + + + Controls\Misc\IGraphArea.cs + + + Controls\Misc\IGraphAreaBase.cs + + + Controls\Misc\IGraphControl.cs + + + Controls\Misc\IPositionChangeNotify.cs + + + Controls\Misc\ITrackableContent.cs + + + Controls\Misc\IVertexConnectionPoint.cs + + + Controls\Misc\IVertexLabelControl.cs + + + Controls\Misc\IZoomControl.cs + + + Controls\Misc\LogicCoreChangedAction.cs + + + Controls\VertexConnectionPoints\StaticVertexConnectionPoint.cs + + + Controls\VertexControl.cs + + + Controls\VertexControlBase.cs + + + Controls\VertexLabels\AttachableVertexLabelControl.cs + + + Controls\VertexLabels\VertexLabelControl.cs + + + CustomHelper.cs + + + GeometryHelper.cs + + + MathHelper.cs + + + Models\AnimationFactory.cs + + + Models\ContentSizeChangedEventHandler.cs + + + Models\ControlEventArgs.cs + + + Models\DefaultLabelFactory.cs + + + Models\EdgeEventOptions.cs + + + Models\EdgeSelectedEventHandler.cs + + + Models\GraphControlFactory.cs + + + Models\Interfaces\IAttachableControl.cs + + + Models\Interfaces\IGraphControlFactory.cs + + + Models\Interfaces\ILabelFactory.cs + + + Models\RemoveControlEventHandler.cs + + + Models\StateStorage.cs + + + Models\VertexEventOptions.cs + + + Models\VertexPositionChangedEH.cs + + + Models\VertexPositionEventArgs.cs + + + Models\VertexSelectedEventHandler.cs + + + TypeExtensions.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6.0.6 + + + 3.6.61114.2 + + + + + {3644d44b-dec0-4b65-bba0-c68e34821aae} + GraphX.PCL.Common + + + + + + + + + + + MSBuild:Compile + Designer + + + + + + + 14.0 + + + true + + + uap_graphx.controls.pfx + + + + mkdir "$(SolutionDir)bin\$(ConfigurationName)" +copy /Y "$(TargetDir)$(TargetName).dll" "$(SolutionDir)bin\$(ConfigurationName)\GraphX.UAP.Controls.dll" + + + \ No newline at end of file diff --git a/GraphX.UAP.Controls/Images/cross-icon.png b/GraphX.UAP.Controls/Images/cross-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ba021279cc28a23cbadb9facf8dbbee84fbc79b4 GIT binary patch literal 50642 zcmV)!K#;$QP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}006q}Nkl~WdRkp!4#yeoy5FnVv zl5G|n5`)baz-9;IfY}1cWPT7<+ma1rnJfh31%5NXd^4F$GLsDR4IrBUURV5~+>;C?D->SOzKKH5jZFNg(NmU<&rS5mFs^>iCZs!o)(H%29F1qNw zi^dmBJ_#j{F3F=%@QDDPNWl@1@^G*?43I+s90KqlKn?Vc2p$LVn3Q-Flnp?!p%7VzLe`Fr&wJ$CfA{5$-IeK%nH=m+ zL3a#upPc`u_dcZ<*>N(9;v@)8EQBYNl;a5;2jEx$2kN^@N--}Wu>Y?AIp_{7{bK}R z(fh9upnxp=3y%SK2*867JOIf35d1=jpO;hReK-D(zr0s{g6`;!4jj8<@bTI=Uvj)~ z`0XHoD>6!;Yge+9t7Jsc@3jDx|xJ`eOakAVH3Ngv6~lNzel2SE{lAcWG#OZE8r zec1!!{$qsw=Lq}6Q9w2yviiLBE0Lh$trUCrH>|VVBH&L6{8WVh&JzE&W5MLVe)F&X zYF&4ybl}(>`}pzdcf8}|$sO~aSAeIpkkduvIRKC85wNn){`&vlL!myH^uR^fgFots zRA5+R^>_B4D~1+o5bYsd?`5ktZ~on1-Pheo9XNK!KEMn|CP$V~Mv43W}n2dG?8{6++5LzDIu(}RvgPLm;x!F!g8Mv?R`2@u}i^yBz{nq_(3s( zf4cE+|Lc#tJFo-C?wBLT6<1tQ+;;abUd*z55x^ILem&J%zl1d2x_A4KA;C*KCJz) z`HWJ9@D=y0i$T@P^?u6&D8X$bknfkk_gLb4OMd04-(9|ZdD-2e9XNK!ZoY2kU-XW1 zK{=*)bEV>z~7jg?&=VbLxz}|WL9!lIQBU872^Y8xV z7Idvc9XNK!E)1Dp|F)$VDPAVT%K)4!QYLJzNg_6d5wj|*ei{3)JmMf_S~gFY-b}W_ zEjH$*g+IcAPW6UOX~=N}BrmMfSN z+){uym4chT{guD|VRt8Y;Mg6raGZD1J5FYamkZ@Q62A_}!BR>S{`C>A$pr>jlHpfH zf`clAY--9aH%kU3BQW-8TNhDsN7?^`K-7n0*{1uH7QyOA)-|RCTvfaboj#CO21~@O zSEK>bIxSliKv`}9if@rq-;`qXAG^wT2aesb6UWOgdiyJivOK>)@d^~>;ofw z@pLYsZtgPcd|TDHUDiM7!Aw7=r&hY_%=VzCfzCmNDC+8dZ~i6;yr|FIOv2P*tg0&8 zyI8-s|6CPtis`2mTS`}-yJd-p3=!n}pEmDVkPzY?l>9~sx$&m|{Wss}?)VNIyQAf} z;Pr1kakAhmrNjlKTu_Rz$$+)7FvLB7QuXvnc&RPhWQuK+rqzay&FLaV7;me$4XViX z;|r;oZ?Au`>_5Ix43cr2pU_$cAk~1hXz(rj?_CN|6#chxqc|0OC#PLkw<`)SCPz^- zNAVoAN*EOViZ}%14FqnO1XtYrmH+;WZY6Z!*d0~q{DwC#q2M(_z8ZpO32ZUNu1Rqi zKu2oSl!^z;nuXCaApLK}m}rQc^jfm(aY0Q6X&GSHWX-yXT+oEJ?7v9~LD2_jQFY>` z0G%ndC%_x`^GF4VsH*sCC#b$(f84NU<^9jxoJu`18C(-_uR9>+U|Z)$ASnM0hE29I){r33vH@x)%k@B?=yq3Vxy&gjiTsAL9Y1m$s*MbRyZ76H-TMsEK`_Z1A;ZKYK#runhDd*MEO-?V>P)`N6V4~?kby5 z6K4_jdqFjLs*Of6Sy-x8sroah)JJvh#hsPl%aFxd6!H({l>Eaj|L{L==vGPxj{C)N z&N=7IoA-ocUXLkxy%4X1l=GXyM?Vi(O{l2L)G#%v2}*Aij?LmV#RdmS6*$(Bqpb&v z$?<6rGjX$-nyHq&^bw5=0(c)~_kltLKp}PGIdkAjN6w-kTlZkruiw0o>6e6nB~@|9 zHE@OzJ53tG?gXOVyWirY8NCGW<7ddFsctt{1|T?5lK*=I@|DTQ*L~&ITW_80R!|3y z``mHnMHd}#z>bj%3zip(@HNPU&Qu^}8mjA@mMK#k;0Oz~uyqmN1fB0Hq@CnbkI=o4 zOaRRZJvb0^ErDt61@cDXyV2bZr$VJ=UI8u}si4?D@ z<-Y30RW|yBD((}3VTDbNpa-9&RQ+_lg+>z|GpvtTc1F!rYvdRhCDTuj_{T`yJZ*r( zu{rZwx(G7|ejJR741qER(B`e}xd(#iSt6jfoFA~0lhwvm0IK_vCY_+!eXklXLEg4X z4-f#pE|kBMjR*hFTW|e;ws$M61INAc+`jBJZ+a7o^35WAZIdTNQ*@{%D*7v`7hd|1 zuPU-g%i^}FE2;=sEFU!sPB(#5asZ-VL96aazfv1_JI0b`na_YWZJh>EV1my0HYU8b zq~*wEU++hdvf}0&>RB6Kw9>EGuzSfYCJ7jJCAH?1*%Vf?jvUy}VTuY72%-S~VT${&E_w~Yw*cjvMbkdf%gD!)4ezSdU?ie&K?v%zhi#WO0k3`> z*jt>e<;t2K?cnuHsk(_LEih&Hn?n%;dZPL->zI_5;W5qr=_YUUuBJL}!A}fp)Ws61 z1#+vIY|W5U@I;b+Fx!X(=>&D%5X`GfogWr=8rYX^t2WdEkn(RS_?uf+eC4a%%Im;! z&K@s&?S(HYg>MJ&R+Mru>X}@XXx9`^#D=?SA|(wE?ZgTbnC-t0H5(Jv+ZUBHQdXvQ z7H#s9=AVKT3@arYtG+W_$SV=^6BAXMAU%5<>&kM{&>bW{_2W#-5RIfS6|CA;b$|BC zq^&5OR-(IxVm`XKWHBpMr8)(|Iv3mP2IUqZ{yR$kx9_a@`|outu>;4slUIDz8%`tn z4hY^ZloOP_Ni6_Doq19N&j#SAn2n0&M9c%~#%}StGRhXfG8{9=hNK5atolv@Bz_)R zHHeGvb7U|V9YSJTf$DRnpviyyal}~ zWm2%$RhfMMYP?YF1|@ZilZ91D`?*jNM_rjGc|QdIjpSe5`t|?yvuU*@sObGxi3Vr?bj24DP`q(7-r5RRX z!)c)bA1$1lHbBBQGDf#yB2w##t}bGEuLH#zVaF8>3-$R!^K%9hG9K4_=C)~%61Z_n zluo@U0)6$d;aa8?h|?tiA|^_zMtb0O5&5sh*u1~I_13@J(yi1E9CvSC@s+QCr4W|@ zd_zx6HfXYj9zL=8uih^+N-#dR=PEALUEB$n=__01r6hmVokDEGRMSLfmf) z#^z@9vGRYZ{@zq)Rr``&{yL$jJD6%L3?_1t5lD9mtDId#ARQWtxYR154#n{B?Y{&hGP}HqevGKcxRG| z!VKZ{O5|vXy4my!HiDH1O1(|PV$&{DKva!Nv!B&A`poX%=d-#Y@!GJE;RV!d$cFD55P|KbPV>_YA793$N+82)(4t6qDF zlvq{>-Xc;SROPyw-CkE1={mCm;Y7N5WDhc0ni?+Ra?;vT(S`n!5u{`;u4899yw# zD&*@R5@!xW0H}p0RF+i`Xl8_YO=;{@4Hl@vg?d4jRNVp6Z>zCA0xd#9Nf#%~sGwFQ z@*=)cH}gxB*T|{S1(|0kE7^3%3p&dcGAA3EG<~T3aiK34BfS2*H-5EqP3)NCkYV&I zUUM-7%K*H#<~9c5XuC>uje}GwD^2ejobZ8%lV(Dt_x}v|m6)H4wMWfhla;d-#8MZL zCyUf#xy|$n19uh;(fVI;%MJlI2uQb6H=ji_T|HN>7rXIwQ4Fpo^`xt#h_N$hW|m!$ zDsiqh9mlll>>mBJ!QuO zt5^O@xAHsYm_3%h;x|qjDa#KQ#BYhE!T2P^!jFn)qQ_vCb@L*H{TpHY_uaH8Y zZ}CeWT7Pi%BxU=^K{b&>q;4rS7}xDEY-W=y-Pp>pP|a`~3smPqBf->4Rn^y6xJKqpUi-sueBRe$GiqiD6Ap?uGC`H1q+&jAuMyL=U;&fG;8EVoGw54Aw0SZ&;t%7+? z8)-OBGnvOaU0B0)AHDkWj?F{~n-IJ~nxGm**ZA!^ZR+zO!OkIZDxm^(`ck(kxHN!X zw`n!W+I|F(_ORD`NFbgYvPX5dAPnQ1o=NJEUR>_jH@O=)meGPZn^K%|+{vdr`rv&l zS9OTcfg=F$h38%H+k#>l1WS90*J)LiWTFEI2YO7zyjagW+o=fG3|_SW`4K_qNs<_v zCVhSgo24x&WNXO4)*!=`b9H|o#WtrarpE}>>E$D&UdUCBP()R8b;K$Si({D6)S$567+N?t`JGzl$e=%s|5+$e#C~+vSy)F`jqUa5=7m18YXr4?$QXp zO;mwpzdv^|!KKHa{8T=0->TcYuzEi}&V2c6o>s`zZwvV0x(7|k|2MtX>7;U#gR@0~ zrY<85MbIiMwacGkIhD|Znw#z|=#=F!$R(oRLeo^O*;3Si>!AynR|Z$3O(F3&Fsm>J z(1=H=XL=X=X7)yDHnCrjAelf~;El!9s_Ui3`!oUcp|C&iUa7rKDfrI@pzLiFW&Ied zzV1P`Y2@*(;d+v^Ne@S>%4p9GAZAmA_U9t`OlnXmUED zND6C4NEM<`G$=u7E^1U&U>3wyVf%;%6*o5LRA!@e7h1grG{wGTKnS=hDMq$#+sVY9r)&%~BipRC#l2p*k@%mvif|I@Q!&Kg1Zn!_-a~Z$*q{8M zKZwEi6(>&8OG>itPN(?&01O=86 z@}fHF9qHSfn>AG{OggIdUwqFZbz(>r5hx}XmkrMlO<}hrLw$3jxcO&s$~`hbu$Ap` zM)j-8n~M}g(zNu&1)Zzt19oXk9B5={@}EtVOCjC&6Hx*nHDF6nDM#`?aW=RKxs&W~ zV0~eobJJ<0QhaK}OE!rus<`Ki&%OGt1H#U8i%k91zbl>Wq zbYb;Ad_4QS^A0*_YUDox_>UkDlYp#O2(7NPJX)g$=-2=fAK&k7=?W2tu+p^b5r!(y%+3 z`(Ohbw&z!n>n6-q*Q07^&IURPIdz|h;0n5rU1yP?_)HjfP9&%8El{!agHkGEuNRQIjeV9os-ICT&VY4vDf$YSMY3P^W zHtsR-g#^!?Hzh|r=_#lFY|VYE9_zqyA34r^>3L@fie-SjqiF_iyoFWAuqh~TXoBth zk!z)9Nld7GV%Bdawk@WUpP0MIoh3pxx zvj@!;i$e5fNI=9Zf=Z}ULMQNR+Q=a<3!}qOzpaaLf{CL4j z&wDkcSO&_=>y<%w16O~`gtufL|Ver{)@@9c*RJ|8V*Z)rfS@5HlDiO zG%BXK<^wN&A@q6ZT&h5V&_V$4=`7{cC!h4R4G;ff^*tRp?xn{W=bU$OK`aCDJW~L1 z@nX%6oN00!2Z1(WG9e*@z_N{xG*VN&;*j)<1x3B*7b*py$M{k>gaJ__jH_WFtgL(J z$Op*Mhy@z+r#h#WREYhSfO=k-)j*3{;C1b&Y}kvd_7qIuG`%hY3FRU>krLmA&^FKw1-C#jmVsf#!f^{kqWDQVdvu}AP+H7z`43hr@{ zhxwmVS~7eN=qN4IofX+-Fk{3x7aKDw2Fy+@aBIaMX;LnAQ#bnZZlU#onqE>lSmvrT z#ub8f&#PzZ;`$zY8v>JbfGG;)1ebc@{E>hxJ?5mR>{#=Q`)=#Nac?-TxT1Ig7kmnW zWh4&Q$vzPYrz-5YpJPu!m`gh6Au~1<-rGxZ+5YxHIgbdc4qxO4J&Or0KI1 zWNuzFWutz?z#%q>%5rJdfrSUg#T-g1G{zvV^=&4}D0}X6MdCDW1Jkb~*}{n{z-03m zq6P)h@19t&_TRju%~M)z?{CN@O)io_zL?r_Lgy9h_YyToM3vLk*Mg=5X^ZQDZ#Pmw zAdm+`_>w1|_>^MJFW&Ke;5+-2fA&7r%JYnK&N=v?a^9y{@Z&zeW%FcS6Gp)oz3Q`_ zJF|XS`BA)j>P1hln4*khH(Fr_uHCNCpeN1%9*Fvc>IoZ>eDh*qqca0WgKn6lej$z` zEAA5cSs{baQJ$;+g%j%=aq?`DCPYXFV+NLO{LWXqg6pmTS$8ez_8ISGomkMgzQ*W# z6;(meHPZKQqLM1#NJ$O8027HI@v>x->(xo1fWG&&BL869yz;aE=hj>I8AGpqhB-d( zoO7Nyznp&siH}5~rv*z|)k6g!RZpNb^iv~+blQiWBJ>}_Osiz*fCo=L?JBHWK%%LL zK|mIH%Ow8@Ry~6eMBO{5fv`X{yd0va1k$_d>$-;ZfI5nsRgXyE@NF+%aP*{(N3T;Hwwpw?r&zTPjK zFFf#=r<{1#nxFrCtOLin0*o(u`7woX87LpF0Z#9M^}KX76RRY$`gtI0#ha7v-@jqH~|NUD!aNN^{mlvORycAQ*AbekA*5?z= zP35C$=B3;DRIg%@R9qs5R2zdzlE6%png&E|e_T95<7f&cWqG9W6Cv3GXtq}`#~oAg z)*K5=yujZgTPppQ&$l39<$pr%>gkH`=fPh3v8GXwxkTmy=f){WHcKiziMx-pqDXQ0Sd0W z&+{GaN5i_khgOZcW)+O1V^K}UXsV-BsRU7zBu#ZZrmtE=xO#qC922zGMbvkJgT(k1 z)O)#dgKwDk(>gG>h2Ch0sNWL)zM}*t2tJgR7DkU+{!TK6VQHSW5>uAc#gdY201{2e z)NY6dLz7QfS&8%_F+R5}dFT^QKH*?WQU#mASWTmj(SmCP6uU-?vjo;qAe zs@HK7bam$leGi~dVf#5@H4niU>X3vfO}luZmpUB}Gh!M39qnh11LhQ*B>`%e2B43? z=ya}a1W1XLuC3t%T`wks$I~%KY1=Gnfdv=dCwvt(*fWA|aTV(*GbgzwC4sIO=M2Vt z8rsj`L@88Je@V_2BmI+1WFtEN7(_3GEx>pmAK1^*bsRZy4b79(=Vu_v8)=iZou-0Q&cdFPz-#Byq6 z8G-ldu3IbqK(k2FB)<3c@T`JnWRSU3eEr_EEJy1-!sR7vVqpt9shgoqqW2bd0kTYU z|FlfOOY~=O-!cr^&l1^)nvpfzIpTWz92bwv_Q_)+=}IsYgfhlfGL?$c*Mx|BI_oG@ zH;YS#6Z&RM>P=3icEl>lqjq{Mn+?($Y2%I zFLo`gAlA>tR51F#D@66yF%_?t;ARTwkN6*nqk%r3*MINIkOlH_dT&G6`-;X(@EXVrtS+-Q4o=)mRzaF%wY-CAfwdQ zz2cn=lY&qkdoAUTvRL=f{kLG|#uyzq>f=|Jp7SXHmzz2ynS{+rQG_lRLx57$9w3yo zt)&{_t9S88#fR3F!2VtNAtywJim@6T*h#QG#ip>We9R zR9{0EGEFf^Ca-JyM5XcHrl^SzU&KuZJ*; zS47nZn<$9DGSu{jYg6$XXNn#SI~ro(%?xMPW1?PpQ#@c$Y;x136X2MkNr;MOXu*ve z+y~~XcxR3Ndx#!utTt}w5kiFB^}h4LY(ZiTz?x#9EIsPU$8TBp@B_DX;5buYJmc(( z$znOc!>Mv_xphZhTo474Dh#%LcmYQesT<1MVgTxGo<>Cvwj2{N9SNI#mHm#$Kdt1yV6unB&nk5{NUr7B~ zMM;?nQmcuCez_Y`A}{hxmt`s;?9MF{2MQy+Y(r(ePe^vmk+9am`g@5WP!0<6lf8eB z5;*d^Nyj1Wz`VI@JtYC2DN3!!bs>8PP0}u>hwFIcejL zD0#79(FDN9HpKDM7-Y+1qs1)&AO_(t+j{ft&m`-J6ORFgelK2@$A#gBCyQi99z%1n zq%SXr=C(S}`n5ggnu3|{JxsH6M5>sq8^0pMuJEQb&rK7*Nw;L5jfx`!4Jc~6hs+W% zOSQO8* zc|BUfqf~8R3Klf&5fWExkdEA`@iUc=lW;UI13nThP6ufNim3*5=^C-qZ(u`4Nz0sV z?Q=fdSEhH4jWY1Q*5HOz60Q~G0~=H3*y;dqbYK>dSB5~C0#~GiD3TlRR0S1Dp;g4@ z#g*Kb{Vt(=Cd0yeZPbtyBfT)LBpaxRpZAXLyUZEa@pl*%IF_u%gGn!}aij>3Kl<3? z?q2usgAa7zI4m$e@2sb?D3%d;IjKR9>0+jqug{nc4+J&6j-_QGi+UUbmZreP3CpCU zDQZ^np$ubo$Rb|!5jhI-siJ=7Gn-6uR^DGETGy_cuCY{m_5^I!+fSPrV^h&}#fsMG zzY;7K)$Zbw0WBWTlqf%^dlALt4-F(4duXZxitbdXx&+y%rQnt{ zdx!U}s_17k9Sm~KW(%nST~vB1bugCdI-gLA9C7rMPq=g4ng<^1z;RG0{p@ESB=bg> z5yd-dJ50T}eC1etpwoXqVRKE9wVFwZCm_Osp=8q1LB~6CR;p0BOo2RPx&~3kD@3V;9xVpr5g-QP?iv{ zNNc8l^XMDZ>o@vV9kCsKIb|^I+DD|-!&-bI3hUKlU-4@%#U*clD{lYMk1#&5Bh4bZ z)Tx&EvYNiMQwuKgZyK~|7jyvjBvsR~^NFb|+&YKh_A#buEweb?W9f-?OAbN;mg;kA z!YBbE&T6*VaI`^L(K<%{pGvbaXgN%i-Ucu_IuD=x$nWC#V~@qZ{`>z4 zidT}bH$R1B@lukfB@u$^|CEGqrY>{B@CN}(23ggrN0NQpTtmYNl;!hfWMupLH4lHc z1INtqtQRb~M5I_oa$ytdQiaoW0Px*Ct@Q?wGxMlyKk}F-uUo(7;h%Ki=#Hm9f9bCYxU2w9L{an^ zOOXuRiVIum0jVkqIAc9O^K5`p&C)hxQtFX14STleYHa}OjlQtED_t&>zQ_UMtTSGK zKl;paELgAr0C4c`eU+tFyw8KB6zL}j@Eb58=MgmQ+=69Ctg5nNoPz3>+vH|XCJj)0c>xg z+ErOuI?#4fT=ub#;I*$jzkc19yzp$SUAG>0uUus&hY0OilukQAG4i@$-0aC>)ov5l zK}}ej5SW?%MgzuFPKH1#rmTk@go$)pzoNZRM4ocwF;8B(;gN^$?ZB~rJma}%J`KPX zMS&Mp{>^^MBMk`^Kvs!laXCYs(AU}Wy1T?SZ)-Qf%H%3pICLyhhm~}BnR?1WT%p`H zdY`rA`S|0{U0DNTb@TvoF>d+pKVfom%07?qx2Rdj7D1ZUBr2E}pNv#h&ZZLD@Anix z!Q+-nM&p2fVkJY(DV~{{He}=)V5}`}^s($%TvGN>xxvzf2@yP2Ei-9FT>DiA!0R|K zqz{a*IzKrrFL~ivcx3H*+`V$8Jtw+JUtb3kH83$M)A>#&Q(^AzQB@uhQ#^55j%*W> z{r+wS;Hr8|wDr`Gz=?m~jS1nI~Q3K>@ zi%-GL-~Aq@rpf?7fJkmC@4uR+7h;XV>>0~)IYvt*(?b(BVJF1^X=lK#t23DsG1`h= zXR#@c*+**2jG@j&&@NVqLFk#E%RcrI{Kl&;$iC`}&ps1t*KIHWne2Ju``nqNQ3Pr8 zdE>pUbEb{(hE9so=ZWcxF4D}kH)D=s+UV+e|Kv6mE7jIp*NdeDH>`d58~Z&tKI3^W z_-#mW1$9dfsgmI|%#TPVW>GYZlGU7S;Yzb~l3O8U_6^syn^k0jtio@*n3$3D4=s#v z<{2-*AAj~rEL^yt^&Hh9_IG+AcHT=ls8*Q%6l-)PNx3vK$5M0A(I9wKD@m%vLz-Or zX$mn3TU&YY6@0kQBW=5(AZeU0(Jt>EHKt3@R8QSg7(Jc1>|-Bo1;#2;dC3dU!rHZK zYk-t$12-)&-%ZU@N4xaqs!$JFFhjE`-JxyTO1nU+*u+`e}*{ND71C}ad8 zFu40%kQ>q&d?KAJSo_2bf-yduf(bukW?CgTPabW&6B6IyLb)d_jZ6OTS-h_M_yD#OxLuPe3i*Gxsr2h$k)PtGG=&; zp5p*w>5z;u46#pn8g9DfJ1Aw!0=;YbWCS909^UqE=%#f&86&hkjAHVwjf*1{NvEM2 z61oZK{HI^P;nR0J(Bi4BF}gWev)L$L4P5wjX3*KRyde)u*2LiL>J-Bimo%M@T7$ zANk~?|9QhBk37C#f#Z=+dh#blO(@w?B-}zp@NMobns#rtDY_6&5vX)I#DW-Zx zmS(oR>5Z#hL90!u%B6{w@)GIGzE#Qpz$m8fD5x6IrLl8pQXov*9Cb^IX#0m|17*L( zgcK{zn6W&p8{x^M6-+WHsGTiodS?20Z#B7f*~dPD*S-3cJH1|B^1`$5$T|g(zQbM| z84R;Wf?QhIl)WP3nq*4JwKR##FDLCq74)fMP!*DsihOH{G+B%(?)c@pHQ(BA!11(a zKks4?%gJJth0DZIO-;~M0TY1_7dui{7lYmd*A_&bJ5)1iO;VX=w9KZqn2eH|h}>!Z zk-*X=J;u1Rz*qz1amV7+Q%=Fnw|)ncQ)Re`Gu)T8oq(i1CkdE0x|UIseQz=+C+(k) zZM6tUU0f44S(J!>I+fB)M0opLZ&&SI3tRKc5{!VlCQHvMi2^0$ z^uv!l`k}|xKk_g8JUBk>SD$}+0WJf1a-rI-Dh63IA7^&raj;i~(QO4b`Ab(hw9-s4 zeymhhntCvl87o#liQrX$j1*P>S7$9f1Aq4WpP4Z*S_ZioH-G2*{XR(5n^rRcf-UCr z1QK@~n(auEq=W_?LN%u+k)EyA=Nt}fbCF)?l1v^!saMBEHL6ia8sLi~Ku?KM0SY9_ z*->eYst4AF;X4ybw;kua=!ICb_7U83&#HzzvMR9oyB3WZoY87zKg%F>8ia;<=X1^x zFdATG${NKdLZxA!J$W`l>9*tC7r(F{Vy{vT*^)9`=V|UeHbum=A1PyDdylAwdcA<^sVcQm zRaUmO1(UyoW(Hnd>tuSJ`!*lXJN(Eet$A$y+Pn5Sa6I*yr$3*-G8Dxz1ye9&v={5} z4gO~J9s_D}K=Fq#ls_d!O~ z8VEwr0T3wdxHt$mJ^x!10KqkGUM=tEp#om3RUTGo%y9lO!}_q4q#4acF0&y{C-6{j+^>adRHo z9;7CHjK9C@fl&iwRivpWX#$U$C`81duRfsPkON>(hUo$K=|j`5Vyz3ZjIQN#a}YKs zeV3ANaBoRlUcQ@vvAQ46eenzN@S0wTos1pm;!C8m?(>Im5^TZ!q6wZh{L*<$dty{A zoVLJ5kyO7$q-K=*TK7ZuV^BgKTfgq>`wTdq@~mII1cK!Si(2YL>kl?LI-p<>LI*p0 zk`gzD!ea7o;@$Wh+oP+1n=rz8NT-HdX%+qKrDxzz|KKyb4H&EA#JbJryO=5`^I>O8 z4<<4#KnY#*K;jq)QnEe7YR}~s-SubY^LRkbnx18lZipy8IWOuwT>kNo;&rciC3g35 z&Wm~>_B|_YzqEK|CF56ZK`{&dXxghJVV${Vak2ff9p5%GEoQbyRku~ia}PiA z=m#EKzwRe{Jvc6Y*0W9%;j)6oiAjzTPkrm6w<{kZtrPt>lH7f45bV zDp{FRyy;hT&RW{*W8B@qsEahGEj|U`zU4b8r%HR1QT!RSm?kRcnlLKAE9k_WR`6+F zkB0R{&sT9YwcV(Xt)1z(sy@`&G&);}7V|?>(HEULv^KTj_@C|^Q$V_>fU#kaFX|O( zR<7zdwnrhWy83ED1+F-fMKUOYKyf|gZe6R2G=pM{?&`3Cwrau`#WFE;{_^ ze}4Rz>o)Aw;CR@P$9%LX_?D_Qr(l!A(`H#Pp|3bFqZN@2s@KBTuU-3jtV&_o7dA{{Uk;rNoJv z#(i1hW+@deC=JS55JW5(n<*;<9_GFO+mpcP z8RWxj`T%LP0n#+INRYIZSTR3IuR2O7TI|JdCxTSTNn%e-%Vkx?Tp9_%{*8751!Ir> za^1K0T5x>I)1ULo0B6q4PcT+ocMH>yuD$J|1TB6Gk?G<~Srv}`#R0bTY=Ibjy{!zT{HLscz*PJ9? z`jQu6&6-DW_dTn8JZgcFDMN0{--^Wf21(K?a4kQoNJP7N#pzFzC{1j_RBXTa&?Arf zKN~l!Te;VP<1?P|jDt&ZISM|%sKc$IVFoQW2Ue5O%6=u=j}3}6g=r>k{FbSdxtU3j zX|S$7l(>XrHF9_6(k1x(AAW9+h0^&P|s&QM~>&uf|+G&V6yOQT%83tW+}B04k1& zf>FsLot8Lz=@R_;AN~HE1x5{!Pd{yOZMk3pfjKcN3!VXNF$B7ldA9JiaQP>GZ%zZF39KK57;6l$TJo^qjqP3I6O4KRf4v(HCiMy7jx5 ztQy5D?_@I5@152fwOxV)-XaKC7DL6NWMB}HMG85j)Z;*rTUg;=(bFUDSID;n_JHwK z*jtWsUi?Bl^2l2J?CzCuu2oMlne)WJ^uan>iiAU@HZ1q+O;S%Kc;OR4V8vlKs@f@A z%3}rGwDFf4Zl3etc=FYION+n^TJ@iKxiOv3)diAZ zk|?HWX&`MSI#s$uf`$-XEv4hB<^oHQ0)S(K!N;uM-tySJ4Hzp1dG1SI)T?6Oz0z3w zrW*}SA&WlWEOEkxo(bwT6!b$$QhQM%yW$*0D;7)Ds4n93X(t}?grn}-^vm`4&uMTx z>nV`#uL}e4E3)^TxN-|+AAqXG$_KV5~#z6OPBzPdybk-Qq?Ky;`pJ(-s+`IXolZqTQJY*EsJzdUA2EnEh3P_rI9VFyQZE(3S%Hlbk8ywP;HC`+h-}dInyxCM9zJ$2gW)FdCrUR@S3Jb zqXlavh?#VcV&wcn@dF)xuSzgfBwgRxW^m3XOlsmcIsl>bnEvpIXM~P50V*or);a0w^dU)O-z&*Kea4_P8-1v z1GLt`>GwWmrb_h(jp2NvS?H{wt1$2KPyF6q4~!{;TvPW!N;TOelAa44L-Sd+V$rE$#-RowZW8*gj0R?9%|Re_vej$&c+*z^EDI zLu($v&+fS=65xs6Cj*BxQF^FIBiQmH;e&aRRSC3wZ-K%1Y&L37`v>=YUbVMM5ftvTE zc11cdLM_cz6meF_)r@_T^Q=J9-Gh~bp~&bFiw^mJAAkJu$vFXzhaPp*TPgf_(PxeI zoUEBdp<|3HJofX|fuFLjMr+BBWFdO8!$_Z+acCwmir{DNBRR%l0P^XJPrFXQ0GnRsi&=tER``iTlBu*9AyfOH_q)|1z5KT@@2&o$9eglkkh+R+8+>`I%@K;+m zXaknjt2||PD3%Wa^qva{Fglrj>jE$+yNX} zu&gMG#Rbu8%&al7Fgs2Hh!xW)=oCw7cQO}Z`%TJfL1ql*qCxr`T(Z~4c=ezB;XV(H zA%mQnGFAMX3A_IP+H^_+0q?92iAyUYNEIVpERktL3Y3CyN=9^hm=$0k1ebl{W4LfX z0LCg>df7QI#zPOU=@n@b$5ugC$~VlpY9>H-8tCRUc#q)|e`xA#JaRYx+&W)d+*sW4d;JC+U~d z9S$O?`z)J0bIzG}=*BI}i;?0~(#}k4 z2B}@^v@=E1*v%HBtZ->6w$T(*Y=zYc-dZm^(@vyCD9&8E6j$$uz^DQ8)WxUZ=38&Y z)MS~2QAvxl_HKQ9KJRAlwI|9$|C7)s^0%idHWFA>B1v5 zYaMrkFfHu#cd)`I5d(;=B;GYkKl98bxcZO(aK8n{>Nu$mvA@$aiZjNbtoH}~&og=6 zsKqLh3uDW3;|~V6YO}HZ6`%Y#F8qzxVt+q+MVd9Z`|g$X`4zphHDSApqe6G?h2&Q8)&_lq<`>Ta=*3u>T!XN)34mjWdbVtP?pN4PWa%)df zJWJzUvM|uxbXr-lDM>PcGlW46GNjaa&!i6(6)`OPY!qqKGxF%9^zJC-AHcbMu;9TUj3*42?y-wj4@@9 zC*bL)F2=WSxmAf(0NFUZ4ZBoi>kXVF2X<{D6502rv-=F1fv6c{2aFMed}z%>xclx^ zP2?t-9stpyZC?39`s-F;(=J*T%@4ihH#nNdXbvRmF@kdOqD6=QXw$~WR_<1CJoK<5 zK2j9L8I|<`seD9gb|#KKGqFz9xggRt%>}jz`m49I8BseG({yj8$GGGST>U41)B)pw z9OSojn@ z3JIDxx0yohTe%v~YgplFujFsu)yiQ|v(Acnstpq0hyYtRKmOR)cN;h!chV_KgtDwC zii4>#<+`uY5NWT~sLmyW5L!!_*_Ovx=06R===2K1)E3S@a|yoqr~j!7rH5dUItLkQ zJ1P~h0Uk~2MkZ`_DxGGEWprsxvg%4@Q-JZkk@|%%|K!JTQ3s3zkEYG%o=i`wxQq!? zMya1v5h!S3+a{bawyyocO7kP@L|8Xl`b}Ewyp@#Yaf=RL^u0}wKmO2e0mnlQKm3D5 zF>*dh6fBzXxv)8hX1*GU-;3xG!%Uu0=MEEqq-T(MO=$JVIt6ytk~47ipLD=DEr9Hg z8kSRKmawxWEg3PC>=he=E}CbH*9?tc;)+jxyaUGRSYLOQ$)W~)Q{RHh4$j7Q5jFycZr5_rv@{c#73I|GoXEXKEQxusvlPR-D? z`icp0{Eh6=Eopa7(WuSio) zPH8iNUhirp6rpF^T_biS1OcSFnpKaS=(ev!^___$A+=mTn-IH_oVenXzlRH7_Z!^> z-02YeC0O&wTKw$pyAkWf_dUR+v9lEij9LOMY4VXw8b$JIo{i|S)J^DVWFn9$Iam((_ z^-jI=<-gtm;|!0Nyy$HF=^uO!qw`1mr&(NbyqTqyM#{PVQ!g5&Db~APSm&v#=@*eW zZD~zAy@|c@Ifit=I7?k42I+i8RVMdWx!2-VxRBFU_?P-z`*`ap}-nuW3nu zv-PL|w7wpoo`k0eWdIiX394T1qG%6umF_mh|3cYQr@pwTRAJ=`6ViiNQx>#)@ zFFqu1lzN&}MejGa-}NIr{nW)c{}-?q%2Q4|1c4;LI+T6@Dl^*6#M#A*5& z(}r%%s~OE+2RTO*N;6eZVkYs}^C0eRQ)An<;afM|f?s{+GjUu8kTW_?JmCZ^KIIgA z^X6MomQ#>q!B{M`ib^?&0}211u1`|uHzhOLxa<=j$3?I2fN`eBJu6q?JsTIy2b_q%NOEX@NNUXxC_QR#ldiRGkQAvd{A~xYB^5~XLkAGvW*5bPf@PohL1>~SrjOW!i3N8?Kp+fWTaPME?fgQ4MA)JJcMC7LKW!xH8YY~JEkV_t((7t zXFu~-x)6J&0C_^MNb}8`Z$Vj3!8YppvClNtYm)^eS%(vPcNVfiOJV4O8zeE)~A zZo_(;vY-W>x|rr|RcSg7o3NO+X6EC{YHucKsRSuC=r%OR^R)DM6ErVK_)BBstnrLI{i*N zcI?1Ee)}f;>a(8N0pu(&$e!HUcQC0M#bGl_N#fAD1vwFc47AcsOi;bYvQK>iZ|s0^ z))-?0jNVvAVug6Ezo73v8G^#$(jc99a}eT`X93fjz=GR z(oz<(tQZ-YUrUjZCa2iUQPWy*>M$7r^Q*tHvP=-dN_Pwikeba#(OW3I=O1a$BAYu^ay%By)!%eiSg*mC%-p5u;e2c1tvDwIRE5{K1DDe#_R) zk3Tpo;CSd^i!LVl3KoUZYot-vsf#kngaVy=U@Ai;fD@@;vuM25qo@Bci>w$-`eFMXB8lCL0Oiyijr03vEm?JGsOA~ z!fKS%grN7kWuN>w-uQ;scPD;^$KCg=#Jk`BTUfV#LzC8^svVR)&|#h9L*0E~u9Z=V zSL;pEG+1A!Oub*t@Q@}M8+}O)j9%7Eyvn%PzPokv=KE#@ zj)xq2=p`H(c?tWfJA}7G(5$d&(V?;~pvf@-iQJA;;%89Fu9``Gy+)FmZ40`ImTH~P zQn?Ow<#tT$z&CHYxoh*8h2!KCPwW?IZn1ihM4S6U8dc=_7&~B`HOBax@Bbjyuiwz5 zJM^Ve2owqBR1+}bRg9HixK{d3<;c>EVg;V!m3KtvWuScLZRqdfdvjlrgiMw9Z{4!_ zmYINKap0oEmK7{cWI^Q-O1M*mz#=J-BGwe7jNnP1;Roc6Smq26N=H}F&|X|@m$F%(W~gA zeqK2_wq^5QO&c7KeDae|CyV7p!BMa34;%W7mx}r^3D+E)VMPRGUICq&lbPC4X zGx+FUBujvsXEoNcrO1;HI`ohm#x`$$Bn)2i;CS4J2wq*x8>y?$)Ga*P6ia#q8GWKt z#@I-VHP4r(rN-w769sU(T%jF6uLmoVs<`JMFjG9{>`_PQRG+!`-vbvOi0i)ar#N%T z8Qm(Ih2y@T{{r8->1N#ez3*YoBWukCSairDy!4zG6sMiKxI0<1aI9Rt8t;1V z2YNZiD3EfrO9W;O)N|9CNh$$boo}R`t9BZzpk{fJMDUUnZ!EE-l&Ju2*+XrqKV!er zU4JgA!~5z_ufbzc?*$JnER^{+c7jTYJTpqG{jhhpkkKJXJW`kUZx4 zQ)u^W*N7EBlObgJJ2-c&8XptgFM$`Xcp>9tIp$sI6XHj}RvE z5?WZoL{hGg}S8_lrr_-H>`R1Z9|9EM<0FkQNoesEO>YW zj4i-J&v}{qYFq@UOjQkqiZutbr1mb z+I+tG?VItOXLqyMvw4h+jF>+pyOT0ojB(ZKUh!qa`bPc>nhf-(O6n;V>j|mzdCUdJ znZU2nOt3wxCgi2Kw~6Ml71N}ZK(jeX3A||3>k3TnQA7?t%%`;EEt=|zC@+qxC+|IqK^2e;kct-S7-+d0NntMIP(y&vn=tuwj=^*!DMu@)E^ zEtJ%L7Y=C66ihV(Eou?gi&30umWsNQw3yfwn`m3!I5j3wTwJ@uY7t$WJcW@Z(YXu3 zQG{o(C~T@g>$C|{j~H=bC>v1p)va32t!YE*52RNg-il4=gllC*LjAe?FnWJ%DT{`} z`uzrEgHc&SYG)FGU~JnMKJeQeKz7I62F6R?_W`V1w_c$J8?U7S_rG@XqcFQh#PSU5 z8|{EBfsRIX4B7`uM3bLJKvy)b=%r6FKR2A$RcAG;>=l^hjG@7?D4PfSN}`GKP3xgT zD}hns6^p3Q`$psQ!set&X@H34WJsN;H5zUaR@Z7FGWcE)rz;|Z!@9AtF}(jnztaI^ zcg)coV+D+Z0MK!sw#Tcyo@mEGv(gQtat+%qv@~zZI_gavn@#>PpoD6uo3!9+03pe1 z5&(t+$D@xv`eZ5ae5$7J1c4YNO&xeP$SL-}0pqNxy+p~@R0&wrprWX7+&8AyGDza~ zHA8@<88gT78sCyOl`WHeJ-)kmc#LZqyfJ-!H**aQfQP)SFzv$?rPaX)4CFea4 zz!7k}L5jjKN!ql^B%WtB)oEI+OgqNK@@+AZGa??F!kh#*Mw7b~4^DyCtn2Q8# z9ovfcefW3qgCBMbvOD&CDE*u7`yke@`=z~E2PKd^!!c_iEtps`B0&mHlPbp~old;? zC{5B1MTi3d<+^55laiRVHJ`%vWGjc+BSuO-Z!kCtPA3YtPq2P*2D0a2p+;z3;Y0%H$E5K1?Nm1=qDyuBze657suf$bTzst?t&6%}3TnRp54MTj6Ss;mY! zU{hVH7-50krNkugyLMnt77+0Cf#66fPfsvF9K&*KRa0r`5Laxv)>iDr02bZOWd7?r z-)$wQiNeJuYkL>h7Ln}5Qx}v}&zCgA?EkGa>#FZNHntV-|ImNH54#*>ckJe4<*L<< zP%V+>^ArJbMPn7DNu57Txq>92DKu}OCLcjQP+ZrDD^Vm^Q>%kZ60+ByqYhoO!`POw zC1ShUE?U~b@#v$EJ_^Khtec;2_*3e!f&F1BVV*h1K{ip`j#25zF?ua8iRAO3LB-nm z=!&E}9u!fPfXeIeA*i-VKg53jhyO!Yr0I^`&KMtAyG|SXsVGZaRX7dOv@mV+@IIib zYI4w^(ny>6NW8y(eP6QU_nFs-btz%<&|A#vU*&VxyF~0A&uy)=0rVJ^XarrKiG})-f2I-3# zs{gTeyPzm_|EAR@QT%oi3L+_GOzDxN4cr2Q8Img`1*4Bp(Resl&~*45Gb!@yEI0~B zo@L7M%n-9^>p;rVH2l@|EJ;6o-TZBK9&tGZanY?9;7yu!#Pa8=SJB=uy(FvXEz^)j z%UMNiom{sY`I9j=Hiq|p=y&kXKfJA5!QHV-j(b+F!n@x4eym-$7Ela~hNiHeTVw(* zqVn##HxYqMt(aUro0O7It-*JnG!5raMtEY(vglHY+Cj)SjC%+UG$mEZLC5X3dj*zo z0TA+8S#TuenZ4v>@J6|Mgs77w86(5euvV*fut|^_tTJM1!^YtZkKcNdd<>z&bKVA6hm#4h2z`cxDzHA^4TVM$>?n&OO*K z-FP`Lb8$S`6y@AyCKK9i$_Arh8L*yN=l1R`egB`KupQ9;I9 zj8Vv&uVU!W5E`}W?nwQuYGl;bE`{J%LU26dh$kN}sD9ZnBB%3fi!dIcU70H!PFJCJ zQ$3S7!77klbzCjWPxDYwlRG0cm8A7=F=Us z28`?0tv9W4Vu~e_a1#-4A=0$sM7cPl?N|Yco{^>_NLJ1@0aFP;(l%>Ll$&#|fjJ_{ zBn5^XR+(g*gHYmEjyU4U$EVD3-sEWj4mPp5q2X*{wVs;M2kHY{lqsjhe@W&WVG zrl#Ty0Mr4tL_3ww9cUJ*&b!A}U8G9#owhL_TefV*r62ro#~{07r;nAZR`(}g*147! zB4(fxnRdh3Wk^l$oNlNBg z>IWYTOrDm2Bc(VsmoOC5?d}BHvaM$jn%pO$3s+U8Ok zJv2!Y$sT0IB{IA`S~3~bR~OPPR%6@7@PXg?5BTBjT@JE4rq38JzVy9V`^Z{5j;mYA zB-pg28MC8jjfN*M0JQ*`Bxq-IIFyd@!XjtXyxn>P>`JEwB#NhXUuIyxFukVnTObG1lVOllBGN(rfFK=Wrlu8n<&Ko8bYnW=6)OVHArSx-{ zNlwzHUh1E*=@m0OpUDXkTegnj(oU?RJEqGR-}`>7Tf5#EUcp2ze(hNX)hj%x3U<^F zsPRIP33_`1W4x7igo~Ca6lo`b?L5ilLnHd;r)Jz~Pz~C=Y1>E4Dt8+#h6sf zMeHk61lzW5#rr<=+Z{l5$H3$6dsgD&_q-Qt*RJi~cZ4JYdO@Nt5Lcm4bzd-zzf>N* zxAcwpm>nII$Q@FLi#xG~U5ZV7=qd;+)b(>E&Ygyh$yy=1TAKt=$|)Wk3CPpz`)M@| zWvMNmI>L?psk}y*`LLsi^e3mUH`i$H%c(Qooit&#ynkxUM4NRkod1L5;d zE^?DtH3#W3a=f<@i=h*yk#OePW<4osNtOz6)tY^34-fm`IByCk_drCF@wocqB~oOm z9-NguXX0qq{F_N`gl-H}phYzG$?;GX^f!r2^Kz#%F0u=5cn50GPHV|d?(ey1BX z><*Po5TkBNpVqWlR_f^^zpC&fJySC(2}OV;~-GdFod`+`ciYIW~khux4zKz=n|!G zkpN}OXo1Vl(d%iMU=PzfEiH?bB=NixdE%UGvQEjE9$bd{nr=_beM>Qt2?DNZp+*9ydk`!$DC z6KgsGb>bLI!udW-N_kQZj+FAm-n0r+V{EO0&45;GV=71GllCPdRR^aPg77(Ax+JWa z+_CsBp}6>>^2f#_Tw6r?f}fhoN$$*9-MD+3$hK``_&_Ijw%-HeyDoiSFUL5`EHN3y z6D_yrT8B*w5aQ^Ja3jv*J9W&9*2A`%6nQB?)m~R?&_w#J5!cWhj(LA5Nj(+q%k(U# zPprWa;0X!&wA+M5J3kZ621L_Lse7L8Kp@hdB}$wLsU<;Ni;bp;Ofb>yN|N?QX%|Cr z(jtOzN`{h-WtplpMM zqO2L~l_2ND=yNIyh8keu+Y;4;jRQpqgk+57E0oHX?wNF=u%Wm(?Z-6}G*-^-ga#Zb z$FrZ@^?5k^OeUD;cZ~-8^a*1;`6%LcAEqFtUrnUNj#YKwhZ8xbN6E$}bPWsH?I{)T zHI;jDZiQZ9SvTe;;M%*XE7PuyLGEXv^t*eZv{9w1bAk#~L}l@G)MFHAnHX19_qLc; zyGrp@RdC4`Wqq-K)uPt5?K0yWsTaBxT}$`P;$C&9N!3N;iISGB9T}5!h{YOb_lHwz zPnqKtbHs7kx#@H&GW&blOsf;zbSKHHhSxE)eJ@ct#ssI59z?M+>Dp9C(p}P?NE)?p zk>Cp%cfvs0SbJ-)8t=OFy*=46N?^*zG@YYb(dd(e zK?|Kg0?`Q<_ZqQSKf$8BkeyPCnO<|YByfP9uvqP67@E-N&qTk>+_<1O({qHza}wq- zjsS2R02GHGe)u8)$5y{+geuvX*hnTTjHJ2&UofZXD~hmQlF(Ozy0J(M%0^a6ayr5^ zVJyvUm5HCF?+}~ZW|>;Hvu+@)0Gnin;H8>#)ZW;A%Z2y;RtJ##He+0gcfR{lJkl?| zh|x1(8d<3I!2oRh*t7(ZP+CWp08qSRr_^H4+WF6;P1uqiDE~Kjz|_|;Tqm@2!}Sn{ zukTt386!@r4%E8_#~yz8;fspNk&!1sa3BI2Y|uZPaF0@Qv=)nAUQ8N+v2@;?>V#UL zt$Lfh@?%QOM3Zn=plLvg;)OC$j}sbqZ8yN~3V4?Jx=@>vjF~2TI<-Hy*h{-*>sDOa z0pvcKW9*FtKC*Vb4RUlox~@iR^-wQNtJZdT@&kxAprsw!DTw>l=wEZS~$2 zi%JQS7An#n+qxC+`M`(pgRV%kPcg=e-+d__Ub7a~w%CKD>%EXvBg@B1;sl;^GiKph z&V;Ap+ij5M61BIJ=t7JunuJp?KK~BuNrM23+>i1~mj3gp$_|6HVfEjUNgiFu6po5Q z(6}TaR=GxsB8pDoRXs}#5Z0LmhWSD5^CA-OCdMVvJ2kpog!%S;UkqzpC{Exa zC5zhr#wee;^Fo)lF;%^4akzYX9b$K*hWi9#eAlJ#!gF!$YEE&9`nH!+YNMfo{}r zZ)S|ER^gqOz87oOt_`$CB@sE1+P$y3XKXGlRo0Ur<)iB_RBbi^B#4`0BdzIN$j+i- zs`tXySyY-(TQgm@3RYW$NK^iLQYNUpsL#i+cT+rreqtfQCl-u@azPp{XA3hX*+D1J zV0Vwi7g~o5)brP>CB_tnY|u_tzfL8A>RZcbH_{ESORx#(&z0&trb;M;ZQBtwx2Xz3 z;ni1_#|lI#sw<<%D#x~M!+SsYp^icBrNDUcyWfjP)~ros<|B10lYiIo29vN^B9}n~ z4x!?78Ug-Kqx6fByn#D zx(?e|5K_n!3y2&M+U7_k3>oCdl5b-fS-$lrn7ts19o?SeLX=U!6cChm>Z4SvULpae*bTE4010Er7wQZd-2HHwN1iF zC!ZrjX;F>clHL!o8%QAAoenA6jAi6Kk2pNnMp`L_s@SGpDoj6QP(zTw?Jy-|D%(#4 zpcWTzLP}TX9BB%~?mn$QlOh*_^ z1E{9xBSf72RI#t?b4#`uokd{3V-qF*eO zOgOurV%cTMEr>OtH}H^pIDlkIFnb^`$vmY*Y&5|uSDhE%;uATU z#pg*RZc9knW->|HH!`Euqf<@3;#nqpjpFZq{|7q;IoBEEyDzO7V^k;+SFH1RV|y1< zw<(4N1!-YA(MVrllqG2{(uzJHF!n+cN7cd@RwEmY8kZ84ZmF)%{9yL1n@n5-afcNk z4kZeZ45(bjsaA9uoXJUVqqMvG@ZP(k=AJ2bsKDezM2u&b*`OuOSJKA!CKV%eIS)yT zHW^3Yy3frt!}tG;Z5_j^8FQhNlEG|lCS z6RUK-q|uH@P{U-4KI(2?+W>-w`KaeH?wJh4uKOc|C2?qh5{D$*O~Tyozz=5?bAnwh zDH6+^0MNbp*t&Hq-u;2!>Hu;M9jjK~i;Le=F~;uLIplMSts+@2Xj2kwikO*v;ULTr z04#Ax!2$-`sE_p9B!2nf*5zjiq!j$6gPXO74*mHp~ zuEaZj^W9kU$UY2=%43RxX!<*;N>_P3$#_LcHZ3SwN@gRyCR{hY#LVDPUh3)Zc_&011qk3DKFHJ?g#U@efek3M^6uSIJtvccgLVk)y#0gZG^rA8qH*E%~ z?2*4v;^olj&L-2&ejWNG>Dzv@D(P~ZB8>{M*r^1Qb9C(+dUxEqWh;LBKYj$8Hf`<@ zY7ZS#Q&aezkNjQ@j0^%eiAV;*TAYgB8b{4=!k5h;Dy#du5|4IyLO)I$4^{XKrqrG? zjZTZ$j-12*QAwyJ`AqLD;PMJ8RY2WKtodQx8|f^V4H?VOM3FSTnqu)m1%Lw>t?-t- zhgZ`uJ^flHov?+QY6>K5;b~e$b>)b@PfGV~G2KUmsM{9m`R(fU9k|wl@U*UhB556w zdTPP9_NYl0YuqJHm58ZbrJ9`80-(LGVI}OvF=em7vSGspTz2JE9ZKz?9A)w37< zh1}?`x>;sz4yYNG9^duSY0#o8R*lD7f*CN9RHTf;+Skde{xpr|T5Q7g9Y>XS$^iug z3!rwOBuPkx*A#=u)+5F_62ke!fC>sy7YBV#wbWduUt0BwIZ|gP8*P)i5LSj=H*Ax} zc`Z~K7iXF!QDZ~j=R(xC)M_hr+oZbq^-eFfn_<9UC`u z&8k_Pxq5@fHL<`c&F8VEeN|7P1i>zyC3c!}6J^q8ffm7tA)Sh=T{CGhOrL8mC_v1Y z78f#c)mc-DM{Wo_nkK1Op;xleIZ7A_Bhz6ZlA*&)Mx_X+pv(YN1F58F5RQkp~8kl4d>z%btGSO5lNcE z5!f=q`BP-eSx&xAT2jSn(zuWKB~*1@lK#s4D5=C37*Vr%bFOZ`<4#OXO?8O18;|e* z(?4TSBXd+x@Hbj7L}Y9?D1Jg2Nkgr`&nL@(Phxc+^Rv`0YpEX_BikS^yaFepJ4i6X9`ed!R$^6fi~NDjHh6FaU`vBrNxve#B?8zx-eqZeCp$Jz^u)L;!Ws{r=!bwa&lcrrLwMzE_td8C zz&8d}O0t@Xn$Msl&@*F$BvY1N^;sIiZ1`wx1!8jT~WeKV8VAj<@5i!C- zR9eg|VLp!m=_>!DY%8?(U1|r{3(M@pQ+MpjWBd4aY#H0?NC1t*SV$YBH#XWU#`U`u zf>AyLT*Cf!&uN)D-)BhwUJwgF)I}Sbu)Pw&^2NR|Wv0e!BCHYD{w84mJ5m*Ubp@fx zX_`8H-Gav?iqal7R?(H_dQ{V9;?56TCbqxXNCCl=nBgPwnaNbf%K@P%y+&<8n$T`B z{WpR7j8ZoYgexoWEDGzw3q!k@#>_ivJZ-9pc31WC?1Zic_8EW#vgn>&8|7oFWG+=P zMOED>jZ~XRs?6-DMMFOO7rZ9Ey}y?-1r|kzTD$2u>c}H;;_=5LmCX0^_D$yk`@6j< z3@DZ+wU0dOLPrIRvECse!g?H#3|eLMM6m?Aq#%|}bSM;Hu zu)YDLFVk!19hsybP=lT{%uN#}Nvl`UY$YLSUPIqNXv91f^cf)@YCGM;o`I$%gG?Jk z{SL|?pGwdW*CXcBoy zN#bkIXj>Ahb?B6&Y5S_1uPHkU024v3-(CQUuah_#qNo<9S8sDNMJaiw9p{o#j4+CJ81T-ZfAK|lt3bIe!M?E0%*~~9@hUgf)YW7^$uQXl|*cRBm4%HH1PrA*O z30uB|q{LW~qMF2oI}cWRyeeq$%(VvO+6Bb#6ts60L&r9IcNo{T0sR$%jA*WNbd2Ue zQyWgf^PYP;PCIpRhgN$a@A&J#_OgsZH}azNQSrjwLXRVIP9#Nvq)C;zT_(L- zOfkYw%ShB_?Zavps!A*_D{3klflz4DzXcmshZxPEuamx*rCq7xqEqv|*<{dtwnyA| zmbfrh9SasLz#o0?vzRw;UWZn@`5=iaKJ^J4b>xw;c~;hQ#G_|3klfs&Vuk=(Y@88I z*n~T%g8KaQt8^(h@v?V;ld zPj~`8d*!nIZgWb)X9rNC*Sf1#N1oYgxks#DgZ!1+~lfW!aRI8eax|rURCbblh8e!rCkEB|ytGXE21+phsy8oVZ zA-|S)YeIL}0T)0s)J;VxeB7wUV3_2o%xWK9{RQd-G@W0CY62Cd;^T7`lCgR9BSqp( z!(6#enae~IKw8lX3ar3X z1^#psJLynV@6VN2T!weOZ5nyrcfO;}V3u#kQnSq_o zkp|`8-Zv^AD+GA7`VE7yv(;M02Yty@iUr!n8o&Xsvr0hjJ^NS5*eOJwF=9U#gU2PU zL&|c&w9UAjZQ5=mcDL12HFe~iP6e2T*+h{=67f!Pq9#{faXH@g&JGyo`f>it&%BYXBMdXb&Pt`{@FQL3jHr=45oCYfv&aCJa=$;Y8KUM&A^1 z&B(Qjz&s6>Y)o$n4_dnBV!;{x$&!}BM+=Y}>e*vDu~?tfguQw)fH6i>HxhUbdjCQR zq%(5*b*TWYIKN-%~Ix*&58B8o3;_7o!1_k9x1)<`4cZ$K4oOV61d=F8g_@Mw5DbDVuecl+ zzoW}B?tK8+W03PkM?Wy=2<;Pe5Rsda)05F{EB z>JR1zxk&`OhPk1Af2uUw$60`@-jYRqQ(bBG!6I$E;3O#JAjubMcc(=|}tu(?v|>gei$+OZ~QuGnUF3 zCLfZ`SYWh>0x}`47Li7$bdjrMMsIC(+AHN7`YREIWd>FIEL{V8T<_D~*lcXuwv)z< zlg7!0jqQewZM(5;Ta9ho=DWZD^?rb}JLfqw&)mb?$~pWDUQwaaCT0qaJFdK&`=whA zi@ce?&?Da77tj|>X6}~kx=@HpE)=b9`^RQ$sRWKhiRmdXXt~KRGu)2|MYV`UNTmAn z_d(tGO_f_$fq1G9fTX(n^&hL9v%WZS!)kn$Ys=(M^a9he;|Q$z4jP-9=!BK9X`WU3 zisiltnbQb~);b}M!m4b0a7=WM{ss$k64^%F13FxQ>4b*bNNM9>hsPZe7>ij=8dym= zH&RlF9_!Eq&5_v6{z*KpQ(`1|4J5xh26cO^fAAH*I&jqKMr3g_n|kAx+~M4I7sbsX z(Z0ksvg6mvK}#XTkPkA+_oK;}Fc_z>-z_wf#v$#7miy{M>I8$ZCKgwA!A+7zq171` zacFBbaw3*FW{@@vM6$n3Vz-%r)^Oex^VP$LlNnFaH_N~n8_4TeQNsf2xV!pTj@r|b z=6!JAFw)sboUjaFG~LgDfr2HT0V?O5D6JxT&F`l9nU#N{J*`h_su!r6dVo?w1$Sin zi4CpHRoed<#@nw@pNAvRsZrQ$D#AN85yetU1%?+^36KX!KnY)@%qgd9J&p-X7qXIk zBgg|YPcnBtn{8;tvC@X*oyORvt(wR*On*d$0SMgxC)>H@TCzJ!F$@O$A9vSLsz?g9 z^N3_J)tqw*A`KZsn9#1Z(6Fk4RYT50i8aDGRFTNT1HVmx%s>Cq78trs2Q|{X%%32k zAVhxW5pgD_-T{=C#0qu%v`~0W^3eAe0=-xpzE6j%Mk}!<5Qt0JvdG?qLr;ocdgaKDk5TA= zc0T`^QO;k$*A5Z3U$M10As?Bv`E08}Z{3~0JV0{v|L<<&Gg z;5Kn?mUT8LW=?dsBsC|GcwZHrl3h>@ph-{k-ak1ijEhE+wMycDZN-T^MffJH6j*@K zB1|!0Y*{;yp}{p;UOxPiu6P=Yg|zt6M6ifmcUw6EDD?d&Ve^y01!a{&CD(ZpU8a#Q zV{1{u0Kawcy&Wg>UM7S9TcC?os*M?im9-Z8cfU z1)!S`zK<34l~A~+X!+|TRIl2K?PGKDBt!ka?Daz~?|=zUvy>_O(4Psh4N|0E426s9 z57Wy&o zZX7XTU*=Q7-H<0p`aE$v&OfwF*s_hue5EiukrASmZSHzCj`wDfF;@H_B(o|{AZo1g z{s@&z=Q)R|26UFaXeT^+U)w;z30g*0c>DU_-$&tdZzA;ms@!Ev^uFTi5OyN&IYt#a zMoCd``E{ey!LHHLl0Xb^y40JD0F1-y^X0?<1Y2Y!4*|MKS$m04P5KA@$ z)0Ry#^NpkJtbhvF`ciPljJZOx$dt>^H8myHJ1{00Ix?0&tt2d1?tMPucs;)*3=gNZ z!Oy00v&CVrlauF>xDg(AHdVS0vBs*wfW^s}Vp3rsN0Y^BH%<^@{r6YlxQv;zI1&OT z}_FH)$g;|(e1p>)CtILUxTxndi^s7|LlslW>MT#z^OtK=YU6k09ZAUv zv8w(QQ!Om*2TfpblEww80gHbPeKWfA-c9k58xG})DgNuk)^AFnxNQ_`l{?A$x{5$4 zWv+^F^0!4pBZe-$JJIbsR&Ko1=|uoiUT?DP2u9GXiTL5E7a6Rr;KBXirMl-~$r}wczc=Y4Sy(@om!8w0ggm-{+6Um7 zRHy2WUrxs2*UXjYpd&Q;R?J~y5f@=k9+JS3jtMx}fa8Jpa5Dy6Di%^p9sW(r?+)T$ zMP;okwBe3N3q$2pX16a_4j;Ie*IYk$lOr#+JVv(bk+y2#t{z&O+PhoY*o7mfVvpgsg49{&-w~0(-66P+O!g zu5QaLrWl$3pz>gu*>G-+X~>#AfkF)^Az6f-{I#R7V50xEB;6&Gx!^M2<;f^J_kAU3 zPaXJ6-TMRw=yuK!=nYl%v5U=Ow<&F7WjqYIcalgakpEnY3EkI@-lG@s9^EiFy?c6y zKF$;VkZy_6O}=l$cgvvBnmg$(FPS5}@t-Ud+snS^KO`Fjy7TkUYX(`kSuFnDe*NQX zwVH!e?4pP9C6kd{rweDTw>mXW#kr%~(8^Bjq`0D1j4S!7`d}$e=W8iL_}dQDz}bIk z`HV0)2Q!HWD+C=N#=y#QMYvXuT)NgMTszzi{PLE zHcaG!6Fg-~l^HbQ-DN=ae5EjLW88I>jn54;Ig=HUK|MMd+F8WmO;Ur^hJGJ#wMkh~PPNlOZ zD4yHAS&V75W5xwrSwGGpA&d$n7gtYi!nN4(m}9JfiKrF0Ix&Qe)d-o2AP-9CX^{5)96z-NsW?_^`qv zXtrLdLypZ!?Z_%L7DHo`o+ro>Ou95~2zP>K8~sB3SvIh5quDY9v_)uUb=H~h223ca-NvKBCp!jA6_@@WF;F2hbT$ zW|?J443kc5d9N-owVoNBmy}&AU?AIA+*8NSjA7QhlZ<=>W1Cm2Jl0)~#7Q;y^C$Qb zL%WNNKCakoTsuY!_-rN~w9&MnxVD|HW*X(ixE%^E{79lf>l!)^cIuY2E>c7tG5dU6 zR9wBZY^mc~CMKKS605XAW}IDiA?2uC6ZC7t^N66R`O8U@@yf53-_E0h#o!!F>*|oQPPz+cmn?`;ZJZn$8NVrITpE z36kng=)0p6)Qr%NkUQK0B7Buj{P^H4t{}~YO1#HXQ8W?o$XPpavecmM zKKU{QX!+e#5jIk_7{%!AD*x>kpS__sk``5pBy=Fh_tNqS(W!neH5guKS++n%=Zqi{ z`J!;5ALuron;5sW=(AQbxA>pl=v9R_(3PDyE9TYO(NFJYn%*FRP+}VmtAKV``OxE^ zVN(mGaA`$JQAIIYnU8+3-y9R}8K8R%SRI1YL*$Ix=MkJ_q#>MWc8rcEimA}WLyhxC%r?x0tS2{*brb9x(<9b+WjHxM zHxF>yfyiL{^vuT|vxrI<-_b`s9YP+d!{Ebcqb}O?s!O@sEs=k)6gaX*u{)XR>#p*D zPX$l((OvlVbNlgFCwNd4`moZZ zV6))*Aw#;n%tLFHc2@;3a)T8HcOR8#sT zTyv&1M2|@LCK3TlLBI3D?LkY!e~z#p;PJs}Fwo%{5AE+Bf!DB*K*>h1Bah`)m?3?@ z(1U>?DS7IEFTdH!-b(`))SE$(aoSPZ|NaIaw-yXN%&5~;5jcXvaWQuxU~?2T%VwVC z@BjqQPH$Ud9tjFBNYXxIS=atS#Yc+OGI&Itlnd!sUUd%A>c?QzH*fEgSF3a(X?pk6 zk{2!YZ1@&%C;o<@8X@!23atwc#5;>Ks^5_d))-rZln;pU8D+01-o8M3p2yqhXMaS| z!DGTs9EBWd^g^k{sGVfA*mI*YyR_RFS`F4;bbr_M2ZND2M^lh-+y-lbj_9CH$BnSm zgT17qoS3t!Ry^`S>El`^qo9nNN-67vRlIC3QrJp87LyWchwaFUj-ShpiA~3~Jt&S> zX_L#z34_885>5V&BB~dLHnXZLqOx0U)l=J?R846WM40a~Oon!46G;^cHj>HwUinoL z3A*w|OM1b+)~jTb-GE$7@nGWHtHbQ}0$^^yug#XJH6^-!ZB~C;@r~ z4@nFsc7umjg)r_R&f0vbWx;pyR%Jt-)`I6^hLYy2=|E(m`wWI~1M|vGsG3{Z!e57% z5I8<{RYUAtJ%3AZ5`Ksc2;XjNb#_A<1cpy?+4{XOm$iMJ{lgabM8WZ`*Ria(_x?oC z-1~aM_6>W$U+mAgJYIX>4n*l&+q^aN-hC1Z2d#&7rM3+oUec)O@e;lkl~+h&(ygi(_xdh+Q>3R&0u7!<*WKtcUUcVp^sDefB6`Ze z9(~m5XU3xDc1e$dKVGRD;KOMFO2$UCTx5J3UDbZxP6>jTP(4PZn)R>QkkZ1y6j9+@ z&PhEX%hXuyuZ3S7XM!oazV91feT%iMZlK(55NHH${h@$(4}a^O3Y3j!jpn~>xulrd z=5e_(&TMmMwe7f(N>mNhB4P+ku&<>$)rdFEf+$2xgNr(W!J(u%FM0M!MeST-yHDY# z8tQIW-EJ}b1p6bh2~`KpLvAJD88~%6M)o#ij!QF<`z3zu^`wl(Dvj+tleh0QE@QVBC zdXLd+IrJmZ{Iy0R6}PM|bepN9F+zB5ls|Xx#-;1Z7q==NQU79}O`pUxmr%-WaWpo5 z`{xEvKuy)OCG6W9kPgz;H;{*BhI6YC^jcJ&&-OA9d}q}UXfh2!MK$Cr4KX;{InB*jcO1*F0Q*|j;F=fJ z=S1kqzO!<_<2nv>4#dP)ZU{PE!hHTD2WgXI$I~om8Xh!8dje7@aTKBTY~zVyy!!5p z)YKj%?)6Z1{b|tfKjnas3#)C*jg)+ns!>yaxYkVAB;*ZC(rBh84R(6EVj`VYhDO6L z(dfC?-B?_j(w>G6)3aoSahR+W<4`ARvOxthN@K2xAVGdSoY`ZwL=EfO)tGvdbU||U z9V%brK?ZrN0@7*)utO(Jy%n%M2G${N%b{ak0)>S*x;wGIO^JAM<&P|ebBB|H&>mjH zB<7wSr%Bk`a!dMibAis^ei_4Nk=&v!SZS?GMEXc2jNi_*SLdWsT^Z6S#@1?EVBRp3 zs;mc*21kT|eU~QXhO41m5fdw5#0?H-{!OZXP4H{($BO zb=-E%Ne4dv8MGmT3L|XUE*Dr6v&6~QZ97H8KUH|h9Z`4B5P3^$e%BDM=24L~>lDUj z1oIM;_X}7!dcXJ1Kp_|awojVSvmW`lzU0S0oIk=5`>#u6blnn<{)$Q)fJL>FxX9+d zBIdN8%IdBj;FwS0Xl_MtcV1k$U+;vRp-$N9S763Tu)>v5(Pc5hw|}!pH)UmI^~dD? z4I$UYm4izhfz3QbTbvnCUD*Og_II^)HTWTQ9t=l-3TjAnQE!GH+D7a?j=^QS?A-wp zplQ9ySE); zDD4PGvwA3F^N~y7`C9xGkNfbZ;kLAMtpy~r3#!Gp=8jSAzp&L?z_~*O_qRdpy%5l7 ztX?QCQMJcH`E^dWv!K*b6j>vcL#yOILSfv5FAwm7NLDY8ec_bEml~~JzA%KN%iC%B zj)m4{(916uOyrWX~z(DNXAAw)r&^R zYaz*f>+jWx#(*_oPiJcr;qOKxj?hfJFXDv?JTbQrt3Q7C4H5(I9wLF)c|v;xTj1XO zU_`C^jj^}SVE8u?!*B*%EL&h{Pxcc#GR$>b!d6_=C6aAYpGW<{ur8 zVswnKknd-Jst5zAmuT#e^urA#6HL1Vl2PjcOb7*?&ug^6oo7 zlwR{fVl~xv6+0XcTX*|x4pcdWSfeqy*Qd*k-J*8cp+{7I=tbh&K0}ZF!qT}=$tz%U zdPg79pwvP8N5N5mq!ExTn>Cr>jPYFEY_oaKT|Y$tX873$h1$Ee{DVtnQgJD0iZlOj*7nbSn!R1#aws}Y|okiv~Q#jf9sY@;C@?tt{`9qhSmY_>Kb(n zHK!PSa|5^TzQ=7pglq21JF;RJ3sNFX?oGcs2H?#~C@WcdSd&bPZcn!B!wBHuN@_d5 z^cytySs)dDw{yUpcNvjBw=~M$J8Hjgk-~>8P2q6k>>%Y^iI1S2{nBpM*o6 zoXP#`KHHfYD&=RaulkrK zj^Q_@q&l-|;c7=FkFG6yOs779IESj*=gj?CyK4X8kfTQO8NgtwQH=fIWtq>V8Ns&6 zm6impc+hLPc&rK+oC9vOfmp{5dmv>zeM9@I`U8wq_}R%vfq;#nJ|ndaWfo%&jok!P8C@PvM{ulj!WqSRR4 znRVQ+JGHm_6yxr#-GERWAKILmTBQ2rC<6wb6zS=h+D44Fe3e3TF?BqN<-C6(BMP9# z$D6>wzyTte=>%tgifBpSO|Yuvc5K^NBCncg-Z0+0Q29nCCqphx8l7(1%4)4ry=;l@ zYkav#!C>WJ8y0Yf#k4NFy#PQi(g1(zYX(Q~bcvq+n6RK7y3tJafjw#fPL7;*LiOmm zZT^YM;My@|z5qC`M%JQ4^6Bih)oJ%p6LTE}7vG@|eKs5Qi(MCng*mL-_eW{9?IRMb zf$iV>-MljI)R~U=+iL_Curb-fZBnc-2r?AOS}LzBaQha+?|oopH&V8GgKp`(4e)4? znWIE8rTW5;9-(cD^@5pTwd9XE8)lKTsnac*M`CHNAIu4SO|}0HVk8XA!~%NHfpi## z*gKcfFPzQanu84slKo2mv1}%sPkfin9-mTNyTJ zL!s;5WHy%fvak^=Cgd&sD$L0c36<~=f4Kr?a2s^9Z~2&*|5!cl`$GwZ?T=HMN(OzTj0yIWSf{WY+Gt)g%tkGa13p$+!uur0#-s=8Wx* zeH6t0dg!#r%?Hgp;GlpM*`?hVnGbfma1hRER%Xq1?1~$}sjVj|B0&|T+XXV^16!zJ z!o5BEBWB%edDxtlF(N^-(^IGUB^rI?$*n8J%}DE32E3ZNdIf;n#zO%U%!=c>*OpIb z*?k}irz7tpS<`U6IB}Or0yjVVdB2uCTff;w!tn6$%>zh(k%pw{OAX4z3uQ zJ|{2h=NxDqXTrBVw-_d^Yl8UVKCoOH^zSqra-#=`d9Q?NldNp`rf3kV35qed(e0Og zhtZ;VL+&#=n~MM-)=&{d^qj{;Y>au!9`Xaz-rnBxDiZhh1f?9GU&a4xrsnczISo2j zToa;OAEmn97$p*=wYo)UO35rIt&6R;;CuO+XF$^d5!iRY!TStUfmla$q2=?VjS!;i zlWZ=y^OWzeC!->N0sP<8h$_38<{~DS9cSN{>r4^!+j7`Pf>@=Vyo?7D;k*i=>Q_&B z;?&J0=y*sDRvxpDqwqkR2*8KV999m-`|hxjKP=Pi4iy_4j7+zGjhsJ}`?G3ZoJ8D& z!)oo;^SefVnNS@8i?%}v`G+*4nNq*XDX_V>mzfvmlE0tdBPO(@q*({M@!tmv8sW)e z+!g9M*u3vX^Ixr2gUzxGZ9C4VgDGqO2oB8@#8Dj1!|Z(<;n4qAO!+qac(JEdyDP<@ z*Y*W&0u^bTVqaECqnu6G$q~PnC~t3_LutW1Q(qRZ_9DsEI=*Swwb?A13R+7GYv}md z_osmDmJe7T{<}O_bMNLwO52qbHB+!P*XOFU<(ScK z5CTP@B+)kheb{gs?K>`ck)pc1|6AHWb`+>8uH6#NpG+`^8rId)_26<({bZAkO9nAN z3~DQgV5VfJ;gO_P%}@#7WR~A;fM#A>^Oc_Yr@voUdeszY)E8B)U(cg&ZraT}_01p% zYJuMGmmuJmBYE54eaQ;`9VTOrG_x|O>wECf+5Z?g_ zcZbXXNbJ}30v9R*#MpcsQ%j%f&Ej%rV&$OY?)}^%=vGaweO@5wX>6Ge9TchCg zzl)$g=52HoxW&8B2858ba_JNmu>8d(hL^}&pi9B?Zggt-k{Htb zkb==71i(E`ZNEd&A_F>oJnq@a?-@}O$Em5QezV~pnK$*Ify_%d3ly7{lH~jh%+UBk z9)c^tJq{YBl*DfP4ig0a$fn)d=dLnC%oc|T*n%zLi zY8JX+@iQn(%~j!^KmAJpO#3x)kr3pa6hJYk=^Kv7qu5FFqZD{2N~>Jj@b=IS0Ch#I zp_O4~FC?uaG_o~6hn?J_ceS;Om+BSK@dVfW+$nr_Nq^}dE0w zut6~5cov5752M{LT+oUAFuT)@ns^)~{#j#4{)d^oCKPcQScQ{7X6jTAoeam(f6VyF zKAL0}%ME8NSr|V5CL0Pe#-|0|p^nq2BMpuYq2qs1I=+5w)C=8G39l~sgH?d}P2723 zg}B(4HO;u|ymgSi=u{-!R3x>py=iw?VtugN;eHW)CHiBK~xw@SO61>T{Yjbd=s+A^>JA(A7@)3CW}Xp3M9@F8{+h<0*sk3h&Xm^d@C0 z=>BP^cj&Ue&E?;7$zC;0h0wc$oM)vFgEoc08FErnmuocr_67z9fd9B%<&3k#c=9Uagc& zaW4dg>~w4&mC)TEVW# zCvt+qCvtoy5&3|G(J;e%Sv{KogA*J6`OMk$46i28TWHjUu$~ag2;oI9J~e zt*s54`Ge35etQN$F=hcznA1jF=<{h7(2=7j{aKNsb{rzV=0eQKP}I1>f7t<%(QKVn z|KIoJ8!oY9Ys$sH^T8W^QCjQ%M;KAK0nHe}^phbTjHeo}Qg5?y-JL8E)!!8%)DsNx zWYXC8;*8$@kiaY!#0bZrC<-P2L&b^uj}7{fsZMnno4g@Y4B7$TH`{c50D!EH2rA{m z{k%5kvdoF6j-GiM1P}YI#_9if+|*_wiFrDGbD&0@JJ1SQBoK+P z{(B6{hYlQ8I-&gUliRuPWmFIW@#~GHX8f&3cV?p@WSQ7chQA6&tyXqkNghaPQO_*# z=2FL;O{iM^e!JcOQi_M`&Hw>Q0(#pHF!L!bV#wQH#RzNcKLh`6JEK!eESx!au)KOiyr8qYEE;-8 z;mY=~6y`e0AYe?de>e{ls)q`4uX@#^#=( z2;*@`2NCfw-n=Lh3Vgpz5b|B@aQ$&TfSn@H@`|d>=tw3%_Y8b{ya8GE=(EDt#Z2 zLz~O+>fwnZPnQ_c`c07q<G?$R5wTG^-mf4 zC#Jz_eP{kNN#7=(L&c0aBlJv%ma9A>@)4As(H{x|D~!1K!~-2JyU)iep&at|z5I*R z)aTLTcc>p!FW!5c{eHBvZO5x($BT=@O)plWLry6_u|`R3G6DO9ZieGTh_zSkS3P0I>t5C2OM+q{snpr`j6PuJ@MCXdreRZd~+e|{w)oE07RuHL5S_|LKx zCt=oaM;b~WjQKRyq@?c_fPv(QR2hqK%U_Ai|4~HL{0IOtcVs`IDhY%PID~PL6Ee#c z4p3xdaHI_>@$eBQOhe(>U=2nNT5-9Rq6>0-xUL_lpL<<(Vq_g4~~QWILaUhkrwT-56!0hvVC zZyFzA=)~kYqe@$9`8M!Xibfwf7dzxUgz$!$~7 zfn8JiaycmSJ!9&C1?eA2EN%Ay_}>Zi3JbsBeww*M8rr}p3GQ)9;-*S&2Y|hl3jZsq zX!(Kjvf*Fvi^_G1@9|JL#8>LI|M;vParRyQi-3N=hIdugHmG^usqu{>IHqDmb~0Nd zEBAd{)`57@($_x!R;F8A^ZdS?tl-;0ZT~CAj~p<;f9#i(*+)x(HN4Yk9Kc%l$74t$ zi0+mcPN7McRN4zjZIyOm&E_us1LZcl%kXmIzlcM_ClUpEvcAoKgK2-BahR_a@Ukmy zd!dYL?{U{--Brt|W(!Q80gv=!wfmcy#3=rF6~9UR`spanhZVC7jHNfDhVi&~SlUxf z(Tlsmz=_qZILaGj`?K%)7eRr7&tdlUu@4cLB40uxnq4~ppQg!>v)=V_^8u=mHQV`m zf4)P-z?;zalHa<*-~2mwG4Fp&(}~JvVDrvO73BzLwAOR2EJq}9I6{oz`0s@AnLODq zyTAP912K;%#sxT`VoSM7L*N=Z5{Z zoYgj1BD$_lGZi(85cBA^A2k8C1Hlv6H?Y=QU4#ZYwNAVvR@HClLM|(& z7x>qHmtx@&btczV^X|gOeU@O^TpBBQigJ_IUI{F^LQNiX23IoPtDwjo01Ekb8wvaAD^O=DB5Ep{0J3ph&qXuJFv(Ttl~4yLZr{cJh!a7MV3O%) zoJ*w}U1C*jBf5PnhBUh3TnC^kWYYr(*zMd+77IkXY)=! zKD3>^MY8Gu?#$}NrTWF!uZ;4jZ$5E}aMTy;|CFEy+@7gQIvmVDKNk@4fT!XS`#OKV zLo6bU&4ukAL$;{7agC~7Q)+2tMmMDSMD%|6k_Jkc^$zj=J9XOpJxo{$Xno!E^6GK_ z`uG_N50sm-uz_sv1+3ID&|FNsk0J7R{WW@cX`V7C?!|iL4*ELx17L#^$HSW4pAY)P zCc&cr!SL%rAD$xsq}p?D=W9NK=jd4)ez>owKKf=5a68iN`3vG; z`gq^#yu)T#W{OQg)m=7379UD>-ZSsBAV=Vt0C$FenFCRHOKd!@pB^~% z3ge~$FlFHFri{d>GYc)fCRRtUvqLQ7PL(~iJ&46U=h3#;-zMv@Tux_^`73*G4U|&E zqT#Ni9t!2yB=%{F{nJ8Yyy+Dg;vssDuA| zR>n~bgWQi8*C6pe2Tn1gk$C~y0V%4{NFSGKw7}!<#(4|BdBY>9~EietJypXB9QX80Rnlh{UB~0-Sk0a z3sWqIKBHuU~T8svoNs>|#M*UcVrT3Ab7t9(4Qj;y}!Bs-U9Wq)yE?7_8#L zBmBgEFrK;yWlWA=;V2%}6(r*%n>ji*it&gcGTO2Gu&7E4W3Rn~&Eoc#k=X4cQSw%13NUfx zi8Jl2!SHQ7jj44d?@Uf8sKm(4n0>B9X>PX0Y4q(ku~x^oB84wLYzGU)0CIr5qPzf0 zn_(|BY>xQ#2t}rCX$9Nb=8$!QG+zKthpRzLw6edG(vH+horFy&#!^w1X?C5{iYRiL zbiu=otx)r>f$ZoXv4Mt6aWF%jDR%C#xlP#333L3n0~%qm(Kmg2fDa)$YU6YT59do; z&5Y*!OxfYg7L4KrT*6N?a^Xc!=(%4FjS$9Ors*2^oPr34fnt7N2qU*P8QfbOnyeO6 zAQ{g=xh3<@<99}I21@&ytX?9uzsVdoDR3=m>g|-Vgk1=SYqZ!{1{R?{ zmE;(km3QGIw$BMmd&pOKp*!qzz%@E}fn`6Z6TEShMUcVzFWwV$v0au_8xgGU5Eq^# zFgF>8LzrYnNJ1t{lUE#*bIOu#BZvk}b>T{MzZf2b_EF~ofAu?RpH@)pqvuvjghd^KUCOLSId~uEwEH;J{1UL9w6$rasCVdACT)TQ=C2hW<_%!wJ z_fcA5Z**q0pO!G;TbZ^{US(R*-^@N;MaPkAwv=W$`F^M{JD1!7ORv&=IO0O`guq#t zIkZU|C|I*B<%$dF-m;vSivFYhw%MP7Az5=XE~-m{@+l*zq+;R(89E-J^9sV;6litd zk#?gxR+HAa>|TF(L0q0=ZZ9L$4tERNIe&u3GY@b8>dazyTom2h-DgL3*nn#CsBjiY zv(+-b5}k**{wcQh|4hjq?(0n?*aH5sGNdA61`oF`Syx5#-#8)O;6j%gA?7BUS#!?i z$sATglA$uDmP-_GaXrTvl_mqfs`U3oOhEDn&q6qkEehP;LONV7cYad1UR z6R@7KxpR{z3nh(5_s9?KgLHJhl>+=%oj{r&`L;*Q-Xl2rN`$jv70yYxEf&M z0~bP&lwsS#RZ#CNWxdhsEEBO$#N+CnSyEINk(cmn3_Iafvtsz6 zcSgm=eNBU+o9Xvf}(hZF>`JE{L%fiACvH#&ribPXU;Bk4+>)ZOd z9;kK!N)%W-o9ut5k-|cAzjPM2hWJL%fE+R%Mj)o8nNplalN=&Q_0#NB)Ng{egeP1E z?wl$(ZaHp)`^Q$j)Gs zM%LB6Ai;Zj+!tlDc)F=yXH8p!D}ziJSt6thJf*M{_Ff%EmsxwwTy4-gATdlJeGJYL zN+lIJsWJB4c>BV7D_O+2?^&~r%`$k!!7Z~8Ah?s0^a?hOWV=tyGmU*`X5)1{XtK#5 zTE%xTtA_jzNX=YtvfLaI6*eOcxfBQ-U~zL6;$M1PEzI)l@w2xo`NJgc)RCv`sO__F zqxJ)uWr{1D$2xU|>MOQ<2$9Wk#6o<`P{i8C_J{>AKma$sMLp~Jy$NDZ5pZf~DE}Q} z2C#Q)vqt1&Xg8SJiABIEk{>JXiO6PAj>|Pb6kcnu4d9)CST*ko@u_Vvd+V9GtkLT(9tM5*DkQ?;g`=7mB*IdxmytZqZ}9+iNCc6^dnRg&I3QL`iQ%T_;q zr|spF>TZ7VBg-xWMHrh^J62uwRe_>JRl!m{_M<{LypBfqnsbv*-66KUTDO_aLZbn~O==@h;aN7ZIS~A(eo* z+vYRi1s{+ZE`g%LSp1WI-lXq*#W21fvD8_F*IdjZPVZfxU&nqFyc`kJmf!Hb+Ybc( zJTA-6oVRfZ_^GHqO`Ut+-@pidTnA-ANI&^yjf!7#AWtH;w6xQ05~5yqJ!QeMT$4{XW^Mzn`@Y`o9h6=LY08q5tk6=xNApfCITe^M|SrlHGG-7e% zt(wH#&KxggUO6cqmDjf`_M72$N08PPRBa~c)zD~>$Z36-o<^KB7-b{ zI6Ca+YRZ7cm$0YUk7u=SvI=@+1+mc_I+al55|RbkWeSwbn&JpTUf%67H}^;Tf*!dA zdAKj{sux+e?G}V+!f)S%(}dgXDQUj@>1IN8Z6L+g<7Hh&I}AosPW_@`wyAEp>!A@B z7BY%7_&!PxO61=secTA)tQcVTL=)~k5!KlD5}LxHYsF8BBXcTnr-;@e^cG{+A$uK~ zXb6vk(4ez_EoC=NK=~17i{p5*g4<;^&dd#z9}KbQafn=Rh>Vbpxrm(^fcGhNziWuY zbkT~#DUx=|7>ALp9DetdF@sAl%BQBb9T+_)Ks7XMm(gwCD+`MZQ`2%Y94%U{H)8e$ zHp<(}W9nA5%?le|k16%!8jDGhY`4*HQq8Y++*1ozKRm1%Md02ej2%FT%1gL^ToJTV z4~Sn$IrhYULS`X=4XuX=7w?p%AW|N~8Tt1k3S+$4X5HP~ZKFLYP7s-IKQ;pFH((## ztB&XX=N^l*lcN8=A2!9KbZn#7riSad+$Eh-qNN};ZQDBZh>H%l-RHRNf!l-wOGIYs zbIObd%({9Fh2PPIb*-6eDn;?r+6Gu6Av?k8fl1SruX(Dm9FD?Bis>(qUM?zZ9c%au z6BPUWMiy|N@q+VUh8N;SaBqjASj%Y`#yR*z44yL%t%nNdAI8$d`5*`D7HBfvOR3Gl z*5ftwQ;HxH03&=)@XNMR$5w^p#Z^!p{WP&I@e@scyyYVnX3`fS1lojh@ zARkNuHK+Wp)Y%|(%52=r6-REB=y6LB@UpEL$%1WfFBfvdHAbMhl!vYSq9yy181Y?c z1C_s=vFm}+?S7Jq?O#+xGPzgX1V7*j@m6vZvY28`I(O3XWuFq z`$^dSF~$sT-}d$zLZ|hEVgC@KSJ_Zqv1=rfJ!DD6BQpEsYDBkBw6{II+BriW1f%z< z;D5ME=d6+!TMiE#WEUmy(Bft+x_X-z-Wn8RQdJ)H0 zX0~=?94{D}OE&&MJvh*7E*RJqk6aPE_XHf^6MLN(Z~VGQ-6P^h=G~8-gLDsp-HHyN zo(Pf*CgFuStY~fC;+(UsUy<~~=}MHpTA=hn1M@?FN_e)Dc+t!Neb%4NY#_^*BY7bM z+tkl@rwM~+|rt65=Lb9lbN;-VLI@nv&&INY^VIe<)X zbndWC8qyKWunFFqp<2-2ieVcf&0ER6ec7RE&L>~j?qBnVc8bE=mHDZe>^-A)GRC)2 z$AggPlJn>h)W7BPEtDJKd36Oa8mr)V)v9NzuYkRFo+8%fa72 z78OE11+TZ8Yz1AmTbPONkcHf5&i?kCfpsAFyhBp(CLoMm%3j$Rros%u0lqQ@G@Go~ zpD_Um8(~*H4&6M+0{7Dh@HHe=0t@{*aO{qj(^PMeUGm<|XrKUF z3gTNO@XZqV$L$+8-q+pX9XNK!EF1?MdgxM;FJp<9fjBq4fZQcll)IvOv&+G5w?bj? z`HUFEEmGhn5xHsGrcFQW?&J;}yJHt#w}TfgIv2uo1m!sZUz9a<<*vSg=JG8hyS9Sf zDoQKgBZ^x=xpm9NjklniV(GxKJ9hg~9DLYeFD}dSMFd|2;)M_#FuRrvvvG6H_M1;r z$!1rxLt+~Q-xtXDilX@5md79eE`YMTJv(shjyZB1c-Ud57iD?2fM)_Y6Tr!PidF72 zM_yj+J^();zkSsgfb$6jz8eDJ|Xl^k7CP|gs@833LS;D}a6x4+*J z691$Bw?_foN$~bkczYo`ZrieD%ewAP>%g%)_VQ!lqD3dq1D=Nxrweg9z~=yROmidb zN27-=iVsTUVGSTZq2R|T@Z(9~uCBt|fn#^e9B{-D#}`vmr%~k862+;6oFc%} z2s|~tX}D+ZwCTG~nWqS_n!qXnR~9Jm7V_?LWaMYt9)0wI?hfdV4jj8Ho`b?6viv|UfLj6C3c+R;*d!v419(h;M?r2VfDM@9I&y05 qym|8;dF-*rHg;F0J7#kH{|5jupWXZX2imm&0000Px#1ZP1_K>z@;j|==^1pojP{z*hZRCr$PU3qjARlff9mVI9ovXMYYNPw^gK^$S+ zN97%T=sTkxK|Q{C$I;Po7zG&=!5Po-xjgkTm(ALkiwzl@g(up!NGo`Y!Qv2p5^rA(J zvwDgP|lSq-(W-Y3$oIKtnrV03|P)t&cWd@kfeMi7CuvG@+FqU-# zGH`Iup53($yW=QwS9hkZwYj~$-KqAB60W%73J)z~CiJ9974+EZ%&e?)va+(P;LQ`@ z(BrW!*J80sVnTwXrKO44VwRK?I<^amiHTydSfrza&g(*VcemK>cIoWsRO@|qI=3_< zYqiMV!IqX&J5IN>)L`4Tef#!)e_#X=bD>L0#uufhr(ZrcFYhXREre)=5IHp^B~@~B zbHN;j4~dVDmxP3PF`LX1hjkq`n^nwav-I{VF%|3(w!hygeSLjOaD)wMZa#@H*dixS zo)qMTYJ=XbYu`Sp))hH&Ym*0>bAthgvBiO zNJ(+A6c>+^bch>gixY$o<*_>Y`g*0M<+So(ig@PC86~JYtX8Wk93DsSN2y6%TpYyj zm-hA!IdbHP)E+v7G}^hX)oypx!}DL?wR6WGP#BF`GGRq5gf?At@g=uou?j+*O>d+S zQ>RXqiDjjdl$1n|LpVm126}pWq^`bR>gwv`#EBCS)vmS&1f)mtb8v+e6&6SVn1Dh( zdbCbvNGkl1I_`2fL=M%-Y$)ejY{0c#wIP5@FFcORSNR+B`-fu&a}15VR(6S zbF(T~hr|A1OH0e6dv@>sytlXK46lSx5pkgrZ_Ono6Dmr^k6!}sy#=D@oPGA$GGW35 znK-djRc5YBx?RQ3y1IHn+#C`P!VgzIncbZ1YzUsOL~d$oR888R?w*tI@)r*suKn|& z+SSy@@)gutgxol@eSfCtl~ zLd;K4P@xJ<9LDpEjC57-t*vbo+>Z564j-z03Nd`+v19c?m%g{qW^EZV3X6(TCzh4n zJE64n@whnKMMXu0wt4gB$?Vy)l*sL<#J>LeYx!c!7TK|L2SUUNh|Eir1s!eTe~8VB zm2sO(7P!S?wt*KS5090Vm)|>X+&Ffe!h)~}J!Z_pfO_=vpy z&bzoYkD^xZhZhfwYEo~P=4@sv(%)@nv*o&~snb?7ulzMw1TA!GYFh3&=gfN$&9tA< zd(S`rM+g-~s=2mj_a6D|v(HrQGxDI(OdTHHZMFUkd0oRiYd;5!poGrK%Fdr!RrLUj z`9&(a&a-FDl)}P773=QWCkl;Z#nEYV_W>g?=zVBg-oFLrda58KWTy2HY;gBdetE=)>Feh!%_t*)*% zRnML+ZSXF(DjFJ2zybX4eDJ)iB)j32=%&m3`SWGr!Ud9_Um(fJNh(IN+ddo|4hJ)> zS~dp`?3YcOHp>@ZY*7WxD=nOY>zyigY_L9njUs)2FKw??&6WzP=vou8jLjdZoo|lAD$;mG$dikY&q$B~?{bs;5SQS+IJ% zG$O}SxF7dt$7t=^HL`Bq(@0|q!b+DKj50cJFx0`q2TgP|mlhV@l<*6F35{;Gxq8l= zJFvPaD>Dn3nToTDY(==(xpSwX5dQFI9IS~{9=dsUa($RJ;| z!`nE}bS^xRofvno2?Z3KG5xyhu9Lg&yi?NCGgJXEeIq-9AwkdP6$P%OHfo~}_!K%j zJBPQH9>N8aR8WwwDnAYiZQs5fCmvEs`$Z>Wc{041qUgql3rvr~o_F4Sx#RZRBquvZ z>yZw%BTyP33EKRY8fo8$g-@Y#a&oV>T5ad>@@5R}M6>Ff9Xr&$IrowdnA+e@B*63; zh8VlAz4jV3%WTTqhu9D>b-@RFk8JJC$;rvNnp;Q0h(hP)=9Z`H8!df51u(-B5~3HY%Q>oqqlSHngz^d0-A2z&Pz5B{0KeP88c?6$~r9VZ8uPA z*qfA=mVN`Za&0xnh(g1YFGj{@p_^@`RPxulO;=*%BofO%Z3db)QwjP&p7E1vNAK};)^bll;q^F#A^KKExH*R z&9vF#F4evpVpyTmGcv{%6c+x(WHzPDnmH2*i+uBqD`YUnhC+H}{jqvAWJ(Wa>wseXL5-i=K2bq#zP;ePE<2)2Y7+T7YkoaDF;k^ zIyySxp>HVfUA_82S-#>v*}8QbuOi{p19~^x(kv7%8A^CZgr5ADzq~AK)~=O<2W$Nj zn>QY&O`E2Ac!u@_K?BUCX4Fpm?g2w9k+}qTz@<1Qo429p&8}94@kxUr@#2dw$s_;y zsA`W>Sc*wIjrP|`VcFGY`~8(yUQr{2zQE%qPj*eu@=h;Q>VVx@(CiY6)tabn@_?bx z=muw_SpJ0`R9ILbyLRnTvD4^8!IECeJK+T9U=T+88Iho;fB9t%1mEQ|UNd~~&N~aq zD7{eV4r-R4m!GYD^?;$!**Vz@a8w~@4spK4zHh%ZJV~h3Vf33XQd|zpa>USAkCOXy z(qSe-NWUX|;X~&jpqbLn0K)`0(_+TT{QP`WTF2B7sL=^xO}Y?o^m00wFEBKvrKU>1 zGrU3%g=w+2;(;MTS5{8WfEQn#oRq948rB`Hb9n)8_lz=fUS5m3+3S0ZM1>dpQ%yXB zv_d6=7q5PNuA+vnvwn{uLZgf>;896QiE0##lS`1)sQqx}D4U#qfeuJdjL658Jhj8} zLaw^QD0E!F{}Rz7>x9tkavNPTqlLWl!HUrrzVED1>!Im{lYr9D9UekwWMtY1Etw)vLz=cP1a7Y;2|{j$p{$$No-?Of zvwnEc<9YMg;fU5uDY1ec(-ORdc9tUU#qmB|BfjyjXY3_b|t3yjUYS@6_TPfHJ)cfMLD zp<-~N4V+}bf(38=@sH0eQX2p-kJdge_h-qtsDFGIpAAj0t|czLw*q;tU8&w0+VB2A^Y@?rUrz=BW(qJIq1iWM~t zPim$rcnU4@9Wv0TKdBTevcW&n?I~7(9QHika2y$9PtrJ@SP>f9sikJFf@kO$kYgb4 zUeaY^Mt=MPcQZIX+SHqL-)}?cpq6g%5W1(QXAe3D>Rm*!B>vMZG6wf?@5GEY!Ztg! z+^w0b;34#xGi`PK{f-8=17eaPf8ctonD41_2|pUB>xHIg1GQAfY48jk01o&pRst*H z!?6kVj0-v(jK}U|`cZ z)m6_>dAMbWuS6ZXz{+l*ueUFA&YbGj5g&hRY&_A512*s=cY4pvi6jvul!!bppG9=1 zvIUva$2p9Sk0#yq(bnH+Zf5B?)x z(`593q0p$!KgNOe9tlR73=Q;JzHF*=VyR54s*Jp7soTfb#kT1Hr>Z+^NbB&w_s6X_{)(GDL^0$o}Wy=>^ z)Id_SY%_wJ$h7+pCr>utgJqXrk0@iuo{o<8zxDS!TbOCmJ;6wl=c3mxTlQUzJZFK}N@q~WY8?=+%JNaWlOZq!UO#E3$p;@NNS>w6hVbs&4@L`Z8I7p)s4wal-$=3$4wJ{P{5FEkdaH&x`k)U_}!H04FuQZcJgkM4< zL1$ZA>pGn5uihsQCkejkytekB&j*0GKcD7xz01isy$JKK(B${jMl)$d_$4%fgxmW2 z9Z#Ssa{%PWsF@Qoi8tSTQ(k@b)j_f8z3yblsHv$@!=>tVZ1@$IB(?kX(4d1*%h`gRey6Ej1w_VHL!_6YixRhl+^cFpD1KZl4b2+5C8oRYwZC z4OsS~Irnr=PtQZBL)z8GVG#2Bqj>_H=xLPZ3pg{+KG>$zzlViTT0KL^TUTD>c2%}U z$AyvJ`9hwbN8X?EC9)9$7Mj3`jv;=oK?$>hgbn{M`1>B@nR(Y_2naz5O`vp}J3Bic z#PT`a7_566_k$(#;>JI9b#<-AvRTW1zzAAs0tTJx?(SIw16~I0=*Zwo(~YCCKO}kx zOCoy%4)A{vF6dCFv}^~3kc1{6?Qt}>egT7?1>1DPvHpXkoBhnov&h>W5c#;4-JlV& z&;;UEi`{Nt3DKW`^!q^%|v+k-a3=7IN_2j+!&(y|va!X`9{(bgwn z`(4PxTg;1=t*{`hLTiAH&fPHhcQAM!}$Y|z=v=ui0mbNnwuB?O)kq}w|#`AAZ zy#wPf!up+HBfW>zG8Z$t+0h8zMH^`=)_uR*El5O6Xg4?=4#$6k(~&tg1$Tp}(OsF1 z0eNoPu$DG~Pt!)1sgXl8gw}BanR^gkb2+#I-`~S>FW3$a@wzax1Kf*qZo+Z}csXoY zO`B*~RG=B6c;%H>YFi@@lgX3i17Tt_(`4FMUjhCY^nKSiOyHoB zyS4$3-bDbss`zAm5y;o$6hIKZ-?9JlAf z3JS2!bSWyRE)~AS7raA@pMKF&WYH4ty*L+U*z&LCaPO{vn{W3|R;=lJ`5{5aM9F z$Ha>mu+7t(cnH5OA|MD*Ly#FZBFNM02tGvd5T4){xE(WELBlBed2h$q>)UGC23g{L z{dPx@@cX0o9`K4f;$`fO!J02Mi!cEK0`MW8iV*?+fx#vb+cEQUO+Z`Ft%*^bCkZ*S z9rLANLPZDLeTtSu5?)b%o4$sZmbRXvq473teQiA>?X8MBTH3mrTDqFrx*FO#CR)ZO z+WLwg{xIfCLCcKf?PKzd)y@yofp6O}z9At&CYqYz;o;lDb+-{o1Wj#YV`EJ%9Zek_ z4M3q092pqm8KDsvtn^;U?{cj0!CoZ4pb$S|prSyo=OJQf$aV}yFww`q59~k`54w{^sw!Y~Sw?Dq319 zZnF0a^d^P}Z#L8XGxaA^e-ebZ@(jV716S13(9+k?)jFV~ZK7*rqNlH}rDvk0B_!lM z<)38O621L=B0nQTPuoOCM_7gs<)3AM(DC*R@%&d(glUE3czc=n5J>@^A?AJoo&>yR zP$0of^HZk~UxvrV!=emWs=AFz07Z@Dk8R&(_S($^5ZGL{s_%8{-Cq#t#dx3xC__Jg)O+n80_xqy_-uM2| zG`~CRUrlKyNM$C#4S-6X^YCk%Y5t|})6DPb9R%j|51pqs)X@Ten%aW@Kd=f9|C!bC zpIL>6|IGS{^V>kb5ObXmv;C=Ch)a-f-)DsVpftdn8|drn>YHi)x%uXozetz$FqQVS)v?gwYV$UVuv^M8X6Ma0#O! zvb_M8NQi_97T^*_Lu7jaE|Cxk6D+_bjE2be0$d^?5++!HOBfB2?FG0*LL^ME0GBWt zBHRB6*V0cv`NIc--}!}uAN1*^EIJ8(45;X}`x{#bic*0f%5eyqfx+i12nyALpw}J{ zWO4z5))1-gk9Go5X`I!U2O?e$cOJ=e?TZ~4W8INlx(R8z(oKAY;$6Q}dXnF$e;=fq zTyn)nnck`>hW!45jp{cs4^l14ytVq}PO%Sp9p4zB*5Txr7NjOQnzkn73yJt2^bXG& zxa`SAU}}7rXC@qEj~5d1t1_#a2b44r8~sP$<`qxF70t%cmu^1u{Q~lE@Nq;!%Yl+W zcNEYGd>|kQ4M7&51%4a(&qM!_oC0LNpTq*Rfb_vai1Ku7o95hH%Mlk?%l+}%0yKA!L%xwG ztq575Wcfg?xE*vQjAC%Ti7X#XqSa4m#jeyU9fo7vmxAxUdo>C4iNz(XiN|qSBR0TG zB<8H?`!F7vx# zaF}@|9@~UJr$X6Mh>E$THap=*05eizpI>J_BG<7`n9Qse?cns@Ak%;$DI~Pm_l(Nz z5ujnjw!Pzdc-dS+efc6JWKyhO*M{-PW5C1npl`u+Z?<`Miy#5?+vkPKNa-bR-J#CU z$tz?_OO7SqZOnkvdmk#dCub0haftGI zjz+54g7h)xX>J=@f`*nO;<1WQHXq&Uy?Lr$m7#!wCO0BitKDaPGn_nIAGH>&j-CP$ z1R&Sl&Ch7-B5XEqj>X58I4+fyo<>l{+?F`F@cCcWdvcGfLt2&Uh-s(OSM!bwEV_6l zBK0Jt!@2o^z;qZoM;supgfx)wrx^+iWr0#omE43h_-Rg`_dhRl5PVkjYki}dBQqSD z-gBCUOpq9~$#Send3rJg9@#ug5Ujw>sG6;gh&@YL&mcQr6QI~ioK`U|{azh06kTLK z)pxn<_3>y@C@*C92$y{;IiqWITpN zVtk&n1 z8UEyH_KHFNQDBpI@`!X*GvrG-fgBK|C(uUMzehW?jR(88J>+2LgUs?YWtQsF$m!{7 zJ%q~Jn#8&~@%VjY1@HPxe97_ZYVttkZAxmndJRuQ zAfV%6HrHetn>n;c8-e{}mLuw&PEz{BxvXtOz^u#r5`q*$CnOe6Wj;JaRtSz_LBtXoYo-SZwFHc_1&K)$oh1oq2Pb}P@=GpP z5nwgloHMg-w&Q$KSF{Ii8H0?E1bz!i(IqupmT({JwMU*mPY!(70549EdfnfGV0gPM zxp0_!_T7{+Q>Crr;rl$~%dw^(IL-)lrozuT!7eG@iI!r?4@w~qQr>3ElAZBbG?d+k zc5rPAb_xIv3B3%D-63i1bZ@Z*HRBsh_x@F8or$>BYLR3^204~`W{b%L+?L6=>#FeZiCG4{d|Ry3 z&~>BxzRQ7lUf$^hc-^cH5BLqHn~w1an;B?}$4WeJtroj2oob!n8El}IJM`5$h>p7AOvmiVm~uS$z{ zUU}wV5H@sD=fcia{>-a03J#{Fm4g*srTKkNs*k9tMOJ8FP-X|~&P=^p?RJ-NzCOcsv^^c@Uw#6WP~E5s*B{C)IE?KWjUs}EV-eAtk&s9N8}H~`x4;xzPF86kJk@1bJjpe zkMESa$E@9cmR2^tQEQLfyAp9+j(`0vNMqUKQTc4Hc_4QggwQHRM_i_^nV8eCqJMW9 z)7`Z6-1I42oaqm2xV?zh6Lxq9gZ$+(2F$lUH@Y&O2C6vS@G`V){Zu?!_Gb>6!BME^ zU^|>k!9W3O&&w3b{w+pb?juK0ypmy7*`?naSQiCM$uTP3b=GdZ)AyDmmZ_Jo*k_5# z_@UQu`#L^t^X!X9oWi~avL~3P8cdV?lqW`kWOt(cA5UIdlzxs9uHIT&5V*TIw};BR zrN)5m@#LB}y-i0M*TS7;`N5Be8t2z*A;USqEJU3I1pfM1OB63lpO?gjOeiC~QdrQQHsD+_m}?yCTT0X2{q3QgqrYHRuP ztF}BzaTd)pIg!V=5?zwEiZ-(7nw1S=DrF%J@7VyiwzLac3acSFdnDS+#kHQoTIp(A294? z(|*2)MOr{-_uJCmO=N;>=m%DCNUXM^20eI~n*~y``^$$M+V#t9EYmq3!25P5y?E6Q z`f%n>3;WWd&KJ*cZa2Mc-8M6?pJBV#yRJ;%z%N#p<1^*>Kt|J`ME(Uz!bUZx1`YEr) zUXM2rWwQ$SS&{ttsF9V818A;o`ThFN0`rzHQI#(Ij-#gA-tsa}m`lUge_Jyvfq`;r z^fRvK8)fEO9cu#sHi!KrF< zs#&TDw%Yp$*}3Im3T0Kwu(N%5)odBM_1E$0z*mC}w492K1-|SC@}=pM4+5Ezea?`b zN$c^hk-a*(Y(r*B%5ZybiWQyUe3qioH&!9bzto2+W zykUCd0EQXNQt_0EA3mib_3uf{+R6ZXzrtJ%r|S|X>8(3 z2uW8(#;-#B{^j74lFQ#4_U3L8NV-{(>qYgqHdL_ppE&<$w!-zrLw-I-u0$~9N`&q? z$~Kmw6E~CPxHy-((nU3)ZE!7~c0`unQliBpPEvP(O|i8FEekwh zJ%KOS(_2T;4$WVoT$~?Nzd1=!ijEpSm*>kZJ=&1EmXC&fTb_VysE;ei^$S>Bh!UvOZMyv&1y{M^c25JXkO7;65-82~dC>s>QbjNLFuXR=HpHT}#a}9N(GhZuiR_ZfImR2;DpquUS7rqO|Wg(eM~V zS^AVmZsZ*C6jTPSrBCn|`0XdwCzI8g(ZK-O%Otb(n55Zb>IgJ67{@i7S>#x(zK-vn zPG{4CQ8D>NXy5U6MCmCAoKn3a(_p{hc7T(n?chatqySZU0Eg=60ww9eYN;+nh^ha1S@_Q;Y0D-gB{6V8uY)b?aP^VK`AQJ0L{Y0w@QXn$7^ zeYmwWl^RoWC6%v@Gr-4$%kli%SaQu(iJXduM_zsZ~Bz8hJ3jS_Y(xj$s6YkOx!Qppf8{L zK6vZrgEyYs!hmn=A#WhNXAYe4;vZ9%DQ~^#lzX)epX)!Fg?b*XH~r8Lixys_4#kFaf9i5;%{2yGj!F0y}O%$5CR2 zJ@VYmO~`|wS_qGNBcS=E-8G(kgh9(^wh(0yi96`7U5osI!dycyJkabg)yq_lpJg*^ z*wRKFi%ny<7G>(ox1@Ynf=_!V&c~4F<5ch35|`3Dv0e&38v9dVhJqh2#<9h`>k=s} za(jgPasYwBNkJxuH%h<-m~5s!(h8I!R*>0%hjf_pKm%>nuIm-)gOwR$v5)^ZYL9G= zOp+a*a!EyK5zZ11V(oNNyq$fYN8`*d_1dJEWxd61vn#54P+N(qdkJE$1y_CW={~TV zVE2+-cFppm`KJ>+NC30h(Pn*5f|o<#8J2R7nV`ywLkRS>s1G9PCsJudN zR_2ybrAgn#;d2_$OGCrD;&}2bc2~{|;QvEdL8aRV3M<6Yr+jb22;)bl579F1ZP!P9e^6RoR^A(YYjJJV9eOdv^ zObLmiKsT5jU=OPSdl(gb+MCGp@5P`BYLa%wUAv5S`1LE4f8Hi!e^foFHnKC>a7a=D zEEW%2U787xRLRakmu1(=aPFc7*1JeV%Q7ljnFn^bf} zY0O;t3JO?2J~)q=50HuA;P|x)0}f@7F-qNU!H)U$GEgk4)J|@eQG`&SjvQc)_@(v!dyw7}i zvjA1L0xX%XECJW5M`~jm!3{z2Wi~mDjlF?3%D;>@D*hfFkxlh_S0>Q6n;s8)rBt4T zKO9EDVaJ=x937O+$}ovDiH!zjc16{913FLb+#3p&kzLyg6I9o`xRnB|%v1$NztF&j zy{UFn+y?R>gIr4tG&6e3tGT~%r^PyZr1`}tbA4q2S!*pDPPTTt8^C+b)ZJn{!8*(( z{N!z!Lmr5E>~1Kbhb%crQt3V$Kb@cBF2i35tR~;rX?pqcnj`BNaEJ9aU7{^13K;OG z$MJBUYbGo2F$Q=;ommwX-RkD17Mn;RJf4+L5u-Pi#ZNRf{iHPab#byw>Z|B@+H>~A zg=B9V>Y4g=hxVUiPCl`g(jbytFQmMxxRbwyXyqya?@Erj^<81&v#EeGq;;o3gzcnc*9nj$w+K^tE zXRre`e+&u`V@A3;()P!02Ky}TsMG8F!{h*J?(_uhehwAQJ>XdTJO&4bUOp)tY=F~> z5@%@vJ=XLXcPDVa(9ed0!1*VKFxGPL3xxC;;MX49QY>!=@DUHqy>{DE=V+<@G%`6L zvO^Bj{bNWtRvcW@B*eoETt5gi8tYdtGL4G9;N0wtqD$PDh8lXs^z`4xP_ehVZ@Q%P zlFzc4_lq9=(y9RK$t70zsxNmzPzvOAve{YV11|VZuwge=vBt8nPucGKQI(@M(%?4a zMYyRf-*gu}d_59O#!Z0J&Sf#=WFRCY3l6s+qA1!s^=e+-XU3uJn!I~h&57d^iS7X$`uL1zE7b$2XyF$JQWD!%*cJZI=2 zKx_Hjwz`>_LBcrUR$`KL$=K2AcB+d*GXh-jU0{C?dejRR~raft#yU>Ds` zz(1HAULO>FgI(*|`CuM$L*51Hl+dV_R0%N1;Lx(!Y^?fo>_u{H?QB?VTUv}l)m;;P%O;LFvXXRT=M>h{`zl}j|3T?&p0u3{F+(uUVFw8_N@ zHlcPowDq_1Z;DTLi2;#_^3t9L__xdv7RVX8h*X0Z70AdUZZY&4JysEI#tSbi8@|3$ zS`d@dyau=j)4fdqU%WZ5Mbei$DvubN2WXrF*B={!-38Y3;GTgjAdAriIEn#V%G`EC z0S_`ay&+MtOyf}kaFjkp8${3cb%>hqe)6$vtpTV#_;+!L_O0TAYh;jMJ-DMU#PF9~ z!08OClI0I2$1uSA0P*M2MHUc6mu!y&{mDi=X6YB=z4OMDAj<$Rx$*J=&OnZzxRYK} zQ~;*jvi^K;weo=D>7AGCo8Km%N2clO%O&O^YI5VqutkWtCb_Gz{5^dTUM6IT}6n}DGe7>dAq2`ql@gs zQ|F9r0C-RsxgS1gH$AFhkF)@RJLSLjoO5(_mUDfa`OpvGQka1?j)oZI0kn}bAg64M z_E9A8D=JoS&T0yRvPl;%U0eqvsDL@vHKZ=i_P=$ABrAZk!DQ3BAYv!UZ;M z({ma+VQyLhKPPaD3$k`b6U0et`bxp;Uem}?0zcnnNkqptK*_WO*f^f7E)#T4AWlE3 zfujJfA$Cu%fhOl1B`6srDGYmJ;Tgz=6KJ&=l&@l(+d27eJcqI6v#5Mm1K9~{V|#}^?GB6TZS+3VLW9b6q;EFBz~ z6lGM&HW{i|E?>?2~2lv3C1g&tdtH^lZU; zT3H`{Bf;5+C_xS3fU|jsOJq~`+FRN_&+uLiB!W3YND0a?%q|BkIFKDbNy*F5M*MmR zj^`jT0i;niwUM7b^yvHoB1Io3APA??HSUTsK>#J>s&_Qv8RRMwCm=1EO%w9u6y$cd zsmV0tIuGPFyZ^UANI=?7iVqItRwDBSoF{P*CJM7KIf$hMq@YhbLLQ>S51}+yZV`hF z^Fa6&ZmG5Nq-1UydoH*fM@;^ym>j$2_ z=ZboJMWQRt8SyMMoH>G;m`opj?aOz(3W0of_3J<6<}0HOkT?@ycbLh#a>~+>_=($g zr1{J9SIZ$!=0|U?J7Tese;QjoGV*n1W>~2Oam%>t=AA=}H%5&&4{U$>N$ziNPSt;b z1;Pyi6;AC;y?MK#l0)AYPZ(tK>06A#ekJkIKEoiiMbV^Mhl_GrgWM@v?ore_JO>(% zi05o&9XP^#ndIKXlb#fYlvqpS_{8x%H!#K9Qf4RBac%sv4T1cqacFwaL4X%vdGB+d z$I+_Hfx;73NPxLwyb}asCME0ICxAfYo&<80T%+4)y2#ylhQ8_arzYb4+af^- zSj!s(DS`+SK<|8;v*0d*Bc!KPB>jT)9A36AG@-`uD=C*^p4*O(x^iK8}< z@YJ;q0t#d1(J&m72pyJa0_v3D9p)y~De_1dQ)d{Z22?pt7$ty?&|^a?j&f@yatwBT%h8*Pbp0bWh`rfFZP$0_na`9?yK zQyvH=<4f02Ix0G9!>H#>^e`c^Q9@BdydaG??9hbg%CFd7ll^SDXaW}q)j@Hyd?b&d z;3M@3lWh@&k%!B|*{fr56-%?V2FM4H1NLZ^dG5SaArvi3Lgy&P<|V#ZA~)0Jj^LTJ zndTY68M+zfAGe6oOs+a*?`VGEKzCUy(R?NSD)jY?Su*_EjjTuL@#jyq$b@6`5QR@G z(8U^|&nbl59*Onbqf%7PDa?E@NNY)LxouTE=lYs#{J|x)q<1$5y5|+JkFAY zT)5XBX2C&|dJ+Gk1&znW;$)R)G=q^e?OObz0*lGBDd$rhZs>4TaQR+{>mquf^nmRF z9T%Tg-iv21CSDNVSijM&6_aPEd8Y_@Lr`-%kMRA&{2MRQt}klRXiX_1P6HVtP-f&1#Nlj^`5PQmIObZx->su*so& zS|jJtV4u5^oL+Ajkgnp8JKSvtKBvd3++I!yiWcGYa5l)p77=q8H&ZZ8fPFCL5^VH+6cwSLurucG3@0spOMXi0X zo|tZq&J8_-GGt*|A?wGQ!kS#N+-kK1wfyvt7R@E!D>^IkDrri-4xbq-s<5lLV{BnU zZBf};)Vz{VmvHCxo%;t;_#~kt=kgi!82nsbIa7*ji%&f2eY_%br*-4uJfDS5A8FsP z;B*B=H)o4gnr7;tf(5ljwadNru*h)byWPA=(!8m3ZQ~tvGfJ+TP6nU72R74E%TnJg zKOZYz5m~WX3H_AuRw#orU02ZMU2})*l*ZS78RCow{5F#Xe(JL7ffnVnEPSSXaW@Nx zN-A?aUThn$QcG`1J7-KwPfLnUz$bK#-ikI>c2st&H#?*o1y9QQvm9ZLypQ@JxdE&= z7I@)-*8*?h?(KN{GB-rah>w|Vy&PG-7WJh1+J$Q|cMI=+Z7O88>{yB|WZs@l?v3lU zIv0H1Z|>teeB*D%k_H= zB+MoKg4bGdRP?pbYne7)bKSQebkcMbZI$W8c)5y1>}~5O_m|g0zodO3p7x!+vHqa&V2vj7dc*L>0?OAf(jPV~tIu^w z?FWiW)jNJEu2$F!)+(68{k1xXJukLag+ygMRXm;Qkvo$eTuQu7;9h)OtP|n|vuZ+x z#e&5*bNB87v*4G9t@e?Xe3u^JciNQ27M#}QA*w(;o72+c7~;ZzX<>HLyrCz&OYC8O z`sJSGw`E;pv7(PxGme(Y-;jTfugD2ezRAO&^R2GHTI{8ylh+v0^o7%xL$uEnNLEEu zaM^uO&tJZoRODC3=B;WIXxP+sx2YV*W|8;?(bwQRi=T#;4b*k`bSKM=cSF+Xq%VX= z6j6>*CtdI#=J@3Kl`hnwt0Co6;;X#;mTF9&`GEQSw+Wu~Tjw6WNcxs^&Yoms^cBgZ z_N(R1E%`CNq#lm3ntK(p)maUaRkdchoxMF0GFsVM8(O9S`E=+juD~vIoe=H=a>!q}=)oC?4e|Ip!;zwUp z+Jm$^e!M?F-5$%V@R>F3owPphu=<+R_49!IQRJ*dtwgW>k1E$6FUP)8+^o9!s94;{ zZozdy@-Sggy}jmf&7-1feVghP@49jy^X+-MbkW}NjXJOIR7W2_q>D+7*R6XyY`1Q2 zPEw8gIkO-1cGrw}u&)%>s@EEATwT64B0C=XLFU%sr{UF4{??5iPuBZCDQuq!zSnmc zw;6L@_H;~2Om_%L$YS~xX)&=cGR_C{`?<1xm_D|2>ch;#?jmX`KEIt0i$lHr$^B20 zek3I{*!kuhEHp0C6pyvNX}eV4=_x2+xS_qb+~o1egJCsm^1S+tFOxsVk>$_QP0e?? zdkHiN2}h^!lGpc51$o9GkSlstS~{*esw(294tBi87zYzGUQatm;D|yXk}{r-#-=uA zu1qFo7FPCB(AAm-D3cXN3VKsmm0#6S*38lhy>8++^>TP2xhJngR6G?iC0|9ns zuEtEBcDD8|;+|5_W4Yp>jD5@pWje0nY9j@`hV76^NA)_Btb?-|lQ6F^k14-^5R<4F zuYj43Ok6;i>8~HCG!ZCCI%CYm(Q?SYx&yySK`mWf z9mVq($lm2I>;Q^`#co&SF{|CcWR@%q1Z4Aw+d^*=ZMd%Sjb|FLTqS9x~; z!C#R6OSgZwbkXv1G~+{?xj48vo0`eHgQ>9mr`fw&ng4Tf{zVe@&3_%cnWxo%X@-6C ztJ$$C{8}MNFjsL|XES402WKq@2V3c1TK3QQ34~7^H?8b34jwL?l6?PO`=3kwPeEpK z#;#`4Kox~}_=R}{`L*Bz;_xe%`Gv&!`AiOp5ZdA_8I}B0O+jfs1^gxdMDzdNhliz^{eRt+zvLWO`R@{39L!xkjGfJ{SpbFjjiLA@ z@LyZ}yJSf|?5SaE^{)%?>*>F)%io&%Ki5$bYYfGK4uByUA7c-8&Hs4z&z^tP*TJr( zt=n;ZQ8+*N;S<3A_phcWU;lek-T!^lldu21=|5ZEu(xuRhX2*uzdb(D3Tv@{nH5do zT$o9Nsr~z-f3JPr%G1nNN6rfDSr@D(3c{{NQ?|D4kQWx*%K{psW+8ow?7f$O&roviQ&u9Il|w)_XK z-$Hb2diDuHQm*vcey@PNMPK@*lW<3(?66f8aWa#&64i;QB2@CoBAc>m(Y#E&qY*w-BAI z@CUAwX#BSP2d>{jbh5%9xK5(++wvc{ehbmb3V+}_iN$eb{tnde}lW6?5{0FYzLUgjiAGl7U@!RqrxPA-K$qIkqI*G<_%YWedEkq|P{DJEv z8ow?7f$O&roviQ&u9Il|w)_XK-$Hbr?Lm=YG5D2wH zyiqF>0+Ah5l)I+oIl5Hm6NMSMGr3(|IZ<4+vM{ldk~Wf-mU6+v!@a5odO=x9rCs}N zavYTA;UPg3Q*2;kz|^VmdyW1mLfgg=23Y~7({~{(*KldB#aB>r%h;2c_2_l-uDgUF zU~YNtjFF`>tP(+Y}A`HeHL`oh{3X05x%t5iS-~|Dp;@@?Ss~^|-RUKRB zSM}pM$JPIT5c&Uc1ik87Nmn6PqO&3$yI94ihittq_8;+6=jL{^fC=&W+Cvv6XcJ54H-k0f^W^pc8-w(0g5uOBmnbaZsN zogL9(Ch1{I@oP%79o`MMwj;I@ZrOaOH$r)r8<)NQ6>+g&=13?0vgWk$8T?zB(4&z z;Ww`0DqQWMK!5Nl@XECQ;fpG6{!aNlMfM;rC_A5t4UJ;&wDj>AOX_b9J+EtEkb};9 zd=sgtE^eicEXMO^tm>YRG^uH1Z*+j9rf0v<7Ko2e1PaF-u1GbYi`iKFENg`PV7*xY zj|lDH!2g7I_>`JCZPR2k;La2yUjEe)3QblyB~?X5M0~6kPD>Esybw)cVPWa(*IgDF zciI*fxXSgG<;@atz6J0>jv5mNBd_E7G3-2LWnJgsR78QrNZ`m`@0k1C9QuB7lR8dg z^s-B%I*xze-fs8x(}#p>chs+&6(=)Gf*#N^*+fii@~E2}EEF_%2zNdh!<`M1>??iJ zldj|WQFxNZqUF)?u|Pf8a05sQp|OCeqavH>a6y)x{=Nl64t zP}D1=^6~MJ^x0DR)$Ex8%Hly>coeTPG7c3~v&7gZX+Qz^Pw>*tAs+iEOfcogdpTv0B@F%b~87&Y`xc+-9ibtFvp3!MStiboBI~ zRFU789sKvW`7WQ{x0|XATz&iSey-Y_2h{QLzy!ob_3~uxZLh9Z_uYveGW5CM+A2>TeyUJA z(p6kFckrn`Z&^)EcU#+;ugdOm2oQ78y14 z?(a+HX+`L8BZX*L<502PUv+eKKli3d%z9NLm5kQXl|NplSrua|oVD9}BQgI<4{NrH zl#uS$+h$#J9}90`hwd@q6)HOEn?NUOf1QIetbN*5oZ-a>u2z${tSlC#9P%FX1QhHI z=&5t2`XP^^65Z4XB>K54rAX;1(tjlS0(Bb#);ekCg zJU(vb8lF>B1Sa?G>nJK}YOmG0?JAGe z2?3f9*1|yW@Wg~U7-?Z4Peo0BR+0VF;?S@D(Ty}6q~WJ~Y))!gvD@rkn~fDed_9kxD&7+U(Aqw9QSobV;u_0OT7DQi3e3n+oLdMR%*<%=gQp zw6(SO4XC4|qlZUFzjP+B7l3^YEaUF3I6gjpmUpB%LTMoe1~WMA#EN(XwtaDN*)PMX zd+Sz~4tMmf-6L<#ykCROA+{pNU_$0aL`4re=Dtt2OZx36qw|D#9X@C&D<1UQW)jeBJf@vBt26h^zQ`KG6N1D#G|r2w43^$GB(4GJH%l%V(f(QkPh;lb15Pl2_}G?6 zuveU(8YV=sQISl7f&ZE%7$J;>89R~x`g@xia(#Whc6-9-uPN~wAdSQov3tg4HX2ML zTz6If6{%`t3Uyn3Sd<@+3ev^J#doa6%8Ys@tYwKtLXA1WJ3<{w&CgfEbX zDMv*i%o0`DytcH`uv%>FI~zM=+)oLH8kY5*?t)fM~f3PC?n5N zR~;`YW&;h!t@7FCt+XFEF*6I+;*vk!bEUw<0+SWPDDw>*2n9t&1M{w~o8WK+j=*=g zo{rAcgPVrT37zkj-A5)TbG7qJ!RFZAea#0wh9OKjf$S zhmeGX#Op6$2Yx-LkPwE8NTB7_M?(576BmbyfmM30#f3ctsQq8&;WQBXcASR&wa4VH zqna_4>p|-XIJqEC&Y5@OszBw<=?Z1ZWf?9&!7-F0$xK6Y@B$+=m>tkS;+x*&rewA1 zW1fbNT5~&Ajpt!+v%06QrvXD3<=2&UZX!B4PoRf_8d_j=8-rwl$5m^{G%|jEmmmfI+H#+8XB{}n#RdZY3es@`1_)b zHWTeBR}&Mbc1qGhR)IqFUSMFYi~f4%!1(oP1GqrY>8YCmH?P#s8r+?h^#H00)lzB> zN<8x|@aU|ktjDV_iQXG$)-LcVDG6S&wIHV#N&KQJN1`fXe>67Cx^W>M=kVqPdPp*lG`lswTm}PaDHS&k z!ki!bI(L2~Z=G~DZh*Xf2-=FsWchFzco$E};wfU$iHAx)WnG40gLCgDTbtfz-0rFj zS;WqQm0gpz@qB>Pll*QLwWlPuI5AQJryblWF92nKOiV%OCdGU}x---$xSMLmg(f$4 zdxj&qvCxHNdbyG}5oSEMLnu(7IqwBs@bsuror3IycntaASCQ!FW~`C2`^LP?e@%RD zFQYfHUi6gs<^;h}LmrFU6v6PROE~I*vb%HzkM7^-`S!w~7^MQ{X+fpYz9{#|Fc-a^ zxgb)4=bN-fxR4L6N*>zx7ql?`sAhm?KVbBnCgVw5V3EhNM{!SFW<%lkoF^u>lAM#hcPUE#>)=1MQ3K0yaG8s z`^1Uy?MU+JDH%uluxM*xq6hhDj1~ijWFqF~!aeM43`?`ZZ?jJjcFesP$n&w-@#7;k ztK<`6pKizg4??jB61C<~=u z-tHrj3>l}~L`2-nhB1eil4|J4x~o;WkaTxBhX}0{ZCa{pDYf+Qm}A zfhFS__a~-|qBOyGByIh=qZgL%-)xS4Mqs{jTJSvKCw)aF^7twQ&1uc#YB6W zl47#ZOk;)~e%-p~97PL{MuvDy6o<=;QaT|%;+fm-F|&lkTRs?z(GP_gG@JYetE~Rg zJL$vt*Vt-J;?<$dZdEiK(QfxX!~svpX%ilChW4e^+or6i%X1yB&h}xkYIG}e23Ol% zKlE#?*^FPsyeCS$gG{ih>|XCtuwx#XA8^-tms+w7+cDe#)@x78WRI!g`Hh(SQ7Ri3 zD`p@dFd@Immo>#;Ho(=?`hrcO_pNf3_C1oK#EgwLiGl?8EA@SPC0fXh#~w84_s#i2 z(jMBmFMT%GOj4!w8@=`QJ$?wv+fwM^P%+13}n#Ypq?gGJu z7V}Xkl&8l*)2xtf@oTI2I6Cs>F*k8_fB&Y2Q{3KmPiF5Nx=s1#%B;@vOZFqN?#YD? z4!dzx^V;|ymmF{!2x?b^-3R#{yfTiACJd@mGWbU<%1Zjsd~z!8EkZ=%vgv&#aFR`l zHjjH_jmcf8u0xq%9&NM>SL7KB z1?7-~+I`EXKN;5)v(IH9=_S6dQU>^++J7~429`spAnTsM$x<^@`}F?N&e>H9%Bodi z9ntKkFG1M$^!jZptMCU8F4%vnYAU={S#@Vmq_}>U3xq#1`^_>lm41tr!=FAq-srHT z?BNBWWodP_48+(9jCWc*>em@6Dk|Q)D55lZSoVs(!)U(N_RR(~sQ9ZK6wuw{UH2_S zJMJ+qY>I!de&AfKBA)h4ha1gJ#hKI%Vs5{jaHJxPe2_}ue#DftLm4S&nrlF2-qBB& z{W{oM{zN+;caC{kCy0DwL@%lt_PV~Tt9QP^T}e`!{wkY)8DNq`k(ia5!n+8@s8mdJd6ri?zJCn^17@;z9YOV z>lq&pEUrHCOqsB)gjjSj0^0`x@5Lh*w=^$A3AaCmEXd}o&=UwMb%G2Vij|D+-^t8&0*tQ$->?Hl0 z&t4s7yb@UL#`r2>Ee(|BYv56s-)_ZT{E>fhEd7(4h1!ZaXs!Gk4euA-MwdmRr%A)* zHq?}q_--BXewl><`>OIh>g`dqqY{yA*+{l_{!jRe57t7oB%{lR_DAFc!CeH;M0tns^(t}*R$k6=I_$SAL3Zr@@=?5%@e91--xQ+&edG&Y0 z6zz`p)J%7Wn*q?FYc=EME-nd%#oLJclO4}TYzM5%=Ul}>I6 z7}sF9_vVM2Klf*4)Fm%jfH)Ma8weeTUBopL-`k4B5GsRHdx z;-K_p7K?7)uHTlz5@JzRGxEiNUVL_)BUUNLkv`PEa`Ajwxn5yXG*%Ui-p(STE~loZ z9wHk-&{ZD`xg_aH`f%wOE;8y@c=z(w%#(XDZ7I%O^aCkDm`K9JEuOX{KnSjk*R=Pf zigwPf7ZemsU5PfT->zHzwMaB@r5yCzo}Qoh-$txP-Cu8YXFf-%5P<-wpt#s&@golv z6;%fY4(JBEDK;grZD3i-!>RUw0d*CZB4s#jhM_7W61XhsyAz8=x~d8Vjblnv1F8XE z6Z{3m8Zxh1KiX3=din|;0uF_LMeqfPZZNl0y#y8s@TOqlp(!daOG$Ho)Fs_ZKXSxJ^!>g5H+U;Qc#2euOigOn03_)H) zB9WK)SYYciOLKG3=yK98FF2CAe?i7(41bvgWywOp;I=X~g7;@f;Bc~(5gG)6;{4Za zN_xEvGa!tDi{%z&Gc*fu(SV4fiadRu(*=PM(o#cOBV9qX>MCA13Wenm#|{8)RpgzY zg{~6$Ku}jlQLQmphluuRc9LQ-*%_g$+*EY2x45ZTlDf$vTMfP0ot}zpXU6Tll2^J0 zNF7w}pdc$Np%uamQxX$W68b(W3K+>w41CAtJM;a+;i0#aB|{P^N36`@mtzN2P<%>)*=y=!_K0gV;uFnPlr)4xIupqpZCP#zCQ{u;-eEQ?({-+<@3(ya zIC93bxKBzIC{c51Wu-!)_B0@wmR44{;N;X~o2OVYL#>zXG!uApiv2e8!SV{}(TpJA z3aZKFNH#!{kE%0J63U6 z6LLQ|_EFC>zGwE8k&CbWf)cyG`ZDWc`aE;FTFlBDjKhU{Ireg#80#hM(vGV~nU{%O z*DHMJFK!E#GEFU^Z#E?(!@}4&P@h*JPwS13L9;j>a}gZs9Dtg#nb-K(>Xd-4Gd!K=oX~;yJU*gD40%#5TRh`R*g{0s9R2#b6;((e^iQ?ixul^Z29%G}C;G3#w`q zxkwqu!=m|3;Q-UFp_HGW-`>l5%h2#4*eTziVif=lxL5MuQx z9vpk0p+=JGTNl2-$8Pg;MFfS-k6w|S2ZJfpmSD@Vl1SnfmnAV?z+kwn3bnKJ3eou= zo)0Y^t`LUHeMye}HajaODe2qlGaeUvj@ensHM>LcaZb>+iU)ofa9w-GX z#9aDG$Dxdhh-yGtUC963oeRs zUWk+jivDax|D_crNVguDYo&(l9Pb*V9KMn;0ony*$fdK~z z1rspKpFh1U92{0JgIp3x@fQysnsQvkBPz}jgi=t4RU#rnH?7Re&tTC@JwEoX-Mdml zQ(TmHD^&v7fO?e87@a8R^71l}igo2`IjAD(85o>AJv)Ap-HA%9=)A;+&V~K`T1HkL zu-=uG+gy&s&vhS2S&yf9gvco-aIsy?wE=k3ktbVs`kdwYWR~ziR!2eCbIEXqmAUGk$?o}gFKMvsi$a|iM87cUT<+;XWyX~uJbvM{GKI#iIyi3QUNw*kpM?HWKE?+~j zw6p}gAQW3d%e0gKeMHSTTWZh1;wCBw&CSE}eblDdX}XOhUHXpoQFxd~+QjLV({dD4 z465F;1d%1hyGQRPuJc(L*Z}0QGw_`3T(BoNoLZNm($jy9t z&0A*}qn0as90&-2Q-GTagepINN{Tv6%oJ8me8HF53G}99F5*DLecn|Ub%!$gU35S7 z(+a(ynxDv~iZUK?HHH&KbVL~)%{Go(HB9qSMM6N<5EyM>u&v9Lz@SrmKtIvb{J?Aj zrwlT2K5nUx;35O7wBKGba|i;7awJ>?hd=ia9Ras|3Z zMu3^u;7#JBihSGGm(XJ#-fD8#KMOL9z_|w5rpyVsFyh2`2G*3PuMtnL@+PrRMKWB@ z@Y}UYPV{@=*Y;Humz?Mp-IadyBTD9xehtUCw6w<9xTrHAqX$4gM*srXpEik)de{I& zz*hqCtX|;@QL-<0voV>MSXjzXb-?59n*~uVh&*vP@9ckXZ<2X%>hRLqB#ys03{K=% zL@-a3J>%>K69Y6RcoZ`}@&Uj2TkT_!dP@i{plAev6&_6GPSx(7n ziV^pSwWMpEr~a;wx^>4&L}r#T9PSgB;-=6bCzGmn79^!nR}uPTARTx369WW*-3^XY z5EdNPCz!Xqfw2gus`_nYF`hnpkGr-VcocEC!pWnIVqlZJ=Sd#Aw1he1)6p9?Z!p!~ zZ=%NBav{f|cdmIk#hDxmiPMa(3j?CkzN&K`PYU!$VA592{Yvubcyc z07z5=C$!3anYO#T``h#6lEby6IX=_Um=*pzGc6NQ;IyJ&?b3-5F}DnB z6c1r@n;@hG3EZviZO#Y4LneU$w>3p2M4wl*#MGaFb85D(zV9*1S9n$Ra*KeX3#uvm zjL(p{=7fT*8zM}=+`+-&30PmSk3y%fywc-&JBY=7E0XH~Ha@bU0NP)JU2% zIeX{^wB4u?Q4-+H{zuvxWYa+c+ER!X1YcOb277;CYiT5MBQhekDAxFvh3h;cw}-+9 z0|J5GWbW4o2X_FI17cHPBSFgiJfrkX&Ex^^`Ad>lmiy=jWICLzlTQIkGIGl*r)l6> z!`+{gIT>?IV33Ny0_kwS1ZP`h$774F@9m7Cg)&5o)JN|r(8Klag8W zT8(QO+cy&Ef=Eql!Md0LP_^?xBu0Pf(hqRmqwDJrUB5cq{raI*w_JIp1h#D6gJ7eI zs7HoYULM3p5q^I40-&QV9gfqqi#hOe!-p0ZSZOC%Pb5E zB27>y+-YxQyS~2Lz;-V+UkP=Si6yj2ESu_{gh;Z9_T^MJ#mVoOO*4=t7HHB6G|Kf~ zk_(>Ax~8hEL?II@WVIN(1k@#TjGyMS)L}S#P6G$H*25M{yQUt%h-;>dmzTVP$!->!dtJt~A$NVv#6 zLM@RzaOb1yY1W*iniUoAobyd$77PP!QhUM-AKcPhX%0jV3g6k%+#u*HN+qIE&5T{* z;N-|zcjby7aC|*6ev@qYjQgC!7o81S#8}PYGXWJeUdeecp;@cedA{=dmKTR zqIf^{F$FZI49ZDjI7qd|xkj=}9BC8SThc!Dt)h;w_Oi=G$xr={g&yO4Q`itcC-r@Z zAcN8JzHzRgZSp5IUS}~szm#em4v5T|+F3#_==n4b7KymeFdEg`#7v6aTGkwj4)Zc# zX~7l+#*O`8F0@g$_=mre|E9+xC0VfD%oQsHoWb;sPn{I9Qr34oUSqgK#YH99b)Xt! z-!Zh@u|eReP-09{B>6rbKUnu$m#d9R z?I<)dp5}VZIUW%3TAL;L{djPXV>|;xdF>DdWB=mwTW~I~RyoD3J$NqyjvH|{Jl>W@ zzRt$ZA*{B0-MD^FkOO$pL_sjl;0{aRnFHC9mvRk@HMt&y5aucP8x_Fs+0fpt!4FNl zc7ZKR(UP+012fxPpINeIh$hR62DjqDJRLBjxDkHO$3d1I&1A{(PkNP`2 ziZ_F0(NM%^&%||NI4Fs@d3odeX2X$Lz)g?uoGCG~!e#VgxV;<{!6@P&l;?ut?F(Jh z(>4f?S}UrZH#mC4$~MS6f}qV6X1m5&9n{A%vaUe3`Z^UBpM9f!Y0^O%S;m=VMHZiZ z3eYj&1ku&exeX55A-8!~aXDz5@zA2+Zo+(1_(n;WjBPS+)xEZC0#35Iv(u6?UM`df zc+JN#^vlTvCvr4@n$Pf>0l)K03dJR3)VdT)Af}DRU$kkiZ2_4Eg)zI zw!^wSV)1oz(T9dtTn$okLMkYC(>XQEEJwVw8nQ&M@hm3KciG_)D)03yd_{X*3l_Z} zJ;`K_%S*$UbSX6At9X3N#|YseKv@3OSqwz)`@q))E&`x!j2i}?_`k2YbMq1g znYI;1GUA4p_Ef4#8YCcsFqv!#hf>k9?py8b%a2To%B3tYAwS5^K7)g-1v_ijNPNE# zk=3{CnJeeO`2x&7F*tC*85Bw~gtLT$FDu@7Tl;3RCtJDG@H*|Yd$#!ET^aC5}_X5G)oYu91A}dQ$gAj|e(JzY5D1&%)dvWzKQ$YtI;Gw+T1K2gOYDOC*lr1YY zSS%hbxQPaA9|oQh2JlU*7>DM10D_Y^wOkM>WTQEuaRmLAuF0`a8e|M+gDj1o z(FRtLUmJ-tYWIE>`ExYxgF9;$4OE=vzKL}Xh`0d_RG%E*35%ZILC_+?r*Gk;x#nJO zkyp5TjdMg4DJ+jH8#$LH_@4Bcno`kXJPPK^$(o=D*qZr)Q zdQXDNqae=_&1C{43oLsi9%Lz4F2$TjaRSbdkc6EeuXD!!h=olCu@Dm0c{rNA`jLr7 z5mm;X1K367PG0lSGed5nJW(VR@fcVUmy)<0er)fl24p7+@ko_3WhPjMTjV-@J2QFs z4(rTj5Xzq1c;wTVoCs;c`3QL>sW# zlMi=WBIS^z(!Qd3X=NBdYAcP~4@);)%vCYrp|znWGqwt{InRV@=StNTPsd3p%8kR&W6Bik;*%krVT_UVI!dK&r`! z;9g^zTKnXEW)-AtkdVq%S-P+^A!7v#gudge><&PfCUAh=JyW+2xDTxYdhL8hF@_>i%Yw}M z+{YeFGFev;tELEUK*O<1uA2lXtXv)LU0IJp?e2`}YLvifvuuLn8%|(y45t46lZ>xz z%JmM|y#nI~Xa+ih!QCqsLPhjl;E8}6c)py~MT_iW`f?(V0kgq!JlI}(=H;a&a6b+t zgg`_PD6E7aIDS#2qJ+H%2X6fWrxfrVGQJieYrI4hJXYua?lJgBCws;kSjw_jujHgN za`g&#=clN5zpz68nvN?u@R8MJ4ia;6SOM@4lv*=1$q^{*OkH!(yK`AFI{NzA$9WrY z5iwJr*T_@LH7?Q~j5{bu2-NskSubCx4Pv0u>T1P2t=FW?!N8yBL>({rQ;>G0{#)eW&LSb9)fs4xNvWq3AFmuL9^3{6w`MpE#F`iwUH5~2{dQjqbq%;M zpsphN_1vt_i&$GSP6RpjHW4hRzxJX!VvCoA{I90>0I(4nS(bpz@m6 z#j+=e-7kLm(K@H%b+8)zzB>KJ!d1QF*GltzcyWUJzO50l?+Mx!5WS={J$IAu%DNg% z5pX>IzN!^?q=>CJm-Bu-`#o;GbC=I3o=8AjtlBjamsezQ%^T+#wh$OnN=@qFQxjL3 zH#xlEyY)cV!}}FEho3YoE6&db?8Hu5;Z1J(6-^88>&C~e$4@q#h2qeN<;tlH!g7iL z37NJ8i2;|O!zm8iaMtJ=bJLTtdK;yqg0i2sO--@*;^?7K{9W}f|3R2gkrvdv8N z+>wHX3i8xKHcwW?jda|YK#4%VuKfv?sSMo3hhfLpp!p{BlpN45o0$U{^62#ym z1aik(=BFA2x6`L(-Hba)202)3?2))`AK#k|o>?-Mx`p_5Mj1PtFqRy^LCO~ra4xC6 zYWmJxqZ=Om21EH&2K>)c3_p7wgw98eQ@BzPZ}h$609O{2J0I1`15K6EsOt<^&5)tv+8 zQT7C5J!4c_f{vOOYQJ0K+rM~YUw~B~{ilhqKW34s4F`D+>#_O-@0-afWYL>Ahxpoe zvzy&589QjnEG;g$<3c$oGSlsiS#3^(+{mz9n*VR+Z!FG1SOE4WD`}bnaN1AfLeh5$x>NfaIs7WUi+?Gjy zH9LA^sX$5vu|kN5@L|AS4k{S$XK4S7B@%&KFykx+XhCp68eEUp-yYa95+=sRXPBShOa4O66>=~#l72|!Xa=M4T!=EaOJ#c0fkS?Ytp4XFoVeW(=G_7zlOJf`d>0 zN&wXU=(-H<*I>_i-XuWMf%^c!O98wwa7gqD4L|N{3@<7{Rv`{P&{4dKIYtH(#_HQt zp%vUTDe`qrnt= zz@A}l#&^PK_l>soNzmjVp)dv_ozzsscKtK`-3`Cz7 zgp?c)l(Jq6pm0R%egq35xsy~Kdpq8qzY##Pi!TqTi|b|0zOG?W`n`TkIiUY2kZw_8 zBUc(!SM|f&IUksT^RPf%$bGL6L`^C%V4*uYs5FFVbHEn_yh&E&dcb`HcmA(PO3nbX z#<^OOceTf>-tWT!YBZl>JD}m}(bW!rW&aKVlTME0xhJ2+!FF+xM?EY1shl25MblF{ z*?ieWsO!@w`k%h(zS4bf-ry1w6N8BLTq1xPOHX3pEz<|5YLHpiN_Db9j10b80Gu}9 z*Xrt|fCs0=(#zg+@jx!Fp=(`sb7{P8xiFBD8GG?p3=#3ecfvB|kksH%(&H=87Y<55 z)wY-jKx7o39J^THY7}6%#nXDo(ik&umW<;F z*~W0IV>vh+kwG82mSTn}r0f$~tf`JQWNk8ygeetqsOU(Ny}7?vbF#w>xz<) z?Zb`77^v>OOzc^D`*7nx>X<2ZuO1nGjHaIl@tcQKs#d$+oOl36o=iv(Jc(C%X9V!E}yd`i+{VjVfycpsD2 zxi+}B6=Mot4HVpB21xK|#@b1e6>ctMzziPtv!S_scO`&Tp zou;r@RTGW^$&%))bhkT!!62sUdt(TUBD@wrCbZp5RN`5-%yfgTJ_XnQM^+TdDm+fx zXfx@y_X1=DA0|@(^NoNmMy(Uz-T~W1%4<3YbwqHFgBA`T4d_nDS{2SO&rvn{QaZ;V zIrQxMG$lbGw^6B*&K+aH@L~XZ^Ooz)l*o5hBQGE2ne^#AhnJ?Dit>tAv&I_c#Y^GO zvTIAl231v6ErU&;_CvapcVxs!qMIrM8+pwRqQ-W>BJ;A2gH&zFJjmFqelEaJq3Ik< zh_8tD!UFI4^LZAv$B95V3k!pkFt07hV(HS9o=sQF=I*AQ6AEGV?m)}bx;{)x1$vwf z^2A@HbxTB6%|9AUyT*m|6+}Wzlu~-@ZCaU7T3n38DsG^oxCFHe&aC#%RDzvDu6fbw zMZ}mm%uf*FHPNT*PpxoI>voYG{(1e$2j3sAKUo#7fQZ`K+61uj`tIC7u>zoVSE?&B z#3Ahj76e!=7^bXT8;$6sgd}b4xRzs*suMsQ013VL@v*%wLI@aHcoP)eUx^stLF=>K zpYxP`;`T36lG&Xg51q9N^hecJsD2F8oPfQ3zLZ~Svby!%2`hUI z`BppZKa}dOJPkNI%`O~VTU%q`t=d3dMSEM9eYnT3hE~|2r_2i_hC?@Tvo*PDp{6i= z?ah|P3-QAOO`@lBK9`GcTQ=FxY*21cof#8dTk1NiUh2WeUI*V){NC1ldaG>vrN+^T zhV=R3kHBS5Dv~4)0C6(h6rBTm9Du!GHTk@ncyJGeoX^3zK*zZeH7s%Dy|O8o6f6FX zqTu^CZURU^tMaApF&P@{IhHv>_hpf1<< zA>3Q=xLL}0Tb>!6+~nJclauPtjBEZ-NXEga2ICvNz=e3epA>SuWL@-(afckkr zmOeQN`6_>WkQ5bUL#4)J*bOzl7{x*Z2QK9N^O0+~+`@gTHHP^Vk<#PcWk}4>px9`3 zfeBy(%1K`1-qxhsO!mYzzeSxL^gd4C%O5pE7#uB`B*m%IZN*gM(R_OONhPk6Pv89j zmmTuFsk-tFZiHGX`3tAaY@Fw59Tyq9l(HAdY#rpJl=o1lpqNR*g?pVbBL_W7nd||x zF~d#+37AXfPN$jnK8fdg27Guj4nJr0nrR#Y?-(ely!9UI*jRd}D4l20&gwsla5|QK z&R?46z>vSXC1c%K7JMyhWYLaY!fGZVHT#OliS+63i{jKax+749IXuY%d&PH4Rt17M z>J|m%S`caty1+vQ{vIs$iZJPfvG2zqQ+X%OZq)CmH zu^N^HJ~r^U6{8L>Fe(1eb+8>atTB~HhFk!OlNd<%bQGx3{_+fo^tBk|J;+NlhJK2`B+mA$)>>p#(r5C;^G+dcaTumYqn{6Po7R^E#f0{>Wh;?Johb6PYwll%h2>2D;J^SRdsY znpNddE4e-y+a8;@Q)s=YPhHADhxKxPr!^KHM2&-pY9>???GTm^Ia$cF!4ka@%zYg! zLmMOh<dxzyB#xcQfOQE#}D6+nz{EBS4F5jO`_*>&+1BWnGImeWAN@w{cl6no3^vNQ#4@2< zf}l!v#Wk-q3p9VXYE;5$-YLKrJUWMW{Fh#wC4+$)j+v>XBxMy*(XvgedG~}yDg>73 z$IC=ci>+$eBVnm~?1$u|q2lO`r?KCg<~fE4rbDhhPn~riF&GILiMF>1&{bHL8k$$@ zuZ;ge1W(j>T&^Q8GP>VL{BTNk*>rDJ*)9{A_j2+ej{@!gfxI=Bam~TFVnG2j& z%q_Wa=Z&P$fg7*8dT$tXi%+IAo?bfwPP1t|(y|$=ZH#LrMYJZJQVG48_tU9#5z#VP zm7w~VfxPPaLnj67Z*El)Pfw=#$rJtrf4m}Hi0t9q15S1;jyAnHO$wyB5b(MRQ zx|kQ|?|d1rmPKl+EU)-}aXc|Bm$NHDq%6P+39qvH+Kq+GNCD{tab9+pX3w0v(wV4< zTEUQNtA6ND7^Frdfm(SdmfTJb!WnXU&{dQUex`zC}94-M<_}lRoe;$E>u1{Z%z(9>> kUys0m29yGcG@rkr)@5I~fhT_)jsn?0va-XMTY8=O5Af#jt^fc4 literal 0 HcmV?d00001 diff --git a/GraphX.UAP.Controls/Models/AnimationHelper.cs b/GraphX.UAP.Controls/Models/AnimationHelper.cs new file mode 100644 index 00000000..04356b41 --- /dev/null +++ b/GraphX.UAP.Controls/Models/AnimationHelper.cs @@ -0,0 +1,33 @@ +using System; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media.Animation; + +namespace GraphX.Controls.Models +{ + public static class AnimationHelper + { + public static Storyboard CreateDoubleAnimation(double? from, double? to, double duration, string propertyName, FrameworkElement target, FillBehavior? fillBehavior = null, EventHandler onCompleted = null) + { + var animation = new DoubleAnimation + { + From = from, + To = to, + Duration = new Duration(TimeSpan.FromMilliseconds(duration)), + EnableDependentAnimation = true , + //FillBehavior = fillBehavior + //EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseOut } + }; + + if (fillBehavior.HasValue) + animation.FillBehavior = fillBehavior.Value; + var sb = new Storyboard(); + Storyboard.SetTarget(animation, target); + Storyboard.SetTargetProperty(animation, propertyName); + sb.Children.Add(animation); + if(onCompleted != null) + sb.Completed += onCompleted; + return sb; + } + } + +} diff --git a/GraphX.UAP.Controls/Models/DelegateCommand.cs b/GraphX.UAP.Controls/Models/DelegateCommand.cs new file mode 100644 index 00000000..6c9786a1 --- /dev/null +++ b/GraphX.UAP.Controls/Models/DelegateCommand.cs @@ -0,0 +1,81 @@ +using System; +using System.Windows.Input; + +namespace GraphX.Controls.Models +{ + public class DelegateCommand : ICommand + { + private readonly Func _canExecuteMethod; + private readonly Action _executeMethod; + + #region Constructors + + public DelegateCommand(Action executeMethod) + : this(executeMethod, null) + { + } + + public DelegateCommand(Action executeMethod, Func canExecuteMethod) + { + _executeMethod = executeMethod; + _canExecuteMethod = canExecuteMethod; + } + + #endregion Constructors + + #region ICommand Members + + public event EventHandler CanExecuteChanged; + + bool ICommand.CanExecute(object parameter) + { + try + { + return CanExecute((T)parameter); + } + catch { return false; } + } + + void ICommand.Execute(object parameter) + { + Execute((T)parameter); + } + + #endregion ICommand Members + + #region Public Methods + + public bool CanExecute(T parameter) + { + return ((_canExecuteMethod == null) || _canExecuteMethod(parameter)); + } + + public void Execute(T parameter) + { + if (_executeMethod != null) + { + _executeMethod(parameter); + } + } + + public void RaiseCanExecuteChanged() + { + OnCanExecuteChanged(EventArgs.Empty); + } + + #endregion Public Methods + + #region Protected Methods + + protected virtual void OnCanExecuteChanged(EventArgs e) + { + var handler = CanExecuteChanged; + if (handler != null) + { + handler(this, e); + } + } + + #endregion Protected Methods + } +} diff --git a/GraphX.UAP.Controls/Models/DispatcherHelper.cs b/GraphX.UAP.Controls/Models/DispatcherHelper.cs new file mode 100644 index 00000000..422ecfd1 --- /dev/null +++ b/GraphX.UAP.Controls/Models/DispatcherHelper.cs @@ -0,0 +1,19 @@ +using System; +using System.Threading.Tasks; +using Windows.UI.Core; + +namespace GraphX.Controls.Models +{ + public static class DispatcherHelper + { + public static async Task CheckBeginInvokeOnUi(Action action) + { + var dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher; + + if (dispatcher.HasThreadAccess) + action(); + else await dispatcher.RunAsync(CoreDispatcherPriority.Normal, + () => action()); + } + } +} diff --git a/GraphX.UAP.Controls/Models/EdgeSelectedEventArgs.cs b/GraphX.UAP.Controls/Models/EdgeSelectedEventArgs.cs new file mode 100644 index 00000000..8fec8a77 --- /dev/null +++ b/GraphX.UAP.Controls/Models/EdgeSelectedEventArgs.cs @@ -0,0 +1,29 @@ +using Windows.UI.Xaml.Input; + +namespace GraphX.Controls.Models +{ + public class EdgeSelectedEventArgs : System.EventArgs + { + public EdgeControl EdgeControl { get; set; } + public PointerRoutedEventArgs Args { get; set; } + + public EdgeSelectedEventArgs(EdgeControl ec, PointerRoutedEventArgs e) + : base() + { + EdgeControl = ec; + Args = e; + } + } + + public sealed class EdgeLabelSelectedEventArgs : EdgeSelectedEventArgs + { + public IEdgeLabelControl EdgeLabelControl { get; set; } + + + public EdgeLabelSelectedEventArgs(IEdgeLabelControl label, EdgeControl ec, PointerRoutedEventArgs e, object nu = null) + : base(ec, e) + { + EdgeLabelControl = label; + } + } +} diff --git a/GraphX.UAP.Controls/Models/FileServiceProviderMETRO.cs b/GraphX.UAP.Controls/Models/FileServiceProviderMETRO.cs new file mode 100644 index 00000000..f9839d4b --- /dev/null +++ b/GraphX.UAP.Controls/Models/FileServiceProviderMETRO.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using GraphX.PCL.Common.Interfaces; +using GraphX.PCL.Common.Models; + +namespace GraphX.Controls.Models +{ + /// + /// WPF implementation of IFileServiceProvider + /// + public static class FileServiceProviderMETRO + { + /// + /// Serializes data classes list to file + /// + /// File name + /// Data classes list + public static void SerializeDataToFile(string filename, List modelsList) + { + + } + /// + /// Deserializes data classes list from file + /// + /// File name + public static List DeserializeDataFromFile(string filename) + { + + return Deserialize(filename).Result; + } + +#pragma warning disable 1998 + private static async Task> Deserialize(string filename) +#pragma warning restore 1998 + { + return new List(); + } + } +} diff --git a/GraphX.UAP.Controls/Models/ModifierKeys.cs b/GraphX.UAP.Controls/Models/ModifierKeys.cs new file mode 100644 index 00000000..36cf89a2 --- /dev/null +++ b/GraphX.UAP.Controls/Models/ModifierKeys.cs @@ -0,0 +1,11 @@ +namespace GraphX.Controls.Models +{ + public class Keyboard + { + public static ModifierKeys Modifiers; + } + + public class ModifierKeys + { + } +} diff --git a/GraphX.UAP.Controls/Models/MouseButtonEventArgs.cs b/GraphX.UAP.Controls/Models/MouseButtonEventArgs.cs new file mode 100644 index 00000000..0aca0031 --- /dev/null +++ b/GraphX.UAP.Controls/Models/MouseButtonEventArgs.cs @@ -0,0 +1,6 @@ +namespace GraphX.Controls.Models +{ + public class MouseButtonEventArgs + { + } +} diff --git a/GraphX.UAP.Controls/Models/VertexMovedEventArgs.cs b/GraphX.UAP.Controls/Models/VertexMovedEventArgs.cs new file mode 100644 index 00000000..6ced638d --- /dev/null +++ b/GraphX.UAP.Controls/Models/VertexMovedEventArgs.cs @@ -0,0 +1,16 @@ +using Windows.UI.Xaml.Input; + +namespace GraphX.Controls.Models +{ + public sealed class VertexMovedEventArgs : System.EventArgs + { + public VertexControl VertexControl { get; private set; } + public PointerRoutedEventArgs Args { get; private set; } + + public VertexMovedEventArgs(VertexControl vc, PointerRoutedEventArgs e) + { + Args = e; + VertexControl = vc; + } + } +} diff --git a/GraphX.UAP.Controls/Models/VertexSelectedEventArgs.cs b/GraphX.UAP.Controls/Models/VertexSelectedEventArgs.cs new file mode 100644 index 00000000..c764b7a5 --- /dev/null +++ b/GraphX.UAP.Controls/Models/VertexSelectedEventArgs.cs @@ -0,0 +1,16 @@ +using Windows.UI.Xaml.Input; + +namespace GraphX.Controls.Models +{ + public sealed class VertexSelectedEventArgs : System.EventArgs + { + public VertexControl VertexControl { get; private set; } + public PointerRoutedEventArgs Args { get; private set; } + + public VertexSelectedEventArgs(VertexControl vc, PointerRoutedEventArgs e) + { + VertexControl = vc; + Args = e; + } + } +} \ No newline at end of file diff --git a/GraphX.UAP.Controls/Models/XamlTypes/ViewModelBase.cs b/GraphX.UAP.Controls/Models/XamlTypes/ViewModelBase.cs new file mode 100644 index 00000000..5236045c --- /dev/null +++ b/GraphX.UAP.Controls/Models/XamlTypes/ViewModelBase.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; + +namespace FancyDevelopment.WinRtPluginSystem.MVVM +{ + public abstract class ViewModelBase : INotifyPropertyChanged + { + + + public event PropertyChangedEventHandler PropertyChanged; + + public ViewModelBase() + { + PropertyValues = new Dictionary(); + PropertyTypes = new Dictionary(); + } + + public IDictionary PropertyValues { get; set; } + + public IDictionary PropertyTypes { get; set; } + + protected T GetPropertyValue(string propertyName) + { + return (T)PropertyValues[propertyName]; + } + + protected void SetPropertyValue(string propertyName, T value) + { + if(!PropertyValues[propertyName].Equals(value)) + { + PropertyValues[propertyName] = value; + OnPropertyChanged(propertyName); + } + } + + public object GetPropertyValue(string propertyName) + { + return PropertyValues[propertyName]; + } + + public void SetPropertyValue(string propertyName, object value) + { + if(value.GetType() != PropertyTypes[propertyName]) + throw new InvalidOperationException("Wrong Type"); + + if (!PropertyValues[propertyName].Equals(value)) + { + PropertyValues[propertyName] = value; + OnPropertyChanged(propertyName); + } + } + + protected void CreateProperty(string propertyName) + { + PropertyTypes[propertyName] = typeof(T); + PropertyValues[propertyName] = default(T); + } + + protected void OnPropertyChanged(string propertyName) + { + if(PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } + } +} diff --git a/GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlMember.cs b/GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlMember.cs new file mode 100644 index 00000000..4cce1e37 --- /dev/null +++ b/GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlMember.cs @@ -0,0 +1,69 @@ +using System; +using Windows.UI.Xaml.Markup; + +namespace FancyDevelopment.WinRtPluginSystem.MVVM +{ + class ViewModelXamlMember : IXamlMember where T : ViewModelBase, new () + { + private readonly string _propertyName; + private readonly ViewModelXamlType _targetType; + private readonly IXamlType _propertyType; + + public ViewModelXamlMember(string propertyName, ViewModelXamlType targetType, IXamlType propertyType) + { + _propertyName = propertyName; + _targetType = targetType; + _propertyType = propertyType; + } + + public object GetValue(object instance) + { + ViewModelBase viewModel = instance as ViewModelBase; + + if(viewModel == null) + throw new InvalidOperationException("Only view model types are supported"); + + return viewModel.GetPropertyValue(_propertyName); + } + + public bool IsAttachable + { + get { return false; } + } + + public bool IsDependencyProperty + { + get { return false; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public string Name + { + get { return _propertyName; } + } + + public void SetValue(object instance, object value) + { + ViewModelBase viewModel = instance as ViewModelBase; + + if (viewModel == null) + throw new InvalidOperationException("Only view model types are supported"); + + viewModel.SetPropertyValue(_propertyName, value); + } + + public IXamlType TargetType + { + get { return _targetType; } + } + + public IXamlType Type + { + get { return _propertyType; } + } + } +} diff --git a/GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlMetadataProvider.cs b/GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlMetadataProvider.cs new file mode 100644 index 00000000..1915f095 --- /dev/null +++ b/GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlMetadataProvider.cs @@ -0,0 +1,28 @@ +using System; +using Windows.UI.Xaml.Markup; + +namespace FancyDevelopment.WinRtPluginSystem.MVVM +{ + /* public class ViewModelXamlMetadataProvider : IXamlMetadataProvider + { + public IXamlType GetXamlType(string fullName) + { + return XamlTypeProvider.Instance.GetType(fullName); + } + + public IXamlType GetXamlType(Type type) + { + return XamlTypeProvider.Instance.GetType(type); + } + + public XmlnsDefinition[] GetXmlnsDefinitions() + { + return new[] + { + new XmlnsDefinition() { XmlNamespace = "http://schemas.panthernet.ru/graphx/", Namespace = "GraphX.Controls" }, + new XmlnsDefinition() { XmlNamespace = "http://schemas.panthernet.ru/graphx/", Namespace = "GraphX.Controls.Animations" }, + new XmlnsDefinition() { XmlNamespace = "http://schemas.panthernet.ru/graphx/", Namespace = "GraphX.Controls.Models" }, + }; + } + }*/ +} diff --git a/GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlType.cs b/GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlType.cs new file mode 100644 index 00000000..7b3af84c --- /dev/null +++ b/GraphX.UAP.Controls/Models/XamlTypes/ViewModelXamlType.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using Windows.UI.Xaml.Markup; + +namespace FancyDevelopment.WinRtPluginSystem.MVVM +{ + class ViewModelXamlType : IXamlType where T : ViewModelBase, new() + { + private readonly IXamlType _baseType; + private IDictionary> _members; + + public ViewModelXamlType(IXamlType baseType) + { + _baseType = baseType; + } + + public object ActivateInstance() + { + return Activator.CreateInstance(); + } + + public void AddToMap(object instance, object key, object value) + { + throw new NotSupportedException(); + } + + public void AddToVector(object instance, object value) + { + throw new NotSupportedException(); + } + + public IXamlType BaseType + { + get { return _baseType; } + } + + public IXamlMember ContentProperty + { + get { return null; } + } + + public object CreateFromString(string value) + { + throw new NotSupportedException(); + } + + public string FullName + { + get { return typeof(T).FullName; } + } + + public IXamlMember GetMember(string name) + { + return _members[name]; + } + + public bool IsArray + { + get { return false; } + } + + public bool IsBindable + { + get { return true; } + } + + public bool IsCollection + { + get { return false; } + } + + public bool IsConstructible + { + get { return true; } + } + + public bool IsDictionary + { + get { return false; } + } + + public bool IsMarkupExtension + { + get { return false; } + } + + public IXamlType ItemType + { + get { throw new NotSupportedException(); } + } + + public IXamlType KeyType + { + get { throw new NotSupportedException(); } + } + + public void RunInitializer() + { + _members = new Dictionary>(); + + // Create a dummy view model to read the property information + T dummy = Activator.CreateInstance(); + + foreach (KeyValuePair property in dummy.PropertyTypes) + { + IXamlType propertyType = XamlTypeProvider.Instance.GetType(property.Value); + + _members.Add(property.Key, new ViewModelXamlMember(property.Key, this, propertyType)); + } + } + + public Type UnderlyingType + { + get { return typeof (T); } + } + } +} diff --git a/GraphX.UAP.Controls/Models/XamlTypes/XamlSystemType.cs b/GraphX.UAP.Controls/Models/XamlTypes/XamlSystemType.cs new file mode 100644 index 00000000..68392e86 --- /dev/null +++ b/GraphX.UAP.Controls/Models/XamlTypes/XamlSystemType.cs @@ -0,0 +1,105 @@ +using System; +using Windows.UI.Xaml.Markup; + +namespace FancyDevelopment.WinRtPluginSystem.MVVM +{ + class XamlSystemType : IXamlType + { + private readonly Type _type; + + public XamlSystemType(Type type) + { + _type = type; + } + + public object ActivateInstance() + { + throw new NotSupportedException(); + } + + public void AddToMap(object instance, object key, object value) + { + throw new NotSupportedException(); + } + + public void AddToVector(object instance, object value) + { + throw new NotSupportedException(); + } + + public IXamlType BaseType + { + get { throw new NotSupportedException(); } + } + + public IXamlMember ContentProperty + { + get { throw new NotSupportedException(); } + } + + public object CreateFromString(string value) + { + throw new NotSupportedException(); + } + + public string FullName + { + get { return _type.FullName; } + } + + public IXamlMember GetMember(string name) + { + throw new NotSupportedException(); + } + + public bool IsArray + { + get { throw new NotSupportedException(); } + } + + public bool IsBindable + { + get { throw new NotSupportedException(); } + } + + public bool IsCollection + { + get { throw new NotSupportedException(); } + } + + public bool IsConstructible + { + get { throw new NotSupportedException(); } + } + + public bool IsDictionary + { + get { throw new NotSupportedException(); } + } + + public bool IsMarkupExtension + { + get { throw new NotSupportedException(); } + } + + public IXamlType ItemType + { + get { throw new NotSupportedException(); } + } + + public IXamlType KeyType + { + get { throw new NotSupportedException(); } + } + + public void RunInitializer() + { + throw new NotSupportedException(); + } + + public Type UnderlyingType + { + get { return _type; } + } + } +} diff --git a/GraphX.UAP.Controls/Models/XamlTypes/XamlTypeProvider.cs b/GraphX.UAP.Controls/Models/XamlTypes/XamlTypeProvider.cs new file mode 100644 index 00000000..42369dbc --- /dev/null +++ b/GraphX.UAP.Controls/Models/XamlTypes/XamlTypeProvider.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Windows.UI.Xaml.Markup; + +namespace FancyDevelopment.WinRtPluginSystem.MVVM +{ + public class XamlTypeProvider + { + private static XamlTypeProvider _instance; + + public static XamlTypeProvider Instance + { + get + { + if(_instance == null) + _instance = new XamlTypeProvider(); + + return _instance; + } + } + + private IDictionary _xamlTypesByType; + private IDictionary _xamlTypesByName; + + public XamlTypeProvider() + { + _xamlTypesByName = new Dictionary(); + _xamlTypesByType = new Dictionary(); + } + + public void RegisterViewModelType(IXamlType baseType = null) where T : ViewModelBase, new () + { + IXamlType xamlType = new ViewModelXamlType(baseType); + AddType(typeof(T), xamlType); + } + + public void AddType(Type underlyingType, IXamlType xamlType) + { + _xamlTypesByType[underlyingType] = xamlType; + _xamlTypesByName[underlyingType.FullName] = xamlType; + } + + public IXamlType GetType(Type underlyingType) + { + if(_xamlTypesByType.ContainsKey(underlyingType)) + { + return _xamlTypesByType[underlyingType]; + } + + return CreateSystemType(underlyingType); + } + + public IXamlType GetType(string fullName) + { + if(_xamlTypesByName.ContainsKey(fullName)) + { + return _xamlTypesByName[fullName]; + } + + return null; + } + + private IXamlType CreateSystemType(Type systemType) + { + XamlSystemType xamlType = new XamlSystemType(systemType); + _xamlTypesByType[systemType] = xamlType; + return xamlType; + } + } +} diff --git a/GraphX.UAP.Controls/PrintHelper.cs b/GraphX.UAP.Controls/PrintHelper.cs new file mode 100644 index 00000000..981f7fad --- /dev/null +++ b/GraphX.UAP.Controls/PrintHelper.cs @@ -0,0 +1,142 @@ +using System; +using GraphX.PCL.Common.Enums; + +namespace GraphX.Controls +{ + internal static class PrintHelper + { + /// + /// Default image resolution + /// + public const double DEFAULT_DPI = 96d; + + //Set pixelformat of image. + /////!!! private static PixelFormat pixelFormat = PixelFormats.Pbgra32; + + /// + /// Method exports the GraphArea to an png image. + /// + /// GraphArea control + /// Image destination path + /// Optional image DPI parameter + /// Optional image quality parameter (for some formats like JPEG) + public static void ExportToImage(GraphAreaBase surface, Uri path, ImageType itype, bool useZoomControlSurface = false, double imgdpi = DEFAULT_DPI, int imgQuality = 100) + { + //TODO + //Create a render bitmap and push the surface to it + /*Visual vis = surface; + if (useZoomControlSurface) + { + if (surface.Parent != null && surface.Parent is IZoomControl) + vis = (surface.Parent as IZoomControl).PresenterVisual; + else if(surface.Parent!=null && surface.Parent is FrameworkElement && (surface.Parent as FrameworkElement).Parent is IZoomControl) + vis = ((surface.Parent as FrameworkElement).Parent as IZoomControl).PresenterVisual; + } + var renderBitmap = + new RenderTargetBitmap( + //(int)surface.ActualWidth, + //(int)surface.ActualHeight, + (int)((vis as UIElement).DesiredSize.Width * (imgdpi / DefaultDPI) + 100), + (int)((vis as UIElement).DesiredSize.Height * (imgdpi / DefaultDPI) + 100), + imgdpi, + imgdpi, + pixelFormat); + + //Render the graphlayout onto the bitmap. + renderBitmap.Render(vis); + + + //Create a file stream for saving image + using (FileStream outStream = new FileStream(path.LocalPath, FileMode.Create)) + { + //Use png encoder for our data + BitmapEncoder encoder; + switch (itype) + { + case ImageType.PNG: encoder = new PngBitmapEncoder(); + break; + case ImageType.JPEG: encoder = new JpegBitmapEncoder() { QualityLevel = imgQuality }; + break; + case ImageType.BMP: encoder = new BmpBitmapEncoder(); + break; + case ImageType.GIF: encoder = new GifBitmapEncoder(); + break; + case ImageType.TIFF: encoder = new TiffBitmapEncoder(); + break; + default: throw new GX_InvalidDataException("ExportToImage() -> Unknown output image format specified!"); + } + + //Push the rendered bitmap to it + encoder.Frames.Add(BitmapFrame.Create(renderBitmap)); + //Save the data to the stream + encoder.Save(outStream); + }*/ + } + + + public static void ShowPrintPreview(GraphAreaBase surface, string description = "") + { + //TODO + /* try + { + var printDialog = new PrintDialog(); + if (printDialog.ShowDialog() == true) + { + printDialog.PrintVisual(surface, description); + } + } + catch (Exception ex) + { + new MessageDialog("Unexpected exception occured while trying to acces default printer. Please ensure that default printer is installed in your OS!").Show(); + }*/ + } + + /*public static Bitmap RenderTargetBitmapToBitmap(RenderTargetBitmap source) + { + using (MemoryStream outStream = new MemoryStream()) + { + //Use png encoder for our data + PngBitmapEncoder encoder = new PngBitmapEncoder(); + + //Push the rendered bitmap to it + encoder.Frames.Add(BitmapFrame.Create(source)); + + //Save the data to the stream + encoder.Save(outStream); + return new Bitmap(outStream); + } + }*/ + + /* public static RenderTargetBitmap RenderTargetBitmap(GraphAreaBase surface, bool useZoomControlSurface, double imgdpi) + { + Visual vis = surface; + if (useZoomControlSurface) + { + if (surface.Parent != null && surface.Parent is IZoomControl) + vis = (surface.Parent as IZoomControl).PresenterVisual; + else if (surface.Parent != null && surface.Parent is FrameworkElement && + (surface.Parent as FrameworkElement).Parent is IZoomControl) + vis = ((surface.Parent as FrameworkElement).Parent as IZoomControl).PresenterVisual; + } + var renderBitmap = + new RenderTargetBitmap( + //(int)surface.ActualWidth, + //(int)surface.ActualHeight, + (int)((vis as UIElement).DesiredSize.Width * (imgdpi / 96) + 100), + (int)((vis as UIElement).DesiredSize.Height * (imgdpi / 96) + 100), + imgdpi, + imgdpi, + pixelFormat); + + vis.SetValue(Panel.BackgroundProperty, System.Windows.Media.Brushes.White); + //Render the graphlayout onto the bitmap. + renderBitmap.Render(vis); + + return renderBitmap; + + }*/ + + + + } +} diff --git a/GraphX.UAP.Controls/Properties/AssemblyInfo.cs b/GraphX.UAP.Controls/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..3f26bb70 --- /dev/null +++ b/GraphX.UAP.Controls/Properties/AssemblyInfo.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("GraphX.UAP.Controls")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GraphX.UAP.Controls")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: ComVisible(false)] \ No newline at end of file diff --git a/GraphX.UAP.Controls/Properties/GraphX.UAP.Controls.rd.xml b/GraphX.UAP.Controls/Properties/GraphX.UAP.Controls.rd.xml new file mode 100644 index 00000000..efa140cc --- /dev/null +++ b/GraphX.UAP.Controls/Properties/GraphX.UAP.Controls.rd.xml @@ -0,0 +1,33 @@ + + + + + + + + + diff --git a/GraphX.UAP.Controls/Themes/Generic.xaml b/GraphX.UAP.Controls/Themes/Generic.xaml new file mode 100644 index 00000000..cdcbc7ad --- /dev/null +++ b/GraphX.UAP.Controls/Themes/Generic.xaml @@ -0,0 +1,262 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/GraphX.UAP.Controls/uap_graphx.controls.pfx b/GraphX.UAP.Controls/uap_graphx.controls.pfx new file mode 100644 index 0000000000000000000000000000000000000000..77650268006761994bc7a3703faa89fe7ad67393 GIT binary patch literal 1709 zcmcIlYcy4982=)Pdab3MAMXo zzeV_xvNxs+-|!tC9FOeq9zR~Hfm3H))f>n~w7nY{Oxmafh1%E>H7|G2IJCQ^ys%}^ z?Bcc=J-;tRz|mF4KgLr_A|9Si4o)3fp)WCCJMFyPNr*z$iPK9g0}@|iDAUw(YrI!k zvW+rk>iVRiscEbdPZU<3+#^8G+WhP=-&HAm%;DVo3niUlZkft4ecKiclLumjq8~nA zt8N!OCa^X@jaK`M!TPg4Jk5maavri%aWHpuWXI{Jirqtb4n3n&;(m0yG^J*po3c~V zpQ5;umOXRzgYCRKZf|2|3eb^GeGS=M9QZ3btmcPT=&&1!x!l22X^txENo?(K<&*{g zkf2(E^u>bS>;<2e&#w~G!$V|s%|?vkv|ZAe-!NJEeC~wJp8a0M1(Tic#FOq)ri1l{ zU8Z)u8|CGST~)(1qf&!(BG@%%3dIItm#>$o2l&wP%Y3t$13{xPz4{tMVz;W;Vp$eq znbkJ#MI~m&lNmAtJ+~{)G^d!mG5UoVh2KA7ReJ*+)4{TzYSM*o?h-1gY4rP*eU2%( zi*YwKG}H!EMXqt)Bvs(H`ON^sac*k%g_)!OJ>Ot$83Wp0AF!vEcj$^9$7x>CF-@tR z>n^=cc*2n2wBxImkGbG#0wa?V008dvwfW zQgsVNMnDfLOo&Y28XN`zg9UV9XhBU2MB>hv;6@A~BV1i^gs`St0ZZTw4ue484^F`J z1Sf$4u!Gk{#SeHv#)3Eu1VGIn@<8AQ@sXu21z^3jE*LU*-~j@m6O)#wUoPGiuaS-EH%y&Igf9)qGrJ zc@sp40`UEWJ#L4Q?8&76_-)apM2IaoK`;qzLR*t?gj8>lGKnSn|8304{`wga3LtUL z1Dq3&ayVeb&a#bCaIvCi;U1=aE#pX?xs;R$+u*a~xNP&OTouLw6KylCw-Sn_9hsPE z%C`P&4~#8K>aX}lr|gRtWu6TA_*+_+c$*8>Ab2IaLYnR%BK+JSJ#$V~xtBtxtCgLo zB2R8@LK}J<I@cU83(KaZZ0;~DU73%P5P*C=9{dC(IM)IGCgXmVbX~jO zx|jE4T0ynJT)++aN5ggF25mAsMB<7@C{+BcRbk(u`v#w;wgBX$pDpAx9-F zFW#u7_|smm-xJ6BuXoFLVfGqX0c+$A$Pd`-B)mG$SDm?J<|;sJH*suvPxmw(Hh=jc z#gp-_XLd(jioZSpDyQ(#ILN07ls;N-x*F9{3{H~LmMO{AIU=N|Gr fqeqr_<}Jrtko