Merge branch 'staging' into trocador

This commit is contained in:
julian 2023-05-03 16:11:14 -06:00
commit 032748fdfe
9 changed files with 561 additions and 57 deletions

View file

@ -9,7 +9,6 @@ import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/biometrics.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -139,6 +138,8 @@ class _CreatePinViewState extends ConsumerState<CreatePinView> {
.background,
counterText: "",
),
isRandom:
ref.read(prefsChangeNotifierProvider).randomizePIN,
submittedFieldDecoration: _pinPutDecoration.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
@ -221,6 +222,8 @@ class _CreatePinViewState extends ConsumerState<CreatePinView> {
),
selectedFieldDecoration: _pinPutDecoration,
followingFieldDecoration: _pinPutDecoration,
isRandom:
ref.read(prefsChangeNotifierProvider).randomizePIN,
onSubmit: (String pin) async {
// _onSubmitCount++;
// if (_onSubmitCount - _onSubmitFailCount > 1) return;

View file

@ -1,5 +1,4 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@ -21,8 +20,8 @@ import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/background.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
import 'package:stackwallet/widgets/custom_pin_put/custom_pin_put.dart';
import 'package:stackwallet/widgets/custom_pin_put/pin_keyboard.dart';
import 'package:stackwallet/widgets/shake/shake.dart';
import 'package:tuple/tuple.dart';
@ -93,7 +92,7 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
final manager =
ref.read(walletsChangeNotifierProvider).getManager(walletId);
if (manager.coin == Coin.monero || manager.coin == Coin.wownero) {
if (manager.coin == Coin.monero) {
await showLoading(
opaqueBG: true,
whileFuture: manager.initializeExisting(),
@ -229,6 +228,26 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// check prefs and hide if user has biometrics toggle off?
Padding(
padding: const EdgeInsets.only(right: 40.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (ref.read(prefsChangeNotifierProvider).useBiometrics ==
true)
CustomTextButton(
text: "Use biometrics",
onTap: () async {
await _checkUseBiometrics();
},
),
],
),
),
const SizedBox(
height: 55,
),
Shake(
animationDuration: const Duration(milliseconds: 700),
animationRange: 12,
@ -247,16 +266,12 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
height: 52,
),
CustomPinPut(
customKey: CustomKey(
semanticsLabel: Platform.isIOS
? "Face ID Button. Checks Face ID."
: "Fingerprint Button. Checks Fingerprint."
,
onPressed: _checkUseBiometrics,
iconAssetName: Platform.isIOS
? Assets.svg.faceId
: Assets.svg.fingerprint,
),
// customKey: CustomKey(
// onPressed: _checkUseBiometrics,
// iconAssetName: Platform.isIOS
// ? Assets.svg.faceId
// : Assets.svg.fingerprint,
// ),
fieldsCount: Constants.pinLength,
eachFieldHeight: 12,
eachFieldWidth: 12,
@ -292,6 +307,9 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
),
selectedFieldDecoration: _pinPutDecoration,
followingFieldDecoration: _pinPutDecoration,
isRandom: ref
.read(prefsChangeNotifierProvider)
.randomizePIN,
onSubmit: (String pin) async {
_attempts++;

View file

@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/security_views/security_view.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/providers/global/secure_store_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
@ -123,6 +123,8 @@ class _ChangePinViewState extends ConsumerState<ChangePinView> {
.background,
counterText: "",
),
isRandom:
ref.read(prefsChangeNotifierProvider).randomizePIN,
submittedFieldDecoration: _pinPutDecoration.copyWith(
color: Theme.of(context)
.extension<StackColors>()!
@ -188,6 +190,8 @@ class _ChangePinViewState extends ConsumerState<ChangePinView> {
.background,
counterText: "",
),
isRandom:
ref.read(prefsChangeNotifierProvider).randomizePIN,
submittedFieldDecoration: _pinPutDecoration.copyWith(
color: Theme.of(context)
.extension<StackColors>()!

View file

@ -146,6 +146,53 @@ class SecurityView extends StatelessWidget {
},
),
),
const SizedBox(
height: 8,
),
RoundedWhiteContainer(
child: Consumer(
builder: (_, ref, __) {
return RawMaterialButton(
// splashColor: Theme.of(context).extension<StackColors>()!.highlight,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: null,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Randomize PIN Pad",
style: STextStyles.titleBold12(context),
textAlign: TextAlign.left,
),
SizedBox(
height: 20,
width: 40,
child: DraggableSwitchButton(
isOn: ref.watch(
prefsChangeNotifierProvider
.select((value) => value.randomizePIN),
),
onValueChanged: (newValue) {
ref
.read(prefsChangeNotifierProvider)
.randomizePIN = newValue;
},
),
),
],
),
),
);
},
),
),
],
),
),

