Commit 3feac8d9 authored by Claes Sjofors's avatar Claes Sjofors

Xtt collect graph updated, and added to collect menu

parent 0ec860ce
......@@ -451,6 +451,27 @@ void XttGtk::activate_collect_clear( GtkWidget *w, gpointer data)
xtt->xnav->collect_clear();
}
void XttGtk::activate_collect_opengraph( GtkWidget *w, gpointer data)
{
Xtt *xtt = (Xtt *)data;
pwr_tCmd cmd = "open graph /collect";
if ( !xtt->xnav->is_authorized())
return;
int showed = 0;
if ( xtt->xnav->brow->ctx != xtt->xnav->collect_brow->ctx) {
xtt->xnav->collect_show();
showed = 1;
}
xtt->xnav->command( cmd);
if ( showed)
// Hide
xtt->xnav->collect_show();
}
void XttGtk::activate_collect_window( GtkWidget *w, gpointer data)
{
Xtt *xtt = (Xtt *)data;
......@@ -868,6 +889,10 @@ XttGtk::XttGtk( int argc, char *argv[], int *return_sts) :
g_signal_connect( functions_collect_clear, "activate",
G_CALLBACK(XttGtk::activate_collect_clear), this);
GtkWidget *functions_collect_opengraph = gtk_menu_item_new_with_mnemonic(CoWowGtk::translate_utf8("O_pen Graph"));
g_signal_connect( functions_collect_opengraph, "activate",
G_CALLBACK(XttGtk::activate_collect_opengraph), this);
GtkWidget *functions_collect_window = gtk_menu_item_new_with_mnemonic(CoWowGtk::translate_utf8("_Copy to Window"));
g_signal_connect( functions_collect_window, "activate",
G_CALLBACK(XttGtk::activate_collect_window), this);
......@@ -901,6 +926,7 @@ XttGtk::XttGtk( int argc, char *argv[], int *return_sts) :
gtk_menu_shell_append(GTK_MENU_SHELL(functions_collect_menu), functions_collect_show);
gtk_menu_shell_append(GTK_MENU_SHELL(functions_collect_menu), functions_collect_remove);
gtk_menu_shell_append(GTK_MENU_SHELL(functions_collect_menu), functions_collect_clear);
gtk_menu_shell_append(GTK_MENU_SHELL(functions_collect_menu), functions_collect_opengraph);
gtk_menu_shell_append(GTK_MENU_SHELL(functions_collect_menu), functions_collect_window);
gtk_menu_shell_append(GTK_MENU_SHELL(functions_collect_menu), functions_collect_new_window);
gtk_menu_shell_append(GTK_MENU_SHELL(functions_collect_menu), functions_collect_signals);
......
......@@ -108,6 +108,7 @@ class XttGtk : public Xtt {
static void activate_collect_show( GtkWidget *w, gpointer data);
static void activate_collect_remove( GtkWidget *w, gpointer data);
static void activate_collect_clear( GtkWidget *w, gpointer data);
static void activate_collect_opengraph( GtkWidget *w, gpointer data);
static void activate_collect_window( GtkWidget *w, gpointer data);
static void activate_collect_new_window( GtkWidget *w, gpointer data);
static void activate_collect_signals( GtkWidget *w, gpointer data);
......
......@@ -659,6 +659,14 @@ void GeDyn::open( ifstream& fp)
}
}
void GeDyn::update_dyntype( grow_tObject object)
{
total_dyn_type1 = get_dyntype1( object);
total_dyn_type2 = get_dyntype2( object);
total_action_type1 = get_actiontype1( object);
total_action_type2 = get_actiontype2( object);
}
ge_mDynType1 GeDyn::get_dyntype1( grow_tObject object)
{
if ( object && dyn_type1 & ge_mDynType1_Inherit) {
......
......@@ -869,6 +869,7 @@ class GeDyn {
//! Execute action after confirm.
int confirmed_action( grow_tObject object, glow_tEvent event);
int change_value( grow_tObject object, char *text);
void update_dyntype( grow_tObject object);
ge_mDynType1 get_dyntype1( grow_tObject object);
ge_mDynType2 get_dyntype2( grow_tObject object);
ge_mActionType1 get_actiontype1( grow_tObject object);
......
......@@ -61,7 +61,6 @@ typedef struct {
static int graph_object_dx( Graph *graph, pwr_sAttrRef *attrref);
static int graph_object_PlcThread( Graph *graph, pwr_sAttrRef *attrref);
static int graph_object_collect( Graph *graph, pwr_sAttrRef *attrref);
static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref);
static graph_sObjectFunction graph_object_functions[] = {
......@@ -162,26 +161,18 @@ int Graph::init_object_graph( int mode)
int is_type = 0;
pwr_sAttrRef attrref;
if ( mode == 0)
{
if ( strcmp( filename, "_none_.pwg") == 0)
{
if ( strcmp( object_name[0], "collect") == 0)
{
if ( mode == 0) {
if ( strcmp( filename, "_none_.pwg") == 0) {
if ( strcmp( object_name[0], "collect") == 0) {
sts = graph_object_collect_build( this, 0);
return sts;
}
}
return 1;
}
if ( strcmp( filename, "_none_.pwg") == 0)
{
if ( strcmp( filename, "_none_.pwg") == 0) {
if ( strcmp( object_name[0], "collect") == 0)
{
sts = graph_object_collect( this, 0);
return sts;
}
return 1;
}
// Get class from filename
......@@ -673,75 +664,6 @@ int Graph::trend_init( graph_sObjectTrend *td, pwr_sAttrRef *arp)
#define MAX_TREND_OBJECTS 100
typedef struct {
char object_name[120];
graph_sObjectTrend trend1;
grow_tObject trend_objects[MAX_TREND_OBJECTS];
double *data_scan_time_p[MAX_TREND_OBJECTS];
int *hold_p[100];
int trend_cnt;
} graph_sObjectCollect;
static void graph_object_collect_scan( Graph *graph)
{
graph_sObjectCollect *od = (graph_sObjectCollect *)graph->graph_object_data;
graph_sObjectTrend *td = &od->trend1;
int i;
// Reconfigure new scantime
if ( td->scan_time_p &&
*td->scan_time_p != td->old_scan_time)
{
if ( graph->scan_time > *td->scan_time_p/200)
{
graph->scan_time = *td->scan_time_p/200;
graph->animation_scan_time = *td->scan_time_p/200;
}
for ( i = 0; i < od->trend_cnt; i++) {
grow_SetTrendScanTime( od->trend_objects[i], double( *td->scan_time_p/200));
*od->data_scan_time_p[i] = double(*td->scan_time_p)/200;
}
td->old_scan_time = *td->scan_time_p;
}
if ( td->hold_button_p && *td->hold_button_p)
{
for ( i = 0; i < od->trend_cnt; i++)
*od->hold_p[i] = !*od->hold_p[i];
*td->hold_button_p = 0;
if ( *td->hold_p && td->hold_button_object)
grow_SetObjectColorTone( td->hold_button_object, glow_eDrawTone_Yellow);
else
grow_ResetObjectColorTone( td->hold_button_object);
}
}
static void graph_object_collect_close( Graph *graph)
{
free( graph->graph_object_data);
}
static int graph_object_collect( Graph *graph, pwr_sAttrRef *attrref)
{
int sts;
graph_sObjectCollect *od = (graph_sObjectCollect *)graph->graph_object_data;
int i;
if ( !od)
return 1;
sts = graph->trend_init( &od->trend1, attrref);
for ( i = 0; i < od->trend_cnt; i++) {
GeDyn *dyn;
grow_GetUserData( od->trend_objects[i], (void **)&dyn);
od->data_scan_time_p[i] = dyn->ref_trend_scantime();
od->hold_p[i] = dyn->ref_trend_hold();
}
return 1;
}
static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
{
pwr_sAttrRef *alist, *ap;
......@@ -749,7 +671,6 @@ static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
int sts;
char name[120];
double x1, y1;
graph_sObjectCollect *od;
grow_sAttrInfo *grow_info, *grow_info_p;
int grow_info_cnt;
int i;
......@@ -758,7 +679,7 @@ static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
grow_tObject t1, l1;
double z_width, z_height, z_descent;
double name_width = 0;
double trend_width = 28;
double trend_width = 48;
double trend_height = 1.2;
double y0 = 2.2;
double x0 = 2;
......@@ -766,6 +687,9 @@ static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
unsigned int attr_size, attr_offset, attr_dimension;
GeDyn *dyn;
char attr_name[120];
grow_sAttributes grow_attr;
unsigned long mask;
int trend_cnt = 0;
if ( ! graph->get_current_objects_cb)
......@@ -777,14 +701,23 @@ static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
if ( cdh_ObjidIsNull( alist->Objid))
return 0;
od = (graph_sObjectCollect *) calloc( 1, sizeof(graph_sObjectCollect));
graph->graph_object_data = (void *) od;
graph->graph_object_close = graph_object_collect_close;
graph->graph_object_data = 0;
graph->graph_object_close = 0;
grow_SetPath( graph->grow->ctx, 1, "pwr_exe:");
// Scantime button
graph->create_node( NULL, "pwr_valuereliefup", x0, y0 - 1, 4, y0 - 1 + 0.7,
// Set graph attributes
// Default color theme
mask = grow_eAttr_color_theme;
strcpy( grow_attr.color_theme, "$default");
grow_SetAttributes( graph->grow->ctx, &grow_attr, mask);
grow_ReadCustomColorFile( graph->grow->ctx, 0);
grow_SetBackgroundColor( graph->grow->ctx, glow_eDrawType_CustomColor1);
// Scantime input field
graph->create_node( NULL, "pwrct_valueinputsmallbg", x0, y0 - 1.3, 4, y0 - 1.3 + 1.2,
&scantime_button);
dyn = new GeDyn( graph);
......@@ -794,43 +727,33 @@ static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
dyn->update_elements();
dyn->set_access( (glow_mAccess) 65535);
dyn->set_attribute( scantime_button, "$local.ScanTime##Float32", 0);
dyn->set_value_input( "%6.0f", 2, 10000000);
dyn->set_value_input( "%3.0f", 2, 10000000);
// Hold button
graph->create_node( "TrendHold", "pwr_smallbutton", x0 + trend_width/2 - 3./2,
y0 - 1 , x0 + trend_width/2 + 3./2, y0 - 1 + 0.85,
graph->create_node( "TrendHold", "pwrct_buttonsmalltoggle", x0 + trend_width/2 - 3./2,
y0 - 1.4 , x0 + trend_width/2 + 3./2, y0 - 1.4 + 1.2,
&hold_button);
grow_SetAnnotation( hold_button, 1, " Hold", 6);
grow_SetAnnotation( hold_button, 1, "Hold", 4);
dyn = new GeDyn( graph);
grow_SetUserData( hold_button, (void *)dyn);
// Set color tone
grow_SelectClear( graph->grow->ctx);
grow_SelectInsert( graph->grow->ctx, hold_button);
grow_SetSelectOrigColorTone( graph->grow->ctx, glow_eDrawTone_Gray);
grow_SelectRemove( graph->grow->ctx, hold_button);
dyn->set_dyn( ge_mDynType1_No, ge_mDynType2_No, ge_mActionType1_SetDig, ge_mActionType2_No);
dyn->update_elements();
dyn->set_access( (glow_mAccess) 65535);
dyn->set_attribute( hold_button, "$local.TrendHold##Boolean", 0);
// Zero text
grow_CreateGrowText( graph->grow->ctx, "", "0",
x0 + trend_width - 0.2, y0 - 0.2,
glow_eDrawType_TextHelveticaBold, glow_eDrawType_Line, 2,
glow_eFont_Helvetica, glow_mDisplayLevel_1,
x0 + trend_width - 0.2, y0 - 0.3,
glow_eDrawType_TextHelvetica, glow_eDrawType_CustomColor5, 3,
glow_eFont_LucidaSans, glow_mDisplayLevel_1,
NULL, &t1);
ap = alist;
is_attrp = is_attr;
x1 = x0;
y1 = y0;
while( cdh_ObjidIsNotNull( ap->Objid))
{
if ( *is_attrp)
{
while( cdh_ObjidIsNotNull( ap->Objid)) {
if ( *is_attrp) {
sts = gdh_AttrrefToName( ap, name, sizeof(name), cdh_mNName);
if ( EVEN(sts)) return sts;
......@@ -839,30 +762,32 @@ static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
if ( EVEN(sts)) return sts;
switch ( attr_type) {
case pwr_eType_Boolean:
case pwr_eType_Boolean: {
grow_tObject trend;
grow_CreateGrowTrend( graph->grow->ctx, "ActualValueTrend",
x1, y1, trend_width, trend_height,
glow_eDrawType_Color37,
0, glow_mDisplayLevel_1, 1, 1,
glow_eDrawType_Color40, NULL,
&od->trend_objects[od->trend_cnt]);
&trend);
dyn = new GeDyn( graph);
dyn->dyn_type1 = ge_mDynType1_Trend;
dyn->update_dyntype( trend);
dyn->update_elements();
grow_SetUserData( od->trend_objects[od->trend_cnt], (void *)dyn);
grow_SetUserData( trend, (void *)dyn);
grow_GetObjectAttrInfo( od->trend_objects[od->trend_cnt], NULL,
grow_GetObjectAttrInfo( trend, NULL,
&grow_info, &grow_info_cnt);
strcpy( attr_name, name);
strcat( attr_name, "##Boolean");
grow_GetUserData( od->trend_objects[od->trend_cnt], (void **)&dyn);
dyn->set_attribute( od->trend_objects[od->trend_cnt], attr_name, 0);
grow_GetUserData( trend, (void **)&dyn);
strcpy( ((GeTrend *)dyn->elements)->attribute1, attr_name);
strcpy( ((GeTrend *)dyn->elements)->timerange_attr, "$local.ScanTime##Float32");
strcpy( ((GeTrend *)dyn->elements)->hold_attr, "$local.TrendHold##Boolean");
grow_info_p = grow_info;
for ( i = 0; i < grow_info_cnt; i++)
{
for ( i = 0; i < grow_info_cnt; i++) {
if ( strcmp( grow_info_p->name, "NoOfPoints") == 0)
*(int *) grow_info_p->value_p = 200;
else if ( strcmp( grow_info_p->name, "HorizontalLines") == 0)
......@@ -870,7 +795,7 @@ static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
else if ( strcmp( grow_info_p->name, "VerticalLines") == 0)
*(int *) grow_info_p->value_p = 9;
else if ( strcmp( grow_info_p->name, "CurveColor1") == 0)
*(int *) grow_info_p->value_p = glow_eDrawType_Color145;
*(int *) grow_info_p->value_p = glow_eDrawType_CustomColor68;
else if ( strcmp( grow_info_p->name, "MaxValue1") == 0)
*(double *) grow_info_p->value_p = 1.2;
else if ( strcmp( grow_info_p->name, "MinValue1") == 0)
......@@ -881,27 +806,31 @@ static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
grow_FreeObjectAttrInfo( grow_info);
// This will configure the curves
grow_SetTrendScanTime( od->trend_objects[od->trend_cnt], 0.5);
grow_SetTrendScanTime( trend, 0.5);
grow_SetObjectOriginalFillColor( trend, glow_eDrawType_CustomColor66);
grow_SetObjectOriginalBorderColor( trend, glow_eDrawType_CustomColor67);
grow_GetTextExtent( graph->grow->ctx, name,
strlen(name), glow_eDrawType_TextHelveticaBold,
2, glow_eFont_Helvetica, &z_width, &z_height, &z_descent);
strlen(name), glow_eDrawType_TextHelvetica,
4, glow_eFont_LucidaSans, &z_width, &z_height, &z_descent);
grow_CreateGrowText( graph->grow->ctx, "", name,
x1 + trend_width + 1, y1 + trend_height/2 + z_height/2,
glow_eDrawType_TextHelveticaBold, glow_eDrawType_Line, 2,
glow_eFont_Helvetica, glow_mDisplayLevel_1,
glow_eDrawType_TextHelvetica, glow_eDrawType_CustomColor5, 4,
glow_eFont_LucidaSans, glow_mDisplayLevel_1,
NULL, &t1);
if ( z_width > name_width)
name_width = z_width;
od->trend_cnt++;
trend_cnt++;
y1 += trend_height;
break;
}
default:
;
}
if ( od->trend_cnt >= MAX_TREND_OBJECTS)
if ( trend_cnt >= MAX_TREND_OBJECTS)
break;
}
......@@ -916,36 +845,39 @@ static int graph_object_collect_build( Graph *graph, pwr_sAttrRef *attrref)
x1 = x0 + trend_width;
grow_CreateGrowLine( graph->grow->ctx, "",
x0 + trend_width, y1, x0 + trend_width + name_width + 2, y1,
glow_eDrawType_Color78, 1, 0, NULL, &l1);
glow_eDrawType_CustomColor4, 1, 0, NULL, &l1);
for ( i = 0; i < od->trend_cnt; i++) {
for ( i = 0; i < trend_cnt; i++) {
y1 += trend_height;
grow_CreateGrowLine( graph->grow->ctx, "",
x0 + trend_width, y1, x0 + trend_width + name_width + 2, y1,
glow_eDrawType_Color71, 1, 0, NULL, &l1);
glow_eDrawType_CustomColor4, 1, 0, NULL, &l1);
}
// Draw frame
graph->create_node( "", "pwr_framethin", x0 - 0.5,
y0 - 1.3 , x0 + trend_width + name_width + 2,
y0 + od->trend_cnt * trend_height + 0.5,
&l1);
dyn = new GeDyn( graph);
grow_SetUserData( l1, (void *)dyn);
grow_CreateGrowRect( graph->grow->ctx, "R1", x0 - 1.5, y0 - 2.7,
trend_width + name_width + 5.5, 1, glow_eDrawType_CustomColor3,
1, 0, glow_mDisplayLevel_1, 1, 0, 0,
glow_eDrawType_CustomColor3, NULL, &l1);
grow_CreateGrowRect( graph->grow->ctx, "R2", x0 - 1.5, y0 + trend_cnt * trend_height + 0.5,
trend_width + name_width + 5.5, 5, glow_eDrawType_CustomColor3,
1, 0, glow_mDisplayLevel_1, 1, 0, 0,
glow_eDrawType_CustomColor3, NULL, &l1);
grow_CreateGrowRect( graph->grow->ctx, "R3", x0 + trend_width + name_width + 2, y0 - 1.7,
2, y0 + trend_cnt * trend_height + 0.9, glow_eDrawType_CustomColor3,
1, 0, glow_mDisplayLevel_1, 1, 0, 0,
glow_eDrawType_CustomColor3, NULL, &l1);
grow_CreateGrowRect( graph->grow->ctx, "R4", x0 - 1.5, y0 - 1.7,
1, y0 + trend_cnt * trend_height + 0.9, glow_eDrawType_CustomColor3,
1, 0, glow_mDisplayLevel_1, 1, 0, 0,
glow_eDrawType_CustomColor3, NULL, &l1);
grow_SetLayout( graph->grow->ctx, x0 - 1, y0 - 2.3, x0 + trend_width +
name_width + 3, y0 + od->trend_cnt * trend_height + 1.5);
// Register scan function
graph->graph_object_scan = graph_object_collect_scan;
name_width + 3, y0 + trend_cnt * trend_height + 1.5);
// Set graph attributes
grow_sAttributes grow_attr;
unsigned long mask = 0;
mask |= grow_eAttr_double_buffer_on;
mask = grow_eAttr_double_buffer_on;
grow_attr.double_buffer_on = 1;
grow_SetAttributes( graph->grow->ctx, &grow_attr, mask);
......
......@@ -751,6 +751,10 @@ void grow_SetAttributes( grow_tCtx ctx, grow_sAttributes *attr,
ctx->initial_position = attr->initial_position;
if ( mask & grow_eAttr_environment)
ctx->environment = attr->environment;
if ( mask & grow_eAttr_tooltip_text_size)
ctx->tiptext_size = attr->tooltip_text_size;
if ( mask & grow_eAttr_color_theme)
strncpy( ctx->color_theme, attr->color_theme, sizeof(ctx->color_theme));
}
void grow_GetAttributes( grow_tCtx ctx, grow_sAttributes *attr,
......@@ -4530,6 +4534,12 @@ void grow_SetLayout( grow_tCtx ctx, double x0, double y0, double x1,
ctx->set_layout( x0, y0, x1, y1);
}
void grow_GetLayout( grow_tCtx ctx, double *x0, double *y0, double *x1,
double *y1)
{
ctx->get_layout( x0, y0, x1, y1);
}
void grow_SetPath( grow_tCtx ctx, int path_cnt, const char *path)
{
ctx->set_path( path_cnt, path);
......
......@@ -120,6 +120,8 @@ extern "C" {
glow_eHotMode hot_mode;
glow_eDirection initial_position;
glow_eEnv environment;
int tooltip_text_size;
char color_theme[40];
} grow_sAttributes;
typedef enum {
......@@ -144,7 +146,9 @@ extern "C" {
grow_eAttr_double_buffer_on = 1 << 18,
grow_eAttr_hot_mode = 1 << 19,
grow_eAttr_initial_position = 1 << 20,
grow_eAttr_environment = 1 << 21
grow_eAttr_environment = 1 << 21,
grow_eAttr_tooltip_text_size = 1 << 22,
grow_eAttr_color_theme = 1 << 23
} grow_eAttribute;
......@@ -1907,6 +1911,17 @@ extern "C" {
void grow_SetLayout( grow_tCtx ctx, double x0, double y0, double x1,
double y1);
//! Get layout.
/*!
\param ctx Grow context.
\param x0 x coordinate for left border.
\param y0 y coordinate for low border.
\param x1 x coordinate for right border.
\param y1 y coordinate for high border.
*/
void grow_GetLayout( grow_tCtx ctx, double *x0, double *y0, double *x1,
double *y1);
//! Set search path for subgraphs and images.
/*!
\param ctx Grow context.
......
......@@ -4698,6 +4698,9 @@ int GrowCtx::read_customcolor_file( char *name)
if ( environment == glow_eEnv_Runtime && strcmp( color_theme, "$default") != 0)
return 0;
if ( name == 0 && strcmp( default_color_theme, "") != 0)
name = default_color_theme;
if ( customcolors) {
sts = customcolors->read_colorfile( this, name);
if ( ODD(sts)) {
......
......@@ -758,6 +758,16 @@ class GrowCtx : public GlowCtx {
void set_layout( double nx0, double ny0, double nx1, double ny1)
{ x0 = nx0; y0 = ny0; x1 = nx1; y1= ny1; };
//! Get layout
/*!
\param nx0 x coordinate for left border.
\param ny0 y coordinate for low border.
\param nx1 x coordinate for right border.
\param ny1 y coordinate for high border.
*/
void get_layout( double *nx0, double *ny0, double *nx1, double *ny1)
{ *nx0 = x0; *ny0 = y0; *nx1 = x1; *ny1= y1; };
//! Group the selected objects.
/*!
\param group Created group.
......
......@@ -491,6 +491,27 @@ XttGeGtk::XttGeGtk( GtkWidget *xg_parent_wid, void *xg_parent_ctx, const char *x
if ( borders)
((Graph *)graph)->set_borders( borders);
if ( strcmp( filename, "_none_") == 0 && xg_width == 0 && xg_height == 0) {
// Set size from current layout
double x0, y0, x1, y1, zoom;
float rd = 0.05;
grow_GetLayout( graph->grow->ctx, &x0, &y0, &x1, &y1);
grow_GetZoom( graph->grow->ctx, &zoom);
window_width = zoom * ( x1 - x0);
window_height = zoom * ( y1 - y0);
if ( window_width < 300 || window_height < 300)
rd = 0.2;
geometry.min_aspect = gdouble(window_width)/window_height * (1.0 - rd);
geometry.max_aspect = gdouble(window_width)/window_height * (1.0 + rd);
gtk_window_set_geometry_hints( GTK_WINDOW(toplevel), GTK_WIDGET(toplevel),
&geometry, GDK_HINT_ASPECT);
gtk_widget_set_size_request( toplevel, window_width, window_height);
}
}
static gint confirm_delete_event( GtkWidget *w, GdkEvent *event, gpointer ge)
......
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