2019-05-08 19:54:14 +01:00
import ' dart:async ' ;
2019-07-17 12:54:31 +01:00
import ' dart:io ' show Platform ;
2019-05-08 19:54:14 +01:00
import ' package:flutter/material.dart ' ;
import ' package:flutter/services.dart ' ;
2019-05-10 12:43:45 +01:00
import ' package:local_spend/common/apifunctions/submit_receipt_api.dart ' ;
2019-05-08 19:54:14 +01:00
import ' package:local_spend/common/functions/show_dialog_single_button.dart ' ;
import ' package:local_spend/common/platform/platform_scaffold.dart ' ;
import ' package:shared_preferences/shared_preferences.dart ' ;
import ' package:url_launcher/url_launcher.dart ' ;
2019-05-16 17:04:08 +01:00
import ' package:intl/intl.dart ' ;
2019-05-10 12:43:45 +01:00
import ' package:datetime_picker_formfield/datetime_picker_formfield.dart ' ;
2019-07-08 11:53:10 +01:00
import ' package:local_spend/common/apifunctions/find_organisations.dart ' ;
2019-07-08 15:03:11 +01:00
import ' package:local_spend/common/widgets/popupListView.dart ' ;
2019-07-16 16:55:00 +01:00
import ' package:local_spend/common/apifunctions/categories.dart ' ;
2019-07-17 14:15:10 +01:00
import ' package:local_spend/common/widgets/awesome_drawer.dart ' ;
2019-05-08 19:54:14 +01:00
const URL = " https://flutter.io/ " ;
2019-07-16 11:28:36 +01:00
const demonstration = false ;
2019-05-08 19:54:14 +01:00
class ReceiptPage extends StatefulWidget {
@ override
State < StatefulWidget > createState ( ) {
return new ReceiptPageState ( ) ;
}
}
class ReceiptPageState extends State < ReceiptPage > {
2019-05-10 12:43:45 +01:00
final TextEditingController _timeController = TextEditingController ( ) ;
final TextEditingController _amountController = TextEditingController ( ) ;
final TextEditingController _essentialController = TextEditingController ( ) ;
2019-07-16 12:54:55 +01:00
final TextEditingController _recurringController = TextEditingController ( ) ;
final TextEditingController _categoryController = TextEditingController ( ) ;
2019-05-10 12:43:45 +01:00
final TextEditingController _orgController = TextEditingController ( ) ;
2019-07-16 11:28:36 +01:00
final OrganizationController _organizationController = OrganizationController ( ) ;
2019-07-16 16:55:00 +01:00
List < String > _categoryDropDownItems = List < String > ( ) ;
2019-05-08 19:54:14 +01:00
2019-07-16 15:12:16 +01:00
FocusNode focusNode ;
2019-07-05 22:56:15 +01:00
2019-05-16 17:04:08 +01:00
DateTime date ;
2019-05-08 19:54:14 +01:00
Future launchURL ( String url ) async {
if ( await canLaunch ( url ) ) {
await launch ( url , forceSafariVC: true , forceWebView: true ) ;
} else {
showDialogSingleButton (
context ,
" Unable to reach your website. " ,
" Currently unable to reach the website $ URL . Please try again at a later time. " ,
" OK " ) ;
}
}
@ override
void initState ( ) {
2019-07-16 16:55:00 +01:00
getCategoriesStrings ( ) . then ( ( value ) {
_categoryDropDownItems = value ;
} ) ;
2019-05-08 19:54:14 +01:00
super . initState ( ) ;
2019-05-10 12:43:45 +01:00
_saveCurrentRoute ( " /ReceiptPageState " ) ;
2019-07-05 22:56:15 +01:00
focusNode = FocusNode ( ) ;
2019-07-16 12:54:55 +01:00
_recurringController . text = " None " ;
2019-07-16 15:12:16 +01:00
_categoryController . text = " " ;
2019-07-16 16:55:00 +01:00
// getCategoriesStrings().then((value) {
// _categoryDropDownItems = value;
// });
2019-07-05 22:56:15 +01:00
}
@ override
void dispose ( ) {
super . dispose ( ) ;
focusNode . dispose ( ) ; //disposes focus node when form disposed
2019-05-08 19:54:14 +01:00
}
_saveCurrentRoute ( String lastRoute ) async {
SharedPreferences preferences = await SharedPreferences . getInstance ( ) ;
await preferences . setString ( ' LastPageRoute ' , lastRoute ) ;
}
2019-07-15 14:48:41 +01:00
// this file is getting really messy sorry everyone
2019-07-16 16:55:00 +01:00
void submitReceipt ( String amount , String time , Organisation organisation , String recurring , String category , String essential ) async {
2019-07-05 15:34:39 +01:00
SystemChannels . textInput . invokeMethod ( ' TextInput.hide ' ) ;
2019-07-16 12:54:55 +01:00
if ( organisation = = null ) {
_findOrganizationsDialog ( context ) ;
/ * await showDialog (
2019-07-05 15:34:39 +01:00
context: context ,
builder: ( BuildContext context ) {
// return object of type Dialog
return AlertDialog (
2019-07-16 12:54:55 +01:00
title: new Text ( " Missing organisation " ) ,
2019-07-16 12:14:47 +01:00
content: new Text (
2019-07-16 12:54:55 +01:00
" Please press 'Find' to select your desired organization. " ) ,
2019-07-05 15:34:39 +01:00
actions: < Widget > [
new FlatButton (
child: new Text ( " OK " ) ,
onPressed: ( ) {
Navigator . of ( context ) . pop ( ) ;
} ,
) ,
] ,
) ;
} ,
2019-07-16 12:54:55 +01:00
) ; * /
2019-07-05 15:34:39 +01:00
}
else {
2019-07-16 12:54:55 +01:00
if ( amount = = " " | | time = = " " ) {
2019-07-16 12:14:47 +01:00
await showDialog (
context: context ,
builder: ( BuildContext context ) {
// return object of type Dialog
return AlertDialog (
2019-07-16 12:54:55 +01:00
title: new Text ( " Missing required data " ) ,
content: new Text (
" We couldn't process your request because one or more required fields are missing. " ) ,
2019-07-16 12:14:47 +01:00
actions: < Widget > [
new FlatButton (
child: new Text ( " OK " ) ,
onPressed: ( ) {
Navigator . of ( context ) . pop ( ) ;
} ,
) ,
] ,
) ;
} ,
2019-07-16 12:54:55 +01:00
) ;
2019-07-16 12:14:47 +01:00
}
else {
2019-07-16 12:54:55 +01:00
if ( demonstration ) {
await showDialog (
context: context ,
builder: ( BuildContext context ) {
// return object of type Dialog
return AlertDialog (
title: new Text ( " Success " ) ,
content: new Text ( " Receipt successfully submitted. " ) ,
actions: < Widget > [
// usually buttons at the bottom of the dialog
new FlatButton (
child: new Text ( " OK " ) ,
onPressed: ( ) {
Navigator . of ( context ) . pop ( ) ;
2019-07-17 12:54:31 +01:00
Navigator . of ( context ) . pushReplacementNamed ( " /ReceiptPage " ) ;
2019-07-16 12:54:55 +01:00
} ,
) ,
] ,
) ;
} ,
) . then ( ( _ ) { } ) ;
}
else {
Receipt receipt = new Receipt ( ) ;
2019-07-16 12:14:47 +01:00
2019-07-16 12:54:55 +01:00
// setting up 'receipt'
receipt . amount = amount ;
receipt . time = formatDate ( time ) ;
// debugPrint(organisation.name + ", " + organisation.streetName + ", " + organisation.town + ", " + organisation.postcode);
receipt . organisationName = organisation . name ;
receipt . street = organisation . streetName ;
receipt . town = organisation . town ;
receipt . postcode = organisation . postcode ;
receipt . recurring = recurring ;
2019-07-16 15:12:16 +01:00
receipt . category = category ;
2019-07-05 22:56:15 +01:00
2019-07-16 16:55:00 +01:00
receipt . essential = essential ;
2019-07-05 15:34:39 +01:00
2019-07-16 12:54:55 +01:00
submitReceiptAPI ( context , receipt ) ;
2019-07-17 12:54:31 +01:00
Navigator . of ( context ) . pushReplacementNamed ( " /ReceiptPage " ) ;
2019-07-16 12:54:55 +01:00
}
2019-07-16 12:14:47 +01:00
}
2019-07-05 15:34:39 +01:00
}
}
2019-07-05 22:56:15 +01:00
String convertBoolToString ( bool toConvert ) {
if ( toConvert )
{
return " true " ;
}
return " false " ;
}
2019-07-16 16:55:00 +01:00
Future < List < String > > getCategoriesStrings ( ) async {
var categories = getCategories ( ) ; //future<list<cat>>
var categoriesStrings = List < String > ( ) ;
categories . then ( ( val ) {
val . forEach ( ( thisCategory ) {
// print(thisCategory.name);
categoriesStrings . add ( thisCategory . name ) ;
} ) ;
// print(categoriesStrings[10]); // prints 'Banana'
// print(categoriesStrings.toString());
_categoryDropDownItems = categoriesStrings ;
return categoriesStrings ;
} ) ;
}
List < String > getRecurringOptions ( ) {
2019-07-15 14:48:41 +01:00
var options = new List < String > ( 7 ) ;
options [ 0 ] = " None " ;
options [ 1 ] = " Daily " ;
options [ 2 ] = " Weekly " ;
options [ 3 ] = " Fortnightly " ;
options [ 4 ] = " Monthly " ;
options [ 5 ] = " Quarterly " ;
options [ 6 ] = " Yearly " ;
return options ;
}
2019-07-05 22:56:15 +01:00
String formatDate ( String date ) {
// return "";
// should be in format:
// yyyy-MM-ddThh:mm:00.000+01:00
// eg 2019-07-05T10:24:00.000+01.00 (real life example, works)
// current format = "dd/MM/yyyy 'at' hh:mm"
2019-07-08 15:34:02 +01:00
// 0123456789ABCDEFGHIJK
2019-07-05 22:56:15 +01:00
var components = new List ( 5 ) ;
components [ 0 ] = ( date . substring ( 0 , 2 ) ) ; // dd
components [ 1 ] = ( date . substring ( 3 , 5 ) ) ; // MM
components [ 2 ] = ( date . substring ( 6 , 10 ) ) ; // yyyy
components [ 3 ] = ( date . substring ( 14 , 16 ) ) ; // hh
components [ 4 ] = ( date . substring ( 17 , 19 ) ) ; // mm
//print(components);
return ( components [ 2 ] + " - " + components [ 1 ] + " - " + components [ 0 ]
+ " T " + components [ 3 ] + " : " + components [ 4 ] + " :00.000+01:00 " ) ;
// Yes, there is probably a function to convert dates, but I didn't
// know that before writing this and it's done now so I'm keeping it.
}
2019-07-16 11:28:36 +01:00
Organisation listOrganisations ( List < Organisation > organisations , context ) {
2019-07-15 16:17:41 +01:00
if ( organisations . length = = 0 ) {
showDialogSingleButton (
context ,
" No matching organizations " ,
" We were unable to find any organizations matching this text. " ,
" OK "
) ;
return null ;
}
2019-07-08 15:03:11 +01:00
var optionsList = new List < String > ( ) ;
for ( var i = 0 ; i < organisations . length ; i + + ) {
optionsList . add ( organisations [ i ] . name ) ;
}
2019-07-15 14:48:41 +01:00
// var popupListView = new PopupListView(context, optionsList, "Choose Organization");
2019-07-08 15:03:11 +01:00
2019-07-15 14:48:41 +01:00
var popupListView = new PopupListView ( ) ;
var dialog = popupListView . dialog ( context , optionsList , " Choose Organization " ) ;
2019-07-08 15:03:11 +01:00
2019-07-15 14:48:41 +01:00
// dialog.then((value) => debugPrint(value));
2019-07-08 15:03:11 +01:00
2019-07-16 11:28:36 +01:00
dialog . then ( ( value ) {
_orgController . text = value ;
_organizationController . organisation = organisations . where ( ( thisOrg ) = > thisOrg . name = = value ) . elementAt ( 0 ) ;
// this may not work when two organisations have the same name,
// then again the popupListView can't display two of the same names properly either
} ) ;
2019-07-15 14:48:41 +01:00
//can't return value as it is <future> and thus would block
2019-07-08 15:03:11 +01:00
}
2019-07-16 12:54:55 +01:00
_findOrganizationsDialog ( context ) {
if ( _orgController . text ! = " " ) {
var organisations = findOrganisations (
_orgController . text ) ; // returns Future<List<Organisation>>
var choice = organisations . then ( ( data ) = >
listOrganisations ( data , context ) ) ;
choice . then ( ( value ) = > _orgController . text = value . name ) ;
choice . then ( ( value ) = > _organizationController . organisation = value ) ;
} else {
// no data entered
showDialogSingleButton (
context ,
" No data " ,
" We were unable to service your request because no data was entered. " ,
" OK "
) ;
}
}
2019-05-08 19:54:14 +01:00
@ override
Widget build ( BuildContext context ) {
2019-07-17 14:15:10 +01:00
var drawer = new AwesomeDrawer ( ) ;
2019-07-16 16:55:00 +01:00
return PlatformScaffold (
2019-07-17 14:15:10 +01:00
drawer: drawer . getDrawer ( context ) ,
2019-07-16 16:55:00 +01:00
appBar: AppBar (
2019-07-17 12:54:31 +01:00
automaticallyImplyLeading: ! Platform . isIOS , // done to remove UI glitch, now works on both platforms
// leading: Drawer(),
2019-07-16 16:55:00 +01:00
backgroundColor: Colors . blue [ 400 ] ,
title: Text (
" Submit Receipt " ,
style: TextStyle (
fontSize: 20 ,
color: Colors . white ,
2019-05-08 19:54:14 +01:00
) ,
) ,
2019-07-16 16:55:00 +01:00
centerTitle: true ,
2019-07-17 12:54:31 +01:00
// iconTheme: IconThemeData(color: Colors.black),
2019-07-16 16:55:00 +01:00
) ,
2019-07-15 12:09:10 +01:00
2019-07-16 16:55:00 +01:00
body: Container (
padding: EdgeInsets . fromLTRB ( 30.0 , 0.0 , 30.0 , 0.0 ) ,
child: ListView (
children: < Widget > [
Padding (
padding: EdgeInsets . fromLTRB ( 0.0 , 25 , 0.0 , 0.0 ) ,
child : Text (
" Time of Transaction " ,
style: TextStyle (
fontSize: 18.0 ,
color: Colors . black ,
fontWeight: FontWeight . bold ,
2019-05-08 19:54:14 +01:00
) ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
DateTimePickerFormField (
inputType: InputType . both ,
format: DateFormat ( " dd/MM/yyyy 'at' hh:mm " ) ,
editable: true ,
controller: _timeController ,
decoration: InputDecoration (
labelText: ' Date/Time of Transaction ' , hasFloatingPlaceholder: false ) ,
onChanged: ( dt ) = > setState ( ( ) = > date = dt ) ,
) ,
Padding (
padding: EdgeInsets . fromLTRB ( 0.0 , 25 , 0.0 , 0.0 ) ,
child: Text (
" Amount " ,
style: TextStyle (
fontSize: 18.0 ,
color: Colors . black ,
fontWeight: FontWeight . bold ,
2019-05-08 19:54:14 +01:00
) ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
Padding (
padding: EdgeInsets . fromLTRB ( 0.0 , 5.0 , 0.0 , 0.0 ) ,
child: TextField (
controller: _amountController ,
decoration: InputDecoration (
hintText: ' Value in £ ' ,
) ,
2019-07-05 13:39:24 +01:00
// obscureText: true,
2019-07-16 16:55:00 +01:00
autocorrect: false ,
keyboardType: TextInputType . number ,
style: TextStyle (
fontSize: 18.0 ,
color: Colors . grey [ 800 ] ,
fontWeight: FontWeight . bold ,
2019-07-05 22:56:15 +01:00
) ,
2019-07-16 16:55:00 +01:00
onSubmitted: ( _ ) {
FocusScope . of ( context ) . requestFocus ( focusNode ) ;
// submitReceipt(_amountController.text, _timeController.text);
} ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
2019-07-05 22:56:15 +01:00
2019-07-16 16:55:00 +01:00
Padding (
padding: EdgeInsets . fromLTRB ( 0.0 , 25 , 0.0 , 0.0 ) ,
2019-07-05 22:56:15 +01:00
2019-07-16 16:55:00 +01:00
child : Container (
height: 22 , // this should be the same height as text
2019-07-05 22:56:15 +01:00
2019-07-16 16:55:00 +01:00
child : ListView (
scrollDirection: Axis . horizontal ,
children: < Widget > [
2019-07-05 22:56:15 +01:00
2019-07-16 16:55:00 +01:00
Container (
child: Text (
" Organization Name " ,
style: TextStyle (
fontSize: 18.0 ,
color: Colors . black ,
fontWeight: FontWeight . bold ,
2019-07-05 22:56:15 +01:00
) ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
Container (
child : Padding (
padding: EdgeInsets . fromLTRB ( 5 , 0 , 0 , 4 ) , // sorry about hardcoded constraints
child: FlatButton (
onPressed: ( ) {
_findOrganizationsDialog ( context ) ;
} ,
child: Text ( " Find " ,
style: TextStyle ( color: Colors . blue , fontSize: 18.0 )
) ,
) ,
) ,
)
2019-07-15 12:09:10 +01:00
2019-07-16 16:55:00 +01:00
] ,
2019-07-05 22:56:15 +01:00
) ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
2019-07-05 22:56:15 +01:00
2019-07-16 16:55:00 +01:00
Padding (
padding: EdgeInsets . fromLTRB ( 0.0 , 5.0 , 0.0 , 0.0 ) ,
child: TextField (
controller: _orgController ,
focusNode: focusNode ,
decoration: InputDecoration (
hintText: ' Eg. Pear Trading ' ,
) ,
2019-07-05 22:56:15 +01:00
// obscureText: true,
2019-07-16 16:55:00 +01:00
autocorrect: true ,
style: TextStyle (
fontSize: 18.0 ,
color: Colors . grey [ 800 ] ,
fontWeight: FontWeight . bold ,
2019-05-08 19:54:14 +01:00
) ,
2019-07-16 16:55:00 +01:00
onSubmitted: ( _ ) {
submitReceipt ( _amountController . text ,
_timeController . text , _organizationController . organisation , _recurringController . text , _categoryController . text , _essentialController . text ) ;
} ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
2019-07-05 15:34:39 +01:00
2019-07-16 16:55:00 +01:00
Padding (
padding: EdgeInsets . fromLTRB ( 0.0 , 25 , 0.0 , 0.0 ) ,
2019-07-05 15:34:39 +01:00
2019-07-16 16:55:00 +01:00
child : Container (
height: 18 ,
2019-07-05 15:34:39 +01:00
2019-07-16 16:55:00 +01:00
child : ListView (
scrollDirection: Axis . horizontal ,
2019-07-05 15:34:39 +01:00
2019-07-16 16:55:00 +01:00
children: < Widget > [
Container (
child: Text (
" Essential " ,
style: TextStyle (
fontSize: 18.0 ,
color: Colors . black ,
2019-07-05 15:34:39 +01:00
) ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
Container (
child : Padding (
padding: EdgeInsets . fromLTRB ( 20.0 , 0.0 , 0 , 0 ) ,
child: Checkbox ( value:
_essentialController . text . toLowerCase ( ) = = ' true ' ,
onChanged: ( bool newValue ) {
setState ( ( ) {
_essentialController . text =
convertBoolToString ( newValue ) ;
} ) ;
} ) ,
) ,
) ,
2019-07-15 12:09:10 +01:00
2019-07-16 16:55:00 +01:00
] ,
) ,
) ,
) ,
2019-07-15 12:09:10 +01:00
2019-07-16 16:55:00 +01:00
Padding (
padding: EdgeInsets . fromLTRB ( 0.0 , 18 , 0.0 , 0.0 ) ,
child : Container (
height: 35 ,
// width: 400,
child : ListView (
scrollDirection: Axis . horizontal ,
children: < Widget > [
Container (
padding: const EdgeInsets . fromLTRB ( 0 , 7 , 0 , 8 ) ,
child: Text (
" Recurring " ,
style: TextStyle (
fontSize: 18.0 ,
color: Colors . black ,
2019-07-15 12:09:10 +01:00
) ,
) ,
2019-07-16 16:55:00 +01:00
) ,
Container (
padding: const EdgeInsets . fromLTRB ( 29 , 0 , 0 , 0 ) ,
child: DropdownButton < String > (
value: _recurringController . text ,
onChanged: ( String newValue ) {
setState ( ( ) {
_recurringController . text = newValue ;
} ) ;
} ,
items: getRecurringOptions ( ) . map < DropdownMenuItem < String > > ( ( String value ) {
return DropdownMenuItem < String > (
value: value ,
child: Text ( value ) ,
) ;
} )
. toList ( ) ,
)
) ,
] ,
2019-07-15 12:09:10 +01:00
) ,
) ,
2019-07-16 16:55:00 +01:00
) ,
2019-07-15 12:09:10 +01:00
2019-07-16 16:55:00 +01:00
Padding (
padding: EdgeInsets . fromLTRB ( 0.0 , 18 , 0.0 , 0.0 ) ,
2019-07-15 12:09:10 +01:00
2019-07-16 16:55:00 +01:00
child : Container (
height: 35 ,
2019-07-15 12:09:10 +01:00
// width: 400,
2019-07-05 15:34:39 +01:00
2019-07-16 16:55:00 +01:00
child : ListView (
scrollDirection: Axis . horizontal ,
children: < Widget > [
Container (
padding: const EdgeInsets . fromLTRB ( 0 , 7 , 0 , 8 ) ,
child: Text (
" Category " ,
style: TextStyle (
fontSize: 18.0 ,
color: Colors . black ,
2019-07-05 15:34:39 +01:00
) ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
2019-07-15 12:09:10 +01:00
2019-07-17 12:54:31 +01:00
// Container(
// padding: const EdgeInsets.fromLTRB(29, 0, 0, 0),
// child: DropdownButton<String>(
// value: _categoryController.text,
// onChanged: (String newValue) {
// setState(() {
// _categoryController.text = newValue;
// });
// },
// items: _categoryDropDownItems.map<DropdownMenuItem<String>>((String value) {
// return DropdownMenuItem<String>(
// value: value,
// child: Text(value),
// );
// }).toList(),
// )
// ),
2019-07-16 16:55:00 +01:00
] ,
2019-07-05 15:34:39 +01:00
) ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
2019-07-05 15:34:39 +01:00
2019-07-16 16:55:00 +01:00
Padding (
2019-07-17 12:31:28 +01:00
padding: EdgeInsets . fromLTRB ( 0.0 , 20.0 , 0.0 , 0.0 ) ,
2019-07-16 16:55:00 +01:00
child: Container (
height: 65.0 ,
child: RaisedButton (
onPressed: ( ) {
try {
submitReceipt (
_amountController . text , _timeController . text ,
_organizationController . organisation , _recurringController . text , _categoryController . text , _essentialController . text ) ;
}
catch ( _ ) {
showDialog (
context: context ,
builder: ( BuildContext context ) {
// return object of type Dialog
return AlertDialog (
title: new Text ( " Invalid data " ) ,
content: new Text (
" We couldn't process your request because some of the data entered is invalid. " ) ,
actions: < Widget > [
new FlatButton (
child: new Text ( " OK " ) ,
onPressed: ( ) {
Navigator . of ( context ) . pop ( ) ;
} ,
) ,
] ,
) ;
} ,
) ;
}
} ,
child: Text ( " GO " ,
style:
TextStyle ( color: Colors . white , fontSize: 22.0 ) ) ,
color: Colors . blue ,
2019-05-08 19:54:14 +01:00
) ,
2019-07-15 12:09:10 +01:00
) ,
2019-07-16 16:55:00 +01:00
) ,
] ,
2019-05-08 19:54:14 +01:00
) ,
) ,
) ;
}
}