Skip to content
Toggle navigation
Toggle navigation
This project
Loading...
Sign in
周伟奇
/
bmw-ocr
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Graphs
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
db73da94
authored
2022-05-30 16:22:58 +0800
by
周伟奇
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
June SE part 2
1 parent
5b24219b
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
33 additions
and
205 deletions
src/apps/doc/consts.py
src/celery_compare/tasks.py
src/common/tools/comparison.py
src/apps/doc/consts.py
View file @
db73da9
...
...
@@ -1409,7 +1409,7 @@ SE_CORPORATE_ALL_FIELD = ['companyName', 'legalRepName', 'firstIdNo', 'businessL
'taxRegistrationCertificateNo'
,
'establishmentDate'
,
'businessLicenseDueDate'
]
SE_NEW_FIELD
=
[
'vinNo'
,
'dealer'
,
'vehicleTransactionAmount'
]
SE_USED_FIELD
=
[
'vinNo'
,
'vehicleTransactionAmount'
]
SE_NEW_ADD_FIELD
=
[
'customerName'
,
'idNum'
,
'dateOfInvoice'
,
'stamp'
,
'发票联'
,
'发票真伪校验'
,
'新旧版式'
]
SE_NEW_ADD_FIELD
=
[
'customerName'
,
'idNum'
,
'dateOfInvoice'
,
'stamp'
,
'发票联'
,
'发票真伪校验'
,
'新旧版式'
,
'不含税价校验'
,
'增值税额校验'
,
'价税合计大小写检验'
]
SE_FPL_VALUE
=
'发票联'
SE_STAMP_VALUE
=
'有'
SE_DYSYR_VALUE
=
'无'
...
...
@@ -1717,6 +1717,12 @@ SME_BL_COMPARE_LOGIC = {
'businessLicenseDueDate'
:
(
'营业期限'
,
'se_date_compare'
,
{
'ocr_split'
:
True
,
'long'
:
True
,
'ocr_replace'
:
True
,
'today'
:
True
},
'公司营业期限疑似过期'
),
}
ZW_METHOD
=
'mvi_special'
LOWER_AMOUNT_FIELD
=
'价税合计小写'
UPPER_AMOUNT_FIELD
=
'价税合计大写'
BHSJ_FIELD
=
'不含税价'
ZZSSE_FIELD
=
'增值税税额'
MVI_COMPARE_LOGIC
=
{
'vinNo'
:
(
'车辆识别代码'
,
'se_common_compare'
,
{},
'发票车架号与系统不一致'
),
'dealer'
:
(
'销方名称'
,
'se_contain_compare_2'
,
{
'brackets_replace'
:
True
},
'发票销货单位名称与系统不一致'
),
...
...
@@ -1726,14 +1732,13 @@ MVI_COMPARE_LOGIC = {
'dateOfInvoice'
:
(
'开票日期'
,
'se_date_compare_2'
,
{
'three_month'
:
True
},
'发票开票日期早于首次提交申请日期'
),
'stamp'
:
(
'销售单位章'
,
'se_common_compare'
,
{},
'发票无章'
),
'发票联'
:
(
'发票类型'
,
'se_common_compare'
,
{},
'发票疑似非发票联'
),
'发票真伪校验'
:
(
'发票真伪校验'
,
'se_common_compare'
,
{},
'发票疑似造假,需人工核算'
),
# '发票真伪校验': ('发票真伪校验', 'se_common_compare', {}, '发票疑似造假,需人工核算'),
'不含税价校验'
:
(
BHSJ_FIELD
,
'se_common_compare'
,
{},
'发票不含税价疑似错误,需人工核算'
),
'增值税额校验'
:
(
ZZSSE_FIELD
,
'se_common_compare'
,
{},
'发票增值税额疑似错误,需人工核算'
),
'价税合计大小写检验'
:
(
'价税合计大小写检验'
,
'se_common_compare'
,
{},
'发票价税合计大小写校验疑似错误,需人工核算'
),
'新旧版式'
:
(
'新旧版式'
,
'se_contain_compare_2'
,
{},
'发票版本与打印版式不符'
),
}
ZW_METHOD
=
'mvi_special'
LOWER_AMOUNT_FIELD
=
'价税合计小写'
UPPER_AMOUNT_FIELD
=
'价税合计大写'
BHSJ_FIELD
=
'不含税价'
ZZSSE_FIELD
=
'增值税税额'
UCI_COMPARE_LOGIC
=
{
'vinNo'
:
(
'车架号'
,
'se_common_compare'
,
{},
'二手车发票车架号与系统不一致'
),
...
...
src/celery_compare/tasks.py
View file @
db73da9
...
...
@@ -1022,11 +1022,14 @@ def get_se_cms_compare_info_auto(last_obj, application_entity, auto=True):
# vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[3], consts.SE_STAMP_VALUE))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
4
],
consts
.
SE_FPL_VALUE
))
bhsj
=
float
(
amount
)
/
1.13
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
5
],
consts
.
SPLIT_STR
.
join
([
format
(
bhsj
,
'.2f'
),
format
(
float
(
amount
)
-
bhsj
,
'.2f'
),
consts
.
RESULT_Y
])))
# vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[5], consts.SPLIT_STR.join([
# format(bhsj, '.2f'),
# format(float(amount) - bhsj, '.2f'),
# consts.RESULT_Y
# ])))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
7
],
format
(
bhsj
,
'.2f'
)))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
8
],
format
(
float
(
amount
)
-
bhsj
,
'.2f'
)))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
9
],
consts
.
RESULT_Y
))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
6
],
consts
.
SE_LAYOUT_VALUE
))
vehicle_info
[
consts
.
MVI_EN
]
=
vehicle_field_input
# 二手车发票、交易凭证、绿本------------------------------------------------------------------------------------------
...
...
@@ -1536,11 +1539,14 @@ def get_se_cms_compare_info(last_obj, application_entity, detect_list, auto=Fals
# vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[3], consts.SE_STAMP_VALUE))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
4
],
consts
.
SE_FPL_VALUE
))
bhsj
=
float
(
amount
)
/
1.13
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
5
],
consts
.
SPLIT_STR
.
join
([
format
(
bhsj
,
'.2f'
),
format
(
float
(
amount
)
-
bhsj
,
'.2f'
),
consts
.
RESULT_Y
])))
# vehicle_field_input.append((consts.SE_NEW_ADD_FIELD[5], consts.SPLIT_STR.join([
# format(bhsj, '.2f'),
# format(float(amount) - bhsj, '.2f'),
# consts.RESULT_Y
# ])))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
7
],
format
(
bhsj
,
'.2f'
)))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
8
],
format
(
float
(
amount
)
-
bhsj
,
'.2f'
)))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
9
],
consts
.
RESULT_Y
))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
6
],
consts
.
SE_LAYOUT_VALUE
))
vehicle_info
[
consts
.
MVI_EN
]
=
vehicle_field_input
# 二手车发票、交易凭证、绿本------------------------------------------------------------------------------------------
...
...
@@ -1906,182 +1912,6 @@ def get_se_cms_compare_info(last_obj, application_entity, detect_list, auto=Fals
return
compare_info
,
cms_info
.
get
(
'applicationVersion'
,
1
),
is_gsyh
def
get_se_compare_info
(
last_obj
,
application_entity
,
detect_list
):
compare_info
=
{}
individual_info_dict
=
{}
main_role_info
=
{}
for
individual_info
in
json
.
loads
(
last_obj
.
individual_cus_info
):
if
isinstance
(
individual_info
.
get
(
'secondIdNum'
),
str
):
id_num
=
'{0}、{1}'
.
format
(
individual_info
[
'idNum'
],
individual_info
[
'secondIdNum'
])
else
:
id_num
=
individual_info
[
'idNum'
]
main_role_info
.
setdefault
(
individual_info
[
'applicantType'
],
[])
.
append
(
(
individual_info
[
'customerName'
],
id_num
,
individual_info
[
'idNum'
]))
license_dict
=
{}
if
individual_info
[
'idType'
]
in
consts
.
SE_FIRST_ID_FIELD_MAPPING
:
license_en
,
field_list
=
consts
.
SE_FIRST_ID_FIELD_MAPPING
[
individual_info
[
'idType'
]]
field_input
=
[]
for
field
in
field_list
:
if
field
in
individual_info
:
field_input
.
append
((
field
,
individual_info
[
field
]))
license_dict
[
license_en
]
=
field_input
if
individual_info
.
get
(
'secondIdType'
)
in
consts
.
SE_SECOND_ID_FIELD_MAPPING
:
second_license_en
,
second_field_list
=
consts
.
SE_SECOND_ID_FIELD_MAPPING
[
individual_info
[
'secondIdType'
]]
if
second_license_en
not
in
license_dict
:
second_field_input
=
[]
for
second_field
,
write_field
in
second_field_list
:
if
second_field
in
individual_info
:
second_field_input
.
append
((
write_field
,
individual_info
[
second_field
]))
license_dict
[
second_license_en
]
=
second_field_input
if
individual_info
[
'customerType'
]
==
consts
.
CUSTOMER_TYPE
[
5
]:
sep_field_input
=
[]
for
sep_field
,
sep_write_field
in
consts
.
SE_SEP_FIELD
:
if
sep_field
in
individual_info
:
sep_field_input
.
append
((
sep_write_field
,
individual_info
[
sep_field
]))
license_dict
[
consts
.
BL_EN
]
=
sep_field_input
if
len
(
license_dict
)
>
0
:
individual_info_dict
.
setdefault
(
individual_info
[
'applicantType'
],
[])
.
append
(
license_dict
)
compare_info
[
'individualCusInfo'
]
=
individual_info_dict
dda_name_list
=
[]
dda_num_list
=
[]
for
applicant_type
in
consts
.
APPLICANT_TYPE
:
if
applicant_type
in
main_role_info
:
main_name
,
main_num
,
_
=
main_role_info
[
applicant_type
][
0
]
hmh_name
,
_
,
hmh_id
=
main_role_info
[
applicant_type
][
0
]
break
for
applicant_type
in
consts
.
APPLICANT_TYPE
[:
2
]:
if
applicant_type
in
main_role_info
:
for
dda_name_part
,
_
,
dda_num_part
in
main_role_info
[
applicant_type
]:
dda_name_list
.
append
(
dda_name_part
)
dda_num_list
.
append
(
dda_num_part
)
dda_name
=
'、'
.
join
(
dda_name_list
)
dda_num
=
'、'
.
join
(
dda_num_list
)
del
main_role_info
company_info
=
None
if
isinstance
(
last_obj
.
corporate_cus_info
,
str
):
corporate_info_dict
=
json
.
loads
(
last_obj
.
corporate_cus_info
)
corporate_info
=
{}
company_info
=
(
corporate_info_dict
[
'companyName'
],
corporate_info_dict
[
'businessLicenseNo'
])
if
corporate_info_dict
[
'firstIdType'
]
==
consts
.
ID_TYPE
[
6
]:
bl_field_input
=
[]
for
bl_field
in
consts
.
SE_CORPORATE_ALL_FIELD
:
bl_field_input
.
append
((
bl_field
,
corporate_info_dict
[
bl_field
]))
corporate_info
[
consts
.
BL_EN
]
=
bl_field_input
else
:
if
corporate_info_dict
[
'firstIdType'
]
in
consts
.
SE_FIRST_ID_FIELD_MAPPING
:
license_en
,
_
=
consts
.
SE_FIRST_ID_FIELD_MAPPING
[
corporate_info_dict
[
'firstIdType'
]]
first_id_field_input
=
[]
for
first_id_field
,
first_id_write_field
in
consts
.
SE_CORPORATE_ID_FIELD
:
first_id_field_input
.
append
((
first_id_write_field
,
corporate_info_dict
[
first_id_field
]))
corporate_info
[
license_en
]
=
first_id_field_input
bl_field_input
=
[]
for
bl_field
in
consts
.
SE_CORPORATE_FIELD
:
bl_field_input
.
append
((
bl_field
,
corporate_info_dict
[
bl_field
]))
corporate_info
[
consts
.
BL_EN
]
=
bl_field_input
compare_info
[
'corporateCusInfo'
]
=
corporate_info
vehicle_info_dict
=
json
.
loads
(
last_obj
.
vehicle_info
)
# TODO 车辆登记证
vehicle_info
=
{}
vehicle_field_input
=
[]
if
vehicle_info_dict
[
'vehicleStatus'
]
==
'New'
:
for
vehicle_field
in
consts
.
SE_NEW_FIELD
:
vehicle_field_input
.
append
((
vehicle_field
,
vehicle_info_dict
[
vehicle_field
]))
if
isinstance
(
company_info
,
tuple
):
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
0
],
company_info
[
0
]))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
1
],
company_info
[
1
]))
else
:
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
0
],
main_name
))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
1
],
main_num
))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
2
],
last_obj
.
first_submmison_date
))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
3
],
consts
.
SE_STAMP_VALUE
))
vehicle_info
[
consts
.
MVI_EN
]
=
vehicle_field_input
else
:
gb_field_input
=
[]
gb34_field_input
=
[]
jypz_field_input
=
[]
for
vehicle_field
in
consts
.
SE_USED_FIELD
:
vehicle_field_input
.
append
((
vehicle_field
,
vehicle_info_dict
[
vehicle_field
]))
for
gb_field
in
consts
.
SE_GB_NEW_FIELD
:
gb_field_input
.
append
((
gb_field
,
vehicle_info_dict
[
gb_field
]))
if
isinstance
(
company_info
,
tuple
):
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
0
],
company_info
[
0
]))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
1
],
company_info
[
1
]))
jypz_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
0
],
company_info
[
0
]))
jypz_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
1
],
company_info
[
1
]))
gb34_field_input
.
append
((
consts
.
SE_GB_USED_FIELD
[
0
],
company_info
[
0
]))
gb34_field_input
.
append
((
consts
.
SE_GB_USED_FIELD
[
1
],
company_info
[
1
]))
else
:
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
0
],
main_name
))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
1
],
main_num
))
jypz_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
0
],
main_name
))
jypz_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
1
],
main_num
))
gb34_field_input
.
append
((
consts
.
SE_GB_USED_FIELD
[
0
],
main_name
))
gb34_field_input
.
append
((
consts
.
SE_GB_USED_FIELD
[
1
],
main_num
))
gb34_field_input
.
append
((
consts
.
SE_GB_USED_FIELD
[
2
],
last_obj
.
first_submmison_date
))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
2
],
last_obj
.
first_submmison_date
))
vehicle_field_input
.
append
((
consts
.
SE_NEW_ADD_FIELD
[
3
],
consts
.
SE_STAMP_VALUE
))
for
jypz_field
in
consts
.
SE_USED_FIELD
:
jypz_field_input
.
append
((
jypz_field
,
vehicle_info_dict
[
jypz_field
]))
jypz_field_input
.
append
((
consts
.
SE_GB_USED_FIELD
[
-
1
],
last_obj
.
first_submmison_date
))
vehicle_info
[
consts
.
MVC_EN
]
=
gb_field_input
vehicle_info
[
consts
.
MVC34_EN
]
=
gb34_field_input
if
not
detect_list
[
0
]:
vehicle_info
[
consts
.
UCI_EN
]
=
vehicle_field_input
if
not
detect_list
[
1
]:
vehicle_info
[
consts
.
JYPZ_EN
]
=
jypz_field_input
if
detect_list
[
0
]
and
detect_list
[
1
]:
vehicle_info
[
consts
.
UCI_EN
]
=
vehicle_field_input
compare_info
[
'vehicleInfo'
]
=
vehicle_info
bank_info_dict
=
json
.
loads
(
last_obj
.
bank_info
)
bank_info
=
{}
bank_field_input
=
[]
for
bank_field
in
consts
.
SE_BANK_FIELD
:
bank_field_input
.
append
((
bank_field
,
bank_info_dict
[
bank_field
]))
if
'工商'
in
bank_info_dict
.
get
(
consts
.
SE_BANK_FIELD
[
-
1
],
''
):
is_gsyh
=
True
else
:
is_gsyh
=
False
bank_info
[
consts
.
BC_EN
]
=
bank_field_input
if
is_gsyh
or
not
detect_list
[
-
1
]:
dda_field_input
=
[]
for
dda_field
in
consts
.
SE_DDA_FIELD
:
if
dda_field
.
startswith
(
'applicationId'
):
dda_field_input
.
append
((
dda_field
,
last_obj
.
application_id
))
elif
dda_field
==
'companyName'
:
company_name
=
consts
.
HIL_COMPANY_NAME
if
application_entity
in
consts
.
HIL_SET
else
consts
.
AFC_COMPANY_NAME
dda_field_input
.
append
((
dda_field
,
company_name
))
elif
dda_field
==
'customerName'
:
dda_field_input
.
append
((
dda_field
,
dda_name
))
elif
dda_field
==
'idNum'
:
dda_field_input
.
append
((
dda_field
,
dda_num
))
else
:
dda_field_input
.
append
((
dda_field
,
bank_info_dict
[
dda_field
]))
bank_info
[
consts
.
DDA_EN
]
=
dda_field_input
compare_info
[
'bankInfo'
]
=
bank_info
if
not
detect_list
[
2
]:
other_info
=
{}
hmh_field_input
=
[]
hmh_field_input
.
append
((
consts
.
SE_HMH_FIELD
[
0
],
hmh_name
))
hmh_field_input
.
append
((
consts
.
SE_HMH_FIELD
[
1
],
hmh_id
))
hmh_field_input
.
append
((
consts
.
SE_HMH_FIELD
[
2
],
last_obj
.
application_id
))
other_info
[
consts
.
HMH_EN
]
=
hmh_field_input
compare_info
[
'other'
]
=
other_info
return
compare_info
,
is_gsyh
def
se_bs_compare
(
license_en
,
ocr_res_dict
,
strip_list
,
is_auto
):
# 主共借至少提供一个
# 有担保人,担保人必须提供。主共借没有时,修改comment:人工查看担保人亲属关系
...
...
@@ -2322,12 +2152,10 @@ def se_compare_license(license_en, ocr_res_dict, field_list):
break
for
idx
,
(
name
,
value
)
in
enumerate
(
field_list
):
if
ocr_field
==
consts
.
MVI_OCR_FIELD
and
name
==
consts
.
SE_NEW_ADD_FIELD
[
5
]:
if
ocr_field
==
consts
.
MVI_OCR_FIELD
and
name
==
consts
.
SE_NEW_ADD_FIELD
[
9
]:
ocr_str
=
getattr
(
cp
,
consts
.
ZW_METHOD
)(
ocr_res_list
[
res_idx
]
.
get
(
consts
.
LOWER_AMOUNT_FIELD
,
''
),
ocr_res_list
[
res_idx
]
.
get
(
consts
.
UPPER_AMOUNT_FIELD
,
''
),
ocr_res_list
[
res_idx
]
.
get
(
consts
.
BHSJ_FIELD
,
''
),
ocr_res_list
[
res_idx
]
.
get
(
consts
.
ZZSSE_FIELD
,
''
)
)
else
:
ocr_str
=
ocr_res_list
[
res_idx
]
.
get
(
compare_logic
[
name
][
0
])
...
...
@@ -2758,8 +2586,9 @@ def se_compare_process(compare_info, ocr_res_dict, is_gsyh, is_auto):
for
name
,
value
,
result
,
ocr_str
,
img_path
,
error_type
,
cn_reason
in
result_field_list
:
total_fields
+=
1
if
result
==
consts
.
RESULT_N
:
failed_count
+=
1
if
license_en
!=
consts
.
MVI_EN
or
name
!=
consts
.
SE_NEW_ADD_FIELD
[
9
]:
successful_at_this_level
=
False
failed_count
+=
1
failure_field
.
append
(
name
)
if
isinstance
(
cn_reason
,
str
):
cn_reason_list
.
append
(
cn_reason
)
...
...
@@ -2868,14 +2697,8 @@ def se_compare(application_id, application_entity, ocr_res_id, last_obj, ocr_res
# 比对逻辑
start_time
=
datetime
.
now
()
detect_list
=
se_result_detect
(
ocr_res_dict
)
# if is_cms:
# last_obj = rebuild_compare_info(last_obj, application_id)
if
is_cms
:
compare_info
,
application_version
,
is_gsyh
=
get_se_cms_compare_info
(
last_obj
,
application_entity
,
detect_list
)
else
:
compare_info
,
is_gsyh
=
get_se_compare_info
(
last_obj
,
application_entity
,
detect_list
)
application_version
=
last_obj
.
application_version
compare_result
,
total_fields
,
failed_count
,
successful_at_this_level
,
failure_reason_str
,
cn_failure_reason_str
,
bs_failure_reason_str
=
se_compare_process
(
compare_info
,
ocr_res_dict
,
is_gsyh
,
False
)
compare_log
.
info
(
'{0} [SE] [compare success] [entity={1}] [id={2}] [ocr_res_id={3}] [result={4}]'
.
format
(
log_base
,
application_entity
,
application_id
,
ocr_res_id
,
compare_result
))
...
...
src/common/tools/comparison.py
View file @
db73da9
...
...
@@ -123,7 +123,7 @@ class Comparison:
ocr_output
=
None
return
self
.
build_res
(
input_str
==
ocr_str
),
ocr_output
def
mvi_special
(
self
,
amount_lower_str
,
amount_upper_str
,
bhsj_str
,
zzsse_str
):
def
mvi_special
(
self
,
amount_lower_str
,
amount_upper_str
):
# 不含税价, 增值税税额
try
:
if
float
(
amount_lower_str
)
!=
rmb_handler
.
to_rmb_lower
(
amount_upper_str
):
...
...
@@ -131,7 +131,7 @@ class Comparison:
except
Exception
:
return
self
.
RESULT_N
else
:
return
self
.
SPLIT_STR
.
join
([
bhsj_str
,
zzsse_str
,
self
.
RESULT_Y
])
return
self
.
RESULT_Y
def
rmb_compare
(
self
,
input_str
,
ocr_str
,
idx
,
**
kwargs
):
if
not
isinstance
(
ocr_str
,
str
)
or
not
isinstance
(
input_str
,
str
):
...
...
Write
Preview
Styling with
Markdown
is supported
Attach a file
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 post a comment