diff --git a/README.md b/README.md
index 17f0113..10854ea 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,9 @@
+
+
+
## Description
@@ -13,6 +16,8 @@
Let's try it now in your browser [Open Dev](https://jamalianpour.github.io/open-dev)
+
+
## Table of Contents
1. [Features 🚀](#features)
2. [Screenshots 📷](#screenshots)
@@ -24,28 +29,43 @@ Let's try it now in your browser [Open Dev](https://jamalianpour.github.io/open-
## Features 🚀
- **JSON Parser and Converter to YAML:** Parse and show JSON in object viewer to read and search, Easily convert JSON data to YAML format for better readability and use in various applications.
+
- **XML Parser and Converter to JSON:** Transform XML data into JSON format effortlessly, making it easier to work with in JavaScript and other environments.
+
- **Cron Parser:** Interpret and validate cron expressions to ensure correct scheduling of automated tasks.
+
- **Unix Time Converter:** Convert Unix timestamps to human-readable dates and vice versa, simplifying the handling of time data.
+
- **README Helper and Real-time Viewer:** Create and preview README files in real-time to ensure your documentation looks perfect.
+
- **Developer News Based on RSS:** Stay updated with the latest developer news through RSS feeds from popular sources.
+
- **Base64 String/Image Encode/Decode:** Encode and decode Base64 strings and images for data processing and transmission.
+
- **JWT Debugger:** Decode and debug JSON Web Tokens (JWT) to verify token contents and ensure security it locally without internet connection.
+
- **Hash Generator:** Generate cryptographic hashes for strings to ensure data integrity and security.
+
- **Color Converter:** Convert colors between different formats (HEX, RGB, HSL) for design and development purposes.
+
- **RegExp Tester:** Test and debug regular expressions to ensure they match the intended patterns.
+
- **Lorem Ipsum Generator:** Generate placeholder text for your projects to fill in design layouts.
+
- **Password Generator:** Create secure, random passwords to enhance security.
+
- **QR Code Generator:** Generate QR codes from text or URLs for easy sharing and access.
+
- **Image Extensions Formatter:** Convert images between different file formats for compatibility and optimization.
+
- **URL Encode/Decode:** Encode and decode URLs to ensure proper formatting and transmission.
+- **UUID Generator/Decoder:** Generate and decode UUIDs (Universally Unique Identifiers) for use in applications that require unique identifiers.
+
## Screenshots 📷
Here are some screenshots of Open Dev in action:
-
-
| Hash Generator | JSON Parser and Converter to YAML |
| ------------------------------------------------------- | ---------------------------------------------- |
|  |  |
diff --git a/lib/main.dart b/lib/main.dart
index 8b164f3..bcb5016 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:open_dev/views/base_view.dart';
+import 'package:open_dev/views/size_error_view.dart';
import 'package:window_manager/window_manager.dart';
import 'utils/color_schemes.g.dart';
@@ -58,7 +59,9 @@ class MyApp extends StatelessWidget {
darkTheme: ThemeData(useMaterial3: true, colorScheme: darkColorScheme),
debugShowCheckedModeBanner: false,
home: kIsWeb
- ? Container(color: Colors.grey[900], child: const BaseView())
+ ? MediaQuery.sizeOf(context).width < 800
+ ? const SizeErrorView()
+ : Container(color: Colors.grey[900], child: const BaseView())
: const SafeArea(
child: TitlebarSafeArea(
child: BaseView(),
diff --git a/lib/utils/uuid_utils.dart b/lib/utils/uuid_utils.dart
new file mode 100644
index 0000000..9df230e
--- /dev/null
+++ b/lib/utils/uuid_utils.dart
@@ -0,0 +1,85 @@
+import 'package:uuid/uuid.dart';
+
+class UuidUtils {
+ static String generateV4() {
+ return const Uuid().v4();
+ }
+
+ static String generateV5(String namespace, String name) {
+ return const Uuid().v5(namespace, name);
+ }
+
+ static String generateV6() {
+ return const Uuid().v6();
+ }
+
+ static String generateV7() {
+ return const Uuid().v7();
+ }
+
+ static String generateV8() {
+ return const Uuid().v8();
+ }
+
+ static String generateV1() {
+ return const Uuid().v1();
+ }
+
+ /// Decodes a UUID and extracts its version, variant, timestamp, clock sequence, and node.
+ ///
+ /// - param `String` uuid - The UUID to decode.
+ /// - return `Tuple` A tuple containing the version, variant, timestamp, clock sequence, and node.
+ static (int, String, int, int, String) decode(String uuid) {
+ // Parse the UUID to a list of bytes
+ List bytes = Uuid.parse(uuid);
+
+ // Extracting information from the UUID
+ var version = bytes[6] >> 4; // Version is in the 7th byte
+ var variant = (bytes[8] & 0xC0) >> 6; // Variant is in the 9th byte
+
+ // Extract timestamp (60 bits: 4 bits from byte 6, all bits from byte 7, 5, 4, 3, 2, and 1)
+ var timestamp = ((bytes[6] & 0x0F) << 56) |
+ (bytes[7] << 48) |
+ (bytes[4] << 40) |
+ (bytes[5] << 32) |
+ (bytes[0] << 24) |
+ (bytes[1] << 16) |
+ (bytes[2] << 8) |
+ bytes[3];
+
+ // UUID timestamp is in 100-nanosecond intervals since 1582-10-15
+ // Convert to Unix epoch (1970-01-01)
+ const UUID_EPOCH = 0x01B21DD213814000;
+ timestamp -= UUID_EPOCH;
+ var millisecondsSinceEpoch = timestamp ~/ 10000; // Convert to milliseconds
+
+ // Extract clock sequence
+ var clockSeq = ((bytes[8] & 0x3F) << 8) | bytes[9];
+
+ // Extract node (MAC address)
+ var node = [
+ bytes[10].toRadixString(16).padLeft(2, '0'),
+ bytes[11].toRadixString(16).padLeft(2, '0'),
+ bytes[12].toRadixString(16).padLeft(2, '0'),
+ bytes[13].toRadixString(16).padLeft(2, '0'),
+ bytes[14].toRadixString(16).padLeft(2, '0'),
+ bytes[15].toRadixString(16).padLeft(2, '0')
+ ].join(':');
+
+ String variantName = '';
+
+ if (variant == 0) {
+ variantName = '0 (NCS backward compatibility)';
+ } else if (variant == 1) {
+ variantName = '1 (RFC 4122/DCE 1.1)';
+ } else if (variant == 2) {
+ variantName = '2 (Microsoft\'s GUIDs)';
+ } else if (variant == 3) {
+ variantName = '3 (Reserved for future use)';
+ } else {
+ variantName = 'Unknown';
+ }
+
+ return (version, variantName, millisecondsSinceEpoch, clockSeq, node);
+ }
+}
diff --git a/lib/views/base_view.dart b/lib/views/base_view.dart
index e5fbaea..5497fac 100644
--- a/lib/views/base_view.dart
+++ b/lib/views/base_view.dart
@@ -19,6 +19,7 @@ import 'readme_view.dart';
import 'regex_view.dart';
import 'unix_time_view.dart';
import 'url_view.dart';
+import 'uuid_view.dart';
class BaseView extends StatefulWidget {
const BaseView({super.key});
@@ -73,7 +74,8 @@ class _BaseViewState extends State {
const PasswordView(),
const QrView(),
const ImageView(),
- const UrlView()
+ const UrlView(),
+ const UuidView(),
],
),
),
diff --git a/lib/views/dashboard_view.dart b/lib/views/dashboard_view.dart
index ac0e101..8b71297 100644
--- a/lib/views/dashboard_view.dart
+++ b/lib/views/dashboard_view.dart
@@ -466,6 +466,39 @@ class DashboardView extends StatelessWidget {
],
),
),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
+ child: Row(
+ children: [
+ Expanded(
+ child: Semantics(
+ button: true,
+ label:
+ 'UUID Generator/Decode | Generate and decode UUIDs (Universally Unique Identifiers) for use in applications that require unique identifiers.',
+ child: DashboardCard(
+ title: 'UUID Generator/Decode',
+ description:
+ 'Generate and decode UUIDs (Universally Unique Identifiers) for use in applications that require unique identifiers.',
+ icon: const Icon(
+ CupertinoIcons.underline,
+ size: 50,
+ color: Colors.white60,
+ ),
+ onTap: () {
+ sideMenu.changePage(17);
+ },
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 16,
+ ),
+ const Expanded(
+ child: SizedBox.shrink(),
+ ),
+ ],
+ ),
+ ),
],
),
),
diff --git a/lib/views/size_error_view.dart b/lib/views/size_error_view.dart
new file mode 100644
index 0000000..647662c
--- /dev/null
+++ b/lib/views/size_error_view.dart
@@ -0,0 +1,36 @@
+import 'package:flutter/material.dart';
+
+class SizeErrorView extends StatelessWidget {
+ const SizeErrorView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Center(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.center,
+ mainAxisSize: MainAxisSize.max,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Image.asset(
+ 'assets/logo/icon.png',
+ width: 125,
+ height: 125,
+ ),
+ ),
+ const Padding(
+ padding: EdgeInsets.all(16),
+ child: Text(
+ 'Sorry but currently Open Dev is not supported on this device 📱. Please use a device with a larger screen 🖥️.',
+ textAlign: TextAlign.center,
+ style: TextStyle(fontSize: 18, height: 1.8),
+ ),
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/views/uuid_view.dart b/lib/views/uuid_view.dart
new file mode 100644
index 0000000..248cb4f
--- /dev/null
+++ b/lib/views/uuid_view.dart
@@ -0,0 +1,280 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:open_dev/utils/uuid_utils.dart';
+import 'package:open_dev/widgets/data_widget.dart';
+
+import '../widgets/secondary_button.dart';
+
+class UuidView extends StatefulWidget {
+ const UuidView({super.key});
+
+ @override
+ State createState() => _UuidViewState();
+}
+
+class _UuidViewState extends State {
+ final TextEditingController _input = TextEditingController();
+ final TextEditingController _generated = TextEditingController();
+ final TextEditingController _generateCount = TextEditingController();
+
+ String version = '', variant = '', timestamp = '', clockSeq = '', node = '';
+
+ String uuidType = 'V1';
+
+ @override
+ void initState() {
+ _input.text = UuidUtils.generateV1();
+ var result = UuidUtils.decode(_input.text);
+ version = result.$1.toString();
+ variant = result.$2;
+ timestamp = result.$3.toString();
+ clockSeq = result.$4.toString();
+ node = result.$5;
+ super.initState();
+ }
+
+ void _decode() {
+ var result = UuidUtils.decode(_input.text);
+ version = result.$1.toString();
+ variant = result.$2;
+ timestamp = result.$3.toString();
+ clockSeq = result.$4.toString();
+ node = result.$5;
+ setState(() {});
+ }
+
+ Padding _buildHeader(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 8),
+ child: Row(
+ children: [
+ Text('UUID Generator/Decode', style: Theme.of(context).textTheme.headlineSmall),
+ ],
+ ),
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ _buildHeader(context),
+ const Divider(
+ indent: 8,
+ endIndent: 8,
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
+ child: Row(
+ children: [
+ Expanded(
+ flex: 9,
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 4),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const Text('input:'),
+ const SizedBox(
+ height: 8,
+ ),
+ Row(
+ children: [
+ Expanded(
+ child: TextField(
+ decoration: InputDecoration(
+ border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), gapPadding: 0),
+ isDense: true,
+ prefixIcon: const Icon(CupertinoIcons.underline),
+ contentPadding: const EdgeInsets.all(0),
+ filled: true,
+ ),
+ controller: _input,
+ onSubmitted: (value) {
+ _decode();
+ },
+ ),
+ ),
+ const SizedBox(
+ width: 6,
+ ),
+ SecondaryButton(
+ text: 'Decode',
+ height: 38,
+ onTap: () {
+ _decode();
+ },
+ )
+ ],
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ DataWidget(
+ value: version,
+ title: 'Version',
+ width: (MediaQuery.sizeOf(context).width - 250) * 0.41,
+ maxWidth: 700,
+ minWidth: 340,
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ DataWidget(
+ value: variant,
+ title: 'Variant',
+ width: (MediaQuery.sizeOf(context).width - 250) * 0.41,
+ maxWidth: 700,
+ minWidth: 340,
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ DataWidget(
+ value: timestamp,
+ title: 'Created',
+ width: (MediaQuery.sizeOf(context).width - 250) * 0.41,
+ maxWidth: 700,
+ minWidth: 340,
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ DataWidget(
+ value: clockSeq,
+ title: 'ClockSeq',
+ width: (MediaQuery.sizeOf(context).width - 250) * 0.41,
+ maxWidth: 700,
+ minWidth: 340,
+ ),
+ const SizedBox(
+ height: 8,
+ ),
+ DataWidget(
+ value: node,
+ title: 'Node',
+ width: (MediaQuery.sizeOf(context).width - 250) * 0.41,
+ maxWidth: 700,
+ minWidth: 340,
+ ),
+ ],
+ ),
+ ),
+ ),
+ const VerticalDivider(),
+ Expanded(
+ flex: 10,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ const Text('UUID:'),
+ const Spacer(),
+ SizedBox(
+ width: 50,
+ child: Container(
+ decoration: BoxDecoration(
+ color: Theme.of(context).splashColor,
+ borderRadius: BorderRadius.circular(3),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.only(left: 4),
+ child: DropdownButtonFormField(
+ borderRadius: BorderRadius.circular(6),
+ decoration: const InputDecoration(
+ border: InputBorder.none,
+ isDense: true,
+ ),
+ items: ['V1', 'V4', 'V5', 'V6', 'V7', 'V8'].map((String value) {
+ return DropdownMenuItem(
+ value: value,
+ child: Text(value),
+ );
+ }).toList(),
+ value: uuidType,
+ onChanged: (value) {
+ setState(() {
+ uuidType = value ?? 'V1';
+ });
+ },
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 4,
+ ),
+ const Text('×'),
+ const SizedBox(
+ width: 4,
+ ),
+ SizedBox(
+ width: 50,
+ child: TextField(
+ controller: _generateCount,
+ decoration: InputDecoration(
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(4), gapPadding: 0, borderSide: BorderSide.none),
+ isCollapsed: true,
+ contentPadding: const EdgeInsets.all(5),
+ fillColor: Theme.of(context).splashColor,
+ filled: true,
+ ),
+ inputFormatters: [
+ FilteringTextInputFormatter.digitsOnly,
+ ],
+ ),
+ ),
+ const SizedBox(
+ width: 8,
+ ),
+ SecondaryButton(
+ text: 'Generate',
+ onTap: () {
+ _generated.clear();
+ int count = int.parse(_generateCount.text);
+ for (int i = 0; i < count; i++) {
+ if (uuidType == 'V1') _generated.text = '${_generated.text}${UuidUtils.generateV1()}\n';
+ if (uuidType == 'V4') _generated.text = '${_generated.text}${UuidUtils.generateV4()}\n';
+ if (uuidType == 'V5') {
+ _generated.text =
+ '${_generated.text}${UuidUtils.generateV5("00000000-0000-0000-0000-000000000000", "00000000-0000-0000-0000-000000000000")}\n';
+ }
+ if (uuidType == 'V6') _generated.text = '${_generated.text}${UuidUtils.generateV6()}\n';
+ if (uuidType == 'V7') _generated.text = '${_generated.text}${UuidUtils.generateV7()}\n';
+ if (uuidType == 'V8') _generated.text = '${_generated.text}${UuidUtils.generateV8()}\n';
+ setState(() {});
+ }
+ },
+ ),
+ ],
+ ),
+ const SizedBox(
+ height: 6,
+ ),
+ Expanded(
+ child: TextField(
+ controller: _generated,
+ decoration: InputDecoration(
+ filled: true,
+ border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), gapPadding: 0),
+ contentPadding: const EdgeInsets.all(12),
+ ),
+ onChanged: (value) {},
+ maxLines: 999,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ))
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/secondary_button.dart b/lib/widgets/secondary_button.dart
index 90d7ca1..ae20d53 100644
--- a/lib/widgets/secondary_button.dart
+++ b/lib/widgets/secondary_button.dart
@@ -3,12 +3,14 @@ import 'package:flutter/material.dart';
class SecondaryButton extends StatelessWidget {
final String text;
final Icon? icon;
+ final double? height;
final Function onTap;
const SecondaryButton({
Key? key,
required this.text,
this.icon,
required this.onTap,
+ this.height,
}) : super(key: key);
@override
@@ -17,6 +19,7 @@ class SecondaryButton extends StatelessWidget {
onTap: () => onTap(),
borderRadius: BorderRadius.circular(8),
child: Container(
+ height: height,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Theme.of(context).colorScheme.primaryContainer,
diff --git a/lib/widgets/side_menu_widget.dart b/lib/widgets/side_menu_widget.dart
index f7f0329..013a7e0 100644
--- a/lib/widgets/side_menu_widget.dart
+++ b/lib/widgets/side_menu_widget.dart
@@ -57,7 +57,7 @@ class SideMenuWidget extends StatelessWidget {
icon: const Icon(CupertinoIcons.doc_text),
),
SideMenuItem(
- title: 'Developer news',
+ title: 'Developer News',
onTap: (index, _) {
sideMenu.changePage(index);
},
@@ -85,7 +85,7 @@ class SideMenuWidget extends StatelessWidget {
icon: const Icon(Icons.fingerprint),
),
SideMenuItem(
- title: 'Color picker',
+ title: 'Color Picker',
onTap: (index, _) {
sideMenu.changePage(index);
},
@@ -120,19 +120,26 @@ class SideMenuWidget extends StatelessWidget {
icon: const Icon(CupertinoIcons.qrcode),
),
SideMenuItem(
- title: 'Image format',
+ title: 'Image Format',
onTap: (index, _) {
sideMenu.changePage(index);
},
icon: const Icon(CupertinoIcons.photo_fill),
),
SideMenuItem(
- title: 'URL parser',
+ title: 'URL Parser',
onTap: (index, _) {
sideMenu.changePage(index);
},
icon: const Icon(CupertinoIcons.globe),
),
+ SideMenuItem(
+ title: 'UUID Generator/Decode',
+ onTap: (index, _) {
+ sideMenu.changePage(index);
+ },
+ icon: const Icon(CupertinoIcons.underline),
+ ),
];
Widget side() {
@@ -149,15 +156,17 @@ class SideMenuWidget extends StatelessWidget {
header: true,
child: Image.asset(
'assets/logo/icon.png',
- width: 65,
- height: 65,
+ width: MediaQuery.sizeOf(context).width > 900 ? 65 : 50,
+ height: MediaQuery.sizeOf(context).width > 900 ? 65 : 50,
),
),
- const SizedBox(width: 4),
- Text(
- 'Open Dev',
- style: Theme.of(context).textTheme.headlineLarge,
- ),
+ if (MediaQuery.sizeOf(context).width > 900) ...[
+ const SizedBox(width: 4),
+ Text(
+ 'Open Dev',
+ style: Theme.of(context).textTheme.headlineLarge,
+ ),
+ ]
],
),
)
@@ -173,9 +182,8 @@ class SideMenuWidget extends StatelessWidget {
style: SideMenuStyle(
itemHeight: 35,
openSideMenuWidth: 250,
- // backgroundColor: Colors.transparent,
- // showHamburger: true,
- displayMode: SideMenuDisplayMode.open,
+ compactSideMenuWidth: 60,
+ displayMode: MediaQuery.sizeOf(context).width < 900 ? SideMenuDisplayMode.compact : SideMenuDisplayMode.open,
selectedTitleTextStyle: TextStyle(fontSize: 14, color: Theme.of(context).colorScheme.primary),
unselectedTitleTextStyle: const TextStyle(fontSize: 14, color: Colors.white70),
selectedColor: Theme.of(context).colorScheme.primaryContainer,
diff --git a/pubspec.lock b/pubspec.lock
index da59d28..ce0b662 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -629,6 +629,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.10.0"
+ sprintf:
+ dependency: transitive
+ description:
+ name: sprintf
+ sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
+ url: "https://pub.dev"
+ source: hosted
+ version: "7.0.0"
stack_trace:
dependency: transitive
description:
@@ -749,6 +757,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.1"
+ uuid:
+ dependency: "direct main"
+ description:
+ name: uuid
+ sha256: "83d37c7ad7aaf9aa8e275490669535c8080377cfa7a7004c24dfac53afffaa90"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.4.2"
vector_math:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 6c77655..705d357 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,7 +1,7 @@
name: open_dev
description: "Open source cross-platform developer assistant"
-version: 0.5.0+1
+version: 0.5.1+2
environment:
sdk: '>=3.2.1 <4.0.0'
@@ -35,6 +35,7 @@ dependencies:
image: ^4.2.0
url_launcher: ^6.3.0
device_info_plus: ^10.1.0
+ uuid: ^4.4.2
dev_dependencies:
flutter_test:
diff --git a/test/uuid_test.dart b/test/uuid_test.dart
new file mode 100644
index 0000000..901c722
--- /dev/null
+++ b/test/uuid_test.dart
@@ -0,0 +1,21 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:open_dev/utils/uuid_utils.dart';
+
+void main() {
+ group('UuidUtils.decode', () {
+ test('should decode a valid UUID', () {
+ var uuid = UuidUtils.generateV1();
+ var result = UuidUtils.decode(uuid);
+
+ expect(result.$1, 1);
+ expect(result.$2, '2 (Microsoft\'s GUIDs)');
+ expect(result.$3 >= 0, true);
+ expect(result.$4 >= 0, true);
+ expect(result.$5.split(':').length, 6);
+ });
+
+ test('should handle invalid UUIDs', () {
+ expect(() => UuidUtils.decode('invalid'), throwsA(isA()));
+ });
+ });
+}
\ No newline at end of file