Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
F
Ftt_Common
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Ftt_Common
Commits
d416d82d
Commit
d416d82d
authored
Dec 01, 2021
by
罗显健
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
wMuiltTaskSimulate 增加消息显示。
parent
7ed9a8f5
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
299 additions
and
55 deletions
+299
-55
TimeWatch.cs
Tools/MyUtils/TimeWatch.cs
+87
-0
Utils.cs
Tools/MyUtils/Utils.cs
+61
-2
Tools.csproj
Tools/Tools.csproj
+1
-0
wMuiltTaskSimulate.Designer.cs
Tools/UI/wMuiltTaskSimulate.Designer.cs
+22
-7
wMuiltTaskSimulate.cs
Tools/UI/wMuiltTaskSimulate.cs
+85
-45
wMuiltTaskSimulate.resx
Tools/UI/wMuiltTaskSimulate.resx
+42
-0
wExtend.cs
Tools/wExtend.cs
+1
-1
No files found.
Tools/MyUtils/TimeWatch.cs
0 → 100644
View file @
d416d82d
using
System
;
namespace
Tools.MyUtils
{
/// <summary>
/// 时间监视
/// </summary>
public
class
TimeWatch
{
private
DateTime
?
dtStart
,
dtEnd
;
/// <summary>
/// 构造函数
/// </summary>
private
TimeWatch
()
{
ReStart
();
}
#
region
公共操作
/// <summary>
/// 停止监视
/// </summary>
public
void
Stop
()
{
dtEnd
=
DateTime
.
Now
;
}
/// <summary>
/// 重启监视
/// </summary>
public
void
ReStart
()
{
dtStart
=
DateTime
.
Now
;
dtEnd
=
null
;
}
/// <summary>
/// 时间间隔
/// </summary>
public
TimeSpan
TimeSpan
{
get
{
return
(
TimeSpan
)((
dtEnd
==
null
?
DateTime
.
Now
:
dtEnd
)
-
dtStart
);
}
}
#
endregion
#
region
静态方法
/// <summary>
/// 启动一个新的监视
/// </summary>
/// <returns></returns>
public
static
TimeWatch
Start
()
{
return
new
TimeWatch
();
}
/// <summary>
/// 写控制台测试日志
/// </summary>
/// <param name="name"></param>
/// <param name="action"></param>
public
static
void
Wrap
(
string
name
,
Action
action
)
{
var
watch
=
Start
();
action
();
ShowTime
(
name
,
watch
);
}
/// <summary>
/// 控制台显示测试时长,单位:毫秒
/// </summary>
/// <param name="name"></param>
/// <param name="timeWatch"></param>
private
static
void
ShowTime
(
string
name
,
TimeWatch
timeWatch
)
{
Console
.
WriteLine
(
$"【
{
name
}
】:
{
timeWatch
.
TimeSpan
.
TotalMilliseconds
}
ms"
);
}
#
endregion
}
}
Tools/MyUtils/Utils.cs
View file @
d416d82d
...
...
@@ -7,6 +7,7 @@ using System.IO;
using
System.Linq
;
using
System.Security.Cryptography
;
using
System.Text
;
using
System.Threading.Tasks
;
//
using
System.Windows.Forms
;
...
...
@@ -325,6 +326,63 @@ namespace Tools.MyUtils
action
();
}
#
region
跨线程相关操作
/// <summary>
/// 在主线程里执行一个动作
/// </summary>
/// <param name="owner">执行动作的控件</param>
/// <param name="action">执行的动作</param>
/// <param name="objData">传递给指定动作的参数</param>
public
static
void
DoMainAsync
(
Control
owner
,
Action
<
object
>
action
,
object
objData
)
{
new
TaskFactory
().
StartNew
(
obj
=>
{
var
dataDo
=
(
DoMainData
)
obj
;
if
(
dataDo
.
Control
!=
null
&&
!
dataDo
.
Control
.
IsDisposed
&&
!
dataDo
.
Control
.
Disposing
)
dataDo
.
Control
?.
Invoke
(
action
,
dataDo
.
Data
);
},
new
DoMainData
{
Control
=
owner
,
Data
=
objData
});
}
/// <summary>
/// 在主线程里执行一个动作
/// </summary>
/// <param name="owner">执行动作的控件</param>
/// <param name="action">执行的动作</param>
public
static
void
DoMainAsync
(
Control
owner
,
Action
action
)
{
new
TaskFactory
().
StartNew
(
obj
=>
{
var
dataDo
=
(
DoMainData
)
obj
;
if
(
dataDo
.
Control
!=
null
&&
!
dataDo
.
Control
.
IsDisposed
&&
!
dataDo
.
Control
.
Disposing
)
dataDo
.
Control
?.
Invoke
(
action
);
},
new
DoMainData
{
Control
=
owner
});
}
/// <summary>
/// 跨线程参数结构
/// </summary>
struct
DoMainData
{
/// <summary>
/// 跨线程操作的主控件
/// </summary>
public
Control
Control
;
/// <summary>
/// 参数
/// </summary>
public
object
Data
;
}
#
endregion
#
endregion
#
region
数据库链接处理
...
...
@@ -861,7 +919,8 @@ namespace Tools.MyUtils
{
var
result
=
new
List
<
string
>();
dt
.
Columns
.
Cast
<
DataColumn
>().
ToList
()
.
ForEach
(
c
=>
{
.
ForEach
(
c
=>
{
if
(!
c
.
AutoIncrement
)
{
result
.
Add
(
c
.
ColumnName
);
...
...
@@ -933,6 +992,6 @@ namespace Tools.MyUtils
}
#
endregion
}
}
Tools/Tools.csproj
View file @
d416d82d
...
...
@@ -112,6 +112,7 @@
<Compile
Include=
"MyUtils\DrawHelper.cs"
/>
<Compile
Include=
"MyUtils\InputtingService.cs"
/>
<Compile
Include=
"MyUtils\SegPicture.cs"
/>
<Compile
Include=
"MyUtils\TimeWatch.cs"
/>
<Compile
Include=
"UI\sys\wLogin.cs"
>
<SubType>
Form
</SubType>
</Compile>
...
...
Tools/UI/wMuiltTaskSimulate.Designer.cs
View file @
d416d82d
...
...
@@ -40,12 +40,13 @@
this
.
label2
=
new
System
.
Windows
.
Forms
.
Label
();
this
.
txtAssembly
=
new
System
.
Windows
.
Forms
.
TextBox
();
this
.
label1
=
new
System
.
Windows
.
Forms
.
Label
();
this
.
txtMsg
=
new
System
.
Windows
.
Forms
.
TextBox
();
this
.
groupBox1
.
SuspendLayout
();
this
.
SuspendLayout
();
//
// btnStart
//
this
.
btnStart
.
Location
=
new
System
.
Drawing
.
Point
(
4
58
,
27
);
this
.
btnStart
.
Location
=
new
System
.
Drawing
.
Point
(
4
31
,
10
);
this
.
btnStart
.
Name
=
"btnStart"
;
this
.
btnStart
.
Size
=
new
System
.
Drawing
.
Size
(
75
,
23
);
this
.
btnStart
.
TabIndex
=
0
;
...
...
@@ -56,7 +57,7 @@
// lblTimes
//
this
.
lblTimes
.
AutoSize
=
true
;
this
.
lblTimes
.
Location
=
new
System
.
Drawing
.
Point
(
43
,
29
);
this
.
lblTimes
.
Location
=
new
System
.
Drawing
.
Point
(
16
,
12
);
this
.
lblTimes
.
Name
=
"lblTimes"
;
this
.
lblTimes
.
Size
=
new
System
.
Drawing
.
Size
(
77
,
12
);
this
.
lblTimes
.
TabIndex
=
1
;
...
...
@@ -64,14 +65,14 @@
//
// txtTimes
//
this
.
txtTimes
.
Location
=
new
System
.
Drawing
.
Point
(
122
,
26
);
this
.
txtTimes
.
Location
=
new
System
.
Drawing
.
Point
(
95
,
9
);
this
.
txtTimes
.
Name
=
"txtTimes"
;
this
.
txtTimes
.
Size
=
new
System
.
Drawing
.
Size
(
100
,
21
);
this
.
txtTimes
.
TabIndex
=
2
;
//
// txtWorks
//
this
.
txtWorks
.
Location
=
new
System
.
Drawing
.
Point
(
316
,
26
);
this
.
txtWorks
.
Location
=
new
System
.
Drawing
.
Point
(
289
,
9
);
this
.
txtWorks
.
Name
=
"txtWorks"
;
this
.
txtWorks
.
Size
=
new
System
.
Drawing
.
Size
(
100
,
21
);
this
.
txtWorks
.
TabIndex
=
4
;
...
...
@@ -79,7 +80,7 @@
// lblWorks
//
this
.
lblWorks
.
AutoSize
=
true
;
this
.
lblWorks
.
Location
=
new
System
.
Drawing
.
Point
(
2
37
,
29
);
this
.
lblWorks
.
Location
=
new
System
.
Drawing
.
Point
(
2
10
,
12
);
this
.
lblWorks
.
Name
=
"lblWorks"
;
this
.
lblWorks
.
Size
=
new
System
.
Drawing
.
Size
(
77
,
12
);
this
.
lblWorks
.
TabIndex
=
3
;
...
...
@@ -93,7 +94,7 @@
this
.
groupBox1
.
Controls
.
Add
(
this
.
label2
);
this
.
groupBox1
.
Controls
.
Add
(
this
.
txtAssembly
);
this
.
groupBox1
.
Controls
.
Add
(
this
.
label1
);
this
.
groupBox1
.
Location
=
new
System
.
Drawing
.
Point
(
45
,
65
);
this
.
groupBox1
.
Location
=
new
System
.
Drawing
.
Point
(
18
,
41
);
this
.
groupBox1
.
Name
=
"groupBox1"
;
this
.
groupBox1
.
Size
=
new
System
.
Drawing
.
Size
(
497
,
136
);
this
.
groupBox1
.
TabIndex
=
5
;
...
...
@@ -148,11 +149,24 @@
this
.
label1
.
TabIndex
=
3
;
this
.
label1
.
Text
=
"程序集:"
;
//
// txtMsg
//
this
.
txtMsg
.
Anchor
=
((
System
.
Windows
.
Forms
.
AnchorStyles
)((((
System
.
Windows
.
Forms
.
AnchorStyles
.
Top
|
System
.
Windows
.
Forms
.
AnchorStyles
.
Bottom
)
|
System
.
Windows
.
Forms
.
AnchorStyles
.
Left
)
|
System
.
Windows
.
Forms
.
AnchorStyles
.
Right
)));
this
.
txtMsg
.
Location
=
new
System
.
Drawing
.
Point
(
18
,
183
);
this
.
txtMsg
.
Multiline
=
true
;
this
.
txtMsg
.
Name
=
"txtMsg"
;
this
.
txtMsg
.
ScrollBars
=
System
.
Windows
.
Forms
.
ScrollBars
.
Both
;
this
.
txtMsg
.
Size
=
new
System
.
Drawing
.
Size
(
500
,
178
);
this
.
txtMsg
.
TabIndex
=
6
;
//
// wMuiltTaskSimulate
//
this
.
AutoScaleDimensions
=
new
System
.
Drawing
.
SizeF
(
6F
,
12F
);
this
.
AutoScaleMode
=
System
.
Windows
.
Forms
.
AutoScaleMode
.
Font
;
this
.
ClientSize
=
new
System
.
Drawing
.
Size
(
591
,
222
);
this
.
ClientSize
=
new
System
.
Drawing
.
Size
(
544
,
379
);
this
.
Controls
.
Add
(
this
.
txtMsg
);
this
.
Controls
.
Add
(
this
.
groupBox1
);
this
.
Controls
.
Add
(
this
.
txtWorks
);
this
.
Controls
.
Add
(
this
.
lblWorks
);
...
...
@@ -182,5 +196,6 @@
private
System
.
Windows
.
Forms
.
Label
label2
;
private
System
.
Windows
.
Forms
.
TextBox
txtAssembly
;
private
System
.
Windows
.
Forms
.
Label
label1
;
private
System
.
Windows
.
Forms
.
TextBox
txtMsg
;
}
}
\ No newline at end of file
Tools/UI/wMuiltTaskSimulate.cs
View file @
d416d82d
...
...
@@ -5,6 +5,8 @@ using System.Threading;
using
System.Threading.Tasks
;
using
System.Windows.Forms
;
using
Tools.MyCommon
;
using
Tools.MyUtils
;
namespace
Tools.UI
{
...
...
@@ -13,8 +15,8 @@ namespace Tools.UI
/// </summary>
public
partial
class
wMuiltTaskSimulate
:
wBasic
{
static
wMuiltTaskSimulate
wInstance
;
int
totalTimes
=
0
,
maxWorks
=
0
;
public
wMuiltTaskSimulate
()
{
...
...
@@ -30,51 +32,21 @@ namespace Tools.UI
txtWorks
.
Text
=
"5"
;
}
int
totalTimes
=
0
,
maxWorks
=
0
;
private
void
Run
(
Action
callBack
)
{
int
finishCount
=
0
;
Task
.
Run
(()
=>
{
Parallel
.
For
(
0
,
totalTimes
,
new
ParallelOptions
{
MaxDegreeOfParallelism
=
maxWorks
},
i
=>
{
try
{
ShowMsg
(
$"准备执行第
{
i
}
任务"
);
Execute
(
txtAssembly
.
Text
,
txtClass
.
Text
,
txtMethod
.
Text
);
ShowMsg
(
$"第
{
i
}
任务执行完成!"
);
}
catch
(
Exception
ex
)
{
ShowMsg
(
ex
.
Message
);
}
finally
{
Interlocked
.
Increment
(
ref
finishCount
);
if
(
finishCount
>=
totalTimes
)
MyUtils
.
Utils
.
AsyncUI
(
wInstance
,
()
=>
callBack
());
}
});
});
}
private
void
btnStart_Click
(
object
sender
,
EventArgs
e
)
{
if
(!
CheckData
())
return
;
if
(!
Check
Input
Data
())
return
;
txtMsg
.
Clear
();
// 每次执行前都清除一遍
btnStart
.
Enabled
=
false
;
Run
(()
=>
btnStart
.
Enabled
=
true
);
}
private
bool
CheckData
()
/// <summary>
/// 校验输入
/// </summary>
/// <returns></returns>
private
bool
CheckInputData
()
{
if
(!
int
.
TryParse
(
txtTimes
.
Text
,
out
totalTimes
)
||
totalTimes
<
0
)
{
...
...
@@ -91,39 +63,107 @@ namespace Tools.UI
return
true
;
}
/// <summary>
/// 功能主要操作入口
/// </summary>
/// <param name="completedCallBack">所有操作执行完成之后的回调</param>
private
void
Run
(
Action
completedCallBack
)
{
int
finishCount
=
0
;
Task
.
Run
(()
=>
{
Parallel
.
For
(
0
,
totalTimes
,
new
ParallelOptions
{
MaxDegreeOfParallelism
=
maxWorks
},
i
=>
{
try
{
Execute
(
txtAssembly
.
Text
,
txtClass
.
Text
,
txtMethod
.
Text
,
i
);
}
catch
(
Exception
ex
)
{
Utils
.
DoMainAsync
(
wInstance
,
ShowMsg
,
$"执行操作失败:
{
ex
.
Message
}
"
);
}
finally
{
Interlocked
.
Increment
(
ref
finishCount
);
// 回调、只有在所有的操作都执行完(无论成功与否)的时候调用。
if
(
finishCount
>=
totalTimes
)
{
Utils
.
DoMainAsync
(
wInstance
,
completedCallBack
);
}
}
});
});
}
/// <summary>
/// 执行计划任务
。
/// 执行计划任务
/// </summary>
/// <returns></returns>
/// <param name="dllName"></param>
/// <param name="className"></param>
/// <param name="methodName"></param>
/// <param name="taskNo"></param>
/// <exception cref="Exception"></exception>
public
void
Execute
(
string
dllName
,
string
className
,
string
methodName
)
public
void
Execute
(
string
dllName
,
string
className
,
string
methodName
,
int
taskNo
)
{
var
assembly
=
Path
.
Combine
(
AppDomain
.
CurrentDomain
.
BaseDirectory
,
dllName
);
if
(!
File
.
Exists
(
assembly
))
throw
new
Exception
(
$"程序集[
{
dllName
}
]不存在"
);
var
type
=
Assembly
.
LoadFrom
(
assembly
).
GetType
(
className
);
if
(
type
==
null
)
throw
new
Exception
(
$"程序集[
{
dllName
}
]中不存在业务类[
{
className
}
]"
);
var
method
=
type
.
GetMethod
(
"RunDapper"
);
var
method
=
type
.
GetMethod
(
methodName
);
if
(
method
==
null
)
throw
new
Exception
(
$"程序集[
{
dllName
}
]-[
{
className
}
]类中不存在[
{
methodName
}
]方法或重载"
);
var
objInstance
=
Activator
.
CreateInstance
(
type
);
ShowMsg
(
$"任务执行、当前线程:
{
Thread
.
CurrentThread
.
ManagedThreadId
}
"
);
Utils
.
DoMainAsync
(
wInstance
,
ShowMsg
,
$"任务构建完成,准备执行。当前线程:
{
Thread
.
CurrentThread
.
ManagedThreadId
}
,任务编号:
{
taskNo
}
"
);
method
.
Invoke
(
objInstance
,
null
);
TimeWatch
timeWatch
=
TimeWatch
.
Start
();
try
{
method
.
Invoke
(
objInstance
,
null
);
Utils
.
DoMainAsync
(
wInstance
,
ShowMsg
,
$"任务执行完成、耗时:
{
timeWatch
.
TimeSpan
.
TotalMilliseconds
}
(毫秒),任务编号:
{
taskNo
}
"
);
}
catch
(
Exception
ex
)
{
Utils
.
DoMainAsync
(
wInstance
,
ShowMsg
,
$"任务:
{
taskNo
}
执行失败、耗时:
{
timeWatch
.
TimeSpan
.
TotalMilliseconds
}
(毫秒),原因:
{
GetAllMessage
(
ex
)}
"
);
}
}
/// <summary>
/// 获取异常所有消息
/// </summary>
/// <param name="ex"></param>
/// <returns></returns>
private
string
GetAllMessage
(
Exception
ex
)
{
return
(
ex
.
InnerException
==
null
)
?
ex
.
Message
:
ex
.
Message
+
"-->"
+
GetAllMessage
(
ex
.
InnerException
);
}
#
region
显示消息
/// <summary>
/// 显示消息
/// </summary>
/// <param name="content"></param>
private
void
ShowMsg
(
string
content
)
{
Console
.
WriteLine
(
content
);
txtMsg
.
AppendText
(
content
);
txtMsg
.
AppendText
(
"\r\n"
);
}
/// <summary>
/// 显示消息
/// </summary>
/// <param name="strObj"></param>
private
void
ShowMsg
(
object
strObj
)
=>
ShowMsg
(
strObj
.
ToString
());
#
endregion
}
}
Tools/UI/wMuiltTaskSimulate.resx
View file @
d416d82d
...
...
@@ -117,4 +117,46 @@
<resheader
name=
"writer"
>
<value>
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<metadata
name=
"btnStart.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"lblTimes.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"txtTimes.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"txtWorks.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"lblWorks.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"groupBox1.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"txtMethod.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"label3.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"txtClass.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"label2.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"txtAssembly.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"label1.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"txtMsg.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
<metadata
name=
"$this.Locked"
type=
"System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
>
<value>
True
</value>
</metadata>
</root>
\ No newline at end of file
Tools/wExtend.cs
View file @
d416d82d
...
...
@@ -60,7 +60,7 @@ namespace Tools
this
.
CreateModule
(
Tools_dev
,
typeof
(
UI
.
wModuleManager
),
"模块管理"
,
"tr:系统模块管理工具(支持生成SQL)"
),
this
.
CreateModule
(
Tools_dev
,
typeof
(
UI
.
wDbAnlysis
),
"SQL效率分析"
,
"tr:用于分析SQL查询效率(执行计划和IO计数)"
),
this
.
CreateModule
(
Tools_dev
,
typeof
(
UI
.
wSysChecker
),
"检查配置工具"
,
"tr:系统通用检查配置服务(通过存储过程检查)"
),
this
.
CreateModule
(
Tools_dev
,
typeof
(
UI
.
wMuiltTaskSimulate
),
"批量并行任务模拟"
,
"
tr
:多线程并行运行指定测试项目,用来做压力性能测试等。。。"
),
this
.
CreateModule
(
Tools_dev
,
typeof
(
UI
.
wMuiltTaskSimulate
),
"批量并行任务模拟"
,
"
lxj
:多线程并行运行指定测试项目,用来做压力性能测试等。。。"
),
//-------------------------------
this
.
CreateModule
(
Tools_human
,
typeof
(
UI
.
wUser
),
"员工管理"
,
"tr:员工状态及头像管理"
),
this
.
CreateModule
(
Tools_human
,
typeof
(
UI
.
wEvaluationOfEmployee
),
"员工考核"
,
"tr:员工考核的记录工具"
),
...
...
Write
Preview
Markdown
is supported
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