From 9b475a307393eb67d5b68e2fb85c206bb0d773a2 Mon Sep 17 00:00:00 2001 From: Watermelon02 <1446157077@qq.com> Date: Tue, 26 Jul 2022 15:51:59 +0800 Subject: [PATCH] =?UTF-8?q?[+]=E6=89=93=E5=8C=85=20[+]=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E7=BE=8E=E5=8C=96=E7=94=A8=E6=88=B7=E7=95=8C=E9=9D=A2=EF=BC=8C?= =?UTF-8?q?=E4=BD=86=E6=98=AF=E6=9D=A5=E4=B8=8D=E5=8F=8A=E5=81=9A=E5=AE=8C?= =?UTF-8?q?=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 30 +++++ app/build.gradle | 4 +- .../tobe/ui/fragment/UserFragment.kt | 1 + .../tobe/view/piechart/PieChartArc1.kt | 106 ++++++++++++++++++ .../tobe/view/piechart/PieChartArc2.kt | 102 +++++++++++++++++ .../tobe/view/piechart/PieChartArc3.kt | 88 +++++++++++++++ .../tobe/view/piechart/PieChartView.kt | 19 ++++ .../tobe/view/piechart/PieChartViewGroup.kt | 71 ++++++++++++ app/src/main/res/layout/fragment_user.xml | 23 ++-- "pic/\351\241\265\351\235\242 1 (2).png" | Bin 16323 -> 0 bytes 10 files changed, 436 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/watermelon/tobe/view/piechart/PieChartArc1.kt create mode 100644 app/src/main/java/watermelon/tobe/view/piechart/PieChartArc2.kt create mode 100644 app/src/main/java/watermelon/tobe/view/piechart/PieChartArc3.kt create mode 100644 app/src/main/java/watermelon/tobe/view/piechart/PieChartView.kt create mode 100644 app/src/main/java/watermelon/tobe/view/piechart/PieChartViewGroup.kt delete mode 100644 "pic/\351\241\265\351\235\242 1 (2).png" diff --git a/README.md b/README.md index 16351f8..683f01d 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,36 @@ fun queryTodoList(status: Int = -1, date: String, priority: Int = 0, index: Int 因为需要满足在`添加\删除`Todo后,Service能及时更改数据,所以需要通过`Binder`实现通信。这里通过`AIDL`然后重写`Stub`的方式完成(总不能要我手写吧) +> Activity + +```kotlin +//绑定启动TodoManagerService +private fun bindTodoManagerService() { + val todoManagerServiceConnection = object : ServiceConnection { + override fun onServiceConnected(name: ComponentName, service: IBinder) { + BaseApp.todoManagerBinder = TodoManager.Stub.asInterface(service) + } + + override fun onServiceDisconnected(name: ComponentName?) {} + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + bindService(Intent(this@DateActivity, TodoManagerService::class.java), + todoManagerServiceConnection, + Context.BIND_AUTO_CREATE) + } + +} +``` + +> Service + +```kotlin +override fun onBind(intent: Intent?): IBinder { + iBinder.queryTodoList() + return iBinder +} +``` + ## 不足 在自定义View方面还不够熟练,浪费了很多时间,而且最后的组件间耦合度比较高。对于Flow的使用不够熟练,有许多暗病. \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index d1a6939..c2c2d7a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,7 +16,9 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } - + lintOptions { + abortOnError false + } buildTypes { release { minifyEnabled false diff --git a/app/src/main/java/watermelon/tobe/ui/fragment/UserFragment.kt b/app/src/main/java/watermelon/tobe/ui/fragment/UserFragment.kt index 2733cc9..0a7da91 100644 --- a/app/src/main/java/watermelon/tobe/ui/fragment/UserFragment.kt +++ b/app/src/main/java/watermelon/tobe/ui/fragment/UserFragment.kt @@ -37,6 +37,7 @@ class UserFragment : DialogFragment() { Editable.Factory.getInstance().newEditable(viewModel.user.value?.data?.publicName) binding.fragmentUserTodoAccountEdit.text = Editable.Factory.getInstance().newEditable(viewModel.user.value?.data?.username) + binding.fragmentUserAccountPieChart.start() return AlertDialog.Builder(requireContext()).setView(binding.root).create() } diff --git a/app/src/main/java/watermelon/tobe/view/piechart/PieChartArc1.kt b/app/src/main/java/watermelon/tobe/view/piechart/PieChartArc1.kt new file mode 100644 index 0000000..4a533c7 --- /dev/null +++ b/app/src/main/java/watermelon/tobe/view/piechart/PieChartArc1.kt @@ -0,0 +1,106 @@ +package watermelon.tobe.view.piechart + +import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.* +import android.graphics.drawable.shapes.ArcShape +import android.os.Build +import android.util.AttributeSet +import android.util.Log +import android.view.MotionEvent +import android.view.View +import androidx.core.graphics.alpha + +/** + * description : TODO:类的作用 + * author : Watermelon02 + * email : 1446157077@qq.com + * date : 2022/7/26 14:38 + */ +class PieChartArc1(context: Context?, attrs: AttributeSet?) : PieChartView(context, attrs) { + private var redAlpha1 = 0 + private var redAlpha2 = 0 + private var redColor1 = Color.WHITE + private var redColor2 = Color.WHITE + private val outOfDatePaint = Paint().apply { + color = PieChartViewGroup.RED + style = Paint.Style.FILL + } + private var redAnimator1 = ValueAnimator.ofFloat(1f, 0.25f).apply { + duration = 9000 + repeatMode = ValueAnimator.REVERSE + repeatCount = ValueAnimator.INFINITE + } + private var redAnimator2: ValueAnimator = ValueAnimator.ofFloat(1f, 4f).apply { + duration = 4000 + repeatMode = ValueAnimator.REVERSE + repeatCount = ValueAnimator.INFINITE + } + private val circlePaint = Paint().apply { + color = Color.WHITE + style = Paint.Style.FILL + } + + override fun onTouchEvent(event: MotionEvent?): Boolean { + Log.d("testTag", "(PieChartView.kt:17) -> 1") + return super.onTouchEvent(event) + } + + @SuppressLint("DrawAllocation") + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val radius = width / 2f + outOfDatePaint.shader = LinearGradient( + 0f, + 0f, + width.toFloat(), + height.toFloat(), + arrayOf(redColor1, redColor2).toIntArray(), + null, + Shader.TileMode.REPEAT + ) + canvas.drawArc(0f, + 0f, + width.toFloat(), + width.toFloat(), + 0f, + 120f, + true, + outOfDatePaint) + canvas.drawCircle(width / 2f, height / 2f, radius - 15, circlePaint) + + } + + override fun start() { + redAnimator1.removeAllUpdateListeners() + redAnimator2.removeAllUpdateListeners() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + redAlpha1 = (PieChartViewGroup.RED.alpha * 0.8).toInt() + redAlpha2 = (PieChartViewGroup.RED.alpha * 0.2).toInt() + } + redAnimator2.addUpdateListener { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + this.redColor2 = Color.argb( + (redAlpha2 * (it.animatedValue as Float)).toInt(), + Color.red(PieChartViewGroup.RED), + Color.green(PieChartViewGroup.RED), + Color.blue(PieChartViewGroup.RED) + ) + } + } + redAnimator1.addUpdateListener { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + this.redColor1 = Color.argb( + (redAlpha1 * (it.animatedValue as Float)).toInt(), + Color.red(PieChartViewGroup.RED), + Color.green(PieChartViewGroup.RED), + Color.blue(PieChartViewGroup.RED) + ) + invalidate() + } + } + redAnimator1.start() + redAnimator2.start() + } +} \ No newline at end of file diff --git a/app/src/main/java/watermelon/tobe/view/piechart/PieChartArc2.kt b/app/src/main/java/watermelon/tobe/view/piechart/PieChartArc2.kt new file mode 100644 index 0000000..f5a1bea --- /dev/null +++ b/app/src/main/java/watermelon/tobe/view/piechart/PieChartArc2.kt @@ -0,0 +1,102 @@ +package watermelon.tobe.view.piechart + +import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.* +import android.os.Build +import android.util.AttributeSet +import android.util.Log +import android.view.MotionEvent +import android.view.View +import androidx.core.graphics.alpha + +/** + * description : TODO:类的作用 + * author : Watermelon02 + * email : 1446157077@qq.com + * date : 2022/7/26 14:38 + */ +class PieChartArc2(context: Context?, attrs: AttributeSet?) : PieChartView(context, attrs) { + private var blueAlpha1 = 0 + private var blueAlpha2 = 0 + private var blueColor1 = Color.WHITE + private var blueColor2 = Color.WHITE + private val circlePaint = Paint().apply { + color = Color.WHITE + style = Paint.Style.FILL + } + private val notFinishedPaint = Paint().apply { + color = Color.GREEN + style = Paint.Style.FILL + } + private var blueAnimator1 = ValueAnimator.ofFloat(1f, 0.2f).apply { + duration = 5000 + repeatMode = ValueAnimator.REVERSE + repeatCount = ValueAnimator.INFINITE + } + private var blueAnimator2: ValueAnimator = ValueAnimator.ofFloat(1f, 5f).apply { + duration = 3000 + repeatMode = ValueAnimator.REVERSE + repeatCount = ValueAnimator.INFINITE + } + + override fun onTouchEvent(event: MotionEvent?): Boolean { + Log.d("testTag", "(PieChartView.kt:17) -> 2") + return super.onTouchEvent(event) + } + + @SuppressLint("DrawAllocation") + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val radius = width / 2f + notFinishedPaint.shader = LinearGradient( + 0f, + 0f, + width.toFloat(), + height.toFloat(), + arrayOf(blueColor1, blueColor2).toIntArray(), + null, + Shader.TileMode.REPEAT + ) + canvas.drawArc(0f, + 0f, + width.toFloat(), + width.toFloat(), + 120f, + 120f, + true, + notFinishedPaint) + canvas.drawCircle(width / 2f, height / 2f, radius - 15, circlePaint) + + } + + override fun start() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + blueAlpha1 = (Color.BLUE.alpha * 0.8).toInt() + blueAlpha2 = (Color.BLUE.alpha * 0.2).toInt() + } + blueAnimator1.addUpdateListener { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + this.blueColor1 = Color.argb( + (blueAlpha1 * (it.animatedValue as Float)).toInt(), + Color.red(PieChartViewGroup.YELLOW), + Color.green(PieChartViewGroup.YELLOW), + Color.blue(PieChartViewGroup.YELLOW) + ) + } + } + blueAnimator2.addUpdateListener { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + this.blueColor2 = Color.argb( + (blueAlpha2 * (it.animatedValue as Float)).toInt(), + Color.red(PieChartViewGroup.YELLOW), + Color.green(PieChartViewGroup.YELLOW), + Color.blue(PieChartViewGroup.YELLOW) + ) + } + } + blueAnimator1.start() + blueAnimator2.start() + } +} \ No newline at end of file diff --git a/app/src/main/java/watermelon/tobe/view/piechart/PieChartArc3.kt b/app/src/main/java/watermelon/tobe/view/piechart/PieChartArc3.kt new file mode 100644 index 0000000..7549e4b --- /dev/null +++ b/app/src/main/java/watermelon/tobe/view/piechart/PieChartArc3.kt @@ -0,0 +1,88 @@ +package watermelon.tobe.view.piechart + +import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.* +import android.os.Build +import android.util.AttributeSet +import android.view.View +import androidx.core.graphics.alpha + +/** + * description : TODO:类的作用 + * author : Watermelon02 + * email : 1446157077@qq.com + * date : 2022/7/26 14:38 + */ +class PieChartArc3(context: Context?, attrs: AttributeSet?) : PieChartView(context, attrs) { + private var yellowAlpha1 = 0 + private var yellowAlpha2 = 0 + private var yellowColor1 = Color.WHITE + private var yellowColor2 = Color.WHITE + private val finishPaint = Paint().apply { + color = Color.BLUE + style = Paint.Style.FILL + } + private val circlePaint = Paint().apply { + color = Color.WHITE + style = Paint.Style.FILL + } + private var yellowAnimator1 = ValueAnimator.ofFloat(1f, 0.2f).apply { + duration = 6000 + repeatMode = ValueAnimator.REVERSE + repeatCount = ValueAnimator.INFINITE + } + private var yellowAnimator2: ValueAnimator = ValueAnimator.ofFloat(1f, 5f).apply { + duration = 8000 + repeatMode = ValueAnimator.REVERSE + repeatCount = ValueAnimator.INFINITE + } + + @SuppressLint("DrawAllocation") + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val radius = width / 2f + finishPaint.shader = LinearGradient( + 0f, + 0f, + width.toFloat(), + height.toFloat(), + arrayOf(yellowColor1, yellowColor2).toIntArray(), + null, + Shader.TileMode.REPEAT + ) + canvas.drawArc(0f, 0f, width.toFloat(), width.toFloat(), 240f, 120f, true, finishPaint) + canvas.drawCircle(width / 2f, height / 2f, radius - 15, circlePaint) + + } + + override fun start() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + yellowAlpha1 = (Color.GREEN.alpha * 0.8).toInt() + yellowAlpha2 = (Color.GREEN.alpha * 0.2).toInt() + yellowAnimator1.addUpdateListener { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + this.yellowColor1 = Color.argb( + (yellowAlpha1 * (it.animatedValue as Float)).toInt(), + Color.red(Color.parseColor("#FFFFFF")), + Color.green(PieChartViewGroup.GREEN), + Color.blue(PieChartViewGroup.GREEN) + ) + } + } + yellowAnimator2.addUpdateListener { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + this.yellowColor2 = Color.argb( + (yellowAlpha2 * (it.animatedValue as Float)).toInt(), + Color.red(PieChartViewGroup.GREEN), + Color.green(PieChartViewGroup.GREEN), + Color.blue(PieChartViewGroup.GREEN) + ) + } + } + yellowAnimator1.start() + yellowAnimator2.start() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/watermelon/tobe/view/piechart/PieChartView.kt b/app/src/main/java/watermelon/tobe/view/piechart/PieChartView.kt new file mode 100644 index 0000000..b91062d --- /dev/null +++ b/app/src/main/java/watermelon/tobe/view/piechart/PieChartView.kt @@ -0,0 +1,19 @@ +package watermelon.tobe.view.piechart + +import android.content.Context +import android.util.AttributeSet +import android.util.Log +import android.view.MotionEvent +import android.view.View + +/** + * description : TODO:类的作用 + * author : Watermelon02 + * email : 1446157077@qq.com + * date : 2022/7/26 14:58 + */ +abstract class PieChartView(context: Context?, attrs: AttributeSet?) : View(context, attrs) { + val pieChartViewGroup by lazy { parent as PieChartViewGroup } + + abstract fun start() +} \ No newline at end of file diff --git a/app/src/main/java/watermelon/tobe/view/piechart/PieChartViewGroup.kt b/app/src/main/java/watermelon/tobe/view/piechart/PieChartViewGroup.kt new file mode 100644 index 0000000..23bd9dc --- /dev/null +++ b/app/src/main/java/watermelon/tobe/view/piechart/PieChartViewGroup.kt @@ -0,0 +1,71 @@ +package watermelon.tobe.view.piechart + +import android.animation.ValueAnimator +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.util.AttributeSet +import android.view.MotionEvent +import android.widget.FrameLayout + +/** + * description : 统计完成和未完成Todo的饼状图 + * author : Watermelon02 + * email : 1446157077@qq.com + * date : 2022/7/26 09:41 + */ +class PieChartViewGroup(context: Context, attrs: AttributeSet?) : + FrameLayout(context, attrs) { + companion object { + val RED = Color.parseColor("#FE4365") + val YELLOW = Color.parseColor("#F9CDAD") + val GREEN = Color.parseColor("#83AF9B") + } + private val textPaint = Paint().apply { + color = Color.BLACK + style = Paint.Style.FILL + textSize = 20f + } + private var touchState = TouchState.NULL + private var centerText = "TEST" + + override fun onTouchEvent(event: MotionEvent?): Boolean { + when (event?.action) { + MotionEvent.ACTION_DOWN -> { + + } + } + return super.onTouchEvent(event) + } + + @SuppressLint("DrawAllocation") + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val radius = width / 2f + //空心圆 + canvas.drawText(centerText, + width / 2f - textPaint.measureText(centerText) / 2, + height / 2f + textPaint.textSize / 2, + textPaint) + } + + fun start() { + for (i in 0..2){ + if (getChildAt(i) is PieChartView) (getChildAt(i) as PieChartView).start() + val animator = ValueAnimator.ofFloat(0f,360f) + animator.addUpdateListener { + rotation = it.animatedValue as Float + } + animator.repeatMode = ValueAnimator.RESTART + animator.repeatCount = ValueAnimator.INFINITE + animator.duration = 18000 + animator.start() + } + } + + enum class TouchState { + FINISHED, NOT_FINISHED, OUT_OF_DATE, NULL + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_user.xml b/app/src/main/res/layout/fragment_user.xml index f664bdc..404cbc1 100644 --- a/app/src/main/res/layout/fragment_user.xml +++ b/app/src/main/res/layout/fragment_user.xml @@ -11,15 +11,24 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="20dp"> - + > + + + + + app:layout_constraintTop_toBottomOf="@id/fragment_user_account_pie_chart" /> sDh4-Q3M4Bkgf>oC@>Ba6lqbwN=I5~L1qL+KtV;N1RIVZ zeFz<*h%_N6V$e_p4ALQlUcR-%`}NlFuf58>?zM9LH`BwS zYoym8ghY=XIrKY1#A^8e%_>3o#^ctHe(=u<&x1$*SOxzDta1oPXfrx`=)fPo34?8c z<}&9WE)6NS{d4OFGjEl=ypg3mXXoa{tAy2C9;Gx-$**pGlWqUQ!M2#FC$)D)8d^BV zMf#o$Jc?fA1TQ|X_xVDvfB*jdlsvqPnmCpFZIA5|(RuFt?g)E$>twShw`{nxC(|G( zgTp$b7(+m)MWe%K1RgoIO@b*OU{il|af}9ElUWOY2hyI*OwWWe- zyf2-1kelWgdZ1tK?3|dXt#fwJB7?ifHZvHZ5l;%`VMIhkWZ8Qi=|~k>G1Ujh$45uA zvh5_0SWP)^c+6~38!;X#DJ#Rs*`LcN-@iWr7v?0=@bIu+?-ZgM^0=YDAx3fF%y@6p z*Xg{brltV=XRtid+$I3x>8XoTmJ$oInp?P5@#u&kRrE(#Fd;53&MLC|d_~t@{MS+- zfh@n;0Zk`!tWv~zQ$p0hEw>1r#2b&RD=Upy_B~&}g51U~_8C7uN+iwxbCQsh~J+OB1k=ZLTRBVig z%}Q1WCagx@e;Ei;fBA#dTz4!xDk{pu!{Y-_5@p4%P(d#rG1qEIiWJEakar9o1xM_o z``WDVZ(;OlD@-aHDAuFL6hwhL_!m0C^Dh+w{Dr7q(_(ATM+Qwiz{~pR)mE2VX43RDV}QTkZFs-jnG(F;XjK9u;|HuBdT%etpBJFo zfKbUM@CH9$-#*Gs32||8r9J_wIE)!3G<{cdW_#-zgTY+U8ls4xmWyzFdgQ#*jw%nX z=o;^cJ!+9gV%Z~x={gvH03J?s$s3;i*I|)~pbr9o6I6`yZhKH5BY&dYtE!2}=)yuYijI!<3kVnl$#e>}o)rc6u@>AIx^-wX5g~&gK`#+H3TKMY zw*TDtA0m>YQN?lybv_XcJrMIWHC1-griE^fnW^dGSoV`APyQg?ZN79DoN4fUfDH>= zdhpz-Cbf$XcQ~_CG6qCV#0~6LIiTdJ+MIcIbZYAF>y5zwn6H;-|8R1BbKlOt(uuGCpk`9lM39vW5$VbA2=Z@oRLc^+SLc|KnOQ8?-Ff{h zuSD!yQHCmw37>RDqSJMFh5EtuuAe*=?X0aGvQOcU9?eI0Bf}Q#p7A9$wf2Hqt(&G! z0rw4iV*XnNcxW&cE?8!-$7kLt{=E#O{!V{;T$A@ayYJ3kr@$x-wS3Q8LDP5A7z;|@XH0Onch-~Yz=$qCkzQKHd_ zRgP3qFfE3-s9-4A_?qrbV_J9Q<>gfqO?7vz=}ZLU8`S`VhL9k)M1NvSGf!f24oY=y zf*ZGbn0w2Liaf?X$*rwLBjCb28Fw8Yq^0fN{np<}O&a@xsi~<4_2+D&iH%mUHnES~ z?uQLbX0hB~dlYW`Bq1Ro6=_^pTzt%iWfQ%kQ5z3wbklrSS^3w{N1?w{Q|A}wM&Nk} zyFT5&Fm~hn;X@yFWTLAe{yjLp!%}f0o?95-pbmYUKVo?gBIU7-5k@;=uOBO+hVBGs z$rKH%u(q`YAdqqR(erB+X9PoE)zL3g4RIthD=oXTI_R0g4eS6lWxuiWT^n`~g=(y7 zP*xZm3@g*Fa^HvriL}V2EonX%lidbh$^V>=9A|))`64xS;6%#_qZ3#W>OOzAWIaJn zclUfkSvw)l_Vzl$%UDmccEXmIlh$ykH5jb)qiIEN1u{=BJ0qbyf|AqH~)df!&z z#_R4k)Y9(a-DoiU{e?SlbneGp!yU*S(_+F%yAxu@$&)7m3oMPw*0>Z1PKF#SLdhI> z?;D{~i}jUtGMW$=yDy?oAm`-g|J$A!@h}SuVp89h^V*+DOis`FTr8cEc-3musQUH3 z4dvEPzu0bT-BF?dZvVxpI>ppy;Ac$SxTM37Q*atCTrVTScKl1O(m?aBclG4#PB zwLDHueY5WkN1)LRbdBCKGrxWGIY?~Gw-xY>GQ88NCQjMz_j`^kdxK10LCwaUcwFcF zyiVw=G9U3PaIAJo;=!7edYc#xodEgy8cVJk5aV}a{B zBOBTq{2Y=mm)R2;JIBt-w=?1DSlKLM?98%R|EXI?rExn*N9Nl~y?}RMGZ)nQDI%Q+ z!+ML^Rr%Tf-Kb}5;5Q*I;CG@s>(&%w5)W( zfKPn<>n1&##v`gTANM#~epy^?)%jY9ECYfGpbGy<_75l{(CSZ0qEk)ez141-5c4%9 zl?Da$;^FaMY;0@**vZPCUkqVlcq97cy#gPc%5IbJCeVy9XydyLg4ieW-mDuU0c&9E zBWki@>2iiuZ@b-DTakZX!2khr3g0tj#rNuZ_4O?7J=4(fhOO6L(K2aLvxycMT#KLD zD=DIaVQ8rQ1-81E&G|y>b9twqWelj9aEGbVB7%@okVwz?83?<9Z4REVu(TA=8#x;E zz*p#e^xP9?wvL|OIe4(p8lqO@d=WG4T}0*AUVEbxB_;d6&R-5bWhAJM;j@gT?yxPJ z4t@#%;&hkycV^D%bij1Bj|;)&BqaFu{3Z^%etbtPD8l5QAPkKhN^4@T#{=xu;U#&e zy>v|hC4S@j!KXIoov)6!pVeV-;KL&${$m`0mOufiY97yvwKd@3(&EU{Fy+toqO!8~ z{xz)`yX!vmy9+^VN@=>7x%5)qB(}x@+(is1E|=^1sKm(VgoBRUd96fm-8ET4a8@ND z&D}#^{@S~En?rJZRAPg(p89hZw?o9SQVK&(r6%pA`}V+vhdc7~^R*@3cKD0+a=Bc- z9W}J?zVQ>BT<+(W11G4PPF~SPXrc|D^`D_`!NIhpx$-6UjAoFtR^o8mQcBr)fCqUU zymbC*b2pR3@>-nkjxN%xjGbx=S3y|QBF>&r}BUI*wgdAvN$MTwvMa#yHiDRs;c00rBY zN(oTLxz^S*kdJ>mU@9#JLoo-z-_@Ns(IdXuACRg$Q&UcGAVYVsynNm=*4eex{2 zGb98~X|@%R)Yiy!nkX&b+j>hs#hGnwXZIZEM4v6WGdlQi_IW>K+AoiQu*BLr_z#4ZQ53qlY z17vyr&n`-HZtFAFsEpde!ff5SL$i>;Sl9AaZ;behTYY)_n#A&*v8xna00s@4f*;S# z`Nt)tKT@p2;7gJr27YPuhCxty%0-n#(_%UM%yf(0Y!<7>Q`%P?q!&DPkfPgA?NW6% z+bxYJEgO&84Z+InN^S*}_j>&Ng#x+zOe(?nxqK zUXMG|T6tpA57i?aPZ{6cF!A*bDZdolPm?ie;v=)SrVu`dDJ#f_!REsaf--wOF7gTt zEpB&I!S*a*dohsX@>XeA_Pgiz7kTghq76V7d|1|2(5-Dhuj%-)ZM7@sC%w)+Ftrf#Q(gW#hlR88JhtTl!S>g?1&~;hM1$+p^mGevRRE`} z>(Rhk@2gDDe-D2#pq18~I9XQ!nlMP|zZKt z>$O|$F!`5rA0rbkkl1TrmEe{xz!=R7wtI>E`GxB59hVT5We<1JegOxu5 zCgd<`@q>kv#S4y${%grQckZ-_W+<=fvGe30ye(=d7$$4$L=rcBVMkO)3N}JSG2Kjb z8|^Q`e%iAvuVaPEzXS-04u~MQ>t8}+C~q)2b2q1|RYfdI3eUx{{>l!|S{xtw=4}08 z<@^l;!OqUrJ^AjjUiyH#ACJZi@4;*W?1Gc_GbqY-8&~_gIkb6yzj$oas~BSZvq}5a z)%@Nw&uU!<$0g^0B%&(>bWPue?PYvVy`pUEt&X>x{maU5-tqeoP8GI}LUwXxaXJ!@ z@7lc!y_tEF58zmRKrZ|7lJ~GQ;%n?nrP45k0daO(M}squVTDbHdwpb|9NyP_VO!f| zfBw2^hShZH8p!iUPTYHzTdnIxp?m>5s+hdgnGR?ArvHQg^;{P~B~1OGFsu}WmbD<~ zvnyvxSDemw@(h-b8zr~`a^DyvGVJBP#pBlFGC1vD)CLiNHTfx@{4z>s2vnx}qzX6&jEa1OFcQB0MPiB6XKtc@XbrPw+nJ z$dcPx2fV3hV4Nfgk#%EzJ=`r{S}azr(FcipczJD)(x^7_XA}i&htPT-=aX3{ty_6! zO!s%+ATYhO06`(|J2>zHGQl40t*u{_L-gKR?g`VczTCliqz5jQQSN5R`nD`tYisK( zy1(Ky&9!{t+X+)zva=OCEkqm#Amx|FfjDRG2$~y8ZfLh4-CdgJ=u3$R+C=BXIb{m! z^}CgAB`~BPrmU@@UDzwxqrWs`#!vMEigI&vandTpyT+i;Sg+LU$EY-UWMf3-ffd## zm&KQ3t>o$NU+fdj0=QXNR5X4+&Fm9B-9S(e)04^o`ygub<4LWpjEEpk|2%_(%Oy0z zC5&!ILD(YTNyzYGK*muN1|`J%w!oaeTANp8X>K0!DZO z%Lwlkz$RZE`i+w9K%DpY?*e?Qy{`6kfi`z0V1)jS*oI@IU|RF8h|1UApZEB0ss)x2 zP=n7FfZNMl$WJ%5&+;T&)`LrQRZBEo>2a8kOB;N3Ol??z7cr+dcw3J|a#WLc)RZj> zNVBi&&GB)4h>DNFnq_`5iJb{hiqVFw8k96<8y|$1%}>81E7hq0*#HzaSm&?q(Wi6; z)xnw=+NX?$Hoa~Y+4KtM;DdP-k2+U>~#dJ&*#zqGZtgG^-;Ffx#wR>Q+Ts+j;N zFP0;U)jFtr2lNn)0TlJK)4i07MeyxwCv`s4K^WWzqLa@$o$i!(ZO;Yvrzp|RCOkA5 za6dLW$t;$Ot84D*ba<-86Q))tt32SN25M=Ki2~UQHs)l|q{gRK2>vzu1ed?6zM|!I zM#8COVWE_{n|v9Mx^-8nMOIst>I{K2>j2myX0rE@m5=XOC*eu3!W2jaa3y;ljUK?D z$eQs97SfUhBwc*GO#bPLhy6tjcr(kX<@5>wr^CY;Fazfw=lJ4cZL72pQ|v{y!P9;Y zzR!UM1_B+YnAmMxhp8pzMvdG55GVqwu5(?wMH;Zg`=dq5J6rcP3c=R&9&oEiM-sFJ zXR(EDY|&by&w*PKaEt!N&tZC}s~jN^a0B^R!r^P>p2L!TG9WywKUiLT!i}f}F&5zc zH+Tjk3Hr;7fmVDpf>)NIZ-jla4+!E4S&tUsAojsiRy$gJ;x?RM)H{wRM|r;{VEA=a z2ClH}zD6f?&roHd?#W4YP}qTeCsS90&N zUL|B}^1<_6%#Ch8;B~CF%J{5il^SAbAMpzsl(Nd0QNUM@E2Yrntv#%lb@wiH-on~w z&a}!H!G`tMrbc@Do@U0Y+)8OQ*?L8*zM{eqw$9Jz!{i<^Ilu|NmelkGMGyn~fXuCd zPbV7H<_uD{QIazT;#3C^9HOQIcr~yF94@1)Y@!Vh^NTcI-TN6>TV(Hp0YEl16OaV{ zmYpGfbLb<|2XxqJ0O`)azyNSZKq*qTeN4K{Plf5`#Cc&jAt4t%8fR?mJ$*p8neGfC zgUlOfuL%rAZRs{09UbQ(;ntC}I??V9xrTbYqaKZIDmrQmEA|D|u~l;Yv9|cd#fQhA zH$jml<1nFRKirxQV?Dy%F5aA$}h9kVLHGT4I7A8aMg!)Ht%$4 zLYzqqK%CT6I9DJzJx0^&Kvsp;-^RxF)%AXuyhxRUAjPmyjH`nWguiWm*Lw|D1L@A4 znAjFhpgl*^ydplbcH4_ z>(BCN-BWXx{Y8siOhT4Cs83dIQnz>ZsVh3G(OhyL1?pF*58Lnm`}$V8Q@a#G@-Da+ z;6H`7|CAU(S^sav)uU0grEh(GeZ83-OE8dX!=ev~`{z5ew*{{phmMXqA@KOWLm{98 z0vMyr*QI?#8w^LEI5QJ^)FU7u0ZM*=P|E{l;c4$S&&_dQWZC8EoArY`q0s>9&OhHc zC=1VK#o3M|1i5r=TUuH(4zotveLb}ee{W{nQO=uZ#jWgS$@?z)pNGB#)Z&w=tvOS( z=Tqj%JGhU8R#H|!n{gaADtv>BJ-5EVC2AQS^30HGuQ zx$z&7{EtwEqaLk1gxKndrjQ7B0N0v{8Pl02T4w4lqcP6hKVV79!9ZVtInq_Ome8%0 zVj-=1?#u@3gNRoVOvlMmZv7agcW_Vy`bOQRK}^QhSf_$#TB|E5 zqOQA32wGs4Gpyy5lxDmag#l1(JeJnn|9tI2iB=$#A77El%@5=OBm$g*S7r>@mHkXa zFm)ogL~B9I7kHwvF?Ul_Q|u2?Q?(LqWkAl3WB100&~^b)1_hjuf0y4~H$B?U8PB_Z z(6+T#(m_+!TW1puP)NDaJ`@0z5wbGmjgU*h2kKbxV&K~Wxv;aR7yv8-^du^g6Hox; z5y&wBI>j~jF2fdyprQLfC)1cvPbbf*AsXZvZf;5Tg{i5K9jDdm=36VN#@D~xNF4nR zD-lZLClF;$uk`fwmssaDa&2H^P2WEbH6f=+OuCh}U)7b1hPt|oQK2CK6RpHDr|Uvg zXG|T`I;s1w?j7@0ypw-KlGykQ1pN-^a(G~h>nMc<1=YAr_q0?4aM^?7%OILc#F^1f z;O-#Lz%_rU-f?2}5Af?3UIYnL`rC3P1t2!S=Q9H%*Y<3TnD1CxplJ#wYrF)AE~AsV zLwRF_wT;dG_<4dwB%yCN!2eM(W?B*^LuyUobXY9bS4pZZ&dN+7yT@6N-w0$;P<0V^ zRYLsw{3l3BJv=?Tt;c16@(-Astl!g&CLXH7GX!A%p-ltuvQ6{{tK83uu{BR2LF$ad z?-w$8-o#J3jFnBEo4boJ8UUYV5g;Y>9vFeMXzl3mfljj$++QUMRhbPn!O%=+(Yy?9 z)i0<#ke%OC56iQ``Dkd8Ji+Vl+t#c+)haZo2qKh$)X2lfhsBe$VyQ(!YLwLkClzoN zfG597kOtYtn|;d-YdfJ?K>vRFr>5@{RmmN=uH7jgbpm9Xh3OOCAmP+TDZW&p3RluA(9| z7X*ZL%<7X`y{T~yzSM@xO)Yr_wu&2*{6!e;@b<yvh#vJ-E4|!|$6_go z@pNN+dK1);6SOw)Q)ag#AoMGLGYLi3O3N$;qQlCO{y)NT;RMDGoD2U(V{R69Kw@B0 zRIxl~HuUiECMG`eR-r5s9Ea9N4(SW-;iCb~g_asQ=^bd)5~dv$4=l5hL70R=i?3#2 z4g6%D=dPX0kte!^^M~LBMF2S^;xX|2^0ykGV7TXlS`L;fy9?wrA1PdfH2;9tO~>PO zg@Cl&v7?=UUXIUU!I3E!q1Q)Q-tOaJT*P0CsIc`iF#NLjb|d@mNJJO`t!EtUjHo7X zrU9wTjW^PfG25W?4@?A_|8%7EyJM7)*j=z8r{kZBW6PuKj48MKFL7$EPP27<|+&_My|@G#}3DZg^%1g$dr_4R$q zwA$>!i7k{je{Nl8Ve6mi)PG)t->;K9CkP?ud;2xQqiHT&v732?D|a@a-J zS=G5>bgOVpxO`|;)w{u^;d-^mP|??`UMU822PLXqlol!ZQHxnA`=T&*1I6e=nyS*^m zn<6OjJIiZuYR)$x;7ai?222pODgCpP;EduJvpPo+Xrz8AYiQIP%M4!Fotk>1#^I|s zg_;EV>vjOh9sg(y75*O3f_iU||8R-IjcRUdvm-xEciZAoB=MkjHx*KI6q5O{m229wl zW^QWgS*^sBBm$bpjacXZSZ@R{;-e~}uEV!u73;nN`|_e0HJXEFHUMcr8J0wt5MW4w zr4x6v~aq3cs5XkkS!&Hx0Vo zprdaqll##eQH8-Lk8bK7(}d?7Ebmd)Ah(sK(Dmh7P+T1G{mQN=0@(nRJD{S=E!>Qz zSNYtGb~c~=EQyG$aYK`SHhbt#6(oYYMam5nh>RgT-#YlJRS9IW(^tH=`O=1}?tMI2 z)G2}|Vo*w>f|uqx-m97P|BM(yaJFy*>k@WL;j2E6ctX86F*g;i_;uo5skQA4mrjay;IN<9ltFW(kH3s|mKaaja4 zuEXCC>c+6?Cb}!pG``G8z9_xZ8VFT*e?d$|*AL~3v(R)!jl$C!{Un8oaCzYFCb6*T z`I+3%Vw7wTtKSA?GaY^X=lIN{V9ST-Z0C}alBf6@2d6)6?d)O1hv6J zHfO^dXnKLa>JpJ4a6JY>Y9{Ld`S3)LByM@%lx>>{ojjmB+@~Hjrl^9Rf>tEkdlx7AY$X~9z+SYfb79eZ_je(mZDhj&y<#MTHuNc+yiMpV z!ZZHCrknmFNZk$FYdqtUD@Yvxvu-@Y9#ZG6K$164^b-(cD$iM_xJ{`x=eX`);?-Q8 zaUC;VB2^wvqtQLS-gvW*^@;WF!NKy-S2L~?{aE3rx}1->X!u?cLA!L+o_Wp4wf6CYyGQar!gEx zA0gk;rvfNGzAr!$;0Ke1#KH`L;-|b#=0iF+T$Z2s)4=qy9_@J&V*IuLsW3IxWJhdn zNzmWUY-ptdRp}n{z2=zzeQ2nDAnC`S>pmQ9MnpIX&ClD#c4^5)k4;W)gw500>Ey-4 zg&-Q`HF^I5S+XR|oEYP13G3~+3Vy`b&(Gc8{SZEa*JQs*$>jl1Ec%1AVSuLvy4Sz| zD2T19`+a&Dm>ldWSppmxxJ6MtF&iV(iVY6bGa!fwW6OJE`Q;0HcsHM}@Q^lK3X`Hf z!r%XDd2e5$sX6nA@#g1XOuw6<&NZ-zQq`WR_gXJSkP=REv`2Q@RODfQx(*cx;CKXO zc8UP;>&DB=vw!%_Y=d`%m$ZNse}xm_2BuFgN(WEz_ly>=LY9Re#oXbj#GrRE_(#w^ z><=1`8J4y2e05Ti_MT!gnLkN&UV~Gh0PXv6U5wN?tyDOPM(b{RZU&vUf|0+ABdWPm zKKtW3$*eXP3D6c00T9py<>k@uFRV8@aVUxNfhZ*MnErEadikTa`hzwXH0o*;<<7{r))!g{i7ig{ zE7mE^a#yM#!(J#tl%8ParB$sxvEB&WwOcGcFCQH_`%>Ggy1HZ7F^GZ(x?;hmpI~{t zWDRJ_ioM{7yuHv9ERH01bWqWigH3AgI&xrbzW)9ZZ7!Ur{fBfyMHs)qu1x`BKfd@- zeBtIo&`7^q6`0U9sJgi2q+E3QmiJ4bd*sOh{9WzkB$Rv@YERteJuw7H*eufZNGJXS zi!p>vB_D=Atg(NPE3_zB0}p_l4Wg}gTSMg_b9_H)+zuu~={X%@y}pv9CxnWCZZ>Jd_QwV zaiui%5jJSzi?d$PP(EXgjzH8h5PwQh&NdJvV+=e&g*?m+H;QOwDAqZQY-`AQ2Yy2Y z_pwIBAK!6Qzk>uzg^bjo>Y3Qbk2G<_!p2ttu}QHm#s$Kt_HBaX3hb3W-A&5}TnVnD zKoeizb+kM$P$+ydhtT-}UUlUUR>l`^XK|E(TPnqBa};rOm0Ego*&lVb;sK5DBb3%X z^_KUHa5zScO6;xfE7|G>K{{$~hNuyEH~VZ#DDz58u0ov(XlubL{HhPVX;mW-tnlgM zTuJL`-O1>VUcdI4a3QKWo+e!HFOHLXgbvf3iKw~Q;jM)V8W%=6T5be>AHUBM3zho) z%9rAbOaP}N>JS&)T$c*?IF4}t>Ze{A7i(?ac;SrSHTA##I-nVShv!@$C`*(L6N0PdKTd zqlH(Yb@7E_-6^HG+Z@0CpEY_HKKIl({0OggDHiPPheMh-8X-X2y17~5MMulG5KIQW zwI7KvNU-7Q5C}p5nxMRTkhfvABg(+Nu|BK1T>z`3Ts&K9dl&-fPJ-JLm?vO6Kc0!* z?7#n5;cTJx+q2o>0E6S}-;x|r18(67CXqIDkF}`2-4y3&2|M=rX}xXp0nTeu-<^ z-%;h!q_#SafXmO+c#HK$K(bk_7yjBcy)ZNmh^oE49eh>G$kcnaNUI#eG!%6VMm89& z1)GAIe0(JM&KOJR;*~@996JKa0stJa>F?F*UEeDv5UzoiHLf1HJ(mY{a>>ZWrGfs% z#l^5C(RmV}C1)>5{k_l79!07^Lc=))k z^K5&!6t%117~oNaitz6`kO3SnLgCnAq0j_?1)$*z{eUePNO5pF z@XVqAJoNvGAi^b|!4IztbJ|=04Oa%0M}rQ5$^wi#bO?GbjP5x?tJPUGY0y-_itCgG zsrW~DZf8uI-ki&YHsx+#ouH|y(l8G;9RoE$THrvz%cwj!bYeXVGJ;SDvz-Sg=K@R0 z%8YGTJC|;Dk4eVY?@*670V4#y!+5J*2Xb3oc81U?0AE6Gt6zF{KDWOp3bM}ZQ*Rtp z_OqEQ(IWijimGarZUF#Xd6HWmF!Lj5x}2Px(xepHdkAMjs2{jxh&AzzJc8Cio5>f|MoH_{Fl?4=Dk}YSu*tD)d{NK|a`q?yn@wSqS0JRJY^J>aPEk6YSLO9csLXF43 z)J#VwC+|^S`*``upevXGU3X<>mvdY`!5|J?qvin#*UTVRuQO_N#Dg1qR}GD;qdpZ_ z*-i|kb_SgM@39DB+um7NJTQFn0{_by!Iji?J$_05=k)sz7MF;kBAoQDhEla|S8>t* zx`qZNbF=9TC08O<2|%0M)yE22e!D%BI5=Eg2XB#ZK}YU+(x}kCw-{TqjrXU1-`5?e z54Sk%l#Vn`T=M~(Kjb7>hVaqRN#dN_dz2-O4IjBefa6Z4SS@iI&u|JRsDT^;YUpCA;pWT>b4B_zUMeL zI@=_+!O7-@w4gq73G^YFg@z&raWLsvv>D3VRU9HmFJ5H+{YwNN8n` z6ZpXec7Nk>LF4aeGx!NcB{+NNSb!gx0U!r@CA(w9zPzJq%=acFn`_tl`1st0M8^1u lWTY|hH8HW-1oGdD#Hk