View file

@ -19,6 +19,7 @@ class Prefs extends ChangeNotifier {
if (!_initialized) {
_currency = await _getPreferredCurrency();
// _exchangeRateType = await _getExchangeRateType();
_randomizePIN = await _getRandomizePIN();
_useBiometrics = await _getUseBiometrics();
_hasPin = await _getHasPin();
_language = await _getPreferredLanguage();
@ -295,6 +296,27 @@ class Prefs extends ChangeNotifier {
// }
// }
// randomize PIN
bool _randomizePIN = false;
bool get randomizePIN => _randomizePIN;
set randomizePIN(bool randomizePIN) {
if (_randomizePIN != randomizePIN) {
DB.instance.put<dynamic>(
boxName: DB.boxNamePrefs, key: "randomizePIN", value: randomizePIN);
_randomizePIN = randomizePIN;
notifyListeners();
}
}
Future<bool> _getRandomizePIN() async {
return await DB.instance.get<dynamic>(
boxName: DB.boxNamePrefs, key: "randomizePIN") as bool? ??
false;
}
// use biometrics
bool _useBiometrics = false;

View file

@ -7,6 +7,7 @@ class CustomPinPut extends StatefulWidget {
const CustomPinPut({
Key? key,
required this.fieldsCount,
required this.isRandom,
this.height,
this.width,
this.onSubmit,
@ -60,6 +61,8 @@ class CustomPinPut extends StatefulWidget {
final CustomKey? customKey;
final bool isRandom;
/// Displayed fields count. PIN code length.
final int fieldsCount;

View file

@ -32,9 +32,9 @@ class CustomPinPutState extends State<CustomPinPut>
} catch (e) {
_textControllerValue = ValueNotifier(_controller.value.text);
}
if (pin.length == widget.fieldsCount) {
widget.onSubmit?.call(pin);
}
// if (pin.length == widget.fieldsCount) {
// widget.onSubmit?.call(pin);
// }
}
}
@ -50,6 +50,9 @@ class CustomPinPutState extends State<CustomPinPut>
@override
Widget build(BuildContext context) {
// final bool randomize = ref
// .read(prefsChangeNotifierProvider)
// .randomizePIN;
return SizedBox(
width: widget.width,
height: widget.height,
@ -69,6 +72,7 @@ class CustomPinPutState extends State<CustomPinPut>
),
Center(
child: PinKeyboard(
isRandom: widget.isRandom,
customKey: widget.customKey,
onNumberKeyPressed: (number) {
if (_controller.text.length < widget.fieldsCount) {

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
@ -247,8 +248,169 @@ class CustomKey extends StatelessWidget {
}
}
class PinKeyboard extends StatelessWidget {
class PinKeyboard extends ConsumerWidget {
const PinKeyboard({
Key? key,
required this.onNumberKeyPressed,
required this.onBackPressed,
required this.onSubmitPressed,
required this.isRandom,
this.backgroundColor,
this.width = 264,
this.height = 360,
this.customKey,
}) : super(key: key);
final ValueSetter<String> onNumberKeyPressed;
final VoidCallback onBackPressed;
final VoidCallback onSubmitPressed;
final Color? backgroundColor;
final double? width;
final double? height;
final CustomKey? customKey;
final bool isRandom;
void _backHandler() {
onBackPressed.call();
}
void _submitHandler() {
onSubmitPressed.call();
}
void _numberHandler(String number) {
onNumberKeyPressed.call(number);
HapticFeedback.lightImpact();
}
@override
Widget build(BuildContext context, WidgetRef ref) {
final list = [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
];
// final isRandom = ref.read(prefsChangeNotifierProvider).randomizePIN;
if (isRandom) list.shuffle();
return Container(
width: width,
height: height,
color: backgroundColor ?? Colors.transparent,
child: Column(
children: [
Row(
children: [
NumberKey(
number: list[0],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: list[1],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: list[2],
onPressed: _numberHandler,
),
],
),
const SizedBox(
height: 24,
),
Row(
children: [
NumberKey(
number: list[3],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: list[4],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: list[5],
onPressed: _numberHandler,
),
],
),
const SizedBox(
height: 24,
),
Row(
children: [
NumberKey(
number: list[6],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: list[7],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: list[8],
onPressed: _numberHandler,
),
],
),
const SizedBox(
height: 24,
),
Row(
children: [
BackspaceKey(
onPressed: _backHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: list[9],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
SubmitKey(
onPressed: _submitHandler,
),
],
)
],
),
);
}
}
class RandomKeyboard extends StatelessWidget {
const RandomKeyboard({
Key? key,
required this.onNumberKeyPressed,
required this.onBackPressed,
@ -278,10 +440,24 @@ class PinKeyboard extends StatelessWidget {
void _numberHandler(String number) {
onNumberKeyPressed.call(number);
HapticFeedback.lightImpact();
debugPrint("NUMBER: $number");
}
@override
Widget build(BuildContext context) {
final list = [
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0",
];
list.shuffle();
return Container(
width: width,
height: height,
@ -291,21 +467,21 @@ class PinKeyboard extends StatelessWidget {
Row(
children: [
NumberKey(
number: "1",
number: list[0],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: "2",
number: list[1],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: "3",
number: list[2],
onPressed: _numberHandler,
),
],
@ -316,21 +492,21 @@ class PinKeyboard extends StatelessWidget {
Row(
children: [
NumberKey(
number: "4",
number: list[3],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: "5",
number: list[4],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: "6",
number: list[5],
onPressed: _numberHandler,
),
],
@ -341,21 +517,21 @@ class PinKeyboard extends StatelessWidget {
Row(
children: [
NumberKey(
number: "7",
number: list[6],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: "8",
number: list[7],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
NumberKey(
number: "9",
number: list[8],
onPressed: _numberHandler,
),
],
@ -365,28 +541,22 @@ class PinKeyboard extends StatelessWidget {
),
Row(
children: [
customKey == null
? const SizedBox(
height: 72,
width: 72,
)
: customKey!,
const SizedBox(
width: 24,
),
NumberKey(
number: "0",
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
BackspaceKey(
onPressed: _backHandler,
),
// SubmitKey(
// onPressed: _submitHandler,
// ),
const SizedBox(
width: 24,
),
NumberKey(
number: list[9],
onPressed: _numberHandler,
),
const SizedBox(
width: 24,
),
SubmitKey(
onPressed: _submitHandler,
),
],
)
],

View file

@ -7,9 +7,13 @@ import 'package:stackwallet/widgets/custom_pin_put/custom_pin_put.dart';
import 'package:stackwallet/widgets/custom_pin_put/pin_keyboard.dart';
void main() {
group("CustomPinPut tests", () {
testWidgets("CustomPinPut with 4 fields builds correctly", (tester) async {
const pinPut = CustomPinPut(fieldsCount: 4);
group("CustomPinPut tests, non-random PIN", () {
testWidgets("CustomPinPut with 4 fields builds correctly, non-random PIN",
(tester) async {
const pinPut = CustomPinPut(
fieldsCount: 4,
isRandom: false,
);
await tester.pumpWidget(
MaterialApp(
@ -31,12 +35,17 @@ void main() {
expect(find.byType(NumberKey), findsNWidgets(10));
});
testWidgets("CustomPinPut entering a pin successfully", (tester) async {
testWidgets("CustomPinPut entering a pin successfully, non-random PIN",
(tester) async {
bool submittedPinMatches = false;
final pinPut = CustomPinPut(
fieldsCount: 4,
onSubmit: (pin) => submittedPinMatches = pin == "1234",
onSubmit: (pin) {
submittedPinMatches = pin == "1234";
print("pin entered: $pin");
},
useNativeKeyboard: false,
isRandom: false,
);
await tester.pumpWidget(
@ -69,16 +78,20 @@ void main() {
await tester.tap(find.byWidgetPredicate(
(widget) => widget is NumberKey && widget.number == "4"));
await tester.pumpAndSettle();
await tester.tap(find.byType(SubmitKey));
await tester.pumpAndSettle();
expect(submittedPinMatches, true);
});
testWidgets("CustomPinPut pin enter fade animation", (tester) async {
testWidgets("CustomPinPut pin enter fade animation, non-random PIN",
(tester) async {
final controller = TextEditingController();
final pinPut = CustomPinPut(
fieldsCount: 4,
pinAnimationType: PinAnimationType.fade,
controller: controller,
isRandom: false,
);
await tester.pumpWidget(
@ -104,12 +117,14 @@ void main() {
expect(controller.text, "");
});
testWidgets("CustomPinPut pin enter scale animation", (tester) async {
testWidgets("CustomPinPut pin enter scale animation, non-random PIN",
(tester) async {
final controller = TextEditingController();
final pinPut = CustomPinPut(
fieldsCount: 4,
pinAnimationType: PinAnimationType.scale,
controller: controller,
isRandom: false,
);
await tester.pumpWidget(
@ -135,12 +150,14 @@ void main() {
expect(controller.text, "");
});
testWidgets("CustomPinPut pin enter rotate animation", (tester) async {
testWidgets("CustomPinPut pin enter rotate animation, non-random PIN",
(tester) async {
final controller = TextEditingController();
final pinPut = CustomPinPut(
fieldsCount: 4,
pinAnimationType: PinAnimationType.rotation,
controller: controller,
isRandom: false,
);
await tester.pumpWidget(
@ -167,11 +184,12 @@ void main() {
});
});
testWidgets("PinKeyboard builds correctly", (tester) async {
testWidgets("PinKeyboard builds correctly, non-random PIN", (tester) async {
final keyboard = PinKeyboard(
onNumberKeyPressed: (_) {},
onBackPressed: () {},
onSubmitPressed: () {},
isRandom: false,
);
await tester.pumpWidget(
@ -188,6 +206,7 @@ void main() {
);
expect(find.byType(BackspaceKey), findsOneWidget);
expect(find.byType(SubmitKey), findsOneWidget);
expect(find.byType(NumberKey), findsNWidgets(10));
expect(find.text("0"), findsOneWidget);
expect(find.text("1"), findsOneWidget);
@ -199,6 +218,220 @@ void main() {
expect(find.text("7"), findsOneWidget);
expect(find.text("8"), findsOneWidget);
expect(find.text("9"), findsOneWidget);
expect(find.byType(SvgPicture), findsOneWidget);
expect(find.byType(SvgPicture), findsNWidgets(2));
});
group("CustomPinPut tests, with random PIN", () {
testWidgets("CustomPinPut with 4 fields builds correctly, with random PIN",
(tester) async {
const pinPut = CustomPinPut(
fieldsCount: 4,
isRandom: true,
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
extensions: [
StackColors.fromStackColorTheme(LightColors()),
],
),
home: const Material(
child: pinPut,
),
),
);
// expects 5 here. Four + the actual text field text
expect(find.text(""), findsNWidgets(5));
expect(find.byType(PinKeyboard), findsOneWidget);
expect(find.byType(BackspaceKey), findsOneWidget);
expect(find.byType(NumberKey), findsNWidgets(10));
});
testWidgets("CustomPinPut entering a pin successfully, with random PIN",
(tester) async {
bool submittedPinMatches = false;
final pinPut = CustomPinPut(
fieldsCount: 4,
onSubmit: (pin) {
submittedPinMatches = pin == "1234";
print("pin entered: $pin");
},
useNativeKeyboard: false,
isRandom: true,
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
extensions: [
StackColors.fromStackColorTheme(LightColors()),
],
),
home: Material(
child: pinPut,
),
),
);
await tester.tap(find.byWidgetPredicate(
(widget) => widget is NumberKey && widget.number == "1"));
await tester.pumpAndSettle();
await tester.tap(find.byWidgetPredicate(
(widget) => widget is NumberKey && widget.number == "2"));
await tester.pumpAndSettle();
await tester.tap(find.byWidgetPredicate(
(widget) => widget is NumberKey && widget.number == "6"));
await tester.pumpAndSettle();
await tester.tap(find.byType(BackspaceKey));
await tester.pumpAndSettle();
await tester.tap(find.byWidgetPredicate(
(widget) => widget is NumberKey && widget.number == "3"));
await tester.pumpAndSettle();
await tester.tap(find.byWidgetPredicate(
(widget) => widget is NumberKey && widget.number == "4"));
await tester.pumpAndSettle();
await tester.tap(find.byType(SubmitKey));
await tester.pumpAndSettle();
expect(submittedPinMatches, true);
});
testWidgets("CustomPinPut pin enter fade animation, with random PIN",
(tester) async {
final controller = TextEditingController();
final pinPut = CustomPinPut(
fieldsCount: 4,
pinAnimationType: PinAnimationType.fade,
controller: controller,
isRandom: true,
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
extensions: [
StackColors.fromStackColorTheme(LightColors()),
],
),
home: Material(
child: pinPut,
),
),
);
await tester.tap(find.byWidgetPredicate(
(widget) => widget is NumberKey && widget.number == "1"));
await tester.pumpAndSettle();
expect(controller.text, "1");
await tester.tap(find.byType(BackspaceKey));
await tester.pumpAndSettle();
expect(controller.text, "");
});
testWidgets("CustomPinPut pin enter scale animation, with random PIN",
(tester) async {
final controller = TextEditingController();
final pinPut = CustomPinPut(
fieldsCount: 4,
pinAnimationType: PinAnimationType.scale,
controller: controller,
isRandom: true,
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
extensions: [
StackColors.fromStackColorTheme(LightColors()),
],
),
home: Material(
child: pinPut,
),
),
);
await tester.tap(find.byWidgetPredicate(
(widget) => widget is NumberKey && widget.number == "1"));
await tester.pumpAndSettle();
expect(controller.text, "1");
await tester.tap(find.byType(BackspaceKey));
await tester.pumpAndSettle();
expect(controller.text, "");
});
testWidgets("CustomPinPut pin enter rotate animation, with random PIN",
(tester) async {
final controller = TextEditingController();
final pinPut = CustomPinPut(
fieldsCount: 4,
pinAnimationType: PinAnimationType.rotation,
controller: controller,
isRandom: true,
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
extensions: [
StackColors.fromStackColorTheme(LightColors()),
],
),
home: Material(
child: pinPut,
),
),
);
await tester.tap(find.byWidgetPredicate(
(widget) => widget is NumberKey && widget.number == "1"));
await tester.pumpAndSettle();
expect(controller.text, "1");
await tester.tap(find.byType(BackspaceKey));
await tester.pumpAndSettle();
expect(controller.text, "");
});
});
testWidgets("PinKeyboard builds correctly, with random PIN", (tester) async {
final keyboard = PinKeyboard(
onNumberKeyPressed: (_) {},
onBackPressed: () {},
onSubmitPressed: () {},
isRandom: true,
);
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(
extensions: [
StackColors.fromStackColorTheme(LightColors()),
],
),
home: Material(
child: keyboard,
),
),
);
expect(find.byType(BackspaceKey), findsOneWidget);
expect(find.byType(SubmitKey), findsOneWidget);
expect(find.byType(NumberKey), findsNWidgets(10));
expect(find.text("0"), findsOneWidget);
expect(find.text("1"), findsOneWidget);
expect(find.text("2"), findsOneWidget);
expect(find.text("3"), findsOneWidget);
expect(find.text("4"), findsOneWidget);
expect(find.text("5"), findsOneWidget);
expect(find.text("6"), findsOneWidget);
expect(find.text("7"), findsOneWidget);
expect(find.text("8"), findsOneWidget);
expect(find.text("9"), findsOneWidget);
expect(find.byType(SvgPicture), findsNWidgets(2));
});
}