Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Hoàng Văn Đạt
mypoint_flutter_app
Commits
6b980613
Commit
6b980613
authored
Nov 14, 2025
by
DatHV
Browse files
update project structure
parent
bfff9e47
Changes
507
Show whitespace changes
Inline
Side-by-side
lib/
screen
/splash/models/check_update_response_model.dart
→
lib/
features
/splash/models/check_update_response_model.dart
View file @
6b980613
File moved
lib/
screen
/splash/models/check_update_response_model.g.dart
→
lib/
features
/splash/models/check_update_response_model.g.dart
View file @
6b980613
File moved
lib/
screen
/splash/models/update_response_model.dart
→
lib/
features
/splash/models/update_response_model.dart
View file @
6b980613
import
'package:json_annotation/json_annotation.dart'
;
import
'package:mypoint_flutter_app/
screen
/splash/models/check_update_response_model.dart'
;
import
'package:mypoint_flutter_app/
features
/splash/models/check_update_response_model.dart'
;
part
'update_response_model.g.dart'
;
...
...
lib/
screen
/splash/models/update_response_model.g.dart
→
lib/
features
/splash/models/update_response_model.g.dart
View file @
6b980613
File moved
lib/
screen
/splash/splash_screen.dart
→
lib/
features
/splash/splash_screen.dart
View file @
6b980613
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/screen/splash/splash_screen_viewmodel.dart'
;
import
'package:mypoint_flutter_app/widgets/alert/custom_alert_dialog.dart'
;
import
'../../base/base_screen.dart'
;
import
'../../base/basic_state.dart'
;
import
'package:mypoint_flutter_app/features/splash/splash_screen_viewmodel.dart'
;
import
'package:mypoint_flutter_app/shared/widgets/alert/custom_alert_dialog.dart'
;
import
'package:mypoint_flutter_app/core/services/web/web_helper.dart'
;
import
'../../shared/widgets/base_view/base_screen.dart'
;
import
'../../shared/widgets/base_view/basic_state.dart'
;
import
'models/check_update_response_model.dart'
;
import
'../../
resources
/base_color.dart'
;
import
'../../widgets/alert/data_alert_model.dart'
;
import
'../../
core/theme
/base_color.dart'
;
import
'../../
shared/
widgets/alert/data_alert_model.dart'
;
class
SplashScreen
extends
BaseScreen
{
const
SplashScreen
({
super
.
key
});
...
...
@@ -18,11 +19,12 @@ class SplashScreen extends BaseScreen {
class
_SplashScreenState
extends
BaseState
<
SplashScreen
>
with
BasicState
{
final
SplashScreenViewModel
_viewModel
=
Get
.
put
(
SplashScreenViewModel
());
Future
<
void
>?
_webSplashCacheFuture
;
bool
_webLoaderNotified
=
false
;
@override
void
initState
()
{
super
.
initState
();
print
(
'🚀 SplashScreen - initState
${DateTime.now().toString()}
'
);
_viewModel
.
checkUpdateResponse
=
(
data
)
{
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
final
updateData
=
(
data
?.
updateRequest
??
[]).
firstOrNull
;
...
...
@@ -40,6 +42,31 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState {
_viewModel
.
checkUpdateApp
();
}
@override
void
didChangeDependencies
()
{
super
.
didChangeDependencies
();
if
(
kIsWeb
&&
_webSplashCacheFuture
==
null
)
{
_webSplashCacheFuture
=
precacheImage
(
const
AssetImage
(
'assets/images/splash_screen.webp'
),
context
,
).
catchError
((
error
,
stackTrace
)
{
debugPrint
(
'Failed to precache splash background:
$error
'
);
debugPrintStack
(
stackTrace:
stackTrace
);
}).
whenComplete
(()
{
if
(!
mounted
)
return
;
WidgetsBinding
.
instance
.
addPostFrameCallback
((
_
)
{
_notifyWebLoaderReady
();
});
});
}
}
void
_notifyWebLoaderReady
()
{
if
(!
kIsWeb
||
_webLoaderNotified
||
!
mounted
)
return
;
_webLoaderNotified
=
true
;
webNotifySplashScreenReady
();
}
@override
Widget
createBody
()
{
final
path
=
kIsWeb
?
"assets/images/splash_screen.webp"
:
"assets/images/splash_screen.png"
;
...
...
@@ -53,7 +80,9 @@ class _SplashScreenState extends BaseState<SplashScreen> with BasicState {
height:
double
.
infinity
,
fit:
BoxFit
.
cover
,
),
Center
(
child:
CircularProgressIndicator
()),
Center
(
child:
kIsWeb
?
SizedBox
.
shrink
()
:
CircularProgressIndicator
()
)
],
),
);
...
...
lib/
screen
/splash/splash_screen_viewmodel.dart
→
lib/
features
/splash/splash_screen_viewmodel.dart
View file @
6b980613
import
'dart:async'
;
import
'package:flutter/foundation.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/network
ing
/restful_api_viewmodel.dart'
;
import
'package:mypoint_flutter_app/network
ing
/restful_api_client_all_request.dart'
;
import
'package:mypoint_flutter_app/
core/utils/
extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/
core/
network/restful_api_viewmodel.dart'
;
import
'package:mypoint_flutter_app/
core/
network/restful_api_client_all_request.dart'
;
import
'package:mypoint_flutter_app/shared/router_gage.dart'
;
import
'../
..
/model/
auth/
login_token_response_model.dart'
;
import
'../
..
/model/
auth/
profile_response_model.dart'
;
import
'../
login
/model/login_token_response_model.dart'
;
import
'../
personal
/model/profile_response_model.dart'
;
import
'models/update_response_model.dart'
;
import
'../../preference/data_preference.dart'
;
import
'../../preference/point/point_manager.dart'
;
import
'../../
shared/
preference
s
/data_preference.dart'
;
import
'../../
shared/
preference
s
/point/point_manager.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'../../web/web_helper.dart'
;
import
'../../
core/services/
web/web_helper.dart'
;
import
'../popup_manager/popup_manager_viewmodel.dart'
;
class
SplashScreenViewModel
extends
RestfulApiViewModel
{
...
...
lib/
screen
/support/support_item_model.dart
→
lib/
features
/support/support_item_model.dart
View file @
6b980613
import
'package:json_annotation/json_annotation.dart'
;
// part 'support_item_model.g.dart';
enum
SupportItemType
{
mail
,
phone
,
facebook
,
question
,
termsOfUse
,
privacyPolicy
}
@JsonSerializable
()
...
...
lib/
screen
/support/support_screen.dart
→
lib/
features
/support/support_screen.dart
View file @
6b980613
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/
screen
/support/support_item_model.dart'
;
import
'package:mypoint_flutter_app/
screen
/support/support_screen_viewmodel.dart'
;
import
'package:mypoint_flutter_app/
features
/support/support_item_model.dart'
;
import
'package:mypoint_flutter_app/
features
/support/support_screen_viewmodel.dart'
;
import
'package:mypoint_flutter_app/shared/router_gage.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'package:universal_html/js_util.dart'
as
js_util
;
import
'../../widgets/custom_navigation_bar.dart'
;
import
'../../
shared/
widgets/custom_navigation_bar.dart'
;
import
'../faqs/faqs_screen.dart'
;
import
'../pageDetail/model/detail_page_rule_type.dart'
;
import
'../../web/web_helper.dart'
;
import
'../../
core/services/
web/web_helper.dart'
;
class
SupportScreen
extends
StatefulWidget
{
const
SupportScreen
({
super
.
key
});
...
...
@@ -123,8 +123,6 @@ class _SupportScreenState extends State<SupportScreen> {
return
Icons
.
receipt_long
;
case
SupportItemType
.
privacyPolicy
:
return
Icons
.
lock_outline
;
default
:
return
Icons
.
info
;
}
}
...
...
lib/
screen
/support/support_screen_viewmodel.dart
→
lib/
features
/support/support_screen_viewmodel.dart
View file @
6b980613
...
...
@@ -2,7 +2,7 @@ import 'dart:convert';
import
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/
screen
/support/support_item_model.dart'
;
import
'package:mypoint_flutter_app/
features
/support/support_item_model.dart'
;
class
SupportViewModel
extends
GetxController
{
var
supportItems
=
<
SupportItemModel
>[].
obs
;
...
...
lib/
screen
/topup/brand_select_sheet_widget.dart
→
lib/
features
/topup/brand_select_sheet_widget.dart
View file @
6b980613
import
'package:flutter/material.dart'
;
import
'package:mypoint_flutter_app/widgets/image_loader.dart'
;
import
'package:mypoint_flutter_app/
shared/
widgets/image_loader.dart'
;
import
'../voucher/models/product_brand_model.dart'
;
class
BrandSelectSheet
extends
StatelessWidget
{
...
...
lib/
screen
/topup/models/brand_network_model.dart
→
lib/
features
/topup/models/brand_network_model.dart
View file @
6b980613
File moved
lib/
screen
/topup/models/brand_network_model.g.dart
→
lib/
features
/topup/models/brand_network_model.g.dart
View file @
6b980613
File moved
lib/
screen
/topup/topup_screen.dart
→
lib/
features
/topup/topup_screen.dart
View file @
6b980613
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:intl/intl.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/
screen
/topup/topup_viewmodel.dart'
;
import
'package:mypoint_flutter_app/widgets/custom_navigation_bar.dart'
;
import
'package:mypoint_flutter_app/widgets/image_loader.dart'
;
import
'../../
base
/base_screen.dart'
;
import
'../../
base
/basic_state.dart'
;
import
'../../
extension
s/debouncer.dart'
;
import
'../../preference/data_preference.dart'
;
import
'../../
resources
/base_color.dart'
;
import
'package:mypoint_flutter_app/
core/utils/
extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/
features
/topup/topup_viewmodel.dart'
;
import
'package:mypoint_flutter_app/
shared/
widgets/custom_navigation_bar.dart'
;
import
'package:mypoint_flutter_app/
shared/
widgets/image_loader.dart'
;
import
'../../
shared/widgets/base_view
/base_screen.dart'
;
import
'../../
shared/widgets/base_view
/basic_state.dart'
;
import
'../../
core/util
s/debouncer.dart'
;
import
'../../
shared/
preference
s
/data_preference.dart'
;
import
'../../
core/theme
/base_color.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../contacts/contacts_picker.dart'
;
import
'brand_select_sheet_widget.dart'
;
...
...
@@ -110,7 +110,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState
selectedBrand:
_viewModel
.
selectedBrand
.
value
,
onSelected:
(
brand
)
{
Navigator
.
pop
(
context
);
if
(
brand
==
null
&&
brand
.
id
!=
_viewModel
.
selectedBrand
.
value
?.
id
)
return
;
if
(
brand
.
id
!=
_viewModel
.
selectedBrand
.
value
?.
id
)
return
;
_viewModel
.
selectedProduct
.
value
=
null
;
_viewModel
.
selectedBrand
.
value
=
brand
;
_viewModel
.
getTelcoDetail
();
...
...
@@ -154,7 +154,7 @@ class _PhoneTopUpScreenState extends BaseState<PhoneTopUpScreen> with BasicState
scrollDirection:
Axis
.
horizontal
,
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
8
),
itemCount:
histories
.
length
,
separatorBuilder:
(
_
,
_
_
)
=>
const
SizedBox
(
width:
8
),
separatorBuilder:
(
_
,
_
)
=>
const
SizedBox
(
width:
8
),
itemBuilder:
(
_
,
index
)
{
final
phone
=
histories
[
index
];
final
myPhone
=
DataPreference
.
instance
.
phone
??
''
;
...
...
lib/
screen
/topup/topup_viewmodel.dart
→
lib/
features
/topup/topup_viewmodel.dart
View file @
6b980613
import
'package:get/get.dart'
;
import
'package:get/get_rx/src/rx_types/rx_types.dart'
;
import
'package:mypoint_flutter_app/network
ing
/api/product_api.dart'
deferred
as
product_api
;
import
'package:mypoint_flutter_app/preference/data_preference.dart'
;
import
'package:mypoint_flutter_app/
screen
/topup/models/brand_network_model.dart'
;
import
'../../
base
/base_response_model.dart'
;
import
'../../network
ing
/restful_api_viewmodel.dart'
;
import
'../../
preferen
ce/contact_storage_service.dart'
;
import
'package:mypoint_flutter_app/
core/
network/api/product_api.dart'
deferred
as
product_api
;
import
'package:mypoint_flutter_app/
shared/
preference
s
/data_preference.dart'
;
import
'package:mypoint_flutter_app/
features
/topup/models/brand_network_model.dart'
;
import
'../../
shared/widgets/base_view
/base_response_model.dart'
;
import
'../../
core/
network/restful_api_viewmodel.dart'
;
import
'../../
core/servi
ce
s
/contact_storage_service.dart'
;
import
'../voucher/models/product_brand_model.dart'
;
import
'../voucher/models/product_model.dart'
;
import
'../voucher/models/product_type.dart'
;
...
...
@@ -50,11 +50,11 @@ class TopUpViewModel extends RestfulApiViewModel {
}
}
firstLoadTopUpData
()
async
{
Future
<
void
>
firstLoadTopUpData
()
async
{
_getTopUpBrands
();
}
_getTopUpBrands
()
async
{
Future
<
void
>
_getTopUpBrands
()
async
{
await
callApi
<
List
<
ProductBrandModel
>>(
request:
()
=>
_callProductApi
((
api
)
=>
api
.
getTopUpBrands
(
ProductType
.
topupMobile
)),
onSuccess:
(
data
,
_
)
{
...
...
@@ -65,11 +65,11 @@ class TopUpViewModel extends RestfulApiViewModel {
);
}
checkMobileNetwork
()
async
{
Future
<
void
>
checkMobileNetwork
()
async
{
await
callApi
<
BrandNameCheckResponse
>(
request:
()
=>
_callProductApi
((
api
)
=>
api
.
checkMobileNetwork
(
phoneNumber
.
value
)),
onSuccess:
(
data
,
_
)
{
final
brandCode
=
data
?
.
brand
??
''
;
final
brandCode
=
data
.
brand
??
''
;
var
brand
=
topUpBrands
.
isNotEmpty
?
topUpBrands
.
firstWhere
(
(
brand
)
=>
brand
.
code
==
brandCode
,
...
...
lib/
screen
/traffic_service/traffic_service_certificate_screen.dart
→
lib/
features
/traffic_service/traffic_service_certificate_screen.dart
View file @
6b980613
import
'dart:io'
;
import
'package:file_saver/file_saver.dart'
;
import
'package:flutter/material.dart'
;
import
'package:share_plus/share_plus.dart'
;
import
'package:webview_flutter/webview_flutter.dart'
;
import
'package:path_provider/path_provider.dart'
;
import
'package:http/http.dart'
as
http
;
import
'../../
base
/app_loading.dart'
;
import
'../../
base
/base_screen.dart'
;
import
'../../
base
/basic_state.dart'
;
import
'../../
resources
/base_color.dart'
;
import
'../../widgets/custom_navigation_bar.dart'
;
import
'../../
shared/widgets/loading
/app_loading.dart'
;
import
'../../
shared/widgets/base_view
/base_screen.dart'
;
import
'../../
shared/widgets/base_view
/basic_state.dart'
;
import
'../../
core/theme
/base_color.dart'
;
import
'../../
shared/
widgets/custom_navigation_bar.dart'
;
import
'dart:typed_data'
as
typed_data
;
class
TrafficServiceCertificateScreen
extends
BaseScreen
{
...
...
lib/
screen
/traffic_service/traffic_service_detail_screen.dart
→
lib/
features
/traffic_service/traffic_service_detail_screen.dart
View file @
6b980613
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/
screen
/traffic_service/traffic_service_certificate_screen.dart'
;
import
'package:mypoint_flutter_app/
screen
/traffic_service/traffic_service_model.dart'
;
import
'package:mypoint_flutter_app/
screen
/traffic_service/traffic_service_viewmodel.dart'
;
import
'package:mypoint_flutter_app/widgets/custom_empty_widget.dart'
;
import
'package:mypoint_flutter_app/
features
/traffic_service/traffic_service_certificate_screen.dart'
;
import
'package:mypoint_flutter_app/
features
/traffic_service/traffic_service_model.dart'
;
import
'package:mypoint_flutter_app/
features
/traffic_service/traffic_service_viewmodel.dart'
;
import
'package:mypoint_flutter_app/
shared/
widgets/custom_empty_widget.dart'
;
import
'package:url_launcher/url_launcher.dart'
;
import
'../../
resources
/base_color.dart'
;
import
'../../widgets/custom_navigation_bar.dart'
;
import
'../../
core/theme
/base_color.dart'
;
import
'../../
shared/
widgets/custom_navigation_bar.dart'
;
class
TrafficServiceDetailScreen
extends
StatefulWidget
{
const
TrafficServiceDetailScreen
({
super
.
key
});
...
...
@@ -52,7 +52,7 @@ class _TrafficServiceDetailScreenState extends State<TrafficServiceDetailScreen>
body:
Obx
(()
{
final
model
=
_viewModel
.
trafficServiceDetail
.
value
;
if
(
model
==
null
)
{
return
const
Center
(
child:
EmptyWidget
());
return
Center
(
child:
EmptyWidget
(
isLoading:
_viewModel
.
isLoading
.
value
));
}
return
Column
(
children:
[
...
...
lib/
screen
/traffic_service/traffic_service_model.dart
→
lib/
features
/traffic_service/traffic_service_model.dart
View file @
6b980613
import
'package:mypoint_flutter_app/
direc
tion
al
/directional_screen.dart'
;
import
'package:mypoint_flutter_app/extensions/datetime_extensions.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/
shared/naviga
tion/directional_screen.dart'
;
import
'package:mypoint_flutter_app/
core/utils/
extensions/datetime_extensions.dart'
;
import
'package:mypoint_flutter_app/
core/utils/
extensions/string_extension.dart'
;
enum
SortFilter
{
asc
,
desc
}
...
...
@@ -30,12 +30,12 @@ class HeaderFilterOrderModel {
String
get
eventNameTracking
{
if
(
sort
==
null
)
{
return
'soskdt_
$
{
suffixChecking
}
'
;
return
'soskdt_
$suffixChecking
'
;
}
return
'soskdt_
${suffixChecking}
_
${sort!.name}
'
;
}
String
get
eventNameTrackingDvCar
=>
'dvcar_
$
{
suffixChecking
}
'
;
String
get
eventNameTrackingDvCar
=>
'dvcar_
$suffixChecking
'
;
}
class
TrafficServiceResponseModel
{
...
...
lib/
screen
/traffic_service/traffic_service_screen.dart
→
lib/
features
/traffic_service/traffic_service_screen.dart
View file @
6b980613
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:get/get.dart'
;
import
'package:mypoint_flutter_app/extensions/datetime_extensions.dart'
;
import
'package:mypoint_flutter_app/extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/screen/traffic_service/traffic_service_detail_screen.dart'
;
import
'package:mypoint_flutter_app/screen/traffic_service/traffic_service_viewmodel.dart'
;
import
'package:mypoint_flutter_app/widgets/custom_empty_widget.dart'
;
import
'package:mypoint_flutter_app/widgets/image_loader.dart'
;
import
'../../extensions/date_format.dart'
;
import
'../../resources/base_color.dart'
;
import
'package:mypoint_flutter_app/core/utils/extensions/datetime_extensions.dart'
;
import
'package:mypoint_flutter_app/core/utils/extensions/string_extension.dart'
;
import
'package:mypoint_flutter_app/features/traffic_service/traffic_service_viewmodel.dart'
;
import
'package:mypoint_flutter_app/shared/widgets/custom_empty_widget.dart'
;
import
'package:mypoint_flutter_app/shared/widgets/image_loader.dart'
;
import
'../../core/utils/extensions/date_format.dart'
;
import
'../../core/theme/base_color.dart'
;
import
'../../shared/router_gage.dart'
;
import
'../../widgets/custom_navigation_bar.dart'
;
import
'../../
shared/
widgets/custom_navigation_bar.dart'
;
class
TrafficServiceScreen
extends
StatefulWidget
{
const
TrafficServiceScreen
({
super
.
key
});
...
...
@@ -72,7 +70,7 @@ class _TrafficServiceScreenState extends State<TrafficServiceScreen> {
child:
Obx
(()
{
final
products
=
_viewModel
.
trafficData
.
value
?.
products
??
[];
return
products
.
isEmpty
?
Center
(
child:
EmptyWidget
())
?
Center
(
child:
EmptyWidget
(
isLoading:
_viewModel
.
isLoading
.
value
))
:
ListView
.
builder
(
itemCount:
products
.
length
,
itemBuilder:
(
context
,
index
)
{
...
...
lib/
screen
/traffic_service/traffic_service_viewmodel.dart
→
lib/
features
/traffic_service/traffic_service_viewmodel.dart
View file @
6b980613
import
'package:get/get_rx/src/rx_types/rx_types.dart'
;
import
'package:mypoint_flutter_app/config
s
/constants.dart'
;
import
'package:mypoint_flutter_app/network
ing
/api/product_api.dart'
deferred
as
product_api
;
import
'package:mypoint_flutter_app/network
ing
/restful_api_client_all_request.dart'
;
import
'package:mypoint_flutter_app/
screen
/traffic_service/traffic_service_model.dart'
;
import
'../../network
ing
/restful_api_viewmodel.dart'
;
import
'../../
base
/base_response_model.dart'
;
import
'package:mypoint_flutter_app/
app/
config/constants.dart'
;
import
'package:mypoint_flutter_app/
core/
network/api/product_api.dart'
deferred
as
product_api
;
import
'package:mypoint_flutter_app/
core/
network/restful_api_client_all_request.dart'
;
import
'package:mypoint_flutter_app/
features
/traffic_service/traffic_service_model.dart'
;
import
'../../
core/
network/restful_api_viewmodel.dart'
;
import
'../../
shared/widgets/base_view
/base_response_model.dart'
;
class
TrafficServiceViewModel
extends
RestfulApiViewModel
{
var
trafficData
=
Rxn
<
TrafficServiceResponseModel
>();
...
...
lib/
screen
/transaction/history/transaction_category_model.dart
→
lib/
features
/transaction/history/transaction_category_model.dart
View file @
6b980613
...
...
@@ -2,11 +2,8 @@ class TransactionCategoryModel {
int
?
id
;
String
?
code
;
String
?
name
;
bool
_isSelected
=
false
;
bool
get
isSelected
=>
_isSelected
;
set
isSelected
(
bool
value
)
=>
_isSelected
=
value
;
TransactionCategoryModel
({
this
.
id
,
...
...
Prev
1
…
15
16
17
18
19
20
21
22
23
…
26
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment