From e5961ffba7cd201c5d34998454715392fccc01e1 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sat, 24 Aug 2024 16:10:28 -0300 Subject: [PATCH 01/30] Building presenter layer --- lib/cubit/cubit.dart | 1 + lib/cubit/restaurant_cubit.dart | 28 ++++++++++++++++++++++++++++ lib/cubit/restaurant_state.dart | 30 ++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 lib/cubit/cubit.dart create mode 100644 lib/cubit/restaurant_cubit.dart create mode 100644 lib/cubit/restaurant_state.dart diff --git a/lib/cubit/cubit.dart b/lib/cubit/cubit.dart new file mode 100644 index 0000000..868fb90 --- /dev/null +++ b/lib/cubit/cubit.dart @@ -0,0 +1 @@ +export 'restaurant_cubit.dart'; diff --git a/lib/cubit/restaurant_cubit.dart b/lib/cubit/restaurant_cubit.dart new file mode 100644 index 0000000..e01a8bb --- /dev/null +++ b/lib/cubit/restaurant_cubit.dart @@ -0,0 +1,28 @@ +import 'package:bloc/bloc.dart'; +import 'package:equatable/equatable.dart'; +import 'package:meta/meta.dart'; +import 'package:restaurant_tour/models/restaurant.dart'; + +import '../usecases/fetch_restaurants.dart'; + +part 'restaurant_state.dart'; + +class RestaurantCubit extends Cubit { + RestaurantCubit(this.fetchRestaurantsUseCase) : super(RestaurantInitial()); + final FetchRestaurants fetchRestaurantsUseCase; + Future fetchRestaurants() async { + emit(LoadingRestaurantsState()); + RestaurantQueryResult? result = + await fetchRestaurantsUseCase.getRestaurantsFromCache(); + if (result != null) { + emit(RestaurantsLoadedState(result: result)); + } else { + emit( + ErrorState( + message: + 'The server encountered a problem and we couldn\'t load the list.', + ), + ); + } + } +} diff --git a/lib/cubit/restaurant_state.dart b/lib/cubit/restaurant_state.dart new file mode 100644 index 0000000..dc4a5bd --- /dev/null +++ b/lib/cubit/restaurant_state.dart @@ -0,0 +1,30 @@ +part of 'restaurant_cubit.dart'; + +@immutable +abstract class RestaurantState extends Equatable {} + +class RestaurantInitial extends RestaurantState { + @override + List get props => []; +} + +class LoadingRestaurantsState extends RestaurantState { + @override + List get props => []; +} + +class RestaurantsLoadedState extends RestaurantState { + final RestaurantQueryResult result; + + RestaurantsLoadedState({required this.result}); + @override + List get props => [result]; +} + +class ErrorState extends RestaurantState { + final String message; + + ErrorState({required this.message}); + @override + List get props => []; +} From 869991e6132feb3d020e6bf3dca6ed96e96c1787 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sat, 24 Aug 2024 16:10:59 -0300 Subject: [PATCH 02/30] Buid presentation layer with the restaurants list view --- lib/main.dart | 70 ++++++------ lib/models/models.dart | 1 + lib/pages/home_page.dart | 75 +++++++++++++ lib/pages/pages.dart | 2 + lib/pages/restaurant_list_page_view.dart | 133 +++++++++++++++++++++++ 5 files changed, 245 insertions(+), 36 deletions(-) create mode 100644 lib/models/models.dart create mode 100644 lib/pages/home_page.dart create mode 100644 lib/pages/pages.dart create mode 100644 lib/pages/restaurant_list_page_view.dart diff --git a/lib/main.dart b/lib/main.dart index 3a4af7d..2b78899 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,51 +1,49 @@ +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; -import 'package:restaurant_tour/repositories/yelp_repository.dart'; +import 'package:get_it/get_it.dart'; +import 'package:restaurant_tour/cubit/cubit.dart'; +import 'package:restaurant_tour/repositories/repositories.dart'; +import 'pages/home_page.dart'; +import 'usecases/fetch_restaurants.dart'; void main() { + setup(); runApp(const RestaurantTour()); } -class RestaurantTour extends StatelessWidget { - const RestaurantTour({Key? key}) : super(key: key); +void setup() { + final getIt = GetIt.instance; - @override - Widget build(BuildContext context) { - return const MaterialApp( - title: 'Restaurant Tour', - home: HomePage(), - ); - } + getIt.registerSingleton(YelpRepository()); + + getIt.registerSingleton( + FetchRestaurants(repository: getIt()), + ); + getIt.registerFactory( + () => RestaurantCubit(getIt()), + ); } -class HomePage extends StatelessWidget { - const HomePage({Key? key}) : super(key: key); +class RestaurantTour extends StatelessWidget { + const RestaurantTour({super.key}); @override Widget build(BuildContext context) { - return Scaffold( - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text('Restaurant Tour'), - ElevatedButton( - child: const Text('Fetch Restaurants'), - onPressed: () async { - final yelpRepo = YelpRepository(); - - try { - final result = await yelpRepo.getRestaurants(); - if (result != null) { - print('Fetched ${result.restaurants!.length} restaurants'); - } else { - print('No restaurants fetched'); - } - } catch (e) { - print('Failed to fetch restaurants: $e'); - } - }, - ), - ], + return MaterialApp( + title: 'Restaurant Tour', + home: const HomePageBlocProvider(), + theme: ThemeData( + fontFamily: 'Lora', + textTheme: const TextTheme( + displayLarge: TextStyle(fontSize: 14, fontFamily: 'Open Sans'), + displayMedium: TextStyle(fontSize: 14, fontFamily: 'Open Sans'), + displaySmall: TextStyle( + fontSize: 12, + fontFamily: 'Open Sans', + fontStyle: FontStyle.italic), + bodyMedium: TextStyle(fontSize: 16, height: 1.5), + bodySmall: TextStyle(fontSize: 12, fontFamily: 'Open Sans'), + headlineLarge: TextStyle(fontSize: 24, fontWeight: FontWeight.w700), ), ), ); diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..d5a0fcf --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1 @@ +export 'restaurant.dart'; diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart new file mode 100644 index 0000000..0d6c7da --- /dev/null +++ b/lib/pages/home_page.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:get_it/get_it.dart'; +import 'package:restaurant_tour/cubit/cubit.dart'; +import 'package:restaurant_tour/pages/restaurant_list_page_view.dart'; + +class HomePageBlocProvider extends StatelessWidget { + const HomePageBlocProvider({super.key}); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => + GetIt.instance()..fetchRestaurants(), + child: const HomePage(), + ); + } +} + +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 2, + child: Scaffold( + appBar: AppBar( + title: Text( + "RestauranTour", + style: Theme.of(context).textTheme.headlineLarge, + ), + actions: [ + Padding( + padding: const EdgeInsets.only(right: 16), + child: TextButton( + onPressed: () {}, + child: const CircleAvatar( + backgroundImage: NetworkImage( + 'https://mdbcdn.b-cdn.net/img/new/avatars/2.webp', + ), + ), + ), + ), + ], + bottom: TabBar( + tabs: [ + Tab( + child: Text( + 'All restaurants', + style: Theme.of(context).textTheme.displayLarge, + ), + ), + Tab( + child: Text( + 'My favorites', + style: Theme.of(context).textTheme.displayLarge, + ), + ), + ], + ), + ), + body: const SafeArea( + minimum: EdgeInsets.all(16), + child: TabBarView( + children: [ + RestaurantListPageView(), + Text('Dias'), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/pages.dart b/lib/pages/pages.dart new file mode 100644 index 0000000..10b9593 --- /dev/null +++ b/lib/pages/pages.dart @@ -0,0 +1,2 @@ +export 'home_page.dart'; +export './restaurant_list_page_view.dart'; diff --git a/lib/pages/restaurant_list_page_view.dart b/lib/pages/restaurant_list_page_view.dart new file mode 100644 index 0000000..8494a94 --- /dev/null +++ b/lib/pages/restaurant_list_page_view.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:restaurant_tour/cubit/cubit.dart'; +import 'package:restaurant_tour/models/models.dart'; +import 'package:restaurant_tour/widgets/open_status.dart'; +import 'package:restaurant_tour/widgets/rating_widget.dart'; + +import '../widgets/restaurant_details.dart'; + +class RestaurantListPageView extends StatelessWidget { + const RestaurantListPageView({super.key}); + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + return BlocBuilder( + builder: (context, state) { + if (state is LoadingRestaurantsState) { + return const Center(child: CircularProgressIndicator()); + } else if (state is ErrorState) { + return Center( + child: Text(state.message), + ); + } + if (state is RestaurantsLoadedState) { + return ListView.builder( + itemCount: state.result.restaurants?.length, + itemBuilder: (BuildContext context, int index) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + // crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile( + restaurant: state.result.restaurants!.elementAt(index), + constraints: constraints, + ), + ], + ); + }, + ); + } + return Container(); + }, + ); + }, + ); + } +} + +class ListTile extends StatelessWidget { + const ListTile({ + super.key, + required this.restaurant, + required this.constraints, + }); + final Restaurant restaurant; + final BoxConstraints constraints; + @override + Widget build(BuildContext context) { + return Container( + width: constraints.maxWidth, + margin: const EdgeInsets.only(bottom: 8, top: 8), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(9), + boxShadow: [ + BoxShadow( + color: Colors.grey.shade200, + blurRadius: 3, + offset: const Offset(0, 2), + ), + ], + ), + child: Row( + children: [ + Column( + children: [ + Hero( + tag: restaurant.id.toString(), + child: ClipRRect( + borderRadius: BorderRadius.circular(9), + child: Image.network( + restaurant.heroImage, + fit: BoxFit.cover, + width: 90, + height: 90, + ), + ), + ), + ], + ), + const Spacer( + flex: 1, + ), + Flexible( + flex: 10, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + restaurant.name ?? '', + maxLines: 2, + ), + const SizedBox( + height: 10, + ), + RestaurantDetails(restaurant: restaurant), + const SizedBox( + height: 10, + ), + Row( + children: [ + StarRating( + rating: restaurant.rating?.round() ?? 0, + ), + Spacer(), + OpenStatus( + isOpen: restaurant.isOpen, + ) + ], + ) + ], + ), + ), + ], + ), + ); + } +} From b9fb6491ca1e744260a264ab87dc3d325b639d9f Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sat, 24 Aug 2024 16:11:10 -0300 Subject: [PATCH 03/30] Build usecases --- lib/usecases/fetch_restaurants.dart | 12 ++++++++++++ lib/usecases/usecases.dart | 1 + 2 files changed, 13 insertions(+) create mode 100644 lib/usecases/fetch_restaurants.dart create mode 100644 lib/usecases/usecases.dart diff --git a/lib/usecases/fetch_restaurants.dart b/lib/usecases/fetch_restaurants.dart new file mode 100644 index 0000000..251be6a --- /dev/null +++ b/lib/usecases/fetch_restaurants.dart @@ -0,0 +1,12 @@ +import 'package:restaurant_tour/models/models.dart'; +import 'package:restaurant_tour/repositories/yelp_repository.dart'; + +class FetchRestaurants { + final YelpRepository repository; + + FetchRestaurants({required this.repository}); + Future getRestaurants() async => + await repository.getRestaurants(); + Future getRestaurantsFromCache() async => + await repository.getRestaurantsFromCache(); +} diff --git a/lib/usecases/usecases.dart b/lib/usecases/usecases.dart new file mode 100644 index 0000000..31d21ed --- /dev/null +++ b/lib/usecases/usecases.dart @@ -0,0 +1 @@ +export './fetch_restaurants.dart'; From 0d374a2bc77e0701d1cdfd81cea110654486d575 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sat, 24 Aug 2024 16:11:17 -0300 Subject: [PATCH 04/30] Build widgets --- lib/widgets/open_status.dart | 25 +++++++++++++++++++++ lib/widgets/rating_widget.dart | 28 ++++++++++++++++++++++++ lib/widgets/restaurant_details.dart | 34 +++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 lib/widgets/open_status.dart create mode 100644 lib/widgets/rating_widget.dart create mode 100644 lib/widgets/restaurant_details.dart diff --git a/lib/widgets/open_status.dart b/lib/widgets/open_status.dart new file mode 100644 index 0000000..89d433e --- /dev/null +++ b/lib/widgets/open_status.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +class OpenStatus extends StatelessWidget { + const OpenStatus({super.key, required this.isOpen}); + final bool isOpen; + @override + Widget build(BuildContext context) { + return Row( + children: [ + Text( + isOpen ? 'Open Now' : 'Closed Now', + style: Theme.of(context).textTheme.displaySmall, + ), + SizedBox( + width: 8, + ), + Icon( + Icons.circle, + size: 8.0, + color: isOpen ? Colors.green : Colors.red, + ) + ], + ); + } +} diff --git a/lib/widgets/rating_widget.dart b/lib/widgets/rating_widget.dart new file mode 100644 index 0000000..b7158b9 --- /dev/null +++ b/lib/widgets/rating_widget.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +class StarRating extends StatelessWidget { + final int rating; + final double starSize; + final Color starColor; + + const StarRating({ + super.key, + required this.rating, // Rating should be between 0 to 5 + this.starSize = 12.0, + this.starColor = Colors.amber, + }) : assert(rating >= 0 && rating <= 5); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: List.generate(rating, (index) { + return Icon( + Icons.star, + size: starSize, + color: starColor, + ); + }), + ); + } +} diff --git a/lib/widgets/restaurant_details.dart b/lib/widgets/restaurant_details.dart new file mode 100644 index 0000000..166c8bc --- /dev/null +++ b/lib/widgets/restaurant_details.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:restaurant_tour/models/restaurant.dart'; + +class RestaurantDetails extends StatelessWidget { + const RestaurantDetails({ + super.key, + required this.restaurant, + }); + + final Restaurant restaurant; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Text( + restaurant.price ?? '-', + style: Theme.of(context).textTheme.bodySmall, + ), + const SizedBox( + width: 6, + ), + Flexible( + child: Text( + restaurant.categories?.map((element) => element.title).first ?? '', + style: Theme.of(context).textTheme.bodySmall, + maxLines: 1, + softWrap: true, + ), + ), + ], + ); + } +} From c2c8af40046ca8f2eb48f70317123a62f3194ee8 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sat, 24 Aug 2024 16:11:26 -0300 Subject: [PATCH 05/30] build repositories --- lib/repositories/repositories.dart | 1 + lib/repositories/sample_json.dart | 1149 +++++++++++++++++++++++++ lib/repositories/yelp_repository.dart | 34 +- 3 files changed, 1183 insertions(+), 1 deletion(-) create mode 100644 lib/repositories/repositories.dart create mode 100644 lib/repositories/sample_json.dart diff --git a/lib/repositories/repositories.dart b/lib/repositories/repositories.dart new file mode 100644 index 0000000..644e268 --- /dev/null +++ b/lib/repositories/repositories.dart @@ -0,0 +1 @@ +export 'yelp_repository.dart'; diff --git a/lib/repositories/sample_json.dart b/lib/repositories/sample_json.dart new file mode 100644 index 0000000..96ebf52 --- /dev/null +++ b/lib/repositories/sample_json.dart @@ -0,0 +1,1149 @@ +const Map sample = { + "data": { + "search": { + "total": 7517, + "business": [ + { + "id": "vHz2RLtfUMVRPFmd7VBEHA", + "name": "Gordon Ramsay Hell's Kitchen", + "price": "\$\$\$", + "rating": 4.4, + "photos": [ + "https://s3-media2.fl.yelpcdn.com/bphoto/q771KjLzI5y638leJsnJnQ/o.jpg" + ], + "reviews": [ + { + "id": "VJCoQlkk4Fjac0OPoRP8HQ", + "rating": 5, + "text": + "Me and my husband came to celebrate my birthday here and it was a 10/10 experience. Firstly, I booked the wrong area which was the Gordon Ramsay pub and...", + "user": { + "id": "0bQNLf0POLTW4VhQZqOZoQ", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/i_0K5RUOQnoIw1c4QzHmTg/o.jpg", + "name": "Glydel L." + } + }, + { + "id": "EeCKH7eUVDsZv0Ii9wcPiQ", + "rating": 5, + "text": + "phenomenal! Bridgette made our experience as superb as the food coming to the table! would definitely come here again and try everything else on the menu,...", + "user": { + "id": "gL7AGuKBW4ne93_mR168pQ", + "image_url": + "https://s3-media1.fl.yelpcdn.com/photo/iU1sA7y3dEEc4iRL9LnWQQ/o.jpg", + "name": "Sydney O." + } + }, + { + "id": "F88H5ow44AmiwisbrbswPw", + "rating": 5, + "text": + "This entire experience is always so amazing. Every single dish is cooked to perfection. Every beef dish was so tender. The desserts were absolutely...", + "user": { + "id": "y742Fi1jF_JAqq5sRUlLEw", + "image_url": + "https://s3-media2.fl.yelpcdn.com/photo/rEWek1sYL0F35KZ0zRt3sw/o.jpg", + "name": "Ashley L." + } + } + ], + "categories": [ + {"title": "New American", "alias": "newamerican"}, + {"title": "Seafood", "alias": "seafood"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": "3570 Las Vegas Blvd S\nLas Vegas, NV 89109" + } + }, + { + "id": "faPVqws-x-5k2CQKDNtHxw", + "name": "Yardbird", + "price": "\$\$", + "rating": 4.5, + "photos": [ + "https://s3-media1.fl.yelpcdn.com/bphoto/xYJaanpF3Dl1OovhmpqAYw/o.jpg" + ], + "reviews": [ + { + "id": "CN9oD1ncHKZtsGN7U1EMnA", + "rating": 5, + "text": + "The food was delicious and the host and waitress were very nice, my husband and I really loved all the food, their cocktails are also amazing.", + "user": { + "id": "HArOfrshTW9s1HhN8oz8rg", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/4sDrkYRIZxsXKCYdo9d1bQ/o.jpg", + "name": "Snow7 C." + } + }, + { + "id": "cqMrOWT9kRQOt3VUqOUbHg", + "rating": 5, + "text": + "Our last meal in Vegas was amazing at Yardbird. We have been to the Yardbird in Chicago so we thought we knew what to expect; however, we were blown away by...", + "user": { + "id": "10oig4nwHnOAnAApdYvNrg", + "image_url": null, + "name": "Ellie K." + } + }, + { + "id": "XpTuzInVGZ2Dmx5BX21aqA", + "rating": 4, + "text": + "The food was great and the atmosphere was fun! Not over the top or too fancy. Perfect for lunch or dinner.", + "user": { + "id": "kp40ga5HSczQfP5TDlzjPQ", + "image_url": null, + "name": "Tacie A." + } + } + ], + "categories": [ + {"title": "Southern", "alias": "southern"}, + {"title": "New American", "alias": "newamerican"}, + {"title": "Cocktail Bars", "alias": "cocktailbars"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": "3355 Las Vegas Blvd S\nLas Vegas, NV 89109" + } + }, + { + "id": "syhA1ugJpyNLaB0MiP19VA", + "name": "888 Japanese BBQ", + "price": "\$\$\$", + "rating": 4.8, + "photos": [ + "https://s3-media1.fl.yelpcdn.com/bphoto/V_zmwCUG1o_vR29xfkb-ng/o.jpg" + ], + "reviews": [ + { + "id": "mb9gfnkSopq00f4LBZVPig", + "rating": 5, + "text": + "Food service and Ambiance are so high quality.povw and always come back every other week .", + "user": { + "id": "AKEHRiPmlrwKHxiiJlLGEQ", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/GdoKcKDBW0fWQ4To-X_clA/o.jpg", + "name": "Mellon D." + } + }, + { + "id": "e06Cw1RLUsjZw5tgNm-J8Q", + "rating": 5, + "text": + "Best bbq off the strip service was amazing and staff were friendly! Will definitely come back for more good eats!", + "user": { + "id": "tTocbjs4Whp_cUpvBceWWQ", + "image_url": null, + "name": "Banny C." + } + }, + { + "id": "DJRN1M6nsBL19HiX2Tkyug", + "rating": 5, + "text": + "Amazing experience. Would recommend to anyone visiting Lad Vegas. Wow! The service was super and very friendly. Definitely worth a try!", + "user": { + "id": "pMxm5enXAlT77jbyElGMjQ", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/Z43vPbN4hxV33IpMQClX0A/o.jpg", + "name": "Angela W." + } + } + ], + "categories": [ + {"title": "Barbeque", "alias": "bbq"}, + {"title": "Japanese", "alias": "japanese"} + ], + "hours": [ + {"is_open_now": false} + ], + "location": { + "formatted_address": "3550 S Decatur Blvd\nLas Vegas, NV 89103" + } + }, + { + "id": "QXV3L_QFGj8r6nWX2kS2hA", + "name": "Nacho Daddy", + "price": "\$\$", + "rating": 4.4, + "photos": [ + "https://s3-media4.fl.yelpcdn.com/bphoto/pu9doqMplB5x5SEs8ikW6w/o.jpg" + ], + "reviews": [ + { + "id": "JU_T9FlCGKVBulGEI-4OHg", + "rating": 5, + "text": + "Alyssa was amazing! The food and atmosphere were great! Definitely will be coming back!", + "user": { + "id": "CgVBZnioGBPgNLxq3z1E8Q", + "image_url": null, + "name": "Jazmin G." + } + }, + { + "id": "CifTHQgZ8L5IJc-dB_bizQ", + "rating": 5, + "text": + "Damn good! Xina was wonderful. 5 stars. Got some great nachos and drinks. Excellent vegan menu.", + "user": { + "id": "zT0QrkMBUGj4DqSye8LnCQ", + "image_url": null, + "name": "Mark T." + } + }, + { + "id": "-MAq_q1q6Vgk1_RQjNCdjA", + "rating": 5, + "text": + "This is my first time at nacho daddy's and My server Shannon was amazing. She came to our table fast and i love how on top of it she was to get our drinks...", + "user": { + "id": "MWZcvuYNlFq_UPJX-NyWLw", + "image_url": null, + "name": "Desiree L." + } + } + ], + "categories": [ + {"title": "New American", "alias": "newamerican"}, + {"title": "Mexican", "alias": "mexican"}, + {"title": "Breakfast & Brunch", "alias": "breakfast_brunch"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": + "3663 Las Vegas Blvd\nSte 595\nLas Vegas, NV 89109" + } + }, + { + "id": "rdE9gg0WB7Z8kRytIMSapg", + "name": "Lazy Dog Restaurant & Bar", + "price": "\$\$", + "rating": 4.5, + "photos": [ + "https://s3-media2.fl.yelpcdn.com/bphoto/_Wz-fNXawmbBinSf9Ev15g/o.jpg" + ], + "reviews": [ + { + "id": "SlDFYj2sdxeeAIibIPJLFg", + "rating": 5, + "text": + "Great food! Service was excellent. Had the Alfredo chicken and it hit the spot. The manager stopped by and made literally conversation. Her name was...", + "user": { + "id": "XcNwCjkxQ-A-ErsAxm2D9g", + "image_url": null, + "name": "Natalie C." + } + }, + { + "id": "WCQ3d28zbUGg4n2D2auUbw", + "rating": 5, + "text": + "What a great experience from our waiter Anthony F.! He saw our daughter was icing her knee after a grueling tournament and was the first to ask if we needed...", + "user": { + "id": "0MKASbKsZ4imiq_ugtt8NQ", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/rCz78mQ16LBbmADoOE9A3Q/o.jpg", + "name": "Barbara S." + } + }, + { + "id": "Gfj013WbLQo3sADlG1mXUQ", + "rating": 5, + "text": + "By far the BEST restaurant that we have been to while visiting Vegas. Food, atmosphere and customer service was phenomenal! Tina was our server, absolutely...", + "user": { + "id": "1TUNMdokzFDEa1SmZ-F3Dw", + "image_url": null, + "name": "Tasha R." + } + } + ], + "categories": [ + {"title": "New American", "alias": "newamerican"}, + {"title": "Comfort Food", "alias": "comfortfood"}, + {"title": "Burgers", "alias": "burgers"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": "6509 S Las Vegas Blvd\nLas Vegas, NV 89119" + } + }, + { + "id": "3kdSl5mo9dWC4clrQjEDGg", + "name": "Egg & I", + "price": "\$\$", + "rating": 4.5, + "photos": [ + "https://s3-media1.fl.yelpcdn.com/bphoto/z4rdxoc6xaM4dmdPovPBDg/o.jpg" + ], + "reviews": [ + { + "id": "P6yj97cmXiHzXJV3B0L7xA", + "rating": 5, + "text": + "The food was delicious and just how i ordered it. I had the chicken sandwich with fries. Our waitress was Crystal, even though it was only her fourth day...", + "user": { + "id": "SxuhAYL2h6441S51H9tlmQ", + "image_url": null, + "name": "Bhlasian G." + } + }, + { + "id": "YLY6BcCx-APSr67Xfd6aJg", + "rating": 5, + "text": + "I came here after reading the reviews. When l checked in l received the banana muffin on the house, it was delicious. I ordered the original burrito and my...", + "user": { + "id": "3RCz-zMjeNEqsrQE43-vIA", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/lG-jJexCutZZi2hazBgH3Q/o.jpg", + "name": "Vicky K." + } + }, + { + "id": "7pOCQU3F1US1T-FpcmTXtA", + "rating": 4, + "text": + "Born and raised in Vegas and for some reason I've never been here. Finally decided to get some \"to go\" sandwiches for breakfast. \n\nOver \$40 for an egg...", + "user": { + "id": "keBv05MsMFBd0Hu98vXThQ", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/IKQxIIRJWxecyHIkv1xw4g/o.jpg", + "name": "Jesse L." + } + } + ], + "categories": [ + {"title": "Breakfast & Brunch", "alias": "breakfast_brunch"}, + {"title": "Burgers", "alias": "burgers"}, + {"title": "American", "alias": "tradamerican"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": "4533 W Sahara Ave\nSte 5\nLas Vegas, NV 89102" + } + }, + { + "id": "gOOfBSBZlffCkQ7dr7cpdw", + "name": "CHICA", + "price": "\$\$", + "rating": 4.3, + "photos": [ + "https://s3-media2.fl.yelpcdn.com/bphoto/FxmtjuzPDiL7vx5KyceWuQ/o.jpg" + ], + "reviews": [ + { + "id": "xXQzEfd0czYwW_PW_QW1RQ", + "rating": 5, + "text": + "Came here with a group of 8 for brunch and we all had a wonderful experience. Our waitress, Karena, was amazing! She was super attentive and such a good...", + "user": { + "id": "A8wuelxCSNiuS6IFY6WKbw", + "image_url": null, + "name": "Joanna M." + } + }, + { + "id": "k0mR3x34X9bXMZfyTsO8nQ", + "rating": 5, + "text": + "The food was amazing. I had the Latin breakfast. Our table shared the donuts...delicious. We had drinks and they were made with fresh ingredients. They...", + "user": { + "id": "47SO7vTL6Louu9Gbkq8UeA", + "image_url": null, + "name": "Brandi T." + } + }, + { + "id": "pLdKzOPNlHmonm08eRP6Fw", + "rating": 5, + "text": + "Every dish was amazing. The parrillada is a must have to share. The sides are also great. I love the corn too. And the famous flaming skull dessert is both...", + "user": { + "id": "IE8XGvC-2fzE0lTltk-46Q", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/vOMr4EWJNoDbKR-lrDSfbg/o.jpg", + "name": "Fabian L." + } + } + ], + "categories": [ + {"title": "Latin American", "alias": "latin"}, + {"title": "Breakfast & Brunch", "alias": "breakfast_brunch"}, + {"title": "Cocktail Bars", "alias": "cocktailbars"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": + "3355 South Las Vegas Blvd\nSte 106\nLas Vegas, NV 89109" + } + }, + { + "id": "JPfi__QJAaRzmfh5aOyFEw", + "name": "Shang Artisan Noodle - Flamingo Road", + "price": "\$\$", + "rating": 4.6, + "photos": [ + "https://s3-media3.fl.yelpcdn.com/bphoto/TqV2TDWH-7Wje5B9Oh1EZw/o.jpg" + ], + "reviews": [ + { + "id": "GcGUAH0FPeyfw7rw7eu2Sg", + "rating": 5, + "text": + "Best beef noodle soup I've ever had. Portion sizes huge. Family of 5 could have shared 3 bowls with some appetizers. Spicy wonton and beef dumplings were...", + "user": { + "id": "4H2AFePQc7B4LGWhGkAb2g", + "image_url": null, + "name": "AA K." + } + }, + { + "id": "JZPALhqqab576i9xk80tgQ", + "rating": 5, + "text": + "Great restaurant with authentic flavors and everything is made from scratch! . Great service and very popular with the Asian community", + "user": { + "id": "MmOJaZ2cPwguz6bPTYdfWQ", + "image_url": null, + "name": "Squadron F." + } + }, + { + "id": "oJGyfL7kGuV43Z5kIceYZg", + "rating": 5, + "text": + "Every time I plan a Vegas trip, this is one of my spots I NEVER MISS. \n\nEach bowl from Shang has so much flavor, and the noodles are so chewy. They have a...", + "user": { + "id": "DJiwsCAKTvybSyOUvm_Avw", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/STrtsOu9xOs5ypKYPFMChQ/o.jpg", + "name": "Annie T." + } + } + ], + "categories": [ + {"title": "Noodles", "alias": "noodles"}, + {"title": "Chinese", "alias": "chinese"}, + {"title": "Soup", "alias": "soup"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": + "4983 W Flamingo Rd\nSte B\nLas Vegas, NV 89103" + } + }, + { + "id": "2iTsRqUsPGRH1li1WVRvKQ", + "name": "Carson Kitchen", + "price": "\$\$", + "rating": 4.5, + "photos": [ + "https://s3-media2.fl.yelpcdn.com/bphoto/LhaPvLHIrsHu8ZMLgV04OQ/o.jpg" + ], + "reviews": [ + { + "id": "PzKQYLK6skSfAUP73P8YXQ", + "rating": 5, + "text": + "Our son gave his mother a birthday gift of a meal at Carson Kitchen. He's the kind of guy that does thorough reviews on everything he's interested in...", + "user": { + "id": "Cvlm-uNVOY2i5zPWQdLupA", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/ZT4s2popID75p_yJbo1xjg/o.jpg", + "name": "Bill H." + } + }, + { + "id": "pq6VEb97OpbB-KwvsJVyfw", + "rating": 4, + "text": + "Came here during my most recent Vegas trip and was intrigued by the menu options! There's a parking lot close by (pay by the booth) but since I came on a...", + "user": { + "id": "TMeT1a_1MJLOYobdY6Bs-A", + "image_url": + "https://s3-media2.fl.yelpcdn.com/photo/CxCo55gIOATctXc5wLa5CQ/o.jpg", + "name": "Amy E." + } + }, + { + "id": "5LF6EKorAR01mWStVYmYBw", + "rating": 4, + "text": + "The service and the atmosphere were amazing! Our server was very knowledgeable about the menu and helped guide our selections. We tired five different...", + "user": { + "id": "a71YY9h3GRv7F-4_OGGiRQ", + "image_url": + "https://s3-media1.fl.yelpcdn.com/photo/3EDvhfkljrLyodxSrn8Fqg/o.jpg", + "name": "May G." + } + } + ], + "categories": [ + {"title": "New American", "alias": "newamerican"}, + {"title": "Desserts", "alias": "desserts"}, + {"title": "Cocktail Bars", "alias": "cocktailbars"} + ], + "hours": [ + {"is_open_now": false} + ], + "location": { + "formatted_address": "124 S 6th St\nSte 100\nLas Vegas, NV 89101" + } + }, + { + "id": "igHYkXZMLAc9UdV5VnR_AA", + "name": "Echo & Rig", + "price": "\$\$\$", + "rating": 4.4, + "photos": [ + "https://s3-media1.fl.yelpcdn.com/bphoto/Q9swks1BO-w-hVskIHrCVg/o.jpg" + ], + "reviews": [ + { + "id": "S8KsRL4i-Qa4OQDpvTYy8Q", + "rating": 5, + "text": + "I had a delightful meal at Echo & Rig, enjoying the filet mignon with a salad and a side of fries. The steak was perfectly cooked and incredibly tender,...", + "user": { + "id": "VZdaG5_PQq6W_5TTbLPSog", + "image_url": null, + "name": "S R." + } + }, + { + "id": "HoUKWihuu-DVt77nA6QI5w", + "rating": 5, + "text": + "I've been here several times. Today I was meeting up with a friend and decided to sit at the bar downstairs to wait for him. I was pleasantly greeted by the...", + "user": { + "id": "cMZVJdi_fKG7rp1no_2ZvA", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/4NcP4S6RklA6sT8Zp2JCfw/o.jpg", + "name": "Joshua S." + } + }, + { + "id": "JId3KfBAwJTv3OqEoS-V9A", + "rating": 5, + "text": + "We had reservations very early at 5.30pm\nThis places is so large however super busy and popular.\nThe food and service are excellent. The only things that...", + "user": { + "id": "1v2UxV8i_Ae64yxT17rRRg", + "image_url": + "https://s3-media1.fl.yelpcdn.com/photo/DxCDFZrPLOdc6o5CddaAoQ/o.jpg", + "name": "Apple S." + } + } + ], + "categories": [ + {"title": "Steakhouses", "alias": "steak"}, + {"title": "Butcher", "alias": "butcher"}, + {"title": "Tapas/Small Plates", "alias": "tapasmallplates"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": "440 S Rampart Blvd\nLas Vegas, NV 89145" + } + }, + { + "id": "SVGApDPNdpFlEjwRQThCxA", + "name": "Juan's Flaming Fajitas & Cantina - Tropicana", + "price": "\$\$", + "rating": 4.6, + "photos": [ + "https://s3-media3.fl.yelpcdn.com/bphoto/a8L9bQZ2XW8etXLomKKdDw/o.jpg" + ], + "reviews": [ + { + "id": "QrqQBcKENE83z4sWBdQyrg", + "rating": 5, + "text": + "My FAVORITE Mexican food in Vegas!! From the service to the food I'd give 5 stars all around!!! Everyone is always friendly and welcoming!!! \n\nI can't ever...", + "user": { + "id": "YvEyOqT0PUyFwZ9NUj_A0A", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/kra2v9Z6sd7W9S1enUDJrA/o.jpg", + "name": "Christy G." + } + }, + { + "id": "apS-lxKwHo2yJBnk0a8Phw", + "rating": 5, + "text": + "One of my favorite places in town. It's always crowded, so it's best to use the Yelp reservation system. Parking can be a toughie too. It's located in the...", + "user": { + "id": "yPVnXy6Zf3LefjcbjOABDQ", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/6sCVZwFwdpUhElhUKTbJ6g/o.jpg", + "name": "Cecille L." + } + }, + { + "id": "4nTGQhV8vMDNS-V3nF99VA", + "rating": 5, + "text": + "I've been here a couple times and each time so far it has been amazing! From food to service - everything was great. \n\nOn my last visit we ordered the...", + "user": { + "id": "ayOlP5JtyF8RwtB0opJzrw", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/qrPJ560WVlLPJ8FFbrJlWg/o.jpg", + "name": "Tia G." + } + } + ], + "categories": [ + {"title": "Mexican", "alias": "mexican"}, + {"title": "Breakfast & Brunch", "alias": "breakfast_brunch"}, + {"title": "Cocktail Bars", "alias": "cocktailbars"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": + "9640 W Tropicana\nSte 101\nLas Vegas, NV 89147" + } + }, + { + "id": "4JNXUYY8wbaaDmk3BPzlWw", + "name": "Mon Ami Gabi", + "price": "\$\$\$", + "rating": 4.2, + "photos": [ + "https://s3-media3.fl.yelpcdn.com/bphoto/FFhN_E1rV0txRVa6elzcZw/o.jpg" + ], + "reviews": [ + { + "id": "baBnM1ontpOLgoeu2xv6Wg", + "rating": 5, + "text": + "the breakfast was amazing, possibly the best french toast i've ever eaten. i'd love to try more items in the future, super appetizing. ate an entire french...", + "user": { + "id": "xSvgz_-dtVa_GINcR85wzA", + "image_url": null, + "name": "Lilly H." + } + }, + { + "id": "Lg_j2vG2CTR8A5NGM7Zqhw", + "rating": 5, + "text": + "We recently ate at this French restaurant for the first time, and it was an amazing experience. Initially, we were eager to sit outside to enjoy the view of...", + "user": { + "id": "pgvFEonlrCa1BCmDg_dofQ", + "image_url": + "https://s3-media2.fl.yelpcdn.com/photo/xMn5z_xxJt_Qq3_PvTZ__g/o.jpg", + "name": "Chul L." + } + }, + { + "id": "Kiv-lCuE-VBUMR1V_fM6HA", + "rating": 5, + "text": + "Although I had a mixed experience at the Paris hotel, Mon Ami Gabi was a pleasant surprise. Given how overpriced some of the items were in the hotel shops I...", + "user": { + "id": "YnSxh5AC2EtmOyg2XqcqPQ", + "image_url": + "https://s3-media1.fl.yelpcdn.com/photo/u9kYpEYZlmkg3sWWIqDtyA/o.jpg", + "name": "Jon L." + } + } + ], + "categories": [ + {"title": "French", "alias": "french"}, + {"title": "Steakhouses", "alias": "steak"}, + {"title": "Breakfast & Brunch", "alias": "breakfast_brunch"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": "3655 Las Vegas Blvd S\nLas Vegas, NV 89109" + } + }, + { + "id": "UidEFF1WpnU4duev4fjPlQ", + "name": "Therapy ", + "price": "\$\$", + "rating": 4.3, + "photos": [ + "https://s3-media3.fl.yelpcdn.com/bphoto/otaMuPtauoEb6qZzmHlAlQ/o.jpg" + ], + "reviews": [ + { + "id": "a3UISKdTa1aMxok4mmzNsQ", + "rating": 5, + "text": + "Step into Therapy and take a sit, Chris the bartender is pretty chill. Talking to him is like talking to a long time friend, the type you don't see for a...", + "user": { + "id": "SbMQm6pAPRwg04y44S5zLA", + "image_url": + "https://s3-media1.fl.yelpcdn.com/photo/3ZuAxm31p7iwQ_zV2lgWOA/o.jpg", + "name": "Vittor V." + } + }, + { + "id": "hfZ-9d6Xxztb9o-cEJmR7Q", + "rating": 5, + "text": + "The food and drinks great! Try the loaded crab fries ~ got seated and served quick- Dallas was the best!", + "user": { + "id": "7_uRkPfh8fvewEHDnhx6mg", + "image_url": null, + "name": "Patricia L." + } + }, + { + "id": "oSb7UzeaA-r_H8WgJYWH3A", + "rating": 5, + "text": + "I come here once in a while. I had a great time spent here dancing on tables! I came for happy hour during the day and had so much fun! They have a great...", + "user": { + "id": "zPRZtDcBqN0VjXDlkYK3cQ", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/4ZS87l3TNsOLSF6-Piqi_A/o.jpg", + "name": "Brenda B." + } + } + ], + "categories": [ + {"title": "Bars", "alias": "bars"}, + {"title": "New American", "alias": "newamerican"}, + {"title": "Dance Clubs", "alias": "danceclubs"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": "518 Fremont St\nLas Vegas, NV 89101" + } + }, + { + "id": "QCCVxVRt1amqv0AaEWSKkg", + "name": "Esther's Kitchen", + "price": "\$\$", + "rating": 4.5, + "photos": [ + "https://s3-media3.fl.yelpcdn.com/bphoto/uk6-4u8H6BpxaJAKDEzFOA/o.jpg" + ], + "reviews": [ + { + "id": "VjmUIlp_Y0_0ISEjqZvKAw", + "rating": 5, + "text": + "Our server Josh was AMAZING! He was so attentive and sweet I've been to their on location and the new one does not disappoint. I tried something new...", + "user": { + "id": "59qcS7L8sHAaxziIg4_i5A", + "image_url": null, + "name": "Caitlin S." + } + }, + { + "id": "54vX-IPr0HmraBhjhNJh2g", + "rating": 5, + "text": + "Esther's Kitchen is a wonderful find, especially for locals who want a variety of good freshly made food at an affordable price. Some dishes/pottery they...", + "user": { + "id": "Uw9yxT40cGDCWI0AffnzdA", + "image_url": null, + "name": "Gigi O." + } + }, + { + "id": "SFLBVnLVHLI5c7Vdb2l5yg", + "rating": 5, + "text": + "Certainly! Here is a sample review for Esther's Kitchen:\n\n---\n\n**Esther's Kitchen - A Hidden Gem in the Heart of the City**\n\nEsther's Kitchen is a...", + "user": { + "id": "A59MiJ0LjgQIWWN1HdeI7A", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/f-xW9DAGYO8jXFKqW3NmFA/o.jpg", + "name": "Alfonso A." + } + } + ], + "categories": [ + {"title": "Italian", "alias": "italian"}, + {"title": "Pizza", "alias": "pizza"}, + {"title": "Cocktail Bars", "alias": "cocktailbars"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": "1131 S Main St\nLas Vegas, NV 89104" + } + }, + { + "id": "mU3vlAVzTxgmZUu6F4XixA", + "name": "Momofuku", + "price": "\$\$", + "rating": 4.1, + "photos": [ + "https://s3-media1.fl.yelpcdn.com/bphoto/mB1g53Nqa62Q04u4oNuCSw/o.jpg" + ], + "reviews": [ + { + "id": "mAEPxxFflcYD6ZtzvnxzKg", + "rating": 3, + "text": + "Service subpar. Lamb was average. Pork belly for kids bad. Overall not worth the prices.", + "user": { + "id": "s4qyTcSQtHzlW8O4nm867A", + "image_url": + "https://s3-media1.fl.yelpcdn.com/photo/lbb5PhyDftjXRuTV8mdBsA/o.jpg", + "name": "Jon L." + } + }, + { + "id": "40BE2te-wIXkc3xevcp4Ew", + "rating": 3, + "text": + "Service is pretty good.\n\nFor food, ordered corn rib, and it was fantastic. The ramen was just so so: mushroom ramen was too salty. kid ordered the other...", + "user": { + "id": "Dk68URVdrfDzQJvghTs9nA", + "image_url": null, + "name": "Peng Z." + } + }, + { + "id": "2OEMhHcFTfJ2rL_e-61-5w", + "rating": 5, + "text": + "Food was just perfect. We tried few different buns and noodles as well as what you see in the pics. My favorite was temaki and iberico pork. Temaki comes...", + "user": { + "id": "qwH-93rwVUExvTyK8QLxjQ", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/rwXdDb1vh2sK61MzYB-fyQ/o.jpg", + "name": "Lin K." + } + } + ], + "categories": [ + {"title": "New American", "alias": "newamerican"}, + {"title": "Asian Fusion", "alias": "asianfusion"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": + "3708 Las Vegas Blvd S\nLevel 2\nBoulevard Tower\nLas Vegas, NV 89109" + } + }, + { + "id": "fL-b760btOaGa85OJ9ut3w", + "name": "Rollin Smoke Barbeque", + "price": "\$\$", + "rating": 4.4, + "photos": [ + "https://s3-media2.fl.yelpcdn.com/bphoto/j6pMPJziv3-_Jzl1bRaMSw/o.jpg" + ], + "reviews": [ + { + "id": "bfnaYmZN0RPzutYSO9tPfg", + "rating": 5, + "text": + "This food was so good it made me write my first ever review. Absolutely delicious. My wife said it was the best mac and cheese she's ever had, and my wife...", + "user": { + "id": "nLXyYA1LoLEtARCBiB6xYA", + "image_url": null, + "name": "Nicholas M." + } + }, + { + "id": "eWVrb6J2OuQ0y8g2-Mm1_g", + "rating": 5, + "text": + "Rollin Smoke BBQ is that spot, for real! This place got the Arkansas Razorbacks vibe on lock, and the food? Straight fire! Let's break it down:\n\n**Ribs:**...", + "user": { + "id": "ZYe4DVeqMNMjJZVLil8yMw", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/0THv8LUjv9SkKLsZWxCqcA/o.jpg", + "name": "Andre W." + } + }, + { + "id": "nuyFJ8XQse6g5pGC5dC7tg", + "rating": 5, + "text": + "5 of 5\nWe celebrate a friend b day from Santa ana\nFamily style barbecue \nMy friend brought the mariachi too\nBbq was delicious \nHappy bday mr Peter's", + "user": { + "id": "uB61MiqCg_VV9wzDtCK7Gg", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/Ux0PYdEc31Y19vpo1rUk_w/o.jpg", + "name": "Araceli C." + } + } + ], + "categories": [ + {"title": "Barbeque", "alias": "bbq"}, + {"title": "Southern", "alias": "southern"}, + {"title": "Sandwiches", "alias": "sandwiches"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": + "3185 S Highland Dr\nSte 2\nLas Vegas, NV 89109" + } + }, + { + "id": "So132GP_uy3XbGs0KNyzyw", + "name": "Casa Di Amore", + "price": "\$\$", + "rating": 4.4, + "photos": [ + "https://s3-media2.fl.yelpcdn.com/bphoto/7Yu5-1ZOYYUgZaXcdz0K9w/o.jpg" + ], + "reviews": [ + { + "id": "k8JeqKM1ehBLiiZda8fcZw", + "rating": 5, + "text": + "The service & food was great!! I recommend you try it!! Or just have a drink at the BAR!! lol", + "user": { + "id": "nXxoKg7AMpiaZIDNeMcgwA", + "image_url": + "https://s3-media1.fl.yelpcdn.com/photo/K-7O4xXLqHi6TGT-DWzr_g/o.jpg", + "name": "Lina A." + } + }, + { + "id": "_U9jbY372Ml8MPay9-OuGA", + "rating": 5, + "text": + "The service! The food! Both so amazing, on top of that we have a live performance of the piano such a vibe, would definitely recommend this place if your in...", + "user": { + "id": "iaGEMG7rXGp6AYM-GAjF_Q", + "image_url": null, + "name": "Amy C." + } + }, + { + "id": "hg0Q990LcQTzAF2aNmDK5w", + "rating": 5, + "text": + "The food and service were great! What a fun place. Randy Thomas the piano play...what a talent. He made our night out exceptional.", + "user": { + "id": "Z4Xjsime8D-qkFU12PmdaA", + "image_url": null, + "name": "Heidi M." + } + } + ], + "categories": [ + {"title": "Italian", "alias": "italian"}, + {"title": "Seafood", "alias": "seafood"}, + {"title": "Pizza", "alias": "pizza"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": "2850 E Tropicana Ave\nLas Vegas, NV 89121" + } + }, + { + "id": "nUpz0YiBsOK7ff9k3vUJ3A", + "name": "Buddy V's Ristorante", + "price": "\$\$", + "rating": 4.2, + "photos": [ + "https://s3-media2.fl.yelpcdn.com/bphoto/cQxDwddn5H6c8ZGBQnjwnQ/o.jpg" + ], + "reviews": [ + { + "id": "v9pnz6eqN7f2STYctnBBlQ", + "rating": 3, + "text": + "The dining experience left much to be desired. The food was subpar, with a notable texture issue in the carbonara; the pieces of crunchy crumbled pancetta...", + "user": { + "id": "Ux0VVNN8ICTmJbuWlW2djg", + "image_url": null, + "name": "Nathan T." + } + }, + { + "id": "JGb9E8nERjsNFM2F7SqCNA", + "rating": 5, + "text": + "Great food and great service.\nNice location.. they have outdoor and indoor seating.\nMeatballs are highly recommended!", + "user": { + "id": "loDGoLca5JC6dARvBQCUmg", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/It7kRVx2aq3EPC9amExlPA/o.jpg", + "name": "Daniel V." + } + }, + { + "id": "37kIixegf3pTb3jb6i1Y5g", + "rating": 3, + "text": + "Overall, the restaurant was average. The calamari was the redeeming aspect since it was one of the best I had, so make sure to get that (Hoboken style, as...", + "user": { + "id": "IAOAGReoxWaxhZm5-EpmOg", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/YI-5O4mLRjh3-o0keMuzbA/o.jpg", + "name": "Juliet M." + } + } + ], + "categories": [ + {"title": "Italian", "alias": "italian"}, + {"title": "American", "alias": "tradamerican"}, + {"title": "Wine Bars", "alias": "wine_bars"} + ], + "hours": [ + {"is_open_now": false} + ], + "location": { + "formatted_address": "3327 S Las Vegas Blvd\nLas Vegas, NV 89109" + } + }, + { + "id": "FNe5PPA9pyj8FjcDefCBpg", + "name": "Weera Thai Restaurant - Sahara", + "price": "\$\$", + "rating": 4.4, + "photos": [ + "https://s3-media2.fl.yelpcdn.com/bphoto/TOPFVZGJtaLJI_-Vyq078A/o.jpg" + ], + "reviews": [ + { + "id": "ETb_y4-gKokiY186fQ1dvw", + "rating": 5, + "text": + "We always come here when visiting Las Vegas. The food is excellent, pork Skewers are well seasoning!! \nBest pad thai and Thai Fried Rice \n\nMango sticky rice...", + "user": { + "id": "UMW1Q7If-YnfitQf271S-Q", + "image_url": + "https://s3-media3.fl.yelpcdn.com/photo/INM0Uxdt1pYMKuiryDWM_g/o.jpg", + "name": "Jesse P." + } + }, + { + "id": "cE_Ah4sxgfBquOSPTuqirQ", + "rating": 5, + "text": + "If you're a fan of Thai food, you absolutely need to check out this place. The pork belly appetizer is an absolute must-have--lightly breaded and bursting...", + "user": { + "id": "zLDkdRzxLJgFEHFFV52fbQ", + "image_url": + "https://s3-media2.fl.yelpcdn.com/photo/jDM2-0g29Ms_CoypGa78XA/o.jpg", + "name": "Kai T." + } + }, + { + "id": "VxDE--0BUyLY0daIiwZfJg", + "rating": 5, + "text": + "Of all our trips to Las Vegas, I am most delighted to have had discovered this hidden gem this trip and why did I not discover this location earlier! All of...", + "user": { + "id": "Kuc7KAZBnrW5O_C-Dn-r_Q", + "image_url": + "https://s3-media2.fl.yelpcdn.com/photo/UIQLPO2XlV4A2WbaWVIKmA/o.jpg", + "name": "Celia Z." + } + } + ], + "categories": [ + {"title": "Thai", "alias": "thai"}, + {"title": "Bars", "alias": "bars"} + ], + "hours": [ + {"is_open_now": true} + ], + "location": { + "formatted_address": + "3839 W Sahara Ave\nSte 7-9\nLas Vegas, NV 89102" + } + }, + { + "id": "-1m9o3vGRA8IBPNvNqKLmA", + "name": "Bavette's Steakhouse & Bar", + "price": "\$\$\$\$", + "rating": 4.5, + "photos": [ + "https://s3-media2.fl.yelpcdn.com/bphoto/pgcnYRHtbw_x_-OG8K4xVg/o.jpg" + ], + "reviews": [ + { + "id": "PbKZJlLCWVcnHLUV0AK45g", + "rating": 5, + "text": + "For a great dining experience look no further!\n\nBavette's has it all; delicious food, fantastic cocktails, and a service staff above them all.\n\nWe were a...", + "user": { + "id": "IJxjNg4fMDar8WTcY_s1NQ", + "image_url": + "https://s3-media1.fl.yelpcdn.com/photo/DN4xv1FYk_5yvPBhydRZGg/o.jpg", + "name": "Lisha K." + } + }, + { + "id": "Bk8AQJD8APVBWR6Y_Opvpw", + "rating": 5, + "text": + "First time at Bavettes and not sure what took us so long. Upon entry you feel whisked into a whole other atmosphere from the casino. The dark woods and...", + "user": { + "id": "c1sHJlr0MizIANx49BTXWQ", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/y9JnzleHF9G9Lx6EHIu8SA/o.jpg", + "name": "Alyssa Y." + } + }, + { + "id": "wmraj3HVLF7IO5FLdPD6oQ", + "rating": 5, + "text": + "10/10 service and hospitality. Ambiance is perfect for a late night dinner with a partner or even family. We definitely enjoyed ourselves here and enjoyed...", + "user": { + "id": "MZJmPApqOQ-St4II1lDnLg", + "image_url": + "https://s3-media4.fl.yelpcdn.com/photo/CTnyY9AwmIc5Rcb-r8BRaQ/o.jpg", + "name": "Kalia A." + } + } + ], + "categories": [ + {"title": "Steakhouses", "alias": "steak"}, + {"title": "Bars", "alias": "bars"}, + {"title": "New American", "alias": "newamerican"} + ], + "hours": [ + {"is_open_now": false} + ], + "location": { + "formatted_address": "3770 Las Vegas Blvd S\nLas Vegas, NV 89109" + } + } + ] + } + } +}; diff --git a/lib/repositories/yelp_repository.dart b/lib/repositories/yelp_repository.dart index 9eab02a..98e46e5 100644 --- a/lib/repositories/yelp_repository.dart +++ b/lib/repositories/yelp_repository.dart @@ -1,8 +1,13 @@ +import 'dart:convert'; +import 'dart:io'; + import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:restaurant_tour/models/restaurant.dart'; +import 'package:restaurant_tour/repositories/sample_json.dart'; -const _apiKey = ''; +const _apiKey = + 'GzcIFZrKe4aMmED9FS9ObPxFP4vAhEOW2wN9usDA0zazBimbxQ8O2LdcpwMUcpkCU1ZYxF-LK_jWygZgGvfeE_5jSulY1XdUPs09j1FCwDtXQmyD_emQYuOEMBHKZnYx'; class YelpRepository { late Dio dio; @@ -60,18 +65,45 @@ class YelpRepository { /// } /// } /// + /// + Future getRestaurantsFromCache( + {int offset = 0}) async { + try { + return RestaurantQueryResult.fromJson(sample['data']['search']); + } catch (e) { + return null; + } + } + Future getRestaurants({int offset = 0}) async { try { final response = await dio.post>( '/v3/graphql', data: _getQuery(offset), ); + // saveToJson(response.data!['data']['search'], 'datastore.json'); return RestaurantQueryResult.fromJson(response.data!['data']['search']); } catch (e) { return null; } } + void saveToJson(Map data, String filePath) { + try { + final file = File(filePath); + final directory = file.parent; + + if (!directory.existsSync()) { + directory.createSync(recursive: true); + } + + file.writeAsStringSync(jsonEncode(data), flush: true); + print('Data successfully written to $filePath'); + } catch (e) { + print('Failed to write data: $e'); + } + } + String _getQuery(int offset) { return ''' query getRestaurants { From 8e75260c1dc7193e8461f00a49beb4834ee93afe Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sat, 24 Aug 2024 16:11:38 -0300 Subject: [PATCH 06/30] pubspec dependencies --- pubspec.lock | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ pubspec.yaml | 4 ++++ 2 files changed, 52 insertions(+) diff --git a/pubspec.lock b/pubspec.lock index 27b6e40..25ba7d5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -33,6 +33,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + bloc: + dependency: "direct main" + description: + name: bloc + sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" + url: "https://pub.dev" + source: hosted + version: "8.1.4" boolean_selector: dependency: transitive description: @@ -193,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + equatable: + dependency: "direct main" + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" fake_async: dependency: transitive description: @@ -222,6 +238,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a + url: "https://pub.dev" + source: hosted + version: "8.1.6" flutter_lints: dependency: "direct dev" description: @@ -251,6 +275,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" + get_it: + dependency: "direct main" + description: + name: get_it + sha256: d85128a5dae4ea777324730dc65edd9c9f43155c109d5cc0a69cab74139fbac1 + url: "https://pub.dev" + source: hosted + version: "7.7.0" glob: dependency: transitive description: @@ -395,6 +427,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" package_config: dependency: transitive description: @@ -435,6 +475,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + provider: + dependency: transitive + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" pub_semver: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4018593..367b1df 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,6 +16,10 @@ dependencies: dio: ^5.6.0 json_annotation: ^4.9.0 flutter_svg: ^2.0.10 + bloc: ^8.1.4 + flutter_bloc: ^8.1.6 + get_it: ^7.7.0 + equatable: ^2.0.5 dev_dependencies: flutter_test: From 3477ad3d1986ac3d1cf187e10f69125c57cf53f9 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 15:56:28 -0300 Subject: [PATCH 07/30] Building the restaurant detail page --- assets/avatars/av1.png | Bin 0 -> 60860 bytes assets/avatars/av2.png | Bin 0 -> 39430 bytes assets/avatars/av3.png | Bin 0 -> 44301 bytes assets/avatars/av4.png | Bin 0 -> 44039 bytes assets/avatars/av5.png | Bin 0 -> 44661 bytes assets/avatars/av6.png | Bin 0 -> 71961 bytes assets/avatars/av7.png | Bin 0 -> 47056 bytes lib/main.dart | 13 +- lib/pages/restaurant_detail_page.dart | 105 +++++++++++++++ lib/pages/restaurant_list_page_view.dart | 126 +++++++++--------- lib/repositories/yelp_repository.dart | 16 --- lib/theme/colors.dart | 5 + lib/theme/text.dart | 30 +++++ lib/utils/get_random_avatar.dart | 21 +++ lib/widgets/divider.dart | 7 + lib/widgets/hero_image_widget.dart | 31 +++++ ...status.dart => rataurant_open_status.dart} | 7 +- .../rating_and_open_status_widget.dart | 29 ++++ lib/widgets/rating_widget.dart | 4 +- lib/widgets/restaurant_details.dart | 4 +- .../restaurant_ratings_review_section.dart | 114 ++++++++++++++++ lib/widgets/widgets.dart | 6 + pubspec.yaml | 2 + 23 files changed, 422 insertions(+), 98 deletions(-) create mode 100644 assets/avatars/av1.png create mode 100644 assets/avatars/av2.png create mode 100644 assets/avatars/av3.png create mode 100644 assets/avatars/av4.png create mode 100644 assets/avatars/av5.png create mode 100644 assets/avatars/av6.png create mode 100644 assets/avatars/av7.png create mode 100644 lib/pages/restaurant_detail_page.dart create mode 100644 lib/theme/colors.dart create mode 100644 lib/theme/text.dart create mode 100644 lib/utils/get_random_avatar.dart create mode 100644 lib/widgets/divider.dart create mode 100644 lib/widgets/hero_image_widget.dart rename lib/widgets/{open_status.dart => rataurant_open_status.dart} (72%) create mode 100644 lib/widgets/rating_and_open_status_widget.dart create mode 100644 lib/widgets/restaurant_ratings_review_section.dart create mode 100644 lib/widgets/widgets.dart diff --git a/assets/avatars/av1.png b/assets/avatars/av1.png new file mode 100644 index 0000000000000000000000000000000000000000..ff6fb58603a1aacf1034fda715206c8b040b2c23 GIT binary patch literal 60860 zcmX6^1yoy2)5hI`yBBxY;*#Q0Tw2^I#ob+tyA+B;ad&qwZo!@44u9V7KRNd#XOrCB zot=4R=9#&Xs>*WcD8wjGP*CVVd1-YhDCpb&E+hoV$oS$`6y%N4R9;;P3d)NP3MwE3 z3hEg$6mSFu<;npCb@B}gN+=x)ir`0fo0B}tGGd`f$Fqi$RMH%P)P>y5DpO+U&z7Jg9&m+D4?{2rpM~pn`MHzwbvHnd+tN}snT;L z%cYXH@VuyKa4lgp5e%Gs0Hu5aZfiSrBW-ZSpOrUC8M_cks!(b-e#u%Cn?W6$vVYZZ z#89wk0liS%!5J6F){f=vZ5^XyU%a{hc0Z(Bie+b2x3$?>{PFgmZRS2b;Jp-lSicdA zCt$%J&&NfwMf(&Ope(DCBlj*53txys5`8i6ynY=${_`Sqr_qg5*ZK7>r+fD7)rp zXc)AbY(O1nvh+xFf||Kb3UvZL73QP(7pmw)I!{645T0$A&8R%1%PJAdjTb|p%g-w( z_m@sBO1PlSx#KtT&7Cc>eDwUxS2oE~Ecu`Qs8(fj_@$Am8U>#?{)}Z0v6R+fp`toW zyyg*<`B$&BUmu-!3xw%N;MUDvQ&(;4v$%)973;7t>)_f0A|%Co3B8IfOsq3`loyJi z_68FG1(d3qBNd69s;UL0W0V{y$udW<*VJabfT!O~j4Kvf;$M$+UwK35I3l?!#zbiO z0S7X=5jdc~Y@a{JS<8HhjW}_MT(n{a`23STQ%ewNWzB8n(mG>J{dCscTSqe+6(nhu zzZ>Axb1N+z*ISfO8eGEJb-GRMQQlHsG{8~B>8<8QgBD$*@~yki;VXidR&)K%xx;(z zdB|nXCa6n3r430Nz=j+%%sG#uEz`Q!bGNLDQ&91Ra2SrEU;wUIp;XX?(+BY25RHo> z{QW_Xg<^Q)2wsOJ3mFd!F@gc=MOvVshGJRn+8Of;FoY*aVH&SGa%~-__q!$1eNKY# zx}`J&tYESfN+42!cmUSGZKZb$iox*)8*JJ?^B^`8~_@C^?*_*lh($N;*p zt=Pi`@yU^u!*`U*>rli}9Xp|w{~T73mkZbHs!IQ*`u-id-PuC9!^J%S%8|dtDNuZ& z;0WL%?Pm*lqdt=%g2jMYiQU8>x6gp53s5LGfE|))iQp*w@+q!t;EQ>|`1-dnLZGyf z?)k&?;W^_>oo|g?z4>?@A)XWkSnOK;s1lKj{az9ZQ;Y>;TI zrxd86uQeGYTVqwNFVSp=bN0)2g{!g>7EzpvE8zt&=aCCLwBN!>8fSVB?JYwnLrBd? zL2__GQmxZOz{vq`fLQD;#ty5^bC4~YJ?)nlIn=C5eJ+~Q?aXLLb z#DH{O#Fe}bx;U$}ou^sicp#p!@qrH65kZ*Z(ObP8J&0f=&wg30a5VhJk~pK|1yN%O zCS(m+V_p+N1PnFiw2j4qfCjxEYt(Ko$DuN}d_epI7KAqTGLT&`>B=om<8Z$^cRzx6 z&iJp+X}NIvT2)t<{vz`ebedKM6`B+^8gL?=*a(VTP7vvA3vzS`PK?xwW%{Q~M9N$R7Q zz+n@RC$EoeNT)dRC%Hr@%UV0Wko_+BYNlzZ;aHGxkIXjB_6vg;Rb;O|3nrfTi0)#x zOmiEIgX8k(A0AR0XUZ^oo&yeWDXr60C#{rO-IofW8lWJEPLuXFyaUP zzUwx7fO{YlK%22foCaBxHO{p;*p$UKR5X$0Ayx}_6>FaoOc_TR0~p>GL=cM-G}~r0 z_4pk3)PaO3zkVEq=RAH-cd>ylFWcRvG|?^P2^;*$?@@!Ijf)SRH>jpsm-8j5~}9{rv?<__$BYeYSgPSx@IULy>> zi^#!12B;05215ou@TxVrlqc?fNFQh5FwkW8J-8!pux_#x`Ve;tH5(psr0D&jUt!m4 z7u)tXYvp40<5*I1T`3vFw|mAJJ<62whR!4e!$3C-?9jtNx(r>G)U|m8Bg8JmSKNK- zG1@S?up$z}@ITwhO26yZk-bB7J_D*48Ysu;(Z9WV9^Hc&ij?FT-8|JmYs5F70M9^! zlO~6ClU8B;(^Y-ijUzwI{RgbgAuKGw3>|eW_Aj(B*UB3G&qUs4I-h^ZNMNEy=9j$N z9=%ft;G!DOMi}FQXgOeRzsG-y-j_gVJzz82=g5fhzGi^4FzuZ!E2BS33dCM-Y>-tRU5WX{`=9g3>lkNFMeL0n#N+jD~68 zXUWxo+EM3J^Rr(y!MZMG!<|Ccns`Doq{+#V41;X!j6QOvU6hg(z@fJDBa2!QQhd`h z`){P6lAZ_TN1{Gg5k2XnF?t=Rt(9dJf5dt&S@O07@_-ApaMQ=AAs?9#oE`=~S%+FX z9%xngYFNkLuio3?Gq%iY{V2~l0b*)58!*l)B9&vMT?Q<&3^_ayCj5?u5=>uN@$`1mYY9yCzRV(+5b{ z8T&_@GvmN$&^kO`Vqb@^Z!@(=BG;HZ2*bS`JD9F2$>2&N)_n-NyibeZ_a6pKqlhTX z*>0e;4%Ycv!IXHvf&Ae*lyjKTW{Lw@o!1VQRot@FDvoys1&p{ZN9ip>(xq%3`M^qv zey8}+=E5``Fh21SX@T=S=x9{Xk%gN&(Z229#U|~CP$b+9BnEzbNio*i*Y>^{;a=AJ z8EsCFm6+U?Bk^P$DAogFAv2*~KzY9J_sd)h_@nFy-B71`xnm}R(H`cA;-j0yS7o~F zxtF>|)rk|t^5K1~;x44YqVmu1T}A?Ld}tn~nx+H(^|Sputgoh3f?2O+C7K<<8GY-Z zHBX{|CyVN2pK8)C)yHHeW5A=x4>aMV^`EHHP)V-~gne$|4vmtk71&Lg(mD8QB}$}l z0}|n-Yfq2S41`<5kBl+9pd$5_6%ix0_%!C7v@roj$74}VXy$7Y8CVa*{TD*Nkp5|8 z-3S*(%eao%zmC>tCC%`wsrm>{xo4L+vyA$TN9&I=hc`z+P|FHAA`lUS~f`)g{ypNW1# zN)Wlluj&E{4~gV%dN8(Rs`SM9p{=egUaYBRN`8~L?<@AdXv;FA=ZJ$n-XK}@SQAat zBT={0K^F79-XOU?M*U0w7qM;TOf4%F|UqgvP;grbcZKnK@m z2(lxWqViWgYEg*syZduiX1nJk18CrC6n};>ilXk3mw#gL>|yfxsx{cPDK&YE_}{+H z>0=m;_LS(I;q1!<{-yDOUT&W~ZLlLBpoJk?u;HPrp2;RH5#2 zInMpl;c(0HDj>T{$e#q+ucX`3=P1ND)n)JW^<|?u*x=E^-PlcU;lzgkiUJ?8h$riU z9n9mLEZ z#GsP6A5X>>R_|3zk5tl46ZZ3_VmV66RmD8$xYXG$(#5-1(M+$bfhxaZcpGyzSrn{D zaS#phr~F4^^WKP3Ft?~mwPyt+ca^N3qrSxiXHEVhS)0yf_lt&1w^LLfQELiM&K2DW zD*5_Y&G50MnWha>aGVygcB3`JFML1062j8DEM;YxzuG(cOzMi>jpCD2RNc|=|6&a+ z#i{#o!Bc+qM8dde_q|eA^9sE1k&&Ixf!gO z6u`>s#aPCJ>8|Os7e|OTbq;jKQ4ZO8DY$d`Q8emnvil_`PyEA2T0BBGBXFiHcF>6)ozXTcg}?Fe0nUph(dZDbM7mnewENSr{93iO9fUh| zwE*GJRb|MGLyqkEhl06ievyGfKr9kVrdN5LkLY zYoF+PA>LSpA(kQOtmKvC$c;8WGriR?{`SD`L)NV$8AB#j15N9C+9$aEfb^(6VDKkf z@kf17muF4h074;ND26lc%tZ~&=&?S1vrB6YkH@=3ADE;(7p!~i zhyb$($kpy!rRr0{d~cuZd%`68n5E$QnDt)MA8}muh&63%gs=V>q@Wq%xSwNp5Q`ts zlJd+pW4W;ey#Ey%7{7rh{_`x$Zg*$`|3)?Mz=YBOGlDz}yg~ok#R_Ig*f_e=<)eae zBAiQa>AR!wjbGh&9*_tS5N4K8EQ}bs8&~Xp<9<~ad!x_m0X{V;`|g4R3{lv>|B%1> zU|x7M;v0{3L)2q!bh-uRpF}M(S0O zo!j8=&Qxioe;gS?(7QmtYFRyJQUb*TxJ^;`${Oo|`)TlQZ=GOhv~{MgO9%ChYP(Gp z1Mpc1;Sq1!vErK6ZJ}&G32TPqw?@YP38r8CakHQ7aw%*4r;XkSC!`bJA^%&sqA}P< znKc&+9L}KYQ>Hz*cguTl(ogw$r`ee>*+sG!Rvmg9-alFz)UX6mSUsw1hZGF2!wl0& zEoEo#&Fk2^;xm=p5N%X@+O}`Isn?ny08nATW+v@wPIbubKI5&anch(L{ z1RV1l7xM}?&MK^iFgVSaUj*|5F)@vX;Gnih3Xonm!youOb?V)}QfA4`%vaIJIEw-+Si$7pE!9jc}9< zi?hL!K12A8k7oJ}#^`hRtU{d+smgbLFuK|^M-f(6d|i#zpEa+$#$KamF-kq41uQ=| z*!T{5Oo#MF>FYZ_7(S6N5<;l}VAbf4;rMShZFw9F>P`IkBe0tEc}l7^y4@o4XB)Jh z56qz+Va6N_eV_|iP#loF)Y4vDbuLJ33%2N^c~jKTCaL#UTRsHL+|3>_z}i5Y$@BNd zb>5sO!Q#zFi zPtGM}*`A28RTXbtsxtyan{ypb_J!J}t-?OrfbG9!VErkF+&{4j$Td|am#7eVe!9cc z@~lVJl?oFH$MPcq@z-RWrFzSV7pDJrD?=fLh4W?X#+N^7$lC2*zn&Wva52fZj_`CZ zFw_X89)-nIMbOK$OY->eNHn^&EAzLQVUBr-Lgbtt<$4H!1MB2Ysos)sI|3&6Z~Uc3 z&q%f5GrFN^=@1d?iqH#)$t`NYM1J=Ag$=)fn^~xmpx6 zT`~yDgEFSGcCwltNcEPYv~e#r6jXUzm4U$Z8oC2IlD^Wa^E^Z`XBq0YCaQuHvK6{x z#>J@naSYCmlk^^5HXwM7vEZ#_`qO+Sq9JRSoB9=fTet@-`**sImlFdnmU!OrBj$br zci=vx5xlL}do{X1LdI*SBZ&HwxL4y6!%8tIUl9G&Au$*n{rRoTZZB!9W<>>np) z_*|nD=M7D3rqk5!k_Dd?WJBZzLB^CmRrCk3M_(bno2lN4P|y8Ek1DZc z!?GmtJ8Npy$nVmROo3NpO%IW+PxZ6Wt0>DwE&8f|8Hiy}cDO0o*pXimz`B4jlFrZL zi?XDp#+@S*!eaC%P5fShYp8%A+1P_Uf!ds|rW8QFF^GV)fEB#eNaJ@xB9x$W^3?J6 z!*K}ZS&3zEB3g7@1aPy3(B-gkmWn8wQiC@`*sXYeEyxpB<=Pb{KP~Avsfg{~PSQy_ z9;|`zo+!?JE?(N9{$QP=*Yq?|RTH#nYEJhOmHt#HI{tb}{YcU&JB}|WzAM03mD!dX z^U_dz!%L3=(MJyU!!(4w_pSnXG8t?LOzf3A{)gl}pCQha3p z2l8WiY=-_K3>DxuG@9bm#>5$*(ZPxouwXkNF??}Y70*zF+jWBUVUXNE1y}uMAQp$` zl2{>9xDBNio_yu0hW3F)!rff?38r+e#qSdlwaK*nX;1`~9MyTNb)Va~EKd`rdFZss zBcl2?qkhS|lUv7l=U24|stZI*;_1n2Yk(grD9wIiy)MHKfMbLyNimS0NCdSYI=2?9rSjYp~H13z=xK$nR-NT@}}DzDdiYA%TSr@~q@ zX{y@@Y+?N^ug-uj6VroK-eFpMU`5(AHs5JP&`X}X-(g2FFjDf3{%B-;!ho?Y5W~e47IR&zKl1xHUj{e#llFHT4I-n?*j;o?`yC<+ zfgNwYkq!;)i$Qmx+?o!q*BQxk=~i)zr46{So<>74s5L8)4&Sd@ztEtVq8KBSz1wUj zV&=pe%?;INT7qfV%^M%T@H28F)1W=jnuQr zX6iJswgtepOcP8#Dj^wK6-z+2dhY5Iw~){-hJ#LYHfkRu(BH&}r>VyxR+4b><;wXg zE!D682@?Oofix8O*JoUr3RQ$=%n{W`A|z3P`sc>tR7=9YjIdS@MwFuT?OD~+|TVA zO&fKB@&*_6rFzj<-|M)~xW<({7>wcCkesPr6$=_?qrC|2^wspwU`jaQFo@(l=Xx9& zeGo?MZ=YF&kpfHC=IIOCoSKxOwKfwN9Q˛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�PngZkFc+qzv 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 Qffy_`Wlg23mzEL#2Sc%Nk^lez literal 0 HcmV?d00001 diff --git a/assets/avatars/av2.png b/assets/avatars/av2.png new file mode 100644 index 0000000000000000000000000000000000000000..d3b671bab6ca8ec117776de3436c66a7e99ab5b2 GIT binary patch literal 39430 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 aVx*-0-$h6twowBZoX48_um%mgsQ(ApCv2Ml literal 0 HcmV?d00001 diff --git a/assets/avatars/av4.png b/assets/avatars/av4.png new file mode 100644 index 0000000000000000000000000000000000000000..af456971a5cbc3a2c047a5d3618865586e7ba301 GIT binary patch literal 44039 zcmX`S1yCGK+ck{41`k1k2Djj{xFisCaS6J(yF&=>8r*FO5Q4i)g1fsc!QJJX`}yDc zi`t@UcDsA}vOecrGZ89ZtHHs+U;Xz%LjkS~&#gxS|ENvn)s*1i zycyu&0z=^79)L@M`*3h>oN#alU*X_{e!#(zIA*n|iU41rn0%I#hI{?*FR#5c3Alpp zD6iuJ2S-f*-v?enjqVJ%i0Z1KB!db=LM5a`f^?ro05ifVNK0sVE*(941e$4i!CpIa zT^x$X1eL}L(Gz9gB#I-@1xw>GEMP`C_3`m7-n>0qI;{7Y-?Z`Z7#(l5@u4_-%lQL~ zhE_%VgU!rarTsr%B|bv1D#ueV|A3W)oC$)KQYo-UZrbYG5@^f8N(S_?nGrK~dnDbo zvhv;H`uNV&a5@Qf40M^#LEOpQ zLCG}qG|7Q?;t^<+k*LY~&1OQO@^EF$g?T#QsXVfv_uo}R@FhZ#xT&pVrlCS5)`K(q z^36v0SdhorOM*N&4CW7!(BQ!Cue?HQiYQx7mJ3al6R)hXwI3AnF*gLFx@+b%=Z@~^ zU^lNgIS@QrRZH6NK>WBY>}bXTt&b(vEHa9`D##ivy0r4NDyTDiudMAmj535%VqY&n ziLcFP0dWD<)z{B+Pq}=ror3{K$e{P}D6&B{Pr1EacoV2saI0nRv{Ur*xdndErLYMH z&U8+!Z`vZnp~j@`Wz5|E@TMu-gK@Riv&Mp9 zZ(#^D!KY-wT?0RtFig$JRJGUPY?0>hXIsd_GkQ(Gi^U?_wpn#%e%OzLL%jgWfv=PC z$1I?XDbZ;tSYh|uSb7F7359kYU+gHBj=MCF#yg7MZt>$W+VJcc8EEJRks z#yqN?4#<4?yeac=5t3C;5Qr`bX%2E`Bq56Z(SWjPFTLtAKgL156q5 zF_1*U2thFGG*>x}e_XGE6plzLe4!7PIZaNULg9Ht~L4K0hAluNH z5Vfvf^)$3-ix5l0wSimlN2Xz5`PSyq!Fo@dz zZ=tc|CUFnqkhMa)5aW*|`qIBN3GynWcg(xmyI8`lH>=22)2rS&2AA!<2<#Jd;m51O z)u$dD&@n1wHKYclWPi#@v_rpyoEiiW^ZjFtTHhJk#pe^(M_6!>of=Nfq0A9NbtSM=99-> z#+yp;E6thcMpz!I%*YR@43YJ`ZNc`2J-^8s69y0^!NN6%GCdP&I_XGVOA`cKz-`ZV zWroX^wBmVSR3ds(-m&k;RnC6PfteRN#(gQS>Re@_Bia8VaYeZ*7q8y-BT!PuD|j=&1R z9<B|Hz{(M~ z{9s-@mv7*ZoJyXtpzQ7Z`pJk8F!bl4XbUJ~i8h$J?0|d2t*bRK4H5jEy>NRZ3I8kO z8S=#G_xFP$xL~kaxf%-U<0_gLWDbZ8i~j%iYoos7JekZR<0sL8a7qnLaOj>L$S!7~ zTY9*B|QJt)>eC%SB(kTl{7nF3-CD)Bdyc4*SMBzLKDx=03O3 zmxO;vlqksc z!}|i5iZ~014;)?JBsg71Zdn*K6Xk!3CH_I`God{9 zOjNY6H4qyLz#-X*RsSFtZhe${e6ZBm+2LPd6Y0U=6m$Xy%bXJ(A9v8R9()`MAZp5= z*mZe_Dqv*#YD=Tq07@cbKywZ!eap9|z5iPfc@M!a;t;52o+5%yYAW?gU7e`@5thF) z4{1HJwp@_zlA-=fx2C0)*uUoN)>~$p#f=IcVvonen!>n(p_M3JaCdNL+$&{ngG}xi zb-^z@LnMLh;In5^Q`261g+=-ydaBNE$hS2A(&V6d8gXsw6wi+N%UpR13%ols^L4~K9aQf0*D97z7drdkR)GpW6o_l z^K(`5c2m?IbR#o{{6I6eHus4+od&D->0m-5VyHC`mw*jpTVQO<4ew44{9G5F6}49# zWfN-Dr=Q2629#=8X@36%XLJOt9p#Q~gIE0Le^!MUhIFaty-w>s8sI14^y1;?8y8ko za`3TFkfh%u%YlouKB>(XUgk^~-HBv+0em4A?PP=|PZ zV}0VN#RraRBz&XFcHBE8M}GTe%|WM<6RQbOuz~DH@73AA6oct@-?~b{ z*PZ01U&^q%d49ZL%?hvNHJj`qv=6yau6#T7(Y7HYAC^~8xG>!4#Jf%r27)4`RN^&y z!XI@VQ)M2>=tw`0q-N|J2mFSY7*v;q<`h*7?IY3uZW!IKYaKopN$Ao?BK}X4*J1zA zbv{Y{O@pR)Y~6d44=fdMOJhhOTM1reZHIoPndE~biTNpbuFHuCoq z%aGZ0xIFsVaMvk3+jsU%AOXOx@B!#g+2L5b&RkpPSd$hT=;x9F{bU@{{ae{uhbTG~esro6v<`P;TG`&HjHkfmMeX@H6N+`CLiY z33GDfzn_-DCd5L8Lzx_y80#7aNbl`7XvMw$vt%p}rfg6E+>7F-zPD?LC(Wj8_c#GC zpy+UdQiZc4@UQoVa!~HT=tswQ5GU1*<+2yKZ7-i5PHAahummnT7oF0nPb!{MJ;^6v<|Gb`BPfc_ldIQH0GKsf#A1ci^?x+r=0N{lA}M zBL>jZyh?#l)ynA*5fSZ?p58esb+~K*uotXUT!xHqbtZBNktVOu_+K~*T>iwm69qrB zfDLlKK+Z%0Ob)7eeDtyXQr)Q5PodQsaG~eC zz!S9)NuDjpm+^gly1Wx3#r35+Hs!OmxHBO z^YS*7h38vT>LL1<=;w{Az`8~6FT>)8b&|q;PDjG-Bmc9RMYgiz_r5H}L76wGGTSnQW7 zyS;8_4-;fdtbK>edy*>2z&qeYvg?Ph-Kx|ZrlPucpZ>;2G8eVrlvl|yLldSjii!wD zK;9xv@wrBbG*92TEasf( ze`~6m>uZNt;ze(9|F)lDea0;nx}xS@lE1=r^rRmaG3MH3h3qt{pcKV;U>w_2-j>HhUm-m{Z=Dp zen_Suu)3`0V`bM*{WzTll=AX0PwrQ3k`tbyE)tD~ZxiNX+H4{EEvU==lDn0AFSdZ$ymD`00r4I{T)T`fNWTpma7T7HBqLJLG>=UU#lV(YaQra{bAYXJN&8bT92!Oj|N;nIpmc|l?+py zr=_`o2d`4a`5*br@>KT^S-dJe#Z(aBndj-5O*aeGpJuSv=| zTPLkrEh?P|B>P$ufV-v#?5-$5I~j}FTZy?s#fa@8s2--vhFv+r*o!|aVn{O2b$wVv z%N@FHTd^H3M<+ivoj+!mdn!u%_wsfcWk2p2g&y*FL{53edwAfT_~o2+eYSLf)NyA5 zV?p(kf8DOx?)cYY7oBZ1OdIXZo(Pp@WK5h1_ zYN~bIL7hw|Iy|#)#&mdYuw2T_yx=1u$QR>IEN&Colzc`wv2_drR5w;5!`_XJ575nn zCpZC;y)VYmw+Xjy_$S_>j_Y4YcA_Hchnz~ot8Z%6FD*OnpT(7wB41wW zFt0^CG@H6MBA$`*>9O2^;^5K5>471GB_tHG+M2Y{&p27-4$Pu9Gsr%Bedp1J;_!Gp zDdIlg=+B0`EA?Df9|>(SH*pHW$ui0`0ISY2a9sohdJwkgkG-KokO&m@58POk`^AVW zC!E$yZM34%9k*%cL-w+IOPj*WK2v=x0e;5Dx8fg&{}RV`k8QA`6KpyE5f6!(?Ew^Y zOWdLeOcQ+LMj-O|!Tr=_e<7Uws9~neMAMG?<{?-1ZCbNRXG1{!oc|2LG%XjEw_NJg zT*YUx37^;_#IA4+?OD+KCEiiHx~-91-%1gYy3DikuwN9VW2d%ztfEl)OAM3SXW@~H zdi!51vrK2NzivQZ6{%3H=UG?X*3*v23IQ^;9%md4mx%Dfa+Vor1aO+q;b=?iQfDK* zAwD_Zu6|%TqyFq?)l)hO%9T0L(^q;vU_A>!dNznx<@#-g`iE`tMr1vX77d`-0QmDI zCD|ME{S($8+K{`#|MJ}t7H9B77)JI@)F*f)t^>dF2_{COWg2LtwF3%IXsZ8oyV?Go zUA=oPoWAr_o*W?>tC*fLsuTBaT)Y4{VN=oYhb+)?eWF+RK~bW9gpMq2f@yf&l*`I@ zTS--+{&r3qAl(Y8k=@_2;C~`btrO-M9-rAKT5*nL!GA1cFaFL5y0KT7AD;=H(8;ke3BVRCm{1fNP;#!_%!YFz4;<2^r-KfXlZar4; zV8eVtvCdO=koZsCNDcfgbe8hQ_B8`<3{5Py47Xh1su#`S;e?7Rmw^cy$7ReEZ!#}`#LGT3U5AU#2 zZ05kwI$r7Ps)w)Bgy$JEokowRZ=Lb)F@IK$oB#gKKHR2#1xf3mwafcN8mh425#;f| zSk3=*H#Lm}deHShm@Ig05p?N~aqcv904KZ#t3*nU=l6?d+o|Rnk5Mdq2Y;T5A{)P4 zll!>7Qtu(;qMYJ5uMP|q65>9}SfnWBM7jgV<1X9IscX+DoksCZ6gKZkisVq+eQSgd zfTIJdGQh<~z16^N^m=DFdDaI}(~Ez;1Elbgq9kGx95pNPw-LZfUZ(`7EvfsM+{ z77XNBuj4$SuAEqn=@UrEg${{cU>_|KoD?07h>gpA8jeWCaJL9T^(EZN?w~?6n~e4~ z`UuI@fD(>J1=S0SzmS&ww`Bhp>LGlwd%T+o%K4F#5qRWvxxdU92J!tRZ|TF}_%7W^Fa=EOf1D4wg#hGQ!#@!Id0s-2^T zM>^cXpU8fVghbAZD4R1)#gC65@u0_kF)<4@qvc;o$68cC#6lngNv`|4hvE4=I+Q*OIvx zUx(8_wb^0r1mrknYc+)vyBVp-Wcx6jBL*xfB;V+JwvFrW?9&C@l(BP?@ls)^lP{EY zt%%DmILC*Qs1ILVNwJ;rcG#=jhWi4l{Fj>?pFkLkQHRSys+i+E3>e-ZVq`xVw=4De zka8Po=s`jxv`p4?1ey0<2h9t=t}|@o&nYa;&8^-A66-}-QX=+n&_sOOeDhY?e=u~D zF`BD6&vvtaJD9}@kebZ6;s5+5l)&qt@B~$@`&zL7T(#fyi`3veVn+Q`s<7 zY7Ys=xOv6F*Q}HhNb^YNj=4Q%@V=ypE#a}4$IJEQrCTwS*vhi|BfH$&RG9$fk_&jy zH%DBl9#}y1vA{7ONo{AWo|z0OBqzta`-hq>)A*(XG|6F!jzQ#Zly z;D+xJ2u<@+ZW)KiV&xkg|A!PIafJpH`$J!6%*57yid1xqvY_H2KYv$RGY-VLl0}^T z@{aDKn3`Io#{7FF7Ovs>uNhj>>VZ!J)6nLqZb}E*mFJ%})*gEiH0CKPd&DW}a=U1+ z3U*C{w*(vjE&aUuPzg9AnXRlA=)Z`nHc*>~KT+6Q&HroW>+s%9xzyUH}<&C>T9)ipB<2a6W4K@3R_Rl!rLF)V5Y^3+_yh7X|IieDtW>hyj z_;uBo!AJLltR>XB0ymhl+hOoa^D+y|3Z7p{)HH*vbiV7d4B5 zIiQN+&|w%<74T7xEn+paBKmkbTuraSFMd=V`ZI-DhB<(_{}r?;PPN&+sygbo>pk*N z`6K1<^0S>RZ9*OFT{ot(I4OGvCS|FomzdhRufJ~;PwrONsYWR@S89jxw|K`bCe4Jz z5E2>P0mrN8SDF0J8g&;`A{3N;IYQB^otQosj&-2MrOWBwtf*eUytK1o2->nP7xw6n z>t#;z24ib-bR%Dk;}Zbtk5GZ>z`+``Ehm>fRuVh6zaB0%>mcuErlMZ3+<=9HB=xaOz@R*p~c&~cUgFrLU&+1#U@CT6sGf@x!n}0Ub=HDslfNneH4rUj? zZ7a&cBOXFqh0&G`scmg!9$Uue2eJ?O#q!45yd}=tp$CnmZf4p!SeZ%Ar0wDjmimmTjdZC)jE?**Fs@e|@XFa&30rq$RU9 zn2t|3Q?M%BZfUd63>VtbUCV(ehQ@mAUV7fGw@MMxnoGO#s9*QQ+_coRt>4p^M3Nd!A*LeS|<>>Rw3Mra$0NJ9zo#9>EmFEv;K#9EL;#d!%I_4#6A%<{QIfw zHpBA~&EP+kRV0bfAg{5p-lUSA_%jU+2(_(w!kn3uD_)7<#4C0s?KNQofSzkrPkxw3 zbh`qVGFXOC!oGNG{qJeadfMF|z8++}KS^EsAbI=#0<-v>4*JO>;k)-FvbVu1w=YPR zJ#7)k_Xo`h@eiKu=bh5H_{W>h|F9oWhFW?1C?FVpKR)zDJWQ#NR*=k1mFL8LtaMzz z-r7N=di$r?;Ub#E?pj|u@<4rUZSHTEI3v_pUs?>qmfbadFPqfWGkzl?Y{>687kyc` z@L0hB)V!@2WU__cCe8fn@qV^0($oC7r>wYwrkq>RFG)|O#Iq9d9#=b)t`6u@Y3*Mq zet;%h>ek}pe+$2bJFAjRgBV5x>K-Mu?{wUZBgF-vQXF|moCr+kZ_t0{I^XFNLSV=# zGV7Nek+kg5l!4kLM84%WsBCISG+m2is&Z14Ng@Vx#eGq~ci?4&Ct?+#?KPVDWN+BL zy-t6-0Ri|{^Pbya^A~?B`YnSA_0mrTEeVO{hmo(s^wcrK?-N*E6|yQ=kp0PLiOPtT z*xElJv_GDG{_x2PPpa>U*%5#kA04EBL1Ghp&UlcN#X@3nT6LSZ^*Kz#Q?!(D?D5rx z=Mu{7O3Idh$Anqw)c<;TN~>DNzpr=wfe$WzRM|uwBI++?NGOxVmwj5P?5h4nn5sTh zeMQ`HN7r2aig`0+sKw%uMW(9A8f2vFwdkY7DzTVR+4t8bvKHj$`{L#IS=GozfaE?U zgrrkl8c+Ss#iJXs-SjnT$5|@e5+h+9K@-5+E?LfEE3 zX83#OBB(ObNLS*%h5S6qIkpkdC4N9@+BY28OJ(BMrR$NtudTLX=>7;Um1ja~}Jw&WGM(g>2fTPchmZ2~qulBg|%y){_%1P3-raZ7esQ1#8PlAfO3QqU*z zlkkE|Kt01+ldsA{X0pt?rLdw!L->h(7_^QQ=_1;$V-|P9_!y&XihCMk4^%>dT1k;y zPnl7|4)srMEjf`fjd(02|7<&`u5*3*c^em-OWtf0hAh3CNt7BjK8)`hFh=utK>Eq*_%6|ufS8258>3b#=aww>WTQsH)|uzD8^mJ<#{)j z=g`C)?0HV8ZeOL@&%#t{(i?mEd~m-E%Vt)a4%E;Xf3*>=?S|{5T-ZQ~?k>R~fFLWR z0`fJQT{yNgO2RDyKjF?kECX%lH=4?Nh0!+U07K7!JA`f8TNP$Tan>)0oo`$ zu;}-Ot7rq6#o{v`mSs54k*+KR z*SaJqPE_t7%UofQ$ARNOaQ8;GBmI~%XPzWyUi=hjwr*~|*QlQ%J>?JV=SQGJL(6%{ z$8;G?$9>D2GRShccf~spLDd`Ae?H8tFvBY)wqqCHYcU=2Pu12Unlp32VtPTJc+?zC z7PT<1^Id{vi!SR4f}hg|)HOLvs+f5&mK(*A(sSs2dGWYS-m+`B(Hl8wBg{5;F(V(t zvNtE*ksDn)&ZHwgdUTyV;F1ra5H=+Cq=BVjBQ7>#q9-jI@~bjsV{qN6qEm28 z1c)QmY3;jivu(sZc2Y796TIPb}Hozg(9(e=Zz!F;l#KfOqCewY*#&Vbu5C5SqI{%+FrX$_WkLo__#u0(?Z zp($_WHA(f2$Ic`8DLLG@BlRLXP5e}>4fR)GCGr|(A8dDj?;G0Eyu#VpH%p^5y^jM< zfPQhFAv+?%XJtqNZZos`sQjXq6QJ>Yr&E=%t+QEV>sJ}t2k z&SPxQW(*TwKJJakjoneYDbTNkP^NnZODj$HSmN`9O50ublMj~B{CQL4RlFQ!e%?Z{ z!#0Ux=JFaR0z;qi^Tf@8AvVO8xp#Q7%T&@Y+zV{J7+`J}Z3#rl_|JdrtaCR02(Ea; zQr*qbn%4%Ex1$9*&!4YkSWw!uX6MLF_u4r8a-hj5@u-2qd$8-hAheqW{~id{cg_#4 zR_`DRfXQ__-|2`8C#7o#o7oNDN4-9|@}`gDKYV%LX4}RgnyxtZ4|CKi@AlndRQRv` zhcTIn7s}wl&O?-L!7<-q+|VekSrR3@NHm65S}h?ev_6}+=Wp)e_)*Gjn4i%6AXQ2; zQ?-jnS#wjcyCgI12bqQVNtb+D{z?TG7!eW{f6B#?+#wwkD z7QUaR>Yr(M|Ild?5yeT{@uXKxTjEJCGqp+^VGPK%fh?ovXT2QxvB@C;*G+<$SAYLn z4-ClS@7AL=j_(TdI!FWklb+H5w14KRs;7%PLBnVV^HM zmW#^;g3ATd!NMy|VPWsKO+zQ@kL3io%YNOSIYxc;)@{P@2uAriHWvBgmGHCe=dimw zSZ7bIT&&UMIfg3^&UrS8$K}L{-%7JT8&%sWCFOz>ZFvi^GotAJ5MIWx?DS%!nMfcH z`Afz@tlrdkf1^_^)J$G9y%27Uyf)m&poS+yQ;C;o|b~|lk?C|;_ku0j^w913S4U*4< zc#jOuPSQNoad6fGON)p*z@MaV^F#arAx0=zv<~&Q-z5t{h29WMVwWT|Uhe|lrJ}q? z$30yI{S(7C9)uE!{4y10IkYDI0uh**{4*UEH|buIJ;^fDkt^z+_)3m@KkVbsLq#c_ z;b^*@8moo5f^v~`(rY(U*=anN%}K9lnkWPjczu8=JA3=LGJDci&cl) z8kFa)?%qlJ!b@{+bNKmT>eBB}(@isVi4b2173F>olS9e7;|J`V<#wfiaNQYHacGTC zU~q(*U+m-fgAtcvFG~4z=dty662vX^uQ@I@w5aku?~KuY<9xc28#M^hduD}Ca0NUO z&~7^TQ{?<7iudj2s}b@a5Xkk%@%ZM7t|>&VtuOyR~l)7(lsCYMtJvt51uqYhTP2A}4gw zE|*IXuv2#1w#^&QLNgoAht?2%FML2-34W*rgS)H0jS+cc*g~WbU8Zsm20M@|XIoJ$5dz$Xx4^7Vh?d@OZLW0{~mj;W? z-mrB5A)1;-n{(v6(9$ILZLhSN)4pE9*8V&UcpqU&8i32$Sa#VOSB7fk;*|BN+y3p@ zJ(V`LM?`8|6vTI&-AaNJJH|6TY+*NU75D2P&yew_9kPMnIwxy&IqUwHe#!l8-~Ms^ z3KH&QWdj}zgvis~%AbCy1%J-1$Jqo<8?H&PEzb~tkRIl(;piK#g>BR!|J___p2$Ox zN7lVL`2M7s>!s!xiz8b^N{IjZzLhFq!~bQ+z#;RzQB!)KjB*cCS#*4D8lq#UKI(JQ z@(t|9tKOkaY81Wa>49sS&RRi!P$tiSUP~4l%ym?;7D(v1D-2mXM(~3ZutTY>eY0Py zDb+Z)3+;z{2Zl!#2>l<1ZEeL1LQ)i_chV+Zy9IwpD~BiMH2iX#Fn97Xzgjo`r^;O__!ie_wPR zU@ChQ9sh|c$T@wz3VF9b7wVZ4SKs~I)gsx+Q%i#dl(dKvXfun&U^)p6=a12Itx7qo zW1-F{9h$w%bJP=_=E6YXX>??hR89rxwmdL%NueDxL(YcMW4)QwIP} z<(elh;(Web%=VI0r@f2`+i!2a-VuX7=~s&dK4XK=09KeV^zfOC! zS8n9nSME9l+>si2-F#QL1*asR<*vP0XwJ_Xaxb;V*-F)tx7L1Kg+%LMJ70OH1!r%T z%EEc^MwxR0l-iA$V&BQ;kHDC|dOt@+k#8@~)9=3#83zL;DECd+h`+Z@xil?1KjA2WxJtU&3V8m{>2vrB{qvS=h*7{Xi`Un|n<$bp{BCl} z0hiH}&$Gaj`*P8FM#7E;%8si+l%enELeV!WSwmAcsh8Yqp6Se{nxp~NSQMGYTBy zA9}8Szvq<{z@OPo{+3mHF+2DoFjvh+{UK_(`VhT}<-eB9z@@MB2*bvhWG7}VLt0G6 za+K>q)HW*y^oJSx?x6#X;VNh4X(j}#a`4Ofi?ZLz@8_wAALFejZFX}FU)m{~Id`f% zU(qVlnARhgtY6Mb*Cju@&F-eff%~cUQ5zc`)!a~fi1Au*Pcv^gjI{FPXce$&E>QA{ zCr-P54&CP3D2LgcIA=9;Q|=ww)2S|tR2p4JZvvU}-|oy{H3Uf~$^$08PeG6O`{af` zi_gQbZ}|D9U*iXtaK5x~5XGI>@UIU7HM;$R8ub3{an7F&UG%gf1_?t(njtqEY9-!!)m_ zu6%`CMiVhApA9jwm()kh)}0D*1`^K1KVMo7dG+`&FFlMZB-A<6vDSv-hcAl{WBBU8 z(23Osh;FCAu{f^t?heRmIVjy>Lzk5hXt_8qri0S91xVEY6DfSRN9hhq=F1=e_FEoz z@Y{>>HHB3v+{Vq1fX-7N8Ry(MHjLH4874Z{J34J#9MdP&kp6FD|1IWjz;cw&45p|5X;qf%x}M--fE8O@I)ku}jr(4(k$B(@ zILMJo0r%x@(dv1t4&iwv$Y9a}jnAOh#M&NpsAO{O3vr)+RBY|n4>f;vnfcZve?nvb z`FA7T9TAM5IVg+r|Lc$*fq4McHV&ln&RA@WKXjB$Darnn@@+|bHI+-HI7xSO%w|k% z(@AIXq2WM}?jx)^YmP&SWumg4^c*NeT@8{{=Rff!N}Q}7qx5C-nU6TTk5twU&M1$Qr; zIkGuADNcWU`LE?SEP~s4~c)8J`GH{IS9m85Uo$lF9{VJ{cr}Fx&BPL zpH$7r9iN4Nk6ldga(zR* zJHrkxZmA1Nspm~P5%#T$s$m)}O0b-5O2}stnbRq1pjNH*nc%KRIk%dbAi~EjSi0Y` zvZvw~+1G?PXC0=jn-v4`Rg|IiZDg#69jc;bC~M%gDANdWh7S{p^uV)OxotLH+`)e? z^?BTXN7{1JB>-mwm}>Q^zPJLxGuvp_6s43e+xzdj5I)tcJ~C&!u?J=l_T;2-#`lp|(R&5p)nnK= zU%a+S9Xv_VgS|kqrIu~n`=j9CDL2boUMi7dKxq=`(2cQW&{eT;LU-O@K$BVYhY9q5 zB04usu3Ay-AJ9Ad%(7R+M|LUl-<&PamJkxtO93q(k&rMRohgYxE-gW$4?k_n3TaYW z_V*?gQw!4;RrWAA!WH67xYaXTPgpLNgMeDVhpDJylYBA{>gtn8HLCISHxn-MB%s_l{fUH3m&!Yk01@z65t;L05(9kS_~5#YJQ z=zI7*t&E9fSJY#*JJVq;_Ef2gq?{QbaOJE@T%3G-PCj4RP{-W!)NQeo^#l1uq_rFF zyaltF%8?D}X~sPnyhc%#%R||%(R!%=nAqB*qDjrzr2}u}zd)=(Lb{m)bAFk1NrzJ(U z9{$WB%z2_B$GEscm^nGSg^kofzm&EmgD4Zfj~Cd_uReHZ&JXe`wj z+PbYD#mtaXU^}YG%(ohBq$voJDE!q{5_vJx&zrod7;2hr;PP^T5N-C`_qbW}H^~*` z7Ax)yw*DXnL=pqGvpV>1l0pM}ZkxRy0~%W8m*$6!7_3(FuW1dLXva(CSW6uic`)Z@ z%RcB38*6H%8V3;yUK2-jZM-F6iPmHKu0+oH0SdE&Cs{EIAGN>jnstmO2gr@BF14YS z!lmO^G(rwOltbqO%ErIm!Mjqq+@>SiK+{dzn8wO4uf0lc|6{ZPS7_WBBd10S3r{;ck3rd(LSz@Jk;7 z9(G7;<%AqB|HZehm3OYC+PiW|gMXpn;8}b?jr*Lk)lcyCNx^Rj8o2~FYK~rO6`UXu zya^w?=^tEU{BdZP1E-4k1j8g;YgWC*nf4qST2@>IN74a}|J0}BlOE*6=<`5IN>SKR z;QPhqKr_Xs(RQo7x+4nox_8SCHOM_V-u@4`EvGidN8cw|uX#A=jssFwFLcWXrCy!l z4gbp)v4hzHSSYnY&#%o}TBzzKuL8vzIOcy61u6j#V^B?I)e!Tet}+Qh}*2B8%_lRxnE*1dg4nczB55@OLPV_-@HgbJC+OkgX5ZXd`QQ?5*Hgs(agC5=87Ps zXR`r((NCA?G8F=%=zwS&@Ow4x-Mqj9Jnb#>Us#)K2iMcXp<%z2&(ea|QJ>7M-}AlZ znj6gSKc3p~-dQ>vjYVr5KIZf}M7?fqr!>aHm15=d^T062ocFAl>nt3e z$_brry#>C@v-%gO2=I(b^FO}7{72M=%Y@f@MhhPPY~JUlK+g#{Tc^O8+n$+U^mq32yl&77QI2D{Wo%yt8nqWpXhej!eLB=<`J$-=f3NG$BQ6}jHD1EjOq8$ zr5f#vZY&~!a0=MI`J1#Krin#OxiHn))?m06zeSZo~bvk4Tsy`NY#GRshriKROo$5r?_C9QUkr zJkt+49YIqmnS1_pUN6n`Lgc3b4WKP1V{TCehA8zJq$6w=DLh4ra;MG1ma$ z9J?>zCh0W)aEcoe)di%O5l-XQQYAaa_uzQVuAnDBEaa19G)C4HT{q0JtN8kkv4 z!T+R6Sl-~b@*{8*cAP)4AH5sN;QGhaSD99mOdll78Cr8ao95R=gt!|19*dg^;FeVV zS(j}eW++PWG$O!rYAxQFZ=$w)+U|6~hKp85o(hfg&wmwotKDl^iK#38E`bkAG`7bcw8gNKV*;hm$x_1&R+=HoOp#5T2D@%_!MOEQGMR0=6u z5A4}q^pd}=hzy~&f9qXngCQeFDBoRHw>riT8`e3k*zRew4UWXzyyr4kl^9||Hb-)Y zbcXD)q?EkVba>A$f@0$~cz+W|GC7mTY8)5=M7 zS#4xi4%a`hFmW&Xk!}p-SQq+;42Cw1f5|p5BmW!ZwTtyveuu~0fL^_q$JfpE9B;9= zr)v9%Iz1XGDQ>(gO(qxR7scuj(oqY@^}1Xz9N_XC4m%}ii-c+m&S}T~|0C%tgW_nq zb#Q_P2o{_`2<~pdEm&Z2celkg5G1&}1&77mA-KD{1r~SLJMVX^D2g9jOz-sc^f`}p zl+632v8d?Vq;!8k3g@kdEbRf}SO%IY|Ij{wpHnPxwG-!=n;FRV*=Z#{+&6JxkY7o4 z^*v(O->g*>_yuzFW&Q~IDo54iG57DA@S<;2$5yPSt!pw%Z~g#^&!U1M2-ybTIA*mk z(O<^juI*>e7S20u4N>U(l497-CiP(_y!W8zX<4I!L={M8I5HFwk#}jvYwAQ-tjGHp ztiJ_ZB+`ZRCIAbItDZytQ0k0;;NR-s$>ZBR?eHNJ6rVwbEn9T(yu*+rV>}#5_T@AP z^!Jul=%TwQEFnSaW#8^Fh8@!gbrt6PNcl(rD#Ksn zN*i*5G}_PWkC@EZ<+s+(;V|N~OQMq~e_TN>V{{IMMg}A#P?`d=lH}YHJ1IW7-mB2W zh40oZI$#%Ezw-v}+BUPxxaggn*XZciKphKnACr2p3q;mdlXi|8zcMECJuCoLo4wG< zu@SmuIjNNlqTuG-{mTg@Vn+E-S@rINiJ+2Td6E9)$8DMXnubXP$32iQ{nRqz_p4zK zPno{n`1^w0nKbGWh=9XL&1jmQ0K!|-oJp!php3Encfm6peJaU)bb3G zN;whdUSim`+LzPKM7D-+FE(n3?*HI?ldP>ln{)YiH(Bq!A zTHSwbr?;to0(eHG9nX!i)X-gchZK_HOnQLUKd!~W|F5OP=>HEP`3Ef zZDh^;s8LkFUscsGsj`oBjT?&ZqF3{=d7KazrR`=u9p-+&sPk`0R``>}fEdXpTxDlS z3RKrsg4W#CqyPJ-k4Q1-0ZTq_5-}{|0pyPvEq*HnHl>ANN~aDphl>xqSiM(2{uYWR zJFoAi>lM@ylk5WzQJ+a$v;f`!gLahL4oQkUHwE>svizEsbmF#cJG$5QW(Fn?8$jys zb-83k3|JqQxMyrUU*q#k`kv-Kg-l!ihrm%GiwQYzv{M=cCMp0Sf>81dsMkRw=KZeeQe3UQoyCH6t!CYLKq%k^>Gv;4LD(T zT#YcF8LG2A$kwA;FWEmGOGI;9a~Xb0*7tt0!RZ?99`{9A?eszQds@G%Drt6{e(5a#sazysN1FHoiP%|_*@_CH;?buYzha-MhvEzb7=%Jk~cBonCrkV1u1()30 zU>|=D;b+yP(Xn;4I54Mkh$l$baSI*CydpN1RDjvvs_9dH*(7zQ8>IzQvl}Nw2mB;z z*tWkhd=+Ez{y*A$)>umokYloNqQ`ufh_2=uW+GFPv$`6xQ__8gE3ZUF#J@Di zqnA_1qwW(E=Ykz#K0{l079FE{ag&%y$4nmLLzVnULQ~E}eUdalTG82*UNVCfkkXtI z2rNH7r!zOsKxo-abyZ*rHwu2F)7?9(pQb@fTW#3C1RJ8y9|ryg14i!;B!rZJz=;Cw z!p>*+*rtMAPpeHbj^2Li-$FSgIV=7tBH|$1VG{ZQsXX;xve2l{vyHC zgaOt9XM^JMx|f_T_=mL=bx9p^z%JRqWS`SgXJWU$!xF)yxAtIFqRkl0wz>Un0yCuq z@l)lQ2R=EL^PiASnhi0j;MHW~94!A)f@U&5qI$fy2K4}ZV=lZ9R_@h^rHwE_UjtX` z1FPz-YeWu0tlKP0XkPX!tRflTutkT*iKjT{jXfMN5!9>`J7fF}SBd8Of83}JrR>Yf zHZ$E;B}eb7TrsTnT_5p-#&cDptw<){Cy$FsrHdqu$5k3i-yeSll*GCz%&L?zGB^US zBue3aPwfwBk7x?H4`ZHf+Nb?lf-ucTn3E%djeCWS+DZTMv%VQ2cc@?&T5P#TWm4b_7>yVYn;El{o7g1O zV4oguPorSlfuNY#n&KKn!@YPDd|1}Sp4Rtzo?rOxS_Sl*#L3es+_#^8L!s##<{G7H z;f;2vt}klcKK$nONu-4XxrNWPI^rl(U&sbpJqus>SU2(*V!!=dmrDzjVk3P0ceFu4 z1n<4gco!cwpj$lg(;n@tZAWe0cV+B1GJsNM^dN+pWO09V3R5dVrYGl9zkjDE5H3$6 z;*9$+ek~ynPqI(#eu)%AnwjpeIQ~4mFbf8j4zhdWsA%y(ynACiiq|1B9|wzdIggBOZd~HQ_7QiXhR^()@$6^V+HdlWC^pZ8c zdp~0T^3Fgc=rQOQTzUOf)#K}|2B_`X+>WVd)scz(uPgf5NbwdM~8-XPhA1ZWn_7nK_54-GMLiH)8*5`I@zczrYm+ieIp>%B+-=ebg8ecbp52%0a@x7EBPz-(Bt(*h$^U zZdk_`zXDscT=T^7KLcVLEP-1_>BLRj4i7ULVdHbx)gZwZKi9(QPy;Ywz!XKB>QX|> zV>unrJfAP!bta2J`7R=I3LtTZ(?7OZ$u_QXJ3Qw04^(O9KAbH#Mfu&&W$*lYd-l-d z0h*ep>1JZT*K)E=4^n{L?HI9R`+*jL%paZkuTl7k8u&voLo`N5I>P=Ke})%+{^WUD zSDMMJ_8{b9D;!#49Wf8h9-5(+Bi9TNbbS}FI?4=N-Y1ucQwd4Gto-^PUZAYq15EmG zoQ#0+2OcuLh5Hu(uw1P%qvns!&TseI%zYBGUUGY6s9dT^#jWR*(3}|yrg(c8!Mxl= zZ5<4v05(7={#Fm0H;Rte=WuVg1wB1JkKm42Wuq)b83C&jmhkgj-FO+No5DXF> zNXknD@!(7USD25w6odBf!rhnDy8s!e;So*{({J_#adN?c6M=BehEKGW8B;TZG{H^f&Y73e-#7g9}(bI(u}@O`B$oC4A2de4ZGnS)10%q>v$e7`Il4^BMFkHw zD)k!ACM4=zRRaW%i5oLbtCz=lkgjTCLRCpYEdN6J)_QsRVuukg095C1Px1UhSh{1{ z9yc6sqKhpyT{{w33}Y1vXoJ0X)2V`6$u)ut$o9tcsvGmcO2Wo+uELZ=WTjuAU|(!e z{ZXJi^E8#p-Cl}*5m(SlU$lNKq^+8`I|l-uFcP27c@eu#s~vXeevcK6jx!Kk2_ic{ zyHV={_iT}NburUSZ0`Bwu{X#H%q~;MLpM_vuXn8JRu;#aVw{%$vPG>hJ z@L#D1(qKW~StH|jD}(t#W_a%bmBUlDE%V0~Dh2;Q+j415gjYd(7~yf3%m&Z}myMKL z2D$s*Rw}M^;&(-)l0D884e#|0%+ld`Q^x0>%2#5zJj>y@_jEsocs1R;=aK(Y*7!a3 z3;-;Wm#$*$`0jrKo17?xj^|_4*`(xZpFXxzozCD^u8JLiJhdza7PPCzx@!Wyn=JZXuM!=t)|kM0H!!e4n;?+Id5_IXrefkV zXQ;{B+|tMIyOi3{ZghOtuIT+wEaKMr$>^SUvtKmXYCiPCsYjLrbjR*=FYe2S;Qi*A zl$I~~4O@@dw6UUAht)KgJ&S`kAuaU=jG@bWmY7lL@~8*eTOPr{l6|%~dzE>LCc^T) z099`G+;s*&Ub2o?M*}3g<0y-L zwUOq;YiNoqazku0cF3Sg(;MwG_tYyT{QGw=mM^-7`u>kGi1(Z2d0u7Sul9;g%aRdA z^V+o&clvn=uVQ_C2_SMHj_tZvWKh@KuLYSa{fnAfsJ@o+zMHv-Qc!T1lc@E>RMrc= z3zi0G`3dR1x%G5Y>~3vD+rB;2%WiS-u@DivW5VLgh{YHF0#pK!sRhGW>^KwYdTVy2 z;2WjzVtaHTneob{=}x*PZZLB5p;q@Wq&u;TmWw2(UjIhuHTLe8MKk#sQW~l*WC`!o zTRnA$+sC$^UsL4Goar%y*ZS!#l2u`X;Oj?iKN~=~Ol6%OyR`V~^8N!B7Z+#E z-L)o$tFxZ-#->IZzGB8+Lw)JuEHBvX$@Y*EYpPGruE#4v|2q#EcN z3kt8!NWSeaO59}vBxKMI%~DMn@TQ*oI)zs>2CVWLPioBL#c|+%rUF1PK=E)=c3W_b zEPiyIBT_K`Z%?J?s$kT?%tCGsHnSPp&NMy#zEX^=e*xS&OxT(q;_Ik7_CzLFKf0l$ zJ*3`4LCx%`bO3{2V*7V?;*a5Qv|*asH$O}Oq43G(tcO1^+@3>Eaj%&?8x8maVJIyr zY$!{Rx+NixZ*9tM12mKXv8=4C)!knxxy_nAsilhhSrjA_hAto3W;XH#D0VQ`9d^|0 z^y&k|8TyB^)=TGCH(Xc7fLD}!m(~8K@K{?bNu1N#?e9vPa_clgmlW_zzt82Wq#G1S z^p*a_B2ftb7t!?{-ia4*HLXL?+4mKZWT;rj=%>bOE&T4Th3zS)NDsKE^wxehr4p!6 z{!Q9tBtHk>$#}_zyU2*k9zk2;qvJwAztcaAvfUxfx}XEYDk?)M0tO*ahw?m4xB|5` zVNKUAoX=C3srRw}Q!za={iuN`h$D-9Wi~*;uu;f-sOm3wo1*viFLE0s->klx;t2Hj zSt*4h8K-;7uuXiLvt99*Ia*_R zC|9WW-r$8yP8PbTYo@?hqn5tW*@5f3IM!^S%ZwXxDs0S_x+B^2d)dVLPx`XG)&5jT zu&15ecs``>jt{6sbthl1s>&jC#A>x~=bB?cyN1Fo03yA^_RQTDzv-plo5d@1qNGm5;C6 zPQsFbZx@*%fY|YiUwRmCeCs#2LP_|3$;nuX(H0^zjzsj2w3R?a z$2YI>9Jm>sw{P(2gw)@ou__@_W|Qbuv-kZDR}kDbn>8ziyIU}%=&l8Bkv({2p?r^d z{RLzFtwmi$SL??;3)1Y>U<1Rz7nLBUFcls6Md-`z+3Tk-&~}ohyh-XbUTW`CtYfT3 zm~eJ^Kwg1aScW~*W)-YhC=H~L%pnpSig}I8H?jm8_gKVGt7(Qebt%r&v~)y0*{{m_ zc<|D+czr4V>c+W)j{wx2La+Np8{H>I3!9-I2dq3Hi>mKa_jWg%IZ-oYFrGsFKl+m~ zJRew5T1@bE!!hHwP>qY?BEnAy1u$s;veff<(JmLAEz$#p`@Qk! zo>Ki*YB00r$Sg;;`i&}L!RWGU`aDmhKccwi`T0L+wBv1BXnDMDMwn0XLoiOg?F0cf zYjzSu*0oG;2%uiatsCsjJmhiT&EqY2*~!UGrC8THGL?#YMmG?GUa-%jM3c=50r|Mx zdHfk}3&FT(VOZk{my!MR-3K|Aoy760kuk)Hx0Lf#vYfo0nRW87$_t_o%O~#CrcAR% zL;slnJW5INuFv&Mjh}{gfHw#rBeEJG^^vqkzN9(T*oZ!*xm*jq&W!4MqCqZZa5fy& zDeD}>36p@=Ld8xQfN_mYx`;amSryQOdcOZJ4P@T7Yvr~k^-L!h`U`T^hp#qzgFJ71D26#jD}t11EygpBlVyvn(2+lB6ZP;5@3 zHhF3#u<(kizRj~BXkn$C$$zNom{zQwA7tiv*FDW|UxsB*d3ToiVf0XgVqtAP*#Xk$*kB zad+M#sHFtH71@gM09-_{_{7mOaEl#*rmzZS(BsM?FLt6w=2Hh9hBKUh@?;9P^}?zl z1Tq|tu|$x(-fL(7I8Cct_r`5=Bx!y2!;U&%)B0d##Q}IY&?>*Th^DQ zstj>mRA0-!2U@!dP1g%0>at?0?}<%*>cC*V;T&~~Ih|P-$7=z#tuA_BDx7GOAO3n_ zI?GYxn9Zk^-Qpm3Z2Ogy6c7;*oS@irL|fNroxAZeED?T+IuK0A>+!Stb_Xcve=l$V zHi>?@M5DIFYbGaL4zzbJ;EnL#o}|q!kCsub4oTz_NEhGm_Zro40evVR8z6p4^`VR* zrSQI>9UZ=5$;16u0k9=Emvqnk`r(a^ULTL2wDSxwdrCu`UcvTYLbf&Yq3b$hfHYO5 z^|eIMgP<`h2LRiaFIw;SW3FJjPl$^;i0Se;!0Rpo4Xd;`$9e8cZeLMGzz=E$dYa;5 zXTwvS_{v;XgROE^@&F8U1I!cZPAsDwxql3jM##}81H`sHt%g#wR6_WdG}a}yy?%4) z=XNbPz-YHR)Q+2HVuqMa1%kAm+`mB)Juf?rKLB{`2XM#Hw{i(vZr%db?|^}iGMYAEE(*L5&sk5w_yTqTqyJ(AL%i5!C)Z~>rulWxb`UtKvTJRi?jcY z48Hm5}zWtgA_U0$Q{D2rVJwbBej8SJIceLIV_;C4D1t&`+% zcI8ggAVS&KRz6>-Ovc|&&UxcrkM6!=FBS3#R1JXN1c->4>|k;>`P%Xqy=ULebX)kL zQ*pO7w-{ZCsKwtgC|_1dS*D_)W0KktFXm$T0ai|;i&Xe0#tpDv?1jV@C;48o0BE7o zZ+U(uv^$6v5XM#O$Zx_9I4SrRLtNedwCgHwV%|tu516xmK%7DW&r9YVm9sf2$DNrE z{PQykEmmBkCAjgaVH}xiI^uUL9H&XEX{h?a$}Z{duJ7#RGhlCtY3UU;a=Bd%n+9C)@A#7BQ6{B+wSO+5{8iPcx*|Tu^f1XKsRSv`x>`-K8 z#*E?J5+qmY=)yHaJ^`~($I!;b$-0;Y-fva`iqcVL*1!SG&HC&J(e@Os%O;jhm^SZk zMY1`$pPKhuotn?a07Hij-pNtO_kN#&J#F8y+tC`_DI-ZBRn$`B=bUz57EfSQR8xE; z``ffJs` zZ#?2bob!77jVe@}-UuBXNX!lUX`o0disTu4D8cpHvTevGc!M2lD_Q>q1;fSp@;@ID zSzBE)_iA0_UB@FXP$TgHU3J;vv`(*NppLHKL85hD+QScT%nVJa&vqV}4U8|IG;Rxv zx+&ups^TBOF8$37MKPBUztEDm(DGrMk0N|CG7|gfBb)Klm1tpX3dyC zs2$k>f1-a=0Z|tW@dPmZ)aqkUk}zfk9$lGAonQSp41tdcwJh!cdWDq!(+#d5h-nlz z^iN(-pyC@ci7Tgbk#ryhw&G^_MoW|HGfr3j!0(%DmYFK$KLV-$=Icu>1byRF1byEue$}nZi*?WzJ&O8Ah=qTehoswxul^zYS^#jRbWE8R`VSD(UNu-zJW@zb?M# zdqjdk79A3h^=LQ%X3D!v^~Iw!WGs`3|+LQhTa)GZI6I#L@&FaQD+% zw0AM$mhLwYV6>EwtU}W7Ce>L5`(+|X!aHexAF=u_HnMH$iZ4>5xxEHlaO|rx2&h3E z|0@+8j;ToCe&Mfe2=mDvUBr7|1ts5iopMEG9QA4y2&ASUyBYd(DwO7CNonYcdCqCo z$TM1W+XfwulAIZnJs2d4`|D}%ck3taaHIO(_`+pOMF7>dt3No$+=56ctNHf|L>uDttH7gK4{-It`+%sIzh?{#G|(L za_cYlDPj=sxtn7GFa_%b&E6B0k&q->p%OIsB8kwrYKW@&QId^bE#6jBK|}3yToXvq zy8lWT=$s?xWIFW>MtpMcfht^J+2~^~uY@Lm7}Ct#IM*|5CymOTfJXg!=E*lU+V7SA zKVh)7g6;?+3;<&CE-#I7yPoDUr2Z*@gaImA8~x@8KwDxirUECQh^v~Mgnic@YHE%f z`KqaEK5N3P)0RE4!LPqkUK86{-}TTMb-Y8j)f5OcJwp@scQ zPX*;Nkf`;0Q8_N;|6WMn^@T(D#;Z^JiJEsST9M;qY#6dIFZS+*!0eAs@w}J$GSaF0jklm_$yR#{Q*EjxG&8yeWPdEeHLzX zmdO8DJN&NbqHrbUj}?Xo^o@DI8XQ&)Yq?|t6kH|r%z1zU_EI$t&?cEMNRD1f_j-$3 z1JV*F5rCZ>`MXa5s0y6XF&rE0e`akNwgd+g5)kf2zikRTfo(}#pGA9vnp8A;I#_)r zK?5kdar7uoKs6V{6ttt0`t!t2N=gb(zP5GT5#1*PR6vCVUC@7`v(uO#^?NvMymwsb z(j*+KfB-^A;3p&JEi4-6??3C~Fzn@$ay=*zDZ;PdNN_!8^^-+sKTanJIgK>@aZ=a1 zRizFd@o6f@H@_?nfvfotC4@uRALDxuN+iibg}Mb}B<}8W2tb8ZzRW*8ocr8Ot7iRhE5?Nv%)Y@YCTda4+>qEzAx|N4z{J& zT5M?x()Yd56_|I8sT6*rR3sDXU+Q=j#h-HA)5h38zbYldeE&nIv@cQ-VK_hh5^z_? z2U75{@mxV^v6bV!E`0CGBCS5tTR|QkTF?HGFt2p^-+~3|yvQ(5?2H$NW}GKxbX*5$ zs|*bmqg%!gknHn;e&58IV6U2R%+ah@i-1s%W31|MYz>jIc4&`VM5fQ^KS+;Xt$g#p zryUS$pWnZV{f94?(|DbM3BoOKI>037zu8CT`9!11Wt32scY%$RL1SJ zlUWS-55GJ~v0n;+YyF57vxX^_ruKLMNT+5)^#8oRQEoR?NB=Cd1l$AXcW8J4@%nnK za=;PV{YB;iagp?O>0wMX$~TN00Gnt@h>B#0>XI0rjwKC;^@-x zJtb7dKI1Y-siBJxW94!iOsVXLU_jbQGCsQy*?z5QYc+-0MUtWz`0+rs3r^u1xB?ss`RY-LMnj>=@SVqQ$3m*X97y<% z3VodZtBd9I^K@-8(E!esfRj-!uV|Et28@Fmj7s}n@H3M7ihs3eG6SUn(}sh?pU-#r5&@D6hKWL;F|iOs|M(}VJ= zNGnwjANEZCLa33&0$8LBfL~Oqau#r9^?~z7prIgMC2DiAwBSdL6GT6GN{E3jxK-sN zqUu4g_a7)aR?y?HXfji-vT(}|167vr(N#Rc7fIFVg$hvOWU#XIN{lmCkA-W(lucT- zP1@AxSFr;uNp@p2^IYKpC(9aCkb6Ve|`rOTbCgZj^$5es>bB;va@bD%+oXk4;bTUy6B9J{QiLr@9 z*)WYbm<4vkiXciN?URw@+nWGpe;CC6V1lti8R&FAn6RdqA!qq(2J=2r7QscD-y^EN z`F51|A30y%)Esj53pe20n`uqXh@ayAb^;V=JI108EdaT+sa2a1Bncx-Du0*Ojdb6A zt_G?xOxn5zzLQ}~i01+Eej&IxWPQu`QSy;cHacd=bO=!smgu{$P~iUCZrp-_EVvMq z7&eXaBNY2F_Z+#el;H*s-_3_)l73!{FGOIKX-U@PU1QvV8!CUPw4Y=g@`^1OV7}yu z<%17G(Iv&1Donkus$_E^(?2>R?m8ZP80X)a-scxvP+$j`A;K% z?(`R^Xf(DR9gR?ELJKQ!xh506(bpIs4jG68whLsjCd?W5Wha!#XuQUq>W-*rS`}wF z7keDcI6g^ay`jh3qi`$Vw3F|ufz-Ima|-MLCyl*EgMVSRCt0X2{}g-Qj60NPJkSuN z@UGX34Ikdqxqc~eBfp@g%2bsF@xmyGF?dJk*FQf|gTL$Qt9PzC!p}rq986-qGs)8_J58PJaz>tCdR4dTf5U7Pi2+-u@GD#pe9R&F<2ev@ zCDESzj|BZeZfYn2?}^5)4~Pa^$wLqU|&>s;LQgeV%LsVWS~%b*gFr!@y`lF z|6n2;3>Pne($+Fr(Chv|aT7>7>oXD<3_*w*2o${dI@lT+GX_mJyqv8KB9E89vKM|< zm+TLIIPhARkh$DWx5AO{W|p|J>elK$Egnd^&$>^&(={;QWK@h&~@+r9`Nf9 zl+EQ_)H8p96(mXuNdCbgp!Bh4xQ{%PN##g8SpS0;%uCN?E!7 z5IW=0(rg>>VwH@m7Uzi8FE5Sa0iP5@Q^}LVTW)~sqlt*a@JiP$dKreKpvKTS!tG=P zu!`#ks&t%ti&{jY3T7Ex-7z*0gcr^R2|RB1INxUPKu_PO8_L$X9{fY8YF_ZZi{UIc zpbC0fJ;VRl7fVrBOZ2a%aLrsDIaRSupc&E7T);|af*FG#x##oNC*7Y zA%aEA#k8en;1N$dz2-!8dF!u=i4>c+Kitd?%Oo`gx8g?ZVCpb=U~SSbXT}q!!z`Zq zSyCRryyKi-tC+udH}*PE;c=ET?@71deGdK}vz24sIk2UIM zZC`vq2To7$j4GY0K(%lB3S@22R_Z4a9@yH$d02~tL&B)!VpM6Jou@Fq|9DNUNd+0rk;Oh4v+gwX6q(9 zSosf89vcr?>6%syd4k+~W=RFBqNVH;-c(1>2nhknc(nxoa zCcKjcrS!JZ-8xde>^(?!sdwYa7y@QzDR#PiFTZB+1!G|RB-s#g#PZI@Eem$vRsrda zp_ev%N26Tz*wl0-^RS%eXt;SmTrrzbGvaE0Ka^*oXwLBy18*;=g)R$O|4?|mRxgR4 zYojYFvazPd5tmh1Yt6~Pq11A_p`N?ic#ca8LUhsF zWZ+hjufGMe8S0Kkr)CGk1WsKAyEA`dr^JK-M5KqCQu;K2$|UHa&keA8>&X!AS~nP4 zf4ZMhnW%AV@-nh@fi9QTCltyyI|7WHI~2}Fw-)_Pi--<^x2_UtJWG^cA@9W}W=#AJ z_sGl7u(%&b+7x%XF5oxOJ0Gy)2Vc6Z zgo5VsAZ4L}=Pp_VNqPEvZlFN@H6FFxiahYU?b@Dw(~}5*r7PUreqd z0bbBKLxg{2%3o+OKM!}mA9uU8a=5o+EDH&Uh=P2ww1^tk1;K?<%`Ld6edqe6V7%LO z5k6GWMcQ$-9qoQ=LEl)p)`r>d52JRj@1D395^>d z3rMOJ#~zEQ{`$C<5fHw>q1^E*`8<02xcJmEb*iv`CJ};^x9s(S1*;0G?;cFO zAeYoQX+id+fd-sn(S{9#9<~I3{VO+8Sf2?7-j$@bJ}HyIGkPO_-UhmN24?``KDS83 zYNQjnwuH-kHNDgoZvIo(tR6XLzjhksqpQ6$D8B|#b|g=TI~h72fjrcYn^3tFCX@7? zqkyi8PFZ32iVy>QYV1nVFXe<8iE*)mPi6}Bhc+AD;GHhN$^wUM{8}DvDHZl76SF$} zQ;4D2`rb*CfJg%A$?y*u$zjMAg|iJu3-h3aNcM)5Z&*;o>$SkS@sxExjgIK<69rwbt5f*R;1|Z#_6yffmuE$&x74)n zZvO>~4QC6wOpzoDy4?^jA?|s_*?p!snB+#IYugMF8tps@nOB@>O4H|c+UI@yXzHe5Rhn%$ zB01xutj->UIg`Uh*O#x3)CibS>?gt-jG_i8Vt=}`S&>LnjD7QVDj)&V;zz zy|LGkt`04ovIiRSR1-sOI*KT}FVoCU*PZ#@DmoK~Rh!cXIkKKLa?O67h@0q{vKO1WI0pDmp)Jg6=boO#+hTp?! zlOc=pTcRMN_&c zQVXl}Ojxl!z4H?W|IB}8QCe*uxS_qdhXb+X$|0&=V~Jeiof_}?NTk)tLGp4W*P0_G zdXOoo%vN(^zJ6t?#*?1WWu*9PIfJuul>4ZDBvh^_)EM^FlQCC)(Ukcv0INQein9Z^|L!sP@xR$=b2#^q zjW6I>U^KQJ;p3`o@lT8_Ev~fs!vRvOLYEIo;X32rALKI7@{ibvvEcT9-N!sutq z!x`JaC!O(THVJfqraB_Au+=S=`9sxaOCbOlKy)P~Bz; zMD8KN*dcYG>lllV=wJ^P4*A}wEPk#aTT6un{6r|j^J~(%g^seFMjxVzknZhivI@DS zTlKCzI67?TenLGGl2w(omF47KoYc4~j5OES4oitjXe%ia87NK%Dg_wrK9$w~3m{%1 z@0r~HAoxqr`Nm~>9UKhYU8ja8G{IkM5rtBD&Hr{_^a8UnKz#%~{e|^y9s@^BIUa&p z(B|dGZT5F<@7<@-^j7^a)QfYF4wxcBVTiFD z%v6~JDGP(t&<)EDf0ap!lTC>EO?@HwmRr?0ABSG^FM#0yXlh5l_89k|MWahqvac#` z7+}JEhKn%mCm4yqj&eI0dYF1D9BdRKvA444_ex>+A!&1(Icak}qAy`Ab@e$4A936y zV4)q|Lh&cHEoi|6ok%SrtZGe)edsFFK)Mj;Fzs_>lKanb*zx)WaOJ9GkBiS%s&4mb z#C|QZ%`cins>#<~ju2db7G#-L^txLL#ag2bFc*j*h+rjPjrZkFn=@1XXw9g`n1f#Z z&}W@%x;wGZB4IKwRWw2KxqEVvWn=9IS!z6Uld-WaYmAZTJR-fdL;4su=StStzoO}f zXfZ{{g_uM(f^Vqksb)^tY@-3>s0ykeh5C(WTq40;9tZcxzMGylTP-E}N?aqo%z2~} zFDJC{RPNPMHBm{dJ9HOBqqx~p7pfBza5FZs;Du1t`GS0c>2}#->vok^?xvFT)zRk& zbt4`UsBR_FX2gbqqaT_1&0Yjk1Q*D9Pb#OiV9nT0EVe8(>KR)g+1t^=HccSd7(3Lh zGMRp31W5*VRZ{>`N2KSOylklW9pOS^UDXW?Gb{o7*tg1!D#1?N4^sX;K|)XvZyTyP)82}nV9k@I9BYS0-An{<;!vBl# zB|qsFUMLww1Z6mCaiPXn_Y4aXa ziy+IMn+U)%^vKOvge5&V=22%`hku*Rfj-O{zx7Xz)mwN!cwpVz}*L*VK z6nKBkc#V}4W~mp-Q3)LGry8m>T@!W5sf{H(Zqpb^U&Wv-IgK6x#$(0GIXR|yy_lM) zJ<8YKFov;!<3)J5uvK?BvHE>+@!k95^#Cv^Rf^Q^l_np_*3Z1C@xK8VzvuA0O=>(# z$o^-wqoU&5csqlP+G0Z1jDw@iY`%Ihp|3m-_$eR2lc`XAJgc5X#Q$E06bm2sWdx=dNoEk z+q%9_GfN2{vQ0zT8Zl#PseU8(9AE)KF>d##6;gx2yxg#_ZyW2GQbR84NThG;8(x)= z);TS$^gD@kV{JC^zwmJ%2naCVQ}l4je1VB@{35o^GDP(cEhaD{@EuowAoY9X@7TXc zU<2Q=b@4AE8WYKMQarJ-WDQe^NS`sdU+!Ipl`RrIcbd4PdS0nQ6&@qOEyfbczsa1x zIv^>HJ}!Z@yF8(9HuJG5)KuffOG`KMd!VA-q@`}288z`hC)K@vBzx!{*@gmv_7D4a zSPmg%|D2ifzJOcgJVSzcZ+s2><|kMpS9@Cbp)rY9{DD0jAw50EH;Q|ZD!zRK7X#Ft z?_MQeZiq{!?i*y=yb7k>0Fy0A|J`%$Id0+F2)&^}S zNI$k=)KuGxVT#b+f@+XBYYgzrxI$!Jv@yNYz3v1ot`3%36ge4lUw#$D`(9<7C4GWo zQNi1NCP5s`lGZAyfKbeKCM|YK#bev!9>%C=H$Vn&0l+H{E;+fAjgGvaKUV1(t5S%7{H{ z;1!=~$Uqj0|LlFTPDGIUsaCfA6;ZWW8wB+}fqE|-FIBbkJ>D}!vK{Mf=~j_6Zh2Qd zWbILlE)b?4@L9|44G~XwKhLhR@nx9jofg{iIv$g*j-X@uhWyZIz-+p45kBYm`xtMd zUYZ8YR1x_K*ZA(@+1E9+Sag8x8NU*4$k1m}qOp;K z& zD_9_>Us#;<>M5nVid>ogtVG0Oz1O=_w_1Z3F`9z*`#et&)A4ORq+C{C>%BuB_(#ea z@j%-^5rWk2o)`B);az`D7(W>9b)pj`pdWHS3U^y~kt2!~ z_G1raqu`~WWFf{fz-n@>U`=0t<>ecygw922_iQiFv2)-hM z*H=2oaYS<0gMUVHxV*JB@@#+ij;>!uTtt=Ar66Wx>utMobG-iHS~C8KH)uCKJNjtf zYTpFoXZP}-cm;DojEIsSpi|Fnz1!&9Et_iy5P>hBiycOHG_k@}Nv1d18JwIg3Y_jm z1{-begWwxRS7U_xO0OSXCfpO}`B{m&(Taq=;h90t+--*jOlO|w#d~yMH;N@57+b>H z@z&ce4(5Rw9UZZQeBMA!nbuGeJzJ{EqzX+XAUTAy8-GM0j;A}Ftwq+m;4=v#*^HwF zJ?{!KY&;9JRqO%?WzM%`Xf4;iO;Su`$$yJtUI<6e2YdP-efkXnxWM<`2#oZDz0lZkTedp*f|FD3`5_rQJ-=f>NXEzSW-xp1u#ug|z;Bs_DR{+19;>ZA)%Pyd;rNR!U2w z(_3&#vR_iDva(gtd#XdQNw%F~-TNAFzF8Z6KKdJUz*!>)I#UPD+hzH=V1!HWTXWlq z!HchQ9BeoBXBOjyyagn0ch1InzIzt8N4a8Ubog;YS~*sA4!2qmtM>G-p?{^ z=d<$pbF(6JgfiIGc`3VvgAN_nxc2uie*0+S|i36PX@vKl=9N6J{rKXxl6_o|sk$Hp5O9667 znmrQ9n5Y3W{n<&Vt;H~%QZ;POHV#UzO+4)@5n-eedOM8Rv^0pW!kgk(K{C?8H2PBD_$H zeiAXXT47FV=)BxAz&Ocp?&AGEJgz}QzgU9ix<0)zC+$z#GtI$6IXaX4;X0~*@Y_hI zf7yPu&mrfm$FgKnrjMRjhNT`o@5TNFe+@=YN-z~AS_I~$^w~}Wk%=Mcw`QUsa!s8% zrTEs0Gw25>8T<=fWE;=v2L!A()CQdAL;KG~8J05bh^U}LZU(@dj1pZiO7wD1{&%gr*1c=pPxEEoz2E)3?RodvXCM8P zAh%`w13Xxb=JjGG?9|hU=ZiKWc@oR8UWn`~Dtq$DtR}H7@lYY-(EDUP=A4l#L#YP@ zZqLNdWsfV>i~oMgt{)}R-!uq!8bv@WZr**6+CX=`ww6Gv=Ywx5E5=2)8k|NH1TTvP zb147p4(o9Wb}`K9+`rdm&172QIx@R6486b8UChYhG;8@KQsh6DmJ=wM!;KQQ<)H+B zD>j<_12Z3WMSv$L*?pUxN!vbJ=@v6Ce~b>IBX5krvr>cjO+*l3X3+^zLJtB6-k~4# zRIJcDjl2vMGKsz?s(qDO+vs2tHa;aZ>3KEK?AM?RY2R?SidPTGfUd(4L80BI#^s+q zU&nD^b+3P;dj-*THomcJt;pp4rAA^JMuBsswsLf3QV9DJ{md-g<@L{abaqPyB99Dg^bE&_wG>?nKJ#=U~Y z8h|5FX1S|~d4ACc_!wK;1qT6Vk~_!C%qIVA$c&SzF>6NQw0Ob!hq?HE=1+JUz@dEY zuA0f@Dcn$cbTbus=Z-hV?9$KrmS!iWDP?O`=P0e({IXX?eT0sV$g&@^!2dIgO)?Y;) zv6C34G@&Au z)GU1rS+<)O+4^MWZm1%jho_~#x&>bBOL!?zVj>*Y>k=_YWYx+6U7n2zvzW24aU?rc zf#V{g^gfNdC>qs=b=#iI3_tyFgj1wg*<8X3xsEYY!q6Qu`HVUL9`68)wogWP89)la zCUzf6PJX&K#6#T)Jw)?tc=DHKNU0mhERr#(Q@$k5yKln1LmD&8Hv3r>SFAd)a!mkz zZu{`u8rTV|&aHU0elg>%HJ98G`ovWAfY_P+Tq+3vP=Qxbw^p4BC1@~>t~*c#vMy;| z1*OLExK()G`;uT;t9n+9{3=tSCb=eTIT)nJ(YS}YCfk;ZX?-1*DVQv>kbEFPp~)m8 zI1gJ3#%cZVl(Ck%D9)2evH26X0MAF6H;10Bo!Ipq!H z4xc371#Vw(guz}nCa=KTb9t&-nbglCs&Tny8mH)--iU{#nAR{$decl%;(Ae$Jf}&S zn)$x*{Ic70?ZBxqFjGsX;-t7`U9Zuu-z&oV9+$jYcgGp`P4(cX_phhb-^q}OY^Zi> zO?>l5$Nbn)^6=neNM_uI(a=bj4ip$GbNL7x_ws7KBH#MqIpgb5CB|TM;rW5YuXq5)plwI7L06H zv!pjYs_BsLti?L4nza%t-gUTiSOdGg=1F*F=Ghuj|H;PN%+W%!KE7K& ziqf7^!|7`oQO=d?9fun}>-iP3ao^NYb<2#jeu!e#n15nE|6eG}X==$f@5I+~tLcIt z)#g5lU+suB)knPYZ`v!+EkC(_C1|&V1+7PWqbg-giL#Aq2b~EN*?nJ2EnP`c;G(99 zhmNE$y1@rS*b>p(0ar=^TT>5C3}OmVJK~}_>Q51lmVN0WWaccK4W)d&CF44gPA@1T zQt;eHGkqClwnn>A(}VE6-1a+uZHxU)qP;VurxcOf{${m2&w%>P64DMUE4E4qC?HQo z&m=y|I|iHgb*|?qqAzvx>0XeMSO{ltNZaqW`5NKsJxkn^a`EwZa#snNz*CxqaPrrT z)4crDpM%HjL7thL*3A_|y^zLKOu=w{wno@ceOm7G{b{266W>ZyTtoeUGsL)(;jK;34{PtOBRX<M(&0%60&tJ|2)_w4`$<;mAz+;sI%#Z zUnf!TWkcR<8A%G+=Hha&k^2Kj2T7PVDB8MjU(b2Oc=mjW|D|KD+mQ8gNT5KE>S2^0 z^H&@n(Ged*-Q+~EucX12i^-QPh$8oGU7)lFS75X)vL}y3xuePG=~=0tjEereoFfh} zq+ntC)OJ##3K5k~=0I?Er}<%6?dB!gE@@`& z_dJ`i|jDP`o67AuI%kdD0 z5r?fIzWmYaHr2syI~Tkxq1xhXp9^BlreMiDcqizzD;)9ZW!Xc3O(-hTUZMrD0_d$< zwRitJ>8$!~ANxN+QOsxJTb;Rx8z8uso|(%DCc3G}_iod5CWz`|=)7t~1Y1&uq31N8FBq`o};&bmDEk=;+8i9)< zy(hG6H3Q1q5_G)M@=z_PoAn{uf9aZqwTV6!ry5Tep{Vy610_>^gWG2PySr& zmLde!Qv7zNKyRt4!mNUXSD;VBUq=q+5h9qy^G$@*1s~1@+S3vx?L~olw_Ro|8lS-= zT*n}Gf7|$pC}9NtF%YP`NV@@Uuv_Sjv>g54PR3S>^z@7jr!s32;&c?&nlLs+;;~7Q zVwLS(?Hs0}+Jy8^WYKDip8$UofD7%MS>~5Sd3Q7@lkU$%yNK??8#%J|L)Y=TfXnEr zHQ|~F)$Pc~)KGZE?le-uVDRU5k+E`1SxU4%RYUOxqThM6C7xeR2KT|p3)MlJO~0OG zw~QNj;On+*ojLD{;|UA>x6=c(4z&(*9dG|g7l%dd;dEs;UUrE*);Y!rynuK?9VCRA zwzA{sXd2A>EuR4IU2pNC9lA58uheTOmh1e=<`=1NewTv+mEbKo59K+%~Ufwx)opXlaUI`$qGtmTfg!@Dq(jl>w5FKu^nU5 z-{To;|4!CVL**%At7W%Tlv6}MjacIrc@6I+IWqWkw93UkMd@Aa))wNRN-@}y_@rUM z#qr~AjoYYsj_J=$FiU7ol+);16!M+Exws)x)>Oys7C+T*TLN2>JmSD#3AmwYChd(<1bHTTUiCwWbqS=9zvtIf)h^Dr_Z?56~F_p z2qN$s;)~+uIlZkMn3+weg-YXH2j4RIO@=%^jS{FfXbktNz^o~YHj;m9w zJvla|AmG;x7t1<4Ny|OX1%p+ukb}}rY8ud_l7F!=97YnkHD$t5P-cp^nCYpiqWJyq zxdBeb1J|;&4u0DoENa_a>b%`hNN*m!**1UWJxRa=0rE`evaX8qL**~ZZ$xDl$+pd~ z)q#N6&$Hf;#-?*{W(sW>cs}qm%)#&2u&hbsOhgEkASGE_aBdQPm!ezZH2cBfkCO}g zO;wuTKJ{+wX^w768t*pI5Z+DmcOKcfKNZy#_Ne)VIJl@+(z_F zDu(Ov*75#Fq*=cB4z5RT;0B$V7Q088M-rr$^%dft_=1xAC+$lifeiBD0;KpS-6f?BCD#rRGuo1g&mtPnX^X&Upmto;X~Ek$m-=(v>FfB)j0iFd7Ut zzGLy3(prD~lF>SrUrjb$jU{5Z;lybth@}_B)VmF4zbKwXVCHRjY6+{HFdy|czrZL& zi>{{>0zx!V=U55W3{#e`>5~o*bN0R_@ec^Vu#}a)X$Tulr97nwU-!@Z?~!f1V4rU! z=b@hC`0eK4)boE^+g`~j-F6d0K5Zaa#&iO$NDsg!JLTQX!Q4h0HHm0tS*pb?-M(zcc7Kw@QT!5LwOMV}JiXxn&Um zkbojJd{bQr9v5%CiU5-wQqbbujh?rWu5_Nv)H|u1kT&TxY0E}BESvmyl2$I zWtB;#Hbi`C8@AIr`cB`t0{)%u<|Doo>UK`< z#gF=fR0-}n7(^6#Mf^*@Ye#lqAg1gXq7z8^Rcfy_UM0-jBi%e;G-BbO3L&x-{7)XG zeZl{Yv)gu_cyc8+7^xq8kXrI*N|K5@3spH&bAU_XCWCRDOgV%Y44!Hg)sxlSgXUy~ ztyJlhUyBXEnjAao7^l4v!-aU^mNBG3%>lBtK@>!VWLu{r$Vm8rXuaz6<31Xzh0Kac zvs||FrQQsy=uSPow8Nhq%c-we%;Ms5m=Rz;HO`B3Xj4u%5w$X=3VArY z-|!I#>$sz`*H00fqH*ZR-TS{1PU^!XuCgw!*E*XzjyWhS;9&+C+1>HZEM)LUQ%b+_ zV{wH0TP0bid{RAQ)YoKt5O$1F`1@E9HgaL=6b_jCLX6~tPVW!LfkLn9@;QRCKB$Z3 zHmh$ZJ}D@z5Z?N);_AG@_{~CkezQELl#O8E)rYb!1VVbH^Itcz0p2Np9}X3rkKE+f zUWTNNnEf$0VwMlP`Sq*id2M}|spdW#{##{=+cHi)(0_)K5#Kc1)vArhuXZvO>JzL6 zp5Yag@mpyg$vf98DcnCN=@0hm&dVpb`)}VQL(f1~s&8S;NE2_1L&oh9hClx$_o6(8 zZQzJ>!QNqj+Wi^!=TGTJUp+blOmTSet@Jy5xl)dD4RpHb zFX&@LMvE8LJa6*3&BpJ{p%emF%@C$tpj(NsBDfWvaeAZI6EhSW z)tzt}){K`j`?jXhr>OzRL7PRd`mvLqR1^$zFsf5XM!l2KF#h?&%VcG|v&uI6 z51<#X6f%*v5iQNHU<65y8lRQxRk%-7xB~(ZnRG<|WcS+opz+r=oV9fFeEJ`$xAR;5 z5sO>zfcBflcb8w9(6vfWn7s}hOyWU*Xa^PlBH9w>6wA*J)1XdJVQee8U*(GIpYIDc z@+9ddZkRymY@a0ZeAdb?{0zM!*O3INGM;1sH0fXbrTeDi-m%2?a|LWY>K1GsjF{i* zrMME8D7}mw(1Ul=QHxw%7a6mCZTqKOCI8A&;!O^_sXef7b^BZH<)|d-%k^&1Uh@Z= z^>Rh>tv=|4oiRdb@;|pyP;>nfwbiB_*~N>f9uSX=`BtR!uxLq%)uStHfbl(&cd_}Q z!{u&FHdK4BNC2}h%MhN?^?c6qb0 z2C*G7yuH55#O2udh5iV*h- zTA!)q!BENg= z<2&P;5q=^+Cvr@g$LRADEj^GucMkXdjeky-f>js6uQCMO5v%WVWCK?ILI6JJI@Vn| zDT>EaIB4?S$>M8s?4_%qkruFXJ@0hl#sGv>%Wz?_d z^Y!Px|A3PWfPg+zsJ^n${yx^qKJ>dH{3&QaasCnkC|&6|&rmM&S*i!;5hnW!=T;PE z3;8P~9sp%x1L1PAZCY~>Ox;v-P;wiF>?!PI+{$G_$owg4d}aQ~@8eL{?ek<@adk4E zmrCmiaH$8m-$h>nz))k~(O*cc5ZKz~Yu8(&nVuC0C624`%Ao@c7Vu3ud?*4QZ;T-w z=djEM(m&jSd|tTTv>+*2Q1iXx>WfL9#wC4c1wu?xJQSBX-;}^E37pR4tM}N!pi^sx zJfQTCg6OF==l2d7to#V_#7aUwYQK_}k!Ka;AeaN;a8IcnZgg9yc> zyxs$@2l)yN&z^Qi&=$jsLmw_o+GnbBM|QD{WHlHB$d8DBh?LCVV4MU72TJ#1;yNKw zIydL%kqK6KI?YU-S&e~JI(wd$at9>}Deyhb8svn8v~gd&m?MvFfl$WE+6X9WGQqM# zaP=N^h^+9m8tvQ1LWl3(V?SY1?$9uL?#z>l%F+OwTNuVb08xH(!7`i`GJy?nJz#EH z*d(5FkBs7-7Kawo3`dF5e4_s+F5`xevRJy$@O8cuTvdV(u}qUaKU5DxRyXVHE{vDu zpfA^*GH0!jgPOO5Yb9Vgm%j1J535EE^@LsDJx%>+a&nkhLQ*9x*oU358JYHXty87n z&|5M_s<~%^Y98F-v)qGKlO|;74WB!^d8s%s7r&QMV@B+FNm@kVV(}{YP+=;idG;<0 z!`b^7@Xt@myYUf%-$m)IHaVI1&(1X0)?bNJ>C$N|VEo>H4cz92-Zx8um~Q$=#7Q5m z*63f>L4t@bGfzE;D4eBAfQD5;(G;n**jNs0ot3-{d$8bIBAdIS4UF~7H z;lXfLSppk{KaB`l@h{j{UYS3;tp_29YqR8@6=YdO*DS#yuO}IJqb7?ngerehQEE%{ z>`ClJzfjMTvbO5OoZfJ>d*P!6zAb4(uIrU8gT*k)`Rsetdt(&s29^y-Ql(#wXk>xB z6A^k80W8+tYh6S9HT$+oNDHX8Fi!VBBUvF8Yl@4P_LVbYN-c#Ja(lKlz|6jgnkB4m zeAk7qEUG`xb8e{M%TTpHbPe&Y<-RNd-koW|!Wd8z%%i~v2kBUL$5pZ1-!^|bqMMX; zSr_K?xX5LUMAS_q{*gMaGFW6>(FcOrD`M|xTDK2+6Xwr$bzyzTGfZp85N~g)j&qL{ zKyw=(r`m#cTT6cY=(lX+Dffn3)7vaM$Hq_lDVPhe&npn@Z>k&?K4Rpuys#+e4z`;Q+v!91pw- z7eg_`D1RBk>8S}Mi5h>C4Z+g0a=HE^7N}`hOy^&44{qlZA3T=_YG{12++g?; zvYKO-bunRxvcle*Z6dNyKupTjZpJn9u`R*UPo10aO4m$QFFeZsL|#)EJnf4K0puTk zD1k?=1M;k=Sj+g`;k!AXW4hMGrsj`0u(s+>ScPmE3hg0)>(~;`{>iselNC51!$OEF zbzVFq4fFH7^b?)_4(Cat9zKKp;-I7~#gXEf=LKV>39P<`f}xt4H@%CJ>%kseVWJ^B@142aFnCS3!rsq zw|}?lDW-wcxocsgWqQky8Z3w*D%!W*OI_qHXlW#0;a}C+6UHbO7 zueZv!nls@X&JDPgXv5T;SC(8@JR3bv@EgCHR!Hri`hI}=ujO4bnZUXDn({435il<_ z$3K|)E0%uO++af(+C#bM*T@r`1FRtM6?mJk^^{R#N=i)1@?^Ed7tnya`1I1FsndPu ztGM(R1jIN2=?ms%GSO~{6X@mL!cg93>&rU(*qD>~V7Dd+z@?P?u;{}98@493GelV$ zh66^cU*k27WBSH}tEM+fM5b5=nK0u0ie({&X+SCz5p?4Z#Cqwm3f4?{bPBiTBqP#Yx_L4Fhij4!tK}uL;w<1q; z;kg9Hzgrvr9)}Lgzh<3^wpZb^G4sjeX2& zHWzw2)%?#N3&oh9f#1+iKU)!DjuzzIc90)uc2w|Z-eKuzkVu*e=KIld4Cy-Gl2d#9 zBt#^G!d|c0bcJR`Q+=@z!KTjnht-16j3wFOOgE~qacMWD#hRgm-_wp@DLuMRP%J(3 zv7hd4fx*nKcqd3Hd0pPRY3rt`C4OJx-2Ij`htdA{#T#q)FMcoWVavq022yEkS}Y7N z8L`f={Nbe`dD?gW;3R%|E59M4%56EaVmOay;ar01lM@vkdv*JDNU0Ln;cZIK zHC!qASb!%jb!ob=-(=$kGs5jk=PthQ=gx1diN>JKR_$gSEf41;$qMMhBk$GmDCpmu zL{))ibndcW`Q2R`q}-dT7*3yqxRkj36FeMa(*C+<e1tDGIvuerDqUMFc~Hxo7osCZ;gTo zJ%JrTx1qyOSL1Ide?`1AYYPt> zQ7bna;0N@a@A(UEJ^^k%A?@dUqR&M{1%1OIio2E~g%&FstPtFx#ob+tyE{BcaV-T}Ah>&>5ZsFecM8E>|I7RR zixpVhBe7~%Qlr=X)W1-OFg zEUV*&fI#y0<%KAx&UgY`ME@$MB!#|kT z%r=7#g`C{@LE%$d;-5l zKp`sNUG>^<@;f?wR@Yv1Dy)4S!mvTg_+v64ehf*%x)!zeV;GnbVFUev;Rf*&Axg!1 z(Uc3Af$@2eW$)+gD+K&c*LE0hF0d~`UPZ}*?Wq4I9HEP>u~>Dpb;|m0eh~2;^1E33 zQjqdI859~C9xh$f(Cos_pj3XM*lI}D6Uifg8Mej^ z!B)%4RkMo+Yv!2hEDX2eoe>0+sdPlh;o|uJ@!TY#qTt<6%Wyy9`45-`;`(===ELr) z#Zm-s_Qa^^ur831#c!$;9Sf+fk#!qN48lBuKj2VPlqy6M&n74nrG4uM>FG`C7NI|X z!FQ%o5_a6Yd?&w?4R#_cvLI+Ri4)iGe=9hNgx2oQGJ|h~ZE=fnEgkwDFpKy1%#eZ4 z1xOh}H)@DPDT=cTp|qk?&n-XYn4U!oJWs|o*XXLnZt3H7511yD#v%Je#)lC0-HPg2?p zws(`;6m`}n_w>-6Hm4jGd@nG*QWW|}5hG55w2Ko^!Pw$3!jly^KA_E&Eaj0c%XEFI z3j&EeRXBq95Q5A=HxDG#)cAFzE3%Y;ZCI-s0@w;_>d_(eCUzFAzg}yHI)8AcAM{^C zb%fgfDE3GuzED9{LC9u6PMQ_xTtoP?$psFp4KHzBk#%_azSa1S(tM+&qay;jy=B>Z z7y&FRX6N%7ck-Llg$xJt{`r4zbVQzCov`eYn%2xCc8RSCBp~a)NuYI*V$HL<>ZJVD z$N2S)Mg3oU%7^TN)c<6yEp)h11(2JO1k%k3_?7hIqF=wwT*^nInbH-rgKj9%ba8n9 z88hB)-?bF_z20t2b(T3nAo1Xl zy`|8ytW*c%+!8I)(X_5p1AF;+qr(KnaCtRhLS`~QQ;ytTf0zwqC1KNAIB$!D2fZEX zd_o_$okTmH)t+Zc0ew)K&(j7%JC(3pz^;NMez5h4o2iD95LmR?lKadT6Bw>Mrf9wt zyJb4UE`k%v2fBs5KF+C3rjgstaHPo7?P^r z5392U@grBElb9-V^2GJN4WjPu`m{=t2=(yk2+*^OSEr$ZmUyiYG?{&zN(BrV1z)bs z1otp;aEPDLZ=r~fAwI>LBa`t!9Lb<_2*Mb59J<4?4B$^isid%k%zZDjKfr92wf!yL z5)&_k^}2vjAnu~h_=7f=!<;h76#awN$TX-=B@F@k;5!7YUG|-|F{RJ!e51B;gk}V- zF8Y9FWEly(glX7^dm7z4F|-hlnHLiNehlJ@n>={45Pf91CRbd63sa`@Im*Oua}fp{ z9{SaJm#N<4#OIO4VqGBG6yKYApe>juI0(i?A&vGA-4Nl?3UX;6@4ZL`Wui%B_|9Tf zKLo#tBLXssOKM4({LoOz#N=d*g?BX^939n8vh~=#A2bIi!!aX>LLLu&3Z1=k96qaG z^a$zcA;`+69R1wxLIl`WQs|$@Yg{O1czYB^f*D@?fD!}$t81#f`D68=X*66^)bRSI zrp#Yno3DYGShV#p)^W9_y*07hqD2|&XLRkAMRiG*X?fBN^KB@Z``kwv$%E;iY*z(A ziqKV;C)t}rc$TT1AFW8Dl>SFfr$hV1y#EU|_HIc@NVM zgZ^93@%x9CWSIqsH?gyK*M?P2PQo;lR1gji&LxEmUbjhF~K zC6C~8+~_VU2(*Wd5x(FqAHxvi7usNg+j66_G2ds(@& z63(8H^=Q7-56OeA5rdBuywM_|z%uA{%bUJ8^lzR50I3BwK=Q*9pylasB$Ga4zk&wQ z3Mg;56bnaNe+;qENqw)s?_u9h#)&C{TtDY1V^__N4RzT;qD5W_%{1hHwP{V=O&e_V zuK1rl$mFWh3L|A=T3cpW*&Zg%`r9R^K>gqQZsuTON2n#4^bqWopNySMC*?+QO2+_ZhTRtTEV#eGfT4mXe{I=J4oQ(=}jXe0oOx- zn7@CArGp4gW>}tOmZt++_rWFNmMvrzM<0E}4aC>WIW_AzAvU4A`tJMP#wiQk&f(=p zGXkG1YsgAWv9LgbBqtdoL3|F9AB`9Fnj1(I_<~{Bmi41=u(7jO`e!0W8qd9b8z%my zL({eLZts_E=>Kuecv5U#zx_+RfT;UWM}-TRepEs$^`A{lKT(c^P4mzPjuRW>7+4K? zgvl!*1V5v&RXZgC0!%^-^UM!!tUZhuL=%Q>$Vr9Ut~$t?12tsqYm>Fo%UANgb_{J~W=Ng|6bukq_DkC1>k*9Ni-f@uwz zX#TPO8rm9F(7GjqZ?9@5!_6Q4pl_fvu#7-_E4rs~y%h@^pVRY-| zMVZogWn*_r+$Z6w!ye8*nvry zU4HvUL>v~yZ2$V9`#E_jO>^Uami}Oa{%8Sdk)w;zDimTMsxX9m=#%#`UU1FS`cnQb zNc0j$#BI^Np>n2v{q@BxuhK7(#fUF(bbmk(&hhsXRa?93&f>>FMkx!N&+(rj87_Kg8KEZ9qfu&fLfn~Ty9c#GuwE*{TJSIN~uWt5?lj2X&HM@d9 zrYtgfmK?L>yJ&9AM-%`GlG90LJ0}Ehq)z2<=8$y&95AOz+N#9#V*S-`>f+Pue{mVU zj~%(c_wRdAQOeknW2>*v9vqtx_nPN*^n@6vI71R0MLhMl{~iOx3=_jwY3Ybw{g?Yq z%Fz*5a6yM?Yggm5sMQJO?`Y`HLKY$Vt^MRJjg1{}j4;Gmf14Sq9hYy|=d zu8)t8+Z)5J?Alw9?VBUKh zv?`Qvj*7ppF0Up4B^v4=NSR11{8dKKB^If@fqY*wY_xH$FcX4s=-;vxfzN4mQRBbW=$!I>bY+FIl;qo2HSiXXs8opr_ zDTH^7Y=n+1B@O4H-zDcj>W5zD{(A6nM*l|dH78l{TA&2%KkIhrItPC-@GX>$UaSaRwH;2G)( za(f)pYFgp56flq4_X_@@=7>3RJN?xWWs{(`*7+Jcemt?7H0C)-X=4ChhrhpLWIA`d zA%~mg=+?&h*m`a32jj~ai>=-5%s-BCe+rXY3HC{f|8sOJxdSu-F-4hW+0u-rg~H8yX^RKP{VcKE2)L zE^dE?&ozD8A6*@s9}D-xSGcrMV9Bz;+K$Kw6a87&h=rhbLnRX^-J6b(|1!3j^~aUT zg+89~u7PDd;XfJ&`Nh9l`rs2&$rd{7I?X|B9BpCcMs9-GJ7a>MeT~Vg=x`sv6GpSL zD2g&I^h||r+T1e2xMS|2aDAm|GUPSYA(uY^vu%8XK~pT;C^|F73xzkoy2g3?ZSfB6 z$$d^_$$K?)X6A3A+#6Ceufac06f1Xkb6kN(R6N8^?a7=c7Kt*;)-dIzi-7zs%nt84 zl2rBj`bJel&8O!eTGQm)AN;8Uc4&mRaL;80gI=1Z-mK3%qnV?=D_0~h)A^j5p1C2o zseK1-rn%stLWedw43ShigP7(N7sFPX{jt-~v9MzH_xJsZq85_6P0%8mw@9y|yestNr4kZ!D2uv7cFu%x zkrS%0N;P-o2QGW#b+zwXdd$tXP$zRqyu=C5oL|PAkvD2U*J=fXGSXMx?vdv0Q~`VJ zgHDPSlE)O|MPXW{IQ@yjnu8Aj!`58a?p50{Jw-e)kV`UPx0Um&CTBSM zQ~Fsg0S~GZ)e&y}6DPwcgQ|d)t73;rOxTKU2XQfb>d*g*a-9(75QpH+anWxW<{L*P z6U7E`#9ERdAdgmHR?+}22zNeYs#N<8n)0ag<6g7j-^R_hj=Ow(d!F7(J>EQg6SktG z7Y?DmLr43p$#Q|Yrk9acnG&NObCgFDaJ}1gTAuv`meERw(UY6mpN8D}UDoAqO~rmd z7-?-qWYqf;Fzk`zq{Dzor8F60;RyX$$t_gabhr{B!%FbI=D((t99s@&fCg@`6wkLk zBdk9BR=K(ExK5E}T*4hBW8N+<_S;!ZJQ?HfLadszOKwG+2%Vi1bhCP#Ec+!RtSQ|T zH98*_V0=&VeUj|J6@5`qmogJikJN6&dijYh?X?4_{%~c(L(%MA5zYGP&v>ZW zq)C$jt{)~wE3g=@RCVFU!*jnowpHWfCuG3HKcdo;?^O1V_CNh;@5$alKzjmjo z;@C_x<=&ZG2KWtxH-sJBj4IFv&xngIO#SXU%qM!)!ch&eO^2nTaP#fDJyf51V=_z0ZF-n*(@I z!eFCAfZMrI^FBwDF|3jN7o|e*u{DcSH!DUn^>~Kteb|a&oBxT#AA+QVApYk6Tg68j z`gbS4=To&o@+q@Us`E@y-$si~hgvaoY zn&9mF+XaJ)mrdQbE^M0=we7p3Xg*B)O(Wp8AB7 z4fG-{lJCsZar|^-2ufq;dUh{?wfy`6FKU5UQbvQ3pf%XRP6)9teo7|KN@H;UQS9lj zQ&j)RX=(p}!(wav@xz|g*RSrGmtW2JPToV@y?Z>Y%jH%d_iZvKKxoG&UU|DHV|?5F-39}SJ+;X4P`G@T<`4^Hf}y+kpxsF8aKx?P%S|bM?T3OgaK6z}DNu9#LT)M?JOdJddI++XzN~ zCfWX|*Uy!#vWP$ke5@YFes}HLZ&q`Q^Ehp@T6^}ls>n(dY zi-VQX9g!{nzh^B4TzBZ7FK}>j8cXl?-@JRrzLx70@aFma$dl7-@pJub$(O^e>9E=3 z3HiML3i7|lv^YZDB&HY&n>3xIz`;yLsSo5{kpIn#wJ*4Y>FK_AuGVCF3y#Ljz|Jyc z=Hy9>d>RH@SHxmV|FFJ@_atWMw%>R2_!I{k=oP4Bp1h-u`iMj{YOvuU4E=WICJ!j4 z2=pWeq-tlM)_7mC3>DPnX1D9ua&zaxY1pea#1M~G*a0(N!1L`8k%LmkD9rPuX52rR z!|xpJ>PXDEWQ{o=`*n-7odcqc8e{rd;sp4m50%gH72o;2W$fY)6V|@UEZwJz>pQ`zyMmm@n(O|{s zpLmF*FCgZUs&2om)<=E4a_qrE7zk%*4;Zu$c#gnsvA+6@Kn2;~<3|m4w6$^AJXn3^ znhV?n0i?+~`EJVvcYrs+OphT3kc68y1xr%>!J4U7o2S}d?VaaAct2b#`sZVzn-Ax! zo|E%mC*Z0~pS#UYCwbCO>)6IE0$iR7@x6Oo_G0^%ah;}O`%E9UX`eSF^B>r=8y)%O z{9RwK1->74%LK&2G)*Afxr(=nYJdXESs=me0O^w`c52K2&HnS;U$<385J>|I(HdoX z&KN0&(6=5{gx%_WcRjoBCA(fjUbc^Jem5HVn@P;GB~VRzv-+5zg9eWh4|n$o9j$E- z;a>TcuocZZ90+d`T~zWlB9Qu1xN7WSJ4T)>y`9MDOSl$2Bdi14{pDku&&o#f6K2#& zBas<@&u7#d+OiHRpRqhwo?jcsY%>MBeG)Zg-WY0hSkyQcR`^2YdlZz=W3LvJv9e5(irv@$HwfDn2XR+nuRxUQbU7Ctm@m-M& zn|k>Y3Y$1aaKvr}yPk*NGZHk){mX>!==;Tv!l zpLl_);?#{krEKn}3O9wY>k8e0>q>#xOz(v%0d6sU9nAqEhpYC-ubR1x z>I~n`7F($%6H}=bWyIvXrm0hUSA2POc?zd}j%%aw8fd>AvUd{~-I;GRl5$uq(-VWKnJ((SvP0L}1{#{{GS@3YKHV8a}dXkt}z+hREMnrs(U!gZx$Q$JyT}e63|E3OSGFNyK;NlvDMz>?v z^Q}c#!;F`T-;n(zK&>A|dByD-?$Kpio@8VDzOxJ?CGjI_HB%?9Cup3Fmn) zPt^JuiUzK;>ib?{AsHV0nAM_&u#Vz#m(tC_hq;s|5)A(OZAZ{fcvX`ZkD&NP2x)r{{;)>cRnjG9`fimc1xeHx$}s$GoBp-4C)#L3*vjWG z(X&9a6NBLyPkaBLh)J_FcwVz1#UGtw8P`J5!dt}eDTLSWCeFg^J#U#gZUKsNrh3RY zH#0_Qir$kudeh32lg4dc%TCOI3>EWw9UR4h_Xs}a^1cu~^y#!$e3(a?jv)Fh#ppReSKgX`@sC1sA&wGDrjbk;+Vr7{0%R_}<*Us?{2C48pLgl&4%S7sK5Ex4pr`sFS zy$cg7qXGr9pnf;PYq#yGnwMowaHzAm$0djkgB8ZbV6>a{`H2SpW;MTUHxuQi<^BkN z`iIK1+-bhaSl`%ie!lvglu-HMWmIKE?{Y8y0_M)~`!J>ppt*5_{K+2r0r@sCC{Utm zR#xya2}7?O;AZ_l4O*N@R-3oJ#z+L?^T(63Dum5_$db#n;Z8}*^SdK|p{dgpd^|ec z=sDWc zw3RgTrHK$|M=6^kmPE&K$=WG7NFpa}0=pg+-cD25wMO(Im)}96WFd01j_A40lB*7D zL^|o~*XovVJ*Q{9nhf${tDjBLKQ*L?0P&je3@^d=rOanEVU~RbMoIESj%D5&ic2L; zgf7%Mb-_&HG6>e6mGyc+nxmc#)q|5+78cL9kI3;k)CL*gr? z4Vx}hRuWmGarZ?7$9Qz|>zF7ch)$H(Y}`{JQLm4VOIwQn!d0aYhr)SoZv@#eeT2FXald!uQkKwg!+wc+Q_J@v8V2tfN<)lwHpT8mk1&^&8KbW8FnT~i zx0?Y{(z>tl@6Z_lmv03Y&(6WNp+E{L^g?PZ&BcK5_7x)J3px>NxYhzBMF8_!_=XeY zal}o0oN42n>gY>l^}x0Qy~Lks^<^8XJwY4YTN2O>3>3>XFmQ}?>A?y`?EE@Ok(NfH z?1jI?R@1OkLB6f;rdjLRo@AJnrPq92C^J=?_D6tT3lCD9=-GGQEOw7RH}*12NYupS zUnxc5c&($9eGAC10NZjQIBI>S2QVX3&Bs#cqde_#p!E`s z2vE1GriC+;Wnj0vw{!fF6$7A$kzn6NweMT3h@#Y=2%K9PsHo!*X zRF(XZRVwwI7Jpk-mNS3f@YgrWO|3;(i6hUY$c1jeNHPEr;GWGhSR}Q3JjFlnk79 zN=2CIrUlAfj|l;5K&tt~!8+k?g}L{_-rT5EvffIBX#b|%y7lP(^w7=9wiVZV4p=T| zRDhM^v!f}Xdh)>YS`66+xQ&;5+7rj$$bbrjgW56cj+e;NUME5|eEwjcloY#pZB7X? zU)IT^C}5^xB+P!5G5vTI@#|o(u%sh<#hQv2w}?x|4)F1KCnFy;slp(bXQ4}oP+P0_ z)?lfki~del$bg=1{=AT*$O_aisS^;z-v?215UM%##f`K2T93t2G@fZ=zKATZ+&=OESt{=p?H0Zqr6n*wEJ zc0g{8#U2yH2KA*E#iej-fmbTnFGo+rS2I>`GMFxA|3SXaXd-UmHF{qvkNBJazR~8&GmPcslv^p~*t+0yV zhUEr*2$*1;gRj<@ilQQl<@=xL`~&&wx5~s5PR^0;47wi(9<#f(ens;wGJ^%aLaW35 zYQF$pkNINe(QB49;r~uNM4(O)(*ewf>th2~FfGLxB{lYu@uB_iX4h z?nmkE{oTCMy7FPgHmgcvx+=-RsvKEAMJKNj0w0YpZ!wu8B7#`FnT_vMDKO}O>@nNl zb<`f2?exeDh>?zwmoY01w)CY+@BRDCKOl|6?RLr&JGwP+l-{&HniuAL|H#&ju3{wb zqUpS3)JzRom=n3u@avz48ED7=!Dv+>*azH~3EQhqSs<{Kb4D=DZr?0z0v)aA=IkMA z)-EX4ptUHD=zA)V%+KdFR9rWmoHlN8zOi;GIk?Cn9_w@_ z`gAuA0#pf_$M^&u1cog`r>?Ou2|h|)nNMKVUOV(276oST>L_`|Dv280WD8$< zKIw(M={rwL7>rMllQ^!Z`r|?r;56&E*6?9PE@C(tC!C7L`;4{odOH7H!s4!Cq4FKa z4vs=X*Y47!&%A>%5HwP5C1-hmu?2ml1*HlR7zP_FbnQM4@*_Js*IQah;RkvTmwWk) zf1>d1`FMF%*VLBYnm}{qaasIl-$i}%tf|Jwt2FNn}Kjn<#Fi(iCxVQ3NbM$CAQK=H! z`g)dsq$qzIU8G80TMYk)TuH<3$RhVM5B0+auK+bs?3lAj#uUFm;orYk0-idHBgE`0 zz85=n!(ZbR>>Km&x?d`0tDDSD@@Qc)I61=Yd@5N!b2IS^{QF-CJ>G;|;9Sj;$dGSkN!n zNTyrh+fJIb?Rn-^ci5V4Pls3m7Z;W^Rbu~5&2f@nTwT_f%{hJ$-em{mul~6&Zx^=3 z&=;mP>q0lY6{OwGij?=ZV>KsVPEF*V2k|8aI*pWor<_d>TV z*hySXU572H3ydcHs#|&}1J9N9#1~5bcVq35L! zI61DLpEgKktYbs3^&v;_`@(6V`)I*j=y>fEcV<@(Py^_Ess#C>Hg#UA1M!R~7@(25 zoo3L`aB+2&IX%anEp-N-q8gt1>bUr^jFR$;#Q4yV1i*}SG4!{tM9dV~@z>XxXU~A! zjF&)Q%ecEg3>vIShy@E%K8V($;hD%m=L{535|bt6%zk<~0Wl%wGb;FSbV=&EGJ;j{ zwY~Y{-29B9n?kJIUgoi4yr>ek!1^R_7Wo&6MCl^!H1xH1#;vgHnE%P;H2yg%{`+=7 zU&;lPlcJeNy#drnDz>^BK^YF`J;5Y2RUmOafn>hvBBVdmkwYbXG!PMSJ+HN>c?Srl z54&NT7YTpYt!bz4tqx(M)rzd`@!lFBd8bV980FDv`7&T8O-=lCwEk?j#}ET%Fl1z? za=WMDVj5HBejd^48hk>IcZ}qDH$04;sgVKNV0A#)wxVQ)p}=(bp|F6#N) zb}Y*<;XhZ@Bbh%dv??c?R*lZ*5xE!r8#$o5oC6O1URDixW9QULMA&4iW#mowzCyG4 z%Ezach6uf;nT)&>LOPN}jV>#WU-z=y{Sy|L`Mk*U(>gkGzyJMZc7HQF_;m2Tt*Ib2 z9D_7eKU6TvLVe(eIqu05Z>&JzY$|@2xvsod#TCLF9*q)39W{lJuXp&1!sO<9ys5^vdjkI7;>#OT*;Y*~w%6!^RIs^UoSb9t@7b?YLyi!of)- zfDXUx#&Ob8<Vc4){%UNYbD@l+816-yX6+c~(9r*cfT2H?r?F zturWxtERmo>bB3D*`QFgjc!+!ZLaqcO89Ws0{2@JQ>iYj;e9*zmz0DVHrc5!Ktdb$ zC^viTpiEPFUVH3P->=?dqoHtnv~A@I3p5zp{U8vI+IP!(ipI2esY-?QAMHsB{G8^p zpD~xp-m$Q%3U7MFOkF?;tQmy?9C}mvho)>h^jJq5D7J@Cu!?e~EG;<2ub!M;?fdgiHkd=*!cIt?I>_SXG0pehCTAT|%Y#!{hzU7XSB4b>+dOlvxq*!F>6% zbJv#5@xV3UfJL=|SE#vS^X|l5gLwJB`1oc4$3Jggm^p&ANoJHE8Yi|jxjZ;Zy69nT zw`-^B`9VuM{xv{Mdw?n@W}IUA=Ry$?+fb~4g*;{hwMcKCAdS+za9daAzbnVIR1($X zT#C2M3_TAUeq(t$%5Fwtf8onA@jZkIz5V@~@3I#&^irW0OJ-urk?%HNh(^n?p2VHnipYdcVtSLyq`qZPAyODw1(Ao=BvBIh?D{Ntc$_jlDGVq&Rw zpWljOS!xkQCPtpLlVIB`1uc1({cuuFr?JC0pC@u?YT|$p*cL0TV$JT&!#Y0m#kk*L zsCF7{^(wk+15C>)uIhyZuXdfL|Jf+A^ZL(rrOgMQbUc^O^2;92nVUf16%pD7W|^)~ zBE_IBP8+P%dhg$M?JW<6kFrnbV8)cVjphqa?XzNSq&cJ$8Zn`}Z@r)YyVzGwIzk6K z20g+5ZBa(_s0Mu_meLmuM61#f2<6pK_&G3$6!y~r*eB*k5DUhgH+1OM@4l9&1%StP zdFt!N2!akRR!ia?rqWHe80#ZSVGbhMMl6Z2LS6>j$KA!QA*vnL4Qp8|*CnyDbHSg1Ekx24rTe*`&+J~1><%N+Bp zF3(E&Tj6aB(jOAO^56R-m|vWsmjQkF?zd8J|6v(fjiS}(m*cUei~>4fEt`MvQeI(k zPe$pb8o4n}=4bl1A>-;qD99rNl4Q`HYa z69Y|w7d!xsZlNBF?qiquG@;_c(p?ck_0F}Hg+{;X3ASUKb$^HF?jA0%7vO zB$qQ;9eTmm4_K($JPjxi`sC{U`2M~4{+Hh|e=wk%kpVJ55cd@1w+AKm7za^xkt(40 z?qw{deEh1ky+B{tWsEaCgmt@U#-To!Boyxk9FkMt8O`US-@$YxsdoCY`y-L1@ZL{~ zk-*>Dp$luk^S&&;hM58A@deyvuht#4kS^iw60_o45^p*8*K-3=(0^9TP_k{2vUyE# zqJ6_IWyJnFHXb6wcrjh_ja!7nSHFa_L7Bv~!)N^!03K(j_X)z){Y6Bg}G4k1L^ITs^(URED+7xWS74305b`rtLZ+pn3xM#GnKp`BP+ssqn?QnfV^h zC}sMXg{>oBzPGUmC8Zt|-boXkw_@nVbhovE{GrL=-UDCyB9>N7A`uEg#1c2yxFV+9 zlms^)JVoBX9Gcpwhq$~`P2HuqobO-!bVXv-7=CD}0yUJXq|~T9=;8X``0w<9XmVeL)LEvU)|HQKFZ$+L zN@6iy=BQt8=x4^;pBdq_3yRn+8X32czSfawxuNrL`@U*J z(u%!Um^sW1>7X=WHb*^whNXzbaN^n5Srgl3Mk zLi8uM2)ZYalF!V0Kb^>{X9o!CBc2~XDL?>J_H%P`2JwvD-^8bGB7dlJfQAr0FXuZ; zXvqUliTJIVHdW1#`40ZNLT`CI0?w#yv(UVK82=S}yYOYV=6l6n7{TppNFgWL+DlH2 z*UEj-nN7b71@}iRz}UG3)LZ1mKhV9@qr7l3gLl5*%v26T(H z!sSAX?xKBkX7)_l5~CSq_TR*BR+gdBP%7>qykAEQcs3 zhDeP-yokxh)#Skp#fcsXt)QD=sq%aGxBb>5aTCm}V$OvS`(ov4x-%5QRzMxA4Z>dT zlrXc`N&DY%Ke40cVYq4ncPVE&z_Er3AGai@zE>-TLL&7fwcf~gOPrz9N7^MEaZOT3 zzg_(p*XzG7Fs9}t#QqKK`W}-Y+3DRSB){s^53aN?<%OfXcZr_;Qv^sI?VhP#preYRlh=Zbd${hi~n~gKm!&#Agw2 z-EiRxBy?0NC%vWor>$K}&@X{4iIjO2Kln*h7Ji75#H)af-83ji*Pq^qIhEYrz+&^tuFqwuo;QPI3EaTd=eT@CQ%E#5oty3Zj=KOQVzd+?zh_z zQZ%g|%M=^88JqRw*uj+Z9B7{v<2Oa+!9)zU6wYNZEsHp6$a*8_*z&v)?ilHs3UpM{ zM{+&>v_UiA)s2PwQJOzopzG=5j%Me-Jt~N@u}H}Hn5v4En>BJUzT$uvW~W?c=71In z&l@qTrLz3U*ySRkm?YARVkG>iMcgib6Lce=8*ibzMCBbonr}Wj{6<7=MlOl0V~FRZ zFBG|k;^9!2%57Dr=%@gm@xw24)7WMU*kpSVE*%E_>w4t7*=Z~=iiz3)^oCM<0?L22 zrX~?jDd)9CxHHwiE05-gO2dG5N1o+LZTXHpR(z6l5}I$Vq(r-Td})HgF!A}hWtm4# z^ze#Ib&0e&9>+mbs2pcq3 zW}njvt@ihNy_wU)+Uk5R+5Uc_wDKbu{se4D{$3z~?>~Mb7GyDkVXU}}e zu=KFqx5K;JF}FNkEw+az`Mcl z5y|0$q$cLn#7zivMw8(&^oR@pPMmeviC_k*Covy#b6ZD})vgWpO2dx_H@m;=lz>7> zs;*Rdo)={#_1>JhJ5zb-Y5}#XJ>e^7_U{@vQyXi_1+sbS}0-@@p0VIZ20=0GnHm4vD!)Pd#@@#O4YwpavK)D|6zw9l6)hIgSq1p2l?M_Xn0RgwOoKr z*;(Hgm{u=4wgO$AO&4HGvBh+nZlkud=z&W1=6Ct{&e`p>%1wNXdJk${>B+%v)3j#} z{W^MLcxhU$?oSW=@sh3r-lsfDngV=WhPMWBsqnYxb z1_FERR*=91m}RiGguBJmoYxjQzg?(V?QrN5BY8@`x$ZyMeBQDw{yU%_{W_uV_9*4s z!wuP>pPU?GmlxbyzsC43%2Cfw`*ZSmMM(7iY2G*D9`%%>$W9lN_Hj?{02d{HOf>GRseySru3 z^~pGd*U_j)jjQV`!4gJ*YFMXrj);N3j6Z8j8l3VPA2yM>DOoySjQv&u=yOzw-XZae zwzoFc$Q)zQuoqn}IpepA+hmYE=b>8vtowb)YQU5Dlk&^v7CLLM0a-ZMM)4-nGNyC3;{UZSl?3wMS1Bl!6 zVDjGm{FbwF&>)yq3dMldA=A0?No9eCiWc9S*@Wcuz(jwc(^0qoe1ks7hL%2c(dXNW7*?0;LzmZvgN0$mF)Gu zTMCRA&wp)Wz}gk)E9|whV=!KNe-SNUyQ-T!gBpe=rfPRtyvZdzOyb&PPy;xR3-IwF zSujd%t8bZ-B1WFX9q!9lWvK$q#=<|S=p`l~?KhKc6xdfD9)+*Ro-hy@mxSg)9WU>; zdgxA*mJ`KC+0>D)Z1sZQ2~deSSuwc@9VrbdPF*u&jH6pm0%9|vLO}t z^mNkf<)MT6irNFA6_RK&ZWFQ-4~9{!=u5#f`9cZ43A|0!3lYvnpJVC&z6jWnba;cY zFtCxN%lc&Qy-nVwT~v$7024CX$6jG{A;!cW<^OnuMz z3uZN2ZE_PmxjM&3YH@v6nTTj|T$>b%0j>Ad_BG2Xw$p^9Kvi8~-NTl8j0e)Hvezj+ zr(96lxot(;g~feazVF|`E zk?U%4?Gc42Y*GB{S7|rYFIk)<&8MaUo~0&)KWbP%UVcZH10ggs|2l~>V&*&i;&{;M z^EP)>?8|2n&oJeJN@qSkj)G#Y?ILBhp`j&4PoyKt zW|W+Pf3mNoAFlj-obRH3d~~p|>h<_YBdPdiM4W|Vq~=Jz@S>(3zjOPE{K&P(0szk) zhSg_89`Y7*GrpU5`~EUgPDD#WOOo|{Z9kNN3!rOS|Kv~qg&3jx*4oNxeQaBdE`)fV z=JL-AQ;NoLZ_lc+;DA-tepE;iVeA8A^0m|B8l&Xd+t6tc>el1gry^7QF$&B5Q5;&P zq^@N{%GLL&WQO_KmbGB>6kHkcp*n>!2KA--lO|g!yU34VDO?Gm$ZaW_-BIoGhtzR=j%l8t^%v3U2&Vkv;JRRa zMj}8^M(^k>Hh$u9R5a)kNhB9kK1%L=+wM}f>a~s;=UV4_eC#!Q?7oa7>^mk4O0(QL z;q4oh-Q#RDHWo%YCMK?HQVxz_JqdLq$OFZJ!iqAwjwZU+BCo1Sttq!Yk4Ry4ZnK`F!UYj5}TII6 z!sU5b0)~E6t)}xmf>xU=K}YYE_=Ok>8JchV?|G976OwUWJpH}tU?m^=X`x0;02fj! z6D)9zMTsZzk$sij%R)~b>ULo%+jeLL5I65DL~a~ zgQ-t{0ToDNru!27tH zdjs`$WMq6zJ2|uKk+uFq(BoDSJ^diB<&_xu$$Nhe`K=9<|NJ6AbCiz5k8&UzCO;=L%CPoDSqXP5o$+%8HThR>t z?06Sk^j#=rB;*A-D<`K&h#hwHjAE(^$DU2Ubx4Oz#b&#Xmohzj2>{xVDp|FgQ5 ztfmEeG%WJIFH#;VxR!G|oa7y?@mL1Q^0J^t5Etz+Z0o3QmopOpYR4m z-RI12pGy)d2q|q#&m=Ck%&5w_AK}hJT?fJj+X~62E6vsvk0?*htkXz$b&u5U&!U8* zba*`iuF$eY7D{pKgWhl8CD-pji6>UWYUHLp+o*du9qt&8fuSIp@h*cP>3h_SRBa@L zDi>Rw0FGAExo;j7UzCt{tnZ}d{Ec)hYfQJk!I_9W@Z`~ZmMjR`&_?S%em=gz-IbU=tw=L7-VLoM!xG2-@ zOivyYMb-@b5YT@kgcUVowqb(!^EtDx3HtW(xOr5trSfW`cm>zMS9!&uAI{;9Chwws z0S3K}f;hhFYp5%WtuK57QemiaDc}8L9ehwg9qCpe!NaLPD3;weQqhyqV;-aCzKJ1; z63~jb&k(1q&#y+EmCNjky;Z7f**8~DB08>ys?#XiLF7Nv^o?gPOL{$ol_xig8efK= zOLu2Y3z={Yp6%w$iYLv+-#$=ZdPrF@(*jid#r^4K#8odpQ|hPhJ>Bcx!X5{2SE`K1 z92R@RX|yr0-D>wWs+l7ahm-!k>n|kfVZt$}Z!MENH+lH{dY-)E@~Pdlv}iQ!sJl<0 z7Y6(64_Tq8nD1YyXjiUud6*r#YV|#y#Kd;va{E1znr5|~wqgFxEM-!YFX{C`P~);Evg~mQiPrV0bj`Rx_Kt zU5-k|FbCFDYDgcs?A9RO3|A*d=Lq5lBTjBnL$bnRJ*aVu)f(Io=KJ@`Ht(k1M~@HF zk7*9J=Cx9{C+#C>u=!;sCo5>fTRSHc?|iCXAs?U4c_#0Wl^-+wI&HNEAg~fuzmH(( z`~LR{W|9-R2gZQN_g+iqJ=(7H4lK&{$+GtoNiqRmPBN-)-0?{MjnA!I`uqt%vsabb z7+{>OK`j)9rhuAWQoagvWyoJQA7#-lwbJY(5Z&Lw1S{+rN71FZXXPTj2sZ%!r#6nS%2(RDrzQYA%~I1!>Y_yeeaKEwLNB0 zE7l%#E*KA550L}}Aj(6LbC^#yf067sF6@+I`K(V+Wtw;(4bplrM8pMJrEk*?&JAR@CH7{uD z?{up?0hIipw6usHHAAE!&CuD zrXsNLdRX7W^`+b(&M$wV$xFFWMU}h%I3j7g0o-=5D%4yNOmFoXcP$mJw{aDf{)h}C z#u{3~m{^-aYt{|p=je-Y{hv!10 zx%vGi0nUxZt*t!{tG#$dX==n;K{p@Dgf3*7LTwYtw;`YFV;mY#!da4%EJYj3-xZZ+ ziCE9^m!y@NV*=Cy%_F8vF=`RZg?!rq-V9G7qm_0G(AJhT?jPkB@j94&@{zUW zB*i9ScyWzQa6(>Dksp$h=}Z1(Dlv3||K&fk-G<-4dD*W?$&8NOGw8E?zhQf?PdyrM zPEMiYz~FC*O9_R9jZ6-m%m?aV6MW4VniE(<-E1V!bT~;sL&c)_QN)WVG=@CO^S+8D za<6rL*pS}Q0t5m_%j=6`wm&Y;Q$$fk)~XruFp&K6*6moy#gbBdX;q}t@1QOF!uL`O zIJGW-mzk5`IMuEhH6QORIS^ImUv5#(qT z5sKF<G#R3vBs%cWa8R@E%GS zwqIK!@aQvhYK^O@P6*f)Gca6f6Jq8$`8zh`a{}aQ5%}3$A(0NBKnoXgs5QLG^Euw$ zSu$qkgT9Of5{1hK_cx>C1Y7NNMzBJHxw1>?8J%RmqfkdVKDNy5ePFe^j+}kTtSEFt z7Hw3x#;MdUS%~?Gh*7_o@&y0&#Sgm~`^2U>bFXLMe^C{sFk@ncY zQI{J{w!7lU_y)$J0JtSH7Yr?)AR@SV*S-($3aeEMHg^4=x`Yz_EtnC>SPognvVLKa^LmSZ5nfQAPb!C>JeEC1#H!WPnzxi-qn$n$w83>V<&}1M z>9adGH@D*|ZItJy|J6)yY2e$aHUlfO{!HXH$dQ7&3EgRSV(^U#9D5#rm6XV><0OZg zu$2E=cMyQ|Ur6_>8Cs2s|GAlStqQy-*X;FDX9Mt&BUgGUi;k3R*wJbc^Lie?>ULN! zxNyaR-NBSyIa=8upj62wKYN6NEVf3<_WiZ2W;&|;OPBw&UXa_tkq>={2uw_XmVJ+Y zbTpDyiK3c(mvdHE+^<#JJL$m&z~+)9xHupUq3NHV+r-ksrYj#_DKDYfa#o<=p9u*r z15R3A3Ej>Zb%y z_IBab3&>?Q=2T>IO0OPO4{O!<+q!rnznwawV0bcw?JiP=OPYT=;gsG<5VvW(Od9GL zfO!a>PYaOs8%*9_1qFz5qGV@X+n=(S=TS%?U%r346g~6`1t)LPT=LYO5>wlXhr6!& zN}sgD%K?>WG;4?eqY&yTi%zR43K-!XFB{!vy6jwTM@;7z67G5Ju_AU$znX;F|s+v;6+SU(Pf zpuA1A$lNP_M6idEv)dwFV_ z!}0!#RF7|yyp7oaldt=*6UA1sR2!=anw}7 z?=#Jgh;^Q9G?FL26YzWr7f_@Fg}OFYJ@lVG#BZ)DzGm-rgzR$-Evj>I|trVA!oj*nbQ}&pyRMOjM0arrK0ew8HcFcV@4Iwc(C+HybZbk>EP^G zU&u!I$TtH?2pgIC+Pu%GwS}ePu+Kl3jhPE3<;@<^)x^z1I(F-Y4v1`6`ym5zwOBs~ z89o`;ZzvH1K}}XvVuD$(g$Jcb`yVwF`#VNFsq87$!*JR;ICo&dLrd(NDDXlbJ0Bkpb7(a ziB?ZhOP&b)xL+|=q$J8z#vW~#f;&~V9%=WD3Vwng;qMdfmJI+uTT}Ei88lkp|H)s+ zUWNg8@!AdVecVp7fUw^(_ei=B#v;v`8l2wals{`j^%o-wdK0+4Bm!3fSu1sVc&uxD zKq(Er_O^FmKx6LcqDvTtKMbeh;9K|Ic5+yJL#FUDx_^5srmBN}3y&o#ieT%ar;CVSGq&PK6NxM~d#NeVK5Rw9f z415+-dEB4o>qj4R8G2THy!V~5H}|F#71DVd;}d7(tC_o~srb@3_;0P9srSt>DPmA7 z>75EA>9t1cH5=fs0e!aZ$`GQpAfSZ@wGluq8o)k3hgP=4fNf*%@F2gsA-iyeeg96m zyP6OAxK~Coz2O_Rvy@SSF^Wu+<$p3W63(YmGJIHV%JH@Ri{BKqF9(W5#?L4pUfFr? zgP^ftnsa;~c$E)ags@q^OT6rx>jrbdIqPU61tE`x zNq&m{H*&pdjYSa5r~moh`c6gr)z0v6O-@qgvU64Ee_AV`YKuK#2!51x+<~XTIF1E$ z{t=oeO(U!WU1p5F*CT{kD^5qn*(~E&$6-$D%CBDh*r=DnaktgOU?EJX`tjB4Tr#llp8rmYPbFBFY$JqlrA~oq(2=Sl3HUO;c#MxsBa{{&1HoYZipS z>pw(#J~yo<68I%CU3ZWF;6ibHc=J|MHAOXL7*zZ~4xyYyP6d=*Y=7zhR#zn`txopv zQuxK5-9!s(&F14%3K)SXPzJeCV=Rev9xx+ywEue-eR_mvwGAd*$m;FeVL~Zhb5nnYoo)bl@QZKc zu{1qq^A1+fZb%K(Q4vQQID7q=wZ|-{tYR&2866yAb$$#qD;zAmUSd)efc<7<`Ri8M z@%>Qb)1b|w<+g~Vc*2-JLxXL}=J|e|{OG8utLVv>OY4s0c8vfV)W!M91)0-VLPKm> zoQaifJ6tFKwI`5eiaR#nrM98+Pk@XDhQ8reji%IH;RloUi!(NdYsR0W(#tx!Ii2D) z;$M;;Z-W`*uY?m=%w8nyr|qt(jSt@87jD1q7=EW(Q*}|S)s}T;ph_7VpRqHL8m`9Z zHmny1%AvE&{_H|Z$C*e+V0Mx>-7qQIQ>%ZnrV()CcBnA_ioWI1dp)VBH-6D^Z!#uw zGm^0Q=3SVE)~+E+^H*b6-rpHD%m8A0Q>e34{EIvU@^c5hf60Pq$6R4xcP;ZLq5ZHn z+rLK_is#A}{cnjNV6y#Hsp}>zCySvfp!^ocwbuD)iQVc!a;LcBCtOwUnq<7au}iI^ zMamzap?vU{bJ*|;EmdW8S%z26khsVyUpr2)3RZpb4E!NO2pMA!lN=`cOb`zR5Oz|^i!`*DCJ z7bLjLNqMssO!Wmx!&b^TG7b$n7R_zt;2Wz=`UrW@ zg~+)Y>Z@J62#U(Sh9S$5V1bOI2M(48%#HYRi8*(r9#>rC9MA z5(6r}X5l;+=aVN{9v?h_qX4G!ld!7jXADsA@7W$2f^E^}4jJh5E}0{M+nt$(Wn*O9 zgqekjW~;iY?qfR9!j0>`iJMjOqQNU_r6w0r5Z&?lY8!Kv>t>o>H%sa}a}*dEwRsJ+ zCWY6GXR#Etu=0|RQvh&PRX=KhaU6@-(+KCp6Hq&yH8mUQQH_~`7S;?pUggG6V&@Yx z6_2)C`@v`rMx=|F z)i356C-@x}8!3K1lquJap;zEgrYA#vL`^P*2>rXT<(@9e(49ETMmz`YkO+A4kMmI` zrraluZS}}!VPR3VzF)L&(wLFmMvpTL7nF7$m#wC-ZjJfL--G*$yT9Ku7Bb%YU>14X}{dYky^{#3L_8Fyqpx9Zy=5S;bx z@sa=!a{r|XW3dc1nv}MC!aKH^_4%YyRk-k?kpsR{M5v*%?6COFC}5>f?2?!I!;tapzEL;eBS ziNo^c-fze(g*$gN7MOk|OQU|S(=EW3(*<++iQY)@Ae4Zk=L?l zZ9~OG6GF*n4uuB9xo<}CEMJM8M2%NwuRd~GT<{Fi z5D;nLdlw=C1wIwdGhx~1>;#O&Ba>+*1pmHx%+rE-HMw37TsPwlS#zD#bvFvJOT#o| zqlda>>oue;*+UE<>CUhE8~Xek4yFR|6@ zEPYo4R@orM<%bu*{Kd04|BMj_$g%HLnj+fGm-g)=@m=6P*e4S(#k}6g--^G#66Y%Z z2W)iu2V@{@>hX=yh?NNV(vdt>l&AvmiMk8nQRqz?{h74R*J2xJ2YpjH+tzU-d0cEa z@KX9ZOpS8Y)ynU{M;Z8@v)iT8BV~{GYp)&&gg?hv!lI@AfQKa;gfLU+GSjrSI{4e; zR{jr|jp7{@bRzHt$!kVe7fN@xV<(ZK%)$FxzF@JYZFnnz%34z>rf3&)Uw~=T<1BochtwVl#*zG zXh2%ABoMF)O9bzAw(TALr`XTN!O*Ca_t|2mMxpti|2Lw`7k1+Vq zP|@WoatK!@Klt8gr$W4v9#_>y*h^@<%-!jB0rOk_8ueUI?MdzOIPJIX&i$DQrj2{2 zdX$6~8#J2DbFgveCfEmaL4D%BoToX$I`V7M(>};Hd_59xYH6WwwBa`1UwYcw2;zW) z@}iME_?@rB(*pb?kT^jYJu{Lb90lU^xQRvXAhBdpp#Q1;21GKIn(VOR!)o%;{Y6WU zhy56b*|BHq(eX3+E;yoq^II4!I`I3ZC{mSmJ*NA_bi)jBPJoD>YfgrN_@q4FVFb&UbLFbe<4i5|4Vj$IdtYVYBa`Y0BqE^`}Gh$n={#4-wux@GQBzE z6j=1{x!k7}+_4&w=g}W`F7`}7mkx5q0N|C?c7r{!GA~1e%dHshU8&Y?%fnzLTFfrr1(x9Q>zg3ZsEO$|7m-z2*)-Q`(G7cqxY{rD#>D|58&Jwrbh>VFf=*q zg1+`Uy7X2&!?+NjRt8R=O-k)jkJ^JLnaGny_apP1LqKoE-_w^tdSu9m#5uts`FE{< zw#H(SXG~yUjZ@aoM2KP{^EHpYtdi=$noMg;QAlQsmHTxQT=Sv(S^cN|A9dyA{qJ~gu9d6^#9IHfZ82PkNSd^xVq@)MR5tj$m60k_zRcW!jV+ICD7qrGGk2HEW9f5 zqV!B~>o^-_)@hx1Vf+pLB$GlyfIVKnf`lYWDqp#DcSrMP1S)v61+!k({ZJ&cZUN-x zlLm#zZAt5QR)og@7ze#e^cGJ~^;1P|u46TEJb(?VClEQzL~=Yv3N3Yik*x^~63psS zc5yU)Z}m;#WN^~$#4dWqyqs8i4gl42i+|)yR7t@WW(uY=)@e|ThA zbh^s!3D+QT1ao!>7F2oWRqkC>)Y8M25wm7(=f09kVmY@CMGmR_&1c>h3MG`*wvQSH zN1zNi25f^vRly&%{32p)NKY1G-+XkbTM*cr9ECkro5i&kB}=&lJM-&qJU~qiWI2rd zk4vP%M^RQNhEr-%`UhnOz~#wx?si$Vad8tjkOR-nwV{K+v%E*>Cl~tvM%@d?9C~>@ zF5lnzcfkEKp4E{?d^KOGF#>PEe^aSB&-rmo=R#!Qar1dAEBDcT#vHd=)Xn{AH;E_G z)L*avUPSd#Pci^I_tM2t{^PgWe#IL?&cmO-6K7s3%=NhXO=%%O-hjsJL@$6urS9x7 zd-0}SomCf)fA2-nicRdk**N=)&~TrYi=`n`0PyomMfR79FGOg4uO^KqFkEUbU`0PJJi5x-)z8+m3{TAf)R4r^&O z0-*~1g~yuUbO(Ai!WgGnWNe2&|C0YAQY!-4@Q?(A%*iEtX-*wD5(Yq)t>(oN;&BOf zzn+J0?{hAWa41aI$D~e^m1`;`jDKboPQ+fhq8ats?)dHv?5geVlO!j|_pp!tmO_o+ zY;l|4J>S)Hk0oy@)r30o*E2>#zEl!k3+DZZF)nC%_bo2$3!u+7tLqdIvx~NH;9Wn( z{_%j(^sZG}@Hl+&gLQe6`vDigKS_X)&*@Zhs$szkurjOdxAL3#8(ByA?c*vzBSSu&JFX*E0hZ{dd8+s)=*Rj_l3t*C>ri2K=mSp@^dq-QJcn|}F3lKe+-$KwIA z`cc^+myyC(273ZNndB<1Pw3eH)r1iQhzK^>3i(~%h-kJPXmV0zOBlL3V%{Zc6`6Nh zX+Az?U=h4spD*v-J53eH(97tL(R0FrkEe00%No7$cpqU9DGBoU>JR1yf5Ee@1p3>4 zh7~%wG##8j`^akMK?Owk$=@UngUcQqmCdntnx&TQ5yN!P{pr9g5tUW80=*}m9 z@61V;A2T=chVh1!^lGZS0k9YcImh}?kUh&v97=CrE1Zig9VfHg;{q>xEwc4kh*Da&1?|8 zyU3NjDbdCWz#C8M2@q%=Lix7RPUe_C#l&p}89(eBvx{a#`oRMNDO@F;gyz4^1p}uD zGUJvaY;mudUXdiO-gS!KZV`1Dd{!t2DX)w)anklR{VBi?0W21WIu3M1V_DsHS*v59 zybNurn&s(-|8t2jL#%No17FOMl6OA6@l6}3GQd$UlH1#6*+u!#`0jv!LE(K0Npq<{ zGyA4WawyRqfu`(am7U0Aa^=-*=0%EflS9G)y0x|!ZS>3~O9U@VW{(H-ElAtQ^0O{6 zFfv-KLhXpG1HlgfLtX>*%zD7Q>HtZg@>MLCXbft0fpkjY>pq4*JbSr?zSw4j1PbRC z7q;aV$VV>-d(M!IR%1AjL(#OX9@8>cua2Wy8!e!Zm-p5b0&L_j={qFLWO#BI$DV_5 z8P>I(U(iQOwcEb+-zJ|?vOUsQh)HP=*HEZg0^&Ro0bJPlKoUeI73096sH+XMO@Eb7 zTRQUee>4H6_OXHIoGo*O;5VG*xIn&VIJ%LoC(+(4MZf*SP=FS4bA=GGg%x$&laH2f z3dJ~BJ3u}zxxR`ht;~gvML+{uZGH*rwwMzF@2DW?#o_05Re&y1XfqI?uEwEv&n^Hy z;Oern?@p%b_G^2L%nW1n!@FIR*96#_#LL{GuCL$Abg4bt>Z>-Q*<+};scCU=%<^$S z1|gIW-6Bn-gmvLGW^+R3sD2EP*wFJsZtYoJL>APMp9o`FZK25)vvoDr5dElp&!; zX(+HCuk&!Y8$R3(!&KIdi=j4ZQI@cZDu460T0>K}cPN}{1?u?*#J`+7pQ}twD(FaI zdo_Dn9FXR)krX{t;r$VmMRR99`Oo*Qqu2=3kdc7{$bUejW+emEQdIimMa)^~?Ut1T z!x$4B^RsVApYI1j3Ob5IdfaUT{hSEt+K~HutY^;zwkfx$2r=-Y&T*s8a3aoNeCTBT zebWP^;-#+poBB=|P_wbl)Yf4>RBMGVVSlRy3B$IY=u2*igS5xhx^yviloK#5T_gtXiDXqBA+38z?l6f2cf+q5We-Zfu`e3%uo`f&8m5SBX_r<% z`uRcb?lODV4RFI4!h$TS1yi}W8>(6gqxqqx&E(~(OP-&5ujt~Lf zFf_$-zi2j}-4^SW_8!oXJ8YaiLw|OH_6%ciJYClJ-uc9_=zF}XUq?c4(En zUrnxXlsolH39-_5fCliT3Cx`P4W5oT^~D>iL1pg=t2ZGiIj9d1{8E@0t{)>|S76j{ z2QnKmt^$mM!?Ap@?tafLIpEUZ;;e_E9czfJ-Me02Yi;dY5#K^n53(e$ zZx+KOyuu{CMyGwBk%UUj)!L9IckGBYh&x0)JEyDdOHU3g(myv`u&PJ)WRs?h=gW;i z!xlb&n*DIyU@>P!$IKBN3XZfI9Al+pb9)<%0%c&#QUq7zSR*(1oB($AteTlpRfcTs9qMrjgw`f3O7SCeHCEI@NX4%G;19}fIEH9(=#ltmydHxZAmYIq~i7gkZ41f&boYR@c*$ z1RcCh5y7LO!V2JEg#suvLg|CY^NvJvUIWoXRE87|`qT;3Z2UH=8X}Fqu0ePf45_Q0 zH-48xn5$rg9^U^RiBpr1T()Nz{@hemw>{x^TyO&ZI6dU&(+&|-+CgO~-Bkcq&e_01 zZTlCR1@XoX%mP8sBfLu%v*_!C*SUt77j12n?L_jt@6om?z|Ha#hcrsCi z)a!XXks#v=6F%Z@Bwv=`92C3@WdL^+jE~b~=y_p6Wlp0z1^@iNOK(w$X`B!0(GD%cVSg`Dc)cU(C&K?Y`V+LV6C1gxnDPDk(LJqw;X%JlCZ50Kj$HNrQ{-4yPtUZiE$f^D7ou{TKecYt@7O0~1SuSD#ON|XBMJ;w{X)%r$bY<^ z*WB#S*y^+AqTap%r^3}$5XQyjnsV-AiJ%^-wf~&Y$Z{I>pSgB&rlpUY|5w}3T)L>m_i{yo{kypC zftsMYB`=D{mANis#9oG=%Tp-2SE1NJDxRA0cc4_W0KQy2|1&0BFY#aa3X%6&{I#A{akV$!RRq2<0_ZW}a z&lfqK{6S_?&{SR|lbG{kQLXWtTzz3#4=g52N4s#G*+6 zXX+q4s`qwc4yxi5<8G>bT?dle4RRwc(#M-nR9<9Hg@sp%3%?!t^UBX3o_}RP{d?+2WXC@c@R38X3A-9Qw4P0cGcO_ zH(_N_?Iw^6jI#D04%3nB{yVBWIUf_^B08&SRFeO+G(1N_VLrAVJoXw(+>D0L`GQL& zK_nt$?>BzBFJ(#YzpRZ1C^H*Bzsbg?I=fRJ@tkXhy&oh~$IHTUL2RnarnYv!u(H9! zzOVmPRQy~3QoY6)y$9e72XB`)LbJ=?9A)F;x2KQY~U7h2hi_l|<^HS=>1 z2JAU{p9D)f&r+dYov8V_>!XJEfqugiF5^9vJ+hh`n+dVWs$C=7Me))STNn+KGwR|~ zUFCZsN-|zj};=Mbl)zfvU=;+HdG#c2%Ak0uD*_Ts9;QwpTglA^8&}!`eW+%Vi<~bC|A2H zUj)`?hP4jN#k&3*l1t7>NFHpEblAXe8&CgWu}w8JLYS#2lcpQsI+ zsVBLmq8J-q+59~}HZ z4sk==k^0Hl>1BgkO(LvEs9IEJxE3&+B7|UebSfm9tY&Jn07Zrp*Mz9t;z661@SZ<|tRP(tY4ao*4uB`jq) znvM%bnAgTcgIU01V|v&Qx3FCKXlExE&MMOc2Q^+>TO0m{VmL9Slzs?u!ib*dR=m_+ zHL-W>GE<(`;P)U_s?*c+lQvSnL6AreUSfPl$Dvdqgf$^sYXBnw)6tF76D)aYf}heJsyI8!zn8583ejinYaipn2LURkN zqN0Wv(ECJsX7Ydgm~;M5F*~1U^f?!jm%pYhIM3qVp+9r!W`Y_hWF{r>KYVaX5xFpY z9By7Wzq_C?S^wbI$;)c<)~qM0L&;#`pkvoMU9LEzYAh1w37H;8ZwoOGg<;;SnZ|Yr zU6s2c#keLMo5vTHcTffk3#599%QNZ8_#UV=^n9ca%y;WFx?*^nCg*T0n8ey1p0yGP zZgZ}|xaT?L9A8Pimy{V1pgluJ9;cqYl2zNqzidI^LJ#;zbN%b5>l1hjImpjdsCzh9 z^rMYs7fR_5H1S|$%o>mT^|{)9g%+$sWDB-QzE&{mqRFSX9`flmY2ZDcpxhQT{DDYktAKYqS$p$Api~l!C%&GO+{Mwn2v|H7qn7_9onqp7l#aT_aOBCJKxQXSJtfSM= zG8Uwq)~q?sE-&QyF5y^5!bv3`$EwtLCXksATb zqE8l=qFtFK@|Ask5ZNUqcHn{{jWmS|KWhF8H>ot68G)h}DViMpqEnUH=+8q(!AO1Q zf_X#2i+ga$mxoe-%lE48Qe2!OQ3pv^dvZ80<5kl4q%fUlQY*+$=P6RVjch!uEl6LJ zSt$DM7wed(Wt8C-CRM)1XQo1IGAwZ>EG5?H${t{_7J$<|3k%DqXDUrr?=eqLc}#8* z927BAOTTwqU*VbjoVEI8SWUfJg*jEE5@Mu4c>~C50c35pr-LmkqVy#e?W4Oa<3Qatk9)|@-t%D@xLmh(G^|rt4f3<-TX-PDY-e3NN^$oTDR2_Si25~KW;-8rj~OzSlMVV zP!MdnKfNe#&h2vA4aiYRcqfU*Mt+zQL_QE-bxf#j`MtDYNO+mHMbZ>Z?1b4|pUo{=;f1*c)W^@#u-OshD;t7MP*QV{sz&TX zNV{R9(N>eCrti>jl9FzHP$JU`h{z*wIa5^r+z}l;b{(lWznj~WF!h`ebdy>}Q zC;t^-B#|En=i@fRdXGGz*W~ooD2+q=15&aQ=HSSJP3?P88WI;sMlEd~1DkgDPNLnz z!~U{IhK`HR!|^QK>!1xvpK44;^IeGZ4FnxBM2A#nUh>ImcP6~PuAVSnNqVQ!((0c9 zF0I5*oBeNf;WL;Y7$G%m2I!ivZ=PumigDbGw83w#?i@_x{H-}tz2Hk;aD=zufBsEQ zV{m!fu^ZnGc#D$AvCeYy49kF`f&;7QewDz`(6^($_A@T7{a-gnDf&cVJS-k-qbllT zZ%s6027LPFNb8GsY1%4ci!a7G$zyyA;KwA$3DfC8ZK=`5OePQH>unXO@5XBaY$CFvb5Yu;lD$c&pJIA!x<#pDEe8`npC44=z%!e-3v(i z`0B|M7A_eHQ8kgq;FMR;{*3|&*8?`5|=XStF9E%H?s=JESJ%>QaFn|2=mV@ow~YZZ0gU>hh804zghn%!%anmm{2mY4Ek_pyk@?v)Y2M2QL zJqwGgyOo=pYTsmvtF`UN^`~*T!IwEfX7;~T6OUfVep90pBtS1bq z67yo<3Xa~4wC5wY=i4_Q;KM3F))IfS|8HQEQHRCBEdWQdbn;14oEkwOYUbd?8zTlL z^6p83C57Cr1qnJdl^2znBS#B^BN@k{t_NSbzA0cs_v_3ote5cIQiXm`FMZilO(6A8 zMzY)~q(uCJ)lWc@@x66u=H4TrG&@BXC5wzZv9;p6F`^XEd>Z_5%|9Xxk9oy!cpdAp zL6j(Zl_)z}os(5ish`EK3#H&Jx_-*eR*5r;;6mjl57+@;?4EmgMFNYKk#zI{y za}b{!;3vyHq_6q5U#^*3{C+L1q%IKjCUDI7C)iTPnbR3dfBkb`ge;-oJwNw*^Y%Ie#6aK4hEJ>oKm$STHyP@5#5# zBxEw%r4OnI-vvlozU{==S!)d3eY`D3s3*+m)5nvxexWQ$1y_0`+LGsQnJkIbxZ}c4 z3}^!4Y|WU4(&1nK)SZ?&A=Pom7ni5@Mp_)2!4HxFS0G&9aZffndIMucyh@dqw$i@$ z{W}oA{e$yn<7vYd?3t(4?n^aNBp<>JHviWLKlupYWTXw&|BlVFqFNFH*lRt>;A7Wl zszqO(Uu>^K0Guw?X&Oi zN7WXkqxWF7Vk=|DKxpA=EOtUCF%7;k(qEmB{N+?sRAgjI!MNWfB&x^De)^84lBtt2 zi4iJx#u;pg4n0#>|c;OeAY`Ekn*K6hd&T`hdUUtg6T3tHO?fZ z-5(}_K4{FC_^(IllUO$0i>V(|<<39Sx1}5625aNTYGVg$L5SO%9UrcmFJ~;&BPgQ1 zZ>U0_J{9E@TiV^KDD_qS%u2tjpmmF7u~QQ{R+9vySx4 z7G2Z*X0Q441t`}qt}~X?H{{z`;armqxy@_FYvPnHMnzC8nxcxLNw2Fht+w{3->c; zyKpIk1AAO&3|F^}3#swJ*hAO59w2BR|Gect@3ZW(sSyophGojJuSb?-yz}OO zkKDdYZxHNTIJ>AZJN$W9gR7%lKTJ*G&bobMu-SWY6z|-G`a1kA6UsbtWYkS~w3LLo zwdMMtSyI1_tS&K!F&9zR1^wd+EGt_YUArm&4l1ID*HIxUe)j!chTj2wisQN0T=Sj9 zOhrrbtgE1+z%q$jSg`s3)%Dg64DKVqzft_A+gf-UxmX=;Yx>mY*AN-#4JLmVF^ZvE}Jon7pGuJgU_v{m_Yfv_x%dyvO zN~J8Uf+C!40_B9KULLh4ZQ354xcdk}a;up2V6)@& z=;)XI$wvVvzSU&Q&Gf=fl z__?pmoa_;^45bg(k9Wq)nOjbu;KuLoTKzXEDXZ|Q5Y>Fc$Ci(C4e*MyPZmFHW#C~f7Sop_eF?84t)LOPB7@+_)LSulpp7-y>ga$&|B1{ z9W~+gc!I`xN{WAne^U!)Z*R|pncM#Ksl5(68}BjLuZXI&eh;Y=<=*{vHi+jrDr0qG zou}QDAz6BrLUxyR5tB8k9blD-hJ1Z~pSR?%$_!GnP{%}Z>8tR=!^ey~yg{YDMp`U{ zXY+yQKs>5yHKLX_80A(}gqr@8-u9Ysy4&g!b6;jyUgIW#eo7j!SvjC61JcrWGam|| z@7_98nr9>CeVQ9xym@&lLh5s5-Ls-cSdZW6Lvlv!hW|e1e4{>+7)YK==v3EEGxZj} zrv_r1X%rrh(w(%GC6=sGo)42uPaN{Jf+#kn9->p=ySBl?A@amvb&Y-R zw}pVE6@2wB%=-S%SvIeqL>CyT5;bVNd$d`|JaDy5OeN%_< znOClz$=M@bigzEb2?)tv6LM?&OK(ce4yC|%Y_E}eL;-xCzJCAyJ-L3?=l(J3{Sq-zZ7*v#8@rMBPbb+F{oS~~*kajP zxxo2>w@O61GnrDjrDk>c-~&~@tas9@oNMd?~faKEIP3n;?feiz6TCNLqRlq z7k%m;8WI{s5%H+~o<6qH5FI_~s;-5x&0+jO$Uxzh@_Wan#%WFN_QAQIRBIe6mmNj5 z7bADSF&a)X{s}+*F>>2#afEL6oE)8_9WdcaZ>vSM(Ft7+mz2N6!*tH?;O2{zO24HJ zUOg*S8LMewkl~Eur=yylk^2>lwPea4DuiVNuZ(;X>0^Gu*xMIjR5W|r>g)+YV+38fMTYh8GmYk=8Q6`WC8U1pc*<=7K;;ytNfa8HHlovL}F zdR`7?{^FsF1`w~XJd)MMn0tX#;kEXF_?hQ~tW4YE2rkIpezG`4qe*xuE%``Jw; zp6sza5F@)eYwsT}FAM}DjRyJI(AS}={IKf1hn-AbhM;~TawvWVr-f}Dy+jOePIx(A zdg@Rp%#uE&@1lcZMyAzG0!*0lcRxnalwg}$_6^k1z07|I1X;$2LUJ6jv#pPCGx_p9 z3%gT|W`7lg)!G$vH>AJ4DpjlTc~HEwcjz^W2EKHA47zL?|DxpKA-?YUyI+~%RA1DK3n5l^1EZY1QCdFTkIWS`@9~a22x~)I*^lo6?7%DOh zuRc0zWK}mbHykj4&-SaXE@0|n9Gl@zF{1eJN&6Ez$3%*p-M8GWbA&Cg6s0)jKk;e=$eAB#%QOl&m+6glv!_fkbWX$h%*HCWUg z*9=!2zU@qlID`5&`?jBozvxM zHJ5m>nm|3QV(#DLz|6DAn_M5_XKc$IbYBmNQCvLlkgQcG*%--pg?k}FHbT*P-z{wM z3X8w3`jniCEp?jzXSUUOTMu2|c7AB4TOe$aRq10bKUM=eMlPPqFg9x=&E?!l_^_%q zc*k~!)Y|M+2j^g~e9wt56?Hpv7B>BBP-ooD4sKD|zk17)vHuWPu!>GKB0D5%b;Zlg zbMen4A6wPeCv%gD-wxf zUnB#RqN0h)tGQfg&seoEls%h(TuaO=M!*w#=3R^Tya6d2e=CN|Xj>)0ijcFHr&3vk z<>ek|qekwSmY9XQGY!(avhz2#5Q3=eU64E(hYt^GSKZnj!u^RaH1Q|bik=7FnVaY0 zr^u%1d21i&Gk%U7ojxj-hM}^vnN}Cc4sJTf?X;GhdjIb?$%2%PgVO&+m5{NlcbCw% zb3v)WfwKP7t-(PKl7y0YuewLsC~Oz^1mQZ(7Iw@ctc>6wu{^GX8VLYL``TAs^p; zVd1`I2QB-JKgVLLy{XP--c~W9k?5>;9Cj&V)m(piG=D2(;noFHrft_?s8JE8BQir% zO4YI4KM+#O16Py*8Q9=Ze1Iemzm%ouwhMYbzE^?(cRE43h?=U_(V@qVt6&Mn&w7NOSohDRQF0+$h2>$v+!J`GxuvjQuEOgF4xt?p{^>{Cux&7}(jU zI_YsZ?)WKyWp7K)ZFY4d0wEX5_5m;HQ>&XWI_2T`-HZC!uD}Sn+N@n-pmj`x#~BQj6PjfBea|PJb!N$Lqv`WUpg?BEE#3+l6T)h}E@Q7Pe68k8W~CO} z>wn4lSaUU{=qgii^;L{0_gxii+=$pz`qM`P9b4pYHxnx4pBRLTY$+K8tCJhA7xtnG z`SP?M$Q5-l1C6FfiK&wF_Pv`tBRW+^eE?6mtll>HBY<(-%*WrBNtz{plgU&$LK8)> znj!v?O(PTv43UGfVq&Umb%>FNFpOIcL{YwSSvH%7z&BHfy(1HIl z%|Y)Qqip3+SK;@9}bP?!>vZ7B{ib{qb zpBpgBZ)gsdr2fiZO8i9rJGyU0)cs=lrd(K+{|voiW7c<}F`yUh8{`(?Nf=ck(s|}t zH4+SNOqjEJJTxra^rvl9L5gR(p}~4xlB@VeIo_+rC0i|9VS&WS_SKppdYH@<1^?(Mj(R>#=a2x_?uU zTsXmihn%}k)|Yg`oHZBYoN88yxBM&?7Bn*5qoxTM;@0H z>z6jH@O@=4yQ9b55}_emO zX(=s^~ZZPo_W ztQOV+5$D7_6EIXOn&WqD0MFQ~;(XkX?d@~TF5DpfU%V$sE@*0-7TePX<$@c4wI!q9 z{BuLtp0f)IKgPlb?`fZ(twu3^fVSl zK@v@oa2d20L~$^E##kT=`&zgEu^;KgEJylCNOsqBK45$Nu`mXb=Cji!W7kQvRBQTA zsS9?du!MOn$>EhNgGL({wezsJ6RQFt@CDy4A%4N%qnRhXcCk!&=*s&oHv^a6m6RK7 z=d!A=C50YsD%I}%_b;=%le%QRddFO$5$F@Wjug7J-?X1p9U6EzF0vJW0UQar?i-ZwUTi4CF7@eN|?y z<1{qb(4nv;_l0*ojiICk95k0?1&ox7K1ps0bOTiRGaGL(7g~^DFMr!d@Gp_S^Cf8r z8n1-$1>u%#`cfpiQ?S=V*iYIYQ@7~@E%*>#-duC2>qd-X~^SQyL4>mj_ zsFYYjqRncEmx#RZrcfrE2GAY^!^C+nD<=K4|EQwyNmFHFAG3UkrfejiRil{n+g(HC zTi~1)UfyJ2?p1P-2I3O*&UH7lX)u7p70is?D6&xN2;Jky=I8r2@iksVlZ60C9(8SA zmDrC|YH@9T&F4pVGeG3zV5?Ns!~5l%JsFK&*_I+61UA^>M|BdH#HQcV^48iMBCEuG zP+&_O5$HzS+&SZ-xMt2pzk=xRv+@PR4O0&uI>gUqJnR!af_fykN}~#XP_YI z@9-q~)M}%fT)WP&sq9K)uXpc=?zh%GVSHwEofKNneCkL5C&wCKF40t$QgpR#+{?Z>e@W_ADN_#Ud)b(G!UuP%{5qkcW?n7g0-jTN-^BPE<==x&8 zfji^8P29v{)HRZF!M5TiaS|Z8S8FA|csg=zDYac>vYJsk&zY>0!t`|ts6PY~U5V_Z z!~h*;)ox${>=lF0+q-Q?n14a8y*)dDOjd z`c)rzKvLuG>)nyx;sr!xo?JKs)Pw&COUFkA$Cnw5WW<5}yG=xp&7M;NFgD|jxod)x z-C9R6peNQ>!DeFm@qOcElWIH$-PhT7N(p5_+>F`NYb+g*<%%Rwgky2C*NRDv;C)xi#78caljB~geN z!XS_-%l`z8n4yA6m|$T)Yv_WKA5lSM(Mc_3UyhCp^)Ka=nkh76{u$(F16g|vnTSG9 zy6~rc!fNGW8)h3E9UM9WDB4ER49G|Blhy!eUAMqyh~D}bUS?I?Y-2+<$w8@bYB*Z~ ze9Y$}%zpSwn<+aQ;G>je=v906UAu>Cs_w)!biYPQ@}KLQ?U=cIsi9T|eN#E1$MyUR zHccvJE!kg-=byY0T#(9jb!|Eu6uv-O4IxbTK;XR`0vM3=0P+NaNZ-)Qe9acPpS`*= zM`w@};NzUq`3YP`b6{)f_0JjWKH3N&0`hMJs&`j(I*`pyQ%-N7Pk2H6a*qPxvt9rg z)}=QQrv*-~nhFunnWYk*{OIbwroIrrBE0xS!>sLR(g*>3!k=bIHyL93)|nA@5>@a- zw`MRa(qzr7-tc<(h#PT@NB^>~{f?EUs3XA@J8$uoByS}DnMed4>ekP-&oHIfQ`HaK z=vCzE|J;;0$5UuQ`9WHhiJH7oRfWhDC2S=1(RzBAx_Zg7DO(y0xDzm|-yr~eP)g_b z>=to5IlW*iv(K|j7qnNM&lfo#$WtX#681)>KP_c*Q$Vwf`A*oR{GI{7u-0q6wstdW z0O1G#y4pz!NxUeI{o{`1w)FX*cYnZ@uEFlY{;Uak>^uJdNm}AFTMlnmP%?$7SL~e8 z;iS>?wVMFHJ=9H<6e9?fPr7CDm{5Kg2w_w?p7UNZ#=;3^dcR zd(zbRShzIt%TA7r+$U)p@L1PC8lN*l*|whAb$f;>g0AQZeHU&jV!kvYRb3-xXGD`w zmGBR!cIk)GZl(P?DJ|EN2Zz}{yl)`(aScL1=6JjXNr$Vq$Ir;}>9`9RNx9L-J)nag zxO|>fprKOM7t1v+85Z_r+Tr9G#^lH6deP2~ zm%?io)G0w@{ch;C3mD;6o0$9$%PT(p)*|lo+B%Lmj0KT5W-_wLHcTB~VcIUn1Tfma zSNw{o5_KdQBhTO16~H@h+(TO@t+Z-TzN)opyUV!wS~0xR7StN`_0i$NnEhYI)O?`G z)Kw69nvV^*yqwpYP}$8gSt(Z2Z4=?_f$ha3e_~FxZkk2G(wzSDhJ4$LiwO-ln0`gx z200I{={E@nF&OCMOf~u*BXeIA0EhhQ@A#K*_Av=Wd=!t_eFHpxLZKp+e#4xU$ zJ$CF}bn;DrlfgB24l1;$wNFK2*#wNG$|h}h1q0sBYrOkB2x2=Z$fH(-T;9W}-=Ibl z&xHKUZX+bWt&BOoMnsWpLPhZzbhSi9SAv-Ga2IqcWeFt#RPR1SY^iAIv?+dN&`f#lQ#p(p z`4{bsKL3$fEZUj&gz$tyza^|}NF$_lK}vEbg(Ra2b8bIXKBa#zAyJ$jSzK@}jtS=S z2e=;NS7d7`dIE{uf`%g4Dran@Uhs=)xO{1$W>@-)GUi%b0ZZc>xKG-~i25y(VT%f` z_*INMl#{D3`zt!Y@_qFE77)av1QrFz8^+s=K4zV_X)20Q!H*uV2qoNty!^W@zF6|D z;6+lvXF+pW8fBd)8q28NkRZZel>e^HVL)gT+zVC~(?PdAB>Enn!3kX{h9SeC#0J7_ z#s)hh|C}E56?m2+xQN4XJb?D3bG!P?MCb)n{xSVR5IH;M_anq=>$ND(%Bd_()Yj6T zsG01H5jMfyZV3J%GQ{PWwfakNAD*4k`jkXJg6*}q8)r47NHouPn~45fui`uVBH4&O z&tKRYrV6E9A|O1Vq&COMf;_i9_xCMCYF%bPuWLPJjD;4iH{|?iZTm+Q2cAlT8dY#zvsT1WBDWb`~Piz z{oo$%XKN|zn*-e1E6T3L87HhsbD7eRICQmCjjrQXVGwmULzG%;{$k0%ZE;IUd>>T( z?UzJ+i1HKf0P_rO0n9!|aNiKA&8bWRypd25B1UnW!N<8X8P84-XJ8P-u43}E{8P1O z-Lt2CkLcI@oLU?0Y2Wy5%NQTIHWB<`MLhWRi^xiIrwacjAT8>*KsG(kXSf6{j8Lm} zKzdM-ecTE)&gr%Q1(T7+16$K{r+!IP))CfE_K>|rTCM1(;TD#C0x8;rWb=zHDckOl{n zjCBC0$-{1gnjsfx37Mp$zHA`YzY9klSiJKM97JXRo|3w7Hk?iU?Sa__5zCIPyDI;-0&@9 zd_5>>-Ez2m3ShO?M~FYw3z1;D^rB(5HOg>p#4PdHPr!Qa-S6P$xYtR<16lAi;&-k! z>-OP;;HD=6X~$w42`Kh^%wN6k;QX=;RtUSyGDW$)&k?(L*CDmVzS`KZYLWI4n+hPx z)<}r|2O}A2;}|t<Os7S9(CPMf5h-wqGfckcIFw>dL(%oVq%cV4}&~S^)D7(^kii z6Jiv6!U?t)?B+qXfVevV>3Iv^37d-x6{$WvLJ`Oqze%y7Us3G>H$@62x1@+T@en_^ z9{WJ4$o!`isR$}uDjB-{Q9J;-8yW;3b3V#`|MWNYHURRwg|z(813b&$7vscOJeVFY z+}pdo1PykpP;?Zs==HW8gPhR?IM%H~@F7^3%(eYk216<%p5VwGSWKwGVee0G}ZVg^1aJjKeFx|GybKhRuA=F{+_+jKM=;D@}?d&0=m6ihyjujnG zR}IDLQC7BQ+f4AWMgr#4-oQALK37>KqTWN<1*8CqxdB7JXf?hf-i}*ThjC^PQ{4yQ z@}^!Q38-iLfCn6y3hB#(LI|VNi1rwM~Tid=m`~WLC89mLZ=b9XJ8bQm&FM6 z+&6^E5e?oCDG)aJ@J=@LvI&i<-4wS4P2Uno=blY}-VGR(N9;@#M0jSU4CkdL@wBNEB(>7&2G1RI14l6>dA<<)WPSGv zS)w5`iZnW(z)o6ZF?tBOD>uYH{~H1k=y*2t0+q^Q0@xGlRZ%cqUSCm#LN3~ZSUIN0 zixqb6#NHQS$MNCtvGBnPQIfp^)#hJn#i{0iQBBouSB0E&!O@gsG52O`ida5uMuh}Q zy^m?ovf6vWU&eI8?$$zcoC0Uft;N6Pj80vbhkB0k05pq~g_t20DKCiMJ0jviNuWoI zCBw-N%UOMCYiWEN9c^kVhd}?GC!{L;P?9!s_pHA=%ps}p9rg$OUJ*Qx9~0N0X7%49 zasXY5%w#{K=G&&M>Y#FrP2B>FGODtiS8qI)VSw!lu@cr=l5__kkMUPQHtv%Snu_*d zbGAEc-mcRTCJD+Y-mt8$2QPcJrG5=q$3yCSzCiX3L-=ahruziPjKegP6$nhpW1<0N z<(kMzL@4-*kr$!HD^Ht>8B=wtTb zk{^Yef}7f`R|=j6at>y;aSUoXJaNWTR@3bWB@t+z3z_Zc1JC`5m!WB1dnNE9(g`;4W*X1J-BgWsXBE$mIyOr>uT%`ZiGGJ}=hX(MQW@hpMx{2|Azk+72lfrKd65Le z*OX|-``s{@FxZd54Nrs~NHpepI>yLY&v2Quw1UPJW@fX1I3fq!Et89%e-xpfdOGx; zTF6cR)o5aS?kwuGrxKUjue0&I?C{&mj%)pj-rJv!SE2RLA9;&Z4gWNb{MQNoY)n;yenl=ssIiiQJjqK&PIXoyA(-J@g_s=W`J+hf4fi!%JiAKzg6ktP;a zRMiB22yFz_lkbvK+uwdBqNktph3=hmsk`1iAg;R6ZSvFe29RtmeZ0e`VdBagk%Z#| zgn2Y%B}JWATC^$e3m{i_%I>_tI|G;fELzyS_aVwQ{l2F~(75qp9`V#bAL(tV?BjvQ zR*N|`&66U_9b~FD58E^?)mBU0(QZ!f&6*v!Q?!oml##rM+T&|8)D718X_K9F-#n+d zzu9H9w;%Kp=|cE5b+v@;qYJ0e^PtK@A#8h$%q>2pL6u~XCOgTAY__1KW2E=Hif^y$ z=)lgf-%aWEQR9+mSxj;C*0b}spA+wXHCtdS{7PP&W923f9Ngj>f~?NcA@!oL&3^u9 zkCCcx0S7gY2zEy~YLz*}nEnW4zb_@?rY5Vtt1N*nVLF!^H({}7_upwswZ~1{S~8d2 z`ju4}z&bxU{APeLw?J)f_0E7GD38bfEFCJkmMw*2@)XYfIg8ZNulhnB<8Vo;ZV`7_zP-fyQ56j?j?9v(*!SQw`HIN&*oU_6Uhl1&o!QZd>d zH%DyAJIvO|4nt-VfZ2vmcU35StldARJFswUA+zUrWh6}lIa1EXD1ho&f8D)I2pyiR zQZ}G~N@#F*+m~}WEuklCQp&7eAO%Mgq7qp* zLqPlA1uL&Xa|Inlc9&O{Mm|D729hCI_g_Xq{}D!BN?gl(?d+eIJB@DscGS0vI5{Us zH)EmN7D=)+fpCuUvSo^cb@`}#Nm6sN=S+?l&ADIp+>xGMHy@YV3?t#W}VvrB2HeA_0ac_rTx!mLg0_4p;B0Iw%qUoA` z8q%o(fepOhTzx}kKaA#F@8sQwI=_#MJgqy|vhKwf@qI;Xj3~zPdzpL3-H6TWWL_d%V)~ z5gHhY7^v%`Mt}uf%STlK%K_dnSYY>^zXZ|E0KNE-13t?%svig-1fQy3-*742tk>|poQI8_ zPmqE@yf833^*tE2T%5sgbhcb3eOmp~-hC{u>ufCgb69}m5PMn~V^cKU#In@PAP|BC zNJxPa=P|VKGiX3TJ-V0_1vX6s7av@xfe=O!Sq!XH0}TD^2@h%{(R=&dv-d~fod<~q zmZTqW(XH@dI1x~qN_D_D6fBMq($^N$Rz#$cTnf&GF+e4S^%?C~$KpxUg z{U-)@3^xLZEj)%pqBZ=*ANxq7xo=o9x54zhq+0?iG@Y7Gf}@&Joy;$a$Ekk1FS!&|LkkwGGe#0Z1*EcC-Z z2<))%eT6{?;AV|j0j!c1Dl$|YMQgOEP~gTLmfX?2C%gcqYSYlHb(fWTi8&hSGIM^C zV{$eSf`Wn}_8o&2x4_Jlfh|lDMY^535>W@W-?dP`j{|YS`Nw&cyp`d>b~cHu(ZM#H z91358sTydSVHkvXgg{D|jMImk=wbmKuG`zn=QiDN0G;S&0WHA0xAovcrId`o2=yj7*7{#KrrtDj?i3@D9Gk zYUJX~enK!pK>}hNIUrG+$#7Ij1i~QGx&1}gm2w!fBcOV&`OSnBXR<81!~6^8Y#4(4I`PRfn`{}WT;lTE-^_gei3zm-RzU6>mXU)8Mg8%T)EdyzljV7C4VQmD}tJY~kzah;s$i~k#3 z3!-~ITbKmx?bV7?BWB{t_^Xjs3~}f=WZL)rz;+sqi_yg=%QvqxDCz&XfgHryN8yas zuTF}EJ}fSqh*Lc4ME0=z{nN1RA#Om6trb4LrfKkjM?^kFVIYP&anYoOT9{-?iC&m# z6Tp7>2ljHD5f^$e&>3!}8d$J9vVm+b?e$AmCJR#@!St(#gfC(!ur< z19l!h5C_v!I zB+`hkS*CjE#?3WR4zeg(pZ#iu86ab8m0JaN%r=duI-@_}59thr@E{nd*9?Ai#~q1_ zvExF|V{)ts(CXudSd@9MTe$Vfv1KPfR(PP6(-baJ!o@l8*p{K`$aTe?l+NLzt-Wbykhbf@EUd5UygNRdlqqQbHhtjgdbbH2?%PIYEP^I9j0kR52 zdtr(rM*|(n1+4#&+qx`o&_Bn{Z2*=5cVAH-g3j`Ug?Z2AcHUaq|v4=By(RzbkpVPKdK$q{9a8g=~+hm63i{tC4mkkA87s zc8!y9yWMw@{)Y*nMlcc+bqTK=q6%TW2$CB*Xw@3{s$sEDSR&$&yEKR1KE_Ccv+=@rCaj*^Bfs2P+mko(OZr5Cw=Y!6eG# zkIw*0yVa8E60hr}SI+?TnEk${v>m9iGMpJhF0vhDu=f;C2%-ha^O{>+y2UeK+Udu( zjztWapwv|Q934cG#Em-O1NukmWt(Vaf@85O%4l7+T(P+jOGETdE4Y6rtm1SX9l`5W z-(rj@*n==J zz(~qs7M(%ZE*9cC;u*|%bhi$4`!{1@BU}`>w#Edzh}npy)+t<%Ia+DM-%<(r@xItR zp{&pmjRNi!#uIDQq6NbsW)RQ9#udBYHe9@Mh-VsC@USl~d=nKzEBbQzcpZ}tphD3d z>G4p5P3sVAm>S>GFOW~N_()!qk4RTAYM&qR0$6Og&`A)7g1pqbf(B*1iNumeSQhID zXUE)P@QfmQez_pbCKSdiKq$Z5AVi-JILv*JMsJsC(gTR`Uje}9L}#$yVs~jb_|LPY z<9jk$Ip*2J>ie!?kt~@9L_*fXAnXXOC3*=jWy>~PF*z;>FKTBJ*Esd$;@CVF&7P8@ zON1oP3x+gGT;bxu_z2W0a#_s`!&a2u5`BAZ1np3I{COxiAt)oLb!_2FYGUJp5<^gY z9V^ydMO&ZzC~#jql%kBn(p-RFA!7OqVKD;Smg;?2Y+NBz0umr#qbfx2?^L*Q zvll_22qUZ2*1Z&0*MNxO)E`YSQ`ft@dI3I!`s2D%`? zKU-!1UGkO|nHCb|KcdXgw0-u2D`wz>(n)vioDJ7<2>d=yR~Y2d#TzrmMMEzXCgFw3 zp@9|SZa6TQlBSX=8KycoFnX{XE}ask#A%l6!&Dq4EP1q_dNZ7f%vFJ$YbuIo17Srw zdo#?W8(qp4ToA0r?C#1&8Dv7@>dS^W!-qH-PP|wcCkk))u@}8unIfYrbcBB=lbWuY z$y-t|H7*00&FJ2GAgHT+8vZo>WrDGx4m)TdbxaX+n!9|vbcFbfN00m6 z**XSs6(9$1X7G3>G&R4!E^&qJBAfd>TaW^^8WA)v6$A2U(f&hyAqmu-F1v+b|dSU^;hfPw0lf*9VJ0@Mu^myon=R0^yjCrDe$fQYFTN zO5xLCH)&_Hi~Dhe3W3{57YGc|-7;}9B~Ne~C?Yb~l11JnyhBfa*soSh6+h~-B0WdW zu2bG(%Dnr+2MGU(L8n%ds1kU()&!0k6Gr%R<)=RUk za-5S=`q}u1fwA>BH$bon{002LuyMhEi(~hJH~_a>A%r`C!Bs9fSmQh<-jd_eHe#w2 z*Ud8p@d0t9kt!FV4G=;v`k7^8L^AY8Odz2?coYe`MCGOli`hJ{Uu6qnJ1n19tPui$ z){&^o1Ftb*ogayb3x4j4*gjA3Jq+H;~(UTchFq9E%4diF)1pXU1KMve5D*B z*rywGXkMqxDGJz~pNSe>d^dUPs4iOk{Vw|VXmRuhv-h~FwzmxzX9y}+k@xp2Cq=n? zKCE^v1ssg8>b>~Qh1)bI;6z3-uxdXYVz2h`n6c5>U)#g{Dhc6hO;Eix3KZ6 z2)XfgS>0c);9iy@T`WCYDMyS{Oe>fJ5bQ}i&DDpgADSir582g1)85c#;qpXOipreX z4QQBf!kOq^bkMxY8F%=gsdL6{dq`FWY&nPUVJUz}M@L+MS@z+U9O4{F`w|a`zJ9E@ zF~f3nDHxcTI0*^K3T1L-$)y^g@huUzyik?S3is|~LnNUIIM!kmObFM;Eg zqV#3f#xd_Ja9abM81(Kq;Md0P5wPx^a%@mYVp*JK*MgBM24jNw4Zk(c4*xlm#kag; zy3Cz<+mb=i+8VjLyBh=R&h7Bbwxg4Ec6oW?c!j>jAw{KP%*qgbv(dq|ohki`^5?^h zn!7534he;*x4cSH@eE@N`zI>Lm}5Zg@e?%Lst+ove060SvFHDhCWNlEyLjMfFU zZMl~l&+&1|m3wZ(I~6hu2=(N&HKpL$=TjM&gF30Ob!P>gozz7~1_p+z zA3sWJYx6rge6w@1tE%k^zkiRmS&Y~VQi!AIFdpH%Z4LW@Vi+P{*mY2wMrJ!4RVyXE z?jkXTQb#^kb~SLo9uRjZKulOK+vhgF^GTi@J{W-yF>L;ac^!5@YArl8MUtGxhNrAl zRQ^u&#z5Y{nb_~40zJyUOx-c?Fw)8sv=zYXosq0aR>ke*(I;LSt zY!v1{%ON5X%fZp0M&qmfBsd8l>}~a{8T{rQ6~%>77n~hFsE)G7H?(Kro_}h2nZJ3q z`a+D1eNk~LK^SkL>XNjsOVc=|8w$uQXY2@14IMDc&dy$K`O9;$+MW`ZR-%>ArL>qc zXot4U>Eg3tBnO}iB{>=Asjp^~VzR?UNyCjw$3>O3akMS!s)4JUi4mhH%e|kqsTIdM z7Qa5ydu3*eM9#@2xH}amFJcuN2J$)gkY z$;jVvlr7CNdYeR4ME5~IHU!CmC}9@-xqsvvPQ7DWu`qAvqSU9c*HH!~wWaxK=Wzf0 zA*uWh4IxFr_xEXwznA7_XXV^(IsW`%fT?$2zRI>GmA&@jdrd?+ie#_S`@B*YFT$W} zMrDCmQ972fb_yzCJAXYPY0PNC<$WNaY@QsTO&$jv2NE`O}@a&-&3A?pIaTCnr%6Gc@Q)JN|n$ez=`zXdrc*ez_JuRT96vkjQB99 zTh6inwJS{crLD#;Jq=&(AwB7j2!YB1T)Yu`Z63Sr{_#6IW?Mcl%EnK_F=t!1#A8xm zC7zHk`sj3IBDzEx5Kh_y9Bi+e$eXy%uimDT{P^nF8ivsgjEM0Xv2@H^B3uIrq8CRY zCG1FhK4;)7bjl6B9y9YyB$0xG@o|L~`>m1bya(sebFW78VTCRc)^INOE~6A{s`C6J zCjf@IsfDe0?}z6|!;w&rEhAV=0jnNJ)@R18-yXq|5m+}T*5tRV7pf;G?Q(&EtQHm) z!^Vf;A}-5$!xQT-0g`j{fwx z|F=J7TB*8fng)t~FK9h?v(y`I58Yh6%jWuP_`O5zK+V=iP4hd=Vv9ezlH_r4&_%Rm zMkaj1<)6+w-G>zYJKJu}C>f1+-raZU=$Iz-i$ecU2U^|uuu~LwAk^HDJM{yHfr`xQ z*Uu6$wA3Gb>qpVgjD8W1kNZRoLxi7zG9~IQ_N&wP=dBGM6P`;y3{;IAJ|@Wl7l13C z4G+eeG<4>FM16S`js^!!fuwvLuyHXWXoy;MjK`uiVNNuao(KsH{k<%0tA8IC5W%UA zmv@#NV^>#z3e^J3)SPvWsSh2Unr8-q|+XH>&A5%+;&UXDPfJN0Dm~TK+8+Byn;}ks$G%>jd)2#`o(GYg<8sz>&`0=8INr>>g;E{LN|&jQ=x}2 z7nf0&Uk8oQFmBj3JKP`gvKnYg-fkEl9gQ|VLA|D7@|j3XOYElwgqswrAU?S|c98sy zJW%iKCw?9+>oMN#WN;!th#o=?=e6q@v@mIbF&Gd#H1c?tqUwEJR&eu*K68C9=rq6T zlWxgS73LrB45Z=Y*&HPHwcwW-VIF`@$<|;E2f>Ef$}tp^Wi$TsR+1O8<>X86v})YY zN_8EiC-h^PpL0py+9Den83D{o`uHG<^jd$;(Vr@ofk_ifvq)r}n6rJ7dw;tO%n*Iv z&SNyMWXqqi_Te(Kv4D}}OI!T{hi&+}lZ9OXgrA~Cg!Cz?F@3MEW zYT*;V%MIU*&@JZD4PS1*%uFG?aPL^ z?ywU5d1&7Z`dfpNp)}adfo^v{N($V%^)2Mc9j)6iQVa-la$Sijp-B7ba|=Ove+yHIHp1MOBftbflp!;k;>MW3YylQ+ag$`02PFkcm=lUL2pM8;83a^VykfUt_>pph zqj_$QUF7*u^6fP6g)={JNA_&JHD_msl4(K$`#4{ezRwdVc`Za3-l!K}+%qZb(~eCV z27vq}T1@lNUm&7N@ggFc*i5WsEUS0OvE=9kZ<2eL98}}mDp`UJXQ0T?cWnqZdk5pPmUU4%d*eM zi-^D7iMagFly1f<$T_*V^v(`!dxE-t@cB~qV~ZYBr~kVByLe zg-k$N=@B3Zu?T!4?-wRxpCS?DBTJcKk)QD+aGwp;A5*Ccy!h5#!k3Nx!j8VZGUercj7>-&^s~**p-F0i!UW1c3!k_1 z*0nY}ZPcPDI3K8G&i-6kL(h7DVP{nk6huIgH0CnSBS(bwx*qrsYA^5I zk3a6D9g0-%tXu8b7%8YD8L$)3ACbU6|2rUDi8k(oG0XG?YnAJ1sI}Y{yr=#{zW@60 zOhuj4;B#q%(YyTfQ%_er*tuVWmG%1O>JW`3-jWTC*5Ur|T~znl3(d%Crx$OCB)p}Y ze!kB$iT!FL{(|0OhA`$L>f?7^4ypXhD%=qw5RoU-MKDXu%OuNWFcE98X|9HnC)Fc) z(8popY%78EFPwb9y_E*)*Ih!^+l_>Rvff@*-f;a=%Ui784N)ncOSKO-&VGKW&a*JG zICsRa&jEi|;;FKJ^82v=4RbKB3o9X=E)X3xc{?b;OGwzc&a5%+Cg`0pIg>2RGU7q+ zcLIf|;2c?ynTPVmbeFDLt9Nd^n?M~Z6}4X-L$D8v=AH3kpKBA*k<3h=ARwT->ner( zmN4-8Q`hTw3^d$-o+RXNDIp@8SrE=OGjfYu(;(MC356+;o!2}01mRv;#`%=?)2WJ{ zy9XUbWX}}zsZ_8}KW|Aqg zUcx%pp}Ls$=p4RI z#4^v9%VzgMZbXCN<3C~!-Ygnkae+K58=J(f9^=p18S0vvF+~xbOjbf|#bhIrbsWb- zLEG>Dh7C%3=$+J4GRHYsm;VFC%Y$3M=ep`So9zeYc5!NEjhf-2ANW6BsC3*Yk{) z7#{ufrhaPQ1?5 zd1Q1GTL@QQXrQOk@FMW){gDM`9G*;?-?=v^FnoQ;gj4nS>=^Pg^DW{1+2lPGN<3}Y zmtokr(k=LsKJD__RG|UTG9mP(KrWr<NRmg zdCC|9lnm347Ig<8;^V6eS2?(7G8D>#1l$NV%c<;EYAM_FzAh5R6$U<-_!A}t2Wp}} zM6`eGcY-y+0h=}~x1?s-wDSw_j91rnPh#i)^D_?o#|@PMj)!=s@K@r^De?!oX#O6E zd|*I3_yYI6*x0{(UrRN*==xPTqfwbQNsf(=Pt3vL<4^9m&_VHYUz08(F-$m&{vezR z^x%PD(dTy?@d94U6ts2hc=9LHd?eW$L6mO>C=$mi&eGQ2-jPO~TSp1+3xWIH4_jvb z|0V6Vhnxz|Ev(9476;cx*u)EVRAleuz+_PX=Pp5cCYMu9UD8o28XgIOyz<84=%u9t zIndw7-_o%`R+PW?O5jt>x+=F#Xckrpl&8X(`*={+lAYkN;c%KW3GvH-dwVWhK9>$} z|9aoONQHf&#%gl*#rBZ@za-|iD}Zmr?j_=ve*BBFCs4c0m~35Vc&!`&dpT*?!!)t` zqjejSX43VmO7l~_gCe$@eisS_noxAVlR2)j5JOuZqVPw}lz=tm%ET+0D-TmBEVrcM z4B+2FF|6m|U+<3S`_X%d#c0AGg4%2n^UEwg)^9w&vbKQjU8l&rnBo>;2_~Jb@#{LN zlPiAu>BA&WZ^^xHIlWXOBDKoF!>XLotc;K4xLU;&#JV(l=z?2~riezvz;AukVxfKN z&7eoj4Hf5(I*TOdlx^TY_<+~PF!Jkvm+v3_?$79QrU;;LhbY5gcY9LBC;Da+^fq^9 zDG|PHcU2aLf2OA|@ymKLlY4W0eel0|dADC_8p;jX8p)7Phh_xF`nC#QytQvJTWkw&2x zadKpVQF-f)%yyuf{^3D<8m+xkg85`&VAqj3Z{SPodmeOO%r<=^jX8T!VZ2bi$M5RJ z(Q3n4Ilp zq0Vx(_C^_RBxlT!;|#>EVclE4_%SRh+29@|#nGSN-T4Fw@j4M&F0wd@Ax{AK8=&=k zAJ8(VB6R)!2nOCMDJ0#BEe%aRdSkT8zBGn)h@$63Wj;ZZEYa7who`#t^BF#`+7Lq) z-Lo=V0@#z9!Bgb$r!)6lr6tdaabT)+x4i+`!JEf{6g=k%3CF=6|w(K~*YO$hYpJ~nmexL8?*KwR+^Cue9=MpEriYie9=j zAF!ybJ*=^jK0cm?*%MAe%?c%aAb_-LqD1W~0=<;`3|v3^DSH$pin0jP8)Nx*ZPQvz zkgWtu#z7pf@t*9=zn}!st+HW5&QBPzhu$s^Faag{%M!Y#a{bvO0J{&8oS!qWX1BMY zS@OM*5n)GjSdaTkIAllZBZ(_5(Fp~5`OYL5;7;0y951cczl^Xk26w~4L>C(5Z|rih z!T)|A5WETY8KJwtxzul6k`3?3AGJ+dg-uRlgBKbXR2%9k0zyytEzN=U;=CJX+ zhP1-*vCu>UG}DreC(Uj>H!K5$28j4~Y%Uj5Tl04Xc!!o`{4R5XTKe3NH1Dab?wZw> zVPx{I(V`IK=0etwI;g`75-zIp=wH4D`(NCCo^6sp7?~Cp3*y1}hTYmFril<5bbG{l z^`{!j_}peV`1thBXpPe3`ex22GF-N^@td`DfPVbh#B|mmV^Ow&w|Ks<#X=hGwDvg$ zgPdzNNPR61TYi@x@6R^lzMN1z&EYXqCLy9o-etyiMV*dI2PKd!{@LM?J{ zQyyu=)zL_R!aw;?K{O{L4E4#1h3be8>!@?O!Reh$C4b)IL@|=WxfNIFb8<2B$6&2c zAEO)*C&Z7)xfuJM0IUs6e|$YtX@nSf5M{xP%j+Zix2Naov(3)V6~&Hcfw01!n$(x& zn*Hi^o&`1I=tbQv>50`Iu82?2TaZjAbD zS?7s}^oZH710gp30tH(w7g9c-8$QveliRyHcS1jY-C?_Idt2MXlk=RF#f?ZxS_u?5 zV{BthU0xO)(z0W+apz(|d4bb(6$ME(%|8~Birz9WovLh5I%M4``h|uET%`J=Y={Gb zGqE3^4NP*k`F8JHpbJ(pi%z}@F43!nEC;2Vv)X|cmbYiNpvbbHVpO_tV$OPmh5^!F zP@C}b+?vjQ7Vsx?fxX$kN@s6|Ay*o22K{1=nGax+pO+h@ozp28Eb3TxIMoM z^N9QV`X{gT`iEePI({6qoK~19p+<&=b3N0QR-PpaRcAd5K3X$!~Q)Vo1_!g zFuv&8ctx6$&m?v}?pHgl| zXR`>wwdQC=eYkSSUvY$D*Q<>*5isC6vbgGc?$O8tx?=uc-Z2uVfgH`noqC(!B7L^A zGknnP4=JQa`9>kuSH1p^)#|3DIFL!ziAhnwtqR|sez&M+QqgB+5W^FUNRcto;B-l* zk|$II?F4eo35p=K(Z+?>&gA95&LjlK!>6N?MFfQ+;|swt74V)Kn6L2M{r!7AuP9np zvZvIL;f83|n{e(h@wkb6dDzlIko%g}qe_XeBNi07ZE|+-)hf$q@mort}dhJO@wrGsrI2PLbd;c*_8)z zIoahay#?b%K-js6B?{><8sav>hnS9X+UaAPa3}$6^t!Yz<-Dy>QbrM1{K7x8(UMis z;z+aa#+liBe2RzqNRJ%>Ma)PS(&J-QPPTOG?~OWALR>nJ*2?yNetvvqex0me7}6ls z@#g<*keX)KD=UG@vneiNQ2GewmMH_Tqn{fM4hz#L=2(oz*E?;K?Os22xzeUbfQ8)F z33`572$E!zBue;SL)(ElaLcQT?MHraO}+N3NB8KZ?_B5RoM06e(%5V0UgTW6e8+S5 zGJ*63|J%RyVLn#GBai+`e-Y(v%S%Iqt5LOU#2fRq2z@XBVkS%3WVB3#9~Ff@e<56O z4VC3)7};4dkyhHj=b5zM^6+qRZ_FAwOY=!t_+*jIH%6+Df2kgRdMQWUFw&i9jSRf*t+o7|kAip~YtK=j0{BAK!Go_>#zk zQGVY$HfUuamlw0)9>0&$<^F|R-DN7Z zA#mw~S5TuxFhN`b+I{?>JF8hmzY)3^fY zt6~XLUDZ50bVl!SD{rB|v5*p=h^Ct6?l7;S%bg{|SWkc-5i#)`=X?gw1fozeka-6o z-_UuyzJb5groxm;HBAHBA|oc#ddom1Ax4*Cw*A(9_jfAcx>CF#W4rAI3mO9B=S{E5 z8yE2bS1%y!?Z>Ggs~vW({0cw5m_0Ur^36+bo2q-ftEp+5W-W%{YrN6O(NQQ*ashI! zB#$;3|M@|syqmM2$(EyKnG!8=BNhVi|5yo{uC?pyz9?HDfGYd0Z~mXEv>I0w8SZRM zMpF!U8yZ`lmlUQ$DfVyG4K%<-b!{=(-s9$M`I5>Yt2-iaa-sD|&V*8;0xiGq8OpUc zY1L>Iiw6UO5D33|2t8+`CjN$lv;!@8H6V)1FFVRfE{rBi7+r*g8;E zwC|O#)saTV%n>xY=LGk|9;&Y+DZ5+|cI0j`uh|YFKt1g!;6jN2afxrmwiMhMJQ}Rw zPGzW`go}jyvf3L+o~2Y?X@?_G-_V}qw9ykL%Tq%OZE09<^^Osgo`p9SCJA6q`L!~X zyj0f6U3TS18<+MCu8HOt5?&3J0cCshlX~{mA+lFrXatERXNPmKlnVsK2~80a=M~#a z+Kl==#RRLOV*#~c-=I~z##O2^t6jSOv@ozxi>i}P`HLi`+m0wqG*Z>yRs-R@#8>QC#7mK1nHmqRf-|{eR`#@7HuBIOs;{3PF)3-EOEf2ZJqPX~qXExNUS4ZcZNoR2)^mF4 zUq=>Sj4)~Y#nkUrIlZ7Yow3+}D#RM+y<^JvGk*9qjsH~Xiwj5Q<7`wN%E#~Lvur}~ zxz!>@O$^^tJiN*3M^G60|46)cnK^o@-bzD(ac+A%f=L6Z4N(6@AMgEa=S9z0GcMIt zrgITgcIBh=XF{PWHk3WIC&6%X-(gseD&h-%$1v!Dlo2(nX~}TJg|vgkeQv=oiR8?$ zRKE*By$04ZH5`=T>R8?|HT8RH>fTQL2GbP3FreTz^etHA`S~S!>CfMm7M=X9mMnbk z-;a)kKThM!<-{fRK?ggg>i3$QUWVtuY=^THu3KaIsS!EjGGJBckpf1wr~mqohM&WCKR zJp0M;JhP9Q3E30I;W+B+ZFEnM@w2br;cI{*7&d>SBWjeluA;01t?e%j9|$2ll}Ljs zEYs7Bx71YHh}+}yEFpJGiQE?ld+X;_;FW@ZlU@fB8{6#6ScI* zTOX7J{w%aBrwWCLfZ8TJ+1#4Wy0V1r^n<$KQBzCwLQMHPlpMC$d3eT;ZR}OH-IN2E zdmmOZY#3MvT}Uw&+GuYLQN*VkR~CHoyYq}n8~K-bmKw@y)5C8#2ELhy&sN)3eebg% z(rXdU_(#U&Hk6vru>df?XBB~m|CcKg0M#{a=eSc)fD`!k8Q`>e2v=gk58fPZ@eD_7 zY}WeUIQ9q(b6^oCH8f~@8&vPRdD0i`tyP#gCfeTq3z`XR$;e~Oxb5rs%~V~}2iOgl z)*!;lr~WvM}-dHQ1n+r z$Tm9MHt`+vDG*j#BpK4E^73Dh7KIzszuk?I!KmEbS$sfJ_DVC`kn-ZAq#fLo-x6}o zUB)J_2xKx|sTJgAIeTa-FG^=-R)(%-XFx7Cai*HNQaV~=Jgy#1#w=D=uA;RaL}tjsCGQs(u8=4&5O4^wNusBi5*k91X6U zW1h)$!v&d$!0-OLv$pfYjzLs8tESv@a;m^IJ%5fAGpA9Xdk;^_ARCGxTOz*ro_Q9T z#&pSTn{=&dI#P~)^`QlV2FrXU$9rLpDy`&yFZT^KWohMV-L;C#N@~Tx9JS_ZBI*H} zA83*WLl~d`G^GPG8mpksDmZhl|IMuS33ph>z{E~s0Eda-LmLf0j7%Y0q!!Z}eZ8L; zYg}bIn(<0jqPg>TpE^hdjg@%YYBlZG<*TC$CpohwhxLq2^(_bgSrw9iKDUOVMt}1} z8m~!;H;|efEtmOUQa(YlY%b@cDgQOT1j;(S-4_I)spBZ?{Tx5r(A)*tGT1wu!pM@5Qy{FjOVuO&;(m7a0a zx2C-@xAli^XfyP8O{$=>gOQ{#a~l5LkPQE~hJ=8;BYxM0jJG-Va9nv`85wz?OLnf6 zWBtcrHKEa%0?ggpwj)mlL9eld6Zhzpig>)3xZ}t6L)TZhC5jcGyz9yhI|N0Io!i3k zff(=3P(t}|H^))uMdhyRmNpIuhDro2-xZd4e?tv0zU2?YXNC#e@ATAX4}0twp@3HR zWTnMy%>l*29SwCH6^vuS+^`bZoq$~^VAC=)Qh+P>zkoFbUsdIRbBy|L7SL3v;) zpIwq_r#&-}rqaLvLL>pWc|t*cT}(}z)iE0TzV@M|h36LfWuccjM-l!7ai*;7ypS6G zWcsqU*-dE^6V__olZisB4{-GGI@ZE91B2`oyqY8hIO3|Kz?M!e)_O!e^y3DdTVRErMPhIvl-;eq|s%>iM3wS@S(kZNvu8*ik=P|CYF4h>(*jN$# zm)|~8d{QCvI%>4z(w&brtpHbABf&3l>gutBgC(h<&xCLsMaa70ZG7ff`?)f^@$3Dz zI$=&rJzV2fa9w<}Ii?p_SA&qaO(?RJVO%q0PRf&CLjP%e*D)wXBRgTiWLvJ^sY7bzWPZ zmUuzSdu9%jAJ;z{ut71*Dig|2r*rvBD(Y-&rGHR*|FTnaQfT#eDE8Z!a#hrAxND;l zu1$n1E!B~`kRF{TM9@Hk))#lKVmC?Q9M8I#fL-QfPlnW?f*iluVh1FR8^{j$nzeOZ zWc?ULX3j9l7MYZvUwr>#e@|WcJ>~5Tl$33{5+Pr9%SSfNeK%q=X$N3HdMpq|G5Lms zk+0g%@9jw za0l^vxs^&~ZEab3N4&Sczs&eAjds#YGSRR-`kt4+b@eSpjw%nbDB@dNrP3hz%?X-)vaKEcIXv?7cs<{c6KiDZiG@SI^s5`|sObAV#X3L> z7^eQY*edxuM}FAz{CsEe(s|USfLNN8E{}aa)(hbw16kFp)m69G-9DVR{V6Y>qZN5q z&FnGyvP$Nto5dDo=oWGK@QI`T{cknkUevyjnhdV<^EXh7~>7nVpK0?Y<66 z{AI~Ezd86+v@^zy`6>C;eg+oCzkKX`!T|NTi@pry#oyk+!E7{|rz2eUm@I1Qo`G92 z6xyLD+bLqXx%O8}JB>q?fsgwZWk-d^$bpecAt`b9kTr!jVCGn^K7=S<9JBu8|46#Z zuqwKCO-qAFi*z^A{emDJ64E6do9^!Jlm;n5LO{B^yQLeXyWuRp^F#l6IWud|TF;%M z9)^1f-xYX0J3XzW>|tqr_Ip)A$9&*VcU3c_`sEQm>%j=4;sf7j>g?>iuNlY{=1R(D zocu|$LSsV@7-uhDM@-R~*I&J`EKMT8l{~|G5D*hj+BuHQ zVE%`#PNCm|?Fzr-So<)7(ufotHpiw>a2YxcFC!<%RKr=bbl9Taez0ARGj!J`cu)H4 zpT!w|N+Tt0!MxKsDvM`r$|l}J{|?g@quvaW1fU*I`wOoC)NcGi#1uDBbug{*ysV)2 zIyu-UFZK>`pdOpqY`4xZn3VzIJS~+hQ{L`!{w=Ue{Jxxr8sWqo*GH_C^ix>rq&hEj zpWebcc4UAvfNrCQyFvWk@L#FPC?eb^N9U~Vqq^1h#xRD_l19R;zqN6uwKlnYga(wU zKe)Mqm2IKtqd$$-f)i9@Sy6^^FFT3&SosVeVZt}NN-@+?Na02@@-gu_J=HVoxsvD1 zG3{J2)>suslI+y21+GQczP4u_MbPL9N1YuO&^mwr{x!FJcAZJma`D{>1dKaTt( z9y7XKSP5u$-lO%(GvtZxv?KaDGk3l05u}y~Atx2*XbtgatJbH+zm*$x^`&}cIBFnnO*=xErxw_5yp_+(y?8z zh=&}`>Plslanj$k$tAw%&EKXc*6754V~qDpc}8ZwDDEIS&r{Eg$~i|j@dEUXl7=nd zZ%tX9V@LF}yu@H=2Xgx~w>r~)!nQE6GT2*)FzDYgpt0qZXV(~FI0e^CiK!1Ds&~w; z!_<A$8j1t!x08ejkTuT8C?mM_gGLa@q5{Ez=O~%w1(vIXYiSk-V0ubH%-# z74^JSQDDjd4tvwFe_wy6Sz^V-d!R`zj})FRjc3dKac5FQS_-zlYJ9z*;$nlv+C^)# z^R%(ebp|c&s#aEFC;!|tyZgS4DMx;+({+IJdna73n z6EF`t4z;YkGCvw$w4%tU8iqDD$g=BfKW!WbC?P9L12}cp`$4P0Wh9)z8ipe+eSLZ$ zq4{d|J#bA~lQ$MHu;!f8nhcL!Qn_sS;tF3Xj%v8&uB@>~<9e}?e{C(-8J z*!5Xw(F4yi_kWg7@X~azzdt#g?F1=j?f^rL$VeIjDe4N>asligg_Plm-|R<@J&=wy zTKw0=!aH331wZUM#%Js#@9pt)rQ5WPQp5;+W*rYt^d}el!Eu2H`%^i5d!5plmxOx> zb8`pv0kaGQ@=aU>& z_p*3;LCleEN_9oLPu>(@0)U0SOu_a!p_oCJ|7m^Uwzp}iH!wdDL+V|wkiAbTL)5<(JlI)U zM*;7s_w_}#?Ruvh>W6^|?J%fW2LZtkj)B9obwm2ZvWKmt8m&98P~&+Ot;5C6=CcljU(x8yS`PT*KQ-v z-(?wUp8b?NWJW-1FP?q#+5WimBE`?n|qvQ*}xnKtd902bumWN z+}m^hf58-;J2tlOnAjN`4_E~6tI1ii zm3x;gPAW0Nc?Ol^@hL8F$3vd6`CS7eGl3n_r8X)top6yAI~Y zwKbyqI4X-A-J0y+_O+ugK2hXfOfg-CONRbjjk)({zL2Ja8`o6ruvw}OC=CDje2Zse zfB0h&!&}HuI;@X_wLql(z}U@+N=qx2R_gn`5=#fW~I2PhP{P2A3aFj!< zSZcE?US#bvFQD~l#+43RW`-G$Be6POvmNKtNTXSTUaBIiE3=(C3@J@ci|@uzxXF$m z$4_zCE=$b51KP~IGAAr`dp9_kXJ&Cs@|*j$n_+|2$FCova;#@O-}*ZWjWu)_Or}uv za3&^wd5f-dgUCZim9&nDQK}<8zPl;>w1Flh;DmdSY|UeW;ivB=$9Yqx(J}a!aF%0w zLS0uH+~mpC8YgOVVOSq)tP%i5c0~5cQDsE-ZV`^mW9ob(L2>veM1lhcAu)D;9wHdX zIOaaniA(em2tA&{)T*U!3fq^wlq5U&aff;62}T{*X` zA_Psxrr20Hj;_EgautPEYU!v|u_E0-=$kpl9xut3A^T0C;T!VO`;bA&TNI{Cq(mi2 zK&J;b*o+`6h69n;)Ak%Sq_J`L(xDNzFp=?BiN43;$G?^(;6EN2Y$OCa$8=Ki+ST1s zewcp*fEZTii1-NL2vxH2>l~Z8s^L&etgdYEQy9zI>}h$k9~On{;ey9l3#s-PGXC38cU;q z`!3^%=TmF!&mB&=Su#x$` zZObmQUhPZ^<^$xzUD#aLS(Z?*(*D89tSr{`-B0GQ-&M82{C~CFj5hhWxHvJ95!&q( z2O({idd@`UjWNg3@(-DFtgj3xn0bzMXQJm=T_5J9M$ypsZ|~(Mr=~`bM)GKVcz;dDqq`qHRXGg}K@!AX{%tQ0 zZ3eFMH91ej82oC?Ma4fNhbs7_=^lv_9%f6|99N<8iaCU)@*62T8++Xe83v2`I&i?A zgRWOEd6KBa>C1`cWM!k{EUt4acM`LyzcBizgAuwST#RD>2__){M!I_GGw*NW!*hiNr@2gcSAv3Q7vQxAawIz&Xzj`m?_Jy%L2&M zf<)lZe@w3s8tvWrob|NF?wrZTUnVNz@PvwbdDf|r^_u7#N#_QZiL^WMalZ$m1m?9v zF~R%Yp2-TCaV8gjRhU{NZdiqC$x4Wsx%v8;MD|)rMaxIJJ>n^SfTvX_`f)0qwrOE> zSukwWBUU%Jk5!NGm8zUH*cbn57HW7XA@)uY$X{NwVa6ylHo+hNPT@qW0b}fc(r!br zI*Ce&LH>Wfs!ghY=?#nU;*oxP?zS-b_t2z%b;CoFj1~5$+Qk%f2{?S=$l zlgab)44cm*Qq)0m?mS#NjqttG4bKQ1G+6`MEtT!H`}3Lu@NhO^>nSTnEjB&f)3}=9 z5=o2DV(V|0r~;poS7db5j+U=JDqOUwOP=ga5zgH+-s zT>m(uc)-eq6%{3yNP#6cV`S+%xzS6pymiM^n$%V95pK4jk!bReG^qk_@>b=@L2-Dn z4e!1+Ijj)jsWKLlGA^=`nr3IAv7D#lIU|kx13saG_Qa=W&@~rkzZ=d)tlO3heqH)b zUQEFTYdoVFt_V*6zv*%I-0C0)jtZdUXxc%tP1exLq1vW@L+G$rnE>Re@>u7*V{{--Rt2%1qYroxNunntPhKY zVDOuBS?TDRr%i?^6Ch0~X{?(#jm6&bN{a|7s8S9CuCTJKEXWDX$HXJA!61k>Bg zL*7vgv?exJ2?IQ=S*Q%Uo+qVxV=&L=W4odTY|p4JRlCE-SZNPIAVYxqUFz;2*X)Vj z#5{GslfYQ&I&}?SnaAJPw*Guhl1!NGSrsAt#7^>Zjqx0t#PAhF9yF&@c#vU`(;zHP zFnq0hSJ^CkLGnj~ISanVqBquh9}%H-V?ti{s@|NGlJy9<<}58dExNEGcA|s*bd%hs z<#l?%a+`>ofjuL**>hd4Z@4+zJWb_ur`V%6*l`yChRvE_`ya6pZCB{yJL*Rk-209e zJ8yuaSev-QT=6aX7h-fJWvqgllJKYzG{D0sX(@eNz%->6MCBgpu3zY_Qfh5B-~`jV z>(l8OK?|K0efKvu=ac6|)9fb??}s|?5Kha#8oncloa_;BvyvTyTDXpzO5bexf0xXA z6sGc1m-oHrvidP$`y1o1QyA81eZev9x$+hV$q>4Nzr8?!gWv!7cxowpxV!S)LlDkO zw?sz9yrPU+m$u;GLliqJuBkwR2%V&f!xkgTRBYgr5Vg2R|THE!;WsrO6t0&hthZqbf9 zm|}!KQE6H=(cz{9$J4PSK#xd3=}+2YP^7U2aQyo3>bauF^bJiZ_(c8tM<~eewNGwq zTJ#56SI>9sYQeKSC<|{*SrUHazv^-S)-6S3O5_+gyI;I&qO8fIm@$0OxT3a=U(GSjE*Vq)-YA~65AQ%SEPC^F#Kt>)PaKq($Tm9;gLCC{lgjRO6;PK)>q=B9K~{t+xi2?NeC8YbfA}Mf!<`6EU6#WipK2Z?;`)6V+AmYZ;4Tg!YGhYKRX$x3UrNnuLK}!Qs%RGPCobOIANO}?p zItP*nJh({Gxjvp1nL!}kRk)cB5*Ixxi0V<_xHtZ8Th3u$cHV8kav=i$Pl`6K{X4vE zt#=O4lpi%V_J=u^(eIl9OmFa7yGpWHAq}KOovb7vR2T;el0?zy`Te?K1_@zqd1+u# z9i;F+>jU@=B9bXacXCkHG1+W)DVy@nEb1LDtB(UF%K79DwTrcX`$FLCHi3hSYyHao zQq9=>3zI%9Og2B>=D#qz*Nc(yYRA2FtSN|qG{q2*r;jP5%b>5Z%h7il2n3ghXRy$= zS3#=o1OzMDbom_<@otE>+V4;(t2L}7z)KCKENyM6)e9a&prMH}nj@RQFwe6wlC2@Ob@yyMuM>pBz_~+Z>eC3zj<$fL2@u^K@D(Y+- z9QVe*@#0$!p^w8jT_#KsvdqE|qhfRXV@J+n2j+;8ZXF*Xo5~YyJR2h3(GZ$ZTWhn> zl?k4K!^;5+0LJo)6Vv_lB>jM!5l}GdU!|R-0wXFX+*H5SVcHRel$SGmKW``i`J_kq zuJ0xC;lu+odn}LU4-;CT|HrBP$;-(R&VM@P=D9-x#Kx2Pa5H;>^#w9QD0it50VWr? z``X@`rAx8#Ib$JY)?TC$J3FzWq^JQ#d?RNOUY_oS0WtC}zneA%Oz#oOdD&a(v2trl zCO;tN71~tPG{z@6&0I!DFOP?6j?7d-B0%VN#rpv*A6vV5ek7Xz*l4DN(^UXwagvTU zA|n=3Jv%xMkE(M7KZkA6mm}Lw2p#wBB&aY{-K~Gu^iVpk?uY>)314aB!nM#?)^aB} zjIAcjDj7)g6nO5p+qrqo_G^e>zrb$F>vK#54C9=Clk4802RXIeZ}jf+SixM|QuyoI)=4BS z9;@QXFd76JQe^Ok`u+Pgp0P#)mzcR$xQa8!4aQ~HN! zilbsdO13)Z3|WL7vt<^goPIAz(S+c)=Kj8gOu8p}UG5*;rJhbPg1>8f_}N)UTUT9u z3qIu$4gp=LH1TspSB)jL!4lkMyX$C{W@RP$K#u?Y@-IvS`DgU!ViuN}jgK<4+pNG> z`rf9sx544VlH2aG=YFn4{ce^A5`ti3GvsU?c6QBzy@Yi|J5lG}TkhTEz}+r#V2)Ua zeY@6S%Q*I1uv3|om-ivrXG{j!os1%D2&{=*3Urq9v>xy&YfE84GdJjq) zlD3yxsxmWwC07I55x4}t7y2pvbD(JndK4P`MCMt@yLqw3$t+D591=qC;VCj}g&5%D zuH3GNhTY=_^=gw3R8%5X9-nEjEW<YSsi&50FKX;QG5F;?p>fO zLc(oBfnniTvms-(-s25}<*&2v)U})Xi*vb{!IW!PK%kT~vVoxc?p#zt(#y*)9GxW>4avDPPI?8wfp%+RQo>jvL#)B=$V$Jjwj%n}jB=VFo_GIacjsf=O`Ww=d z55gcp&I=(HtXD%Jg9qRaOn?FnP852YZNWG-oN&#=`H9?IB61A@E~20-0#p6oA@d!m zBDw3RUfl#2dC~raah7@VNX?*DPECYtfRCW`&l>}U03O1NQPw^&l$}luBKKo)Dkwi^ zF2*=J2OI1z3GBlj1c)D3_P-DnB-W0a;?u!(ay0O;_OqZ9t!L)Z@J=lD^~B**gl(y^ zlLI8PxTtx157C;hDoq6nfr?ls9EzcX%~I#rTLEHv3Ipce&y{~xUF2Ma$dVFittW+yceZy1x zz-m&6<2S~Eq|IgA`6WEV*gWNsi9GN>>99>6ZG3|Dc3y7z=jX5~qT_$mPwfkX zv&Qmc*jZ@qQRkBb)9mXD5HxmOU9>5XdXT|lv%vL~XNT_Ww8<$4xZN|4VXbnTal$X2 z@dK0|H%A61t%3k@IGnWHTeuR!M&QY1!XP5Kw|M`a7nrVLZ;Id(36_Q`6H65;LOZ*<1;DU;JHXHY@`Ogb! zNF(#dG-*8p9TYM^CUQ`MAtG0ynL2aqVrOC#Ot#x~#|s^G&Q_+7Ps?RY^0{4f7m=XS zM%U{KN9frVPfl*6RHG&N4aqH*%aR?9lM{G@!we(?V;k>{p2^^*bAHnO65IJWrPVHv z?9QC~8~&E4U(y0@noYSd)nq+4F&&kABF`hZR)cfG%4m>_{c9GO>t<2W{WOq6!{Q19 zx?UMbPse|ZMGpvj@0+T2@8JqMpl(Vnc8ekDJTv_5zuv^y-gb(&w@lR~{qQgfYhkuh_2-{5B^dK3oGg)i!>MjQh9gu*AG%#kTUEQjjy8gbj@Ev5+I%M!R5(A5=m46J?%n2U5#!!}7dF|*n9 zt6^yHQ02#y_)Lce&nC3cm5Z{Rz_~3gGB=JWyz1er!rUiGJ}{aD0kcfdR{eptzR38S zjm<44ro9W$xgo=qZfs^2x=9mV>GPs1pUKzphNLvVz?c9m#q{*_w z*f3ME08pKc1OEu{jRKGQ>#CuB0sD3#pu3-rKLGONObw_~{Cx`XquVqL=o|Z}ubb?G zpU86`i*S40@%(2E9!DLGgMc$Tcf-8BKlMRU%qbwu0DMx}yURB#y(c%yU%qsds9Mf9 z8uMGul@~P>ry37wA|dDu#45>u)!Ms#I3!#0J|0OK(_|}Z^+!U{c{?+wI&w&g_}~SY zN7i^*g9R>RWGNoyzkTNA1Kn?tZ<}4^95frUF<%)#0RGTkb;S`Tx#>i)Ft|raGEg=5 z_ieJ0(pz-9lYck>Y%*4qZFrD)cA9+*>TI!-+_rbT#5f0Po8-szO_$@Qh$_)EsC z@L)06<7Le)A$~s+JF6HOhse`|Ky@4=mng`ggH9+)LOL>R^eldn$&6lzZxe= z8(L+RA=dFR#uLGPZ$_pg|r{#t$rng^q@eixTHL{urc|( z>LdNHlH%gxf|9Cm#eSy={?UREFgzlffwzB2gz1N@tW|Kc~{=5uOk*FyDxyO z;275h7SM*L?i$K^5*|*RYx30>_$g@tONi2RvUD1{Iz2DvH8cz0C~tc?RbJuu9z1%h zsP8H;u-g3cwoDbL)cj{ptXi~(Vtdd!{s-8AMs%;R_@QkO^-Ta7h}*+z1vXUJwp9fO z2b5pP%l~R2%cG4>2Vr8%v=xb9^f)7%^ZPXuzPEa}o{c@ZAzQB!pnL1X4*c4~GIRP|j4+90ERRM@Ici|3fu6jsGY{etqkjQCZ3MT2D2lAiPtQ zlmt$JyqcOQQ0D|XrntZaf{7?;wFr^=rI2m8Q3IdU#uhCMiS_f(L21vHFcMS&3N!Gj zTm))7lGDN0rg_{nl2PqzXO*u*2lpj>4}O)8KDiN`JH$8du>T`GJJVX$HI@o|Gh5!9 zh}AaNB~ipzkN>`h0;Eo7D@#jYroLOtA(4Sz8@2P3RcN}uM*yuAmF^>&W0co0PXNYh z-k(2-J3Gcpb|BZ`w#AmrWSQ4onql@Q(02aFrSRmPpD0$7?@wPcTExa}E;tlqsU%Ey zqY?zn9NBl=S_ShFsku5>{)TuSchBWxw+}kmAG1b*ZVV=sNllG`4@YHUu-*_=`3^g5 z;;F6c>#tl~-14KPHy+yDFEe~oRMi@~e_g(Ve;(1|IRZmT9OLkK`vo}EddBn~=|HcA zLEi@#yVWO*-<#3=XLpZ{qsu)MOPZGhB^+~vE-^A<4GQiy){AL9LADZw$OGRL9Sg7r zw6k<*#?CKV-Vj8_C$*GV={50Km@*jRav+>{9ug92Pp4F{%W zQ4$}%J5yoPlG&DHnb?)*QG~Lh0)PeVUblbVQ%CK5l`K%oSJKhmJKmVD>~eH;w7oqQ z0VQg^e>o4#EVZInS!jB^kPKjEETm26iZeH0VCY4fmN=DJQDdpG$^0PHn4+;Pl;%&b zlbC0r;opn@SI&TDVbEqXu(Yp*pI?w&diia0<#*~}Z$;H@CQbQq%blYyy&BN9G!+dEIalhj0v z_gG85sKPHFHOE)lGIDzXrL;ej=8%%jdW~8h3Md7x2YYtWHtk+)$79w1-wC6ImBAxb;vk$av{SvILv5oo&R^O($npu9(;DkQp^b)?>vq?NEE+Rb4?tPtpT10EK4(%Kth6}ubIBuk)rreeQ1g16WAVv?XjysLz zbGO8j1eeZXfi`z=BI4S74{_FuBZ=^{Ba1|%$M2%cu$bE?fm%1gHupJ*l?6m&di5UZ zW2Zz)UDlHyXT}v*0;?zO)>g_g7J?MTe@mhIC{puMZ=ENzJ=kJJ^?A{0-0yEYB%0h# zy3KW{a#EEOl_=wpUaL=chWAA;(!QK01D{mS!IiuvQ&WFzyGH>X`T~O6CdTtx)3Lfm z$5DIT_se!m4pJ<`&@+7Uq~@!rk!wv9>slk~p@9`|@6!p>*BLTe_p1;N(rrUaOVX;x zC7E-%b}OZ}5_&wb4QB`}1Mj-cCnP_k`^*QiIcS;hsHxkxs?i_$qxHPxYa209qiAkd z-ejK+b@c(&2irr9Q|7xBS64^C8y?SFQsArX&_`?=iy7PP zgsJ5cI;9<4b0h4iAGr10FE^iw^Nl0ilhRZ;$D?-=fl#)jjAx~KE41QSqePgs;M`bd}#j`SuuzF6Ph_~-uDN#lt!gmL8=c=A)Y|1 z+d*xdD0U##kf|xZ+ryp|IEKRkwW2oi$J^|Q@Oc8(#bNQ>SS-LV-L)?$NG$Fh@u=Is z{WFz>__?+*3KP2B<|~e!ho3dUXFnf}1azR>hD;Rt+@80hT=wzt>95NzI1=V-((z^6)n!{ zV&B3a2$+a9>=jeddEs;aohp`<);Pr7`rwP(RdE_&zfGctL?YQ{%Ev zsrq+V&u7<*vN>Mw4g6HuG#24US~N6J?ejKJ{dCqnu`^Ibxn8QAN>o8(3LDe6j5N!y zqZzMaGo4!$-5Pbc$_l7(=hcF5ZWpp()l-%&P;P=ilf!9uGTLL_8|O())u1_!6tS|q zZZ=62;Q$kYS{5z%U~uxOY3 zWs$@yMW;zHUF@?WohV9Up)b^;UmQm_la%Cbza$GZ zO~iMa6q_J&ON~fs<*ibN^zU%Zx*&5E2Z+SY>+P~Xb1F=!y=?Cgw^=R3_D;Ft@v_oe zsfLg+@C0h6dGa#;@eE|QJdxQD3yQ3&drEy!80qY*Djl$P2@{p5CRCVHfMWzE~?-y2PMa_944HsqPJ*^B_O~m#tR1A9p9yegX?06~EbbxKxyc%e696nDx2m4um8s*a@1eyWW1~CfW%*SJ z3z0Oay*An8{p6p^cif$nHl)>0_Hfo{51|@^ZzM*~&iWq8(|+YlFmilcKqc{dBm*9O zc2=JDil@Ie<4e>2W4jF3lh%o}CHlE|gK^SedY6Ot@lzjo5x}pY6^d< zBTwQQA#WloPbyRtA#33u*N?b4CIi>6sJHN%H*d#>g(Du6twkOgTK#!O!+zS#$|HDb zOT?s^w+H-nM!mxpxWfO>uK|@f$lU#w=4C6p8VuQ}pO_K9s9B4I`{ZMAvT2M+kjcnb z|9Si0ik;!^JJ{LtPNV5itQ4{znmS4^^l)L8nw1Qh}I~>$o`d+r&^o`b&sx z)`2EFa@c_~mZ2)sm6XW0oHEg%6H?cETfB3fHQBh*>jCn;*PlR$@TVn}1#aUSeCkI^ zo$A21`U|n6O`SY;N25p>0Vcf0&KaQzjNace5NvJC&fOwpg<{C4h^N{qs3uwaB}oW) z9nRWqH8|tK`MR4M3#QCWq5-4ieR_D)ujS_70mYzJ+Iy1yQd^D*KIi7Sah(U3iCvV- zn$hK_l4ZW!1R*2%C}TeS5XJ{c!wV=fxCH4)dF}eyzBGX;ChdFhkAmvLF;HKk<985l`IOiO}u$36->Xeczlh33Cn38ijJI zDmxsD;P}U`l_Dh~0I$F)ve%tyt{{1mfK!HQoHmN`ki4v9uY6)C!#6$g+K8 zMld+oN-La%wocl``)&&F>@LZw6W`_q(p!qX-xvQ6S%k}Gf{mw}ridSC|G@2Xil4Hx zo~kRnjl+5S)Is3%P8wF=8I#xtks)O^%9tY}3qU^a+pd#$NI}KL&qZS7Z}YJ)CZ3p~ zW5oCsIF-NSerl5r`WyOXFjga42ofF;>;LSU@p698-#tZ;Jg1_=M)?IXtPf8#jXfLK zwBA*)_+nl-<&=MBci@Tc0<}!9^@A6kC}VNbRJ)eQQvV@ZP;w>Z$jox2D9S2?rVsjR z2x%mgr)r_b45Y3=d*7ZBk6xlFs(tPJ8_YK-Dzb&`hoiJ{_9iaaw0CHTI(TL8fp|LSdp$HHM(N!J+KELK%Qju&twh=2#{K7Y6rYqse!EY*rBgeTN)2PJglfI2* zEx$Gh_JNRn|8Az6aWP6POfz**toiFw>uJj%W3zq}<2|w@OOszy?KwGWogdJ^4cJ5i zcVYed$Ev{9YRWxXRn-@w$C<_bK08cF-_`S$Vq3E7zug}5WUMeFf4$~=tb^IIqQ;W6 z+S+YUn4}^A)5(Wfm>LX&x^AMTeT1$8Wk)eg;KMFO&^^&Qr_tj~#P=rnc2lo;K(FoP zEztH@%Ctt3jiUffDpSFf^;uaAi0VEsPi@<#EYE=|e4N=>pX3U(L3bX*%XN2aPc8$y7Z+4n$F+rum?C}S06M|l z3TCfjGSW0>TywG;CF6QDL?F{GWn8)Pjqvx$pVyuE45KvNOz`rEsZw^1CLLMn%=*9P z@5Uv`5br(v=}5lUlizrm*jhz+QU^_fn7qt)P;7Zoo&6FBa`U^&0yUy2h)?dP;R z6W6$PWS%S#+i?+=vk316lk$UvyiEL&el-gVjrJAs-A-|@Z1!azQ67B#j+z1&L?5 zr(c0uy`}h~>WlTiknMS{;!3jfh0Dm~6eQ@c%%3c*5Vy@xbgKXC18WG&%fB&mGpqcP z`*m~TDssTTtAmdc@*xW#1bUVK_K6d7@vuOAh@V#PN}NYRwGyn~M!kk_mKBTX2veeAY-z1K9tbd72g&e381o^rexT*na{+IGwTx?SkljxQvoS@4>jGX7{T zeCHLPmon#n;$zFFG}X{1BG^t~|IqAxix1*oJq;b}19N{=R8NN?>26jR?iN4deo^O1 zk%8zRuqib|Hs`qpCZJ2T@BdzfaEnmKkqQzsT!ZiU?V#+Q!xmGLD6f4UC z5}T=Hdmf0P!3X>LLbr~ETY2bx@G25iIMr4-NrT%;G~DUy-kdTh7024nm-$7-^GX6CY<)t7!>QzCUg3n+I%J& z%qa-KrJPsftd@>fUb3`*33sI*8G7-#erA`9=V&>B^QmYG!A*_RG&P@4Evvy7gnAQ? zAFAWO7Pr*(t%3ArG}*-Eb9K!_dkg>O-xaU=<(fQAUv*#7$~Q2us3xrVs3wI)PA;ly zDPJ{`G);qN*Uwuph~tvtG*orS#f_3*{+7`53w-SCqS)|Sk$B2RQM+w>xx2X~X?vK9 ztSIFoa8Uhnn`)|XHjXw!U0Z$r!f{Qwv5%TEhkpE>-yQkZ z)!0~p3>-Yw@KHN0Ay;dORFjTahue>+Moo+ayb{h{wXY2VP3<9dy?4iV45hfp>Bl5U zaISZ!(9h3!x|=dIF%twa5PJVb$vlkZI+67su^AQbFY^Sf8=5c`WtrmjGOq+2F=EiB zEjX>Cm)C|SZm$<`iX2_>%zkqqZUXaUt1T zCx<;WN<~Q~MM;)=?j^bF69e6dBSl#jC0Qnc6<9adL*>D3tdo`(bWn)P*VP5vWRIRD zax*XXX{?1Ej;-zCB7oet^lxv_xD=H9EcN~$2Zf9j<^oE+;`4zcsn(|js+AVIh$PPr zCe5ayCspzFA)1)8o3>Lz;hUu?F_`C&!Bm^ZMy2?)CMkDoR5~}tb(H;im2>lW2k!o| z(ZlP4t5Y*6= zr`7Qs|0s^Nc2gjc#Ix?B_AO5FgH!o)1Q{||GFBW)DuWJsJwT27+I%F)o_`o!ec z1uwI1bGyTs5aKUH2*0aZmN#0FR5ZX#D z%HG}@Q08Aqu$Gb;4xh;60j009Vx?#et^JjO4x-9b$3$!h((y1uMSd;Qu(te zVXerCs?>v}wu5^+dMD$_$~Edq{l<1RwxN*LvB%K!qG0#7tfILm%ufi$<%{2gCuKOM z*s&7!8^uu?jnwAu@h~-{z%GpJCtUsM!C~Ep(9VB{%(`wEF|&PkM5B5J^IxBuUT2yX5jS>7ga2aZHEFv17rdhV7*QKFxCL*xraU}jlVQ$7 z_oNne?HSgcAn7C*o0XjkX5H<>ZtMo>AkPA64Q?Usn=*Q2uOrA~cH5b1>)nO}s`H=C zxjz!=WsC=^$KJwejSHW~%4F>xrcN9-qV&j@X0L2xnA$%wh8K%}Evisra-+8+Ce99l zXhlXXZzaSCZ&>O*(2>WDN8hoe`IbN_WGrl!hq~J>oykk8{#Pd?e0VJBQa@D5j34P& zh-AeXdULfECF7--vN>{Kl9iMye-zWXYO%9^F(V`bG~ zw?%kZ5+%dUK#WbkAkoeY#hbexyzF%wL9cMws&tzz&&H6Z2IHASicC7WFVrIMJ zFwZ+|-$&xMJLVWIHJvZVttl@pJ%D=%tiLe8MXqXrB?zO~I0`j;Po5%%?GP$Gkoi2( zKYgN~rGsc^suWKiTl=Zv_QG-BTdr||uHB;H|#3A8n2U=0q`H4}y zXp-%87QsFRL9cjM+O22`FImImopGE*536vCZKAqS&y>-1!*0F@;zvKK{9PON>j9T> zh8~C)hJe8JyCDV{?FRQSi?ZN+NKw{TGf~Bki*do@0RP3-YuSo)iR^xVrjsm$xqto~ z3QkR*mn*F6vtfS{R{bJbn2G5(#T=@p9b#9cBV&XmT3m*=QqGVredvhO*Tii!H~7m{ z2uY}@Cp_RzNp9d_?+e=J1=p_6alVLQr(3=kk)0b2C;alr{x~=^b}_jQYt7w`+ae^6 zNZ!%3I}Xj*GB`YQL*V^St}$31^WgC1@l8^^r+rvZWi{jS^Kkm_o%J(J6?&XrnqCcE z-5?2a4iSRr~jsiqf6zEEJ3+qhIaF@92{LB;;cs;J`E4`7U2r&(+pF(qnu+ zL(kcjZ;_^gRxM@vWFRTl2{<{#w!5S{R}-VyV|7&VP>G?G)qscX@eZa@c6zGvwihPR zN_5@(hL?ZO)piBl(+t{=>m;`8Z`yVV957-ea@6}T*58~=EzgXco|0ndoZMqd{*>+r zFGMUsx7t*8JH+#J$~#uhr8wM~u2!A<+4pGe>czT)I}!ARvDZ&e52s>8irB#_U;4p4 zSldvSjvV#FFYTN^RbsrEVs?z=ex#6f(zLO<1=g^8Jtd{Guf=-^I9-%##fm?_E@Qfv zw@c?rwklDn6~{6rtB-CEsFsxOL~PN=2#<>?W9tg=3@Qj;VCxAx`I}0FgoSA5hLxQU zr!(ha(%vlGO76#IwDd+{yhKX=2r;a9Ci44DveC(YbfK=MR3xB8%5C8Mn6 zT~17_08?O}%5EyWQ&!j7?gzVQIc{f|T^O8$sEfY5c@bAnq5AM+oH)=Et%~#ahtM}m z8x6n5mM0c<2{S$w1G&${^#n+P&JA2i{U38uW>&Up=N@vc%;e4cA^$Z{84 z-dm#gvMryzos##5PVB*AO4wiXc~rjZ=*q+S`ITX*-Y&|KujNSf7>0Lu zRa`!R3*kWgtYhO@77bbUB0lQiemp=S^@o%1{XjjpZFujq9@G7(zHt>CkES9H zM9gs4oNlqQM8l0v42{&r;V^EWu+54W^2~s~-*6i!3W$o7RZX$;MykaqJG8xE=VEj>FHjB`Aj-^17Pc4iU#l@OP%ip+0>;>Vy`K zc62^W#Lit(raRUJW`&yXxtha=w@w$Qu1dcdBhn4IQ?s&+^mBZg=HMg}_~6$!p(Siw zT@MA4&4E5yso8EhjU9CC8rdbdEWpp#jVDjE9hDb?e|!i9j3z~N{=eTLis%e^`Iv2a zxE|u=C(6o4v-5Kgy>D)Sj8U|!U=I=s1qKr8qqv?jwTASelfvyag3l^+E^WZnhVZ`0 zE_r)?hkx{MZDdp8c1LFH?9uNnRvfF+;0Nvv7k-Jc3=h{oxJuH=DJhcFYHz8XsRvrzFbt#n;8?j#8s7cY+h5MKrGSby$cmpzGzf`4)rm&Hz$m9B* zd7+aH6)jx%w(qk?ms_ETiQfYsvvffu#KuRR|1A>xQmTG^b-+{rY_szgDGM=S*=~P_ z-B!6c@^KI*Ok3d(THWzw@Zt=HiFxPrMqmHCHeg&dF;(X4sZE*Ff&}E>42anI&^S(f^1>!68p6!VTgO9+f_fbuCV*} zqL4RxmNpc`$XFObiU(6enq;NVZhxK$++7745*dt@im^wpc@SpY4frj29dmZ>c8JS@ zA);kpyEvkl+?rik`)$?UC}5zSPb&&bxHs|6PxY9o(X^c5hZp*7f`HWu>z2|FTI8d3 zR=*?FALpm1u44bk(KSb9)^+ij?4FvMFd36=PqsNd*|u%lZnAC9WZQ0XO}4-LervVr z`J>h9o_o$d`-iRlYRiPFWWeS1!S65o>U!=I? zz-p$MnU<3Nndv6@FFYUbeC9Sp3sP8&SZ~%YcK)UiOoWTH?fIjK6BRW!yGX4fVd^l> zVT{iSJ}C$c89JDa=dtNH&8G=Z{7Zv6VZwxP7`&(gt?R83sjC_uER=P0u^$Xc3LM}m z=}>VT2_TJQ#emA!*=t@3MV2}-_g_S%baUg4#|{x}1Dfsaxj^+gN;rJd zY%_8s?Gnu@9~-oAP(Yxzb{6*0zMC)M5bU#?MQv`5TU6YZ`0xb<`sMDN3KT^6I&zZ+ z@Q+f&Ni_*^C%S-bTbA>sCFP{9KV|%_wx;?#vf(oWY^Sng?jk9izV-ritlOuf@S&p^ zajxlw0W(+FjVtUveE8?pzfMDjxBZ5BvVoWuK4@NM{+ z)`D_Ea(?qx&>)q%uFrG?Rl!i`p9OR|9sK%wZX1xAL~$g@!k_~!ZJOn)RVj{`Clwk;5*8X@>Ag7l?A2;IzI16x?Nj4C0knb> zf|JNd!04EIoZldUSJkZw~b7|A+TA4zWx_ z;b9{9rG!$i+6NXuIX^VM_fB6yi08`xnB#5Y1l}I3_zyupprM;eE7xs%P6yR55-52W z<9KmP{k7Tw;h*<3=yuII;iG+h1#C=3dS6{R5fvCBDqi@F_28$3AI!+{hS*LB9>m&D zl!5StA*-6EDO&*k9%8P%=p506+it8_xlnop({8@-p)1be%HQ`D38u`w%9%hOeXYP( zpZKR>YkiFZ#}UL2B_YPx)c^jX)f&rDZeYLlmgm_pu^iHELk5Eao2*5MXq_gI>nJeE zTqjcpTO?Oqo)DTko=}GYE z_)|iJf&>XK>PA7Zot5iehWf;NTWN%lIGGFyx=zJ=s=@;bZffm0#c)%u9iHUMv}Ee& z-l!^dyW9Zd$%k&9%A6!-B!(q7=Eg6Lig@Z2Dm6-)urZQ-nWmNPDd&SAii4=EnXT>Q}w#rZ0&Q5mZA zzB4&UT!QwsVU zu~Xf5YG5djU&rsR>(w!>4)0)=L;m8d8WQ|)Yc6b6Tlni`U#q~{sAw{(eSF1Mwm^Dm z6}X0=_1%IJ-g|yzu#q&!I(>GNcFE8oY34`%Q%T1r+NYjkG&78mNM}R^Lzbpyg7Aaf zB9SF$DK`9#`Z)B__81%Nqw)}J?1Sm0ZaMJB_NpU1F*fh|5Q{E<%uIHHS{X69gt)

%74i8g(}2`4;tdxTCC!J~OJQUO&iIrD&ME{>GOGwSe+-a(bnkzqQur)$tt4ft= zj)9-#>cTa+%f*4#tJrLa1t++^hw!OT_siZS@s!%y8&$s{CALG_%$!zF*_1t~kcLkM#Fp0)V4Ez~L6L4Bd1 zjkjN$;kC;#vdu{*2JTTSd#s~;o4TT^a3TtR#6x7<+#9kn$sh6SR=Gw zhZ(S_jH#EK0}Z)2n|G59-TrazD5Oos$f+1hFV&a(x%ULu~|Q>OP*6h2~W`OuP@65g_e^M?xo^}(X`!Dd8p{U}r0v!(Y9 z{dSW|u$QNSxJ4OlCFAJ*>8?YBHCT_;&yeR9@1&pEDym$N3S3mHX|Q9GkQ|O-GEwnz zxBSz~hj7OZn>eXzRbjD^2FkRur*7mIWJ-`Il&CHI-LeBzHG7^m$KP~S%6(7~Z+@C6 zM!nvmK(5gG({5b}$e-x%Hj~H)=L6$HNjv`ZBR(?*p7;`) z6$FZE|6stE%-_oAUY8qE_!dafK2noJNhYmw%~mdo-(|)7$OT-O5Orozo16S9&SMt- zqrVZHH`2`JwJA7GL^OZb$0c=@9T9+gHEpy=EHFz|^E8F_<|t_#!?bY6Grp-|K{T_I z?bjtrgu{t~Ap61shln;eoisQsWoTpVU0%KG_mPxFtIo%q!J9@6GwN^Db(3&cIh27z zp2Ia5BeWQl#bX#OmZcpoH!V! z!=xk|!)E((@?ekG*8CGlfHZ*qSUA{tLUWB(%tz*A9Bt~uU7MIjJNNmAt}hU7|B!?J zaxX-bT88tS6LN6q{HPo!Rf-H#+8m1p`n*E|J9tQ5kaZKoybeEe;2-ZHg}~10x+txu zD|kGJL_vfP^+NgTi7fz)@ah~ckivt}IZ~=yj7z;JjW#i7DqfpjX+*V7w#Hy{cPCuT zP=s`*%4@ijG~Fc7MkY~Eot1XTKyr1jvuJTwPyth+(Yb0=6+d2%R2^%B*PTC*a{qVf z&OL)?+m&~)(>k2=1<2r*$jQZ4Dl^Galpp`Y?;Bz&)v+k6@dHKg$ep!21Zz*o*J-$x zHop62eM1%5a?$MW0_|%5DK$!C>Lf?Dh%)9PnE}KJ&vh(fsO)TQz$lqd>1=9hNlBT2 zL&dbjP$Wz23KqA}mr@H(3X1T%w9y5{E*9!1Vm7(IsaZiXOAmvw(28fg#ADxrlYTuB z&4hD0K(xQG$C}WW z4(P9!us*V!?475o$m;3+wkT_r*^-;jDX*%5H|5D>`MpRc`JaLRo>j=g2-4GjLWTL( za0idh?3<(*oFFh1l8=uMe4jSkGvO0v=iTJ4x z^QVY5O;3)mIvcd^w0I?p%+`$D?GjSNF?ISA-tiM&*$Upi)m>fgqTvP5!g$+X7??0` zyC5t@1iMG`xzIMSu$K>+J7Ayh{qDw1Cg_u@pFYo?l=#HkKqri~|QS5$^uI{rTTEdb%C&&dh1%|EPY#VDPKlY7RYX_!BPDnpnpQ%?4BIij z)vzoR*<;sbB*4ydoi~ROs+u^}&*lWf(mf%V{D3);*2pwXa_hUQmKYlKTex7kNyBZA zf{KFbRN;kqA(U!hvx_>X$sQ32x@CK$&0?Ac&hFbc0V8g%m|afrrsby8I{es@=O$b5 zeK&TvKlZG@<_Zx@E=5BcDc5due>xjtm(?$I8F^Em+%M6C*x1;G1qF^31WHmPGTP)e zUu0prhz&@g8+!F|)z`Y%Dl~YT@xm)(`x|E_aHZS0swZ=I4`#_{i!iN*2IEok33#iH zfC|^Z(UhqcN&IocTp}nkZjiWKJ`!P&p4puC!R%b8<6BMo)VQ9;U^n~0gOF5sC05Ui zFuw#SpGU?0QANE<^mg`}J@Wibt>3*X`SUE2i>g#V{d6aoV~y)cRX&^qUUAnE2# zPpGaD4Gt%QLP4}-Q6gj~$Q-XF{$k=(>lOBfGJ6|(Z3AleNF_S?x|D*-)LJV@P<56` zfsDi^U8fILwsmY*Y|^wq5T_H8v7X~3o}SeeE@AXr&{fg5`SEgfRLQP;kuPvbOaFg0NIA) z5w(OQ`kx>_cB03psolCI5Cki9L=yr_nZ3!}m+>Ns^eMS`YI;MSuR?G^3ZPS!E+_~p za<+yDW82En>EDOY&iBaCi;d?x{dtCA{_(OoZD-3el~GqCXRdARuJKA$%e?Y$lBU`` zTBL^rHi)x}Uy8Z}L>*|z9mYhh=1%Rm#)A6vbG+}}xzX{#3%)kH zlbS!vUJ2Iez;lh)AwuU^wOR?ExX4<9wlQ)9x75QtsM>8#D%BcfD27^jAE;W?s}-v; zKZS!3PP{!r$P+RYi%b^T32&b^x^L)I6fc*d3q_!WoDF?2JYdnjMYZi~RPKF!x;%(& z<97Ae;)*;mM_EqPsy#mnvoZitp^TGaLrzsVn#QKyG|6)A87tx$ zfR*DL9}_cKrHSASW%xr5E^L6^HtnL_VCh2bQ}N0#%+tD-_}PiXrE!GFm7kL`of8v9 z(ki#;&5fsAQ?R#{P%6>Pss%#BJ#v8(3!p!sdaI7NBLYuUVlC_YZo&St!(UY!ck>(y zm3wVWzQH5OYe|;mtfImm;oGp{?A?jzxw-|Gtb&IM-(YhH3)83*vnCmxef)*$gUY}X z;JslHmIFjOk@7|q1G!4&rRT&BX;MpQp%i+ zw|l+*^MJ+1tji#Y!2MdaE`vgM1pPMn{I$DSkQJc`A+4E$z5y1EzXv?xbA;XKYL#KW zN%YlX_c;Er4nHz-&NN+CJ};B4#ctMfixA~=1PQ2ItWcXA`)Y3Si}5dhVjE-XiPf~9jWEBt3CL0UCD*Q|m=h%REuYI>%zzU^rQT)ft zB;hLgRHjnLl%7ShE<>0^G3a?X()K5Va(VKRHibZ#z;?{!xXJI^XPXD4JAW<`JW(V< zr)YQa2X9FBjPjW^{@;A7kLZOMno_gebM7z4gQUD${-*BdFr|9pCtQMGl_3TO2| zdjE_N(v8n2(hw*>rS2?&FkCI*HenmmGD)CmFl}pdiXXU*yPz_Z?PQkEmh=68x7^BJ*_BvO_u0JFiM_lZC#wjdg0=b=0c@v^&BU5PBpQ zyiv@|^E_Y){enlvh%SJXpFul4D9bZ#D@O`FQ@2<0(>R84!BNO^i#}QvE++Fn>xx5$NTDO0E;WRp2$-i{ zifA(Ws`ddx`Rb;1PcNwpda zJG3w)4ZYP_WeTy4X_-WfHJG+Ce^99wL?t;$3;+9OFI?yTwZTyYk_n>QL$yQ!l+8D+ z1#|n-AI9r~4G*_O6Wc->g4#A`|Bt8uDPK2hfv>aR^4vzVHI7Ks$7rm2hkY8h|&d1^sm%v(`aXqdO!td=-O$wC9t~M zru%6^7pQ!8DYHF3=2BTcEv9=T>Xw! zGUed%3OSex_!7z=k{pti3^c#Pz_64_Ml?YH-{p|`hDP#CB}6hxWT=G5aibg!wpp`h z=uz(Rc4lw6zN^_NvQ*@Zu74#~@h_$-??WJ$R1^MwN4)wB9MNVKWs)2 zRm8?2*!fTKe|~;$VP2>ASA}Zuv-X+qV$j_@*h$tTqR-hBpF3TyycJ>S38BEkD17 z<$PWuy*LwYbgjLrpp7TH8Pm${_+51D2;?7B3kVO%pI{cLH;@|!rEL6#$i<7342W6A z{^S%Oxf1;9sH!=3#6c1H?nM?PNIWBfR<| z8x;N^Vtx@_&zfUmOd{)2=C^xSC%{fhTHv*VsB7Y8hTWsPLT%g%V<<7$^t^OvlTd?v z{vvB#39ZB&KKgjB!;D&bSZRr=c73Cj{*rVvM_8|^A)@Tvp`=F!!cLJZZ|#+_NSJhE zz(4J(pCk~u_*9<;D_`$$IO7G1A>wWag~}6oz@C>sn`m&;w2{-xWbYJ!1&G0NyPT7U zxHosKFpnxx%q^)ljEPx5HcCAe(>*>{z%aeWK3zyj8AOD3Muv7~)Ot#!T}MDam1RiY zBa)ZU=RjLyW`h`~L_!y?0A;#_($kN64K)U_#;{H^m z{*-R}ipQTz=xGT_sMJfh7r3(ZGT8FIBJgr30sq9@W*4VV{5W{{7Bh6eBN1A!v$y(c z+UfnqqXp)amz-+p&o80ICH75wzZXQG;epYH64v`Uyg**t#d{n>3?+2a5%M~%n3On0 zgs$x>=__F&7TtEsD$sqM>gDjlH`?@@^2Q>brcdsZs&P^789{EK@fX zJByWh?vgDY2CbJ`nwtxf_{Z9Ra?7Vk8L1Y>8?6xB>*RoID8 zVw!DLkmz558Z)D1is>?;pBdRGP+8YAGWGGwFtd`rETzi%306=O?)||ojU`&B;|1sT z1#4h|9TST zwTG16XQxhK`Aq%8`oqR?DaX;O8z{J{V>`7KkBb6PM}z?yFWT8!W6f!Dn+Mn9rogcr z7BYbuYi{nOtlHU6wGh2drUhzL+aDaE-Q|*yNgzp`(Plzuj@T zpCalS0kxn!DQu8wP$`zlurI+cK0N4m2X_{V5JvIqKQ8z2yDa1xm86*Wd3R}+I0XP# z0~UjxM$-^(aeemktcihhRChm7cAbqE(8mHG#!iC$(Wae^_)p!B!J@)60@y-9BsLY> zm!Cy0wzVDin++99_cTW7E_Wtc0EFdVuOkLmSA}^Hp`f55z}7Gr{WK<1wfP+^cXJ)z zaujg~LT%!3{}++(V6~0$7Oqb(m%G2dCq7v!&IYlKzVV(_>Ifl8XKo#mO`QfhEE4{Rw(+o!_M`7=`=;{wwhk01A2 zZ;q}HH6Zaz%wK1MK2y6h0FRchv)u>w?SpOc`7PstH`c5<8^-~HlUjhtD7XLh!YJtb zDCeWA2#Uw9SMv8-%uMXYWZnBLtlz&)`M1ne0fj)gvB{SCpqk_R&k+U(m%qY3Ui+Rh z)$2kWclff(97uI%%i|@cX0P-oL^_1&Rog=`k3OmD~FrXW+ql8Qx}VE>C?AFJ|WEy0is{3Q3>%zz&L1 zAlONmHmnjuQ$$jz*WVPEk48j85 zVaep>do-cF@jdTIFLiNON5ZcZLq#U)!br)l%q#$01R|KmQA`g}5RKj!c#&iC(-M}& zXd4wO6-Vrp8Fc8p7i40ni1J_1Dng0^XWsTC;UKtD42$K1#IAG%r~t1wOM!{456_Rd z_;^KD*_D%ZuGXg;Cio9_bbU3BZC|%ff$zWJsje_TB}i10azZ&>tdp;Qz-g_eP?e<1 zZT@}!3tc_#D^;fUsqHPo7W^btzt5^}GU?cQ$T%!w8(J+BfV@CV|4HqEBTCuvo~{%WU=1ci zq}dz&$y~&m?vQba(m5`%L>v%3L1cp^YPU!Y89wYx;4oehdAX1@Y@a!dCmJ|6OQ(e{mfO5g*+-_N!q)A=iY=8fMwW6!MuACVBy8blR7 za+BZ9lF>TxD%sMD`;K64gsFc2mOyCbA z8u9oqHQ|;=X!0uw1HMP#9O=}T+l>{x@`ws}UyDcg)n0h|DX+o(bVpjFLj_FR&1aYV zCl!)2K{2@p^izZeH^=0*im}2&#~1br1?(7 zcg4RdlsktsQ#!fGYDD?Bd}N_qUZYN{%eS*mD5y8=UXCMcGsmwvh)01O`*~elDM+Y2 zY47hX4)Xw6Oj5P|n&FZXoca=xszzRUY8ftOLa?zMvcQzxp?~ob5O=uv?J~?5<%S6l zX2-cw9B+<_H*xc&U*bY22qK{2#2|xqKj-7?f3>Mj$Qo6UNO?$Z@d0qV&wi?JwC?kO zu8ExBDQh( z#H|b2K|T&x`VV7Xpp2~ zF*ZwI)RQ_w7K&&tg3U8AsNKEFa}|i9bUPaC5uW;hbO(67GGm)Jnf)P5ixaq}wmnk@ zCON6Gog)C&Easb?aoU~`G&12lo$M5R05=~`6MFAHkzzBAx9bwX-n za`(yEU!$@xhHMiLWyS{>GJ$9Dk09O0r=E$UBmXl{Oxw5SB&}4G7J~g$LP_x%b>r1A zW|(;>5tlvVb9>y=llc?6NqOJlg(pWN8Y%#<-e-m)otv7Bb$To9X`379g-L)AR}Ix zS+veO$bT(Yl%x`cFgIdPEf#J-HwCPUajBuxnIUnI&@iD%tzlBG`+F+RF?WCR%FTGC zTfP6O*>DXU zb|53DEDqD z@g$q^$_vmJk)LL>n`s4q&YdEX7A;lN3g%MGonNp(y!F_Ph7t`_fFn^9;nd_u7#}cXNEqrid*{xmUsEurD)r5%PuxAdk|B1NvIJ z=0kTaT*Z>2ao&+vW|}8a3{m~U8=^Wpu=13LYiBAJYL|bxnOS*k+bxD_!AbCT3(m1b zkl%f`hWD~`*pL1xfKp!w*i6W{jL4r}SQ&_9=pOgIk$(s4_`b>MF6?SUp2x2Yp4Dd&2aODZxg1n4^*!{!y7uyBJSeNAvi84^BZ+nL%b%-Z{ld z1LX4y>|u}T3iWxY~f?{r|S zsAk4Yn&ulhKkf$_mMOmpmq2V&arWCImt*cpfdJFEbm-Rh-Zsl)8b*q zz>vYNPJbkj6)S|wjt*9&-Aj}5)P!-{d3?3m>F)}(g2Xn#f~=kA3fKXHEzi6d{&pB> zNbUNLzQ6edatXaYU%qJ7ynSY*4YZ;fm>94eFDe1(?LvexjB;oTG2^O91Md?N5=l(; zkrXA_*nMU1#^5hdUV{AuHojg8NMKX8o_<(Ef$zE#*Q4ZYUt~@bY{-Zm=*z4(gvGqR<#UxOGTW$2D2I`Dn za20d!JkX+0NJjnms`YpMO}Q zKCn690pt{k?nrHht_i?|HD{T4IA;MVB!CK(8K5wP)*D*uv}odM_84jLKiUy8eoajj zm_|@JH8j^mr~J^9&IEpUvQc)SG>*QQli#krjK8ns3Fm~@ulRX-0vD@zsy;)v*X18y z)k`gwnFu_oHL+OEIRzf-yyGb#>UStJ0*&rCosJlFpZ}^qo~ZXsTGn*^8CD<+Y4ZkZ zVfE2Qa71fg7fQAj8_CCXA@n{8Sn zL}tHA+8JE3GT{3JiZnJHxBjQ)6YTyS|7l@jE&jDatY5FzFi51aEqS<67C?;YN(e9X zySm@_jsX(Jwfe&^Gg6(C?G~>jR2LvdQzeMRrU|W1%xy_PB2WQ8)aNE3wB)sG+QjhT z+kGzb287m`_V{yOT9Kz-nQHQkGmlK7GgJ#qRH)Pt3nMDVOG?tUx(0+iVEWiILM|y$ zw>NlZiz`!yQ|6ooJeGQ|%FAch*oT1>C*$V^NAmfD5YaS7v<%fiTX<}mtgIp%H80;a z1pZ8Q@syT4SU{KS4p~KYcXZrc4N-bNYU2ST7pgF+G(%`>#^#ln@K0%O`k1s)DneRQ z_Dr?{MsRbpiyWT7i2TRx)TOKM+XWLRXV6qh{>Ay_A4w|rZ^u$y{G~20Vgzl>WA%bk z7DAWt#aE8M!GDUNnq=S$=hd%lOyL@uz52Y^p>qt3fqHncmHQ_YC4WdmN`31kD6;z z$t6aMOL(Hxfa`0swLZ^1De?}QkU}-)&q?}Og5yrZY0T(JGY&ytGu^L)8y6nSF{1Ug z{aae^h~;9z9P(btW<>4Hf&i`n7Y5q$KFEr7pxn$X%eV6T!uNSlj#$MG{oqcx@8;ZT z26c&dv|g%n{7jcHJYF-M4+cGY@pJQVKegq)K>Ivp_6*Y0bc!)zuTF-WqxJU&jmNsim;;{wu7P|hujTPVtGmtRBmwrGT*`E8vnbRtpeK^SnU+PGhE_^jWYhCGkuk>-~8Mbs-_ZomzTt82|4xWHt`yaaOfkvIm^k(4>w z{R7~B0x0o)O#ldQBXlnx@Fi~&pa>37CQ?_o6F+m8=g*>@mRsgtZ1uK!>aTn~Hb{sa z^bzV#*iSCdHEMNqq6;p73-5ANPGrknd zynti!{)|xMw0}kTN{@tsa6Z#~x3dsXgqav0$jkGfq6T zr|{i^3%up65k^d;sV3Kba@WR|s7{OU&xF-5f@=k2fRhrhS9z>a-a6`Fv*SEysK@ov_A%*h#Ec9-t%E7wyLV@ES7gbXKd^gR^K&+dO7)a330TfLoIhyj z&3tdc`*ZZW;l^X1Pp`G$K{ain&hV~A>;*GTL~ovOD3|+RjGE4CYTK?SQ60A(@?L#` zm^r1BS#^I)PVCv8I=ndXX72EyUz$m!2-|k}!8gAdE}>LAq^YP>q}MfCf2WVQV(Yf) z5GuFbb-YRtjRL+1F1FY8;!gMGq`wEfm;n1#tU>p$lqppS{Sq3`EN2Lg&6ri14HKz~ zN0Me^=lLmu0yKSjH!ACrzYb@E5?J^%a`}0jXFDjXLT8WOpH)PK z(MB`S-aDzZP-4EZr=rNcZH46Bmierb;#;1$ppQt|gvSnT?)2VLsNB|9h%LH#?byhv zh>C7}PoxG}it1H+)kYSZ0k0^`W}3%0!OSWP;K=`zA`KSk2msk0PyZvEe6;3?i|LUy z*Mi*tA(aikU`-1cka7BWaW%^tWb^# zL_+rek|ipR&@&A%!9j||Yew$o{bwECTaQF)YycJ6IiHi*>b~)-7S!(|wu+$Ni(^Y5 zv0+wo#mE+?kts_lu~CETN6hxpp&`P_v~AavFq&*yF)?;f?%weV$8vLzZ+s1G~F@NaEo#ikpOTyhy(WU~U_Ft$TI;Ya2_!cG|HiJOFtiA=Skq zw|{d9Rsm+P8v0H|w?|c&pRUb5Sn{xIhw}p|J22CrfV5U`jKV&lYhI1aQyp z%z5{>7mRCboBS& zO1K@441#nO3XU;Mq%Ue^KBbPZ9*9d7{}Ycw?7Pf%blPtXSa|tagu4?qnk^eP4QsZh zgYj2;FOMH#WvVx?dGGM^^_}|8h=r^L zA@l{B%~_oF^%LP_Jv{?5JhU1dXGWn+e^o}3hQSDDNkAyYo)5TD(jZ{or!NJi4sX9yLMr&d_QN`L|>Nlcov&A7}_l zQcA&?n_cgaK= zs5J+T?qsnvTJyW{U;glmUm#x z?|Rvk`kSOXrMbEoGYO1f`Z@VK0!a&idrXDEGqKjls> zjq2Zd){*TXC5SrxtJ3Uk`5vmXM6dn}#w%i*rd9x{{kQc`%}IvK^NF6nfYnv1skfQG zgcQHG8xC;AFs(Y9Dbr}w*Y*~r%l{mmG}P#zIm1D1o*|H94K9#fBTCmTHevq`KGP0F zshsez>7GRIV`j3pbX{^I2H17L6~C|9AczV}(l2cNsG`gFwmtKMglZvTU8^%9ztn4| ze+kgUjj~J5zbX=Z`W zz!Oth@!ML1&1z`#PB9CjC4xtHq&m7#Tb>NNfNxf^y|vxa`D;~#h*IfZE3YGpe+L@h z>W7Ll(0U1&{}Z2Dn$D&oYV2_5k{A{{G`Sr~eY68%cpMo-N{kX_C=xisXFB{14!Z@9 z|FaX6h!FUuYkjr9;`gBJWv<{gNkHmy9~1RhodzAPgUvPHq+GZ3MCH8h!F^Yu*uoAK=Gqx)KDjl#nPsaHAnP*Z) zi~_(m{)f@o8wzx9r^jt%X~fC?yequFP+r#V`reC*1v%~7-^br9P>tKW0*{jL&dNO+z*V1iO$fay6sf~Yy3q_4@Z7K&3r??;GEo(00(|*6ShZ%ti z=<~a%Bk+PX-y2W8zUlP6dHK(GP{+??O>t@I1H&W6$>i2vX0hHVYoe??{+$A_M|4zw zDuxTzpp*lX%@`ehLTKWZUg3HeYaZh3ZR&Q(o5r(Bz;2#F4_1QsjP9_H^yE-{tig(1 z(Bq9Qd&j33s7V05F`F(ef0JnG8%>IzL*TAoWvS;ax8XqR;{Y5IIl1lsPRUTM6Tla? z;)}t_A@NF+fjsu&3wXi;i6Zy3@#tAoF2%DeT{xOcmPSI6Wj>ku@&EG9WSCFcIT$Z_ zv^w#ozfhRO)9{P|Tq%HB6R{jZOz|X@0@!kasCM?;OIswOs0z?_nMx4tKS^~*+ON~s zmUDX&*WueZbe&4*(bf>HG_7)78Ht=_4IE?VRab+C`MbT`NsA^3gWAGk)#^0rSB-{$FsGhoY1ZM5Po_J+u(>w-t6abg;3iy&IOgppDZ@^~~4o3(d(_ z9xYwY9z!liJ3gHrhTlJi;7GM$%@Lb8@a0nzqUdx;!IQ1-#~Uby(&5EsNUr!cv#7AZ z>90%6c0}IjuKk8CO8MyRAI-6p{MV%g)tfKHT4^Q{qvGj1WFa;GGrI79ia7Pk#>eYF zAko*iaL$TQEY_g81QOH52}Kapn_v#lC4yk?Qb{+sa;j`?b})s#Bvhxr<{8}7PFw@G znHaEt#{I|I@lNGioKeu8x1LEy&Y?Y8D~vN0$JE-=hXI{wcjCfWOe6eLA8?qAJ=h!l zel`ynn8bjkmo!a=L;ACQH}Nmb6AFOt5e`Pu$M}-U|H!^Y|LRXpVRQYdVbUk5RC)l& zzpV1Q%G%l25{!%Js!yJf{`+Z_d#R6mi-3%G^||7ysCaiqFKZXF8IZ zneuz4)OWLR-P{3@12C@wT(s;Hx1WlAFkp!uYZGnxR07>eBU%dN_W%Hb@}5wFY;y>a zp=$F*@Z0Y~<(zeK?gkrO0rrz762KG+Py^tx%oi2Hw{T(-|5DRwLI_dH~Zr>k%y?7BSG#>y@zAI8gINjR%+>5A2C zS+YAfxHsFJhT58gdBSWIY8$K~t+<4%6Rgn>m&f2l+d`eJ$GoC0vf@E1Q4ZeMo7pjn zu1CYa)^ayJN;YO$*{2&u;DG~L^6YkX`K>?Ts>#sR;Uptdd5X@!W7Lah^dPH!@9}p- zRf2Mh{}^RwG|xxY^jG*1E2A}}cGA2C{HLDRpcCIaTtZSem_Hn5X!r_L2O=orQq{fujiL0;ICf|02?9CE#S=-sg{eikiGlaEU0$a{3}j%N)JYo=VbGAfqXsuVGjS)JId6p9;kiT{|5oE+?D`B1_CQPek{x` z-kEO%L+&$-_Zj5opn0m<-u#qYXW!X=#e5WQ$2#_{Arzq=aT))6;6|+V&GZ-eKT@M_ zKOV?5%2c=*wh=DzYAx+Ss{Tey1N&_NW^n;L20ey!JNC^2wFSv4 z`j|s?920*x>Btg({YT5_I*R8PGP9Raig>F@SFYJVjFz0U#dikF=zX)mZ7_p> zLGiVn6msp$MFEgu80intY_E{(g+9$2nZ6=NOyO4cO9C4dH7^AS``W7o3Y^6j zZgc%e>-&S84Lx|AREcv#9GRftBfsT)wdqo@agNmYL3?$o_{QgOx+4$rS$H@p!ZDFilze;nYf+xPsF&Wp8Yc}WHSWUyFt9AF;9=#8W{ z`cI}fR3)Tsi9r+Jgf8Qr6bK&s?B16_OpA0^ipmj_Rms~mLPszFsMG@w#>h^@&kVI2 z35-R>gvoapWG6l+I3;;%-2Db=&tJZYep0z``E@Y+7GhWs-1^E@coLU;xI@ zYB{(y>G(8-L>95m=>~9^V1q+bysbC<>Yy107PTVf{G7XQ!xz{4VZ}7ONy)EL4{CP{ zk?BJ2`T}4M$RK0!jPfG!8$Drw@wcw!P~VM+B~;6#&p0JRNnOoHFM*`x^}zz-%sB6K zv3%8PN+B3yx@Xq|mnTwiB>iua8PcLUK!+?Mj|eU_i2+c3y}jFD z8gRb_ud)`jL$l=&v5>^oBCX*R+liAr=hj->wSr65e75l|Ma)D5W1C|hJJc1xXa*4S zdv;{ho9MhG#>2yIru$6Xzvo>ezB6ZjqnZv6%wqp4*Iz?fuYkAovu2TB6fM1EZ36aZ z9ms)CO{qV~*EorGZba3-7{CGMiky8aJX@;G_`^Gu(K1`iOxaXXAt z?<%64ujkHq`)o>^{q@q=3GNvtPyBKPtFt4rHQ1@Luf8nU9ukI5vsi8WMQySF`l!Uw z=@-??egZlQwkF-$sZN{4haXD1n5sXM>znIZn3af$GHP~Gn2qC9W=Qhov*G-j-RTIg^#`?DRshIs+|Aw*#h=R}@t_&yH5kYxsu>|5gJ5(>&rqhO1_SXw zF2ge%zC?2G%02f)`9OVRK zFu^?vpPv-(=$ZbR0ES2Wq;k`x=Z?pSoi!9dmSZN?`<`^OTJFeY@7)%4hmahZ+O30iWb>E^1Z!EuS-VC~!9R#qZT`5(f+4yz3pTwa@-dH7yMk z%_~~nu>mHF9cb5|$wx8s%zf7n7k-ysKVrv@C2uracXFLDvE-+IxVqdit+d`)QC~1B zuX#w*5t9iGG0L{Kt+jmil$rB6B#7e)~Ab z9$Jn_hr7y13)3e}9T@sPu~9YTD{!n0H9GP_n4MZ&oo6(*)3t^p(d`p=680y@W@3kwB#k&L^bg#jJ< z>2o?WXvg7;IP(eIgDu_XKFc(n9$?P00NZ1w_UzHbVweU9D3~qa zF%#)|N#W%FIhi2!dpD<^u0$W+>?l`VXx#~59?7E{uIKE)Oat$-ycZ2I2)FFZl%V9V1Cd z88M@gCDfpy@g0<>BqnF&(ojnr3NVTM#JXa=|M|K&K&BCW49{`J^W+`lD4pY@{W%q|YhiRWxgFu= zVxiOC^cUxB)#MwybE93)z42oGh8PZfRC9fvX(LMJy75`J%t(JI;hYetejd*s%$L!o zpvm>h-QYPNRg$SFfS?Jor6`T@uV@V+&Us**>Hu&FgNN* zmRnTTx~HmD0qkr*jR8t2@GvWgso~6bL@BRbR~dbu?7gj_{74Xh!8LaL5Hv z(l~YGPr>Qcb^u!{)ajACuRZC$uzFsCQA`7jynL-8b-X0~z*1plx!-VJhU@4Ae#BYB z^PO9TID7gfiKy74o)jM3X3dkvm80MFyb_2ginKcYs^!Vko3h~;VGkh7jm3;80@mA} zq$DpdLx6Xi)eYGCwkJ51jZ8-I*G)#ijoEiJuLL91nun&!!4O%aPv0P2P_i;5P&dtp zH3SvR@L6Y@Yo<%>AXOySjcU z`_GbO#{K+F!4)sW0xmFW6|(aw_pphD+fdx9 zv@wgwioZo()tI!7r+SEf&0f7*m)3^FpsyFOD)!ZpL?V@u z%@ogV)j8;V=7|dP?Xsnb+Q7qW3f+Vt`UJ1tKRVWa0pZ062I==<_WV;x%?qB+Rv+U( zklCJ((j-kiPy%$LveCEHH^8^vlD?I$<>@&G)czQhH@2xy04q^A6p@QL8uIAO2#s@eNfc(?0Bwyvo1$OYs9 z;=P)xBQAA;?+OF|$m{9zsr%yI<{i1GWGZ@LUH1Sh>!_-J6HQfS1?SR5R`OeRXM(>j zJgEW`JoS}ci7K=!G{$|C3n+Rs-?)SpujOPvM?#MA{c3(mHKf|V%bz89GeLT69UTHf zCJU<-v{>uh3+fPpIzQN}cj1nAX@NmHp>gT89D?k<3b5!G<$YCahPp1WGu537e}hN5 zrveqJ?!9C9OH6=WrhsO!WAfcFbM@t2Eg5j&6mJrU2d0*Lkr|E|Y36d}?O~<9TCTHa zK@O%5(*4Q3oIiawYDkRa-LvL^w9+%xZ3xcJ`g->$H;ohav?iF*bFvRn)TFjW75=~a zI+E4FssZyLtk#6uDlz7C`g>RpJ> z$vRpRv(+E=z%*dm1>%5R9VB-Y@9pWsUmbqo2cb2w?-soG_sJ2_i=F)*-FU2O(=l|O zDaRbARI5}u3d&juW$#1uy8oRVORyawQT*lPHzFZKV#Pa8n*(Ukt-(#RIn6L|~fFMp6J>E(BL;$RTQDg@4di0b~!&JK4f-nyNGXU?! zb2WEY^CHTccFY7t%ONUg2|KvZ8hCF&9bs-}@kza`zTWDG+ZQVt<4rNB+C$5WMk9x- zuv`X0P#ahQTV-ZW&xfzpB!3;?R%Ex5RK?U5o4_WlHB3xtJka-coG(p872 zhQ$2yCJtH^vN=3f=Gg5dguTQB&qQ}n>z(3|L|>klF*S|$PO)x_g)o|1`KKFkq!PQd zR)yD72PuVyQdPRX?KmC+;%&RTlrQ+Nk;fI<`f38x&(n^96;lEJzuk(W^Zu!VAq73LZE}cM}f9%j5C8AY~`y*ifkuhfx?&zsoHnlIVmt!IR z==@_wE9v0V)nVF?%>Z%A;xz7Z=FA=7{o7M7yJ@jWTR|;hs+PH$v()QPqQ(l5lK4ia zdiDD4P&spI?bS|>a&zD<;N~?i&*u|9H%riAt>6rYB->6T(pp8l#MS+1L7`8XfgLLQSMkw^j^*Eu(-PHD+$xM z?g#@X88`<@iOKk+efid;RX<>O8m9cj!>i|j?$z90P8w&X-JA_AFk-(NchIm4*RHv$ z-V~w2!G8F?a^FKIF~!{lwJM#uHOJcdB2^nTji$=G7N>XwMog7^sixDtS{ww-%XWmP z@QAk^H`Rjv+etp?4Mv^SC|nf?{wm~Q61jRNZ@9x9UvqIiYii}Uny1#v<#k;VU$X*P z4p4Kz2JXFaqZ0+c#NGv@Zrp?I@X!jiu>ph3C!B>dFgBJ_=;<5!?ihG^vhp1GtgB!H z^AH$tA$ol6y_B57wfo|EgY1d%21#Av-R)4|#lQ)@1V6=UMw#F6L82TE4pw5E@=G>% z4KTX~Bn4mG(&lX~VWsLqp(#h9#dOTAp6`6BET;rwzfWSpAu(>Vl5F)vGl{quWE@CI zob%1aI!osFm=eFfWbGW@M5287vbleUMk*L7W-OoM!M(sYpk#6 z((LEBcgq~nHgZ4AQzA_hIWGN7q<^FTK_IiI852=y;XRMA7W5pgoaDfc?EMdO9OVns z^3o9KEI%P9*074d1T{v1;Bq5Ruri{!)z1vp%o_nfyn%eZX6@P|D%RDIgkeuyn+k=o z`G_X*0iWFiOgRSI*)I}jGf44+r%9h}ejEPg*%;cg)at@5{&4J z809Q@ zh#89JD6&*Or`w=xDgG>_a4QSzja`RTS&$$H?%^i2cjDOn2R{+tDmbG55UG#xn3OJUAd$#7-dj=}=)+n-I9_f& zlXPTW601w6@s({rJL^8H063|2dg<|5?A>6yO?%msg#FrQz62dhcIQoaH~EN@or%9l9pNhWw~JQPRy8WTkQW@>B9nB$p` zXkEv2!a|H8(^oI`?){s{0A`u|fE6)k@B$xrXPw9>u|6H`O|~1!k~7Srt^ndhnp)fH_g_zdRocJx>_loqE zyw;8PnxY+s2;h)u{^biX5yS&wG5|M-dv97$Y*;3ow0gB+{Lj1cpcljYRLuivgBIY3 z@(?@FIPUCk`#Jd!K);ATKL*}81U%;i5alAOD)nHx8np)|or*By`g{c*PA;4k>KHv; z&fT&YsXWARYq}PjM6g#fFblQ%`_7&gq#PUj`ilbA6h!&m^bZv(*yikSIG?xxeTuo_ z^Xd10?;FHTDRS=oNb^h)&>AB+66gf)9tdwm>=dh;f)~GLw zcUI$7^WT%F>l~f{E~?X)FtOS^ZgnH5VhTFclz7qkHuDV&G&Id}(iPRUp)7_lN!H{M zDt0XUrG&W9ha8OWU+#In6eEV4m8n8UPYB$VFI>LuAOiH(PI#2GF{bcNcX;@sZ&naQ z!SGD2W|Dfx0h6%OC|O<&{@0Wa95&RZSld?GzgS#zslr{^T)PJRlMZ?XQHeUijP&ht+PMq9}mgNfDA zg7Pk&IYbxkRupN^kH}XgL(&AD=rRy$90+MOUw31AI{GWB-|oP90~NEa8&O{O**#O$ z*XT8b<^HV)jnMNDXdtB0 zYo8oO!iRv=hfnS#u$4JRXUo!v(0krmuVk9PG-?}L?jaS z^d+_EFr3d0x6L>CtY?pSpPgTkr~*M$IK;W9`kz~)V+B|+0}=fOS)fG_xb%H0)tr>- zh_Gm*TuW`w3y_z?jhL+aBQ|K-ezeplyvisbFC{vbv_yaFcm=;qLV_+euJ7i27Fe^u zUj`aiF5;E^Y~v9OT%0?d7Q`T{xovj6rckX!-1uXMe-FR#xe%xj?Rzf9Pb87}7z-X! z!qUQ8qNy~A#~MDfl7*#AyFLpM!b6_7TA#Gw#$Pxp&_C%SzJA%#$#R<@G9|mpf?I?Y zDZwrKj@1z>(}o+|(^6hC{{T|~zI2(_*9MO})46mEV`3;^?|bMjWZ$ym5tc7cGJT&_ z>+8!WuA)yiruxau!U>V$$dfQ*pl@mc$Q=KUkz=oudE)zTti1<4ErYfJHlIOiWhX!Q z+(T|&NJ*QW)WiO1tb`hVvb1gU3_e-I6F9s{)OVM;dHCqr@h9YD_t%oCP$qf!pvxKW|^Y%IS^6s6mk7>|oI-5*T&1MRfHe4Xi&t{u>k(RAK$E z4vvpkmXQgtu5wShy30@^ zS;OQ7ZznWNYSp@3RN)YG?TjEYw4>EnhY_s`z(wHNPnB2xlla@?lRN3=5Vmo?aMG-2&XnwC zNy6~6V&b*5B;=hs;wI_G6cLpB{%^d_Oh_Y7-(U^kZ^?p3KAhijPemHrk=pIbA#{vG zJ5k)7@nd=oU3aT)Xuz1WitN3g?9$Hx&9%huirDiPT@uT3Se-+k4bv|9Dy{} z5unm<|5M@m?Jqd+k!1KM4{Vz~I~%gySs$Bl)}Lv^Q%j1)B@gqPZhfxZlka8zJ4b?6 z?!LCZ`WlGL)%>yS5rbX;vopBJb6rSN+6~q8b0iBp)5{(gz2$7hy@*8s))%&mba1c@ z>iM(vJ;}BiHWMk2T_4^|`nG7pblJw$PvU^oA1*C@-!gF0)wejOg%6@cH?Tei3CB>8 z05NZ3VtOR;2^&lu?3j}saz7XeJqQfk!jE^Q5PDZ?$gMJb6n*tHu3laBhIv+!N{uYS z|90phEAX6_oO)ISsXtHZq2SB9C=6%Nv`<@TUXFR&cj|4t=5){UL?3F??Q-AW40ep?lEE z?UATt-ehAzmOeQsqFNAs+8EspRo~`y6Zmka;lEQK8 zglpppZT}5Bu|rjy_Vwm=z6X;jQnYT-4LeYXyR3RXk3G?cEcCVjWH~XejVH^7e(O16 zmAG7C^jZiXV-!{@gy??M;<0sFW}3F^mg_kpPb5n1BtI}O#f|+)j)i!-ktJp=DmZkJY`H2O=m%=}>t^@h0<0?89jDq}y-;YgRA zgk_-SS!9%n8tXNfHpsC>Qj;4oX0{sdDM@XuKrh$2ABfdn>l+s# zHwvOufSm4-bgqRPn_U}_Equx$>~LQNKPJTy{^j{MDv5Mfv%dxLll!X@6cLDE-Dh5g5R%c-E z&BO+loWFM{*=81RmKBD#Qq6Z2C+;BKN#2i<9})p|vm3A6)qD-P!9&*h%_iimJ$Hs+ zpLhv>0+yF;t9)-gv}xiUM{?VS=sKzSN^?Hc%s)dy3FjBGq5St7iqoC8vL%sLZ3#8a z2cqcpHZ5hh>o8!Kp>RGxU|N{hd|uV@2RC>$uBafw{qB=5)b7dPaR$+D2)=Px*O8w0 zIN*vh2YrwrbYp*R&QK%B-4>lUj(e~MOu59nB2}^q9%LWoS5*?$BP~mKUt{0ayu7cG zK5`UN6Gn;Uy{>!Os>tou!0LKSnJkJhhSnMMv?S7_ErwfC>R#uFutK-*)-kM-5_8Ol zcDE#PoZecFS0~CU58P4!ZLBhSL;R84d4XLpFAIPlN%RFj2&epYWPg#V;v}1KkKBx- zT24%a!6tGG2mBj(^ZiTJr)iZN`f==$-vZ}HME^`MrDSW!IG%{ydJ*4Rv#?XMA;eC4 z=QAB<^?e=AwVqM^<1=0OjX8Pa!cOgh+@8;FOIzU@2MriHNd_i4$E+`g$XGoN-Dp0) zDZ76RbKLtLEf0t&<$7J^D;L{cexLbQ*=>}4&7o52<1rv|0TcM+3eCaB6n7=s<-8-V zlOK3es8Xf=Q8Y#3L5=)tV~8eknET8PZ36B1w+dMm>V)V&A)E2vaRQNr67N2uPVbB+ zqdFFS@%1Bnru%qR)qLMDwZp<{2<&qN#!X{fHyxmh=RPNHc6iJdcQVDvRpl%-$l@QF z9p^ruGMG369-x2BytuJ-MQtU`0fTekCf#~;w%pg3n4M1D*CJ_!&eKa0}UW9-{Y>oRKNtzC)1SAc1{~$~* zTo43al`h{X_>D&YbW$j=euUd*SB94=mGQ)bkj!~Lo>Lqu!$?GgJl`Qj<95T+XEB#Q zdGq555KUe&w)q+u|y^rfF6thlyr{~W1D4fcb@rsmyj-Ofs#!?=z$KhY8{7-!I@R= zAEzZ<0D5|m8B|c=Z^GIfDZhFToau9zUV#D4@>d5~E~hqWYY{ZPiMJpFeLh3~}d!u(LaC$*Z`J zkIj{H2Z;X&&S7OgrCgt)0!2h|K8!Wz6C}W}ln3tUUteV69H&2=IM3{+2#+n9J*Vu7 zP@}Rwwm!_XB7b{{@8Y)4aLOqprI@iXt6SUEJ+iRO7IEyH603Er!VpW`K;&w?lM7k1 zt%rEDekhwVE^Pb21d_FwEO+=ogx_dGFc%33odmp$tHr1EcNZd@%+bK)_0EF+zp#Ns zu`jy4Wq}xoXi!oRW7un8+aUk4C0w^%Is6Icc>ZVTPMTBa#VGGDmWL-feve?m%KoV* zqrgT%b3axlF9|y9XeX7-12ltAf)r5HJYWOOJ*-<}^8EL8Da3(XL4e3A_q&XIYLV(C zn=4HoSHaQx-JT2rgm$(w98aR5KtF|(%*qFTi&E4?+y1nT@}X?@R!FvZD+CG<+6;uj zV*OgJlZEErr{F$``w+*g8`87M=Ae|AjY-MlD*jDUBpIYz=nN>&D8fu=>Od@BZLwDg zbJFVO=meOcE{RCTkBDO;M-*_@dd2QdA@$doO`L(LqY>Ywz?ex>a?2g)e(IVtZ$m-c z#)vFz4ooXl%zq#1Y>NvBY}g;s;|j)j@d)48Apz#ezSJ0HJEJ)$cpSf#Dn6N~dP-UT zyFTeHi1A7kvycCtoNe&kJ%+eqFnj0jVXM$QN{+TDBHQB61-WV9ciiQH@6I!eD;TQNc!zLem1FDoL#)m8&bs*hpkJfNhP z0xw2SB-*{afJ|}$gurU8LFoL=g5K7#J!vSPvMp_-rJ48F%U@vTv-yi_q4uno6;8X7_=pdBZK(C4 z6kVYbbYE=8B^P;!tg zWto2fL+SzL9<)p1wVPENt|_RLz4Ns|oI98c1F(|fUq@;VhOcqZ96$-_I+-tAOWWby zXsklRFTtOU27fjQmH!I;fdA?Q)@}uHp^}|BzfTc>{JK9-l`l5lT{eezX2CnncNdxi zEn^o_+t5CpLJZTf6xj<47Tg?QqEM| zzTOk*1=1G?gsS^JI|jQQ+?pWq5J15q;*P^=_4EULCz!f98ei#7sJ5Q*=>ySq#mSi$ z+#$;Ee~ZThgQ@0_{`NI>5*VCu;S-bpfRB1*e#Lh2BuoB_B;&nlxI6un!7Vz_9sWs3 z-$W;o9aKnjLjTRy*QVFGyT3YdA@zfh9q;S50l?oZ&~R9gr-}EkNcXR}XkHmqQzy1_ z{{Ky22OkA-zFJ?Q>I$U&{^xs!004UG`wi*f2-`VSI>%dE6aEzA46tW7qTdj{dh8=q zUFSplT?{HBC*Ie`Aa?HWG1W~?&`f)+Y=XM0-I)LwhnebnimasX=NCBy0dcF4wgr_r zD#;EMePYqiFNRai-Yp|+v!7Kjg2?EvPx@f$AYKx&Ye@K2F_d4kc((S|Q+dGax25Le z*jTD^&dN&|a==xEI6gfu2wu?DAMXzb9{W~Ym+$ZUC+d}T=`r;| zcw+iEwi7MLBzOybS7D6Kr#c zy<+W8e+Q4!DLXBXBQ2-K3)vby!zA`9=Hf=J6SucH`4<66Ao`*t0J?PKd(hb)6<(8o zOGy}AV=$~MMUW=ao_onKeQhA!iwuJiUtL*fB`n-0f}G56uwqmH`(4zamTP9F@NnOp z`Ol;J=+g(?RWItlS9Zo-dy51U;Za|286dN5&>+^_^B|PC!TnCQ5Z9S9D9e@FPit88 zM+?^(2WT*1ucjz2uP{;fQ{KVUNtM#YeSuG96`vFlheX&QTVZ8WPQKrji?CI=ke2}( z;o7Bb^SCA|%7wIx_8%>Qne^0Q6%G!!PxY>NBhc-Uj_-nV0})R{?$iw-C!@&XL22#O zzHddO3yh5ZIKIZSYnZ7l^d&huyX^8R4rzP)vYGMIV^{R&?Bpo!Z!#N3gr`-AD0k8l zowTph#Qn-h2^JpPRCi8~l6`EPmdcWK5xaRdCCt}u)SaN=%SdrnAc-q9!3G=kR;R}f ztzJJux-(iL2B(X;TPGgaEU+hJhp}nr8t(M&CPIV7jVZwGe&v}K&$GWb`_l?XhBzec zcNYe=9(6__=FQ(nG~u_UywpcqajwX4R!ZMcaejn@ro~8`jIzRdHs2fLKOGX{sRY{B z2KAeB-tLK}vnVa<{}|@J^ZkyQ^eG~x{;4ixz3vO_e7poM!_~QWJ`GhaT@)TewEm}$ ze+_7Q*7_cm6Cne?2#)Kcvo(zsSd+XM%PvG1MjF6UE==R?fM7rvjRzlK@!MNCyGcq-HzeYfN#y48U{v8%+4UDC=0l(BiYBxd*9K z^)q^JR_y7Ome_4rY^(F5aftu&7w#LpsJhKVFL7ssjJbB4NZRYq%ogd>k-j{?yr+1S zI_&#o+mgFq#|DqhZG0Ne{^maHHI@CIYzD2hie2kO_R08F1Ob|}m}bi+-?ibC&(@j! zoCkI#RcdZqsxdNbXh77S{MAe1tii0i#oo(A6|KYbfB}?yCJkO4Ys8JorMug9@-nO6 z!+Ft1^M7_WM>i7TNTOI!-q9~X@bS~|Y3JO|>EG^jr%!8pmRW4HX=5eUn$V3Qx1SNm zDU+=CZUz?$q+d%R=tq|4=a(JG;$D|n=mzwDI+WeiXxZIy^r3Wjcgd1&E1*EEH->#$ z@jXUZjSoD^_dC^bva)r|G{?SwgG%K-qUpGPV{f`Y1nUHs#Kg--!7J{uab3x7>TOY7O$!^J$Wd-vU|KNzbx{T-ld6?9o+M{IY03CU#XkS z>L5~0$nMHtyJ)SXz^_qDqKu!tEjRK&?XnFne%RZ26oQX#Iq}!(yunW}EMHR*KHFf) zJ3Xs=Re!E1f4blig^6hi(a=0>sPmqxoglkeJQ3l_$hrB{_7&b$vAK0ea;*Ea_XM9O zg_(4U|G-j#P;$D4LsE|c-&a-l04_&6LXRxbjEQ>oH#={6r9X^Ey{$!YY@IyMg~3mg z;2!Bq%O_5oUHM`et*cgBQ6Ky_Zc6kp=k1H<&D&!u4 zqT89C);2P~r@H#B8mFH$DE>;LB;Sk?&|s1amN(4s?nX!Ya`k0)x2ns2+T-lMjopC| zMGQGh!vBKL$G5`3l(CF+-MuvOdp=B^lcMfxSdOjk8E1aI^sY|{|IM6m)n~JsU(Q1u z%n`oRoRiIQ*ShJ_Fx|+%RKh9{ePlaJh4JDuxQW?>LK|0J6I=|4gAIg}Qlup{o6Z+! zd85OaQApZc?r#!R(8fGYP7%7Hlpas@Pr78EaFA8HA+R%Wr-%A(MVmy960yiqmXE_F z$hE9VRmCI?Z>iX5+P#7nSF!GW)?bBAj8O1$5~D%~H)%62@tMq9Sp8RRQ82Y8b6wEy zsZRsMp|@r};(@nYv|jI9ln#BIMH@*MM;HSGAR+6o3kg*(5ZQ`UM-VpuRc)xC(quN%&y^n9ABChWhcC2Kqu7ueS!J1QW5-Wp3S%uQZgCnc%L=mfRJVSS!{JHhHP}UxOI^ zuBEO`O*^0IhffcCHSBj+B>bLCM>&+Hp$=x&X2MjQJwF6J^f(-Tw`17+kU1vujqqsB z&|Tth`jzsLdTz9J3s9tOkJ$Bu$feIi3wh5Z7-F7y@Y|Eu$juigB%|-f>tMhPVM+29Sh_(7X9}euveBeo<%EJ#5 zRm0TFYm)iziJK+TC}-*@2h4 zH7XtU3->RVzCLy5g~6elkkSCkSn}Z;dujbU`xl!2wr`Wq4(Yn|T5KGYp#nT;g9pKN zcj9H_DC~R!-a#)nd{w7}PL)^VgInP(Vf?ou$n^IeUV+s~vvcgZ9Qy4`$*YK{8E!D( z>6dIfqVxPl+_LC zNE=AkzIZ9NThKBbK1u*Lj{$KJj!eKc(uJhOrX6RuGBq5sFv5Zlyvw$Qp2RebLSVju zNT#Gq*xh=UV3U#m?I5v*!->|jMdGlE#IIqso}lwjlvpTFV6tIe8RP`3B>&<*WB1 zT|U7LGfdyHI69PHwbWqrUyVOB?f!nX#HBQ!C(l%>MLU)iPtkr>+;J#cQ?$2MA)IZw zkbVGGyGeSmXr+>x7;1;mBA)UJ33{DBn{nEsHZ^fYG-6|%aLeR9+dW*f{^#YZuut&1N`qVFSG zy&g}8Xnob~3_94Zrb+5fFDp;rmv1>}{(uu6FCNeDKF;`!*|fj33@^AUoWy1!RqZ{Y z7xyXhw|ldeS~lY{d!6A77CcCgd>Hnid?8JiTF>v|d0gTO{w)*2HC z8o%Q!AF_8z-GJK%2^VLAaq&LPEU953;OlYqk zTJr~^av{=(mz?b{Uf>VPONnd7VaHRa+{vY&82j7TnNE%*vn$JJTv$zns0fUNnx^8E zdZWdP&T#23a4Ah+{z%^I-eYQErSK29gZHV{ z)au=FJ9)})9STf&4AhfM903H+>#@xzLxwF_}qNSiSryXh05?KxdXdF9-d8IB=R; z4@sY;qMaY{y=-KvM|*SYy41yaZisQZu1Mlk$hLbs1N@%tOZ8;+X?cGJq8954inFiLbV$gCD^dX7O>@mu-^vaL#(8d^f#C7)A)uPb?W7vAeEa zyOW*OSs}ed-P88VL3rVMg&ds>M~dw`VMlRi;YcN$LVgm8gpV{);Tz0?M%Ur0Up{m8 z@bR_O(Q9FHbb#$*ZnQ2cPHM(G>m>{;5k9!w5`#_&f7R|V zv|qr7k2zKOKPF7nm8zS0O;7?=JA`{{)W%(ElG-R`8p`=-*RzwW^9E9m&RuYSV5 zN{LPVvs~WYR7eUn8CP$O6utMYETtgrH60b->zZ3_{24_5_Wo=0P`hY*3vvq9{2_%l zRSj-`Fo(V+TB%53DGkSRro4U!2G#DiZDBmGek?}z@2GAxBD>i&loE)|Ue<3MiC^6% z%VD@WVd6-NbIh$@>Xh#<&qXp2>v_*OtpTc^r@oK`0}{TawIIb~)cGriEXygNsUb&9rvdnu}qiz#CE& z3r=b?!W4Paevk9vMI?qtD8j%r`9}xCwMBpZ{H`J1cEt6HlLfuNg@fnST~YrNC&%hL9Q1+dGWmU;2e0k3czpPJb&nw1_uPPK^(%P% zFq1})>$oG!UvA2u#mRPcyR=^FdtYx(fFK^fE9<|kGcgnp;uqI1M8&r5D_TEnueKf? zPs#OmV608lz3Or-lR9Y7W$vF5fxdwHZ5vH5ErwT!R5aeDjFUC(bwrNUE@^~UGVK!~ zswE_pL|}eri{9u$k#3J&7HXaF{wzvOhCzv5(-MxP!dV^H@=lW`)3}MGp1Q|z7CisNmyx>|{2$xERyaY`{P zi&Nutu<4zo{i5i~9mJvSOXgIzGi8+UZ3_K`Ytz@;6<#&^HJfmCUu(u}SaG|X3TgVv zs0$nyZplpCMTFm(35gL%aWB=R(Lg}>)s7)r{=(7=<8o$aIc!X z_I9lonMSNTp11XlD!3byl%At=)2KlJ9@jDM*&TFwYay%0?6C%8@lC8F z;W;w*X@XqZR z;MJ`2Lf;@fD^Afn{g|ckyVCEa0xBZb+&B|RVMx7DrlR1K@~n#di0dG~mIc`gzZ;hh zi+!mN3jOobWrQ=o=l(Kz>&wIwiJLgY6&-??Zx?T4E8Z`kL7ZUQxS3F{G6HyC!Vc50 z?ZUA3rm>x`|FSCo(gzwNj+5oHVPUd|DRi=E>WzEFs|Uso%lGERM!FkbS8p*k6izzu zYzQt5=qEH2Nx%_VgN}vTrN?aWfQ7LS@!ykF_TPKl6X!v9v^v>!EQEai)8ba(pHtN) zzRI7F)i$iMa+e+I)VQ&s8*yHq6G&CaQ*9b@>eChun!zB5nM>RQsKQshJOZw0pM8(E z%bp!}Vu_sm?s{*|a%G{SHxrSx&_yntVkhoS0xWg`|0^mT+xx^9AV5vYrJ?wW;e9yB ziXbPAV!guqDopvmx~@DL%K!T-#K)2*#+FJWB};^48)PhH-**O$v1J`&%P{IgB4f!e zGf}b?$x>q&5{WQL)`>wy)-m>V{GQJ5oZmUWbH3kyp69Q7-uF4@dEa|q_jQ;1bPC0o z05lyjUw1rzv`Y?q5|6XJ3t#6V$NeJx>KV&+6Q3LWoHl1Mi}eQYB0JX3kH1ydzBgrK zL|Y$A^At{=<0eGi86g z3?(OqJ>FKR*rHD7wKTD#nQ|k$+vp_-(C)Ky(y-pq=fI7vCdR6N3)OM97D@8AQIH+G`WeX z@k#C+jz5!f2lcQHH?E;Ujc&|Z==4t+I!LXxI5^Q&Cr9<~1;OX1t#6jAfq}|+p!qcE zsjCvt6X421GGDmJU){8`XS?i;L#=*C-4$uh8I6HQOJJ_G0hz5|GAIFQluXrg-7Dft z$G5I%!eB2qJ6vA-tDFt+5iW11H%|+9R(5th&|1Uh0;w!kH^Ewm^}fvq@B`Xo1mAn< zXe&K4X8#!`-I{Q?)um#)$U!i<+!QEngM#7dya~Nu4X9O=hd=GV^6rUg(#nwbS8V2P zeX@2~Un|x9NHY0km9>xnK3WZ}@ZBh#`x}T>=ws$t1}vWXCkBdJKSjdPffetfFCehD zv-sO$-E%9&Y_flP?&xE;d<6C1?>FlBL#JkHOZcsheMzHFzI$Rwr*;Rm(&Gkl-TF*C zzD+6yFL!9f?!DV?4x~~v8Q*I!<7+3JE`e?vxX{*PHZeMS9iHq?;rh4rsKP4~I^HEI zUz)k;F*PzUoDi?^&8UA6DLBtzWQl#oJ<+UZi(Gx>+9{mu;&B<=sQK;$` zWdp}Tb*Hb{v|d^5MEuwfHSdXPoE3gTPR7j2#BK*{zgdhwG;X0|Wgd$^JQv)prpl0o z%&^@k9on{T&RN$xu<*2tW?Dsqi=os_%M}%T5}dj1=7Au#J*m zy{D{vCfpDfyF7|8an+7|#{GT+z*Jb{_L}A`IqtY>yKH#GB#u6_PlgAjG>mMgElVFv z7i#50vqjWIt?9)!0EJZntYqCRI^#l{n2ijlTeUvqzNuHPaoxZ>tuEkCQ-WnBMA!VD z_St}m55hy-F9vc~(q+6=HHm~RJwxj=)L_a9WQw(zY755*JX9WIF#SgAo?hf>VQbZd z9@Rv+F1tl#Nb1xXc zgRZO;UDaFi`E02FA&5a%sGN;$hFZkDZ zm92qV1G#Of2(*2X(FAAnDpvBZh5wR#t2}k-hnq%$3tBYq7+zpwz2ueUXbI%TfWqn- zUja0}Hr*I`#WuUZS;D!X)Gzl@0_6n1`spGbbWN#6-*nUpm+U_2Kq~pCnplyh4m=ur zp1Kh&TNhGg)Hyz;b-)D-?#(m_*_$CRIl2Uxs8Q2;luj`3a7rXwvfYK%zuiZWXcKnu zh38zHJ`g}3;~wILLFb4cy0S#B*5b2tE~f@b<=oY(C%8OAomlZ;?LX03=p685U~*Jy z&G_QpRwmeZmrOD7$aGPoBEIquT%72hG`L`&ZrtiF@Y`ng;=@ndA&285>B$YOsZ1tL zPsrKc)x0=!E-Y}#)3@3DM(9k_`RQlkhT#0;NYl+r(gyW{Rzjy@z>Tk^ttuVk4bQ!K z#mN)h_IBpSH2=Gm_X+QZ86D*hOt{n?l^~QxVs=)_H33DKGYp9!we1z$*-&+Bq1d*sfyXUcd1D~p}p?Lm7<<=tz^I4>Kp%>Ce=En zzt9y(s@(Iq8ozb_mc-KJ>Q^9;>~_##ErRL2l9K#K;HMi;jz@-!_s(Q-kkaV2j)KqX z&!$UjRz#67+9jOH%4O@P)9h@?nr(s^P2!CuUYlsaX_16E8+4HDE6T<8*vYL9c{`pM z(D;FodmF2r*kAPqV*bDTB1by(@age#$?y-`&Fo~uU41BZsl$2yqR|QnbdVX7js0A)dkaXHAJ-E9K-OW_m?{J z@~Rf`id#}Di2UNJ7@BL@A17Pa<*JeSNVCD!G@-&pyQ~6NN#_Dd=l*nDgzT?y3A-%j zhWOy_;P(lqbi+7Hsq1C!s5>NpIjoBcrnVc!MW@R>7zv*Ge(qA}&rvt1zsPXK8?Z>N z>%QJ+o-_m407F+!`;LfRque+A@}gKztT$!Es3KC-9?G^F^S~5y-4Dm6#=wG20e@?! zOqp9|9L|iov+Hh z_2NZZZsY6C@8?JXef;Dsq0m2I0x<5Tn;4QgAdonw@W(@@yP!B(GgyF*7?a zOAQPl)J$sG5*k`YtSb8?d9PKU^x&nsd0CHLt(G53fuhTrhPPYlOLCGxpbUlN(sFjc zBIn1Fp1`2L{DL#yfRcIVi$rT7fX#X?SKy>p&}f{ZNc+t)T1i&2?^owXl|9X$u^}oA zTnBMqK3U+2ztyFIqt!EJVcPr2@TZ~+Zq5q4gUl963o9HGS~~XfK2dxK6kPh(`Q#uq zQF+V$L03)Z4Dby$TO{(X0_4J%`d1B5Y9>FC0c=rjy#O+EIeXG@L>)f}kMKJz*GAlH z{4HPb;3{XQpWCImg1P6;$Rq$LbdQet-aXc~?!QHnk_035RTDz3Y|TqT*KCl#e(41w zN}$7Tr!&;2ggsTe9Z1k0b(8D|+svQToINNzo29 zdIc^K*UujH3LUN24O~8{`7|)CAtLc(t` z$pMLuss^J+3Iq3ezdgbwjMTao)@UDkg`fM|RvcJC+xk`#$%*0`e3_>NQc}F^`OB52 zGx{4>@{&5@%jx%qCH9Y?TP+W0k5ZAiF1AObbpTvl6T@FFTc~%6AQK-t7$({gFeB@Z0YF*>!HIJ-56crSeuT;%Kv*v U3iHA)Aj5K7-%PJs*Zuzg0771ElmGw# literal 0 HcmV?d00001 diff --git a/assets/avatars/av7.png b/assets/avatars/av7.png new file mode 100644 index 0000000000000000000000000000000000000000..63ce78ff27447a254cf5c59354b09c3b3ae57b7e GIT binary patch literal 47056 zcmW(+1yozj5+=C2ySo;5m*P^axKrHS9SXsUdnpvR;_mLnJwSm{BzW+b|DD{NWUbsq^K}3Fc=?|)1f0MZc2upFffD+ z|GfbpwdujoK_st_YVt_O@JRTivaG>EnvKK;H0Q_mzKZK#EQGboPm+8VBzL z{6GMj61Hmgoe()tn65y}k`NYP z1%trw!om0wDhn|!PQhkIf)FT`@O@3em4z)sQ3BLfHN(_O{X$lgBBzN?gGmd6ai?|% z{9;c*t1XVxlwkn~>v~85l<2JCKS&{#gr(^-xMp-S9f~nK0Lp~7(wE(iQ7dA`qNCpH z33Dew1Ij<;f(^-m2=ULh!sNfCL`orm3M7xWHf3{r=xl-CHj)6i7-FI4y4TPj(@O@$)6C> z7_p@DNDK^zD-ooPa7TdTc0kz@7n}QTssr{SUS-QsX1ENu-SYj2)XKQBf-+c>q){0C z4l*E9ICfh6e~g4cb2Ap@lfTDd(lRBIu;lRfY~;8?C6i%9+*NOoGdbeHtSZGKK$`j) z1@Ojw7daMgJem1>NtQSvt^zeOcj0_ZgIttuzk)egL%3#l7H+_1{M73vCJbxT&MQm_ zQz-EoN;fLG)}IO{^sgFU*uAhoTixqeouu08dlVSJXG9^=wEeh&!aR!OS8!HLsK`dcKq+?CK+?l2DtXzc{DS*?Czrqapit)yB|AkE~g1>@djI@Qm z1yjR-@8A}cc!XSKS6xwcV)%rEY{ASk{bTv#faq|IqyU&1s8 zFjZsY*)Uijzq-ia?5ei6ZhqZxQM9&3<~=P!D1cAm^k+JJusBt*qvEbxF@(k_{J9l^?!NYk*)p*@qL zBI}t)#z=7&-lapqui-9-gO*{yeE5;-+9p754X`E8yswWJ0KyzooxrP$4uyqe4jvd_ zel0;Z$7iMFBQVx3C~bB3{aJdX^fMz9|L`lQ4}lv?3M@hhx0(PJfl{6@CFeWMNwCKZ z=9?76?zQ>`r^jsXoyk=3=Hl!<^s}_p&G$#CEwjzw^sRDB{Kv(}AgN?#LFz3H=6xeK z#{r5PS(to!)r#k|!M5;M1!gu2EwX)T;VhoZ3XCn2leqjKy+*4taR82pRvlhDl^;h5 z(++M+0WfA1H{c=}&J2!n88vnoi{jo3C)aY;(O2$k*E9Kzx=8I=OT)~kU%wG*()bz( zKuP^%VUFSV70%v5<;Ae%u#~X9iP!CRLIn2hvppLOnYLLhm)Uk(6vx?ui(f`yuNrr9 zY|tgxuub8*@!F#s1UiSbxbVZWPkoAjy|7>g%Rx~vM_d~>a4C#>;Pf2noX zE+)9qfqe!Wo)nBT1QcI+rP|Ri(3r9CVKEtA8-}|9X)`YE-qRcxn4Z%pf17b(;;RG; zd6jhfa~(W3MZ=83ffeUoLPudRYe+!|e{NXC=u+edSp7!hyR2N?d^4={SZoP~*8Syl z(^!q!z?^%|QO=4cBLa%0+~{JcL8O0Zc8?7hsM(zl;QX^_F0;kA3J$Xg7Qe`cXIIWr zux{hdCWT6ZJbo2cIC}}v{!m>bx$x}ovsh2E=>8Qr>3;?^?BA9LPASBGQzhSzqBS)U z>^0q+>3;yM!d3o9m_s66|7y4ftOlM>0vf|^>^GI~p2mz9v+mQ`UZ1}t$Tn)9J0O~3 z3&{Elf=$iwEQYs1ZpPUbdpLWS;jR|M!!q&!Z^sP^-mz^SAW7;}Ov#-?YrrD%D(ri_ z8!*U!>0X%JTM5_@`@CBkv@Uq7|Lw}#b=JyPmB{y}5a&mc+U8~{PJIFoCDbhzFwNeb zl{dVfV&1s3!EZOvjlCa%4ZD-S3StyCgbNW4mVeK}5UgAdh;863fs2 z>O?{19Ogq;7?IM}1(3ZIW5C%v7O0pNJIs$0|5E5{7asXZN}5W9-B2o>CayyJl>Z^7 zq8bn98R|Q`3{|GvkqPxODCS0CY#V@~E%fq_sra5_AbV~!SX5w6agRwceOt)ljHP*& z=kr+$qB6EaVA};8HlcSC@S+D1LcSWL+D*BCW5@R02`JsGyM|Sa{pLij+9DJk-ahy* ztO&tW)*t~YQg(76%scW6e+(UbRKYeXr@KqZLEQx`V}afzp|*q)dGj#l-cOXNW*<4{ zq9IVWP9f48`X63mg^?I8Mib(Yf&IEOSO&?=9!~R&k$x<|JAwgOi!)}d)ebY@9q>}w zC}xX6kc-@N_l@k0i1Z?XlRM#ydV zqrx`B%xG%5D8Ft<#13iwCP$Dc2S3oFV`IncZRWEtv0Y3qvplM{kmUk&2?3IbFG6*b zc~CA$0KnMb=WqVVR4NGI?X3Xu{W^n!RCP8r9%fxBjzYg~LWu63i}51#-gdF4@IJXm zw5asDhk)SyIz5V13SGI;o@)kVDjMU2mH)V|IOIXLv0%jxIY zO5G~b1?w^(I$xV5@>rT75>mT`@gm@cbwMgZo}L4#Z6I_aK|$4=kkOQKLRnH@+bL$m zG==SET+#@?8j3miU}2X;bN>@LtL-%!^>zOP=pUkQv_rm^2)VQvAY46)ijIA=lOC!x zz})Yhb-BuzEcv6>$q-w7$6vyrofvWfjZF1gAan53M^>!>uS zsVpqvDtVQJs1P$oMze!68$eT+!;4~iE@;WiEq1leTg#PNsKWBq6zTgC-{9()ZYOu; z3N=!&eMW&*f>0}KV^G0_kQh+?$4)is zuok5w?48OnZa59A53xfjBA?^~1!CK(K3B)QyIR`UP&gYUpZA6r|NGo*<4s&{<~L{x zkchn2`j*Arj_S#u&_&CyAc2?Z!cSSz6ys*{h!j>{;p{0y`;+z1_Exvs%4`f>EFNDy zRz~z6Z3qirek>7|nwLda9h1Qmsnaok$!ae+Dwqf?%KVP_4UFtK*k#GbAK8V=FB77a zijOVDknG2D0T)8l&hQ`eKTCg51V8sC3O{mdi{XXGnIU6Pv08G#o2=s0`0=*>`wX^3 zQ(ODpZ&vbxGx(9cj#v!?R40R>InJU$gN(QP`O~BO9#Pnc*5;9$91tc$Z08E;Dme&q zg0cXtP|G8|Mzkwyb0@lx$*)DmkAyT4+3)J7CWdn;6*QlJvr;-*@ESMqW2oiNGFqc_ z)GllErSn>P&S-&1*;m!$TCwE!tPv{!ju?I;y;u zQYSk^$=yzp_F6W9QHnj$Hl}sqp%of*qMn)HIQUgkl|x%dhspF20Sl2EUge^s>2b)uDX=77q+dVW>^Je8G78w3CYRaGE~sz{lBF44IRA`85Wxe*U)PN#wY4*-IDV@fBh$_8aSs2?f7% zYVsgqcfYxUs31fQWfe&|Xd>aeuo5v139$C)*N@RezzX^N;yJj-ng~G4k4b_MN(h^| z=aLVUuTj3&Mv&(>%t=GS^6X@btEV@(O9-46*$4gMFe=2i)G#tN82A(oQLQ3J=nOPD zS~d_jKfJH=j$&_N-03}R|F?VT{=~D<-3MPK_X>$$>vjSC(t!8*pQ*QR(JyBnSc8() zW1DJ#$Z+G?_$T9i_+TKjEy0{r6_I9Z#Wl(vllz1#=9nS;4>!cn%U$aAUW9KjzLf_8 zP@8@SA5$|cI?ot4kwBu82nL>3WeDjl?fsA z72=F7PV_x7 z5GcW~$f5Ovm|QR@gK_0nK5h{bXeTK^$uFcOBfKvngH*6R|5q@2y(?e{4)3+YLG;F) zbTMCo@2OUUfP>Z1*VU4j+QIFzOm2a6Z_tBbNowE6Uoy5zEUn?paf?9>=y*B`5)`hM0`_B-HNZ^ zh)*L1X?Y@S>CrqsWGx@K^+3gX$KK#&p>| z-#moAjPK|cuefypZNiwG1ruk77~_4OuK&3v4IlI~t2e&1vp8^V8dH6qYtSHjJN^;Y zZhuXfu}K;S1r-~=pD09wRBKwaohExWz^iv za)rbDpFYUUk+>>6?jlnS9GhP&8R*tkPQ*Vw3P~5i64{zjtG@IiG5pBK%tEwzPC3I- zy+=-yL@2ZPk%nkgiP|jgi*&HFhz}QsOoWkKh4JtchSbGyLJH({r?Wf|s0!&3B6W=P z6U{YFbT*9^sF%vijE$gj1aL`MylWL5eld<&)Lf%ncK_m()7f5eGeS(4u?#S!>(QG?>0NW7g?6O@=EUHK?I=Zzhc@!#2HveS99M%}|xs`O-E ze^T!zC!V4F(i=gG7TX~~4f;pg>`m8dLy&udDIQWH;4LMk@L=f?JS*yJ%;GBdXhs_} zj2!$}gUj69ETj>P&UAvuTsGu=w1^sxck@)jYO6g zmm<)u`fzU8K%)n;3?OwkGAK~gY#z_)qP`a{Q;{8d!- ze9nOfgEGsgA{pUKZi_1trc)aA`Rc=8sD!BQO4j~g@oq@%jE5CdZvoRe$J~)~bR7~u z^6LWj@DPIPx-b02_Tp(>RhEU{@htxEbA^`^S{bccb@`ZYwtZKd8qkQ^RHVPqR=0{V z1wI`vW0{gOon{>t=uI%cA}>5%k}rL2B9+@wT!I^>CajyJXp*I z5%EIA7z2qXb4~@&}9mUKJinf}W(mk@aAymsNZu#^VQpNVXkI;pmp zjliq?3li*#E&6K_hGoHQ^{D$THHg+B{rk@n1aaOU5CA@YB1j~<52h}DgHw?Jz=|+^ zLfM^;WrbLX!j|;KCWs{aKqk@u5^p$okA<%Ve$x|g;JawUdES7=OhLmY_1RTz24Z}+ zv2gCmu=tB=UgL*G1g#LY;*>c@*?KKk1L;+ovU$`IT=Vq`Fwb6j#kmKzgVq;(&m+U> z2}N#Mu9$y=V@Ih4LenXy!a85ApTSMReq&VqJ}yiK*Q8E!YWCgEE72yCUsMAm)r-sH zm9m!%s@Vt~@US3ps6UqvLP=FRvh{H>SWhw7P9EWva2nY0hNu9(3eGx1bXE*9MZ==^ zy3^xz+_KyL2fxPF{A;YafA&TS->|m^dorK(w3STk7(R(oKjLW$oy&~>9vP-tAZQ`D zQ^JMtHy$Q|4g{#jZN8NwP6xRvNpo3ypP{s?V1%M~b2#LY=CVY08xVLLC(U8#)^BG* zw|mPN-|xX@RTf7QL@4tp8xy?yoAt!QzI=)zcS{jhdY=RgGk`%VR}f)K@6;(6-ZHAT~re<4wmRlb&8 zK2akMwzPb$_?%2$s$^=MGOy(oGZnsiFz>vkpl<|)tP2LwcBBgPUk&9svT-f(f{-Ep z)FEZh-qY9smi&Q#&mT;8^-~&!^_UJ@BD1;iLr>i;hw9CMlf1+Sex`Q22NP#)hO}oeBj|MhFscsQHLIXsg z?)0boAxS2YtYftAtnnui{}4;?y+z9|A*!qiAsR?q4J+zyZ$Pt{*j|iNiOb_;jBz$O z|FC73Z1m}oidnLp0C-G#C|pUS@VnfnA4#L#1e6>uueG_PiL6vd6*^}I>U&Yl1{EX< zD!4BRS^N?INJZWHZ!WIqnn~$to`I|2P@^NN{fmxToTDLG3k_OQ8}$pNOtrzd4dGk* zV#LGzjbT{|+&2v5P-LgXjq(^70$#Am%j>)5-K4vzzc?+T6UrqdGJ7HT(@IZ~`IX7u zNVyAAk)(TTVei3y#rMiG3xvMtdf}THBspORxVLJ*Z#TjWEn(@0glFSbvdR+Gy6+K` zQSX>rlr1J0kuVwTZzUQyfsa_+LtVr-_vClV+5f0>hK7BD(f9!bh_g}QC7NAZO5My?=vCA8}f0=YkPXaP+|jj zsmTb5{M8{ECo&jxMVbrlH{5`*~p?Rr&e z<~3}llC3hgaa%3*sSG`-@HK``N>0l!D6>iB4+;*j^7W~pk5QnI@g(mopSQCuq zS2=IwtEx~9x?j>hE|?SF#CeNlR@t{)|H1TYXR}5H%?Mt4rFQRIW z2tB-kbiJ_~hn~rtVMIji!aG+p^(}Xz*1aL0L0IffKu1eIWmFB?$IOa3tyMd@xoJYUu7RO_>(c5k_6#d5IQ zLH$6QksDeq(|7xBip{?w0&~2Q380~UI?HOEX0#{--s>a9!F?WBls*0M=hD_nnuZ6QIj?#TU9FB%{%SYeac?1q4tuLw0Z=ywkD}{v>HXc zbYvPJJP_wChr4uvCu^Qxb_la5OlMIL)PMUhU53h zMI$+%t;1Jk@4!>`FBHq!n=&BkB~L442{m#>%Co9>tg-W*F^B$}IJUu8uvUKdoOo+Q zD8v(@*t<8p#S?xS%nd;mdyZ{5HY?6Au>9pf_yR17I4Z+9tz>I`7HRg6#=Eii&m#y? zK-e{?NL+dtsc@8@`&oT+q|7_$3iF?k==Sb{N#6VW!Z<+C8BusN$-}qb(Yb=qJ%~;^ zTW>MjFOG-M9~JPtCFL7VW*aza>6FFxe#-m*p=wb} z3iCbXd4Vg6QpRLD0;194GLGK`;}t#z69;&oo(I%NQb^))x;x@)>3?werc1vg8~1}`eD#?v7FHP zGw{5F#X*HU-9HbNs?jDfW8S?+@YKb67K=qsngb=;4E7>!qZ~m)b3hXE4h_phd3=p2 zEvW-xO<(-7K@tR0m*E_eFd+#DWM2ts3_P$lnw=5>{Ve6LYacFCa6rHb{`Xb zX!7*2b`j$RIM}(niL(+|&vdFhpN`9^lO9&hUxTPW_7}}NEX*1+hU7eh-38ynn8)h- z+x2_+?>V)QT}Z>*cEdhDdpDBO$o)=CYmK2_Y->Y14upZ7g~3=&muo4h_*gL`EkaiW zKLpL~74bN?I4bmnSLvt$twq!pizh{#B;a%?kg<=-F{V}$-ei+dGcEu71ZBh@SD1rd z74Lp5bBKoDUB;pok*{8el2-U9-Z*e%l(QCvXMC9N6H51+qDipN*clxoJJIu^nbbYx z@F6d=e+5gXs;yUH39Tf-#0#m_JMw1sUnD;Gt3fLn7V7#_yS+Ef$qy+p=EHUj2*MU_ zONYD^Dx6=e<|K0Po#vo*d(m2Z{?d>!aakWi$KFxf zD|<-`KeZF*ym{Dt^K@{IOr^{p8~)uZY3}Fht$hKNRs*#^JZPvrv%)hu3>xJDgYO1w zxha6_a&SW6%aVqotxMc?ZPolQSBoOyH3>lO`%6>%K4ulr%E$T`oBRDO|W zLhvhA+d_ExG_%=-tqBH(4iTidPt)PXZ27+PCQ|0V_&kdkysLvx-O6Vm@N7E?0vx_O z{;y4>5Z!M+9I_=bJ-4|Ojl3k$ABw#IeVFXP|5g@u2n5}QI$F@v3ZEkJq)4E5y?;5y zbY?Td`sz}}#bv_LdcYb{Rv*8CJC<={yBC=Oje^>R_*qV@7#`9<6VK9nI~C3j$b3${ zv>gY~^k`bra&P#+?a(oO_bdNUjIVT4`jeYCf#nQ*^==ZQNU6Z6`yc4a?mdjF%YC2( zk+O_upp;IBECm z!0O#k&nO-a3rpIp)w?D|H*dhNS1wTxhEfh1bB-GG@+iNgqaR>g<2MRpXe!LrL+!4q zPu->kY2EgDgdT?vA3p0xe|PDwsO{!vRJXb7nqO&|6*cqw5mvIZ0)3=5dJvxxESta1aAN)_iv!kLBbgAd#Ex6qs&9e=Cne?9MrH_tJ$ z=n7lMd?C-wwi~MOsMX|+D5OHwP%a+E3CV2$bz2oeQw5r6-laQBL&xI7MGiuEOLH*6 z$@9_SgLY5Db??T_;_~;(kxwhVSeE>SnCI=JVv?_(AiF;$WGydLFR03km{6wMK3$oT_xUX&i;R)3!DjTq%bn62nPK| zc}eT1{V3I|Aalu2a}wR`VMW;B1t*E*CHMarX#_BRBH?i8lP#>*@JexFkNPpQv~`rn zC@y?q$n7k3;<7BjVx6LeSN=z4@q-?bgDd;RCx~?N2Fs=v8C|=~2prB1R=0qICn-j{ za1{RBl5?}kTyqKB`TQsNU5*YTO?wzcs<5qziA#s`b)g3vzd})dwS@4j(nl)wNJgA8;=nR7@UPC2 zzpDw#R~PyXNUKau^kgSiaqU0oWLE}1!M_P{t29aC?-AoZ&ELq1+#`T-LJ}HG3alhh zCZV;6J0aXJ0^#SE$U~xyFds8cueiyxWZ;C}Y9~l8_Xn=Ks8?jXh;}p$uk<1qd=-Pz z$Z@Vs;p%1kzxs`GX-l`w6vLwW!d)iaf8t}*o-l7xtQ1{sJu77rEjfWppjW~61l=RV zXE%6kRoXH3tu~T~2+HI6K$WB?!+a)iC>BkzbP@BV#-J1R$`tcLM7pt><2nemE>xWBo~zjA*TM|1E|YCS(z@^_gyA z**{rso|k0giF)$Gpq!9C4kv4Zthr;whru%D=ab6ThPY|skTCj57ju(&WPHWq_sR*^ zmYS#w=jl0&;ypnf!v}!V<;+E)r|Kc;UgX5@g-60v&K6&TT2lZZNf?a*METUDWyBqf>V7t?DGCD{|ACn41dS3$i7KXKJAL=x z25NkraHtSQW?%T^#${enERv!))Wy0LL&Bra#F)lssX)z9HCaALK(}-YSUHwRUd;B^kZpodE<=9N>bip#(BV>Dw#N(qy3T8I{9 z{+aLgx-U;%vfOObT))P%zwz)*7PggP10NV{R7i=4OA5|)CmtR!n8H~iQwvoG?HRe5rI%e&Pz3!XOa?%GB z_6}N0na0`u#W{!3NV--g6RQfc@Tid~7kMwHo1ejTKh!gzLM`t;KZb4Wm1 zgS5|u?JmS`8ArQs^4xd)&q0DE9KZ0(^PSAL5mQ{lh4Fy-Aa;(8&m)ap^Q;8_@snjAys9 zpE^P?`>*Ypf>nWyPMUnh`W7vAY`(nq2E*^1G<6m@qdm7W{w}L!b2-Ib)Au6M(s`NRXV@ILcgB_uMKX!rgq%S>j+(TtIr#d zwFWyb+2(%@J37$p^&4#xl6KXEXB8eV%zn}Pz3*VT6}@B#7`We2empg!F$h|HdC>9Y zBX!?k%l{Oi@to|t1gheJ8`9u5GX4GB3{^Is^qd_(xi!WnVAZZ+MXSM? z3<^6=jbj$l!NNU4Mr4a4&^iS92tAk>cYnoW#uXLe;lA~qcjsQ;n|*HrAuafIp*4yg zr4#NcYUZMO-jWM5MYs^meu4o7h7)-D1d#uVVeD+A(3f`}H4L1T_?&36_3ZP}9RnzJ z!MApkd*c`1kim)_6TnV-`J?Innc3{daZO%uP7RMJ_F%D_5~ObJf;uz(^ttRM<-1hY z7~x*vF$iAR7S5_cTo6>?=XR}K{HTE3bF+sVSyxewyLy7J9?20wB>9{hFWZF22h*2P z{EQf}d^zf4O29bPVKjQ%L_xvp|t4 z18j@T;od%w+u`YACxq-AQfuIg*!hnAVm<^m%*YUlAJ%|BzyA@f^ z8?bG3Qf>yaNkif2-`8#uJKG_^se>=Ny+|jn4wXDu;&E`92Fs$pmZoECg-|=drS}bb z>+xdK%pQFaZf9@=vch)gq*N2;;0)C~veG6Zkd@^t%!+*_2?AV#`z!)o=nb9%oSw_M zr*@#Nd$z`OgO1_vqDB@Eh97MTHJw64-CV7Ij=BF~ws#7{|wD+X7I?16#xo(+ZE!Qm;w@5(KFHQgF1lfy68hI;hYeUw-%~A4Zr;(Dp*<-h>ZA8X}mZF>Ne%1keMRA7J@cnx@>> zAs?X$+EBj#{b0tyq=d*KIjTsBJ=-U=UIT8@Iy@>oe@P)Wh}FBzSw}h)>Lm0$B4Pa}5q7?T(_#VKI93ZED*_-jk(526;vUv1 z&5w0^lBMv)_~Nw2d9uUfJFT{?t$1gHOw!rLQ0zGY1g;*L9Rv*)YsLiQMXxEq*h5(y zqB%W;od}}hoTcWWlU((Z9Qt84rKYH6{Nl(R95a8oceOH{KN z$)j00ypSJ@UZZv^LJcM9lA(G{u*`_8`r!eyg&u@sfPa_cK1~a|1LDHoeC^9|;A;xr zKFL`@+mWZG9v4Pv`{aFH*!(oMcb!$7QR zZCTWj=hQ%+Kaha=NTNSqN495Ic9b$flEJN6=49 z(=h4QJFHov)M=m))@q$!_bH-PjvN5H{EMn{G1cWvRP$=S32B|)VMFG!r!tODx97o+ z0ewdFa+_y0E({S`;E}p!s&IOmvxp@2-4$l^{2ES%Lpf>vEprP0j_rE>#^U_GtUnZH zRUue`+%vN8o$Bi0{brpAo-e(h^0S!ff*L&fpn30jdhk!kQ?Ep!C{KS0h%d*IM9yAg z)Nprwl%ksOrd*9}z41qEyIq6G7+pSYz)1*p%uya%2~rVr>`oV+@0f8Z6lsw5{~g=- z)n$ZZ4%)Wji)yp%5j<>s6}PP&Ud*!Z{%7P zbELySe6usw>M3N4*JA(u>*OdEjX{W{`Vz(QRl*<{0+3OKx`4M&lGAKn5uZ9{ZWo%c zKB)>F;g0Oy2ts1ts7i9t?(MPA+lrZ!sm_l>gPsw3d+U=e8L}4&+qh2m`+D9Kb~^p< z@+re{gnjR}hy4Rf_w?tjadH{`E(=v^Jf}Z6EchX1s7Wd}ykH1v`KlJ9zr>-we+wW! zoZ;;gV;|Xt-0Hr@^@NfdEH7dGUBV}7nLSqE95#M629ztMW z7@=uy=kqwvC;)Nyt84 z7i4-Cj%X`L-iWu}uq!c7|F-En$Jw%{HT_VQnfUZjth(wWHrTVxY=){Av|`93*f3cy z4(1DeDIl^FlidCN?XWga|0=!B>A16OJFK|ME^CBg$`0?}Xy%BpyYDo9i~WuAr2Z>x zt7BJJD7n?kcRNU_2SToq9peJ;{XCo6p1xE@HM~p0(>TS=utELpP8Z}%GBjfDTukVX ztw|;PZs-i6gx9MrRDbFJ>Q|2gsJq{DF<#cwMITFD`=siOg^z!AXd~##*EI~~A)^x{ z1le4sPARvNjT1ngkMF_Y0lb&%?bU19RcG3Z9PUo2J7^{%Z06C0dV{FuLmFLFyz^m> zub!%KJWBV>Z-sr|gYLLWXQsBq4`BRcvB6miN^`f7ye_kr%6tBr&d)0pcd4RBI0sr6 zy;<9@ls*Zm$1yhIFGF3Ie?oh&1nSH-WVeW69Z_oZLfN;~K88HjIX*s$*3n!P^t^WF zrFFaiRu!ua_ZT`w_kDSl1f;o&Aw>2lV_uNhZr_qjnaun~#S z3hUwf&rR8Zdd|O|IzOOLJtA*6TIjAM^&jJ<6(NU6GVD5O+nsRdQOZsLtIfuUTj-MF zdA1$A>cT;8o!hJ57n!ve3Zqr9^-5gBnBha z8^zs_@H*>=qV7A^=}!xhJg(hmr3_RQ&Ztm5m^|kEN>(i>Y5QXcKpnCA&b-lDIGOvf zUkF21sJ<7%FE%P@cRxU~EnJp}8x^@Kj%)_AQ7YjvCPup_e#d{k3&9V)F35r$6Wwb! zP8tc;@9SUm0-;v>Tiu@QcmIMV3Eg~dTb-&2F~7rklnp$07vr5NsL^bs zy9d!#$drFN0=vc70gH}qx-hS-cPm+r9|H5zUJjrl!ywaFe=o6e;w{BStBUu2{6+BZ zKa(P^f;zKU~coW48WAwy74`F6WPjM7Ci5TGC7nJU8 z4IM4eiG7TRx#8~x<-rHesjkeb;+YX>sAmkPcHe4{Sg$Sy*|0sN zZOjy_X7P9aK9g%lLSMl1cFl!-PII3=QjBmqn{mkE&Tzm@4t+osMW7$fzyQNqFXgSO z%9_N=WXGl`DI5>9j19%e#i7NOh2MzXJ5Ri1h~*q7k2n;YH~js&T2!@GZ>g!g<0tce z>4eoHp$taH;f?BUt~<>MW_`y2X}!L)&nlmD?YoRGUxG&Q{=uX2cr_pd*8I#hXhRlX z29~E=1a8D{LeCzxM)=--ReCD!Is&fdqMA6A7m*7(OY0M>lmueTlisC@98n1e<10s3 z%w&6h%6KsORan&PELs~++>6tC=X1^GYo?;%>7jT0G)9uAQtt=FJ_DQZ0_}0`_bksE zUA!tt5_mL^d${a}q0QKkU^7_JUmqrc2x9`~Nd1~qw-Vg7><=X+4s@Bg6qd%7t1-i@ zi=p)7*0xq(*2S#kMu-0K%oQ^eE!rUDT1xb}&)sdcg&>S6{Mu^n&f*ZKm{yUp9BdMr z8KWUmL^2v2?!4(5=@{;ejzuni-^{jofHq#YJ8rf&!#$7=$yROj(0EvHGHM*a{)T4e}|?4S+3o93hx_KH~XOT;qm%Yp7UBrQ4V z+_Yy@VRPYXkx5BcD9&RKwZynP-a)D$ytIi{kTRmCU|a?`dmfaK#eoF~(m zoM;W{s1J%w7JvKj=)vvXb009&rWCm1?{f!4%>KPAJ-J@N;Vw6({p}y1Y5l7PhN*V3 zl>|gWB@7C`uqyJ6pHQc%@RnohWl*SeKBfz9k8aFPFrduh+>v7AS5KY-_1?p*<(7vKj;1uB55{G9t6LVlg+qKC76E3^A6|=OfVFS z;LG^lI_y4z49~!~o^;;H>0m{^U=alJR2YBTQ4BpEBr|cssnVQ-8HmS#m#JcBL5>FxPh(cRU^M1AtMkB;<}ed*e0&{_JvV3 z&XbQ;8UfnVlZOg;`whf+*$`h{z|ZSOZGt+2w}FLR90gs5i)djOs?dK0H4a6c<@>fHsP>0p=J3? z)Dx*RgOMsGtGJVAqFv8V>I@JCnfR)>c1BB zyg>_h##Jc^k6T?n!j(7OUUS*pZ0@Eri>f$H4 z+&MOSUdDX}su_lPrw?bdde^dmqEUG*8mHx4b~@*dhNt|z(qzP1^QKr7FZSBs3t>(; zLmuXrpIp^hPI#gh;Q6xJGgR=4+}VwPWJlia@uB6j)@s%2e z27&6Z{YgRKy%TCEwY@|*kWX5KAOSMW{WQFrMayl^h|}sw;WXf7Q>AiH&P#BREe=0% zFRcmBMbg3pv^S_~kT-XQo^&i+4R%(Ro-U` zxupb;Yru{W{a9udi$SFApt@tOS|O2gUz()$t4X4Th7WBH zeUqOMJJ-K#!5{O*^QDv#%f+?|A>M+c$*MMF&or^(4f!GK(o zmNWR$+HTxxfxkX9B|?5=MgjY(C3BzeO_FItkj|y4|(RA$;&zE`2Og z<{YIX6FZ-ErpNl^#&_ZpH68+JZv;e{qf(<~Y?_J%$6n`U>+hs_O~Vbs#8;BU7x7}& z&dLAB(p3h<(R6DxcyPA_LU4!RZb5=1xH|-Qch`jk_W&>Mu8X@Z5ZrxncfFIZZWaHi zn(67C?mp+SiFzP{OZ2fZa9?m=WyeJRK0)>H7w`{9B->`^4rcVMryl3#j5jqC{JR$l zoaxSW-_vHEs;Vp@ZM45N6@eE4p(XAoDl#InT}p$6QNzkEA?p;!w@3W?J}7PPO6m7> zD*8$qeOiiE{Nu<8HXZUk5slINQjOj6=NtrFozabXl+BTh*8v=N_dw-G9*wpu+!rb-)VQ`zdKX? z)=ZSZSy|tyKnDyju&Z`74(vEBK-gQP4D#*41a5u!?ug+*l3C^(N8rpZhSYOxZp1iA z(a;Zyz=|J3{ywH8KZ935zc-b}KTm2e+Xs~Y!n>S-*#96X3L%b`#N8KC_3D-)-|u{L zT188gzPp~xspW=s(V8Pk+ zuCl~_Gbdt5nQ#baTd!!NA7)*5WhQM~W~chkSQyx<)$O!eh`jZE-C@JfXoMfOgrlHl zsjRlPTZ48ha(@LA_0)P=F5jH~s(*25fHlInZT9 zFOpDk=i&fUl?%P~JAZDM{4ghm+RR{OO^%%x5>&~bUwtLeRAF|Mr$`~-^ZT^$QYhd`2Q6vKglI}l2P=4wFChSZhSO}`gaeOy5nkZ;{>#NIBwCuOn=iDUZ``C2-i6v# zUat!^|7BRGxW$qCNksE?HNDT;ILr1;dbP>cQD@qcv0vz^ZQT2rLnts4G{1S+0l|R% zP8PF-EOV`kFRwaZpqBP&AGNHXrjPr}7t!h7lzixB`<>K)4|Pv=E;hx2zs{ger4gj%PI0SG9BB zRFOJYb1+@zfZ`Y%9e{_XoVoV9f%r6Cp=50SmOLx5+fU7&wy8q<7-xz~96=hD#_uQt za=w7ahzWF7DE99{{Sde)Wt>rX(#QBoKKHkr$>jq<7EW7eP+?(>^T2Txor8!}V-}k% z{!t?Af6uzQ4WF>)-8+EKWM_9QSznCx2Z!$M=pto+@iy!2)w@!AuoRS>#!Q3WGhwgj zVNO|M+Lc`CBLnjK92tVRf!cB||Al2A)-V@W6T2Y^giKt9qrouYXM`VE1j^b|yL$REsi%-z`8(w;)ETTEB*_rn3;CH_HESrz)r5!;YpA)8{zJTmXDXKMR_=?(fswv zx5+`x9=cm4h>X6Y_jh1XdH`Wnh>n}zTGEmjt&jxSx)~n192Q4KXFnoU_uY*CgWqRE zNnYN>y?xKclMeQk4l9&wv?d56RgXh%pS}JElu8sLKF>Hyf*;iKf&cAKJ9Qe}8=H_N02AsnEE9pSR1*5>dYtTZLaPH{$9j0oG(Q;A1K z(GBGd$Eg&{F%xT=t3A3t|733uV49=L>Cg`BXcIE(o+1POt{lNvoL&0g8*6pGlNe)vk z_eE@~3bhp(xgK^juW<~U{Y!vT*&YOns1))dk^elxlfBh7 zx%0dHh+pR+_{rW#Ph2TWVkU4@m$g z!grSO!wp6%Q#mu~qI1Bb&TSHNwYEosZB(qh<=*k2*Wv5ogrn>JBk14D`kl?bsDC?Uy9G+=yTAt?YsC<=!tYcl= zsDNY0wQ6*aS&yCd=HL78E594UWNcuP7BO208Dab7944$CA(J?Ftj=+upVa5T=6atn zsNZgw^H6mx)YBUdO1So2!eIw+y(OHBi#L0vzQvWl-5ER;##6i3QSL#f4rBOP$kBoM zelQ;2uy%BZHINLMRn6Uf%V6-!5=Np(uzgG%tmpPXY$%mE2L9(irK1Qz?J)$SF$AoB zt3uT6CZi<6uX6$xEQbSn+gkmhE94eGareUx$-HPJ&^3BjVU1X?4c!p+V5t>4ZwgJ+ zn^kF=({MC*(b_OCX2CKR>gD1vX{+K=vES~6ervJ3?iB0bgkZa&!x^8WBy5qzf~@un zARO8338mfi+T(?8;v&nsrR0aZ0KA#Ic|B&#khj5y={x6$IRs)rWfX)r!A%_pGCZXD ztOEWB(hh&2U(cs^JN5CTul`To?qJ-;xx}p)W!*&08!c2$v{1DW4*@|PrTn{!_tfY= zWFDjzZE=gdr`4y)Q^#RV7a{hI$x4EZJE-eYj^x>DrcfTeLWOj<7MqcpCRUT&zDv^6EIf(DSHaKQs3&hn5G50ZIc1U$@neFsZRVGCq5yB@yRx8}2 zY~Ydx9iliZ4FF7WcDLHMm0VaiI)A7+QwjpdzgB~**p>VAagXJQ+(iY{B4gXXLA`?^~~0`TX$!jX(!RG z=ATCRZ}Yu8aoO{}I=L}o@)svxItQH+6~X7uer-ngz&>S!rkYf0&&bYuCT)U1rXD5! zlQhTrAKz`tx5b@Tu_`GBSw{}uSIn<<9nDuY*RJiQ1XF$(t_2)Ju06Z5?`4v{1b(45 z`p?-B!2Jons3&2po|KEQ9_yDQ2v(mF?RJgV=%bifKTP~eNSqLe%SIM)994VX0DZf9 z>#Gbgrf_B?HYdf0P1!x=m50+b4ReRZQBQN^WutJ$E>{T!c+>fEE&cS$aIM$*@Z@kYex77P^osSHG@YoyVLvGM7EPJlW^A z(eqs`9n}R=ipqC?+Z#tT7R?MlB^t!d9lZM}wScy|iHxT1@tPUaJ;%UPwZHq1%6QXX zQlhVR;i0+zb<|W{OvBwK)XW;pzDY4g_;9g7D_BEbFV@LkIQzvrQggFerR5yQPBv%7DM3Z=YZr0_FA}8>@a%ARiBOR|EF+% zMs@%#>G)CJZlyPV_h;_#A!ZIaUX}RgxBz<&E}nuQo@@9v6L|-AxwAbfiw)a?ANU%cT?AA0>p~R>0r)&~HH?6eUY0ZSYKg3Xa zyS_JL>8&a=bXo*<`G%?8TwCzreNXFz{R(Eejr z1%1vDifSL^{pNVW#)VGWt(UcHcTp+*x6FdBq=$iWX`*p$;_-5#Vd;B+v{)%IP9z(3 z>-Qj^_i~8UU&d}TqREHj zdoq>lzh?rfsq@g)@Q0pC2|;(`0P)@FFHL)$o+pjqIdN86z#=E)XhS?AD9sp zAjN3#5JK&DuD`Gb`8eS+;XaTJ*0mn}z3=iinsK~D{5S!Lpo?_)=6kv2=%iYdBL z9&n4*w4~R&Luh&4ar9EEp2ozoq0m!#wMe!9nYQ!V_C011?aB6BQuO^rMicgx!nb)l z8T{YhQoYyxJdK6J*oVgNsPg~Kh2j}!-cTO4!Wps=KGop!N5j#tj&%R(j&L@oaY^1R#`BFp6T(#%{HuRU|7@W(tjSJ)eBjg#r=we2Xt4KI5~w<#*Hdn< z3@H8Fah13++ETtO~C`~wAz)i2!}{#mVYBQ(k!nIo;_l}z1y+}2#;NCdD4-B5~zInU9`s7p`F?G?D-7O=Jkc_yk5H8 z(ALNQDjL;AxIPD&zNb!NBC(ELB9e(^Qy*R3rVP>dB0VNhI|9Mr4u5kM7KaSg+{)FCj-UzNQtjp|DEkgU{L>);G&0zrf!T*F5L(I#TQT>Pc zu+dhUu$A5y$7jn#rWdHHpA>woSw0F;=W3jaA9II%D8L?@lwSai1ITzW_R3DQiIt#O zN+kw#irQR3`cxmB*y%rSeV@;>HUOeo)mX`YPVd)yzF9uov#{?>FHAL{G!~YwMfqu! zmf_pv`oR{~{DFAv@W)s0iAYc8JOa*huEbTm2oOQB`>C3dXNx>t zUnS+iR3Rdzp6lYaqRex2PYr!9I#U74n?2#guk%L}SkPuYHq()--p2*rtT2Ui3W?l@aO8k3qx!*2UGPimr40fu|w?tISFH zJ52vDrzdl+#a-#^cLOjj#jy@Ebf`;pf|>GF@E=t%gwDDYFMeRmvJ%+@oUZdd8Qra* z5Ul`qTYhnL^L?}S-W+H01rjp&=E7DGTEbW3`7?*vVk->n>&Y_9^}xl|vl@Fbmd8Rt zP@3_@Q%8uqPkO^WIT{Y_K1e>#x=MW6`>;peo=6fxXN;0 zcf3)u!9$v12Sb%7LHaH?>O7P4B*v3Mta(ZzKD+aUY{+e|upEO~?)p^` zVwW#{ZvJF|L7(;zBLX&xSIk`(9b(9{j`ewvPo;{P!R)x{4c_;a^iK+(zcx`w${UWN z@Md588g{VhQ^d(*o$?GhMySfa0UC*=*mhN}93z0|umZ&?d`}aqpK|{23f4g|PXYl` z?jyxNZmzCBwYc-L$b*&w!L_b5HVAVE1v;fisx}xJIXG3p)7zcW%RK^G5<`&lT)3hq z^1z;JCni{hiF{ue1K`G{pzfOR%^{vrSqGK_N3oCZhO_=f6a4ZKNm4rt(Hv>9LnEVH z0Sappx`o+gwo#rB;RcRy%GSjwLN$SeMwUGFm0^{(lZ~J8+%Eq74qhn%Hj(qPco984 zyVJ_uAW3x9>HDWQlwpd3+S3=yQBNh1z`8*r4>WH}(8LZ5*QEO*~uxpd1 z&TbLii++ajW^0^FXwSH*)NFL0-WGyJ28(g7C>UUhiCgY1B6e0`#0o=uj20V({V^7J z(_NISk17W$m*3CDzT@tHaGmeZylJ;34l>^Fjsu_mUME5Cjye8#dr67oeZ%_enf{Kg z>3oR95D%E+1DrUMDlnn;l3tMR_=mri|7}U1g~_0+)_Tai#x7iS2D@(=A)}toY4Vz4 z#3SyN+9sIf0vqEO!>0Aq_I9nl2<7)o1sfbW6>7T3v+NillRExM3lk!rZ%5vGVvb>F zP`qCf*hO<6w;dEPO^_?w2=!_Qm?P5=1*xxN%^$8upJWN;Q|>bV+Y~)cCjLI(%>NxFb@hDT}CYeWUjauP(QS@{ghwR)ws8hpKNXD_A9s3P0Z=`m&$4c zPJwn=XdDlM48I8Xwmk*)TrZ-OQ~?^SlU*f~=J>YlT9h+B*)!V4qwT)zH|F+y13t!M z#g(JbUo|}(X@I(5=41B9<_lpW-mt~Hb{&WyMhr60zRm^WK6mG{p5MIqx_sJx-pUf# zw^hW^Jw1f&2Z{$q33ST<;-yI9#bBXVwIG_R-rKdHLW1y~QwkF6w2$k!PKV;Bpiwa( zS?5^qOnh46>l=0ooja@~0_;DeI7R7fi!x`ux5S1bfU?aI&Am#?>%o}i&xC~g7y%Ud z30U=nC1mW*9{4tJV$SaPS@6J5t1vOC&N`d4Is8$fqyD?NzVv9LFOOijv6S zOMuw%Uv`a%6KP2xRLUmyf8(}Jx%|;&M{ACLE9ZngGoCA8PK;89DfjrnZ;x&1j&k9Y z6q#T>)Xhd>yJFK#am6|ihUoeSz0Jo#QJ}RyBtq0{KzT~P+YmaJ9YW`6FGe$riKkC~ zcziW^KBINN+}}({45}laQm^N}TE1Hwx|}l)V*JMB5_Fo%Sh{XT{~p-P8T8+psw+sV zqwQ$-TVQSV587|{QB?VMmvM@n2BhT3H9~?`J;+r@JTU!RjimHGT@P{gbHq^y53dV9 zF&M0RCn_AQe8>F8o?`%p@&oGAosoXBQms=JO0bF14`xEL9d-#IV#Z)VU^@7unWXJr z(FW?qwRW(#l>ZTHv)&vS4=S}w&aFFM6pvg^TN^>&5=k>Co9JX@IR2pl zZ_hpY*}Ps+x(_|f=Ih?G{C)?O)<2^jG``paVTBmkAmrkxHfCe#TSMtPAT_7Y?X-)f z1!>t6Bi#~{$Mp`X%YhmLEthriHPqMUY=viPAPG8wZcz8VxsR&%z4dWZpzbm z#)vR_+RFkw*Rcy`Rvn~R++1NYTxtkrRYhl4QoaO;i zAQJcjgdW(sM*!1A2kvts?(O2X0+ZrW6-XmEgxw?D#I3~7$aRrFh{qR8=p1M7A^g`i z(g(Wv%<4F^lKk9=Ga=5Nf7F@v)1$}jeU}G&YMR5*h}83g&e_gmfsixxo=LNrHAve` zVIkbzc>0OGDCdLbld#S5KryopU1mg5$vq6JR^VS1ogK|CIxHpQrnL|~Fk;;s%~&O^ zgc0j*S}LDF4)QF69o!rPpnZFKC*yfMBul~Xk!cZ!>A;cDcKpieUZFKIxbB2BKbB-6 zeDM{)rHWnq0+@k-JRpxR98j|UGlV?6a!#lbS}M2*J4oHeAQO9{^&3(k5tk?}g#)MIxBYn^Wif-9qRaoEKs@vwy- z%L>s=77g5T=17?XkH-tba^tdX|Q*Xzr94ym)YueJ&*IvHIEXYK>HLdYbFb zSlCZL>yN-8GP|L?$KWeG{q>KkXSrcD@^Oqvg*P0r;@z#HCv zu^!dL)URJxtfF~D8T2TL&e0mT!00dMxeVb~$swlh`ibzIOz<&9B|zB0dWxJoAp36F zgJ_+4ZK`*3iY#2lSw+X=y(8otygYwZ=58>Uy!O8Q(2RCUPk3uCSKyG89k907=uzhT z%(5B^d;y|HDd44vr2i~QBLyUg@>`9PfzWC!r>Kl;Gyw-@@6v?&>v?R`A#l8HVY9YJ^t(`pp=}f$_c&-K>~J z2MxMDwE35?!R-BDsAjDP{jh12!e`tx3^?7+^6;DvSAnyY#^gBmP^B@U?DG}S3&#Jp5jl#&v;#7!XtFcnLK7_oA-VJK_r@ zyG&)rQbqTnm*87Xa*Karh}4y zFdg#t9?nP2nw5sDLqmgwJkMU-{7n@JJJ9Iih{i}4&*D5dKII+4@ckt zZ?-|8T5wA_me+N}KA*Tj9v7jj*LSOg{57|>H?9sn-TwT8>dYR4^M}JoayEI(m#zA@8gx4dVfnw+G|Cd5Pd(X-&LNFRqFNu9C~YpxRQ_He;qKAK2%gAXrE`s55=?)LQ8&DnOJ z`}f}?xuTciYTGSX%Lq^MnzrdmJot5|p?%;9K!H+(0ishoWu z3W;`L>Wr!#AQhi1;)S1e@bzG+eQMHR2rEj$8VW z2;k`GBJ}|oUXaHg7j*8RX}84xDeH-}pkr!FO9|wWw5{l6$5yknvf7e4ZO*1VRIKx}UKzhX`Pd6S=?&s6lk7z6*P?)+8h>VKjAJMITJDWoB0K(O90-6T&rX5$a%)nq zcZqY9(jls}%x+vGX!qg`{-`{x2EINbnU!aSt11?kA6@jmBNK~5VFD8eWQoFfsOSJK zbKjMqu*V&|%mUL68_}_LHQ*a# zw$b>OhNU$La`Z}b_T^0=GN9rfn;Zok|2$*8PY91{d=9VCP_O;jH@f4J&jYT~whg_G z@8QIL=+Ld*q>Tx+6-gw%_HfjS$p?omTl8o-LI{=?yr22sXSSzLB>yPad8EqF5FGzK zAu(ZHg;uKnIBX9@V8G)>Fa3GgBkH-h>b!&^dp#ddH^7I0r+`|_3Jq49zel_1eK`p* zMc-@uR#`NngKDbVOE<^%zfZ)lZ0}0ASGRjp>Zl71FZHwjo#v9<-{h?Vf5z@c7Yru; zCwy<6YQN618qO9$SDbLdq)rJo_CQ=9XqbIJ`00Cvp)~k39UbDzE5-NJm4Yd%z4bwdzJ?!?qm)9>DsKD+X|UHJW%+3+*tTXL=wM zx}1_GAb@oPC4=%B+Hw9}J&~(HR1o&ThT1o>NR*hxm0kBVYAGHu$XF7k95S5SaE)2D z*Wz1cax_A_*m{WKCGf~rcnn;ettdxSy#wD?YnD#mOWSDvUOW~>0mlWqnn2Z4J%noV zeAfer$WJ|gW%8!)i#BO?aZE#u)Mlf=QF3zfzz_X1HwvDkG{LYA;{*$K998^VMsuvb zfo1bP83n6P=Yq7y+<`z;V;s*pS5mT?iVmj%8Q}tayp@Q?6fKIEwKs1ZOHWxBOtl~& z1&)nYO+nR&8krmpNYP&!d`-#T7ScBTwN8h*qgG0uXgbWWv$R~JH_CS_OX-as^Ea8# z$cBMB>uBfU<*pXGaATu+D=080+yekyM6}0K`LKm=?52ypmgUS=)_cKvb57=^IH<3Q z8F4q#gtuD=tJtu{J@l8q{=)jU$&-2H4qd=&WeYsoUKYT&yUB$1pG*@m&T?gL7gV6t zZGYKm709hiIgWSY=ZtW8h_xd7Yhsfvq+z+;4}VvEcHi*t=JS=_5oW7MJ#JNs3;AN` zpTUHj^$CU-wz21lZ$bBX&pkUlg?QI;sK&|l$sQCQ-)80nNdEc!bd?p!ORAwIg5d@% z>^`kQ708Pl=!=&y#y(;46igl;|5nfF$&=PTXzx6>#hY0VT)le-N+cpLZdUw#HPl>9 zC}AYxV2q@rAv}D`y>9LZHKILMQ5iN-6q26w<{S!Q$@wnoseL@tw3rxl3KbO+^(4u4 z$~_?iEgC8eIp-&LtkUTF){3rY<2=-p`>zuXB`c~-3Fh^DU1VCx%QBI2`u%NapiJVU zK?8QXGg9fc_h=&O(t>9o_D8yi-}LoY*V#{ttM0hV>O$QhSIobwe&vTWt!SM7A-je& z-srY^lf#a*So&%ori33})4v!0s1O(CT$8)us^&V(cVH462%+P&;k!5fr5Cr$=UJ>! zQ2YV5GmJ2a&Ik?+F~zHjtH90UVoEZ&I~Se!SdhqDik>oTp$R2fyFWp<)oDN3jnN>XpR zsA-#BC|4;*0s?{M)T_N2srDT7kxO-p~xnWT}t>QJP8X%U>B$Z>`+a&CWgQukrFJW?$u%g#c-G;3XEu{W zf4Jd@a<3I*{lA8vU7kmEpbu#hUpKjy+S@03+*5YgsS|^uuMJ!Go$BR?zsuH&b(tXB z|C_i5h~~jY!qZ6my)wubLO{1?&az`dH)8of6qr1SNdAWi`M?PSBg{m<`Rjh9J8RhP zQM{{8Ps4Ua)?ZK@W+ugMOVQosc$Em`RcMfoU?hT_2oevF;UbzJQ)=v9+b6JUOwmq! zph;(&4sT!VmT%91(-vnyHM2=rCj!VNPQ8W=+Cx;swI#YgEyzrXMr|c37RC^KZyLB) z95R>`2j?uCp&?%B}KkzE)QgzdBoXR>0yAKHC5YX?J|VP}%l*+1a?|rMy3!DFyNQ>rC}i!61CgCQ z2w;7Y@0jUHXj>nv;UsM~Stiu1^Pr`IwPV?pQ~Bf!6Z9PVxBDoL_KHT4mPKXj@la_%WP<&iN~fEPMYm2nlk`#jI8@(X z(jJ`$kXt_HOb6&xHewMS#k*h65OnaiCLZzl1(Wjl^_uk<&>P1eJO0Ppth_fh+SQb? zwO?Rm511&Wy5tR2Ixu{&G$%uy$p4CpQySl^c12_EECL<}Tw0{y+ciMZdqCaN4`V1ZC+0RkEAr9TyDOKtHJ6#H6H_3mQMq@OZa1Sa%` zQh3+g!&3Blhn$tpwl`jJW6&*VJ+}WY+qbS4wfvcg)DaDFKC%^Tydux!t;=q!d}Wev zeGjB(j7rA?2}1(ds9rCBkp%N~1y|nx#k!vR0-#HH**KfLEX&|rZ1{p8r;SA_h!1z~ zL4F;se$KT!7HT(g%SekJoLX)}1q$Sjo(4Ug?xPjt;Zq?A6`Q{1fBhatuqm2kIP_n+ z!$rnzzdAG4H%iD0Os~8fR&9=@Y}+y!`tOSDOrUon<^9F9GZJ6(+b7`lC~ru)9w-u~ zrATt&yzdcr5FoR_R#C-x0vQY{o3l6BKf&o}2x*$Laju7Y)T05St90+$O+{YNkYcBUchft-m(|5UI!v0-WhUes+WE2+e;LvGw|kks?Ob-du%29zEZ&_&KK( z{3rKv27T8T(f_(6vX#-z4RBW0;_))~~an8?5ldcM{6wcde)JUE8Q! zP5O_IO7fFZ14pJlNJcRGk&krb&T(Jw1H66g(~3GXHz!B?s{=in1^0tdp7#l4>J#fj+?dBQ;p*x&+$%4rE`)l&yW6;fpq0z-*&MzFv&HAu=k`^1hl3e~$PJuLTbd z2d}5Vn%Q-k(ih8vD8SH*GPUDR9Cw~Nh2*`~AL_$=*D)4c@FkRTh@GF!U;hDtk#3nR zZG;{shQ0m3mZ#3>Z>_9O2XM0L``p50TSW91btK6bpe8wqmZ%mg(wrnUNO8J)K~LaL z?vm#xhG2t2UzGo4N6tfb6CWmRFE8UKnpdgXPyzmi8MZzgfvO%jtgyB6c_)xV$&bA^ zmk_$nm}7|guz?%`6-JLbP75(?Ry#=41Y*Gu@~GdJ z{IVVuKw5JQwXrO;_5QI=r0Yjj$FHsd(UlkWNV!J+9M^0O53NAezt=Rr(!K7bY6GWf zDFKA}!p4KU>~mY!vqh-?o1z_7kgnn%Jc>%~YYL!Vxp9m!bt&x#bD7ht?7X2ltZ1cT?H>QpDo$k)xWF<~xee+4lgY2^-_8*Bk{5YZ62 z4#ksAI?|g_2(ZQH#?KGo=@zai(GNKe3N0_T`riC^m*Z>23K6_u;0RU@DxF?j9Rc4N zgrDVPtP1m|As7G2`w-0!LYs&fZLb=Qnc$t+ zN9*~sHBwxBb+}*lA!g_|jF=k=J6e1Q^Czs@GkMyB)Bo<4j@G=h@8Xs*WLpzlirQL} zg$+df@EG)5OQ&6PyeB-fp)QVRdRLkck8}DW?h_B2OslCqUx zm?^-o`Gr>Ya{;1(@p?*k5%ql6eWa_dTR$Hdgn4qPaB;m|6|ZQ9)Sm9pEmh>OH4Nt5 zHPCGjYbbL&e-298aeDQO!}m+Bl+3a!r8YskepIK&!c#NaO_ujCUxe-}DAbC9!-rLZ zuzgGD7^R+a(C1CMQm!_yW5dxBj0P8^*`hJKlsuLs6*GD@A@T%-l0s3 zF{ZSiF@cV#9c_o5%e3m8o&v18yg8OxJ0IKi>#pXKSqLV4$xRZIs_czUO3A@~9r1N8 zh{nIzRr%fCR`>;_G~2ex1;N+;Q)}G)?_Bp!clE!olOtyL&@ASxogne&J!lQU57HnC zign7bRfuCD@!!2;YOjihQbyt0Gx}`l2sQVRy)tW%bB%yTbm=X=;o~2^n4A- zdD@Z(G^BMe{ZiHotpzCat`Y79sUjAhId#{JB2KW}+-mT0J){f`zhrq|n8h2U1+mSn z{}PXB-D1|eerpf|UmvS_%%xHaS8B9r@75|R5tHD>!Y~XGV3v=KJf=q z>Yq!7?8@`hn(yA~L!2i(X&u%C6iIFaPURAph9ukk?Jy!DYAb*PSO2l|=K-&kDUvI# z_|zxl8;CPiIpLpH%J7sC*fBi#F0m7&O!u6wN1G6zkCx$TtosW)_#-ZPc^7 z_7EaHgLF~Lb?sW+mC!eG!KZor``0dlU@GjC(JJAbpE5VX@|G9QWebf32jlZN*jsu( zv;Cg&Inq}A{2TK)Ms_uFAjK-&y#zB2Pt7xjL%eM(b{MGP(ii^#fm(W7spDmQ-}Tw9er5+`iPaK_d(7Cnna(!jT!1?adz; z!I(V!Cu1facTW>!11G!%{2ZX-1-GiXU)bzi$3kgE`VTm<6|^x!X|1jJcn>z_21fx< zSRz+bC5OJ0N6oAd8k=*f>ek7ezKHo3fi@FYP?7za;mvQZK!bMq<0p>NujL77>%QNs zXm0+!yUZTJANJq+zp9l~RqfdeKPXDam8`xs#BiJ)>>jTz&Km&i%rH`Wx8_2IfngtfZJKw#=jdN{|`(SIM7N0wB-PD$=ykGdtH@ z88$5EQe6^X&hz72is1A%Vno^={f!!Ne;n#GE-CcmH;aET zraF$)>&JmFd-xkM9o#BW&wL=nnOC>C-a?H=w(yW~o$hXPFlf8leAi81x4v-RWROfG z^3K4M0+jJagQ>w#9IG($bfmef)K^_+_Rd-V1xcG|(1-*U8njGqepwA z<=>!Uk-6+|QoSvZ7zzG6kN)F(BwC_!Nc)s|*|_EnWi(iy&T5|PH29%b&|3IA?(Ky} zA#JXWcoZ#Kz0T*Lu(vVBl`I@sqgv-<)?f-!fl3gj|1ni*S=ptRgS@M$po+I{DR+n@ z`f`TScA8mEk&ynWm|k~@XufN(f9dm8fDGB!w%~R@Ool&k#MB7%SRawbK95b;T`C~V zbcGcVXLo=TPRd&AYUPkB~c>LbLc91Kr%VR5!1KrLXc}b7AB&gF=o8r-p zX74Rn@Nom@-#_fU6bw^&Ecliixo*6UpV5@|fUS(ypj+LcI9fsa-Q7)nxxUxo43xPO zBx$9qh2-kWm}~5k8$LyO)bM25&|L^ce~j9k3-wMe6^s+Ara1$YrRvGTS*EW!t(MCt zz}IS?{LbE$3~_9iKk9=Qn{0oYkC&c&6}g*;RhbZc;uU@zcE^r9?VQOT_Y%C^*n%}1 ziKgZ{v4akabcVQ#)}=*7AyYo|^($luQ*iE}ILXbF`|>F_4iM`P{sn}U-nqgyX`k9E+t z$B88A6WrrPwv|}Znci9^?zb2*8;oHG!O+kDoU90Pw>I+%hugYHrpdGJdLG5;;waD1 zw&F8*$7}VrAasqhY~k>cU5Uu-khvI(FI7ko4zHqbv*gR z4~OKZ8I%2PSL^ht$NwTkcURdR(LIMPOX&#%UR5`=zjl|&gIAG3Zv}WNRW6KEqqE>8-w&ar z+vPgnMT*vHg4{l%1Rbw+ug9rPy}8m2VuS9r#m7-&R&?3+rm(4nRD*}N$=T(&v-`)^ z4KEt9rkgh3b1>Nrr)aq3fb#a-5}>H1FuLI}x=dY1W&v$QmY^~4MR3zfF0$Y+arQ1I z%H+M(9{~;@f zcE^&?t&!wE(XLOuP1pC{@1vSmIkER7WBT9QLQ~vWk62WQ{tD{*Fb)t#$FQ9!=fIudp0J_Hd6%pVWm3%Y2eK(DaC-g{g{WgpI_b zoEupZ1!ta9hfI8?84be>|ml+S%nnn*A}so*rfe)WH77Exj!zhWiK+^6Zxn<#dVRdtWz| z7T-n7rkAlgDwQOX)zo3LF9R{9yLFtg+Y#0q6NN%xJr?i7;=Ym>7I6>TV;Z}Udo`O) z{;D7yxDs>W_FAf8twRze$^Liz=;GNy6*bNNm4wyd{Wjl9EIMVfjFI3HwNP)VP`|Um=@a@Ozlzr;r7b^Y=c3=+o+wYtQPunu%lUPehNDgN zUl7*5=wzwVV+GiJ_1G_l0jlbd=?K8r{N3ai`edJ&>n_Tv|6CUpc{9>2Ec8DP`n_Qk zo8a;6C~M-cUS31P1{h8UCaifaetEb!9+xul!A>gQ`n{oY_@T zIak4sL#KsiS~kO(qqlc?Nz?e$6^4>hMsQj?Sy3rxf0jA(PJkEQ%yK4iqQOS*C)3qL zniJ`HhaFipuwN`Cv9K{iy$d_H?b7`E+`*Qy8mOeyDp|t|4buu8Jd>E-v-9K#a{VC_rE?wa)9z(f4ui%tqm~lPMCa9K02+_(*6MHd_gf#I$#f7bNe1V} zq;vsJPb%dIrNkPMH1K(dkX-^L%{8l+@w9Spz3_uz5D`f*FGwv&L#Z!{-}Y)Uf$SC| zQ+m5;`pF}pO;2dX5tce|)ZU+U|F-_?@B*$Do*+)4izb1K?L$LT6-b3sMKZJ@pQqGbTKaoDm3bb;^yA}ThwWyN} z#IE#9vpn0=#4PKj%l=Trxr{nREYSHLh3Ke6@F)<_#Jf$O|MUyYn46LB1~$25k@I>A zmvBF`yzb9yL!L7hUz~OJ6o?b@z28_dzwjt)js87UMbkz?&oy$yUhjRwnRN4xp6NAo z_UglB_uzg-d!E-Kb#NI1B2*_)Ozns-WqpJO;UY#@`N^Obynk+U@(a_5VZO6Ki&t%$ zz$6vTW>D%TzKO?KJjK=Vj{ks6g@19*mx5_4yE&Pa)pP$WWE9j)ZW5$8Bl;rB3QZZf z%gY<%{IS^WnDHCo0AdG$gaq-T!-vJ~y|d8L&gOD)lFRmfC~9gGxzzdYtdMo}(YJ2N z?1(ZM@se)90BswR={D+sC%M-F##x+qlmqxkir#Y=1yqWOd)Ek~5{nb)&gGU@9!-bh#o^UTUAFqTA7-8a*+L8m);=s;z$-qdWnV zKG^YKZ)!y)CFb>Hp!Ln_z3VfvYF)fU%p)ELcW}w!3-ur@$>GDRW`t6s4{EjZM#ucB zsS9FEGWIsDJEs^)ccL)#QHl@*5|?q0#W@f1&INh>S&p`PpQT7d~!$0hBgN{YTxt zKmVQ!*lPKBzQ|5qW!9Q)}&iRzdXU5WRG#dQ+JjXspSJJy(&X!2sT^R46@X}zPnD{8`aT530c-ls>7Evbdr+( zD@PK<1PlM+jS?DtT_`=+chQ_pNau}`yA)$PM;bd)i@f%Ar>P<)|8!7|>O~_C(sf5k z<3EGBfcolcTu+-k*;yF5kU>?->g7jpANHc~5OoR7id3V2 zz&C&*ZktFbza9=VTgfo+eJi@_(jOuq)lkRoClrh`1f`+AQ|=f{ChO2AILl3gjfPdY z+YSV=e}JRhwc1B```u%V#M<7utR|bGZ0*^ufhQ~TFyAdihO65#OQMt(fAwq)!c7W_ zdrPFu^Rdzs7E!#KU-ZuwZyo(BUKqX+vGfSs?YrFLxI0a_!joU*U-eewaQ=CmRovm4 znBXvgrC#5(l=jrl-adMf$omL)_eDltm)` zDcp|%CS=EviyYb^=be+F-3EwKX;j!J*E7C^`Bj#QN#vsLxydf!hwl!INN=v_@o>J> zXstoyeuc#(irqabE*Zg<7r!(f?G4;=24?iRlhK2>QgCGblycxzopr)hiBi5D8Gc*% zg)ASupSGc7y*QVn>!}%}5z{YxeQR-_XOx~Xsj}^8+(mDoLuVs{)CGgF=blm(Rc^6t zAjAgs`AvgEG>KVr_2*x8UKgOT5_y$sq7_7CWD%`o_*8&yFs7XFhrTHRX3!Ul^ZmU4 z)0nouemK@5Qc(r-+I>Z~A-x7|n8@b{m3=e=Q;I<+HsAquzEw03<@P%CDTf!wL{Xje z(G4*EF-1-7Ss}U1HoP1b|4$BGZtgW#NFwfF=N0j%B<~hZlUeCjPH~Ik6>1ZUHm)x$ z4yd~Z^+1|tiV3lEIkXHKLCn?!3k`NGy}Inn316J;awz(iM^L*XC@}o8NBEtye`y2P z0QX881@e1S`z@&?W~L6Ujwk-UsDWb6;H)@|tKCrbmLAamRA#Uw>^V(KpC z%KH#vNerFjHW`}AJ0iE-u_0jB>6THr+kgl!1$P>SIF>lvV4zR+Pn|Yz&7g-GU))h1 zT`7Ji7*iW7wp^t_f&HxM)M7xHkna&!%Ivy35j67D3QLEAS6cE*q7??7iV9w?X6fw$ zHf&^cK}u`(61L6XS?A*rCDKd8(0glcCNO(17O!2r0)p!=6RVd~N-{Mfy=fPbpmuTQ7Xw;cK7CnR$QhXumVsE2TI5 z|G0CKgFK)fse2T2m32SMoeM^=WDi=wzz`>)Tp=6ybm*(WaL}6$pTQ964KIc7lRwgk z_gJ&su|=pVm{4LC=OtHaBy!D3pfG35_Gmo^bUs^6ofNwldgFcsPyU@=G5YXaE9@~Y z>2+5oE?Z;eh*a;PBQ1|HBMP6A-FuNm*43TQ z%|A_=WECy5&GeSx{BV|E3K@2+_vByWZC#E3LS`awzUY}kRQb4^pw}%A1;KM&Y3Fo3h?dsFc=l;#uN(* zd1wFEfrTD+^@}LPsA7Qmq|^=%0p~ATCFVsTx|a4gM}yT7rbx1gKeB{C_{n1Ypb?$1 zuO2=3DGHAoO!zBsGhGuJ9rllb+D!Psl?!)F^%8_}bxq>TAW2a6d-*V)`0HsCk#77} zo4We1VOjjT4Tw37SV{E$@J3i5+aOYG^X#VJxNaKxp|Jo2@j+^k@EQtTgLU}#1w)Fg zI?`i!&vzAax;qE7@*-&dV8kB~P_kPZa4GjJP#Ip(nSN}FazW=%JnATrj+KaNXPwu* zia^HiqufOj#297ZbTQF1oa+nCabr|o$YC4o(zZCRLgdnVjZFi5S z2AvW_U;L}Up8*UFMtS@R3q_{q!`~gM$(diXriKM018-{*)TFC%A#Ur86@%j=8)J%! zjA`*LDc`YHb8KA8hlrOK`FYWr zhZ5Fn7O(B!@cx?4TV<>elSHcYYjo+RE(gz|qE%;nB@4^NNWFFU>_@BVxtzgj3DdcP zWXj-w`oUSyq&FI*n)GxXu{RD32$xyJnNYr?hBs*a0S{7H0E7*1T#0(fp+Q*Aj#QsA zJIsbxj<<3nRw+zXrEjP&+a`y)Ztzza<>-HyUqbXoUlK=Tt_RaK`;(Sp|2M{qqW;8c zFwy;PqlC4F97|)da)P^?VW1`R>~$rdYBcFUU>B&2o#Jl|o@6e?=c?MjXBwXPOK&&| z@$qzb&ZI%tee~_OIGR#ZcrfDca=J}e?)&>gd5Fpnu3?%qm?R!JaZNWjUTeP?iQ;H^ zhC4Q&2E$ge?FzgV@#lD89$$?Ddj{MVUz3WxD>!!d<3T~;Q) z;4wZswrWQ}P`r3T#@Y4ys%{LTnvwl|sXSp%B|WVy>82&_vdB>a1<8FV*Hw(Y}B zl-Hl^W%})O{RO64L}Ry1Oq#2Q^#cCDKwQfz?uIC)$pYaY=Tf zrtV1BzM){n!`4AnGJQE0=3@0THauzAcT&r|TxR>D6!;5~Ul#t{wfYTWrPl8vrh!Kw z(dE;Q$SF(KdfJa(lBq25N62420VgZK=2npA4I~MGxgaUox2Hc=9~?BTufBzES|kKt zIdf@OEF=LNjeiwUfMTQd^UyQ_utV=MpBsT5c&RmK5oSEB$pgcK(ab}Z#KP8LvXH#JNxzroa#*W$SR#20#Q)+ zXA4bT1M+PZoh+Ivuv=MQz=Og8c?xvon2=VbQy!hpta&P_!jQpVvZmsC-ctidj_@yA z>d{ngro&_STH=reoM7={xsZ=AWJ9m`SQZ=ut^U-WKKc zsFqOehVz1e?(*n~Fs8-I!TxPmq9nswUZ^5=yxncGIDM->+7%hP{GcPTJjP=%q|er2 zp*B3OMPk#YNiT>D=I6=~%s(YSe}*bn6z^Tp5xNNBVesw^Aek%}rOIt*H6@sWv}^Li ziaDjEblei?;tU~G<3kvoZyACiajkAguTWRU&iDsLHDpzxwKdI#3tZ^HGhoU!1E@p> z2TPaZ#WXVcWjJSlXO3`Dm3iH+56DD(Px*avCe2ZU(fNl$I?x3jLxyLor=ga#SayDQ zp)L5AX)7(R?^dD5oJ%jG27QLTkg_Ssl)c9tFXhfo6V%Apt<3=25FptgkIoaSoQ3oF z0Em;;3JCtwurLvR!yfDbzF?yTa7mZQi;W-RpA2tQ zc%ZI~@P!QX&~VF(*kP^2#Xa!Xo%T>lFkn-0iISq2DAs@JqfXXc(bMZTyJkHLt|KxB zJ0vw#th0EVof3+_O95RTR%HIumRpx?@L-AdTiz!uJ?wxLhAwFOuld@Wx_)*^tIVe| z;UXoYRbIWA`sRA7kEvaX@EDEWfMfk<1jXM5%8e;09C%H?LUCy&SW^l(0LWDcsnm2y zcoZ$A>74XT4N~8yrE2cTB$BJ~YldJyHPhM6IT6$7co1zea;zhVG>1&}+!+49BgJQfOYLWK6J@{`^Vs;h4;QHh!oY6ay?Toace?fh#qSBg7LTB*6-?Q+mx&n1A_{+-mK59RM5vsSbE3cpF(nx$=r9L(KDf zkHW2i^dWn>D2^P$+LAKpQ&RZzPWt7~fUlFM6JTt`n&H621b9K+-3RVR47ghX<&L0V zFh!(>(Z*3+uogtkxXK$+}`B9&P(m0 zKv1B~wd){@G#K>=zIyVe6$%W!X%GzS0y*PLq%~`r6#vhrkc$uYjb+{{!Cw5SL8pyv ziMEj%e0^3X5{s#15vWH$9YivoeWI#TTA&;|5sgRZpG^QYGFGBE@LY{sF{dk56m2~m9xN(5rbM&>f|Um>SRg7iHLTMLv)V&MLT?vHu|?XX)$ zA4VmyPS<6$HQHqjgoDs0C?GF{W>1OJe??>AiVNq~nyLv^gnAUZ!UicsB493Fq@V*z zgLdwH`@?1>g6o)$?>`BN47f!O^*>(I;3XJ#aXV@IFP0P9yY4$KHw#J#K>OO9v`%kt z*vNtvzm1@uF^{yMIJQOG84%nGAYbbl?8A)MET(ua4&^R$7c7MZc9Hvhf! zqkd!KZ1ZC2*=dv?3ephV$O>gWQ;ZXU*kpK+Cl*`Ew8Z#;(R!~I4PnxT0-7#i49J2o z$Me*Iu4ZlyE4cgGnzsfonL;S=GuN7h;ZB*UbS}?-6G9k{A7{Tn%T+@t{tU$@Y#k`# zlwxI+a996bc^IhV49*J&RucTqJg;+SGkkl3S?ye}fh&M*LYz;7<%gh*DQ73MdMJs9 z-%RD>dlfDruOWU!VT+`k^v5U1cK(gXe|FZUwEnhA)!^4^irOW$B}aqc3%dtVlM+?V zJ_$`Ub-M=`Ik)7@<3Y>+yi3zxAA>~zw>)?;3ScMC|HDptivQ7*dErQrO6)-o31Vs7 z$AvQbwVNYH!1c6hAO&OXJRJzJS=;}6g`al?y>V}2mbD@aHgo`9>B|{Gf2SOgc)kgM zryXc8bQY{ff3kz)%tG>E66%r1f?8>XzliJW^&dZ_rpk`8DdW{FpnFB%37f{a%%lAe za?QZLDuX%$hZGVW?Cc~Y-jTcslTrKGN$`T>H@_}?w&^-i zYx1)LJn{5b1BAZho;2mmaadKMM;f3h8o2fcc6Z$M1!^$#2_Ab1MCI1k_i6Pd4Mo`o1ddqVzm1uK++TL?XB`NS7k z46=*r&u@5N{`AoF-BX`!+D!uK;jInEn}(?GgNPzz$QNEis~5PaVkI!3R8N zsmW&&P9q@N$D$s<&#!l`*T1cnW0vARVve{JbsVXyLmCoPpdR%1!`)Hd^)4S?)qBAL z4F$si5XpUB$y1(@ou;!4PYFty{X}SjWA9R_PrbC05AAJ1ht}x`xica z>z>};`{X7Q#d#xV{R450Xj@57@moCA1!@+MQG*beK%}C)+EKr>OyC*!vYdNqqBDQ}2{lZ{bf5?XSK#uWvvTYG9Sxt#pmrUyDvyZ43?*9#kLD7Q95@iO6TL$)M2m`9Y;; z+0!h0(tM8gf@_)01;c(mYZWMEXYFX-n2+Ycs1?}Vn1gV)SjL5>)FrXY&$Nh>-~F`x zeDyF?MHx@|vp$<+E$N4B;F$iHPa)QRx%l_0H~H92M31Znryb}^eT_55l{?fGv{jJ^ zC7w`*O8b)#xxnd?z^UKsT?dce0xw?>M0q;d9W95ekZh|!nP4<92sWW za#gp-AGGA4gL)82;4lCK;s9JeM?8SwlgNY-f?PwfxqQR^mpk7##L(L<=#`J>)GS{b zwfCt|$KZtGV$6KAr{-GRSYZa>ZaEAK%}kFLI<2ARuR19YAwHnIiHm|VT`R}SF1?ZT z;nU@KD1%=P&7Fbo7*~daZW5tC@=IdFWW=c3WZNwZ6g(MeT|@Ok?auhD1=H(03rh4M zg;2-vDIh40FYC|s&_x|uPA6~OSz=80^{K9?daRPYBtGYqghikpm<}lljx3dDSxH1A zChbaM7*K4P`8kd@Z|eE%8NUU;ey&O4v3>c>?d7w$T|&LD}ng}AlYHR@me zvp8OuXiD1OM{X@0QNXdr*sRRT_hd9&{-rRQ{m=YB=^NcwT@x(Y*p}3=zN()!->5%B zBtmp@9O)D9jobYOH2+Whm$vY{%&+jRD9ind!;UQ-m*q|UrRB^=D~`C10dUZ>SZw7t zx=>kAp_9#degjk&19hqYYCuZK%1k?OM40?hYC2bh%3lfyZs3PXEW)WQi~X@Qkp zRI;`c62IYtw)qnN6>#A3fJNTaF4KSAhDP(2bCNX1=7$=HOK7ifO&cz2=IUG^HITT0 zw*VuV;n|%r%*#6}SVa?mcN;!)KX*~@d#8`~?I6DZ)GBS%}Z2-h8}iIJ^4vSQa$5PgZ@X^8tT z%Yue|buu|6vCo-FrtSmL53Neejr9CZ!OOru!u&2PO&>+&(Y6ljarf3(PJ+CTjOZ;YPr;XItQ0qGR6E6x;s!y@rshWr?-$L+LW@4zKHitw;2)z(LcL0zA6rqO zwqEZY?Sk*e>I?$CFa=ZMW39&4o8x;WoaaAUK};?F&0S>vhnO=~ID?Ll8cLIhqdgN- z<{z<4w2+RMzG&xnKr=f-|D|Z;CH;B=qzq0;Pb>OnsUECPq0-f zrSLzja@AMkR-8VDkRB?l#(yo0VQ`DjNYf6PqeKHsFz#d1OifN>548d%EJ9bW@!2G4 zt=!krDvHzc$9bCEweU;#SuRn-WphC-)%BAJrBBQyJhlEs0o^X6xr5lcX;}MWeP{~r znM&_$m#)-3^`hgCmG%2!IEPZ1@E{h~z4o!rjQEfgOu7Dd|dl7ZcQ z8enYcy^hw*{ixa)^KJd4+dFL58(@kH^zmFuBwSV4{Pw5V=~>6gljKVHdMLXt}?-x&JN_ zkDx&;M?GBS9(GFE4n|}MI28G?!f3ETiq!8BclV{cWpndws6~JM!QOAJ&T)}C<2+oc zKy6vhiO=4sdVB@;=gAO^PWaNkt96(KnmhC!yQ4eh_wBOl+LN4L5%B8jd~094zURPO zCSVGPH{O_SuYuYQp$nZ>(anMJX*i+#<vCXmuNVz%>=OE~Z%!9wEc^@wWF9Sy0_NxC(NeA=&Sva1}UkQJeBI zH~M;iob)uZC@f^Qx-j5`rCVI8Iy?sdgU>IN45s>3DJ{Wr{*bf%nPlnA^>hj+w*dBT zU!>OWI&iLM!lt(%oXgyuPq@3FJyunXFG1k_89juwhzn}j-wt;T7^N~@dz>CiyTuY{ z;JW>p@-Y!>pUIc+=yv*4to|^f&fp}=a+p;#pnhPy!@@gO)EQWfJGcyh2&D*19>O-f zAxy}32z)p#}HB7D6g+{l}txGu4s1ix^$nGtv`fhcxbm;rTEg)Y2KLL`eDYc&3@+J16n}+U2d$UY(%- zevq}k`tG!VgMGBBR(xi%37o1LH2?iEqJIi)}^Z(ikeYR2YH&g17Zu?P3rN z-C$?Ar-Z)Q<+pLOl^kjdTt!$s)_?4LVYGQWsWN{&kX#~u-inMyJJ%k2oj{wLEY>N= zc!?vqs_ycq+poWz7 zF}hi;@4c%A)8(`oK$|M zl$@@bAS9GE`1#iw^rne=FyCdeX!bgB5MDjo7Q7jy5^G|Ij!8RE9^2MFwOe0CVOYCX zUNb$bM7n`=G3eui)IruKxfktjeiAKx2;9X-)Zu!V+>lsd%&~m8I?(cGvNTL1J-{%u z2PVD*OW@um57}SQppdsrb-!LlJ@F;ePTr$@9NVby0BAvV3@aZmR14hl<6`X&qGxFy zIchKbss%z=?gb7^3SO)J6(dMmaaw0y+x#HU;r{j^bUQ8lcA*bmfbURz@DXIb;uDX~ zBzYVYNwI<=$&Iij)BN&V1iK2_9r|0q38ABj_WC!=$i|Yx!yW++P;Z}A68yqPqI6b! z{?u+mSz9fT+r#b$KP)Izsh$6Oek9GVGILC21a2DmTiZ{Tp^#!+LoZ0`uDx|yJaEWs zoLnJw8h|7KydlI8gaYN6vZ-Jd(l>Y;(7aips%omZiX?GPjnv~a$^Gl$rpt;`e>vtb zob%|3>n3w~6G*IPoSel(Ei@4>Yw@7qafOUVy0I;jASohEmXg>UN^pMCF_7I8xciA6 z(pbG-1J&c$OmhH=oL)?f*pfqvCvr$*>fUN8xQbJQ(MwyPq0f44S4Cy&LKXOo3NNO5 z0?>!~b_6!mf;ES3F(nzu*t9YpXvVeCipy_brcL8`yV_a=$v_?qB}ZLv50O}Hko1B$+<{X#LDVCkaij15wI4FNR{$-I!a z&NDN-^wLCON>_|dS(ml$!fG&FeHn{mlpls@irLz~M~a8_W=z+7s*X#Vrh+cwvO96H z=GA-H*<%l%1UJD&(M2;-m}S~-AkAO4M4qcd5!pL~@KK(lBW9XyDHiU;TZzgaxyku* z75~~sAJKeK$euaY4U$BJXzFXzVmq=0Im!-mm!7(S;}BOF;%lyA_?ASMBPGK!h1;ap0Zwj1|AL2Vxz5;E%LZESl^=X0(yt>0$dp}cAL zD9iQBl{#Rt0=vl=9o?GVIgtAB5xIdFi!IG3D(vcW_wxsva<#qwST`{Q1O&CS RestaurantDetailPage(restaurant: restaurant), ), - ], - ), - child: Row( - children: [ - Column( - children: [ - Hero( - tag: restaurant.id.toString(), - child: ClipRRect( - borderRadius: BorderRadius.circular(9), - child: Image.network( - restaurant.heroImage, - fit: BoxFit.cover, - width: 90, - height: 90, - ), - ), - ), - ], - ), - const Spacer( - flex: 1, - ), - Flexible( - flex: 10, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, + ); + }, + child: Container( + width: constraints.maxWidth, + margin: const EdgeInsets.only(bottom: 8, top: 8), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(color: Colors.grey.shade300), + borderRadius: BorderRadius.circular(9), + boxShadow: [ + BoxShadow( + color: Colors.grey.shade200, + blurRadius: 3, + offset: const Offset(0, 2), + ), + ], + ), + child: Row( + children: [ + Column( children: [ - Text( - restaurant.name ?? '', - maxLines: 2, + HeroImageWidget( + restaurant: restaurant, + width: 90, + height: 90, + borderRadius: 9.0, ), - const SizedBox( - height: 10, - ), - RestaurantDetails(restaurant: restaurant), - const SizedBox( - height: 10, - ), - Row( - children: [ - StarRating( - rating: restaurant.rating?.round() ?? 0, - ), - Spacer(), - OpenStatus( - isOpen: restaurant.isOpen, - ) - ], - ) ], ), - ), - ], + const Spacer( + flex: 1, + ), + Flexible( + flex: 10, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + restaurant.name ?? '', + maxLines: 2, + ), + const SizedBox( + height: 10, + ), + PriceAndClassificationRowWidget(restaurant: restaurant), + const SizedBox( + height: 10, + ), + RatingAndOpenStatusWidget(restaurant: restaurant) + ], + ), + ), + ], + ), ), ); } diff --git a/lib/repositories/yelp_repository.dart b/lib/repositories/yelp_repository.dart index 98e46e5..45af280 100644 --- a/lib/repositories/yelp_repository.dart +++ b/lib/repositories/yelp_repository.dart @@ -88,22 +88,6 @@ class YelpRepository { } } - void saveToJson(Map data, String filePath) { - try { - final file = File(filePath); - final directory = file.parent; - - if (!directory.existsSync()) { - directory.createSync(recursive: true); - } - - file.writeAsStringSync(jsonEncode(data), flush: true); - print('Data successfully written to $filePath'); - } catch (e) { - print('Failed to write data: $e'); - } - } - String _getQuery(int offset) { return ''' query getRestaurants { diff --git a/lib/theme/colors.dart b/lib/theme/colors.dart new file mode 100644 index 0000000..586527e --- /dev/null +++ b/lib/theme/colors.dart @@ -0,0 +1,5 @@ +import 'package:flutter/material.dart'; + +class ThemeColors { + static const starColor = Color(0xFFFFB800); +} diff --git a/lib/theme/text.dart b/lib/theme/text.dart new file mode 100644 index 0000000..9a6d4f8 --- /dev/null +++ b/lib/theme/text.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class ThemeText { + static const textTheming = TextTheme( + displayLarge: TextStyle( + fontSize: 14, + fontFamily: 'Open Sans', + fontWeight: FontWeight.w600, + height: 1.5), + displayMedium: TextStyle(fontSize: 14, fontFamily: 'Open Sans'), + displaySmall: TextStyle( + fontSize: 12, + fontFamily: 'Open Sans', + fontStyle: FontStyle.italic, + ), + bodyMedium: TextStyle(fontSize: 16, height: 1.5), + bodySmall: TextStyle( + fontSize: 12, + fontFamily: 'Open Sans', + fontWeight: FontWeight.w400, + ), + bodyLarge: TextStyle( + fontSize: 16, + fontFamily: 'Open Sans', + fontWeight: FontWeight.w400, + ), + headlineLarge: TextStyle(fontSize: 24, fontWeight: FontWeight.w700), + headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w700), + ); +} diff --git a/lib/utils/get_random_avatar.dart b/lib/utils/get_random_avatar.dart new file mode 100644 index 0000000..1ab3e36 --- /dev/null +++ b/lib/utils/get_random_avatar.dart @@ -0,0 +1,21 @@ +import 'dart:math'; +import 'package:flutter/material.dart'; + +ImageProvider getRandomAvatar() { + // Lista de avatares + final List avatars = [ + 'assets/avatars/av1.png', + 'assets/avatars/av2.png', + 'assets/avatars/av3.png', + 'assets/avatars/av4.png', + 'assets/avatars/av5.png', + 'assets/avatars/av6.png', + 'assets/avatars/av7.png', + ]; + + // Seleciona um índice aleatório + final randomIndex = Random().nextInt(avatars.length); + + // Retorna a imagem correspondente + return AssetImage(avatars[randomIndex]); +} diff --git a/lib/widgets/divider.dart b/lib/widgets/divider.dart new file mode 100644 index 0000000..17c603e --- /dev/null +++ b/lib/widgets/divider.dart @@ -0,0 +1,7 @@ +import 'package:flutter/material.dart'; + +Divider buildDivider() { + return const Divider( + thickness: 0.3, + ); +} diff --git a/lib/widgets/hero_image_widget.dart b/lib/widgets/hero_image_widget.dart new file mode 100644 index 0000000..d7bcaa5 --- /dev/null +++ b/lib/widgets/hero_image_widget.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +import '../models/restaurant.dart'; + +class HeroImageWidget extends StatelessWidget { + const HeroImageWidget( + {super.key, + required this.restaurant, + this.borderRadius = 0, + required this.width, + required this.height}); + final Restaurant restaurant; + final double borderRadius; + final double width; + final double height; + @override + Widget build(BuildContext context) { + return Hero( + tag: restaurant.id.toString(), + child: ClipRRect( + borderRadius: BorderRadius.circular(borderRadius), + child: Image.network( + restaurant.heroImage, + fit: BoxFit.cover, + width: width, + height: height, + ), + ), + ); + } +} diff --git a/lib/widgets/open_status.dart b/lib/widgets/rataurant_open_status.dart similarity index 72% rename from lib/widgets/open_status.dart rename to lib/widgets/rataurant_open_status.dart index 89d433e..aa2ac36 100644 --- a/lib/widgets/open_status.dart +++ b/lib/widgets/rataurant_open_status.dart @@ -1,17 +1,18 @@ import 'package:flutter/material.dart'; -class OpenStatus extends StatelessWidget { - const OpenStatus({super.key, required this.isOpen}); +class OpenStatusWidget extends StatelessWidget { + const OpenStatusWidget({super.key, required this.isOpen}); final bool isOpen; @override Widget build(BuildContext context) { return Row( + mainAxisSize: MainAxisSize.min, children: [ Text( isOpen ? 'Open Now' : 'Closed Now', style: Theme.of(context).textTheme.displaySmall, ), - SizedBox( + const SizedBox( width: 8, ), Icon( diff --git a/lib/widgets/rating_and_open_status_widget.dart b/lib/widgets/rating_and_open_status_widget.dart new file mode 100644 index 0000000..b9957d0 --- /dev/null +++ b/lib/widgets/rating_and_open_status_widget.dart @@ -0,0 +1,29 @@ +import 'package:flutter/widgets.dart'; + +import '../models/restaurant.dart'; +import 'rating_widget.dart'; +import 'widgets.dart'; + +class RatingAndOpenStatusWidget extends StatelessWidget { + const RatingAndOpenStatusWidget({ + super.key, + required this.restaurant, + }); + + final Restaurant restaurant; + + @override + Widget build(BuildContext context) { + return Row( + children: [ + StarRating( + rating: restaurant.rating?.round() ?? 0, + ), + const Spacer(), + OpenStatusWidget( + isOpen: restaurant.isOpen, + ) + ], + ); + } +} diff --git a/lib/widgets/rating_widget.dart b/lib/widgets/rating_widget.dart index b7158b9..d1cf130 100644 --- a/lib/widgets/rating_widget.dart +++ b/lib/widgets/rating_widget.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import '../theme/colors.dart'; + class StarRating extends StatelessWidget { final int rating; final double starSize; @@ -9,7 +11,7 @@ class StarRating extends StatelessWidget { super.key, required this.rating, // Rating should be between 0 to 5 this.starSize = 12.0, - this.starColor = Colors.amber, + this.starColor = ThemeColors.starColor, }) : assert(rating >= 0 && rating <= 5); @override diff --git a/lib/widgets/restaurant_details.dart b/lib/widgets/restaurant_details.dart index 166c8bc..e14ebcb 100644 --- a/lib/widgets/restaurant_details.dart +++ b/lib/widgets/restaurant_details.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:restaurant_tour/models/restaurant.dart'; -class RestaurantDetails extends StatelessWidget { - const RestaurantDetails({ +class PriceAndClassificationRowWidget extends StatelessWidget { + const PriceAndClassificationRowWidget({ super.key, required this.restaurant, }); diff --git a/lib/widgets/restaurant_ratings_review_section.dart b/lib/widgets/restaurant_ratings_review_section.dart new file mode 100644 index 0000000..dfdd623 --- /dev/null +++ b/lib/widgets/restaurant_ratings_review_section.dart @@ -0,0 +1,114 @@ +import 'package:flutter/material.dart'; +import 'package:restaurant_tour/models/restaurant.dart'; +import 'package:restaurant_tour/utils/get_random_avatar.dart'; +import 'package:restaurant_tour/widgets/divider.dart'; +import 'package:restaurant_tour/widgets/rating_widget.dart'; + +import '../pages/restaurant_detail_page.dart'; +import '../theme/colors.dart'; + +class BuildRatingSection extends StatelessWidget { + const BuildRatingSection({super.key, required this.restaurant}); + final Restaurant restaurant; + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Overall Rating', + style: Theme.of(context).textTheme.bodySmall, + ), + const SizedBox( + height: 16, + ), + overallClassificationRow(context), + const SizedBox( + height: spacingXL, + ), + buildDivider(), + const SizedBox( + height: spacingXL, + ), + Text( + '${restaurant.reviews?.length} reviews', + style: Theme.of(context).textTheme.bodySmall, + ), + // const SizedBox( + // height: spacingXL, + // ), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: restaurant.reviews?.length, + itemBuilder: (context, index) { + var review = restaurant.reviews?[index]; + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: spacingM, + ), + StarRating( + rating: review?.rating ?? 0, + ), + const SizedBox( + height: spacingSM, + ), + review?.text != null + ? Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + review!.text!, + style: Theme.of(context).textTheme.bodyLarge, + ), + ) + : Container(), + const SizedBox( + height: 8, + ), + Row( + children: [ + CircleAvatar( + radius: 35, + backgroundImage: review?.user?.imageUrl != null + ? NetworkImage(review!.user!.imageUrl!) + : getRandomAvatar(), + ), + const SizedBox( + width: 8, + ), + Text(review?.user?.name ?? 'Not identified'), + ], + ), + const SizedBox( + height: spacingM, + ), + buildDivider() + ], + ); + }, + ), + ], + ); + } + + Row overallClassificationRow(BuildContext context) { + return Row( + children: [ + Text( + restaurant.rating.toString(), + style: Theme.of(context).textTheme.headlineMedium, + ), + const SizedBox( + width: 6, + ), + const Icon( + Icons.star, + color: ThemeColors.starColor, + ), + ], + ); + } +} diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart new file mode 100644 index 0000000..acb1533 --- /dev/null +++ b/lib/widgets/widgets.dart @@ -0,0 +1,6 @@ +export 'hero_image_widget.dart'; +export 'rataurant_open_status.dart'; +export './rating_widget.dart'; +export './restaurant_details.dart'; +export './rating_and_open_status_widget.dart'; +export './restaurant_ratings_review_section.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 367b1df..f26a4a1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,6 +31,8 @@ dev_dependencies: flutter: generate: true uses-material-design: true + assets: + - assets/avatars/ fonts: - family: Lora fonts: From 13385b1f96619a8e1fb6b3270b0ba4cf722b10ed Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 18:06:30 -0300 Subject: [PATCH 08/30] Working on the favorites button and state management --- lib/cubit/restaurant_cubit.dart | 35 ++++++-- lib/cubit/restaurant_state.dart | 88 +++++++++++++++++-- lib/main.dart | 28 ++++-- lib/pages/home_page.dart | 25 +++--- lib/pages/pages.dart | 2 +- lib/pages/restaurant_detail_page.dart | 12 +-- ...ge_view.dart => restaurant_list_page.dart} | 10 +-- lib/theme/text.dart | 4 + lib/usecases/fetch_restaurants.dart | 7 ++ lib/widgets/appbar.dart | 39 ++++++++ .../restaurant_ratings_review_section.dart | 8 +- lib/widgets/widgets.dart | 1 + 12 files changed, 205 insertions(+), 54 deletions(-) rename lib/pages/{restaurant_list_page_view.dart => restaurant_list_page.dart} (93%) create mode 100644 lib/widgets/appbar.dart diff --git a/lib/cubit/restaurant_cubit.dart b/lib/cubit/restaurant_cubit.dart index e01a8bb..bdc19b8 100644 --- a/lib/cubit/restaurant_cubit.dart +++ b/lib/cubit/restaurant_cubit.dart @@ -1,6 +1,6 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:meta/meta.dart'; +import 'package:flutter/material.dart'; import 'package:restaurant_tour/models/restaurant.dart'; import '../usecases/fetch_restaurants.dart'; @@ -8,21 +8,46 @@ import '../usecases/fetch_restaurants.dart'; part 'restaurant_state.dart'; class RestaurantCubit extends Cubit { - RestaurantCubit(this.fetchRestaurantsUseCase) : super(RestaurantInitial()); + RestaurantCubit(this.fetchRestaurantsUseCase) + : super(const RestaurantInitial(favoriteRestaurants: [])); final FetchRestaurants fetchRestaurantsUseCase; + Future fetchRestaurants() async { - emit(LoadingRestaurantsState()); + emit(const LoadingRestaurantsState(favoriteRestaurants: [])); RestaurantQueryResult? result = await fetchRestaurantsUseCase.getRestaurantsFromCache(); + List favoriteRestaurants = + await fetchRestaurantsUseCase.getFavoriteRestaurants(); if (result != null) { - emit(RestaurantsLoadedState(result: result)); + emit( + RestaurantsLoadedState( + result: result, + favoriteRestaurants: favoriteRestaurants, + ), + ); } else { emit( - ErrorState( + const ErrorState( message: 'The server encountered a problem and we couldn\'t load the list.', + favoriteRestaurants: [], ), ); } } + + Future favoriteAResturant(String id) async { + final favoriteRestaurants = List.from(state.favoriteRestaurants); + if (favoriteRestaurants.contains(id)) { + favoriteRestaurants.remove(id); + } else { + favoriteRestaurants.add(id); + } + emit( + FavoriteRestaurantState( + result: state.result!, + favoriteRestaurants: List.of(favoriteRestaurants), + ), + ); + } } diff --git a/lib/cubit/restaurant_state.dart b/lib/cubit/restaurant_state.dart index dc4a5bd..c3b75ac 100644 --- a/lib/cubit/restaurant_state.dart +++ b/lib/cubit/restaurant_state.dart @@ -1,30 +1,104 @@ +// ignore_for_file: overridden_fields + part of 'restaurant_cubit.dart'; @immutable -abstract class RestaurantState extends Equatable {} +abstract class RestaurantState extends Equatable { + final List favoriteRestaurants; + final RestaurantQueryResult? result; + + const RestaurantState({ + required this.favoriteRestaurants, + this.result, + }); + + RestaurantState copyWith({List? favoriteRestaurants}); + @override + List get props => [favoriteRestaurants]; +} class RestaurantInitial extends RestaurantState { + const RestaurantInitial({required super.favoriteRestaurants}); + @override - List get props => []; + RestaurantState copyWith({List? favoriteRestaurants}) { + return RestaurantInitial( + favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants, + ); + } } class LoadingRestaurantsState extends RestaurantState { + const LoadingRestaurantsState({required super.favoriteRestaurants}); + + @override + List get props => [favoriteRestaurants]; + @override - List get props => []; + RestaurantState copyWith({List? favoriteRestaurants}) { + return LoadingRestaurantsState( + favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants, + ); + } } class RestaurantsLoadedState extends RestaurantState { + const RestaurantsLoadedState({ + required this.result, + required super.favoriteRestaurants, + }); + + @override final RestaurantQueryResult result; - RestaurantsLoadedState({required this.result}); @override - List get props => [result]; + List get props => [result, favoriteRestaurants]; + + @override + RestaurantsLoadedState copyWith({List? favoriteRestaurants}) { + return RestaurantsLoadedState( + favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants, + result: result, + ); + } +} + +class FavoriteRestaurantState extends RestaurantState { + @override + final RestaurantQueryResult result; + @override + final List favoriteRestaurants; + + const FavoriteRestaurantState({ + required this.result, + required this.favoriteRestaurants, + }) : super(favoriteRestaurants: favoriteRestaurants, result: result); + @override + List get props => [favoriteRestaurants]; + + @override + FavoriteRestaurantState copyWith({List? favoriteRestaurants}) { + return FavoriteRestaurantState( + favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants, + result: result, + ); + } } class ErrorState extends RestaurantState { final String message; - ErrorState({required this.message}); + const ErrorState({ + required super.favoriteRestaurants, + super.result, + required this.message, + }); + @override - List get props => []; + RestaurantState copyWith({List? favoriteRestaurants}) { + return ErrorState( + favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants, + message: message, + ); + } } diff --git a/lib/main.dart b/lib/main.dart index 4d39648..261e930 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,7 @@ -import 'package:dio/dio.dart'; +import 'dart:ffi'; + import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get_it/get_it.dart'; import 'package:restaurant_tour/cubit/cubit.dart'; import 'package:restaurant_tour/repositories/repositories.dart'; @@ -20,8 +22,8 @@ void setup() { getIt.registerSingleton( FetchRestaurants(repository: getIt()), ); - getIt.registerFactory( - () => RestaurantCubit(getIt()), + getIt.registerSingleton( + RestaurantCubit(getIt()), ); } @@ -30,12 +32,20 @@ class RestaurantTour extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Restaurant Tour', - home: const HomePageBlocProvider(), - theme: ThemeData( - fontFamily: 'Lora', - textTheme: ThemeText.textTheming, + return BlocProvider.value( + value: GetIt.instance()..fetchRestaurants(), + child: MaterialApp( + title: 'Restaurant Tour', + debugShowCheckedModeBanner: false, + home: const HomePage(), + theme: ThemeData( + fontFamily: 'Lora', + scaffoldBackgroundColor: const Color.fromARGB(255, 255, 255, 255), + appBarTheme: const AppBarTheme( + backgroundColor: Color.fromARGB(255, 255, 255, 255), + ), + textTheme: ThemeText.textTheming, + ), ), ); } diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 0d6c7da..944bfd5 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -1,21 +1,18 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:get_it/get_it.dart'; -import 'package:restaurant_tour/cubit/cubit.dart'; import 'package:restaurant_tour/pages/restaurant_list_page_view.dart'; -class HomePageBlocProvider extends StatelessWidget { - const HomePageBlocProvider({super.key}); +// class HomePageBlocProvider extends StatelessWidget { +// const HomePageBlocProvider({super.key}); - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => - GetIt.instance()..fetchRestaurants(), - child: const HomePage(), - ); - } -} +// @override +// Widget build(BuildContext context) { +// return BlocProvider( +// create: (context) => +// GetIt.instance()..fetchRestaurants(), +// child: const HomePage(), +// ); +// } +// } class HomePage extends StatelessWidget { const HomePage({super.key}); diff --git a/lib/pages/pages.dart b/lib/pages/pages.dart index 10b9593..9d6aaab 100644 --- a/lib/pages/pages.dart +++ b/lib/pages/pages.dart @@ -1,2 +1,2 @@ export 'home_page.dart'; -export './restaurant_list_page_view.dart'; +export 'restaurant_list_page.dart'; diff --git a/lib/pages/restaurant_detail_page.dart b/lib/pages/restaurant_detail_page.dart index 5166791..08181bd 100644 --- a/lib/pages/restaurant_detail_page.dart +++ b/lib/pages/restaurant_detail_page.dart @@ -1,11 +1,8 @@ import 'package:flutter/material.dart'; import 'package:restaurant_tour/models/restaurant.dart'; -import 'package:restaurant_tour/widgets/divider.dart'; import 'package:restaurant_tour/widgets/widgets.dart'; - -const spacingXL = 24.0; -const spacingM = 16.0; -const spacingSM = 8.0; +import '../theme/text.dart'; +import '../widgets/appbar.dart'; class RestaurantDetailPage extends StatelessWidget { const RestaurantDetailPage({super.key, required this.restaurant}); @@ -13,11 +10,10 @@ class RestaurantDetailPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text(restaurant.name ?? ''), + appBar: RestaurantDetailAppBar( + restaurant: restaurant, ), body: SafeArea( - // minimum: const EdgeInsets.all(16), child: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { return SingleChildScrollView( diff --git a/lib/pages/restaurant_list_page_view.dart b/lib/pages/restaurant_list_page.dart similarity index 93% rename from lib/pages/restaurant_list_page_view.dart rename to lib/pages/restaurant_list_page.dart index e0bb40a..2f4f453 100644 --- a/lib/pages/restaurant_list_page_view.dart +++ b/lib/pages/restaurant_list_page.dart @@ -2,10 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:restaurant_tour/cubit/cubit.dart'; import 'package:restaurant_tour/models/models.dart'; -import 'package:restaurant_tour/widgets/rataurant_open_status.dart'; -import 'package:restaurant_tour/widgets/rating_widget.dart'; - -import '../widgets/restaurant_details.dart'; import '../widgets/widgets.dart'; import 'restaurant_detail_page.dart'; @@ -17,6 +13,10 @@ class RestaurantListPageView extends StatelessWidget { return LayoutBuilder( builder: (context, constraints) { return BlocBuilder( + buildWhen: (previous, current) => + current is LoadingRestaurantsState || + current is RestaurantsLoadedState || + current is ErrorState, builder: (context, state) { if (state is LoadingRestaurantsState) { return const Center(child: CircularProgressIndicator()); @@ -31,7 +31,6 @@ class RestaurantListPageView extends StatelessWidget { itemBuilder: (BuildContext context, int index) { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - // crossAxisAlignment: CrossAxisAlignment.start, children: [ ListTile( restaurant: state.result.restaurants!.elementAt(index), @@ -58,6 +57,7 @@ class ListTile extends StatelessWidget { }); final Restaurant restaurant; final BoxConstraints constraints; + @override Widget build(BuildContext context) { return GestureDetector( diff --git a/lib/theme/text.dart b/lib/theme/text.dart index 9a6d4f8..9fe8350 100644 --- a/lib/theme/text.dart +++ b/lib/theme/text.dart @@ -28,3 +28,7 @@ class ThemeText { headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w700), ); } + +const spacingXL = 24.0; +const spacingM = 16.0; +const spacingSM = 8.0; diff --git a/lib/usecases/fetch_restaurants.dart b/lib/usecases/fetch_restaurants.dart index 251be6a..9120914 100644 --- a/lib/usecases/fetch_restaurants.dart +++ b/lib/usecases/fetch_restaurants.dart @@ -9,4 +9,11 @@ class FetchRestaurants { await repository.getRestaurants(); Future getRestaurantsFromCache() async => await repository.getRestaurantsFromCache(); + + Future> getFavoriteRestaurants() async { + //this could be fetched from anywhere later... a shared prefs or another database + await Future.delayed(const Duration(milliseconds: 500)); + + return ['vHz2RLtfUMVRPFmd7VBEHA']; + } } diff --git a/lib/widgets/appbar.dart b/lib/widgets/appbar.dart new file mode 100644 index 0000000..f32b220 --- /dev/null +++ b/lib/widgets/appbar.dart @@ -0,0 +1,39 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:restaurant_tour/cubit/restaurant_cubit.dart'; +import 'package:restaurant_tour/models/restaurant.dart'; + +class RestaurantDetailAppBar extends StatelessWidget + implements PreferredSizeWidget { + final Restaurant restaurant; + + const RestaurantDetailAppBar({super.key, required this.restaurant}); + + @override + Widget build(BuildContext context) { + final isFavorite = context + .watch() + .state + .favoriteRestaurants + .contains(restaurant.id); + return AppBar( + title: Text(restaurant.name ?? ''), + actions: [ + Padding( + padding: const EdgeInsets.only(right: 13.0), + child: IconButton( + icon: isFavorite + ? const Icon(Icons.favorite) + : const Icon(Icons.favorite_border_outlined), + onPressed: () => context + .read() + .favoriteAResturant(restaurant.id!), + ), + ), + ], + ); + } + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); +} diff --git a/lib/widgets/restaurant_ratings_review_section.dart b/lib/widgets/restaurant_ratings_review_section.dart index dfdd623..895752c 100644 --- a/lib/widgets/restaurant_ratings_review_section.dart +++ b/lib/widgets/restaurant_ratings_review_section.dart @@ -1,10 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:restaurant_tour/models/restaurant.dart'; +import 'package:restaurant_tour/models/models.dart'; +import 'package:restaurant_tour/theme/text.dart'; import 'package:restaurant_tour/utils/get_random_avatar.dart'; -import 'package:restaurant_tour/widgets/divider.dart'; -import 'package:restaurant_tour/widgets/rating_widget.dart'; - -import '../pages/restaurant_detail_page.dart'; +import 'package:restaurant_tour/widgets/widgets.dart'; import '../theme/colors.dart'; class BuildRatingSection extends StatelessWidget { diff --git a/lib/widgets/widgets.dart b/lib/widgets/widgets.dart index acb1533..6f30fb9 100644 --- a/lib/widgets/widgets.dart +++ b/lib/widgets/widgets.dart @@ -4,3 +4,4 @@ export './rating_widget.dart'; export './restaurant_details.dart'; export './rating_and_open_status_widget.dart'; export './restaurant_ratings_review_section.dart'; +export './divider.dart'; From 353bd47445c6778afdd1bff07148de99e7a75cbe Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 20:06:20 -0300 Subject: [PATCH 09/30] cleanup --- lib/main.dart | 2 -- lib/repositories/yelp_repository.dart | 8 ++------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 261e930..4da1374 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,3 @@ -import 'dart:ffi'; - import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get_it/get_it.dart'; diff --git a/lib/repositories/yelp_repository.dart b/lib/repositories/yelp_repository.dart index 45af280..edd76be 100644 --- a/lib/repositories/yelp_repository.dart +++ b/lib/repositories/yelp_repository.dart @@ -1,6 +1,3 @@ -import 'dart:convert'; -import 'dart:io'; - import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:restaurant_tour/models/restaurant.dart'; @@ -66,12 +63,11 @@ class YelpRepository { /// } /// /// - Future getRestaurantsFromCache( - {int offset = 0}) async { + RestaurantQueryResult getRestaurantsFromCache({int offset = 0}) { try { return RestaurantQueryResult.fromJson(sample['data']['search']); } catch (e) { - return null; + throw Exception(); } } From 13150f6d793dc2fa2c285ee4a9a8cc1a31266fa9 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 20:06:54 -0300 Subject: [PATCH 10/30] Widget testing... initial thoughts --- test/widget_loading_test.dart | 51 +++++++++++++++++++++++++++++++++++ test/widget_test.dart | 2 +- 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 test/widget_loading_test.dart diff --git a/test/widget_loading_test.dart b/test/widget_loading_test.dart new file mode 100644 index 0000000..8aaff27 --- /dev/null +++ b/test/widget_loading_test.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:get_it/get_it.dart'; +import 'package:restaurant_tour/cubit/cubit.dart'; +import 'package:restaurant_tour/main.dart'; +import 'package:restaurant_tour/models/restaurant.dart'; +import 'package:restaurant_tour/repositories/repositories.dart'; +import 'package:restaurant_tour/usecases/fetch_restaurants.dart'; + +class MockFetchRestaurants extends Mock implements FetchRestaurants {} + +class MockYelpRepository extends Mock implements YelpRepository {} + +void main() { + late FetchRestaurants mockFetchRestaurants; + late RestaurantCubit restaurantCubit; + + setUp(() { + final getIt = GetIt.instance; + getIt.reset(); + + mockFetchRestaurants = MockFetchRestaurants(); + restaurantCubit = RestaurantCubit(mockFetchRestaurants); + + getIt.registerSingleton(restaurantCubit); + }); + + testWidgets( + 'displays loading state and then loaded state with "All restaurants"', + (WidgetTester tester) async { + when(() => mockFetchRestaurants.getRestaurantsFromCache()).thenAnswer( + (_) async => YelpRepository().getRestaurantsFromCache(), + ); // Add relevant data + + when(() => mockFetchRestaurants.getFavoriteRestaurants()) + .thenAnswer((_) async => []); + + // Pump the widget tree + await tester.pumpWidget(const RestaurantTour()); + + // Expect the loading state + expect(find.byType(CircularProgressIndicator), findsOneWidget); + + // Allow the state to change + await tester.pump(); + + // Expect the "All restaurants" text to be found after loading + expect(find.text('RestauranTour'), findsOneWidget); + }); +} diff --git a/test/widget_test.dart b/test/widget_test.dart index b729d48..22f2ca9 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -14,6 +14,6 @@ void main() { await tester.pumpWidget(const RestaurantTour()); // Verify that tests will run - expect(find.text('Fetch Restaurants'), findsOneWidget); + expect(find.text('All restaurants'), findsOneWidget); }); } From 20574531f88284c1b969c2c2b244ff9944060b65 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 20:07:02 -0300 Subject: [PATCH 11/30] Create cubit_test.dart --- test/cubit/cubit_test.dart | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 test/cubit/cubit_test.dart diff --git a/test/cubit/cubit_test.dart b/test/cubit/cubit_test.dart new file mode 100644 index 0000000..a671b20 --- /dev/null +++ b/test/cubit/cubit_test.dart @@ -0,0 +1,92 @@ +import 'dart:io'; + +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get_it/get_it.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:restaurant_tour/cubit/cubit.dart'; +import 'package:restaurant_tour/pages/pages.dart'; +import 'package:restaurant_tour/repositories/repositories.dart'; +import 'package:restaurant_tour/usecases/usecases.dart'; +import 'package:restaurant_tour/widgets/widgets.dart'; + +// Mock classes +class MockRestaurantCubit extends MockCubit + implements RestaurantCubit {} + +class MockRestaurantState extends Fake implements RestaurantState {} + +class MockFetchRestaurantsUseCase extends Mock implements FetchRestaurants {} + +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} + +void main() { + late MockRestaurantCubit restaurantCubit; + late MockFetchRestaurantsUseCase mockFetchRestaurantsUseCase; + + group('Load Restaurants State successfully', () { + setUp(() { + HttpOverrides.global = MyHttpOverrides(); + + registerFallbackValue(MockRestaurantState()); + + mockFetchRestaurantsUseCase = MockFetchRestaurantsUseCase(); + + restaurantCubit = MockRestaurantCubit(); + + // GetIt.I.registerFactory( + // () => RestaurantCubit(mockFetchRestaurantsUseCase), + // ); + }); + + tearDown(() { + // GetIt.I.reset(); + }); + + testWidgets('Display loading State', (tester) async { + when(() => restaurantCubit.state) + .thenReturn(const LoadingRestaurantsState(favoriteRestaurants: [])); + + await tester.pumpWidget( + MaterialApp( + home: BlocProvider.value( + value: restaurantCubit, + child: const HomePage(), + ), + ), + ); + + expect(find.byType(CircularProgressIndicator), findsOneWidget); + }); + + testWidgets('Display List View State', (tester) async { + var fakeData = YelpRepository().getRestaurantsFromCache(); + when(() => restaurantCubit.state).thenReturn( + RestaurantsLoadedState(favoriteRestaurants: [], result: fakeData), + ); + await tester.runAsync(() async { + await tester.pumpWidget( + MaterialApp( + home: BlocProvider.value( + value: restaurantCubit, + child: const HomePage(), + ), + ), + ); + await tester.pumpAndSettle(); + }); + + expect(find.byType(HeroImageWidget), findsAny); + }); + }); +} From efeaadb110146e5d1010ad2bb122647e84d8c649 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 20:07:15 -0300 Subject: [PATCH 12/30] dependencies updated --- pubspec.lock | 102 +++++++++++++++++++++++++++++++++++++++++++++++++-- pubspec.yaml | 3 ++ 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 25ba7d5..5033c47 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -41,6 +41,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.4" + bloc_test: + dependency: "direct dev" + description: + name: bloc_test + sha256: "165a6ec950d9252ebe36dc5335f2e6eb13055f33d56db0eeb7642768849b43d2" + url: "https://pub.dev" + source: hosted + version: "9.1.7" boolean_selector: dependency: transitive description: @@ -169,6 +177,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "3945034e86ea203af7a056d98e98e42a5518fff200d6e8e6647e1886b07e936e" + url: "https://pub.dev" + source: hosted + version: "1.8.0" crypto: dependency: transitive description: @@ -185,6 +201,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + diff_match_patch: + dependency: transitive + description: + name: diff_match_patch + sha256: "2efc9e6e8f449d0abe15be240e2c2a3bcd977c8d126cfd70598aee60af35c0a4" + url: "https://pub.dev" + source: hosted + version: "0.4.1" dio: dependency: "direct main" description: @@ -300,7 +324,7 @@ packages: source: hosted version: "2.3.1" http: - dependency: transitive + dependency: "direct dev" description: name: http sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 @@ -335,10 +359,10 @@ packages: dependency: transitive description: name: js - sha256: d9bdfd70d828eeb352390f81b18d6a354ef2044aa28ef25682079797fa7cd174 + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf url: "https://pub.dev" source: hosted - version: "0.6.3" + version: "0.7.1" json_annotation: dependency: "direct main" description: @@ -427,6 +451,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + mocktail: + dependency: "direct dev" + description: + name: mocktail + sha256: "890df3f9688106f25755f26b1c60589a92b3ab91a22b8b224947ad041bf172d8" + url: "https://pub.dev" + source: hosted + version: "1.0.4" nested: dependency: transitive description: @@ -435,6 +467,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" package_config: dependency: transitive description: @@ -507,6 +547,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" shelf_web_socket: dependency: transitive description: @@ -536,6 +592,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.4" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" source_span: dependency: transitive description: @@ -584,6 +656,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.1" + test: + dependency: transitive + description: + name: test + sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073" + url: "https://pub.dev" + source: hosted + version: "1.25.2" test_api: dependency: transitive description: @@ -592,6 +672,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.0" + test_core: + dependency: transitive + description: + name: test_core + sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4" + url: "https://pub.dev" + source: hosted + version: "0.6.0" timing: dependency: transitive description: @@ -672,6 +760,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" xml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f26a4a1..e943694 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,9 @@ dev_dependencies: flutter_lints: ^4.0.0 build_runner: ^2.4.10 json_serializable: ^6.8.0 + mocktail: ^1.0.4 + bloc_test: ^9.1.7 + http: ^1.2.2 flutter: generate: true From 679af7f81526136c318de5381d97c91c9deb47b4 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 20:49:32 -0300 Subject: [PATCH 13/30] Update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 1be2d87..288c22a 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,5 @@ app.*.map.json /android/app/release # fvm -.fvm/flutter_sdk \ No newline at end of file +.fvm/flutter_sdk +.env \ No newline at end of file From 5b03cfb0696d888622dc23e1899d51dc47bf01a0 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 22:27:23 -0300 Subject: [PATCH 14/30] favorites page view --- .gitignore | 4 ++- lib/main.dart | 6 +++- lib/pages/favorites_list_page_view.dart | 47 +++++++++++++++++++++++++ lib/pages/home_page.dart | 5 +-- lib/pages/restaurant_list_page.dart | 13 +++---- lib/repositories/yelp_repository.dart | 7 ++-- lib/usecases/fetch_restaurants.dart | 4 +-- 7 files changed, 70 insertions(+), 16 deletions(-) create mode 100644 lib/pages/favorites_list_page_view.dart diff --git a/.gitignore b/.gitignore index 288c22a..bed6da6 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,6 @@ app.*.map.json # fvm .fvm/flutter_sdk -.env \ No newline at end of file +.env +*.env +env.dart \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 4da1374..118706b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:get_it/get_it.dart'; import 'package:restaurant_tour/cubit/cubit.dart'; import 'package:restaurant_tour/repositories/repositories.dart'; @@ -7,8 +8,11 @@ import 'package:restaurant_tour/theme/text.dart'; import 'pages/home_page.dart'; import 'usecases/fetch_restaurants.dart'; -void main() { +Future main() async { setup(); + WidgetsFlutterBinding.ensureInitialized(); + + // await dotenv.load(); runApp(const RestaurantTour()); } diff --git a/lib/pages/favorites_list_page_view.dart b/lib/pages/favorites_list_page_view.dart new file mode 100644 index 0000000..9d24606 --- /dev/null +++ b/lib/pages/favorites_list_page_view.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:restaurant_tour/cubit/cubit.dart'; +import 'package:restaurant_tour/models/restaurant.dart'; +import 'package:restaurant_tour/pages/restaurant_list_page.dart'; + +class FavoritesListPageView extends StatelessWidget { + const FavoritesListPageView({super.key}); + // final List restaurants; + @override + Widget build(BuildContext context) { + return Scaffold(body: BlocBuilder( + builder: (context, state) { + if (state is LoadingRestaurantsState) { + return const Center(child: CircularProgressIndicator()); + } + if (state is RestaurantsLoadedState || + state is FavoriteRestaurantState) { + return LayoutBuilder( + builder: (context, constraints) { + List favoritesList = state.result!.restaurants! + .where( + (element) => state.favoriteRestaurants.contains(element.id), + ) + .toList(); + return ListView.builder( + itemCount: favoritesList.length, + itemBuilder: (BuildContext context, int index) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + RestaurantListTile( + restaurant: favoritesList.elementAt(index), + constraints: constraints, + ), + ], + ); + }, + ); + }, + ); + } + return Container(); + }, + )); + } +} diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index 944bfd5..d9ad952 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:restaurant_tour/pages/restaurant_list_page_view.dart'; +import 'package:restaurant_tour/pages/favorites_list_page_view.dart'; +import 'package:restaurant_tour/pages/restaurant_list_page.dart'; // class HomePageBlocProvider extends StatelessWidget { // const HomePageBlocProvider({super.key}); @@ -62,7 +63,7 @@ class HomePage extends StatelessWidget { child: TabBarView( children: [ RestaurantListPageView(), - Text('Dias'), + FavoritesListPageView(), ], ), ), diff --git a/lib/pages/restaurant_list_page.dart b/lib/pages/restaurant_list_page.dart index 2f4f453..6a0f6c9 100644 --- a/lib/pages/restaurant_list_page.dart +++ b/lib/pages/restaurant_list_page.dart @@ -25,15 +25,16 @@ class RestaurantListPageView extends StatelessWidget { child: Text(state.message), ); } - if (state is RestaurantsLoadedState) { + if (state is RestaurantsLoadedState || + state is FavoriteRestaurantState) { return ListView.builder( - itemCount: state.result.restaurants?.length, + itemCount: state.result!.restaurants?.length, itemBuilder: (BuildContext context, int index) { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - ListTile( - restaurant: state.result.restaurants!.elementAt(index), + RestaurantListTile( + restaurant: state.result!.restaurants!.elementAt(index), constraints: constraints, ), ], @@ -49,8 +50,8 @@ class RestaurantListPageView extends StatelessWidget { } } -class ListTile extends StatelessWidget { - const ListTile({ +class RestaurantListTile extends StatelessWidget { + const RestaurantListTile({ super.key, required this.restaurant, required this.constraints, diff --git a/lib/repositories/yelp_repository.dart b/lib/repositories/yelp_repository.dart index edd76be..4f78775 100644 --- a/lib/repositories/yelp_repository.dart +++ b/lib/repositories/yelp_repository.dart @@ -1,11 +1,10 @@ import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:restaurant_tour/env.dart'; import 'package:restaurant_tour/models/restaurant.dart'; import 'package:restaurant_tour/repositories/sample_json.dart'; -const _apiKey = - 'GzcIFZrKe4aMmED9FS9ObPxFP4vAhEOW2wN9usDA0zazBimbxQ8O2LdcpwMUcpkCU1ZYxF-LK_jWygZgGvfeE_5jSulY1XdUPs09j1FCwDtXQmyD_emQYuOEMBHKZnYx'; - class YelpRepository { late Dio dio; @@ -16,7 +15,7 @@ class YelpRepository { BaseOptions( baseUrl: 'https://api.yelp.com', headers: { - 'Authorization': 'Bearer $_apiKey', + 'Authorization': 'Bearer $API_KEY', 'Content-Type': 'application/graphql', }, ), diff --git a/lib/usecases/fetch_restaurants.dart b/lib/usecases/fetch_restaurants.dart index 9120914..1ba1e22 100644 --- a/lib/usecases/fetch_restaurants.dart +++ b/lib/usecases/fetch_restaurants.dart @@ -5,8 +5,8 @@ class FetchRestaurants { final YelpRepository repository; FetchRestaurants({required this.repository}); - Future getRestaurants() async => - await repository.getRestaurants(); + Future getRestaurants() async => await repository + .getRestaurantsFromCache(); //CHANGE THIS LATER TO FETCH FROM THE REAL API Future getRestaurantsFromCache() async => await repository.getRestaurantsFromCache(); From 74bb259a88452f54cc23921a5b85174bfae74bf0 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 22:27:31 -0300 Subject: [PATCH 15/30] Update restaurant_cubit.dart --- lib/cubit/restaurant_cubit.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cubit/restaurant_cubit.dart b/lib/cubit/restaurant_cubit.dart index bdc19b8..72f358a 100644 --- a/lib/cubit/restaurant_cubit.dart +++ b/lib/cubit/restaurant_cubit.dart @@ -15,7 +15,7 @@ class RestaurantCubit extends Cubit { Future fetchRestaurants() async { emit(const LoadingRestaurantsState(favoriteRestaurants: [])); RestaurantQueryResult? result = - await fetchRestaurantsUseCase.getRestaurantsFromCache(); + await fetchRestaurantsUseCase.getRestaurants(); List favoriteRestaurants = await fetchRestaurantsUseCase.getFavoriteRestaurants(); if (result != null) { From 55068540c50715a2cb6995ed48fcd8411209d021 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 22:30:45 -0300 Subject: [PATCH 16/30] coverage report --- coverage/lcov.info | 458 +++++++ coverage_report/amber.png | Bin 0 -> 141 bytes coverage_report/cmd_line | 1 + coverage_report/cubit/index-sort-f.html | 117 ++ coverage_report/cubit/index-sort-l.html | 117 ++ coverage_report/cubit/index.html | 117 ++ .../cubit/restaurant_cubit.dart.func-c.html | 75 ++ .../cubit/restaurant_cubit.dart.func.html | 75 ++ .../cubit/restaurant_cubit.dart.gcov.html | 129 ++ .../cubit/restaurant_state.dart.func-c.html | 75 ++ .../cubit/restaurant_state.dart.func.html | 75 ++ .../cubit/restaurant_state.dart.gcov.html | 180 +++ coverage_report/emerald.png | Bin 0 -> 141 bytes coverage_report/gcov.css | 1101 +++++++++++++++++ coverage_report/glass.png | Bin 0 -> 167 bytes coverage_report/index-sort-f.html | 177 +++ coverage_report/index-sort-l.html | 177 +++ coverage_report/index.html | 177 +++ coverage_report/models/index-sort-f.html | 117 ++ coverage_report/models/index-sort-l.html | 117 ++ coverage_report/models/index.html | 117 ++ .../models/restaurant.dart.func-c.html | 75 ++ .../models/restaurant.dart.func.html | 75 ++ .../models/restaurant.dart.gcov.html | 233 ++++ .../models/restaurant.g.dart.func-c.html | 75 ++ .../models/restaurant.g.dart.func.html | 75 ++ .../models/restaurant.g.dart.gcov.html | 185 +++ .../pages/home_page.dart.func-c.html | 75 ++ .../pages/home_page.dart.func.html | 75 ++ .../pages/home_page.dart.gcov.html | 148 +++ coverage_report/pages/index-sort-f.html | 129 ++ coverage_report/pages/index-sort-l.html | 129 ++ coverage_report/pages/index.html | 129 ++ .../restaurant_detail_page.dart.func-c.html | 75 ++ .../restaurant_detail_page.dart.func.html | 75 ++ .../restaurant_detail_page.dart.gcov.html | 177 +++ .../restaurant_list_page.dart.func-c.html | 75 ++ .../pages/restaurant_list_page.dart.func.html | 75 ++ .../pages/restaurant_list_page.dart.gcov.html | 205 +++ .../repositories/index-sort-f.html | 105 ++ .../repositories/index-sort-l.html | 105 ++ coverage_report/repositories/index.html | 105 ++ .../yelp_repository.dart.func-c.html | 75 ++ .../yelp_repository.dart.func.html | 75 ++ .../yelp_repository.dart.gcov.html | 199 +++ coverage_report/ruby.png | Bin 0 -> 141 bytes coverage_report/snow.png | Bin 0 -> 141 bytes coverage_report/updown.png | Bin 0 -> 117 bytes .../fetch_restaurants.dart.func-c.html | 75 ++ .../usecases/fetch_restaurants.dart.func.html | 75 ++ .../usecases/fetch_restaurants.dart.gcov.html | 95 ++ coverage_report/usecases/index-sort-f.html | 105 ++ coverage_report/usecases/index-sort-l.html | 105 ++ coverage_report/usecases/index.html | 105 ++ .../utils/get_random_avatar.dart.func-c.html | 75 ++ .../utils/get_random_avatar.dart.func.html | 75 ++ .../utils/get_random_avatar.dart.gcov.html | 97 ++ coverage_report/utils/index-sort-f.html | 105 ++ coverage_report/utils/index-sort-l.html | 105 ++ coverage_report/utils/index.html | 105 ++ .../widgets/appbar.dart.func-c.html | 75 ++ coverage_report/widgets/appbar.dart.func.html | 75 ++ coverage_report/widgets/appbar.dart.gcov.html | 115 ++ .../widgets/divider.dart.func-c.html | 75 ++ .../widgets/divider.dart.func.html | 75 ++ .../widgets/divider.dart.gcov.html | 83 ++ .../hero_image_widget.dart.func-c.html | 75 ++ .../widgets/hero_image_widget.dart.func.html | 75 ++ .../widgets/hero_image_widget.dart.gcov.html | 107 ++ coverage_report/widgets/index-sort-f.html | 189 +++ coverage_report/widgets/index-sort-l.html | 189 +++ coverage_report/widgets/index.html | 189 +++ .../rataurant_open_status.dart.func-c.html | 75 ++ .../rataurant_open_status.dart.func.html | 75 ++ .../rataurant_open_status.dart.gcov.html | 102 ++ ...ng_and_open_status_widget.dart.func-c.html | 75 ++ ...ting_and_open_status_widget.dart.func.html | 75 ++ ...ting_and_open_status_widget.dart.gcov.html | 105 ++ .../widgets/rating_widget.dart.func-c.html | 75 ++ .../widgets/rating_widget.dart.func.html | 75 ++ .../widgets/rating_widget.dart.gcov.html | 106 ++ .../restaurant_details.dart.func-c.html | 75 ++ .../widgets/restaurant_details.dart.func.html | 75 ++ .../widgets/restaurant_details.dart.gcov.html | 110 ++ ...nt_ratings_review_section.dart.func-c.html | 75 ++ ...rant_ratings_review_section.dart.func.html | 75 ++ ...rant_ratings_review_section.dart.gcov.html | 188 +++ 87 files changed, 9956 insertions(+) create mode 100644 coverage/lcov.info create mode 100644 coverage_report/amber.png create mode 100644 coverage_report/cmd_line create mode 100644 coverage_report/cubit/index-sort-f.html create mode 100644 coverage_report/cubit/index-sort-l.html create mode 100644 coverage_report/cubit/index.html create mode 100644 coverage_report/cubit/restaurant_cubit.dart.func-c.html create mode 100644 coverage_report/cubit/restaurant_cubit.dart.func.html create mode 100644 coverage_report/cubit/restaurant_cubit.dart.gcov.html create mode 100644 coverage_report/cubit/restaurant_state.dart.func-c.html create mode 100644 coverage_report/cubit/restaurant_state.dart.func.html create mode 100644 coverage_report/cubit/restaurant_state.dart.gcov.html create mode 100644 coverage_report/emerald.png create mode 100644 coverage_report/gcov.css create mode 100644 coverage_report/glass.png create mode 100644 coverage_report/index-sort-f.html create mode 100644 coverage_report/index-sort-l.html create mode 100644 coverage_report/index.html create mode 100644 coverage_report/models/index-sort-f.html create mode 100644 coverage_report/models/index-sort-l.html create mode 100644 coverage_report/models/index.html create mode 100644 coverage_report/models/restaurant.dart.func-c.html create mode 100644 coverage_report/models/restaurant.dart.func.html create mode 100644 coverage_report/models/restaurant.dart.gcov.html create mode 100644 coverage_report/models/restaurant.g.dart.func-c.html create mode 100644 coverage_report/models/restaurant.g.dart.func.html create mode 100644 coverage_report/models/restaurant.g.dart.gcov.html create mode 100644 coverage_report/pages/home_page.dart.func-c.html create mode 100644 coverage_report/pages/home_page.dart.func.html create mode 100644 coverage_report/pages/home_page.dart.gcov.html create mode 100644 coverage_report/pages/index-sort-f.html create mode 100644 coverage_report/pages/index-sort-l.html create mode 100644 coverage_report/pages/index.html create mode 100644 coverage_report/pages/restaurant_detail_page.dart.func-c.html create mode 100644 coverage_report/pages/restaurant_detail_page.dart.func.html create mode 100644 coverage_report/pages/restaurant_detail_page.dart.gcov.html create mode 100644 coverage_report/pages/restaurant_list_page.dart.func-c.html create mode 100644 coverage_report/pages/restaurant_list_page.dart.func.html create mode 100644 coverage_report/pages/restaurant_list_page.dart.gcov.html create mode 100644 coverage_report/repositories/index-sort-f.html create mode 100644 coverage_report/repositories/index-sort-l.html create mode 100644 coverage_report/repositories/index.html create mode 100644 coverage_report/repositories/yelp_repository.dart.func-c.html create mode 100644 coverage_report/repositories/yelp_repository.dart.func.html create mode 100644 coverage_report/repositories/yelp_repository.dart.gcov.html create mode 100644 coverage_report/ruby.png create mode 100644 coverage_report/snow.png create mode 100644 coverage_report/updown.png create mode 100644 coverage_report/usecases/fetch_restaurants.dart.func-c.html create mode 100644 coverage_report/usecases/fetch_restaurants.dart.func.html create mode 100644 coverage_report/usecases/fetch_restaurants.dart.gcov.html create mode 100644 coverage_report/usecases/index-sort-f.html create mode 100644 coverage_report/usecases/index-sort-l.html create mode 100644 coverage_report/usecases/index.html create mode 100644 coverage_report/utils/get_random_avatar.dart.func-c.html create mode 100644 coverage_report/utils/get_random_avatar.dart.func.html create mode 100644 coverage_report/utils/get_random_avatar.dart.gcov.html create mode 100644 coverage_report/utils/index-sort-f.html create mode 100644 coverage_report/utils/index-sort-l.html create mode 100644 coverage_report/utils/index.html create mode 100644 coverage_report/widgets/appbar.dart.func-c.html create mode 100644 coverage_report/widgets/appbar.dart.func.html create mode 100644 coverage_report/widgets/appbar.dart.gcov.html create mode 100644 coverage_report/widgets/divider.dart.func-c.html create mode 100644 coverage_report/widgets/divider.dart.func.html create mode 100644 coverage_report/widgets/divider.dart.gcov.html create mode 100644 coverage_report/widgets/hero_image_widget.dart.func-c.html create mode 100644 coverage_report/widgets/hero_image_widget.dart.func.html create mode 100644 coverage_report/widgets/hero_image_widget.dart.gcov.html create mode 100644 coverage_report/widgets/index-sort-f.html create mode 100644 coverage_report/widgets/index-sort-l.html create mode 100644 coverage_report/widgets/index.html create mode 100644 coverage_report/widgets/rataurant_open_status.dart.func-c.html create mode 100644 coverage_report/widgets/rataurant_open_status.dart.func.html create mode 100644 coverage_report/widgets/rataurant_open_status.dart.gcov.html create mode 100644 coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html create mode 100644 coverage_report/widgets/rating_and_open_status_widget.dart.func.html create mode 100644 coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html create mode 100644 coverage_report/widgets/rating_widget.dart.func-c.html create mode 100644 coverage_report/widgets/rating_widget.dart.func.html create mode 100644 coverage_report/widgets/rating_widget.dart.gcov.html create mode 100644 coverage_report/widgets/restaurant_details.dart.func-c.html create mode 100644 coverage_report/widgets/restaurant_details.dart.func.html create mode 100644 coverage_report/widgets/restaurant_details.dart.gcov.html create mode 100644 coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html create mode 100644 coverage_report/widgets/restaurant_ratings_review_section.dart.func.html create mode 100644 coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html diff --git a/coverage/lcov.info b/coverage/lcov.info new file mode 100644 index 0000000..3e9b1c8 --- /dev/null +++ b/coverage/lcov.info @@ -0,0 +1,458 @@ +SF:lib/cubit/restaurant_state.dart +DA:10,6 +DA:16,1 +DA:17,2 +DA:21,2 +DA:23,0 +DA:25,0 +DA:26,0 +DA:32,4 +DA:34,1 +DA:35,2 +DA:37,0 +DA:39,0 +DA:40,0 +DA:46,2 +DA:54,1 +DA:55,3 +DA:57,0 +DA:59,0 +DA:60,0 +DA:61,0 +DA:72,1 +DA:75,1 +DA:76,1 +DA:77,2 +DA:79,0 +DA:81,0 +DA:82,0 +DA:83,0 +DA:91,3 +DA:97,0 +DA:99,0 +DA:100,0 +DA:101,0 +LF:33 +LH:15 +end_of_record +SF:lib/cubit/restaurant_cubit.dart +DA:11,1 +DA:12,1 +DA:15,1 +DA:16,1 +DA:18,2 +DA:20,2 +DA:22,1 +DA:23,1 +DA:29,1 +DA:39,1 +DA:40,3 +DA:41,1 +DA:42,1 +DA:44,0 +DA:46,1 +DA:47,1 +DA:48,2 +DA:49,1 +LF:18 +LH:17 +end_of_record +SF:lib/models/restaurant.dart +DA:10,1 +DA:15,1 +DA:16,1 +DA:18,0 +DA:26,1 +DA:30,2 +DA:32,0 +DA:42,1 +DA:48,2 +DA:50,0 +DA:60,1 +DA:67,2 +DA:69,0 +DA:77,1 +DA:81,1 +DA:82,1 +DA:84,0 +DA:99,1 +DA:111,1 +DA:112,1 +DA:114,0 +DA:117,0 +DA:118,0 +DA:119,0 +DA:125,1 +DA:126,3 +DA:127,2 +DA:134,1 +DA:135,3 +DA:136,3 +DA:148,1 +DA:153,1 +DA:154,1 +DA:156,0 +LF:34 +LH:24 +end_of_record +SF:lib/models/restaurant.g.dart +DA:9,2 +DA:10,1 +DA:11,1 +DA:14,0 +DA:15,0 +DA:16,0 +DA:19,2 +DA:20,1 +DA:23,0 +DA:24,0 +DA:27,2 +DA:28,1 +DA:29,1 +DA:30,1 +DA:33,0 +DA:34,0 +DA:35,0 +DA:36,0 +DA:39,2 +DA:40,1 +DA:41,1 +DA:42,1 +DA:44,2 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:53,2 +DA:54,1 +DA:57,0 +DA:58,0 +DA:61,2 +DA:62,1 +DA:63,1 +DA:64,1 +DA:65,2 +DA:67,4 +DA:68,1 +DA:69,3 +DA:70,1 +DA:71,1 +DA:72,3 +DA:73,1 +DA:74,1 +DA:75,3 +DA:76,1 +DA:77,1 +DA:79,2 +DA:82,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:92,0 +DA:95,1 +DA:97,1 +DA:98,1 +DA:99,1 +DA:100,3 +DA:101,1 +DA:104,0 +DA:106,0 +DA:107,0 +DA:108,0 +LF:69 +LH:39 +end_of_record +SF:lib/usecases/fetch_restaurants.dart +DA:7,0 +DA:8,0 +DA:9,0 +DA:10,0 +DA:11,0 +DA:13,0 +DA:15,0 +DA:17,0 +LF:8 +LH:0 +end_of_record +SF:lib/repositories/yelp_repository.dart +DA:12,1 +DA:15,1 +DA:16,1 +DA:18,1 +DA:66,1 +DA:68,3 +DA:70,0 +DA:74,0 +DA:76,0 +DA:78,0 +DA:81,0 +DA:87,0 +DA:121,0 +LF:13 +LH:6 +end_of_record +SF:lib/pages/home_page.dart +DA:18,1 +DA:20,1 +DA:22,1 +DA:24,1 +DA:25,1 +DA:26,1 +DA:28,3 +DA:30,1 +DA:43,1 +DA:44,1 +DA:45,1 +DA:46,1 +DA:48,3 +DA:51,1 +DA:52,1 +DA:54,3 +LF:16 +LH:16 +end_of_record +SF:lib/pages/restaurant_list_page.dart +DA:9,1 +DA:11,1 +DA:13,1 +DA:14,1 +DA:15,1 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,1 +DA:21,1 +DA:23,1 +DA:24,0 +DA:25,0 +DA:28,1 +DA:29,1 +DA:30,3 +DA:31,1 +DA:32,1 +DA:34,1 +DA:35,1 +DA:36,3 +DA:44,0 +DA:53,1 +DA:61,1 +DA:63,1 +DA:64,0 +DA:65,0 +DA:67,0 +DA:68,0 +DA:72,1 +DA:73,2 +DA:76,1 +DA:78,2 +DA:79,1 +DA:80,1 +DA:81,1 +DA:82,1 +DA:88,1 +DA:89,1 +DA:90,1 +DA:91,1 +DA:92,1 +DA:93,1 +DA:103,1 +DA:105,1 +DA:108,1 +DA:109,1 +DA:110,2 +DA:116,2 +DA:120,2 +LF:51 +LH:40 +end_of_record +SF:lib/pages/restaurant_detail_page.dart +DA:8,0 +DA:10,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:24,0 +DA:25,0 +DA:27,0 +DA:29,0 +DA:32,0 +DA:33,0 +DA:37,0 +DA:41,0 +DA:43,0 +DA:49,0 +DA:50,0 +DA:52,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:60,0 +DA:62,0 +DA:77,0 +DA:84,0 +DA:86,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:95,0 +DA:96,0 +LF:39 +LH:0 +end_of_record +SF:lib/widgets/appbar.dart +DA:10,0 +DA:12,0 +DA:15,0 +DA:16,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:24,0 +DA:28,0 +DA:29,0 +DA:30,0 +DA:37,0 +LF:15 +LH:0 +end_of_record +SF:lib/utils/get_random_avatar.dart +DA:4,0 +DA:6,0 +DA:17,0 +DA:20,0 +LF:4 +LH:0 +end_of_record +SF:lib/widgets/divider.dart +DA:3,0 +LF:1 +LH:0 +end_of_record +SF:lib/widgets/hero_image_widget.dart +DA:6,1 +DA:16,1 +DA:18,1 +DA:19,3 +DA:20,1 +DA:21,2 +DA:22,1 +DA:23,2 +DA:25,1 +DA:26,1 +LF:10 +LH:10 +end_of_record +SF:lib/widgets/rataurant_open_status.dart +DA:4,1 +DA:6,1 +DA:8,1 +DA:10,1 +DA:11,1 +DA:12,1 +DA:13,3 +DA:18,1 +DA:21,1 +LF:9 +LH:9 +end_of_record +SF:lib/widgets/rating_and_open_status_widget.dart +DA:8,1 +DA:15,1 +DA:17,1 +DA:18,1 +DA:19,1 +DA:20,3 +DA:23,1 +DA:24,2 +LF:8 +LH:8 +end_of_record +SF:lib/widgets/rating_widget.dart +DA:10,1 +DA:15,3 +DA:17,1 +DA:19,1 +DA:21,3 +DA:22,1 +DA:24,1 +DA:25,1 +LF:8 +LH:8 +end_of_record +SF:lib/widgets/restaurant_details.dart +DA:5,1 +DA:12,1 +DA:14,1 +DA:15,1 +DA:16,1 +DA:17,2 +DA:18,3 +DA:23,1 +DA:24,1 +DA:25,6 +DA:26,3 +LF:11 +LH:11 +end_of_record +SF:lib/widgets/restaurant_ratings_review_section.dart +DA:9,0 +DA:12,0 +DA:14,0 +DA:16,0 +DA:17,0 +DA:19,0 +DA:24,0 +DA:28,0 +DA:32,0 +DA:33,0 +DA:34,0 +DA:39,0 +DA:42,0 +DA:43,0 +DA:44,0 +DA:45,0 +DA:47,0 +DA:51,0 +DA:52,0 +DA:57,0 +DA:58,0 +DA:60,0 +DA:61,0 +DA:62,0 +DA:65,0 +DA:69,0 +DA:70,0 +DA:71,0 +DA:73,0 +DA:74,0 +DA:75,0 +DA:80,0 +DA:86,0 +DA:95,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:100,0 +LF:39 +LH:0 +end_of_record diff --git a/coverage_report/amber.png b/coverage_report/amber.png new file mode 100644 index 0000000000000000000000000000000000000000..2cab170d8359081983a4e343848dfe06bc490f12 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^G2tW}LqE04T&+ z;1OBOz`!j8!i<;h*8KqrvZOouIx;Y9?C1WI$O`1M1^9%x{(levWG + + + + + + LCOV - lcov.info - cubit + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cubitCoverageTotalHit
Test:lcov.infoLines:62.7 %5132
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
restaurant_cubit.dart +
94.4%94.4%
+
94.4 %1817-
restaurant_state.dart +
45.5%45.5%
+
45.5 %3315-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/cubit/index-sort-l.html b/coverage_report/cubit/index-sort-l.html new file mode 100644 index 0000000..93dfeaf --- /dev/null +++ b/coverage_report/cubit/index-sort-l.html @@ -0,0 +1,117 @@ + + + + + + + LCOV - lcov.info - cubit + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cubitCoverageTotalHit
Test:lcov.infoLines:62.7 %5132
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
restaurant_state.dart +
45.5%45.5%
+
45.5 %3315-
restaurant_cubit.dart +
94.4%94.4%
+
94.4 %1817-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/cubit/index.html b/coverage_report/cubit/index.html new file mode 100644 index 0000000..57ea65a --- /dev/null +++ b/coverage_report/cubit/index.html @@ -0,0 +1,117 @@ + + + + + + + LCOV - lcov.info - cubit + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cubitCoverageTotalHit
Test:lcov.infoLines:62.7 %5132
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
restaurant_cubit.dart +
94.4%94.4%
+
94.4 %1817-
restaurant_state.dart +
45.5%45.5%
+
45.5 %3315-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/cubit/restaurant_cubit.dart.func-c.html b/coverage_report/cubit/restaurant_cubit.dart.func-c.html new file mode 100644 index 0000000..9f65524 --- /dev/null +++ b/coverage_report/cubit/restaurant_cubit.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - cubit/restaurant_cubit.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cubit - restaurant_cubit.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:94.4 %1817
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/cubit/restaurant_cubit.dart.func.html b/coverage_report/cubit/restaurant_cubit.dart.func.html new file mode 100644 index 0000000..164b318 --- /dev/null +++ b/coverage_report/cubit/restaurant_cubit.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - cubit/restaurant_cubit.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cubit - restaurant_cubit.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:94.4 %1817
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/cubit/restaurant_cubit.dart.gcov.html b/coverage_report/cubit/restaurant_cubit.dart.gcov.html new file mode 100644 index 0000000..0914007 --- /dev/null +++ b/coverage_report/cubit/restaurant_cubit.dart.gcov.html @@ -0,0 +1,129 @@ + + + + + + + LCOV - lcov.info - cubit/restaurant_cubit.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cubit - restaurant_cubit.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:94.4 %1817
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:bloc/bloc.dart';
+       2              : import 'package:equatable/equatable.dart';
+       3              : import 'package:flutter/material.dart';
+       4              : import 'package:restaurant_tour/models/restaurant.dart';
+       5              : 
+       6              : import '../usecases/fetch_restaurants.dart';
+       7              : 
+       8              : part 'restaurant_state.dart';
+       9              : 
+      10              : class RestaurantCubit extends Cubit<RestaurantState> {
+      11            1 :   RestaurantCubit(this.fetchRestaurantsUseCase)
+      12            1 :       : super(const RestaurantInitial(favoriteRestaurants: []));
+      13              :   final FetchRestaurants fetchRestaurantsUseCase;
+      14              : 
+      15            1 :   Future<void> fetchRestaurants() async {
+      16            1 :     emit(const LoadingRestaurantsState(favoriteRestaurants: []));
+      17              :     RestaurantQueryResult? result =
+      18            2 :         await fetchRestaurantsUseCase.getRestaurants();
+      19              :     List<String> favoriteRestaurants =
+      20            2 :         await fetchRestaurantsUseCase.getFavoriteRestaurants();
+      21              :     if (result != null) {
+      22            1 :       emit(
+      23            1 :         RestaurantsLoadedState(
+      24              :           result: result,
+      25              :           favoriteRestaurants: favoriteRestaurants,
+      26              :         ),
+      27              :       );
+      28              :     } else {
+      29            1 :       emit(
+      30              :         const ErrorState(
+      31              :           message:
+      32              :               'The server encountered a problem and we couldn\'t load the list.',
+      33              :           favoriteRestaurants: [],
+      34              :         ),
+      35              :       );
+      36              :     }
+      37              :   }
+      38              : 
+      39            1 :   Future<void> favoriteAResturant(String id) async {
+      40            3 :     final favoriteRestaurants = List<String>.from(state.favoriteRestaurants);
+      41            1 :     if (favoriteRestaurants.contains(id)) {
+      42            1 :       favoriteRestaurants.remove(id);
+      43              :     } else {
+      44            0 :       favoriteRestaurants.add(id);
+      45              :     }
+      46            1 :     emit(
+      47            1 :       FavoriteRestaurantState(
+      48            2 :         result: state.result!,
+      49            1 :         favoriteRestaurants: List.of(favoriteRestaurants),
+      50              :       ),
+      51              :     );
+      52              :   }
+      53              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/cubit/restaurant_state.dart.func-c.html b/coverage_report/cubit/restaurant_state.dart.func-c.html new file mode 100644 index 0000000..e9ae3fa --- /dev/null +++ b/coverage_report/cubit/restaurant_state.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - cubit/restaurant_state.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cubit - restaurant_state.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:45.5 %3315
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/cubit/restaurant_state.dart.func.html b/coverage_report/cubit/restaurant_state.dart.func.html new file mode 100644 index 0000000..27e7f83 --- /dev/null +++ b/coverage_report/cubit/restaurant_state.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - cubit/restaurant_state.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cubit - restaurant_state.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:45.5 %3315
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/cubit/restaurant_state.dart.gcov.html b/coverage_report/cubit/restaurant_state.dart.gcov.html new file mode 100644 index 0000000..7893a6d --- /dev/null +++ b/coverage_report/cubit/restaurant_state.dart.gcov.html @@ -0,0 +1,180 @@ + + + + + + + LCOV - lcov.info - cubit/restaurant_state.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - cubit - restaurant_state.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:45.5 %3315
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : // ignore_for_file: overridden_fields
+       2              : 
+       3              : part of 'restaurant_cubit.dart';
+       4              : 
+       5              : @immutable
+       6              : abstract class RestaurantState extends Equatable {
+       7              :   final List<String> favoriteRestaurants;
+       8              :   final RestaurantQueryResult? result;
+       9              : 
+      10            6 :   const RestaurantState({
+      11              :     required this.favoriteRestaurants,
+      12              :     this.result,
+      13              :   });
+      14              : 
+      15              :   RestaurantState copyWith({List<String>? favoriteRestaurants});
+      16            1 :   @override
+      17            2 :   List<Object?> get props => [favoriteRestaurants];
+      18              : }
+      19              : 
+      20              : class RestaurantInitial extends RestaurantState {
+      21            2 :   const RestaurantInitial({required super.favoriteRestaurants});
+      22              : 
+      23            0 :   @override
+      24              :   RestaurantState copyWith({List<String>? favoriteRestaurants}) {
+      25            0 :     return RestaurantInitial(
+      26            0 :       favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants,
+      27              :     );
+      28              :   }
+      29              : }
+      30              : 
+      31              : class LoadingRestaurantsState extends RestaurantState {
+      32            4 :   const LoadingRestaurantsState({required super.favoriteRestaurants});
+      33              : 
+      34            1 :   @override
+      35            2 :   List<Object?> get props => [favoriteRestaurants];
+      36              : 
+      37            0 :   @override
+      38              :   RestaurantState copyWith({List<String>? favoriteRestaurants}) {
+      39            0 :     return LoadingRestaurantsState(
+      40            0 :       favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants,
+      41              :     );
+      42              :   }
+      43              : }
+      44              : 
+      45              : class RestaurantsLoadedState extends RestaurantState {
+      46            2 :   const RestaurantsLoadedState({
+      47              :     required this.result,
+      48              :     required super.favoriteRestaurants,
+      49              :   });
+      50              : 
+      51              :   @override
+      52              :   final RestaurantQueryResult result;
+      53              : 
+      54            1 :   @override
+      55            3 :   List<Object?> get props => [result, favoriteRestaurants];
+      56              : 
+      57            0 :   @override
+      58              :   RestaurantsLoadedState copyWith({List<String>? favoriteRestaurants}) {
+      59            0 :     return RestaurantsLoadedState(
+      60            0 :       favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants,
+      61            0 :       result: result,
+      62              :     );
+      63              :   }
+      64              : }
+      65              : 
+      66              : class FavoriteRestaurantState extends RestaurantState {
+      67              :   @override
+      68              :   final RestaurantQueryResult result;
+      69              :   @override
+      70              :   final List<String> favoriteRestaurants;
+      71              : 
+      72            1 :   const FavoriteRestaurantState({
+      73              :     required this.result,
+      74              :     required this.favoriteRestaurants,
+      75            1 :   }) : super(favoriteRestaurants: favoriteRestaurants, result: result);
+      76            1 :   @override
+      77            2 :   List<Object?> get props => [favoriteRestaurants];
+      78              : 
+      79            0 :   @override
+      80              :   FavoriteRestaurantState copyWith({List<String>? favoriteRestaurants}) {
+      81            0 :     return FavoriteRestaurantState(
+      82            0 :       favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants,
+      83            0 :       result: result,
+      84              :     );
+      85              :   }
+      86              : }
+      87              : 
+      88              : class ErrorState extends RestaurantState {
+      89              :   final String message;
+      90              : 
+      91            3 :   const ErrorState({
+      92              :     required super.favoriteRestaurants,
+      93              :     super.result,
+      94              :     required this.message,
+      95              :   });
+      96              : 
+      97            0 :   @override
+      98              :   RestaurantState copyWith({List<String>? favoriteRestaurants}) {
+      99            0 :     return ErrorState(
+     100            0 :       favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants,
+     101            0 :       message: message,
+     102              :     );
+     103              :   }
+     104              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/emerald.png b/coverage_report/emerald.png new file mode 100644 index 0000000000000000000000000000000000000000..38ad4f4068b935643d2486f323005fb294a9bd7e GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^Jb!lvI6;R0X`wF(yt=9xVZRt1vCRixIA4P dLn>}1Cji+@42)0J?}79&c)I$ztaD0e0sy@GAL0N2 literal 0 HcmV?d00001 diff --git a/coverage_report/gcov.css b/coverage_report/gcov.css new file mode 100644 index 0000000..6c23ba9 --- /dev/null +++ b/coverage_report/gcov.css @@ -0,0 +1,1101 @@ +/* All views: initial background and text color */ +body +{ + color: #000000; + background-color: #ffffff; +} + +/* All views: standard link format*/ +a:link +{ + color: #284fa8; + text-decoration: underline; +} + +/* All views: standard link - visited format */ +a:visited +{ + color: #00cb40; + text-decoration: underline; +} + +/* All views: standard link - activated format */ +a:active +{ + color: #ff0040; + text-decoration: underline; +} + +/* All views: main title format */ +td.title +{ + text-align: center; + padding-bottom: 10px; + font-family: sans-serif; + font-size: 20pt; + font-style: italic; + font-weight: bold; +} +/* "Line coverage date bins" leader */ +td.subTableHeader +{ + text-align: center; + padding-bottom: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: center; +} + +/* All views: header item format */ +td.headerItem +{ + text-align: right; + padding-right: 6px; + font-family: sans-serif; + font-weight: bold; + vertical-align: top; + white-space: nowrap; +} + +/* All views: header item value format */ +td.headerValue +{ + text-align: left; + color: #284fa8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; +} + +/* All views: header item coverage table heading */ +td.headerCovTableHead +{ + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; +} + +/* All views: header item coverage table entry */ +td.headerCovTableEntry +{ + text-align: right; + color: #284fa8; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #dae7fe; +} + +/* All views: header item coverage table entry for high coverage rate */ +td.headerCovTableEntryHi +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #a7fc9d; +} + +/* All views: header item coverage table entry for medium coverage rate */ +td.headerCovTableEntryMed +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #ffea20; +} + +/* All views: header item coverage table entry for ow coverage rate */ +td.headerCovTableEntryLo +{ + text-align: right; + color: #000000; + font-family: sans-serif; + font-weight: bold; + white-space: nowrap; + padding-left: 12px; + padding-right: 4px; + background-color: #ff0000; +} + +/* All views: header legend value for legend entry */ +td.headerValueLeg +{ + text-align: left; + color: #000000; + font-family: sans-serif; + font-size: 80%; + white-space: nowrap; + padding-top: 4px; +} + +/* All views: color of horizontal ruler */ +td.ruler +{ + background-color: #6688d4; +} + +/* All views: version string format */ +td.versionInfo +{ + text-align: center; + padding-top: 2px; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all)/Test case descriptions: + table headline format */ +td.tableHead +{ + text-align: center; + color: #ffffff; + background-color: #6688d4; + font-family: sans-serif; + font-size: 120%; + font-weight: bold; + white-space: nowrap; + padding-left: 4px; + padding-right: 4px; +} + +span.tableHeadSort +{ + padding-right: 4px; +} + +/* Directory view/File view (all): filename entry format */ +td.coverFile +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + background-color: #dae7fe; + font-family: monospace; +} + +/* Directory view/File view (all): directory name entry format */ +td.coverDirectory +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + background-color: #b8d0ff; + font-family: monospace; +} + +/* Directory view/File view (all): filename entry format */ +td.overallOwner +{ + text-align: center; + font-weight: bold; + font-family: sans-serif; + background-color: #dae7fe; + padding-right: 10px; + padding-left: 10px; +} + +/* Directory view/File view (all): filename entry format */ +td.ownerName +{ + text-align: right; + font-style: italic; + font-family: sans-serif; + background-color: #E5DBDB; + padding-right: 10px; + padding-left: 20px; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; +} + +/* Directory view/File view (all): bar-graph entry format*/ +td.owner_coverBar +{ + padding-left: 10px; + padding-right: 10px; + background-color: #E5DBDB; +} + +/* Directory view/File view (all): bar-graph outline color */ +td.coverBarOutline +{ + background-color: #000000; +} + +/* Directory view/File view (all): percentage entry for files with + high coverage rate */ +td.coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #a7fc9d; + font-weight: bold; + font-family: sans-serif; +} + +/* 'owner' entry: slightly lighter color than 'coverPerHi' */ +td.owner_coverPerHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #82E0AA; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry */ +td.coverNumDflt +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + white-space: nowrap; + font-family: sans-serif; +} + +/* td background color and font for the 'owner' section of the table */ +td.ownerTla +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #E5DBDB; + white-space: nowrap; + font-family: sans-serif; + font-style: italic; +} + +/* Directory view/File view (all): line count entry for files with + high coverage rate */ +td.coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #a7fc9d; + white-space: nowrap; + font-family: sans-serif; +} + +td.owner_coverNumHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #82E0AA; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + medium coverage rate */ +td.coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ffea20; + font-weight: bold; + font-family: sans-serif; +} + +td.owner_coverPerMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #F9E79F; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + medium coverage rate */ +td.coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ffea20; + white-space: nowrap; + font-family: sans-serif; +} + +td.owner_coverNumMed +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #F9E79F; + white-space: nowrap; + font-family: sans-serif; +} + +/* Directory view/File view (all): percentage entry for files with + low coverage rate */ +td.coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ff0000; + font-weight: bold; + font-family: sans-serif; +} + +td.owner_coverPerLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #EC7063; + font-weight: bold; + font-family: sans-serif; +} + +/* Directory view/File view (all): line count entry for files with + low coverage rate */ +td.coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ff0000; + white-space: nowrap; + font-family: sans-serif; +} + +td.owner_coverNumLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #EC7063; + white-space: nowrap; + font-family: sans-serif; +} + +/* File view (all): "show/hide details" link format */ +a.detail:link +{ + color: #b8d0ff; + font-size:80%; +} + +/* File view (all): "show/hide details" link - visited format */ +a.detail:visited +{ + color: #b8d0ff; + font-size:80%; +} + +/* File view (all): "show/hide details" link - activated format */ +a.detail:active +{ + color: #ffffff; + font-size:80%; +} + +/* File view (detail): test name entry */ +td.testName +{ + text-align: right; + padding-right: 10px; + background-color: #dae7fe; + font-family: sans-serif; +} + +/* File view (detail): test percentage entry */ +td.testPer +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-family: sans-serif; +} + +/* File view (detail): test lines count entry */ +td.testNum +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-family: sans-serif; +} + +/* Test case descriptions: test name format*/ +dt +{ + font-family: sans-serif; + font-weight: bold; +} + +/* Test case descriptions: description table body */ +td.testDescription +{ + padding-top: 10px; + padding-left: 30px; + padding-bottom: 10px; + padding-right: 30px; + background-color: #dae7fe; +} + +/* Source code view: function entry */ +td.coverFn +{ + text-align: left; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + background-color: #dae7fe; + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #ff0000; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-weight: bold; + font-family: sans-serif; +} + +td.coverFnAlias +{ + text-align: right; + padding-left: 10px; + padding-right: 20px; + color: #284fa8; + /* make this a slightly different color than the leader - otherwise, + otherwise the alias is hard to distinguish in the table */ + background-color: #E5DBDB; /* very light pale grey/blue */ + font-family: monospace; +} + +/* Source code view: function entry zero count*/ +td.coverFnAliasLo +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #EC7063; /* lighter red */ + font-family: sans-serif; +} + +/* Source code view: function entry nonzero count*/ +td.coverFnAliasHi +{ + text-align: right; + padding-left: 10px; + padding-right: 10px; + background-color: #dae7fe; + font-weight: bold; + font-family: sans-serif; +} + +/* Source code view: source code format */ +pre.source +{ + font-family: monospace; + white-space: pre; + margin-top: 2px; +} + +/* elided/removed code */ +span.elidedSource +{ + font-family: sans-serif; + /*font-size: 8pt; */ + font-style: italic; + background-color: lightgrey; +} + +/* Source code view: line number format */ +span.lineNum +{ + background-color: #efe383; +} + +/* Source code view: line number format when there are deleted + lines in the corresponding location */ +span.lineNumWithDelete +{ + foreground-color: #efe383; + background-color: lightgrey; +} + +/* Source code view: format for Cov legend */ +span.coverLegendCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #cad7fe; +} + +/* Source code view: format for NoCov legend */ +span.coverLegendNoCov +{ + padding-left: 10px; + padding-right: 10px; + padding-bottom: 2px; + background-color: #ff6230; +} + +/* Source code view: format for the source code heading line */ +pre.sourceHeading +{ + white-space: pre; + font-family: monospace; + font-weight: bold; + margin: 0px; +} + +/* All views: header legend value for low rate */ +td.headerValueLegL +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 4px; + padding-right: 2px; + background-color: #ff0000; + font-size: 80%; +} + +/* All views: header legend value for med rate */ +td.headerValueLegM +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 2px; + background-color: #ffea20; + font-size: 80%; +} + +/* All views: header legend value for hi rate */ +td.headerValueLegH +{ + font-family: sans-serif; + text-align: center; + white-space: nowrap; + padding-left: 2px; + padding-right: 4px; + background-color: #a7fc9d; + font-size: 80%; +} + +/* All views except source code view: legend format for low coverage */ +span.coverLegendCovLo +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #ff0000; +} + +/* All views except source code view: legend format for med coverage */ +span.coverLegendCovMed +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #ffea20; +} + +/* All views except source code view: legend format for hi coverage */ +span.coverLegendCovHi +{ + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + background-color: #a7fc9d; +} + +a.branchTla:link +{ + color: #000000; +} + +a.branchTla:visited +{ + color: #000000; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered New Code (+ => 0): +Newly added code is not tested" */ +td.tlaUNC +{ + text-align: right; + background-color: #FF6230; +} +td.tlaBgUNC { + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered New Code (+ => 0): +Newly added code is not tested" */ +span.tlaUNC +{ + text-align: left; + background-color: #FF6230; +} +span.tlaBgUNC { + background-color: #FF6230; +} +a.tlaBgUNC { + background-color: #FF6230; + color: #000000; +} + +td.headerCovTableHeadUNC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Lost Baseline Coverage (1 => 0): +Unchanged code is no longer tested" */ +td.tlaLBC +{ + text-align: right; + background-color: #FF6230; +} +td.tlaBgLBC { + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Lost Baseline Coverage (1 => 0): +Unchanged code is no longer tested" */ +span.tlaLBC +{ + text-align: left; + background-color: #FF6230; +} +span.tlaBgLBC { + background-color: #FF6230; +} +a.tlaBgLBC { + background-color: #FF6230; + color: #000000; +} + +td.headerCovTableHeadLBC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered Included Code (# => 0): +Previously unused code is untested" */ +td.tlaUIC +{ + text-align: right; + background-color: #FF6230; +} +td.tlaBgUIC { + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered Included Code (# => 0): +Previously unused code is untested" */ +span.tlaUIC +{ + text-align: left; + background-color: #FF6230; +} +span.tlaBgUIC { + background-color: #FF6230; +} +a.tlaBgUIC { + background-color: #FF6230; + color: #000000; +} + +td.headerCovTableHeadUIC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered Baseline Code (0 => 0): +Unchanged code was untested before, is untested now" */ +td.tlaUBC +{ + text-align: right; + background-color: #FF6230; +} +td.tlaBgUBC { + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Uncovered Baseline Code (0 => 0): +Unchanged code was untested before, is untested now" */ +span.tlaUBC +{ + text-align: left; + background-color: #FF6230; +} +span.tlaBgUBC { + background-color: #FF6230; +} +a.tlaBgUBC { + background-color: #FF6230; + color: #000000; +} + +td.headerCovTableHeadUBC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FF6230; +} + +/* Source code view/table entry background: format for lines classified as "Gained Baseline Coverage (0 => 1): +Unchanged code is tested now" */ +td.tlaGBC +{ + text-align: right; + background-color: #CAD7FE; +} +td.tlaBgGBC { + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained Baseline Coverage (0 => 1): +Unchanged code is tested now" */ +span.tlaGBC +{ + text-align: left; + background-color: #CAD7FE; +} +span.tlaBgGBC { + background-color: #CAD7FE; +} +a.tlaBgGBC { + background-color: #CAD7FE; + color: #000000; +} + +td.headerCovTableHeadGBC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained Included Coverage (# => 1): +Previously unused code is tested now" */ +td.tlaGIC +{ + text-align: right; + background-color: #CAD7FE; +} +td.tlaBgGIC { + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained Included Coverage (# => 1): +Previously unused code is tested now" */ +span.tlaGIC +{ + text-align: left; + background-color: #CAD7FE; +} +span.tlaBgGIC { + background-color: #CAD7FE; +} +a.tlaBgGIC { + background-color: #CAD7FE; + color: #000000; +} + +td.headerCovTableHeadGIC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained New Coverage (+ => 1): +Newly added code is tested" */ +td.tlaGNC +{ + text-align: right; + background-color: #CAD7FE; +} +td.tlaBgGNC { + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Gained New Coverage (+ => 1): +Newly added code is tested" */ +span.tlaGNC +{ + text-align: left; + background-color: #CAD7FE; +} +span.tlaBgGNC { + background-color: #CAD7FE; +} +a.tlaBgGNC { + background-color: #CAD7FE; + color: #000000; +} + +td.headerCovTableHeadGNC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Covered Baseline Code (1 => 1): +Unchanged code was tested before and is still tested" */ +td.tlaCBC +{ + text-align: right; + background-color: #CAD7FE; +} +td.tlaBgCBC { + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Covered Baseline Code (1 => 1): +Unchanged code was tested before and is still tested" */ +span.tlaCBC +{ + text-align: left; + background-color: #CAD7FE; +} +span.tlaBgCBC { + background-color: #CAD7FE; +} +a.tlaBgCBC { + background-color: #CAD7FE; + color: #000000; +} + +td.headerCovTableHeadCBC { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #CAD7FE; +} + +/* Source code view/table entry background: format for lines classified as "Excluded Uncovered Baseline (0 => #): +Previously untested code is unused now" */ +td.tlaEUB +{ + text-align: right; + background-color: #FFFFFF; +} +td.tlaBgEUB { + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Excluded Uncovered Baseline (0 => #): +Previously untested code is unused now" */ +span.tlaEUB +{ + text-align: left; + background-color: #FFFFFF; +} +span.tlaBgEUB { + background-color: #FFFFFF; +} +a.tlaBgEUB { + background-color: #FFFFFF; + color: #000000; +} + +td.headerCovTableHeadEUB { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Excluded Covered Baseline (1 => #): +Previously tested code is unused now" */ +td.tlaECB +{ + text-align: right; + background-color: #FFFFFF; +} +td.tlaBgECB { + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Excluded Covered Baseline (1 => #): +Previously tested code is unused now" */ +span.tlaECB +{ + text-align: left; + background-color: #FFFFFF; +} +span.tlaBgECB { + background-color: #FFFFFF; +} +a.tlaBgECB { + background-color: #FFFFFF; + color: #000000; +} + +td.headerCovTableHeadECB { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Deleted Uncovered Baseline (0 => -): +Previously untested code has been deleted" */ +td.tlaDUB +{ + text-align: right; + background-color: #FFFFFF; +} +td.tlaBgDUB { + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Deleted Uncovered Baseline (0 => -): +Previously untested code has been deleted" */ +span.tlaDUB +{ + text-align: left; + background-color: #FFFFFF; +} +span.tlaBgDUB { + background-color: #FFFFFF; +} +a.tlaBgDUB { + background-color: #FFFFFF; + color: #000000; +} + +td.headerCovTableHeadDUB { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Deleted Covered Baseline (1 => -): +Previously tested code has been deleted" */ +td.tlaDCB +{ + text-align: right; + background-color: #FFFFFF; +} +td.tlaBgDCB { + background-color: #FFFFFF; +} + +/* Source code view/table entry background: format for lines classified as "Deleted Covered Baseline (1 => -): +Previously tested code has been deleted" */ +span.tlaDCB +{ + text-align: left; + background-color: #FFFFFF; +} +span.tlaBgDCB { + background-color: #FFFFFF; +} +a.tlaBgDCB { + background-color: #FFFFFF; + color: #000000; +} + +td.headerCovTableHeadDCB { + text-align: center; + padding-right: 6px; + padding-left: 6px; + padding-bottom: 0px; + font-family: sans-serif; + white-space: nowrap; + background-color: #FFFFFF; +} + +/* Source code view: format for date/owner bin that is not hit */ +span.missBins +{ + background-color: #ff0000 /* red */ +} diff --git a/coverage_report/glass.png b/coverage_report/glass.png new file mode 100644 index 0000000000000000000000000000000000000000..e1abc00680a3093c49fdb775ae6bdb6764c95af2 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)gaEa{HEjtmSN`?>!lvI6;R0X`wF z|Ns97GD8ntt^-nxB|(0{3=Yq3q=7g|-tI089jvk*Kn`btM`SSr1Gf+eGhVt|_XjA* zUgGKN%6^Gmn4d%Ph(nkFP>9RZ#WAE}PI3Z}&BVayv3^M*kj3EX>gTe~DWM4f=_Dpv literal 0 HcmV?d00001 diff --git a/coverage_report/index-sort-f.html b/coverage_report/index-sort-f.html new file mode 100644 index 0000000..25553a5 --- /dev/null +++ b/coverage_report/index-sort-f.html @@ -0,0 +1,177 @@ + + + + + + + LCOV - lcov.info + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelCoverageTotalHit
Test:lcov.infoLines:52.6 %386203
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
cubit/ +
62.7%62.7%
+
62.7 %5132-
models/ +
61.2%61.2%
+
61.2 %10363-
pages/ +
52.8%52.8%
+
52.8 %10656-
repositories/ +
46.2%46.2%
+
46.2 %136-
usecases/ +
0.0%
+
0.0 %8-
utils/ +
0.0%
+
0.0 %4-
widgets/ +
45.5%45.5%
+
45.5 %10146-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/index-sort-l.html b/coverage_report/index-sort-l.html new file mode 100644 index 0000000..73e8f92 --- /dev/null +++ b/coverage_report/index-sort-l.html @@ -0,0 +1,177 @@ + + + + + + + LCOV - lcov.info + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelCoverageTotalHit
Test:lcov.infoLines:52.6 %386203
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
utils/ +
0.0%
+
0.0 %4-
usecases/ +
0.0%
+
0.0 %8-
widgets/ +
45.5%45.5%
+
45.5 %10146-
repositories/ +
46.2%46.2%
+
46.2 %136-
pages/ +
52.8%52.8%
+
52.8 %10656-
models/ +
61.2%61.2%
+
61.2 %10363-
cubit/ +
62.7%62.7%
+
62.7 %5132-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/index.html b/coverage_report/index.html new file mode 100644 index 0000000..fd43494 --- /dev/null +++ b/coverage_report/index.html @@ -0,0 +1,177 @@ + + + + + + + LCOV - lcov.info + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top levelCoverageTotalHit
Test:lcov.infoLines:52.6 %386203
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Directory Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
cubit/ +
62.7%62.7%
+
62.7 %5132-
models/ +
61.2%61.2%
+
61.2 %10363-
pages/ +
52.8%52.8%
+
52.8 %10656-
repositories/ +
46.2%46.2%
+
46.2 %136-
usecases/ +
0.0%
+
0.0 %8-
utils/ +
0.0%
+
0.0 %4-
widgets/ +
45.5%45.5%
+
45.5 %10146-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/models/index-sort-f.html b/coverage_report/models/index-sort-f.html new file mode 100644 index 0000000..9a30385 --- /dev/null +++ b/coverage_report/models/index-sort-f.html @@ -0,0 +1,117 @@ + + + + + + + LCOV - lcov.info - models + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - modelsCoverageTotalHit
Test:lcov.infoLines:61.2 %10363
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
restaurant.dart +
70.6%70.6%
+
70.6 %3424-
restaurant.g.dart +
56.5%56.5%
+
56.5 %6939-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/models/index-sort-l.html b/coverage_report/models/index-sort-l.html new file mode 100644 index 0000000..504dafe --- /dev/null +++ b/coverage_report/models/index-sort-l.html @@ -0,0 +1,117 @@ + + + + + + + LCOV - lcov.info - models + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - modelsCoverageTotalHit
Test:lcov.infoLines:61.2 %10363
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
restaurant.g.dart +
56.5%56.5%
+
56.5 %6939-
restaurant.dart +
70.6%70.6%
+
70.6 %3424-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/models/index.html b/coverage_report/models/index.html new file mode 100644 index 0000000..5394571 --- /dev/null +++ b/coverage_report/models/index.html @@ -0,0 +1,117 @@ + + + + + + + LCOV - lcov.info - models + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - modelsCoverageTotalHit
Test:lcov.infoLines:61.2 %10363
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
restaurant.dart +
70.6%70.6%
+
70.6 %3424-
restaurant.g.dart +
56.5%56.5%
+
56.5 %6939-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/models/restaurant.dart.func-c.html b/coverage_report/models/restaurant.dart.func-c.html new file mode 100644 index 0000000..fd8db83 --- /dev/null +++ b/coverage_report/models/restaurant.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - models/restaurant.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - models - restaurant.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:70.6 %3424
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/models/restaurant.dart.func.html b/coverage_report/models/restaurant.dart.func.html new file mode 100644 index 0000000..2a41e98 --- /dev/null +++ b/coverage_report/models/restaurant.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - models/restaurant.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - models - restaurant.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:70.6 %3424
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/models/restaurant.dart.gcov.html b/coverage_report/models/restaurant.dart.gcov.html new file mode 100644 index 0000000..d439461 --- /dev/null +++ b/coverage_report/models/restaurant.dart.gcov.html @@ -0,0 +1,233 @@ + + + + + + + LCOV - lcov.info - models/restaurant.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - models - restaurant.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:70.6 %3424
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:json_annotation/json_annotation.dart';
+       2              : 
+       3              : part 'restaurant.g.dart';
+       4              : 
+       5              : @JsonSerializable()
+       6              : class Category {
+       7              :   final String? alias;
+       8              :   final String? title;
+       9              : 
+      10            1 :   Category({
+      11              :     this.alias,
+      12              :     this.title,
+      13              :   });
+      14              : 
+      15            1 :   factory Category.fromJson(Map<String, dynamic> json) =>
+      16            1 :       _$CategoryFromJson(json);
+      17              : 
+      18            0 :   Map<String, dynamic> toJson() => _$CategoryToJson(this);
+      19              : }
+      20              : 
+      21              : @JsonSerializable()
+      22              : class Hours {
+      23              :   @JsonKey(name: 'is_open_now')
+      24              :   final bool? isOpenNow;
+      25              : 
+      26            1 :   const Hours({
+      27              :     this.isOpenNow,
+      28              :   });
+      29              : 
+      30            2 :   factory Hours.fromJson(Map<String, dynamic> json) => _$HoursFromJson(json);
+      31              : 
+      32            0 :   Map<String, dynamic> toJson() => _$HoursToJson(this);
+      33              : }
+      34              : 
+      35              : @JsonSerializable()
+      36              : class User {
+      37              :   final String? id;
+      38              :   @JsonKey(name: 'image_url')
+      39              :   final String? imageUrl;
+      40              :   final String? name;
+      41              : 
+      42            1 :   const User({
+      43              :     this.id,
+      44              :     this.imageUrl,
+      45              :     this.name,
+      46              :   });
+      47              : 
+      48            2 :   factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
+      49              : 
+      50            0 :   Map<String, dynamic> toJson() => _$UserToJson(this);
+      51              : }
+      52              : 
+      53              : @JsonSerializable()
+      54              : class Review {
+      55              :   final String? id;
+      56              :   final int? rating;
+      57              :   final String? text;
+      58              :   final User? user;
+      59              : 
+      60            1 :   const Review({
+      61              :     this.id,
+      62              :     this.rating,
+      63              :     this.user,
+      64              :     this.text,
+      65              :   });
+      66              : 
+      67            2 :   factory Review.fromJson(Map<String, dynamic> json) => _$ReviewFromJson(json);
+      68              : 
+      69            0 :   Map<String, dynamic> toJson() => _$ReviewToJson(this);
+      70              : }
+      71              : 
+      72              : @JsonSerializable()
+      73              : class Location {
+      74              :   @JsonKey(name: 'formatted_address')
+      75              :   final String? formattedAddress;
+      76              : 
+      77            1 :   Location({
+      78              :     this.formattedAddress,
+      79              :   });
+      80              : 
+      81            1 :   factory Location.fromJson(Map<String, dynamic> json) =>
+      82            1 :       _$LocationFromJson(json);
+      83              : 
+      84            0 :   Map<String, dynamic> toJson() => _$LocationToJson(this);
+      85              : }
+      86              : 
+      87              : @JsonSerializable()
+      88              : class Restaurant {
+      89              :   final String? id;
+      90              :   final String? name;
+      91              :   final String? price;
+      92              :   final double? rating;
+      93              :   final List<String>? photos;
+      94              :   final List<Category>? categories;
+      95              :   final List<Hours>? hours;
+      96              :   final List<Review>? reviews;
+      97              :   final Location? location;
+      98              : 
+      99            1 :   const Restaurant({
+     100              :     this.id,
+     101              :     this.name,
+     102              :     this.price,
+     103              :     this.rating,
+     104              :     this.photos,
+     105              :     this.categories,
+     106              :     this.hours,
+     107              :     this.reviews,
+     108              :     this.location,
+     109              :   });
+     110              : 
+     111            1 :   factory Restaurant.fromJson(Map<String, dynamic> json) =>
+     112            1 :       _$RestaurantFromJson(json);
+     113              : 
+     114            0 :   Map<String, dynamic> toJson() => _$RestaurantToJson(this);
+     115              : 
+     116              :   /// Use the first category for the category shown to the user
+     117            0 :   String get displayCategory {
+     118            0 :     if (categories != null && categories!.isNotEmpty) {
+     119            0 :       return categories!.first.title ?? '';
+     120              :     }
+     121              :     return '';
+     122              :   }
+     123              : 
+     124              :   /// Use the first image as the image shown to the user
+     125            1 :   String get heroImage {
+     126            3 :     if (photos != null && photos!.isNotEmpty) {
+     127            2 :       return photos!.first;
+     128              :     }
+     129              :     return '';
+     130              :   }
+     131              : 
+     132              :   /// This logic is probably not correct in all cases but it is ok
+     133              :   /// for this application
+     134            1 :   bool get isOpen {
+     135            3 :     if (hours != null && hours!.isNotEmpty) {
+     136            3 :       return hours!.first.isOpenNow ?? false;
+     137              :     }
+     138              :     return false;
+     139              :   }
+     140              : }
+     141              : 
+     142              : @JsonSerializable()
+     143              : class RestaurantQueryResult {
+     144              :   final int? total;
+     145              :   @JsonKey(name: 'business')
+     146              :   final List<Restaurant>? restaurants;
+     147              : 
+     148            1 :   const RestaurantQueryResult({
+     149              :     this.total,
+     150              :     this.restaurants,
+     151              :   });
+     152              : 
+     153            1 :   factory RestaurantQueryResult.fromJson(Map<String, dynamic> json) =>
+     154            1 :       _$RestaurantQueryResultFromJson(json);
+     155              : 
+     156            0 :   Map<String, dynamic> toJson() => _$RestaurantQueryResultToJson(this);
+     157              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/models/restaurant.g.dart.func-c.html b/coverage_report/models/restaurant.g.dart.func-c.html new file mode 100644 index 0000000..07ba84f --- /dev/null +++ b/coverage_report/models/restaurant.g.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - models/restaurant.g.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - models - restaurant.g.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:56.5 %6939
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/models/restaurant.g.dart.func.html b/coverage_report/models/restaurant.g.dart.func.html new file mode 100644 index 0000000..ef21f97 --- /dev/null +++ b/coverage_report/models/restaurant.g.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - models/restaurant.g.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - models - restaurant.g.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:56.5 %6939
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/models/restaurant.g.dart.gcov.html b/coverage_report/models/restaurant.g.dart.gcov.html new file mode 100644 index 0000000..cd625a3 --- /dev/null +++ b/coverage_report/models/restaurant.g.dart.gcov.html @@ -0,0 +1,185 @@ + + + + + + + LCOV - lcov.info - models/restaurant.g.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - models - restaurant.g.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:56.5 %6939
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : // GENERATED CODE - DO NOT MODIFY BY HAND
+       2              : 
+       3              : part of 'restaurant.dart';
+       4              : 
+       5              : // **************************************************************************
+       6              : // JsonSerializableGenerator
+       7              : // **************************************************************************
+       8              : 
+       9            2 : Category _$CategoryFromJson(Map<String, dynamic> json) => Category(
+      10            1 :       alias: json['alias'] as String?,
+      11            1 :       title: json['title'] as String?,
+      12              :     );
+      13              : 
+      14            0 : Map<String, dynamic> _$CategoryToJson(Category instance) => <String, dynamic>{
+      15            0 :       'alias': instance.alias,
+      16            0 :       'title': instance.title,
+      17              :     };
+      18              : 
+      19            2 : Hours _$HoursFromJson(Map<String, dynamic> json) => Hours(
+      20            1 :       isOpenNow: json['is_open_now'] as bool?,
+      21              :     );
+      22              : 
+      23            0 : Map<String, dynamic> _$HoursToJson(Hours instance) => <String, dynamic>{
+      24            0 :       'is_open_now': instance.isOpenNow,
+      25              :     };
+      26              : 
+      27            2 : User _$UserFromJson(Map<String, dynamic> json) => User(
+      28            1 :       id: json['id'] as String?,
+      29            1 :       imageUrl: json['image_url'] as String?,
+      30            1 :       name: json['name'] as String?,
+      31              :     );
+      32              : 
+      33            0 : Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
+      34            0 :       'id': instance.id,
+      35            0 :       'image_url': instance.imageUrl,
+      36            0 :       'name': instance.name,
+      37              :     };
+      38              : 
+      39            2 : Review _$ReviewFromJson(Map<String, dynamic> json) => Review(
+      40            1 :       id: json['id'] as String?,
+      41            1 :       rating: json['rating'] as int?,
+      42            1 :       user: json['user'] == null
+      43              :           ? null
+      44            2 :           : User.fromJson(json['user'] as Map<String, dynamic>),
+      45              :     );
+      46              : 
+      47            0 : Map<String, dynamic> _$ReviewToJson(Review instance) => <String, dynamic>{
+      48            0 :       'id': instance.id,
+      49            0 :       'rating': instance.rating,
+      50            0 :       'user': instance.user,
+      51              :     };
+      52              : 
+      53            2 : Location _$LocationFromJson(Map<String, dynamic> json) => Location(
+      54            1 :       formattedAddress: json['formatted_address'] as String?,
+      55              :     );
+      56              : 
+      57            0 : Map<String, dynamic> _$LocationToJson(Location instance) => <String, dynamic>{
+      58            0 :       'formatted_address': instance.formattedAddress,
+      59              :     };
+      60              : 
+      61            2 : Restaurant _$RestaurantFromJson(Map<String, dynamic> json) => Restaurant(
+      62            1 :       id: json['id'] as String?,
+      63            1 :       name: json['name'] as String?,
+      64            1 :       price: json['price'] as String?,
+      65            2 :       rating: (json['rating'] as num?)?.toDouble(),
+      66              :       photos:
+      67            4 :           (json['photos'] as List<dynamic>?)?.map((e) => e as String).toList(),
+      68            1 :       categories: (json['categories'] as List<dynamic>?)
+      69            3 :           ?.map((e) => Category.fromJson(e as Map<String, dynamic>))
+      70            1 :           .toList(),
+      71            1 :       hours: (json['hours'] as List<dynamic>?)
+      72            3 :           ?.map((e) => Hours.fromJson(e as Map<String, dynamic>))
+      73            1 :           .toList(),
+      74            1 :       reviews: (json['reviews'] as List<dynamic>?)
+      75            3 :           ?.map((e) => Review.fromJson(e as Map<String, dynamic>))
+      76            1 :           .toList(),
+      77            1 :       location: json['location'] == null
+      78              :           ? null
+      79            2 :           : Location.fromJson(json['location'] as Map<String, dynamic>),
+      80              :     );
+      81              : 
+      82            0 : Map<String, dynamic> _$RestaurantToJson(Restaurant instance) =>
+      83            0 :     <String, dynamic>{
+      84            0 :       'id': instance.id,
+      85            0 :       'name': instance.name,
+      86            0 :       'price': instance.price,
+      87            0 :       'rating': instance.rating,
+      88            0 :       'photos': instance.photos,
+      89            0 :       'categories': instance.categories,
+      90            0 :       'hours': instance.hours,
+      91            0 :       'reviews': instance.reviews,
+      92            0 :       'location': instance.location,
+      93              :     };
+      94              : 
+      95            1 : RestaurantQueryResult _$RestaurantQueryResultFromJson(
+      96              :         Map<String, dynamic> json) =>
+      97            1 :     RestaurantQueryResult(
+      98            1 :       total: json['total'] as int?,
+      99            1 :       restaurants: (json['business'] as List<dynamic>?)
+     100            3 :           ?.map((e) => Restaurant.fromJson(e as Map<String, dynamic>))
+     101            1 :           .toList(),
+     102              :     );
+     103              : 
+     104            0 : Map<String, dynamic> _$RestaurantQueryResultToJson(
+     105              :         RestaurantQueryResult instance) =>
+     106            0 :     <String, dynamic>{
+     107            0 :       'total': instance.total,
+     108            0 :       'business': instance.restaurants,
+     109              :     };
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/home_page.dart.func-c.html b/coverage_report/pages/home_page.dart.func-c.html new file mode 100644 index 0000000..fb8644c --- /dev/null +++ b/coverage_report/pages/home_page.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - pages/home_page.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pages - home_page.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %1616
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/home_page.dart.func.html b/coverage_report/pages/home_page.dart.func.html new file mode 100644 index 0000000..66e1bed --- /dev/null +++ b/coverage_report/pages/home_page.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - pages/home_page.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pages - home_page.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %1616
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/home_page.dart.gcov.html b/coverage_report/pages/home_page.dart.gcov.html new file mode 100644 index 0000000..7f7333a --- /dev/null +++ b/coverage_report/pages/home_page.dart.gcov.html @@ -0,0 +1,148 @@ + + + + + + + LCOV - lcov.info - pages/home_page.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pages - home_page.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %1616
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : import 'package:restaurant_tour/pages/restaurant_list_page.dart';
+       3              : 
+       4              : // class HomePageBlocProvider extends StatelessWidget {
+       5              : //   const HomePageBlocProvider({super.key});
+       6              : 
+       7              : //   @override
+       8              : //   Widget build(BuildContext context) {
+       9              : //     return BlocProvider(
+      10              : //       create: (context) =>
+      11              : //           GetIt.instance<RestaurantCubit>()..fetchRestaurants(),
+      12              : //       child: const HomePage(),
+      13              : //     );
+      14              : //   }
+      15              : // }
+      16              : 
+      17              : class HomePage extends StatelessWidget {
+      18            1 :   const HomePage({super.key});
+      19              : 
+      20            1 :   @override
+      21              :   Widget build(BuildContext context) {
+      22            1 :     return DefaultTabController(
+      23              :       length: 2,
+      24            1 :       child: Scaffold(
+      25            1 :         appBar: AppBar(
+      26            1 :           title: Text(
+      27              :             "RestauranTour",
+      28            3 :             style: Theme.of(context).textTheme.headlineLarge,
+      29              :           ),
+      30            1 :           actions: [
+      31              :             // Padding(
+      32              :             //   padding: const EdgeInsets.only(right: 16),
+      33              :             //   child: TextButton(
+      34              :             //     onPressed: () {},
+      35              :             //     child: const CircleAvatar(
+      36              :             //       backgroundImage: NetworkImage(
+      37              :             //         'https://mdbcdn.b-cdn.net/img/new/avatars/2.webp',
+      38              :             //       ),
+      39              :             //     ),
+      40              :             //   ),
+      41              :             // ),
+      42              :           ],
+      43            1 :           bottom: TabBar(
+      44            1 :             tabs: [
+      45            1 :               Tab(
+      46            1 :                 child: Text(
+      47              :                   'All restaurants',
+      48            3 :                   style: Theme.of(context).textTheme.displayLarge,
+      49              :                 ),
+      50              :               ),
+      51            1 :               Tab(
+      52            1 :                 child: Text(
+      53              :                   'My favorites',
+      54            3 :                   style: Theme.of(context).textTheme.displayLarge,
+      55              :                 ),
+      56              :               ),
+      57              :             ],
+      58              :           ),
+      59              :         ),
+      60              :         body: const SafeArea(
+      61              :           minimum: EdgeInsets.all(16),
+      62              :           child: TabBarView(
+      63              :             children: [
+      64              :               RestaurantListPageView(),
+      65              :               Text('Dias'),
+      66              :             ],
+      67              :           ),
+      68              :         ),
+      69              :       ),
+      70              :     );
+      71              :   }
+      72              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/index-sort-f.html b/coverage_report/pages/index-sort-f.html new file mode 100644 index 0000000..5c98282 --- /dev/null +++ b/coverage_report/pages/index-sort-f.html @@ -0,0 +1,129 @@ + + + + + + + LCOV - lcov.info - pages + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pagesCoverageTotalHit
Test:lcov.infoLines:52.8 %10656
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
home_page.dart +
100.0%
+
100.0 %1616-
restaurant_detail_page.dart +
0.0%
+
0.0 %39-
restaurant_list_page.dart +
78.4%78.4%
+
78.4 %5140-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/index-sort-l.html b/coverage_report/pages/index-sort-l.html new file mode 100644 index 0000000..356c96c --- /dev/null +++ b/coverage_report/pages/index-sort-l.html @@ -0,0 +1,129 @@ + + + + + + + LCOV - lcov.info - pages + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pagesCoverageTotalHit
Test:lcov.infoLines:52.8 %10656
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
restaurant_detail_page.dart +
0.0%
+
0.0 %39-
restaurant_list_page.dart +
78.4%78.4%
+
78.4 %5140-
home_page.dart +
100.0%
+
100.0 %1616-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/index.html b/coverage_report/pages/index.html new file mode 100644 index 0000000..0a357a6 --- /dev/null +++ b/coverage_report/pages/index.html @@ -0,0 +1,129 @@ + + + + + + + LCOV - lcov.info - pages + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pagesCoverageTotalHit
Test:lcov.infoLines:52.8 %10656
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
home_page.dart +
100.0%
+
100.0 %1616-
restaurant_detail_page.dart +
0.0%
+
0.0 %39-
restaurant_list_page.dart +
78.4%78.4%
+
78.4 %5140-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/restaurant_detail_page.dart.func-c.html b/coverage_report/pages/restaurant_detail_page.dart.func-c.html new file mode 100644 index 0000000..8bd9e82 --- /dev/null +++ b/coverage_report/pages/restaurant_detail_page.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - pages/restaurant_detail_page.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pages - restaurant_detail_page.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %390
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/restaurant_detail_page.dart.func.html b/coverage_report/pages/restaurant_detail_page.dart.func.html new file mode 100644 index 0000000..bfabb91 --- /dev/null +++ b/coverage_report/pages/restaurant_detail_page.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - pages/restaurant_detail_page.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pages - restaurant_detail_page.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %390
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/restaurant_detail_page.dart.gcov.html b/coverage_report/pages/restaurant_detail_page.dart.gcov.html new file mode 100644 index 0000000..373db8e --- /dev/null +++ b/coverage_report/pages/restaurant_detail_page.dart.gcov.html @@ -0,0 +1,177 @@ + + + + + + + LCOV - lcov.info - pages/restaurant_detail_page.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pages - restaurant_detail_page.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %390
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : import 'package:restaurant_tour/models/restaurant.dart';
+       3              : import 'package:restaurant_tour/widgets/widgets.dart';
+       4              : import '../theme/text.dart';
+       5              : import '../widgets/appbar.dart';
+       6              : 
+       7              : class RestaurantDetailPage extends StatelessWidget {
+       8            0 :   const RestaurantDetailPage({super.key, required this.restaurant});
+       9              :   final Restaurant restaurant;
+      10            0 :   @override
+      11              :   Widget build(BuildContext context) {
+      12            0 :     return Scaffold(
+      13            0 :       appBar: RestaurantDetailAppBar(
+      14            0 :         restaurant: restaurant,
+      15              :       ),
+      16            0 :       body: SafeArea(
+      17            0 :         child: LayoutBuilder(
+      18            0 :           builder: (BuildContext context, BoxConstraints constraints) {
+      19            0 :             return SingleChildScrollView(
+      20            0 :               child: Column(
+      21            0 :                 children: [
+      22            0 :                   HeroImageWidget(
+      23            0 :                     restaurant: restaurant,
+      24            0 :                     width: constraints.maxWidth,
+      25            0 :                     height: constraints.maxHeight * 0.4,
+      26              :                   ),
+      27            0 :                   Padding(
+      28              :                     padding: const EdgeInsets.all(24),
+      29            0 :                     child: Column(
+      30              :                       mainAxisAlignment: MainAxisAlignment.start,
+      31              :                       crossAxisAlignment: CrossAxisAlignment.start,
+      32            0 :                       children: [
+      33            0 :                         BuildCategoryStatusRow(restaurant: restaurant),
+      34              :                         const SizedBox(
+      35              :                           height: spacingXL,
+      36              :                         ),
+      37            0 :                         buildDivider(),
+      38              :                         const SizedBox(
+      39              :                           height: spacingXL,
+      40              :                         ),
+      41            0 :                         Text(
+      42              :                           'Address',
+      43            0 :                           style: Theme.of(context).textTheme.bodySmall,
+      44              :                           textAlign: TextAlign.start,
+      45              :                         ),
+      46              :                         const SizedBox(
+      47              :                           height: spacingXL,
+      48              :                         ),
+      49            0 :                         Text(
+      50            0 :                           restaurant.location?.formattedAddress ??
+      51              :                               'No Address Informed',
+      52            0 :                           style: Theme.of(context).textTheme.displayLarge,
+      53              :                         ),
+      54              :                         const SizedBox(
+      55              :                           height: spacingXL,
+      56              :                         ),
+      57            0 :                         buildDivider(),
+      58            0 :                         restaurant.rating != null
+      59            0 :                             ? BuildRatingSection(
+      60            0 :                                 restaurant: restaurant,
+      61              :                               )
+      62            0 :                             : Container(),
+      63              :                       ],
+      64              :                     ),
+      65              :                   ),
+      66              :                 ],
+      67              :               ),
+      68              :             );
+      69              :           },
+      70              :         ),
+      71              :       ),
+      72              :     );
+      73              :   }
+      74              : }
+      75              : 
+      76              : class BuildCategoryStatusRow extends StatelessWidget {
+      77            0 :   const BuildCategoryStatusRow({
+      78              :     super.key,
+      79              :     required this.restaurant,
+      80              :   });
+      81              : 
+      82              :   final Restaurant restaurant;
+      83              : 
+      84            0 :   @override
+      85              :   Widget build(BuildContext context) {
+      86            0 :     return Row(
+      87              :       mainAxisSize: MainAxisSize.max,
+      88            0 :       children: [
+      89            0 :         Expanded(
+      90            0 :           child: PriceAndClassificationRowWidget(
+      91            0 :             restaurant: restaurant,
+      92              :           ),
+      93              :         ),
+      94              :         const Spacer(),
+      95            0 :         OpenStatusWidget(
+      96            0 :           isOpen: restaurant.isOpen,
+      97              :         ),
+      98              :       ],
+      99              :     );
+     100              :   }
+     101              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/restaurant_list_page.dart.func-c.html b/coverage_report/pages/restaurant_list_page.dart.func-c.html new file mode 100644 index 0000000..b542212 --- /dev/null +++ b/coverage_report/pages/restaurant_list_page.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - pages/restaurant_list_page.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pages - restaurant_list_page.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:78.4 %5140
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/restaurant_list_page.dart.func.html b/coverage_report/pages/restaurant_list_page.dart.func.html new file mode 100644 index 0000000..674b3aa --- /dev/null +++ b/coverage_report/pages/restaurant_list_page.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - pages/restaurant_list_page.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pages - restaurant_list_page.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:78.4 %5140
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/pages/restaurant_list_page.dart.gcov.html b/coverage_report/pages/restaurant_list_page.dart.gcov.html new file mode 100644 index 0000000..f7d717f --- /dev/null +++ b/coverage_report/pages/restaurant_list_page.dart.gcov.html @@ -0,0 +1,205 @@ + + + + + + + LCOV - lcov.info - pages/restaurant_list_page.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - pages - restaurant_list_page.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:78.4 %5140
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : import 'package:flutter_bloc/flutter_bloc.dart';
+       3              : import 'package:restaurant_tour/cubit/cubit.dart';
+       4              : import 'package:restaurant_tour/models/models.dart';
+       5              : import '../widgets/widgets.dart';
+       6              : import 'restaurant_detail_page.dart';
+       7              : 
+       8              : class RestaurantListPageView extends StatelessWidget {
+       9            1 :   const RestaurantListPageView({super.key});
+      10              : 
+      11            1 :   @override
+      12              :   Widget build(BuildContext context) {
+      13            1 :     return LayoutBuilder(
+      14            1 :       builder: (context, constraints) {
+      15            1 :         return BlocBuilder<RestaurantCubit, RestaurantState>(
+      16            0 :           buildWhen: (previous, current) =>
+      17            0 :               current is LoadingRestaurantsState ||
+      18            0 :               current is RestaurantsLoadedState ||
+      19            0 :               current is ErrorState,
+      20            1 :           builder: (context, state) {
+      21            1 :             if (state is LoadingRestaurantsState) {
+      22              :               return const Center(child: CircularProgressIndicator());
+      23            1 :             } else if (state is ErrorState) {
+      24            0 :               return Center(
+      25            0 :                 child: Text(state.message),
+      26              :               );
+      27              :             }
+      28            1 :             if (state is RestaurantsLoadedState) {
+      29            1 :               return ListView.builder(
+      30            3 :                 itemCount: state.result.restaurants?.length,
+      31            1 :                 itemBuilder: (BuildContext context, int index) {
+      32            1 :                   return Row(
+      33              :                     mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+      34            1 :                     children: [
+      35            1 :                       ListTile(
+      36            3 :                         restaurant: state.result.restaurants!.elementAt(index),
+      37              :                         constraints: constraints,
+      38              :                       ),
+      39              :                     ],
+      40              :                   );
+      41              :                 },
+      42              :               );
+      43              :             }
+      44            0 :             return Container();
+      45              :           },
+      46              :         );
+      47              :       },
+      48              :     );
+      49              :   }
+      50              : }
+      51              : 
+      52              : class ListTile extends StatelessWidget {
+      53            1 :   const ListTile({
+      54              :     super.key,
+      55              :     required this.restaurant,
+      56              :     required this.constraints,
+      57              :   });
+      58              :   final Restaurant restaurant;
+      59              :   final BoxConstraints constraints;
+      60              : 
+      61            1 :   @override
+      62              :   Widget build(BuildContext context) {
+      63            1 :     return GestureDetector(
+      64            0 :       onTap: () {
+      65            0 :         Navigator.push(
+      66              :           context,
+      67            0 :           MaterialPageRoute(
+      68            0 :             builder: (context) => RestaurantDetailPage(restaurant: restaurant),
+      69              :           ),
+      70              :         );
+      71              :       },
+      72            1 :       child: Container(
+      73            2 :         width: constraints.maxWidth,
+      74              :         margin: const EdgeInsets.only(bottom: 8, top: 8),
+      75              :         padding: const EdgeInsets.all(16),
+      76            1 :         decoration: BoxDecoration(
+      77              :           color: Colors.white,
+      78            2 :           border: Border.all(color: Colors.grey.shade300),
+      79            1 :           borderRadius: BorderRadius.circular(9),
+      80            1 :           boxShadow: [
+      81            1 :             BoxShadow(
+      82            1 :               color: Colors.grey.shade200,
+      83              :               blurRadius: 3,
+      84              :               offset: const Offset(0, 2),
+      85              :             ),
+      86              :           ],
+      87              :         ),
+      88            1 :         child: Row(
+      89            1 :           children: [
+      90            1 :             Column(
+      91            1 :               children: [
+      92            1 :                 HeroImageWidget(
+      93            1 :                   restaurant: restaurant,
+      94              :                   width: 90,
+      95              :                   height: 90,
+      96              :                   borderRadius: 9.0,
+      97              :                 ),
+      98              :               ],
+      99              :             ),
+     100              :             const Spacer(
+     101              :               flex: 1,
+     102              :             ),
+     103            1 :             Flexible(
+     104              :               flex: 10,
+     105            1 :               child: Column(
+     106              :                 mainAxisAlignment: MainAxisAlignment.start,
+     107              :                 crossAxisAlignment: CrossAxisAlignment.start,
+     108            1 :                 children: [
+     109            1 :                   Text(
+     110            2 :                     restaurant.name ?? '',
+     111              :                     maxLines: 2,
+     112              :                   ),
+     113              :                   const SizedBox(
+     114              :                     height: 10,
+     115              :                   ),
+     116            2 :                   PriceAndClassificationRowWidget(restaurant: restaurant),
+     117              :                   const SizedBox(
+     118              :                     height: 10,
+     119              :                   ),
+     120            2 :                   RatingAndOpenStatusWidget(restaurant: restaurant)
+     121              :                 ],
+     122              :               ),
+     123              :             ),
+     124              :           ],
+     125              :         ),
+     126              :       ),
+     127              :     );
+     128              :   }
+     129              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/repositories/index-sort-f.html b/coverage_report/repositories/index-sort-f.html new file mode 100644 index 0000000..ed24dc9 --- /dev/null +++ b/coverage_report/repositories/index-sort-f.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - repositories + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - repositoriesCoverageTotalHit
Test:lcov.infoLines:46.2 %136
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
yelp_repository.dart +
46.2%46.2%
+
46.2 %136-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/repositories/index-sort-l.html b/coverage_report/repositories/index-sort-l.html new file mode 100644 index 0000000..641e900 --- /dev/null +++ b/coverage_report/repositories/index-sort-l.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - repositories + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - repositoriesCoverageTotalHit
Test:lcov.infoLines:46.2 %136
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
yelp_repository.dart +
46.2%46.2%
+
46.2 %136-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/repositories/index.html b/coverage_report/repositories/index.html new file mode 100644 index 0000000..2e05c70 --- /dev/null +++ b/coverage_report/repositories/index.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - repositories + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - repositoriesCoverageTotalHit
Test:lcov.infoLines:46.2 %136
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
yelp_repository.dart +
46.2%46.2%
+
46.2 %136-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/repositories/yelp_repository.dart.func-c.html b/coverage_report/repositories/yelp_repository.dart.func-c.html new file mode 100644 index 0000000..29fcb4b --- /dev/null +++ b/coverage_report/repositories/yelp_repository.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - repositories/yelp_repository.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - repositories - yelp_repository.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:46.2 %136
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/repositories/yelp_repository.dart.func.html b/coverage_report/repositories/yelp_repository.dart.func.html new file mode 100644 index 0000000..7a85301 --- /dev/null +++ b/coverage_report/repositories/yelp_repository.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - repositories/yelp_repository.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - repositories - yelp_repository.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:46.2 %136
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/repositories/yelp_repository.dart.gcov.html b/coverage_report/repositories/yelp_repository.dart.gcov.html new file mode 100644 index 0000000..67124a2 --- /dev/null +++ b/coverage_report/repositories/yelp_repository.dart.gcov.html @@ -0,0 +1,199 @@ + + + + + + + LCOV - lcov.info - repositories/yelp_repository.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - repositories - yelp_repository.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:46.2 %136
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:dio/dio.dart';
+       2              : import 'package:flutter/foundation.dart';
+       3              : import 'package:restaurant_tour/models/restaurant.dart';
+       4              : import 'package:restaurant_tour/repositories/sample_json.dart';
+       5              : 
+       6              : const _apiKey =
+       7              :     'GzcIFZrKe4aMmED9FS9ObPxFP4vAhEOW2wN9usDA0zazBimbxQ8O2LdcpwMUcpkCU1ZYxF-LK_jWygZgGvfeE_5jSulY1XdUPs09j1FCwDtXQmyD_emQYuOEMBHKZnYx';
+       8              : 
+       9              : class YelpRepository {
+      10              :   late Dio dio;
+      11              : 
+      12            1 :   YelpRepository({
+      13              :     @visibleForTesting Dio? dio,
+      14              :   }) : dio = dio ??
+      15            1 :             Dio(
+      16            1 :               BaseOptions(
+      17              :                 baseUrl: 'https://api.yelp.com',
+      18            1 :                 headers: {
+      19              :                   'Authorization': 'Bearer $_apiKey',
+      20              :                   'Content-Type': 'application/graphql',
+      21              :                 },
+      22              :               ),
+      23              :             );
+      24              : 
+      25              :   /// Returns a response in this shape
+      26              :   /// {
+      27              :   /// "data": {
+      28              :   ///   "search": {
+      29              :   ///     "total": 5056,
+      30              :   ///     "business": [
+      31              :   ///       {
+      32              :   ///         "id": "faPVqws-x-5k2CQKDNtHxw",
+      33              :   ///         "name": "Yardbird Southern Table & Bar",
+      34              :   ///         "price": "$$",
+      35              :   ///         "rating": 4.5,
+      36              :   ///         "photos": [
+      37              :   ///           "https:///s3-media4.fl.yelpcdn.com/bphoto/_zXRdYX4r1OBfF86xKMbDw/o.jpg"
+      38              :   ///         ],
+      39              :   ///         "reviews": [
+      40              :   ///           {
+      41              :   ///             "id": "sjZoO8wcK1NeGJFDk5i82Q",
+      42              :   ///             "rating": 5,
+      43              :   ///             "user": {
+      44              :   ///               "id": "BuBCkWFNT_O2dbSnBZvpoQ",
+      45              :   ///               "image_url": "https:///s3-media2.fl.yelpcdn.com/photo/v8tbTjYaFvkzh1d7iE-pcQ/o.jpg",
+      46              :   ///               "name": "Gina T.",
+      47              :   ///               "text": "I love this place! The food is amazing and the service is great."
+      48              :   ///             }
+      49              :   ///           },
+      50              :   ///           {
+      51              :   ///             "id": "okpO9hfpxQXssbTZTKq9hA",
+      52              :   ///             "rating": 5,
+      53              :   ///             "user": {
+      54              :   ///               "id": "0x9xu_b0Ct_6hG6jaxpztw",
+      55              :   ///               "image_url": "https:///s3-media3.fl.yelpcdn.com/photo/gjz8X6tqE3e4praK4HfCiA/o.jpg",
+      56              :   ///               "name": "Crystal L.",
+      57              :   ///               "text": "Greate place to eat"
+      58              :   ///             }
+      59              :   ///           },
+      60              :   ///        ...
+      61              :   ///     ]
+      62              :   ///   }
+      63              :   /// }
+      64              :   ///
+      65              :   ///
+      66            1 :   RestaurantQueryResult getRestaurantsFromCache({int offset = 0}) {
+      67              :     try {
+      68            3 :       return RestaurantQueryResult.fromJson(sample['data']['search']);
+      69              :     } catch (e) {
+      70            0 :       throw Exception();
+      71              :     }
+      72              :   }
+      73              : 
+      74            0 :   Future<RestaurantQueryResult?> getRestaurants({int offset = 0}) async {
+      75              :     try {
+      76            0 :       final response = await dio.post<Map<String, dynamic>>(
+      77              :         '/v3/graphql',
+      78            0 :         data: _getQuery(offset),
+      79              :       );
+      80              :       // saveToJson(response.data!['data']['search'], 'datastore.json');
+      81            0 :       return RestaurantQueryResult.fromJson(response.data!['data']['search']);
+      82              :     } catch (e) {
+      83              :       return null;
+      84              :     }
+      85              :   }
+      86              : 
+      87            0 :   String _getQuery(int offset) {
+      88              :     return '''
+      89              : query getRestaurants {
+      90              :   search(location: "Las Vegas", limit: 20, offset: $offset) {
+      91              :     total    
+      92              :     business {
+      93              :       id
+      94              :       name
+      95              :       price
+      96              :       rating
+      97              :       photos
+      98              :       reviews {
+      99              :         id
+     100              :         rating
+     101              :         text
+     102              :         user {
+     103              :           id
+     104              :           image_url
+     105              :           name
+     106              :         }
+     107              :       }
+     108              :       categories {
+     109              :         title
+     110              :         alias
+     111              :       }
+     112              :       hours {
+     113              :         is_open_now
+     114              :       }
+     115              :       location {
+     116              :         formatted_address
+     117              :       }
+     118              :     }
+     119              :   }
+     120              : }
+     121            0 : ''';
+     122              :   }
+     123              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/ruby.png b/coverage_report/ruby.png new file mode 100644 index 0000000000000000000000000000000000000000..991b6d4ec9e78be165e3ef757eed1aada287364d GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^FceV#7`HfI^%F z9+AZi4BSE>%y{W;-5;PJOS+@4BLl<6e(pbstUx|nfKQ0)e^Y%R^MdiLxj>4`)5S5Q b;#P73kj=!v_*DHKNFRfztDnm{r-UW|iOwIS literal 0 HcmV?d00001 diff --git a/coverage_report/snow.png b/coverage_report/snow.png new file mode 100644 index 0000000000000000000000000000000000000000..2cdae107fceec6e7f02ac7acb4a34a82a540caa5 GIT binary patch literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga>?NMQuI!iC1^MM!lvI6;R0X`wF|Ns97GD8ntt^-nBo-U3d c6}OTTfNUlP#;5A{K>8RwUHx3vIVCg!071?oo&W#< literal 0 HcmV?d00001 diff --git a/coverage_report/updown.png b/coverage_report/updown.png new file mode 100644 index 0000000000000000000000000000000000000000..aa56a238b3e6c435265250f9266cd1b8caba0f20 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^AT}Qd8;}%R+`Ae`*?77*hG?8mPH5^{)z4*}Q$iB}huR`+ literal 0 HcmV?d00001 diff --git a/coverage_report/usecases/fetch_restaurants.dart.func-c.html b/coverage_report/usecases/fetch_restaurants.dart.func-c.html new file mode 100644 index 0000000..1cee42c --- /dev/null +++ b/coverage_report/usecases/fetch_restaurants.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - usecases/fetch_restaurants.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - usecases - fetch_restaurants.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %80
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/usecases/fetch_restaurants.dart.func.html b/coverage_report/usecases/fetch_restaurants.dart.func.html new file mode 100644 index 0000000..5a0491f --- /dev/null +++ b/coverage_report/usecases/fetch_restaurants.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - usecases/fetch_restaurants.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - usecases - fetch_restaurants.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %80
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/usecases/fetch_restaurants.dart.gcov.html b/coverage_report/usecases/fetch_restaurants.dart.gcov.html new file mode 100644 index 0000000..1cc9ab9 --- /dev/null +++ b/coverage_report/usecases/fetch_restaurants.dart.gcov.html @@ -0,0 +1,95 @@ + + + + + + + LCOV - lcov.info - usecases/fetch_restaurants.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - usecases - fetch_restaurants.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %80
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:restaurant_tour/models/models.dart';
+       2              : import 'package:restaurant_tour/repositories/yelp_repository.dart';
+       3              : 
+       4              : class FetchRestaurants {
+       5              :   final YelpRepository repository;
+       6              : 
+       7            0 :   FetchRestaurants({required this.repository});
+       8            0 :   Future<RestaurantQueryResult?> getRestaurants() async => await repository
+       9            0 :       .getRestaurantsFromCache(); //CHANGE THIS LATER TO FETCH FROM THE REAL API
+      10            0 :   Future<RestaurantQueryResult?> getRestaurantsFromCache() async =>
+      11            0 :       await repository.getRestaurantsFromCache();
+      12              : 
+      13            0 :   Future<List<String>> getFavoriteRestaurants() async {
+      14              :     //this could be fetched from anywhere later... a shared prefs or another database
+      15            0 :     await Future.delayed(const Duration(milliseconds: 500));
+      16              : 
+      17            0 :     return ['vHz2RLtfUMVRPFmd7VBEHA'];
+      18              :   }
+      19              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/usecases/index-sort-f.html b/coverage_report/usecases/index-sort-f.html new file mode 100644 index 0000000..0e67ce5 --- /dev/null +++ b/coverage_report/usecases/index-sort-f.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - usecases + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - usecasesCoverageTotalHit
Test:lcov.infoLines:0.0 %80
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
fetch_restaurants.dart +
0.0%
+
0.0 %8-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/usecases/index-sort-l.html b/coverage_report/usecases/index-sort-l.html new file mode 100644 index 0000000..2567e96 --- /dev/null +++ b/coverage_report/usecases/index-sort-l.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - usecases + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - usecasesCoverageTotalHit
Test:lcov.infoLines:0.0 %80
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
fetch_restaurants.dart +
0.0%
+
0.0 %8-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/usecases/index.html b/coverage_report/usecases/index.html new file mode 100644 index 0000000..13e12ea --- /dev/null +++ b/coverage_report/usecases/index.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - usecases + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - usecasesCoverageTotalHit
Test:lcov.infoLines:0.0 %80
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
fetch_restaurants.dart +
0.0%
+
0.0 %8-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/utils/get_random_avatar.dart.func-c.html b/coverage_report/utils/get_random_avatar.dart.func-c.html new file mode 100644 index 0000000..0eb0807 --- /dev/null +++ b/coverage_report/utils/get_random_avatar.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - utils/get_random_avatar.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils - get_random_avatar.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %40
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/utils/get_random_avatar.dart.func.html b/coverage_report/utils/get_random_avatar.dart.func.html new file mode 100644 index 0000000..7dafbab --- /dev/null +++ b/coverage_report/utils/get_random_avatar.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - utils/get_random_avatar.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils - get_random_avatar.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %40
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/utils/get_random_avatar.dart.gcov.html b/coverage_report/utils/get_random_avatar.dart.gcov.html new file mode 100644 index 0000000..d8f783e --- /dev/null +++ b/coverage_report/utils/get_random_avatar.dart.gcov.html @@ -0,0 +1,97 @@ + + + + + + + LCOV - lcov.info - utils/get_random_avatar.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utils - get_random_avatar.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %40
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'dart:math';
+       2              : import 'package:flutter/material.dart';
+       3              : 
+       4            0 : ImageProvider getRandomAvatar() {
+       5              :   // Lista de avatares
+       6            0 :   final List<String> avatars = [
+       7              :     'assets/avatars/av1.png',
+       8              :     'assets/avatars/av2.png',
+       9              :     'assets/avatars/av3.png',
+      10              :     'assets/avatars/av4.png',
+      11              :     'assets/avatars/av5.png',
+      12              :     'assets/avatars/av6.png',
+      13              :     'assets/avatars/av7.png',
+      14              :   ];
+      15              : 
+      16              :   // Seleciona um índice aleatório
+      17            0 :   final randomIndex = Random().nextInt(avatars.length);
+      18              : 
+      19              :   // Retorna a imagem correspondente
+      20            0 :   return AssetImage(avatars[randomIndex]);
+      21              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/utils/index-sort-f.html b/coverage_report/utils/index-sort-f.html new file mode 100644 index 0000000..09b74f8 --- /dev/null +++ b/coverage_report/utils/index-sort-f.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - utils + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utilsCoverageTotalHit
Test:lcov.infoLines:0.0 %40
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
get_random_avatar.dart +
0.0%
+
0.0 %4-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/utils/index-sort-l.html b/coverage_report/utils/index-sort-l.html new file mode 100644 index 0000000..b075281 --- /dev/null +++ b/coverage_report/utils/index-sort-l.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - utils + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utilsCoverageTotalHit
Test:lcov.infoLines:0.0 %40
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
get_random_avatar.dart +
0.0%
+
0.0 %4-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/utils/index.html b/coverage_report/utils/index.html new file mode 100644 index 0000000..d657f72 --- /dev/null +++ b/coverage_report/utils/index.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - utils + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - utilsCoverageTotalHit
Test:lcov.infoLines:0.0 %40
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
get_random_avatar.dart +
0.0%
+
0.0 %4-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/appbar.dart.func-c.html b/coverage_report/widgets/appbar.dart.func-c.html new file mode 100644 index 0000000..0f1c097 --- /dev/null +++ b/coverage_report/widgets/appbar.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/appbar.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - appbar.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %150
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/appbar.dart.func.html b/coverage_report/widgets/appbar.dart.func.html new file mode 100644 index 0000000..19197e0 --- /dev/null +++ b/coverage_report/widgets/appbar.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/appbar.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - appbar.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %150
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/appbar.dart.gcov.html b/coverage_report/widgets/appbar.dart.gcov.html new file mode 100644 index 0000000..51eeee5 --- /dev/null +++ b/coverage_report/widgets/appbar.dart.gcov.html @@ -0,0 +1,115 @@ + + + + + + + LCOV - lcov.info - widgets/appbar.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - appbar.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %150
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : import 'package:flutter_bloc/flutter_bloc.dart';
+       3              : import 'package:restaurant_tour/cubit/restaurant_cubit.dart';
+       4              : import 'package:restaurant_tour/models/restaurant.dart';
+       5              : 
+       6              : class RestaurantDetailAppBar extends StatelessWidget
+       7              :     implements PreferredSizeWidget {
+       8              :   final Restaurant restaurant;
+       9              : 
+      10            0 :   const RestaurantDetailAppBar({super.key, required this.restaurant});
+      11              : 
+      12            0 :   @override
+      13              :   Widget build(BuildContext context) {
+      14              :     final isFavorite = context
+      15            0 :         .watch<RestaurantCubit>()
+      16            0 :         .state
+      17            0 :         .favoriteRestaurants
+      18            0 :         .contains(restaurant.id);
+      19            0 :     return AppBar(
+      20            0 :       title: Text(restaurant.name ?? ''),
+      21            0 :       actions: [
+      22            0 :         Padding(
+      23              :           padding: const EdgeInsets.only(right: 13.0),
+      24            0 :           child: IconButton(
+      25              :             icon: isFavorite
+      26              :                 ? const Icon(Icons.favorite)
+      27              :                 : const Icon(Icons.favorite_border_outlined),
+      28            0 :             onPressed: () => context
+      29            0 :                 .read<RestaurantCubit>()
+      30            0 :                 .favoriteAResturant(restaurant.id!),
+      31              :           ),
+      32              :         ),
+      33              :       ],
+      34              :     );
+      35              :   }
+      36              : 
+      37            0 :   @override
+      38              :   Size get preferredSize => const Size.fromHeight(kToolbarHeight);
+      39              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/divider.dart.func-c.html b/coverage_report/widgets/divider.dart.func-c.html new file mode 100644 index 0000000..a83b291 --- /dev/null +++ b/coverage_report/widgets/divider.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/divider.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - divider.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %10
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/divider.dart.func.html b/coverage_report/widgets/divider.dart.func.html new file mode 100644 index 0000000..76f00ad --- /dev/null +++ b/coverage_report/widgets/divider.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/divider.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - divider.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %10
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/divider.dart.gcov.html b/coverage_report/widgets/divider.dart.gcov.html new file mode 100644 index 0000000..b0b486a --- /dev/null +++ b/coverage_report/widgets/divider.dart.gcov.html @@ -0,0 +1,83 @@ + + + + + + + LCOV - lcov.info - widgets/divider.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - divider.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %10
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : 
+       3            0 : Divider buildDivider() {
+       4              :   return const Divider(
+       5              :     thickness: 0.3,
+       6              :   );
+       7              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/hero_image_widget.dart.func-c.html b/coverage_report/widgets/hero_image_widget.dart.func-c.html new file mode 100644 index 0000000..c42269f --- /dev/null +++ b/coverage_report/widgets/hero_image_widget.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/hero_image_widget.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - hero_image_widget.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %1010
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/hero_image_widget.dart.func.html b/coverage_report/widgets/hero_image_widget.dart.func.html new file mode 100644 index 0000000..b99ae6a --- /dev/null +++ b/coverage_report/widgets/hero_image_widget.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/hero_image_widget.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - hero_image_widget.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %1010
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/hero_image_widget.dart.gcov.html b/coverage_report/widgets/hero_image_widget.dart.gcov.html new file mode 100644 index 0000000..8066ea3 --- /dev/null +++ b/coverage_report/widgets/hero_image_widget.dart.gcov.html @@ -0,0 +1,107 @@ + + + + + + + LCOV - lcov.info - widgets/hero_image_widget.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - hero_image_widget.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %1010
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : 
+       3              : import '../models/restaurant.dart';
+       4              : 
+       5              : class HeroImageWidget extends StatelessWidget {
+       6            1 :   const HeroImageWidget(
+       7              :       {super.key,
+       8              :       required this.restaurant,
+       9              :       this.borderRadius = 0,
+      10              :       required this.width,
+      11              :       required this.height});
+      12              :   final Restaurant restaurant;
+      13              :   final double borderRadius;
+      14              :   final double width;
+      15              :   final double height;
+      16            1 :   @override
+      17              :   Widget build(BuildContext context) {
+      18            1 :     return Hero(
+      19            3 :       tag: restaurant.id.toString(),
+      20            1 :       child: ClipRRect(
+      21            2 :         borderRadius: BorderRadius.circular(borderRadius),
+      22            1 :         child: Image.network(
+      23            2 :           restaurant.heroImage,
+      24              :           fit: BoxFit.cover,
+      25            1 :           width: width,
+      26            1 :           height: height,
+      27              :         ),
+      28              :       ),
+      29              :     );
+      30              :   }
+      31              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/index-sort-f.html b/coverage_report/widgets/index-sort-f.html new file mode 100644 index 0000000..0b38746 --- /dev/null +++ b/coverage_report/widgets/index-sort-f.html @@ -0,0 +1,189 @@ + + + + + + + LCOV - lcov.info - widgets + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgetsCoverageTotalHit
Test:lcov.infoLines:45.5 %10146
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
appbar.dart +
0.0%
+
0.0 %15-
divider.dart +
0.0%
+
0.0 %1-
hero_image_widget.dart +
100.0%
+
100.0 %1010-
rataurant_open_status.dart +
100.0%
+
100.0 %99-
rating_and_open_status_widget.dart +
100.0%
+
100.0 %88-
rating_widget.dart +
100.0%
+
100.0 %88-
restaurant_details.dart +
100.0%
+
100.0 %1111-
restaurant_ratings_review_section.dart +
0.0%
+
0.0 %39-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/index-sort-l.html b/coverage_report/widgets/index-sort-l.html new file mode 100644 index 0000000..1a17552 --- /dev/null +++ b/coverage_report/widgets/index-sort-l.html @@ -0,0 +1,189 @@ + + + + + + + LCOV - lcov.info - widgets + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgetsCoverageTotalHit
Test:lcov.infoLines:45.5 %10146
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
divider.dart +
0.0%
+
0.0 %1-
appbar.dart +
0.0%
+
0.0 %15-
restaurant_ratings_review_section.dart +
0.0%
+
0.0 %39-
rating_and_open_status_widget.dart +
100.0%
+
100.0 %88-
rating_widget.dart +
100.0%
+
100.0 %88-
rataurant_open_status.dart +
100.0%
+
100.0 %99-
hero_image_widget.dart +
100.0%
+
100.0 %1010-
restaurant_details.dart +
100.0%
+
100.0 %1111-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/index.html b/coverage_report/widgets/index.html new file mode 100644 index 0000000..12ea64e --- /dev/null +++ b/coverage_report/widgets/index.html @@ -0,0 +1,189 @@ + + + + + + + LCOV - lcov.info - widgets + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgetsCoverageTotalHit
Test:lcov.infoLines:45.5 %10146
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

File Sort by file nameLine Coverage Sort by line coverageFunction Coverage Sort by function coverage
Rate Total Hit Rate Total Hit
appbar.dart +
0.0%
+
0.0 %15-
divider.dart +
0.0%
+
0.0 %1-
hero_image_widget.dart +
100.0%
+
100.0 %1010-
rataurant_open_status.dart +
100.0%
+
100.0 %99-
rating_and_open_status_widget.dart +
100.0%
+
100.0 %88-
rating_widget.dart +
100.0%
+
100.0 %88-
restaurant_details.dart +
100.0%
+
100.0 %1111-
restaurant_ratings_review_section.dart +
0.0%
+
0.0 %39-
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/rataurant_open_status.dart.func-c.html b/coverage_report/widgets/rataurant_open_status.dart.func-c.html new file mode 100644 index 0000000..da40adf --- /dev/null +++ b/coverage_report/widgets/rataurant_open_status.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/rataurant_open_status.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - rataurant_open_status.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %99
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/rataurant_open_status.dart.func.html b/coverage_report/widgets/rataurant_open_status.dart.func.html new file mode 100644 index 0000000..358daad --- /dev/null +++ b/coverage_report/widgets/rataurant_open_status.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/rataurant_open_status.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - rataurant_open_status.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %99
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/rataurant_open_status.dart.gcov.html b/coverage_report/widgets/rataurant_open_status.dart.gcov.html new file mode 100644 index 0000000..797dee0 --- /dev/null +++ b/coverage_report/widgets/rataurant_open_status.dart.gcov.html @@ -0,0 +1,102 @@ + + + + + + + LCOV - lcov.info - widgets/rataurant_open_status.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - rataurant_open_status.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %99
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : 
+       3              : class OpenStatusWidget extends StatelessWidget {
+       4            1 :   const OpenStatusWidget({super.key, required this.isOpen});
+       5              :   final bool isOpen;
+       6            1 :   @override
+       7              :   Widget build(BuildContext context) {
+       8            1 :     return Row(
+       9              :       mainAxisSize: MainAxisSize.min,
+      10            1 :       children: [
+      11            1 :         Text(
+      12            1 :           isOpen ? 'Open Now' : 'Closed Now',
+      13            3 :           style: Theme.of(context).textTheme.displaySmall,
+      14              :         ),
+      15              :         const SizedBox(
+      16              :           width: 8,
+      17              :         ),
+      18            1 :         Icon(
+      19              :           Icons.circle,
+      20              :           size: 8.0,
+      21            1 :           color: isOpen ? Colors.green : Colors.red,
+      22              :         )
+      23              :       ],
+      24              :     );
+      25              :   }
+      26              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html b/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html new file mode 100644 index 0000000..aa5a870 --- /dev/null +++ b/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/rating_and_open_status_widget.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - rating_and_open_status_widget.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %88
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/rating_and_open_status_widget.dart.func.html b/coverage_report/widgets/rating_and_open_status_widget.dart.func.html new file mode 100644 index 0000000..8a858a0 --- /dev/null +++ b/coverage_report/widgets/rating_and_open_status_widget.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/rating_and_open_status_widget.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - rating_and_open_status_widget.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %88
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html b/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html new file mode 100644 index 0000000..7c3bc79 --- /dev/null +++ b/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html @@ -0,0 +1,105 @@ + + + + + + + LCOV - lcov.info - widgets/rating_and_open_status_widget.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - rating_and_open_status_widget.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %88
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/widgets.dart';
+       2              : 
+       3              : import '../models/restaurant.dart';
+       4              : import 'rating_widget.dart';
+       5              : import 'widgets.dart';
+       6              : 
+       7              : class RatingAndOpenStatusWidget extends StatelessWidget {
+       8            1 :   const RatingAndOpenStatusWidget({
+       9              :     super.key,
+      10              :     required this.restaurant,
+      11              :   });
+      12              : 
+      13              :   final Restaurant restaurant;
+      14              : 
+      15            1 :   @override
+      16              :   Widget build(BuildContext context) {
+      17            1 :     return Row(
+      18            1 :       children: [
+      19            1 :         StarRating(
+      20            3 :           rating: restaurant.rating?.round() ?? 0,
+      21              :         ),
+      22              :         const Spacer(),
+      23            1 :         OpenStatusWidget(
+      24            2 :           isOpen: restaurant.isOpen,
+      25              :         )
+      26              :       ],
+      27              :     );
+      28              :   }
+      29              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/rating_widget.dart.func-c.html b/coverage_report/widgets/rating_widget.dart.func-c.html new file mode 100644 index 0000000..e5147dc --- /dev/null +++ b/coverage_report/widgets/rating_widget.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/rating_widget.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - rating_widget.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %88
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/rating_widget.dart.func.html b/coverage_report/widgets/rating_widget.dart.func.html new file mode 100644 index 0000000..1cce6bf --- /dev/null +++ b/coverage_report/widgets/rating_widget.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/rating_widget.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - rating_widget.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %88
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/rating_widget.dart.gcov.html b/coverage_report/widgets/rating_widget.dart.gcov.html new file mode 100644 index 0000000..3ddc0cf --- /dev/null +++ b/coverage_report/widgets/rating_widget.dart.gcov.html @@ -0,0 +1,106 @@ + + + + + + + LCOV - lcov.info - widgets/rating_widget.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - rating_widget.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %88
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : 
+       3              : import '../theme/colors.dart';
+       4              : 
+       5              : class StarRating extends StatelessWidget {
+       6              :   final int rating;
+       7              :   final double starSize;
+       8              :   final Color starColor;
+       9              : 
+      10            1 :   const StarRating({
+      11              :     super.key,
+      12              :     required this.rating, // Rating should be between 0 to 5
+      13              :     this.starSize = 12.0,
+      14              :     this.starColor = ThemeColors.starColor,
+      15            3 :   }) : assert(rating >= 0 && rating <= 5);
+      16              : 
+      17            1 :   @override
+      18              :   Widget build(BuildContext context) {
+      19            1 :     return Row(
+      20              :       mainAxisSize: MainAxisSize.min,
+      21            3 :       children: List.generate(rating, (index) {
+      22            1 :         return Icon(
+      23              :           Icons.star,
+      24            1 :           size: starSize,
+      25            1 :           color: starColor,
+      26              :         );
+      27              :       }),
+      28              :     );
+      29              :   }
+      30              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/restaurant_details.dart.func-c.html b/coverage_report/widgets/restaurant_details.dart.func-c.html new file mode 100644 index 0000000..7da6982 --- /dev/null +++ b/coverage_report/widgets/restaurant_details.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/restaurant_details.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - restaurant_details.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %1111
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/restaurant_details.dart.func.html b/coverage_report/widgets/restaurant_details.dart.func.html new file mode 100644 index 0000000..f428c3e --- /dev/null +++ b/coverage_report/widgets/restaurant_details.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/restaurant_details.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - restaurant_details.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %1111
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/restaurant_details.dart.gcov.html b/coverage_report/widgets/restaurant_details.dart.gcov.html new file mode 100644 index 0000000..916ccea --- /dev/null +++ b/coverage_report/widgets/restaurant_details.dart.gcov.html @@ -0,0 +1,110 @@ + + + + + + + LCOV - lcov.info - widgets/restaurant_details.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - restaurant_details.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:100.0 %1111
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : import 'package:restaurant_tour/models/restaurant.dart';
+       3              : 
+       4              : class PriceAndClassificationRowWidget extends StatelessWidget {
+       5            1 :   const PriceAndClassificationRowWidget({
+       6              :     super.key,
+       7              :     required this.restaurant,
+       8              :   });
+       9              : 
+      10              :   final Restaurant restaurant;
+      11              : 
+      12            1 :   @override
+      13              :   Widget build(BuildContext context) {
+      14            1 :     return Row(
+      15            1 :       children: [
+      16            1 :         Text(
+      17            2 :           restaurant.price ?? '-',
+      18            3 :           style: Theme.of(context).textTheme.bodySmall,
+      19              :         ),
+      20              :         const SizedBox(
+      21              :           width: 6,
+      22              :         ),
+      23            1 :         Flexible(
+      24            1 :           child: Text(
+      25            6 :             restaurant.categories?.map((element) => element.title).first ?? '',
+      26            3 :             style: Theme.of(context).textTheme.bodySmall,
+      27              :             maxLines: 1,
+      28              :             softWrap: true,
+      29              :           ),
+      30              :         ),
+      31              :       ],
+      32              :     );
+      33              :   }
+      34              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html b/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html new file mode 100644 index 0000000..c6b9584 --- /dev/null +++ b/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/restaurant_ratings_review_section.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - restaurant_ratings_review_section.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %390
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html b/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html new file mode 100644 index 0000000..764a251 --- /dev/null +++ b/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html @@ -0,0 +1,75 @@ + + + + + + + LCOV - lcov.info - widgets/restaurant_ratings_review_section.dart - functions + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - restaurant_ratings_review_section.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %390
Test Date:2024-08-25 20:45:43Functions:-00
+
+ +
+ + + + + + + + + +

Function Name Sort by function nameHit count Sort by function hit count
+
+
+ + + +
Generated by: LCOV version 2.1-1
+
+ + + diff --git a/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html b/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html new file mode 100644 index 0000000..cb8280f --- /dev/null +++ b/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html @@ -0,0 +1,188 @@ + + + + + + + LCOV - lcov.info - widgets/restaurant_ratings_review_section.dart + + + + + + + + + + + + + + +
LCOV - code coverage report
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current view:top level - widgets - restaurant_ratings_review_section.dart (source / functions)CoverageTotalHit
Test:lcov.infoLines:0.0 %390
Test Date:2024-08-25 20:45:43Functions:-00
+
+ + + + + + + + +

+
            Line data    Source code
+
+       1              : import 'package:flutter/material.dart';
+       2              : import 'package:restaurant_tour/models/models.dart';
+       3              : import 'package:restaurant_tour/theme/text.dart';
+       4              : import 'package:restaurant_tour/utils/get_random_avatar.dart';
+       5              : import 'package:restaurant_tour/widgets/widgets.dart';
+       6              : import '../theme/colors.dart';
+       7              : 
+       8              : class BuildRatingSection extends StatelessWidget {
+       9            0 :   const BuildRatingSection({super.key, required this.restaurant});
+      10              :   final Restaurant restaurant;
+      11              : 
+      12            0 :   @override
+      13              :   Widget build(BuildContext context) {
+      14            0 :     return Column(
+      15              :       crossAxisAlignment: CrossAxisAlignment.start,
+      16            0 :       children: [
+      17            0 :         Text(
+      18              :           'Overall Rating',
+      19            0 :           style: Theme.of(context).textTheme.bodySmall,
+      20              :         ),
+      21              :         const SizedBox(
+      22              :           height: 16,
+      23              :         ),
+      24            0 :         overallClassificationRow(context),
+      25              :         const SizedBox(
+      26              :           height: spacingXL,
+      27              :         ),
+      28            0 :         buildDivider(),
+      29              :         const SizedBox(
+      30              :           height: spacingXL,
+      31              :         ),
+      32            0 :         Text(
+      33            0 :           '${restaurant.reviews?.length} reviews',
+      34            0 :           style: Theme.of(context).textTheme.bodySmall,
+      35              :         ),
+      36              :         // const SizedBox(
+      37              :         //   height: spacingXL,
+      38              :         // ),
+      39            0 :         ListView.builder(
+      40              :           shrinkWrap: true,
+      41              :           physics: const NeverScrollableScrollPhysics(),
+      42            0 :           itemCount: restaurant.reviews?.length,
+      43            0 :           itemBuilder: (context, index) {
+      44            0 :             var review = restaurant.reviews?[index];
+      45            0 :             return Column(
+      46              :               crossAxisAlignment: CrossAxisAlignment.start,
+      47            0 :               children: [
+      48              :                 const SizedBox(
+      49              :                   height: spacingM,
+      50              :                 ),
+      51            0 :                 StarRating(
+      52            0 :                   rating: review?.rating ?? 0,
+      53              :                 ),
+      54              :                 const SizedBox(
+      55              :                   height: spacingSM,
+      56              :                 ),
+      57            0 :                 review?.text != null
+      58            0 :                     ? Padding(
+      59              :                         padding: const EdgeInsets.only(top: 8.0),
+      60            0 :                         child: Text(
+      61            0 :                           review!.text!,
+      62            0 :                           style: Theme.of(context).textTheme.bodyLarge,
+      63              :                         ),
+      64              :                       )
+      65            0 :                     : Container(),
+      66              :                 const SizedBox(
+      67              :                   height: 8,
+      68              :                 ),
+      69            0 :                 Row(
+      70            0 :                   children: [
+      71            0 :                     CircleAvatar(
+      72              :                       radius: 35,
+      73            0 :                       backgroundImage: review?.user?.imageUrl != null
+      74            0 :                           ? NetworkImage(review!.user!.imageUrl!)
+      75            0 :                           : getRandomAvatar(),
+      76              :                     ),
+      77              :                     const SizedBox(
+      78              :                       width: 8,
+      79              :                     ),
+      80            0 :                     Text(review?.user?.name ?? 'Not identified'),
+      81              :                   ],
+      82              :                 ),
+      83              :                 const SizedBox(
+      84              :                   height: spacingM,
+      85              :                 ),
+      86            0 :                 buildDivider()
+      87              :               ],
+      88              :             );
+      89              :           },
+      90              :         ),
+      91              :       ],
+      92              :     );
+      93              :   }
+      94              : 
+      95            0 :   Row overallClassificationRow(BuildContext context) {
+      96            0 :     return Row(
+      97            0 :       children: [
+      98            0 :         Text(
+      99            0 :           restaurant.rating.toString(),
+     100            0 :           style: Theme.of(context).textTheme.headlineMedium,
+     101              :         ),
+     102              :         const SizedBox(
+     103              :           width: 6,
+     104              :         ),
+     105              :         const Icon(
+     106              :           Icons.star,
+     107              :           color: ThemeColors.starColor,
+     108              :         ),
+     109              :       ],
+     110              :     );
+     111              :   }
+     112              : }
+        
+
+
+ + + + +
Generated by: LCOV version 2.1-1
+
+ + + From 5faf8080d96e00bc8430c91c38527485925924c5 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 23:15:05 -0300 Subject: [PATCH 17/30] Update .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bed6da6..64680be 100644 --- a/.gitignore +++ b/.gitignore @@ -49,4 +49,5 @@ app.*.map.json .fvm/flutter_sdk .env *.env -env.dart \ No newline at end of file +env.dart +coverage_report \ No newline at end of file From f7753a760a06599fdc896473a73152f70e511bf7 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 23:15:29 -0300 Subject: [PATCH 18/30] iOS configs --- ios/Flutter/Debug.xcconfig | 1 + ios/Flutter/Release.xcconfig | 1 + ios/Podfile | 44 +++++++ ios/Podfile.lock | 23 ++++ ios/Runner.xcodeproj/project.pbxproj | 112 ++++++++++++++++++ .../contents.xcworkspacedata | 3 + 6 files changed, 184 insertions(+) create mode 100644 ios/Podfile create mode 100644 ios/Podfile.lock diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..d97f17e --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..9d67035 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,23 @@ +PODS: + - Flutter (1.0.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - Flutter (from `Flutter`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + +SPEC CHECKSUMS: + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 + +COCOAPODS: 1.14.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 182fb57..bfc9f2e 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -10,6 +10,8 @@ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 5B9EB8175B8C5B859CCEC015 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7A10419AE997EB6DE7E5D6A /* Pods_RunnerTests.framework */; }; + 6321356C5CCA15700174FB76 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6A9A3C3DE807B1C6583136EC /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -44,9 +46,13 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 339EEEBAD5DCF72F3BEFB8C0 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 4202DE8A265392A0073DDC58 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + 6A9A3C3DE807B1C6583136EC /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 754CE2B68064AF3945817F8B /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; @@ -55,13 +61,26 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A74BE093EA688B08B5BBECD4 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + F4AC0A48403EA673C8AADA67 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + F7A10419AE997EB6DE7E5D6A /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + F964336D93D08154B23C613A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 3FFD19965B4C9D566984E5F5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 5B9EB8175B8C5B859CCEC015 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 6321356C5CCA15700174FB76 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -76,6 +95,20 @@ path = RunnerTests; sourceTree = ""; }; + 8C577AD6DF1DDC3C789A7B26 /* Pods */ = { + isa = PBXGroup; + children = ( + F4AC0A48403EA673C8AADA67 /* Pods-Runner.debug.xcconfig */, + A74BE093EA688B08B5BBECD4 /* Pods-Runner.release.xcconfig */, + F964336D93D08154B23C613A /* Pods-Runner.profile.xcconfig */, + 339EEEBAD5DCF72F3BEFB8C0 /* Pods-RunnerTests.debug.xcconfig */, + 4202DE8A265392A0073DDC58 /* Pods-RunnerTests.release.xcconfig */, + 754CE2B68064AF3945817F8B /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -94,6 +127,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + 8C577AD6DF1DDC3C789A7B26 /* Pods */, + F800066FBB912D75920385E0 /* Frameworks */, ); sourceTree = ""; }; @@ -121,6 +156,15 @@ path = Runner; sourceTree = ""; }; + F800066FBB912D75920385E0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6A9A3C3DE807B1C6583136EC /* Pods_Runner.framework */, + F7A10419AE997EB6DE7E5D6A /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -128,8 +172,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + 5BFF67856F74324DED4DA1A8 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + 3FFD19965B4C9D566984E5F5 /* Frameworks */, ); buildRules = ( ); @@ -145,12 +191,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + FF18833D2F062EF8455E3171 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 96B65B20AD61D17724ED7179 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -238,6 +286,45 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 5BFF67856F74324DED4DA1A8 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 96B65B20AD61D17724ED7179 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -253,6 +340,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + FF18833D2F062EF8455E3171 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,6 +488,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 339EEEBAD5DCF72F3BEFB8C0 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -396,6 +506,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 4202DE8A265392A0073DDC58 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -411,6 +522,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 754CE2B68064AF3945817F8B /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + From a1e6b027ed9941b9d1455283f3447c4369251b76 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Sun, 25 Aug 2024 23:15:59 -0300 Subject: [PATCH 19/30] clean up tests folder --- test/cubit/cubit_test.dart | 154 +++++++++++----------- test/home_test.dart | 92 +++++++++++++ test/repository/yelp_repository_test.dart | 96 ++++++++++++++ test/widget_loading_test.dart | 51 ------- test/widget_test.dart | 19 --- 5 files changed, 265 insertions(+), 147 deletions(-) create mode 100644 test/home_test.dart create mode 100644 test/repository/yelp_repository_test.dart delete mode 100644 test/widget_loading_test.dart delete mode 100644 test/widget_test.dart diff --git a/test/cubit/cubit_test.dart b/test/cubit/cubit_test.dart index a671b20..2ab9c2f 100644 --- a/test/cubit/cubit_test.dart +++ b/test/cubit/cubit_test.dart @@ -1,92 +1,92 @@ -import 'dart:io'; - import 'package:bloc_test/bloc_test.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:get_it/get_it.dart'; import 'package:mocktail/mocktail.dart'; -import 'package:restaurant_tour/cubit/cubit.dart'; -import 'package:restaurant_tour/pages/pages.dart'; -import 'package:restaurant_tour/repositories/repositories.dart'; -import 'package:restaurant_tour/usecases/usecases.dart'; -import 'package:restaurant_tour/widgets/widgets.dart'; - -// Mock classes -class MockRestaurantCubit extends MockCubit - implements RestaurantCubit {} - -class MockRestaurantState extends Fake implements RestaurantState {} +import 'package:restaurant_tour/cubit/restaurant_cubit.dart'; +import 'package:restaurant_tour/models/restaurant.dart'; +import 'package:restaurant_tour/usecases/fetch_restaurants.dart'; class MockFetchRestaurantsUseCase extends Mock implements FetchRestaurants {} -class MyHttpOverrides extends HttpOverrides { - @override - HttpClient createHttpClient(SecurityContext? context) { - return super.createHttpClient(context) - ..badCertificateCallback = - (X509Certificate cert, String host, int port) => true; - } -} +class MockRestaurantQueryResult extends Mock implements RestaurantQueryResult {} void main() { - late MockRestaurantCubit restaurantCubit; + late RestaurantCubit restaurantCubit; late MockFetchRestaurantsUseCase mockFetchRestaurantsUseCase; - group('Load Restaurants State successfully', () { - setUp(() { - HttpOverrides.global = MyHttpOverrides(); - - registerFallbackValue(MockRestaurantState()); - - mockFetchRestaurantsUseCase = MockFetchRestaurantsUseCase(); - - restaurantCubit = MockRestaurantCubit(); - - // GetIt.I.registerFactory( - // () => RestaurantCubit(mockFetchRestaurantsUseCase), - // ); - }); - - tearDown(() { - // GetIt.I.reset(); - }); + setUp(() { + mockFetchRestaurantsUseCase = MockFetchRestaurantsUseCase(); + restaurantCubit = RestaurantCubit(mockFetchRestaurantsUseCase); + }); - testWidgets('Display loading State', (tester) async { - when(() => restaurantCubit.state) - .thenReturn(const LoadingRestaurantsState(favoriteRestaurants: [])); + tearDown(() { + restaurantCubit.close(); + }); - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: restaurantCubit, - child: const HomePage(), - ), + blocTest( + 'Emits Loading and Loaded states when fetchRestaurants is successful', + build: () { + final mockResult = MockRestaurantQueryResult(); + when(() => mockFetchRestaurantsUseCase.getRestaurants()) + .thenAnswer((_) async => mockResult); + + when(() => mockFetchRestaurantsUseCase.getFavoriteRestaurants()) + .thenAnswer((_) async => ['abc', 'def']); + return restaurantCubit; + }, + act: (cubit) => cubit.fetchRestaurants(), + expect: () => [ + const LoadingRestaurantsState(favoriteRestaurants: []), + isA(), + ], + verify: (cubit) { + verify(() => mockFetchRestaurantsUseCase.getRestaurants()).called(1); + verify(() => mockFetchRestaurantsUseCase.getFavoriteRestaurants()) + .called(1); + }, + ); + + blocTest( + 'emits [LoadingRestaurantsState, ErrorState] when fetchRestaurants fails', + build: () { + when(() => mockFetchRestaurantsUseCase.getRestaurants()) + .thenAnswer((_) async => null); + when(() => mockFetchRestaurantsUseCase.getFavoriteRestaurants()) + .thenAnswer((_) async => []); + return restaurantCubit; + }, + act: (cubit) => cubit.fetchRestaurants(), + expect: () => [ + const LoadingRestaurantsState(favoriteRestaurants: []), + const ErrorState( + message: + 'The server encountered a problem and we couldn\'t load the list.', + favoriteRestaurants: [], + ), + ], + verify: (cubit) { + verify(() => mockFetchRestaurantsUseCase.getRestaurants()).called(1); + verify(() => mockFetchRestaurantsUseCase.getFavoriteRestaurants()) + .called(1); + }, + ); + + blocTest( + 'emits [FavoriteRestaurantState] when someone favorites or un-favorites a restaurant', + build: () => restaurantCubit, + setUp: () { + restaurantCubit.emit( + RestaurantsLoadedState( + result: MockRestaurantQueryResult(), + favoriteRestaurants: const ['1', '2'], ), ); - - expect(find.byType(CircularProgressIndicator), findsOneWidget); - }); - - testWidgets('Display List View State', (tester) async { - var fakeData = YelpRepository().getRestaurantsFromCache(); - when(() => restaurantCubit.state).thenReturn( - RestaurantsLoadedState(favoriteRestaurants: [], result: fakeData), - ); - await tester.runAsync(() async { - await tester.pumpWidget( - MaterialApp( - home: BlocProvider.value( - value: restaurantCubit, - child: const HomePage(), - ), - ), - ); - await tester.pumpAndSettle(); - }); - - expect(find.byType(HeroImageWidget), findsAny); - }); - }); + }, + act: (cubit) => cubit.favoriteAResturant('1'), + expect: () => [ + FavoriteRestaurantState( + result: MockRestaurantQueryResult(), + favoriteRestaurants: List.of(['2']), + ), + ], + ); } diff --git a/test/home_test.dart b/test/home_test.dart new file mode 100644 index 0000000..b7618a2 --- /dev/null +++ b/test/home_test.dart @@ -0,0 +1,92 @@ +import 'dart:io'; +import 'package:bloc_test/bloc_test.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get_it/get_it.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:restaurant_tour/cubit/cubit.dart'; +import 'package:restaurant_tour/pages/pages.dart'; +import 'package:restaurant_tour/repositories/repositories.dart'; +import 'package:restaurant_tour/usecases/usecases.dart'; +import 'package:restaurant_tour/widgets/widgets.dart'; + +// Mock classes +class MockRestaurantCubit extends MockCubit + implements RestaurantCubit {} + +class MockRestaurantState extends Fake implements RestaurantState {} + +class MockFetchRestaurantsUseCase extends Mock implements FetchRestaurants {} + +class MyHttpOverrides extends HttpOverrides { + @override + HttpClient createHttpClient(SecurityContext? context) { + return super.createHttpClient(context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + } +} + +void main() { + late MockRestaurantCubit restaurantCubit; + + group('Home Page Widget Testing', () { + setUp(() { + HttpOverrides.global = MyHttpOverrides(); + + registerFallbackValue(MockRestaurantState()); + + restaurantCubit = MockRestaurantCubit(); + GetIt.I.registerSingleton(restaurantCubit); + }); + + tearDown(() { + GetIt.I.reset(); + }); + + testWidgets( + 'Expects to display a loading State with CircularProgressIndicator', + (tester) async { + when(() => restaurantCubit.state) + .thenReturn(const LoadingRestaurantsState(favoriteRestaurants: [])); + + await tester.runAsync(() async { + await tester.pumpWidget( + MaterialApp( + home: BlocProvider.value( + value: GetIt.I(), + child: const HomePage(), + ), + ), + ); + + await tester.pump(Duration(seconds: 1)); + }); + + expect(find.byType(CircularProgressIndicator), findsOneWidget); + }); + + testWidgets( + 'When restaurants are loaded, display a listview with a HeroImageWidget', + (tester) async { + var fakeData = YelpRepository().getRestaurantsFromCache(); + when(() => restaurantCubit.state).thenReturn( + RestaurantsLoadedState(favoriteRestaurants: [], result: fakeData), + ); + await tester.runAsync(() async { + await tester.pumpWidget( + MaterialApp( + home: BlocProvider.value( + value: GetIt.I(), + child: const HomePage(), + ), + ), + ); + await tester.pumpAndSettle(); + }); + + expect(find.byType(HeroImageWidget), findsAny); + }); + }); +} diff --git a/test/repository/yelp_repository_test.dart b/test/repository/yelp_repository_test.dart new file mode 100644 index 0000000..67a48cf --- /dev/null +++ b/test/repository/yelp_repository_test.dart @@ -0,0 +1,96 @@ +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:restaurant_tour/models/restaurant.dart'; +import 'package:restaurant_tour/repositories/repositories.dart'; +import 'package:restaurant_tour/repositories/sample_json.dart'; + +class MockDio extends Mock implements Dio {} + +class MockResponse extends Mock implements Response {} + +String fakequery = ''' +query getRestaurants { + search(location: "Las Vegas", limit: 20, offset: 0) { + total + business { + id + name + price + rating + photos + reviews { + id + rating + text + user { + id + image_url + name + } + } + categories { + title + alias + } + hours { + is_open_now + } + location { + formatted_address + } + } + } +} +'''; +void main() { + late YelpRepository repository; + late MockDio mockDio; + setUp(() { + mockDio = MockDio(); + repository = YelpRepository(dio: mockDio); + }); + + // test('Get Restaurants should return a RestaurantQueryResult', () async { + // final response = Response( + // requestOptions: RequestOptions(path: 'https://example.com'), + // data: sample, + // statusCode: 200, + // ); + // final requestData = {'key': 'value'}; + + // // final mockResponse = MockResponse(); + // // when(() => mockResponse.data).thenReturn(aaaaa); + // // when(() => mockResponse.statusCode).thenReturn(200); + // when(() => mockDio.post( + // any(), + // data: fakequery, + // )).thenAnswer((_) async => response); + + // final result = await repository.getRestaurants(); + + // expect(result, isA()); + + // expect(result, isNotNull); + // }); + test('fromJson should parse the sample data correctly', () { + final result = RestaurantQueryResult.fromJson(sample['data']['search']); + expect(result, isNotNull); + expect(result, isA()); + }); + test('returns null on error', () async { + // Arrange + when(() => mockDio.post>( + any(), + data: any(named: 'data'), + )).thenThrow(DioError( + requestOptions: RequestOptions(path: '/v3/graphql'), + )); + + // Act + final result = await repository.getRestaurants(); + + // Assert + expect(result, isNull); + }); +} diff --git a/test/widget_loading_test.dart b/test/widget_loading_test.dart deleted file mode 100644 index 8aaff27..0000000 --- a/test/widget_loading_test.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:get_it/get_it.dart'; -import 'package:restaurant_tour/cubit/cubit.dart'; -import 'package:restaurant_tour/main.dart'; -import 'package:restaurant_tour/models/restaurant.dart'; -import 'package:restaurant_tour/repositories/repositories.dart'; -import 'package:restaurant_tour/usecases/fetch_restaurants.dart'; - -class MockFetchRestaurants extends Mock implements FetchRestaurants {} - -class MockYelpRepository extends Mock implements YelpRepository {} - -void main() { - late FetchRestaurants mockFetchRestaurants; - late RestaurantCubit restaurantCubit; - - setUp(() { - final getIt = GetIt.instance; - getIt.reset(); - - mockFetchRestaurants = MockFetchRestaurants(); - restaurantCubit = RestaurantCubit(mockFetchRestaurants); - - getIt.registerSingleton(restaurantCubit); - }); - - testWidgets( - 'displays loading state and then loaded state with "All restaurants"', - (WidgetTester tester) async { - when(() => mockFetchRestaurants.getRestaurantsFromCache()).thenAnswer( - (_) async => YelpRepository().getRestaurantsFromCache(), - ); // Add relevant data - - when(() => mockFetchRestaurants.getFavoriteRestaurants()) - .thenAnswer((_) async => []); - - // Pump the widget tree - await tester.pumpWidget(const RestaurantTour()); - - // Expect the loading state - expect(find.byType(CircularProgressIndicator), findsOneWidget); - - // Allow the state to change - await tester.pump(); - - // Expect the "All restaurants" text to be found after loading - expect(find.text('RestauranTour'), findsOneWidget); - }); -} diff --git a/test/widget_test.dart b/test/widget_test.dart deleted file mode 100644 index 22f2ca9..0000000 --- a/test/widget_test.dart +++ /dev/null @@ -1,19 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter_test/flutter_test.dart'; -import 'package:restaurant_tour/main.dart'; - -void main() { - testWidgets('Page loads', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const RestaurantTour()); - - // Verify that tests will run - expect(find.text('All restaurants'), findsOneWidget); - }); -} From 01eff4e8fe95e75320612a60e9cd18d80da55867 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 11:43:21 -0300 Subject: [PATCH 20/30] cleanups --- ios/Podfile.lock | 7 ------- ios/Runner.xcodeproj/project.pbxproj | 18 ------------------ lib/cubit/restaurant_cubit.dart | 1 + lib/main.dart | 2 -- lib/repositories/yelp_repository.dart | 1 - pubspec.yaml | 3 ++- 6 files changed, 3 insertions(+), 29 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 9d67035..3c9ea6d 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,22 +1,15 @@ PODS: - Flutter (1.0.0) - - shared_preferences_foundation (0.0.1): - - Flutter - - FlutterMacOS DEPENDENCIES: - Flutter (from `Flutter`) - - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) EXTERNAL SOURCES: Flutter: :path: Flutter - shared_preferences_foundation: - :path: ".symlinks/plugins/shared_preferences_foundation/darwin" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index bfc9f2e..db52082 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -198,7 +198,6 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 96B65B20AD61D17724ED7179 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -308,23 +307,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 96B65B20AD61D17724ED7179 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; diff --git a/lib/cubit/restaurant_cubit.dart b/lib/cubit/restaurant_cubit.dart index 72f358a..ddde3a1 100644 --- a/lib/cubit/restaurant_cubit.dart +++ b/lib/cubit/restaurant_cubit.dart @@ -43,6 +43,7 @@ class RestaurantCubit extends Cubit { } else { favoriteRestaurants.add(id); } + // await fetchRestaurantsUseCase.saveFavoriteRestaurants(favoriteRestaurants); emit( FavoriteRestaurantState( result: state.result!, diff --git a/lib/main.dart b/lib/main.dart index 118706b..e9ec874 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:get_it/get_it.dart'; import 'package:restaurant_tour/cubit/cubit.dart'; import 'package:restaurant_tour/repositories/repositories.dart'; @@ -12,7 +11,6 @@ Future main() async { setup(); WidgetsFlutterBinding.ensureInitialized(); - // await dotenv.load(); runApp(const RestaurantTour()); } diff --git a/lib/repositories/yelp_repository.dart b/lib/repositories/yelp_repository.dart index 4f78775..353d4fa 100644 --- a/lib/repositories/yelp_repository.dart +++ b/lib/repositories/yelp_repository.dart @@ -1,6 +1,5 @@ import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:restaurant_tour/env.dart'; import 'package:restaurant_tour/models/restaurant.dart'; import 'package:restaurant_tour/repositories/sample_json.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index e943694..6a0ae3e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: restaurant_tour description: Flutter developer coding challenge starter project. -publish_to: 'none' +# publish_to: 'none' version: 1.0.0+1 @@ -36,6 +36,7 @@ flutter: uses-material-design: true assets: - assets/avatars/ + - assets/.env fonts: - family: Lora fonts: From 232a503f66eea85a0a8809fd48d699fb2c41ac13 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 11:43:37 -0300 Subject: [PATCH 21/30] automating tests + coverage report --- coverage/lcov.info | 297 ++++++++++-------- coverage_report/cubit/index-sort-f.html | 22 +- coverage_report/cubit/index-sort-l.html | 22 +- coverage_report/cubit/index.html | 22 +- .../cubit/restaurant_cubit.dart.func-c.html | 8 +- .../cubit/restaurant_cubit.dart.func.html | 8 +- .../cubit/restaurant_cubit.dart.gcov.html | 25 +- .../cubit/restaurant_state.dart.func-c.html | 6 +- .../cubit/restaurant_state.dart.func.html | 6 +- .../cubit/restaurant_state.dart.gcov.html | 24 +- coverage_report/index-sort-f.html | 32 +- coverage_report/index-sort-l.html | 50 +-- coverage_report/index.html | 32 +- coverage_report/models/index-sort-f.html | 2 +- coverage_report/models/index-sort-l.html | 2 +- coverage_report/models/index.html | 2 +- .../models/restaurant.dart.func-c.html | 2 +- .../models/restaurant.dart.func.html | 2 +- .../models/restaurant.dart.gcov.html | 38 +-- .../models/restaurant.g.dart.func-c.html | 2 +- .../models/restaurant.g.dart.func.html | 2 +- .../models/restaurant.g.dart.gcov.html | 80 ++--- .../pages/home_page.dart.func-c.html | 8 +- .../pages/home_page.dart.func.html | 8 +- .../pages/home_page.dart.gcov.html | 151 ++++----- coverage_report/pages/index-sort-f.html | 34 +- coverage_report/pages/index-sort-l.html | 34 +- coverage_report/pages/index.html | 34 +- .../restaurant_detail_page.dart.func-c.html | 2 +- .../restaurant_detail_page.dart.func.html | 2 +- .../restaurant_detail_page.dart.gcov.html | 2 +- .../restaurant_list_page.dart.func-c.html | 6 +- .../pages/restaurant_list_page.dart.func.html | 6 +- .../pages/restaurant_list_page.dart.gcov.html | 211 ++++++------- .../repositories/index-sort-f.html | 12 +- .../repositories/index-sort-l.html | 12 +- coverage_report/repositories/index.html | 12 +- .../yelp_repository.dart.func-c.html | 6 +- .../yelp_repository.dart.func.html | 6 +- .../yelp_repository.dart.gcov.html | 246 +++++++-------- .../fetch_restaurants.dart.func-c.html | 4 +- .../usecases/fetch_restaurants.dart.func.html | 4 +- .../usecases/fetch_restaurants.dart.gcov.html | 58 ++-- coverage_report/usecases/index-sort-f.html | 6 +- coverage_report/usecases/index-sort-l.html | 6 +- coverage_report/usecases/index.html | 6 +- .../utils/get_random_avatar.dart.func-c.html | 2 +- .../utils/get_random_avatar.dart.func.html | 2 +- .../utils/get_random_avatar.dart.gcov.html | 2 +- coverage_report/utils/index-sort-f.html | 2 +- coverage_report/utils/index-sort-l.html | 2 +- coverage_report/utils/index.html | 2 +- .../widgets/appbar.dart.func-c.html | 2 +- coverage_report/widgets/appbar.dart.func.html | 2 +- coverage_report/widgets/appbar.dart.gcov.html | 2 +- .../widgets/divider.dart.func-c.html | 2 +- .../widgets/divider.dart.func.html | 2 +- .../widgets/divider.dart.gcov.html | 2 +- .../hero_image_widget.dart.func-c.html | 2 +- .../widgets/hero_image_widget.dart.func.html | 2 +- .../widgets/hero_image_widget.dart.gcov.html | 2 +- coverage_report/widgets/index-sort-f.html | 2 +- coverage_report/widgets/index-sort-l.html | 2 +- coverage_report/widgets/index.html | 2 +- .../rataurant_open_status.dart.func-c.html | 2 +- .../rataurant_open_status.dart.func.html | 2 +- .../rataurant_open_status.dart.gcov.html | 2 +- ...ng_and_open_status_widget.dart.func-c.html | 2 +- ...ting_and_open_status_widget.dart.func.html | 2 +- ...ting_and_open_status_widget.dart.gcov.html | 2 +- .../widgets/rating_widget.dart.func-c.html | 2 +- .../widgets/rating_widget.dart.func.html | 2 +- .../widgets/rating_widget.dart.gcov.html | 2 +- .../restaurant_details.dart.func-c.html | 2 +- .../widgets/restaurant_details.dart.func.html | 2 +- .../widgets/restaurant_details.dart.gcov.html | 2 +- ...nt_ratings_review_section.dart.func-c.html | 2 +- ...rant_ratings_review_section.dart.func.html | 2 +- ...rant_ratings_review_section.dart.gcov.html | 2 +- run_tests.sh | 37 +++ 80 files changed, 896 insertions(+), 769 deletions(-) create mode 100755 run_tests.sh diff --git a/coverage/lcov.info b/coverage/lcov.info index 3e9b1c8..6facf0b 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -1,12 +1,12 @@ SF:lib/cubit/restaurant_state.dart -DA:10,6 +DA:10,7 DA:16,1 DA:17,2 -DA:21,2 +DA:21,3 DA:23,0 DA:25,0 DA:26,0 -DA:32,4 +DA:32,5 DA:34,1 DA:35,2 DA:37,0 @@ -19,21 +19,21 @@ DA:57,0 DA:59,0 DA:60,0 DA:61,0 -DA:72,1 -DA:75,1 -DA:76,1 -DA:77,2 +DA:72,0 +DA:75,0 +DA:76,0 +DA:77,0 DA:79,0 DA:81,0 DA:82,0 DA:83,0 -DA:91,3 +DA:91,4 DA:97,0 DA:99,0 DA:100,0 DA:101,0 LF:33 -LH:15 +LH:11 end_of_record SF:lib/cubit/restaurant_cubit.dart DA:11,1 @@ -50,34 +50,35 @@ DA:40,3 DA:41,1 DA:42,1 DA:44,0 -DA:46,1 -DA:47,1 -DA:48,2 -DA:49,1 -LF:18 -LH:17 +DA:46,2 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +LF:19 +LH:14 end_of_record SF:lib/models/restaurant.dart -DA:10,1 -DA:15,1 -DA:16,1 +DA:10,2 +DA:15,2 +DA:16,2 DA:18,0 -DA:26,1 -DA:30,2 +DA:26,2 +DA:30,4 DA:32,0 -DA:42,1 -DA:48,2 +DA:42,2 +DA:48,4 DA:50,0 -DA:60,1 -DA:67,2 +DA:60,2 +DA:67,4 DA:69,0 -DA:77,1 -DA:81,1 -DA:82,1 +DA:77,2 +DA:81,2 +DA:82,2 DA:84,0 -DA:99,1 -DA:111,1 -DA:112,1 +DA:99,2 +DA:111,2 +DA:112,2 DA:114,0 DA:117,0 DA:118,0 @@ -88,62 +89,62 @@ DA:127,2 DA:134,1 DA:135,3 DA:136,3 -DA:148,1 -DA:153,1 -DA:154,1 +DA:148,2 +DA:153,2 +DA:154,2 DA:156,0 LF:34 LH:24 end_of_record SF:lib/models/restaurant.g.dart -DA:9,2 -DA:10,1 -DA:11,1 +DA:9,4 +DA:10,2 +DA:11,2 DA:14,0 DA:15,0 DA:16,0 -DA:19,2 -DA:20,1 +DA:19,4 +DA:20,2 DA:23,0 DA:24,0 -DA:27,2 -DA:28,1 -DA:29,1 -DA:30,1 +DA:27,4 +DA:28,2 +DA:29,2 +DA:30,2 DA:33,0 DA:34,0 DA:35,0 DA:36,0 -DA:39,2 -DA:40,1 -DA:41,1 -DA:42,1 -DA:44,2 +DA:39,4 +DA:40,2 +DA:41,2 +DA:42,2 +DA:44,4 DA:47,0 DA:48,0 DA:49,0 DA:50,0 -DA:53,2 -DA:54,1 +DA:53,4 +DA:54,2 DA:57,0 DA:58,0 -DA:61,2 -DA:62,1 -DA:63,1 -DA:64,1 -DA:65,2 -DA:67,4 -DA:68,1 -DA:69,3 -DA:70,1 -DA:71,1 -DA:72,3 -DA:73,1 -DA:74,1 -DA:75,3 -DA:76,1 -DA:77,1 -DA:79,2 +DA:61,4 +DA:62,2 +DA:63,2 +DA:64,2 +DA:65,4 +DA:67,8 +DA:68,2 +DA:69,6 +DA:70,2 +DA:71,2 +DA:72,6 +DA:73,2 +DA:74,2 +DA:75,6 +DA:76,2 +DA:77,2 +DA:79,4 DA:82,0 DA:83,0 DA:84,0 @@ -155,12 +156,12 @@ DA:89,0 DA:90,0 DA:91,0 DA:92,0 -DA:95,1 -DA:97,1 -DA:98,1 -DA:99,1 -DA:100,3 -DA:101,1 +DA:95,2 +DA:97,2 +DA:98,2 +DA:99,2 +DA:100,6 +DA:101,2 DA:104,0 DA:106,0 DA:107,0 @@ -169,53 +170,59 @@ LF:69 LH:39 end_of_record SF:lib/usecases/fetch_restaurants.dart -DA:7,0 DA:8,0 DA:9,0 DA:10,0 DA:11,0 -DA:13,0 -DA:15,0 -DA:17,0 -LF:8 +DA:12,0 +DA:14,0 +DA:21,0 +DA:25,0 +DA:28,0 +LF:9 LH:0 end_of_record SF:lib/repositories/yelp_repository.dart -DA:12,1 -DA:15,1 +DA:10,2 +DA:13,1 +DA:14,1 DA:16,1 -DA:18,1 -DA:66,1 -DA:68,3 -DA:70,0 -DA:74,0 -DA:76,0 -DA:78,0 -DA:81,0 -DA:87,0 -DA:121,0 +DA:64,1 +DA:66,3 +DA:68,0 +DA:72,1 +DA:74,2 +DA:76,1 +DA:79,0 +DA:85,1 +DA:119,1 LF:13 -LH:6 +LH:11 end_of_record -SF:lib/pages/home_page.dart -DA:18,1 -DA:20,1 -DA:22,1 -DA:24,1 -DA:25,1 -DA:26,1 -DA:28,3 -DA:30,1 -DA:43,1 -DA:44,1 -DA:45,1 -DA:46,1 -DA:48,3 -DA:51,1 -DA:52,1 -DA:54,3 -LF:16 -LH:16 +SF:lib/pages/favorites_list_page_view.dart +DA:8,1 +DA:10,0 +DA:12,0 +DA:13,0 +DA:14,0 +DA:17,0 +DA:18,0 +DA:19,0 +DA:20,0 +DA:21,0 +DA:22,0 +DA:23,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:31,0 +DA:32,0 +DA:33,0 +DA:43,0 +LF:21 +LH:1 end_of_record SF:lib/pages/restaurant_list_page.dart DA:9,1 @@ -233,45 +240,69 @@ DA:23,1 DA:24,0 DA:25,0 DA:28,1 -DA:29,1 -DA:30,3 -DA:31,1 +DA:29,0 +DA:30,1 +DA:31,3 DA:32,1 -DA:34,1 +DA:33,1 DA:35,1 -DA:36,3 -DA:44,0 -DA:53,1 -DA:61,1 -DA:63,1 -DA:64,0 +DA:36,1 +DA:37,3 +DA:45,0 +DA:54,1 +DA:62,1 +DA:64,1 DA:65,0 -DA:67,0 +DA:66,0 DA:68,0 -DA:72,1 -DA:73,2 -DA:76,1 -DA:78,2 -DA:79,1 +DA:69,0 +DA:73,1 +DA:74,2 +DA:77,1 +DA:79,2 DA:80,1 DA:81,1 DA:82,1 -DA:88,1 +DA:83,1 DA:89,1 DA:90,1 DA:91,1 DA:92,1 DA:93,1 -DA:103,1 -DA:105,1 -DA:108,1 +DA:94,1 +DA:104,1 +DA:106,1 DA:109,1 -DA:110,2 -DA:116,2 -DA:120,2 -LF:51 +DA:110,1 +DA:111,2 +DA:117,2 +DA:121,2 +LF:52 LH:40 end_of_record +SF:lib/pages/home_page.dart +DA:19,1 +DA:21,1 +DA:23,1 +DA:25,1 +DA:26,1 +DA:27,1 +DA:29,3 +DA:31,1 +DA:32,1 +DA:34,1 +DA:35,0 +DA:44,1 +DA:45,1 +DA:46,1 +DA:47,1 +DA:49,3 +DA:52,1 +DA:53,1 +DA:55,3 +LF:19 +LH:18 +end_of_record SF:lib/pages/restaurant_detail_page.dart DA:8,0 DA:10,0 diff --git a/coverage_report/cubit/index-sort-f.html b/coverage_report/cubit/index-sort-f.html index b3fb1ce..b99acd2 100644 --- a/coverage_report/cubit/index-sort-f.html +++ b/coverage_report/cubit/index-sort-f.html @@ -31,13 +31,13 @@ lcov.info Lines: - 62.7 % - 51 - 32 + 48.1 % + 52 + 25 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -82,11 +82,11 @@ restaurant_cubit.dart -
94.4%94.4%
+
73.7%73.7%
- 94.4 % - 18 - 17 + 73.7 % + 19 + 14 - @@ -94,11 +94,11 @@ restaurant_state.dart -
45.5%45.5%
+
33.3%33.3%
- 45.5 % + 33.3 % 33 - 15 + 11 - diff --git a/coverage_report/cubit/index-sort-l.html b/coverage_report/cubit/index-sort-l.html index 93dfeaf..d6dd913 100644 --- a/coverage_report/cubit/index-sort-l.html +++ b/coverage_report/cubit/index-sort-l.html @@ -31,13 +31,13 @@ lcov.info Lines: - 62.7 % - 51 - 32 + 48.1 % + 52 + 25 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -82,11 +82,11 @@ restaurant_state.dart -
45.5%45.5%
+
33.3%33.3%
- 45.5 % + 33.3 % 33 - 15 + 11 - @@ -94,11 +94,11 @@ restaurant_cubit.dart -
94.4%94.4%
+
73.7%73.7%
- 94.4 % - 18 - 17 + 73.7 % + 19 + 14 - diff --git a/coverage_report/cubit/index.html b/coverage_report/cubit/index.html index 57ea65a..e79492f 100644 --- a/coverage_report/cubit/index.html +++ b/coverage_report/cubit/index.html @@ -31,13 +31,13 @@ lcov.info Lines: - 62.7 % - 51 - 32 + 48.1 % + 52 + 25 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -82,11 +82,11 @@ restaurant_cubit.dart -
94.4%94.4%
+
73.7%73.7%
- 94.4 % - 18 - 17 + 73.7 % + 19 + 14 - @@ -94,11 +94,11 @@ restaurant_state.dart -
45.5%45.5%
+
33.3%33.3%
- 45.5 % + 33.3 % 33 - 15 + 11 - diff --git a/coverage_report/cubit/restaurant_cubit.dart.func-c.html b/coverage_report/cubit/restaurant_cubit.dart.func-c.html index 9f65524..fa8335d 100644 --- a/coverage_report/cubit/restaurant_cubit.dart.func-c.html +++ b/coverage_report/cubit/restaurant_cubit.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 94.4 % - 18 - 17 + 73.7 % + 19 + 14 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/cubit/restaurant_cubit.dart.func.html b/coverage_report/cubit/restaurant_cubit.dart.func.html index 164b318..fe5200a 100644 --- a/coverage_report/cubit/restaurant_cubit.dart.func.html +++ b/coverage_report/cubit/restaurant_cubit.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 94.4 % - 18 - 17 + 73.7 % + 19 + 14 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/cubit/restaurant_cubit.dart.gcov.html b/coverage_report/cubit/restaurant_cubit.dart.gcov.html index 0914007..ae204d4 100644 --- a/coverage_report/cubit/restaurant_cubit.dart.gcov.html +++ b/coverage_report/cubit/restaurant_cubit.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 94.4 % - 18 - 17 + 73.7 % + 19 + 14 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -105,14 +105,15 @@ 43 : } else { 44 0 : favoriteRestaurants.add(id); 45 : } - 46 1 : emit( - 47 1 : FavoriteRestaurantState( - 48 2 : result: state.result!, - 49 1 : favoriteRestaurants: List.of(favoriteRestaurants), - 50 : ), - 51 : ); - 52 : } - 53 : } + 46 2 : await fetchRestaurantsUseCase.saveFavoriteRestaurants(favoriteRestaurants); + 47 0 : emit( + 48 0 : FavoriteRestaurantState( + 49 0 : result: state.result!, + 50 0 : favoriteRestaurants: List.of(favoriteRestaurants), + 51 : ), + 52 : ); + 53 : } + 54 : } diff --git a/coverage_report/cubit/restaurant_state.dart.func-c.html b/coverage_report/cubit/restaurant_state.dart.func-c.html index e9ae3fa..c425cfe 100644 --- a/coverage_report/cubit/restaurant_state.dart.func-c.html +++ b/coverage_report/cubit/restaurant_state.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 45.5 % + 33.3 % 33 - 15 + 11 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/cubit/restaurant_state.dart.func.html b/coverage_report/cubit/restaurant_state.dart.func.html index 27e7f83..6a8882c 100644 --- a/coverage_report/cubit/restaurant_state.dart.func.html +++ b/coverage_report/cubit/restaurant_state.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 45.5 % + 33.3 % 33 - 15 + 11 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/cubit/restaurant_state.dart.gcov.html b/coverage_report/cubit/restaurant_state.dart.gcov.html index 7893a6d..3a08218 100644 --- a/coverage_report/cubit/restaurant_state.dart.gcov.html +++ b/coverage_report/cubit/restaurant_state.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 45.5 % + 33.3 % 33 - 15 + 11 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -69,7 +69,7 @@ 7 : final List<String> favoriteRestaurants; 8 : final RestaurantQueryResult? result; 9 : - 10 6 : const RestaurantState({ + 10 7 : const RestaurantState({ 11 : required this.favoriteRestaurants, 12 : this.result, 13 : }); @@ -80,7 +80,7 @@ 18 : } 19 : 20 : class RestaurantInitial extends RestaurantState { - 21 2 : const RestaurantInitial({required super.favoriteRestaurants}); + 21 3 : const RestaurantInitial({required super.favoriteRestaurants}); 22 : 23 0 : @override 24 : RestaurantState copyWith({List<String>? favoriteRestaurants}) { @@ -91,7 +91,7 @@ 29 : } 30 : 31 : class LoadingRestaurantsState extends RestaurantState { - 32 4 : const LoadingRestaurantsState({required super.favoriteRestaurants}); + 32 5 : const LoadingRestaurantsState({required super.favoriteRestaurants}); 33 : 34 1 : @override 35 2 : List<Object?> get props => [favoriteRestaurants]; @@ -131,14 +131,14 @@ 69 : @override 70 : final List<String> favoriteRestaurants; 71 : - 72 1 : const FavoriteRestaurantState({ + 72 0 : const FavoriteRestaurantState({ 73 : required this.result, 74 : required this.favoriteRestaurants, - 75 1 : }) : super(favoriteRestaurants: favoriteRestaurants, result: result); - 76 1 : @override - 77 2 : List<Object?> get props => [favoriteRestaurants]; + 75 0 : }) : super(favoriteRestaurants: favoriteRestaurants, result: result); + 76 0 : @override + 77 0 : List<Object?> get props => [favoriteRestaurants]; 78 : - 79 0 : @override + 79 0 : @override 80 : FavoriteRestaurantState copyWith({List<String>? favoriteRestaurants}) { 81 0 : return FavoriteRestaurantState( 82 0 : favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants, @@ -150,7 +150,7 @@ 88 : class ErrorState extends RestaurantState { 89 : final String message; 90 : - 91 3 : const ErrorState({ + 91 4 : const ErrorState({ 92 : required super.favoriteRestaurants, 93 : super.result, 94 : required this.message, diff --git a/coverage_report/index-sort-f.html b/coverage_report/index-sort-f.html index 25553a5..7a7fad9 100644 --- a/coverage_report/index-sort-f.html +++ b/coverage_report/index-sort-f.html @@ -31,13 +31,13 @@ lcov.info Lines: - 52.6 % - 386 - 203 + 49.4 % + 413 + 204 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -82,11 +82,11 @@ cubit/ -
62.7%62.7%
+
48.1%48.1%
- 62.7 % - 51 - 32 + 48.1 % + 52 + 25 - @@ -106,11 +106,11 @@ pages/ -
52.8%52.8%
+
45.0%45.0%
- 52.8 % - 106 - 56 + 45.0 % + 131 + 59 - @@ -118,11 +118,11 @@ repositories/ -
46.2%46.2%
+
84.6%84.6%
- 46.2 % + 84.6 % 13 - 6 + 11 - @@ -133,7 +133,7 @@
0.0%
0.0 % - 8 + 9 - diff --git a/coverage_report/index-sort-l.html b/coverage_report/index-sort-l.html index 73e8f92..15b112d 100644 --- a/coverage_report/index-sort-l.html +++ b/coverage_report/index-sort-l.html @@ -31,13 +31,13 @@ lcov.info Lines: - 52.6 % - 386 - 203 + 49.4 % + 413 + 204 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -97,44 +97,44 @@
0.0%
0.0 % - 8 + 9 - - widgets/ + pages/ -
45.5%45.5%
+
45.0%45.0%
- 45.5 % - 101 - 46 + 45.0 % + 131 + 59 - - repositories/ + widgets/ -
46.2%46.2%
+
45.5%45.5%
- 46.2 % - 13 - 6 + 45.5 % + 101 + 46 - - pages/ + cubit/ -
52.8%52.8%
+
48.1%48.1%
- 52.8 % - 106 - 56 + 48.1 % + 52 + 25 - @@ -152,13 +152,13 @@ - cubit/ + repositories/ -
62.7%62.7%
+
84.6%84.6%
- 62.7 % - 51 - 32 + 84.6 % + 13 + 11 - diff --git a/coverage_report/index.html b/coverage_report/index.html index fd43494..d3180bd 100644 --- a/coverage_report/index.html +++ b/coverage_report/index.html @@ -31,13 +31,13 @@ lcov.info Lines: - 52.6 % - 386 - 203 + 49.4 % + 413 + 204 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -82,11 +82,11 @@ cubit/ -
62.7%62.7%
+
48.1%48.1%
- 62.7 % - 51 - 32 + 48.1 % + 52 + 25 - @@ -106,11 +106,11 @@ pages/ -
52.8%52.8%
+
45.0%45.0%
- 52.8 % - 106 - 56 + 45.0 % + 131 + 59 - @@ -118,11 +118,11 @@ repositories/ -
46.2%46.2%
+
84.6%84.6%
- 46.2 % + 84.6 % 13 - 6 + 11 - @@ -133,7 +133,7 @@
0.0%
0.0 % - 8 + 9 - diff --git a/coverage_report/models/index-sort-f.html b/coverage_report/models/index-sort-f.html index 9a30385..0ad9d8b 100644 --- a/coverage_report/models/index-sort-f.html +++ b/coverage_report/models/index-sort-f.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/models/index-sort-l.html b/coverage_report/models/index-sort-l.html index 504dafe..f57d979 100644 --- a/coverage_report/models/index-sort-l.html +++ b/coverage_report/models/index-sort-l.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/models/index.html b/coverage_report/models/index.html index 5394571..e7bb6dc 100644 --- a/coverage_report/models/index.html +++ b/coverage_report/models/index.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/models/restaurant.dart.func-c.html b/coverage_report/models/restaurant.dart.func-c.html index fd8db83..575f209 100644 --- a/coverage_report/models/restaurant.dart.func-c.html +++ b/coverage_report/models/restaurant.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/models/restaurant.dart.func.html b/coverage_report/models/restaurant.dart.func.html index 2a41e98..54d73b0 100644 --- a/coverage_report/models/restaurant.dart.func.html +++ b/coverage_report/models/restaurant.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/models/restaurant.dart.gcov.html b/coverage_report/models/restaurant.dart.gcov.html index d439461..e63036b 100644 --- a/coverage_report/models/restaurant.dart.gcov.html +++ b/coverage_report/models/restaurant.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -69,13 +69,13 @@ 7 : final String? alias; 8 : final String? title; 9 : - 10 1 : Category({ + 10 2 : Category({ 11 : this.alias, 12 : this.title, 13 : }); 14 : - 15 1 : factory Category.fromJson(Map<String, dynamic> json) => - 16 1 : _$CategoryFromJson(json); + 15 2 : factory Category.fromJson(Map<String, dynamic> json) => + 16 2 : _$CategoryFromJson(json); 17 : 18 0 : Map<String, dynamic> toJson() => _$CategoryToJson(this); 19 : } @@ -85,11 +85,11 @@ 23 : @JsonKey(name: 'is_open_now') 24 : final bool? isOpenNow; 25 : - 26 1 : const Hours({ + 26 2 : const Hours({ 27 : this.isOpenNow, 28 : }); 29 : - 30 2 : factory Hours.fromJson(Map<String, dynamic> json) => _$HoursFromJson(json); + 30 4 : factory Hours.fromJson(Map<String, dynamic> json) => _$HoursFromJson(json); 31 : 32 0 : Map<String, dynamic> toJson() => _$HoursToJson(this); 33 : } @@ -101,13 +101,13 @@ 39 : final String? imageUrl; 40 : final String? name; 41 : - 42 1 : const User({ + 42 2 : const User({ 43 : this.id, 44 : this.imageUrl, 45 : this.name, 46 : }); 47 : - 48 2 : factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); + 48 4 : factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); 49 : 50 0 : Map<String, dynamic> toJson() => _$UserToJson(this); 51 : } @@ -119,14 +119,14 @@ 57 : final String? text; 58 : final User? user; 59 : - 60 1 : const Review({ + 60 2 : const Review({ 61 : this.id, 62 : this.rating, 63 : this.user, 64 : this.text, 65 : }); 66 : - 67 2 : factory Review.fromJson(Map<String, dynamic> json) => _$ReviewFromJson(json); + 67 4 : factory Review.fromJson(Map<String, dynamic> json) => _$ReviewFromJson(json); 68 : 69 0 : Map<String, dynamic> toJson() => _$ReviewToJson(this); 70 : } @@ -136,12 +136,12 @@ 74 : @JsonKey(name: 'formatted_address') 75 : final String? formattedAddress; 76 : - 77 1 : Location({ + 77 2 : Location({ 78 : this.formattedAddress, 79 : }); 80 : - 81 1 : factory Location.fromJson(Map<String, dynamic> json) => - 82 1 : _$LocationFromJson(json); + 81 2 : factory Location.fromJson(Map<String, dynamic> json) => + 82 2 : _$LocationFromJson(json); 83 : 84 0 : Map<String, dynamic> toJson() => _$LocationToJson(this); 85 : } @@ -158,7 +158,7 @@ 96 : final List<Review>? reviews; 97 : final Location? location; 98 : - 99 1 : const Restaurant({ + 99 2 : const Restaurant({ 100 : this.id, 101 : this.name, 102 : this.price, @@ -170,8 +170,8 @@ 108 : this.location, 109 : }); 110 : - 111 1 : factory Restaurant.fromJson(Map<String, dynamic> json) => - 112 1 : _$RestaurantFromJson(json); + 111 2 : factory Restaurant.fromJson(Map<String, dynamic> json) => + 112 2 : _$RestaurantFromJson(json); 113 : 114 0 : Map<String, dynamic> toJson() => _$RestaurantToJson(this); 115 : @@ -207,13 +207,13 @@ 145 : @JsonKey(name: 'business') 146 : final List<Restaurant>? restaurants; 147 : - 148 1 : const RestaurantQueryResult({ + 148 2 : const RestaurantQueryResult({ 149 : this.total, 150 : this.restaurants, 151 : }); 152 : - 153 1 : factory RestaurantQueryResult.fromJson(Map<String, dynamic> json) => - 154 1 : _$RestaurantQueryResultFromJson(json); + 153 2 : factory RestaurantQueryResult.fromJson(Map<String, dynamic> json) => + 154 2 : _$RestaurantQueryResultFromJson(json); 155 : 156 0 : Map<String, dynamic> toJson() => _$RestaurantQueryResultToJson(this); 157 : } diff --git a/coverage_report/models/restaurant.g.dart.func-c.html b/coverage_report/models/restaurant.g.dart.func-c.html index 07ba84f..2e9c56d 100644 --- a/coverage_report/models/restaurant.g.dart.func-c.html +++ b/coverage_report/models/restaurant.g.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/models/restaurant.g.dart.func.html b/coverage_report/models/restaurant.g.dart.func.html index ef21f97..72a11b7 100644 --- a/coverage_report/models/restaurant.g.dart.func.html +++ b/coverage_report/models/restaurant.g.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/models/restaurant.g.dart.gcov.html b/coverage_report/models/restaurant.g.dart.gcov.html index cd625a3..9d71c9d 100644 --- a/coverage_report/models/restaurant.g.dart.gcov.html +++ b/coverage_report/models/restaurant.g.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -68,9 +68,9 @@ 6 : // JsonSerializableGenerator 7 : // ************************************************************************** 8 : - 9 2 : Category _$CategoryFromJson(Map<String, dynamic> json) => Category( - 10 1 : alias: json['alias'] as String?, - 11 1 : title: json['title'] as String?, + 9 4 : Category _$CategoryFromJson(Map<String, dynamic> json) => Category( + 10 2 : alias: json['alias'] as String?, + 11 2 : title: json['title'] as String?, 12 : ); 13 : 14 0 : Map<String, dynamic> _$CategoryToJson(Category instance) => <String, dynamic>{ @@ -78,18 +78,18 @@ 16 0 : 'title': instance.title, 17 : }; 18 : - 19 2 : Hours _$HoursFromJson(Map<String, dynamic> json) => Hours( - 20 1 : isOpenNow: json['is_open_now'] as bool?, + 19 4 : Hours _$HoursFromJson(Map<String, dynamic> json) => Hours( + 20 2 : isOpenNow: json['is_open_now'] as bool?, 21 : ); 22 : 23 0 : Map<String, dynamic> _$HoursToJson(Hours instance) => <String, dynamic>{ 24 0 : 'is_open_now': instance.isOpenNow, 25 : }; 26 : - 27 2 : User _$UserFromJson(Map<String, dynamic> json) => User( - 28 1 : id: json['id'] as String?, - 29 1 : imageUrl: json['image_url'] as String?, - 30 1 : name: json['name'] as String?, + 27 4 : User _$UserFromJson(Map<String, dynamic> json) => User( + 28 2 : id: json['id'] as String?, + 29 2 : imageUrl: json['image_url'] as String?, + 30 2 : name: json['name'] as String?, 31 : ); 32 : 33 0 : Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{ @@ -98,12 +98,12 @@ 36 0 : 'name': instance.name, 37 : }; 38 : - 39 2 : Review _$ReviewFromJson(Map<String, dynamic> json) => Review( - 40 1 : id: json['id'] as String?, - 41 1 : rating: json['rating'] as int?, - 42 1 : user: json['user'] == null + 39 4 : Review _$ReviewFromJson(Map<String, dynamic> json) => Review( + 40 2 : id: json['id'] as String?, + 41 2 : rating: json['rating'] as int?, + 42 2 : user: json['user'] == null 43 : ? null - 44 2 : : User.fromJson(json['user'] as Map<String, dynamic>), + 44 4 : : User.fromJson(json['user'] as Map<String, dynamic>), 45 : ); 46 : 47 0 : Map<String, dynamic> _$ReviewToJson(Review instance) => <String, dynamic>{ @@ -112,33 +112,33 @@ 50 0 : 'user': instance.user, 51 : }; 52 : - 53 2 : Location _$LocationFromJson(Map<String, dynamic> json) => Location( - 54 1 : formattedAddress: json['formatted_address'] as String?, + 53 4 : Location _$LocationFromJson(Map<String, dynamic> json) => Location( + 54 2 : formattedAddress: json['formatted_address'] as String?, 55 : ); 56 : 57 0 : Map<String, dynamic> _$LocationToJson(Location instance) => <String, dynamic>{ 58 0 : 'formatted_address': instance.formattedAddress, 59 : }; 60 : - 61 2 : Restaurant _$RestaurantFromJson(Map<String, dynamic> json) => Restaurant( - 62 1 : id: json['id'] as String?, - 63 1 : name: json['name'] as String?, - 64 1 : price: json['price'] as String?, - 65 2 : rating: (json['rating'] as num?)?.toDouble(), + 61 4 : Restaurant _$RestaurantFromJson(Map<String, dynamic> json) => Restaurant( + 62 2 : id: json['id'] as String?, + 63 2 : name: json['name'] as String?, + 64 2 : price: json['price'] as String?, + 65 4 : rating: (json['rating'] as num?)?.toDouble(), 66 : photos: - 67 4 : (json['photos'] as List<dynamic>?)?.map((e) => e as String).toList(), - 68 1 : categories: (json['categories'] as List<dynamic>?) - 69 3 : ?.map((e) => Category.fromJson(e as Map<String, dynamic>)) - 70 1 : .toList(), - 71 1 : hours: (json['hours'] as List<dynamic>?) - 72 3 : ?.map((e) => Hours.fromJson(e as Map<String, dynamic>)) - 73 1 : .toList(), - 74 1 : reviews: (json['reviews'] as List<dynamic>?) - 75 3 : ?.map((e) => Review.fromJson(e as Map<String, dynamic>)) - 76 1 : .toList(), - 77 1 : location: json['location'] == null + 67 8 : (json['photos'] as List<dynamic>?)?.map((e) => e as String).toList(), + 68 2 : categories: (json['categories'] as List<dynamic>?) + 69 6 : ?.map((e) => Category.fromJson(e as Map<String, dynamic>)) + 70 2 : .toList(), + 71 2 : hours: (json['hours'] as List<dynamic>?) + 72 6 : ?.map((e) => Hours.fromJson(e as Map<String, dynamic>)) + 73 2 : .toList(), + 74 2 : reviews: (json['reviews'] as List<dynamic>?) + 75 6 : ?.map((e) => Review.fromJson(e as Map<String, dynamic>)) + 76 2 : .toList(), + 77 2 : location: json['location'] == null 78 : ? null - 79 2 : : Location.fromJson(json['location'] as Map<String, dynamic>), + 79 4 : : Location.fromJson(json['location'] as Map<String, dynamic>), 80 : ); 81 : 82 0 : Map<String, dynamic> _$RestaurantToJson(Restaurant instance) => @@ -154,13 +154,13 @@ 92 0 : 'location': instance.location, 93 : }; 94 : - 95 1 : RestaurantQueryResult _$RestaurantQueryResultFromJson( + 95 2 : RestaurantQueryResult _$RestaurantQueryResultFromJson( 96 : Map<String, dynamic> json) => - 97 1 : RestaurantQueryResult( - 98 1 : total: json['total'] as int?, - 99 1 : restaurants: (json['business'] as List<dynamic>?) - 100 3 : ?.map((e) => Restaurant.fromJson(e as Map<String, dynamic>)) - 101 1 : .toList(), + 97 2 : RestaurantQueryResult( + 98 2 : total: json['total'] as int?, + 99 2 : restaurants: (json['business'] as List<dynamic>?) + 100 6 : ?.map((e) => Restaurant.fromJson(e as Map<String, dynamic>)) + 101 2 : .toList(), 102 : ); 103 : 104 0 : Map<String, dynamic> _$RestaurantQueryResultToJson( diff --git a/coverage_report/pages/home_page.dart.func-c.html b/coverage_report/pages/home_page.dart.func-c.html index fb8644c..56bb9f2 100644 --- a/coverage_report/pages/home_page.dart.func-c.html +++ b/coverage_report/pages/home_page.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 100.0 % - 16 - 16 + 94.7 % + 19 + 18 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/pages/home_page.dart.func.html b/coverage_report/pages/home_page.dart.func.html index 66e1bed..5940687 100644 --- a/coverage_report/pages/home_page.dart.func.html +++ b/coverage_report/pages/home_page.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 100.0 % - 16 - 16 + 94.7 % + 19 + 18 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/pages/home_page.dart.gcov.html b/coverage_report/pages/home_page.dart.gcov.html index 7f7333a..109d740 100644 --- a/coverage_report/pages/home_page.dart.gcov.html +++ b/coverage_report/pages/home_page.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 100.0 % - 16 - 16 + 94.7 % + 19 + 18 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -61,77 +61,78 @@
            Line data    Source code
        1              : import 'package:flutter/material.dart';
-       2              : import 'package:restaurant_tour/pages/restaurant_list_page.dart';
-       3              : 
-       4              : // class HomePageBlocProvider extends StatelessWidget {
-       5              : //   const HomePageBlocProvider({super.key});
-       6              : 
-       7              : //   @override
-       8              : //   Widget build(BuildContext context) {
-       9              : //     return BlocProvider(
-      10              : //       create: (context) =>
-      11              : //           GetIt.instance<RestaurantCubit>()..fetchRestaurants(),
-      12              : //       child: const HomePage(),
-      13              : //     );
-      14              : //   }
-      15              : // }
-      16              : 
-      17              : class HomePage extends StatelessWidget {
-      18            1 :   const HomePage({super.key});
-      19              : 
-      20            1 :   @override
-      21              :   Widget build(BuildContext context) {
-      22            1 :     return DefaultTabController(
-      23              :       length: 2,
-      24            1 :       child: Scaffold(
-      25            1 :         appBar: AppBar(
-      26            1 :           title: Text(
-      27              :             "RestauranTour",
-      28            3 :             style: Theme.of(context).textTheme.headlineLarge,
-      29              :           ),
-      30            1 :           actions: [
-      31              :             // Padding(
-      32              :             //   padding: const EdgeInsets.only(right: 16),
-      33              :             //   child: TextButton(
-      34              :             //     onPressed: () {},
-      35              :             //     child: const CircleAvatar(
-      36              :             //       backgroundImage: NetworkImage(
-      37              :             //         'https://mdbcdn.b-cdn.net/img/new/avatars/2.webp',
-      38              :             //       ),
-      39              :             //     ),
-      40              :             //   ),
-      41              :             // ),
-      42              :           ],
-      43            1 :           bottom: TabBar(
-      44            1 :             tabs: [
-      45            1 :               Tab(
-      46            1 :                 child: Text(
-      47              :                   'All restaurants',
-      48            3 :                   style: Theme.of(context).textTheme.displayLarge,
-      49              :                 ),
-      50              :               ),
-      51            1 :               Tab(
-      52            1 :                 child: Text(
-      53              :                   'My favorites',
-      54            3 :                   style: Theme.of(context).textTheme.displayLarge,
-      55              :                 ),
-      56              :               ),
-      57              :             ],
-      58              :           ),
-      59              :         ),
-      60              :         body: const SafeArea(
-      61              :           minimum: EdgeInsets.all(16),
-      62              :           child: TabBarView(
-      63              :             children: [
-      64              :               RestaurantListPageView(),
-      65              :               Text('Dias'),
-      66              :             ],
-      67              :           ),
-      68              :         ),
-      69              :       ),
-      70              :     );
-      71              :   }
-      72              : }
+       2              : import 'package:restaurant_tour/pages/favorites_list_page_view.dart';
+       3              : import 'package:restaurant_tour/pages/restaurant_list_page.dart';
+       4              : 
+       5              : // class HomePageBlocProvider extends StatelessWidget {
+       6              : //   const HomePageBlocProvider({super.key});
+       7              : 
+       8              : //   @override
+       9              : //   Widget build(BuildContext context) {
+      10              : //     return BlocProvider(
+      11              : //       create: (context) =>
+      12              : //           GetIt.instance<RestaurantCubit>()..fetchRestaurants(),
+      13              : //       child: const HomePage(),
+      14              : //     );
+      15              : //   }
+      16              : // }
+      17              : 
+      18              : class HomePage extends StatelessWidget {
+      19            1 :   const HomePage({super.key});
+      20              : 
+      21            1 :   @override
+      22              :   Widget build(BuildContext context) {
+      23            1 :     return DefaultTabController(
+      24              :       length: 2,
+      25            1 :       child: Scaffold(
+      26            1 :         appBar: AppBar(
+      27            1 :           title: Text(
+      28              :             "RestauranTour",
+      29            3 :             style: Theme.of(context).textTheme.headlineLarge,
+      30              :           ),
+      31            1 :           actions: [
+      32            1 :             Padding(
+      33              :               padding: const EdgeInsets.only(right: 16),
+      34            1 :               child: TextButton(
+      35            0 :                 onPressed: () {},
+      36              :                 child: const CircleAvatar(
+      37              :                   backgroundImage: NetworkImage(
+      38              :                     'https://mdbcdn.b-cdn.net/img/new/avatars/2.webp',
+      39              :                   ),
+      40              :                 ),
+      41              :               ),
+      42              :             ),
+      43              :           ],
+      44            1 :           bottom: TabBar(
+      45            1 :             tabs: [
+      46            1 :               Tab(
+      47            1 :                 child: Text(
+      48              :                   'All restaurants',
+      49            3 :                   style: Theme.of(context).textTheme.displayLarge,
+      50              :                 ),
+      51              :               ),
+      52            1 :               Tab(
+      53            1 :                 child: Text(
+      54              :                   'My favorites',
+      55            3 :                   style: Theme.of(context).textTheme.displayLarge,
+      56              :                 ),
+      57              :               ),
+      58              :             ],
+      59              :           ),
+      60              :         ),
+      61              :         body: const SafeArea(
+      62              :           minimum: EdgeInsets.all(16),
+      63              :           child: TabBarView(
+      64              :             children: [
+      65              :               RestaurantListPageView(),
+      66              :               FavoritesListPageView(),
+      67              :             ],
+      68              :           ),
+      69              :         ),
+      70              :       ),
+      71              :     );
+      72              :   }
+      73              : }
         
diff --git a/coverage_report/pages/index-sort-f.html b/coverage_report/pages/index-sort-f.html index 5c98282..3f4c23c 100644 --- a/coverage_report/pages/index-sort-f.html +++ b/coverage_report/pages/index-sort-f.html @@ -31,13 +31,13 @@ lcov.info Lines: - 52.8 % - 106 - 56 + 45.0 % + 131 + 59 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -79,14 +79,26 @@ Total Hit + + favorites_list_page_view.dart + +
4.8%4.8%
+ + 4.8 % + 21 + 1 + - + + + home_page.dart -
100.0%
+
94.7%94.7%
- 100.0 % - 16 - 16 + 94.7 % + 19 + 18 - @@ -106,10 +118,10 @@ restaurant_list_page.dart -
78.4%78.4%
+
76.9%76.9%
- 78.4 % - 51 + 76.9 % + 52 40 - diff --git a/coverage_report/pages/index-sort-l.html b/coverage_report/pages/index-sort-l.html index 356c96c..2aabcae 100644 --- a/coverage_report/pages/index-sort-l.html +++ b/coverage_report/pages/index-sort-l.html @@ -31,13 +31,13 @@ lcov.info Lines: - 52.8 % - 106 - 56 + 45.0 % + 131 + 59 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -91,13 +91,25 @@ + + favorites_list_page_view.dart + +
4.8%4.8%
+ + 4.8 % + 21 + 1 + - + + + restaurant_list_page.dart -
78.4%78.4%
+
76.9%76.9%
- 78.4 % - 51 + 76.9 % + 52 40 - @@ -106,11 +118,11 @@ home_page.dart -
100.0%
+
94.7%94.7%
- 100.0 % - 16 - 16 + 94.7 % + 19 + 18 - diff --git a/coverage_report/pages/index.html b/coverage_report/pages/index.html index 0a357a6..08d26e9 100644 --- a/coverage_report/pages/index.html +++ b/coverage_report/pages/index.html @@ -31,13 +31,13 @@ lcov.info Lines: - 52.8 % - 106 - 56 + 45.0 % + 131 + 59 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -79,14 +79,26 @@ Total Hit + + favorites_list_page_view.dart + +
4.8%4.8%
+ + 4.8 % + 21 + 1 + - + + + home_page.dart -
100.0%
+
94.7%94.7%
- 100.0 % - 16 - 16 + 94.7 % + 19 + 18 - @@ -106,10 +118,10 @@ restaurant_list_page.dart -
78.4%78.4%
+
76.9%76.9%
- 78.4 % - 51 + 76.9 % + 52 40 - diff --git a/coverage_report/pages/restaurant_detail_page.dart.func-c.html b/coverage_report/pages/restaurant_detail_page.dart.func-c.html index 8bd9e82..b75d0ab 100644 --- a/coverage_report/pages/restaurant_detail_page.dart.func-c.html +++ b/coverage_report/pages/restaurant_detail_page.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/pages/restaurant_detail_page.dart.func.html b/coverage_report/pages/restaurant_detail_page.dart.func.html index bfabb91..4db5c98 100644 --- a/coverage_report/pages/restaurant_detail_page.dart.func.html +++ b/coverage_report/pages/restaurant_detail_page.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/pages/restaurant_detail_page.dart.gcov.html b/coverage_report/pages/restaurant_detail_page.dart.gcov.html index 373db8e..92997e8 100644 --- a/coverage_report/pages/restaurant_detail_page.dart.gcov.html +++ b/coverage_report/pages/restaurant_detail_page.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/pages/restaurant_list_page.dart.func-c.html b/coverage_report/pages/restaurant_list_page.dart.func-c.html index b542212..957cef5 100644 --- a/coverage_report/pages/restaurant_list_page.dart.func-c.html +++ b/coverage_report/pages/restaurant_list_page.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 78.4 % - 51 + 76.9 % + 52 40 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/pages/restaurant_list_page.dart.func.html b/coverage_report/pages/restaurant_list_page.dart.func.html index 674b3aa..2bd7844 100644 --- a/coverage_report/pages/restaurant_list_page.dart.func.html +++ b/coverage_report/pages/restaurant_list_page.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 78.4 % - 51 + 76.9 % + 52 40 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/pages/restaurant_list_page.dart.gcov.html b/coverage_report/pages/restaurant_list_page.dart.gcov.html index f7d717f..41d1ef1 100644 --- a/coverage_report/pages/restaurant_list_page.dart.gcov.html +++ b/coverage_report/pages/restaurant_list_page.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 78.4 % - 51 + 76.9 % + 52 40 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -87,108 +87,109 @@ 25 0 : child: Text(state.message), 26 : ); 27 : } - 28 1 : if (state is RestaurantsLoadedState) { - 29 1 : return ListView.builder( - 30 3 : itemCount: state.result.restaurants?.length, - 31 1 : itemBuilder: (BuildContext context, int index) { - 32 1 : return Row( - 33 : mainAxisAlignment: MainAxisAlignment.spaceEvenly, - 34 1 : children: [ - 35 1 : ListTile( - 36 3 : restaurant: state.result.restaurants!.elementAt(index), - 37 : constraints: constraints, - 38 : ), - 39 : ], - 40 : ); - 41 : }, - 42 : ); - 43 : } - 44 0 : return Container(); - 45 : }, - 46 : ); - 47 : }, - 48 : ); - 49 : } - 50 : } - 51 : - 52 : class ListTile extends StatelessWidget { - 53 1 : const ListTile({ - 54 : super.key, - 55 : required this.restaurant, - 56 : required this.constraints, - 57 : }); - 58 : final Restaurant restaurant; - 59 : final BoxConstraints constraints; - 60 : - 61 1 : @override - 62 : Widget build(BuildContext context) { - 63 1 : return GestureDetector( - 64 0 : onTap: () { - 65 0 : Navigator.push( - 66 : context, - 67 0 : MaterialPageRoute( - 68 0 : builder: (context) => RestaurantDetailPage(restaurant: restaurant), - 69 : ), - 70 : ); - 71 : }, - 72 1 : child: Container( - 73 2 : width: constraints.maxWidth, - 74 : margin: const EdgeInsets.only(bottom: 8, top: 8), - 75 : padding: const EdgeInsets.all(16), - 76 1 : decoration: BoxDecoration( - 77 : color: Colors.white, - 78 2 : border: Border.all(color: Colors.grey.shade300), - 79 1 : borderRadius: BorderRadius.circular(9), - 80 1 : boxShadow: [ - 81 1 : BoxShadow( - 82 1 : color: Colors.grey.shade200, - 83 : blurRadius: 3, - 84 : offset: const Offset(0, 2), - 85 : ), - 86 : ], - 87 : ), - 88 1 : child: Row( - 89 1 : children: [ - 90 1 : Column( - 91 1 : children: [ - 92 1 : HeroImageWidget( - 93 1 : restaurant: restaurant, - 94 : width: 90, - 95 : height: 90, - 96 : borderRadius: 9.0, - 97 : ), - 98 : ], - 99 : ), - 100 : const Spacer( - 101 : flex: 1, - 102 : ), - 103 1 : Flexible( - 104 : flex: 10, - 105 1 : child: Column( - 106 : mainAxisAlignment: MainAxisAlignment.start, - 107 : crossAxisAlignment: CrossAxisAlignment.start, - 108 1 : children: [ - 109 1 : Text( - 110 2 : restaurant.name ?? '', - 111 : maxLines: 2, - 112 : ), - 113 : const SizedBox( - 114 : height: 10, - 115 : ), - 116 2 : PriceAndClassificationRowWidget(restaurant: restaurant), - 117 : const SizedBox( - 118 : height: 10, - 119 : ), - 120 2 : RatingAndOpenStatusWidget(restaurant: restaurant) - 121 : ], - 122 : ), - 123 : ), - 124 : ], - 125 : ), - 126 : ), - 127 : ); - 128 : } - 129 : } + 28 1 : if (state is RestaurantsLoadedState || + 29 0 : state is FavoriteRestaurantState) { + 30 1 : return ListView.builder( + 31 3 : itemCount: state.result!.restaurants?.length, + 32 1 : itemBuilder: (BuildContext context, int index) { + 33 1 : return Row( + 34 : mainAxisAlignment: MainAxisAlignment.spaceEvenly, + 35 1 : children: [ + 36 1 : RestaurantListTile( + 37 3 : restaurant: state.result!.restaurants!.elementAt(index), + 38 : constraints: constraints, + 39 : ), + 40 : ], + 41 : ); + 42 : }, + 43 : ); + 44 : } + 45 0 : return Container(); + 46 : }, + 47 : ); + 48 : }, + 49 : ); + 50 : } + 51 : } + 52 : + 53 : class RestaurantListTile extends StatelessWidget { + 54 1 : const RestaurantListTile({ + 55 : super.key, + 56 : required this.restaurant, + 57 : required this.constraints, + 58 : }); + 59 : final Restaurant restaurant; + 60 : final BoxConstraints constraints; + 61 : + 62 1 : @override + 63 : Widget build(BuildContext context) { + 64 1 : return GestureDetector( + 65 0 : onTap: () { + 66 0 : Navigator.push( + 67 : context, + 68 0 : MaterialPageRoute( + 69 0 : builder: (context) => RestaurantDetailPage(restaurant: restaurant), + 70 : ), + 71 : ); + 72 : }, + 73 1 : child: Container( + 74 2 : width: constraints.maxWidth, + 75 : margin: const EdgeInsets.only(bottom: 8, top: 8), + 76 : padding: const EdgeInsets.all(16), + 77 1 : decoration: BoxDecoration( + 78 : color: Colors.white, + 79 2 : border: Border.all(color: Colors.grey.shade300), + 80 1 : borderRadius: BorderRadius.circular(9), + 81 1 : boxShadow: [ + 82 1 : BoxShadow( + 83 1 : color: Colors.grey.shade200, + 84 : blurRadius: 3, + 85 : offset: const Offset(0, 2), + 86 : ), + 87 : ], + 88 : ), + 89 1 : child: Row( + 90 1 : children: [ + 91 1 : Column( + 92 1 : children: [ + 93 1 : HeroImageWidget( + 94 1 : restaurant: restaurant, + 95 : width: 90, + 96 : height: 90, + 97 : borderRadius: 9.0, + 98 : ), + 99 : ], + 100 : ), + 101 : const Spacer( + 102 : flex: 1, + 103 : ), + 104 1 : Flexible( + 105 : flex: 10, + 106 1 : child: Column( + 107 : mainAxisAlignment: MainAxisAlignment.start, + 108 : crossAxisAlignment: CrossAxisAlignment.start, + 109 1 : children: [ + 110 1 : Text( + 111 2 : restaurant.name ?? '', + 112 : maxLines: 2, + 113 : ), + 114 : const SizedBox( + 115 : height: 10, + 116 : ), + 117 2 : PriceAndClassificationRowWidget(restaurant: restaurant), + 118 : const SizedBox( + 119 : height: 10, + 120 : ), + 121 2 : RatingAndOpenStatusWidget(restaurant: restaurant) + 122 : ], + 123 : ), + 124 : ), + 125 : ], + 126 : ), + 127 : ), + 128 : ); + 129 : } + 130 : } diff --git a/coverage_report/repositories/index-sort-f.html b/coverage_report/repositories/index-sort-f.html index ed24dc9..013957e 100644 --- a/coverage_report/repositories/index-sort-f.html +++ b/coverage_report/repositories/index-sort-f.html @@ -31,13 +31,13 @@ lcov.info Lines: - 46.2 % + 84.6 % 13 - 6 + 11 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -82,11 +82,11 @@ yelp_repository.dart -
46.2%46.2%
+
84.6%84.6%
- 46.2 % + 84.6 % 13 - 6 + 11 - diff --git a/coverage_report/repositories/index-sort-l.html b/coverage_report/repositories/index-sort-l.html index 641e900..d2d34c0 100644 --- a/coverage_report/repositories/index-sort-l.html +++ b/coverage_report/repositories/index-sort-l.html @@ -31,13 +31,13 @@ lcov.info Lines: - 46.2 % + 84.6 % 13 - 6 + 11 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -82,11 +82,11 @@ yelp_repository.dart -
46.2%46.2%
+
84.6%84.6%
- 46.2 % + 84.6 % 13 - 6 + 11 - diff --git a/coverage_report/repositories/index.html b/coverage_report/repositories/index.html index 2e05c70..a196ddc 100644 --- a/coverage_report/repositories/index.html +++ b/coverage_report/repositories/index.html @@ -31,13 +31,13 @@ lcov.info Lines: - 46.2 % + 84.6 % 13 - 6 + 11 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -82,11 +82,11 @@ yelp_repository.dart -
46.2%46.2%
+
84.6%84.6%
- 46.2 % + 84.6 % 13 - 6 + 11 - diff --git a/coverage_report/repositories/yelp_repository.dart.func-c.html b/coverage_report/repositories/yelp_repository.dart.func-c.html index 29fcb4b..d40275a 100644 --- a/coverage_report/repositories/yelp_repository.dart.func-c.html +++ b/coverage_report/repositories/yelp_repository.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 46.2 % + 84.6 % 13 - 6 + 11 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/repositories/yelp_repository.dart.func.html b/coverage_report/repositories/yelp_repository.dart.func.html index 7a85301..6238adb 100644 --- a/coverage_report/repositories/yelp_repository.dart.func.html +++ b/coverage_report/repositories/yelp_repository.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 46.2 % + 84.6 % 13 - 6 + 11 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/repositories/yelp_repository.dart.gcov.html b/coverage_report/repositories/yelp_repository.dart.gcov.html index 67124a2..0ed7518 100644 --- a/coverage_report/repositories/yelp_repository.dart.gcov.html +++ b/coverage_report/repositories/yelp_repository.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 46.2 % + 84.6 % 13 - 6 + 11 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -62,127 +62,125 @@
        1              : import 'package:dio/dio.dart';
        2              : import 'package:flutter/foundation.dart';
-       3              : import 'package:restaurant_tour/models/restaurant.dart';
-       4              : import 'package:restaurant_tour/repositories/sample_json.dart';
-       5              : 
-       6              : const _apiKey =
-       7              :     'GzcIFZrKe4aMmED9FS9ObPxFP4vAhEOW2wN9usDA0zazBimbxQ8O2LdcpwMUcpkCU1ZYxF-LK_jWygZgGvfeE_5jSulY1XdUPs09j1FCwDtXQmyD_emQYuOEMBHKZnYx';
-       8              : 
-       9              : class YelpRepository {
-      10              :   late Dio dio;
-      11              : 
-      12            1 :   YelpRepository({
-      13              :     @visibleForTesting Dio? dio,
-      14              :   }) : dio = dio ??
-      15            1 :             Dio(
-      16            1 :               BaseOptions(
-      17              :                 baseUrl: 'https://api.yelp.com',
-      18            1 :                 headers: {
-      19              :                   'Authorization': 'Bearer $_apiKey',
-      20              :                   'Content-Type': 'application/graphql',
-      21              :                 },
-      22              :               ),
-      23              :             );
-      24              : 
-      25              :   /// Returns a response in this shape
-      26              :   /// {
-      27              :   /// "data": {
-      28              :   ///   "search": {
-      29              :   ///     "total": 5056,
-      30              :   ///     "business": [
-      31              :   ///       {
-      32              :   ///         "id": "faPVqws-x-5k2CQKDNtHxw",
-      33              :   ///         "name": "Yardbird Southern Table & Bar",
-      34              :   ///         "price": "$$",
-      35              :   ///         "rating": 4.5,
-      36              :   ///         "photos": [
-      37              :   ///           "https:///s3-media4.fl.yelpcdn.com/bphoto/_zXRdYX4r1OBfF86xKMbDw/o.jpg"
-      38              :   ///         ],
-      39              :   ///         "reviews": [
-      40              :   ///           {
-      41              :   ///             "id": "sjZoO8wcK1NeGJFDk5i82Q",
-      42              :   ///             "rating": 5,
-      43              :   ///             "user": {
-      44              :   ///               "id": "BuBCkWFNT_O2dbSnBZvpoQ",
-      45              :   ///               "image_url": "https:///s3-media2.fl.yelpcdn.com/photo/v8tbTjYaFvkzh1d7iE-pcQ/o.jpg",
-      46              :   ///               "name": "Gina T.",
-      47              :   ///               "text": "I love this place! The food is amazing and the service is great."
-      48              :   ///             }
-      49              :   ///           },
-      50              :   ///           {
-      51              :   ///             "id": "okpO9hfpxQXssbTZTKq9hA",
-      52              :   ///             "rating": 5,
-      53              :   ///             "user": {
-      54              :   ///               "id": "0x9xu_b0Ct_6hG6jaxpztw",
-      55              :   ///               "image_url": "https:///s3-media3.fl.yelpcdn.com/photo/gjz8X6tqE3e4praK4HfCiA/o.jpg",
-      56              :   ///               "name": "Crystal L.",
-      57              :   ///               "text": "Greate place to eat"
-      58              :   ///             }
-      59              :   ///           },
-      60              :   ///        ...
-      61              :   ///     ]
-      62              :   ///   }
-      63              :   /// }
-      64              :   ///
-      65              :   ///
-      66            1 :   RestaurantQueryResult getRestaurantsFromCache({int offset = 0}) {
-      67              :     try {
-      68            3 :       return RestaurantQueryResult.fromJson(sample['data']['search']);
-      69              :     } catch (e) {
-      70            0 :       throw Exception();
-      71              :     }
-      72              :   }
-      73              : 
-      74            0 :   Future<RestaurantQueryResult?> getRestaurants({int offset = 0}) async {
-      75              :     try {
-      76            0 :       final response = await dio.post<Map<String, dynamic>>(
-      77              :         '/v3/graphql',
-      78            0 :         data: _getQuery(offset),
-      79              :       );
-      80              :       // saveToJson(response.data!['data']['search'], 'datastore.json');
-      81            0 :       return RestaurantQueryResult.fromJson(response.data!['data']['search']);
-      82              :     } catch (e) {
-      83              :       return null;
-      84              :     }
-      85              :   }
-      86              : 
-      87            0 :   String _getQuery(int offset) {
-      88              :     return '''
-      89              : query getRestaurants {
-      90              :   search(location: "Las Vegas", limit: 20, offset: $offset) {
-      91              :     total    
-      92              :     business {
-      93              :       id
-      94              :       name
-      95              :       price
-      96              :       rating
-      97              :       photos
-      98              :       reviews {
-      99              :         id
-     100              :         rating
-     101              :         text
-     102              :         user {
-     103              :           id
-     104              :           image_url
-     105              :           name
-     106              :         }
-     107              :       }
-     108              :       categories {
-     109              :         title
-     110              :         alias
-     111              :       }
-     112              :       hours {
-     113              :         is_open_now
-     114              :       }
-     115              :       location {
-     116              :         formatted_address
-     117              :       }
-     118              :     }
-     119              :   }
-     120              : }
-     121            0 : ''';
-     122              :   }
-     123              : }
+       3              : import 'package:restaurant_tour/env.dart';
+       4              : import 'package:restaurant_tour/models/restaurant.dart';
+       5              : import 'package:restaurant_tour/repositories/sample_json.dart';
+       6              : 
+       7              : class YelpRepository {
+       8              :   late Dio dio;
+       9              : 
+      10            2 :   YelpRepository({
+      11              :     @visibleForTesting Dio? dio,
+      12              :   }) : dio = dio ??
+      13            1 :             Dio(
+      14            1 :               BaseOptions(
+      15              :                 baseUrl: 'https://api.yelp.com',
+      16            1 :                 headers: {
+      17              :                   'Authorization': 'Bearer $API_KEY',
+      18              :                   'Content-Type': 'application/graphql',
+      19              :                 },
+      20              :               ),
+      21              :             );
+      22              : 
+      23              :   /// Returns a response in this shape
+      24              :   /// {
+      25              :   /// "data": {
+      26              :   ///   "search": {
+      27              :   ///     "total": 5056,
+      28              :   ///     "business": [
+      29              :   ///       {
+      30              :   ///         "id": "faPVqws-x-5k2CQKDNtHxw",
+      31              :   ///         "name": "Yardbird Southern Table & Bar",
+      32              :   ///         "price": "$$",
+      33              :   ///         "rating": 4.5,
+      34              :   ///         "photos": [
+      35              :   ///           "https:///s3-media4.fl.yelpcdn.com/bphoto/_zXRdYX4r1OBfF86xKMbDw/o.jpg"
+      36              :   ///         ],
+      37              :   ///         "reviews": [
+      38              :   ///           {
+      39              :   ///             "id": "sjZoO8wcK1NeGJFDk5i82Q",
+      40              :   ///             "rating": 5,
+      41              :   ///             "user": {
+      42              :   ///               "id": "BuBCkWFNT_O2dbSnBZvpoQ",
+      43              :   ///               "image_url": "https:///s3-media2.fl.yelpcdn.com/photo/v8tbTjYaFvkzh1d7iE-pcQ/o.jpg",
+      44              :   ///               "name": "Gina T.",
+      45              :   ///               "text": "I love this place! The food is amazing and the service is great."
+      46              :   ///             }
+      47              :   ///           },
+      48              :   ///           {
+      49              :   ///             "id": "okpO9hfpxQXssbTZTKq9hA",
+      50              :   ///             "rating": 5,
+      51              :   ///             "user": {
+      52              :   ///               "id": "0x9xu_b0Ct_6hG6jaxpztw",
+      53              :   ///               "image_url": "https:///s3-media3.fl.yelpcdn.com/photo/gjz8X6tqE3e4praK4HfCiA/o.jpg",
+      54              :   ///               "name": "Crystal L.",
+      55              :   ///               "text": "Greate place to eat"
+      56              :   ///             }
+      57              :   ///           },
+      58              :   ///        ...
+      59              :   ///     ]
+      60              :   ///   }
+      61              :   /// }
+      62              :   ///
+      63              :   ///
+      64            1 :   RestaurantQueryResult getRestaurantsFromCache({int offset = 0}) {
+      65              :     try {
+      66            3 :       return RestaurantQueryResult.fromJson(sample['data']['search']);
+      67              :     } catch (e) {
+      68            0 :       throw Exception();
+      69              :     }
+      70              :   }
+      71              : 
+      72            1 :   Future<RestaurantQueryResult?> getRestaurants({int offset = 0}) async {
+      73              :     try {
+      74            2 :       final response = await dio.post<Map<String, dynamic>>(
+      75              :         '/v3/graphql',
+      76            1 :         data: _getQuery(offset),
+      77              :       );
+      78              :       // saveToJson(response.data!['data']['search'], 'datastore.json');
+      79            0 :       return RestaurantQueryResult.fromJson(response.data!['data']['search']);
+      80              :     } catch (e) {
+      81              :       return null;
+      82              :     }
+      83              :   }
+      84              : 
+      85            1 :   String _getQuery(int offset) {
+      86              :     return '''
+      87              : query getRestaurants {
+      88              :   search(location: "Las Vegas", limit: 20, offset: $offset) {
+      89              :     total    
+      90              :     business {
+      91              :       id
+      92              :       name
+      93              :       price
+      94              :       rating
+      95              :       photos
+      96              :       reviews {
+      97              :         id
+      98              :         rating
+      99              :         text
+     100              :         user {
+     101              :           id
+     102              :           image_url
+     103              :           name
+     104              :         }
+     105              :       }
+     106              :       categories {
+     107              :         title
+     108              :         alias
+     109              :       }
+     110              :       hours {
+     111              :         is_open_now
+     112              :       }
+     113              :       location {
+     114              :         formatted_address
+     115              :       }
+     116              :     }
+     117              :   }
+     118              : }
+     119            1 : ''';
+     120              :   }
+     121              : }
         
diff --git a/coverage_report/usecases/fetch_restaurants.dart.func-c.html b/coverage_report/usecases/fetch_restaurants.dart.func-c.html index 1cee42c..3dfef03 100644 --- a/coverage_report/usecases/fetch_restaurants.dart.func-c.html +++ b/coverage_report/usecases/fetch_restaurants.dart.func-c.html @@ -32,12 +32,12 @@ Lines: 0.0 % - 8 + 9 0 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/usecases/fetch_restaurants.dart.func.html b/coverage_report/usecases/fetch_restaurants.dart.func.html index 5a0491f..4d0fcd5 100644 --- a/coverage_report/usecases/fetch_restaurants.dart.func.html +++ b/coverage_report/usecases/fetch_restaurants.dart.func.html @@ -32,12 +32,12 @@ Lines: 0.0 % - 8 + 9 0 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/usecases/fetch_restaurants.dart.gcov.html b/coverage_report/usecases/fetch_restaurants.dart.gcov.html index 1cc9ab9..14fc0ae 100644 --- a/coverage_report/usecases/fetch_restaurants.dart.gcov.html +++ b/coverage_report/usecases/fetch_restaurants.dart.gcov.html @@ -32,12 +32,12 @@ Lines: 0.0 % - 8 + 9 0 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -62,23 +62,45 @@
        1              : import 'package:restaurant_tour/models/models.dart';
        2              : import 'package:restaurant_tour/repositories/yelp_repository.dart';
-       3              : 
-       4              : class FetchRestaurants {
-       5              :   final YelpRepository repository;
-       6              : 
-       7            0 :   FetchRestaurants({required this.repository});
-       8            0 :   Future<RestaurantQueryResult?> getRestaurants() async => await repository
-       9            0 :       .getRestaurantsFromCache(); //CHANGE THIS LATER TO FETCH FROM THE REAL API
-      10            0 :   Future<RestaurantQueryResult?> getRestaurantsFromCache() async =>
-      11            0 :       await repository.getRestaurantsFromCache();
-      12              : 
-      13            0 :   Future<List<String>> getFavoriteRestaurants() async {
-      14              :     //this could be fetched from anywhere later... a shared prefs or another database
-      15            0 :     await Future.delayed(const Duration(milliseconds: 500));
+       3              : // import 'package:shared_preferences/shared_preferences.dart';
+       4              : 
+       5              : class FetchRestaurants {
+       6              :   final YelpRepository repository;
+       7              : 
+       8            0 :   FetchRestaurants({required this.repository});
+       9            0 :   Future<RestaurantQueryResult?> getRestaurants() async => await repository
+      10            0 :       .getRestaurantsFromCache(); //CHANGE THIS LATER TO FETCH FROM THE REAL API
+      11            0 :   Future<RestaurantQueryResult?> getRestaurantsFromCache() async =>
+      12            0 :       await repository.getRestaurantsFromCache();
+      13              : 
+      14            0 :   Future<List<String>> getFavoriteRestaurants() async {
+      15              :     // final prefs = await SharedPreferences.getInstance();
       16              : 
-      17            0 :     return ['vHz2RLtfUMVRPFmd7VBEHA'];
-      18              :   }
-      19              : }
+      17              :     // Retrieve the list from SharedPreferences
+      18              :     // List<String>? favoriteRestaurants = prefs.getStringList('fav');
+      19              : 
+      20              :     // Simulate delay
+      21            0 :     await Future.delayed(const Duration(milliseconds: 500));
+      22              : 
+      23              :     // Return the list or a default value if it doesn't exist
+      24              :     // return favoriteRestaurants ?? [];
+      25            0 :     return ['vHz2RLtfUMVRPFmd7VBEHA'];
+      26              :   }
+      27              : 
+      28            0 :   Future<void> saveFavoriteRestaurants(List<String> favoriteRestaurants) async {
+      29              :     // final prefs = await SharedPreferences.getInstance();
+      30              : 
+      31              :     // Save the list to SharedPreferences
+      32              :     // await prefs.setStringList('fav', favoriteRestaurants);
+      33              :   }
+      34              : }
+      35              :   // Future<List<String>> getFavoriteRestaurants() async {
+      36              :   //   //this could be fetched from anywhere later... a shared prefs or another database
+      37              :   //   await Future.delayed(const Duration(milliseconds: 500));
+      38              : 
+      39              :   //   return ['vHz2RLtfUMVRPFmd7VBEHA'];
+      40              :   // }
+      41              : 
         
diff --git a/coverage_report/usecases/index-sort-f.html b/coverage_report/usecases/index-sort-f.html index 0e67ce5..4a51186 100644 --- a/coverage_report/usecases/index-sort-f.html +++ b/coverage_report/usecases/index-sort-f.html @@ -32,12 +32,12 @@ Lines: 0.0 % - 8 + 9 0 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -85,7 +85,7 @@
0.0%
0.0 % - 8 + 9 - diff --git a/coverage_report/usecases/index-sort-l.html b/coverage_report/usecases/index-sort-l.html index 2567e96..675d2a8 100644 --- a/coverage_report/usecases/index-sort-l.html +++ b/coverage_report/usecases/index-sort-l.html @@ -32,12 +32,12 @@ Lines: 0.0 % - 8 + 9 0 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -85,7 +85,7 @@
0.0%
0.0 % - 8 + 9 - diff --git a/coverage_report/usecases/index.html b/coverage_report/usecases/index.html index 13e12ea..2af5b3e 100644 --- a/coverage_report/usecases/index.html +++ b/coverage_report/usecases/index.html @@ -32,12 +32,12 @@ Lines: 0.0 % - 8 + 9 0 Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - @@ -85,7 +85,7 @@
0.0%
0.0 % - 8 + 9 - diff --git a/coverage_report/utils/get_random_avatar.dart.func-c.html b/coverage_report/utils/get_random_avatar.dart.func-c.html index 0eb0807..c284f8c 100644 --- a/coverage_report/utils/get_random_avatar.dart.func-c.html +++ b/coverage_report/utils/get_random_avatar.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/utils/get_random_avatar.dart.func.html b/coverage_report/utils/get_random_avatar.dart.func.html index 7dafbab..8d3a9b5 100644 --- a/coverage_report/utils/get_random_avatar.dart.func.html +++ b/coverage_report/utils/get_random_avatar.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/utils/get_random_avatar.dart.gcov.html b/coverage_report/utils/get_random_avatar.dart.gcov.html index d8f783e..de4330c 100644 --- a/coverage_report/utils/get_random_avatar.dart.gcov.html +++ b/coverage_report/utils/get_random_avatar.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/utils/index-sort-f.html b/coverage_report/utils/index-sort-f.html index 09b74f8..ebfbadd 100644 --- a/coverage_report/utils/index-sort-f.html +++ b/coverage_report/utils/index-sort-f.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/utils/index-sort-l.html b/coverage_report/utils/index-sort-l.html index b075281..fb4c274 100644 --- a/coverage_report/utils/index-sort-l.html +++ b/coverage_report/utils/index-sort-l.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/utils/index.html b/coverage_report/utils/index.html index d657f72..a76d0c4 100644 --- a/coverage_report/utils/index.html +++ b/coverage_report/utils/index.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/appbar.dart.func-c.html b/coverage_report/widgets/appbar.dart.func-c.html index 0f1c097..241bab4 100644 --- a/coverage_report/widgets/appbar.dart.func-c.html +++ b/coverage_report/widgets/appbar.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/appbar.dart.func.html b/coverage_report/widgets/appbar.dart.func.html index 19197e0..07c9032 100644 --- a/coverage_report/widgets/appbar.dart.func.html +++ b/coverage_report/widgets/appbar.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/appbar.dart.gcov.html b/coverage_report/widgets/appbar.dart.gcov.html index 51eeee5..f45ec73 100644 --- a/coverage_report/widgets/appbar.dart.gcov.html +++ b/coverage_report/widgets/appbar.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/divider.dart.func-c.html b/coverage_report/widgets/divider.dart.func-c.html index a83b291..4d4cc45 100644 --- a/coverage_report/widgets/divider.dart.func-c.html +++ b/coverage_report/widgets/divider.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/divider.dart.func.html b/coverage_report/widgets/divider.dart.func.html index 76f00ad..2c42a13 100644 --- a/coverage_report/widgets/divider.dart.func.html +++ b/coverage_report/widgets/divider.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/divider.dart.gcov.html b/coverage_report/widgets/divider.dart.gcov.html index b0b486a..9ce2d70 100644 --- a/coverage_report/widgets/divider.dart.gcov.html +++ b/coverage_report/widgets/divider.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/hero_image_widget.dart.func-c.html b/coverage_report/widgets/hero_image_widget.dart.func-c.html index c42269f..3bb7d20 100644 --- a/coverage_report/widgets/hero_image_widget.dart.func-c.html +++ b/coverage_report/widgets/hero_image_widget.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/hero_image_widget.dart.func.html b/coverage_report/widgets/hero_image_widget.dart.func.html index b99ae6a..ac011c2 100644 --- a/coverage_report/widgets/hero_image_widget.dart.func.html +++ b/coverage_report/widgets/hero_image_widget.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/hero_image_widget.dart.gcov.html b/coverage_report/widgets/hero_image_widget.dart.gcov.html index 8066ea3..04d5890 100644 --- a/coverage_report/widgets/hero_image_widget.dart.gcov.html +++ b/coverage_report/widgets/hero_image_widget.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/index-sort-f.html b/coverage_report/widgets/index-sort-f.html index 0b38746..2d938f3 100644 --- a/coverage_report/widgets/index-sort-f.html +++ b/coverage_report/widgets/index-sort-f.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/index-sort-l.html b/coverage_report/widgets/index-sort-l.html index 1a17552..e3d4db0 100644 --- a/coverage_report/widgets/index-sort-l.html +++ b/coverage_report/widgets/index-sort-l.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/index.html b/coverage_report/widgets/index.html index 12ea64e..231dd9d 100644 --- a/coverage_report/widgets/index.html +++ b/coverage_report/widgets/index.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/rataurant_open_status.dart.func-c.html b/coverage_report/widgets/rataurant_open_status.dart.func-c.html index da40adf..56619de 100644 --- a/coverage_report/widgets/rataurant_open_status.dart.func-c.html +++ b/coverage_report/widgets/rataurant_open_status.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/rataurant_open_status.dart.func.html b/coverage_report/widgets/rataurant_open_status.dart.func.html index 358daad..3978ce6 100644 --- a/coverage_report/widgets/rataurant_open_status.dart.func.html +++ b/coverage_report/widgets/rataurant_open_status.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/rataurant_open_status.dart.gcov.html b/coverage_report/widgets/rataurant_open_status.dart.gcov.html index 797dee0..e6a1cde 100644 --- a/coverage_report/widgets/rataurant_open_status.dart.gcov.html +++ b/coverage_report/widgets/rataurant_open_status.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html b/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html index aa5a870..08a7d19 100644 --- a/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html +++ b/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/rating_and_open_status_widget.dart.func.html b/coverage_report/widgets/rating_and_open_status_widget.dart.func.html index 8a858a0..be671f6 100644 --- a/coverage_report/widgets/rating_and_open_status_widget.dart.func.html +++ b/coverage_report/widgets/rating_and_open_status_widget.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html b/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html index 7c3bc79..ffde9a3 100644 --- a/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html +++ b/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/rating_widget.dart.func-c.html b/coverage_report/widgets/rating_widget.dart.func-c.html index e5147dc..a948ffe 100644 --- a/coverage_report/widgets/rating_widget.dart.func-c.html +++ b/coverage_report/widgets/rating_widget.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/rating_widget.dart.func.html b/coverage_report/widgets/rating_widget.dart.func.html index 1cce6bf..ba128a2 100644 --- a/coverage_report/widgets/rating_widget.dart.func.html +++ b/coverage_report/widgets/rating_widget.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/rating_widget.dart.gcov.html b/coverage_report/widgets/rating_widget.dart.gcov.html index 3ddc0cf..0ff34c7 100644 --- a/coverage_report/widgets/rating_widget.dart.gcov.html +++ b/coverage_report/widgets/rating_widget.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/restaurant_details.dart.func-c.html b/coverage_report/widgets/restaurant_details.dart.func-c.html index 7da6982..a278828 100644 --- a/coverage_report/widgets/restaurant_details.dart.func-c.html +++ b/coverage_report/widgets/restaurant_details.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/restaurant_details.dart.func.html b/coverage_report/widgets/restaurant_details.dart.func.html index f428c3e..72d4922 100644 --- a/coverage_report/widgets/restaurant_details.dart.func.html +++ b/coverage_report/widgets/restaurant_details.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/restaurant_details.dart.gcov.html b/coverage_report/widgets/restaurant_details.dart.gcov.html index 916ccea..f5ea323 100644 --- a/coverage_report/widgets/restaurant_details.dart.gcov.html +++ b/coverage_report/widgets/restaurant_details.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html b/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html index c6b9584..b802dbb 100644 --- a/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html +++ b/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html b/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html index 764a251..a236272 100644 --- a/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html +++ b/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html b/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html index cb8280f..a4e4775 100644 --- a/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html +++ b/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 20:45:43 + 2024-08-25 23:11:19 Functions: - diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 0000000..22acfd5 --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Set the colors for the output +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Function to run tests +run_tests() { + echo -e "${YELLOW}Running all tests...${NC}" + + # Run the tests and save the output + flutter test --coverage > test_output.txt 2>&1 + + # Check if tests passed or failed + if grep -q 'All tests passed!' test_output.txt; then + echo -e "${GREEN}All tests passed!${NC}" + else + echo -e "${RED}Some tests failed.${NC}" + echo -e "${YELLOW}Here are the details:${NC}" + grep -A 10 'Some tests failed' test_output.txt + fi + + # Generate coverage report (if coverage is enabled) + if [ -f "coverage/lcov.info" ]; then + echo -e "${YELLOW}Generating coverage report...${NC}" + genhtml coverage/lcov.info -o coverage_report + echo -e "${GREEN}Coverage report generated in the coverage_report directory.${NC}" + fi +} + +# Run the tests +run_tests + +# Cleanup +rm -f test_output.txt From 9b85764084863fcf5ed3951ba8bce3e782d5cfdf Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 14:13:00 -0300 Subject: [PATCH 22/30] chore: improving scalability of the network and datasource layers Added some refactorings to improve scalability, thinking about the future possibilities, trying to make reusable networking layers, separating responsibilities that previously were all inside the repository. --- lib/datasources/datasources.dart | 1 + lib/datasources/yielp_datasource.dart | 66 +++++++++++ lib/main.dart | 25 +++- lib/models/restaurant.g.dart | 1 + lib/network/dio_http_client.dart | 22 ++++ lib/network/network_client.dart | 7 ++ lib/repositories/info.txt | 41 +++++++ lib/repositories/yelp_repository.dart | 113 ++----------------- lib/{repositories => utils}/sample_json.dart | 0 test/home_test.dart | 12 +- test/repository/yelp_repository_test.dart | 11 +- 11 files changed, 194 insertions(+), 105 deletions(-) create mode 100644 lib/datasources/datasources.dart create mode 100644 lib/datasources/yielp_datasource.dart create mode 100644 lib/network/dio_http_client.dart create mode 100644 lib/network/network_client.dart create mode 100644 lib/repositories/info.txt rename lib/{repositories => utils}/sample_json.dart (100%) diff --git a/lib/datasources/datasources.dart b/lib/datasources/datasources.dart new file mode 100644 index 0000000..4f6b57e --- /dev/null +++ b/lib/datasources/datasources.dart @@ -0,0 +1 @@ +export './datasources.dart'; diff --git a/lib/datasources/yielp_datasource.dart b/lib/datasources/yielp_datasource.dart new file mode 100644 index 0000000..5be2739 --- /dev/null +++ b/lib/datasources/yielp_datasource.dart @@ -0,0 +1,66 @@ +import 'dart:developer'; + +import 'package:restaurant_tour/env.dart'; +import 'package:restaurant_tour/network/network_client.dart'; + +class YielpDatasource { + final INetworkClient networkClient; + final String baseUrl; + + YielpDatasource({required this.networkClient, required this.baseUrl}); + + Future?> fetchRestaurants(int offset) async { + try { + final String query = _getQuery(offset); + final response = await networkClient.post( + '$baseUrl/v3/graphql', + data: query, + headers: { + 'Authorization': 'Bearer $API_KEY', + 'Content-Type': 'application/graphql', + }, + ); + return response; + } on Exception catch (e) { + log(e.toString()); + return null; + } + } + + String _getQuery(int offset) { + return ''' +query getRestaurants { + search(location: "Las Vegas", limit: 20, offset: $offset) { + total + business { + id + name + price + rating + photos + reviews { + id + rating + text + user { + id + image_url + name + } + } + categories { + title + alias + } + hours { + is_open_now + } + location { + formatted_address + } + } + } +} +'''; + } +} diff --git a/lib/main.dart b/lib/main.dart index e9ec874..e7f9483 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,11 @@ +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get_it/get_it.dart'; import 'package:restaurant_tour/cubit/cubit.dart'; +import 'package:restaurant_tour/datasources/yielp_datasource.dart'; +import 'package:restaurant_tour/env.dart'; +import 'package:restaurant_tour/network/dio_http_client.dart'; import 'package:restaurant_tour/repositories/repositories.dart'; import 'package:restaurant_tour/theme/text.dart'; import 'pages/home_page.dart'; @@ -16,8 +20,27 @@ Future main() async { void setup() { final getIt = GetIt.instance; + final dio = Dio( + BaseOptions( + baseUrl: 'https://api.yelp.com', + headers: { + 'Authorization': 'Bearer $API_KEY', + 'Content-Type': 'application/graphql', + }, + ), + ); + getIt.registerSingleton(DioHttpClient(dio: dio)); + + getIt.registerSingleton( + YielpDatasource( + networkClient: getIt(), + baseUrl: 'https://api.yelp.com', + ), + ); - getIt.registerSingleton(YelpRepository()); + getIt.registerSingleton( + YelpRepository(datasource: getIt()), + ); getIt.registerSingleton( FetchRestaurants(repository: getIt()), diff --git a/lib/models/restaurant.g.dart b/lib/models/restaurant.g.dart index 3ed33f9..0693ae5 100644 --- a/lib/models/restaurant.g.dart +++ b/lib/models/restaurant.g.dart @@ -39,6 +39,7 @@ Map _$UserToJson(User instance) => { Review _$ReviewFromJson(Map json) => Review( id: json['id'] as String?, rating: json['rating'] as int?, + text: json['text'] as String?, user: json['user'] == null ? null : User.fromJson(json['user'] as Map), diff --git a/lib/network/dio_http_client.dart b/lib/network/dio_http_client.dart new file mode 100644 index 0000000..0c56f51 --- /dev/null +++ b/lib/network/dio_http_client.dart @@ -0,0 +1,22 @@ +import 'package:dio/dio.dart'; + +import 'network_client.dart'; + +class DioHttpClient implements INetworkClient { + final Dio dio; + + DioHttpClient({required this.dio}); + @override + Future> post( + String url, { + required data, + Map? headers, + }) async { + final response = await dio.post>( + url, + data: data, + options: headers != null ? Options(headers: headers) : null, + ); + return response.data!; + } +} diff --git a/lib/network/network_client.dart b/lib/network/network_client.dart new file mode 100644 index 0000000..f36dc83 --- /dev/null +++ b/lib/network/network_client.dart @@ -0,0 +1,7 @@ +abstract class INetworkClient { + Future> post( + String url, { + required data, + Map? headers, + }); +} diff --git a/lib/repositories/info.txt b/lib/repositories/info.txt new file mode 100644 index 0000000..aa0ed85 --- /dev/null +++ b/lib/repositories/info.txt @@ -0,0 +1,41 @@ + /// Returns a response in this shape + /// { + /// "data": { + /// "search": { + /// "total": 5056, + /// "business": [ + /// { + /// "id": "faPVqws-x-5k2CQKDNtHxw", + /// "name": "Yardbird Southern Table & Bar", + /// "price": "$$", + /// "rating": 4.5, + /// "photos": [ + /// "https:///s3-media4.fl.yelpcdn.com/bphoto/_zXRdYX4r1OBfF86xKMbDw/o.jpg" + /// ], + /// "reviews": [ + /// { + /// "id": "sjZoO8wcK1NeGJFDk5i82Q", + /// "rating": 5, + /// "user": { + /// "id": "BuBCkWFNT_O2dbSnBZvpoQ", + /// "image_url": "https:///s3-media2.fl.yelpcdn.com/photo/v8tbTjYaFvkzh1d7iE-pcQ/o.jpg", + /// "name": "Gina T.", + /// "text": "I love this place! The food is amazing and the service is great." + /// } + /// }, + /// { + /// "id": "okpO9hfpxQXssbTZTKq9hA", + /// "rating": 5, + /// "user": { + /// "id": "0x9xu_b0Ct_6hG6jaxpztw", + /// "image_url": "https:///s3-media3.fl.yelpcdn.com/photo/gjz8X6tqE3e4praK4HfCiA/o.jpg", + /// "name": "Crystal L.", + /// "text": "Greate place to eat" + /// } + /// }, + /// ... + /// ] + /// } + /// } + /// + /// \ No newline at end of file diff --git a/lib/repositories/yelp_repository.dart b/lib/repositories/yelp_repository.dart index 353d4fa..c49add0 100644 --- a/lib/repositories/yelp_repository.dart +++ b/lib/repositories/yelp_repository.dart @@ -1,68 +1,16 @@ -import 'package:dio/dio.dart'; -import 'package:flutter/foundation.dart'; -import 'package:restaurant_tour/env.dart'; +import 'dart:developer'; +import 'package:restaurant_tour/datasources/yielp_datasource.dart'; import 'package:restaurant_tour/models/restaurant.dart'; -import 'package:restaurant_tour/repositories/sample_json.dart'; +import 'package:restaurant_tour/utils/sample_json.dart'; class YelpRepository { - late Dio dio; + final YielpDatasource datasource; - YelpRepository({ - @visibleForTesting Dio? dio, - }) : dio = dio ?? - Dio( - BaseOptions( - baseUrl: 'https://api.yelp.com', - headers: { - 'Authorization': 'Bearer $API_KEY', - 'Content-Type': 'application/graphql', - }, - ), - ); + YelpRepository({required this.datasource}); - /// Returns a response in this shape - /// { - /// "data": { - /// "search": { - /// "total": 5056, - /// "business": [ - /// { - /// "id": "faPVqws-x-5k2CQKDNtHxw", - /// "name": "Yardbird Southern Table & Bar", - /// "price": "$$", - /// "rating": 4.5, - /// "photos": [ - /// "https:///s3-media4.fl.yelpcdn.com/bphoto/_zXRdYX4r1OBfF86xKMbDw/o.jpg" - /// ], - /// "reviews": [ - /// { - /// "id": "sjZoO8wcK1NeGJFDk5i82Q", - /// "rating": 5, - /// "user": { - /// "id": "BuBCkWFNT_O2dbSnBZvpoQ", - /// "image_url": "https:///s3-media2.fl.yelpcdn.com/photo/v8tbTjYaFvkzh1d7iE-pcQ/o.jpg", - /// "name": "Gina T.", - /// "text": "I love this place! The food is amazing and the service is great." - /// } - /// }, - /// { - /// "id": "okpO9hfpxQXssbTZTKq9hA", - /// "rating": 5, - /// "user": { - /// "id": "0x9xu_b0Ct_6hG6jaxpztw", - /// "image_url": "https:///s3-media3.fl.yelpcdn.com/photo/gjz8X6tqE3e4praK4HfCiA/o.jpg", - /// "name": "Crystal L.", - /// "text": "Greate place to eat" - /// } - /// }, - /// ... - /// ] - /// } - /// } - /// - /// RestaurantQueryResult getRestaurantsFromCache({int offset = 0}) { try { + log('fetching from cache'); return RestaurantQueryResult.fromJson(sample['data']['search']); } catch (e) { throw Exception(); @@ -71,51 +19,14 @@ class YelpRepository { Future getRestaurants({int offset = 0}) async { try { - final response = await dio.post>( - '/v3/graphql', - data: _getQuery(offset), - ); - // saveToJson(response.data!['data']['search'], 'datastore.json'); - return RestaurantQueryResult.fromJson(response.data!['data']['search']); + final data = await datasource.fetchRestaurants(offset); + if (data != null) { + return RestaurantQueryResult.fromJson(data['data']['search']); + } else { + return null; + } } catch (e) { return null; } } - - String _getQuery(int offset) { - return ''' -query getRestaurants { - search(location: "Las Vegas", limit: 20, offset: $offset) { - total - business { - id - name - price - rating - photos - reviews { - id - rating - text - user { - id - image_url - name - } - } - categories { - title - alias - } - hours { - is_open_now - } - location { - formatted_address - } - } - } -} -'''; - } } diff --git a/lib/repositories/sample_json.dart b/lib/utils/sample_json.dart similarity index 100% rename from lib/repositories/sample_json.dart rename to lib/utils/sample_json.dart diff --git a/test/home_test.dart b/test/home_test.dart index b7618a2..90d067e 100644 --- a/test/home_test.dart +++ b/test/home_test.dart @@ -1,11 +1,14 @@ import 'dart:io'; import 'package:bloc_test/bloc_test.dart'; +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:get_it/get_it.dart'; import 'package:mocktail/mocktail.dart'; import 'package:restaurant_tour/cubit/cubit.dart'; +import 'package:restaurant_tour/datasources/yielp_datasource.dart'; +import 'package:restaurant_tour/network/dio_http_client.dart'; import 'package:restaurant_tour/pages/pages.dart'; import 'package:restaurant_tour/repositories/repositories.dart'; import 'package:restaurant_tour/usecases/usecases.dart'; @@ -19,6 +22,8 @@ class MockRestaurantState extends Fake implements RestaurantState {} class MockFetchRestaurantsUseCase extends Mock implements FetchRestaurants {} +class MockDio extends Mock implements Dio {} + class MyHttpOverrides extends HttpOverrides { @override HttpClient createHttpClient(SecurityContext? context) { @@ -70,7 +75,12 @@ void main() { testWidgets( 'When restaurants are loaded, display a listview with a HeroImageWidget', (tester) async { - var fakeData = YelpRepository().getRestaurantsFromCache(); + var fakeData = YelpRepository( + datasource: YielpDatasource( + baseUrl: 'http://example.com/get', + networkClient: DioHttpClient(dio: MockDio()), + ), + ).getRestaurantsFromCache(); when(() => restaurantCubit.state).thenReturn( RestaurantsLoadedState(favoriteRestaurants: [], result: fakeData), ); diff --git a/test/repository/yelp_repository_test.dart b/test/repository/yelp_repository_test.dart index 67a48cf..3612270 100644 --- a/test/repository/yelp_repository_test.dart +++ b/test/repository/yelp_repository_test.dart @@ -1,9 +1,11 @@ import 'package:dio/dio.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; +import 'package:restaurant_tour/datasources/yielp_datasource.dart'; import 'package:restaurant_tour/models/restaurant.dart'; +import 'package:restaurant_tour/network/dio_http_client.dart'; import 'package:restaurant_tour/repositories/repositories.dart'; -import 'package:restaurant_tour/repositories/sample_json.dart'; +import 'package:restaurant_tour/utils/sample_json.dart'; class MockDio extends Mock implements Dio {} @@ -48,7 +50,12 @@ void main() { late MockDio mockDio; setUp(() { mockDio = MockDio(); - repository = YelpRepository(dio: mockDio); + repository = YelpRepository( + datasource: YielpDatasource( + networkClient: DioHttpClient(dio: mockDio), + baseUrl: 'https://example.com', + ), + ); }); // test('Get Restaurants should return a RestaurantQueryResult', () async { From 4f364af38ba8b40d1c863e8f95240d3200f84ff4 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 14:22:27 -0300 Subject: [PATCH 23/30] chore: treating null safe in the frontend --- assets/placeholder.png | Bin 0 -> 1002 bytes lib/utils/sample_json.dart | 6 ------ lib/widgets/hero_image_widget.dart | 23 +++++++++++++++++------ pubspec.yaml | 1 + 4 files changed, 18 insertions(+), 12 deletions(-) create mode 100644 assets/placeholder.png diff --git a/assets/placeholder.png b/assets/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..71bc239a50832113c9ace0bdaffc4a65d6b601e9 GIT binary patch literal 1002 zcmeAS@N?(olHy`uVBq!ia0y~yU=#$hcW^KR$coXRqF#zjA%Yp8fAWf7`KV-|qbfx9r?=`1q+CcOM)%ar)u2m#5BOGG6b; z!@$6t@9E+gQZeW4oYzIG6-3-bd!3SdD*sQny;rnILCsC#^}8s0tIS&liD%iPB@8`* zR^kE=wl7jDD4G9l!K`0Gb9Q;2(>nU(y4Gd?x;A-Y@8}U95ASL6cMq>M3H^Wcc4k1j z0=L(lia>4{GBi*Bqa`f*Qi-?tlE>{d?XxY&22#3y8?o7p16Pgzlu zCJLN3adZorRQ`I)UR%NBBTu%kdUY-HdQp7*5{Z}BYniR?PMv)4#Md`&S8}UD<4t$Z znl?eOT5(VMORd8magp3xWmgLcy7g=>oKkC_=OUr`relluf%VoZ2Rl~XJv+(V`})*a zXF)eF_Y<>U|5n;v-RrqxU#|Qe*%w#&UWQap?Kp8F_3?_A%VcXm|7mAY_I&)#Y5kP@ zg>v6C1rv{0Y*kzRcYf`w&l-Y>Pj2SbgUz%$`&ot8~;Ox}fXR zwPk-NO6SMVnY3k!kfqx#^WLCi?+?fF_i4_ocbYWutG^D<%%hE;!+SLRo$fR$FS)j7 zX~gc`Nz*3n2TK0VU#9s}+AXZDXR*s7!Qkk8@vFD3C&hWONEw!z&eyuHma@!c-o!AE zS@+cHe<&zshR3+6KI-}6w5<6+wd^C$&MmK2zxv5{Gu=5Y#K=%dP1#>@?xcVD(k&e( zNowE!e$)I}ae~7%=~bpulxnn)(#4LIZ)G>-n!9xyCvo5G5ev({@@_NpA)`&!ikEt} zq?UhwsT}BbCN(&8V*ZgBr#bdQDNA4PBJ!Mjs<%QuG;B7BRqQDbYrz8$62Bu`)dAa=f#yjfZ`7V{xMG3Vj{lx R>-AG0WuC5nF6*2UngFy((0%{_ literal 0 HcmV?d00001 diff --git a/lib/utils/sample_json.dart b/lib/utils/sample_json.dart index 96ebf52..b97f7a1 100644 --- a/lib/utils/sample_json.dart +++ b/lib/utils/sample_json.dart @@ -62,12 +62,6 @@ const Map sample = { }, { "id": "faPVqws-x-5k2CQKDNtHxw", - "name": "Yardbird", - "price": "\$\$", - "rating": 4.5, - "photos": [ - "https://s3-media1.fl.yelpcdn.com/bphoto/xYJaanpF3Dl1OovhmpqAYw/o.jpg" - ], "reviews": [ { "id": "CN9oD1ncHKZtsGN7U1EMnA", diff --git a/lib/widgets/hero_image_widget.dart b/lib/widgets/hero_image_widget.dart index d7bcaa5..3d604b2 100644 --- a/lib/widgets/hero_image_widget.dart +++ b/lib/widgets/hero_image_widget.dart @@ -19,12 +19,23 @@ class HeroImageWidget extends StatelessWidget { tag: restaurant.id.toString(), child: ClipRRect( borderRadius: BorderRadius.circular(borderRadius), - child: Image.network( - restaurant.heroImage, - fit: BoxFit.cover, - width: width, - height: height, - ), + child: restaurant.heroImage.isNotEmpty && + Uri.tryParse(restaurant.heroImage)?.isAbsolute == true + ? Image.network( + restaurant.heroImage, + fit: BoxFit.cover, + width: width, + height: height, + ) + : Container( + width: width, + height: height, + color: const Color.fromARGB(255, 197, 233, 199), + child: Image.asset( + 'assets/placeholder.png', + fit: BoxFit.fitHeight, + ), + ), ), ); } diff --git a/pubspec.yaml b/pubspec.yaml index 6a0ae3e..af7e177 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,6 +37,7 @@ flutter: assets: - assets/avatars/ - assets/.env + - assets/ fonts: - family: Lora fonts: From 2125af0522ece7c95536b030f67869040666a24b Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 14:23:34 -0300 Subject: [PATCH 24/30] Update sample_json.dart --- lib/utils/sample_json.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/utils/sample_json.dart b/lib/utils/sample_json.dart index b97f7a1..620b5fa 100644 --- a/lib/utils/sample_json.dart +++ b/lib/utils/sample_json.dart @@ -62,6 +62,11 @@ const Map sample = { }, { "id": "faPVqws-x-5k2CQKDNtHxw", + "name": "Yardbird", + "price": "\$\$", + "photos": [ + "https://s3-media1.fl.yelpcdn.com/bphoto/xYJaanpF3Dl1OovhmpqAYw/o.jpg" + ], "reviews": [ { "id": "CN9oD1ncHKZtsGN7U1EMnA", From 4956d8e6fc40723b722f3a13ce488e21357849db Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 14:55:09 -0300 Subject: [PATCH 25/30] refactor: moving test files to different folders --- test/{ => interface}/home_test.dart | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{ => interface}/home_test.dart (100%) diff --git a/test/home_test.dart b/test/interface/home_test.dart similarity index 100% rename from test/home_test.dart rename to test/interface/home_test.dart From 3c3bbd0fc8b19fcc7e244d3ca82f5ba134b0ff94 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 14:55:12 -0300 Subject: [PATCH 26/30] Update pubspec.yaml --- pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/pubspec.yaml b/pubspec.yaml index af7e177..be72877 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: flutter_bloc: ^8.1.6 get_it: ^7.7.0 equatable: ^2.0.5 + dev_dependencies: flutter_test: From b95f52456d9fc4cb1252ccc57d6c039ccf41b394 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 14:56:40 -0300 Subject: [PATCH 27/30] chore: adding note --- lib/usecases/fetch_restaurants.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/usecases/fetch_restaurants.dart b/lib/usecases/fetch_restaurants.dart index 1ba1e22..ccf16d2 100644 --- a/lib/usecases/fetch_restaurants.dart +++ b/lib/usecases/fetch_restaurants.dart @@ -7,11 +7,12 @@ class FetchRestaurants { FetchRestaurants({required this.repository}); Future getRestaurants() async => await repository .getRestaurantsFromCache(); //CHANGE THIS LATER TO FETCH FROM THE REAL API + Future getRestaurantsFromCache() async => await repository.getRestaurantsFromCache(); Future> getFavoriteRestaurants() async { - //this could be fetched from anywhere later... a shared prefs or another database + // Simulate delay await Future.delayed(const Duration(milliseconds: 500)); return ['vHz2RLtfUMVRPFmd7VBEHA']; From 2fc1eb4e840fd9ba02f4f1c9ae4972fde0cb0e9a Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 14:56:48 -0300 Subject: [PATCH 28/30] iOS essentials --- ios/Podfile.lock | 7 +++++++ ios/Runner.xcodeproj/project.pbxproj | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3c9ea6d..9d67035 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,15 +1,22 @@ PODS: - Flutter (1.0.0) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS DEPENDENCIES: - Flutter (from `Flutter`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) EXTERNAL SOURCES: Flutter: :path: Flutter + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" SPEC CHECKSUMS: Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index db52082..0efa999 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -198,6 +198,7 @@ 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 33BB0A415525F547416C12A9 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -269,6 +270,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 33BB0A415525F547416C12A9 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; From 71a351982a52a360242e2cafa614e1435bf3d876 Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 14:57:08 -0300 Subject: [PATCH 29/30] capitalizing letters --- lib/pages/home_page.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/home_page.dart b/lib/pages/home_page.dart index d9ad952..7a3133c 100644 --- a/lib/pages/home_page.dart +++ b/lib/pages/home_page.dart @@ -45,13 +45,13 @@ class HomePage extends StatelessWidget { tabs: [ Tab( child: Text( - 'All restaurants', + 'All Restaurants', style: Theme.of(context).textTheme.displayLarge, ), ), Tab( child: Text( - 'My favorites', + 'My Favorites', style: Theme.of(context).textTheme.displayLarge, ), ), From 9d7821e27fad2d554266d22730f091400649b85c Mon Sep 17 00:00:00 2001 From: Fernanda Date: Mon, 26 Aug 2024 14:57:26 -0300 Subject: [PATCH 30/30] chore: updating coverage report --- coverage/lcov.info | 148 +++++++++------- coverage_report/cubit/index-sort-f.html | 22 +-- coverage_report/cubit/index-sort-l.html | 22 +-- coverage_report/cubit/index.html | 22 +-- .../cubit/restaurant_cubit.dart.func-c.html | 8 +- .../cubit/restaurant_cubit.dart.func.html | 8 +- .../cubit/restaurant_cubit.dart.gcov.html | 18 +- .../cubit/restaurant_state.dart.func-c.html | 6 +- .../cubit/restaurant_state.dart.func.html | 6 +- .../cubit/restaurant_state.dart.gcov.html | 16 +- coverage_report/index-sort-f.html | 64 ++++--- coverage_report/index-sort-l.html | 70 +++++--- coverage_report/index.html | 64 ++++--- coverage_report/models/index-sort-f.html | 16 +- coverage_report/models/index-sort-l.html | 16 +- coverage_report/models/index.html | 16 +- .../models/restaurant.dart.func-c.html | 2 +- .../models/restaurant.dart.func.html | 2 +- .../models/restaurant.dart.gcov.html | 2 +- .../models/restaurant.g.dart.func-c.html | 8 +- .../models/restaurant.g.dart.func.html | 8 +- .../models/restaurant.g.dart.gcov.html | 145 ++++++++-------- .../pages/home_page.dart.func-c.html | 2 +- .../pages/home_page.dart.func.html | 2 +- .../pages/home_page.dart.gcov.html | 2 +- coverage_report/pages/index-sort-f.html | 2 +- coverage_report/pages/index-sort-l.html | 2 +- coverage_report/pages/index.html | 2 +- .../restaurant_detail_page.dart.func-c.html | 2 +- .../restaurant_detail_page.dart.func.html | 2 +- .../restaurant_detail_page.dart.gcov.html | 2 +- .../restaurant_list_page.dart.func-c.html | 2 +- .../pages/restaurant_list_page.dart.func.html | 2 +- .../pages/restaurant_list_page.dart.gcov.html | 2 +- .../repositories/index-sort-f.html | 16 +- .../repositories/index-sort-l.html | 16 +- coverage_report/repositories/index.html | 16 +- .../yelp_repository.dart.func-c.html | 8 +- .../yelp_repository.dart.func.html | 8 +- .../yelp_repository.dart.gcov.html | 161 ++++-------------- .../fetch_restaurants.dart.func-c.html | 2 +- .../usecases/fetch_restaurants.dart.func.html | 2 +- .../usecases/fetch_restaurants.dart.gcov.html | 65 +++---- coverage_report/usecases/index-sort-f.html | 2 +- coverage_report/usecases/index-sort-l.html | 2 +- coverage_report/usecases/index.html | 2 +- .../utils/get_random_avatar.dart.func-c.html | 2 +- .../utils/get_random_avatar.dart.func.html | 2 +- .../utils/get_random_avatar.dart.gcov.html | 2 +- coverage_report/utils/index-sort-f.html | 2 +- coverage_report/utils/index-sort-l.html | 2 +- coverage_report/utils/index.html | 2 +- .../widgets/appbar.dart.func-c.html | 2 +- coverage_report/widgets/appbar.dart.func.html | 2 +- coverage_report/widgets/appbar.dart.gcov.html | 2 +- .../widgets/divider.dart.func-c.html | 2 +- .../widgets/divider.dart.func.html | 2 +- .../widgets/divider.dart.gcov.html | 2 +- .../hero_image_widget.dart.func-c.html | 8 +- .../widgets/hero_image_widget.dart.func.html | 8 +- .../widgets/hero_image_widget.dart.gcov.html | 39 +++-- coverage_report/widgets/index-sort-f.html | 16 +- coverage_report/widgets/index-sort-l.html | 32 ++-- coverage_report/widgets/index.html | 16 +- .../rataurant_open_status.dart.func-c.html | 2 +- .../rataurant_open_status.dart.func.html | 2 +- .../rataurant_open_status.dart.gcov.html | 2 +- ...ng_and_open_status_widget.dart.func-c.html | 2 +- ...ting_and_open_status_widget.dart.func.html | 2 +- ...ting_and_open_status_widget.dart.gcov.html | 2 +- .../widgets/rating_widget.dart.func-c.html | 2 +- .../widgets/rating_widget.dart.func.html | 2 +- .../widgets/rating_widget.dart.gcov.html | 2 +- .../restaurant_details.dart.func-c.html | 2 +- .../widgets/restaurant_details.dart.func.html | 2 +- .../widgets/restaurant_details.dart.gcov.html | 2 +- ...nt_ratings_review_section.dart.func-c.html | 2 +- ...rant_ratings_review_section.dart.func.html | 2 +- ...rant_ratings_review_section.dart.gcov.html | 2 +- 79 files changed, 603 insertions(+), 583 deletions(-) diff --git a/coverage/lcov.info b/coverage/lcov.info index 6facf0b..a1cff15 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -19,10 +19,10 @@ DA:57,0 DA:59,0 DA:60,0 DA:61,0 -DA:72,0 -DA:75,0 -DA:76,0 -DA:77,0 +DA:72,1 +DA:75,1 +DA:76,1 +DA:77,2 DA:79,0 DA:81,0 DA:82,0 @@ -33,7 +33,7 @@ DA:99,0 DA:100,0 DA:101,0 LF:33 -LH:11 +LH:15 end_of_record SF:lib/cubit/restaurant_cubit.dart DA:11,1 @@ -50,13 +50,12 @@ DA:40,3 DA:41,1 DA:42,1 DA:44,0 -DA:46,2 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 -LF:19 -LH:14 +DA:47,1 +DA:48,1 +DA:49,2 +DA:50,1 +LF:18 +LH:17 end_of_record SF:lib/models/restaurant.dart DA:10,2 @@ -119,33 +118,33 @@ DA:39,4 DA:40,2 DA:41,2 DA:42,2 -DA:44,4 -DA:47,0 +DA:43,2 +DA:45,4 DA:48,0 DA:49,0 DA:50,0 -DA:53,4 -DA:54,2 -DA:57,0 +DA:51,0 +DA:54,4 +DA:55,2 DA:58,0 -DA:61,4 -DA:62,2 +DA:59,0 +DA:62,4 DA:63,2 DA:64,2 -DA:65,4 -DA:67,8 -DA:68,2 -DA:69,6 -DA:70,2 +DA:65,2 +DA:66,4 +DA:68,8 +DA:69,2 +DA:70,6 DA:71,2 -DA:72,6 -DA:73,2 +DA:72,2 +DA:73,6 DA:74,2 -DA:75,6 -DA:76,2 +DA:75,2 +DA:76,6 DA:77,2 -DA:79,4 -DA:82,0 +DA:78,2 +DA:80,4 DA:83,0 DA:84,0 DA:85,0 @@ -156,48 +155,67 @@ DA:89,0 DA:90,0 DA:91,0 DA:92,0 -DA:95,2 -DA:97,2 +DA:93,0 +DA:96,2 DA:98,2 DA:99,2 -DA:100,6 -DA:101,2 -DA:104,0 -DA:106,0 +DA:100,2 +DA:101,6 +DA:102,2 +DA:105,0 DA:107,0 DA:108,0 -LF:69 -LH:39 +DA:109,0 +LF:70 +LH:40 end_of_record SF:lib/usecases/fetch_restaurants.dart DA:8,0 DA:9,0 DA:10,0 -DA:11,0 DA:12,0 -DA:14,0 -DA:21,0 -DA:25,0 -DA:28,0 +DA:13,0 +DA:15,0 +DA:22,0 +DA:26,0 +DA:29,0 LF:9 LH:0 end_of_record -SF:lib/repositories/yelp_repository.dart +SF:lib/datasources/yielp_datasource.dart DA:10,2 -DA:13,1 +DA:12,1 DA:14,1 -DA:16,1 +DA:15,2 +DA:16,2 +DA:18,1 +DA:24,1 +DA:25,0 +DA:30,1 DA:64,1 -DA:66,3 -DA:68,0 -DA:72,1 -DA:74,2 -DA:76,1 -DA:79,0 -DA:85,1 -DA:119,1 -LF:13 -LH:11 +LF:10 +LH:9 +end_of_record +SF:lib/repositories/yelp_repository.dart +DA:9,2 +DA:11,1 +DA:13,1 +DA:14,3 +DA:16,0 +DA:20,1 +DA:22,2 +DA:24,0 +LF:8 +LH:6 +end_of_record +SF:lib/network/dio_http_client.dart +DA:8,2 +DA:9,1 +DA:15,2 +DA:18,1 +DA:20,0 +LF:5 +LH:4 end_of_record SF:lib/pages/favorites_list_page_view.dart DA:8,1 @@ -385,12 +403,18 @@ DA:18,1 DA:19,3 DA:20,1 DA:21,2 -DA:22,1 -DA:23,2 -DA:25,1 -DA:26,1 -LF:10 -LH:10 +DA:22,3 +DA:23,5 +DA:24,1 +DA:25,2 +DA:27,1 +DA:28,1 +DA:30,0 +DA:31,0 +DA:32,0 +DA:34,0 +LF:16 +LH:12 end_of_record SF:lib/widgets/rataurant_open_status.dart DA:4,1 diff --git a/coverage_report/cubit/index-sort-f.html b/coverage_report/cubit/index-sort-f.html index b99acd2..2ff87b7 100644 --- a/coverage_report/cubit/index-sort-f.html +++ b/coverage_report/cubit/index-sort-f.html @@ -31,13 +31,13 @@ lcov.info Lines: - 48.1 % - 52 - 25 + 62.7 % + 51 + 32 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -82,11 +82,11 @@ restaurant_cubit.dart -
73.7%73.7%
+
94.4%94.4%
- 73.7 % - 19 - 14 + 94.4 % + 18 + 17 - @@ -94,11 +94,11 @@ restaurant_state.dart -
33.3%33.3%
+
45.5%45.5%
- 33.3 % + 45.5 % 33 - 11 + 15 - diff --git a/coverage_report/cubit/index-sort-l.html b/coverage_report/cubit/index-sort-l.html index d6dd913..f350ba9 100644 --- a/coverage_report/cubit/index-sort-l.html +++ b/coverage_report/cubit/index-sort-l.html @@ -31,13 +31,13 @@ lcov.info Lines: - 48.1 % - 52 - 25 + 62.7 % + 51 + 32 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -82,11 +82,11 @@ restaurant_state.dart -
33.3%33.3%
+
45.5%45.5%
- 33.3 % + 45.5 % 33 - 11 + 15 - @@ -94,11 +94,11 @@ restaurant_cubit.dart -
73.7%73.7%
+
94.4%94.4%
- 73.7 % - 19 - 14 + 94.4 % + 18 + 17 - diff --git a/coverage_report/cubit/index.html b/coverage_report/cubit/index.html index e79492f..111a966 100644 --- a/coverage_report/cubit/index.html +++ b/coverage_report/cubit/index.html @@ -31,13 +31,13 @@ lcov.info Lines: - 48.1 % - 52 - 25 + 62.7 % + 51 + 32 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -82,11 +82,11 @@ restaurant_cubit.dart -
73.7%73.7%
+
94.4%94.4%
- 73.7 % - 19 - 14 + 94.4 % + 18 + 17 - @@ -94,11 +94,11 @@ restaurant_state.dart -
33.3%33.3%
+
45.5%45.5%
- 33.3 % + 45.5 % 33 - 11 + 15 - diff --git a/coverage_report/cubit/restaurant_cubit.dart.func-c.html b/coverage_report/cubit/restaurant_cubit.dart.func-c.html index fa8335d..e758734 100644 --- a/coverage_report/cubit/restaurant_cubit.dart.func-c.html +++ b/coverage_report/cubit/restaurant_cubit.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 73.7 % - 19 - 14 + 94.4 % + 18 + 17 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/cubit/restaurant_cubit.dart.func.html b/coverage_report/cubit/restaurant_cubit.dart.func.html index fe5200a..c2fc654 100644 --- a/coverage_report/cubit/restaurant_cubit.dart.func.html +++ b/coverage_report/cubit/restaurant_cubit.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 73.7 % - 19 - 14 + 94.4 % + 18 + 17 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/cubit/restaurant_cubit.dart.gcov.html b/coverage_report/cubit/restaurant_cubit.dart.gcov.html index ae204d4..fc0b223 100644 --- a/coverage_report/cubit/restaurant_cubit.dart.gcov.html +++ b/coverage_report/cubit/restaurant_cubit.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 73.7 % - 19 - 14 + 94.4 % + 18 + 17 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -105,11 +105,11 @@ 43 : } else { 44 0 : favoriteRestaurants.add(id); 45 : } - 46 2 : await fetchRestaurantsUseCase.saveFavoriteRestaurants(favoriteRestaurants); - 47 0 : emit( - 48 0 : FavoriteRestaurantState( - 49 0 : result: state.result!, - 50 0 : favoriteRestaurants: List.of(favoriteRestaurants), + 46 : // await fetchRestaurantsUseCase.saveFavoriteRestaurants(favoriteRestaurants); + 47 1 : emit( + 48 1 : FavoriteRestaurantState( + 49 2 : result: state.result!, + 50 1 : favoriteRestaurants: List.of(favoriteRestaurants), 51 : ), 52 : ); 53 : } diff --git a/coverage_report/cubit/restaurant_state.dart.func-c.html b/coverage_report/cubit/restaurant_state.dart.func-c.html index c425cfe..314155a 100644 --- a/coverage_report/cubit/restaurant_state.dart.func-c.html +++ b/coverage_report/cubit/restaurant_state.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 33.3 % + 45.5 % 33 - 11 + 15 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/cubit/restaurant_state.dart.func.html b/coverage_report/cubit/restaurant_state.dart.func.html index 6a8882c..cfa8a32 100644 --- a/coverage_report/cubit/restaurant_state.dart.func.html +++ b/coverage_report/cubit/restaurant_state.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 33.3 % + 45.5 % 33 - 11 + 15 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/cubit/restaurant_state.dart.gcov.html b/coverage_report/cubit/restaurant_state.dart.gcov.html index 3a08218..f80c546 100644 --- a/coverage_report/cubit/restaurant_state.dart.gcov.html +++ b/coverage_report/cubit/restaurant_state.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 33.3 % + 45.5 % 33 - 11 + 15 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -131,14 +131,14 @@ 69 : @override 70 : final List<String> favoriteRestaurants; 71 : - 72 0 : const FavoriteRestaurantState({ + 72 1 : const FavoriteRestaurantState({ 73 : required this.result, 74 : required this.favoriteRestaurants, - 75 0 : }) : super(favoriteRestaurants: favoriteRestaurants, result: result); - 76 0 : @override - 77 0 : List<Object?> get props => [favoriteRestaurants]; + 75 1 : }) : super(favoriteRestaurants: favoriteRestaurants, result: result); + 76 1 : @override + 77 2 : List<Object?> get props => [favoriteRestaurants]; 78 : - 79 0 : @override + 79 0 : @override 80 : FavoriteRestaurantState copyWith({List<String>? favoriteRestaurants}) { 81 0 : return FavoriteRestaurantState( 82 0 : favoriteRestaurants: favoriteRestaurants ?? this.favoriteRestaurants, diff --git a/coverage_report/index-sort-f.html b/coverage_report/index-sort-f.html index 7a7fad9..1aab820 100644 --- a/coverage_report/index-sort-f.html +++ b/coverage_report/index-sort-f.html @@ -31,13 +31,13 @@ lcov.info Lines: - 49.4 % - 413 - 204 + 51.7 % + 429 + 222 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -82,11 +82,23 @@ cubit/ -
48.1%48.1%
+
62.7%62.7%
- 48.1 % - 52 - 25 + 62.7 % + 51 + 32 + - + + + + + datasources/ + +
90.0%90.0%
+ + 90.0 % + 10 + 9 - @@ -94,11 +106,23 @@ models/ -
61.2%61.2%
+
61.5%61.5%
- 61.2 % - 103 - 63 + 61.5 % + 104 + 64 + - + + + + + network/ + +
80.0%80.0%
+ + 80.0 % + 5 + 4 - @@ -118,11 +142,11 @@ repositories/ -
84.6%84.6%
+
75.0%75.0%
- 84.6 % - 13 - 11 + 75.0 % + 8 + 6 - @@ -154,11 +178,11 @@ widgets/ -
45.5%45.5%
+
44.9%44.9%
- 45.5 % - 101 - 46 + 44.9 % + 107 + 48 - diff --git a/coverage_report/index-sort-l.html b/coverage_report/index-sort-l.html index 15b112d..c8e439e 100644 --- a/coverage_report/index-sort-l.html +++ b/coverage_report/index-sort-l.html @@ -31,13 +31,13 @@ lcov.info Lines: - 49.4 % - 413 - 204 + 51.7 % + 429 + 222 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -103,6 +103,18 @@ + + widgets/ + +
44.9%44.9%
+ + 44.9 % + 107 + 48 + - + + + pages/ @@ -116,13 +128,13 @@ - widgets/ + models/ -
45.5%45.5%
+
61.5%61.5%
- 45.5 % - 101 - 46 + 61.5 % + 104 + 64 - @@ -130,35 +142,47 @@ cubit/ -
48.1%48.1%
+
62.7%62.7%
- 48.1 % - 52 - 25 + 62.7 % + 51 + 32 - - models/ + repositories/ -
61.2%61.2%
+
75.0%75.0%
- 61.2 % - 103 - 63 + 75.0 % + 8 + 6 - - repositories/ + network/ -
84.6%84.6%
+
80.0%80.0%
- 84.6 % - 13 - 11 + 80.0 % + 5 + 4 + - + + + + + datasources/ + +
90.0%90.0%
+ + 90.0 % + 10 + 9 - diff --git a/coverage_report/index.html b/coverage_report/index.html index d3180bd..5a9109e 100644 --- a/coverage_report/index.html +++ b/coverage_report/index.html @@ -31,13 +31,13 @@ lcov.info Lines: - 49.4 % - 413 - 204 + 51.7 % + 429 + 222 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -82,11 +82,23 @@ cubit/ -
48.1%48.1%
+
62.7%62.7%
- 48.1 % - 52 - 25 + 62.7 % + 51 + 32 + - + + + + + datasources/ + +
90.0%90.0%
+ + 90.0 % + 10 + 9 - @@ -94,11 +106,23 @@ models/ -
61.2%61.2%
+
61.5%61.5%
- 61.2 % - 103 - 63 + 61.5 % + 104 + 64 + - + + + + + network/ + +
80.0%80.0%
+ + 80.0 % + 5 + 4 - @@ -118,11 +142,11 @@ repositories/ -
84.6%84.6%
+
75.0%75.0%
- 84.6 % - 13 - 11 + 75.0 % + 8 + 6 - @@ -154,11 +178,11 @@ widgets/ -
45.5%45.5%
+
44.9%44.9%
- 45.5 % - 101 - 46 + 44.9 % + 107 + 48 - diff --git a/coverage_report/models/index-sort-f.html b/coverage_report/models/index-sort-f.html index 0ad9d8b..1ecbf9e 100644 --- a/coverage_report/models/index-sort-f.html +++ b/coverage_report/models/index-sort-f.html @@ -31,13 +31,13 @@ lcov.info Lines: - 61.2 % - 103 - 63 + 61.5 % + 104 + 64 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -94,11 +94,11 @@ restaurant.g.dart -
56.5%56.5%
+
57.1%57.1%
- 56.5 % - 69 - 39 + 57.1 % + 70 + 40 - diff --git a/coverage_report/models/index-sort-l.html b/coverage_report/models/index-sort-l.html index f57d979..545c4a7 100644 --- a/coverage_report/models/index-sort-l.html +++ b/coverage_report/models/index-sort-l.html @@ -31,13 +31,13 @@ lcov.info Lines: - 61.2 % - 103 - 63 + 61.5 % + 104 + 64 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -82,11 +82,11 @@ restaurant.g.dart -
56.5%56.5%
+
57.1%57.1%
- 56.5 % - 69 - 39 + 57.1 % + 70 + 40 - diff --git a/coverage_report/models/index.html b/coverage_report/models/index.html index e7bb6dc..b4e6223 100644 --- a/coverage_report/models/index.html +++ b/coverage_report/models/index.html @@ -31,13 +31,13 @@ lcov.info Lines: - 61.2 % - 103 - 63 + 61.5 % + 104 + 64 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -94,11 +94,11 @@ restaurant.g.dart -
56.5%56.5%
+
57.1%57.1%
- 56.5 % - 69 - 39 + 57.1 % + 70 + 40 - diff --git a/coverage_report/models/restaurant.dart.func-c.html b/coverage_report/models/restaurant.dart.func-c.html index 575f209..c4982fb 100644 --- a/coverage_report/models/restaurant.dart.func-c.html +++ b/coverage_report/models/restaurant.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/models/restaurant.dart.func.html b/coverage_report/models/restaurant.dart.func.html index 54d73b0..0fb3e27 100644 --- a/coverage_report/models/restaurant.dart.func.html +++ b/coverage_report/models/restaurant.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/models/restaurant.dart.gcov.html b/coverage_report/models/restaurant.dart.gcov.html index e63036b..165dc05 100644 --- a/coverage_report/models/restaurant.dart.gcov.html +++ b/coverage_report/models/restaurant.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/models/restaurant.g.dart.func-c.html b/coverage_report/models/restaurant.g.dart.func-c.html index 2e9c56d..ba92530 100644 --- a/coverage_report/models/restaurant.g.dart.func-c.html +++ b/coverage_report/models/restaurant.g.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 56.5 % - 69 - 39 + 57.1 % + 70 + 40 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/models/restaurant.g.dart.func.html b/coverage_report/models/restaurant.g.dart.func.html index 72a11b7..a90fe0b 100644 --- a/coverage_report/models/restaurant.g.dart.func.html +++ b/coverage_report/models/restaurant.g.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 56.5 % - 69 - 39 + 57.1 % + 70 + 40 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/models/restaurant.g.dart.gcov.html b/coverage_report/models/restaurant.g.dart.gcov.html index 9d71c9d..acaf7b1 100644 --- a/coverage_report/models/restaurant.g.dart.gcov.html +++ b/coverage_report/models/restaurant.g.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 56.5 % - 69 - 39 + 57.1 % + 70 + 40 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -101,74 +101,75 @@ 39 4 : Review _$ReviewFromJson(Map<String, dynamic> json) => Review( 40 2 : id: json['id'] as String?, 41 2 : rating: json['rating'] as int?, - 42 2 : user: json['user'] == null - 43 : ? null - 44 4 : : User.fromJson(json['user'] as Map<String, dynamic>), - 45 : ); - 46 : - 47 0 : Map<String, dynamic> _$ReviewToJson(Review instance) => <String, dynamic>{ - 48 0 : 'id': instance.id, - 49 0 : 'rating': instance.rating, - 50 0 : 'user': instance.user, - 51 : }; - 52 : - 53 4 : Location _$LocationFromJson(Map<String, dynamic> json) => Location( - 54 2 : formattedAddress: json['formatted_address'] as String?, - 55 : ); - 56 : - 57 0 : Map<String, dynamic> _$LocationToJson(Location instance) => <String, dynamic>{ - 58 0 : 'formatted_address': instance.formattedAddress, - 59 : }; - 60 : - 61 4 : Restaurant _$RestaurantFromJson(Map<String, dynamic> json) => Restaurant( - 62 2 : id: json['id'] as String?, - 63 2 : name: json['name'] as String?, - 64 2 : price: json['price'] as String?, - 65 4 : rating: (json['rating'] as num?)?.toDouble(), - 66 : photos: - 67 8 : (json['photos'] as List<dynamic>?)?.map((e) => e as String).toList(), - 68 2 : categories: (json['categories'] as List<dynamic>?) - 69 6 : ?.map((e) => Category.fromJson(e as Map<String, dynamic>)) - 70 2 : .toList(), - 71 2 : hours: (json['hours'] as List<dynamic>?) - 72 6 : ?.map((e) => Hours.fromJson(e as Map<String, dynamic>)) - 73 2 : .toList(), - 74 2 : reviews: (json['reviews'] as List<dynamic>?) - 75 6 : ?.map((e) => Review.fromJson(e as Map<String, dynamic>)) - 76 2 : .toList(), - 77 2 : location: json['location'] == null - 78 : ? null - 79 4 : : Location.fromJson(json['location'] as Map<String, dynamic>), - 80 : ); - 81 : - 82 0 : Map<String, dynamic> _$RestaurantToJson(Restaurant instance) => - 83 0 : <String, dynamic>{ - 84 0 : 'id': instance.id, - 85 0 : 'name': instance.name, - 86 0 : 'price': instance.price, - 87 0 : 'rating': instance.rating, - 88 0 : 'photos': instance.photos, - 89 0 : 'categories': instance.categories, - 90 0 : 'hours': instance.hours, - 91 0 : 'reviews': instance.reviews, - 92 0 : 'location': instance.location, - 93 : }; - 94 : - 95 2 : RestaurantQueryResult _$RestaurantQueryResultFromJson( - 96 : Map<String, dynamic> json) => - 97 2 : RestaurantQueryResult( - 98 2 : total: json['total'] as int?, - 99 2 : restaurants: (json['business'] as List<dynamic>?) - 100 6 : ?.map((e) => Restaurant.fromJson(e as Map<String, dynamic>)) - 101 2 : .toList(), - 102 : ); - 103 : - 104 0 : Map<String, dynamic> _$RestaurantQueryResultToJson( - 105 : RestaurantQueryResult instance) => - 106 0 : <String, dynamic>{ - 107 0 : 'total': instance.total, - 108 0 : 'business': instance.restaurants, - 109 : }; + 42 2 : text: json['text'] as String?, + 43 2 : user: json['user'] == null + 44 : ? null + 45 4 : : User.fromJson(json['user'] as Map<String, dynamic>), + 46 : ); + 47 : + 48 0 : Map<String, dynamic> _$ReviewToJson(Review instance) => <String, dynamic>{ + 49 0 : 'id': instance.id, + 50 0 : 'rating': instance.rating, + 51 0 : 'user': instance.user, + 52 : }; + 53 : + 54 4 : Location _$LocationFromJson(Map<String, dynamic> json) => Location( + 55 2 : formattedAddress: json['formatted_address'] as String?, + 56 : ); + 57 : + 58 0 : Map<String, dynamic> _$LocationToJson(Location instance) => <String, dynamic>{ + 59 0 : 'formatted_address': instance.formattedAddress, + 60 : }; + 61 : + 62 4 : Restaurant _$RestaurantFromJson(Map<String, dynamic> json) => Restaurant( + 63 2 : id: json['id'] as String?, + 64 2 : name: json['name'] as String?, + 65 2 : price: json['price'] as String?, + 66 4 : rating: (json['rating'] as num?)?.toDouble(), + 67 : photos: + 68 8 : (json['photos'] as List<dynamic>?)?.map((e) => e as String).toList(), + 69 2 : categories: (json['categories'] as List<dynamic>?) + 70 6 : ?.map((e) => Category.fromJson(e as Map<String, dynamic>)) + 71 2 : .toList(), + 72 2 : hours: (json['hours'] as List<dynamic>?) + 73 6 : ?.map((e) => Hours.fromJson(e as Map<String, dynamic>)) + 74 2 : .toList(), + 75 2 : reviews: (json['reviews'] as List<dynamic>?) + 76 6 : ?.map((e) => Review.fromJson(e as Map<String, dynamic>)) + 77 2 : .toList(), + 78 2 : location: json['location'] == null + 79 : ? null + 80 4 : : Location.fromJson(json['location'] as Map<String, dynamic>), + 81 : ); + 82 : + 83 0 : Map<String, dynamic> _$RestaurantToJson(Restaurant instance) => + 84 0 : <String, dynamic>{ + 85 0 : 'id': instance.id, + 86 0 : 'name': instance.name, + 87 0 : 'price': instance.price, + 88 0 : 'rating': instance.rating, + 89 0 : 'photos': instance.photos, + 90 0 : 'categories': instance.categories, + 91 0 : 'hours': instance.hours, + 92 0 : 'reviews': instance.reviews, + 93 0 : 'location': instance.location, + 94 : }; + 95 : + 96 2 : RestaurantQueryResult _$RestaurantQueryResultFromJson( + 97 : Map<String, dynamic> json) => + 98 2 : RestaurantQueryResult( + 99 2 : total: json['total'] as int?, + 100 2 : restaurants: (json['business'] as List<dynamic>?) + 101 6 : ?.map((e) => Restaurant.fromJson(e as Map<String, dynamic>)) + 102 2 : .toList(), + 103 : ); + 104 : + 105 0 : Map<String, dynamic> _$RestaurantQueryResultToJson( + 106 : RestaurantQueryResult instance) => + 107 0 : <String, dynamic>{ + 108 0 : 'total': instance.total, + 109 0 : 'business': instance.restaurants, + 110 : }; diff --git a/coverage_report/pages/home_page.dart.func-c.html b/coverage_report/pages/home_page.dart.func-c.html index 56bb9f2..14dfed4 100644 --- a/coverage_report/pages/home_page.dart.func-c.html +++ b/coverage_report/pages/home_page.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/home_page.dart.func.html b/coverage_report/pages/home_page.dart.func.html index 5940687..3423b0d 100644 --- a/coverage_report/pages/home_page.dart.func.html +++ b/coverage_report/pages/home_page.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/home_page.dart.gcov.html b/coverage_report/pages/home_page.dart.gcov.html index 109d740..83da089 100644 --- a/coverage_report/pages/home_page.dart.gcov.html +++ b/coverage_report/pages/home_page.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/index-sort-f.html b/coverage_report/pages/index-sort-f.html index 3f4c23c..8afb46b 100644 --- a/coverage_report/pages/index-sort-f.html +++ b/coverage_report/pages/index-sort-f.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/index-sort-l.html b/coverage_report/pages/index-sort-l.html index 2aabcae..97ccc27 100644 --- a/coverage_report/pages/index-sort-l.html +++ b/coverage_report/pages/index-sort-l.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/index.html b/coverage_report/pages/index.html index 08d26e9..98e3690 100644 --- a/coverage_report/pages/index.html +++ b/coverage_report/pages/index.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/restaurant_detail_page.dart.func-c.html b/coverage_report/pages/restaurant_detail_page.dart.func-c.html index b75d0ab..06a464a 100644 --- a/coverage_report/pages/restaurant_detail_page.dart.func-c.html +++ b/coverage_report/pages/restaurant_detail_page.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/restaurant_detail_page.dart.func.html b/coverage_report/pages/restaurant_detail_page.dart.func.html index 4db5c98..ea89c17 100644 --- a/coverage_report/pages/restaurant_detail_page.dart.func.html +++ b/coverage_report/pages/restaurant_detail_page.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/restaurant_detail_page.dart.gcov.html b/coverage_report/pages/restaurant_detail_page.dart.gcov.html index 92997e8..5ed64c1 100644 --- a/coverage_report/pages/restaurant_detail_page.dart.gcov.html +++ b/coverage_report/pages/restaurant_detail_page.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/restaurant_list_page.dart.func-c.html b/coverage_report/pages/restaurant_list_page.dart.func-c.html index 957cef5..6aa2d37 100644 --- a/coverage_report/pages/restaurant_list_page.dart.func-c.html +++ b/coverage_report/pages/restaurant_list_page.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/restaurant_list_page.dart.func.html b/coverage_report/pages/restaurant_list_page.dart.func.html index 2bd7844..4b3d8de 100644 --- a/coverage_report/pages/restaurant_list_page.dart.func.html +++ b/coverage_report/pages/restaurant_list_page.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/pages/restaurant_list_page.dart.gcov.html b/coverage_report/pages/restaurant_list_page.dart.gcov.html index 41d1ef1..2b08e61 100644 --- a/coverage_report/pages/restaurant_list_page.dart.gcov.html +++ b/coverage_report/pages/restaurant_list_page.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/repositories/index-sort-f.html b/coverage_report/repositories/index-sort-f.html index 013957e..1667bde 100644 --- a/coverage_report/repositories/index-sort-f.html +++ b/coverage_report/repositories/index-sort-f.html @@ -31,13 +31,13 @@ lcov.info Lines: - 84.6 % - 13 - 11 + 75.0 % + 8 + 6 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -82,11 +82,11 @@ yelp_repository.dart -
84.6%84.6%
+
75.0%75.0%
- 84.6 % - 13 - 11 + 75.0 % + 8 + 6 - diff --git a/coverage_report/repositories/index-sort-l.html b/coverage_report/repositories/index-sort-l.html index d2d34c0..e064664 100644 --- a/coverage_report/repositories/index-sort-l.html +++ b/coverage_report/repositories/index-sort-l.html @@ -31,13 +31,13 @@ lcov.info Lines: - 84.6 % - 13 - 11 + 75.0 % + 8 + 6 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -82,11 +82,11 @@ yelp_repository.dart -
84.6%84.6%
+
75.0%75.0%
- 84.6 % - 13 - 11 + 75.0 % + 8 + 6 - diff --git a/coverage_report/repositories/index.html b/coverage_report/repositories/index.html index a196ddc..c5e84b7 100644 --- a/coverage_report/repositories/index.html +++ b/coverage_report/repositories/index.html @@ -31,13 +31,13 @@ lcov.info Lines: - 84.6 % - 13 - 11 + 75.0 % + 8 + 6 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -82,11 +82,11 @@ yelp_repository.dart -
84.6%84.6%
+
75.0%75.0%
- 84.6 % - 13 - 11 + 75.0 % + 8 + 6 - diff --git a/coverage_report/repositories/yelp_repository.dart.func-c.html b/coverage_report/repositories/yelp_repository.dart.func-c.html index d40275a..aaefd16 100644 --- a/coverage_report/repositories/yelp_repository.dart.func-c.html +++ b/coverage_report/repositories/yelp_repository.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 84.6 % - 13 - 11 + 75.0 % + 8 + 6 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/repositories/yelp_repository.dart.func.html b/coverage_report/repositories/yelp_repository.dart.func.html index 6238adb..d854f87 100644 --- a/coverage_report/repositories/yelp_repository.dart.func.html +++ b/coverage_report/repositories/yelp_repository.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 84.6 % - 13 - 11 + 75.0 % + 8 + 6 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/repositories/yelp_repository.dart.gcov.html b/coverage_report/repositories/yelp_repository.dart.gcov.html index 0ed7518..e4c2139 100644 --- a/coverage_report/repositories/yelp_repository.dart.gcov.html +++ b/coverage_report/repositories/yelp_repository.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 84.6 % - 13 - 11 + 75.0 % + 8 + 6 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -60,127 +60,38 @@
            Line data    Source code
-       1              : import 'package:dio/dio.dart';
-       2              : import 'package:flutter/foundation.dart';
-       3              : import 'package:restaurant_tour/env.dart';
-       4              : import 'package:restaurant_tour/models/restaurant.dart';
-       5              : import 'package:restaurant_tour/repositories/sample_json.dart';
-       6              : 
-       7              : class YelpRepository {
-       8              :   late Dio dio;
-       9              : 
-      10            2 :   YelpRepository({
-      11              :     @visibleForTesting Dio? dio,
-      12              :   }) : dio = dio ??
-      13            1 :             Dio(
-      14            1 :               BaseOptions(
-      15              :                 baseUrl: 'https://api.yelp.com',
-      16            1 :                 headers: {
-      17              :                   'Authorization': 'Bearer $API_KEY',
-      18              :                   'Content-Type': 'application/graphql',
-      19              :                 },
-      20              :               ),
-      21              :             );
-      22              : 
-      23              :   /// Returns a response in this shape
-      24              :   /// {
-      25              :   /// "data": {
-      26              :   ///   "search": {
-      27              :   ///     "total": 5056,
-      28              :   ///     "business": [
-      29              :   ///       {
-      30              :   ///         "id": "faPVqws-x-5k2CQKDNtHxw",
-      31              :   ///         "name": "Yardbird Southern Table & Bar",
-      32              :   ///         "price": "$$",
-      33              :   ///         "rating": 4.5,
-      34              :   ///         "photos": [
-      35              :   ///           "https:///s3-media4.fl.yelpcdn.com/bphoto/_zXRdYX4r1OBfF86xKMbDw/o.jpg"
-      36              :   ///         ],
-      37              :   ///         "reviews": [
-      38              :   ///           {
-      39              :   ///             "id": "sjZoO8wcK1NeGJFDk5i82Q",
-      40              :   ///             "rating": 5,
-      41              :   ///             "user": {
-      42              :   ///               "id": "BuBCkWFNT_O2dbSnBZvpoQ",
-      43              :   ///               "image_url": "https:///s3-media2.fl.yelpcdn.com/photo/v8tbTjYaFvkzh1d7iE-pcQ/o.jpg",
-      44              :   ///               "name": "Gina T.",
-      45              :   ///               "text": "I love this place! The food is amazing and the service is great."
-      46              :   ///             }
-      47              :   ///           },
-      48              :   ///           {
-      49              :   ///             "id": "okpO9hfpxQXssbTZTKq9hA",
-      50              :   ///             "rating": 5,
-      51              :   ///             "user": {
-      52              :   ///               "id": "0x9xu_b0Ct_6hG6jaxpztw",
-      53              :   ///               "image_url": "https:///s3-media3.fl.yelpcdn.com/photo/gjz8X6tqE3e4praK4HfCiA/o.jpg",
-      54              :   ///               "name": "Crystal L.",
-      55              :   ///               "text": "Greate place to eat"
-      56              :   ///             }
-      57              :   ///           },
-      58              :   ///        ...
-      59              :   ///     ]
-      60              :   ///   }
-      61              :   /// }
-      62              :   ///
-      63              :   ///
-      64            1 :   RestaurantQueryResult getRestaurantsFromCache({int offset = 0}) {
-      65              :     try {
-      66            3 :       return RestaurantQueryResult.fromJson(sample['data']['search']);
-      67              :     } catch (e) {
-      68            0 :       throw Exception();
-      69              :     }
-      70              :   }
-      71              : 
-      72            1 :   Future<RestaurantQueryResult?> getRestaurants({int offset = 0}) async {
-      73              :     try {
-      74            2 :       final response = await dio.post<Map<String, dynamic>>(
-      75              :         '/v3/graphql',
-      76            1 :         data: _getQuery(offset),
-      77              :       );
-      78              :       // saveToJson(response.data!['data']['search'], 'datastore.json');
-      79            0 :       return RestaurantQueryResult.fromJson(response.data!['data']['search']);
-      80              :     } catch (e) {
-      81              :       return null;
-      82              :     }
-      83              :   }
-      84              : 
-      85            1 :   String _getQuery(int offset) {
-      86              :     return '''
-      87              : query getRestaurants {
-      88              :   search(location: "Las Vegas", limit: 20, offset: $offset) {
-      89              :     total    
-      90              :     business {
-      91              :       id
-      92              :       name
-      93              :       price
-      94              :       rating
-      95              :       photos
-      96              :       reviews {
-      97              :         id
-      98              :         rating
-      99              :         text
-     100              :         user {
-     101              :           id
-     102              :           image_url
-     103              :           name
-     104              :         }
-     105              :       }
-     106              :       categories {
-     107              :         title
-     108              :         alias
-     109              :       }
-     110              :       hours {
-     111              :         is_open_now
-     112              :       }
-     113              :       location {
-     114              :         formatted_address
-     115              :       }
-     116              :     }
-     117              :   }
-     118              : }
-     119            1 : ''';
-     120              :   }
-     121              : }
+       1              : import 'dart:developer';
+       2              : import 'package:restaurant_tour/datasources/yielp_datasource.dart';
+       3              : import 'package:restaurant_tour/models/restaurant.dart';
+       4              : import 'package:restaurant_tour/utils/sample_json.dart';
+       5              : 
+       6              : class YelpRepository {
+       7              :   final YielpDatasource datasource;
+       8              : 
+       9            2 :   YelpRepository({required this.datasource});
+      10              : 
+      11            1 :   RestaurantQueryResult getRestaurantsFromCache({int offset = 0}) {
+      12              :     try {
+      13            1 :       log('fetching from cache');
+      14            3 :       return RestaurantQueryResult.fromJson(sample['data']['search']);
+      15              :     } catch (e) {
+      16            0 :       throw Exception();
+      17              :     }
+      18              :   }
+      19              : 
+      20            1 :   Future<RestaurantQueryResult?> getRestaurants({int offset = 0}) async {
+      21              :     try {
+      22            2 :       final data = await datasource.fetchRestaurants(offset);
+      23              :       if (data != null) {
+      24            0 :         return RestaurantQueryResult.fromJson(data['data']['search']);
+      25              :       } else {
+      26              :         return null;
+      27              :       }
+      28              :     } catch (e) {
+      29              :       return null;
+      30              :     }
+      31              :   }
+      32              : }
         
diff --git a/coverage_report/usecases/fetch_restaurants.dart.func-c.html b/coverage_report/usecases/fetch_restaurants.dart.func-c.html index 3dfef03..01f8565 100644 --- a/coverage_report/usecases/fetch_restaurants.dart.func-c.html +++ b/coverage_report/usecases/fetch_restaurants.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/usecases/fetch_restaurants.dart.func.html b/coverage_report/usecases/fetch_restaurants.dart.func.html index 4d0fcd5..e1902a5 100644 --- a/coverage_report/usecases/fetch_restaurants.dart.func.html +++ b/coverage_report/usecases/fetch_restaurants.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/usecases/fetch_restaurants.dart.gcov.html b/coverage_report/usecases/fetch_restaurants.dart.gcov.html index 14fc0ae..1336ee9 100644 --- a/coverage_report/usecases/fetch_restaurants.dart.gcov.html +++ b/coverage_report/usecases/fetch_restaurants.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -70,37 +70,38 @@ 8 0 : FetchRestaurants({required this.repository}); 9 0 : Future<RestaurantQueryResult?> getRestaurants() async => await repository 10 0 : .getRestaurantsFromCache(); //CHANGE THIS LATER TO FETCH FROM THE REAL API - 11 0 : Future<RestaurantQueryResult?> getRestaurantsFromCache() async => - 12 0 : await repository.getRestaurantsFromCache(); - 13 : - 14 0 : Future<List<String>> getFavoriteRestaurants() async { - 15 : // final prefs = await SharedPreferences.getInstance(); - 16 : - 17 : // Retrieve the list from SharedPreferences - 18 : // List<String>? favoriteRestaurants = prefs.getStringList('fav'); - 19 : - 20 : // Simulate delay - 21 0 : await Future.delayed(const Duration(milliseconds: 500)); - 22 : - 23 : // Return the list or a default value if it doesn't exist - 24 : // return favoriteRestaurants ?? []; - 25 0 : return ['vHz2RLtfUMVRPFmd7VBEHA']; - 26 : } - 27 : - 28 0 : Future<void> saveFavoriteRestaurants(List<String> favoriteRestaurants) async { - 29 : // final prefs = await SharedPreferences.getInstance(); - 30 : - 31 : // Save the list to SharedPreferences - 32 : // await prefs.setStringList('fav', favoriteRestaurants); - 33 : } - 34 : } - 35 : // Future<List<String>> getFavoriteRestaurants() async { - 36 : // //this could be fetched from anywhere later... a shared prefs or another database - 37 : // await Future.delayed(const Duration(milliseconds: 500)); - 38 : - 39 : // return ['vHz2RLtfUMVRPFmd7VBEHA']; - 40 : // } - 41 : + 11 : + 12 0 : Future<RestaurantQueryResult?> getRestaurantsFromCache() async => + 13 0 : await repository.getRestaurantsFromCache(); + 14 : + 15 0 : Future<List<String>> getFavoriteRestaurants() async { + 16 : // final prefs = await SharedPreferences.getInstance(); + 17 : + 18 : // Retrieve the list from SharedPreferences + 19 : // List<String>? favoriteRestaurants = prefs.getStringList('fav'); + 20 : + 21 : // Simulate delay + 22 0 : await Future.delayed(const Duration(milliseconds: 500)); + 23 : + 24 : // Return the list or a default value if it doesn't exist + 25 : // return favoriteRestaurants ?? []; + 26 0 : return ['vHz2RLtfUMVRPFmd7VBEHA']; + 27 : } + 28 : + 29 0 : Future<void> saveFavoriteRestaurants(List<String> favoriteRestaurants) async { + 30 : // final prefs = await SharedPreferences.getInstance(); + 31 : + 32 : // Save the list to SharedPreferences + 33 : // await prefs.setStringList('fav', favoriteRestaurants); + 34 : } + 35 : } + 36 : // Future<List<String>> getFavoriteRestaurants() async { + 37 : // //this could be fetched from anywhere later... a shared prefs or another database + 38 : // await Future.delayed(const Duration(milliseconds: 500)); + 39 : + 40 : // return ['vHz2RLtfUMVRPFmd7VBEHA']; + 41 : // } + 42 : diff --git a/coverage_report/usecases/index-sort-f.html b/coverage_report/usecases/index-sort-f.html index 4a51186..5c0407b 100644 --- a/coverage_report/usecases/index-sort-f.html +++ b/coverage_report/usecases/index-sort-f.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/usecases/index-sort-l.html b/coverage_report/usecases/index-sort-l.html index 675d2a8..e9b7f69 100644 --- a/coverage_report/usecases/index-sort-l.html +++ b/coverage_report/usecases/index-sort-l.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/usecases/index.html b/coverage_report/usecases/index.html index 2af5b3e..46682c5 100644 --- a/coverage_report/usecases/index.html +++ b/coverage_report/usecases/index.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/utils/get_random_avatar.dart.func-c.html b/coverage_report/utils/get_random_avatar.dart.func-c.html index c284f8c..ff5de2b 100644 --- a/coverage_report/utils/get_random_avatar.dart.func-c.html +++ b/coverage_report/utils/get_random_avatar.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/utils/get_random_avatar.dart.func.html b/coverage_report/utils/get_random_avatar.dart.func.html index 8d3a9b5..b11e9da 100644 --- a/coverage_report/utils/get_random_avatar.dart.func.html +++ b/coverage_report/utils/get_random_avatar.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/utils/get_random_avatar.dart.gcov.html b/coverage_report/utils/get_random_avatar.dart.gcov.html index de4330c..6cb5863 100644 --- a/coverage_report/utils/get_random_avatar.dart.gcov.html +++ b/coverage_report/utils/get_random_avatar.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/utils/index-sort-f.html b/coverage_report/utils/index-sort-f.html index ebfbadd..44c858c 100644 --- a/coverage_report/utils/index-sort-f.html +++ b/coverage_report/utils/index-sort-f.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/utils/index-sort-l.html b/coverage_report/utils/index-sort-l.html index fb4c274..c771aa1 100644 --- a/coverage_report/utils/index-sort-l.html +++ b/coverage_report/utils/index-sort-l.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/utils/index.html b/coverage_report/utils/index.html index a76d0c4..8448817 100644 --- a/coverage_report/utils/index.html +++ b/coverage_report/utils/index.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/appbar.dart.func-c.html b/coverage_report/widgets/appbar.dart.func-c.html index 241bab4..3a2faab 100644 --- a/coverage_report/widgets/appbar.dart.func-c.html +++ b/coverage_report/widgets/appbar.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/appbar.dart.func.html b/coverage_report/widgets/appbar.dart.func.html index 07c9032..7e9b876 100644 --- a/coverage_report/widgets/appbar.dart.func.html +++ b/coverage_report/widgets/appbar.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/appbar.dart.gcov.html b/coverage_report/widgets/appbar.dart.gcov.html index f45ec73..91c3d47 100644 --- a/coverage_report/widgets/appbar.dart.gcov.html +++ b/coverage_report/widgets/appbar.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/divider.dart.func-c.html b/coverage_report/widgets/divider.dart.func-c.html index 4d4cc45..ec3eb75 100644 --- a/coverage_report/widgets/divider.dart.func-c.html +++ b/coverage_report/widgets/divider.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/divider.dart.func.html b/coverage_report/widgets/divider.dart.func.html index 2c42a13..791682b 100644 --- a/coverage_report/widgets/divider.dart.func.html +++ b/coverage_report/widgets/divider.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/divider.dart.gcov.html b/coverage_report/widgets/divider.dart.gcov.html index 9ce2d70..fc2a9b4 100644 --- a/coverage_report/widgets/divider.dart.gcov.html +++ b/coverage_report/widgets/divider.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/hero_image_widget.dart.func-c.html b/coverage_report/widgets/hero_image_widget.dart.func-c.html index 3bb7d20..42f3d09 100644 --- a/coverage_report/widgets/hero_image_widget.dart.func-c.html +++ b/coverage_report/widgets/hero_image_widget.dart.func-c.html @@ -31,13 +31,13 @@ lcov.info Lines: - 100.0 % - 10 - 10 + 75.0 % + 16 + 12 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/hero_image_widget.dart.func.html b/coverage_report/widgets/hero_image_widget.dart.func.html index ac011c2..d85ad43 100644 --- a/coverage_report/widgets/hero_image_widget.dart.func.html +++ b/coverage_report/widgets/hero_image_widget.dart.func.html @@ -31,13 +31,13 @@ lcov.info Lines: - 100.0 % - 10 - 10 + 75.0 % + 16 + 12 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/hero_image_widget.dart.gcov.html b/coverage_report/widgets/hero_image_widget.dart.gcov.html index 04d5890..c86672c 100644 --- a/coverage_report/widgets/hero_image_widget.dart.gcov.html +++ b/coverage_report/widgets/hero_image_widget.dart.gcov.html @@ -31,13 +31,13 @@ lcov.info Lines: - 100.0 % - 10 - 10 + 75.0 % + 16 + 12 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -81,16 +81,27 @@ 19 3 : tag: restaurant.id.toString(), 20 1 : child: ClipRRect( 21 2 : borderRadius: BorderRadius.circular(borderRadius), - 22 1 : child: Image.network( - 23 2 : restaurant.heroImage, - 24 : fit: BoxFit.cover, - 25 1 : width: width, - 26 1 : height: height, - 27 : ), - 28 : ), - 29 : ); - 30 : } - 31 : } + 22 3 : child: restaurant.heroImage.isNotEmpty && + 23 5 : Uri.tryParse(restaurant.heroImage)?.isAbsolute == true + 24 1 : ? Image.network( + 25 2 : restaurant.heroImage, + 26 : fit: BoxFit.cover, + 27 1 : width: width, + 28 1 : height: height, + 29 : ) + 30 0 : : Container( + 31 0 : width: width, + 32 0 : height: height, + 33 : color: const Color.fromARGB(255, 197, 233, 199), + 34 0 : child: Image.asset( + 35 : 'assets/placeholder.png', + 36 : fit: BoxFit.fitHeight, + 37 : ), + 38 : ), + 39 : ), + 40 : ); + 41 : } + 42 : } diff --git a/coverage_report/widgets/index-sort-f.html b/coverage_report/widgets/index-sort-f.html index 2d938f3..0f172c1 100644 --- a/coverage_report/widgets/index-sort-f.html +++ b/coverage_report/widgets/index-sort-f.html @@ -31,13 +31,13 @@ lcov.info Lines: - 45.5 % - 101 - 46 + 44.9 % + 107 + 48 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -106,11 +106,11 @@ hero_image_widget.dart -
100.0%
+
75.0%75.0%
- 100.0 % - 10 - 10 + 75.0 % + 16 + 12 - diff --git a/coverage_report/widgets/index-sort-l.html b/coverage_report/widgets/index-sort-l.html index e3d4db0..d9d81e1 100644 --- a/coverage_report/widgets/index-sort-l.html +++ b/coverage_report/widgets/index-sort-l.html @@ -31,13 +31,13 @@ lcov.info Lines: - 45.5 % - 101 - 46 + 44.9 % + 107 + 48 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -116,19 +116,19 @@ - rating_and_open_status_widget.dart + hero_image_widget.dart -
100.0%
+
75.0%75.0%
- 100.0 % - 8 - 8 + 75.0 % + 16 + 12 - - rating_widget.dart + rating_and_open_status_widget.dart
100.0%
@@ -140,25 +140,25 @@ - rataurant_open_status.dart + rating_widget.dart
100.0%
100.0 % - 9 - 9 + 8 + 8 - - hero_image_widget.dart + rataurant_open_status.dart
100.0%
100.0 % - 10 - 10 + 9 + 9 - diff --git a/coverage_report/widgets/index.html b/coverage_report/widgets/index.html index 231dd9d..470ddaf 100644 --- a/coverage_report/widgets/index.html +++ b/coverage_report/widgets/index.html @@ -31,13 +31,13 @@ lcov.info Lines: - 45.5 % - 101 - 46 + 44.9 % + 107 + 48 Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - @@ -106,11 +106,11 @@ hero_image_widget.dart -
100.0%
+
75.0%75.0%
- 100.0 % - 10 - 10 + 75.0 % + 16 + 12 - diff --git a/coverage_report/widgets/rataurant_open_status.dart.func-c.html b/coverage_report/widgets/rataurant_open_status.dart.func-c.html index 56619de..00a934d 100644 --- a/coverage_report/widgets/rataurant_open_status.dart.func-c.html +++ b/coverage_report/widgets/rataurant_open_status.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/rataurant_open_status.dart.func.html b/coverage_report/widgets/rataurant_open_status.dart.func.html index 3978ce6..3c5ae88 100644 --- a/coverage_report/widgets/rataurant_open_status.dart.func.html +++ b/coverage_report/widgets/rataurant_open_status.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/rataurant_open_status.dart.gcov.html b/coverage_report/widgets/rataurant_open_status.dart.gcov.html index e6a1cde..543cc8b 100644 --- a/coverage_report/widgets/rataurant_open_status.dart.gcov.html +++ b/coverage_report/widgets/rataurant_open_status.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html b/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html index 08a7d19..f160466 100644 --- a/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html +++ b/coverage_report/widgets/rating_and_open_status_widget.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/rating_and_open_status_widget.dart.func.html b/coverage_report/widgets/rating_and_open_status_widget.dart.func.html index be671f6..aa9a287 100644 --- a/coverage_report/widgets/rating_and_open_status_widget.dart.func.html +++ b/coverage_report/widgets/rating_and_open_status_widget.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html b/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html index ffde9a3..3bd747b 100644 --- a/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html +++ b/coverage_report/widgets/rating_and_open_status_widget.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/rating_widget.dart.func-c.html b/coverage_report/widgets/rating_widget.dart.func-c.html index a948ffe..eb096e6 100644 --- a/coverage_report/widgets/rating_widget.dart.func-c.html +++ b/coverage_report/widgets/rating_widget.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/rating_widget.dart.func.html b/coverage_report/widgets/rating_widget.dart.func.html index ba128a2..cdf239e 100644 --- a/coverage_report/widgets/rating_widget.dart.func.html +++ b/coverage_report/widgets/rating_widget.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/rating_widget.dart.gcov.html b/coverage_report/widgets/rating_widget.dart.gcov.html index 0ff34c7..3f30547 100644 --- a/coverage_report/widgets/rating_widget.dart.gcov.html +++ b/coverage_report/widgets/rating_widget.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/restaurant_details.dart.func-c.html b/coverage_report/widgets/restaurant_details.dart.func-c.html index a278828..fe73f6e 100644 --- a/coverage_report/widgets/restaurant_details.dart.func-c.html +++ b/coverage_report/widgets/restaurant_details.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/restaurant_details.dart.func.html b/coverage_report/widgets/restaurant_details.dart.func.html index 72d4922..644b718 100644 --- a/coverage_report/widgets/restaurant_details.dart.func.html +++ b/coverage_report/widgets/restaurant_details.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/restaurant_details.dart.gcov.html b/coverage_report/widgets/restaurant_details.dart.gcov.html index f5ea323..a41b462 100644 --- a/coverage_report/widgets/restaurant_details.dart.gcov.html +++ b/coverage_report/widgets/restaurant_details.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html b/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html index b802dbb..e79140a 100644 --- a/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html +++ b/coverage_report/widgets/restaurant_ratings_review_section.dart.func-c.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html b/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html index a236272..8e7d4d3 100644 --- a/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html +++ b/coverage_report/widgets/restaurant_ratings_review_section.dart.func.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: - diff --git a/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html b/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html index a4e4775..517eef7 100644 --- a/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html +++ b/coverage_report/widgets/restaurant_ratings_review_section.dart.gcov.html @@ -37,7 +37,7 @@ Test Date: - 2024-08-25 23:11:19 + 2024-08-26 14:48:33 Functions: -