Start adding user gallery

This commit is contained in:
Roland Geider
2021-05-06 14:01:42 +02:00
parent 6ab3e26db4
commit 431f749674
10 changed files with 319 additions and 60 deletions

View File

@@ -26,6 +26,7 @@ import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/auth_screen.dart';
import 'package:wger/screens/dashboard.dart';
import 'package:wger/screens/form_screen.dart';
import 'package:wger/screens/gallery_screen.dart';
import 'package:wger/screens/gym_mode.dart';
import 'package:wger/screens/home_tabs_screen.dart';
import 'package:wger/screens/nutritional_plan_screen.dart';
@@ -89,6 +90,7 @@ class MyApp extends StatelessWidget {
routes: {
DashboardScreen.routeName: (ctx) => DashboardScreen(),
FormScreen.routeName: (ctx) => FormScreen(),
GalleryScreen.routeName: (ctx) => GalleryScreen(),
GymModeScreen.routeName: (ctx) => GymModeScreen(),
HomeTabsScreen.routeName: (ctx) => HomeTabsScreen(),
NutritionScreen.routeName: (ctx) => NutritionScreen(),

View File

@@ -0,0 +1,48 @@
/*
* This file is part of wger Workout Manager <https://github.com/wger-project>.
* Copyright (C) 2020, 2021 wger Team
*
* wger Workout Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* wger Workout Manager is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:json_annotation/json_annotation.dart';
import 'package:wger/helpers/json.dart';
part 'image.g.dart';
@JsonSerializable()
class Image {
@JsonKey(required: true)
final int id;
@JsonKey(required: true, toJson: toDate)
late DateTime date;
@JsonKey(required: true, name: 'image')
final String url;
@JsonKey(defaultValue: '')
final String description;
Image({
required this.id,
required this.date,
required this.url,
required this.description,
});
// Boilerplate
factory Image.fromJson(Map<String, dynamic> json) => _$ImageFromJson(json);
Map<String, dynamic> toJson() => _$ImageToJson(this);
}

View File

@@ -0,0 +1,24 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'image.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Image _$ImageFromJson(Map<String, dynamic> json) {
$checkKeys(json, requiredKeys: const ['id', 'date', 'image']);
return Image(
id: json['id'] as int,
date: DateTime.parse(json['date'] as String),
url: json['image'] as String,
description: json['description'] as String? ?? '',
);
}
Map<String, dynamic> _$ImageToJson(Image instance) => <String, dynamic>{
'id': instance.id,
'date': toDate(instance.date),
'image': instance.url,
'description': instance.description,
};

View File

@@ -24,6 +24,7 @@ import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:wger/helpers/consts.dart';
import 'package:wger/models/exercises/exercise.dart';
import 'package:wger/models/gallery/image.dart' as gallery;
import 'package:wger/models/http_exception.dart';
import 'package:wger/models/workouts/day.dart';
import 'package:wger/models/workouts/log.dart';
@@ -44,6 +45,7 @@ class WorkoutPlans extends WgerBaseProvider with ChangeNotifier {
static const _settingsUrlPath = 'setting';
static const _logsUrlPath = 'workoutlog';
static const _sessionUrlPath = 'workoutsession';
static const _galleryUrlPath = 'gallery';
static const _weightUnitUrlPath = 'setting-weightunit';
static const _repetitionUnitUrlPath = 'setting-repetitionunit';
@@ -52,6 +54,7 @@ class WorkoutPlans extends WgerBaseProvider with ChangeNotifier {
List<WorkoutPlan> _workoutPlans = [];
List<WeightUnit> _weightUnits = [];
List<RepetitionUnit> _repetitionUnit = [];
List<gallery.Image> images = [];
WorkoutPlans(Auth auth, Exercises exercises, List<WorkoutPlan> entries, [http.Client? client])
: this._exercises = exercises,
@@ -422,4 +425,29 @@ class WorkoutPlans extends WgerBaseProvider with ChangeNotifier {
notifyListeners();
return newLog;
}
/*
* Gallery
*/
Future<void> fetchAndSetGallery() async {
final data = await fetch(makeUrl(_galleryUrlPath));
data['results'].forEach((e) {
gallery.Image image = gallery.Image.fromJson(e);
images.add(image);
});
notifyListeners();
}
Future<gallery.Image> addImage(gallery.Image image) async {
final data = await post(image.toJson(), makeUrl(_galleryUrlPath));
final newImage = gallery.Image.fromJson(data);
images.add(newImage);
notifyListeners();
return newImage;
}
}

View File

@@ -59,6 +59,8 @@ class _DashboardScreenState extends State<DashboardScreen> {
if (!Provider.of<Auth>(context, listen: false).dataInit) {
Provider.of<Auth>(context, listen: false).setServerVersion();
await Provider.of<WorkoutPlans>(context, listen: false).fetchAndSetGallery();
// Base data
await Future.wait([
Provider.of<WorkoutPlans>(context, listen: false).fetchAndSetUnits(),

View File

@@ -0,0 +1,60 @@
/*
* This file is part of wger Workout Manager <https://github.com/wger-project>.
* Copyright (C) 2020, 2021 wger Team
*
* wger Workout Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* wger Workout Manager is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart';
import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/form_screen.dart';
import 'package:wger/widgets/app_drawer.dart';
import 'package:wger/widgets/core/core.dart';
import 'package:wger/widgets/gallery/overview.dart';
import 'package:wger/widgets/workouts/forms.dart';
class GalleryScreen extends StatelessWidget {
static const routeName = '/gallery';
const GalleryScreen();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: WgerAppBar(
AppLocalizations.of(context)!.labelWorkoutPlans,
),
drawer: AppDrawer(),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
Navigator.pushNamed(
context,
FormScreen.routeName,
arguments: FormScreenArguments(
AppLocalizations.of(context)!.newWorkout,
WorkoutForm(WorkoutPlan.empty()),
),
);
},
),
body: Consumer<WorkoutPlans>(
builder: (context, workoutProvider, child) => Gallery(),
),
);
}
}

View File

@@ -23,6 +23,7 @@ import 'package:provider/provider.dart';
import 'package:wger/models/workouts/workout_plan.dart';
import 'package:wger/providers/workout_plans.dart';
import 'package:wger/screens/form_screen.dart';
import 'package:wger/screens/gallery_screen.dart';
import 'package:wger/widgets/app_drawer.dart';
import 'package:wger/widgets/core/core.dart';
import 'package:wger/widgets/workouts/forms.dart';
@@ -35,11 +36,40 @@ class WorkoutPlansScreen extends StatefulWidget {
_WorkoutPlansScreenState createState() => _WorkoutPlansScreenState();
}
enum WorkoutListOptions {
gallery,
}
class _WorkoutPlansScreenState extends State<WorkoutPlansScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: WgerAppBar(AppLocalizations.of(context)!.labelWorkoutPlans),
appBar: WgerAppBar(
AppLocalizations.of(context)!.labelWorkoutPlans,
[
PopupMenuButton<WorkoutListOptions>(
icon: Icon(Icons.more_vert),
onSelected: (value) {
// Gallery
if (value == WorkoutListOptions.gallery) {
Navigator.pushNamed(
context,
GalleryScreen.routeName,
);
}
},
itemBuilder: (BuildContext context) {
return [
PopupMenuItem<WorkoutListOptions>(
value: WorkoutListOptions.gallery,
child: Text('Gallery'),
),
const PopupMenuDivider(),
];
},
),
],
),
drawer: AppDrawer(),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),

View File

@@ -46,13 +46,19 @@ class MutedText extends StatelessWidget {
/// Appbar that extends [PreferredSizeWidget]
class WgerAppBar extends StatelessWidget with PreferredSizeWidget {
String _title;
late List<Widget> _actions = [];
WgerAppBar(this._title);
WgerAppBar(this._title, [List<Widget>? actions]) {
if (actions != null) {
_actions = actions;
}
}
@override
Widget build(BuildContext context) {
return AppBar(
title: Text(_title),
actions: _actions,
);
}

View File

@@ -0,0 +1,46 @@
/*
* This file is part of wger Workout Manager <https://github.com/wger-project>.
* Copyright (C) 2020, 2021 wger Team
*
* wger Workout Manager is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* wger Workout Manager is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:wger/providers/workout_plans.dart';
class Gallery extends StatelessWidget {
const Gallery();
@override
Widget build(BuildContext context) {
final provider = Provider.of<WorkoutPlans>(context, listen: false);
return Padding(
padding: const EdgeInsets.all(5),
child: GridView.count(
crossAxisCount: 2,
mainAxisSpacing: 5,
crossAxisSpacing: 5,
children: List.generate(provider.images.length, (index) {
return FadeInImage(
placeholder: AssetImage('assets/images/placeholder.png'),
image: NetworkImage(provider.images[index].url),
fit: BoxFit.cover,
);
}),
),
);
}
}

View File

@@ -2,13 +2,14 @@
// in wger/test/workout_form_test.dart.
// Do not manually edit this file.
import 'dart:async' as _i14;
import 'dart:ui' as _i16;
import 'dart:async' as _i15;
import 'dart:ui' as _i17;
import 'package:http/src/client.dart' as _i5;
import 'package:http/src/response.dart' as _i12;
import 'package:http/src/response.dart' as _i13;
import 'package:mockito/mockito.dart' as _i1;
import 'package:wger/models/exercises/exercise.dart' as _i15;
import 'package:wger/models/exercises/exercise.dart' as _i16;
import 'package:wger/models/gallery/image.dart' as _i12;
import 'package:wger/models/workouts/day.dart' as _i7;
import 'package:wger/models/workouts/log.dart' as _i11;
import 'package:wger/models/workouts/repetition_unit.dart' as _i3;
@@ -18,7 +19,7 @@ import 'package:wger/models/workouts/setting.dart' as _i9;
import 'package:wger/models/workouts/weight_unit.dart' as _i2;
import 'package:wger/models/workouts/workout_plan.dart' as _i6;
import 'package:wger/providers/auth.dart' as _i4;
import 'package:wger/providers/workout_plans.dart' as _i13;
import 'package:wger/providers/workout_plans.dart' as _i14;
// ignore_for_file: comment_references
// ignore_for_file: unnecessary_parenthesis
@@ -47,12 +48,14 @@ class _FakeWorkoutSession extends _i1.Fake implements _i10.WorkoutSession {}
class _FakeLog extends _i1.Fake implements _i11.Log {}
class _FakeResponse extends _i1.Fake implements _i12.Response {}
class _FakeImage extends _i1.Fake implements _i12.Image {}
class _FakeResponse extends _i1.Fake implements _i13.Response {}
/// A class which mocks [WorkoutPlans].
///
/// See the documentation for Mockito's code generation for more information.
class MockWorkoutPlans extends _i1.Mock implements _i13.WorkoutPlans {
class MockWorkoutPlans extends _i1.Mock implements _i14.WorkoutPlans {
MockWorkoutPlans() {
_i1.throwOnMissingStub(this);
}
@@ -113,108 +116,118 @@ class MockWorkoutPlans extends _i1.Mock implements _i13.WorkoutPlans {
super.noSuchMethod(Invocation.method(#resetCurrentPlan, []),
returnValueForMissingStub: null);
@override
_i14.Future<void> fetchAndSetAllPlans() =>
_i15.Future<void> fetchAndSetAllPlans() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetAllPlans, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<void> fetchAndSetWorkoutPlan(int? workoutId) => (super
_i15.Future<void> fetchAndSetWorkoutPlan(int? workoutId) => (super
.noSuchMethod(Invocation.method(#fetchAndSetWorkoutPlan, [workoutId]),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<_i6.WorkoutPlan> addWorkout(_i6.WorkoutPlan? workout) =>
_i15.Future<_i6.WorkoutPlan> addWorkout(_i6.WorkoutPlan? workout) =>
(super.noSuchMethod(Invocation.method(#addWorkout, [workout]),
returnValue: Future<_i6.WorkoutPlan>.value(_FakeWorkoutPlan()))
as _i14.Future<_i6.WorkoutPlan>);
as _i15.Future<_i6.WorkoutPlan>);
@override
_i14.Future<void> editWorkout(_i6.WorkoutPlan? workout) =>
_i15.Future<void> editWorkout(_i6.WorkoutPlan? workout) =>
(super.noSuchMethod(Invocation.method(#editWorkout, [workout]),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<void> deleteWorkout(int? id) =>
_i15.Future<void> deleteWorkout(int? id) =>
(super.noSuchMethod(Invocation.method(#deleteWorkout, [id]),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<Map<String, dynamic>> fetchLogData(
_i6.WorkoutPlan? workout, _i15.Exercise? exercise) =>
_i15.Future<Map<String, dynamic>> fetchLogData(
_i6.WorkoutPlan? workout, _i16.Exercise? exercise) =>
(super.noSuchMethod(Invocation.method(#fetchLogData, [workout, exercise]),
returnValue:
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
as _i14.Future<Map<String, dynamic>>);
as _i15.Future<Map<String, dynamic>>);
@override
_i14.Future<void> fetchAndSetRepetitionUnits() =>
_i15.Future<void> fetchAndSetRepetitionUnits() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetRepetitionUnits, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<void> fetchAndSetWeightUnits() =>
_i15.Future<void> fetchAndSetWeightUnits() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetWeightUnits, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<void> fetchAndSetUnits() =>
_i15.Future<void> fetchAndSetUnits() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetUnits, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<_i7.Day> addDay(_i7.Day? day, _i6.WorkoutPlan? workout) =>
_i15.Future<_i7.Day> addDay(_i7.Day? day, _i6.WorkoutPlan? workout) =>
(super.noSuchMethod(Invocation.method(#addDay, [day, workout]),
returnValue: Future<_i7.Day>.value(_FakeDay()))
as _i14.Future<_i7.Day>);
as _i15.Future<_i7.Day>);
@override
_i14.Future<void> deleteDay(_i7.Day? day) =>
_i15.Future<void> deleteDay(_i7.Day? day) =>
(super.noSuchMethod(Invocation.method(#deleteDay, [day]),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<_i8.Set> addSet(_i8.Set? workoutSet) => (super.noSuchMethod(
_i15.Future<_i8.Set> addSet(_i8.Set? workoutSet) => (super.noSuchMethod(
Invocation.method(#addSet, [workoutSet]),
returnValue: Future<_i8.Set>.value(_FakeSet())) as _i14.Future<_i8.Set>);
returnValue: Future<_i8.Set>.value(_FakeSet())) as _i15.Future<_i8.Set>);
@override
_i14.Future<void> fetchComputedSettings(_i8.Set? workoutSet) => (super
_i15.Future<void> fetchComputedSettings(_i8.Set? workoutSet) => (super
.noSuchMethod(Invocation.method(#fetchComputedSettings, [workoutSet]),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<String> fetchSmartText(
_i8.Set? workoutSet, _i15.Exercise? exercise) =>
_i15.Future<String> fetchSmartText(
_i8.Set? workoutSet, _i16.Exercise? exercise) =>
(super.noSuchMethod(
Invocation.method(#fetchSmartText, [workoutSet, exercise]),
returnValue: Future<String>.value('')) as _i14.Future<String>);
returnValue: Future<String>.value('')) as _i15.Future<String>);
@override
_i14.Future<void> deleteSet(_i8.Set? workoutSet) =>
_i15.Future<void> deleteSet(_i8.Set? workoutSet) =>
(super.noSuchMethod(Invocation.method(#deleteSet, [workoutSet]),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i14.Future<void>);
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i14.Future<_i9.Setting> addSetting(_i9.Setting? workoutSetting) =>
_i15.Future<_i9.Setting> addSetting(_i9.Setting? workoutSetting) =>
(super.noSuchMethod(Invocation.method(#addSetting, [workoutSetting]),
returnValue: Future<_i9.Setting>.value(_FakeSetting()))
as _i14.Future<_i9.Setting>);
as _i15.Future<_i9.Setting>);
@override
_i14.Future<dynamic> fetchSessionData() =>
_i15.Future<dynamic> fetchSessionData() =>
(super.noSuchMethod(Invocation.method(#fetchSessionData, []),
returnValue: Future<dynamic>.value(null)) as _i14.Future<dynamic>);
returnValue: Future<dynamic>.value(null)) as _i15.Future<dynamic>);
@override
_i14.Future<_i10.WorkoutSession> addSession(_i10.WorkoutSession? session) =>
_i15.Future<_i10.WorkoutSession> addSession(_i10.WorkoutSession? session) =>
(super.noSuchMethod(Invocation.method(#addSession, [session]),
returnValue:
Future<_i10.WorkoutSession>.value(_FakeWorkoutSession()))
as _i14.Future<_i10.WorkoutSession>);
as _i15.Future<_i10.WorkoutSession>);
@override
_i14.Future<_i11.Log> addLog(_i11.Log? log) =>
_i15.Future<_i11.Log> addLog(_i11.Log? log) =>
(super.noSuchMethod(Invocation.method(#addLog, [log]),
returnValue: Future<_i11.Log>.value(_FakeLog()))
as _i14.Future<_i11.Log>);
as _i15.Future<_i11.Log>);
@override
void addListener(_i16.VoidCallback? listener) =>
_i15.Future<void> fetchAndSetGallery() =>
(super.noSuchMethod(Invocation.method(#fetchAndSetGallery, []),
returnValue: Future<void>.value(null),
returnValueForMissingStub: Future.value()) as _i15.Future<void>);
@override
_i15.Future<_i12.Image> addImage(_i12.Image? image) =>
(super.noSuchMethod(Invocation.method(#addImage, [image]),
returnValue: Future<_i12.Image>.value(_FakeImage()))
as _i15.Future<_i12.Image>);
@override
void addListener(_i17.VoidCallback? listener) =>
super.noSuchMethod(Invocation.method(#addListener, [listener]),
returnValueForMissingStub: null);
@override
void removeListener(_i16.VoidCallback? listener) =>
void removeListener(_i17.VoidCallback? listener) =>
super.noSuchMethod(Invocation.method(#removeListener, [listener]),
returnValueForMissingStub: null);
@override
@@ -230,27 +243,27 @@ class MockWorkoutPlans extends _i1.Mock implements _i13.WorkoutPlans {
super.noSuchMethod(Invocation.method(#makeUrl, [path],
{#id: id, #objectMethod: objectMethod, #query: query}));
@override
_i14.Future<Map<String, dynamic>> fetch(Uri? uri) => (super.noSuchMethod(
_i15.Future<Map<String, dynamic>> fetch(Uri? uri) => (super.noSuchMethod(
Invocation.method(#fetch, [uri]),
returnValue: Future<Map<String, dynamic>>.value(<String, dynamic>{}))
as _i14.Future<Map<String, dynamic>>);
as _i15.Future<Map<String, dynamic>>);
@override
_i14.Future<Map<String, dynamic>> post(
_i15.Future<Map<String, dynamic>> post(
Map<String, dynamic>? data, Uri? uri) =>
(super.noSuchMethod(Invocation.method(#post, [data, uri]),
returnValue:
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
as _i14.Future<Map<String, dynamic>>);
as _i15.Future<Map<String, dynamic>>);
@override
_i14.Future<Map<String, dynamic>> patch(
_i15.Future<Map<String, dynamic>> patch(
Map<String, dynamic>? data, Uri? uri) =>
(super.noSuchMethod(Invocation.method(#patch, [data, uri]),
returnValue:
Future<Map<String, dynamic>>.value(<String, dynamic>{}))
as _i14.Future<Map<String, dynamic>>);
as _i15.Future<Map<String, dynamic>>);
@override
_i14.Future<_i12.Response> deleteRequest(String? url, int? id) =>
_i15.Future<_i13.Response> deleteRequest(String? url, int? id) =>
(super.noSuchMethod(Invocation.method(#deleteRequest, [url, id]),
returnValue: Future<_i12.Response>.value(_FakeResponse()))
as _i14.Future<_i12.Response>);
returnValue: Future<_i13.Response>.value(_FakeResponse()))
as _i15.Future<_i13.Response>);
}