Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
las3_pub
/
predictable_parallel_patterns
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
ebf6fec7
authored
5 years ago
by
FritzFlorian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move inputs and outputs to correct namespace.
parent
6333222f
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
35 additions
and
26 deletions
+35
-26
app/playground/main.cpp
+8
-8
lib/pls/CMakeLists.txt
+1
-1
lib/pls/include/pls/dataflow/internal/function_node.h
+2
-2
lib/pls/include/pls/dataflow/internal/function_node_impl.h
+6
-6
lib/pls/include/pls/dataflow/internal/graph.h
+3
-2
lib/pls/include/pls/dataflow/internal/graph_impl.h
+7
-7
lib/pls/include/pls/dataflow/internal/inputs.h
+2
-0
lib/pls/include/pls/dataflow/internal/node.h
+1
-0
lib/pls/include/pls/dataflow/internal/outputs.h
+2
-0
lib/pls/include/pls/pls.h
+3
-0
No files found.
app/playground/main.cpp
View file @
ebf6fec7
...
@@ -4,14 +4,14 @@
...
@@ -4,14 +4,14 @@
#include <tuple>
#include <tuple>
#include <array>
#include <array>
#include
<pls/pls.h>
#include
"pls/pls.h"
#include
<pls/dataflow/internal/inputs.h>
#include
"pls/dataflow/internal/inputs.h"
#include
<pls/dataflow/internal/outputs.h>
#include
"pls/dataflow/internal/outputs.h"
#include
<pls/dataflow/internal/function_node.h>
#include
"pls/dataflow/internal/function_node.h"
#include
<pls/dataflow/internal/graph.h>
#include
"pls/dataflow/internal/graph.h"
#include
<pls/dataflow/internal/switch_node.h>
#include
"pls/dataflow/internal/switch_node.h"
#include
<pls/dataflow/internal/split_node.h>
#include
"pls/dataflow/internal/split_node.h"
#include
<pls/dataflow/internal/merge_node.h>
#include
"pls/dataflow/internal/merge_node.h"
int
main
()
{
int
main
()
{
using
namespace
pls
::
dataflow
;
using
namespace
pls
::
dataflow
;
...
...
This diff is collapsed.
Click to expand it.
lib/pls/CMakeLists.txt
View file @
ebf6fec7
...
@@ -56,7 +56,7 @@ add_library(pls STATIC
...
@@ -56,7 +56,7 @@ add_library(pls STATIC
include/pls/internal/scheduling/task.h src/internal/scheduling/task.cpp
include/pls/internal/scheduling/task.h src/internal/scheduling/task.cpp
include/pls/internal/scheduling/scheduler_memory.h src/internal/scheduling/scheduler_memory.cpp
include/pls/internal/scheduling/scheduler_memory.h src/internal/scheduling/scheduler_memory.cpp
include/pls/internal/scheduling/lambda_task.h
include/pls/internal/scheduling/lambda_task.h
include/pls/dataflow/internal/split_node.h
)
include/pls/dataflow/internal/split_node.h
include/pls/internal/helpers/member_function.h
)
# Add everything in `./include` to be in the include path of this project
# Add everything in `./include` to be in the include path of this project
target_include_directories
(
pls
target_include_directories
(
pls
PUBLIC
PUBLIC
...
...
This diff is collapsed.
Click to expand it.
lib/pls/include/pls/dataflow/internal/function_node.h
View file @
ebf6fec7
...
@@ -26,10 +26,10 @@ template<typename INS, typename OUTS, typename F>
...
@@ -26,10 +26,10 @@ template<typename INS, typename OUTS, typename F>
class
function_node
{};
class
function_node
{};
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
class
function_node
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>
,
F
>
:
public
node
{
class
function_node
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>
,
F
>
:
public
node
{
private
:
private
:
// Our own type
// Our own type
using
self_type
=
function_node
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>
,
F
>
;
using
self_type
=
function_node
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>
,
F
>
;
// Input-Output port types
// Input-Output port types
using
multi_in_port_type
=
multi_in_port
<
self_type
,
0
,
I0
,
I
...
>
;
using
multi_in_port_type
=
multi_in_port
<
self_type
,
0
,
I0
,
I
...
>
;
...
...
This diff is collapsed.
Click to expand it.
lib/pls/include/pls/dataflow/internal/function_node_impl.h
View file @
ebf6fec7
...
@@ -8,7 +8,7 @@ namespace internal {
...
@@ -8,7 +8,7 @@ namespace internal {
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
int
POS
,
typename
T
>
template
<
int
POS
,
typename
T
>
void
function_node
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>
,
F
>::
void
function_node
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>
,
F
>::
token_pushed
(
token
<
T
>
token
)
{
token_pushed
(
token
<
T
>
token
)
{
auto
current_memory
=
get_invocation
<
invocation_memory
>
(
token
.
invocation
());
auto
current_memory
=
get_invocation
<
invocation_memory
>
(
token
.
invocation
());
...
@@ -24,7 +24,7 @@ token_pushed(token<T> token) {
...
@@ -24,7 +24,7 @@ token_pushed(token<T> token) {
// Helpers for actually calling the work lambda
// Helpers for actually calling the work lambda
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
void
function_node
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>
,
F
>::
void
function_node
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>
,
F
>::
execute_function
(
invocation_memory
*
invocation_memory
,
invocation_info
invocation_info
)
{
execute_function
(
invocation_memory
*
invocation_memory
,
invocation_info
invocation_info
)
{
auto
lambda
=
[
&
]()
{
auto
lambda
=
[
&
]()
{
input_tuple
&
inputs
=
invocation_memory
->
input_buffer_
;
input_tuple
&
inputs
=
invocation_memory
->
input_buffer_
;
...
@@ -39,14 +39,14 @@ execute_function(invocation_memory *invocation_memory, invocation_info invocatio
...
@@ -39,14 +39,14 @@ execute_function(invocation_memory *invocation_memory, invocation_info invocatio
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
int
N
,
typename
...
OT
>
template
<
int
N
,
typename
...
OT
>
struct
function_node
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>
,
F
>::
struct
function_node
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>
,
F
>::
propagate_output
{
propagate_output
{
propagate_output
(
multi_out_port_type
&
,
output_tuple
&
)
{}
propagate_output
(
multi_out_port_type
&
,
output_tuple
&
)
{}
void
propagate
()
{}
void
propagate
()
{}
};
};
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
int
N
,
typename
OT1
,
typename
...
OT
>
template
<
int
N
,
typename
OT1
,
typename
...
OT
>
struct
function_node
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>
,
F
>::
struct
function_node
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>
,
F
>::
propagate_output
<
N
,
OT1
,
OT
...
>
{
propagate_output
<
N
,
OT1
,
OT
...
>
{
multi_out_port_type
&
out_port_
;
multi_out_port_type
&
out_port_
;
output_tuple
&
output_tuple_
;
output_tuple
&
output_tuple_
;
...
@@ -62,14 +62,14 @@ propagate_output<N, OT1, OT...> {
...
@@ -62,14 +62,14 @@ propagate_output<N, OT1, OT...> {
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
typename
T
>
template
<
typename
T
>
void
function_node
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>
,
F
>::
void
function_node
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>
,
F
>::
set_invocation_info
(
token
<
T
>
&
token
,
invocation_info
invocation_info
)
{
set_invocation_info
(
token
<
T
>
&
token
,
invocation_info
invocation_info
)
{
token
.
set_invocation
(
invocation_info
);
token
.
set_invocation
(
invocation_info
);
}
}
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
,
typename
F
>
template
<
int
...
IS
,
int
...
OS
>
template
<
int
...
IS
,
int
...
OS
>
void
function_node
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>
,
F
>::
void
function_node
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>
,
F
>::
execute_function_internal
(
input_tuple
&
inputs
,
sequence
<
IS
...
>
,
execute_function_internal
(
input_tuple
&
inputs
,
sequence
<
IS
...
>
,
output_tuple
&
outputs
,
sequence
<
OS
...
>
,
output_tuple
&
outputs
,
sequence
<
OS
...
>
,
invocation_info
invocation_info
)
{
invocation_info
invocation_info
)
{
...
...
This diff is collapsed.
Click to expand it.
lib/pls/include/pls/dataflow/internal/graph.h
View file @
ebf6fec7
...
@@ -24,10 +24,10 @@ template<typename INS, typename OUTS>
...
@@ -24,10 +24,10 @@ template<typename INS, typename OUTS>
class
graph
{};
class
graph
{};
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
class
graph
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>>
:
public
node
{
class
graph
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>>
:
public
node
{
private
:
private
:
// Our own type
// Our own type
using
self_type
=
graph
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>>
;
using
self_type
=
graph
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>>
;
// Input-Output port types (internal)
// Input-Output port types (internal)
using
inputs_type
=
multi_out_port
<
I0
,
I
...
>
;
using
inputs_type
=
multi_out_port
<
I0
,
I
...
>
;
...
@@ -71,6 +71,7 @@ class graph<pls::dataflow::inputs<I0, I...>, pls::dataflow::outputs<O0, O...>> :
...
@@ -71,6 +71,7 @@ class graph<pls::dataflow::inputs<I0, I...>, pls::dataflow::outputs<O0, O...>> :
void
build
();
void
build
();
void
run
(
value_input_tuple
input
,
value_output_tuple
&
output
)
{
void
run
(
value_input_tuple
input
,
value_output_tuple
&
output
)
{
PLS_ASSERT
(
build_state_
==
build_state
::
built
,
"Must build graph before running it!"
)
pls
::
scheduler
::
spawn_child
<
run_graph_task
>
(
this
,
input
,
&
output
);
pls
::
scheduler
::
spawn_child
<
run_graph_task
>
(
this
,
input
,
&
output
);
}
}
...
...
This diff is collapsed.
Click to expand it.
lib/pls/include/pls/dataflow/internal/graph_impl.h
View file @
ebf6fec7
...
@@ -8,14 +8,14 @@ namespace internal {
...
@@ -8,14 +8,14 @@ namespace internal {
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
int
POS
,
typename
T
>
template
<
int
POS
,
typename
T
>
void
graph
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>>::
void
graph
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>>::
token_pushed
(
token
<
T
>
token
)
{
token_pushed
(
token
<
T
>
token
)
{
auto
invocation
=
get_invocation
<
invocation_memory
>
(
token
.
invocation
());
auto
invocation
=
get_invocation
<
invocation_memory
>
(
token
.
invocation
());
std
::
get
<
POS
>
(
*
invocation
->
output_buffer_
)
=
token
.
value
();
std
::
get
<
POS
>
(
*
invocation
->
output_buffer_
)
=
token
.
value
();
}
}
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
void
graph
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>>::
void
graph
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>>::
build
()
{
build
()
{
PLS_ASSERT
(
build_state_
==
build_state
::
fresh
,
"Must only build a dataflow graph once!"
)
PLS_ASSERT
(
build_state_
==
build_state
::
fresh
,
"Must only build a dataflow graph once!"
)
PLS_ASSERT
(
is_fully_connected
(),
"Must fully connect all inputs/outputs inside a dataflow graph!"
)
PLS_ASSERT
(
is_fully_connected
(),
"Must fully connect all inputs/outputs inside a dataflow graph!"
)
...
@@ -31,7 +31,7 @@ build() {
...
@@ -31,7 +31,7 @@ build() {
}
}
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
void
graph
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>>::
void
graph
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>>::
build_recursive
(
node
*
node
)
{
build_recursive
(
node
*
node
)
{
if
(
node
->
build_state_
!=
build_state
::
fresh
)
{
if
(
node
->
build_state_
!=
build_state
::
fresh
)
{
return
;
// Already visited
return
;
// Already visited
...
@@ -48,7 +48,7 @@ build_recursive(node *node) {
...
@@ -48,7 +48,7 @@ build_recursive(node *node) {
}
}
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
void
graph
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>>::
void
graph
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>>::
add_node
(
node
*
new_node
)
{
add_node
(
node
*
new_node
)
{
new_node
->
memory_index_
=
num_nodes_
++
;
new_node
->
memory_index_
=
num_nodes_
++
;
...
@@ -63,7 +63,7 @@ add_node(node *new_node) {
...
@@ -63,7 +63,7 @@ add_node(node *new_node) {
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
int
N
,
typename
...
IT
>
template
<
int
N
,
typename
...
IT
>
struct
graph
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>>::
struct
graph
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>>::
feed_inputs
{
feed_inputs
{
feed_inputs
(
inputs_type
&
,
value_input_tuple
&
,
invocation_info
&
)
{}
feed_inputs
(
inputs_type
&
,
value_input_tuple
&
,
invocation_info
&
)
{}
void
run
()
{}
void
run
()
{}
...
@@ -71,7 +71,7 @@ feed_inputs {
...
@@ -71,7 +71,7 @@ feed_inputs {
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
int
N
,
typename
IT1
,
typename
...
IT
>
template
<
int
N
,
typename
IT1
,
typename
...
IT
>
struct
graph
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>>::
struct
graph
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>>::
feed_inputs
<
N
,
IT1
,
IT
...
>
{
feed_inputs
<
N
,
IT1
,
IT
...
>
{
inputs_type
&
inputs_
;
inputs_type
&
inputs_
;
value_input_tuple
&
input_values_
;
value_input_tuple
&
input_values_
;
...
@@ -90,7 +90,7 @@ feed_inputs<N, IT1, IT...> {
...
@@ -90,7 +90,7 @@ feed_inputs<N, IT1, IT...> {
};
};
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
template
<
typename
I0
,
typename
...
I
,
typename
O0
,
typename
...
O
>
class
graph
<
pls
::
dataflow
::
inputs
<
I0
,
I
...
>
,
pls
::
dataflow
::
outputs
<
O0
,
O
...
>>::
run_graph_task
:
public
pls
::
task
{
class
graph
<
inputs
<
I0
,
I
...
>
,
outputs
<
O0
,
O
...
>>::
run_graph_task
:
public
pls
::
task
{
graph
*
self_
;
graph
*
self_
;
value_input_tuple
input_
;
value_input_tuple
input_
;
value_output_tuple
*
output_
;
value_output_tuple
*
output_
;
...
...
This diff is collapsed.
Click to expand it.
lib/pls/include/pls/dataflow/internal/inputs.h
View file @
ebf6fec7
...
@@ -4,6 +4,7 @@
...
@@ -4,6 +4,7 @@
namespace
pls
{
namespace
pls
{
namespace
dataflow
{
namespace
dataflow
{
namespace
internal
{
template
<
typename
I1
,
typename
...
I
>
template
<
typename
I1
,
typename
...
I
>
struct
inputs
{
struct
inputs
{
...
@@ -11,5 +12,6 @@ struct inputs {
...
@@ -11,5 +12,6 @@ struct inputs {
}
}
}
}
}
#endif //PLS_DATAFLOW_INTERNAL_INPUTS_H_
#endif //PLS_DATAFLOW_INTERNAL_INPUTS_H_
This diff is collapsed.
Click to expand it.
lib/pls/include/pls/dataflow/internal/node.h
View file @
ebf6fec7
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
#define PLS_DATAFLOW_INTERNAL_NODE_H_
#define PLS_DATAFLOW_INTERNAL_NODE_H_
#include "build_state.h"
#include "build_state.h"
#include "token.h"
namespace
pls
{
namespace
pls
{
namespace
dataflow
{
namespace
dataflow
{
...
...
This diff is collapsed.
Click to expand it.
lib/pls/include/pls/dataflow/internal/outputs.h
View file @
ebf6fec7
...
@@ -4,6 +4,7 @@
...
@@ -4,6 +4,7 @@
namespace
pls
{
namespace
pls
{
namespace
dataflow
{
namespace
dataflow
{
namespace
internal
{
template
<
typename
O0
,
typename
...
O
>
template
<
typename
O0
,
typename
...
O
>
struct
outputs
{
struct
outputs
{
...
@@ -11,5 +12,6 @@ struct outputs {
...
@@ -11,5 +12,6 @@ struct outputs {
}
}
}
}
}
#endif //PLS_DATAFLOW_INTERNAL_OUTPUTS_H_
#endif //PLS_DATAFLOW_INTERNAL_OUTPUTS_H_
This diff is collapsed.
Click to expand it.
lib/pls/include/pls/pls.h
View file @
ebf6fec7
...
@@ -7,6 +7,7 @@
...
@@ -7,6 +7,7 @@
#include "pls/internal/scheduling/task.h"
#include "pls/internal/scheduling/task.h"
#include "pls/internal/scheduling/scheduler.h"
#include "pls/internal/scheduling/scheduler.h"
#include "pls/internal/helpers/unique_id.h"
#include "pls/internal/helpers/unique_id.h"
#include "pls/internal/helpers/member_function.h"
namespace
pls
{
namespace
pls
{
...
@@ -16,6 +17,8 @@ using internal::scheduling::malloc_scheduler_memory;
...
@@ -16,6 +17,8 @@ using internal::scheduling::malloc_scheduler_memory;
using
internal
::
scheduling
::
scheduler
;
using
internal
::
scheduling
::
scheduler
;
using
unique_id
=
internal
::
helpers
::
unique_id
;
using
unique_id
=
internal
::
helpers
::
unique_id
;
template
<
class
C
,
typename
R
,
typename
...
ARGS
>
using
member_function
=
internal
::
helpers
::
member_function
<
C
,
R
,
ARGS
...
>
;
using
internal
::
scheduling
::
task
;
using
internal
::
scheduling
::
task
;
using
internal
::
scheduling
::
lambda_task_by_reference
;
using
internal
::
scheduling
::
lambda_task_by_reference
;
...
...
This diff is collapsed.
Click to expand it.
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