Commit 21c9850a authored by Madeline Wade's avatar Madeline Wade Committed by Madeline Wade
Browse files

Added additional latency montioring to calibration pipeline. Exposed timestamp...

Added additional latency montioring to calibration pipeline. Exposed timestamp property in lal_latency.
parent df887d93
Pipeline #73068 failed with stages
in 1 minute and 7 seconds
......@@ -1121,6 +1121,11 @@ elif InputConfigs["datasource"] == "frames": # Data is to be read from frame fil
if test_latency:
src = pipeparts.mklatency(pipeline, src, name = "%s_src" % OutputConfigs["frametype"])
src.connect("notify::current-latency", handler.latency_new_buffer)
elif InputConfigs["datasource"] == "lvshm":
src = pipeparts.mklatency(pipeline, src, name = "%s_src" % OutputConfigs["frametype"], silent = True)
src.connect("notify::current-latency", handler.latency_new_buffer)
#
# Hook up the relevant channels to the demuxer
......@@ -2267,6 +2272,10 @@ if actsr != hoft_sr:
if test_latency:
ctrl = pipeparts.mklatency(pipeline, ctrl, name = "%s_ctrl" % OutputConfigs["frametype"])
ctrl.connect("notify::current-latency", handler.latency_new_buffer)
elif InputConfigs["datasource"] == "lvshm":
ctrl = pipeparts.mklatency(pipeline, ctrl, name = "%s_ctrl" % OutputConfigs["frametype"], silent = True)
ctrl.connect("notify::current-latency", handler.latency_new_buffer)
#
# RESIDUAL BRANCH
......@@ -2361,6 +2370,10 @@ if dewhitening:
if test_latency:
res = pipeparts.mklatency(pipeline, res, name = "%s_res" % OutputConfigs["frametype"])
res.connect("notify::current-latency", handler.latency_new_buffer)
elif InputConfigs["datasource"] == "lvshm":
res = pipeparts.mklatency(pipeline, res, name = "%s_res" % OutputConfigs["frametype"], silent = True)
res.connect("notify::current-latency", handler.latency_new_buffer)
filter_settle_time = max(res_filter_settle_time, tst_filter_settle_time, pumuim_filter_settle_time)
filter_latency = max(res_filter_latency, tst_filter_latency, pumuim_filter_latency)
......@@ -2389,6 +2402,11 @@ except KeyError:
strain = pipeparts.mkprogressreport(pipeline, strain, "progress_hoft_%s" % instrument)
if test_latency:
strain = pipeparts.mklatency(pipeline, strain, name = "%s_hoft" % OutputConfigs["frametype"])
strain.connect("notify::current-latency", handler.latency_new_buffer)
elif InputConfigs["datasource"] == "lvshm":
strain = pipeparts.mklatency(pipeline, strain, name = "%s_hoft" % OutputConfigs["frametype"], silent = True)
strain.connect("notify::current-latency", handler.latency_new_buffer)
# Put the units back to strain before writing to frames
straintagstr = "units=strain,channel-name=%sCALIB_STRAIN%s,instrument=%s" % (chan_prefix, chan_suffix, instrument)
......@@ -2931,6 +2949,10 @@ if remove_cal_lines or any(line_witness_channel_list) or any(witness_channel_lis
clean_strain = pipeparts.mkprogressreport(pipeline, clean_strain, "progress_hoft_cleaned_%s" % instrument)
if test_latency:
clean_strain = pipeparts.mklatency(pipeline, clean_strain, name = "%s_hoft_cleaned" % OutputConfigs["frametype"])
clean_strain.connect("notify::current-latency", handler.latency_new_buffer)
elif InputConfigs["datasource"] == "lvshm":
clean_strain = pipeparts.mklatency(pipeline, clean_strain, name = "%s_hoft_cleaned" % OutputConfigs["frametype"], silent = True)
clean_strain.connect("notify::current-latency", handler.latency_new_buffer)
clean_straintagstr = "units=strain,channel-name=%sCALIB_STRAIN_CLEAN%s,instrument=%s" % (chan_prefix, chan_suffix, instrument)
clean_straintee = pipeparts.mktee(pipeline, clean_strain)
if not pick_cleanest_strain_channel:
......@@ -2989,6 +3011,10 @@ if compute_calib_statevector:
calibstatevector = pipeparts.mkprogressreport(pipeline, calibstatevector, "progress_calibstatevec_%s" % instrument)
if test_latency:
calibstatevector = pipeparts.mklatency(pipeline, calibstatevector, name = "%s_calibstatevec" % OutputConfigs["frametype"])
calibstatevector.connect("notify::current-latency", handler.latency_new_buffer)
elif InputConfigs["datasource"] == "lvshm":
calibstatevector = pipeparts.mklatency(pipeline, calibstatevector, name = "%s_calibstatevec" % OutputConfigs["frametype"], silent = True)
calibstatevector.connect("notify::current-latency", handler.latency_new_buffer)
dqtagstr = "channel-name=%s:GDS-CALIB_STATE_VECTOR, instrument=%s" % (instrument, instrument)
calibstatevector = pipeparts.mktaginject(pipeline, calibstatevector, dqtagstr)
calibstatevector = pipeparts.mktee(pipeline, calibstatevector)
......@@ -3042,19 +3068,19 @@ if compute_kappapum:
kpumIout = calibration_parts.mkresample(pipeline, kpumIout, 1, False, record_kappa_caps)
kpumIout = pipeparts.mkprogressreport(pipeline, kpumIout, "progress_kappa_pum_imag_%s" % instrument)
if test_latency:
kpumIout = pipeparts.mklatency(pipeline, kpumIout, name = "%s_kappa_pum_imag" % OutputConfigs["frametype"])
kpumIout = pipeparts.mklatency(pipeline, kpumIout, name = "%s_kappa_pum_imag" % (OutputConfigs["frametype"]))
smooth_kpumR_nogate = pipeparts.mkgeneric(pipeline, smooth_kpumR_nogate, "lal_typecast")
smooth_kpumR_nogate = calibration_parts.mkresample(pipeline, smooth_kpumR_nogate, 1, False, record_kappa_caps)
smooth_kpumR_nogate = pipeparts.mkprogressreport(pipeline, smooth_kpumR_nogate, "progress_kappa_pum_real_nogate_%s" % instrument)
if test_latency:
smooth_kpumR_nogate = pipeparts.mklatency(pipeline, smooth_kpumR_nogate, name = "%s_kappa_pum_real_nogate" % OutputConfigs["frametype"])
smooth_kpumR_nogate = pipeparts.mklatency(pipeline, smooth_kpumR_nogate, name = "%s_kappa_pum_real_nogate" % (OutputConfigs["frametype"]))
smooth_kpumI_nogate = pipeparts.mkgeneric(pipeline, smooth_kpumI_nogate, "lal_typecast")
smooth_kpumI_nogate = calibration_parts.mkresample(pipeline, smooth_kpumI_nogate, 1, False, record_kappa_caps)
smooth_kpumI_nogate = pipeparts.mkprogressreport(pipeline, smooth_kpumI_nogate, "progress_kappa_pum_imag_nogate_%s" % instrument)
if test_latency:
smooth_kpumI_nogate = pipeparts.mklatency(pipeline, smooth_kpumI_nogate, name = "%s_kappa_pum_imag_nogate" % OutputConfigs["frametype"])
smooth_kpumI_nogate = pipeparts.mklatency(pipeline, smooth_kpumI_nogate, name = "%s_kappa_pum_imag_nogate" % (OutputConfigs["frametype"]))
# Resample the \kappa_uim channels at the specified recording sample rate and change them to single precision channels
if compute_kappauim:
......@@ -3063,25 +3089,25 @@ if compute_kappauim:
kuimRout = calibration_parts.mkresample(pipeline, kuimRout, 1, False, record_kappa_caps)
kuimRout = pipeparts.mkprogressreport(pipeline, kuimRout, "progress_kappa_uim_real_%s" % instrument)
if test_latency:
kuimRout = pipeparts.mklatency(pipeline, kuimRout, name = "%s_kappa_uim_real" % OutputConfigs["frametype"])
kuimRout = pipeparts.mklatency(pipeline, kuimRout, name = "%s_kappa_uim_real" % (OutputConfigs["frametype"]))
kuimIout = pipeparts.mkgeneric(pipeline, smooth_kuimItee, "lal_typecast")
kuimIout = calibration_parts.mkresample(pipeline, kuimIout, 1, False, record_kappa_caps)
kuimIout = pipeparts.mkprogressreport(pipeline, kuimIout, "progress_kappa_uim_imag_%s" % instrument)
if test_latency:
kuimIout = pipeparts.mklatency(pipeline, kuimIout, name = "%s_kappa_uim_imag" % OutputConfigs["frametype"])
kuimIout = pipeparts.mklatency(pipeline, kuimIout, name = "%s_kappa_uim_imag" % (OutputConfigs["frametype"]))
smooth_kuimR_nogate = pipeparts.mkgeneric(pipeline, smooth_kuimR_nogate, "lal_typecast")
smooth_kuimR_nogate = calibration_parts.mkresample(pipeline, smooth_kuimR_nogate, 1, False, record_kappa_caps)
smooth_kuimR_nogate = pipeparts.mkprogressreport(pipeline, smooth_kuimR_nogate, "progress_kappa_uim_real_nogate_%s" % instrument)
if test_latency:
smooth_kuimR_nogate = pipeparts.mklatency(pipeline, smooth_kuimR_nogate, name = "%s_kappa_uim_real_nogate" % OutputConfigs["frametype"])
smooth_kuimR_nogate = pipeparts.mklatency(pipeline, smooth_kuimR_nogate, name = "%s_kappa_uim_real_nogate" % (OutputConfigs["frametype"]))
smooth_kuimI_nogate = pipeparts.mkgeneric(pipeline, smooth_kuimI_nogate, "lal_typecast")
smooth_kuimI_nogate = calibration_parts.mkresample(pipeline, smooth_kuimI_nogate, 1, False, record_kappa_caps)
smooth_kuimI_nogate = pipeparts.mkprogressreport(pipeline, smooth_kuimI_nogate, "progress_kappa_uim_imag_nogate_%s" % instrument)
if test_latency:
smooth_kuimI_nogate = pipeparts.mklatency(pipeline, smooth_kuimI_nogate, name = "%s_kappa_uim_imag_nogate" % OutputConfigs["frametype"])
smooth_kuimI_nogate = pipeparts.mklatency(pipeline, smooth_kuimI_nogate, name = "%s_kappa_uim_imag_nogate" % (OutputConfigs["frametype"]))
# Resample the \kappa_pu channels at the specified recording sample rate and change them to single precision channels
if compute_kappapu:
......@@ -3090,25 +3116,25 @@ if compute_kappapu:
kpuRout = calibration_parts.mkresample(pipeline, kpuRout, 1, False, record_kappa_caps)
kpuRout = pipeparts.mkprogressreport(pipeline, kpuRout, "progress_kappa_pu_real_%s" % instrument)
if test_latency:
kpuRout = pipeparts.mklatency(pipeline, kpuRout, name = "%s_kappa_pu_real" % OutputConfigs["frametype"])
kpuRout = pipeparts.mklatency(pipeline, kpuRout, name = "%s_kappa_pu_real" % (OutputConfigs["frametype"]))
kpuIout = pipeparts.mkgeneric(pipeline, smooth_kpuItee, "lal_typecast")
kpuIout = calibration_parts.mkresample(pipeline, kpuIout, 1, False, record_kappa_caps)
kpuIout = pipeparts.mkprogressreport(pipeline, kpuIout, "progress_kappa_pu_imag_%s" % instrument)
if test_latency:
kpuIout = pipeparts.mklatency(pipeline, kpuIout, name = "%s_kappa_pu_imag" % OutputConfigs["frametype"])
kpuIout = pipeparts.mklatency(pipeline, kpuIout, name = "%s_kappa_pu_imag" % (OutputConfigs["frametype"]))
smooth_kpuR_nogate = pipeparts.mkgeneric(pipeline, smooth_kpuR_nogate, "lal_typecast")
smooth_kpuR_nogate = calibration_parts.mkresample(pipeline, smooth_kpuR_nogate, 1, False, record_kappa_caps)
smooth_kpuR_nogate = pipeparts.mkprogressreport(pipeline, smooth_kpuR_nogate, "progress_kappa_pu_real_nogate_%s" % instrument)
if test_latency:
smooth_kpuR_nogate = pipeparts.mklatency(pipeline, smooth_kpuR_nogate, name = "%s_kappa_pu_real_nogate" % OutputConfigs["frametype"])
smooth_kpuR_nogate = pipeparts.mklatency(pipeline, smooth_kpuR_nogate, name = "%s_kappa_pu_real_nogate" % (OutputConfigs["frametype"]))
smooth_kpuI_nogate = pipeparts.mkgeneric(pipeline, smooth_kpuI_nogate, "lal_typecast")
smooth_kpuI_nogate = calibration_parts.mkresample(pipeline, smooth_kpuI_nogate, 1, False, record_kappa_caps)
smooth_kpuI_nogate = pipeparts.mkprogressreport(pipeline, smooth_kpuI_nogate, "progress_kappa_pu_imag_nogate_%s" % instrument)
if test_latency:
smooth_kpuI_nogate = pipeparts.mklatency(pipeline, smooth_kpuI_nogate, name = "%s_kappa_pu_imag_nogate" % OutputConfigs["frametype"])
smooth_kpuI_nogate = pipeparts.mklatency(pipeline, smooth_kpuI_nogate, name = "%s_kappa_pu_imag_nogate" % (OutputConfigs["frametype"]))
# Resample the \kappa_c channels at the specified recording sample rate and change it to a single precision channel
if compute_kappac:
......@@ -3116,13 +3142,13 @@ if compute_kappac:
kcout = calibration_parts.mkresample(pipeline, kcout, 1, False, record_kappa_caps)
kcout = pipeparts.mkprogressreport(pipeline, kcout, "progress_kappa_c_%s" % instrument)
if test_latency:
kcout = pipeparts.mklatency(pipeline, kcout, name = "%s_kappa_c_imag" % OutputConfigs["frametype"])
kcout = pipeparts.mklatency(pipeline, kcout, name = "%s_kappa_c_imag" % (OutputConfigs["frametype"]))
smooth_kc_nogate = pipeparts.mkgeneric(pipeline, smooth_kc_nogate, "lal_typecast")
smooth_kc_nogate = calibration_parts.mkresample(pipeline, smooth_kc_nogate, 1, False, record_kappa_caps)
smooth_kc_nogate = pipeparts.mkprogressreport(pipeline, smooth_kc_nogate, "progress_kappa_c_nogate_%s" % instrument)
if test_latency:
smooth_kc_nogate = pipeparts.mklatency(pipeline, smooth_kc_nogate, name = "%s_kappa_c_nogate" % OutputConfigs["frametype"])
smooth_kc_nogate = pipeparts.mklatency(pipeline, smooth_kc_nogate, name = "%s_kappa_c_nogate" % (OutputConfigs["frametype"]))
# Resample the f_cc channels at the specified recording sample rate and change it to a single precision channel
if compute_fcc:
......@@ -3130,13 +3156,13 @@ if compute_fcc:
fccout = calibration_parts.mkresample(pipeline, fccout, 1, False, record_kappa_caps)
fccout = pipeparts.mkprogressreport(pipeline, fccout, "progress_f_cc_%s" % instrument)
if test_latency:
fccout = pipeparts.mklatency(pipeline, fccout, name = "%s_f_cc_imag" % OutputConfigs["frametype"])
fccout = pipeparts.mklatency(pipeline, fccout, name = "%s_f_cc_imag" % (OutputConfigs["frametype"]))
smooth_fcc_nogate = pipeparts.mkgeneric(pipeline, smooth_fcc_nogate, "lal_typecast")
smooth_fcc_nogate = calibration_parts.mkresample(pipeline, smooth_fcc_nogate, 1, False, record_kappa_caps)
smooth_fcc_nogate = pipeparts.mkprogressreport(pipeline, smooth_fcc_nogate, "progress_f_cc_nogate_%s" % instrument)
if test_latency:
smooth_fcc_nogate = pipeparts.mklatency(pipeline, smooth_fcc_nogate, name = "%s_f_cc_nogate" % OutputConfigs["frametype"])
smooth_fcc_nogate = pipeparts.mklatency(pipeline, smooth_fcc_nogate, name = "%s_f_cc_nogate" % (OutputConfigs["frametype"]))
# Resample the f_s channels at the specified recording sample rate and change it to a single precision channel
if compute_fs:
......@@ -3144,13 +3170,13 @@ if compute_fs:
fs_squared_out = calibration_parts.mkresample(pipeline, fs_squared_out, 1, False, record_kappa_caps)
fs_squared_out = pipeparts.mkprogressreport(pipeline, fs_squared_out, "progress_f_s_squared_%s" % instrument)
if test_latency:
fs_squared_out = pipeparts.mklatency(pipeline, fs_squared_out, name = "%s_f_s_squared" % OutputConfigs["frametype"])
fs_squared_out = pipeparts.mklatency(pipeline, fs_squared_out, name = "%s_f_s_squared" % (OutputConfigs["frametype"]))
smooth_fs_squared_nogate = pipeparts.mkgeneric(pipeline, smooth_fs_squared_nogate, "lal_typecast")
smooth_fs_squared_nogate = calibration_parts.mkresample(pipeline, smooth_fs_squared_nogate, 1, False, record_kappa_caps)
smooth_fs_squared_nogate = pipeparts.mkprogressreport(pipeline, smooth_fs_squared_nogate, "progress_f_s_squared_nogate_%s" % instrument)
if test_latency:
smooth_fs_squared_nogate = pipeparts.mklatency(pipeline, smooth_fs_squared_nogate, name = "%s_f_s_squared_nogate" % OutputConfigs["frametype"])
smooth_fs_squared_nogate = pipeparts.mklatency(pipeline, smooth_fs_squared_nogate, name = "%s_f_s_squared_nogate" % (OutputConfigs["frametype"]))
# Resample the SRC Q channels at the specified recording sample rate and change it to a single precision channel
if compute_srcq:
......@@ -3158,13 +3184,13 @@ if compute_srcq:
srcQ_inv_out = calibration_parts.mkresample(pipeline, srcQ_inv_out, 1, False, record_kappa_caps)
srcQ_inv_out = pipeparts.mkprogressreport(pipeline, srcQ_inv_out, "progress_SRC_Q_%s" % instrument)
if test_latency:
srcQ_inv_out = pipeparts.mklatency(pipeline, srcQ_inv_out, name = "%s_SRC_Q" % OutputConfigs["frametype"])
srcQ_inv_out = pipeparts.mklatency(pipeline, srcQ_inv_out, name = "%s_SRC_Q" % (OutputConfigs["frametype"]))
smooth_srcQ_inv_nogate = pipeparts.mkgeneric(pipeline, smooth_srcQ_inv_nogate, "lal_typecast")
smooth_srcQ_inv_nogate = calibration_parts.mkresample(pipeline, smooth_srcQ_inv_nogate, 1, False, record_kappa_caps)
smooth_srcQ_inv_nogate = pipeparts.mkprogressreport(pipeline, smooth_srcQ_inv_nogate, "progress_SRC_Q_nogate_%s" % instrument)
if test_latency:
smooth_srcQ_inv_nogate = pipeparts.mklatency(pipeline, smooth_srcQ_inv_nogate, name = "%s_SRC_Q_nogate" % OutputConfigs["frametype"])
smooth_srcQ_inv_nogate = pipeparts.mklatency(pipeline, smooth_srcQ_inv_nogate, name = "%s_SRC_Q_nogate" % (OutputConfigs["frametype"]))
#
# CREATE MUXER AND HOOK EVERYTHING UP TO IT
......@@ -3267,6 +3293,10 @@ mux = pipeparts.mkprogressreport(pipeline, mux, "progress_sink_%s" % instrument)
if test_latency:
mux = pipeparts.mklatency(pipeline, mux, name = "%s_sink" % OutputConfigs["frametype"])
mux.connect("notify::current-latency", handler.latency_new_buffer)
elif InputConfigs["datasource"] == "lvshm":
mux = pipeparts.mklatency(pipeline, mux, name = "%s_sink" % OutputConfigs["frametype"], silent = True)
mux.connect("notify::current-latency", handler.latency_new_buffer)
if OutputConfigs["datasink"] == "lvshm":
pipeparts.mkgeneric(pipeline, mux, "gds_lvshmsink", sync=False, async=False, shm_name = OutputConfigs["outputshmpartition"], num_buffers = int(OutputConfigs["numbuffers"]), blocksize = int(OutputConfigs["framesize"])*options.frame_duration*options.frames_per_file, buffer_mode = int(OutputConfigs["buffermode"]))
......
......@@ -35,6 +35,7 @@ Gst.init(None)
from gstlal import simplehandler
from lal import LIGOTimeGPS
from kafka import errors
#
# =============================================================================
......@@ -73,11 +74,14 @@ class Handler(simplehandler.Handler):
self.kafka_server = kafka_server
if self.kafka_server is not None:
from kafka import KafkaProducer
try:
self.producer = KafkaProducer(
bootstrap_servers = [kafka_server],
key_serializer = lambda m: json.dumps(m).encode('utf-8'),
value_serializer = lambda m: json.dumps(m).encode('utf-8'),
)
except errors.NoBrokersAvaialble:
self.producer = None
def appsink_statevector_new_buffer(self, elem, ifo, bitmaskdict):
with self.lock:
......@@ -91,9 +95,19 @@ class Handler(simplehandler.Handler):
state = int(state)
buf.unmap(mapinfo)
monitor_dict = {}
monitor_dict['time'] = float(buf_timestamp)
for key, bitmask in bitmaskdict.items():
monitor_dict[key] = state & bitmask
if self.kafka_server is not None:
if self.kafka_server is not None and self.producer is not None:
self.producer.send("%s_statevector_bit_check" % ifo, value = monitor_dict)
return Gst.FlowReturn.OK
def latency_new_buffer(self, elem, param):
with self.lock:
latency = elem.get_property("current-latency")
name = elem.get_property("name")
time = elem.get_property("timestamp")
if self.kafka_server is not None and self.producer is not None:
self.producer.send("%s_latency" % (name.split("_")[0]), value = {"time": time, name: latency})
return Gst.FlowReturn.OK
......@@ -108,6 +108,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE(
enum property {
ARG_SILENT = 1,
ARG_CURRENT_LATENCY,
ARG_TIMESTAMP,
ARG_FAKE
};
......@@ -153,6 +154,7 @@ static GstFlowReturn transform_ip(GstBaseTransform *trans, GstBuffer *buf)
gdouble buffer_time = (double) GST_TIME_AS_SECONDS(GST_BUFFER_PTS(buf));
element->current_latency = current_time - buffer_time;
element->timestamp = buffer_time;
/* Tell the world about the latency by updating the latency property */
GST_LOG_OBJECT(element, "Just computed new latency");
......@@ -206,6 +208,10 @@ static void set_property(GObject *object, enum property prop_id, const GValue *v
element->current_latency = g_value_get_double(value);
break;
case ARG_TIMESTAMP:
element->timestamp = g_value_get_double(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
......@@ -236,6 +242,10 @@ static void get_property(GObject *object, enum property prop_id, GValue *value,
g_value_set_double(value, element->current_latency);
break;
case ARG_TIMESTAMP:
g_value_set_double(value, element->timestamp);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
......@@ -282,6 +292,14 @@ static void gstlal_latency_class_init(GSTLALLatencyClass *klass)
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS
);
properties[ARG_TIMESTAMP] = g_param_spec_double(
"timestamp",
"Timestamp",
"The current buffer timestamp",
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS
);
g_object_class_install_property(
gobject_class,
ARG_SILENT,
......@@ -292,6 +310,11 @@ static void gstlal_latency_class_init(GSTLALLatencyClass *klass)
ARG_CURRENT_LATENCY,
properties[ARG_CURRENT_LATENCY]
);
g_object_class_install_property(
gobject_class,
ARG_TIMESTAMP,
properties[ARG_TIMESTAMP]
);
gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&src_factory));
gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sink_factory));
......
......@@ -79,6 +79,7 @@ struct _GSTLALLatency {
/* properties */
gboolean silent;
gdouble current_latency;
gdouble timestamp;
};
......
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