From 207762adca4c7aa17e4caf0355f21df003917140 Mon Sep 17 00:00:00 2001 From: Ray Ryan Date: Thu, 18 Jan 2024 12:09:18 -0800 Subject: [PATCH] Fix tutorial fileTemplates Our templates were out of date, and our `install.sh` script doesn't work any more. Replaced with an IDE-produced zip file that the IDE is willing to import. Replaces `Layout Runner (ViewBinding)` with `Android Screen (ViewBinding)`: ```kotlin package ${PACKAGE_NAME} import com.squareup.workflow1.ui.AndroidScreen import com.squareup.workflow1.ui.ScreenViewFactory import com.squareup.workflow1.ui.ScreenViewRunner import com.squareup.workflow1.ui.ViewEnvironment import com.squareup.workflow1.ui.WorkflowUiExperimentalApi @OptIn(WorkflowUiExperimentalApi::class) data class $Name( // TODO: add properties needed to update $VIEW_BINDING_TYPE ) : AndroidScreen<$Name> { override val viewFactory = ScreenViewFactory.fromViewBinding($VIEW_BINDING_TYPE::inflate, ::${Name}Runner) } @OptIn(WorkflowUiExperimentalApi::class) private class ${Name}Runner( private val viewBinding: $VIEW_BINDING_TYPE ) : ScreenViewRunner<$Name> { override fun showRendering( rendering: $Name, environment: ViewEnvironment ) { TODO("Update viewBinding from rendering") } } ``` --- README-templates.md | 8 ++ fileTemplates/Layout Runner (ViewBinding).kt | 27 ------ fileTemplates/Stateful Workflow.kt | 87 ------------------ fileTemplates/Stateless Workflow.kt | 61 ------------ install-templates.sh | 27 ------ .../java/workflow/tutorial/TodoEditScreen.kt | 20 ++++ .../workflow/tutorial/TodoEditScreenRunner.kt | 24 ----- .../java/workflow/tutorial/TodoListScreen.kt | 35 +++++++ .../workflow/tutorial/TodoListScreenRunner.kt | 39 -------- .../java/workflow/tutorial/WelcomeScreen.kt | 20 ++++ .../workflow/tutorial/WelcomeScreenRunner.kt | 23 ----- workflow-file-templates.zip | Bin 0 -> 2416 bytes 12 files changed, 83 insertions(+), 288 deletions(-) create mode 100644 README-templates.md delete mode 100644 fileTemplates/Layout Runner (ViewBinding).kt delete mode 100644 fileTemplates/Stateful Workflow.kt delete mode 100644 fileTemplates/Stateless Workflow.kt delete mode 100755 install-templates.sh delete mode 100644 samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoEditScreenRunner.kt delete mode 100644 samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoListScreenRunner.kt delete mode 100644 samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/WelcomeScreenRunner.kt create mode 100644 workflow-file-templates.zip diff --git a/README-templates.md b/README-templates.md new file mode 100644 index 000000000..79f0de221 --- /dev/null +++ b/README-templates.md @@ -0,0 +1,8 @@ +# File Templates + +`workflow-file-templates.zip` can be imported into Android Studio / IntelliJ IDEA to add a few Workflow-specific file templates, via _File > Manage IDE Settings > Import Settingsā€¦_. + +To update the templates: + +* edit them in the IDE (_Settings > Editor > File and Code Templates_) +* export them (_File > Manage IDE Settings > Import Settingsā€¦_), taking care to clear every checkbox except that for File Templates. diff --git a/fileTemplates/Layout Runner (ViewBinding).kt b/fileTemplates/Layout Runner (ViewBinding).kt deleted file mode 100644 index 9b0f3af2c..000000000 --- a/fileTemplates/Layout Runner (ViewBinding).kt +++ /dev/null @@ -1,27 +0,0 @@ -## Unlike the Workflow Templates, we never generate inner classes for view bindings -## or rendering types. i.e. they are never "optional" -package ${PACKAGE_NAME} - -import com.squareup.workflow1.ui.LayoutRunner -import com.squareup.workflow1.ui.LayoutRunner.Companion.bind -import com.squareup.workflow1.ui.ViewEnvironment -import com.squareup.workflow1.ui.ViewFactory -import com.squareup.workflow1.ui.WorkflowUiExperimentalApi - -#parse("File Header.java") -@OptIn(WorkflowUiExperimentalApi::class) -class $Name( - private val binding: $VIEW_BINDING_TYPE -) : LayoutRunner<$RENDERING_TYPE> { - - override fun showRendering( - rendering: $RENDERING_TYPE, - viewEnvironment: ViewEnvironment - ) { - TODO("Update ViewBinding from rendering") - } - - companion object : ViewFactory<$RENDERING_TYPE> by bind( - $VIEW_BINDING_TYPE::inflate, ::$NAME - ) -} diff --git a/fileTemplates/Stateful Workflow.kt b/fileTemplates/Stateful Workflow.kt deleted file mode 100644 index 6f7d54c9f..000000000 --- a/fileTemplates/Stateful Workflow.kt +++ /dev/null @@ -1,87 +0,0 @@ -#set ($prefix = $NAME.replace('Workflow', '') ) -## build props string -#if( $PROPS_TYPE_OPTIONAL == '') - #set ($props_type = $prefix + "Props") -#else - #set ($props_type = $PROPS_TYPE_OPTIONAL) -#end -## build state string -#if( $STATE_TYPE_OPTIONAL == '') - #set ($state_type = $prefix + "State") -#else - #set ($state_type = $STATE_TYPE_OPTIONAL) -#end -## build output string -#if( $OUTPUT_TYPE_OPTIONAL == '') - #set ($output_type = $prefix + "Output") -#else - #set ($output_type = $OUTPUT_TYPE_OPTIONAL) -#end -## build rendering string -#if( $RENDERING_TYPE_OPTIONAL == '') - #set ($rendering_type = $prefix + "Rendering") -#else - #set ($rendering_type = $RENDERING_TYPE_OPTIONAL) -#end -package $PACKAGE_NAME - -import com.squareup.workflow1.Snapshot -import com.squareup.workflow1.StatefulWorkflow - -#if( $PROPS_TYPE_OPTIONAL == '') ## import if we create below -import $PACKAGE_NAME.$NAME.$props_type -#end -#if( $STATE_TYPE_OPTIONAL == '') ## import if we create below -import $PACKAGE_NAME.$NAME.$state_type -#end -#if( $OUTPUT_TYPE_OPTIONAL == '') ## import if we create below -import $PACKAGE_NAME.$NAME.$output_type -#end -#if( $RENDERING_TYPE_OPTIONAL == '') ## import if we create below -import $PACKAGE_NAME.$NAME.$rendering_type -#end - -#parse("File Header.java") -object $NAME : StatefulWorkflow<$props_type, $state_type, $output_type, $rendering_type>() { - - #if( $PROPS_TYPE_OPTIONAL == '') ## create if not supplied - data class $props_type( - // TODO add args - ) - #end - - #if( $STATE_TYPE_OPTIONAL == '') ## create if not supplied - data class $state_type( - // TODO add args - ) - #end - - #if( $OUTPUT_TYPE_OPTIONAL == '') ## create if not supplied - data class $output_type( - // TODO add args - ) - #end - - #if( $RENDERING_TYPE_OPTIONAL == '') ## create if not supplied - data class $rendering_type( - // TODO add args - ) - #end - - override fun initialState( - props: $props_type, - snapshot: Snapshot? - ): $state_type = TODO("Initialize state") - - override fun render( - renderProps: $props_type, - renderState: $state_type, - context: RenderContext - ): $rendering_type { - TODO("Render") - } - - override fun snapshotState(state: $state_type): Snapshot? = Snapshot.write { - TODO("Save state") - } -} diff --git a/fileTemplates/Stateless Workflow.kt b/fileTemplates/Stateless Workflow.kt deleted file mode 100644 index e103179e0..000000000 --- a/fileTemplates/Stateless Workflow.kt +++ /dev/null @@ -1,61 +0,0 @@ -#set ($prefix = $NAME.replace('Workflow', '') ) -## build props string -#if( $PROPS_TYPE_OPTIONAL == '') - #set ($props_type = $prefix + "Props") -#else - #set ($props_type = $PROPS_TYPE_OPTIONAL) -#end -## build output string -#if( $OUTPUT_TYPE_OPTIONAL == '') - #set ($output_type = $prefix + "Output") -#else - #set ($output_type = $OUTPUT_TYPE_OPTIONAL) -#end -## build rendering string -#if( $RENDERING_TYPE_OPTIONAL == '') - #set ($rendering_type = $prefix + "Rendering") -#else - #set ($rendering_type = $RENDERING_TYPE_OPTIONAL) -#end -package $PACKAGE_NAME - -import com.squareup.workflow1.StatelessWorkflow - -#if( $PROPS_TYPE_OPTIONAL == '') ## import if we create below -import $PACKAGE_NAME.$NAME.$props_type -#end -#if( $OUTPUT_TYPE_OPTIONAL == '') ## import if we create below -import $PACKAGE_NAME.$NAME.$output_type -#end -#if( $RENDERING_TYPE_OPTIONAL == '') ## import if we create below -import $PACKAGE_NAME.$NAME.$rendering_type -#end - -#parse("File Header.java") -object $NAME : StatelessWorkflow<$props_type, $output_type, $rendering_type>() { - - #if( $PROPS_TYPE_OPTIONAL == '') ## create if not supplied - data class $props_type( - // TODO add args - ) - #end - - #if( $OUTPUT_TYPE_OPTIONAL == '') ## create if not supplied - data class $output_type( - // TODO add args - ) - #end - - #if( $RENDERING_TYPE_OPTIONAL == '') ## create if not supplied - data class $rendering_type( - // TODO add args - ) - #end - - override fun render( - renderProps: $props_type, - context: RenderContext - ): $rendering_type { - TODO("Render") - } -} diff --git a/install-templates.sh b/install-templates.sh deleted file mode 100755 index 3c012c9aa..000000000 --- a/install-templates.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# Installs Workflow file templates for IntelliJ and Android Studio. - - -OS="$(uname -s)" -echo "Installing Workflow file templates on $OS system..." -ideaConfigPath="" -if [[ "$OS" == Linux ]]; then - ideaConfigPath="$HOME/.config" -elif [[ "$OS" == Darwin ]]; then - ideaConfigPath="$HOME/Library/Application Support" -fi -TEMPLATES="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/fileTemplates" -for i in "$ideaConfigPath"/Google/AndroidStudio* \ - "$ideaConfigPath"/JetBrains/IdeaIC* \ - "$ideaConfigPath"/JetBrains/IntelliJIdea* -do - echo $i - if [[ -d "$i" ]]; then - mkdir -p "$i/fileTemplates" - cp -frv "$TEMPLATES"/* "$i/fileTemplates" - fi -done - -echo "Done." -echo "" -echo "Restart IntelliJ and/or AndroidStudio." diff --git a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoEditScreen.kt b/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoEditScreen.kt index 84523531b..0fc973c32 100644 --- a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoEditScreen.kt +++ b/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoEditScreen.kt @@ -2,8 +2,12 @@ package workflow.tutorial import com.squareup.workflow1.ui.AndroidScreen import com.squareup.workflow1.ui.ScreenViewFactory +import com.squareup.workflow1.ui.ScreenViewRunner import com.squareup.workflow1.ui.TextController +import com.squareup.workflow1.ui.ViewEnvironment import com.squareup.workflow1.ui.WorkflowUiExperimentalApi +import com.squareup.workflow1.ui.control +import com.squareup.workflow1.ui.navigation.setBackHandler import workflow.tutorial.views.databinding.TodoEditViewBinding @OptIn(WorkflowUiExperimentalApi::class) @@ -19,3 +23,19 @@ data class TodoEditScreen( override val viewFactory = ScreenViewFactory.fromViewBinding(TodoEditViewBinding::inflate, ::TodoEditScreenRunner) } + +@OptIn(WorkflowUiExperimentalApi::class) +private class TodoEditScreenRunner( + private val binding: TodoEditViewBinding +) : ScreenViewRunner { + + override fun showRendering( + rendering: TodoEditScreen, + environment: ViewEnvironment + ) { + binding.root.setBackHandler(rendering.onBackPressed) + binding.save.setOnClickListener { rendering.onSavePressed() } + rendering.title.control(binding.todoTitle) + rendering.note.control(binding.todoNote) + } +} diff --git a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoEditScreenRunner.kt b/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoEditScreenRunner.kt deleted file mode 100644 index e5796f988..000000000 --- a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoEditScreenRunner.kt +++ /dev/null @@ -1,24 +0,0 @@ -package workflow.tutorial - -import com.squareup.workflow1.ui.ScreenViewRunner -import com.squareup.workflow1.ui.ViewEnvironment -import com.squareup.workflow1.ui.WorkflowUiExperimentalApi -import com.squareup.workflow1.ui.control -import com.squareup.workflow1.ui.navigation.setBackHandler -import workflow.tutorial.views.databinding.TodoEditViewBinding - -@OptIn(WorkflowUiExperimentalApi::class) -class TodoEditScreenRunner( - private val binding: TodoEditViewBinding -) : ScreenViewRunner { - - override fun showRendering( - rendering: TodoEditScreen, - environment: ViewEnvironment - ) { - binding.root.setBackHandler(rendering.onBackPressed) - binding.save.setOnClickListener { rendering.onSavePressed() } - rendering.title.control(binding.todoTitle) - rendering.note.control(binding.todoNote) - } -} diff --git a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoListScreen.kt b/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoListScreen.kt index 13a664473..8b5cf9519 100644 --- a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoListScreen.kt +++ b/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoListScreen.kt @@ -1,8 +1,13 @@ package workflow.tutorial +import androidx.recyclerview.widget.LinearLayoutManager import com.squareup.workflow1.ui.AndroidScreen import com.squareup.workflow1.ui.ScreenViewFactory +import com.squareup.workflow1.ui.ScreenViewRunner +import com.squareup.workflow1.ui.ViewEnvironment import com.squareup.workflow1.ui.WorkflowUiExperimentalApi +import com.squareup.workflow1.ui.navigation.setBackHandler +import workflow.tutorial.views.TodoListAdapter import workflow.tutorial.views.databinding.TodoListViewBinding /** @@ -22,3 +27,33 @@ data class TodoListScreen( override val viewFactory = ScreenViewFactory.fromViewBinding(TodoListViewBinding::inflate, ::TodoListScreenRunner) } + +@OptIn(WorkflowUiExperimentalApi::class) +private class TodoListScreenRunner( + private val todoListBinding: TodoListViewBinding +) : ScreenViewRunner { + + private val adapter = TodoListAdapter() + + init { + todoListBinding.todoList.layoutManager = LinearLayoutManager(todoListBinding.root.context) + todoListBinding.todoList.adapter = adapter + } + + override fun showRendering( + rendering: TodoListScreen, + environment: ViewEnvironment + ) { + todoListBinding.root.setBackHandler(rendering.onBackPressed) + todoListBinding.add.setOnClickListener { rendering.onAddPressed() } + + with(todoListBinding.todoListWelcome) { + text = + resources.getString(workflow.tutorial.views.R.string.todo_list_welcome, rendering.username) + } + + adapter.todoList = rendering.todoTitles + adapter.onTodoSelected = rendering.onRowPressed + adapter.notifyDataSetChanged() + } +} diff --git a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoListScreenRunner.kt b/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoListScreenRunner.kt deleted file mode 100644 index 35bd5b8a2..000000000 --- a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/TodoListScreenRunner.kt +++ /dev/null @@ -1,39 +0,0 @@ -package workflow.tutorial - -import androidx.recyclerview.widget.LinearLayoutManager -import com.squareup.workflow1.ui.ScreenViewRunner -import com.squareup.workflow1.ui.ViewEnvironment -import com.squareup.workflow1.ui.WorkflowUiExperimentalApi -import com.squareup.workflow1.ui.navigation.setBackHandler -import workflow.tutorial.views.TodoListAdapter -import workflow.tutorial.views.databinding.TodoListViewBinding - -@OptIn(WorkflowUiExperimentalApi::class) -class TodoListScreenRunner( - private val todoListBinding: TodoListViewBinding -) : ScreenViewRunner { - - private val adapter = TodoListAdapter() - - init { - todoListBinding.todoList.layoutManager = LinearLayoutManager(todoListBinding.root.context) - todoListBinding.todoList.adapter = adapter - } - - override fun showRendering( - rendering: TodoListScreen, - environment: ViewEnvironment - ) { - todoListBinding.root.setBackHandler(rendering.onBackPressed) - todoListBinding.add.setOnClickListener { rendering.onAddPressed() } - - with(todoListBinding.todoListWelcome) { - text = - resources.getString(workflow.tutorial.views.R.string.todo_list_welcome, rendering.username) - } - - adapter.todoList = rendering.todoTitles - adapter.onTodoSelected = rendering.onRowPressed - adapter.notifyDataSetChanged() - } -} diff --git a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/WelcomeScreen.kt b/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/WelcomeScreen.kt index 42d759826..075b6cea4 100644 --- a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/WelcomeScreen.kt +++ b/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/WelcomeScreen.kt @@ -2,8 +2,11 @@ package workflow.tutorial import com.squareup.workflow1.ui.AndroidScreen import com.squareup.workflow1.ui.ScreenViewFactory +import com.squareup.workflow1.ui.ScreenViewRunner import com.squareup.workflow1.ui.TextController +import com.squareup.workflow1.ui.ViewEnvironment import com.squareup.workflow1.ui.WorkflowUiExperimentalApi +import com.squareup.workflow1.ui.control import workflow.tutorial.views.databinding.WelcomeViewBinding @OptIn(WorkflowUiExperimentalApi::class) @@ -13,6 +16,23 @@ data class WelcomeScreen( /** Callback when the login button is tapped. */ val onLogInPressed: () -> Unit ) : AndroidScreen { + override val viewFactory = ScreenViewFactory.fromViewBinding(WelcomeViewBinding::inflate, ::WelcomeScreenRunner) } + +@OptIn(WorkflowUiExperimentalApi::class) +private class WelcomeScreenRunner( + private val viewBinding: WelcomeViewBinding +) : ScreenViewRunner { + + override fun showRendering( + rendering: WelcomeScreen, + environment: ViewEnvironment + ) { + // TextController is a helper provided by the workflow library that takes + // care of the complexity of correctly interacting with EditTexts in a declarative manner. + rendering.username.control(viewBinding.username) + viewBinding.login.setOnClickListener { rendering.onLogInPressed() } + } +} diff --git a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/WelcomeScreenRunner.kt b/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/WelcomeScreenRunner.kt deleted file mode 100644 index 165e55677..000000000 --- a/samples/tutorial/tutorial-final/src/main/java/workflow/tutorial/WelcomeScreenRunner.kt +++ /dev/null @@ -1,23 +0,0 @@ -package workflow.tutorial - -import com.squareup.workflow1.ui.ScreenViewRunner -import com.squareup.workflow1.ui.ViewEnvironment -import com.squareup.workflow1.ui.WorkflowUiExperimentalApi -import com.squareup.workflow1.ui.control -import workflow.tutorial.views.databinding.WelcomeViewBinding - -@OptIn(WorkflowUiExperimentalApi::class) -class WelcomeScreenRunner( - private val welcomeBinding: WelcomeViewBinding -) : ScreenViewRunner { - - override fun showRendering( - rendering: WelcomeScreen, - environment: ViewEnvironment - ) { - // TextController is a helper provided by the workflow library that takes - // care of the complexity of correctly interacting with EditTexts in a declarative manner. - rendering.username.control(welcomeBinding.username) - welcomeBinding.login.setOnClickListener { rendering.onLogInPressed() } - } -} diff --git a/workflow-file-templates.zip b/workflow-file-templates.zip new file mode 100644 index 0000000000000000000000000000000000000000..b66969bb6f0c4102270ccc7b1cbc5dc7ecbcacb2 GIT binary patch literal 2416 zcmai#3pAAL8pl6lYQ|+;V`rFS+>N^~gKWxu)0DxuWN6P|OjC1-8AGXDnq0Qq$u&eV z*pxVh+7g*u%1%hi5>mV3G`3BXq-l1}%(*O+I%_}Q`qp~a`rhYR?|T3L@At>;wds66<@S-_*H?e((D@b?^Zf-esX}3;JI87vH zoN{dUL#1=xC-63eh#kj7sr~YO3Xe(en(sU}(>ZgwMwWG|-Ig<6ps4j;=FGvWl=*G+ zTklJ6w1-^Ci}>tFNM=3y9mea@>>`F5FyYe=o%pTI`;!`nIBt1R7qr1mzUcRi73vsB@3-B?1%lcb9UAJl~Hg5 z<7fHtgc4OdMT0&krD~1k4%4zZgUhFMFm`i`59AZ~=#6gGLkW&|_@Qdw8hp2@Vs5x^X=bU9@2kx3WwCo9(EIe$y$dn`;I$b5*4-2O z)0ghC`pP{n^r%<{B?=i38A~G3k)~`4DIOU?p+`~ZWR%26`FLNDt;(61Pv*w=dgu{P zR-e|#6a{9gX3O`Qj8Y+2{N#Vt{N4u1-TBos(yf_0n61q9@wi$XRd~x+&To-^;lq24Tx<7GxNtSy zaF<=XMyM7d=iaNX*t%An@QrnJe9@C1IyAcM9=7RonPac%JVMMr8(vN8qngzYP&FbG zgRm(sFI`E{U{gc?W&Ohsp%awxVj6;~!K{p~Hgz@jKoM484|4C>5&#HfX@nN%07dcg zV}A7~%E0}qIiq_>6+>?qZWQpA8mB33jwLta!VKFFz1-)ooc8|Y?dNl zL)M<{k-SJnXMkrIufpE=&DKpohRW5GCRj=aQS_Im5FDexPj;5qLhJ;k7WeP-zLR}R z)1uP*hi$XXV0|rGGga&*ku2F^L~w5oyFyNiX+!IvKR}VJXI&4t3h+*csy06!x&0b@ zFUTfNm1iQ6xPZe2r;8oLv!H1&%^5LU~m!AKgta`S#WqCDv zzM3XugnQJa55de9r;^KS!XK|WYxjUSTQm&~la7j<=T_Tn9W)6rRFCShRFq;#%OW$K z2+|>U| znKfhfa-ZP3`nwsBWzFT-CfLf3rR+l~7{8@tc1UOh`_DMGMz4q5PU+~U;q2MXlKKHkUvpb@0 zcHT`Hu|r}mQc{$Qa^P;Y+1COF{8spUT}$nQilk*{O*8+(kH!tRjJNqjrn+e$^iz-- zs&iPqs{(a!aPadEJFAN};9ho^k;RYrpPO0(S4bV{H-s@dSx05OtcTyftRGtwq_WDd z>S9iQTFdf6k2*zXbGBAn$mFZIV9(?ItP2-KHT>il=b@~`eZuR9PUgQ{0rPL0_7Py3 z#}5b~^GUTkk^&BxRPBtLbmTUYnZ0FYm9SCw=O&r8&7Y4zn;R|^?vHs2dKT6DN$d3%CfdD{FPTIWb8~6kho0mdo zvWQeFDawkKz}h=B{Mg*eVxNVNrRB(djQ74V^MT>vfguYSG36jo9T69*E$-10zY^;G zCto*CMToz8)5Rf4rT8Gd-9228UQ|W|k%|l;u~=fxF|m7PK=Q!<4`*?|RBeoE8PFDB zJ*=fcED7uNvJfx7?EPkROAhnDff9a8|Mn7ouh(JmeSSIcuV^kkTLKPgRV3h8uYKT+ zv%iHA>3Nb{m)1j~<$B3OHYh87=id@+y_Fzt{R{aviBk^%HjAIzVnCLQ8vx*6-4vqo literal 0 HcmV?d00001