Showing
6 changed files
with
124 additions
and
36 deletions
@@ -161,18 +161,31 @@ class GetInstance { | @@ -161,18 +161,31 @@ class GetInstance { | ||
161 | bool fenix = false, | 161 | bool fenix = false, |
162 | }) { | 162 | }) { |
163 | final key = _getKey(S, name); | 163 | final key = _getKey(S, name); |
164 | - _singl.putIfAbsent( | ||
165 | - key, | ||
166 | - () => _InstanceBuilderFactory<S>( | 164 | + |
165 | + if (_singl.containsKey(key)) { | ||
166 | + final dep = _singl[key]; | ||
167 | + if (dep != null && dep.isDirty) { | ||
168 | + _singl[key] = _InstanceBuilderFactory<S>( | ||
167 | isSingleton, | 169 | isSingleton, |
168 | builder, | 170 | builder, |
169 | permanent, | 171 | permanent, |
170 | false, | 172 | false, |
171 | fenix, | 173 | fenix, |
172 | name, | 174 | name, |
173 | - ), | 175 | + lateRemove: dep as _InstanceBuilderFactory<S>, |
174 | ); | 176 | ); |
175 | } | 177 | } |
178 | + } else { | ||
179 | + _singl[key] = _InstanceBuilderFactory<S>( | ||
180 | + isSingleton, | ||
181 | + builder, | ||
182 | + permanent, | ||
183 | + false, | ||
184 | + fenix, | ||
185 | + name, | ||
186 | + ); | ||
187 | + } | ||
188 | + } | ||
176 | 189 | ||
177 | /// Initializes the dependencies for a Class Instance [S] (or tag), | 190 | /// Initializes the dependencies for a Class Instance [S] (or tag), |
178 | /// If its a Controller, it starts the lifecycle process. | 191 | /// If its a Controller, it starts the lifecycle process. |
@@ -222,6 +235,16 @@ class GetInstance { | @@ -222,6 +235,16 @@ class GetInstance { | ||
222 | } | 235 | } |
223 | } | 236 | } |
224 | 237 | ||
238 | + void markAsDirty<S>({String? tag, String? key}) { | ||
239 | + final newKey = key ?? _getKey(S, tag); | ||
240 | + if (_singl.containsKey(newKey)) { | ||
241 | + final dep = _singl[newKey]; | ||
242 | + if (dep != null) { | ||
243 | + dep.isDirty = true; | ||
244 | + } | ||
245 | + } | ||
246 | + } | ||
247 | + | ||
225 | /// Initializes the controller | 248 | /// Initializes the controller |
226 | S _startController<S>({String? tag}) { | 249 | S _startController<S>({String? tag}) { |
227 | final key = _getKey(S, tag); | 250 | final key = _getKey(S, tag); |
@@ -258,7 +281,8 @@ class GetInstance { | @@ -258,7 +281,8 @@ class GetInstance { | ||
258 | S find<S>({String? tag}) { | 281 | S find<S>({String? tag}) { |
259 | final key = _getKey(S, tag); | 282 | final key = _getKey(S, tag); |
260 | if (isRegistered<S>(tag: tag)) { | 283 | if (isRegistered<S>(tag: tag)) { |
261 | - if (_singl[key] == null) { | 284 | + final dep = _singl[key]; |
285 | + if (dep == null) { | ||
262 | if (tag == null) { | 286 | if (tag == null) { |
263 | throw 'Class "$S" is not registered'; | 287 | throw 'Class "$S" is not registered'; |
264 | } else { | 288 | } else { |
@@ -266,11 +290,16 @@ class GetInstance { | @@ -266,11 +290,16 @@ class GetInstance { | ||
266 | } | 290 | } |
267 | } | 291 | } |
268 | 292 | ||
293 | + // if (dep.lateRemove != null) { | ||
294 | + // dep.isDirty = true; | ||
295 | + // if(dep.fenix) | ||
296 | + // } | ||
297 | + | ||
269 | /// although dirty solution, the lifecycle starts inside | 298 | /// although dirty solution, the lifecycle starts inside |
270 | /// `initDependencies`, so we have to return the instance from there | 299 | /// `initDependencies`, so we have to return the instance from there |
271 | /// to make it compatible with `Get.create()`. | 300 | /// to make it compatible with `Get.create()`. |
272 | final i = _initDependencies<S>(name: tag); | 301 | final i = _initDependencies<S>(name: tag); |
273 | - return i ?? _singl[key]!.getDependency() as S; | 302 | + return i ?? dep.getDependency() as S; |
274 | } else { | 303 | } else { |
275 | // ignore: lines_longer_than_80_chars | 304 | // ignore: lines_longer_than_80_chars |
276 | throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"'; | 305 | throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"'; |
@@ -324,7 +353,16 @@ class GetInstance { | @@ -324,7 +353,16 @@ class GetInstance { | ||
324 | return false; | 353 | return false; |
325 | } | 354 | } |
326 | 355 | ||
327 | - final builder = _singl[newKey]!; | 356 | + final dep = _singl[newKey]; |
357 | + | ||
358 | + if (dep == null) return false; | ||
359 | + | ||
360 | + final _InstanceBuilderFactory builder; | ||
361 | + if (dep.isDirty) { | ||
362 | + builder = dep.lateRemove ?? dep; | ||
363 | + } else { | ||
364 | + builder = dep; | ||
365 | + } | ||
328 | 366 | ||
329 | if (builder.permanent && !force) { | 367 | if (builder.permanent && !force) { |
330 | Get.log( | 368 | Get.log( |
@@ -346,8 +384,15 @@ class GetInstance { | @@ -346,8 +384,15 @@ class GetInstance { | ||
346 | } | 384 | } |
347 | 385 | ||
348 | if (builder.fenix) { | 386 | if (builder.fenix) { |
387 | + //TODO: Remove if is late remove | ||
349 | builder.dependency = null; | 388 | builder.dependency = null; |
350 | builder.isInit = false; | 389 | builder.isInit = false; |
390 | + return true; | ||
391 | + } else { | ||
392 | + if (dep.lateRemove != null) { | ||
393 | + dep.lateRemove = null; | ||
394 | + Get.log('"$newKey" deleted from memory'); | ||
395 | + return false; | ||
351 | } else { | 396 | } else { |
352 | _singl.remove(newKey); | 397 | _singl.remove(newKey); |
353 | if (_singl.containsKey(newKey)) { | 398 | if (_singl.containsKey(newKey)) { |
@@ -355,10 +400,10 @@ class GetInstance { | @@ -355,10 +400,10 @@ class GetInstance { | ||
355 | } else { | 400 | } else { |
356 | Get.log('"$newKey" deleted from memory'); | 401 | Get.log('"$newKey" deleted from memory'); |
357 | } | 402 | } |
358 | - } | ||
359 | - | ||
360 | return true; | 403 | return true; |
361 | } | 404 | } |
405 | + } | ||
406 | + } | ||
362 | 407 | ||
363 | /// Delete all registered Class Instances and, closes any open | 408 | /// Delete all registered Class Instances and, closes any open |
364 | /// controllers `DisposableInterface`, cleans up the memory | 409 | /// controllers `DisposableInterface`, cleans up the memory |
@@ -382,11 +427,11 @@ class GetInstance { | @@ -382,11 +427,11 @@ class GetInstance { | ||
382 | }); | 427 | }); |
383 | } | 428 | } |
384 | 429 | ||
385 | - void reload<S>( | ||
386 | - {String? tag, | 430 | + void reload<S>({ |
431 | + String? tag, | ||
387 | String? key, | 432 | String? key, |
388 | bool force = false, | 433 | bool force = false, |
389 | - bool closeInstance = true}) { | 434 | + }) { |
390 | final newKey = key ?? _getKey(S, tag); | 435 | final newKey = key ?? _getKey(S, tag); |
391 | 436 | ||
392 | final builder = _getDependency<S>(tag: tag, key: newKey); | 437 | final builder = _getDependency<S>(tag: tag, key: newKey); |
@@ -406,7 +451,7 @@ class GetInstance { | @@ -406,7 +451,7 @@ class GetInstance { | ||
406 | return; | 451 | return; |
407 | } | 452 | } |
408 | 453 | ||
409 | - if (i is GetLifeCycleBase && closeInstance) { | 454 | + if (i is GetLifeCycleBase) { |
410 | i.onDelete(); | 455 | i.onDelete(); |
411 | Get.log('"$newKey" onDelete() called'); | 456 | Get.log('"$newKey" onDelete() called'); |
412 | } | 457 | } |
@@ -467,6 +512,10 @@ class _InstanceBuilderFactory<S> { | @@ -467,6 +512,10 @@ class _InstanceBuilderFactory<S> { | ||
467 | 512 | ||
468 | bool isInit = false; | 513 | bool isInit = false; |
469 | 514 | ||
515 | + _InstanceBuilderFactory<S>? lateRemove; | ||
516 | + | ||
517 | + bool isDirty = false; | ||
518 | + | ||
470 | String? tag; | 519 | String? tag; |
471 | 520 | ||
472 | _InstanceBuilderFactory( | 521 | _InstanceBuilderFactory( |
@@ -475,8 +524,9 @@ class _InstanceBuilderFactory<S> { | @@ -475,8 +524,9 @@ class _InstanceBuilderFactory<S> { | ||
475 | this.permanent, | 524 | this.permanent, |
476 | this.isInit, | 525 | this.isInit, |
477 | this.fenix, | 526 | this.fenix, |
478 | - this.tag, | ||
479 | - ); | 527 | + this.tag, { |
528 | + this.lateRemove, | ||
529 | + }); | ||
480 | 530 | ||
481 | void _showInitLog() { | 531 | void _showInitLog() { |
482 | if (tag == null) { | 532 | if (tag == null) { |
@@ -319,7 +319,7 @@ class GetDelegate extends RouterDelegate<GetNavConfig> | @@ -319,7 +319,7 @@ class GetDelegate extends RouterDelegate<GetNavConfig> | ||
319 | return route; | 319 | return route; |
320 | } | 320 | } |
321 | 321 | ||
322 | - Future<void> toNamed( | 322 | + Future<T> toNamed<T>( |
323 | String page, { | 323 | String page, { |
324 | dynamic arguments, | 324 | dynamic arguments, |
325 | Map<String, String>? parameters, | 325 | Map<String, String>? parameters, |
@@ -332,13 +332,19 @@ class GetDelegate extends RouterDelegate<GetNavConfig> | @@ -332,13 +332,19 @@ class GetDelegate extends RouterDelegate<GetNavConfig> | ||
332 | final decoder = Get.routeTree.matchRoute(page, arguments: arguments); | 332 | final decoder = Get.routeTree.matchRoute(page, arguments: arguments); |
333 | decoder.replaceArguments(arguments); | 333 | decoder.replaceArguments(arguments); |
334 | 334 | ||
335 | - await pushHistory( | 335 | + final completer = Completer<T>(); |
336 | + | ||
337 | + _allCompleters[decoder.route!] = completer; | ||
338 | + | ||
339 | + pushHistory( | ||
336 | GetNavConfig( | 340 | GetNavConfig( |
337 | currentTreeBranch: decoder.treeBranch, | 341 | currentTreeBranch: decoder.treeBranch, |
338 | location: page, | 342 | location: page, |
339 | state: null, //TODO: persist state? | 343 | state: null, //TODO: persist state? |
340 | ), | 344 | ), |
341 | ); | 345 | ); |
346 | + | ||
347 | + return completer.future; | ||
342 | } | 348 | } |
343 | 349 | ||
344 | Future<void> offNamed( | 350 | Future<void> offNamed( |
@@ -400,6 +406,8 @@ class GetDelegate extends RouterDelegate<GetNavConfig> | @@ -400,6 +406,8 @@ class GetDelegate extends RouterDelegate<GetNavConfig> | ||
400 | return false; | 406 | return false; |
401 | } | 407 | } |
402 | 408 | ||
409 | + final _allCompleters = <GetPage, Completer>{}; | ||
410 | + | ||
403 | bool _onPopVisualRoute(Route<dynamic> route, dynamic result) { | 411 | bool _onPopVisualRoute(Route<dynamic> route, dynamic result) { |
404 | final didPop = route.didPop(result); | 412 | final didPop = route.didPop(result); |
405 | if (!didPop) { | 413 | if (!didPop) { |
@@ -7,7 +7,7 @@ import '../../get.dart'; | @@ -7,7 +7,7 @@ import '../../get.dart'; | ||
7 | class RouterReportManager<T> { | 7 | class RouterReportManager<T> { |
8 | /// Holds a reference to `Get.reference` when the Instance was | 8 | /// Holds a reference to `Get.reference` when the Instance was |
9 | /// created to manage the memory. | 9 | /// created to manage the memory. |
10 | - static final Map<String, Route?> _routesKey = {}; | 10 | + static final Map<Route?, String> _routesKey = {}; |
11 | 11 | ||
12 | /// Stores the onClose() references of instances created with `Get.create()` | 12 | /// Stores the onClose() references of instances created with `Get.create()` |
13 | /// using the `Get.reference`. | 13 | /// using the `Get.reference`. |
@@ -29,7 +29,7 @@ class RouterReportManager<T> { | @@ -29,7 +29,7 @@ class RouterReportManager<T> { | ||
29 | /// Links a Class instance [S] (or [tag]) to the current route. | 29 | /// Links a Class instance [S] (or [tag]) to the current route. |
30 | /// Requires usage of `GetMaterialApp`. | 30 | /// Requires usage of `GetMaterialApp`. |
31 | static void reportDependencyLinkedToRoute(String depedencyKey) { | 31 | static void reportDependencyLinkedToRoute(String depedencyKey) { |
32 | - _routesKey.putIfAbsent(depedencyKey, () => _current); | 32 | + _routesKey[_current] = depedencyKey; |
33 | } | 33 | } |
34 | 34 | ||
35 | static void clearRouteKeys() { | 35 | static void clearRouteKeys() { |
@@ -47,9 +47,9 @@ class RouterReportManager<T> { | @@ -47,9 +47,9 @@ class RouterReportManager<T> { | ||
47 | if (Get.smartManagement != SmartManagement.onlyBuilder) { | 47 | if (Get.smartManagement != SmartManagement.onlyBuilder) { |
48 | WidgetsBinding.instance!.addPostFrameCallback((_) { | 48 | WidgetsBinding.instance!.addPostFrameCallback((_) { |
49 | ///TODO: Is necessary this comparator? | 49 | ///TODO: Is necessary this comparator? |
50 | - if (_current != disposed) { | 50 | + //if (_current != disposed) { |
51 | _removeDependencyByRoute(disposed); | 51 | _removeDependencyByRoute(disposed); |
52 | - } | 52 | + // } |
53 | }); | 53 | }); |
54 | } | 54 | } |
55 | } | 55 | } |
@@ -57,8 +57,8 @@ class RouterReportManager<T> { | @@ -57,8 +57,8 @@ class RouterReportManager<T> { | ||
57 | static void reportRouteWillDispose(Route disposed) { | 57 | static void reportRouteWillDispose(Route disposed) { |
58 | final keysToRemove = <String>[]; | 58 | final keysToRemove = <String>[]; |
59 | _routesKey.forEach((key, value) { | 59 | _routesKey.forEach((key, value) { |
60 | - if (value == disposed) { | ||
61 | - keysToRemove.add(key); | 60 | + if (key == disposed) { |
61 | + keysToRemove.add(value); | ||
62 | } | 62 | } |
63 | }); | 63 | }); |
64 | 64 | ||
@@ -74,7 +74,8 @@ class RouterReportManager<T> { | @@ -74,7 +74,8 @@ class RouterReportManager<T> { | ||
74 | } | 74 | } |
75 | 75 | ||
76 | for (final element in keysToRemove) { | 76 | for (final element in keysToRemove) { |
77 | - GetInstance().reload(key: element, closeInstance: false); | 77 | + GetInstance().markAsDirty(key: element); |
78 | + | ||
78 | //_routesKey.remove(element); | 79 | //_routesKey.remove(element); |
79 | } | 80 | } |
80 | 81 | ||
@@ -88,8 +89,8 @@ class RouterReportManager<T> { | @@ -88,8 +89,8 @@ class RouterReportManager<T> { | ||
88 | static void _removeDependencyByRoute(Route routeName) { | 89 | static void _removeDependencyByRoute(Route routeName) { |
89 | final keysToRemove = <String>[]; | 90 | final keysToRemove = <String>[]; |
90 | _routesKey.forEach((key, value) { | 91 | _routesKey.forEach((key, value) { |
91 | - if (value == routeName) { | ||
92 | - keysToRemove.add(key); | 92 | + if (key == routeName) { |
93 | + keysToRemove.add(value); | ||
93 | } | 94 | } |
94 | }); | 95 | }); |
95 | 96 | ||
@@ -105,9 +106,11 @@ class RouterReportManager<T> { | @@ -105,9 +106,11 @@ class RouterReportManager<T> { | ||
105 | } | 106 | } |
106 | 107 | ||
107 | for (final element in keysToRemove) { | 108 | for (final element in keysToRemove) { |
108 | - GetInstance().delete(key: element); | 109 | + final value = GetInstance().delete(key: element); |
110 | + if (value) { | ||
109 | _routesKey.remove(element); | 111 | _routesKey.remove(element); |
110 | } | 112 | } |
113 | + } | ||
111 | 114 | ||
112 | keysToRemove.clear(); | 115 | keysToRemove.clear(); |
113 | } | 116 | } |
@@ -36,9 +36,11 @@ class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> { | @@ -36,9 +36,11 @@ class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> { | ||
36 | bool fullscreenDialog = false, | 36 | bool fullscreenDialog = false, |
37 | this.middlewares, | 37 | this.middlewares, |
38 | }) : super(settings: settings, fullscreenDialog: fullscreenDialog) { | 38 | }) : super(settings: settings, fullscreenDialog: fullscreenDialog) { |
39 | - RouterReportManager.reportCurrentRoute(this); | 39 | + _bla = this; |
40 | } | 40 | } |
41 | 41 | ||
42 | + late Route _bla; | ||
43 | + | ||
42 | @override | 44 | @override |
43 | final Duration transitionDuration; | 45 | final Duration transitionDuration; |
44 | final GetPageBuilder? page; | 46 | final GetPageBuilder? page; |
@@ -73,8 +75,17 @@ class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> { | @@ -73,8 +75,17 @@ class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> { | ||
73 | final bool maintainState; | 75 | final bool maintainState; |
74 | 76 | ||
75 | @override | 77 | @override |
78 | + void install() { | ||
79 | + super.install(); | ||
80 | + RouterReportManager.reportCurrentRoute(this); | ||
81 | + } | ||
82 | + | ||
83 | + @override | ||
76 | void dispose() { | 84 | void dispose() { |
77 | super.dispose(); | 85 | super.dispose(); |
86 | + if (_bla != this) { | ||
87 | + throw 'DJHOSIDS'; | ||
88 | + } | ||
78 | RouterReportManager.reportRouteDispose(this); | 89 | RouterReportManager.reportRouteDispose(this); |
79 | 90 | ||
80 | // if (Get.smartManagement != SmartManagement.onlyBuilder) { | 91 | // if (Get.smartManagement != SmartManagement.onlyBuilder) { |
@@ -85,12 +96,17 @@ class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> { | @@ -85,12 +96,17 @@ class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> { | ||
85 | middlewareRunner.runOnPageDispose(); | 96 | middlewareRunner.runOnPageDispose(); |
86 | } | 97 | } |
87 | 98 | ||
88 | - @override | ||
89 | - Widget buildContent(BuildContext context) { | 99 | + Widget? _child; |
100 | + | ||
101 | + Widget _getChild() { | ||
102 | + if (_child != null) return _child!; | ||
90 | final middlewareRunner = MiddlewareRunner(middlewares); | 103 | final middlewareRunner = MiddlewareRunner(middlewares); |
91 | - final bindingsToBind = middlewareRunner.runOnBindingsStart(bindings); | ||
92 | 104 | ||
93 | - binding?.dependencies(); | 105 | + final localbindings = [ |
106 | + if (bindings != null) ...bindings!, | ||
107 | + if (binding != null) ...[binding!] | ||
108 | + ]; | ||
109 | + final bindingsToBind = middlewareRunner.runOnBindingsStart(localbindings); | ||
94 | if (bindingsToBind != null) { | 110 | if (bindingsToBind != null) { |
95 | for (final binding in bindingsToBind) { | 111 | for (final binding in bindingsToBind) { |
96 | binding.dependencies(); | 112 | binding.dependencies(); |
@@ -98,7 +114,13 @@ class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> { | @@ -98,7 +114,13 @@ class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> { | ||
98 | } | 114 | } |
99 | 115 | ||
100 | final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!; | 116 | final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!; |
101 | - return middlewareRunner.runOnPageBuilt(pageToBuild()); | 117 | + _child = middlewareRunner.runOnPageBuilt(pageToBuild()); |
118 | + return _child!; | ||
119 | + } | ||
120 | + | ||
121 | + @override | ||
122 | + Widget buildContent(BuildContext context) { | ||
123 | + return _getChild(); | ||
102 | } | 124 | } |
103 | 125 | ||
104 | @override | 126 | @override |
1 | +import 'dart:async'; | ||
2 | + | ||
1 | import 'package:flutter/cupertino.dart'; | 3 | import 'package:flutter/cupertino.dart'; |
2 | import 'package:flutter/foundation.dart'; | 4 | import 'package:flutter/foundation.dart'; |
3 | import 'package:flutter/material.dart'; | 5 | import 'package:flutter/material.dart'; |
@@ -89,6 +91,8 @@ class GetPage<T> extends Page<T> { | @@ -89,6 +91,8 @@ class GetPage<T> extends Page<T> { | ||
89 | this.showCupertinoParallax = true, | 91 | this.showCupertinoParallax = true, |
90 | this.preventDuplicates = true, | 92 | this.preventDuplicates = true, |
91 | }) : path = _nameToRegex(name), | 93 | }) : path = _nameToRegex(name), |
94 | + assert(name.startsWith('/'), | ||
95 | + 'It is necessary to start route name [$name] with a slash: /$name'), | ||
92 | super( | 96 | super( |
93 | key: ValueKey(name), | 97 | key: ValueKey(name), |
94 | name: name, | 98 | name: name, |
@@ -175,10 +179,11 @@ class GetPage<T> extends Page<T> { | @@ -175,10 +179,11 @@ class GetPage<T> extends Page<T> { | ||
175 | @override | 179 | @override |
176 | Route<T> createRoute(BuildContext context) { | 180 | Route<T> createRoute(BuildContext context) { |
177 | // return GetPageRoute<T>(settings: this, page: page); | 181 | // return GetPageRoute<T>(settings: this, page: page); |
178 | - return PageRedirect( | 182 | + final _page = PageRedirect( |
179 | route: this, | 183 | route: this, |
180 | settings: this, | 184 | settings: this, |
181 | unknownRoute: unknownRoute, | 185 | unknownRoute: unknownRoute, |
182 | ).getPageToRoute<T>(this, unknownRoute); | 186 | ).getPageToRoute<T>(this, unknownRoute); |
187 | + return _page; | ||
183 | } | 188 | } |
184 | } | 189 | } |
@@ -181,8 +181,8 @@ class GetObserver extends NavigatorObserver { | @@ -181,8 +181,8 @@ class GetObserver extends NavigatorObserver { | ||
181 | Get.log("REPLACE ROUTE $oldName"); | 181 | Get.log("REPLACE ROUTE $oldName"); |
182 | Get.log("NEW ROUTE $newName"); | 182 | Get.log("NEW ROUTE $newName"); |
183 | 183 | ||
184 | - if (oldRoute != null) { | ||
185 | - RouterReportManager.reportCurrentRoute(oldRoute); | 184 | + if (newRoute != null) { |
185 | + RouterReportManager.reportCurrentRoute(newRoute); | ||
186 | } | 186 | } |
187 | 187 | ||
188 | _routeSend?.update((value) { | 188 | _routeSend?.update((value) { |
-
Please register or login to post a comment