From a2a7222b4f2fc3fa99263b0616d518fd1567e88e Mon Sep 17 00:00:00 2001 From: Eric Rozell Date: Tue, 5 Jan 2016 17:37:04 -0500 Subject: [PATCH] Towards #92 - Adds very early prototype of ReactTextViewManager. --- ReactWindows/Playground/Playground.csproj | 4 +- .../Playground/Resources/main.dev.jsbundle | 7 +- ReactWindows/ReactNative/ReactNative.csproj | 6 +- .../ReactNative/Shell/MainReactPackage.cs | 6 +- .../ReactNative/UIManager/BaseViewManager.cs | 8 - .../ReactNative/UIManager/LayoutShadowNode.cs | 15 +- .../UIManager/NativeViewHierarchyManager.cs | 2 +- .../UIManager/NativeViewHierarchyOptimizer.cs | 2 +- .../ReactNative/UIManager/ReactShadowNode.cs | 4 +- .../UIManager/SimpleViewManager.cs | 4 +- .../UIManager/SizeMonitoringPanel.cs | 2 +- .../ReactNative/UIManager/UIImplementation.cs | 4 +- .../Views/Text/ReactRawTextManager.cs | 33 +++ .../Views/Text/ReactTextShadowNode.cs | 221 ++++++++++++++++++ .../ReactNative/Views/Text/ReactTextUpdate.cs | 12 + .../Views/Text/ReactTextViewManager.cs | 37 +++ .../ReactNative/Views/View/ReactPanel.cs | 2 +- .../References/Facebook.CSSLayout.dll | Bin 27648 -> 28672 bytes 18 files changed, 341 insertions(+), 28 deletions(-) create mode 100644 ReactWindows/ReactNative/Views/Text/ReactRawTextManager.cs create mode 100644 ReactWindows/ReactNative/Views/Text/ReactTextShadowNode.cs create mode 100644 ReactWindows/ReactNative/Views/Text/ReactTextUpdate.cs create mode 100644 ReactWindows/ReactNative/Views/Text/ReactTextViewManager.cs diff --git a/ReactWindows/Playground/Playground.csproj b/ReactWindows/Playground/Playground.csproj index 1d98b26bdff..e5ea7c85dcc 100644 --- a/ReactWindows/Playground/Playground.csproj +++ b/ReactWindows/Playground/Playground.csproj @@ -142,11 +142,11 @@ - + + False ..\References\Facebook.CSSLayout.dll - 14.0 diff --git a/ReactWindows/Playground/Resources/main.dev.jsbundle b/ReactWindows/Playground/Resources/main.dev.jsbundle index ed313bfdcd6..67546e62a1e 100644 --- a/ReactWindows/Playground/Resources/main.dev.jsbundle +++ b/ReactWindows/Playground/Resources/main.dev.jsbundle @@ -1188,12 +1188,13 @@ typeof global!=='undefined'?global:typeof self!=='undefined'?self:this); __d('react-xaml-wpf/index.ios.js',function(global, require, module, exports) { 'use strict'; var React=require('react-native/Libraries/react-native/react-native.js');var -AppRegistry=React.AppRegistry;var View=React.View; +AppRegistry=React.AppRegistry;var View=React.View;var Text=React.Text; var ReactRoot=React.createClass({displayName:'ReactRoot', render:function(){ return ( -React.createElement(View,{elevation:'1.0'}));}}); +React.createElement(View,{elevation:'1.0'}, +React.createElement(Text,null,'Hello React Native')));}}); @@ -57327,4 +57328,4 @@ module.exports=findDOMNode; }); ;require("InitializeJavaScriptAppEngine"); ;require("react-xaml-wpf/index.ios.js"); -__SSTOKENSTRING = "@generated SignedSource<<8a9aad82927145a159f9ecb21a3904c7>>"; +__SSTOKENSTRING = "@generated SignedSource<>"; diff --git a/ReactWindows/ReactNative/ReactNative.csproj b/ReactWindows/ReactNative/ReactNative.csproj index 65bc908bb29..18e440dfa7e 100644 --- a/ReactWindows/ReactNative/ReactNative.csproj +++ b/ReactWindows/ReactNative/ReactNative.csproj @@ -251,6 +251,9 @@ + + + @@ -269,7 +272,8 @@ - + + False ..\References\Facebook.CSSLayout.dll diff --git a/ReactWindows/ReactNative/Shell/MainReactPackage.cs b/ReactWindows/ReactNative/Shell/MainReactPackage.cs index 5d5bd7fd164..9a1a9e3c802 100644 --- a/ReactWindows/ReactNative/Shell/MainReactPackage.cs +++ b/ReactWindows/ReactNative/Shell/MainReactPackage.cs @@ -2,10 +2,10 @@ using ReactNative.Modules.Core; using ReactNative.Modules.WebSocket; using ReactNative.UIManager; +using ReactNative.Views.Text; using ReactNative.Views.View; using System; using System.Collections.Generic; -using Windows.UI.Xaml; namespace ReactNative.Shell { @@ -36,12 +36,12 @@ public IReadOnlyList CreateViewManagers( //new ReactHorizontalScrollViewManager(), //new ReactImageManager(), //new ReactProgressBarViewManager(), - //new ReactRawTextManager(), + new ReactRawTextManager(), //new RecyclerViewBackedScrollViewManager(), //new ReactScrollViewManager(), //new ReactSwitchManager(), //new ReactTextInputManager(), - //new ReactTextViewManager(), + new ReactTextViewManager(), //new ReactToolbarManager(), new ReactViewManager(), //new ReactViewPagerManager(), diff --git a/ReactWindows/ReactNative/UIManager/BaseViewManager.cs b/ReactWindows/ReactNative/UIManager/BaseViewManager.cs index 597acafcfcf..3022736fcc1 100644 --- a/ReactWindows/ReactNative/UIManager/BaseViewManager.cs +++ b/ReactWindows/ReactNative/UIManager/BaseViewManager.cs @@ -28,14 +28,6 @@ public abstract class BaseViewManager : Vi private const string PROP_DECOMPOSED_MATRIX_TRANSLATE_Y = "translateY"; private const string PROP_OPACITY = "opacity"; - /// - /// Sets the background color of the . - /// - /// - /// - [ReactProperty(PROP_BACKGROUND_COLOR, DefaultInteger = 0x00FFFFFF /* Colors.Transparent */, CustomType = "Color")] - public abstract void SetBackgroundColor(TFrameworkElement view, int backgroundColor); - /// /// Set's the styling layout /// properties, based on the map. diff --git a/ReactWindows/ReactNative/UIManager/LayoutShadowNode.cs b/ReactWindows/ReactNative/UIManager/LayoutShadowNode.cs index d6d3798e482..d582003fcb8 100644 --- a/ReactWindows/ReactNative/UIManager/LayoutShadowNode.cs +++ b/ReactWindows/ReactNative/UIManager/LayoutShadowNode.cs @@ -205,10 +205,23 @@ public void SetBorderWidth(int index, float borderWidth) public void SetPosition(string position) { PositionType = position != null - ? Parse(position) + ? ParsePositionType(position) : CSSPositionType.Relative; } + private static CSSPositionType ParsePositionType(string position) + { + switch (position.ToLowerInvariant()) + { + case "relative": + return CSSPositionType.Relative; + case "absolute": + return CSSPositionType.Absolute; + default: + throw new ArgumentException("Invalid position type.", position); + } + } + private static T Parse(string value) { return (T)Enum.Parse(typeof(T), value); diff --git a/ReactWindows/ReactNative/UIManager/NativeViewHierarchyManager.cs b/ReactWindows/ReactNative/UIManager/NativeViewHierarchyManager.cs index 6371d4969d0..5409535b0ab 100644 --- a/ReactWindows/ReactNative/UIManager/NativeViewHierarchyManager.cs +++ b/ReactWindows/ReactNative/UIManager/NativeViewHierarchyManager.cs @@ -134,7 +134,7 @@ public void UpdateLayout(int parentTag, int tag, int x, int y, int width, int he { var viewToUpdate = ResolveView(tag); // TODO: call viewToUpdate.Measure() - throw new NotImplementedException(); + //throw new NotImplementedException(); } } diff --git a/ReactWindows/ReactNative/UIManager/NativeViewHierarchyOptimizer.cs b/ReactWindows/ReactNative/UIManager/NativeViewHierarchyOptimizer.cs index 9df492d07bf..642db078d0f 100644 --- a/ReactWindows/ReactNative/UIManager/NativeViewHierarchyOptimizer.cs +++ b/ReactWindows/ReactNative/UIManager/NativeViewHierarchyOptimizer.cs @@ -157,7 +157,7 @@ public void HandleManageChildren(ReactShadowNode nodeToManage, int[] indicesToRe // the time this method is called, these views have already been // removed from the shadow hierarchy and the indices are no longer // useful to operate on. - for (var i = 0; i< tagsToRemove.Length; ++i) + for (var i = 0; i < tagsToRemove.Length; ++i) { var tagToRemove = tagsToRemove[i]; var delete = tagsToDelete.Contains(tagToRemove); diff --git a/ReactWindows/ReactNative/UIManager/ReactShadowNode.cs b/ReactWindows/ReactNative/UIManager/ReactShadowNode.cs index 0f590bfe068..a8f87204528 100644 --- a/ReactWindows/ReactNative/UIManager/ReactShadowNode.cs +++ b/ReactWindows/ReactNative/UIManager/ReactShadowNode.cs @@ -43,7 +43,7 @@ public virtual bool IsVirtual /// will not try to perform /// manage children operations on such views. /// - public bool IsVirtualAnchor + public virtual bool IsVirtualAnchor { get { @@ -534,7 +534,7 @@ internal void DispatchUpdates( /// /// Marks a node as updated. /// - protected void MarkUpdated() + protected virtual void MarkUpdated() { if (_nodeUpdated) { diff --git a/ReactWindows/ReactNative/UIManager/SimpleViewManager.cs b/ReactWindows/ReactNative/UIManager/SimpleViewManager.cs index b405d457cae..163e8d7139a 100644 --- a/ReactWindows/ReactNative/UIManager/SimpleViewManager.cs +++ b/ReactWindows/ReactNative/UIManager/SimpleViewManager.cs @@ -14,7 +14,7 @@ public abstract class SimpleViewManager : BaseViewManager instance. /// /// The shadow node instance. - public override ReactShadowNode CreateShadowNodeInstance() + protected sealed override LayoutShadowNode CreateShadowNodeInstanceCore() { return new LayoutShadowNode(); } @@ -26,7 +26,7 @@ public override ReactShadowNode CreateShadowNodeInstance() /// /// The root view. /// The extra data. - public override void UpdateExtraData(FrameworkElement root, object extraData) + protected override void UpdateExtraData(TFrameworkElement root, object extraData) { } } diff --git a/ReactWindows/ReactNative/UIManager/SizeMonitoringPanel.cs b/ReactWindows/ReactNative/UIManager/SizeMonitoringPanel.cs index 5ed10378bd0..1740aab3e1d 100644 --- a/ReactWindows/ReactNative/UIManager/SizeMonitoringPanel.cs +++ b/ReactWindows/ReactNative/UIManager/SizeMonitoringPanel.cs @@ -6,7 +6,7 @@ namespace ReactNative.UIManager /// /// allows registering for size change events. The main purpose for this class is to hide complexity of ReactRootView /// - public partial class SizeMonitoringPanel : Panel + public partial class SizeMonitoringPanel : Grid { private ISizeChangedListener _onSizeChangedListener; diff --git a/ReactWindows/ReactNative/UIManager/UIImplementation.cs b/ReactWindows/ReactNative/UIManager/UIImplementation.cs index 931bc4b7a29..507661dbb8f 100644 --- a/ReactWindows/ReactNative/UIManager/UIImplementation.cs +++ b/ReactWindows/ReactNative/UIManager/UIImplementation.cs @@ -233,7 +233,7 @@ public void ManageChildren( var numToRemove = removeFrom?.Length ?? 0; var viewsToAdd = new ViewAtIndex[numToMove + numToAdd]; var indicesToRemove = new int[numToMove + numToRemove]; - var tagsToRemove = new int[addAtIndices.Length]; + var tagsToRemove = new int[indicesToRemove.Length]; var tagsToDelete = new int[numToRemove]; if (numToMove > 0) @@ -250,7 +250,7 @@ public void ManageChildren( if (numToAdd > 0) { - for (var i = 0; i < numToRemove; ++i) + for (var i = 0; i < numToAdd; ++i) { viewsToAdd[numToMove + i] = new ViewAtIndex(addChildTags[i], addAtIndices[i]); } diff --git a/ReactWindows/ReactNative/Views/Text/ReactRawTextManager.cs b/ReactWindows/ReactNative/Views/Text/ReactRawTextManager.cs new file mode 100644 index 00000000000..3720b0f5734 --- /dev/null +++ b/ReactWindows/ReactNative/Views/Text/ReactRawTextManager.cs @@ -0,0 +1,33 @@ +using ReactNative.UIManager; +using System; +using Windows.UI.Xaml.Controls; + +namespace ReactNative.Views.Text +{ + public class ReactRawTextManager : ReactTextViewManager + { + private const string ReactClass = "RCTRawText"; + + public override string Name + { + get + { + return ReactClass; + } + } + + protected override TextBlock CreateViewInstanceCore(ThemedReactContext reactContext) + { + throw new InvalidOperationException("RCTRawText does not map to a native view."); + } + + protected override void UpdateExtraData(TextBlock root, object extraData) + { + } + + protected override ReactTextShadowNode CreateShadowNodeInstanceCore() + { + return new ReactTextShadowNode(true); + } + } +} diff --git a/ReactWindows/ReactNative/Views/Text/ReactTextShadowNode.cs b/ReactWindows/ReactNative/Views/Text/ReactTextShadowNode.cs new file mode 100644 index 00000000000..270317dae40 --- /dev/null +++ b/ReactWindows/ReactNative/Views/Text/ReactTextShadowNode.cs @@ -0,0 +1,221 @@ +using Facebook.CSSLayout; +using ReactNative.UIManager; +using System; +using System.Collections.Generic; +using System.Text; +using Windows.UI.Text; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Documents; +using Windows.UI.Xaml.Media; + +namespace ReactNative.Views.Text +{ + public class ReactTextShadowNode : LayoutShadowNode + { + private const string INLINE_IMAGE_PLACEHOLDER = "I"; + private const int UNSET = -1; + + private const string PROP_TEXT = "text"; + + private const string PROP_SHADOW_OFFSET = "textShadowOffset"; + private const string PROP_SHADOW_RADIUS = "textShadowRadius"; + private const string PROP_SHADOW_COLOR = "textShadowColor"; + private const int DEFAULT_TEXT_SHADOW_COLOR = 0x55000000; + + private int _lineHeight = UNSET; + private bool _isColorSet = false; + private int _color; + private bool _isBackgroundColorSet = false; + private int _backgroundColor; + + private int _numberOfLines = UNSET; + private int _fontSize = UNSET; + + private double _textShadowOffsetDx = 0.0; + private double _textShadowOffsetDy = 0.0; + private double _textShadowRadius = 1.0; + private int _textShadowColor = DEFAULT_TEXT_SHADOW_COLOR; + + private FontStyle? _fontStyle; + private FontWeight? _fontWeight; + + private string _fontFamily; + private string _text; + + private string _inlineText; + + private readonly bool _isVirtual; + + public ReactTextShadowNode(bool isVirtual) + { + _isVirtual = isVirtual; + + if (!_isVirtual) + { + MeasureFunction = TextMeasureFunction; + } + } + + public override bool IsVirtual + { + get + { + return _isVirtual; + } + } + + public override bool IsVirtualAnchor + { + get + { + return !_isVirtual; + } + } + + public override void OnBeforeLayout() + { + if (_isVirtual) + { + return; + } + + _inlineText = FromTextCSSNode(this); + MarkUpdated(); + } + + protected override void MarkUpdated() + { + base.MarkUpdated(); + + if (!_isVirtual) + { + dirty(); + } + } + + public override void OnCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) + { + if (_isVirtual) + { + return; + } + + base.OnCollectExtraUpdates(uiViewOperationQueue); + if (_inlineText != null) + { + uiViewOperationQueue.EnqueueUpdateExtraData(ReactTag, _inlineText); + } + } + + [ReactProperty("text")] + public void SetText(string text) + { + _text = text; + MarkUpdated(); + } + + [ReactProperty(ViewProperties.NumberOfLines, DefaultInteger = UNSET)] + public void SetNumberOfLines(int numberOfLines) + { + _numberOfLines = numberOfLines; + MarkUpdated(); + } + + [ReactProperty(ViewProperties.LineHeight, DefaultInteger = UNSET)] + public void SetLineHeight(int lineHeight) + { + _lineHeight = lineHeight; + MarkUpdated(); + } + + [ReactProperty(ViewProperties.FontSize, DefaultDouble = UNSET)] + public void SetFontSize(double fontSize) + { + _fontSize = (int)fontSize; + MarkUpdated(); + } + + [ReactProperty(ViewProperties.FontFamily)] + public void SetFontFamily(string fontFamily) + { + _fontFamily = fontFamily; + MarkUpdated(); + } + + [ReactProperty(ViewProperties.FontWeight)] + public void SetFontWeight(string fontWeightString) + { + var fontWeightNumeric = fontWeightString != null + ? ParseNumericFontWeight(fontWeightString) + : -1; + + var fontWeight = default(FontWeight?); + if (fontWeightNumeric >= 500 || fontWeightString == "bold") + { + fontWeight = FontWeights.Bold; + } + else if (fontWeightString == "normal" || (fontWeightNumeric != -1 && fontWeightNumeric < 500)) + { + fontWeight = FontWeights.Normal; + } + + if (_fontWeight.HasValue != fontWeight.HasValue || + (_fontWeight.HasValue && fontWeight.HasValue && + _fontWeight.Value.Weight != fontWeight.Value.Weight)) + { + _fontWeight = fontWeight; + MarkUpdated(); + } + } + + [ReactProperty(ViewProperties.FontStyle)] + public void SetFontStyle(string fontStyleString) + { + var fontStyle = default(FontStyle?); + if (fontStyleString == "italic") + { + fontStyle = FontStyle.Italic; + } + else if (fontStyleString == "normal") + { + fontStyle = FontStyle.Normal; + } + + if (_fontStyle != fontStyle) + { + _fontStyle = fontStyle; + MarkUpdated(); + } + } + + private static MeasureOutput TextMeasureFunction(CSSNode node, float width, float height) + { + // TODO: implement + return new MeasureOutput(width, height); + } + + private static int ParseNumericFontWeight(string fontWeightString) + { + return fontWeightString.Length == 3 && fontWeightString.EndsWith("00") && + fontWeightString[0] <= '9' && fontWeightString[0] >= '1' + ? 100 * (fontWeightString[0] - '0') + : -1; + } + + private static string FromTextCSSNode(ReactTextShadowNode textNode) + { + var builder = new StringBuilder(); + for (var i = 0; i < textNode.ChildCount; ++i) + { + var child = textNode.GetChildAt(i); + var textChild = child as ReactTextShadowNode; + if (textChild != null) + { + builder.Append(textChild._text); + } + } + + return builder.ToString(); + } + } +} \ No newline at end of file diff --git a/ReactWindows/ReactNative/Views/Text/ReactTextUpdate.cs b/ReactWindows/ReactNative/Views/Text/ReactTextUpdate.cs new file mode 100644 index 00000000000..723cf4d3a60 --- /dev/null +++ b/ReactWindows/ReactNative/Views/Text/ReactTextUpdate.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ReactNative.Views.Text +{ + class ReactTextUpdate + { + } +} diff --git a/ReactWindows/ReactNative/Views/Text/ReactTextViewManager.cs b/ReactWindows/ReactNative/Views/Text/ReactTextViewManager.cs new file mode 100644 index 00000000000..a2047728e6c --- /dev/null +++ b/ReactWindows/ReactNative/Views/Text/ReactTextViewManager.cs @@ -0,0 +1,37 @@ +using System; +using ReactNative.UIManager; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; +using Windows.UI.Text; + +namespace ReactNative.Views.Text +{ + public class ReactTextViewManager : BaseViewManager + { + private const string ReactClass = "RCTText"; + + public override string Name + { + get + { + return ReactClass; + } + } + + protected override TextBlock CreateViewInstanceCore(ThemedReactContext reactContext) + { + return new TextBlock(); + } + + protected override ReactTextShadowNode CreateShadowNodeInstanceCore() + { + return new ReactTextShadowNode(false); + } + + protected override void UpdateExtraData(TextBlock root, object extraData) + { + var stringData = (string)extraData; + root.Text = stringData; + } + } +} diff --git a/ReactWindows/ReactNative/Views/View/ReactPanel.cs b/ReactWindows/ReactNative/Views/View/ReactPanel.cs index 75f023695ac..6e5b7aefa2b 100644 --- a/ReactWindows/ReactNative/Views/View/ReactPanel.cs +++ b/ReactWindows/ReactNative/Views/View/ReactPanel.cs @@ -14,7 +14,7 @@ namespace ReactNative.Views.View /// aren't common, lazy initializes most of the storage needed for them. Also supports /// 3D transformations such as elevation depth. /// - public class ReactPanel : Panel, ICatalystInterceptingViewGroup, ReactPointerEventsView + public class ReactPanel : Grid, ICatalystInterceptingViewGroup, ReactPointerEventsView { private IOnInterceptTouchEventListener _onInterceptTouchEventListener; private PointerEvents _PointerEvents = PointerEvents.Auto; diff --git a/ReactWindows/References/Facebook.CSSLayout.dll b/ReactWindows/References/Facebook.CSSLayout.dll index 16f1573f73e5a1fa8c3f085c0d1b699557b4076d..56743eb6c412ea55d5ded23883cb20d3bd11abc3 100644 GIT binary patch literal 28672 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 J%b#xq{x{Y>_7eaA literal 27648 zcmeHw34EMab?^DUZ!|NKM$&v5TbpHjyu}l3k*vj%?8F{zwt_7$QXDyPP{z{Oo_M5D zW=7r=B??*C5|R`HrZ40tl8}ZxAV7dpO4^VH(l+ElTFPr_UteBHTlz{DT1qMKlJ`I7 z-fuR^0e%UM= zpDBKM!{?2CFK-w-6-xzYlZlhb$aHWrGBcA%2aiXC$+?+eY$iBxU^FyBCbJvm+&R>3vMdEnZf?c=T$)P`D4-U zdsvnKm%VC|S@;}VBs##z647|Z2s8BOIU=8f|2)@V#&v1s1-&reE)BXq0sxte zRr?J}K0%_JTau~dBq;H135XltDSUH2yD?oY$!I(QMe+4H2-(&x_~v|e6ZPegfoqHCGvZqQyX4vqFqb9-x^yUppli0)Ti)B4i;ZA5HKRnj1ueRNB;cIMK3Xly*X zr6!3h__f+8hhLX$6aE_Axx=qdVo^YUt>RZZ{B_A2g}=Vo6ld;3E|`yQSznSo%lyzP z4kmmGv|3b+E4;C*N*aBp+j<=M8h7=0iQ9Znto?5re%Y+MpPgF>Vo+v{!ohHvD!gWB zH5y3qtOu=_ zmL5}PS4M<0r zboeb|+!z?8)WG^?;XPk|{bG|usy(SZsx%aynQUXxodh--6Y ziG^JCzBf@9S-yJzo2ZLSsrTv*2cTYkso{j4w|Su-z{DEb>s-a!0>#?PDOMFIR$Wf9 zra-Y~B}EiqSFS~&FQ=G07*?##RdjN72!d>`GNniBDD25oV5&d?TXc>ErV12>^AwoM z29&GUJXR%-3h~X5@ZBLX1G!QrA%%OQyb)w3pLBwtv}g0_f@$4qV2QdyCCJSt6cN{* zOzU*J!L&wPp-tR^MMpII_srBu@D_Lln<-?qdx5(%QzoNLjMk;lcgX^8KzciBNudk( zBG+N;KdM;biW!8NPl3e#mJ0uBp%q>^Dr5@l>5a>Xvdx>zOKGZ+en z=3(Kx8v?CG^c3nCe^8pa7?^bnyyVT)+n}%z&Y~P4&E+Max7#gMvTZDFsn*vTeXUj3 z1zrn!J1*2+;MCIRDNY}aa-wLIQ$nLW`8rr%QKzhCuk6evO}3(&Jc@3pYOu_sJTWC3 zKlbIV+h2EKoF=^;V=O|w7QadamRe0NtGc~TFJtbwMC06DX=Bi;X>nP#?KPUqUOF1= zTdB+EkrQ8Yz!OJ@>a*SL^>mpYpIeLEc_Md*>GpYfFLqNA(#f6Ki`BXCCfKzuUQ%s& zhvh_?=TP0ACtAOPB->FZT4Fm~-Zq9FHJ@kn_P0uRx8ER_#O(#r2_?NTD;?L3IR{o~ zoF`tPb!aoD1tF9bxPfh`LAjUUs_d&UOdg4eIM4Z`y}MMRBWk*xu!vN7cd1lQh2@Dh zV0{raTx->|`^=hlv$nykZ8vKgOqdL`8ngvcZ?+HKXG`48t165TBqdG7K&}ANXjGTD z8-~m#93tDjHC8B&@F2b3Z>hjujdo4G9Kvx+wot5FK9o7*!Z_t)h9<#n9yRB=7R;Lf zIpL_jBbMWHmz3Xa*OL1l;HKgc6|2Y7`xCS>DhsU|7ZK zB9=UIBcn%%ZdKBFFUrofWkgRB*E7jl??p)}??p*@7(5MwiHZ(@;U=wbS^D7P8gKQ8PF4~!dfIu<=*WBoce8s^X4Q#MC*lt{M zI?f+hb8sb5*5|7{b`XPaG^zp{3pJ~pEnxi$k{lCtg(GwtveixYMtjrEJ

YU^Cdn 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 aK>i*4zY&2&93tT9C%Lfw`{&