From fe3b6e25ddbd04419ad4aaf5cc6c64f6ad1d4e3c Mon Sep 17 00:00:00 2001 From: dandiindra29 Date: Sat, 7 Oct 2023 12:00:31 +0700 Subject: [PATCH 01/12] create quiz registration page --- .gitignore | 3 +- app/lib/app.dart | 2 + app/lib/core/bases/widgets/atoms/button.dart | 12 +- .../main/presentation/pages/main_page.dart | 2 +- .../bloc/quiz_registration_cubit.dart | 15 ++ .../bloc/quiz_registration_event.dart | 8 + .../bloc/quiz_registration_state.dart | 38 +++ .../presentation/pages/_pages.dart | 10 + .../pages/quiz_registration_page.dart | 235 ++++++++++++++++++ app/lib/services/router_service.dart | 4 + 10 files changed, 323 insertions(+), 6 deletions(-) create mode 100644 app/lib/features/quiz_registration/bloc/quiz_registration_cubit.dart create mode 100644 app/lib/features/quiz_registration/bloc/quiz_registration_event.dart create mode 100644 app/lib/features/quiz_registration/bloc/quiz_registration_state.dart create mode 100644 app/lib/features/quiz_registration/presentation/pages/_pages.dart create mode 100644 app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart diff --git a/.gitignore b/.gitignore index 0a764a4..7ed4bc8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -env +.env +google-service.json \ No newline at end of file diff --git a/app/lib/app.dart b/app/lib/app.dart index 0b85c38..3c5208d 100644 --- a/app/lib/app.dart +++ b/app/lib/app.dart @@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:google_fonts/google_fonts.dart'; import 'features/onboarding/presentation/bloc/user_initialization_bloc.dart'; +import 'features/quiz_registration/bloc/quiz_registration_cubit.dart'; import 'services/di.dart'; import 'services/router_service.dart'; @@ -24,6 +25,7 @@ class App extends StatelessWidget { OnboardingAuthEvent(), ), ), + BlocProvider(create: (context) => QuizRegistrationCubit()) ], child: MaterialApp.router( theme: ThemeData( diff --git a/app/lib/core/bases/widgets/atoms/button.dart b/app/lib/core/bases/widgets/atoms/button.dart index 2dcd802..383e1a1 100644 --- a/app/lib/core/bases/widgets/atoms/button.dart +++ b/app/lib/core/bases/widgets/atoms/button.dart @@ -13,6 +13,8 @@ class Button extends StatelessWidget { final double innerHorizontalPadding; final double innerVerticalPadding; final double fontSize; + final Color customButtonColor; + final Color customTextColor; const Button({ required this.text, @@ -23,6 +25,8 @@ class Button extends StatelessWidget { this.innerHorizontalPadding = 20, this.innerVerticalPadding = 16, this.fontSize = 16, + this.customButtonColor = Colors.transparent, + this.customTextColor = BaseColors.black, super.key, }); @@ -41,12 +45,12 @@ class Button extends StatelessWidget { buttonColor = BaseColors.white; break; case ButtonType.tertiary: - textColor = BaseColors.primarySwatch; - buttonColor = BaseColors.black; + textColor = BaseColors.white; + buttonColor = Colors.blueAccent; break; case null: - textColor = BaseColors.black; - buttonColor = Colors.transparent; + textColor = customTextColor; + buttonColor = customButtonColor; break; } diff --git a/app/lib/features/main/presentation/pages/main_page.dart b/app/lib/features/main/presentation/pages/main_page.dart index e99e45d..8febd95 100644 --- a/app/lib/features/main/presentation/pages/main_page.dart +++ b/app/lib/features/main/presentation/pages/main_page.dart @@ -71,7 +71,7 @@ class _MainPageState extends State { Button( buttonType: ButtonType.primary, onTap: () async { - await context.push('/construction'); + await context.push('/quiz_registration'); }, text: 'Ikut Quiz', ), diff --git a/app/lib/features/quiz_registration/bloc/quiz_registration_cubit.dart b/app/lib/features/quiz_registration/bloc/quiz_registration_cubit.dart new file mode 100644 index 0000000..83bc631 --- /dev/null +++ b/app/lib/features/quiz_registration/bloc/quiz_registration_cubit.dart @@ -0,0 +1,15 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +part 'quiz_registration_state.dart'; +part 'quiz_registration_event.dart'; + +class QuizRegistrationCubit extends Cubit { + QuizRegistrationCubit() : super(QuizRegistrationInitialState()); + + void selectWeek(String selectedWeek) { + emit(QuizRegistrationLoading()); + + emit(QuizRegistrationWeekSelected(selectedWeek)); + } +} diff --git a/app/lib/features/quiz_registration/bloc/quiz_registration_event.dart b/app/lib/features/quiz_registration/bloc/quiz_registration_event.dart new file mode 100644 index 0000000..a048663 --- /dev/null +++ b/app/lib/features/quiz_registration/bloc/quiz_registration_event.dart @@ -0,0 +1,8 @@ +part of 'quiz_registration_cubit.dart'; + +abstract class QuizRegistrationEvent extends Equatable { + const QuizRegistrationEvent(); + + @override + List get props => []; +} diff --git a/app/lib/features/quiz_registration/bloc/quiz_registration_state.dart b/app/lib/features/quiz_registration/bloc/quiz_registration_state.dart new file mode 100644 index 0000000..994a204 --- /dev/null +++ b/app/lib/features/quiz_registration/bloc/quiz_registration_state.dart @@ -0,0 +1,38 @@ +part of 'quiz_registration_cubit.dart'; + +abstract class QuizRegistrationState extends Equatable { + const QuizRegistrationState(); + + @override + List get props => []; +} + +class QuizRegistrationInitialState extends QuizRegistrationState {} + +class QuizRegistrationLoading extends QuizRegistrationState {} + +class QuizRegistrationWeekSelected extends QuizRegistrationState { + final String selectedWeek; + + const QuizRegistrationWeekSelected(this.selectedWeek); + + @override + List get props => [selectedWeek]; +} + +// class QuizRegistrationSuccess extends QuizRegistrationState { +// final List QuizRegistrations; + +// const QuizRegistrationSuccess(this.QuizRegistrations); + +// @override +// List get props => [QuizRegistrations]; +// } + +// class QuizRegistrationFailed extends QuizRegistrationState { +// final String error; + +// const QuizRegistrationFailed(this.error); +// @override +// List get props => [error]; +// } diff --git a/app/lib/features/quiz_registration/presentation/pages/_pages.dart b/app/lib/features/quiz_registration/presentation/pages/_pages.dart new file mode 100644 index 0000000..91946da --- /dev/null +++ b/app/lib/features/quiz_registration/presentation/pages/_pages.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../../../core/bases/enum/button_type.dart'; +import '../../../../core/bases/widgets/atoms/button.dart'; +import '../../../../core/bases/widgets/layout/bebras_scaffold.dart'; +import '../../../../core/constants/assets.dart'; +import '../../bloc/quiz_registration_cubit.dart'; + +part 'quiz_registration_page.dart'; diff --git a/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart b/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart new file mode 100644 index 0000000..6667c6e --- /dev/null +++ b/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart @@ -0,0 +1,235 @@ +// ignore_for_file: lines_longer_than_80_chars, require_trailing_commas + +part of '_pages.dart'; + +class QuizRegistrationPage extends StatefulWidget { + const QuizRegistrationPage({super.key}); + + @override + State createState() => _QuizRegistrationPageState(); +} + +class _QuizRegistrationPageState extends State { + final nama = 'dummy'; + + @override + Widget build(BuildContext context) { + Future showModal() async { + return showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return BlocConsumer( + listener: (context, state) { + // TODO: implement listener + }, + builder: (context, state) { + if (state is QuizRegistrationWeekSelected && + state.selectedWeek != '') { + return Container( + constraints: const BoxConstraints(minHeight: 30), + width: double.infinity, + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox( + height: 20, + ), + Container( + margin: const EdgeInsets.only(left: 20), + child: InkWell( + onTap: () => context + .read() + .selectWeek(''), + child: const Row( + children: [ + Icon(Icons.chevron_left), + Text('Pilih Minggu') + ], + ), + ), + ), + const SizedBox( + height: 20, + ), + Container( + margin: const EdgeInsets.only(left: 20), + child: Text( + 'Daftar Latihan Bebras ${state.selectedWeek == 'next_week' ? 'Minggu Depan' : 'Minggu Ini'}', + textAlign: TextAlign.left, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold), + ), + ), + const SizedBox( + height: 25, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectWeek('next_week'), + customButtonColor: Colors.blue.shade400, + customTextColor: Colors.white, + text: 'siKecil', + )), + const SizedBox( + height: 15, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectWeek('this_week'), + customButtonColor: Colors.green.shade400, + customTextColor: Colors.white, + text: 'Siaga', + )), + const SizedBox( + height: 15, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectWeek('this_week'), + customButtonColor: Colors.red.shade400, + customTextColor: Colors.white, + text: 'Penggalang', + )), + const SizedBox( + height: 15, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectWeek('this_week'), + customButtonColor: Colors.orange.shade400, + customTextColor: Colors.white, + text: 'Penegak', + )), + const SizedBox( + height: 20, + ), + ], + ), + ); + } + return Container( + height: 260, + width: double.infinity, + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox( + height: 40, + ), + Container( + margin: const EdgeInsets.only(left: 20), + child: const Text( + 'Daftar Latihan Bebras', + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 18, fontWeight: FontWeight.bold), + ), + ), + const SizedBox( + height: 25, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectWeek('next_week'), + customButtonColor: Colors.green.shade400, + customTextColor: Colors.white, + text: 'Latihan Minggu Depan', + )), + const SizedBox( + height: 20, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectWeek('this_week'), + customButtonColor: Colors.brown.shade400, + customTextColor: Colors.white, + text: 'Latihan Minggu Ini', + )) + ], + ), + ); + }, + ); + }, + ).whenComplete(() => null); + } + + return BebrasScaffold( + body: SingleChildScrollView( + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.all(32), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset( + Assets.bebrasPandaiText, + ), + const SizedBox( + height: 40, + ), + const Text('Latihan yang pernah diikuti'), + const SizedBox( + height: 10, + ), + Container( + height: MediaQuery.of(context).size.height - 300, + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 16), + decoration: BoxDecoration(border: Border.all()), + child: const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'Silahkan klik Tombol `Daftar Latihan Bebras` dibawah untuk memulai', + ) + ]), + ), + const SizedBox( + height: 10, + ), + Button( + buttonType: ButtonType.tertiary, + onTap: () async { + await showModal(); + }, + text: 'Daftar Latihan Bebras', + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/app/lib/services/router_service.dart b/app/lib/services/router_service.dart index 4992421..31c6f29 100644 --- a/app/lib/services/router_service.dart +++ b/app/lib/services/router_service.dart @@ -4,6 +4,7 @@ import '../features/authentication/signin/presentation/pages/_pages.dart'; import '../features/error/presentation/pages/_pages.dart'; import '../features/main/presentation/pages/_pages.dart'; import '../features/onboarding/presentation/pages/_pages.dart'; +import '../features/quiz_registration/presentation/pages/_pages.dart'; GoRouter router = GoRouter( routes: [ @@ -23,5 +24,8 @@ GoRouter router = GoRouter( path: '/construction', builder: (context, state) => const UnderConstructionPage(), ), + GoRoute( + path: '/quiz_registration', + builder: (context, state) => const QuizRegistrationPage()), ], ); From 7b13ba87f03bb18391aec2c03ae5b0231df46734 Mon Sep 17 00:00:00 2001 From: 12henbx Date: Sat, 14 Oct 2023 21:08:14 +0700 Subject: [PATCH 02/12] edit login page, update bloc for register, create register form --- .idea/.gitignore | 3 + .idea/bebras-pandai.iml | 13 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + app/assets/images/bebras-mascot.png | Bin 0 -> 106237 bytes app/lib/app.dart | 8 +- app/lib/core/constants/assets.dart | 1 + .../core/constants/bebrasBiroDropdown.dart | 110 +++++++ app/lib/core/constants/colorConstant.dart | 7 + .../register/presentation/pages/_pages.dart | 15 + .../presentation/pages/register_page.dart | 227 ++++++++++++++ .../signin/presentation/pages/_pages.dart | 3 +- .../presentation/pages/sign_in_page.dart | 53 +++- .../main/presentation/pages/main_page.dart | 282 +++++++++++++----- .../bloc/user_initialization_bloc.dart | 58 +++- .../bloc/user_initialization_event.dart | 24 ++ .../bloc/user_initialization_state.dart | 54 +++- .../presentation/model/registered_user.dart | 28 ++ .../presentation/pages/splash_screen.dart | 11 +- .../repositories/register_user_repo.dart | 63 ++++ app/lib/services/di.dart | 2 +- app/lib/services/router_service.dart | 5 + .../Flutter/GeneratedPluginRegistrant.swift | 2 + app/pubspec.lock | 44 ++- app/pubspec.yaml | 4 +- 25 files changed, 915 insertions(+), 116 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/bebras-pandai.iml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 app/assets/images/bebras-mascot.png create mode 100644 app/lib/core/constants/bebrasBiroDropdown.dart create mode 100644 app/lib/core/constants/colorConstant.dart create mode 100644 app/lib/features/authentication/register/presentation/pages/_pages.dart create mode 100644 app/lib/features/authentication/register/presentation/pages/register_page.dart create mode 100644 app/lib/features/onboarding/presentation/model/registered_user.dart create mode 100644 app/lib/features/onboarding/presentation/repositories/register_user_repo.dart diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/bebras-pandai.iml b/.idea/bebras-pandai.iml new file mode 100644 index 0000000..f33560c --- /dev/null +++ b/.idea/bebras-pandai.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..2604166 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/assets/images/bebras-mascot.png b/app/assets/images/bebras-mascot.png new file mode 100644 index 0000000000000000000000000000000000000000..125eb4d8d8506ada5629ad5a390c41f82cd9dbf6 GIT binary patch literal 106237 zcmXV1cRW@9|1TNWzPR?f*St1`t`PUSR@Sx2rHqojitKRjb&XK=NL`UtD4Xm}AsLmu zi_DD3_#L0`?+*`;bM85>^LoGDulanv-Z2}R5lx>PpE^9#5jcSaf@FI{?{NPA*W0bEmi>sb3;y2Q|N@prk$tH|ln zrSk$^G}7#`-S1QCI_y~BDsB0-p&MLZo`9J_LRxa)K~%M9hj<@-@)%{szcZA_4X|e3 zJ8c@d@u$`3LYCS;^6Zd+<`C~jwYkO#@N>kgI9@8orw=`9DUg)b9D4E3Ipi6&Z`}B^ z{cg7GhsleP8FROdCjSjv^Q}Z@Rr5!k#ikv6XaCL(>2HC_k>IuDt|N-_UymdMEH5s} zkwuTd5r@C_-`Z*KXGz{pTvxD_xws7`CsFQn&6NhR(zd4k#*IkNb;ATnSJ1(NGJ&9iY2j2PaL1TBQh&vsoUG}i~rq^OhOP_qW6Q0 z%b~{Y3$vQgwENX|Z;qmj*-*CsQEw9isbHlhKVC;CdW(eQnlVv@-Y;WcF#YdGn4)p# z-5ur$S8-7FEB|Y{QfFz1THtGuP;?}lSeYniUw z`V5y4MA0MNheai8+7(^A1VZV8*hQsouPF^Zjor9KNa$cQANr3RC_>1V$);{ip@%+Q znl^9vj=nL|e=9{$Fj$zt7GHJEmS}rBMBPlZa@*gn>7(*o%lz%)1v)vrsz+mt%X%Xg zE&+TXg$lW?(3Cq|`dleIV7*!*pw?3zV$!;ZqxhOV$}7=0daUqubhZ4KS-OPX3lzOXClX1=5Yr{1s21P!vTG}uwW%+O^ z{AwyyuF@ODjS9AC;+}AQVxDgL@givmA;uB9nH zDCB9cip;p_Z@QIxKsf|ML(&#Hhw~fmbs)FKpHJ>NG&19|^5iZSk;De7Tc8|Psd?AF zd@jnKh+kZa4r20GISBW>GNdc)%9WRdSw5|Ad=&Mvkuz>=U~=@2+iD6c{>hV&xi`5d zf)aIq!MH399t|XT1b4ryphU%I!29#9h;5s~beHO);;$Ni(^d_xpy%m>=KaTMLlTLo zPJ1D6;QGW~Q2TJ2jUtZ;KQH%?+SU66yZt?0>PJr?F9EJ7iBDdxnGeP+&IYWrrv2QC zqvqE3DzM}B4Y)F|)KZ%Mt`R|j?(elai{J&(ce*vPW~;nQf2S7`OS`I2+OwJSi!~J; zu_b|m#X?9Rg=pM!3S^Od%^HQ56XWNU1#=`p3Q-_He&W>a60XGYq3iMD(zIf1gpVSn2k<&Q;`7P!jlK4yn;=?p zE%L}tSJl=4&OTDX1M=u`)+LVTZVz;u!n{yV1^(lVVnM=ih7WcR4PzbfLEFn&`4K?{7gs%}9F2ppe=n@!Jc&HW1t>lRX@S5>_9E{a%<; z#y_Kl&}?^9FV%1YPeK`3Bf*6g9B3HKNe`r%Wo9=a5c2X_N%PT(U`>YD0Q~@`yF*tA zpwFY^%(vLcNz9$pFwx6BHysPNXU3+Taq+Z)ezO@3r(Zgbv@I}!SgX)aryfD`eB(i7 z_WAzmOFlRKoqb(GZ33Pa1?M{Pe2@z&bdxQTf2vm%W!M=)1XTEr+aC^P-qMAT!TumpC#(tJ=KX)Dd{HSHcaGg8F?Z#8Rzn$k-^`s;O8JOAdH~;MAt@}!`zNs)6{`5mUGtoN? z<5?&Hf^DfPmL2aO9<7|oRj((FK~kLeN@@v9z(yU^0xUR~?_?{!*)USv;ILS~ejqGG z6AI?h^9^t#Tc2tdLiK`zMP7W&qk!dAfXR#Q@%INwL782_OoT|N5cRuz0!CFu5Dp$0e`qyweHZ8j=YtrSFi zq?|M(wl*T169VIm0}5J&I~5X+YspDzU_d{~=6?H(FxVLX@JTu4MRPuV4Qua=xpo&l zJ+_*rR{t-rf+uYG{XJNuTkfY>3+3_pHvvnv^frHIHXrX*tg@v=ZX}*)Vo}_M)?imo zfH6!sbWbOxPK@Y&81zK5|vF!*=5ztrK)#@TQw%T0g z#wF1-7ID}xC4MM*EB@Z%)NXKCn8W<3d_``UVmhPRkN)xkt!`>=|JVQ)?bZH#Q}rz>&?CqIOE-EqDq2nksAl7Ml&`)BQW997xh(1J%Z{jpy##gQ;WI&eU6jA*E+ z7!Ma0wWSG!ESwRB`S4e$=$nx1<^HwhjY4$iOf&UX4Vc@Q2$yBW6Oq27;5uS_d>m?< zR=w`-T}fz}G!4-MKS~ys+xhtVl&j-kY%&|Z;!%KiIVwAj3|XXr=Ac1&w8f}OAs=*o z2$VVsF8t+^=&#dWOnc?M%hyP!F!cxTIdCElvTt{MwKVO;!14K z%+-Qd9LZz?{5Kbi?8BwWBJT?2LPsS8=qN~vbDatQI$~76Mh>s8`3*q`#;w-k5a(%+ z!WSYft*zam3jysv(*8z*59Q$3>A~FcCS?M~9ORQ=)U$0F0jBr8n%cVT2=doqX?XIO z4Jdf7>a`dZI~CGXzGbVISBOUjq!0nP^P(_>wckRG?>$$F_Fg=6rkDFq$4AAy;po}L zzz}e(yqdHyh=~J|nUuYvE1zkRA!_vU&P z?@0DPtv`o`9VbqDBa*+F$O|v_dX37mP#oKi$|F3D6Z7X|BEuyx1sMCW1u~%L#vl1L z;o*{FCmiWX&4FTyZDm5(Cl#Mz%=J>DCl*UyPh~fp`<(5{j9_mk@{%@MQ#E+WC{!ac zEdLQEB>S4*z#D7Y$aN*y7m&6ur^`AhXSovMm~u3xT(O-Ml;ai&q~a&n`Xu&VILh|% z?o$t_N&*Wf-M=u>F#`c0ahPc;ZB(70t9|P|-?`%@Y1mMZQze^+3y4z3HUyQyp_J78 zv@`xX?`fn39NvQmFusBIL=G9z&hLaR>#-N%DZ%b2@(7tcOp(}yK0Hd+0c9o&23nXg z2%gZeJ0yMalSB(RJo7HSQxKmx#uSgORc{bys zuhGdQ{=7>L;u^d6+>adTP2qw5DVL6DzLEi{5!?Z1yP&@4;!qTh;EB2iQ^x|2!@L~( zLX@U#XZLT&$&>t7C_7kB9Qluev{(BlC8s@+l?KDByuKi=n{85ssS_FH-(G}ns0co_RhzsUd{aN99<%6u38`qj3x%Fv5!_gfP3`sOF3nO zSkjR7QC+VO1(xDH`~OS0favcUExIT07H?9IEdRHEYpFAJeLA4C9#I9OJ;H;exZv5X z=W#zZa4_=vf)9-;8Wz-#ZSk5KOA)?m^v|r;DxumH*xb9tCu6TLK|AOCuoeuB5sn1F1O!%*C83^l`v4u0b_b~0sUThmf-%~K|I8sqyNuX?OK$j7nt`uGCj&L$ljhzb$ z+u+$!)Ptt=O=>t{?6YgQe=^T-v$oZB=^B@05NGg-o@+yDH&{B|tOi{$VK9d#49~F` zb6T&GS&>qw90Z^{&b7Y3Yuov)<6McB!_naHO5s@n#(?sm~Nj^VPnw8>(ZCJ zZ}vTXczTpRz^Un-zL3T`KlW+JD_i{jkxf^^{P?v0yXW!?Y%~fn7cS~fuP!!kB5LL} z$6RlU1f6U|vO?Z#2uQ~F5ALBlc=zZZX~#EmFvYhrexN`S^M#k3;i1p6!X!p6+n;WE zi?i~gf>6L;Q1bGo^8qsv-}5BxbN|a(;ug5k`(48S;bZ;3L+0OZ6B)?{hBWklv`LMf z@c3}0Q5`)r)^N9T_K|kz{6dJip3aVwPdWi1!89aeMfys?`MB$(Gj%Ii`>o~6X?fVP zwY7475UW?$DJb;sxz~4Z@BXcM9d_kGMiswL<2xe4QE_6(|KvnY0%MbU4MC!o?67;J z<86&k2%_<>#K7k!X$9^2I(`!4{5;B-V~K5di>b!ihZdiud6C!Du5~S?9PY;TJo7Op z3YdxF9_doFo?fGu`KPIDOid#w__xSOTBzuO7|Ii-lG(!g|H{MP8RTO9=dB%G;&NI~ z)rT1RzBAn#d8U#pxEa&KLGg7yfl)qrcV<3vlzh=8LWRHmy5QN%S9!v>x2;ed*7pTz z72+;r$4~PD=^2=#gSv|w=SR^mG)CKRcz~Z0dn($QSlV&UJCNj8Cz>UxaT00tNwOa> zUv+k3preXm8tck`4kgG$-N+-L5EFzo?m!-Cc!wh&KFn6kL4F6r(NOV9=q&2^Ru1(-5VtcGa3Lr|ZwhMmMerMG5X{p1>NN{|F*L092!s3J zvRcuw_+wC~9bB8_>ZF$;7^bmV28i?`8U$IDPc%$T_X7@eLCs!yGwu?kBoio8W0|#@ z4P*e;0pf(nq)-sIrDQaCUfU|8g17d$41AP^X&M#8HqwXzuaPM&(4ze9#i<$QLuX!- z_n9--7TZ`n)Jb@SsYE}d-5OtynX*L|gv=M`%#C=aa8A-f=lS%dOim?{`ohc|>qZ%1SY0V_dW_S)n&tyK#`ocCr(><38!P}CZ&QWOZa+{TNB z+~9Q6W?7s48i~0*2tvsossx&OOe;JOcOs_{jc;Y~fsgVE0EO2jn3fL}X3E}Vu8le( z`O3g@U&O?2p557c4Bg-y0FR9EN+|zPVnAcCumf zb@u09th4tQ&}|Fv=?Bp;>3IN=$={EMaxk|kkRSMU!UT+g-C`o3s-w0Y-}TR0FyrP$ zniN;O241MxjY-tNg%UAX6tY4v&kdCL^HKPPmfQq*bGyWtyLMM8Ty6SS*o!T z>Xw#o;|=*q`&Bp{0~TQZqCk$-kUk?PtpGM>MoVl}2vRCtFaQI*dPmve@*Lt&-4pNb ze3fABi3CS+l)?U0=_8o{)foU;6L^s1W4D_=EYbZ?uTvVAXKC-oB~l=XjGxO~f_N|U zXygFa;3DK_+bgg{Q}%T|=H%4BsU)>Gk}Y66F+4P@Vg0!5#E2Y8q%G!{olz{(>fTk8 zji&v0v#I8BA~{J5;K+#@4Yjv?6VWL>Qgk1TPn=dV4Rvs_ITMY9*1alhGJYDr+TPFf zH{NcEY3mOkHHuz9a0e&(1e*Vpwsa)5E3<T9j*<@m?WUOtxfLjZISAe>K4 z;$*^65aAG9e{0n%BKY%T1hD-N(y~SYvwmtqf3QdBVG5kr}3XyTp573K-b)d;w`#0yG(EA>;N3Z74 z7&XbiG7{IYn1^FgQz!seiw-?Zqo;aJNSXI+f)}yiO0;mKIW9D8!I+0Er~Pdd zJjC6vCA}6xp67p>Wyge%OhWc5&`k!=tMf=-z+L77&LVBXb@*p8wQ)$q^!pD3EVwav z9vpLYP(v~u`wZz!q7obHiA?fvsH*r+F99nw2dvOLM(u~RV!+$qW`}Rr*engexY!QO zY2MpB-M!a^CXz1n_r}s&i8`SgSs^F=RL{|*_p^RUHCORiL^>aVe&+J|`_H0A)!93? zy2W$=n3R-pM1ZFD|Btq=lfBO4{WgWBaeE7LJ}D8!4W66AG_Rqo?U7JOhvw4j?BhR) z0x;n5F&Mzg(?`FBZ^@|59tEFOx1AU*{Q36cn)o;sVEGgWV@-k4GmW#?=cixJPCgdD z+Uk_|mMyL8w--o&0bc?*;khj5{RV}AT9q8S+&jw3=S3<@Cm4mFCg9^ai?bO6RRIPH zm;gvEC)h*@-ta+c?k+!8vAiq$c4t@y#rs~l=x2d)vBvpNpJL1bMZx-|+vzLIb&nP= z;yT8H<8j`CkEKB9Vm>z9ZiSjJi7kKz1O6QqHajA(DX=Bct#S|S12>}w!qS9Q?c4cR z=fmuOt4Dw^khH2}MpGQmhVy=|vkIr^iBT@w(Et2JH0KlEh3@aYUp{arKBYx!-Mg%Y zli~Hm>aWIbh1H7WTuvS7z`@F6uBhuEZNMkuFFL=!trmbf$EGK1Q&#l z`(VNnDsFIFjDP()U*h`nSOnziQ;-Hs3}e5%*g=s|M`(6@z&*2k=*_dJ{(v(A4%(+= zw*ckcdgGh%T&rLEQy(0}8E zFgeKTwamhaTTQupfIA}qMXFGjbkpX*v_h1MdV71EvnUH!9-c63Bt@i}&^NtvYL@8g z=7IqN89jtpM-He%(4~N+y|^l0Y7fMe8mYPZ(Qq8Xn@*QYTE6d|77xKzhpPh7q8OA& z4img^3Xx!HswRn#+Juj1^F^y%T0Rs55weo3XKivH-R;Z5e-z4iSe|wyN1V41HAv(3 z+%4-ZykFQ&>hF(^k+CF+S9>iOhB>%oi|RPG?ihEHk}hgs-46yb5)(`g3z{`p zAgcs-!ldsNFUDR57NrkZh|Y7JGMJJE&ZVCseouse+mVuG8^ zO;RfMJYTf&j$lL-E?q21>>;BMO95aEw4<@`J=j*o^Mxd^;!ArvG!IRtI*ybiUq|3c zeJ7rxq_lBE#h(zxp57F?m@CLh9$uMpg;*i!&zSz%&Hs#xf;2Lk1>Y;qM+ohsJ4qN? zK;Yt+RU4a&(#`L5*hY6Zk%7~X2xcnjG@?VBeF}rp_$@x>n+*Yv0v1GhkUGqrb4^Bk z`)D(%_J21*K3t^`JE6~`;c0XL^iPLX={0p~dk|MFBa1PX;O5eX?3jUqgXMp);etrs zc}cXrW6KM%+iNE?SfB2YrsL{M1(!ZW`=nz3Hsu|5Rh)hi#&%9umPnk#mB2sh%H>{Y zJVuo_`UOysd@tDSiwm;Gr-Wi-JA4;+u(Za=-m3-DDf;%|a=b>Il;sg*496lO3iiwI zm7P&at@*yKT!K0^g8hgwZ zY~nz6O?r+YqKu-49w$orNHHkED3Qjx1D@r-GfR7b-}w^bQCW4knsY!QvoX z%1Hq;=x230f{t9E?prk`P0GJ6VM@M)K)$U8GO7fOc>ng6y}=0R11nIUCsE4$yk}eR zTSJ;zn#%Ij2hH7*I7~;ozwO8Hvnn5{LxYlvRCo9%g3q)1h|%#q+@CJo^^}0UiQMM? z9NlDS^R3Vp&8I(C?e~@m@T0W8H7p}fIHZpV#10*UODN^x5vA_*lamjs&>`t{A=Q z4@n%p7Azx9(RPjdD5zGqm*0CQ|Ei?&mqMNkDDUb-o4%YSFE8#r?2}u|Hq?>cTvNeQ z9UJ_F01nXNq34?Jy%yG0Oc5pE5nMXVAingLL5Tt=_&3I*5v>lzJv^fGvXEIErIrvEtu<-DYrzHpef~g3Rr76-lqdsc z3aF#0(G<*a0u!tH<^p^unKDl`SPB`IKbG;AcGhm}P{KtAArA4|b}q*Qv?^G+mu zWG~Ho2k%$!(L2rl1$c&{$ie65oz`o+W<{3)Nm>)GFf4diAHs#fG3Jm|F! zVNqXS+&F1>B8c_i)r&&*uBf4(tc`hEI*dw<)MI2+H)2id3|QL-jAoT3&UL`#ZBph7 zJbYska7Lb7~^N%TBWXs3x9@DA|N|7RqWFD_xIiF^^ z9BBjj*aC*9f!P(02{CaU2l{=g>5bf(6*Dym0#T!w;2#fo9yWE3nPST>p3d9sgl3MA zu*p}c+#IPu6Bjl}g5u^dJPTY4d<|smTbfPnzAa21*MGA1e3w|(_Z*2^W#`@moW1QvusnI(GM3@q_Q&~Ms~nfp1|fU%3iO8Fny z3lkUfXdmYv} zgiJHB?~*ihdJ(jnuPz$tyx33A0ytRMkHWj==+gT4SGF`+qj?JNjKyvHfKxLLOxOVv z#_dw&Tq{~}h$*b0E9y}^R4$jUxjb>jUTVXY9LAN<3A4XFk=n$g*MVw0;WY`(J5!bZ zDdtbzp~?Di`l31OYgL^8Zhd8C%bc+em!l8jFT6|!h7qAD74M;)J)@4E=yxgilw|*zik?03UqZ39WF*jA@C^{KPORf>aa!0sSvg=77 z+lE|_@WEFYx&$CZzRr#MES{UwA?d3n>I*}@?;2ZO6aGahTo3f3rH`L>v$}N+I}l>$ zWfyRv^%>fa3H8sJO%g7eIPmaG*(e28J%ley{M=G#PxT9P+Y~{eE0fUFDxcUFCpl(5 zFNbhCt*S#foXoOo{;*u7nz*O;|BDcCYc?~E|0z|UfE4rqd}<(k_bX@4&; z$pe!~6VL%ScztSmzVF1G$2KMR@0fu|o*|8cv9EHAh8NT>XpFi|^_>_WMN&*+q z)XB#ou{kyY!Uug}Gzo-)(H%Q9u;GwX??0G&MNKb2SC9Y!$FNPG7atvZucKS>_)z}Q zxVS&?6k4%HNd2QIo-Y*0;@K|)b>{Sb!lrzpl;`))yFmTIZfhcfw8 z(lB;m-9}s&^a&URq{6xIk^pe@+l;Tq8Q?C5pcLAE18HQd<_m1Q-=BX-_CrL>x4s3g z+t9N{=%@~(1~!W-S65`>Hp(Bx0Ya9{NSH5~(THd9H~PJCFXU=w#0BXWnXI&br&!*l zU#!X$V>fvN?lOPyapl=S7-@!jeVAXzLZi2SWi0eadvlIl@7rGhy;^dT$cebKokU>_ zO7Q*dN@k+UvxG9;cY72sdD-$^0ggX#rl9**D%lrHai>p3H`{=YJgSMsAJ5r)5>KO% zgPIW4@TGovM_D_lmzsnqiF_1G?D&d-uiiZ`Kn$%RtjS7}#1yHoz+7{-Y{@Ak?aQE~ z`)PNd0B&&ReFN8Eo|~3u`g-y;l4B0ahZ-*nGS!;iEUR0fsSZ00+Fyv1DLI@8HZm|Y z%)PC$vU>7wZS2e7^2f6L5%H3z(ao}|p7~cuDm?Uld=9m7l1xxmZ-8z zyy5@J@V8Hd1{b<%u~+j^rk9npsO;dZ_*mGd<=`S~pf$1f!tYP5dCa0b<}OSVaUMS1@MvahQQ*guCk1%JCJkc-UJ8eWtFuW-USa_gyaS2*Rv+sH8uXWm0D(y_}&2xp%FQ8rZpz&{rz1zRMNvAKGn!i6~-U&cdfMi zcFchM?VnCeS~NGjjcf^y#VBcoA;j9OxH++1s~4_HBEKM5=vvOlKmEJx4vC0rBQHrb z;6?0$`dB~iTP%`LTH7Cq8lDEw>Bui3DCsIbzceNOpl=}y@Hs9*eelV zKfaGYBK)^UG?q>U;+e^nrQl3}9)#wFe(M(vNLK818*fIB+!p4=qY?^Kzg(QL_Y~Ir zuK1mAHL%W`-|}WS;y0ikUvr; zqI~H6hFyTfF9W>tXrIEAge`#zx#}EIH?^0%{FM$bvj=^5?-v23UT%y~>g$H)j}Vs5 zy-q6B&fzyesN!!BeVFBz_c{8^7!iIt5&rJxpUjFc)$<<@ez>^~q)Dx1I_DZ^U-vpF zd1gPOB2r25b!Mi_q73`XTq=F>bLi`}vh~WZ#!v%}%pR+Om(46nYfs=#@jq#2UjO}= zKf%6F!<-F5G#p+#9!#4K!Yh1U@v7%KvNY9c4+egc%@9E z9~T}q=Y^IEdWO}|1ESG>y!rhQHXMXP)F=5Tb@Uk2js^5T4v3&`hS~^P4^}% zxR?Sv=&$GO1QSs~!fB3Q6G$hjml1CO)Tozz(*&EkhSUiRPGJrpFI)n=6%ZiltQBQW z`3OF|jP3K*SyKW|{L*NUaQfn)^46zW33~fGJgr6UKdN-6{U8BU2;&oNQU&&DN?DL8NR{-c#SdflrnnZ`QBI z`(7T1Ku9u3ELvn$m4A2H4qJN~Z1JdPqi*g)t$lI#L|w2kmsz?m{de!utMA|!umZ4Z z5UEjW8sm$tT}()|&2*_1G-FhzuThFM)Nhq~sEP5+>s$XeY1#atVaD70OE1;dhvdNe z_x{H1E%s%wJj@#s&3@nfNk+&*w~#K+-o6ol7>7?#GEMiT`YhlSXOQyeC| zyJA_7g6BJZrrkJ4^c^hRwdwy*Ml8s%o;@9ztVnUQy2(gN0HB1?Yh}9*;_c(pU+}O~ zno5j{pc%i2!8-$TPLf?obTRgR{tI1JA0?0hyTk1h0dkhgTS~4O*Xev2>;|S)qly^r z6?67)mRXhXTu99E(fvG_dlvfhQ{Opq(4+WYRV>`z9GMBs>?O%A@f(XM_wj2))Goav zSm6`5R`FC6Jn$)27q_o19##!1dV>9vj^Q>NUaIOlM%gxFV1#R(!?<*{U(x;b+u~z1G+&kiL^5V4 ze{PtnSV}SPTO~((OFb>OMSeqk`Ybs0@n*mT2lg}6_}B3xODO@m^(&}1*e+IrVazGS z&dzIamaStMq1*aa)~1DP{?B8XfQk4j{QMZ>=Fsf5==T98F_N7yU3(oPlz9AQA8j}X z>A}}Qf&c_H+UmEHlNuTJNVhLkNf7w;xH|aRm5^|=4kgC3z z8SP?162^BU;_qTCvGlFw{sMD`&4MD2>ZxWJrM7Q4>zU2`!Xby)k{Wwl&qV_CB4FN(^y8fwIiX9x*}LVyv*husSq^T=G$P^5k~yGr8t!3RHSrKZp0GHwCwD z@s#>x($yhg{Z%D>&Jg1aZJfQwlU~QwIdRbCo=|cdlP*>e@=QcojSNEiNsHkV)GsZm zc+E5R6Xbn29sB`9?Y}kiqQ#kEGgk&a@isGSrrLF^~pfrbd4kir|qQCZXJJqkhHoHQUeQWpa7ua5Vzr9H#zF;E~M)_Tr z=?$^7eIiYP!~sbI32(F~!-+QVy1DlHWtrF$?+P&l9&FT0`r_05Nj zz+RvwFD?5$!TYSA_1X5;StoO>Ax*~+Ncj$(ug%m;*#YP)=})b7pM>TXu6Fx$R=W{* z85_xVOka~z0lYJKlZ6H(l~%ZZPSl_ixbMRhdR=aPLGjv@{kK}*|111yspms z9LH#|(5T+o-S>jMEuS;wI{pQC(rP-6A5C*NEaI@&j6U^7xlL4zvPP}9nAZ|zKPfgt zJ7H+`F)r*fE1@GWM^~SDJDD)fu`C|1gjC(b|56CeV-`=;wMnDrZeP3NE2~#Og@a5c zJ>+^=C0|rfnLT>%Pxjak^A~G>_{%rqWPMW|tCrik`~o)}u24%b`)pvwrF;*1ML?*s zFjr%`v?~%3ye}*DKTtsU$Z)$l;Kacv~;y&duU-mzj6maiv99&Z~_ z_nTyu4oIEBeF@^C(>$H&-KFapGjP+?T!yZaW^)7>AJ47iWZ#|aeTQxOXgk%J(k8dm zC`AQZ^j+K>VU7l=wYRc=a^3Z$K_yiDLiJ`0zc)=!Vi9E+xaib5yxIC$bYqHr%V~oaz2)!S&XUM~U{KWd zrFnUYS_C%TV?zb*f5A>-fNEe5fp6PULCYSF$Vm>v{zwvn!Sr zlCiJ=^2T;H>Pt&4b2XgVJcx& zAOHDaVFYfV1S)(WcW46^ZL1tufbHN6>iVo*t_-+5O6gRwuW_t54k%#K_F~7!J!1#8 z(YuKsH1KEvs>@}}1Jzm;%!KT-IZ0|8*AGH8p=cfpzUJ_nD>YQyY%+GgV>Gy|wO#JN z$cLgq%!*})Dkzqp2=z{=z!D)nE7+aZ_A6&S7x^=x?p_+U-c0GhZx5L8Rx{6l=?+8w}r42?A;9v;5{V8=QJ2Yn=8(b-Eitu;JociuczW>W_l=$k}JTNoFP-2uV&t;QW)^xZYp6%uQcL8h9%D zb^y1&^5anisKY7dg^|v=%2zgCA~L5vIV#gd#*ut;{!M^(G8{YK%Cf{4D;s}F0D8-- zeXP{7RC(*;*G5eUAp+qvv)TQWdth*yo~#GFipiPox4*$8%uqV$wSz^aE8!r|a}+AA zU%aERw<&d(F(w{OH~Q})CI|{c52vw>E6-E~lzIczAzG0kiYp605Kvu9s3?6qI3hzm zqaJaH!I6ZGJUF+zx4%CDV{1KM1h@^9**1JJ#D=giT2cBdn$ z8(PUa`faQ^r4;j@W<-jw`m5_tB%P?GV{pt5mt){5;|grOxzFez8JGtS^qxJy07er_ z4!yOQqR(afmGH-*->TJx@>|;?9v6T#Xc619J3s9gL$0Da%}6Fsx!BtWY7CMJFh#p_ zLglmHoL~5HP)fr{j_k6{p7+b^qIAKPwya-x8YNmr=F~^n5g->^$B5s;n_}iL^XG7B z82E+=E@%HE%ElYq(&*Ruh?p70L9>&=Ye4x zzfS~7CP~3uwO^Fx7i4U|vo*4l_{F<wc%RU{yuIsa43-}Xb^^^BsYXIO zS!H3=#-NRjjog2A!H1rLt4Ya_1@G@4(@uIBQkjmM=HAtt&G4oH3q%oA*!=@@8aw>Xkn)Ut*A4tK8#CyRsaW+dkl1D}U|i zUYi{*Z_+G-?SCfdnAw<6i3ZU%}3r zZ1^P>6Fk=I({Fdoozql?Eun=V@-$giQ}!qQj;6-MSB?u5^IGAsJ-Do#i}50RO~&>~ z&2htneu3rP0&4zBnRFKX9#<#R$+xZ-YyJ0lua-zVPWgC92HZ3`Hm3$>J|w;RhC$nt zI}OEBjrELkSHCpkh)!fkC?;`zl8~o}ju=iJuwZL9(+^@30Bto6h4c%atCih>Ezz4; z`A&M&77Od8rAS>Rojz5&{SJcQC@XQo|HK*OAN|c^tKRGeZoxU{O$_41#) zo`I6)UEiJdcNN$3`p7mv&C+lp2TQ)pe{!0BPKoS=BqK2RkIr|TCY$fKs-k%)Us&ND zCvo2&c}Z70oMz(T?hWx_WQyq``vCsh(&!RhM{xNQd^uFuPnE`~5qE~TK|a?%VAvRW zHMcD2E?5H%y570vA&k(#*~@<;eqOK+1aUU@2jQ3DKtUC=wA!=cXl zI5PWts6qRMq!y16MDY6NmlIW(RPUF9Q1CP6asKJ4*JlIlg{1>&HNj+H?WBLr;FRvK zW4bwhlh2htFOdTa!I4x`+HK-cvHDmdip$#cp@2TV*_rvaf6w^zGTwfaa{SHW=E=&q zz3lyR9_7Or*-vCR&X|;no98=*)er1E72hvWk2B<~=H)KVC?mSf?R=%^$t9f1tD@-B zyL-F2D`aRocHP}y&7r5-y-(U9zUjEf8A~hgZdZ$kdx?V@WD65dklA7)#9mpL%K}HY zON}G|h}XV_|7LbHxH?bO#>GTf$p_9s3^jkr%Jy8~3ioaQJaA9wHjn;oBOLX$`#h#D zSolwH?8(QJD;$)jMv>4Q_mS&z3zC*duq4bwJr+~K50Jn-U>-GAg{0>t^@;HFrc`8z zy|f-*qn~4cE~t}YtP%-bN+V-#5&j&{d2RG~KmKZUPxv78!CPB~WXfq^+6t!C4^j5p z{fxnXAj-;jG)U3oMas}H9o7%3{C7qr7i3}Wtni9$Gc2SRkyi9Vtxq91LEKR zgwj1U2c-t+yQG9&6kLB{NpQmjS7mh{W8C7i*nQIU6{paYpobai6nzjItcVf!AfAf z;wiO(x;tBRQJ=9qwPrR5iv&N1X(2LsZzA4X=>V99sT>3BYpKg=*35}ut?a?(lR7*q zwjwkeF%JN@y_{w94Ug7y8VGyJl7yY0W#TU@P$W1xW8P`8_r)AAs$1B$B0B@-KW^Xa zeEuVG@9BWP6YPv@2cJ$}Ptw zo1*&neeZgGOmC5*HF#@#C?UC&dYy7~mnn#~K zQ^+$mQNOvz(^=wM+0fq_Ltrs98P2``Z&Kq(8^sJ1OA(+DQ`**djoK=(x<{6ZD?TiQ zZZS!JULR^EyvXOWb=^<2sI+;6-v9x4V|@5`RY;{to7l*(RQlZU_4>x;Bbhr{r2CIV z*(1WkXNx9UFggi9&SD4k_cQ_yA_9k#P8w&b0@^z-Dxyhqf`3!xx z)=q#}fv&bK0f36X=N9rDb`O%cH^2J=CID1kAJz#tUZ1LvoU?NP;~B0YNaplM~}NlBNS zPUXvpzwcTe}|oVvI1*BF-2qhOR& z+YT{qlsNUq^2qZb^4gj;$Mf$utC!?(w{UMV9_|i#ue9k%-bwzaS@83Eu zK0Xsc!46j^L@njVmwGQJTo*5n>~wiDy>j_=3^dJ|M=NFXRSmumuHoL~HUwBKh;pw8 zwEVLV#r+%Uw%`!4jp1Wu!nI-GXz2=2=g41a{`MjENCN|dnW0LCcJKt#GvbpyFZ^%R zExpbIOUO&i3rRC#5G$b@*dq$jo8_B4DXvR2_7ZgV|5Xp)?|x0Nmx;!JfYF~%SIYyy zLByLp&AGWVB~0NpP&OkTwX$QQyZNEd&pBCs3^)wnV(-_vc zr_1^l6j9he9!l0`k$`7@|6XM2ncZ^tz-7YYe$TI$+RGiy)Cvgy8|ORkBGlliu6Z zg?+Ay-79yL-pvjs{7J;+7gN~xURHFCh>ut{8MW5)f9L2p1m8-JP z8hLXt*)yExQLn$uxE1i6-$Kz`4i&B4gjC+(YO>+8fOGJ(s}hujX(i&V$XM4j{5*uc#I=VHJ6=7&}) zIriu|iQ|LMp~SX_;)Co%8)lZ0zsB->8g3Wh9Sl`!md>k#UOleClg99Bg5(xiFz*VupX8PcRJ}h6@|YB?xA) zMDCN59$>o}6B6CzibsLQ^q6z`t(wCJ%yUIaiCsk~&q_K6rt3aq_xyJA-Uqdh)DaOx zs)LRFP1-&dN6!!P4Q0@M5xS?xY!)L@Dc^fj3xQ90%kBJV>{#oJ@fkDOdbdXVz{>-p zH|S|v8C2Tye23jOi5UiIkVcS{kY?x{TDrR% zq(hqb`2Ih^+%wlb=j^@qTE9(6>GDS{=-EBn*ZDA_h*OMDGDoe&bNivhl@Jf&C*i+J z5CN`U3rwV@jQ5RlEd+}NjD1oI0vxLRNuMz7)TK(vbKJ+4(wSxjwQ@UsC>lEU4ztym zQTtjCu5;q=JbvJX07d<@{+k-=cZDqZKW);*)niIrTK$zCvopkpo)w*fLqG3Ud@prw zb#628*Qr|ud_xj*HG>Y-NA)2a#Ji2e)&(|@QtGAbcAIFzAHY8ZA4-_1_E{t0LlcC? z$({|DR&IxJG0xKr$V?KI(+y7sJpnQ zEMD1v)0)hy`uMqhq4Lb>YN7e+&Hl^y2Cw0XA(04|wq`lwi+hQTghAG_*d@HY{~#1n z?%0s9ViL3dIehx(rUanuC{_Tl1yI2ox(VjLLeDg@+-#VvPhu$`d}oK@o_@SwGzsTh z;d=dWFWyNw=+6w;^)4!HWi;z%o$6{$vt6tCdiEqRmc{?!sZ=aDRputlX}bt zI9DmEdF?_1Itx**Nu9f3p=V?BdgY`Gkc&N!O$h&B$(8{5O^4v|apx-dPQM@7Zr@81 zT4S9pP!PUWcoZ%w*#Zsb&MQpSR3AR7J~4x7VPNsRUwAXw z@sVBmh1k;syw<6aJikC!pbvpM+}&mh{p<|wl?e|w0{b1=#13y4Abj?2A<&PwjUjJr zzI(FS@Su${`hRv{l2M(}3+j`xU#1+qh@G&R4SvD>oT%omW(LZ&4un-!5k(hhXqL0y z)no1oX8(2pSQ}a-Bc;cMN4#u_`&RO*QnZrx#-#3$&iuq`(SVa*UymKb;)~^pCx9m7 zBSwz7`zsqe$^J(T8Ybua8crf^E=hi+$-#EW{Bm>&yqoq&?Kz)(V6;qJoPS??9Vhne z;&+p_0c{$H_MiBee%NC`I+`t+Sd?D`1f*VXF)E_MH__J1zi9 zZo+)@LCbvR-0Q2&2Z{WSa03=P{6-mmoL$PkqHZE6;icn@BJ#&iLUp&fX9pgJY#aO^ z2Gboi2N7eo6X?21c9%cRv9buW^HGoNZ4E8HqIE6wvNNT&}N@O%?{!n3anP?2>R3p><*ZEtHj~Ju`UVrrQ-zM%J>`7VtG9O;uai z63VLNx$zDMJ>N#}(ZwNzzM z7XO|~7=<%EmnE`VV!~u154;3aBwa|?$Y6&pyISL-Rk0`d5P5>_=WM2x{@P;$R0V6E zo17^MN`CHpx1Q}4Q*?4%d5=Syk}A6py!NVl?V;wVtEZ;{AJPyS7Cp(q<(}#_mPUcb^yfistw^^6ZopGEE}?o!lp5$7{aWqRHfe z-@SMZiDzGK9%FWvIgeOZfM1*zy*qHtr`iC;%ioZ7>K%f4zw&(Z8JJd3Rjo*ov(>bs zc*SXFYeI=?gvj7_Ix`rVB8M|z+4*>EKVPq2#EyhrYqyOl;G4?d(N(LxZ)&#((2?&TiznFok~#DgO%~L9BM{RZT>X|Lg`}U;(cqsK2}d% zw&{tw50=QT+y0lcC6E3!gbW@($CtD^9!b%aFjjv`pqSXcfQeM^Iu#t}VCQ&>yp+2? zoCTwA5-s9pu#iqu<;^!;T@OaT3MT#zQ_ZSZIP7BafY$sTJXwU;yDQ8jl{OLPO3i&9 zxFsnW$-V7Sr%l0D7vd*hF8JACc?IDVIO?T7&en3F{K+9xaK8%W zEfslt)IE6A6>qq*(^}VDesYe?kz+)~of_{THo36$;|?B2Q9NRMh3R|rdzmQVhlb5< z^CeyFV2T2DE<-10w*ZHNftjVeuk3knB0*NFi0edvBE>nu=)r_}ZGB_OcWJhSVx>CC z-VG~iBSeoPm)f$J^KKS_M${WY?37BtQa*S#+T1%e=$n=R*B|KNxHUCFb4phZr1gPL zV>#26)8*^~*8UYIqJ}6wVs0}wH*0QUd#ny?kQY8r%`eAd&2*8=xtsij>Q=tx+dd{x z#HM}h%DO66^Pt>i4#G!8H_;%!LaWhK*?$hm3Y#Y`|D{3jEH47q+Kicx&w`~pQe;|i)g zO<#8RCqoFRXu#ONfH0=_zlGvi z@ss$qOoq`7e;)@A?@^lK(q(_RA62!_&EAGJ(`blQsca-Vtoy9Sf@9Ofk;;T+P~ z{@3NKeBTRiw(7!VEjN3A4zwBDG5Q z0e#K`D5KK~CxpHHNBc%r8}HTTa#xnxr+JM&fjS7kUu@&(JYjCvR03v-=|(=bGDt|K z00AqY`B_ONlXKLv#XfR4yjrSq7rt$dM++;3>E%Ok!FZi|EW`u{&tE&GN6jbtsAdQE z9=N|TE0~e)5Ho3iLC9*%MC7kA`L^ zS<4Rfw}~$FmM`7W_m%hFWmm>k=7zd!bwzD5RC-R;P=E!kcE!p1NRW5uz*T!9kxG%Y z6yM*kGs_ZAj=16}rfGz{P@rtB^zD*f2)#9&B{k-Zqo&OStoiCLiOe8fE=Lb?ds)DK z>4t|FIUN<2IEgAL6x1mUOrt}7Z~7LA<7_mP@qFT`<8s>i{1In_E*In`uL}yZK>8u# zii-zph_D)_TUScJhdP|s_b|+t_wuy!7@G-+CM=JY;5yl&@djx`N;{*AHGgT5LJaET z!AOScB!V^5nDbvA)8xj1+!x&0-3Kx+ttf?#X^s-~tCECPGRzxfV9X-ZNpeqTlpHAw3hCSY<4SN&6 zimq4AVn6cu0C&F%y}$U&_KMS4aPKPfuRI!KL|Gb-`y53Mqc5ZS=MXf`#rC+CR~&!% zi*?NO&^F?>*<8lBp~auLyHox~75^I}1X)5a`IN$eOLNd-2S=}e?BhIW-Z=50?EEy!M_7RPZnO=ch8*Xg8VYKRU zBexA-)ZNj?X;QTma2JaV5-RNx;HFDXB{;c$Z(3vUgOtHa!*3bskN75q!_lQwkxWB> zzPN*#BsU@1q17m&BaH7(<8@?M zruSXWZa$cb&24PUI6)beV%ZgkXL#Jtw9xhtKPd273(DCNX@EVLW{6mN|S{ zd_Q^63}!fPXQQkIYORF*@I!SOuegw9;W&CrYAnF@=&u!<7M|BgV+isPIU zEF4)hxev(;g{kMm-9AV4lxiD6()P>bKQ{`S1vGeB1U+Su0pb>F2*@l|u+AgF&iQfs za5C-JH{!Zmh{CA6>=-@%?TVK}XMb7gQr8DCBlj+c3(`O%rvO1hFKdr*G^{wegX|JQ z$Ld^w7*RM#Ea|!;?oIh3k4ZOBCj4v83gdqctXS%HFTS9PI!RJKwpjgPbz12Fh&YHz zKl42N`LhOg%mVrqhoc-kMq-=+Q?&Yw()0QG?Bap`&7PH>s*}T$eWGzWmosg-S%D@1`$5AXN`s!qX(Q&5>)iTC=y;7$7M=qYK`xz{l5IYLiNVw zR3y(OZSBKxJnyJX)bCuA0GiD2L!BqDCCIc~4239Zv|$5a6uw-Z;s~ZXX>{hAfQQng zt99}=Z(H!==HbrtV^pWe-Ow&D5toEx%8t0eq>Xy)(Ioo_p_%>0VF7p%9G4Ld5R`^G z^O50IVySfn4N`$h1{*0Le2RsSU+5+XVN?Iuy^@S8i=Wo+C_;>zpJGe>a>j?ex^A1Hw~((htthgao8rXTN?g6yq%SI`={M7?RoakCP@oT z9gF)vGyFjgiAoVr*uK$U!uR<4t<>l}Ab2Ok5OhYET|Du1oIx4LEKk)Rn=$wCbZN3k zv(yY%yd?}=a<=tE-?O;aAG?5Us{F;%@%BinRcLPnD z+~JJ@w~AgY|ptJ~J?)zn!LvfI;H3)w%-_#_I4V7h{#`TISQO9(Gu>b|68JXPtM(0njq5!$@ zi`WqTcg+fqciTrLt?=MEJ~DuDe0bY%I~MhS1M%<1K=*4TWX4d$2X5~vdsdloDVu)(e*yHT3iZ;#Cz#MUHi zF?PwV<|d^{esU|c9x0oAZ$cWrsa5;22njnl*L}~2JB<8wA9w5!c(_G{6KU+2+Xt;S zEHwEkeW$1!G%Zc$sWy$;K>8|qtT(?e93k}elfVy8@&M0UpM?>+zBlPkB;nr^KM~Z> z#6Vox+$b|F&3~$|5BTFj)54)M?4x#?yQBOP@<5n^9VbsoLV^83V=z;|rHvV<1}pcp zTy=i*nsFAiTe%Nl%O|x#@O$U&-Qj>UU zsl8-rR)7FBkO6DZ?cPWrC7I2*s0W8=HCxy+U_CY_f$M0Oyns@O`+2O^I|tM4a~pcUi%MI6DUHT^$Q-t&8{Fow&KSIfjd&xz_KTfGTUu4qkikJ z;lcZUBx*_uO@e6`Dh7<(aKge`phj%V8K};lMGpv}lZ(&nVR`t|#p`L=aje)#8=3^0 z#?bD6V{KglQ2?Q3tdFA~8c9h{^`~k?S~s;2s}dV^<}ou*;c;TfVYq)8VD-NWMK4_f ze|~5yoo*o;*xA8Hdb(R}-@eKUD+)Sce?FOw@+B=7uaGegQsA@D0ZxxhFFfpRyt>^O zQEOtzlQ)o|9R0C^(6PNC0?2d3`Q8=0fFHU#ztnS_w;(oau(Ppr11L+BfLg23AX;-f zOcyCh$V8-qLy)K0V0faYFC0NF##;{Mtf)OqTDg`LP{ousy-5mr{wZmyCYP4r{>gQs zY2XTIg~SGH6NXG(W9(1ly`hcRx|y@3RFB7g214`Szx}1oR`UROs8MM9m`Nd#JZ!SK zcAakKJbDjDa}qf?2GHJpyqoanbHqd5)=dU=z@BpPe1lcRUrP1&;KekjldIx@KIru2 zadLGzV{XFgn{`c++7d+)-SS=QSaBx4t1SY>pTza9qDU0R$VL;$5z-@7HJ8`MF~cHq z8x7Fd1IDBQbWLL1< zcx%x5djOErcp0vG5U@?}mvV4+Us31$mjLCd_sK#^6GIN7;gJehSPY~`#x9yLA<&#QluFx-L*bTG|zrqE# zu<8Co4QGz>Kykx;zR$3jp|xBBGev0OBRbGpm(L)y^cm9 zxr&md=@m~O!keDH0zi^#^xUH)V|x3;<4jH6Vg(j7o$iBOom#)Y0W7u=sd>ZQiI=+z zGcULx>ovYaxP?##h}k?R1?qlZQ08|93_7gMPV{K=#Fxxn5&&0&Nq3~+tl;HLJwDphFU+{zKqZEMM%Z0!B(uGa8hYdO!Q)8==1K8 zo2O_<5fHg*nAnJ*K32ySzfz>Hvgs)g_k;TsjQ%TDv*Q6J^118jarQ=DyaLP zr^xAI-);KKd0%+(5CtIRBYeXPSh6*cFTLGYOSaT929i4ju!z@Iej!fAz=jfR|DDYofqMd z2*s)+srwf2dr*1%X6{4YCmQBUptrnoNZSlB6%ns&N5k6a#Wa}qv4Iyg5_8s7|JTRy zmG?0u89~vLe}{SALYOIfMo?qNM=Sbs787^?Bs360z4x^NGr1o{x2=Nh$A{u=rxJFs zIvAe@qlY&NHy8J9Dl3a54S8CL`GQRph1BA2OPq3s5X^D?+8h5-AHVZ(zm_+3~nGzh6DG@|_;9sTNaQDh1sp~=wN^uBt#}{S_pVszU51yVanwfEm>5N6|2R%M- zfRCw}154CcdE_y&{I;vpRvcoHHcmq=2uupxi$e&Pq@_*HzHU6Ffw|TX{qiCa_cNK< z183ewU;K9t8V|h1o4X0hL?lGbrqT;jsapg}Odeg8@RIriG5_lt9#D?{DdQuY+9Jjz!!34i}2zRKpx zVcAZKmA#BOAFA2<4RMl%uyCJ{X|DQvvOM==l~>!nXP4eQ{aAB%Y3iRE^zEhYZtJs` z=99V)=$qE};}wY?C)Ah6Bs&STe5OD%H7xM~=X~ye(-3|x(b924{f}yg`9Uj`oIgP~ zRJTimaOeO=tfPOQg9iaBGGTO)i+=p^RziM<*rgxHJp-H=l;SJHA}N5`RoVU)C2ZX$ z8E#$Z{>OE-;cnZ{3rU(qHC2e82&&GOXs6%x35k|G(+KFCh8|k-M*X?e)M$|0km_5# zhnfY-&}4r!xY7=~{Tp@=NX#V$5k}kjW;B_b<#}fiD+%28thgN>Y=S4agsLEPbamXi zQ%&;7U-du{+{dKn$IMZLSz2-FqnW1f*hyr6f4Hd=evNmO{_-rPR9ZX$Trdx}1Dw68 za|oi^s9q0TW?Qh|s1xnbgU3n!@@b#{zk{-|g|U2e>n zBe$-)`dYUl0HjI?^vcQrO>?M#1vv&2uwM!ZxZD6$wH8=Zn-KW~Fip1983QD(qv&%f zEatE+Vx71TLQpOI<>cnWZ{b%>+<<_5r{p#vaq>q8{!!)5EIKii;9&Z@*T}bzIAS=g z@^&uHYBrwp#(y7r3SV5AWgCkVp-P>*BKsjIq?QmY!lsa=t74gh5mS-+4J62H^cMl5 z@@>Frm}kION~?~FCwa3IjD8}><-d}2tWS#C#(k&WO-sYE2f zA=fY8UTsmM3$7KdqwDl%*+rIXzz_ApKZ9- z{oWH=?~Aa=eGAC}ETrXJ8LL}FrB1%yT9jlkohoCj<8{g`dB?x*DGu1PB*8vo#IG;u z*jR<~@ew@5yn?a_*RJ&A2eATiFSnoegB?*C;DNAj5J$X%|4=NEJ_v;+q*iv64f-pA zlf45EmZp|FHE3|$@{J%#H6H}NB3KaLvl=35Kc|YNJBsi}YQ;C?-jJ99CMJC=~HN>8ME^u@Yi*VUoa$Yxu^Zv;d_xg(dF{ z;56buif?5aLPWh#kiwQE5j~NkB{95~Xt)5cQa_Je#%xMW!g;-q{ zfGq`hQuZ7({$Ajrzt#09N*jeDWn$1EjpLQ07|u~uNpsJl=gIn+=J4c8J)#&;6b?62 z#}vilG~x21pG9bV0mslbLa#oA4D3)fga8W4kK;SI%x$(72^y$9y(#&J?s`p7b@hR? z8DWk}*1OvS2(rwNhk$iJHTnK-3sM6u<($e?BW)y12qh($H6&$(PI`F%d>@l@$UR^{ z3h2j}(d7jLo?gHwA+#T*OwktpIHctF(9ob!x9y&nxS4784uZg>&hbhMO33PYpz^(H8*Aj-|FI+S(v?5%1Mmhx?s-q@ z+-l{T0d)O9 z-&#KQZf3D4xhoNG?mV4dkn8}Z3EID+wus9AAZ3MPb2?>M;S+xr`jB=TAmX1~%|Ur< zkn@gHgEOyp?W8Ew8$M)91zMeHy$~&}pEoQJnoi&OiX%{#r``&TJEFTq|6JT}9RxTW z{-}TEML2g}TAv6;o*HD|DEu-XyuWHPu2^2lTVgTN9HWaGw$eIL^i@BhAzkwwwN^47 zBdJ&Bo-Jwp#Ut8WKc10fB(JKQc%bA{xZNP0axB7u;EDX#zhwWZ7P0fF+*vcltkDSV z!1D(h&I5;4;qtb>k(NClY42lj{A#?Mj9Al&f*wy+wM=hIXQ$pgkD{)$Sa$#S#tqNf zuIq433_CWalv8B%&w8p=%UBh0Si8rYG|B0gtIya$5A-gEl_(zTr>1;As0 zuYZ^>NgUPUUT{yMZd+Xpp(xGJUWUH8fuCfaE}@q{Y&KCsK={r36F8nvm$DV)qET&$ zd0B%x7(4VXb2l-%FCO;1S1-ak#`dNNPHf7vGSJP?gq&KaR%SCds0tUM^L?ygOJo#_|Lx|Hz4K_A`C&`VVhgctoom$1gTVI#@~_k6C7J9s=-Bzxg<#O@(gQO>HMrF#j_`SGU91rDT-?gLA|{G zg5KU3MUU(r-rv=|956qSj(o^kXLrFWqLqubLa86CF8rp4j?@>&$}%05{dTW`?1=E| zJ-mu~>E3%iV!r`$@)+cT@d;aaU*a}&dBusf$TIL|)hKJ;U#PbV@7zl)c^Jjt>#&yP zSDmOTxX-_E%Tu-|yT&wX&;yO+u)c%0jXoUQEnvO|7H!bsvdL!HKyZg^(zBbu#3n_1T5nrd4>t|g<8^K_GlI~iN%Y4P#$X;8bdR}@(*4qn)_ zhCn3GQsvoEHTbO^Xl#0hxCkUJx3no_af}$De4q7>UdK38NNFP%D>zlQ3S*PYqK)K^ zdXY_$F4_A4qQ?IM$clVg7APoD08>J~>l^7Xg$qn(f#*hy=YrTc^ZA6ErJX)S^ZZH< zv}hB7(R{)i!N{GX#6mK=xk-NEa-c-IRj2+U(iTjZ%)Yet+_zmab1fK_oPEDww-EJH?kOXkH!po+0Oo#){HXTQXlg4aI{j*L^K10> zQ)H5H29o%LZMn+?BqC*e1PFL{Rg!8N&V}g#uNrpo*F_%!JyiLe#KUf+?LHY}KVk`g zYH9fD7n^j8ah0aZqo z=B`@BGbY>1IzJb&(ZKFX)Z-*L+g#+ogGskCgN3jV`O4Aka}tjM)1IlfRGgrB)x?l; z6kbS~V(S`aH;u6dEG*@MffkE;mc74MCR)??I0QH!rVlhM-c2#g5x-#EGx?qjf5J_y zsT9=yqT*-(DtppCC-Cd(lzMX*w*sCOZbswpilJZbPou!FPI5uHA(&b zy?I9Zxt@{G`&{o$?&AdMcF*q1%kBFH1sbAMpFWPVjsv;N9grLE)4c~HTBkH2c;VtY z5e;xvtpbq5wD((|FZP)3VTv#Ia5J0pX@;U!Bx#_=19?FYr|!$0IvuE?{cN@Rcy3$B zvUuSI(ix>=Fye{L6MACk@RA6X0TeDSVsTHZXc zsxt++)%_PZNbb*4z4d-^E+K6nfy7eY|JUi`S}o#X+JcC35cpurxQU9>mJOq3VjQVq zEH8b2Tl{zfj0;#q-!IL6>&~yG851YfCoB!qesl5871tPdub&?c&J!MsOJ8E3()1tW z|4vnZjaB-{_kuAID@H{Y!(|0vS`Mx%gfgfQi#tMR8L1P0Z?JUx4A=fJ( z0t||K6uwGQ?@&MQ6zt&T$y^v*mBf7Tj=?M!!A(VzMs0-Tm#-7cmbtj1BY1vMn-4dK zKh0zQGQJm(mv$NqjA+7p z1Z+ESW?Dy|;d0>44Yb~+w5JDsO6QT>>(Z+?U`3o(d17|0y=lFe9l0`^&c6WR1;ILo z7jb>--AtQV8$wN+s+EleSC2!OF?+t&Rc55CZSFSna|M!zgWzpV31sSI6m{=wI4|^z; zO3pYdQf7}1wzfhiWn}nhIBbopO(GFA_Km)`P>H*E=5nKu#8d*kcwH~PvlOlJ zh^Ukp@0|UO)5!ay)>C9*h#)s^ZeoLRV%5aG{r{R3EEq8%i&8&qwMbr$_{Wpdla*fDS<{~Vu{3F+7?sOsOO3~i*8?W{)I!2J zbz~z}$94`{!_jwjaCNwC>r$BuUbL9g6)Qz7mQo37yGu6e*HgM#9ySM3U;{}wX)m<^AE z9~D5=0$i0VycHqhNp~Q4r_hx9UMlFw>Df(DhRwSak0fLaxbG23Na`@ZRKP_30+_Hw zAzD#UW9NLvSY8Cy(R$B*t=tW@Ij>j0jWRJCW>IwmQiI&mM7=<}kSfrfSs zpm&7=s=mS?(pLcf$2^VB`4KOT`a7v^b4+w`=u3hU7h7<&-Ez0h+=QN=?(F?N^VD&k z7s6HgFb}YJ0azw$97@zp)U5proFTW0B|Lr8N4PWmX~u;6(^B%s^#3ZZ+8-)SA8!Hl zS=XIMb+GlC>3x}rK&eQ5&^a6K-))r-9)9H0;eE_gF9vtJY4cUh{2ctv;smJt?Zami zUb(SkqBC_24;m^`ohWzm{K)Za?cfdB1bEvX*ncD@?sJZwC;;rXCn^}qBJP{;=elQU znRRW*X=YF`Q`D3j*@*Yz^3M0z*|I1%h7&8tkQ!MCl#jA;Sww80Fg`s|gyZlc{If?i zH!)te-({y|MIg24j*I7ByCLQ~Hv_}Gy8*6yq?|h9yBEpgjW>vc*!Jn4*S#$oyDpDs z6{`PFX7!F!B`4osx!=NrPoLLF{(3qwO)VD>*q@5|kKyJ-M6~chYc6ucej@umb=s@> zWUq1o7$4jXO?x=>^5)B}I|bFri2Yoh9kZ2Dnb96dDR-YW+nBgm)OP4@>9!BI==-;{ zZFcYRGOsOSuCIU(B=&2bF2=q59+G%(3wQ@skyC{$IVz!n$4oSQs+eyU4YjvZ3YgNOXVHTOIL(&{Q?U z5FW%`7jqcH;Lj`71eYW#E*u#yd?l*Rn7f6$T&`9hJkRxVNvwr~=N4Crh*cakFfZxk zDkYzH>4qp?0TI;;)IJaAjUP|H7Sl^q8SrOnhu>gfGT)n7B(yn&Y16`fHCLSI1U(r} z!g(x>jIAhKRvBxD8M_%DdQ+^6R5>`0e$*Xeru@B*F4+wd&VBM)tc0^%cIx{9Qx~zn zuD1xP3eo~{8YLwO*{_PypoMiXDZa2lTSFkYpNR$}+)IOh4}bqjDDl?1wVG#JnuTuf zk5LI4tWs~0if0at0nA>5{sO9yuw?CYl@Q=n2P3B4G3uI)_B zO~k^lLv1P2odek|QiUn-kG`Telc#3)%}b&`suM^$u(3tLp+>^X5faiNiyZnGcD>143HW>m zS|`HIRo@QzJCSqil@8o`m>h1__3CQDVJGiy6GN)-BQLfh+Ae?}&^M(>4!)3pCJKd< z(J7H8wD+a9(14&jehx8}JM#^(j)dww_&`}-tivwX-1ebmXX6r~oU~^{isG(_gR_;{ zP0;0RoJj)!-N;ypUqa4?b;G9z{r*V#p)rJ+5xTyzlOOibN-yG~6?N5&tpe6&l~H?; zKAzT&u4WGQPZA)^;~tQ9}KE({~^zai{+DGs)`e zV0y&>ZlC0R=m9{Pij*^kunU9`JWdur$k&8A0@ME!Wlb7TH`qW&2Qgt4gJp+MuF#|C zb`a7=nXY_tpv>WfR17J3zf1L*U8YSc4J~kKdcF)D*M`p<50p3hZg`uQGc_+#+^){A zJIt<Z@+6HzKYJqk{uD_fJhuW!HK^@c-R|ArKxLzFePs! zXSz*=pU$YC#|dCxr2YcXvXc7MK*QFn8AJP3@dMOlo`Abgo;^gmpAVNjMz5SPAs=~@ z@S$)XOkul*&&`_vpAg(%(BYbEQyrF~S@;bD!P_m&@rt*PfiOccTm#sS)-@oD04d>; z+P&p3D{LHSlOKY7Pb^K(NxwDXj3K@fv;pw4=*$@*G%XfZx-#S%DIpQ;N<3ANwlJ8! zrsLB{O1a}Kf`?g<73sqViW&N#Ynz}#@!J8_9qR89)FU!HcQh3D_oG<%roQ_H2M-q> z^k{y5eqv{+1;`&slR!{_eQIhlIH_#Z!Le1O9*ed{u|dORt_p-d;cvhF#*Wee9wFN? z_?i*#A{(a;GeY)X&>yj~@HbiCNx>!0Fg8Frso&(K|G9AY8ew)Lo-yPqTrxVyv^h(j zukU|JH8rHy4)S`UJAwO@<~z^0orM9mZL6nozQ*uczu3cRm;J@g@IeIg5bmh=YCwIx z(HGK|hjSofun}L&L#S>m%jh2T@;za-x@;McT~zxWy3WVTk#ainP=>9#;}V&3q%=S7 z^@4O)IK7UHHcBK}El7f(=xcdzD4`0KPcZuqyy!KM)K(m^cgv!eFW{&BLw!P}16V2z z;&W4JxUzS-Y9oKpk(}JZJw$(UDyzc)Z6-{Re+y6C^Ms>xjF*-*vAxUVX`fRpI6(e( z{-lCS?6^9sBdu$^`LMis>MIfZxr9JhVMiXt(a~|b5_1F${ANy-G6Ecy75x&%^jWYy zckd2$GmBFg<~JuUV`zlq;az7a5 zC2O$pEGXiky=7{&zrU}8Jj_ft79Pr2qgv4k!qq9{d77rg_&x?AM3!{tfA^bPU!@Ck zPk)((7S=128Kn|L?26#LJQ-h|j;(#~|JT+EWy9(suTcw)#T2B|glh(Bc+ucpr`=aO z)Va;?^nEk?qtbU&@eF_r>-NEwucmHFAyd4dy}fDD7NO1=4CpW|CvC-D1rIIan*Br! zHkDLA#-ycl$o|x*FFFu)`lKUi)gsr|A*nBQVQ3!9|0W?}+Ht*gY|pP$V5S)O6JsqL zCCHKfHe&<#Of@o1U_oxMlrL-i4|;bJ=Hj^+<|cI}I&Zs&rIM3R(40fDCVIITvq3OE z5^Hqb8%fZ+HseU};!6n}T9uq)Mc564v=f`S&l3W=_NA+)Xz0(bk!|Co2d*2w0~zwV z-%0CFs-TB6O)fKDyC$eU1OYCIl_5+HM+@mPPuxJB0SDVo=E?%+G;@!jBvz3nTnLo3 zln##&Hbljbg1S)Gxnj{OyY)-5b9~Za=h+Vv?FR0tPkn8E1g3EK;&pV9t~j}Z=rafp zUm)}0$Z4OLqvmh#TntWy%GPdYk-Nl!=RJf;7n@R%~*P2H!ev2voLzU zZnP%${Zw+|tzS~#OzVZ@ulN%igO5m=Mz(Hd392xbt=mD!Y|0)%^MDLN4DDph%<|ke zdbhnN2rslDbX5HQ*S{pZLA|r_zrz}S(I}0fUBvv(WSJX5MnUh$O|G~W9yb`=8CnW^ z&(A5v97OkPG6F=Pxkx`G5QUHAwf~-67+R=3AZ{0)=)gKUMkq1$ry1r}nvTv*55oIe zPNSRj@Y~ftSH%AN1u3H5ad>WZbMK(=REq{%lhPsax{h{N{>Icd-F2w=yBDv|2c>D; zlfs1f@v=iu3jMHhhqoENRq78pk{Su5B0Pkg+>a8kmxg|+N){tWZRT}^v26*hNz=XC zT&phT(;fiQcNhp@9Nz~6XAH1ss@;ebB4$Y-g1H29+qw#$ zzJOZRLNHrG@Y0no=6;rzDjIuEYv0OUbLdw~A1zpYI{I^#5_Fp~17Yvs8MhqIl>rQ+ zu!X+3I@7Rd2QkJz#y`zU|yE`~(@9*pR?}S)dWHbByWdV$L}gHLFQg zt|0y|$Cn>SB-X+!_kEJDQyG|k@Sw}|Z{r?MZ@B)ga;unQz^EOfwWNfz-Tg0el6n^a z%8g3uaFlhR;U#$Mg%*cD$v!qdYL1x&gez`EqZ=^+{GE#Qd4x>x%*(!DyKTBJ# zScpshJ>hwQ85b5>9(fi^HvZ8b74nA9 zxRC^#S7N%@*Y|I}b8SfJrJysZOXox{u6-axx|hQj+lO&f-o!YSj{ZGb+--CYv($H! zrp**3Yt%T-h~G#I`LcG&o;vvbVw^rdHOYe%0&+}}OHGyP zpSKc8@gj8!D^y3j4@E1-sfnD-&niiD%1IY4d7sZ?wb-V9SU4v%g4T^-(+wnsA6(rc z8_aH%1Rvq|qf<_P?PbaaJ%kWXwnJz>F=7M&fFto)18K4^*5j*>$KF73;PEF_89Jin zh^hAZ2+c4@{5|12uCP4j9G_z_KL)1O2Xr;Tz+!_KAon9Z1feW;{F!oE&}3^|!x?0l zz;YxL(@*$qh(Mc$N=W$lO7s&iFQn3)P>4k&onx)@!maWxk$vOX8ULX_c+CYbq#6&R zpzJ3}VdCL-v)3ZzFA9Eh(SG0DKDZjGYHDiwWWw**V+L=AhLEAdz_}4SKA2~n0^MR; zE>JssEcVPUX}RMWI`x=*GxHeSRVHMte|3u_Vfq&Smv|>iMqEc*OTOvf9}xpubLiU< zbRbnM)z9=-MS(F=glB7A4e#$C_lcMaM94=Ktwk^CfTsJODq;h5>Bfpr(-K_}$QU4p)r!29$=yDm-89~AO3KSS(PZ;-X-6e6c z{}8P-w8J(*e-J8-2Sux@6b)fXRQu2fWdctY-5}elnnez&l#8=yJr~@7KAA@boGW4%78-=;g4DC5ae{M%c=-Y$ojTo zf7<1{h3z(uAZuc;!cqo27WSgQwGl!tu`^m@K{!04|1=C);SqVnY`DU9b@^1MJ-GC zSxy6oIa}l4E)FF6JM9&h>=maT`O zh6Q`=KW#;vTq<~OdeRhTXaxqdb35ecGBTdn(XlktRIyYlUSf&UP=g~oSZE}R^q={V z=Dktw7^LI%-;lDL#&9`Q=BX?+5_~tKE+B;K2ED1lgTQKpZo||{fk6*ASl%zgt2HRi z)hR41DOO^{hgn?RSn8`Pn*h~ll7;Odv4%jF_2~RBKt;5GZ1Q?{kl=r-(2f2GCTb3+ z!@-2HW6jGW3}#Ph7n31$Dq4{;0JmUb$M}G6|<=^-lMkHb|ToZ zaz~wC&0#hMl)1YehsJBWL%{1Z#uu_~Now;B$19U7WGJ zw?nNlgAU}pFtB1D9?f!jfxg+X+EvA$Lo98^3j=qr_tnaCY||AANRW*S@Dn<<)j4IE zEtoA0XG9;MtD3RTIA8}kHxA-upwML5D-aTE{Gp=5IV#V!2a)&@Q2!rKXW-`62-8JXzv-fpfAM<$$ z%mUD-QY&+IHhfoF1!sp;&4Q3_?E{OuKaVG{8((jp%u5h^ziIwzn0wP1YlE4y_>wpv zd=`$138faxX3?Wi5QNN!OlV^T2FBEHw1oID^>&*sl&Kt9;BlnumMF0T`IcPPtVnM% zj5cZ?u!9<(I30%>avr$D+mQ5B_CHo{1pbX~?wVP}D#~q4E-ueG$Cf9WJL`;f(i7E0 z^{n|GI^6K3Ii(Q_7~=H4<59E{sbf9#+M}XdQs#pFa9o=~i~xW13mE3ZB$h6wy-J_C zl>5@B(sDYhewh0Fc)NGH;Ky8R?L^FxPQ*1H^90o~lnS`_fYpAOnvMqj@AaydYFtno zZ&=zIZ6Q7~%NHeKVf1mZ3;t+z=5AhT7y4?bMJG;;l@VVC?ML+VIsUfwxdkNefK~$+ zWjKxhdq+6AkAd}VZ+7HTr>hE6ZYAE0fc7eL^gUh2Y}{)J52N;6FCx`abCB}VZ0~51 z*CwJTLwCDIc%QprWd~qC-=Lt4_CAouLPBV49iiR1V9A>Zawvxgg!(gM1S{*zzDcm{ zArIBM={G3>A>7W4V_zjnOEsiZw|dwg(ojV#^QhY2tz=w@$lX5DP()eb1%;Dgu5bIR zny3C8yX^$v$FQbf!Y(t-l$P8JE^so_{5|LAZtgaOoG{{tfY7*V<;cp8MfRrX?;+j1 z13MqpDd*)Q+)TM$$zJ32UqHZ0@w!%B0gexM z|3_c3o-Lb{NS{Nt9!0gBQfR3sZM4XG+6J;0a#>heb9cwHvV2X@Ad6<1?v$^C5gb;t z+ouaGt|!Y+0(>9cx6u#h8XsCUoQD<|EMJZmNr=Nl|24=}$%hci0YHEPagPckNm6OO z@r7G^<>v@P>~RSMYVe+zH^t6@iIlO=#Z8;>Y9nvy_a*}*c#78#-tX|g4%A|Fw-(y0 z1_A(hmqJzkyOte&gHJhHT`prbEUmVyzRP5oSp%F|>}aB))F?sYy|Z=Blg&YP0LS`+ z&Oi)N4|RpJ8@Kj{HoX>?lJ_JiX|)7sc}P|zI-+3RFI4G@ARvwY!yJB#{R8-2mxMO0 zYiy+h1bc{$h#*DH`%T~^ygyGp zhm*kH>z(plT2en9xJ$tK(-;_5+sm>6kVF8mfZf3F@+Sc{ur?!Yd>&Sgl2^5x{W+wD zT^UI!cUySVbk$|adN%SGBKcHLW#T3BbJSbJT}%MQv4K?{m}4~umeGUaXi}4tMMlxv z)5bxL4@}Bq=n||#VvHrK=-e0!6XVH#;`zr^OJ@@DMA%F0HU;$$+B@XztL_@5zNNyS z(hmf6dul8oW_fJgSRE7V;tHVBC79vWSZ{j%`uN4@^ks>gv46maqZC^X9fvZ)a64c4pp#HF95yVe~=t` zOwKkof`tt^|HkqS0Hsw$F#pg;X_(sr7R&j&r#rs>ZHc!OE4vpvxY0qmcjI4E?RF$& z(P)4jK2p>T2o{ql6)P;^z}215Gw!ZrcKTM`A<>H)*dNQ8BPeBLYh;YPG~A?H_e&{= zd5)R7Xrl3}50QOxAiBHmCn{p-!j+B7V#gg=g|hcEnixc!^|PP8RoPfH<1UZLgf=B@ zVJ=uxLoA2KRm=|c^>5Y-jV}|ga`%w3#Fn`Ig`5K^dVp*qeW>p9k>(RyPLKw)u6tIG zeAT=KCOY7wx@S((t~5pAoTAR{TbUeu*}!Qhu6iW)?inS5>ndxYc5mv$0wmoWgca6U zT3EM(?QKVo0O618^-c3nlIa|xAG>2rQ?i3_f1uo;)~-z6wMXK)8~L_$2hNS;b3q%J z;LIB5j7I@BN*zMDj*j>DK3* zK|VSzcmOYsDZT5ZBxKX%d9eof*SqOXioTUu6hOs~#pRshV6=Y_=-(OjF36A(+Yl%l zS*$l1;>ZVovRSJGAVOL@gq!@yjUTwHoclg})BLGH#_fW#tcZzZxVntl!JLB^#`POJ z^o_q!yFOJAWjdua+jai3R4agUW^HcPcQsDZY)j?@)bW>#&%FrermU%BLL2ctSNAYG zxrRRI%Z=@;#%P*k+MGE%7grh3vSkGLpCH!dW@;x_*RnL*_620gDM|ake+uq>m5Y|g z+dOYQc;fj5-OjQf)&oAYX0^baBD%d+5|W%XoLdNVyOBUp(!THmV-afUKc1MFGTlfD zc5h^{OM7#s*D|`3gjP?kyTXuchg zr!&W`>PHmPIpP2LE^}x5WHRwt1cj_TzDH6Jf{7t_ffUd#*@c#_yTmL6J&bBnQaE zW*?B|yKhEK7c}G_~ zyP9`YSG1Q@A!nG@LV;S1HrSB&Km50hxy*v!!s`v)a8WC6j~3!OG&8AD^K0OY&SW*~ z6+_QP4t@y+r+H%}fvGy+a$|~#a*P2QElYyb*!-_KTtK>YhTZl9=@Yp`&n}Ikp_0{y z{;fVk2M3kWl-QHEVMsgP!2{DU(c>PsCKcnuFV`0?b#5+qo|3f?UT%w<4~p8vpvUXC z(o7AQQ6BGL+4N>yy7qK`JcIF;B2aB% z7bSoZd>=2->$WwId)gjmXD{3Xy_hJmSE25B zv95R9u*DZY_fJAw$J#nNZBH%55s{JZqh(7=vV3OB{i9zIZm`p#L_JVOt?5Dn!sA}I zRIt2Zenxm^{yXqmhkOOYDnRuBMC38}zmJ-(q}K-n@x-twSNK9Z8u$T=08zRXZXe-i z&SJ$8N3;6;)V=O5bme^)GT8vG%SJ5O-DGu>n_4byWU=y}wiDfs8m<<`o(sUF>eyQJ z>k5ll=8)?s=eZ~Yyv5OTK!e0IQ(d-b>jpPj;`3|p06*31$#}$W%H9pTLQ0RkzM*}M zwSwKhHalkNli+1boARTc~h&3RQd4xiOR3Z=> zt+HX_@RCfg5(x{15CjhiXat5EDft3DP8dTQ41 zWoi5+mcp;PD-_qFllnO$((-)7jRYZ=`S_smW>(^QQpB+#mxw3^ov)xftI?TD&oXmM zl^See)Yc$}W|ZcG+GnE$F4q-ZTw;FsP-RMZv-3J0+RLIS>_EnsV}LQfhb%)q5(gD# z%$(dt9Ogb-MGvaE;tZkY*X<9a5IWCc8adNt>>~cQ=6T)cAIWyo&0!*FpKK+izj55K zX0x(Li9C_GOE;H6gS62tZe3b8BCe0q+4d^Xrl>*s?Wo5c=d$3T-4248UuN}vFXC{p+4CI)T@w(Tcr&5n`Dxm{kkF_`sV z@wAoYNjqD1#Zj(2a5Orh7S(YiI@NHmr@%aWNUu0`NVYp}!`CsBEV%JO%8ty82)U@r zTJy3oc4s|81Q7{`xbVJZ%wk8H61d?iomDSqcVa*1I$cG^40$r23{3H{k3f@ObPDWB z(+TxMWanaBSO8McnV8`+<)THWI3}(lQCz?cb|(V`^oRI<@7V4~xrGGf-l25n?_gNnr-Tj{z{37srYVRT233E! z_w}u^=;ZzO4VjA17p939($B4`ESC-U*#nz$yshj=@9JN#?ovz-tN2@?;mw}Vt9ymw z#>4d?xgxeSvMtG^k=;sU#wVSS4II-dpvb6FBh>touE$dAy%h$%Kt!OLZnkC?Wy)I^ z0mvqF8sS4wbfiWX)Zl)Z=zccT+r-@XC9{X8?cvD%B#TXgADUr!6kfWBcWK*J`c4{- z=GUwzg9rdcV_a}#hq_sUHiqs!F0Zn#Xkmn|=W(4r+g}ILcfNN$Bpy64Im-LTeitnVomcPi!pgEE`oKhjZP3c@$(lUI2m!vzl~tCEvT~g5XUdK#QuSfVF{332<5- zo^#H8r`HOjZ;E3zJh{H!r@cvxmJYEj6h9PVS;qhh)Aa;dbi@QK%_?ob(=#5<)4 z=_yNlM1;NRW@eb?b*{7gXKusy>KzL)3DVS9IZu~_F4k-^B8NDsV!?id;>oON>0&(( zo(ud!aZ0*D4j{#;AHi@*W#iV$eAm)nY}Xn+#Ivw+)4_7}HUBc}%VJ#KR=m76nzWNDA~jd}}lM%()DO-^fc-OpH{ZfL9-o z05m`lBp_KYa$pO4d_4k*JQZ&yo|92el-7#m$*0jOF$?$Q!mUlT3SL)h?cp)D~$_I6RGPBI-mk8;VonLZ^ge_3h-N@(tMKwzixLa{Zf zz}}{Uh#$Qi^leg85Ycut$}R!#dlCInBLdgrvU9%jJT?pLY{T1DqXYz#d~1 z)}5@<_5uusQ|9Pxu3rkJFSS#@rD3J$I%%jL?apv|Uuo5+jBof4`Bww5G3uosz&%8UNo02 zvP>7Kvfb*;?;9H5*Z#!HIlHxfAh>ujc(&8^cHIl%I^VKwK=s7rd%~tf@)kTG)XeIj z)W;*vxqhl&f8qtQQ>NvpulaX`_q~rB3dbw#^-U(X&wJT4L-wl7R=SGkR9Y9F@J?a3mLItX_w z?Y>afTCx5L*b@OQ+@N0$^e!mCL*k#}yQtZTEaI4}fxfqlyk^30FG{&xX6$*W*E~)% zs$8*wSA19{D3JQiGn{5tR)$fOQSw{gq5EU(tl*KVpmS#$BxvWS{Db7GYJVk`193bD zH6W$R#v;l}q}L>(aha!SO|CB%!! zS&ry=SWbb|;Kj{z!G)-A{Ywj0aH~S^?ZM7*>}uJU@!yx)Gq(mLD&7I-f8caQIP7d* z>|7Mz619~7w5vkIbqf&@GYs=r(uG3Qm%qLnE8jsHElFk4)% z^QYA3V%F}+pG?ONG(?^+X_#(Zi2)WY40V?5-V$%hew?Li>Yo;)R$&A~L7Nyak+)J{ zmHbSYVX(f0s?yD^mEl%4ue;N?KeFj#-ExX(^^a)L?r`Xm@n`lJQygz_ks6{7){D}nq+?7E zjj#L3i{9)x#LOR-h>Y=o$bgolk8#c-Afh5WBppmAwovoR@$$9#J?lrx40sHf)GW#0 zYwWh%QBf@Tf$2DA3fq4%D6(6ny!dWGpWFU6l+!q&q6cCnQ-mVVfpfb39wXo|o^w)n zS;*)+>NxmEWQ*^|eXTr9M0%wI)AJqd{G$$`mu*c_jvzReSD{sWjU=XT*F<6v9w2$1 zXl#0pGgzTnTJK!s$=eJ4_(oT#$q&82wdIDz0g57@wS$^p<9}4e70vxAY zho20MA*yNv=sm>a2Vb`dnk`*WNm?3J>*`Fm@_bH;o(~i|G(B30!Ttr@hS$}cr-Edo z1Fq+d7ljyH^oqy#bv2QWPu=THw*R9IqA~G*n?GvS9Rs@?1fGuKC~#7C1G}}}Lq4%L zVfG|PcO?e1;{E@StWXst@Xaou{yTnFzW(!Q97`EN`T)?uNPhNwkVLIFw>$mUKRBEgO zvZ0Rv(U6tllOeUrQjP7Enk>zQFQIr5zVlAZy# zV+5V^WGV(M5*@}J=pXa>fF>TL1Quuiu6m;R-N%(>gX)GXYZ9UED8r`jMDbg@1aNTW zjSV@{eJuVzVwCYdSWXfQOtPbruepg>(NhKQZW`vDgOP!lM^WoFt`l~%cxxD#f6bam zQk@#rQ1u~$EGFtUx=i8O8{?(#nJ$yL+t_CeilreN!VTK}Xi!#xWx}wMzMX$Wga(x~n2?pvo9h|(%AU61QzaG5a_p36+ap;+j_`Kr?Z3Npi5evP z$n>5!FtXcyk>$w?$!PR1QVVI08Qzt|&C<>O=0WAfXA*%A^~0f%1|g(t>uOHj(u)0O z=r-Dyq3@KV!l3=<`)$AHb{i#&;wlB1iXr#fgwMO8n9FEVlS~iHph^~Boy23$l{%*R z8m31o4Va4B`^ZXTFj4;24F`Pp;x@gF9+##7Q1Db6+H|)RIE3lK8s)X8Nf$Rk^`oaz zLAx2T?`4w->?q=XGi^PRYsOVJg`cW`g5%?Wp+hl`U&ucQ^X=-gq~iSCf&?1{(hy0j z2$L=}#g<+T`osUY3X%g7uZOv=o~*l1cl|34jbrqJX$K z=AKDu=vs@duXsR^3L3?VWe$|_w1eVS0>4YMDyFIUhcG)5Nrvcu7h$jjVIc6Ys2L89*bp zE9P>A!as57?&TK^{R330)@}lMN^<;lmBr08aKCr7=*gUUGv(p9GP}J9xhJFx6!S!|sm&FZW;i z>n^NRct@j`+1a-oxv%WvBCGG@ZAFO7s3Y zck8zS#2WQI%ndR1oQ6E12`~+)T4~GR7FMnZ75t)!h=K4D&WpF33Dns+{hk=Y?9GKy zm6Wji)Mw{awem{*y`)lvX<4L%702?2hoA%DxWcZOJPC^?kDl&~V_?R+Mjmdy0x{I* zj^qqNs_ihk+ufHc8a5b{&inyIgzVs*KGVW7qZwwG5wA=I5#=+ot^O)O$p_P99Vt*s zN`qmmw_EFG6d?1fmrKjOrAQvD!&&ZPd8a(EsioR#hrc&6$m89IY&P+_Qp@;dxQitl zICF!b+GBTUhF|-^h)|^bto$DzH8j1L_zo;Uay;u{0t_}C^))}OB$k33e~}DwT?LXh zD0@)g_{)Znk}vSf+zpCPA|}5aQ~!N$*c51?1{nwp|Il7BV<5D?Vwx>1T>N%EYS#8> zSV)Fw2!eGG^NKX(`glo)p1`rhq?d&bbiu(6x|=^wzDQs?^NFJD1V)HYfF5c2lv z`UHz-(h_%*SqO`^%G1@cd5+2hj*pRrR|AIr>zAttqTfcK+fCLb=vp`FTr}-=&9IuQ zX&(!H5WkqhuAB;l%Mm!8q^_)B@kFZ^8*ro988+U|r$jXyn{xz^_I@&{uOgjBy=Fvd zIx_Kb_-xKPlK!Vjz(&Dz`!%LB0|(|2J}`oCKIIxDAd;{Pm<$4Uh^QRM(X+GK^YvD| zy_0ZxO$E+UEEJFwyzWMRBZ?9U>KG1k-fYwLm_^j*g#=dCA~G%2Y35pE+L~nE7Q>zC zsnn`cW1vTshyQ>r_FQp;F?B^!RpKN83MR-|vJF|(#S50BEZ$oT$mlDk5sbB?V|(IE zheKzEmmFvEKSk9%E#3OC#HVu8yRv3?`pIkwy)3gUqFnHz`#miil$V(d+0yRSlkGC{ z4%_J5Z!F~j=J`S-=L>BbZp2b3V?VO!5@HXr$7Dzn)c}uc+;@u*CX9vlLFwg}4Ztw* z8wjD!Rg&t?onWFC0So3OVI_c^<$bNaf;Qv*8;pYAlN?3hc3KS^r${TelW{gUN7jVI&!N5pv0; z<)QQT<&_JkdQPpZv!3iVJoWF~!4@LrhCFj%FMFxM3Kc`4^rrt|oA=pa!5!xX_zFEe zoOjO{vi8S33>tk@KwFwGuQT-cs6jJ%Pu!vFBB0@CSiYSMIH*(l$K%qKc1coNI~1J; zE6i*4s+3~y`uf8_tEKC@QD+^YuJnG_kV~&i`{6|L!5o|v{F&OF*NOMVe*DQhv@XbN zuD(;zm$afzSe7*CbFo$FZSeulR%Xz4)UTFFd1pFOloY%e9JTO84HDHsKWwYGQ0!a*gx4r2*nhzirEW8?N#782FLuVVWeH!5s}4tW*Y|I zQWuMpG6Or@OT4k`L=8b9-Oe8PdC4hWp6k2JA>sd9v;^c4`W8S9s+RZYKotg5&^g3%T?P z6}vyspPxjk?sDI664R~l)Y&&abUgz!<8NA186BD*9gvYdaWOFZ6QX_$6KwM*`kj5| z;exe_!sjX@bgZK-Pk7b|Z`Xf3^E60oIs5%4U!N2#P7Q2W9z)g(J&o>vfl;M?ZU@~B z3BGC%c>-#Z-J2+KBtNC`R3pqP>&PXDP=a~gWm!ZHKPk34}h%lER|3>eWP^t zK+u%Nx6&A7giUgfjZ_eJb|L~9ZZeT5D-LgcffjXp(cG2?euF3`>?bMk5YvIfA70g8 zy|RPxYPCg<<=VVfW{UA4lX@1-NA6&I$^Cn*c211*nt0f$W^ZD*L^=?zav=R8tJyEB zykF}|kXKt|XkbVN4;Q=SkYnD3-Y)Fa)KP$N8W@ib9iYKZra*ke2Eueh(ty0+Y}sWo z$fcAmti(=(qg0`PCuL>+F?W9mR$t-5l@ML5K2BsfNJ0&w!{)XMIK-8^`9IUh161q)s@ztIVVg_L|IsBQ1`qT<0|MobOkcWZ& zTen20xx`5aGfV(%8fa%nC9+Hb3(WRB8cQj;`5_Az7q;E z)lxP!rXu;L8V@yjh@%cUwvsn@?OCPsYS@M_^J5;p0OOwF%X4uCee4pt{}1k!HY7ul zy{6gz5-m)>$M4|a0qEH8C1;|u*3^-v-tEir-tU$*>B=zDH+I?uZs`L^$M5YDOgBuL zj0Io5pS~DyH{7eSo#n4@#y-QdNR`_Wob03rNjRIyw(tUG*17ye4wmxOWIIhFfbGU8 zM_wIfGDD4Z-FQ;;dry`n19V0Pz`_EUx8Y5Dn+aQTVQ0|K0J*VZyT47`83j=M+5UmK z{ErGW^Wn6v@vjR@p#bCS;jm~C?UJ6Y5c@Et@1#HBRq6H&o91J?QoP9%Qb3w-j$pfP zo_MYh4W(t4m>4N8P|HsqEq!(Mr>3|0rt;ceC+p0a-XsLUaC6=+rpIOV!LTrzK7@*ikob}aNXF1R+(hIewK)P7Zi{yVFhi3_i=$EX13_7D}XTF z#Ep63mx3y3OmsoTC_m^&^q`H2;NR5S*k&r?c)%<>ga>10*pSU15Gd+~^8``mo#{r) zM!+SEt*sa)EGt%lez8{z=O~F$P$BlfW{U{ST|^cqWa9Ycx! z0GN#K9HRFj%jyTvNfS7=6(9hfNFhGrEt~&~BZ+9{GXB5G8oc@_-lcHkWkImmDOMp z$f)^x=_hd|jR1no5+}OIm9{ z3XR3G;J7dHzboIsy<$CJp`CsYiyETRok%{iKslE_A@e=08MU@lcPzVYl;tRW%klRY zig1?L&4&kyKeA2@`j1zooPWT9ookOCC*`ExC_Njc!`!C_gPpKT7Iz?*RNZ)Mh{)+5 z6+QlLf|ZlIX{$9b5b z5f!<*m%QcJh>P>3NnCSFQy*raCI?5!j>ogx&vvHH z-y1D3T&}N@QjbxaR999yQ_H(;{eL5QxX!hj)yLbzrP6SJ^euGM5SW_!4$y3K6d?={ zF8((o0IVnh*wLzn+r<;QcNh1gmZ?3<%|PCo1IqWrbkVJ z@!TZhHC?!lnykM!wfqPu);c9RcC*bw}|V^qDKtOhjVvQck`JB+WvdS)IZ2 zcLkU&7j{^i`CoyGe2g4T&(CTwm1Xo-rR>XfAEYC=_$L*PobAo3XOn*h z%kwkI+{5G!Cpa)KAg-RliW^TNBjpR;GoLfkFy%6p(ZN_w@ z;aah;{^4hOiOtD3^*N#pHQXq!;>$Yf_1C49soZyA7dCw8K~zP&Frl<$rQp({2K`O9 z(NdkInIs+F*2kH5WV7RnV$%*J8zFJYDmG+~q_`#^aZV|Rzf%-+xfAcvGp_8JFGHB= zKk%XP{g@1rH8$)XVx&`5M3F0QV$;DWQECTTxr=26H5O=)P4HfXl9NEFXqbiD_zsfN zck6Zk1$liI8Evq{%R;c}n#J2_09V_s&aHsJ6M*Gt4=v?okxEVypT~WFHvH??!PG>M-|ccMING$OKH;^^(9L^QpN$zPxI5Sw$VT&@V@%#o&Oo# zuZ+y(Qf%t@&y&+fJfR_d8Vp3L7@TpwMW4BcTkUeQnbfls3YtyycxdYIY#dcg)Wbo8T~FB9*+v8O9)C@fYN!Gj+&d?!Zs zSil5csC3;|M^x@z^VDXlp&bN0rTJdkP9H7Q%mBdZxYtmYZIqd7qOa&drgj|Spb>L& z!3m+i{NoY2J^8w#A!KL`zS-hGUWofGX0$z1ncXTBJJbY`k6<{X0mgA-OklaLDhWJ{ z#d=bOw@6fYH|Pc^8sf=#vB8*b0XW~SJeH=jUWV@v5S%S%6rcXgHhYrlc{4q8%?kdHW{O zMe)t2mB-T`Cm%T!!};MeI<&72srzxg1IuJP+VMTo3`b{|Vwmu}Swg>TuN89aEw8_O zUYpNv87Ge2_iX?k+VG{XTFMYzyKug9d>N4#Ww?@?2D%+0F1=RvKg)CJsrRYpeHK9g z_fJ48PKGj?^NPtAHi=lN{lBk*M#kM|DQ2$_-R9R+_LnZOiX_lI1hTeUQ z0}KvpS#as(b(;!b5hO#fhTi(<|FQ05ZqH+;TQ-<*y0+aukCO@r`038L)E4kFr$sZ< z_i1WA5PEv=ykhWDpnY*aUbgymxHYTee(fdA75P~k%V(P9+D$lfBSEqVsf!pVVF*TO zpZIhebQlz~ZuU84LL@nP4q7~q8vx3b`A#i1_z7XNs)&c`<2_$EFRubm^b;YRla_B5 zV?NQ^r#6gx`td*G;le*VUA2<~@FYn$F$f6hMCi3^rLM2fF-E#*DAHSv2hhfOYQJB4 zt<;yJ8=AkrVdV=!mu?DTZ?&z&g~er<6qq%nM26Y zQGif|he4g0`^Z2d@Q`RkR9rrP5U;~KbZ4s7I@!3~=6MYw#>b1K%Ugw-S4kn2=X*^2 znE|0JAJezLTXPUOT7Y>La0)gL%Zk%L6C{C$kfBzEe0lVeeWd9cG!`Q_>M`g%y&HD? z1@^f2H7GzJ?HIpYUih=Y;k?^~&iM3d5t~Sjk|%GQ)%H+x5l9BvH+}Ywkdy0261c>F z?DlQ;X-8@dNq+>pZ!hK5{?-%g#|fM>@NIiAc%6GyuiN)-1MH;FcLPGezZyS8R9Dm| z`Vr?$-(q8jb)cFSY-p}{P!0j+ZRNmLXREb(vNN3mA|>g-=PW0HE5%t6UBz@ypoDxS z{i*ZUOO&#z5>>m?Z*`kCC4kb#a8n8EBIUAW+N?iqy5sn-5=ol*Rhani(V=7BqETc- zRT`p#n0zfFG89Qgcs{m($6L=RLl&w!>gA$7NUa5WrK5H@t{`K+**6si0%|w?=k{;3 zaqecI>f$^9*g$i7-H^U+aq610HT1A2{Xg#hoF?*E@BH$l#>jH^5RRLk2GAJ}B`tdSdOEDk!=wUE)d+(&oubg2loJ!LeuvRpJn9Gp}OymxXa3Q*4z&P$0kPpL7t7 zPNzhzL4}M0>^D5{bpW=$Pb{VFKV9a)$xi-_OF$n})7aBhrRNEeHFV*3w z<0=)c$h<<5%~hgCLr-}+uG~w#WqJub5WHOmhK<}o?ac5FDACw@6CCn5*xCEn#K?wP z>1J9L>z#TW*3G!}zbFSqd*yZKS2x;Rpp*9LVtQHC`*AuD^efnhx# z8Ibn8FXAl6FUQN~UT_~GPhFGmTLwDVzwroUyNYk#%k2#sH-b9GQt@sT+54*+++X7K17NFJ1|@#Zx&z` zKTKt5xUOJ-<5Yn`6RPBGp-76rEHf>yc%$t+^XJcgOF$mQUOBd48L1EftejZ6fY!eW zP_j?ylgXTcVLDQMxIhrn0yMx)W;Yw5y z_u#i#TXuccJ9rYGnvVEPe9#aTnc>h5HUd>c?^2{8(sQ{kr>=@V%$tZU%-UB&uHB?w zlH3FXmGRsZNp?$F&nX^zX=`edJ}-_Of<*LR5UFq-Z`K=eRc;o_4dO;eOs4pIwBg@6 zuUw_*bJr(ktE2IR!cui=zwqZU;rzBOG3$O2n}6*u)bKu^D0Vrtrpw_Mi+X=06frZ5 zm2~Eq^{D%z%xwHnQ;CR7PFAFtRjyI4`EiSWT~o#T)WjdT!#q za`5FXFroN$f#z)NQzVoxYE15-#E=y*$ zZpYe4DTU%WLWuB_Gn{P;E#eVf?Ia|(V%j`|OeX$A8(G)EFRzV(n)Dr7r$Ua?>k~0` z+}riOb1{>L=Q*tInyxhj)Qhux*E)sPksmVmWpNc11-B^_PPIZ2=~h~@|{JG<#3_wJT{{3R)sqAN4SKOz&-laev}jFO|Pj~bPu?$9*n zrJXhJb>qa5#e$e`?WMwSEW{84Hj4ZeS?ZjMv!V?{B_?8^>*WQo9+`c|`k*E?!OaD; z(Q7ftd|1zk_;KlHU)vDTk4qsv&&ToymF-gW@D`5JYkyBcer9Y09}Yf^PcX4UMzkxY ze+Y|h$0`B|nBKXy<&c3hS%ZfkwdFJcpdPn%f*&y3X+l5#3JS3|O+gloL4vSEplq0O zm5Au?Meq}*=zY49{V%i9-}0AHVH4M7o_xl1ejns7@)PQ?PY_mCYfK9tf-dxjlN4uz z{|#$nprA;cupO95h*Q1ykKN)2NE(Q_dpx3+@8u-sw#87l(Jl1ggkNvjh#U>Q7#8Qf z$1FvpGPKNDb048}6Poz$x*ex4aGms`-5$$tJS>rev#8u-kPWCHQdj@#OQ}mqkiIyO zRgopI31huXl03&YA5{-u2(eJf91`eCSm>#KTxi+s$+q8$SzHQU86WH8AR?CaQPZaZ zh9=Af@>y58&B20=)@t`;820EnsRUm!F&bzj{PO!Yd>B-QtZKi*4mUYb8@JYGhN-=C z@x;&=%)R_6{U)|5lt{%5Z)ODa)h{+Q6+P64MD7et@Q#H_QnelL-3vEk&N!hQazvSz z3n`Wl)o3%ztHnWRJDhN@Yv2wM1nMhR`jHBX0lSL6&`kWHTIv#UJ4B}agPZPwYYg7{ zF5D1MX0bT!cj0^~gaO_zTGI~(SSnwMur2iBPypsffR)sz#8|6jlfaAR6o%4;ob_4+ zk?odXWsi?ITP-12PW<)v`Fj+bQc*F%oB~T}j2m{n5cT;&3K}#W0>_yloI4&4pCy8i zTUZ3vdm?r}3{^rE=P6>0{7n91B=(Omo%ZJI5qj)qzNl(&Evf2)%*^tQdJ?G<)sI{9 zU^m|^Eme9j?VqK~uJLTQwXq(`z12)MK)fSeVz@xDFdu>cp&ig2URHSR0T4L;+=bouRoacra->~XKwe`NglOo0efw~?nVUsnr8QDp`Oc+EWApu4s z;@)40ijI)L34YQOBOR@58MC>(AVS8U%B?)RhR4pv+S4RUF{lNW1v$OcynWqGpsnV7 zZC<59cv=GB&M_R!jy`TOkFjGvkXGZ>?OFZ^qf_2zsGU+5MtchJvSoc97YvciO2XJlPjje9k zcSF_Is2e62<$fteRS$7~LUZ#2`ELrql;QNxSua!^ds`%$?_ck;E`NHT`a}mp$P|gj2Q)Q^!o2&!Bai_SIT! zV)O$L#ljM>zMy3jF*fvsmImoPabs{um(cT+(DlWCdR>l-L4nV+9RF6m?jepfVAabZ z{HfQ|P?z20q8vW=eg4zH;{e^_RWp%~TgsCtJVDNejOb%BpxvLAPb$PT4JSiGw<{mm z6F1k{;&R!cy%#zU07xeGsNQl&O5gyxmu=x5FbsTQy?Gy;82%CEwv!5+1uF zQ~lYU(AvDEp8wsNqF1G+JPyn%FH96V*Uk;71qQmj$un#AG1b0f#2ZLw=E&zAYCJEn zj5liko#?&^%ha!H%v05cN`mzZrEeyyCI?S8cF)nTZ;f{cDoDY0+=1Ldj24rpOqPcP z8n9Uouv)Sv+hFEil;l-)bJ*R9!Y$+C#9%(JQZ5D?16bm4PEPe-Zd7QmOpV2W9a(t+ zO{>{z2Wm*q`wpQmhZlhk3r|vWepu;0M^_>hs|HgzymmcB*->%T=Eqx~9GuTPo*Pzw zDQh(z1N9(2kwZ+8qkN6Y=q! z@FWMq0)L0=_3j{?lp>aQdnW*@t-w!n&!@w*s6CkbtA)AtDKcZE;agV_z6G4a$_ z5VMIyTz$7Lt60np4*XldFxAWAB$=<P-_v(;zcAE7Hpv=`GB#V^^(kWbs>MsKj!`1vgoAELFDT#ipvb9=<9-*M_ z?F}|cIbS!Y>Eb$6e{cgcnshjH|M<8r(|og`Jg1rmdPs0lAq^>$7Q<`qqn!f}ej?Z1 z|G}Q7pSG!a>?0H2OXMXloZB$Rk)-eY=7V@6aacg+Pg#)*jo|F1y>LMH#=w&vG(bACJ52pXB2fAPI;253{BMTco?~@$M0g&iTs_vkFnX{%yf}SYadI^a(3M(| z7W3V{Ir?r>E|;J6{1!NNq3QuxpQV6}jakE-$B26Y|G&44;!522O3H6%&>7&u|MCLI z7=Z%b@iF->YFr8Z>NBEK&VP@7x{?*OsRusi!)0tZ&$P?#ZOtHSdaGym^LZ~ej2#i* z*P)-@Szoe<3LN;mXU|94HM+sy?h_KeqbALrXT3N>ZFAR9ZANphAx4se{)nSwZ}`G>P1 zM5go%O739p!YlJy#DdGuVC`Kmf`U>3;9h6~8LT>iRZKFx(>?1cp9*Z?yAQdp@qIm= z;RDXj39p(v*GTyUck^Q+OzDJTW}YqDKCAbu&nkx7M!CGfJ9yu0)J~m~n1tQUjG)I= z)CAdK@i^q4{lS#?)}YwcT^xH58(d@+BEu;m{!OZp595`pT<;+Q8^ zszVaCxrr~I*%MT`aT)es!sI_Y0JPZxnkCw67;n1XI0A#+>)!qR76Mjqk@@%8AyRK+ z*gVzrG(8tijLtjuo_T9<4sz(CaL@zBln3kGy13V1M zAZ6{j7^}f26AL{@0`#CE;qn~7x*Q$=a*&^0oP$l41VT`o(QEoh-vKr@4=B3X_3qBE zRfh7-?p4Yg>?3NU>UA3vG!GJ+S_aBi z)Pwi73p>A>@*BTKO20*N55mfU7vXRi-*jPe(wV2LOde*^Enn2u5r_>oHV?P5H`o21 zTV>&tVfq%y2>d?Gj>W3}rM2K#?uI9)A!UunN2`tJ<7wk}Qj=v}Z82*-HnTCJI;X!X zK(zy$8XdHng3`C+@PdQ*dXrl-%a43#e56t~Qyi3rB74H9De@1(C3?y7)_%+1b>@(N zPWc#aAzC4Mfp&W%FLrP#C3=)~M4&pgI8vWg+cQ*C$K11D4oT_muAv)5x*O^4`0nTZesNv=fIVl;OMhu!u~rFe&M9dWTvfQMN;d-Ce0mZMhCj8KvB zw?2kFqCgxV`t7r%ej^5-sCb2cI!XrVoK>=tz zni65z<8%O2XyJjCG^!uK$V5KiITyQp%^QLo5^p2HL5KMP(-ZLjEEe^#Xwfc8M;Y*X z)7s{819QQmS>awcl0GXPOYi=SSvxQ;8u={PpWSGNldK~C&tR#1r(*w#LSYlcSI<{W zp5*MIIT&gv@(-hzRvA8kwEM9*;DS+eDwZUZm>@KCF_q|(Dkk$-Mex!6md(`OJtEsk za^O$oEv$^PkTtrtcgM$Pws+)U1+WLm9*;`6FhjsY|7mkV!No|aM5u)Mb8^P+XQw^- zs~MeE$vA*+16yc@zL#>}{pHrGCsn!QcA)v`zy6kSn6C{KDhopF<#7;U!9%lkwpJhA zAN7sK1Dh2WVX(@f%pRK4L?_`e)3>iIi6ts_A8|b95XnBu6lLs)(BH0zzCRY6F!Crt z??*nejWza?Yv$BWRA=tmZ##2$&M+ETYM|mq#ibs5ab{t9H<{V+ z+$g)Vhh!4clWl>3nFH8)b}o(pRJ_d5yWTxLs!OZu zUPs0hrQv#Kp)A8Z4OjiFtTjZ0=PG>5+NM5J(P27Z;^}Nvp#ES`+at_#!BJV?6}@SK zlvx$3Udx5f03cSJS&~6~ZOuBF1S~>&8qSLMVq+{53?z*l zPM<952biPW51#(T$};kq6bIebyx#fr!COt9OpvA4190a80NjKZ1=lR}5Ec{3p8VJ( zKswVYUYBIzz@^3@{lp3pxIuzOtq&PNHr82IzB(6O);q!+;kzv-o<=eY6Y$X6~6j zQC2J~Oc-Js^fKY5^BTR7;&?je>AHLgMNv>cOfo+u-Ou+pkTqhB!gjS?1aNfwJX@;Y z#0B(#bIBcLo?8SQ9(z^;T;Bk#oUxrvl0UOz8H0jD5^EHFW%k9j+>e?GbXQjDPtJU!Mb}soe+NE7vju%Pv)M%)PT`BKMXsx_D#A*eS-rM}hoR zy}6DqkGuStZl8WBy}xT@sFQx{TjYUN$#D<3h1v844K%4=KOP*9iLreAntMQJp4mDA zUx{IC{O;^y%42YxvW5#EfHe!e7qN$@Kzb5}xq=&P`cIz#p(pj>B=!c|__D4?&S>m! zuN|;igA%OJA0C{X;=jag3l8;OI`bCiGWE4R4nSxz^)4TP8Q62Cfw!8>q(NTpQ+Y=j zUa%H&b4RRb=kjomzpPs8+~JF)T$r$Qcp^~b`v2h;DoRX$&vu`Bd64%JoG>W*)B^px z_WX61FreO9%~o=#GeAn#Xp4C-iTk~sdL6Z`Y7_$xK~7CkohGl_mcGzAxtNfBXNw_j z_($A^4?e3BcL`f$$8`|#rko;OHkhtI*Y6j`sG^X|?1?QJG(bT2!*+DJ#lH4};;te+ zrr*tgFZ(4`f+c>4_yL6^9LQh#&XY30kBP9JA><*Je{(2TXq3ZFO)cNtaUyS;-ER5- zW%vxAf5CV**`s425gUSLk#pQ^J08xTIu@E)TW~ST*FW8iso#|Ix#cPbSnU~8nIz@K zp-AMO1*X>+cR9N+D!5!mrLW3sI<9ZhV)oC1R|3(ALp&JM5`G8Gh_3&baYh0HTNZx!*?Xy`AlOw5IJCz_a#~t?utu075!HCUf_F zRR5>UJbldkj-{GnB@uv?ba-0LI%ZSpmUm5t*)1gl2PKC-uB_6iKfLri*fBcjL{QM~ z;=zF}(_YEp2xi=-tA2uF^>>2^ zCQz%X{ydvT9PP~(OwPD{X^7vwRFk0026ndCnjLdrmHCAgK;On>NYNy2hX`U>) zMS9E(o+t=u9Ms@!Aqc^zs#Uh1`oO<^l5zpZVwb)b`S76;3M}bxkf*MuptoDUJe}ZI z0jNOeG`v@70iX$JSW6D2xnh?T)F(Fx$`b;zavUE5+#O76Tm%FQb)Ax(NVX_a*Ft|d zV0Oa?G^o=gLmU^o)^6rSouHNj!k#B5i@VDUpuIDUl@@x=ssmD0>PR=S;DY!&=cpJ`#jz1# z8)QHA=6=$&kbZVH#+QXg-vot#rw4rFtkQr~^(_Wj5PBApU4uw8$jt-Q;wZT}Ia?AU zIWhvl94hgl@1((->(A32_u9o}Wgo7t%*5*Qseq#nQiSe^-4nl*7%KWC8`;iqWi47WsW`dX#LemBA8tT6)AG%{guGduX_b ziKn2TP^YJ#{$(Bxsl~yXYDS&qFfL#Bxmzrj4mJ|f;cru^2IZv!uGQ-@N*kJ+&pUZ# zeNn&2736f9J_{`IYof3H^!=t=LIV4>KTKnH6I`V!duNcD}5C>S+iTs-O`Z8+d#4We^wn{%8@KO0q%dchTh2K7UB&UsXT{{8qd z^XPn~1M7$UI)*Bl5f)Bb1V+h3-5~exy&gRJnCqnH73E&=u`!6J*4A>=CL(VM-jtb~ zpZ{edJ5`ucGk4`U`R@JZ#uO7}emio=WY9`Ol+|AGD>G%W@vL0$-p|3~JHG;!>ib03 zPe^+?nu0lMMv(~#jbM;SVdCvRN;_<#5DrnmXDOpJ+T<(Qe;I=+jW`=Ugc+i__+K;U z8Ec-LEg6r`j;+hqV`CI#GBEJ|(|6w}@e!`A$kfXMX^@}yq{a_<_hr5%{bX%2SGu<{ zu_oveh|Gl``pBJDNU%l3m?&@5n@GovN*}wRn-^rYxfXjv`7{b(+T93zbPtDSlK$z| zNu>)+SGSs-_>mQ7?Q(lu0JA0>ycH3f+mVIA2pm_7!Y?+L8FPc`rp|;$Rk;ptHKEI0cE# z8dtfy`s-1|8>VO>gljOO1*P3j0u`Yv)n!Gkb8x)_z!){GOc&r8WRJwki3L?-OdG%m z3S6Sf77KODv^D=DJ0!pRu`v5a6DEnT$a}@t!}@vL9rycs9(uVZT$IXHe0le!Bq*od{hCVFNFl7fN4yk+zrgekc27 z9*W+bLq|0AUP{ksZ-g^`XiFS^&OX@TlU3(zOR;hKF*+pXW3A06lZYrt@Z_Xg1td2$ zY~#5XB3U%_-^=RME=C)$Wa=N T|efm#|vOPVP%_qD~AQIg!Df=v_149hx`cO^ljm%9uphF z*K+@qZvOp49N?n0O}Vd^$OU@Y4LY}TNV`VIT#zV?y2sxaY~`!Xq4#En0RTD-Y=+kZc= zSQ~Yr5F$E#NI^hQZzDli<1$*-)G{4_-hCKb zBuOM~1e^h6%>TubDzT`+VlG4VCxYu8&GmfPurYYx5=9UGXD$d?JzmujT;2ngVJh$< zJ-)CF+S8A18943kmvGMXvVAs)rfs;C9!|MSuprKohX@L7ZPDQlOB|3_{Q5A0!5A`< z%-LN8LH4BlX{S>L;31#zWFUZfFUqmWu4O5LaD)zkHdyWnB-RC)f8_KlW-gSHNh@>~VMC#uG0ZME-W!gM8 zT#JvJyQGP!&XNuoAxy!MXre-|eXn}g`ky!0|Bei^-}vsVO3rO1W!>0pQZy&~ZaBdw zAGbY2B;y@>A?4!O8$<-MDu|eBD(M_ne}Bp3L=Qe}F^Q%4nf5k6+Ux*3TIBl|DJ)7> zpmHeMYHS7j5Ih~wTzgn8H{g0jJjA?+^-tGST$X(3pwg%~qSk7`jrM%8BQqbhz6NfN zHEk9-{Lm$>)W&SngGYF*H(b8lNIWC^===NgyJpe`uiV{mrf_6@O{#k~OMlq~quVwt zEEzCSXmqwJndHP)l9Y|P?RY(*Dljck^CjGbj3&-FzVQtkrcZGbh~a-(7FK38z+DMf58J766+b@hZo!Aiickw~4E%W52q>z$AqlLtUJD;~ms=x2AP9#K5=~Gbi z{^7T)VWiFdp2`$^p(U|wz?2qz6_#gXspVFksSS4MeK^h~+~2+#{dg+?ZE)L`EDmWE z6aDrYv8A|3VH6J}C|poi_#>y*AK+)2!(_jK##?+-Nt%|yAx`_{ET=i~u+8I$3c0C+; z`HMcb`*5|eAu_~~Anb&}$H8bPbzCl}K%65^QW6g+uZE!al3rnunV+qnP+z6@y<7nP zW6|9vmN6uefVi(lC)sCud)yQT>xE4aI@2bV?XqS{$)4pf5*y?3_f}&Bc`~fT=J6Lm>Je>l5;oa_sqET-9Iv4-us>K^hO&2+aqhzeT#g-Ue%MFQBqF2>O=JR zra_2WmKazt1kmwN9Swn~g)3zETX9CpfE+z^A*`9PmZ#(%X9jpPHdy!k?Nh0_lA5JBh2{)#A*U)J-i*NW* zG3{v(QhMhYE6!rO9H=L-3wUqmPJvW1I)L}JLLLdAe;g|Xe&akg7!o~1{Oi_eE6Z{# zR|anXyW-=~!z7@S=lF(~;shtODL_sxPJ~2*@O5HY5T+5=(C)CZY!!mqfOH&B;f!QF zfQbP*!drFaRW|WuMZi`E?uXI;Rr7D96`B=OK&Q(u#;MIOJLLO2#9u5u+KZ=%0V4E% z=iu2V>@Ur$U?*K2zQfVf7Ul38=x7x_vO@{*`9GVHeo+a$aqNb0+9*I^f1Y% zR?R_;F0gJv8g8rRFK=;M#xp8VHsAoS%ciYqHz%8SgCp|O^ni>l`0`}ssEq%4zv6F% z;bV@cXBXmCoY%?d3t-p;Px~)FVL-}b5#y(7<>q#J>>YnN|w>w2(Y)3EsgWR z5o58y@B2B@(BPyZdFYMO=kjfG>XpGk2AfbC4PX?wzgM>pXkd}(OhI-4F;1i zF_b_>ROT;`aSSc~sX9^QWJXT`gtVZbAWdBuL7vO#xbJmMs?8TdzX+0_-)anQwvSVP zn1V5TsR%!>sxGNv>?sJ?dDb+4mnga4s>ZF8&UD6y0V?ao%F&o7Hs7uP5QYGgc^eXJ zqAJnKo-cd_C2C)4DrMSy=2~e{TwhaYzij?8s(|DbEFax)l^QMv(4VRNwdQ^o{&CF? zRVAI`zzmV#cqWnib)1S1!ue1s_ZJhYx~BVwPzRsIn#N@(^rv(>baJIn9tfHS`UTq89EOnQ_CJ(8>* zd|J^C=KI+MZ1(yHs(4>#CV$+!2OS#MnucPhK|h?MA3# zXXOqk*3A1?hqm2+hRO?55(cJsldxg0FB8ZxO(cx7V`I`Ug8o)Be&@-s$;d9jfCSxp zfID;Ho~X!CYo2qn;`T;9}_S@m$1;wD4S zg+0k>cnei_bn2X4xeU)7*s%YR>+Jm;7{Y;4coj=k-2pb#-|ygD%o^<5`#`B2Tae zxduEtJf?%1s1!+~*VhWw#pcZnR8@yK9|s3w`J1|+ zR%vNS-8sN4$QXJypM{9}Vfs2cwU>$bFL$?nstsV`qL@LfrcugJ1GA@m%fk-Q16&z__VNx3}?aJeKLMu*D2&D~FT#sI=ND#0i;0 zpH|%g_)xpPz*|L?(;KzMx!_`T3Wr{Qe(v^(f}Y zRsGb%=~Df@Q-g89d}whfx@MojK`Nx9VDRt_QPWZhbz^m<;^*!3`}H#nm!llhaz@ta zTOrIEuhiC7Koi{7>k=a&UD}cG%b(w?_pKH<8Jn(4)s3bVBq6ISe1#}r!1~P5j*1D#?X0oODgnc3@aAXqFTU0qyn5bCu(~mi zGK1tMpKmonch8kSa<%uUj@@s*OpAdsl=yr+3Ydgqj;MHs%%y*y3k#(1Y@xpJ*6lB9 znm=PUH-KgyWEW4poo zSUgNpUtIs~VZ2JyujAd49;Few5gasmd+Bc$LCtnuZifr%zuyJO;yWRuIROsS+~1yc z=^H^oQ)4HmJz%;?S*mKqt9QtY99(xWWw~`X&nwqKdHjwWaE{wUB*{l)QZ6aOrPCEG z2_n=eV(dWkmr@cak#J9lj~u3|BhUW0)3~blZ1hQp>{biYQTp@Hnj)ol zU%R%n4%PyA#gYUiD753gq{H&bi=ta)T&wo=MEW*zxjR#0v4KU@@eW*Twcal<@| z_~spWFF?ZIgbF0bmzV1m-+(9-FI4kVcUjsl zj=Wr_i$0mpd1cB40cLQ>(a#q|o1nX2eCzbX3Pd-_zAfHh59<9;$(h6dbDWZZ>yvEDq zf5G}EmoWXR6Is+>^%%>4nuTUseMMT<+8^dZnWmX}SxM?Ba4zswhE zLIcKob;qf#-WaV~VnKuoNNR;thDiOYbsB|;`clgM-!M$yNK#>14q?vy`PZxeW%}xU}@iwW`YjakJ=?$Hh$0tqgOmm#>`<#VPh6d zv5V{Nb1%cbn6#bU32=_oD$+ zaR^bsX0(PW(|w(SZV`d^;o!F5F+0i9eRLF6aMo_Y`TOZ>$=7E`$%E z5)nI)?U-^2LN|GcLdCYwW=}8jh!v05*SkaKKl+{%0xO%0Sq{F(o-`?3r;sGdxAb#7 z)h484j=zBfL6nBj+f+UUN4*`bQF^abCHbbDYvp)IX1nz=vc1PREPxVSsxef^C-hZ0 zc&R(I!Cg-5uO`~dCoQ(@7uU{Zl*YHx{gs1!*5FFiFEmf1b|YS!S*?-XIHjY6iwYFl znhO1Mb82k#NR5f;J0#tVDtTrF1VZ-v6&m=^;vgJ@SPrU!{6>LVQ7K_iD2q>MMcXxn z*dO@7fc#ERwhA)NHItR>?C;`qWjIGmC#Uikg{JL2+JmYivN1#m^KiV$B=@ z=`|V5{C{#O4(rm*+7%k8qyw_%41itI^}N&N%a*G8^FoJ9rI`B~^22OdTb!#58gZx) zc-Gbjx@)P-*kX1zsLbegvTC<7JbAs7X8pk5-evdH`MVkv3Sr&UA~|@&`CP_w+i37t zAb#@bDWQ`M=}%N;Fqn4MKAqzM`$*peT`J)x*ZuwTw&8QHcl>);`CzJ*``va@+Ravg zRiR+8V~t0eK$n36jOVo40b)iO=u;p&mxq-r7>0whdyYV9S#xy|@?IRh=Tj={Rk0$L zJIzK8)L3*N;KkE=qb$4HA1^O`-%PROvb0me`}s-Y`b7BtwsYjM&-mGcK27b$35}ue zVXoR7hL$@V`16b))M7+M%Kb5`e;&mNX(~Bd7m5lBxPCooKSgpC=|?ze?!HzaX2!nc zO6hgeg*HFAn`usu^t}D$`cuP7^S@t>L4==Z}#h}rqC=jGZ{6`htUDhcy2sG z*DNejx7oSqPPzJPh<>7E#X5y?;qTnsZtp&tMkp}GB=X{BuR!c?bzA5FDTofn!RS78 z`YZ4i44I$!f;4%o-lrAMvWZgm$GvKVfVU4zIKLz)v72-BeM>Wpt&n{u5Z@R}I1xdz zlvH`x$MCaP`WG(pg$I?IU02-dUAL1M5}PX>2e%&jSX z7dI~TDKT4jjS-y!`fBej_HsrV?<S+J?as9fVN0SWJI^|rkl3bn$ZmxszPz9 zq6c&HKqI8{;T-8H#!2ki!FBA5Th%bNZ!+8Sp?Q-)@D#H@`jVcAZYSFT#g1Xes~ifr zsuo8UkB5YsfH5w)uUdj?4QgQdM{JyGiNQ_>%?WeZaOF|%x!*3t#yII@B!zp_{3pux z*4q$+q{KwW9|efW;3e5qb^0MC>F|wapoBebFBy*ngWl^VjQv5nQ4cSW(Ojn(I2$ zv$*^TEScx&>%X%Q)X8hHF(bvtPZ5v@jngY-&+c&tI~4*k2UhduSgCUcOTsz)CeqcZ zzxvcWn(LVI!cooUYf^`AZIWUCzF8&n)kld_<=m*cIqJR&xDC=qn|rBgN)q-HdTXok z@a8i#RQ~~cm$WE}Ww|GN#I*WV_B2+x&ENey!oBz);nfq$G{?UFdON{yk5Ie`wa!0Gg#nnvZ|~zjw23XNU+g!7H{6t zjPQ^z{(8Kl7QHn9lX3PKX}~yau*<%>Z|Cd~NYRp5g&OM#&T$SsFGlzrt{7fbYk!6& z1b3)db&Wrye>^Xa2HU?D|BmmjVmy!7;ECK1DP1=>kf zF>jf_C4jBD0`}x=8IbAHjph}cH63oH$9ukhlc<53>`~~_H*wFi^wHw3FC-{EWA`rR zuBy8EBhS&>x8|pF(wYRmx+y@uTU%~>N{OgMFdt#VVW3wN_UEMM8y={WAnwMY*ZIKHl#EnnFO3xgt(uaz#uk7J$wd%%;5{I&Rk}Ar^ZYRo)r_+xzL@=9W(pO4~pdVy9F}Y)v$g7 z7U~~nw6^~>`sqfMhwT!_z~X%R0z^Y1?&uY0iM|fK%`7@TAKwO@HOt!)HxRGf_o;7Z(@n-LYRw81W1xle}-RF9=O3SH4my zMl{`IQfz-JB7?yKMWy1uW+DCH(9Nl=^f%{{r0T=Tu}K_*Y>2>o`a2gL`-@u z@E7c~kG33db8I(#7CqSw`H@Rzof{Gev^vWnxCLADcHT?etTktdG^B0x^i}b5oY}2r zrUQ+%u`gaS9qaSvnWL7LmLujr5hi(Mps;s?^0>(nADDwgLaXQP zU`9mBEKDfKi{@jjCO6)t;a|SPdMZ5*1~^XS9*4%g=EPbj`dNs?kn`h?j%lScScF9s ze?}q2`Pr!|)+fdZubh}X@YkotIOds=n+^|Ln2#F~Z*L#|oZhWjuzV>pZ-g=_XNRFv zHU2CvRAyxVbej>{#7+KHgql-@$_I*gsIJAp#<2bNieg`S_UoD)cQa#^BT$9jMYt+7 zIrI033af|Dz}@NX)tJ1Y8#{sP$ak3#5kg@KtLh;VaWAtc~s?GLeN znW9(br_{`a)oU5o|HERmfFPBEWj zW0o%#FNks?O$w#6JL-N#GlZAZmxiSO=Fpj!CFqbUulGbHy&lp%`7 z-tl!)Q<2rxm8A+Nqx4rWD-n>6p|8)Qb(<_&I^;>Qrs+Xo$ukA*qY_~@XGo_b36d?r zwTLu*&*L(aZ+@EeG!_mF1y|bw-H&X1Jh6l|4yu~*f7vQ%XZpd(Z94!GED-s#^qNwV zNRlcaLjY=z3kJPxz#Uy}gUenSbn-shEq9^*YrV%-dM(?HcURhXk=v*5H|sR;aPt)D zadCH~>V{{vSeJ%#vn^Sv*#kDVmhJ;fXThqN-?C9HCL*Fuy~F(_Sq@aZi0H_=s=nA* z1kkuJ`ojgxY8*8!EihZxEW{?aG#$m6?mM7@&TyIq6Eg5sjno=dsL`9%s7yYG#gEG@P+13^Zc{MPaae0Shp&zL% zxcuxkB+Wr6U9$?pt}y@oe-5i{8H}lEX$i|>0#Gu2wburmo#F5Ef`4Sia->rL-)#D} zuN3yg2v>A%AlJpTl2TKI`%SZ==qQyOJDv2ppAau+#7C3{YN@rYbiu2I0H80gzpcqM zOA@^VJ>iFKe{d>c0^Nn+c*Y4bNh-vt`y9HI@- zarWy2>AERtzW+KiAm*BQ?C-oQraSSyUI<~gsaWBEQ3d}Hct?FtDs6-oKg3D+cOD3j zEb7o23Ao7HCeIu5i#v-Y_ zVs9U?eeazdAqkUu&u_D>c)`|(Z?^R=^Og0ap}@o>FC#L-(4al8OOMgPb-M5dAI#W? zT4H8~!wLajaa4$%b%-^;O+RbT1!2hjO~o_^%MpT|j|rcgRy+O#a{b?^@~-gKS~&pz zNdF8hVWe+&^s#k&;cp8v86eMx$Op&4R;1DUD*-xWEz3AwgU?_m+tfHqY~{Bx1!TBH zE#f-E(15`i=fFFnr=TaBI3{2mib$MlWA%2jt-?>4YN1P`uC4ZHi$X{U8jb`pN{lNS zpGes`x7TBN6whS7$I(>ird4dO7$n?K{Snd^@YC__f1x0=Fw?KTQ(RdVjve%s;*9*s z-~jQb?cw1@rt>5ab21qFfSt>Z&#)~f;_=3Lc4APl=4L_Ah9Ko>9WU+15xrreBJ%yP zGs?tAfw`l%TeP^sdblYuWO{YhP4NQ3ube+8@K12Up8LkX19y{9nTl) ztaN2$THh5UlpdgF`b`EbKz(WtmdZb?P#tIYzcE%-zF0hGOza?tmj|lIS~vZ;DQRP zN?x(yXAEIy9+LwIkfL~KQkt$Q~Z)JrZZ$L}U;jt)D=7u`MP|2bLiyR`3BM#yBT zt6bk3lpq?B_2n_CxbmYP&}LQ5-Fw%lFZk5u$y7en zDh+ka2@aqb$A1NFyX&=T&loxMEve6Z52GGrdT0IaTSP(sMV-eLP^|tu+W20W8zdau zLgN)F;?|9G7?#g?4Yz4XdC~UWlUAlTA@JxizxwqGt_qXCWE?uw>50lC!(^Qa|8Wh%*fT%8Gg@3h*M5gdjK0( zh|$SeoJqh8m$*DhLSpqs_<2>^kX$qkw=dJB3?cH_OyA(~_+{6mf|MW)8GM2Dx?ho9 zc(i<)Ov4_Du+gRWZZkbJ+(F3db$A0EydW-0%H;_hoV^c?;TZgbYZl*T=zC{&@q}I%If;&<${=F97WgzR?99yR_AX2|7c``Yf5G#H|ZSsM;fl^)@HJ zH<#*P?Gv&_7W1eyo?Do=+!t$?BNFD3(8N7Go2H^Al5m52wW8|Rm1q4S zi_;nz2_tJ*k)-v+0`Dz(Vm<6+e(UCqtgAR94SnsU*H@p*Gc&7XBj*6OV4$_95?4!B zULoDEe4na(%~%8`%BqpOtD800G~517Mn$zHw-5l)V8fxWMpff4?q)?jh(sDQdIPKs zGK86Rmp*&-^r1r9(9+)u21$DxSm$AncYz}S)u|vQHh|lgOI0j?U6=lW*#J_>CKRbJ zqtlB00?CIhdt#|cLLtbKRGtB0-+oPdxGrfSx)OgR*<&eR#~73#)*axz%oog#6z`ec zGu2}JZ;P}+fpck(Gez=63LXmrYG9{A?0cNtm4ftbBO-s_?ze{;S}13{YTJ|7fh_WPQdqVxH`m0Ula|7Vx_c=E8Do=6ZnGwor{Za`Nj zG#>sb+GIlg{CR4NT%dgj9Ti%QXuY#cS!RI1`wHhAuq16x=_N34B_Al|5bnLbppMA`6zNH(HpC zDxcirM*a~WrvUtG>EI}>j&;1%z1;>i$5I=Cnr;Xv^iHUVs$Srd2>PzgHI%jAOK=^N zdj3yWFPNQ%hI;E@$Nr%2J$DO8IOa=;QJhDA$Z?H|uu!8{u@G4Lbo9S= zw{~`NViMN|!{XmU)y{1SsuMVRv$bQu_5|`s^$0}vmU8Ti9aRY@^vB+-Pck@CO!n9T zvlAFpQew?o>DNBOu#a6UL1?31&jLw5e=SQ814gU^sqL||huf^W&Nznd>nIm$k6*+2 zS^w)wqIN)vdy~9({45H=C_UhES*;5>OmQkcEfU#OCp4A%m`ZY--msgax|`_g+@tPC z*VRFz`ilWjM;-O8-;-29zwPe$TO*{P0&Z5@w$5>%!ArV!AR(;iDVPi?!V%fkm<5wK&Jxjr@IiPHGPQ~F%#q%ahw}myDpp;JZ!b(zvLn}rP z4o=KZ4t-a>wQvg({3AS}x_LH`T{bCwFTo0}RLqE4My=&!E%hN5BECvxnKiQd%bO}0 zFUqi2uQJvZq$M=oj3LeiJHl_5Rgc(39JkP00AVizT}?DK9c%CLKkbZonTB$5Xb*su z=ZN_uKI^$k#{0pSGQ>g&F-xi;O;P^6io{dn2nT%|s;2u?M7!6ozp?HT)hwLvNmE7= zUQ$U?kq8OMs8yfzfV?*HY_F&IJ?E5K9_H(xkRIne++$zF9s+iI7p<3tJNY^m`&W1} zgr~)ZRLD0f7eQgK9tunVBMPHb2ct^wZ=Aw2A{3C_bFNL9&e5xVKI!#!h4~N^Z}V#0 zlBBY=rw|DErmj9^T;=zH{>`(bFiKyE&vZMYuN9hbd`X(4pVrCI;_!m-ui+ULY_bk| z;eEyq4!)b{N>sg9e1Y&PeqGdfQg#UD2@0u)k3xcCO;6U@#Xou4m4dH#>aNFM+$s&* zPW9d?nv(O0YEvmCz2nUcBlWgEWKpEx%ezXDb@`&VfSS zbpWy`eO{P&)FQ?!aosj_ix%3oip+wC1F60W5<=5qB2$&sKZ$*>QME4l-D-+aMh|cN zUT#KTz<5xGpO|g3)*na^D>(ggDBRg{tTcuvP#ehPzW)bFVTb|O&Z1}TI6rb3)IVI0 z3hD@BNDu@TZz*ewAIEZC25}Rb2}5t+X~0ECEMZt z%JM#(G2G)WP&;bx~1h=F;+DjCHYs1csO6#g$f^4bfWDkXB^gj~jBg>5UX zUhN?=>QRhdw`e>E{k?A&hl5n^4FuQ&ONO_%7;PdE4maBCHGv%`^JV8&WX~J4pL7jp<`%UM6_A1=I&63tAC2CaO zO@-^acz_R%$8i#Ry4D6PW)_5pde<>FN!k)M`)1RxSEOr+TOGwew0>lNYr5OgXplU% zydWUxm^%ZCw560x*O}l+8ck13gZx|ao8bN1Tw6xFOQHDasoA038SeGVkJcrEq*8Lz zYX9(f=P5*}Hj%i>WSg*qJxB)Su=NumJA5A#bM6!7lL>2hxJQK%S(e-J$k63YU|s;r z=7X>4SK7*`INe5ju-hw5PaK3Ct1;0B>kGA3BC?J}GkmOl z4*yfFBXVhGkFj*Y*4oln`ckbbCz~;d;?ZER(*6Su0$*+q?>{{Q_0B}z1jn1xF)NB& zho=S0dQS=Rl8VUPk0n-LAZZ-wpz`~DqIDXF{R5GS-23hvW()mA70sGMU;f=T)`dr4y5Y5cWYi33{VslQfF0j z3tA8G#sh2{2OOmM$Vn*}(#Ay0+h(Z34s&r9;TNP?`_WY19eM^y;AOi%R&~A5Au9!M zESmrn@}Lq`9g&(FMc#Q}<~55xjv48tPA-YBvf(K87XIP=xVurN$$M0Lq9Eypfe91u zm>8FsO8P#)(S%hr^C!_fjJR+2;_}^9{#gvG?93}K(1k_+3q;?J&RYWYI5yH!9H2?w zA;-WgQ#x_mP7HJzS+=YyKX{!UWEm6Y3~3T#N>lJ1O>sPTA=R?c=Q)zpUvhDviZgzJ z#LM^QrJW!sN+RG`UcEy>*PK6ayF4_zmzuz;%?Q*`epSIN?BrQy*}CymCNSOGH&w)N+V^ zs>c3BXEhXA@p6dUMA{J0B_aAF(*7V2E~&Mm+K;**{AGBs^CQ(vyXGF5TF?kQ^{%Oo znJpBriqK~4hrm_eiK6c2?X12j41P||KsfUNAop+gF-UZ4CP2`Va5y0pR#L>Oa)age z8Nv)PUG6*i5@UR#-<5iygO3b&({3+GT!m?=6rDX_NC0rj80lME;C=XLp{|tf_@8Bv z+UCt?lR$n~=Nv0l*=K-DUIgp_h9*Hb?HKocK-4hcXSEhhH#_iNxy+Qy&Yqp#dZXG* zheJy+%U1C<^TD3&VV_2sl2uqrTo#2f1wSYV$(Yk3U$fY+toR3S@uxw(Ro}Rq2L$Yp zzigJ&l(-JLjl)f)`o29PIr-iT?y14rGD}-qZApcZkj4IR;C=Nz{1J{^w1|uz}`qnaf6(1ocH)~d77T(p5^ha zdm4cj6wfJ|048NkYEi0WIPk8%4pz;*)FZ>K*eD)p2}2nJOVc6Nv4+Pvf!rFR&qoDV z(hcC!hW5M+87`%mn3W*8AwQ~0DQzDrrE2M#;iJ}h zFX1AG=;zXQso5yW%_rW3kXhlR6L*|!droxoQzyS6OtCu*t;$OHVmY`lX@)n&*&g+XcOI`GUit3-jHb@ zGa6)ubuINvO5>zUGYu8+Mz*n6v<+xF{d%2y{Df3GEKoWiJ5z|A8GJ-`9nul@pWE3C0&i$bo@vvvMrI^iU|iGLoiqnyLM(GOHpl-V)vL7u`V~Sbhdcg^)Id z%SE+#CpT0Vx3c?kA^92pGow+PD33@^Au7sWIKmC`lQ|P&1DAibM?Hw68}KjL1myAz zztaPpKkxXeo?_ICDV+TsPq?%^EEha*YlBDa-ZuF+qv zj?`4hCM2%@?m5Hc&+_b88WY+%*&8_l6lWFt-XHHD=v|*e|Gv}p{iCSg^>92@a?TN7 zX^XpHBi!xKLFH&AI92p7KjQVIVMmGFl%eO0Rlh_SR0;q&)`1n?QN$_b@hg;b0Ju3% zh-L-X?spzmc`nDS;#;@_Dc9@579NnZIM)FFjOhdPi;+<$cAOOT_gv_rWANTe`O7*ku1_>tTUr z#)y~3IF5_bir=m%KWM)g+E@XbyWI?X)eCN8o#2zI|86dhC#oSi#akm@l?-1&Mc+`% zTN25Z@n_OeRuA+)tLjE`G~L!=w6F^DWi9@DR9kXVY+_yzbfk3ezkKVnVGtW;-11-V zXFC)(^fEmHKTKCC#Ozb1xYy_SThcM%^f$VO*r*R#y6!|kEkfR3(1r&2`APdQ$so<( z&l{%%TActWh5C#2S~%L|iU>7}`JX+q12&#aO{pxAj{0W>a=*#kUxtL9J&uH8~iUSTsx-T&M-bOb7gGq%d#%8*#bM1 zwN;RSAzUZR|3u02?%&jx_~g2-MxD@bW>U%v+8(X?h7SNOc$O_s)Zgc{e=t%4duieL z?28phjtd+)7ZXW`6RP%3e#x$7kgGd*$FFT8-Nbo^Odo60;gezD~3C zn7JZ}rJwg|aucoe?sA60Zl_@L$>?4adDRI|Q zkJib}pf`7=XUKFNDa|p;Tibe4trkixX#E~r?{K=3HDR3RoWlm4FsCr8qb}dBcafug zje51N4c3i0%O(>vdoW4rc|W((YhjN-s8^RQj45GoaWMtrV$_bb{ehuRJT zbzz<^E%_~lx`*$XD}0w4B;tffYBqtSpUu3UYh~`hc_L2r1N+cKUcdfZZCY9ix^lZS zdL^?w4oGQF-qFG7VvwhE6fd+yeSgaeZX{|Za&s~;bMkPOJ^hsAWvgz`zMcI+k7PGO zOl%quA8kG`!sI8Vfp+L`XXbHJQf$e0Ug#Qt{U>zw(xB>Bs`Vf}uDZSsWpf6$APG=g z(Zhv72{2ff0m+EthbYSIHhi05z6TF)y0diC_^?lcHdRAk{!}Guaz<20ti}iq+N_|% zp_g?KIVExEpKqeS5Oi=B)zN{RbuY~1q@c_0&R21TTU!ifhqaxjm3gL0Zl4a5forbO z4aAz#8&Jj8X(!`um3ghJ2g@OC8eV+JCPC`Ea5Y#xVw!2Zt|)5g?!AP;+4t>6|6N>H z+%Z~cFahe4TIxuo$}fRGASO$;*uuLl;NrC_-ahc1Fl_(gOTrs<f|XpRtBv9 z;g<5?46l}?gV7uf3%9=odWXMBqF8x+=-i3j->0Phx1E2&g^1a=SJ)jFqrAR;#-B|w zc#CG8Ir)7lwRur!GeQx-CD94K2-h zU80n9`*&G%5|pho?D6cBwo@O0DNC^^948J8&DEgKIzl?;8=G?~ zGa>(Uf;lTex%GTvXUpV+N9t6--4=Q6-bFv9U&__Bm{M8v;mo9JZrNg#)AY*-maoqB)x~fH2O2i&OLXcw>ITM!tXu4vb zb?xQlYa7>Qmx)a9Ty0-0reeG**rylf&dH@W-0J{qUFw%vU91a< zC(;DTy!YZBQ-5#sw?Ad0i7u8Wbm4nOOpdd@uP?iJoDAsZ?lnb)0yk0UI~&=niSJr_ znO+P0j9s`Qxt0;dWxx6xIdJ9Ji2o3A;uNkZUEC`^a7wFMIY;C*l^@@fpY@PgU{*aR z9<%d4Fqd$Fwmzx$sH(3o^B%W!gIHPSRDY|N&sQJfiOZmqIi~X^T4wJ@!yV;3|FE&) zijQ4IDxBk}G(1yL-hinXbV_^5U=fCRHFq~{u@^DxD45;1JZU1jHL6ndgGQadWjMY> zF7m$wA-Sm%gW5Qfyuv&&Q&OBQ!NK;Zmq2rNIw&{-B~T{c#%I8TvnY4+MY*=JOUD3l z*N&@9#j~2ykQEIy87M-RCrht;I74@ElBOMRBtqs%9J6fZ{&ZKud_spv0(rS-?7x41 zXjoo%c3)OHY&KY|fMvmV;j(o73KMAjw<}MyF!}3N+i-o(ye8lcZ(Q%AUW>?}4 ztfV0up(oWi*?8}DfY4{k?B|Vda5o2e;;xynYU3^z+PK4+I!19Phta<=$i0~B%!P8Z z=6#)7#m3LmC~2kjgkZ@^Ef;$&N-$@2$7vy0o!{Z5|7U?R7L|?v0W6dc7eU!QC54IM zcIgGKRl~m;He=n|uQs{LU(5Zj&|VS-hKg82E!ENgC%H|`>&Y%=#Ctx~B+qtFqWSi$ z(&CdPuz4}a+>8mUGWsprCOD2I{BH@#pA!RWCSuZXA|_&fXBKiz%nzzwRXtB9-cf$L z?}rm>O8h3@HMyBoQBO;6isqPLn?uK)eu!zNOW#pqEF%(OEux z4BA3?U>hIidh_^dPp%|br1OlwQG4vuY!|dvBdCn|4!aa}`}?H7*?@tYIto}c&Zl$t z@PNmvVZ7#Ky*Wrp^~RB7BKF!FI@oFa5#8ZK6PHUR5SPmcwgn@lt=>>~JoR*`>*?Vx z$@p?JBb^b24l&BO=E`hu()s_7Q&3m}p7dTa(PnqDbff9A_l+oZ0HP?V8`L=IP82Y; zmcYlh!an++fVut3XKe*h(E+~{X5#8!=OdAstV!4(DZT|Z@W|T$oYolfZBve_FQki; z_>Sd+^t^d>%=2wZ*+Le_p6yeYopN{h)2fY5Jg*)tTvwtnbfASEwJXF2TGKaiNzYS~ zLW+6`z(#JFF5U`{Jj4H<*~*6>2^X#S^E7tF*~J1j_CgmpkBO5`7J{z9U3~p9KmUva zfPDC@=fP4_gfXeGBiB)5E54My;&=YeqJY@!FMz8?Ser=bJj}4e^uOE@u&I2O+NBR! z+47R<%Y8+&qvQCXxkiq7Yj+~K+)Xe(Ftm7&L)(lqY-Y$W!bbeNO)b06@|&uZR1eq> zwQsi>3{gPedXY@85Mr@KrO7%cJF_4QQbMn(HHCF^>ds$t;nJ}u>0A?bcoK@!VKm_R zjI$7isFjWUX70A>`g*WoavPn;C*!(sjn!iK)~{7Wp$IVfrx7 z89F$qtt?-fSJrM9|O2DUCSQ!H!hPHBamujE+zQl4~ z^lX>kedlMjIKmm18H<^inJlF4Co4kJnIME+JZ1%(PO6r|Tdl4swyAM{!o=1D4^-I0 zH~XJFWJh6YkB_HwC8ms;p5Cg1!GYcuvr-r+98{TpwRP;(D?Gi&%`ibIggu4Sf_&;f z0obHShL6kiTdHP*Z}90dKve5`aeueb6j>Ju2MJbE%UeOZh!TvTtCaYAS_5i%lg!o`v94c^oqS4s0T-T}>z*N7?`tS>JkzPyAWcKR6kk+LBhx2o3`=oxRffevg za;2WAtxMt0yUs?Bc3VtP1+iJ77y_dhq6IuGbV2r3{Lh{&VfzxAGk&IIjaHDAMi1ZK zM>|)-4(8WzsMxwCVNR!Lc<5ro^R7uWdVq`Bq5%ry9q8qEI-3|GAUi2WnaHJJ74jF! zR{}f^<@NHCspa45^r2Y28?M<`R^npS+EH8HDn@WPZlFsPy>HDt|4KLa0N?v;v+1R- zXpq8ZKy^cCGn`>7naJTd#ivp!EY0x?2M(nP9q0dr0Dc~JpeT}H+N`!Nuv*=_Ro{IT z9JR7sBRYqN?ibSpwe#Is??0G-;i(UA0%Wgm+QB@Gow*PNTSFsEx*Ni3cETi}rv^qaRywI4*o$Aiq1)M0 zk^HVnR+XmhC3Oyw!Vz};$8=BvOlO~}jK5>z8|P;2`n7tMKgt~2wS`ff1AO*{8FU$m ziDb0qhQND&w0?;Zwwm>u2R3?@$7$gT-y-F|zHAN9-7u0Wh zJz($866JC7?8+M7G!a0DUqkix1OYLUezSl5)vL%aLk7gayeh@|tj+FHs6e*j{I1}a zsrdIX3*c^Fbf%q(55!;Ov`JkAw?wtKspXU)4e9ct??h-xLytml4puQVO`AyadIbm@ z&c4WRvd8{cngQ^C=H&RE&>nfppbK||#zMe_5f3Lthz0C_#P2Jv5RMd0HFg)My1FTHVVFY|)e^6^HdsXceI? zx3QSg7ru%4Y&uVpVk-S7h+kvEVxi-vCI6eN)}8+eM0TX34Cr?15XP8L;EyjkcX`)S z6_|iz&_xnJ3D9T=gC<^4O{j6lIek6eye}LA(9kfV9-$1sGC*E#pStXhZ3gk|6(%L# z5>!>m%9Z9g5*yxLD><*-IioSZHd(#E{M~o^Aql8GPYpGNkz8Pz{e#k?+ab*P;SGXQ z_kasbzU7kY_kd^Bk7{~_CnB>*3kmZH#lqpU^zfPIa0=khKNGdbb>&PF0W>s00?K_Z zRy5W>W6{fUi+bViLsy&GPLhc@98V+x3&6)-jCAeExJq;|^5NXGkpqVec|Z6Yum0SX z(CDihiQY8{Dp^Sk!4j`A#r=atJjQjWw06)>G>(Sjo`k_~&_B6@dtek#-vx4hgh$F? z`&ktSI1YT#crP|Xi;~qzKyJ~zev#@V3)Hq{MC%IJFD2+wp;0!rGxr5Ws)t9_WrX3> zD_F;QiYs)tA0&~St9jmagfa9;=TOr=2MAj4`xQYwlOaX}moKU{ zsbko`pRI|V0-)5Vi}5hEuVxtmh>niqQZ=Ha-Ezf-faf`y?({(QsQ@yzQR||}4uFBR z&t?uSQEad}EMwG+hG+it4xAtqPu5o92&7APk&kDD@HMLoSS^3Xwz{3Py+NgPU*puA zXSiLJG6Hks5rMvD#0H0e)*WYlC~*ai#VMO{+E0CyE$d)*D6kAhfAZ%w6w1-_l(_n@ z4GQ?z)@QVmB$6c-lzYV(%vq=Uv(z}6)p||yZ~Jw+reHIA-)n`L)+JkAJ)=&1`0$@< z4CYJTa`)4lKrdhm*lzYKaq$@HB~ZFy1p&)IO(^`rDhfxQ)LuvQOg25|d>P3TFU1>-Y z7Pi*9D15JtB3T|5H3C2t>NMt?*@5$I2Uk!K6vQ`n}hNjuWbxv33@(+y6K)6NVWfsArpC`pJc3!lvt7G z_{~>F;iFG4Ez`0@5_Aba)m*b@?fKZt=}f##^WkRqMm@GlVKqWB%JnO)^W0KnTS#=f zXgIv^4W}pOA!eQiEC!cIGx}3}!Rf#>irIcS7}52+VM1*ZiuMqwq;wF12@$Hi_(Md~ zejZw5%8O5AqvujN`3Ubp7D--EzTi#Q07NbsqNNG@QvSXE-I>k#VI{7f&kn7gXX_67 z5))SZ#$Wv4zi;$3DJZ+t@!7YW;5*%_Mf~+PzInQ2>ECa0hFG?yRA>M5vbBBYBn5Nt zeYh|RUXX(InTh>&G{x*+X!5I{ZvTk$%A$omutw@;W@H)@zL;r8{%j88gOewAkF>kFb6t5h1w?A`k>{~)e5;$9R-L~= zkU;C*0?zz{KtsZwmkve3x%|}oKFo8=~Q(^GQIahh3xnv^ij;p}ApwmoM#NDaXgCG!bwRw462l&-87m=?F0rZ+v zmq@mxo!a1Gp;k5JaUUrY)Ryn*JFe z29m-*Q=C2FdH;C;Fl~u;`^IORt`m6}(&cS}e~4L=h0aX8UQMMao>t7;~zWkXd)3&0}X(R`$ID4a9uuSBqR zb%}zSgXa0mhS6v60W{6aqYjel{n=V^HFmfuoQ@K*nG8X`WJk-rUQ1H1It+TaDJdv; z`h8)HHa1MTPi~{H5mpi*xRz-04PJlTOgRiSOMCv^)NLo)Cum6%E*DP3f+>!pP%pjr zqL~r}&ura+XXZDSl()-wb(QJ+7j!rHTKrvOCakk|Y_IrH7B>W3X{MjR{O&rAUND;; zmpV*-J))6h)DF5fSDor&<80}S^7u(-ncp2f+S|%Rg+zP0(R?2`IWs@R*kDGl(8i3= zJQAINv@=T6=|UdL?MA%qhmWKBtj|s2IV|+W z0iy=bPx0enj-pop5&%%}_er-!w-*ohi}lkdm@9;F^Ph$725s_i8BhHdZy2b?1+p#V zmOfDAeJsAZG{(kb5j#?$e_t+exlDVvmqO`7^^|b57#Whx=XYN6T(Gm_AENLIAoNyi zt66E@!|YM1rAXW>7v*ES?-Sr84hi-TR`4<#lR(k`S-}6_d8iC9Sie2J{~S~bh3r=M3R7?alY&R{_r6yx&y0~ zF|QZb*pkkIk{8(JOhAo#)NIVe`~`FcFf3Qiad(ascm)!|M>)lOh#|SUJU)qdM|vq-nx2U zGgr=jO~R`mAW4-N$g~I!eIgO3W_P<+w;y%j3L;A*s{b0$x6SS#o`fytlcEXgFuB{& z+mP^K`m3$7ERbUvdqE%rI(~*QF~>4_qC1#nLswxf-`*2G^%^+MONJbks73>N^&^#L zz|B~$uhWIS5}P*R+y)T=qgv*rT0JxAHafVBRg1N~2%9EX&_8{&KeUK}0Voi`KccYzQ!JWPHK3>nk~Z9Y?{-O62e z$dr7>drkcgi;)~9;Jup@d|bTeSn;3Q=kW;Fx)WA!63IlosiqYRh~$=R2ej<86|XgG zo36h4jAZUatk0Fgm8Q6M!Eg@QHT{8J&%YNnN48dgQoG1%;3|N3)MWbC{7iu8(P<6d zrzl~#W5HVA;;MDTPj54EQCmVQ_A{A=wlEUOUhHM5`&B6%*H1eA&4E~VO%cUZZ0tA^ zVctNG({j7cyBd`df(b$gDT0TY=-P+6nTdevU<`o~{`g;gwE1ykRz|_WR^NTR&xHIo zFTt~c?!99YG3HB(>}$Tg%2YqKl6;1dz+JrYC)jFOP zl`X3w-;^?XPL<4(orc^@E8gzRdwm&MJHg;5B}Cu&V}epz#jiFQT`<_f>a^%tINpXQ z=WKqlde6H=!@`4$aon3qToaUk+T%(iEvhearQK5UN-~*c4?P*nxA-KrPNi?s^;qI! zt^?aFJzPhbc)%z8H^+_womcg2!RocB)Am}T%ajqgS@sL}APIZyrD}m>nr2~6U?0sY5RdPN0ioJ94 zpFbx(&cq2$C@3wj#(4K8&^5ov1J!@s=h(*1dm6XTfy$Q2raM6cq=^w4b21#i8X9Kw zZ8E!B*w1iRK1No^NHK>~$7Rz54WN$k1_Hv}wkXZQ9&lZ5O&)fG))~dyQsMzImu#YH zG#qf%aTB9gfyaWp+o;!HN;l*dp>U0Mao*R`0M_93ZR>imvX8s<0jtbYU<5d{&cl48 z>t{*p<*)db@%?u-U6#j1R$P~N&68T)H#=(=R>5v>wcqteak)COb}j=}wbjjiqnh*l z*~`EC`iRTG>1sk9;OM*%7)oJTZDZFHM@E_V1OX0extTxoUR-*NaNr@%KOm9MV%BYy z*@|2REP_^wadgxMnKszNOK=j2&P8G;Oys1IQsDmywaaT$M1p#ZO;NA? zmA+l8RnK$$>F+RRo*MMNAG+>qALUy6i_e}w$`%{TdcGjZg(@WVOAx<^zaZ`pje&zY z0BMdcV7;LEusglH+B03KsFu&D){rOj@uOWb7jM(q8-P%VBGgo$Rc~j;H$yEn23@5E zQM=*(=97;rC(WLUqZjwy5;K&8xyMW0dxLGj`wHH`MUwTQE$H_0Z5On|&qR`Q4C#89 zbhH9UcXuu%oZ9$1?TkzT^{-Y0uy{f*xNviSHGbs&l*uK$i;{yOwswbN{ATu{P{^3@9DfUb2@cec9_0O1Smjs-@Y02;)K&NycA+u@}u?(>S3nv_jI(%ANmQVbvCst4*h>+(QiYn4ynr}Bww1+J&v3GHZ%37%A0}qPVi677J-=^Q_P< z1GHsaB66JVC8U~|J)=%rSeUFVd0$7Ywk!)nD&vIn_kJjHpcyI<=7VZUXSFQZQ|6rs z>KWYYa)RqpnfC$(qKcJp%|EUI7v+&Lt(HH4Dh$ex7?(o$Vk~m7 zvPT?ti)Oy^4x7@Jm99H3FMIwoYhVHp+pjb%+Y(?fQvDErlHejAol5~1^F5Bu zSJn$skn@oj1SR^gz_>wh**%a5z)A21PbW#^BVsQqyGkIh@Vxm8!ffDH1T< zya&l$I6ySfT`s%Jny0IYJ!I7LK;sCF#*28GnV?IJSZ3lL_0Hde%ugt8!*j{cr-2+* zT{95)J&_o&i;U?(&*?AdJUrhnk)4n91;lj-cjMjLAC6FUKr^|KgNiYkP2PBnuQa>3 z*M9wZR;4h`&o&+%bF;&SW8$+;ar!_8Hrv&^DbI+(08L~tWeiKEQxP z7YkD^ssph7laV6P^pQw)%WAe4ZtwWTooulWm9R8Ry5Lf|jE;9<-V4RG&ds8l(I>nB zK)hv_b$KPj_BXpatn}IBb2)njQVb#6cFz<5L?d=wR3r=gP-2o2!{>jwfupC1UwgF7 z{l_G2qz74aC?fXey4G(g3saK}{Mo%SMS@}V)@ts1o-N9X za5N+nXY4VSAG9ma6u7$YYGi%zn>|{w*XOdy3JwU-Y1ck&pd- z%cggdvW*tbSQ24uIDcSvo-Qlvmg0*(UsY;aoTGhc@c|(3yISE&g}UGrFR14)!e^0L zc~HNDlei=6jK>35S^WqrcMduy9Zxlh2{X?aT&ZSdpJ3GHl8*uVq;fx$+YeB-O@EIm z1Fl#Er@Csr*|J{w;9T!b4kGhht*2@MmhZ5 zSQs|P{L(BNHjIx&ng_c@Qe6WhKb@GUWNckbJ0ll5hIKw9^#iFun;Mkg%8e$uJy>I&X>e&PPg=~@ zIP5L>9j+hCxNQ!v7ns{G^tKCC7O`H84iPm@6rCLMjWqe>s{dGuh+D}`b3fng0LdbU4s%aMk zzeYEN?KXR4%)bZ8)`gRqP3j&9JHf-knPpuj%Sw4Q!=K0PLlrZae6zns?_)S2}nG9Ja_tP^r9fZY5CsPc5%s!pbQkO`HYF7Q> z@4wOL>N(QGIU}rc7ZFd9^0JxNNO-{sy{F<`yD%XqzK6;b21o{$p*}YWH5x_;qTrf@ z_y;fIMsIL{;_j4_B}ZO39IV&6V7jDtMXpy{eGb(prcaLDyI%EB2!9t&F;~IW$ z=2c$2))O(*bz5I3A}w0)K=wt-n}PYG%T62&HQ}N1rwcBxwqvYzK+M@X113~V16YROGSa( z7{UBr7)##fqO;FdYOa6lm*cbas9ApZwu^oq3{A?KUm^OJfsc0ZZtQUS>r?l13vzb> zj1i^YnMHN{5J=~WD-4nFSgLa&utq^IJw{Z=f9G77g!%S@oo0WLZ`@75+GC`O0;Iyz z(R-Adt8!Nf7`khT3YwCoW`o@RPK%dCFZF@vsyW(LTLRL4x(^0eDfrA&W{DKJ&pH{g80Y|h%YmB(hDKd5IKq}2cbBCh78>PR zMSSj^RzODe`H=q0b3*3p=F@Fo9yAvqORMKg%gdzlQaB?sgT-i6JM8E2(H7bnYmG@b4X!{Y4yhFLU5^FAaL1`q0KkDM5+mH_{_UH3bM%|OyQeiqNHxGkpQ0pfOv8p6hKZTyJLO8=;aphA> zVID;zl_{=45lk_2Pk$s5lcY0Mb#QkdzdCT_b1t~kOVef3jUwIMs_v1TU6DD;q-f#V_M2d^1Y<%29R*D_aQPv)^P1Wl3K0rNt3Um zemIHKwi$`T`F%sv_6m><&-&KwkpDDG97@nZN=S=R!_vD6HhF6XTMFb13;|qj;bK$N zxSeJ^mON&{q6Y5Fv4gFJ6OJ)lXm&Kzc1IZON-R+Z<&s!!jy$P$_>)x>% z=)uuoBA)dOSo&)R4Tin+7+Z679E!u3O8@*zeyB0|rO?a4`@4e0V*~Ms?!!SquC!XK zd#z4*>=B5eZwBi5rxGwOt{?ftoFWuTb#t6g6;Fd~pe1rPPMonPOXHhsbPJyUXW_I; z*ul7k`9wPXsy=j!S*{*tZz*YlSr_JvqlKN4h$l<`{CN+fo2j2k=S;YVxej&!5>>4< z@HKfy;GdmNc|f1p|5Pvu{7?>f>s3n1m>r1pJ@!-U7n+aln>=%{))pJS%=%oFQXV*Y zQvC-TX*1;tdmhj<=@T-3jqg0 zXs(v`xqQl*u5m^_rOkHc_a75KEQrl;Dx{;|J9aRkIp)N`=6(ds-JR1|lS%_iGGeGK z{|!7a#6&7D7}$xo$UnodfWi4-PHp*&a2DTpO$-?_vfaZa{J)tp!T0Uw^w(O=YcyYR&#=r**AOZjs?J!2$|WeLd(Y5$wUOWZV6e2SSKQYSHNPOXw_7G9`ulM-^rdz z8rtNc=xR2txkv3m;5UgL$D9ENGzc3-n{h~!2F+8o5SO}a#|S7EAnx!`aV=SN`zufRKK` zcCBc2gGWjN4q+7aqw#tOr-k;ndmGm%@`0Qfj~EX=>wSq4I--3t=7J_wuk1)qN=Dkg zBb*%5)`lejR5MFF=?Y)+k>J_>Ty6b}iFBWOk9)c@g{o$`E7&C&i9 z@mM+GNHB1h2{9p{hC(V47vvm*i_dUyR>_fOyp<#t+*#zH>>A=oAW!X3gJPMorl!`f ztc4uTVU$`TtEueS(Z}t<`IO@)CGRe3P#Pq$jFI;w27ZR!y^ht-vI_C-ni%{Hm;->_ zK;G<$Eq8==lgsSYnQ+z$3j2CZ5f3DepGay z-7UUdTFIf*5kfC>y;SB^i~JHpP2*n9r!^#4*m|=!PfVOEnmQbU^Zs0BB-p&iUY|Hs z!!{xEK3h`)_`sneuHv^cX3Shpg%+6mnJ;&N;IN!yCp5ZO_TnxWm>kotp@}ZLyTiPD zK+XxoNpA#4yxS<==;za<726Ln*_(iKm5LU!G)BGh319k_`?G!)~FzB1p^#BSQnjEm~rI;dd&cqTVAi`y_G=#(YID2l1+t$Et{TC7(*b4+7U_c^DH zAdwkV_Bg)v)9k^mcrn3sOxm#L;+mGOVQZXw%r&tWAU;W*3DKsY@B=)3?Ao8+T{`k5 zzGk9}&jkSgSe#FYC)1X;ATc%oGe0c+<`zP#m3(X89SgA(c8a8Mg+8q4)&)U8A=0WvgmlSiUN^hoUCzdn zag52A4aucOnr*2FQH-nQFzqZa5-`!&1kJFrdtJjH7;YB=f z^7o#3hU`g3p%bZWslmT~O+mvzzykFb zsit&pJ}l-=CSSby`^liI;oy_SBEmq4km)baS7|UZ)Q|4J>QSA{Pgi9hMl%wg1QFnB zS*r`y?e@@D{fR55QT*UXnB?QZjQWnP+&@CCxJ2QLMvEuuW=t*ar6y2d75rxWM82LX zwj#mssc^`yvhw9}`0TqzDaY+hFa}Yr^W;NrI8a}!>IV@%{ zcQGbX_O?GtS;hP6a*FqE*xyrNuFcS32&u+r&l0Rv2WV=B6h;3o_$N91S|dBv6uL>Q z?+_W84@j6PTE+^W&Z9oKv$%br%^OnFoo}d<@mwxl4C?V;Q;l_LyQ*%<;%Q>hvWQr} z>vmB*C=^LOA+!={IA(Ji5&I z%*5EmE$6~DJ5KlA{zAj~I;&PSO@F%fwndX@5BKxxF3xPvvHJr0ptX7bDO*OrF3&c7 zXq>r|#ctKtnxTDO9X;Lsulv~YpiKO+SN*vzC!ZcwPLy{vsW|&%U};P02XU{*zX8!S zO1=!pyDyqgREN6BLQ#y#M6v|!H~?~${vIMS?e_lT1p|WGmeru9a(snUf0gpAB-Fko zS7H?`5w1p!%&P^<%oyi^L&3NRwURuIRDrbYft*sILV=Vy!JLg6@b=Q;qOI^@J!`eW zG`?H{3+nVl0@t^+yE+ulYQ~#Ol{ViC9I92YI7&PxgEDi0Mgjf(#m2!`Dl!BXDI@Gz zc&Y~oj0jlVXqG!AHV{{st}$A6Pyyn$wVerkB@MUlLRlsUmuu>(K9c;`iKFAgZWQl3HoqI zbNkWHJJ)uwl@SG!dl3B@bEZ24gWR>9Z-h-eiJlEs5QrdC7 zXh>E&J-|g}H7w(t%W0AOZR`{eJtTF!LThfi=G2Jc z9g!=)2yj{Bk6#hyn^oj$U(`xk={s}!015TbI}wM^A599w_L|qS0>6J(VUc0N(aVy^ z4mj(tp1CTftjc!qSS)1yI0LuGeySrMu63U5v)i|kd2)q<5*2IHFo|jED#V*lQ{YpD zGk?Sb;1W4kQ&|!W{%;JjOF(dDGxyW)5(8)nA_iV($FndX^tXT*h+nCJP>mi3GBOIy zv{ZVuS19e)INn2KiOAap?hvNCvrchcqox=>f5*FSo3jl-86ufmObwLkl$=k$kvBjx zW+z&eqoSuDZvQw=F02}Tj?e=2XkcS0a8=DWrf_nol%>$Fs?Y?4foo}ozj4YwL3n1x z13F2pgy+y_NZ)a=U+P#;`V(iuWxAczR4dy4Qg6V#j*&KMdkqinK=?!#&<)!zsN@W5k!(h#TZF6R*N#p)4^!(mb7{ zNcPt;RI()g3icn`{8alX1UL<`k*Lw+sy)yD5fix{3U|WsfA)4;)_PQL()xn{Y%TG8y3|zWSGHUu;ZL=-`L*E`)T9K z57OLX!@+LxIfc#!4N48mdp=a8Tuks@m%ypstgmGw8Xb8RoO9#1El}+fBwwZh#Tj^8 zI+^xAwe%{}6yxy%D^)Hyow={5awCpLM*sIx;<8VSzwQuFj>G9Y$(H!sCn)(B8eb7d zSZcp}9hVkGQ|bWg@}7%u5%4AqOqX(z-t$%i(*;z#W&>#=m9|8#T+5bovS+77#;Dxe zq6EzMO-B)LPny8pzM?bn`OBsVqTyv&P`(6+>iQEz$OZ7K$^3_#@fM6m`(aq;o$^4h zxPOb4^annxA&h^c_ATg7#D4{N0xtxx*4??;2GERGAPs)BRqW1ZvK5uXB$!;DUrG8? z5+mLDN^?JRi@Hswb3v6mDJVW*>N^v-Tvi6AWSlz4!^1`8-I;%Nk)zr|Ckj68kA+@wU znA}ShzeeQHKUS=oETb}d-j57RrW(}^v*}s&4~UEw<6^f*bwbU37u8HGlEh60<>3ZK z{TUkCFo?nI0aGJ$Cc&;OPJB>^m`u6|LhV}p^1^v}zf=~CF}85?c4uYOGi59L{(EwX zy0+|S|3hGjay zh}b&IZ_hBUG3Rw?AX;#zz}*#OyOp`3vNAox&XeNfWPZP?LelhM!A)_Bdt#5*o%1Q? z_naXA!NZrott4r1N4WMR6da%P)L5xBZH0w14Z64F5I=6z^GjF=E}ie>h0mef`6YxQ z>1$H8#u-TeXiB!n&YgC?VCuFu%4-Rtkbc|lBNzGW;-g_- z5L;(9y@MnkV2!|$FS!eWK-!i-?2-JMbhsuD%jdo92_YYvbI^J0=fl&%Ce5aq^RXm9 zPkLfx`vJv)KdehEJ#UA`_aEffFKe=OZC*1FDe{jG+Hj_05Mv=fN5ZmfKVc@C-v*1^ zP69VMcG(wbP0&7P`_X<_()^e2SaMlOpw1kWGv+*tWgb@O5o6YznWQVOV{SiQ~Ct}B9)G+W7~q-1p~UC@}l|_cFkrV1L0$|g^5NWW{_EwK}ge!F{39* z@GV?J=`nK9raJIDKF|08a>saT*}}~sU0bW+riEH`w9FWhZQ1%6d_jW#>eVAkStZW~ z+#(=>gmQC;rn88A1+3D&oI>FPYVodBg!A0ox0HUU+DAFSr{Z$!+53aTOE=@3MGcU^ z8EwD9G>8eG-yI{t)(gFd!H|rHNZVUV z*&*Zce;DoHPbf5E(@|k>&-Q~qRon~Fv@G`=ynErH{9l^ zjkjJELtn&2k?D$hwj}?VNdDHnPk^D^OSRCf)X)7$v@v`r#q_;?LJvntSl;w$IMIzz z_k6gA(rH*lj>itFR6S71fVI+MyF>nNimhs>fB(1i*zI`jf(!(j-VW3gVEX%?Nf)7M zZq@vC&~xbfulZNr@9q|Uti+tdX#n68`=&@u`<`}VcaQH?=;3G8HNs#O6rP1-us}od zKf2^Y!Q@;Z#&LWq&Vg^T9Jp%>9KrE4v>mCSR!z(E$wE?@67=%ycG+`b4rdZp`kC84 ztL^jVi>jwKgDd21ko)whiB{{OlGTG8?;Dl~;b7a1_=f>E`ze_Rf&`C&{%P*C?X(2I zq~0HQRvQBcSb^f?wAfXgRnV$GBHr)y0Z%RlKy>tqz^)`L==5lD%j)2mc4x+-e1q0H zR8{)I$1TAtt1Si7BUqYSloNYwgmwsyXjXK&cV@P^iPG?LMl9wNY?sz6+U+zhr&R~L zk&>l2Ryp%2hIRI!tcJQv^@n7V!MB;}Gv!9QkkG<#X1d1fUz|L1&N-dp7QRDRZ7<4g zX%4U8+j=NTI&c82sJQ>Kh5K3GLmEt#`C-IlUxcwdj9lK)`PZW+mvOo6h}D3lg}t7@#xl$ zrkg!NXG_5A8C;|2jNmUvhSiIr=Ri#VOp4U?Sh(qdK0^8jO9QXIl|a1>Q^r0A*lTN( z9GBgHY>I;z7PxiXfu4YpY!SM+?!uETc^I&8Ma-4zX>%RQ)#QztpiUFioU&orSFZ)d zL*kJj8cs&sN04R>7si~IhRe}4Dw9EE?x3yG;If)xg&O~!Ia$^BO&TRi7>agwKLl89 z7t`cHza0BgJasjE9ba^m?#5nVPL0I_*uyk%2aL%&M}^`Z&=Kj9B7WSl>5uAN_B_0J zcXBJEp6mFMC>SdDOrP|}udUEiYF8ZQqmLe2xC;z$cF15p-dZp~DY=7Rw|f_Kh1}$( z^5Z!;zv=u_GuWpMgaxO+i{qNKK6dx;f_qpL1u((uA}~O5)GqAO)NecgxbNvwAKo+n!3B^EZ8%4*Q$6pPhCTh9Cyqe~h#UyQoAK~U zaT~b2k#6}vM4e?oRA1EYX@(xUV~`k-&HIN|A06X^{|+8d3=X z=|)0nNy&Tozwf>G6Q7uU_KCgMUh7%EhpouYN2=~~_S-i{U)f08J+q1$zr?_AG4-2+ zb+i8sWVcpV5Ev;%8hC|Sv70?au zm#PhBe3M zy)4Vc4L83q?76tQtgkx+50{kag`z66O`-m4_QtGvlqCsTzzmg@G6b`l;1Zn~GS!tE z(v#HW?J@c-G2S~x@+ziR#JOCr$zQEIC+C8vo6r_rAgZqTDS1QP>-e{bZ9awaHJWlJ z_1RPquD)4P36Hs!K=B=zTvYu5W78TAo-QdM@x(!J%a~d;acq4rP#cQ}It%;;{~Qmi zEj|00cX8o<6Mf$vdj`ncK54(T=)U#sB@_UT&wx2D0IgP=z}eA_0vb_`e(4{-834LX z38d{$**IHVk<6#7-E@+(o?bNY8$fbyvuAS9U`Pmwb50FEXn-g{5@6* zl0w21LN+-UZ3hEf0MsP(RP5+#zH-dgzfCmfbFi|2JS}@n1+>l0(s$*n5=N8WgCe}G zw_}v#D1RW%FURN~ixpZ_+8w0QhXp1+NVV)VWXfq)xmM-?orABE*83g;Ju0m*1KbVE zU(8q?Ko}ZjV!~(Dy{IhD25TK&*#*vz1~<{tM!XoFP64F1(sRu&tI5!If96h?a*NnB8X^=%93g$YRwuh)@<~W;mQ= zXcWlGdlGHUGAR)kR$4VGIn$N;noF{}Vv0_g$eb|-to~x~qnXfDU{I7>?f-h6kP3zW zhB;alt{lA$@Lf=$?F=4YqQaZrsBaNj)WwtrwJS03~54&Ok$e^8JB&t!->0gWo znlfQ8YS-)$H9S3Gc`VkLs&Q{_IQq(KpPi}4_}iOf0M`vz2)~jXzz z#;uJHEv-*7(%}wpUtcVaK2{sYKy}A>u#i0`!;02sSt_Ddfx9E}fD-2G4Z`Cooy;dF z4vaL+q{64~Y2O82XnX^|AnRe$L3V#kxA?P?#awUyZ&s0u&16Ih!l;j}29}Mw7eB{$ zkGzT4ZFtuT3%pFIyF0)QU{UEnoQBueQAmU;6-BmA* z0HJ-)$1re|BKK=tI@pg)c(jy)GWSbhhg71G>=&wJGlWHL3;Ni^ztn`s1J^V7j1b(z zvn`*_BiLU@GfH|!Tyr}&J!7mZKkUB$8*!hZ88iuBbdzr*r)P( zHMlID+q(Z3;!F{EV?9Q~r6nrm^daRD z@aDhn(yk4wg-6amBPyt!yg&sB;Xbo5O@BM_I@rB@8Xijo+7R|6BvF;91%Kx6xHNm@P`{mAEmUb9O9O55{Jp=2_Teo&1v&C#{wn>zMt5~@8&Y|!}A3S{$FBs zK+DLNHwT^#I1%v&X8fy2JFYxX&Y_pWw z+O89vZ)<7YTZgYZ63&kY;giq0pH_D4$RJafFEJ6&p<$r+nxG@vHWoppZzfk?+Ves~ znh*MIj1|=>D0@<2A_xhUxi}mqDXeVy6v1OROd-P7B%}*0p#v*i#68_^&7746;^YFJ zWVT4JRl4Xp?^&`PA9tV&*>!&ThFRwF`q;JB_HTTdD?D+VAAa!6I{RAO2mp}m3t`P3 zx}-Nmv7JzSL@3Kf?<;`W!}09bU->)7{HtW36M1>vsM`3v@Xj-ZG*fAc5AtA+cYKP1 zT?)7bil7}dF#Mpfmf#10qd;vgd|;PAg(-fZ0TMCKZgM?|gk$;eH0?U){dN~?m_qi{ zhHF1z)RHapJuCuc7bt*~fU#8HyAr#9X-<_zpt{R09Ya{22ELbyO8Cf>1s}2fZ;+4a zyHh=nZ=!zNcf8DQV#C8z<`NYs7tW`*eigGyDi{eQ-q@Y5$4ENPik=V5zGUXpXzZ^= znq|BcoCn2tPQA}tDYdm!glhD^uoS-yq?I@TxTb(8?^{sG_pO8nmEQ6xO29bk>k|H0 zz~92P2EiGU^aO{>s?CpELSf&dijb^6doMhu0F}oX`+3vn)-O@Ya?)fyycg%d&D(*^ z2D0Z_^@&Aw1pl{Xmv-<7fW>#y9Wrz^}GhBkABL#3BR{;Z{J}+>@vnuZIiz zz(tAk7tj4_AI-7QTA7{#+1wXOQcGATS?_!(=bkT`#GSa#GKhW0a;Mss+};=VitNX> zu{*a74rPZ<*fEyyKC*^EIV! z<-_fv6z@r6{xY%_`(CLz{Opkej#;3}XbS|nm@my)VeEDZ6 z!?N*nAYe7vhgF$k3Q9rkv0I@Q`@kMgJ+|OAv*z3I>Dl)!o+m|%;~qek`}6YHhyF2! zec7L#7zA8#bs0D|U{XjYmayBrraZ3Hl}|w)5lUbey2m93g7pGrj)4^uiG*=+ z%|C?H)|8QKIFQIES?B^rPm-wOSOf10+%*wps@vsgSlb{t796in?qe-t(W5-t`00kx z{GSPVO(Huuin?zaX939WQcAZ(VO`&iWO(&JvCwNEMc#;cqsCn5D*<)PI_^j|Jhh?f zm+8wkMRb7)JzVOF_xYNz%9dH2g7@I|C^QwI?}S85Q`;J?3GIJ03S!<~?Fk!4(uA?W zKm1EaDnQFLCeQNnF0f9I)@;t)l(kkR5<7WL7{uz>*_~^LMuzzt&S|8(u1MYnbTBW; z4-H|}Avm@EA~0~-!IWrE%%}&@$byj(8`Ihk9Khg8;3(Lgf!Ht=pd^7{FUUw1`c=Km zHfGCP0T4H;zeD>-G`>NF)i&68iOy;8@ySN0a(XGZ!HQOY``}FsZY=u{<9V+~#2DT{i*Tnhjpyi7l*{AlC(DQk0?N=+YZ36V%bw z0!nCb$jJHR6Ij$>2O!y@-fmKM`bmms*hd-s6G>_Jgh6dGt>z+NrMC3T2?G|a%eF#j zxBm6`!%<&O&g(<0jpYL};@UKc7y9@h9d1c47h9e{-??8-W1}54l8=u9XsF72lfhPC4=wuZG1h%ln^z=7Bm;h;=leLfBn)&>s2LdiIRf zr5?2D!61)48$4lsm&Uo9^YW5%TyrF+mnL8M8vxIO_pB)JTnx*;e;RnsMjNp9k0b2D z91zGa`si~e=c{ME2By}IeBz3tQUroO+zn%xiw+Js5{SRFNA*ve6hLb(gWNHCcsaXA z!6cfVF#^Q69n37xlgUW5dF4N@oE>#jMGsJ-E2Kj!6)WpLVK>#DiX1E{%81JlKK+LP zCg67b$V86+1^@AZ;7!u$S*xzbd{@CBASvUv2nY2f=g1}wS2ELPZ+(AD8=L8z2ULZ4 zA9~3r@3A%{l7zH5wd6~zkXBn8kEkFFMhbF=W${Y@Zc36DY$hpb^m|c;bh`$BUdNSmBJz%LS!H1CfwW=yfRsjNAsHVUeqxA4j)j zL#*5(L*14Sf63pmD{pCERe8VF1vdeYoA^DUC(d+D#R{Xwm|7;+YePDrRJ_+v4%npa z?s6fENk{?DC;CGNnW;~;j>1}x*%Cyo4VN4mq3_FZ{c=DGz zIlr28PQHb!LORg5X36;aCN4Rh!eTFM0_WvaL_C+@gbuQk2s3fX-R+Gz7_t~mVovNABvHZ6LY z70!lcyXC5T$HCto;U39B$nz#T6Fn)*2>zmQt@s#LC|a0MUzRqH!XzO6jDx#j0JBXA zrzM{)JDA=_=66y(`{KFtRq<>tWL?M|TO$2ifoS6P6zd<*n&VdkiI?mqZ_ER{vme_b zul(zS{j7kqX-b`(ws5bj);;7#{8-qrUjr`zR@dex zL(!w(R8H$r+29|0rVUt{{o3egynxr;Az@+OC<>Z|_)H7ppc=M<)#@^epKeV0q`GaN zu7V}Raz2vLK1u(S)pDB{nGv|~4b4W}REtpI%m&VljsF|#9M67;1&4WJADu_YDIPUN zc2rfyDb>Doc%`Qg6=+kZqDTYwgzeA)N=YNlRCn$&p-2e3laEG;hUXR{>^h#9Nx`@> zShqRxP=$o^+~~}v%!v^nz6!_>C0T`+uAWF0{|Ne}Gc1GK*5Hcoju`w^!kFahf%um| zVd4Q&hDBikj!p+L&adpV6aw*XS=i1zQ=(}|u5(v9gCn)yBU53Znmw{#n>GWHaL6h^ zP*TEAPauD>7Wrqe@1qaBoiojdy{lA|3w7k&>e(|LnjGb}l|pX9^9LB!g$d;*m!>jq za_U&KUUjUwi;J$Ur6uOFFGwGL{3y;U6#+@lVvb6S*6;Qta-rF5ta%y+t*j+belMqd zb*P>N?j~E)Ia!Zee$`;#Nr1LRDXrp^waW`ZrD@-CDHipjc$7l!PQm)N$&Y}Cg8Zh2 zHsfll2TnI){`o1bQ5b?6{=#N=o$5S4xN{O~JNtwDHOV|w$>=-sxw*20+t`Q6cpnZ2 z{@J$MxtWe5?5AkZ%FpGS3Q<0x2W;YkW2}h9>6RzOrNU@bJrGD^^6XcMM>@=o%RjyW znhT7ZjO|YiSak_3nwVSz9XwK}kE-flTTVVgI#zr>7jxP1?EpU&3BF#J938PV8vgK* z$@>&&3^S}#=SW;RVBTUNc}zuN@GH4VhodVwaXk~+=E}sFh|T%jSRW+x14xdi&{cja zUC&QgUt6%0JuI4>6{8}CmLdI_+Z~zjtOJ&Uu(g31w47nXmbP9E( zh0pk{o(#fcYM)<-nNLaGeyvLd&pX&xmcc3Q(2w;kt0 zc&weufg&gXzgnXCyQPooO?RhU0v2LRGGQ%x=uO%e&X#2^7<>m&TA3>FwBYtUaqN zpts6k6ioI0EmnQ`8N6QzeSwd&Y`)V_KMikr;O_FrPT|>S-t7$UqUZkgus?jHA<~bY zpz__SLO%KmqqY!R zdrM9G8s?c_K};VBTnNoVw3g8&agDe~Mrd*4>f9irQ`&~`K(kLAZTu>I!|vfl&R8HS zGa0Nv#;tP+jzPAspp~Ae!*1L&nW6(hgv7$;^N*63hl)06_LH`hA|BHuYDA12<_XL^ zvu_uorA>wR-4niWo8;)I`}LfZOhQvX8nzf~J-)2l*+zRYWBJ<8G{`O$Vgy-1GTy9W z0o1nXf)_PYU~AxzjX0JUPV}HoQFNeFVcVf$A7GG*^2A-GkQTm2(5{V!Oa*c1dTT|< zP1=@6_pO-a+(hYYEep|5gN2n}Wx&lmTkCrt3a`0dkNt59J3RKfu(Rmd4~yN9?l|WO zwWSl=HKR^{BaCELQe{FTcqL1o5-?Pd9Q_0+u*QPWbx!j~s$vPOHgo`1a27$u+yv&d zRXh#Hbv>Q_+E*QL>E!3FOV%Mf!3B6SM(c)(|1$H%YO8uuW2bF6_}9^dZtaiYM|cZa~@Q>Xk3kLe$SN96U@knj)dT(mBfaj=A+!WLz96dsSJ zOqnB9pNMOJ6{@Yt^~T=##oW3q$vQ|<400e3r?|>o?A*euBdkPvHf*^o$8blMBczIA$WKSr?*@rHG1NQBe=8LR3C^M+0&ok}{;1_L2p1P3Q~ ze)%I1ua{iN)a;LbshR?_bzUe-&PXFd{VMFxVAo#ZSfeptf1+a|!1+ywxyJm@K}GwP zo=)^(>TE3Wv`~c`RD`XJ+q$>VJPBwoQR|c7)<8%|Vr6Q+{~!+*}|MKcCt++S%XLmS)bmDSsb36N67;xf7+T?8C_6ScbWdhhI{evs@cbS+C;MX(eXqhhzT0&4`CUVty58JsJlaz7 z!A{D6#c+Mf`msAg70BY0kff(B>OkECUw`IGy+LPXWCxYKMXvdo8%HH$Be(mNvs-;H zQA(W7NIEe&E`ocB=hiTPfIW$^l0jp{r5U&z- z-3tK^WL77w-%(B4ZYNK-^hUr`-kHBz^#e*(bSF>LOURqNM7j->eM#&U8{)0iXIzGv zZ>zplUJqx^9B2T7|-`qRM8 zcA7%rvv;c%C+zL?FJgbH*j!hhrg+(&Dvo}j_7(8`ZOSH-~WTs z>)oo36z+!VSZsrosR7PDhQ<)L)i4QZVGf_UK{T|1wD=-c3CCH;0Zk9oljuj_cGQ4YqC*XIvNRl9@w9o18k%?Ud z`(X=<>MM3s&C`dEV=mbufgirml>I6j-kta@9ERS4iozbmYg9kW%53!Fw3dAFTbWGT zOc;NKAud&NbD|D}~n=&7gmT7-4`g>j(xt(f{3=x?_VXiO<$z};5Xp9mGbaMM;Q-seA; zJU{u*BUJ^0Ufm^oHFMpuu0RD0j0ayZ`7QNh{(%2%%p8P7oxZ3Ko4Q~EyI?asF+R%7 zZqQdDEfsXs)#n%ysn0e?c?-Ke8Wg$*9jnT~zueAf! zbtQsi$n~Lwzq#NO@EzH~gTW3~Y6C0PXgzPrXhr58?!=yeAIZtbkM{-0f&TnhzS=I> zZmG?q#_G`tX?iES$VANZ-Rh4ypLPz}ar%{TPyV`Ht`U!}(j0{xg_oNXl3@*PGd{vW zPDxqNw_V43)z8#1m6Y%SH)w3m=_Z$NTYFbnbHR!!>BE-C`5<}7_1R6%yaRPGI1n6c za(}JO!QfYluMUoGQ!nQAF^itAdu#QC*jZHK{}zl~@nLXm8ENCRVapT6RK(fp??Zlv zSxJyu&@VeNoz)LAZ&r!fbK>q+c%LvHkLEt2hw95kX!X->jFBbXNbW`u)J% zZ|GUcVsfhz(>gr7uM+a#^=hLF)PXo8x_NH&9Ncj}diNbzbnklcWTd}0c|I?2%QTjJ z`>E)!l8K2&PzN!xj4%Kf!dn-o+n7Mi#-U4=%d#Vi?&#mLEp06s(+63NNeHmLk`ZB- z5SqG2GHo1fn$ufbJE^^)Xk{q0w zJ3?5^a?AxYRr6l9=C@yjjjKE~bNZUq%1G2i-{0HPO6flb^Q@l2J(%D@Vr^Y|Z0u9$ zD1l>+M4 zW!A~Nyg-jiKdynp|0LP>{M5TIHoY^XHYm6}(8+Y<;TgK5>|8`)8k1?Y`SDn2&~-s| zxG+iotVi;47I5Q9V(z9#r%3qqUY{2Yajh5WrZlf37MOa30ImaQO^G57SV#X7Y^33% zGd53_>1@8td^jgPuzu0Yyu=znCK-(UvIQ4{LjuUw1(FN<4c;$`DEMA z!o6Y1;6+7Ay<2Kd`>T>#R`46F9}eYM0f3`#TVlN7EQ(P^-{T#SgqBiXR}!?oB%;l1 z@_S6zcONk2k9{%wnR%NX`4)y&mwQZusIIA*GGtrp#VKuuh1vS=PzR(nbuh7vSd}n*Z`I7#7WYkILTWH!}U~fNyS|HC-dgO75g)J5MkY7+_BzTl8Jfhcfrq|D6uN zWG0X(hgFtW+K4&~Bc4>6qVr}wA?7d_uYaR|7}jj#Vzrusc@=QtC`8w6*(g{$s($Fd z?!!b^jP!>D+eMP4?lLhOOQ&LlgS#s$J{Y}>M`dc546;+@%*+kOO+OW!btH5nuevn zPtz}o>eMeqUTR6acanR^pAB1`SrSE8U;jCFozIKCabjKQ$k_vG+A+oeflNONL0Ti% z-4Njl`{|$8+zAJ)Smjv{XS#W(?7dfoGFlsb7X~9im8Nl!z zn&aM7{(&P5I=QV5aN34w(OGO7c&igSISx#UIkH+0WHzYRTzaM-qj3N)mam0BBNM-} zP;XV2muKdF-eqch_G1m`xSf2GQM+|}>(#iw@Ox9V&-9>pcsHT<+e~%!J4!j4{T^*J zQFujQCXJ8g5YltJ*S?ZI?>flg2yIwoNmapK4~SQN;gC*@_=_eH&J9D4cKanpe1W2j z-`In&8mGdtN4bK*41gPHT{9els_*d3cR+PXGYFx zj{+RejWu@uN~S-`AESE|>&-yV@xz+##fPAw`$5zy8TCsPJMvjQ2}dp3zW?C#!LDA# z**ZMW;(pYK6-Kxv6u%FNM!0{0J^A~cc2_pcpYP#c-fWG2iMMR#LLgKQxy#XE2vQ5_ zd4w+<-W4A>eD$u+qcoog=`Mq*A165^q(uO1LP3CV%7lP8@&ebY*e5|Tt)Nr!df!@y z@4z(71to_T!fIZ}Q5OEvHSJV#fF675O04iIzjENCsB+cK8Pi)T+T$LwpQ-iKCv?w= zQJ5bOd&-I*CSnJ>UUV~l@1JJGS31auRQEN#%yCN;5z!bx#&Mm{N>_cvR*Y)NUcq@s zdt-W^D@b0k`|$I{@#`3ur-p|8e;CW&C5LY5Kn>^ZWBEY!_w3~R&WvLae!{Qj@Xm2 ztL1Q5Nl`MWM@)LIFgA>;ZnF8L!viI9B~3&BqoN;5sWeSO3Aaj3=h{U=m_UH=ZwPy{ zio$byK?2puPn`YJVG@b-U+ne%?!XoC`2`qd%ENC9!tH_n!$Pm#CRPQpKlKZRpV0Va zX6r7L^9ec}KOaTJZw@uPSjP=#A%$8&&OEIj-AS#7 zuJmArJ-}H{$AMh9Z!wdt?YFm1wSA_HR`A`iEV=E*0TK+q9-0M5cMcXR^CfCn7ZTDL zy!`7Sc*e)CTx%o5`LNX96|TO{roqI9W^jk($jUd3{h_KhYs?{1kq=K#zkyjuv1C& z@=JiTMxW^icsNdP*faky2VriB|KwXx!n`DY!f%d{`^&YR?ltV$h?m{{Jjvcgk71@F zq>Hu*ihc(2ls z){;ITy-!v^_`Xra37rtJ`&%Unt8>h?sH{c=2m51li}2-`4(2N3*tCYJo|?0|O}tc$ z%@89iN>7XwtW@!UXbb?=y;tTkJFZgb18h*wob#)upH>DmAI~W`)DhdCb@+ceZocW; zqf?!=-rl6^;}0RAyvH0C?=i$tdz_LaUQ6fzJZiSH=vW{E9Ns4DBtfRSp0XlVWws-F`&9r0U$bxI@TYA5`>5FtQ+-7b|A$KFxJd zFsk=)60<7`k=#5qptImTA#yg5+mgtmQ;?HT@0E2$ioILXOH|<7ZOoKn-;~Rj?XQ6z zS9-#W3gw{}ETy6_01d1lJ6OrCSU6ec9DKv#qss zZ)Hc*p0Q(hD7dtmLt(Na-CxW|vy$m(lSRlSpym&3$qUj+grOR97|E+FHbk0vO7_1T zkvo{^<-!G4l#FC{lV3QY4m-yE@S%+^7uQLKyC2>rWhSR$16fuXAEF+-?fAB%!YL!t zQpdjOf=B*p`};U&*-alX(+0pXU)&3y)wVi>KTS`pl{#{seyUDix*iZOl!Nv7ZHi)+ z#$cBHuL2vbjPd{seI-B2Q{bq2pF;T%-ss}Lb-pBaz!?wfIm>!V6CC5jsL>T)x5=_0 z$PhD5^or@}x4|MKBA-R2hyEeWg44xNMg%rsQUE&qw>@r}b0J}+QLx9bFEjORKR5_DUYi05A@58Tr2o1~hO{sQNahH##p*9U zk`oqKP|^b7BZ;bfcHLG>?b#R+5nlCBp7~Xs=QXdS+8>6NYk`~OJ{tiKtA75RW{uyG ztiYW99URdO#8qV!bJeRij4wU~_fH6~U?M?VV-H90HtfNT?eKym4`!nEn$4|8lpLwb|gps@`SCh3mrd*vi)Qe=H zd;uX@odTX0#~EJhDJ|ZO1t4ND@^w4}aBcv%EKz3I++HX$HCmDCVf~trHs!ah>Q&iI zw@P9^pTiy!;Ty&>b4L~KZeaeu7+C@ubN7~KhLT*7ch|~XAAUcR+~WCcSCRk_ZYh6x zA32jjnuKugZy^KwUpNtQQKzgHCEz)38iP@dFhe6i)d*gSY;xTQ5S=`ba(xD5)v1P> zqr%z9B_j5I{}E0Em#%U|R&yt+($i;^(`ZOCz7rB@2+~JgWuBaR5i#yCUKk07HdChc z`Kk8NzJZMgZ=<{-hp7|?`5(D7-eq-_|KNMjzgME@szz>z4I}~`&O%>m-pkVgZ!iM; zJ+H@R^(1@c0PShrwO*(&LELMGA$$*lwaY<+IbIL=wYab9MI40)Fq~4ymu>E{q(xe^Z++ZAR(ud?IoO-?% z(?T&lC0D6{)X}3DJKaFTRBfma*4GYNH^E_)W557zeI1T^oN8VxtP?m zn*sZSw!K{t%NO?3);>ib(FtsdTE1g~#lbcjJL&aoME8#{f%qdV9K&__hYZgpr)$%g z#x$WvSKK)P68cok>2dGw+r3rfY^i0 zi*jgAm>|0$JPM+#}7+~&C4?5;+d zL-v@Ozj+itr03X0udWLQT5C1GE)%Iwdfa;z$nj!2MS+@;odNhL;nnb>TsM&1`Qo&J zxd9&Unx3f60{|20gg3AJe-U*%LCdYWuAd>}7!q%q-K6e&-L}Qi^ZsGyZi%&~fg>6r z)^C1C6xN_Mv3{?naV!Gm@Ap@|kwl*3YXT2iPci?bryPBHIo{@rb&$-JVhEg6!w14B z)BPGD@YPf6SA#+6I(EIQmh$e&!5x1SX^mAcyKgR5*aDp$QF~0x8)`=Pc5~-9m^D9N zxVsl-BpDY6naw6zsJ{$)NNAxEbX~hGn;W2}&olA2a+VV?N$TpQxoxCUFG|=o`TG+o z@Z-t$rX1c^I_@GM3|35tuu|Sj6;Z0uH_;Il0am|YtDH4((P3G9@s9ZQ#-R{x^z!b( zRzH7x`>uys>r5+a!}0o99ZQIhA6cEO@`K%yGAKoRlqb>Eyw1^;-(~g+-et!t7KC@> z`Fxk~t_P!JMsz}rD4*H5AaUuU((4l2a^b|v^)cMuhlCp9K@2~{+^=3^!VwGZPzX@c z38&*eH0BGhnP5NwzFuwXbE3m)`)Gbr`4-+=agW@^h-;XCLk#Odh-X}I$EUZ!A8L~0 z`vvKmmYL{QVmz6vMv8w118Ywp=YmpKXTrp_XE6ZA%lNs`muWsfKMPpnUfe|LQ8+^i zCas&rApJl$?53F4f`9K|d9+#U1{+rTK-$G6NIli<3meKOoB}mn^g@?rq{7bQ`V}kU z)OawX+U{cErlyYd(Y%eE7oNbk9!cGJw~VI?He#+LAFAvD>69xVDgQ}DRd3I^-b3mg zA2*vo-)r0L=?4_uE%)w%-TYf#Q@?me=4v#YH%NB4)+kAg+}<^iuKQe<-Y)I-SEz4m z`CzjN+#_R&=kN%1ERL&8VpTnfbKmLJ=x+M%A5`w}Dq-101u*biBzYiRz;|b{zt17W zRy6lKVoB+Jz1UZ-AUAj%P-g(Ag&iM7BcUpYr!D(yQoDm4?K45?R)BpI`BvR+*vVcY zkd*-JD~Mv~9*+DL(@BE}K!k9WsEQ)n&Q~x)tZC4HnW}Rhkyr(@OLF`Wk*=6>*Snq08a-L1i9-|m5IsJo?X{wpx@r|A7{de|D@npk9%+21& z{^n*&%!1vI^H$h}JVO)U){CsiRL?Q~2m>5IPhUo8iagOxG{(s0AJISG)ke_oy#39G zuxetBuoR*EglP+wZV#DV&gZL(qynT=c*it=Rmj3x>7f+Lfs3 z{S~4h_{;m%tC!BeS{m#`(#B;FF}|X1pfApFQxA5W8w6o`QiO&XFraqtyGYvzd`gLc z$O$-}kghUal6*&Vl1?;oB|m14qa6Ivq%fl>6WK@DrZzm^Ouo-DGy|)aB(MyX+O_m&;jN2l%pYVM0(gXd{f_x zc$yE@l%CK*lt}Fl8`WcFNr3^|of4^qN~^e|W?1l$DV?h6i+!IDdw@-f8V_k2sErGY z{C&ATMYOlgzG)P6@}l)|MS>Ri-b@Pox8Q(lES~j}7_dCnjNsFPr?5YrbW(2Q9(YGHq09 zB2M}!uPwv`gc=mHd*yHEQZ)qnUx_9;c)cKCHw6~_NCufiZ1<=$v$W#(cr$fpA%2U! z+MA-kar4*v-XK$mAtXlriqBx3!sJBK=Gpf6t}bjya>Rn66C8_L~JC{BSeS=i0rvC>h5OA z>>6cn4KD1xKoYoYbG^1Z{1c(~0#b{hD@20{qsN#Dr}te7$!=5)LJ9#lZq~*4EMYTtZicgD!pEX zX9lw#x=03vgv9S9A~Ushq9>O9ak4hu!s)yZu$x~X;$*3@ssCqx%5iq$}S3S<|n}nvV2Xy6hc+yq>RDZy(+__ZiF% zyG^XBo_f{$I`*NUY;(CeSD@*Aqd`cN^a!g4HuD$tawp#TRbi(9tZgd4 zWn;UyO=4Jpt47Ep_wi1KhVwB|zFu-UX1e9$5>j9tAZKch4%2W3s&B~)bhk`i0_BYkV!U7G;ADp89Wi%7AkrmD=;} zON8loq9UkNTmPv_e>`2s?Z^S{`{)O@(#tS{C(!+*wF?DZm$Dq^ zi6PHoDgNh;l0IY){fPj8*$p)#J5#-UjkEpxmf?Vvq+%av-V(Rk>M|c0;8d& z7PKV_e4|g6=cqb4vmOm%_XW;+D95gNU{%2GptD2xF3C#r+wK4i2Ou>zP$B~KWFf$9 z;Z^qKJjr_}u^|l~1h@>gXyn>dX8Cc9RJjbufcuVONk3d+!V5ss&g+j0klJ67U|J|I zs&5o**tyh-rv$W3oolm~Z=WlBXFzbiw&&=AKimh6XzY8kUf4i5EE4F0O@|B!X^cVA z3y@r`NjetRbiTj6;);LKsq$a4j(Zb1O%SB~$L0xAV8R=LeGiAhrA&c!euM~JNcyE3 zK^MX8C!CFmcA~N-_k0hd?bq0bY_$o{~aJcFOyi`YT2br-Ng7Z=(GRfBv3T zn)#g68DEUgA2nmy)Tyj5T)1FOx6vSVN<;AvaJdUdsqOuL55k^Un5J~a%46M6EN_fuwKij>dSUYTe)nX8kFS6!h)KfEElR7F! zY4R588+d@Up$AA~<9P$4_&=S`KVIdULZePHLHRe-ih*Pb;y$#4bF) za7!E)7V@NrKyR9XPL$TuINswQ@TrBs?`?0_feN-oZyylTW$Cf|1$21IdjysL3@RZ( z<64d7bP};zt>Bz9;`{l?gqu3*npy{DQpkDZtx4eN*IT#jB|j(;2WRVl%{Gpm)6+@L-Ys?ARb&3$VH`Vv#QuTn z%DC&yjFa47H9rt%GQJj{W!y+9MAB8|pmELonGaFZS^&_qoa z<`I~P{n>|U4RA$i4(&wvuGMo9hF#1dkx4c9w0|xbj!xHH`h$by58L&Jetu`TU*#-2 z5g-+&kp0%0QUj(6_)PgP#v#%|xVXQKpuMu5Bk{w|LKLs{n4HtDago)tB`yMZ;kb_v zkT)J)Qfk(6^2v&H{1pGyun$44VA92Xt8EnzVU2V|pJOjG2IYIAcy+CU@6`hEFQM^( zdJV^kDh3>tywK7Y^ovZxzy2!yCR%Te>CumzXDSV`i=3L>v!6P~+=M;WaRkxha0sF3 zHVq*r_Bm;{?#b?Ku3YQ(w?8I199`#tNMa4legrgaom&iU=sdWeO7O3CSQ~IOxPHBn zm*|Bp9-<7jis05s5%K1@V$2;IXzLkeR(^a&>r}Ih-5UB$>E%9(Ru7a|XcT&N|wSfPxjFd{R=nx7uFK3X&MZ~0*c;2yH!)KqIT&5hqwLJVpZ6imC zl?NxaP6vZ(>E&plk@pKlP83Yv_>+i z6EcIb21ZI`TIgU`aN57)v2TJ<3F2=*?k@+dDc@q-zhJ2fPRw#&E#9o6ba&59yIPr= zel(6S=Zs$MewVSE2h;|VuTy}c zHel}zj*HHgj0JR>MT+p1PT$Fda&r0U@*Es)@-;5@TpWjmQajFm&*AXHNJvOD17Zs6 z+Ga&%*$j&d^YKjAvQ&tgXW?t<``5A&AZXk8TA7(_LoUqh4FL@qebJZ;s5jQKQRI_O z<*@GQ)UxTKQY-YBcU6@WmVGh=`tiI(P>1zxQqcEUV*{ee1+YwFx zIS#o*^Eg_aQwX|VhKS1Z6t3W0BZKV0ybB*R*69zeL=5wloCMq`^os}&QU#1m|BG#V-DE@R2Tu+`OWNs*|H$DR+ z-&}d$ov#3gs7aeJ{krap5b+9^?N10`{(1gcXGbvC($&H<@k-wt$o+EP9eFHJVA_Qp zyDSGM(STRa*6-rKt_f9ufN}@zEkHKkWWGP$&Z_*zog_l_94viFUHlt3yeT>u+C_Jw zFodDzF+uC#FC7SuKCAzfz0xzkc)IR)YZHcuj`7Iby!?73(L|4h)#Q&EH~{8Cm8T?5 z)?u8}3e;kZgk@Tx<0F@iq?c%l$UKNJe`n-#3veAaUSwKfYflj+k6AdYqo+AkGOtqh zu4-ZjQA_66OGHP}zOUCjaNVe--2)lG@>kPmWQhd*bgx(q9+2LDh>dlvs$rdMk5kvc zvj3-~YmaB@|NqP|nmJ<(4V&v)atWFH#$1vZl@cW+B9~R}g2b{D=9m2!)v z+)7HJ5nU+vkn8X4^E>~a^FEK)`~7;oU)Sd|BW3%y?5{B!VrclOW8P*3;Mm2+iz#h+ zwY@Wn#Md6SD0+bKYC4DC^TFBSao=D1c$Hl&Q%!gk0k~u_xKBU&oYjG|GKkZ;tyan> z4`XF;DE;kTA3D)QE8M`4cScr3j$y_Y2hOc< zkg-zinE2)0Hx-iVJYmb>nDzsD)s^$7pZVrSYRMF|ndx$aDKL|muNvPRLI-X$LnI95 z%Cz%9P+aA(O)R=5axN)GOu{a*j;CHr*{^%wxy+OSrw}%Bw#9`s4$RI6N}3 zIQsS;0#>xy?&T5W^6|1h=j0m7i>ew&`L$+iam9(~dvCa#QwoV&8xE<=l-?fWjp3?4 zTb{Ya<8qyb^ZNWeeKo(OCAQ^S%C>};oBVr%ULxi)m}UU6BlsrE2xi4I~L2#W7YINYTM}vOHU~Ljb zPDzXN`QAYQxkp5lcH+G8YHpUeq*By}wSt-i;AmW4Kigm-IXS=kQ+bpLooW$#UPk4Y z%t=9Pf+=U~jUpCqaN&3VaG8L_B{AN~h=I`9Xji16M4n25GZu~md~DnFRX~93e&xN* zYH-@*94b5X1lD9!oz*!^@*zfc+XI=Oyqv26AP_*8K|8iO=5?XZt`H39^n3h`+YWTW;9SI~2!*EN*xdx=7IHYZW$Fzjul7 zDe(Bw+Go|(K2O|Td`vVIXCzbCK_$^#+mh3Zd5F?dqvdQo92s5Xc_>w2NJif)`MEB3 zSw3b}>$o*&FKJ?14W%sprufow)Dg+=awh6j=Y)2qTSx2J$e!Jq3S8;xjUn1nre5vN z#K4po*0HDH#DT_RrolGEuv zadgzAe1d6SS)H1AwM3OmJJewkq=%V?Sx)b}Ec`OuF5ld5<|=s z1HlFVaTGg-ZaHdbXvc5%e-8p>8nSE8lYaRrd}WQdKYN);zIDnbu@N@n4>L}n-mT_X|mg7U!Cn5LvZ02)g zgTA4C{KO+?xIn-k1^u01BG()HefpKS(6FS|Y8}|S=xbwS{i*HOt4=}Nwb8H;xKy8V z>Elg~g=qqm%*Sr0ZXo!DoTayhbxXyn+-bA$r4sWH={AU#eFVP~D{9x4lblIXlw7_o z8XTQRe2~xPN7M0ty(AGM&Duv0^N;Z*HWGLBzz_u1CR&xF^BD6vrdM0|$WXEI=<^>L zod-W5v#;uTVEWziI7z0;BoyIqL&C5esX{R=W{leU)hx`zX%D{0-7tu0>D`!#{jre|+Db~X%Ug-IVLIBzx@naNwH1t51ZP)e4s7JaCpjpY z3_Y^5`9iABQBem%%WFb1@8L8hkqOJktpS$gi7zX6Xt&;&*T)?rCS+_sjSrQ1g4Qam z`Vh??dv&#Is%pJJE;$t9(?t^bcOy6;u%>-+gW@nP3z@CIyaHFtY@e1@t>a(ctVxUl zp~qilgtGDoo%9Aq-zk?@>M6&2`%Kjlar~9|b!6;62lME_ooljJH0K_gu3Knrj0R1u zNH62(-hviM?vE0zEu&vKu%*p4=Sp#jof)oib)onI=x-KeJQt}`5ZC0#K*S_muiVs` zH~#BBTa5vMk!@RtSo{6#$*aoNXjEdG-ID7__=y|PEq zvl($aPVC7NZ#V@fmny@Z zEQT%|=z5KrnS%vy7t(Bv`#*(QFx4qCw^Y);R+^u5J3pf3m1t}Y$thY0j(yskk>VIF zt}*iZ<@)#@OO}6gY<;=PMf$;Zbtw5x99Tg7gtKHAOx8{x#L%dozt z-vZt5@SSDA*+;qaR1bB;k|h=e&<5Dj@rl7fu)!)me!q-{*2uGGFoOHv1 z78Z6aT~2t!5{|G1U1bn%2#Y8Xo$V48N(ZCPnLH_yq%?46E(k-7Eo*Uf;$*+{60(R1r`92qcz zg~KhS8x;va46Jh-Ed3lVAO+2dXf=LDG!*)syFISru%LJGPW(x&ECqKpHi@fr5p?^Y z{%&yrY`;RjG5~$U@8CfY90*E=@~i9ohQuVBi{^vnqc*`ZeT=a!q6|&UpE;K;+wr1- zP<}=(zneqxr(33(&OALYgu51D3=XL>unb7oeAE(b)D#Nql15B4nC8W13aCfQ)k(H)?M?s=4f@`!Tcgi&@w*=tI@;t;SQ~Y>HrZ#u2ATUgn>IBFV&n{hi$j zp3L)>PkPjel&=KiMVuzv1^_W0; z@Y(^BgCPmCI_bu1<jOa2_C{Mbc;kkSHsKg@o$By-EkX{S9 zqk2StS1OaGgydtBI{Ge*4J!^AwkHiHS&(A&q2vz1B1bk^O0kJVSkD!P{yY281q zGbm_*+}l5-fggWzG)iqGZjA}M61YPh^rFV499l+I&6@CZhE1g7Yr)N(`Z0lL?WyAqPP^)Zwipk4VOc-ulMv(_!iscKJoybUO zJzGRF-ygdD-`*G47LqzXm{u!1kqRPX{ioC#v3sxNkxU}20rI7Nvfk5RqwA;c)@nf#i;(R*(-Bbl;5)ZN>Q- z|A6KL@^B}E&BwEB05sDiEYmMseqh5d92ft|UKgMNmmuTwBK( + create: (_) => get() + ..add( + GetUserData(), + ), + ), ], child: MaterialApp.router( theme: ThemeData( - textTheme: GoogleFonts.interTextTheme(), + textTheme: GoogleFonts.poppinsTextTheme(), ), routerConfig: router, debugShowCheckedModeBanner: false, diff --git a/app/lib/core/constants/assets.dart b/app/lib/core/constants/assets.dart index bfa8295..4915cfb 100644 --- a/app/lib/core/constants/assets.dart +++ b/app/lib/core/constants/assets.dart @@ -2,4 +2,5 @@ class Assets { static const logo = 'assets/images/logo.jpg'; static const bebrasPandaiText = 'assets/images/bebras-banner.png'; static const studyBackground = 'assets/images/study-background.jpg'; + static const bebrasMascot = 'assets/images/bebras-mascot.png'; } diff --git a/app/lib/core/constants/bebrasBiroDropdown.dart b/app/lib/core/constants/bebrasBiroDropdown.dart new file mode 100644 index 0000000..532c412 --- /dev/null +++ b/app/lib/core/constants/bebrasBiroDropdown.dart @@ -0,0 +1,110 @@ +class BebrasBiro { + String bebrasBiroUniv; + String valueDropdown; + bool isActive; + + BebrasBiro({ + required this.bebrasBiroUniv, + required this.valueDropdown, + this.isActive = true, + }); + + String userAsString() { + return this.bebrasBiroUniv; + } +} + +List bebrasBiroList = [ + BebrasBiro(bebrasBiroUniv: "Institut Teknologi Bandung", valueDropdown: "institut_teknologi_bandung", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Institut Pertanian Bogor", valueDropdown: "institut_pertanian_bogor", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Indonesia", valueDropdown: "universitas_indonesia", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Institut Teknologi Sepuluh November", valueDropdown: "institut_teknologi_sepuluh_november", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Kristen Maranatha", valueDropdown: "universitas_kristen_maranatha", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Atmajaya Yogyakarta", valueDropdown: "universitas_atmajaya_yogyakarta", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Diponegoro", valueDropdown: "universitas_diponegoro", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Islam Indonesia", valueDropdown: "universitas_islam_indonesia", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Jendral Soedirman", valueDropdown: "universitas_jendral_soedirman", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Jember", valueDropdown: "universitas_jember", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Sriwijaya", valueDropdown: "universitas_sriwijaya", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Institut Teknologi Del", valueDropdown: "institut_teknologi_del", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Sekolah Tinggi Teknologi Garut", valueDropdown: "sekolah_tinggi_teknologi_garut", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Mulawarman", valueDropdown: "universitas_mulawarman", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Unversitas Udayana", valueDropdown: "unversitas_udayana", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Negeri Malang", valueDropdown: "universitas_negeri_malang", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Dian Nuswantoro", valueDropdown: "universitas_dian_nuswantoro", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Politeknik Caltex Riau", valueDropdown: "politeknik_caltex_riau", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Katolik Parahyangan", valueDropdown: "universitas_katolik_parahyangan", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Institut Teknologi Sumatera", valueDropdown: "institut_teknologi_sumatera", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Lambung Mangkurat", valueDropdown: "universitas_lambung_mangkurat", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Tanjungpura", valueDropdown: "universitas_tanjungpura", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Sumatera Utara", valueDropdown: "universitas_sumatera_utara", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Pembangunan Jaya", valueDropdown: "universitas_pembangunan_jaya", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Kristen Satya Wacana", valueDropdown: "universitas_kristen_satya_wacana", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Maritim Raja Ali Haji", valueDropdown: "universitas_maritim_raja_ali_haji", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Paramadina", valueDropdown: "universitas_paramadina", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Katolik Widya Mandira", valueDropdown: "universitas_katolik_widya_mandira", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Batam", valueDropdown: "politeknik_negeri_batam", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Malang", valueDropdown: "politeknik_negeri_malang", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Katolik Soegijapranata", valueDropdown: "universitas_katolik_soegijapranata", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Muhammadiyah Surakarta", valueDropdown: "universitas_muhammadiyah_surakarta", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Jakarta", valueDropdown: "politeknik_negeri_jakarta", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Gajah Mada", valueDropdown: "universitas_gajah_mada", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Negeri Yogyakarta", valueDropdown: "universitas_negeri_yogyakarta", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Bandung", valueDropdown: "politeknik_negeri_bandung", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Hasanudin", valueDropdown: "universitas_hasanudin", isActive: true,), + BebrasBiro(bebrasBiroUniv: "UIN Alauddin Makassar", valueDropdown: "uin_alauddin_makassar", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Pasundan", valueDropdown: "universitas_pasundan", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Telkom", valueDropdown: "universitas_telkom", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Sanata Dharma", valueDropdown: "universitas_sanata_dharma", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Andalas", valueDropdown: "universitas_andalas", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Islam Nusantara", valueDropdown: "universitas_islam_nusantara", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Sains Al-Qur’an Wonosobo", valueDropdown: "universitas_sains_al_qur_an_wonosobo", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Bina Nusantara", valueDropdown: "universitas_bina_nusantara", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Komputer Indonesia", valueDropdown: "universitas_komputer_indonesia", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Singaperbangsa Karawang", valueDropdown: "universitas_singaperbangsa_karawang", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Pendidikan Indonesia Kampus Purwakarta", valueDropdown: "universitas_pendidikan_indonesia_kampus_purwakarta", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas President", valueDropdown: "universitas_president", isActive: true,), + BebrasBiro(bebrasBiroUniv: "STIKOM PGRI Banyuwangi", valueDropdown: "stikom_pgri_banyuwangi", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Bumigora", valueDropdown: "universitas_bumigora", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Pendidikan Indonesia", valueDropdown: "universitas_pendidikan_indonesia", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Padjadjaran", valueDropdown: "universitas_padjadjaran", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Katolik De La Salle Manado", valueDropdown: "universitas_katolik_de_la_salle_manado", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Ahmad Dahlan", valueDropdown: "universitas_ahmad_dahlan", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Negeri Makassar", valueDropdown: "universitas_negeri_makassar", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Pendidikan Muhammadiyah Sorong", valueDropdown: "universitas_pendidikan_muhammadiyah_sorong", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Al-Azhar Indonesia", valueDropdown: "universitas_al_azhar_indonesia", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Indramayu", valueDropdown: "politeknik_negeri_indramayu", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Nahdlatul Ulama Sunan Giri Bojonegoro", valueDropdown: "universitas_nahdlatul_ulama_sunan_giri_bojonegoro", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Institut Bisnis dan Informatika Kwik Kian Gie", valueDropdown: "institut_bisnis_dan_informatika_kwik_kian_gie", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Internasional Semen Indonesia", valueDropdown: "universitas_internasional_semen_indonesia", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Madiun", valueDropdown: "politeknik_negeri_madiun", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Kristen Petra", valueDropdown: "universitas_kristen_petra", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Muhammadiyah Magelang", valueDropdown: "universitas_muhammadiyah_magelang", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Surabaya", valueDropdown: "universitas_surabaya", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Katolik Indonesia Atma Jaya", valueDropdown: "universitas_katolik_indonesia_atma_jaya", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Ciputra Surabaya", valueDropdown: "universitas_ciputra_surabaya", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Katolik Widya Mandala Surabaya", valueDropdown: "universitas_katolik_widya_mandala_surabaya", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Kristen Duta Wacana", valueDropdown: "universitas_kristen_duta_wacana", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Politeknik Manufaktur Negeri Bangka Belitung", valueDropdown: "politeknik_manufaktur_negeri_bangka_belitung", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Kristen Krida Wacana", valueDropdown: "universitas_kristen_krida_wacana", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Institut Agama Islam Negeri Salatiga", valueDropdown: "institut_agama_islam_negeri_salatiga", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Muhammadiyah Purworejo", valueDropdown: "universitas_muhammadiyah_purworejo", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Institut Teknologi dan Bisnis Kalbis", valueDropdown: "institut_teknologi_dan_bisnis_kalbis", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Mercu Buana Jakarta", valueDropdown: "universitas_mercu_buana_jakarta", isActive: true,), + BebrasBiro(bebrasBiroUniv: "UPN “Veteran” Jakarta", valueDropdown: "upn_veteran_jakarta", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Pertamina", valueDropdown: "universitas_pertamina", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Dr. Soetomo", valueDropdown: "universitas_dr_soetomo", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Bakrie", valueDropdown: "universitas_bakrie", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Bengkulu", valueDropdown: "universitas_bengkulu", isActive: true,), + BebrasBiro(bebrasBiroUniv: "UIN Walisongo Semarang", valueDropdown: "uin_walisongo_semarang", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Islam Sultan Agung Semarang", valueDropdown: "universitas_islam_sultan_agung_semarang", isActive: true,), + BebrasBiro(bebrasBiroUniv: "UIN Imam Bonjol Padang", valueDropdown: "uin_imam_bonjol_padang", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Institut Pesantren Mathali’ul Falah Pati", valueDropdown: "institut_pesantren_mathali_ul_falah_pati", isActive: true,), + BebrasBiro(bebrasBiroUniv: "UIN Sunan Gunung Djati Bandung", valueDropdown: "uin_sunan_gunung_djati_bandung", isActive: true,), + BebrasBiro(bebrasBiroUniv: "IAIN Pekalongan", valueDropdown: "iain_pekalongan", isActive: true,), + BebrasBiro(bebrasBiroUniv: "UIN Sultan Aji Muhammad Idris Samarinda", valueDropdown: "uin_sultan_aji_muhammad_idris_samarinda", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Politeknik Jambi", valueDropdown: "politeknik_jambi", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Trisakti", valueDropdown: "universitas_trisakti", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Biro Institut Teknologi dan Bisnis Yadika Pasuruan", valueDropdown: "biro_institut_teknologi_dan_bisnis_yadika_pasuruan", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Biro Universitas Widyagama Malang", valueDropdown: "biro_universitas_widyagama_malang", isActive: true,), +]; diff --git a/app/lib/core/constants/colorConstant.dart b/app/lib/core/constants/colorConstant.dart new file mode 100644 index 0000000..f2c2fb0 --- /dev/null +++ b/app/lib/core/constants/colorConstant.dart @@ -0,0 +1,7 @@ +import 'dart:ui'; + +class ColorConstants { + static const Color primaryBlueColor = Color(0XFF6191CB); + static const Color darkPrimaryBlueColor = Color(0XFF2f609c); + static const Color whiteColor = Color(0XFFFFFFFF); +} \ No newline at end of file diff --git a/app/lib/features/authentication/register/presentation/pages/_pages.dart b/app/lib/features/authentication/register/presentation/pages/_pages.dart new file mode 100644 index 0000000..1939ba0 --- /dev/null +++ b/app/lib/features/authentication/register/presentation/pages/_pages.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; + +import '../../../../../core/bases/enum/button_type.dart'; +import '../../../../../core/bases/widgets/atoms/button.dart'; +import '../../../../../core/constants/assets.dart'; +import '../../../../../core/constants/bebrasBiroDropdown.dart'; +import '../../../../../core/constants/colorConstant.dart'; +import '../../../../../services/di.dart'; +// import '../bloc/sign_in_bloc.dart'; +import 'package:dropdown_search/dropdown_search.dart'; + +part 'register_page.dart'; diff --git a/app/lib/features/authentication/register/presentation/pages/register_page.dart b/app/lib/features/authentication/register/presentation/pages/register_page.dart new file mode 100644 index 0000000..6d8db16 --- /dev/null +++ b/app/lib/features/authentication/register/presentation/pages/register_page.dart @@ -0,0 +1,227 @@ +part of '_pages.dart'; + +class RegisterPage extends StatefulWidget { + const RegisterPage({super.key}); + + @override + State createState() => _RegisterPageState(); +} + +class _RegisterPageState extends State { + // late final SignInBloc _signInBloc; + TextEditingController dateinput = TextEditingController(); + String? selectedValue = null; + + @override + void initState() { + // _signInBloc = get(); + + super.initState(); + } + + final _formKey = GlobalKey(); + + Widget buildTextField(String labelText) { + return Container( + height: 50.0, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: TextFormField( + validator: (value) { + if (value == null || value.isEmpty) { + return 'Please enter some text'; + } + return null; + }, + style: TextStyle(fontSize: 12.0), + decoration: InputDecoration( + labelText: labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + ), + ), + ), + ); + } + + Widget buildTextFieldDatePicker(String labelText) { + return Container( + height: 50.0, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: TextField( + controller: dateinput, + style: TextStyle(fontSize: 12.0, color: Colors.black), + decoration: InputDecoration( + labelText: labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + ), + readOnly: true, + //set it true, so that user will not able to edit text + onTap: () async { + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2000), + lastDate: DateTime(2101)); + + if (pickedDate != null) { + String formattedDate = + DateFormat('yyyy-MM-dd').format(pickedDate); + + setState(() { + dateinput.text = formattedDate; + }); + } else { + print("Date is not selected"); + } + }, + ), + ), + ); + } + + List get dropdownItems { + var list = bebrasBiroList.where((el) => el.isActive).toList(); + // List> + var menuItems = list + .map((element) => BebrasBiro( + bebrasBiroUniv: element.bebrasBiroUniv, + valueDropdown: element.valueDropdown, + isActive: element.isActive,), + ).toList(); + return menuItems; + } + + Future> getData(filter) async { + // var response = await Dio().get( + // "https://63c1210999c0a15d28e1ec1d.mockapi.io/users", + // queryParameters: {"filter": filter}, + // ); + + // final data = bebrasBiroList; + // if (data != null) { + // return UserModel.fromJsonList(data); + // } + + return bebrasBiroList; + } + + Widget buildDropdown(String labelText) { + return Container( + height: 105.0, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: DropdownSearch( + asyncItems: (String filter) => getData('filter'), + itemAsString: (BebrasBiro bebras) => bebras.userAsString(), + compareFn: (item, item2) => item == item2, + // dropdownBuilder: _customDropDownExampleMultiSelection, + // print(item); + // print(item2); + // item.i(item2), + popupProps: PopupProps.menu( + showSearchBox: true, + showSelectedItems: true, + // disabledItemFn: (String s) => s.startsWith('I'), + ), + items: dropdownItems, + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + labelText: labelText, + hintText: labelText, + ), + ), + onChanged: print, + selectedItem: null, + ), + // DropdownButtonFormField( + // style: TextStyle(color: Colors.orange), + // decoration: InputDecoration( + // labelText: labelText, + // enabledBorder: OutlineInputBorder( + // borderSide: BorderSide(color: Colors.blue, width: 2), + // borderRadius: BorderRadius.circular(20), + // ), + // border: OutlineInputBorder( + // borderSide: BorderSide(color: Colors.blue, width: 2), + // borderRadius: BorderRadius.circular(20), + // ), + // // filled: true, + // // fillColor: Colors.blueAccent, + // ), + // validator: (value) => value == null ? "Select a country" : null, + // dropdownColor: Colors.blueAccent, + // value: selectedValue, + // onChanged: (String? newValue) { + // print(newValue); + // setState(() { + // selectedValue = newValue!; + // }); + // }, + // items: dropdownItems, + // ), + ), + ); + } + + @override + Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; + return Scaffold( + resizeToAvoidBottomInset: false, + body: Padding( + padding: const EdgeInsets.only(left: 16.0, top: 30.0, right: 16.0), + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Image.asset( + Assets.bebrasPandaiText, + ), + buildTextField('Field Name'), + buildTextField('Email'), + buildTextField('Nama'), + buildTextFieldDatePicker('TTL'), + buildTextField('Sekolah'), + buildTextField('Provinsi'), + // buildTextField('Bebas Biro'), + buildDropdown('Bebras Biro'), + SizedBox(height: 20.0), + ElevatedButton( + onPressed: () { + // Handle form submission + }, + child: Text('Submit'), + ), + ], + ), + ), + ), + ); + } +} diff --git a/app/lib/features/authentication/signin/presentation/pages/_pages.dart b/app/lib/features/authentication/signin/presentation/pages/_pages.dart index c3065f5..4706ef8 100644 --- a/app/lib/features/authentication/signin/presentation/pages/_pages.dart +++ b/app/lib/features/authentication/signin/presentation/pages/_pages.dart @@ -2,9 +2,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; -import '../../../../../core/bases/enum/button_type.dart'; -import '../../../../../core/bases/widgets/atoms/button.dart'; import '../../../../../core/constants/assets.dart'; +import '../../../../../core/constants/colorConstant.dart'; import '../../../../../services/di.dart'; import '../bloc/sign_in_bloc.dart'; diff --git a/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart b/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart index 71ddd30..a337876 100644 --- a/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart +++ b/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart @@ -21,23 +21,24 @@ class _LoginPageState extends State { Widget build(BuildContext context) { final size = MediaQuery.of(context).size; return Scaffold( + backgroundColor: ColorConstants.primaryBlueColor, body: SafeArea( child: Stack( children: [ - Image.asset( - Assets.studyBackground, - fit: BoxFit.cover, - height: size.height * 0.45, - ), + // Image.asset( + // Assets.studyBackground, + // fit: BoxFit.cover, + // height: size.height * 0.45, + // ), Align( alignment: Alignment.bottomCenter, child: Container( padding: const EdgeInsets.all(32), - height: size.height * 0.6, + height: size.height, width: size.width, decoration: BoxDecoration( borderRadius: BorderRadius.circular(32), - color: Colors.white, + color: Colors.transparent, ), child: Column( children: [ @@ -45,21 +46,33 @@ class _LoginPageState extends State { Assets.bebrasPandaiText, ), const SizedBox( - height: 100, + height: 55, + ), + Image.asset( + Assets.bebrasMascot, + fit: BoxFit.cover, + height: size.height * 0.4, + ), + const SizedBox( + height: 30, ), const Text( 'Selamat Datang di Aplikasi Bebras Pandai!', textAlign: TextAlign.center, style: TextStyle( + color: ColorConstants.whiteColor, fontWeight: FontWeight.bold, fontSize: 24, ), ), const SizedBox( - height: 24, + height: 10, ), const Text( 'Yuk cari tahu seberapa tajam logikamu!', + style: TextStyle( + color: ColorConstants.whiteColor, + ), ), const SizedBox( height: 24, @@ -68,17 +81,29 @@ class _LoginPageState extends State { bloc: _signInBloc, listener: (context, state) { if (state is SignInSuccessState) { - context.go('/main'); + // context.go('/main'); + context.go('/register'); } }, builder: (context, state) { return SizedBox( height: 50, width: 200, - child: Button( - text: 'Login with Google', - buttonType: ButtonType.primary, - onTap: () { + child: ElevatedButton( + child: Text( + 'Login with Google', + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w900,),), + style: ButtonStyle( + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18.0), + ) + ), + backgroundColor: MaterialStateProperty.all( + ColorConstants.darkPrimaryBlueColor, + ), + ), + onPressed: () { if (state is! SignInLoadingState) { _signInBloc.add( TriggerSignInEvent(), diff --git a/app/lib/features/main/presentation/pages/main_page.dart b/app/lib/features/main/presentation/pages/main_page.dart index e99e45d..b5db7d3 100644 --- a/app/lib/features/main/presentation/pages/main_page.dart +++ b/app/lib/features/main/presentation/pages/main_page.dart @@ -7,8 +7,20 @@ class MainPage extends StatefulWidget { State createState() => _MainPageState(); } +class Course { + String title; + String description; + Course(this.title, this.description); +} + class _MainPageState extends State { final nama = 'dummy'; + final List courses = [ + Course('SiKecil', 'abdcdafadf'), + Course('Siaga', 'abdcdafadf'), + Course('Penggalang', 'abdcdafadf'), + Course('Penegak', 'abdcdafadf'), + ]; @override Widget build(BuildContext context) { @@ -16,69 +28,117 @@ class _MainPageState extends State { return BebrasScaffold( body: SingleChildScrollView( - child: Stack( + child: Column( children: [ + // Row with Name, Subtitle, and Profile Picture Padding( - padding: const EdgeInsets.all(32), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + padding: const EdgeInsets.all(16.0), + child: Row( children: [ - Image.asset( - Assets.bebrasPandaiText, - ), - const SizedBox( - height: 100, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('John Doe', style: TextStyle(fontSize: 22, fontWeight: FontWeight.w700)), + Text('Subtitle', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.grey)), + ], ), - RichText( - text: TextSpan( - text: 'Selamat Datang\n', - style: FontTheme.blackTitle(), - children: [ - TextSpan( - text: - // ignore: lines_longer_than_80_chars - '${FirebaseService.auth().currentUser?.displayName},', - style: FontTheme.blackTitleBold(), - // recognizer: TapGestureRecognizer() - // ..onTap = () => context.go('/signup'), - ), - ], + Spacer(), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.0), + color: Colors.orange, + ), + child: CircleAvatar( + backgroundImage: AssetImage('assets/profile_image.jpg'), + radius: 30, ), ), - const SizedBox( - height: 30, - ), - Button( - buttonType: ButtonType.primary, - onTap: () async { - await context.push('/construction'); - }, - text: 'Lihat Materi', + ], + ), + ), + + // Banner Photo with Rounded Radius + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20.0), + image: DecorationImage( + image: AssetImage('/assets/bebras-banner.png'), + fit: BoxFit.cover, + ), + ), + height: 200.0, + ), + + // Horizontal Sliding with Big Icon Buttons + Container( + height: 100.0, + child: ListView( + scrollDirection: Axis.horizontal, + children: [ + IconButton( + icon: Icon(Icons.home), + onPressed: () {}, + iconSize: 48.0, ), - const SizedBox( - height: 10, + IconButton( + icon: Icon(Icons.search), + onPressed: () {}, + iconSize: 48.0, ), - Button( - buttonType: ButtonType.primary, - onTap: () async { - await context.push('/construction'); - }, - text: 'Cetak Materi', + IconButton( + icon: Icon(Icons.home), + onPressed: () {}, + iconSize: 48.0, ), - const SizedBox( - height: 10, + IconButton( + icon: Icon(Icons.search), + onPressed: () {}, + iconSize: 48.0, ), - Button( - buttonType: ButtonType.primary, - onTap: () async { - await context.push('/construction'); - }, - text: 'Ikut Quiz', - ), - const SizedBox( - height: 10, + ], + ), + ), + + // Popular Title Aligned Left + Padding( + padding: const EdgeInsets.only(left: 16.0, top: 16.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text('Popular', + style: TextStyle( + fontSize: 24.0, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + + // Vertical List of Cards with Join Button + ListView.builder( + shrinkWrap: true, + physics: NeverScrollableScrollPhysics(), + itemCount: courses.length, + itemBuilder: (context, index) { + return Card( + // Your card content and styling here + child: Column( + children: [ + // Course details + Text(courses[index].title), + Text(courses[index].description), + // Join button + ElevatedButton( + onPressed: () { + // Handle join button click + }, + child: Text('Join'), + ), + ], ), - Button( + ); + }, + ), + Button( buttonType: ButtonType.primary, onTap: () async { await GoogleSignIn().signOut(); @@ -86,31 +146,103 @@ class _MainPageState extends State { }, text: 'Log out', ), - const SizedBox( - height: 60, - ), - InkWell( - onTap: () async { - final url = Uri.parse( - 'https://bebras.or.id/v3/bebras-indonesia-challenge-2022/', - ); - if (!await launchUrl(url)) { - throw Exception('Could not launch $url'); - } - }, - child: Center( - child: Text( - 'Tentang Bebras Challange', - textAlign: TextAlign.center, - style: FontTheme.blackTextBold(), - ), - ), - ), - ], - ), - ), ], ), + // Stack( + // children: [ + // Padding( + // padding: const EdgeInsets.all(32), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Image.asset( + // Assets.bebrasPandaiText, + // ), + // const SizedBox( + // height: 100, + // ), + // RichText( + // text: TextSpan( + // text: 'Selamat Datang\n', + // style: FontTheme.blackTitle(), + // children: [ + // TextSpan( + // text: + // // ignore: lines_longer_than_80_chars + // '${FirebaseService.auth().currentUser?.displayName},', + // style: FontTheme.blackTitleBold(), + // // recognizer: TapGestureRecognizer() + // // ..onTap = () => context.go('/signup'), + // ), + // ], + // ), + // ), + // const SizedBox( + // height: 30, + // ), + // Button( + // buttonType: ButtonType.primary, + // onTap: () async { + // await context.push('/construction'); + // }, + // text: 'Lihat Materi', + // ), + // const SizedBox( + // height: 10, + // ), + // Button( + // buttonType: ButtonType.primary, + // onTap: () async { + // await context.push('/construction'); + // }, + // text: 'Cetak Materi', + // ), + // const SizedBox( + // height: 10, + // ), + // Button( + // buttonType: ButtonType.primary, + // onTap: () async { + // await context.push('/construction'); + // }, + // text: 'Ikut Quiz', + // ), + // const SizedBox( + // height: 10, + // ), + // Button( + // buttonType: ButtonType.primary, + // onTap: () async { + // await GoogleSignIn().signOut(); + // context.go('/onboarding'); + // }, + // text: 'Log out', + // ), + // const SizedBox( + // height: 60, + // ), + // InkWell( + // onTap: () async { + // final url = Uri.parse( + // 'https://bebras.or.id/v3/bebras-indonesia-challenge-2022/', + // ); + // if (!await launchUrl(url)) { + // throw Exception('Could not launch $url'); + // } + // }, + // child: Center( + // child: Text( + // 'Tentang Bebras Challange', + // textAlign: TextAlign.center, + // style: FontTheme.blackTextBold(), + // ), + // ), + // ), + // ], + // ), + // ), + // ], + // ), ), ); } diff --git a/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart b/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart index 1c43fce..f924df1 100644 --- a/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart +++ b/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart @@ -1,32 +1,78 @@ import 'dart:async'; import 'package:equatable/equatable.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:injectable/injectable.dart'; +import '../repositories/register_user_repo.dart'; + part 'user_initialization_event.dart'; + part 'user_initialization_state.dart'; @injectable @singleton class UserInitializationBloc extends Bloc { + final RegisterUserRepository registerUserRepository; final GoogleSignIn _googleSignIn = GoogleSignIn(); - UserInitializationBloc() : super(UserInitializationInitial()) { + + UserInitializationBloc(this.registerUserRepository) : super(UserInitializationInitial()) { on(_auth); + on(_checkUserRegistered); } - FutureOr _auth( - OnboardingAuthEvent state, - Emitter emit, - ) async { + FutureOr _auth(OnboardingAuthEvent state, + Emitter emit,) async { final creds = await _googleSignIn.signInSilently(); - if (creds != null) { emit(UserAuthenticated()); } else { emit(UserUnauthenticated()); } } + + FutureOr _checkUserRegistered(GetUserData state, + Emitter emit) async { + emit(UserInitializationLoading()); + final FirebaseAuth auth = FirebaseAuth.instance; + String userId = auth.currentUser?.uid as String; + // await Future.delayed(const Duration(seconds: 1)); + + try { + final data = await registerUserRepository.getById(userId); + print(data); + + if (data == null) { + emit(UserUnregistered()); + } else { + emit(UserRegistered()); + } + } catch (e) { + emit(UserError(e.toString())); + // emit(Us) + } + } + + FutureOr _createUserData(CreateUserData state, + Emitter emit,) async { + emit(UserGetDataLoading()); + await Future.delayed(const Duration(seconds: 1)); + + try { + await registerUserRepository.create( + email: state.email, + name: state.name, + birth_date: state.birth_date, + school: state.school, + province: state.province, + bebras_biro: state.bebras_biro, + ); + emit(UserDataUploaded()); + } catch (e) { + // emit(Us) + } + } } diff --git a/app/lib/features/onboarding/presentation/bloc/user_initialization_event.dart b/app/lib/features/onboarding/presentation/bloc/user_initialization_event.dart index 0e451ee..824d80c 100644 --- a/app/lib/features/onboarding/presentation/bloc/user_initialization_event.dart +++ b/app/lib/features/onboarding/presentation/bloc/user_initialization_event.dart @@ -8,3 +8,27 @@ abstract class UserInitializationEvent extends Equatable { } class OnboardingAuthEvent extends UserInitializationEvent {} + +class CheckRegisteredUser extends UserInitializationEvent {} + +class CreateUserData extends UserInitializationEvent { + final String email; + final String name; + final DateTime birth_date; + final String school; + final String province; + final String bebras_biro; + + CreateUserData( + this.email, + this.name, + this.birth_date, + this.school, + this.province, + this.bebras_biro, + ); +} + +class GetUserData extends UserInitializationEvent { + GetUserData(); +} diff --git a/app/lib/features/onboarding/presentation/bloc/user_initialization_state.dart b/app/lib/features/onboarding/presentation/bloc/user_initialization_state.dart index 3490edc..2e81ff1 100644 --- a/app/lib/features/onboarding/presentation/bloc/user_initialization_state.dart +++ b/app/lib/features/onboarding/presentation/bloc/user_initialization_state.dart @@ -1,16 +1,58 @@ part of 'user_initialization_bloc.dart'; -abstract class UserInitializationState extends Equatable { - const UserInitializationState(); +abstract class UserInitializationState extends Equatable {} +class UserInitializationInitial extends UserInitializationState { @override List get props => []; } -class UserInitializationInitial extends UserInitializationState {} +class UserInitializationLoading extends UserInitializationState { + @override + List get props => []; +} + +class UserError extends UserInitializationState { + final String error; -class UserInitializationLoading extends UserInitializationState {} + UserError(this.error); + @override + List get props => [error]; +} -class UserAuthenticated extends UserInitializationState {} +class UserAuthenticated extends UserInitializationState { + @override + List get props => []; +} + +class UserUnauthenticated extends UserInitializationState { + @override + List get props => []; +} + +class UserUnregistered extends UserInitializationState { + @override + List get props => []; +} + +class UserRegistered extends UserInitializationState { + @override + List get props => []; +} + +class UserGetDataLoading extends UserInitializationState { + @override + List get props => []; +} + +class UserDataUploaded extends UserInitializationState { + @override + List get props => []; +} -class UserUnauthenticated extends UserInitializationState {} +// class UserDataLoaded extends UserInitializationState { +// final RegisteredUserModel userData; +// UserDataLoaded(this.userDataList); +// @override +// List get props => [userDataList]; +// } diff --git a/app/lib/features/onboarding/presentation/model/registered_user.dart b/app/lib/features/onboarding/presentation/model/registered_user.dart new file mode 100644 index 0000000..86fdd40 --- /dev/null +++ b/app/lib/features/onboarding/presentation/model/registered_user.dart @@ -0,0 +1,28 @@ +class RegisteredUserModel { + final String email; + final String name; + final DateTime birth_date; + final String school; + final String province; + final String bebras_biro; + + RegisteredUserModel({ + required this.email, + required this.name, + required this.birth_date, + required this.school, + required this.province, + required this.bebras_biro, + }); + + factory RegisteredUserModel.fromJson(Map json) { + return RegisteredUserModel( + email: json['email'] as String, + name: json['name'] as String, + birth_date: json['birth_date'] as DateTime, + school: json['school'] as String, + province: json['province'] as String, + bebras_biro: json['bebras_biro'] as String + ); + } +} \ No newline at end of file diff --git a/app/lib/features/onboarding/presentation/pages/splash_screen.dart b/app/lib/features/onboarding/presentation/pages/splash_screen.dart index d894df6..0fbae7e 100644 --- a/app/lib/features/onboarding/presentation/pages/splash_screen.dart +++ b/app/lib/features/onboarding/presentation/pages/splash_screen.dart @@ -8,12 +8,15 @@ class SplashScreen extends StatelessWidget { final size = MediaQuery.of(context).size; return BlocListener( listener: (context, state) { - if (state is UserAuthenticated) { - context.go('/main'); - } else if (state is UserUnauthenticated) { + print(state.toString()); + if (state is UserUnauthenticated) { context.go('/onboarding'); + } else if (state is UserUnregistered) { + context.go('/register'); + } else if (state is UserRegistered) { + context.go('/main'); } - }, + }, child: Scaffold( body: Column( children: [ diff --git a/app/lib/features/onboarding/presentation/repositories/register_user_repo.dart b/app/lib/features/onboarding/presentation/repositories/register_user_repo.dart new file mode 100644 index 0000000..24846da --- /dev/null +++ b/app/lib/features/onboarding/presentation/repositories/register_user_repo.dart @@ -0,0 +1,63 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:flutter/foundation.dart'; +import 'package:injectable/injectable.dart'; + +import '../model/registered_user.dart'; +@Injectable() +class RegisterUserRepository { + final _firecloud = FirebaseFirestore.instance.collection('registered_user'); + + Future create({ + required String email, + required String name, + required DateTime birth_date, + required String school, + required String province, + required String bebras_biro, + }) async { + try { + await _firecloud.add({"name": name, "email": email, }); + } on FirebaseException catch (e) { + if (kDebugMode) { + print("Failed with error '${e.code}': '${e.message}'"); + } + } catch (e) { + throw Exception(e.toString()); + } + } + + Future> getAll() async { + List registeredUserList = []; + try { + final result = await FirebaseFirestore.instance.collection("registered_user").get(); + + result.docs.forEach((element) { + return registeredUserList.add(RegisteredUserModel.fromJson(element.data())); + }); + return registeredUserList; + } on FirebaseException catch (e) { + if (kDebugMode) { + print("Failed with error '${e.code}': '${e.message}'"); + } + return registeredUserList; + } catch (e) { + throw Exception(e.toString()); + } + } + + Future getById(String userId) async { + try { + final result = await FirebaseFirestore.instance + .collection("registered_user").doc(userId).get(); + + return RegisteredUserModel.fromJson(result as Map); + } on FirebaseException catch (e) { + if (kDebugMode) { + print("Failed with error '${e.code}': '${e.message}'"); + } + } catch (e) { + throw Exception(e.toString()); + } + return null; + } +} \ No newline at end of file diff --git a/app/lib/services/di.dart b/app/lib/services/di.dart index d53fac3..e7abc66 100644 --- a/app/lib/services/di.dart +++ b/app/lib/services/di.dart @@ -2,7 +2,7 @@ import 'package:get_it/get_it.dart'; import 'package:injectable/injectable.dart'; import 'di.config.dart'; -final GetIt get = GetIt.I; +final GetIt get = GetIt.instance; @InjectableInit( initializerName: 'init', diff --git a/app/lib/services/router_service.dart b/app/lib/services/router_service.dart index 4992421..d4c14f0 100644 --- a/app/lib/services/router_service.dart +++ b/app/lib/services/router_service.dart @@ -1,5 +1,6 @@ import 'package:go_router/go_router.dart'; +import '../features/authentication/register/presentation/pages/_pages.dart'; import '../features/authentication/signin/presentation/pages/_pages.dart'; import '../features/error/presentation/pages/_pages.dart'; import '../features/main/presentation/pages/_pages.dart'; @@ -15,6 +16,10 @@ GoRouter router = GoRouter( path: '/onboarding', builder: (context, state) => const LoginPage(), ), + GoRoute( + path: '/register', + builder: (context, state) => const RegisterPage(), + ), GoRoute( path: '/main', builder: (context, state) => const MainPage(), diff --git a/app/macos/Flutter/GeneratedPluginRegistrant.swift b/app/macos/Flutter/GeneratedPluginRegistrant.swift index 29f9a61..2c93bec 100644 --- a/app/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import cloud_firestore import firebase_auth import firebase_core import flutter_local_notifications @@ -14,6 +15,7 @@ import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin")) FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) diff --git a/app/pubspec.lock b/app/pubspec.lock index 49449d1..18b216b 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: transitive description: name: _flutterfire_internals - sha256: "1a5e13736d59235ce0139621b4bbe29bc89839e202409081bc667eb3cd20674c" + sha256: d84d98f1992976775f83083523a34c5d22fea191eec3abb2bd09537fb623c2e0 url: "https://pub.dev" source: hosted - version: "1.3.5" + version: "1.3.7" analyzer: dependency: transitive description: @@ -169,6 +169,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + cloud_firestore: + dependency: "direct main" + description: + name: cloud_firestore + sha256: "1179ae4c69e2ea18179d844d70fc6ed2f082a2bbeb7fa62d35a2a24e2992bd4d" + url: "https://pub.dev" + source: hosted + version: "4.9.3" + cloud_firestore_platform_interface: + dependency: transitive + description: + name: cloud_firestore_platform_interface + sha256: acdcf0743bbdd0e6b342f3d2033e15d260a2c6f9434dd34b008b8f1c35e62b23 + url: "https://pub.dev" + source: hosted + version: "5.16.2" + cloud_firestore_web: + dependency: transitive + description: + name: cloud_firestore_web + sha256: "321bb0732c8d782a49aede96805e59609e05cf98b6c34370faa04103f46a4a3a" + url: "https://pub.dev" + source: hosted + version: "3.7.2" code_builder: dependency: transitive description: @@ -233,6 +257,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.3.2" + dropdown_search: + dependency: "direct main" + description: + name: dropdown_search + sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab" + url: "https://pub.dev" + source: hosted + version: "5.0.6" either_dart: dependency: "direct main" description: @@ -301,10 +333,10 @@ packages: dependency: "direct main" description: name: firebase_core - sha256: c78132175edda4bc532a71e01a32964e4b4fcf53de7853a422d96dac3725f389 + sha256: "95580fa07c8ca3072a2bb1fecd792616a33f8683477d25b7d29d3a6a399e6ece" url: "https://pub.dev" source: hosted - version: "2.15.1" + version: "2.17.0" firebase_core_platform_interface: dependency: transitive description: @@ -317,10 +349,10 @@ packages: dependency: transitive description: name: firebase_core_web - sha256: "4cf4d2161530332ddc3c562f19823fb897ff37a9a774090d28df99f47370e973" + sha256: e8c408923cd3a25bd342c576a114f2126769cd1a57106a4edeaa67ea4a84e962 url: "https://pub.dev" source: hosted - version: "2.7.0" + version: "2.8.0" fixnum: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 1ac30c7..118146d 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -51,10 +51,12 @@ dependencies: auto_size_text: ^3.0.0 flutter_polyline_points: ^1.0.0 google_sign_in: ^6.1.4 - firebase_core: ^2.15.1 + firebase_core: ^2.17.0 firebase_auth: ^4.9.0 url_launcher: ^6.1.14 flutter_dotenv: ^5.1.0 + cloud_firestore: ^4.9.3 + dropdown_search: ^5.0.6 dev_dependencies: build_runner: null From c7dee2306c1a3d08e18e78c92d79c224ccb5f572 Mon Sep 17 00:00:00 2001 From: Mirza Widihananta Date: Sun, 15 Oct 2023 09:20:00 +0700 Subject: [PATCH 03/12] fix linter --- app/lib/app.dart | 2 +- .../presentation/pages/quiz_registration_page.dart | 2 +- app/lib/services/router_service.dart | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/lib/app.dart b/app/lib/app.dart index 3c5208d..df79ed7 100644 --- a/app/lib/app.dart +++ b/app/lib/app.dart @@ -25,7 +25,7 @@ class App extends StatelessWidget { OnboardingAuthEvent(), ), ), - BlocProvider(create: (context) => QuizRegistrationCubit()) + BlocProvider(create: (context) => QuizRegistrationCubit()), ], child: MaterialApp.router( theme: ThemeData( diff --git a/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart b/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart index 6667c6e..ede84f3 100644 --- a/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart +++ b/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart @@ -20,7 +20,7 @@ class _QuizRegistrationPageState extends State { builder: (BuildContext context) { return BlocConsumer( listener: (context, state) { - // TODO: implement listener + // TODO(someone): implement listener }, builder: (context, state) { if (state is QuizRegistrationWeekSelected && diff --git a/app/lib/services/router_service.dart b/app/lib/services/router_service.dart index 31c6f29..e24c062 100644 --- a/app/lib/services/router_service.dart +++ b/app/lib/services/router_service.dart @@ -25,7 +25,8 @@ GoRouter router = GoRouter( builder: (context, state) => const UnderConstructionPage(), ), GoRoute( - path: '/quiz_registration', - builder: (context, state) => const QuizRegistrationPage()), + path: '/quiz_registration', + builder: (context, state) => const QuizRegistrationPage(), + ), ], ); From 4d72f83a4839fa1caae2cc0d0ad243ba1f0e6ae1 Mon Sep 17 00:00:00 2001 From: dandiindra29 Date: Tue, 17 Oct 2023 11:28:34 +0700 Subject: [PATCH 04/12] add quiz component --- .../bloc/quiz_registration_cubit.dart | 6 + .../bloc/quiz_registration_state.dart | 20 +- .../pages/quiz_registration_page.dart | 303 ++++++++++-------- 3 files changed, 182 insertions(+), 147 deletions(-) diff --git a/app/lib/features/quiz_registration/bloc/quiz_registration_cubit.dart b/app/lib/features/quiz_registration/bloc/quiz_registration_cubit.dart index 83bc631..405075f 100644 --- a/app/lib/features/quiz_registration/bloc/quiz_registration_cubit.dart +++ b/app/lib/features/quiz_registration/bloc/quiz_registration_cubit.dart @@ -12,4 +12,10 @@ class QuizRegistrationCubit extends Cubit { emit(QuizRegistrationWeekSelected(selectedWeek)); } + + void selectLevel(String selectedLevel) { + emit(QuizRegistrationLoading()); + + emit(QuizRegistrationLevelSelected(selectedLevel)); + } } diff --git a/app/lib/features/quiz_registration/bloc/quiz_registration_state.dart b/app/lib/features/quiz_registration/bloc/quiz_registration_state.dart index 994a204..35dce2a 100644 --- a/app/lib/features/quiz_registration/bloc/quiz_registration_state.dart +++ b/app/lib/features/quiz_registration/bloc/quiz_registration_state.dart @@ -20,19 +20,11 @@ class QuizRegistrationWeekSelected extends QuizRegistrationState { List get props => [selectedWeek]; } -// class QuizRegistrationSuccess extends QuizRegistrationState { -// final List QuizRegistrations; +class QuizRegistrationLevelSelected extends QuizRegistrationState { + final String selectedLevel; -// const QuizRegistrationSuccess(this.QuizRegistrations); + const QuizRegistrationLevelSelected(this.selectedLevel); -// @override -// List get props => [QuizRegistrations]; -// } - -// class QuizRegistrationFailed extends QuizRegistrationState { -// final String error; - -// const QuizRegistrationFailed(this.error); -// @override -// List get props => [error]; -// } + @override + List get props => [selectedLevel]; +} diff --git a/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart b/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart index 6667c6e..c8e60a8 100644 --- a/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart +++ b/app/lib/features/quiz_registration/presentation/pages/quiz_registration_page.dart @@ -12,121 +12,52 @@ class QuizRegistrationPage extends StatefulWidget { class _QuizRegistrationPageState extends State { final nama = 'dummy'; - @override - Widget build(BuildContext context) { - Future showModal() async { - return showModalBottomSheet( - context: context, - builder: (BuildContext context) { - return BlocConsumer( - listener: (context, state) { - // TODO: implement listener - }, - builder: (context, state) { - if (state is QuizRegistrationWeekSelected && - state.selectedWeek != '') { - return Container( - constraints: const BoxConstraints(minHeight: 30), - width: double.infinity, - color: Colors.white, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox( - height: 20, - ), - Container( - margin: const EdgeInsets.only(left: 20), - child: InkWell( - onTap: () => context - .read() - .selectWeek(''), - child: const Row( - children: [ - Icon(Icons.chevron_left), - Text('Pilih Minggu') - ], - ), - ), - ), - const SizedBox( - height: 20, - ), - Container( - margin: const EdgeInsets.only(left: 20), - child: Text( - 'Daftar Latihan Bebras ${state.selectedWeek == 'next_week' ? 'Minggu Depan' : 'Minggu Ini'}', - textAlign: TextAlign.left, - style: const TextStyle( - fontSize: 18, fontWeight: FontWeight.bold), - ), - ), - const SizedBox( - height: 25, - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 40), - width: double.infinity, - child: Button( - onTap: () => context - .read() - .selectWeek('next_week'), - customButtonColor: Colors.blue.shade400, - customTextColor: Colors.white, - text: 'siKecil', - )), - const SizedBox( - height: 15, - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 40), - width: double.infinity, - child: Button( - onTap: () => context - .read() - .selectWeek('this_week'), - customButtonColor: Colors.green.shade400, - customTextColor: Colors.white, - text: 'Siaga', - )), - const SizedBox( - height: 15, - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 40), - width: double.infinity, - child: Button( - onTap: () => context - .read() - .selectWeek('this_week'), - customButtonColor: Colors.red.shade400, - customTextColor: Colors.white, - text: 'Penggalang', - )), - const SizedBox( - height: 15, - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 40), - width: double.infinity, - child: Button( - onTap: () => context - .read() - .selectWeek('this_week'), - customButtonColor: Colors.orange.shade400, - customTextColor: Colors.white, - text: 'Penegak', - )), - const SizedBox( - height: 20, - ), - ], - ), - ); - } + Widget quizCard() { + return Container( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 18), + decoration: BoxDecoration(border: Border.all()), + child: const Column(children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Quiz A', + style: TextStyle(fontSize: 18), + ), + Text( + 'Nilai: 100', + style: TextStyle(fontSize: 18), + ) + ], + ), + SizedBox( + height: 8, + ), + Row( + children: [ + Text( + 'dikerjakan: 2023-09-09 09:09', + style: TextStyle(fontSize: 12), + ) + ], + ) + ]), + ); + } + + Future showModal() async { + return showModalBottomSheet( + context: context, + builder: (BuildContext context) { + return BlocConsumer( + listener: (context, state) { + // TODO: implement listener + }, + builder: (context, state) { + if (state is QuizRegistrationWeekSelected && + state.selectedWeek != '') { return Container( - height: 260, + constraints: const BoxConstraints(minHeight: 30), width: double.infinity, color: Colors.white, child: Column( @@ -134,14 +65,31 @@ class _QuizRegistrationPageState extends State { mainAxisSize: MainAxisSize.min, children: [ const SizedBox( - height: 40, + height: 20, + ), + Container( + margin: const EdgeInsets.only(left: 20), + child: InkWell( + onTap: () => context + .read() + .selectWeek(''), + child: const Row( + children: [ + Icon(Icons.chevron_left), + Text('Pilih Minggu') + ], + ), + ), + ), + const SizedBox( + height: 20, ), Container( margin: const EdgeInsets.only(left: 20), - child: const Text( - 'Daftar Latihan Bebras', + child: Text( + 'Daftar Latihan Bebras ${state.selectedWeek == 'next_week' ? 'Minggu Depan' : 'Minggu Ini'}', textAlign: TextAlign.left, - style: TextStyle( + style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold), ), ), @@ -154,13 +102,27 @@ class _QuizRegistrationPageState extends State { child: Button( onTap: () => context .read() - .selectWeek('next_week'), + .selectLevel('sikecil'), + customButtonColor: Colors.blue.shade400, + customTextColor: Colors.white, + text: 'siKecil', + )), + const SizedBox( + height: 15, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectLevel('siaga'), customButtonColor: Colors.green.shade400, customTextColor: Colors.white, - text: 'Latihan Minggu Depan', + text: 'Siaga', )), const SizedBox( - height: 20, + height: 15, ), Container( padding: const EdgeInsets.symmetric(horizontal: 40), @@ -168,20 +130,91 @@ class _QuizRegistrationPageState extends State { child: Button( onTap: () => context .read() - .selectWeek('this_week'), - customButtonColor: Colors.brown.shade400, + .selectLevel('penggalang'), + customButtonColor: Colors.red.shade400, customTextColor: Colors.white, - text: 'Latihan Minggu Ini', - )) + text: 'Penggalang', + )), + const SizedBox( + height: 15, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectLevel('penegak'), + customButtonColor: Colors.orange.shade400, + customTextColor: Colors.white, + text: 'Penegak', + )), + const SizedBox( + height: 20, + ), ], ), ); - }, - ); - }, - ).whenComplete(() => null); - } + } + return Container( + height: 260, + width: double.infinity, + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox( + height: 40, + ), + Container( + margin: const EdgeInsets.only(left: 20), + child: const Text( + 'Daftar Latihan Bebras', + textAlign: TextAlign.left, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + ), + const SizedBox( + height: 25, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectWeek('next_week'), + customButtonColor: Colors.green.shade400, + customTextColor: Colors.white, + text: 'Latihan Minggu Depan', + )), + const SizedBox( + height: 20, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 40), + width: double.infinity, + child: Button( + onTap: () => context + .read() + .selectWeek('this_week'), + customButtonColor: Colors.brown.shade400, + customTextColor: Colors.white, + text: 'Latihan Minggu Ini', + )) + ], + ), + ); + }, + ); + }, + ).whenComplete(() => null); + } + @override + Widget build(BuildContext context) { return BebrasScaffold( body: SingleChildScrollView( child: Stack( @@ -206,12 +239,16 @@ class _QuizRegistrationPageState extends State { width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration(border: Border.all()), - child: const Column( + child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( + const Text( 'Silahkan klik Tombol `Daftar Latihan Bebras` dibawah untuk memulai', - ) + ), + const SizedBox( + height: 20, + ), + quizCard() ]), ), const SizedBox( From a1973879412d258d63a6af758a6e25f103232b00 Mon Sep 17 00:00:00 2001 From: 12henbx Date: Tue, 17 Oct 2023 15:47:47 +0700 Subject: [PATCH 05/12] fix bloc register form, finish store data to firestore, fix handler error form --- app/android/app/build.gradle | 1 + app/lib/app.dart | 5 + app/lib/core/constants/indonesiaProvince.dart | 57 ++++ .../register/bloc/user_register_bloc.dart | 157 +++++++++ .../register/bloc/user_register_event.dart | 62 ++++ .../register/bloc/user_register_state.dart | 57 ++++ .../register/model/form_item.dart | 15 + .../register}/model/registered_user.dart | 16 +- .../register/model/validation_form_model.dart | 5 + .../register/presentation/pages/_pages.dart | 9 + .../presentation/pages/register_page.dart | 304 ++++++------------ .../widgets/biro_bebras_dropdown.dart | 63 ++++ .../widgets/custom_date_picker.dart | 71 ++++ .../widgets/custom_text_field.dart | 39 +++ .../widgets/province_dropdown.dart | 64 ++++ .../register/provider/FormProvider.dart | 95 ++++++ .../repositories/register_user_repo.dart | 32 +- .../presentation/pages/sign_in_page.dart | 1 - .../bloc/user_initialization_bloc.dart | 36 ++- .../bloc/user_initialization_event.dart | 2 +- .../presentation/pages/splash_screen.dart | 1 - 21 files changed, 859 insertions(+), 233 deletions(-) create mode 100644 app/lib/core/constants/indonesiaProvince.dart create mode 100644 app/lib/features/authentication/register/bloc/user_register_bloc.dart create mode 100644 app/lib/features/authentication/register/bloc/user_register_event.dart create mode 100644 app/lib/features/authentication/register/bloc/user_register_state.dart create mode 100644 app/lib/features/authentication/register/model/form_item.dart rename app/lib/features/{onboarding/presentation => authentication/register}/model/registered_user.dart (50%) create mode 100644 app/lib/features/authentication/register/model/validation_form_model.dart create mode 100644 app/lib/features/authentication/register/presentation/widgets/biro_bebras_dropdown.dart create mode 100644 app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart create mode 100644 app/lib/features/authentication/register/presentation/widgets/custom_text_field.dart create mode 100644 app/lib/features/authentication/register/presentation/widgets/province_dropdown.dart create mode 100644 app/lib/features/authentication/register/provider/FormProvider.dart rename app/lib/features/{onboarding/presentation => authentication/register}/repositories/register_user_repo.dart (68%) diff --git a/app/android/app/build.gradle b/app/android/app/build.gradle index 6548875..3e8e3c4 100644 --- a/app/android/app/build.gradle +++ b/app/android/app/build.gradle @@ -70,4 +70,5 @@ flutter { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'com.google.android.gms:play-services-vision:20.1.3' } diff --git a/app/lib/app.dart b/app/lib/app.dart index 8911108..0ba3ad0 100644 --- a/app/lib/app.dart +++ b/app/lib/app.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'features/authentication/register/bloc/user_register_bloc.dart'; import 'features/onboarding/presentation/bloc/user_initialization_bloc.dart'; import 'services/di.dart'; import 'services/router_service.dart'; @@ -30,6 +31,10 @@ class App extends StatelessWidget { GetUserData(), ), ), + BlocProvider(create: (_) => get() + ..add( + InitEvent(), + )), ], child: MaterialApp.router( theme: ThemeData( diff --git a/app/lib/core/constants/indonesiaProvince.dart b/app/lib/core/constants/indonesiaProvince.dart new file mode 100644 index 0000000..e1cf1d7 --- /dev/null +++ b/app/lib/core/constants/indonesiaProvince.dart @@ -0,0 +1,57 @@ +class IndonesiaProvince { + String provinceName; + String valueProvince; + bool isActive; + + IndonesiaProvince({ + required this.provinceName, + required this.valueProvince, + this.isActive = true, + }); + + String userAsString() { + return this.provinceName; + } +} + +List provinceList = [ + IndonesiaProvince(provinceName: "Bali", valueProvince: "bali", isActive: true,), + IndonesiaProvince(provinceName: "Banten", valueProvince: "banten", isActive: true,), + IndonesiaProvince(provinceName: "Nanggroe Aceh Darussalam", valueProvince: "nanggroe_aceh_darussalam", isActive: true,), + IndonesiaProvince(provinceName: "Sumatera Utara", valueProvince: "sumatera_utara", isActive: true,), + IndonesiaProvince(provinceName: "Sumatera Selatan", valueProvince: "sumatera_selatan", isActive: true,), + IndonesiaProvince(provinceName: "Sumatera Barat", valueProvince: "sumatera_barat", isActive: true,), + IndonesiaProvince(provinceName: "Bengkulu", valueProvince: "bengkulu", isActive: true,), + IndonesiaProvince(provinceName: "Riau", valueProvince: "riau", isActive: true,), + IndonesiaProvince(provinceName: "Kepulauan Riau", valueProvince: "kepulauan_riau", isActive: true,), + IndonesiaProvince(provinceName: "Jambi", valueProvince: "jambi", isActive: true,), + IndonesiaProvince(provinceName: "Lampung", valueProvince: "lampung", isActive: true,), + IndonesiaProvince(provinceName: "Bangka Belitung", valueProvince: "bangka_belitung", isActive: true,), + IndonesiaProvince(provinceName: "Kalimantan Barat", valueProvince: "kalimantan_barat", isActive: true,), + IndonesiaProvince(provinceName: "Kalimantan Timur", valueProvince: "kalimantan_timur", isActive: true,), + IndonesiaProvince(provinceName: "Kalimantan Selatan", valueProvince: "kalimantan_selatan", isActive: true,), + IndonesiaProvince(provinceName: "Kalimantan Tengah", valueProvince: "kalimantan_tengah", isActive: true,), + IndonesiaProvince(provinceName: "Kalimantan Utara", valueProvince: "kalimantan_utara", isActive: true,), + IndonesiaProvince(provinceName: "DKI Jakarta", valueProvince: "dki_jakarta", isActive: true,), + IndonesiaProvince(provinceName: "Jawa Barat", valueProvince: "jawa_barat", isActive: true,), + IndonesiaProvince(provinceName: "Jawa Tengah", valueProvince: "jawa_tengah", isActive: true,), + IndonesiaProvince(provinceName: "DI Yogyakarta", valueProvince: "daerah_istimewa_yogyakarta", isActive: true,), + IndonesiaProvince(provinceName: "Jawa Timur", valueProvince: "jawa_timur", isActive: true,), + IndonesiaProvince(provinceName: "Nusa Tenggara Timur", valueProvince: "nusa_tenggara_timur", isActive: true,), + IndonesiaProvince(provinceName: "Nusa Tenggara Barat", valueProvince: "nusa_tenggara_barat", isActive: true,), + IndonesiaProvince(provinceName: "Gorontalo", valueProvince: "gorontalo", isActive: true,), + IndonesiaProvince(provinceName: "Sulawesi Barat", valueProvince: "sulawesi_barat", isActive: true,), + IndonesiaProvince(provinceName: "Sulawesi Tengah", valueProvince: "sulawesi_tengah", isActive: true,), + IndonesiaProvince(provinceName: "Sulawesi Utara", valueProvince: "sulawesi_utara", isActive: true,), + IndonesiaProvince(provinceName: "Sulawesi Tenggara", valueProvince: "sulawesi_tenggara", isActive: true,), + IndonesiaProvince(provinceName: "Sulawesi Selatan", valueProvince: "sulawesi_selatan", isActive: true,), + IndonesiaProvince(provinceName: "Maluku Utara", valueProvince: "maluku_utara", isActive: true,), + IndonesiaProvince(provinceName: "Maluku", valueProvince: "maluku", isActive: true,), + IndonesiaProvince(provinceName: "Papua Barat", valueProvince: "papua_barat", isActive: true,), + IndonesiaProvince(provinceName: "Papua", valueProvince: "papua", isActive: true,), + IndonesiaProvince(provinceName: "Papua Tengah", valueProvince: "papua_tengah", isActive: true,), + IndonesiaProvince(provinceName: "Papua Pegunungan", valueProvince: "papua_pegunungan", isActive: true,), + IndonesiaProvince(provinceName: "Papua Selatan", valueProvince: "papua_selatan", isActive: true,), + IndonesiaProvince(provinceName: "Papua Barat Daya", valueProvince: "papua_barat_daya", isActive: true,), +]; + diff --git a/app/lib/features/authentication/register/bloc/user_register_bloc.dart b/app/lib/features/authentication/register/bloc/user_register_bloc.dart new file mode 100644 index 0000000..69fcd41 --- /dev/null +++ b/app/lib/features/authentication/register/bloc/user_register_bloc.dart @@ -0,0 +1,157 @@ +import 'dart:async'; + +import 'package:equatable/equatable.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:injectable/injectable.dart'; + +import '../../../authentication/register/repositories/register_user_repo.dart'; +import '../model/form_item.dart'; + +part 'user_register_event.dart'; + +part 'user_register_state.dart'; + +@injectable +@singleton +class UserRegisterBloc extends Bloc { + final RegisterUserRepository registerUserRepository; + UserRegisterBloc(this.registerUserRepository) : super(const RegisterFormState()) { + on(_initState); + on(_onEmailChanged); + on(_onNameChanged); + on(_onBirthDateChanged); + on(_onSchoolChanged); + on(_onProvinceChanged); + on(_onBebrasBiroChanged); + on(_onFormSubmitted); + on(_onFormReset); + } + + final formKey = GlobalKey(); + + Future _initState(InitEvent event, Emitter emit) async { + emit(state.copyWith(formKey: formKey)); + } + + Future _onNameChanged( + NameEvent event, Emitter emit) async { + emit( + state.copyWith( + name: BlocFormItem( + value: event.name.value, + error: event.name.value == '' ? 'Mohon mengisi nama terlebih dahulu.' : null, + ), + formKey: formKey, + ), + ); + } + + Future _onEmailChanged( + EmailEvent event, Emitter emit) async { + emit( + state.copyWith( + email: BlocFormItem( + value: event.email.value, + error: event.email.value == '' ? 'Mohon mengisi e-mail terlebih dahulu.' : null, + ), + formKey: formKey, + ), + ); + } + + Future _onBirthDateChanged( + BirthDateEvent event, Emitter emit) async { + emit( + state.copyWith( + birth_date: BlocFormItem( + value: event.birthDate.value, + error: event.birthDate.value == '' ? 'Mohon mengisi tanggal lahir terlebih dahulu.' : null, + ), + formKey: formKey, + ), + ); + } + + Future _onSchoolChanged( + SchoolEvent event, Emitter emit) async { + emit( + state.copyWith( + school: BlocFormItem( + value: event.school.value, + error: event.school.value == '' ? 'Mohon mengisi nama sekolah terlebih dahulu.' : null, + ), + formKey: formKey, + ), + ); + } + + Future _onProvinceChanged( + ProvinceEvent event, Emitter emit) async { + emit( + state.copyWith( + province: BlocFormItem( + value: event.province.value, + error: event.province.value == '' ? 'Mohon mengisi nama provinsi terlebih dahulu.' : null, + ), + formKey: formKey, + ), + ); + } + + Future _onBebrasBiroChanged( + BebrasBiroEvent event, Emitter emit) async { + emit( + state.copyWith( + bebras_biro: BlocFormItem( + value: event.bebras_biro.value, + error: event.bebras_biro.value == '' ? 'Mohon mengisi biro bebras terlebih dahulu.' : null, + ), + formKey: formKey, + ), + ); + } + + Future _onFormReset( + FormResetEvent event, + Emitter emit, + ) async { + state.formKey?.currentState?.reset(); + } + + Future _onFormSubmitted( + FormSubmitEvent event, + Emitter emit, + ) async { + final FirebaseAuth auth = FirebaseAuth.instance; + String userId = auth.currentUser?.uid as String; + + if (state.formKey!.currentState!.validate()) { + + String email = state.email.value.toString(); + String name = state.name.value.toString(); + String birthDate = state.birth_date.value.toString(); + String school = state.school.value.toString(); + String province = state.province.value.toString(); + String bebrasBiro = state.bebras_biro.value.toString(); + + emit(UserRegisterLoadingState()); + + try { + await registerUserRepository.create( + userId: userId, + email: email, + name: name, + birth_date: birthDate, + school: school, + province: province, + bebras_biro: bebrasBiro, + ); + emit(UserRegisterSuccessState()); + } catch (e) { + // emit(Us) + } + } + } +} diff --git a/app/lib/features/authentication/register/bloc/user_register_event.dart b/app/lib/features/authentication/register/bloc/user_register_event.dart new file mode 100644 index 0000000..9513ead --- /dev/null +++ b/app/lib/features/authentication/register/bloc/user_register_event.dart @@ -0,0 +1,62 @@ +part of 'user_register_bloc.dart'; + +abstract class UserRegisterEvent extends Equatable { + const UserRegisterEvent(); + + @override + List get props => []; +} + +class FormSubmitEvent extends UserRegisterEvent { + const FormSubmitEvent(); +} + +class FormResetEvent extends UserRegisterEvent { + const FormResetEvent(); +} + +class InitEvent extends UserRegisterEvent { + const InitEvent(); +} + +class EmailEvent extends UserRegisterEvent { + const EmailEvent({required this.email}); + final BlocFormItem email; + @override + List get props => [email]; +} + +class NameEvent extends UserRegisterEvent { + const NameEvent({required this.name}); + final BlocFormItem name; + @override + List get props => [name]; +} + +class BirthDateEvent extends UserRegisterEvent { + const BirthDateEvent({required this.birthDate}); + final BlocFormItem birthDate; + @override + List get props => [birthDate]; +} + +class SchoolEvent extends UserRegisterEvent { + const SchoolEvent({required this.school}); + final BlocFormItem school; + @override + List get props => [school]; +} + +class ProvinceEvent extends UserRegisterEvent { + const ProvinceEvent({required this.province}); + final BlocFormItem province; + @override + List get props => [province]; +} + +class BebrasBiroEvent extends UserRegisterEvent { + const BebrasBiroEvent({required this.bebras_biro}); + final BlocFormItem bebras_biro; + @override + List get props => [bebras_biro]; +} diff --git a/app/lib/features/authentication/register/bloc/user_register_state.dart b/app/lib/features/authentication/register/bloc/user_register_state.dart new file mode 100644 index 0000000..a905072 --- /dev/null +++ b/app/lib/features/authentication/register/bloc/user_register_state.dart @@ -0,0 +1,57 @@ +part of 'user_register_bloc.dart'; + +class RegisterFormState extends Equatable { + + const RegisterFormState({ + this.email = const BlocFormItem(error: 'Mohon mengisi e-mail terlebih dahulu.'), + this.name = const BlocFormItem(error: 'Mohon mengisi nama terlebih dahulu.'), + this.birth_date = const BlocFormItem(error: 'Mohon mengisi tanggal lahir terlebih dahulu.'), + this.school = const BlocFormItem(error: 'Mohon mengisi nama sekolah terlebih dahulu.'), + this.province = const BlocFormItem(error: 'Mohon mengisi nama provinsi terlebih dahulu.'), + this.bebras_biro = const BlocFormItem(error: 'Mohon mengisi biro bebras terlebih dahulu.'), + this.formKey, + }); + + final BlocFormItem email; + final BlocFormItem name; + final BlocFormItem birth_date; + final BlocFormItem school; + final BlocFormItem province; + final BlocFormItem bebras_biro; + final GlobalKey? formKey; + + RegisterFormState copyWith({ + BlocFormItem? email, + BlocFormItem? name, + BlocFormItem? birth_date, + BlocFormItem? school, + BlocFormItem? province, + BlocFormItem? bebras_biro, + GlobalKey? formKey, + }) { + return RegisterFormState( + email: email ?? this.email, + name: name ?? this.name, + birth_date: birth_date ?? this.birth_date, + school: school ?? this.school, + province: province ?? this.province, + bebras_biro: bebras_biro ?? this.bebras_biro, + formKey: formKey, + ); + } + + @override + List get props => [email, name, birth_date, school, province, bebras_biro]; +} + +enum FormStatus { none, inProgress, valid, invalid } + +class UserRegisterLoadingState extends RegisterFormState { + @override + List get props => []; +} + +class UserRegisterSuccessState extends RegisterFormState { + @override + List get props => []; +} \ No newline at end of file diff --git a/app/lib/features/authentication/register/model/form_item.dart b/app/lib/features/authentication/register/model/form_item.dart new file mode 100644 index 0000000..2982ce4 --- /dev/null +++ b/app/lib/features/authentication/register/model/form_item.dart @@ -0,0 +1,15 @@ +class BlocFormItem { + final String? error; + final String value; + const BlocFormItem({this.error, this.value = ''}); + + BlocFormItem copyWith({ + String? error, + String? value, + }) { + return BlocFormItem( + error: error ?? this.error, + value: value ?? this.value, + ); + } +} \ No newline at end of file diff --git a/app/lib/features/onboarding/presentation/model/registered_user.dart b/app/lib/features/authentication/register/model/registered_user.dart similarity index 50% rename from app/lib/features/onboarding/presentation/model/registered_user.dart rename to app/lib/features/authentication/register/model/registered_user.dart index 86fdd40..ddf11be 100644 --- a/app/lib/features/onboarding/presentation/model/registered_user.dart +++ b/app/lib/features/authentication/register/model/registered_user.dart @@ -1,7 +1,7 @@ class RegisteredUserModel { final String email; final String name; - final DateTime birth_date; + final String birth_date; final String school; final String province; final String bebras_biro; @@ -15,14 +15,14 @@ class RegisteredUserModel { required this.bebras_biro, }); - factory RegisteredUserModel.fromJson(Map json) { + factory RegisteredUserModel.fromJson(dynamic json) { return RegisteredUserModel( - email: json['email'] as String, - name: json['name'] as String, - birth_date: json['birth_date'] as DateTime, - school: json['school'] as String, - province: json['province'] as String, - bebras_biro: json['bebras_biro'] as String + email: json.data()['email'].toString(), + name: json.data()['name'].toString(), + birth_date: json.data()['birth_date'].toString(), + school: json.data()['school'].toString(), + province: json.data()['province'].toString(), + bebras_biro: json.data()['bebras_biro'].toString() ); } } \ No newline at end of file diff --git a/app/lib/features/authentication/register/model/validation_form_model.dart b/app/lib/features/authentication/register/model/validation_form_model.dart new file mode 100644 index 0000000..9493f29 --- /dev/null +++ b/app/lib/features/authentication/register/model/validation_form_model.dart @@ -0,0 +1,5 @@ +class ValidationFormModel { + String? value; + String? error; + ValidationFormModel(this.value, this.error); +} \ No newline at end of file diff --git a/app/lib/features/authentication/register/presentation/pages/_pages.dart b/app/lib/features/authentication/register/presentation/pages/_pages.dart index 1939ba0..2421992 100644 --- a/app/lib/features/authentication/register/presentation/pages/_pages.dart +++ b/app/lib/features/authentication/register/presentation/pages/_pages.dart @@ -8,8 +8,17 @@ import '../../../../../core/bases/widgets/atoms/button.dart'; import '../../../../../core/constants/assets.dart'; import '../../../../../core/constants/bebrasBiroDropdown.dart'; import '../../../../../core/constants/colorConstant.dart'; +import '../../../../../core/constants/indonesiaProvince.dart'; import '../../../../../services/di.dart'; // import '../bloc/sign_in_bloc.dart'; import 'package:dropdown_search/dropdown_search.dart'; +import '../../bloc/user_register_bloc.dart'; +import '../../model/form_item.dart'; +import '../../repositories/register_user_repo.dart'; +import '../widgets/biro_bebras_dropdown.dart'; +import '../widgets/custom_date_picker.dart'; +import '../widgets/custom_text_field.dart'; +import '../widgets/province_dropdown.dart'; + part 'register_page.dart'; diff --git a/app/lib/features/authentication/register/presentation/pages/register_page.dart b/app/lib/features/authentication/register/presentation/pages/register_page.dart index 6d8db16..8233ae9 100644 --- a/app/lib/features/authentication/register/presentation/pages/register_page.dart +++ b/app/lib/features/authentication/register/presentation/pages/register_page.dart @@ -8,220 +8,120 @@ class RegisterPage extends StatefulWidget { } class _RegisterPageState extends State { - // late final SignInBloc _signInBloc; + late final UserRegisterBloc _userRegisterBloc; TextEditingController dateinput = TextEditingController(); + String? selectedValue = null; @override void initState() { - // _signInBloc = get(); + _userRegisterBloc = get(); super.initState(); } - final _formKey = GlobalKey(); - - Widget buildTextField(String labelText) { - return Container( - height: 50.0, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: TextFormField( - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter some text'; - } - return null; - }, - style: TextStyle(fontSize: 12.0), - decoration: InputDecoration( - labelText: labelText, - filled: true, - fillColor: Colors.grey.shade200, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0), - borderSide: BorderSide(color: Colors.grey.shade200), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0), - borderSide: BorderSide(color: Colors.grey.shade400), - ), - ), - ), - ), - ); - } - - Widget buildTextFieldDatePicker(String labelText) { - return Container( - height: 50.0, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: TextField( - controller: dateinput, - style: TextStyle(fontSize: 12.0, color: Colors.black), - decoration: InputDecoration( - labelText: labelText, - filled: true, - fillColor: Colors.grey.shade200, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0), - borderSide: BorderSide(color: Colors.grey.shade200), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0), - borderSide: BorderSide(color: Colors.grey.shade400), - ), - ), - readOnly: true, - //set it true, so that user will not able to edit text - onTap: () async { - DateTime? pickedDate = await showDatePicker( - context: context, - initialDate: DateTime.now(), - firstDate: DateTime(2000), - lastDate: DateTime(2101)); - - if (pickedDate != null) { - String formattedDate = - DateFormat('yyyy-MM-dd').format(pickedDate); - - setState(() { - dateinput.text = formattedDate; - }); - } else { - print("Date is not selected"); - } - }, - ), - ), - ); - } - - List get dropdownItems { - var list = bebrasBiroList.where((el) => el.isActive).toList(); - // List> - var menuItems = list - .map((element) => BebrasBiro( - bebrasBiroUniv: element.bebrasBiroUniv, - valueDropdown: element.valueDropdown, - isActive: element.isActive,), - ).toList(); - return menuItems; - } - - Future> getData(filter) async { - // var response = await Dio().get( - // "https://63c1210999c0a15d28e1ec1d.mockapi.io/users", - // queryParameters: {"filter": filter}, - // ); - - // final data = bebrasBiroList; - // if (data != null) { - // return UserModel.fromJsonList(data); - // } - - return bebrasBiroList; - } - - Widget buildDropdown(String labelText) { - return Container( - height: 105.0, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: DropdownSearch( - asyncItems: (String filter) => getData('filter'), - itemAsString: (BebrasBiro bebras) => bebras.userAsString(), - compareFn: (item, item2) => item == item2, - // dropdownBuilder: _customDropDownExampleMultiSelection, - // print(item); - // print(item2); - // item.i(item2), - popupProps: PopupProps.menu( - showSearchBox: true, - showSelectedItems: true, - // disabledItemFn: (String s) => s.startsWith('I'), - ), - items: dropdownItems, - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - labelText: labelText, - hintText: labelText, - ), - ), - onChanged: print, - selectedItem: null, - ), - // DropdownButtonFormField( - // style: TextStyle(color: Colors.orange), - // decoration: InputDecoration( - // labelText: labelText, - // enabledBorder: OutlineInputBorder( - // borderSide: BorderSide(color: Colors.blue, width: 2), - // borderRadius: BorderRadius.circular(20), - // ), - // border: OutlineInputBorder( - // borderSide: BorderSide(color: Colors.blue, width: 2), - // borderRadius: BorderRadius.circular(20), - // ), - // // filled: true, - // // fillColor: Colors.blueAccent, - // ), - // validator: (value) => value == null ? "Select a country" : null, - // dropdownColor: Colors.blueAccent, - // value: selectedValue, - // onChanged: (String? newValue) { - // print(newValue); - // setState(() { - // selectedValue = newValue!; - // }); - // }, - // items: dropdownItems, - // ), - ), - ); - } - @override Widget build(BuildContext context) { - final size = MediaQuery.of(context).size; - return Scaffold( - resizeToAvoidBottomInset: false, - body: Padding( - padding: const EdgeInsets.only(left: 16.0, top: 30.0, right: 16.0), - child: Form( - key: _formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Image.asset( - Assets.bebrasPandaiText, - ), - buildTextField('Field Name'), - buildTextField('Email'), - buildTextField('Nama'), - buildTextFieldDatePicker('TTL'), - buildTextField('Sekolah'), - buildTextField('Provinsi'), - // buildTextField('Bebas Biro'), - buildDropdown('Bebras Biro'), - SizedBox(height: 20.0), - ElevatedButton( - onPressed: () { - // Handle form submission - }, - child: Text('Submit'), + return BlocListener( + listener: (context, state) { + if (state is UserRegisterSuccessState) { + context.go('/main'); + } + }, + child: BlocBuilder( + builder: (context, state) { + return Scaffold( + resizeToAvoidBottomInset: false, + body: Padding( + padding: const EdgeInsets.only( + left: 16.0, top: 50.0, right: 16.0), + child: Form( + key: state.formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Image.asset( + Assets.bebrasPandaiText, + height: 40, + ), + SizedBox( + height: 20, + ), + Text( + 'Detail Akun', + style: TextStyle( + fontSize: 22, fontWeight: FontWeight.w700), + ), + SizedBox( + height: 8, + ), + CustomTextField('Email', (value) { + BlocProvider.of(context) + .add(EmailEvent(email: BlocFormItem(value: value!))); + }, (val) { + return state.email.error; + },), + CustomTextField('Nama', (value) { + BlocProvider.of(context) + .add(NameEvent(name: BlocFormItem(value: value!))); + }, (val) { + return state.name.error; + },), + CustomDatePicker('Tanggal Lahir', (value) { + BlocProvider.of(context) + .add(BirthDateEvent(birthDate: BlocFormItem( + value: value!))); + }, (val) { + return state.birth_date.error; + }), + CustomTextField('Sekolah', (value) { + BlocProvider.of(context) + .add(SchoolEvent(school: BlocFormItem( + value: value!))); + }, (val) { + return state.school.error; + }), + ProvinceDropdown('Provinsi', (value) { + BlocProvider.of(context) + .add(ProvinceEvent(province: BlocFormItem( + value: value!))); + }, (val) { + return state.province.error; + }), + BiroBebrasDropdown('Bebras Biro', (value) { + BlocProvider.of(context) + .add(BebrasBiroEvent(bebras_biro: BlocFormItem( + value: value!))); + }, (val) { + return state.bebras_biro.error; + }), + SizedBox(height: 20.0), + BlocConsumer( + bloc: _userRegisterBloc, + listener: (context, state) { + if (state is UserRegisterSuccessState) { + context.go('/main'); + } + }, + builder: (context, state) { + return ElevatedButton( + onPressed: () { + if (state is! UserRegisterLoadingState) { + BlocProvider.of(context) + .add(const FormSubmitEvent()); + // context.go('/main'); + } + }, + child: Text('Submit'), + ); + }), + ], + ), ), - ], - ), - ), - ), + ), + ); + }, + ) ); } } diff --git a/app/lib/features/authentication/register/presentation/widgets/biro_bebras_dropdown.dart b/app/lib/features/authentication/register/presentation/widgets/biro_bebras_dropdown.dart new file mode 100644 index 0000000..bd56707 --- /dev/null +++ b/app/lib/features/authentication/register/presentation/widgets/biro_bebras_dropdown.dart @@ -0,0 +1,63 @@ +import 'package:bebras_pandai/core/constants/bebrasBiroDropdown.dart'; +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:flutter/material.dart'; + +class BiroBebrasDropdown extends StatelessWidget { + BiroBebrasDropdown(this.labelText, this.handleTextInput, this.validator); + + final String labelText; + final void Function (String value)? handleTextInput; + final String? Function(BebrasBiro?)? validator; + + List get dropdownItems { + var list = bebrasBiroList.where((el) => el.isActive).toList(); + var menuItems = list + .map((element) => BebrasBiro( + bebrasBiroUniv: element.bebrasBiroUniv, + valueDropdown: element.valueDropdown, + isActive: element.isActive,), + ).toList(); + return menuItems; + } + + @override + Widget build(BuildContext context) { + return Container( + height: 63.0, + child: DropdownSearch( + validator: validator, + itemAsString: (BebrasBiro bebras) => bebras.userAsString(), + popupProps: PopupProps.menu( + showSearchBox: true, + ), + items: dropdownItems, + dropdownDecoratorProps: DropDownDecoratorProps( + textAlignVertical: TextAlignVertical.center, + baseStyle: TextStyle(fontSize: 12.0), + dropdownSearchDecoration: InputDecoration( + helperText: '', + helperStyle: TextStyle(fontSize: 10,), + hintText: labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + ), + enabledBorder: UnderlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: UnderlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + ), + ), + onChanged: (BebrasBiro? test) => handleTextInput!(test!.valueDropdown), + // print(test?.valueDropdown); + selectedItem: null, + ), + ); + } + +} \ No newline at end of file diff --git a/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart b/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart new file mode 100644 index 0000000..20f2600 --- /dev/null +++ b/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart @@ -0,0 +1,71 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; + +class CustomDatePicker extends StatefulWidget { + CustomDatePicker(this.labelText, this.handleTextInput, this.validator); + + final String labelText; + final void Function (String value)? handleTextInput; + final String? Function(String?)? validator; + + @override + State createState() => _CustomDatePickerState(); +} + +class _CustomDatePickerState extends State { + final TextEditingController dateinput = TextEditingController(); + + @override + Widget build(BuildContext context) { + return Container( + height: 60.0, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 0.0), + child: TextFormField( + controller: dateinput, + validator: widget.validator, + style: TextStyle(fontSize: 12.0, color: Colors.black), + decoration: InputDecoration( + helperText: '', + helperStyle: TextStyle(fontSize: 10), + labelText: widget.labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + ), + readOnly: true, + //set it true, so that user will not able to edit text + onTap: () async { + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2000), + lastDate: DateTime(2101)); + + if (pickedDate != null) { + String formattedDate = + DateFormat('dd MMM yyyy').format(pickedDate); + widget.handleTextInput!(pickedDate.toIso8601String()); + setState(() { + dateinput.text = formattedDate; + }); + } else { + print("Date is not selected"); + } + }, + onChanged: (value) => widget.handleTextInput!(value), + ), + ), + ); + } +} \ No newline at end of file diff --git a/app/lib/features/authentication/register/presentation/widgets/custom_text_field.dart b/app/lib/features/authentication/register/presentation/widgets/custom_text_field.dart new file mode 100644 index 0000000..046edf1 --- /dev/null +++ b/app/lib/features/authentication/register/presentation/widgets/custom_text_field.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; + +class CustomTextField extends StatelessWidget { + CustomTextField(this.labelText, this.handleTextInput, this.validator); + + final String labelText; + final void Function (String value)? handleTextInput; + final String? Function(String?)? validator; + + @override + Widget build(BuildContext context) { + return Container( + height: 60.0, + child: TextFormField( + onChanged: (value) => handleTextInput!(value), + validator: validator, + style: TextStyle(fontSize: 12.0), + decoration: InputDecoration( + helperText: '', + helperStyle: TextStyle(fontSize: 10), + labelText: labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/app/lib/features/authentication/register/presentation/widgets/province_dropdown.dart b/app/lib/features/authentication/register/presentation/widgets/province_dropdown.dart new file mode 100644 index 0000000..da543fb --- /dev/null +++ b/app/lib/features/authentication/register/presentation/widgets/province_dropdown.dart @@ -0,0 +1,64 @@ +import 'package:bebras_pandai/core/constants/indonesiaProvince.dart'; +import 'package:dropdown_search/dropdown_search.dart'; +import 'package:flutter/material.dart'; + +class ProvinceDropdown extends StatelessWidget { + ProvinceDropdown(this.labelText, this.handleTextInput, this.validator); + + final String labelText; + final void Function (String value)? handleTextInput; + final String? Function(IndonesiaProvince?)? validator; + + List get dropdownIndonesiaProvince { + var list = provinceList.where((el) => el.isActive).toList(); + var menuItems = list + .map((element) => IndonesiaProvince( + provinceName: element.provinceName, + valueProvince: element.valueProvince, + isActive: element.isActive,), + ).toList(); + return menuItems; + } + + @override + Widget build(BuildContext context) { + return Container( + // margin: const EdgeInsets.only(top: 10), + height: 63.0, + child: DropdownSearch( + validator: validator, + itemAsString: (IndonesiaProvince indonesiaProvince) => + indonesiaProvince.userAsString(), + popupProps: PopupProps.menu( + showSearchBox: true, + ), + items: dropdownIndonesiaProvince, + dropdownDecoratorProps: DropDownDecoratorProps( + textAlignVertical: TextAlignVertical.center, + baseStyle: TextStyle(fontSize: 12.0), + dropdownSearchDecoration: InputDecoration( + helperText: '', + helperStyle: TextStyle(fontSize: 10), + hintText: labelText, + filled: true, + fillColor: Colors.grey.shade200, + border: UnderlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + ), + enabledBorder: UnderlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade200), + ), + focusedBorder: UnderlineInputBorder( + borderRadius: BorderRadius.circular(10.0), + borderSide: BorderSide(color: Colors.grey.shade400), + ), + ), + ), + // onChanged: (IndonesiaProvince? test) => print(test?.valueProvince), + onChanged: (IndonesiaProvince? test) => handleTextInput!(test!.valueProvince), + selectedItem: null, + ), + ); + } +} \ No newline at end of file diff --git a/app/lib/features/authentication/register/provider/FormProvider.dart b/app/lib/features/authentication/register/provider/FormProvider.dart new file mode 100644 index 0000000..c353252 --- /dev/null +++ b/app/lib/features/authentication/register/provider/FormProvider.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; + +import '../model/validation_form_model.dart'; + +extension extString on String { + bool get isValidEmail { + final emailRegExp = RegExp(r"^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+"); + return emailRegExp.hasMatch(this); + } + + bool get isValidName{ + final nameRegExp = new RegExp(r"^\s*([A-Za-z]{1,}([\.,] |[-']| ))+[A-Za-z]+\.?\s*$"); + return nameRegExp.hasMatch(this); + } + + bool get isNotNull{ + return this!=null; + } + + bool get isValidPhone{ + final phoneRegExp = RegExp(r"^\+?0[0-9]{10}$"); + return phoneRegExp.hasMatch(this); + } + +} + +class FormProvider extends ChangeNotifier { + ValidationFormModel _email = ValidationFormModel(null, null); + ValidationFormModel _name = ValidationFormModel(null, null); + ValidationFormModel _birth_date = ValidationFormModel(null, null); + ValidationFormModel _school = ValidationFormModel(null, null); + ValidationFormModel _province = ValidationFormModel(null, null); + ValidationFormModel _bebras_biro = ValidationFormModel(null, null); + + ValidationFormModel get email => _email; + ValidationFormModel get name => _name; + ValidationFormModel get birthDate => _birth_date; + ValidationFormModel get school => _school; + ValidationFormModel get province => _province; + ValidationFormModel get bebrasBiro => _bebras_biro; + + void validateEmail(String? val) { + if (val != null && val.isValidEmail) { + _email = ValidationFormModel(val, null); + } else { + _email = ValidationFormModel(null, 'Mohon mengisi e-mail terlebih dahulu!'); + } + notifyListeners(); + } + + void validateName(String? val) { + if (val != null && val.isValidName) { + _name = ValidationFormModel(val, null); + } else { + _name = ValidationFormModel(null, 'Mohon mengisi nama terlebih dahulu!'); + } + notifyListeners(); + } + void validateSchool(String? val) { + if (val != null) { + _school = ValidationFormModel(val, null); + } else { + _school = ValidationFormModel(null, 'Mohon mengisi nama sekolah terlebih dahulu!'); + } + notifyListeners(); + } + + + void validateProvince(String? val) { + if (val != null) { + _province = ValidationFormModel(val, null); + } else { + _province = ValidationFormModel(null, 'Mohon mengisi nama provinsi terlebih dahulu!'); + } + notifyListeners(); + } + + void validateBebrasBiro(String? val) { + if (val != null) { + _bebras_biro = ValidationFormModel(val, null); + } else { + _bebras_biro = ValidationFormModel(null, 'Mohon mengisi bebras biro terlebih dahulu!'); + } + notifyListeners(); + } + + bool get validate { + return _email.value != null && + _name.value != null && + _birth_date.value != null && + _school.value != null && + _province.value != null && + _bebras_biro.value != null; + } +} diff --git a/app/lib/features/onboarding/presentation/repositories/register_user_repo.dart b/app/lib/features/authentication/register/repositories/register_user_repo.dart similarity index 68% rename from app/lib/features/onboarding/presentation/repositories/register_user_repo.dart rename to app/lib/features/authentication/register/repositories/register_user_repo.dart index 24846da..c1868e5 100644 --- a/app/lib/features/onboarding/presentation/repositories/register_user_repo.dart +++ b/app/lib/features/authentication/register/repositories/register_user_repo.dart @@ -8,15 +8,26 @@ class RegisterUserRepository { final _firecloud = FirebaseFirestore.instance.collection('registered_user'); Future create({ - required String email, + required String userId, + required dynamic email, required String name, - required DateTime birth_date, + required String birth_date, required String school, required String province, required String bebras_biro, }) async { try { - await _firecloud.add({"name": name, "email": email, }); + await _firecloud.doc(userId) + .set({ + "name": name, + "email": email, + "birth_date": birth_date, + "school": school, + "province": province, + "bebras_biro": bebras_biro, + }, + SetOptions(merge: true), + ); } on FirebaseException catch (e) { if (kDebugMode) { print("Failed with error '${e.code}': '${e.message}'"); @@ -48,9 +59,20 @@ class RegisterUserRepository { Future getById(String userId) async { try { final result = await FirebaseFirestore.instance - .collection("registered_user").doc(userId).get(); + .collection("registered_user") + .doc(userId) + .get() + .then((DocumentSnapshot documentSnapshot) { + if (documentSnapshot.exists) { + return documentSnapshot; + } + }); + if(result != null) { + return RegisteredUserModel.fromJson(result); + } else { + return null; + } - return RegisteredUserModel.fromJson(result as Map); } on FirebaseException catch (e) { if (kDebugMode) { print("Failed with error '${e.code}': '${e.message}'"); diff --git a/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart b/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart index a337876..6e9b181 100644 --- a/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart +++ b/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart @@ -81,7 +81,6 @@ class _LoginPageState extends State { bloc: _signInBloc, listener: (context, state) { if (state is SignInSuccessState) { - // context.go('/main'); context.go('/register'); } }, diff --git a/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart b/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart index f924df1..c5b5c3f 100644 --- a/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart +++ b/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart @@ -6,7 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:injectable/injectable.dart'; -import '../repositories/register_user_repo.dart'; +import '../../../authentication/register/repositories/register_user_repo.dart'; part 'user_initialization_event.dart'; @@ -37,32 +37,38 @@ class UserInitializationBloc FutureOr _checkUserRegistered(GetUserData state, Emitter emit) async { emit(UserInitializationLoading()); - final FirebaseAuth auth = FirebaseAuth.instance; - String userId = auth.currentUser?.uid as String; - // await Future.delayed(const Duration(seconds: 1)); - - try { - final data = await registerUserRepository.getById(userId); - print(data); + final creds = await _googleSignIn.signInSilently(); + if (creds != null) { + final FirebaseAuth auth = FirebaseAuth.instance; + String userId = auth.currentUser?.uid as String; + try { + final data = await registerUserRepository.getById(userId); - if (data == null) { - emit(UserUnregistered()); - } else { - emit(UserRegistered()); + if (data == null) { + emit(UserUnregistered()); + } else { + emit(UserRegistered()); + } + } catch (e) { + emit(UserError(e.toString())); + // emit(Us) } - } catch (e) { - emit(UserError(e.toString())); - // emit(Us) } + + // emit(UserUnregistered()); + } FutureOr _createUserData(CreateUserData state, Emitter emit,) async { + final FirebaseAuth auth = FirebaseAuth.instance; + String userId = auth.currentUser?.uid as String; emit(UserGetDataLoading()); await Future.delayed(const Duration(seconds: 1)); try { await registerUserRepository.create( + userId: userId, email: state.email, name: state.name, birth_date: state.birth_date, diff --git a/app/lib/features/onboarding/presentation/bloc/user_initialization_event.dart b/app/lib/features/onboarding/presentation/bloc/user_initialization_event.dart index 824d80c..52fd027 100644 --- a/app/lib/features/onboarding/presentation/bloc/user_initialization_event.dart +++ b/app/lib/features/onboarding/presentation/bloc/user_initialization_event.dart @@ -14,7 +14,7 @@ class CheckRegisteredUser extends UserInitializationEvent {} class CreateUserData extends UserInitializationEvent { final String email; final String name; - final DateTime birth_date; + final String birth_date; final String school; final String province; final String bebras_biro; diff --git a/app/lib/features/onboarding/presentation/pages/splash_screen.dart b/app/lib/features/onboarding/presentation/pages/splash_screen.dart index 0fbae7e..859159d 100644 --- a/app/lib/features/onboarding/presentation/pages/splash_screen.dart +++ b/app/lib/features/onboarding/presentation/pages/splash_screen.dart @@ -8,7 +8,6 @@ class SplashScreen extends StatelessWidget { final size = MediaQuery.of(context).size; return BlocListener( listener: (context, state) { - print(state.toString()); if (state is UserUnauthenticated) { context.go('/onboarding'); } else if (state is UserUnregistered) { From 109adbf93d018a2180a4885fb4b16dd9064a33d3 Mon Sep 17 00:00:00 2001 From: 12henbx Date: Tue, 17 Oct 2023 15:59:32 +0700 Subject: [PATCH 06/12] fix minor bug university name --- app/lib/core/constants/bebrasBiroDropdown.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/core/constants/bebrasBiroDropdown.dart b/app/lib/core/constants/bebrasBiroDropdown.dart index 532c412..182f7f7 100644 --- a/app/lib/core/constants/bebrasBiroDropdown.dart +++ b/app/lib/core/constants/bebrasBiroDropdown.dart @@ -48,7 +48,7 @@ List bebrasBiroList = [ BebrasBiro(bebrasBiroUniv: "Universitas Katolik Soegijapranata", valueDropdown: "universitas_katolik_soegijapranata", isActive: true,), BebrasBiro(bebrasBiroUniv: "Universitas Muhammadiyah Surakarta", valueDropdown: "universitas_muhammadiyah_surakarta", isActive: true,), BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Jakarta", valueDropdown: "politeknik_negeri_jakarta", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Gajah Mada", valueDropdown: "universitas_gajah_mada", isActive: true,), + BebrasBiro(bebrasBiroUniv: "Universitas Gadjah Mada", valueDropdown: "universitas_gadjah_mada", isActive: true,), BebrasBiro(bebrasBiroUniv: "Universitas Negeri Yogyakarta", valueDropdown: "universitas_negeri_yogyakarta", isActive: true,), BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Bandung", valueDropdown: "politeknik_negeri_bandung", isActive: true,), BebrasBiro(bebrasBiroUniv: "Universitas Hasanudin", valueDropdown: "universitas_hasanudin", isActive: true,), From 31488113e9944f202dfd40b68f0c958c3be9c5a1 Mon Sep 17 00:00:00 2001 From: 12henbx Date: Wed, 18 Oct 2023 00:26:50 +0700 Subject: [PATCH 07/12] fix user login and register in flutter bloc --- app/lib/app.dart | 15 ++---- .../presentation/bloc/sign_in_bloc.dart | 18 ++++++- .../presentation/bloc/sign_in_state.dart | 18 +++++++ .../presentation/pages/sign_in_page.dart | 4 +- .../main/presentation/pages/_pages.dart | 1 + .../main/presentation/pages/main_page.dart | 1 + .../bloc/user_initialization_bloc.dart | 49 +++---------------- 7 files changed, 52 insertions(+), 54 deletions(-) diff --git a/app/lib/app.dart b/app/lib/app.dart index 0ba3ad0..4d3b26e 100644 --- a/app/lib/app.dart +++ b/app/lib/app.dart @@ -19,22 +19,17 @@ class App extends StatelessWidget { ]); return MultiBlocProvider( providers: [ + BlocProvider(create: (_) => get() + ..add( + InitEvent(), + )), BlocProvider( create: (_) => get() ..add( OnboardingAuthEvent(), ), + lazy: false, ), - BlocProvider( - create: (_) => get() - ..add( - GetUserData(), - ), - ), - BlocProvider(create: (_) => get() - ..add( - InitEvent(), - )), ], child: MaterialApp.router( theme: ThemeData( diff --git a/app/lib/features/authentication/signin/presentation/bloc/sign_in_bloc.dart b/app/lib/features/authentication/signin/presentation/bloc/sign_in_bloc.dart index 2ec8dd5..2cda657 100644 --- a/app/lib/features/authentication/signin/presentation/bloc/sign_in_bloc.dart +++ b/app/lib/features/authentication/signin/presentation/bloc/sign_in_bloc.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:bebras_pandai/features/authentication/register/repositories/register_user_repo.dart'; import 'package:equatable/equatable.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -13,7 +14,8 @@ part 'sign_in_state.dart'; @injectable class SignInBloc extends Bloc { final SignInUseCase _signInUseCase; - SignInBloc(this._signInUseCase) : super(SignInInitialState()) { + final RegisterUserRepository registerUserRepository; + SignInBloc(this._signInUseCase, this.registerUserRepository) : super(SignInInitialState()) { on(_userSignIn); } @@ -35,6 +37,20 @@ class SignInBloc extends Bloc { }, (right) async { emit(SignInSuccessState(user: right)); + final creds = FirebaseAuth.instance.currentUser; + String userId = creds!.uid as String; + try { + final data = await registerUserRepository.getById(userId); + + print(data); + if (data == null) { + emit(UserUnregistered()); + } else { + emit(UserRegistered()); + } + } catch (e) { + emit(UserError(e.toString())); + } }, ); } diff --git a/app/lib/features/authentication/signin/presentation/bloc/sign_in_state.dart b/app/lib/features/authentication/signin/presentation/bloc/sign_in_state.dart index f2d580a..0984e9f 100644 --- a/app/lib/features/authentication/signin/presentation/bloc/sign_in_state.dart +++ b/app/lib/features/authentication/signin/presentation/bloc/sign_in_state.dart @@ -32,3 +32,21 @@ class SignInFailureState extends SignInState { @override List get props => [message]; } + +class UserUnregistered extends SignInState { + @override + List get props => []; +} + +class UserRegistered extends SignInState { + @override + List get props => []; +} + +class UserError extends SignInState { + final String error; + + UserError(this.error); + @override + List get props => [error]; +} diff --git a/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart b/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart index 6e9b181..2012a64 100644 --- a/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart +++ b/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart @@ -80,8 +80,10 @@ class _LoginPageState extends State { BlocConsumer( bloc: _signInBloc, listener: (context, state) { - if (state is SignInSuccessState) { + if (state is UserUnregistered) { context.go('/register'); + } else if (state is UserRegistered) { + context.go('/main'); } }, builder: (context, state) { diff --git a/app/lib/features/main/presentation/pages/_pages.dart b/app/lib/features/main/presentation/pages/_pages.dart index 1e1b68d..783f4be 100644 --- a/app/lib/features/main/presentation/pages/_pages.dart +++ b/app/lib/features/main/presentation/pages/_pages.dart @@ -1,3 +1,4 @@ +import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:google_sign_in/google_sign_in.dart'; diff --git a/app/lib/features/main/presentation/pages/main_page.dart b/app/lib/features/main/presentation/pages/main_page.dart index b5db7d3..770aaa8 100644 --- a/app/lib/features/main/presentation/pages/main_page.dart +++ b/app/lib/features/main/presentation/pages/main_page.dart @@ -141,6 +141,7 @@ class _MainPageState extends State { Button( buttonType: ButtonType.primary, onTap: () async { + await FirebaseAuth.instance.signOut(); await GoogleSignIn().signOut(); context.go('/onboarding'); }, diff --git a/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart b/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart index c5b5c3f..a6a0455 100644 --- a/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart +++ b/app/lib/features/onboarding/presentation/bloc/user_initialization_bloc.dart @@ -17,33 +17,23 @@ part 'user_initialization_state.dart'; class UserInitializationBloc extends Bloc { final RegisterUserRepository registerUserRepository; - final GoogleSignIn _googleSignIn = GoogleSignIn(); + // final GoogleSignIn _googleSignIn = GoogleSignIn(); UserInitializationBloc(this.registerUserRepository) : super(UserInitializationInitial()) { on(_auth); - on(_checkUserRegistered); } FutureOr _auth(OnboardingAuthEvent state, Emitter emit,) async { - final creds = await _googleSignIn.signInSilently(); + // final creds = await _googleSignIn.signInSilently(); + final creds = FirebaseAuth.instance.currentUser; if (creds != null) { emit(UserAuthenticated()); - } else { - emit(UserUnauthenticated()); - } - } - - FutureOr _checkUserRegistered(GetUserData state, - Emitter emit) async { - emit(UserInitializationLoading()); - final creds = await _googleSignIn.signInSilently(); - if (creds != null) { - final FirebaseAuth auth = FirebaseAuth.instance; - String userId = auth.currentUser?.uid as String; + String userId = creds.uid as String; try { final data = await registerUserRepository.getById(userId); + print(data); if (data == null) { emit(UserUnregistered()); } else { @@ -51,34 +41,9 @@ class UserInitializationBloc } } catch (e) { emit(UserError(e.toString())); - // emit(Us) } - } - - // emit(UserUnregistered()); - - } - - FutureOr _createUserData(CreateUserData state, - Emitter emit,) async { - final FirebaseAuth auth = FirebaseAuth.instance; - String userId = auth.currentUser?.uid as String; - emit(UserGetDataLoading()); - await Future.delayed(const Duration(seconds: 1)); - - try { - await registerUserRepository.create( - userId: userId, - email: state.email, - name: state.name, - birth_date: state.birth_date, - school: state.school, - province: state.province, - bebras_biro: state.bebras_biro, - ); - emit(UserDataUploaded()); - } catch (e) { - // emit(Us) + } else { + emit(UserUnauthenticated()); } } } From ae9cad56c327b50bd1d58f8ed1e6492432f80bcf Mon Sep 17 00:00:00 2001 From: 12henbx Date: Wed, 18 Oct 2023 00:33:16 +0700 Subject: [PATCH 08/12] revert main page --- .../main/presentation/pages/main_page.dart | 270 +++++------------- 1 file changed, 75 insertions(+), 195 deletions(-) diff --git a/app/lib/features/main/presentation/pages/main_page.dart b/app/lib/features/main/presentation/pages/main_page.dart index 770aaa8..77c48f5 100644 --- a/app/lib/features/main/presentation/pages/main_page.dart +++ b/app/lib/features/main/presentation/pages/main_page.dart @@ -28,117 +28,69 @@ class _MainPageState extends State { return BebrasScaffold( body: SingleChildScrollView( - child: Column( + child: Stack( children: [ - // Row with Name, Subtitle, and Profile Picture Padding( - padding: const EdgeInsets.all(16.0), - child: Row( + padding: const EdgeInsets.all(32), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('John Doe', style: TextStyle(fontSize: 22, fontWeight: FontWeight.w700)), - Text('Subtitle', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w400, color: Colors.grey)), - ], + Image.asset( + Assets.bebrasPandaiText, ), - Spacer(), - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.0), - color: Colors.orange, - ), - child: CircleAvatar( - backgroundImage: AssetImage('assets/profile_image.jpg'), - radius: 30, + const SizedBox( + height: 100, + ), + RichText( + text: TextSpan( + text: 'Selamat Datang\n', + style: FontTheme.blackTitle(), + children: [ + TextSpan( + text: + // ignore: lines_longer_than_80_chars + '${FirebaseService.auth().currentUser?.displayName},', + style: FontTheme.blackTitleBold(), + // recognizer: TapGestureRecognizer() + // ..onTap = () => context.go('/signup'), + ), + ], ), ), - ], - ), - ), - - // Banner Photo with Rounded Radius - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.0), - image: DecorationImage( - image: AssetImage('/assets/bebras-banner.png'), - fit: BoxFit.cover, - ), - ), - height: 200.0, - ), - - // Horizontal Sliding with Big Icon Buttons - Container( - height: 100.0, - child: ListView( - scrollDirection: Axis.horizontal, - children: [ - IconButton( - icon: Icon(Icons.home), - onPressed: () {}, - iconSize: 48.0, + const SizedBox( + height: 30, ), - IconButton( - icon: Icon(Icons.search), - onPressed: () {}, - iconSize: 48.0, + Button( + buttonType: ButtonType.primary, + onTap: () async { + await context.push('/construction'); + }, + text: 'Lihat Materi', ), - IconButton( - icon: Icon(Icons.home), - onPressed: () {}, - iconSize: 48.0, + const SizedBox( + height: 10, ), - IconButton( - icon: Icon(Icons.search), - onPressed: () {}, - iconSize: 48.0, + Button( + buttonType: ButtonType.primary, + onTap: () async { + await context.push('/construction'); + }, + text: 'Cetak Materi', ), - ], - ), - ), - - // Popular Title Aligned Left - Padding( - padding: const EdgeInsets.only(left: 16.0, top: 16.0), - child: Align( - alignment: Alignment.centerLeft, - child: Text('Popular', - style: TextStyle( - fontSize: 24.0, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - - // Vertical List of Cards with Join Button - ListView.builder( - shrinkWrap: true, - physics: NeverScrollableScrollPhysics(), - itemCount: courses.length, - itemBuilder: (context, index) { - return Card( - // Your card content and styling here - child: Column( - children: [ - // Course details - Text(courses[index].title), - Text(courses[index].description), - // Join button - ElevatedButton( - onPressed: () { - // Handle join button click - }, - child: Text('Join'), - ), - ], + const SizedBox( + height: 10, ), - ); - }, - ), - Button( + Button( + buttonType: ButtonType.primary, + onTap: () async { + await context.push('/construction'); + }, + text: 'Ikut Quiz', + ), + const SizedBox( + height: 10, + ), + Button( buttonType: ButtonType.primary, onTap: () async { await FirebaseAuth.instance.signOut(); @@ -147,103 +99,31 @@ class _MainPageState extends State { }, text: 'Log out', ), + const SizedBox( + height: 60, + ), + InkWell( + onTap: () async { + final url = Uri.parse( + 'https://bebras.or.id/v3/bebras-indonesia-challenge-2022/', + ); + if (!await launchUrl(url)) { + throw Exception('Could not launch $url'); + } + }, + child: Center( + child: Text( + 'Tentang Bebras Challange', + textAlign: TextAlign.center, + style: FontTheme.blackTextBold(), + ), + ), + ), + ], + ), + ), ], ), - // Stack( - // children: [ - // Padding( - // padding: const EdgeInsets.all(32), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Image.asset( - // Assets.bebrasPandaiText, - // ), - // const SizedBox( - // height: 100, - // ), - // RichText( - // text: TextSpan( - // text: 'Selamat Datang\n', - // style: FontTheme.blackTitle(), - // children: [ - // TextSpan( - // text: - // // ignore: lines_longer_than_80_chars - // '${FirebaseService.auth().currentUser?.displayName},', - // style: FontTheme.blackTitleBold(), - // // recognizer: TapGestureRecognizer() - // // ..onTap = () => context.go('/signup'), - // ), - // ], - // ), - // ), - // const SizedBox( - // height: 30, - // ), - // Button( - // buttonType: ButtonType.primary, - // onTap: () async { - // await context.push('/construction'); - // }, - // text: 'Lihat Materi', - // ), - // const SizedBox( - // height: 10, - // ), - // Button( - // buttonType: ButtonType.primary, - // onTap: () async { - // await context.push('/construction'); - // }, - // text: 'Cetak Materi', - // ), - // const SizedBox( - // height: 10, - // ), - // Button( - // buttonType: ButtonType.primary, - // onTap: () async { - // await context.push('/construction'); - // }, - // text: 'Ikut Quiz', - // ), - // const SizedBox( - // height: 10, - // ), - // Button( - // buttonType: ButtonType.primary, - // onTap: () async { - // await GoogleSignIn().signOut(); - // context.go('/onboarding'); - // }, - // text: 'Log out', - // ), - // const SizedBox( - // height: 60, - // ), - // InkWell( - // onTap: () async { - // final url = Uri.parse( - // 'https://bebras.or.id/v3/bebras-indonesia-challenge-2022/', - // ); - // if (!await launchUrl(url)) { - // throw Exception('Could not launch $url'); - // } - // }, - // child: Center( - // child: Text( - // 'Tentang Bebras Challange', - // textAlign: TextAlign.center, - // style: FontTheme.blackTextBold(), - // ), - // ), - // ), - // ], - // ), - // ), - // ], - // ), ), ); } From 131505a5ee656357da1f8f1c6c2b9c4a8633cff9 Mon Sep 17 00:00:00 2001 From: 12henbx Date: Wed, 18 Oct 2023 12:16:06 +0700 Subject: [PATCH 09/12] revert design, use general scaffold component --- .../bases/widgets/layout/bebras_scaffold.dart | 4 +- .../register/presentation/pages/_pages.dart | 1 + .../presentation/pages/register_page.dart | 10 +- .../widgets/custom_date_picker.dart | 2 +- .../presentation/pages/sign_in_page.dart | 134 +++++++++++++++--- .../main/presentation/pages/main_page.dart | 2 +- 6 files changed, 123 insertions(+), 30 deletions(-) diff --git a/app/lib/core/bases/widgets/layout/bebras_scaffold.dart b/app/lib/core/bases/widgets/layout/bebras_scaffold.dart index 93db499..eb267f3 100644 --- a/app/lib/core/bases/widgets/layout/bebras_scaffold.dart +++ b/app/lib/core/bases/widgets/layout/bebras_scaffold.dart @@ -2,11 +2,13 @@ import 'package:flutter/material.dart'; class BebrasScaffold extends StatelessWidget { final Widget body; - const BebrasScaffold({required this.body, super.key}); + final bool avoidBottomInset; + const BebrasScaffold({required this.body, super.key, this.avoidBottomInset = true}); @override Widget build(BuildContext context) { return Scaffold( + resizeToAvoidBottomInset: avoidBottomInset, body: SafeArea( child: body, ), diff --git a/app/lib/features/authentication/register/presentation/pages/_pages.dart b/app/lib/features/authentication/register/presentation/pages/_pages.dart index 2421992..32f9bcd 100644 --- a/app/lib/features/authentication/register/presentation/pages/_pages.dart +++ b/app/lib/features/authentication/register/presentation/pages/_pages.dart @@ -5,6 +5,7 @@ import 'package:intl/intl.dart'; import '../../../../../core/bases/enum/button_type.dart'; import '../../../../../core/bases/widgets/atoms/button.dart'; +import '../../../../../core/bases/widgets/layout/bebras_scaffold.dart'; import '../../../../../core/constants/assets.dart'; import '../../../../../core/constants/bebrasBiroDropdown.dart'; import '../../../../../core/constants/colorConstant.dart'; diff --git a/app/lib/features/authentication/register/presentation/pages/register_page.dart b/app/lib/features/authentication/register/presentation/pages/register_page.dart index 8233ae9..ccb1085 100644 --- a/app/lib/features/authentication/register/presentation/pages/register_page.dart +++ b/app/lib/features/authentication/register/presentation/pages/register_page.dart @@ -30,11 +30,11 @@ class _RegisterPageState extends State { }, child: BlocBuilder( builder: (context, state) { - return Scaffold( - resizeToAvoidBottomInset: false, + return BebrasScaffold( + avoidBottomInset: false, body: Padding( padding: const EdgeInsets.only( - left: 16.0, top: 50.0, right: 16.0), + left: 16.0, top: 30.0, right: 16.0), child: Form( key: state.formKey, child: Column( @@ -45,7 +45,7 @@ class _RegisterPageState extends State { height: 40, ), SizedBox( - height: 20, + height: 40, ), Text( 'Detail Akun', @@ -112,7 +112,7 @@ class _RegisterPageState extends State { // context.go('/main'); } }, - child: Text('Submit'), + child: Text('Daftar'), ); }), ], diff --git a/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart b/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart index 20f2600..1b648d7 100644 --- a/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart +++ b/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart @@ -49,7 +49,7 @@ class _CustomDatePickerState extends State { DateTime? pickedDate = await showDatePicker( context: context, initialDate: DateTime.now(), - firstDate: DateTime(2000), + firstDate: DateTime(1900), lastDate: DateTime(2101)); if (pickedDate != null) { diff --git a/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart b/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart index 2012a64..7af8086 100644 --- a/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart +++ b/app/lib/features/authentication/signin/presentation/pages/sign_in_page.dart @@ -21,24 +21,23 @@ class _LoginPageState extends State { Widget build(BuildContext context) { final size = MediaQuery.of(context).size; return Scaffold( - backgroundColor: ColorConstants.primaryBlueColor, body: SafeArea( child: Stack( children: [ - // Image.asset( - // Assets.studyBackground, - // fit: BoxFit.cover, - // height: size.height * 0.45, - // ), + Image.asset( + Assets.studyBackground, + fit: BoxFit.cover, + height: size.height * 0.45, + ), Align( alignment: Alignment.bottomCenter, child: Container( padding: const EdgeInsets.all(32), - height: size.height, + height: size.height * 0.6, width: size.width, decoration: BoxDecoration( borderRadius: BorderRadius.circular(32), - color: Colors.transparent, + color: Colors.white, ), child: Column( children: [ @@ -46,33 +45,21 @@ class _LoginPageState extends State { Assets.bebrasPandaiText, ), const SizedBox( - height: 55, - ), - Image.asset( - Assets.bebrasMascot, - fit: BoxFit.cover, - height: size.height * 0.4, - ), - const SizedBox( - height: 30, + height: 100, ), const Text( 'Selamat Datang di Aplikasi Bebras Pandai!', textAlign: TextAlign.center, style: TextStyle( - color: ColorConstants.whiteColor, fontWeight: FontWeight.bold, fontSize: 24, ), ), const SizedBox( - height: 10, + height: 24, ), const Text( 'Yuk cari tahu seberapa tajam logikamu!', - style: TextStyle( - color: ColorConstants.whiteColor, - ), ), const SizedBox( height: 24, @@ -123,5 +110,108 @@ class _LoginPageState extends State { ), ), ); + // Scaffold( + // backgroundColor: ColorConstants.primaryBlueColor, + // body: SafeArea( + // child: Stack( + // children: [ + // // Image.asset( + // // Assets.studyBackground, + // // fit: BoxFit.cover, + // // height: size.height * 0.45, + // // ), + // Align( + // alignment: Alignment.bottomCenter, + // child: Container( + // padding: const EdgeInsets.all(32), + // height: size.height, + // width: size.width, + // decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(32), + // color: Colors.transparent, + // ), + // child: Column( + // children: [ + // Image.asset( + // Assets.bebrasPandaiText, + // ), + // const SizedBox( + // height: 55, + // ), + // Image.asset( + // Assets.bebrasMascot, + // fit: BoxFit.cover, + // height: size.height * 0.4, + // ), + // const SizedBox( + // height: 30, + // ), + // const Text( + // 'Selamat Datang di Aplikasi Bebras Pandai!', + // textAlign: TextAlign.center, + // style: TextStyle( + // color: ColorConstants.whiteColor, + // fontWeight: FontWeight.bold, + // fontSize: 24, + // ), + // ), + // const SizedBox( + // height: 10, + // ), + // const Text( + // 'Yuk cari tahu seberapa tajam logikamu!', + // style: TextStyle( + // color: ColorConstants.whiteColor, + // ), + // ), + // const SizedBox( + // height: 24, + // ), + // BlocConsumer( + // bloc: _signInBloc, + // listener: (context, state) { + // if (state is UserUnregistered) { + // context.go('/register'); + // } else if (state is UserRegistered) { + // context.go('/main'); + // } + // }, + // builder: (context, state) { + // return SizedBox( + // height: 50, + // width: 200, + // child: ElevatedButton( + // child: Text( + // 'Login with Google', + // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w900,),), + // style: ButtonStyle( + // shape: MaterialStateProperty.all( + // RoundedRectangleBorder( + // borderRadius: BorderRadius.circular(18.0), + // ) + // ), + // backgroundColor: MaterialStateProperty.all( + // ColorConstants.darkPrimaryBlueColor, + // ), + // ), + // onPressed: () { + // if (state is! SignInLoadingState) { + // _signInBloc.add( + // TriggerSignInEvent(), + // ); + // } + // }, + // ), + // ); + // }, + // ), + // ], + // ), + // ), + // ), + // ], + // ), + // ), + // ); } } diff --git a/app/lib/features/main/presentation/pages/main_page.dart b/app/lib/features/main/presentation/pages/main_page.dart index 77c48f5..4e8a3f6 100644 --- a/app/lib/features/main/presentation/pages/main_page.dart +++ b/app/lib/features/main/presentation/pages/main_page.dart @@ -39,7 +39,7 @@ class _MainPageState extends State { Assets.bebrasPandaiText, ), const SizedBox( - height: 100, + height: 40, ), RichText( text: TextSpan( From 88ba58eb9bc8d3ccf6cd1cac0ddae8d7128d68ae Mon Sep 17 00:00:00 2001 From: 12henbx Date: Wed, 18 Oct 2023 12:30:37 +0700 Subject: [PATCH 10/12] adjust style register page --- .../register/presentation/pages/register_page.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/lib/features/authentication/register/presentation/pages/register_page.dart b/app/lib/features/authentication/register/presentation/pages/register_page.dart index ccb1085..13315fb 100644 --- a/app/lib/features/authentication/register/presentation/pages/register_page.dart +++ b/app/lib/features/authentication/register/presentation/pages/register_page.dart @@ -22,6 +22,7 @@ class _RegisterPageState extends State { @override Widget build(BuildContext context) { + final size = MediaQuery.of(context).size; return BlocListener( listener: (context, state) { if (state is UserRegisterSuccessState) { @@ -105,6 +106,14 @@ class _RegisterPageState extends State { }, builder: (context, state) { return ElevatedButton( + style: ElevatedButton.styleFrom( + fixedSize: Size(size.width, 45), + backgroundColor: Colors.black, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), onPressed: () { if (state is! UserRegisterLoadingState) { BlocProvider.of(context) @@ -112,7 +121,7 @@ class _RegisterPageState extends State { // context.go('/main'); } }, - child: Text('Daftar'), + child: Text('Daftar', style: TextStyle(fontWeight: FontWeight.w600),), ); }), ], From 0d344b4430fabb41cc4f214d504189e3928b9f7c Mon Sep 17 00:00:00 2001 From: 12henbx Date: Thu, 19 Oct 2023 14:23:59 +0700 Subject: [PATCH 11/12] change list of dropdown, adjust date picker value --- .../core/constants/bebrasBiroDropdown.dart | 186 +++++++++--------- app/lib/core/constants/indonesiaProvince.dart | 78 ++++---- .../widgets/biro_bebras_dropdown.dart | 21 +- .../widgets/custom_date_picker.dart | 2 +- .../widgets/province_dropdown.dart | 22 +-- 5 files changed, 141 insertions(+), 168 deletions(-) diff --git a/app/lib/core/constants/bebrasBiroDropdown.dart b/app/lib/core/constants/bebrasBiroDropdown.dart index 182f7f7..f73e86b 100644 --- a/app/lib/core/constants/bebrasBiroDropdown.dart +++ b/app/lib/core/constants/bebrasBiroDropdown.dart @@ -14,97 +14,97 @@ class BebrasBiro { } } -List bebrasBiroList = [ - BebrasBiro(bebrasBiroUniv: "Institut Teknologi Bandung", valueDropdown: "institut_teknologi_bandung", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Institut Pertanian Bogor", valueDropdown: "institut_pertanian_bogor", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Indonesia", valueDropdown: "universitas_indonesia", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Institut Teknologi Sepuluh November", valueDropdown: "institut_teknologi_sepuluh_november", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Kristen Maranatha", valueDropdown: "universitas_kristen_maranatha", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Atmajaya Yogyakarta", valueDropdown: "universitas_atmajaya_yogyakarta", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Diponegoro", valueDropdown: "universitas_diponegoro", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Islam Indonesia", valueDropdown: "universitas_islam_indonesia", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Jendral Soedirman", valueDropdown: "universitas_jendral_soedirman", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Jember", valueDropdown: "universitas_jember", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Sriwijaya", valueDropdown: "universitas_sriwijaya", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Institut Teknologi Del", valueDropdown: "institut_teknologi_del", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Sekolah Tinggi Teknologi Garut", valueDropdown: "sekolah_tinggi_teknologi_garut", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Mulawarman", valueDropdown: "universitas_mulawarman", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Unversitas Udayana", valueDropdown: "unversitas_udayana", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Negeri Malang", valueDropdown: "universitas_negeri_malang", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Dian Nuswantoro", valueDropdown: "universitas_dian_nuswantoro", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Politeknik Caltex Riau", valueDropdown: "politeknik_caltex_riau", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Katolik Parahyangan", valueDropdown: "universitas_katolik_parahyangan", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Institut Teknologi Sumatera", valueDropdown: "institut_teknologi_sumatera", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Lambung Mangkurat", valueDropdown: "universitas_lambung_mangkurat", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Tanjungpura", valueDropdown: "universitas_tanjungpura", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Sumatera Utara", valueDropdown: "universitas_sumatera_utara", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Pembangunan Jaya", valueDropdown: "universitas_pembangunan_jaya", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Kristen Satya Wacana", valueDropdown: "universitas_kristen_satya_wacana", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Maritim Raja Ali Haji", valueDropdown: "universitas_maritim_raja_ali_haji", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Paramadina", valueDropdown: "universitas_paramadina", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Katolik Widya Mandira", valueDropdown: "universitas_katolik_widya_mandira", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Batam", valueDropdown: "politeknik_negeri_batam", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Malang", valueDropdown: "politeknik_negeri_malang", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Katolik Soegijapranata", valueDropdown: "universitas_katolik_soegijapranata", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Muhammadiyah Surakarta", valueDropdown: "universitas_muhammadiyah_surakarta", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Jakarta", valueDropdown: "politeknik_negeri_jakarta", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Gadjah Mada", valueDropdown: "universitas_gadjah_mada", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Negeri Yogyakarta", valueDropdown: "universitas_negeri_yogyakarta", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Bandung", valueDropdown: "politeknik_negeri_bandung", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Hasanudin", valueDropdown: "universitas_hasanudin", isActive: true,), - BebrasBiro(bebrasBiroUniv: "UIN Alauddin Makassar", valueDropdown: "uin_alauddin_makassar", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Pasundan", valueDropdown: "universitas_pasundan", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Telkom", valueDropdown: "universitas_telkom", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Sanata Dharma", valueDropdown: "universitas_sanata_dharma", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Andalas", valueDropdown: "universitas_andalas", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Islam Nusantara", valueDropdown: "universitas_islam_nusantara", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Sains Al-Qur’an Wonosobo", valueDropdown: "universitas_sains_al_qur_an_wonosobo", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Bina Nusantara", valueDropdown: "universitas_bina_nusantara", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Komputer Indonesia", valueDropdown: "universitas_komputer_indonesia", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Singaperbangsa Karawang", valueDropdown: "universitas_singaperbangsa_karawang", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Pendidikan Indonesia Kampus Purwakarta", valueDropdown: "universitas_pendidikan_indonesia_kampus_purwakarta", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas President", valueDropdown: "universitas_president", isActive: true,), - BebrasBiro(bebrasBiroUniv: "STIKOM PGRI Banyuwangi", valueDropdown: "stikom_pgri_banyuwangi", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Bumigora", valueDropdown: "universitas_bumigora", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Pendidikan Indonesia", valueDropdown: "universitas_pendidikan_indonesia", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Padjadjaran", valueDropdown: "universitas_padjadjaran", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Katolik De La Salle Manado", valueDropdown: "universitas_katolik_de_la_salle_manado", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Ahmad Dahlan", valueDropdown: "universitas_ahmad_dahlan", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Negeri Makassar", valueDropdown: "universitas_negeri_makassar", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Pendidikan Muhammadiyah Sorong", valueDropdown: "universitas_pendidikan_muhammadiyah_sorong", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Al-Azhar Indonesia", valueDropdown: "universitas_al_azhar_indonesia", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Indramayu", valueDropdown: "politeknik_negeri_indramayu", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Nahdlatul Ulama Sunan Giri Bojonegoro", valueDropdown: "universitas_nahdlatul_ulama_sunan_giri_bojonegoro", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Institut Bisnis dan Informatika Kwik Kian Gie", valueDropdown: "institut_bisnis_dan_informatika_kwik_kian_gie", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Internasional Semen Indonesia", valueDropdown: "universitas_internasional_semen_indonesia", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Politeknik Negeri Madiun", valueDropdown: "politeknik_negeri_madiun", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Kristen Petra", valueDropdown: "universitas_kristen_petra", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Muhammadiyah Magelang", valueDropdown: "universitas_muhammadiyah_magelang", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Surabaya", valueDropdown: "universitas_surabaya", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Katolik Indonesia Atma Jaya", valueDropdown: "universitas_katolik_indonesia_atma_jaya", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Ciputra Surabaya", valueDropdown: "universitas_ciputra_surabaya", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Katolik Widya Mandala Surabaya", valueDropdown: "universitas_katolik_widya_mandala_surabaya", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Kristen Duta Wacana", valueDropdown: "universitas_kristen_duta_wacana", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Politeknik Manufaktur Negeri Bangka Belitung", valueDropdown: "politeknik_manufaktur_negeri_bangka_belitung", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Kristen Krida Wacana", valueDropdown: "universitas_kristen_krida_wacana", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Institut Agama Islam Negeri Salatiga", valueDropdown: "institut_agama_islam_negeri_salatiga", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Muhammadiyah Purworejo", valueDropdown: "universitas_muhammadiyah_purworejo", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Institut Teknologi dan Bisnis Kalbis", valueDropdown: "institut_teknologi_dan_bisnis_kalbis", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Mercu Buana Jakarta", valueDropdown: "universitas_mercu_buana_jakarta", isActive: true,), - BebrasBiro(bebrasBiroUniv: "UPN “Veteran” Jakarta", valueDropdown: "upn_veteran_jakarta", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Pertamina", valueDropdown: "universitas_pertamina", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Dr. Soetomo", valueDropdown: "universitas_dr_soetomo", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Bakrie", valueDropdown: "universitas_bakrie", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Bengkulu", valueDropdown: "universitas_bengkulu", isActive: true,), - BebrasBiro(bebrasBiroUniv: "UIN Walisongo Semarang", valueDropdown: "uin_walisongo_semarang", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Islam Sultan Agung Semarang", valueDropdown: "universitas_islam_sultan_agung_semarang", isActive: true,), - BebrasBiro(bebrasBiroUniv: "UIN Imam Bonjol Padang", valueDropdown: "uin_imam_bonjol_padang", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Institut Pesantren Mathali’ul Falah Pati", valueDropdown: "institut_pesantren_mathali_ul_falah_pati", isActive: true,), - BebrasBiro(bebrasBiroUniv: "UIN Sunan Gunung Djati Bandung", valueDropdown: "uin_sunan_gunung_djati_bandung", isActive: true,), - BebrasBiro(bebrasBiroUniv: "IAIN Pekalongan", valueDropdown: "iain_pekalongan", isActive: true,), - BebrasBiro(bebrasBiroUniv: "UIN Sultan Aji Muhammad Idris Samarinda", valueDropdown: "uin_sultan_aji_muhammad_idris_samarinda", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Politeknik Jambi", valueDropdown: "politeknik_jambi", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Universitas Trisakti", valueDropdown: "universitas_trisakti", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Biro Institut Teknologi dan Bisnis Yadika Pasuruan", valueDropdown: "biro_institut_teknologi_dan_bisnis_yadika_pasuruan", isActive: true,), - BebrasBiro(bebrasBiroUniv: "Biro Universitas Widyagama Malang", valueDropdown: "biro_universitas_widyagama_malang", isActive: true,), +List bebrasBiroList = [ + "Institut Teknologi Bandung", + "Institut Pertanian Bogor", + "Universitas Indonesia", + "Institut Teknologi Sepuluh November", + "Universitas Kristen Maranatha", + "Universitas Atmajaya Yogyakarta", + "Universitas Diponegoro", + "Universitas Islam Indonesia", + "Universitas Jendral Soedirman", + "Universitas Jember", + "Universitas Sriwijaya", + "Institut Teknologi Del", + "Sekolah Tinggi Teknologi Garut", + "Universitas Mulawarman", + "Unversitas Udayana", + "Universitas Negeri Malang", + "Universitas Dian Nuswantoro", + "Politeknik Caltex Riau", + "Universitas Katolik Parahyangan", + "Institut Teknologi Sumatera", + "Universitas Lambung Mangkurat", + "Universitas Tanjungpura", + "Universitas Sumatera Utara", + "Universitas Pembangunan Jaya", + "Universitas Kristen Satya Wacana", + "Universitas Maritim Raja Ali Haji", + "Universitas Paramadina", + "Universitas Katolik Widya Mandira", + "Politeknik Negeri Batam", + "Politeknik Negeri Malang", + "Universitas Katolik Soegijapranata", + "Universitas Muhammadiyah Surakarta", + "Politeknik Negeri Jakarta", + "Universitas Gadjah Mada", + "Universitas Negeri Yogyakarta", + "Politeknik Negeri Bandung", + "Universitas Hasanudin", + "UIN Alauddin Makassar", + "Universitas Pasundan", + "Universitas Telkom", + "Universitas Sanata Dharma", + "Universitas Andalas", + "Universitas Islam Nusantara", + "Universitas Sains Al-Qur’an Wonosobo", + "Universitas Bina Nusantara", + "Universitas Komputer Indonesia", + "Universitas Singaperbangsa Karawang", + "Universitas Pendidikan Indonesia Kampus Purwakarta", + "Universitas President", + "STIKOM PGRI Banyuwangi", + "Universitas Bumigora", + "Universitas Pendidikan Indonesia", + "Universitas Padjadjaran", + "Universitas Katolik De La Salle Manado", + "Universitas Ahmad Dahlan", + "Universitas Negeri Makassar", + "Universitas Pendidikan Muhammadiyah Sorong", + "Universitas Al-Azhar Indonesia", + "Politeknik Negeri Indramayu", + "Universitas Nahdlatul Ulama Sunan Giri Bojonegoro", + "Institut Bisnis dan Informatika Kwik Kian Gie", + "Universitas Internasional Semen Indonesia", + "Politeknik Negeri Madiun", + "Universitas Kristen Petra", + "Universitas Muhammadiyah Magelang", + "Universitas Surabaya", + "Universitas Katolik Indonesia Atma Jaya", + "Universitas Ciputra Surabaya", + "Universitas Katolik Widya Mandala Surabaya", + "Universitas Kristen Duta Wacana", + "Politeknik Manufaktur Negeri Bangka Belitung", + "Universitas Kristen Krida Wacana", + "Institut Agama Islam Negeri Salatiga", + "Universitas Muhammadiyah Purworejo", + "Institut Teknologi dan Bisnis Kalbis", + "Universitas Mercu Buana Jakarta", + "UPN “Veteran” Jakarta", + "Universitas Pertamina", + "Universitas Dr. Soetomo", + "Universitas Bakrie", + "Universitas Bengkulu", + "UIN Walisongo Semarang", + "Universitas Islam Sultan Agung Semarang", + "UIN Imam Bonjol Padang", + "Institut Pesantren Mathali’ul Falah Pati", + "UIN Sunan Gunung Djati Bandung", + "IAIN Pekalongan", + "UIN Sultan Aji Muhammad Idris Samarinda", + "Politeknik Jambi", + "Universitas Trisakti", + "Biro Institut Teknologi dan Bisnis Yadika Pasuruan", + "Biro Universitas Widyagama Malang", ]; diff --git a/app/lib/core/constants/indonesiaProvince.dart b/app/lib/core/constants/indonesiaProvince.dart index e1cf1d7..0106e04 100644 --- a/app/lib/core/constants/indonesiaProvince.dart +++ b/app/lib/core/constants/indonesiaProvince.dart @@ -14,44 +14,44 @@ class IndonesiaProvince { } } -List provinceList = [ - IndonesiaProvince(provinceName: "Bali", valueProvince: "bali", isActive: true,), - IndonesiaProvince(provinceName: "Banten", valueProvince: "banten", isActive: true,), - IndonesiaProvince(provinceName: "Nanggroe Aceh Darussalam", valueProvince: "nanggroe_aceh_darussalam", isActive: true,), - IndonesiaProvince(provinceName: "Sumatera Utara", valueProvince: "sumatera_utara", isActive: true,), - IndonesiaProvince(provinceName: "Sumatera Selatan", valueProvince: "sumatera_selatan", isActive: true,), - IndonesiaProvince(provinceName: "Sumatera Barat", valueProvince: "sumatera_barat", isActive: true,), - IndonesiaProvince(provinceName: "Bengkulu", valueProvince: "bengkulu", isActive: true,), - IndonesiaProvince(provinceName: "Riau", valueProvince: "riau", isActive: true,), - IndonesiaProvince(provinceName: "Kepulauan Riau", valueProvince: "kepulauan_riau", isActive: true,), - IndonesiaProvince(provinceName: "Jambi", valueProvince: "jambi", isActive: true,), - IndonesiaProvince(provinceName: "Lampung", valueProvince: "lampung", isActive: true,), - IndonesiaProvince(provinceName: "Bangka Belitung", valueProvince: "bangka_belitung", isActive: true,), - IndonesiaProvince(provinceName: "Kalimantan Barat", valueProvince: "kalimantan_barat", isActive: true,), - IndonesiaProvince(provinceName: "Kalimantan Timur", valueProvince: "kalimantan_timur", isActive: true,), - IndonesiaProvince(provinceName: "Kalimantan Selatan", valueProvince: "kalimantan_selatan", isActive: true,), - IndonesiaProvince(provinceName: "Kalimantan Tengah", valueProvince: "kalimantan_tengah", isActive: true,), - IndonesiaProvince(provinceName: "Kalimantan Utara", valueProvince: "kalimantan_utara", isActive: true,), - IndonesiaProvince(provinceName: "DKI Jakarta", valueProvince: "dki_jakarta", isActive: true,), - IndonesiaProvince(provinceName: "Jawa Barat", valueProvince: "jawa_barat", isActive: true,), - IndonesiaProvince(provinceName: "Jawa Tengah", valueProvince: "jawa_tengah", isActive: true,), - IndonesiaProvince(provinceName: "DI Yogyakarta", valueProvince: "daerah_istimewa_yogyakarta", isActive: true,), - IndonesiaProvince(provinceName: "Jawa Timur", valueProvince: "jawa_timur", isActive: true,), - IndonesiaProvince(provinceName: "Nusa Tenggara Timur", valueProvince: "nusa_tenggara_timur", isActive: true,), - IndonesiaProvince(provinceName: "Nusa Tenggara Barat", valueProvince: "nusa_tenggara_barat", isActive: true,), - IndonesiaProvince(provinceName: "Gorontalo", valueProvince: "gorontalo", isActive: true,), - IndonesiaProvince(provinceName: "Sulawesi Barat", valueProvince: "sulawesi_barat", isActive: true,), - IndonesiaProvince(provinceName: "Sulawesi Tengah", valueProvince: "sulawesi_tengah", isActive: true,), - IndonesiaProvince(provinceName: "Sulawesi Utara", valueProvince: "sulawesi_utara", isActive: true,), - IndonesiaProvince(provinceName: "Sulawesi Tenggara", valueProvince: "sulawesi_tenggara", isActive: true,), - IndonesiaProvince(provinceName: "Sulawesi Selatan", valueProvince: "sulawesi_selatan", isActive: true,), - IndonesiaProvince(provinceName: "Maluku Utara", valueProvince: "maluku_utara", isActive: true,), - IndonesiaProvince(provinceName: "Maluku", valueProvince: "maluku", isActive: true,), - IndonesiaProvince(provinceName: "Papua Barat", valueProvince: "papua_barat", isActive: true,), - IndonesiaProvince(provinceName: "Papua", valueProvince: "papua", isActive: true,), - IndonesiaProvince(provinceName: "Papua Tengah", valueProvince: "papua_tengah", isActive: true,), - IndonesiaProvince(provinceName: "Papua Pegunungan", valueProvince: "papua_pegunungan", isActive: true,), - IndonesiaProvince(provinceName: "Papua Selatan", valueProvince: "papua_selatan", isActive: true,), - IndonesiaProvince(provinceName: "Papua Barat Daya", valueProvince: "papua_barat_daya", isActive: true,), +List provinceList = [ + "Bali", + "Banten", + "Nanggroe Aceh Darussalam", + "Sumatera Utara", + "Sumatera Selatan", + "Sumatera Barat", + "Bengkulu", + "Riau", + "Kepulauan Riau", + "Jambi", + "Lampung", + "Bangka Belitung", + "Kalimantan Barat", + "Kalimantan Timur", + "Kalimantan Selatan", + "Kalimantan Tengah", + "Kalimantan Utara", + "DKI Jakarta", + "Jawa Barat", + "Jawa Tengah", + "DI Yogyakarta", + "Jawa Timur", + "Nusa Tenggara Timur", + "Nusa Tenggara Barat", + "Gorontalo", + "Sulawesi Barat", + "Sulawesi Tengah", + "Sulawesi Utara", + "Sulawesi Tenggara", + "Sulawesi Selatan", + "Maluku Utara", + "Maluku", + "Papua Barat", + "Papua", + "Papua Tengah", + "Papua Pegunungan", + "Papua Selatan", + "Papua Barat Daya", ]; diff --git a/app/lib/features/authentication/register/presentation/widgets/biro_bebras_dropdown.dart b/app/lib/features/authentication/register/presentation/widgets/biro_bebras_dropdown.dart index bd56707..7d2740b 100644 --- a/app/lib/features/authentication/register/presentation/widgets/biro_bebras_dropdown.dart +++ b/app/lib/features/authentication/register/presentation/widgets/biro_bebras_dropdown.dart @@ -7,30 +7,18 @@ class BiroBebrasDropdown extends StatelessWidget { final String labelText; final void Function (String value)? handleTextInput; - final String? Function(BebrasBiro?)? validator; - - List get dropdownItems { - var list = bebrasBiroList.where((el) => el.isActive).toList(); - var menuItems = list - .map((element) => BebrasBiro( - bebrasBiroUniv: element.bebrasBiroUniv, - valueDropdown: element.valueDropdown, - isActive: element.isActive,), - ).toList(); - return menuItems; - } + final String? Function(String?)? validator; @override Widget build(BuildContext context) { return Container( height: 63.0, - child: DropdownSearch( + child: DropdownSearch( validator: validator, - itemAsString: (BebrasBiro bebras) => bebras.userAsString(), popupProps: PopupProps.menu( showSearchBox: true, ), - items: dropdownItems, + items: bebrasBiroList, dropdownDecoratorProps: DropDownDecoratorProps( textAlignVertical: TextAlignVertical.center, baseStyle: TextStyle(fontSize: 12.0), @@ -53,8 +41,7 @@ class BiroBebrasDropdown extends StatelessWidget { ), ), ), - onChanged: (BebrasBiro? test) => handleTextInput!(test!.valueDropdown), - // print(test?.valueDropdown); + onChanged: (String? item) => handleTextInput!(item!), selectedItem: null, ), ); diff --git a/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart b/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart index 1b648d7..20d4e21 100644 --- a/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart +++ b/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart @@ -55,7 +55,7 @@ class _CustomDatePickerState extends State { if (pickedDate != null) { String formattedDate = DateFormat('dd MMM yyyy').format(pickedDate); - widget.handleTextInput!(pickedDate.toIso8601String()); + widget.handleTextInput!(formattedDate); setState(() { dateinput.text = formattedDate; }); diff --git a/app/lib/features/authentication/register/presentation/widgets/province_dropdown.dart b/app/lib/features/authentication/register/presentation/widgets/province_dropdown.dart index da543fb..bb7d407 100644 --- a/app/lib/features/authentication/register/presentation/widgets/province_dropdown.dart +++ b/app/lib/features/authentication/register/presentation/widgets/province_dropdown.dart @@ -7,32 +7,19 @@ class ProvinceDropdown extends StatelessWidget { final String labelText; final void Function (String value)? handleTextInput; - final String? Function(IndonesiaProvince?)? validator; - - List get dropdownIndonesiaProvince { - var list = provinceList.where((el) => el.isActive).toList(); - var menuItems = list - .map((element) => IndonesiaProvince( - provinceName: element.provinceName, - valueProvince: element.valueProvince, - isActive: element.isActive,), - ).toList(); - return menuItems; - } + final String? Function(String?)? validator; @override Widget build(BuildContext context) { return Container( // margin: const EdgeInsets.only(top: 10), height: 63.0, - child: DropdownSearch( + child: DropdownSearch( validator: validator, - itemAsString: (IndonesiaProvince indonesiaProvince) => - indonesiaProvince.userAsString(), popupProps: PopupProps.menu( showSearchBox: true, ), - items: dropdownIndonesiaProvince, + items: provinceList, dropdownDecoratorProps: DropDownDecoratorProps( textAlignVertical: TextAlignVertical.center, baseStyle: TextStyle(fontSize: 12.0), @@ -55,8 +42,7 @@ class ProvinceDropdown extends StatelessWidget { ), ), ), - // onChanged: (IndonesiaProvince? test) => print(test?.valueProvince), - onChanged: (IndonesiaProvince? test) => handleTextInput!(test!.valueProvince), + onChanged: (String? item) => handleTextInput!(item!), selectedItem: null, ), ); From abc0d3602f80bd6275bb73c09005d34cfd2088d3 Mon Sep 17 00:00:00 2001 From: 12henbx Date: Thu, 19 Oct 2023 14:41:25 +0700 Subject: [PATCH 12/12] adjust date time format --- .../register/presentation/widgets/custom_date_picker.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart b/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart index 20d4e21..7238aa1 100644 --- a/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart +++ b/app/lib/features/authentication/register/presentation/widgets/custom_date_picker.dart @@ -54,7 +54,7 @@ class _CustomDatePickerState extends State { if (pickedDate != null) { String formattedDate = - DateFormat('dd MMM yyyy').format(pickedDate); + DateFormat('yyyy-MM-dd').format(pickedDate); widget.handleTextInput!(formattedDate); setState(() { dateinput.text = formattedDate;