Загрузка данных
import 'dart:async';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const YaxxApp());
}
const purple = Color(0xFF8255FF);
const cyan = Color(0xFF42D9FF);
const darkBg = Color(0xFF090817);
class YaxxApp extends StatefulWidget {
const YaxxApp({super.key});
@override
State<YaxxApp> createState() => _YaxxAppState();
}
class _YaxxAppState extends State<YaxxApp> {
ThemeMode _themeMode = ThemeMode.dark;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'YAXX VPN',
debugShowCheckedModeBanner: false,
themeMode: _themeMode,
theme: ThemeData(
brightness: Brightness.light,
scaffoldBackgroundColor: const Color(0xFFF7F5FF),
colorScheme: ColorScheme.fromSeed(
seedColor: purple,
brightness: Brightness.light,
),
useMaterial3: true,
),
darkTheme: ThemeData(
brightness: Brightness.dark,
scaffoldBackgroundColor: darkBg,
colorScheme: ColorScheme.fromSeed(
seedColor: purple,
brightness: Brightness.dark,
),
useMaterial3: true,
),
home: YaxxHome(
onThemeChanged: (isDark) {
setState(() {
_themeMode = isDark ? ThemeMode.dark : ThemeMode.light;
});
},
isDark: _themeMode == ThemeMode.dark,
),
);
}
}
class YaxxHome extends StatefulWidget {
final ValueChanged<bool> onThemeChanged;
final bool isDark;
const YaxxHome({
super.key,
required this.onThemeChanged,
required this.isDark,
});
@override
State<YaxxHome> createState() => _YaxxHomeState();
}
class _YaxxHomeState extends State<YaxxHome>
with TickerProviderStateMixin {
late final AnimationController _animation;
late final AnimationController _pulse;
Timer? _timer;
bool _loading = true;
bool _connected = false;
bool _busy = false;
bool _autoConnect = false;
bool _notifications = true;
bool _protection = true;
String _key = '';
String _language = 'Русский';
int _seconds = 0;
int _tab = 0;
final _keyController = TextEditingController();
bool get _isDark => widget.isDark;
Color get _textColor =>
_isDark ? Colors.white : const Color(0xFF201A35);
Color get _mutedColor =>
_isDark ? Colors.white54 : const Color(0xFF77718D);
@override
void initState() {
super.initState();
_animation = AnimationController(
vsync: this,
duration: const Duration(seconds: 12),
)..repeat();
_pulse = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1800),
lowerBound: 0.0,
upperBound: 1.0,
)..repeat(reverse: true);
_loadSettings();
}
Future<void> _loadSettings() async {
final prefs = await SharedPreferences.getInstance();
if (!mounted) return;
setState(() {
_key = prefs.getString('vpn_key') ?? '';
_autoConnect = prefs.getBool('auto_connect') ?? false;
_notifications = prefs.getBool('notifications') ?? true;
_protection = prefs.getBool('protection') ?? true;
_language = prefs.getString('language') ?? 'Русский';
_loading = false;
});
}
Future<void> _saveBool(String name, bool value) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(name, value);
}
String _tr(String ru, String en) =>
_language == 'English' ? en : ru;
Future<void> _saveKey(String value) async {
final input = value.trim();
if (input.isNotEmpty &&
!input.startsWith('vless://') &&
!input.startsWith('vmess://')) {
_message('Поддерживаются ссылки VLESS и VMess');
return;
}
final prefs = await SharedPreferences.getInstance();
await prefs.setString('vpn_key', input);
if (!mounted) return;
setState(() {
_key = input;
_connected = false;
_seconds = 0;
});
_stopTimer();
_keyController.clear();
_message(
input.isEmpty
? 'Ключ удалён'
: 'Ключ сохранён локально. Это тестовый режим.',
);
}
void _toggleConnection() {
if (_key.isEmpty) {
_showKeyDialog();
return;
}
setState(() {
_connected = !_connected;
_seconds = 0;
});
if (_connected) {
_startTimer();
_message('Тестовый режим: реального VPN-соединения нет');
} else {
_stopTimer();
_message('Тестовое подключение остановлено');
}
}
void _startTimer() {
_stopTimer();
_timer = Timer.periodic(
const Duration(seconds: 1),
(_) {
if (mounted && _connected) {
setState(() => _seconds++);
}
},
);
}
void _stopTimer() {
_timer?.cancel();
_timer = null;
}
String get _duration {
final h = (_seconds ~/ 3600).toString().padLeft(2, '0');
final m = ((_seconds % 3600) ~/ 60).toString().padLeft(2, '0');
final s = (_seconds % 60).toString().padLeft(2, '0');
return '$h:$m:$s';
}
void _message(String text) {
if (!mounted) return;
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(
SnackBar(
content: Text(text),
behavior: SnackBarBehavior.floating,
backgroundColor: const Color(0xFF282044),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
),
);
}
Future<void> _pasteKey() async {
final data = await Clipboard.getData('text/plain');
if (!mounted) return;
if (data?.text == null || data!.text!.trim().isEmpty) {
_message('Буфер обмена пуст');
return;
}
_keyController.text = data.text!.trim();
_showKeyDialog();
}
void _showKeyDialog() {
_keyController.text = _key;
showDialog<void>(
context: context,
builder: (dialogContext) => AlertDialog(
title: Text(_tr('VPN-ключ', 'VPN key')),
content: TextField(
controller: _keyController,
maxLines: 4,
minLines: 2,
style: TextStyle(color: _textColor),
decoration: InputDecoration(
hintText: 'vless://...',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(14),
),
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext),
child: Text(_tr('Отмена', 'Cancel')),
),
FilledButton(
onPressed: () {
final value = _keyController.text;
Navigator.pop(dialogContext);
_saveKey(value);
},
child: Text(_tr('Сохранить', 'Save')),
),
],
),
);
}
Future<void> _resetKey() async {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('vpn_key');
_stopTimer();
if (!mounted) return;
setState(() {
_key = '';
_connected = false;
_seconds = 0;
});
if (mounted) Navigator.pop(context);
}
void _openSettings() {
showModalBottomSheet<void>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (sheetContext) {
return StatefulBuilder(
builder: (context, updateSheet) {
return Container(
padding: const EdgeInsets.fromLTRB(22, 12, 22, 28),
decoration: BoxDecoration(
color: _isDark
? const Color(0xFF171329)
: Colors.white,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(30),
),
border: Border.all(
color: _isDark
? Colors.white12
: Colors.black12,
),
),
child: SafeArea(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 42,
height: 4,
decoration: BoxDecoration(
color: _mutedColor.withOpacity(0.4),
borderRadius: BorderRadius.circular(8),
),
),
const SizedBox(height: 24),
Row(
children: [
const Icon(
Icons.settings_rounded,
color: purple,
),
const SizedBox(width: 12),
Text(
_tr('Настройки', 'Settings'),
style: TextStyle(
color: _textColor,
fontSize: 23,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 24),
_sectionTitle(
_tr('Интерфейс', 'Interface'),
),
ListTile(
contentPadding: EdgeInsets.zero,
leading: const Icon(
Icons.language_rounded,
color: purple,
),
title: Text(
_tr('Язык приложения', 'App language'),
),
trailing: DropdownButton<String>(
value: _language,
underline: const SizedBox.shrink(),
items: const [
DropdownMenuItem(
value: 'Русский',
child: Text('Русский'),
),
DropdownMenuItem(
value: 'English',
child: Text('English'),
),
],
onChanged: (value) async {
if (value == null) return;
setState(() => _language = value);
updateSheet(() {});
final prefs =
await SharedPreferences.getInstance();
await prefs.setString('language', value);
},
),
),
SwitchListTile(
contentPadding: EdgeInsets.zero,
secondary: Icon(
_isDark
? Icons.dark_mode_rounded
: Icons.light_mode_rounded,
color: purple,
),
title: Text(
_tr('Тёмная тема', 'Dark theme'),
),
value: _isDark,
activeThumbColor: purple,
onChanged: (value) {
widget.onThemeChanged(value);
updateSheet(() {});
},
),
const SizedBox(height: 16),
_sectionTitle(
_tr('Подключение', 'Connection'),
),
SwitchListTile(
contentPadding: EdgeInsets.zero,
secondary: const Icon(
Icons.bolt_rounded,
color: purple,
),
title: Text(
_tr('Автоподключение', 'Auto-connect'),
),
subtitle: Text(
_tr(
'Настройка для будущего VPN',
'For future VPN integration',
),
style: TextStyle(color: _mutedColor),
),
value: _autoConnect,
activeThumbColor: purple,
onChanged: (value) {
setState(() => _autoConnect = value);
updateSheet(() {});
_saveBool('auto_connect', value);
},
),
SwitchListTile(
contentPadding: EdgeInsets.zero,
secondary: const Icon(
Icons.shield_rounded,
color: purple,
),
title: Text(
_tr('Защита', 'Protection'),
),
value: _protection,
activeThumbColor: purple,
onChanged: (value) {
setState(() => _protection = value);
updateSheet(() {});
_saveBool('protection', value);
},
),
SwitchListTile(
contentPadding: EdgeInsets.zero,
secondary: const Icon(
Icons.notifications_rounded,
color: purple,
),
title: Text(
_tr('Уведомления', 'Notifications'),
),
value: _notifications,
activeThumbColor: purple,
onChanged: (value) {
setState(() => _notifications = value);
updateSheet(() {});
_saveBool('notifications', value);
},
),
const SizedBox(height: 18),
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
onPressed: _resetKey,
icon: const Icon(
Icons.delete_outline_rounded,
),
label: Text(
_tr('Сбросить VPN-ключ', 'Reset VPN key'),
),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.redAccent,
padding: const EdgeInsets.all(15),
),
),
),
const SizedBox(height: 10),
Text(
'YAXX VPN • TEST BUILD',
style: TextStyle(
color: _mutedColor,
letterSpacing: 2,
fontSize: 10,
),
),
],
),
),
),
);
},
);
},
);
}
Widget _sectionTitle(String text) {
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.only(bottom: 8, top: 8),
child: Text(
text,
style: const TextStyle(
color: purple,
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
),
);
}
Widget _glassCard({
required Widget child,
EdgeInsets padding = const EdgeInsets.all(18),
}) {
return ClipRRect(
borderRadius: BorderRadius.circular(24),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 12, sigmaY: 12),
child: Container(
width: double.infinity,
padding: padding,
decoration: BoxDecoration(
color: _isDark
? Colors.white.withOpacity(0.055)
: Colors.white.withOpacity(0.8),
borderRadius: BorderRadius.circular(24),
border: Border.all(
color: _isDark
? Colors.white.withOpacity(0.09)
: purple.withOpacity(0.12),
),
),
child: child,
),
),
);
}
Widget _powerButton() {
return AnimatedBuilder(
animation: Listenable.merge([_animation, _pulse]),
builder: (context, child) {
final t = _animation.value;
final glow = 0.12 + _pulse.value * 0.16;
return Transform.translate(
offset: Offset(0, -2 + _pulse.value * 4),
child: GestureDetector(
onTap: _toggleConnection,
child: Container(
width: 226,
height: 226,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: SweepGradient(
transform: GradientRotation(t * 6.28318),
colors: const [
purple,
cyan,
Color(0xFF4030A8),
purple,
],
),
boxShadow: [
BoxShadow(
color: purple.withOpacity(glow),
blurRadius: 45,
spreadRadius: 6,
),
BoxShadow(
color: cyan.withOpacity(glow * 0.6),
blurRadius: 65,
spreadRadius: 2,
),
],
),
padding: const EdgeInsets.all(5),
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _isDark
? const Color(0xFF111027)
: const Color(0xFFF7F5FF),
),
padding: const EdgeInsets.all(10),
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment(-1 + 2 * t, -1),
end: Alignment(1 - 2 * t, 1),
colors: _connected
? const [
Color(0xFF4933A8),
Color(0xFF177C9B),
]
: const [
Color(0xFF29205D),
Color(0xFF39247C),
Color(0xFF242A64),
],
),
),
child: Icon(
_connected
? Icons.check_rounded
: Icons.power_settings_new_rounded,
color: Colors.white,
size: 72,
),
),
),
),
),
);
},
);
}
Widget _subscriptionCard() {
return _glassCard(
child: Column(
children: [
Row(
children: [
Container(
width: 44,
height: 44,
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [purple, cyan],
),
borderRadius: BorderRadius.circular(15),
),
child: const Icon(
Icons.shield_rounded,
color: Colors.white,
size: 26,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'YAXX VPN',
style: TextStyle(
color: _textColor,
fontSize: 17,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
_key.isEmpty
? _tr(
'Подписка не добавлена',
'No subscription added',
)
: _tr(
'Тестовая подписка',
'Test subscription',
),
style: TextStyle(
color: _mutedColor,
fontSize: 12,
),
),
],
),
),
IconButton(
tooltip: 'Добавить ключ',
onPressed: _showKeyDialog,
icon: const Icon(
Icons.add_circle_outline_rounded,
color: purple,
size: 28,
),
),
],
),
const SizedBox(height: 18),
Row(
children: [
const Icon(
Icons.info_outline_rounded,
color: cyan,
size: 19,
),
const SizedBox(width: 8),
Expanded(
child: Text(
_tr(
'Тестовый режим интерфейса',
'Interface test mode',
),
style: TextStyle(
color: _mutedColor,
fontSize: 12,
),
),
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
decoration: BoxDecoration(
color: purple.withOpacity(0.15),
borderRadius: BorderRadius.circular(20),
),
child: const Text(
'BETA',
style: TextStyle(
color: purple,
fontWeight: FontWeight.bold,
fontSize: 10,
),
),
),
],
),
const SizedBox(height: 14),
ClipRRect(
borderRadius: BorderRadius.circular(20),
child: LinearProgressIndicator(
value: _connected ? 1 : 0.04,
minHeight: 4,
backgroundColor: _mutedColor.withOpacity(0.15),
valueColor: const AlwaysStoppedAnimation(cyan),
),
),
],
),
);
}
Widget _actionButton({
required IconData icon,
required String title,
required VoidCallback onTap,
}) {
return Expanded(
child: Material(
color: purple.withOpacity(_isDark ? 0.2 : 0.1),
borderRadius: BorderRadius.circular(19),
child: InkWell(
borderRadius: BorderRadius.circular(19),
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 16,
horizontal: 8,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, color: _textColor, size: 21),
const SizedBox(width: 8),
Flexible(
child: Text(
title,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: _textColor,
fontWeight: FontWeight.w600,
fontSize: 12,
),
),
),
],
),
),
),
),
);
}
Widget _homeScreen() {
return SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 24),
child: Column(
children: [
Row(
children: [
ShaderMask(
shaderCallback: (bounds) =>
const LinearGradient(
colors: [Colors.white, cyan],
).createShader(bounds),
child: const Icon(
Icons.shield_moon_rounded,
size: 32,
color: Colors.white,
),
),
const SizedBox(width: 10),
Text(
'YAXX ',
style: TextStyle(
color: _textColor,
fontSize: 24,
fontWeight: FontWeight.w900,
letterSpacing: 1.2,
),
),
const Text(
'VPN',
style: TextStyle(
color: purple,
fontSize: 24,
fontWeight: FontWeight.w900,
letterSpacing: 1.2,
),
),
const Spacer(),
IconButton(
onPressed: _openSettings,
icon: Icon(
Icons.settings_rounded,
color: _textColor,
size: 27,
),
),
],
),
const SizedBox(height: 22),
Text(
_connected
? _tr('ЗАЩИТА ВКЛЮЧЕНА', 'PROTECTION ON')
: _tr('ГОТОВ К РАБОТЕ', 'READY TO CONNECT'),
style: TextStyle(
color: _connected ? cyan : _mutedColor,
fontSize: 12,
letterSpacing: 3,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 22),
_powerButton(),
const SizedBox(height: 22),
Text(
_connected
? _tr('Тестовое подключение', 'Test connection')
: _tr('Не подключен', 'Disconnected'),
style: TextStyle(
color: _textColor,
fontSize: 24,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
_connected
? _duration
: _tr(
'Нажми кнопку, чтобы проверить анимацию',
'Tap to test the interface',
),
textAlign: TextAlign.center,
style: TextStyle(
color: _mutedColor,
fontSize: 13,
),
),
const SizedBox(height: 26),
_subscriptionCard(),
const SizedBox(height: 14),
Row(
children: [
_actionButton(
icon: Icons.content_paste_rounded,
title: _tr('Из буфера', 'Clipboard'),
onTap: _pasteKey,
),
const SizedBox(width: 12),
_actionButton(
icon: Icons.qr_code_scanner_rounded,
title: 'QR-код',
onTap: () => _message(
'Сканирование QR-кода добавим позже',
),
),
],
),
const SizedBox(height: 22),
Row(
children: [
Icon(
Icons.lock_outline_rounded,
color: _mutedColor,
size: 17,
),
const SizedBox(width: 8),
Expanded(
child: Text(
_tr(
'Данные ключа хранятся на устройстве',
'Your key is stored on this device',
),
style: TextStyle(
color: _mutedColor,
fontSize: 11,
),
),
),
],
),
],
),
);
}
Widget _settingsScreen() {
return SingleChildScrollView(
padding: const EdgeInsets.all(22),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_tr('Настройки', 'Settings'),
style: TextStyle(
color: _textColor,
fontSize: 28,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 28),
_sectionTitle(_tr('Интерфейс', 'Interface')),
_glassCard(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Column(
children: [
ListTile(
leading: const Icon(
Icons.language_rounded,
color: purple,
),
title: Text(_tr('Язык', 'Language')),
trailing: DropdownButton<String>(
value: _language,
underline: const SizedBox.shrink(),
items: const [
DropdownMenuItem(
value: 'Русский',
child: Text('Русский'),
),
DropdownMenuItem(
value: 'English',
child: Text('English'),
),
],
onChanged: (value) async {
if (value == null) return;
setState(() => _language = value);
final prefs =
await SharedPreferences.getInstance();
await prefs.setString('language', value);
},
),
),
SwitchListTile(
secondary: const Icon(
Icons.dark_mode_rounded,
color: purple,
),
title: Text(_tr('Тёмная тема', 'Dark theme')),
value: _isDark,
activeThumbColor: purple,
onChanged: widget.onThemeChanged,
),
],
),
),
const SizedBox(height: 26),
_sectionTitle(_tr('Безопасность', 'Security')),
_glassCard(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Column(
children: [
SwitchListTile(
secondary: const Icon(
Icons.shield_rounded,
color: purple,
),
title: Text(_tr('Защита', 'Protection')),
subtitle: Text(
_tr(
'Настройка будущего VPN-движка',
'For future VPN integration',
),
style: TextStyle(color: _mutedColor),
),
value: _protection,
activeThumbColor: purple,
onChanged: (value) {
setState(() => _protection = value);
_saveBool('protection', value);
},
),
ListTile(
leading: const Icon(
Icons.vpn_key_rounded,
color: purple,
),
title: Text(_tr('VPN-ключ', 'VPN key')),
subtitle: Text(
_key.isEmpty
? _tr('Не добавлен', 'Not added')
: _tr('Сохранён локально', 'Saved locally'),
style: TextStyle(color: _mutedColor),
),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: _showKeyDialog,
),
],
),
),
const SizedBox(height: 26),
_sectionTitle(_tr('О приложении', 'About')),
_glassCard(
child: const Row(
children: [
Icon(
Icons.shield_moon_rounded,
size: 38,
color: purple,
),
SizedBox(width: 14),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'YAXX VPN',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 17,
),
),
SizedBox(height: 4),
Text(
'Version 0.1.0 • Test build',
style: TextStyle(color: Colors.grey),
),
],
),
],
),
),
],
),
);
}
@override
Widget build(BuildContext context) {
if (_loading) {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(color: purple),
),
);
}
return Scaffold(
extendBody: true,
body: Stack(
children: [
Positioned.fill(
child: AnimatedBuilder(
animation: _animation,
builder: (context, child) {
final t = _animation.value;
return DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment(
-1 + 2 * t,
-0.8,
),
end: Alignment(
1 - 2 * t,
0.9,
),
colors: _isDark
? const [
Color(0xFF17134A),
Color(0xFF10152D),
Color(0xFF090817),
Color(0xFF211044),
]
: const [
Color(0xFFE8E2FF),
Color(0xFFF6F4FF),
Color(0xFFDFF8FF),
],
),
),
);
},
),
),
SafeArea(
child: _tab == 0
? _homeScreen()
: _settingsScreen(),
),
],
),
bottomNavigationBar: Container(
decoration: BoxDecoration(
color: _isDark
? const Color(0xFF0D0B1D).withOpacity(0.94)
: Colors.white.withOpacity(0.95),
border: Border(
top: BorderSide(
color: _mutedColor.withOpacity(0.12),
),
),
),
child: SafeArea(
top: false,
child: NavigationBar(
height: 68,
backgroundColor: Colors.transparent,
elevation: 0,
selectedIndex: _tab,
indicatorColor: purple.withOpacity(0.15),
onDestinationSelected: (index) {
setState(() => _tab = index);
},
destinations: [
NavigationDestination(
icon: const Icon(Icons.home_outlined),
selectedIcon: const Icon(
Icons.home_rounded,
color: purple,
),
label: _tr('Главная', 'Home'),
),
NavigationDestination(
icon: const Icon(Icons.settings_outlined),
selectedIcon: const Icon(
Icons.settings_rounded,
color: purple,
),
label: _tr('Настройки', 'Settings'),
),
],
),
),
),
);
}
@override
void dispose() {
_stopTimer();
_animation.dispose();
_pulse.dispose();
_keyController.dispose();
super.dispose();
}
}