Commit 6532e234 authored by 林生雨's avatar 林生雨

comiit

parent 1253304c
......@@ -10,6 +10,10 @@ import 'dart:io';
import 'package:rxdart/rxdart.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:gmalpha_flutter/ActivityReportModel/service/remote/entity/ActivityReportEntity.dart';
import 'package:gmalpha_flutter/commonModel/net/DioUtil.dart';
......@@ -30,11 +34,19 @@ class ActivityReportApiImpl {
Observable<ActivityReportEntity> getActivityReport(int id, int type) {
return Observable.fromFuture(DioUtil().get('api/v1/survey_question/report',
data: {'survey_record_id': id, 'template_id': type})).map((value) {
data: {'survey_record_id': id, 'template_id': type})).flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return ActivityReportEntity.fromJson(map);
// Map map = json.decode(value.toString());
// return ActivityReportEntity.fromJson(map);
return Observable.fromFuture(
compute(paseActivityReportEntity, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
}
ActivityReportEntity paseActivityReportEntity(String value) {
return ActivityReportEntity.fromJson(json.decode(value));
}
......@@ -24,6 +24,7 @@ class ServiceGenerator extends GeneratorForAnnotation<ServiceCenter> {
}
StringBuffer improtBuffer = new StringBuffer();
StringBuffer methodBuffer = StringBuffer("");
StringBuffer outBuffer=StringBuffer();
StringBuffer mapBuffer = new StringBuffer();
List<String> differentList = [];
for (var methodElement in (element as ClassElement).methods) {
......@@ -31,10 +32,10 @@ class ServiceGenerator extends GeneratorForAnnotation<ServiceCenter> {
final metadata = annometadata.computeConstantValue();
if (metadata.type.name == "Post" || metadata.type.name == "Get") {
if (!differentList.contains(methodElement.returnType.name)) {
if(methodElement.returnType.name=="SimpleResponce"){
if (methodElement.returnType.name == "SimpleResponce") {
improtBuffer.write(
"import 'package:gmalpha_flutter/commonModel/net/Responce/SimpleResponce.dart';\n");
}else {
} else {
var pathSegments = buildStep.inputId.pathSegments;
StringBuffer path = new StringBuffer();
for (int i = 0; i < pathSegments.length; i++) {
......@@ -43,9 +44,7 @@ class ServiceGenerator extends GeneratorForAnnotation<ServiceCenter> {
}
}
improtBuffer.write(
"import 'package:${buildStep.inputId.package}/${path
.toString()}entity/${methodElement.returnType
.name}.dart\';\n");
"import 'package:${buildStep.inputId.package}/${path.toString()}entity/${methodElement.returnType.name}.dart\';\n");
}
differentList.add(methodElement.returnType.name);
}
......@@ -68,15 +67,15 @@ class ServiceGenerator extends GeneratorForAnnotation<ServiceCenter> {
} else {
tempParams = "${tempParams},${paramsMeta}";
}
if(i==0){
if (i == 0) {
mapBuffer.write(
",data:{\'${queryAnno.getField("params").toStringValue()}\':${paramsMeta.name}");
if(methodElement.parameters.length>1){
if (methodElement.parameters.length > 1) {
mapBuffer.write(",");
}else{
} else {
mapBuffer.write("}");
}
}else if (i == methodElement.parameters.length - 1) {
} else if (i == methodElement.parameters.length - 1) {
mapBuffer.write(
"\'${queryAnno.getField("params").toStringValue()}\':${paramsMeta.name}}");
} else {
......@@ -90,11 +89,19 @@ class ServiceGenerator extends GeneratorForAnnotation<ServiceCenter> {
// throw HttpException("RESPONCE error :\${value}");
// }
mapBuffer.write("))");
outBuffer.write("""
${methodElement.returnType.name} pase${methodElement.returnType.name}(String value){
return ${methodElement.returnType.name}.fromJson(json.decode(value));
}\n
""");
mapBuffer.write("""
.map((value){
.flatMap((value){
if(value!=null&&value.statusCode==200){
Map map = json.decode(value.toString());
return ${methodElement.returnType.name}.fromJson(map);
// Map map = json.decode(value.toString());
// return ${methodElement.returnType.name}.fromJson(map);
return Observable.fromFuture(compute(pase${methodElement.returnType.name}, value.toString()));
}else {
return Observable.fromFuture(null);
}
});
""");
......@@ -112,6 +119,8 @@ class ServiceGenerator extends GeneratorForAnnotation<ServiceCenter> {
import 'dart:convert';\n
import 'dart:io';\n
import 'package:rxdart/rxdart.dart';\n
import 'package:dio/dio.dart';\n
import 'package:flutter/foundation.dart';\n
${improtBuffer.toString()}
import 'package:gmalpha_flutter/commonModel/net/DioUtil.dart';\n
class ${element.displayName}Impl{
......@@ -131,6 +140,7 @@ class ServiceGenerator extends GeneratorForAnnotation<ServiceCenter> {
${methodBuffer.toString()}
}
${outBuffer.toString()}
""";
}
}
......@@ -4,26 +4,26 @@
// RouterCenterGenerator
// **************************************************************************
//NewMessageRouterImpl is resign : true
//PrestigeImpl is resign : true
//BuriedImpl is resign : true
//AlbumRouterImpl is resign : true
//ActivityReportRouterImpl is resign : true
//BuriedImpl is resign : true
//MessageRouterImpl is resign : true
//NewMessageRouterImpl is resign : true
//PrestigeImpl is resign : true
//UserRouterImpl is resign : true
import "package:gmalpha_flutter/NewMessageModel/NewMessageRouterImpl.dart";
import "package:gmalpha_flutter/NewMessageModel/NewMessageRouter.dart";
import "package:gmalpha_flutter/PrestigeModel/PrestigeImpl.dart";
import "package:gmalpha_flutter/PrestigeModel/PrestigeRouter.dart";
import "package:gmalpha_flutter/BuriedLib/BuriedImpl.dart";
import "package:gmalpha_flutter/BuriedLib/BuriedRouter.dart";
import "package:gmalpha_flutter/AlbumModel/AlbumRouterImpl.dart";
import "package:gmalpha_flutter/AlbumModel/AlbumRouter.dart";
import "package:gmalpha_flutter/ActivityReportModel/ActivityReportRouterImpl.dart";
import "package:gmalpha_flutter/ActivityReportModel/ActivityReportRouter.dart";
import "package:gmalpha_flutter/BuriedLib/BuriedImpl.dart";
import "package:gmalpha_flutter/BuriedLib/BuriedRouter.dart";
import "package:gmalpha_flutter/messageModel/MessageRouterImpl.dart";
import "package:gmalpha_flutter/messageModel/MessageRouter.dart";
import "package:gmalpha_flutter/NewMessageModel/NewMessageRouterImpl.dart";
import "package:gmalpha_flutter/NewMessageModel/NewMessageRouter.dart";
import "package:gmalpha_flutter/PrestigeModel/PrestigeImpl.dart";
import "package:gmalpha_flutter/PrestigeModel/PrestigeRouter.dart";
import "package:gmalpha_flutter/userModel/UserRouterImpl.dart";
import "package:gmalpha_flutter/userModel/UserRouter.dart";
......@@ -54,12 +54,12 @@ class RouterCenterImpl {
}
void init() {
map.putIfAbsent("NewMessageModel", () => NewMessageRouterImpl());
map.putIfAbsent("prestigeModel", () => PrestigeImpl());
map.putIfAbsent("buried_router", () => BuriedImpl());
map.putIfAbsent("albumModel", () => AlbumRouterImpl());
map.putIfAbsent("ActivityReportModel", () => ActivityReportRouterImpl());
map.putIfAbsent("buried_router", () => BuriedImpl());
map.putIfAbsent("messageModel", () => MessageRouterImpl());
map.putIfAbsent("NewMessageModel", () => NewMessageRouterImpl());
map.putIfAbsent("prestigeModel", () => PrestigeImpl());
map.putIfAbsent("userModel", () => UserRouterImpl());
}
......@@ -67,18 +67,18 @@ class RouterCenterImpl {
return map[modelName];
}
AlbumRouter findAlbumRouter() {
if (map["albumModel"] == null) {
NewMessageRouter findNewMessageRouter() {
if (map["NewMessageModel"] == null) {
return null;
}
return map["albumModel"] as AlbumRouter;
return map["NewMessageModel"] as NewMessageRouter;
}
ActivityReportRouter findActivityReportRouter() {
if (map["ActivityReportModel"] == null) {
PrestigeRouter findPrestigeRouter() {
if (map["prestigeModel"] == null) {
return null;
}
return map["ActivityReportModel"] as ActivityReportRouter;
return map["prestigeModel"] as PrestigeRouter;
}
BuriedRouter findBuriedRouter() {
......@@ -88,25 +88,25 @@ class RouterCenterImpl {
return map["buried_router"] as BuriedRouter;
}
MessageRouter findMessageRouter() {
if (map["messageModel"] == null) {
AlbumRouter findAlbumRouter() {
if (map["albumModel"] == null) {
return null;
}
return map["messageModel"] as MessageRouter;
return map["albumModel"] as AlbumRouter;
}
NewMessageRouter findNewMessageRouter() {
if (map["NewMessageModel"] == null) {
ActivityReportRouter findActivityReportRouter() {
if (map["ActivityReportModel"] == null) {
return null;
}
return map["NewMessageModel"] as NewMessageRouter;
return map["ActivityReportModel"] as ActivityReportRouter;
}
PrestigeRouter findPrestigeRouter() {
if (map["prestigeModel"] == null) {
MessageRouter findMessageRouter() {
if (map["messageModel"] == null) {
return null;
}
return map["prestigeModel"] as PrestigeRouter;
return map["messageModel"] as MessageRouter;
}
UserRouter findUserRouter() {
......
......@@ -27,7 +27,7 @@ abstract class MessageApi{
@Get('api/v1/message/notice')
AttentionEntity getAttentionList(@Query('page') int page, @Query('count') int count);
@Get('/api/v1/follow/list')
@Get('/api/v1/follow/list')
FocusPageEntity getFocusPage(@Query('type') int type, @Query('page') int page, @Query('count') int count);
}
\ No newline at end of file
......@@ -10,6 +10,10 @@ import 'dart:io';
import 'package:rxdart/rxdart.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:gmalpha_flutter/NewMessageModel/service/remote/entity/MyMessageEntity.dart';
import 'package:gmalpha_flutter/NewMessageModel/service/remote/entity/UnreadMessageEntity.dart';
import 'package:gmalpha_flutter/NewMessageModel/service/remote/entity/LatestMessageEntity.dart';
......@@ -35,10 +39,14 @@ class MessageApiImpl {
Observable<MyMessageEntity> getMyMessage(int page, int count) {
return Observable.fromFuture(DioUtil().get('api/v1/message/my',
data: {'page': page, 'count': count})).map((value) {
data: {'page': page, 'count': count})).flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return MyMessageEntity.fromJson(map);
// Map map = json.decode(value.toString());
// return MyMessageEntity.fromJson(map);
return Observable.fromFuture(
compute(paseMyMessageEntity, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
......@@ -46,51 +54,95 @@ class MessageApiImpl {
Observable<UnreadMessageEntity> getUnreadMessage(int type) {
return Observable.fromFuture(
DioUtil().get('api/v1/message/unread', data: {'type': type}))
.map((value) {
.flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return UnreadMessageEntity.fromJson(map);
// Map map = json.decode(value.toString());
// return UnreadMessageEntity.fromJson(map);
return Observable.fromFuture(
compute(paseUnreadMessageEntity, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<LatestMessageEntity> getLatestMessage() {
return Observable.fromFuture(DioUtil().get('api/v1/push/newest/info'))
.map((value) {
.flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return LatestMessageEntity.fromJson(map);
// Map map = json.decode(value.toString());
// return LatestMessageEntity.fromJson(map);
return Observable.fromFuture(
compute(paseLatestMessageEntity, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<LikePageEntity> getLikePage(int page, int count) {
return Observable.fromFuture(DioUtil().get('api/v1/message/like',
data: {'page': page, 'count': count})).map((value) {
data: {'page': page, 'count': count})).flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return LikePageEntity.fromJson(map);
// Map map = json.decode(value.toString());
// return LikePageEntity.fromJson(map);
return Observable.fromFuture(
compute(paseLikePageEntity, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<AttentionEntity> getAttentionList(int page, int count) {
return Observable.fromFuture(DioUtil().get('api/v1/message/notice',
data: {'page': page, 'count': count})).map((value) {
data: {'page': page, 'count': count})).flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return AttentionEntity.fromJson(map);
// Map map = json.decode(value.toString());
// return AttentionEntity.fromJson(map);
return Observable.fromFuture(
compute(paseAttentionEntity, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<FocusPageEntity> getFocusPage(int type, int page, int count) {
return Observable.fromFuture(DioUtil().get('/api/v1/follow/list',
data: {'type': type, 'page': page, 'count': count})).map((value) {
data: {'type': type, 'page': page, 'count': count})).flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return FocusPageEntity.fromJson(map);
// Map map = json.decode(value.toString());
// return FocusPageEntity.fromJson(map);
return Observable.fromFuture(
compute(paseFocusPageEntity, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
}
MyMessageEntity paseMyMessageEntity(String value) {
return MyMessageEntity.fromJson(json.decode(value));
}
UnreadMessageEntity paseUnreadMessageEntity(String value) {
return UnreadMessageEntity.fromJson(json.decode(value));
}
LatestMessageEntity paseLatestMessageEntity(String value) {
return LatestMessageEntity.fromJson(json.decode(value));
}
LikePageEntity paseLikePageEntity(String value) {
return LikePageEntity.fromJson(json.decode(value));
}
AttentionEntity paseAttentionEntity(String value) {
return AttentionEntity.fromJson(json.decode(value));
}
FocusPageEntity paseFocusPageEntity(String value) {
return FocusPageEntity.fromJson(json.decode(value));
}
......@@ -10,6 +10,10 @@ import 'dart:io';
import 'package:rxdart/rxdart.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:gmalpha_flutter/PrestigeModel/service/remote/entity/PrestigeEntity.dart';
import 'package:gmalpha_flutter/commonModel/net/DioUtil.dart';
......@@ -31,11 +35,19 @@ class PrestigeApiImpl {
Observable<PrestigeEntity> getReputations(int userId) {
return Observable.fromFuture(
DioUtil().get('api/v1/reputations', data: {'user_id': userId}))
.map((value) {
.flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return PrestigeEntity.fromJson(map);
// Map map = json.decode(value.toString());
// return PrestigeEntity.fromJson(map);
return Observable.fromFuture(
compute(pasePrestigeEntity, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
}
PrestigeEntity pasePrestigeEntity(String value) {
return PrestigeEntity.fromJson(json.decode(value));
}
......@@ -13,7 +13,7 @@ class TestPage extends StatelessWidget {
TestPage() {
Api.getInstance().setDioCookie({
'Cookie':
'sessionid=ley6ne6wdi3w4sapyqgwa5mtjberyaum;_gtid=d7fdc2def3b311e99a80525400e82fab3556;_gm_token=4ab9e41571629122'
'sessionid=oji01pi0mou9l5ktg425mibrimyq5vc3;_gtid=120408d4f3c911e99a80525400e82fab6178;_gm_token=06e9361571644418'
});
}
......
/*
* @author lsy
* @date 2019-10-21
**/
import 'dart:isolate';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
class IsolateUtil {
static ReceivePort receivePort = ReceivePort();
static Future<T> paseJsonByIsolate<T>(Function function) async {
// 通过spawn新建一个isolate,并绑定静态方法
await Isolate.spawn(dataLoader, receivePort.sendPort);
// 获取新isolate的监听port
SendPort sendPort = await receivePort.first;
// 调用sendReceive自定义方法
return await sendReceive(sendPort, function);
}
// isolate的绑定方法
static dataLoader(SendPort sendPort) async {
// 创建监听port,并将sendPort传给外界用来调用
ReceivePort receivePort = ReceivePort();
sendPort.send(receivePort.sendPort);
// 监听外界调用
await for (var msg in receivePort) {
SendPort callbackPort = msg[0];
Function function = msg[1];
callbackPort.send(function());
}
}
// 创建自己的监听port,并且向新isolate发送消息
static Future sendReceive(SendPort sendPort, Function function) {
ReceivePort receivePort = ReceivePort();
sendPort.send([receivePort.sendPort, function]);
// 接收到返回值,返回给调用者
return receivePort.first;
}
}
......@@ -9,13 +9,13 @@ import 'package:gmalpha_flutter/Error_Page.dart';
import 'package:gmalpha_flutter/TestPage.dart';
import 'package:gmalpha_flutter/commonModel/cache/CacheManager.dart';
import 'package:gmalpha_flutter/commonModel/net/Api.dart';
import 'package:gmalpha_flutter/commonModel/util/IsolateUtil.dart';
import 'package:gmalpha_flutter/messageModel/home/message_home.dart';
import 'commonModel/GMBase.dart';
void main() {
initParams(() => runApp(MyApp()));
}
class MyApp extends StatefulWidget {
......
......@@ -5,8 +5,10 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:gmalpha_flutter/commonModel/GMBase.dart';
import 'package:gmalpha_flutter/commonModel/toast/toast.dart';
import 'package:gmalpha_flutter/commonModel/util/IsolateUtil.dart';
import 'package:gmalpha_flutter/userModel/page/country/CountryJson.dart';
import 'package:gmalpha_flutter/userModel/service/UserRepository.dart';
import 'package:gmalpha_flutter/userModel/service/remote/entity/CountryBean.dart';
......@@ -20,15 +22,21 @@ class CountryModel extends BaseModel {
CountryModel(this.refer);
getCountries(BuildContext context) {
getStaticCountry().then((value) {
// getStaticCountry().then((value) {
// if (value != null) {
// liveData.notifyView(value);
// } else {
// getCountryFromNet(context);
// }
// }).catchError((error) {
// Toast.debugShow(context, error);
// print(error);
// });
paseJson().then((value) {
if (value != null) {
liveData.notifyView(value);
} else {
getCountryFromNet(context);
}
}).catchError((error) {
Toast.debugShow(context, error);
print(error);
});
}
......@@ -41,8 +49,8 @@ class CountryModel extends BaseModel {
});
}
Future getStaticCountry() async {
return await CountryBean.fromJson(json.decode(STATIC_COUNTRY_JSON));
Future paseJson() async {
return await compute(pase, 1);
}
@override
......@@ -50,3 +58,7 @@ class CountryModel extends BaseModel {
liveData.dispost();
}
}
CountryBean pase(int a) {
return CountryBean.fromJson(json.decode(STATIC_COUNTRY_JSON));
}
......@@ -10,6 +10,10 @@ import 'dart:io';
import 'package:rxdart/rxdart.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:gmalpha_flutter/userModel/service/remote/entity/UserResultBean.dart';
import 'package:gmalpha_flutter/userModel/service/remote/entity/CommentBean.dart';
import 'package:gmalpha_flutter/userModel/service/remote/entity/CountryBean.dart';
......@@ -35,40 +39,56 @@ class UserApiImpl {
Observable<UserResultBean> getUserInfo(String userID) {
return Observable.fromFuture(DioUtil().get('api/account/user_profile',
data: {'user_id': userID})).map((value) {
data: {'user_id': userID})).flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return UserResultBean.fromJson(map);
// Map map = json.decode(value.toString());
// return UserResultBean.fromJson(map);
return Observable.fromFuture(
compute(paseUserResultBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<CommentBean> comment(String content, String phone) {
return Observable.fromFuture(DioUtil().post('api/v1/suggestion',
data: {'content': content, 'phone': phone})).map((value) {
data: {'content': content, 'phone': phone})).flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return CommentBean.fromJson(map);
// Map map = json.decode(value.toString());
// return CommentBean.fromJson(map);
return Observable.fromFuture(
compute(paseCommentBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<CountryBean> getCountrys() {
return Observable.fromFuture(DioUtil().get('api/v1/countries'))
.map((value) {
.flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return CountryBean.fromJson(map);
// Map map = json.decode(value.toString());
// return CountryBean.fromJson(map);
return Observable.fromFuture(
compute(paseCountryBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
Observable<UploadTokenBean> getUploadToken(int token_type) {
return Observable.fromFuture(DioUtil().post('api/v1/app/upload_token',
data: {'token_type': token_type})).map((value) {
data: {'token_type': token_type})).flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return UploadTokenBean.fromJson(map);
// Map map = json.decode(value.toString());
// return UploadTokenBean.fromJson(map);
return Observable.fromFuture(
compute(paseUploadTokenBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
......@@ -82,10 +102,14 @@ class UserApiImpl {
'profile_pic': profile_pic,
'user_id': user_id,
'age': age
})).map((value) {
})).flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return SetUserBean.fromJson(map);
// Map map = json.decode(value.toString());
// return SetUserBean.fromJson(map);
return Observable.fromFuture(
compute(paseSetUserBean, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
......@@ -93,11 +117,39 @@ class UserApiImpl {
Observable<SimpleResponce> logout(String user_id) {
return Observable.fromFuture(
DioUtil().post('api/account/logout/', data: {'user_id': user_id}))
.map((value) {
.flatMap((value) {
if (value != null && value.statusCode == 200) {
Map map = json.decode(value.toString());
return SimpleResponce.fromJson(map);
// Map map = json.decode(value.toString());
// return SimpleResponce.fromJson(map);
return Observable.fromFuture(
compute(paseSimpleResponce, value.toString()));
} else {
return Observable.fromFuture(null);
}
});
}
}
UserResultBean paseUserResultBean(String value) {
return UserResultBean.fromJson(json.decode(value));
}
CommentBean paseCommentBean(String value) {
return CommentBean.fromJson(json.decode(value));
}
CountryBean paseCountryBean(String value) {
return CountryBean.fromJson(json.decode(value));
}
UploadTokenBean paseUploadTokenBean(String value) {
return UploadTokenBean.fromJson(json.decode(value));
}
SetUserBean paseSetUserBean(String value) {
return SetUserBean.fromJson(json.decode(value));
}
SimpleResponce paseSimpleResponce(String value) {
return SimpleResponce.fromJson(json.decode(value));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment