Skip to content
Snippets Groups Projects
Commit 74c074d1 authored by Denis Oliveira Damazio's avatar Denis Oliveira Damazio Committed by Edward Moyse
Browse files

Noise burst work

parent 3c88ff38
No related branches found
No related tags found
No related merge requests found
Showing
with 432 additions and 3 deletions
...@@ -10,7 +10,7 @@ find_package( tdaq-common COMPONENTS hltinterface ) ...@@ -10,7 +10,7 @@ find_package( tdaq-common COMPONENTS hltinterface )
atlas_add_component( TrigCaloHypo atlas_add_component( TrigCaloHypo
src/*.cxx src/components/*.cxx src/*.cxx src/components/*.cxx
INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS} INCLUDE_DIRS ${TDAQ-COMMON_INCLUDE_DIRS}
LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} CaloInterfaceLib GaudiKernel LArRecConditions LArRecEvent StoreGateLib TrigCaloEvent TrigInterfacesLib TrigSteeringEvent TrigTimeAlgsLib xAODCaloEvent xAODEventInfo ) LINK_LIBRARIES ${TDAQ-COMMON_LIBRARIES} AthViews CaloInterfaceLib DecisionHandlingLib GaudiKernel LArRecConditions LArRecEvent StoreGateLib TrigCaloEvent TrigInterfacesLib TrigSteeringEvent TrigTimeAlgsLib xAODCaloEvent xAODEventInfo )
# Install files from the package: # Install files from the package:
atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} --extend-extensions=ATL900,ATL901 ) atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} --extend-extensions=ATL900,ATL901 )
/*
Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
*/
#ifndef TRIGCALOHYPO_ITRIGLARNOISEBURSTHYPOTOOL_H
#define TRIGCALOHYPO_ITRIGLARNOISEBURSTHYPOTOOL_H 1
#include "GaudiKernel/IAlgTool.h"
#include "AthenaBaseComps/AthAlgTool.h"
#include "DecisionHandling/HLTIdentifier.h"
#include "DecisionHandling/TrigCompositeUtils.h"
#include "CaloEvent/CaloCellContainer.h"
#include "TrigSteeringEvent/TrigRoiDescriptorCollection.h"
#include "Identifier/HWIdentifier.h"
/**
* @class Base for tools dooing LArNoiseBurst Hypo selection
* @brief
**/
class ITrigLArNoiseBurstHypoTool
: virtual public ::IAlgTool
{
public:
DeclareInterfaceID(ITrigLArNoiseBurstHypoTool, 1, 0);
virtual ~ITrigLArNoiseBurstHypoTool(){}
struct CaloCellNoiseInfo {
CaloCellNoiseInfo( TrigCompositeUtils::Decision* d,
const TrigRoiDescriptor* r,
const CaloCellContainer* c,
const std::set<unsigned int>* bf,
const std::vector<HWIdentifier>* MNBfeb,
const TrigCompositeUtils::Decision* previousDecision )
: decision( d ),
roi( r ),
cells(c),
knownBadFEBs(bf), knownMNBFEBs(MNBfeb),
previousDecisionIDs( TrigCompositeUtils::decisionIDs( previousDecision ).begin(),
TrigCompositeUtils::decisionIDs( previousDecision ).end() )
{}
TrigCompositeUtils::Decision* decision;
const TrigRoiDescriptor* roi;
const CaloCellContainer* cells;
const std::set<unsigned int>* knownBadFEBs;
const std::vector<HWIdentifier>* knownMNBFEBs;
const TrigCompositeUtils::DecisionIDContainer previousDecisionIDs;
};
/**
* @brief decides upon all clusters
* Note it is for a reason a non-virtual method, it is an interface in gaudi sense and implementation.
* There will be many tools called often to perform this quick operation and we do not want to pay for polymorphism which we do not need to use.
* Will actually see when N obj hypos will enter the scene
**/
virtual StatusCode decide( std::vector<CaloCellNoiseInfo>& input ) const = 0;
/**
* @brief Makes a decision for a single object
* The decision needs to be returned
**/
virtual bool decide( const CaloCellNoiseInfo& i ) const = 0;
protected:
};
#endif //> !TRIGCALOHYPO_ITRIGLARNOISEBURSTHYPOTOOL_H
...@@ -58,3 +58,28 @@ class L2JetHypo (L2JetHypoBase): ...@@ -58,3 +58,28 @@ class L2JetHypo (L2JetHypoBase):
self.doTimeQualityCleaning = False self.doTimeQualityCleaning = False
self.doEMfCleaningHighEta = False self.doEMfCleaningHighEta = False
self.doEMfCleaningLowEta = False self.doEMfCleaningLowEta = False
from AthenaConfiguration.ComponentFactory import CompFactory
class TrigLArNoiseBurstHypoToolIncCfg ( CompFactory.TrigLArNoiseBurstHypoToolInc ):
def __init__(self,name="TrigLArNoiseBurstHypoToolIncCfg", **kwargs):
super(TrigLArNoiseBurstHypoToolIncCfg,self).__init__(name,**kwargs)
from LArBadChannelTool.LArBadChannelToolConf import LArBadFebCondAlg
from AthenaCommon.AlgSequence import AthSequencer
condSeq = AthSequencer("AthCondSeq")
if ( not hasattr(condSeq,"LArKnownBadFebAlg") ):
conddb.addFolder('LAR_ONL',"/LAR/BadChannels/KnownBADFEBs", className="AthenaAttributeList")
condSeq+=LArBadFebCondAlg("LArKnownBadFebAlg",ReadKey="/LAR/BadChannels/KnownBADFEBs",WriteKey="LArKnownBadFEBs")
if ( not hasattr(condSeq,"LArKnownMNBFebAlg") ):
conddb.addFolder('LAR_ONL',"/LAR/BadChannels/KnownMNBFEBs", className="AthenaAttributeList")
condSeq+=LArBadFebCondAlg("LArKnownMNBFebAlg",ReadKey="/LAR/BadChannels/KnownMNBFEBs",WriteKey="LArKnownMNBFEBs")
theLArNoisyROTool=LArNoisyROTool(SaturatedCellTightCut=20,MNBLooseCut=5,MNBTightCut=17)
self.NoiseTool = theLArNoisyROTool
class TrigLArNoiseBurstAlgCfg ( CompFactory.TrigLArNoiseBurstAlg ):
def __init__(self,name="TrigLArNoiseBurstAlgCfg", **kwargs):
super(TrigLArNoiseBurstAlgCfg,self).__init__(name,**kwargs)
self.HypoTools = [TrigLArNoiseBurstHypoToolIncCfg()]
def TrigLArNoiseBurstHypoToolGen(chainDict):
return TrigLArNoiseBurstHypoToolIncCfg(chainDict['chainName'])
/*
Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
*/
#include "Gaudi/Property.h"
#include "TrigLArNoiseBurstAlg.h"
#include "TrigCompositeUtils/HLTIdentifier.h"
#include "TrigCompositeUtils/TrigCompositeUtils.h"
#include "AthViews/ViewHelper.h"
using namespace TrigCompositeUtils;
TrigLArNoiseBurstAlg::TrigLArNoiseBurstAlg( const std::string& name,
ISvcLocator* pSvcLocator ) :
::HypoBase( name, pSvcLocator ) {}
StatusCode TrigLArNoiseBurstAlg::initialize() {
ATH_CHECK( m_cellContainerKey.initialize() );
ATH_CHECK( m_knownBadFEBsVecKey.initialize() );
ATH_CHECK( m_knownMNBFEBsVecKey.initialize() );
ATH_CHECK( m_hypoTools.retrieve() );
return StatusCode::SUCCESS;
}
StatusCode TrigLArNoiseBurstAlg::execute( const EventContext& context ) const {
ATH_MSG_DEBUG ( "Executing " << name() << "..." );
auto previousDecisionsHandle = SG::makeHandle( decisionInput(), context );
ATH_CHECK( previousDecisionsHandle.isValid() );
ATH_MSG_DEBUG( "Running with "<< previousDecisionsHandle->size() <<" previous decisions");
// new output decisions
SG::WriteHandle<DecisionContainer> outputHandle = createAndStore(decisionOutput(), context );
auto decisions = outputHandle.ptr();
// input for decision
std::vector<ITrigLArNoiseBurstHypoTool::CaloCellNoiseInfo> toolInput;
ATH_CHECK( previousDecisionsHandle->size() == 1 );
const auto previousDecision = previousDecisionsHandle->at(0);
//get RoI
auto roiELInfo = findLink<TrigRoiDescriptorCollection>( previousDecision, initialRoIString() );
ATH_CHECK( roiELInfo.isValid() );
const TrigRoiDescriptor* roi = *(roiELInfo.link);
// get cells
SG::ReadHandle<CaloCellContainer> cellsHandle(m_cellContainerKey, context);
ATH_CHECK( cellsHandle.isValid() );
ATH_MSG_DEBUG ( "Cluster handle size: " << cellsHandle->size() << "..." );
// necessary conditions
std::set<unsigned int> bf;
std::vector<HWIdentifier> MNBfeb;
SG::ReadCondHandle<LArBadFebCont> badHdl(m_knownBadFEBsVecKey, context);
const LArBadFebCont* badCont=*badHdl;
if(badCont) {
for(LArBadFebCont::BadChanVec::const_iterator i = badCont->begin(); i!=badCont->end(); i++) {
bf.insert(i->first);
}
}
SG::ReadCondHandle<LArBadFebCont> MNBHdl(m_knownMNBFEBsVecKey, context);
const LArBadFebCont* MNBCont=*MNBHdl;
if(MNBCont) {
for(LArBadFebCont::BadChanVec::const_iterator i = MNBCont->begin(); i!=MNBCont->end(); i++) {
MNBfeb.push_back(HWIdentifier(i->first));
}
}
// Get new output decision, child of previousDecision
auto d = newDecisionIn (decisions, previousDecision, "", context );
// create summary struct
toolInput.emplace_back( d, roi, cellsHandle.cptr(), &bf, &MNBfeb, previousDecision );
// link the cluster
{
auto cell = ElementLink<CaloCellContainer>( *cellsHandle, 0 );
ATH_CHECK( cell.isValid() );
d->setObjectLink( featureString(), cell );
}
ATH_MSG_DEBUG( "Found "<<toolInput.size()<<" inputs to tools");
for ( auto& tool: m_hypoTools ) {
ATH_CHECK( tool->decide( toolInput ) );
}
ATH_CHECK( hypoBaseOutputProcessing(outputHandle) );
return StatusCode::SUCCESS;
}
/*
Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
*/
#ifndef TRIGCALOHYPO_TRIGLARNOISEBURSTALG
#define TRIGCALOHYPO_TRIGLARNOISEBURSTALG
#include <string>
#include "AthenaBaseComps/AthReentrantAlgorithm.h"
#include "AthViews/View.h"
#include "TrigSteeringEvent/TrigRoiDescriptorCollection.h"
#include "DecisionHandling/HypoBase.h"
#include "LArRecConditions/LArBadChannelCont.h"
#include "StoreGate/ReadHandleKey.h"
#include "TrigCaloHypo/ITrigLArNoiseBurstHypoTool.h"
/**
* @class TrigLArNoiseBurstAlg
* @brief Implements LArNoiseBurst detection for the new HLT framework
**/
class TrigLArNoiseBurstAlg : public ::HypoBase {
public:
TrigLArNoiseBurstAlg( const std::string& name, ISvcLocator* pSvcLocator );
virtual StatusCode initialize() override;
virtual StatusCode execute( const EventContext& context ) const override;
private:
SG::ReadHandleKey<CaloCellContainer > m_cellContainerKey { this, "CellContainerKey", "CellsClusters","SG Key of cells"};
SG::ReadCondHandleKey<LArBadFebCont> m_knownBadFEBsVecKey {this, "BadFEBsKey", "LArKnownBadFEBs", "key to read the known Bad FEBs"};
SG::ReadCondHandleKey<LArBadFebCont> m_knownMNBFEBsVecKey {this, "MNBFEBsKey", "LArKnownMNBFEBs", "key to read the known MNB FEBs"};
ToolHandleArray< ITrigLArNoiseBurstHypoTool > m_hypoTools { this, "HypoTools", {}, "Hypo tools" };
};
#endif
/*
Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
*/
#include <algorithm>
#include "TrigCompositeUtils/HLTIdentifier.h"
#include "TrigCompositeUtils/Combinators.h"
#include "AthenaMonitoringKernel/Monitored.h"
#include "GaudiKernel/SystemOfUnits.h"
#include "LArRecEvent/LArNoisyROSummary.h"
#include "TrigLArNoiseBurstHypoToolInc.h"
using namespace TrigCompositeUtils;
TrigLArNoiseBurstHypoToolInc::TrigLArNoiseBurstHypoToolInc( const std::string& type,
const std::string& name,
const IInterface* parent )
: base_class( type, name, parent ),
m_noisyROTool("LArNoisyROTool",this),
m_decisionId( HLT::Identifier::fromToolName( name ) )
{
declareProperty( "Tool",m_noisyROTool);
}
StatusCode TrigLArNoiseBurstHypoToolInc::initialize() {
// prepare mask
m_mask = 0x0;
if ( m_badFEBFlaggedPartitions ) m_mask|=0x1;
if ( m_satTightFlaggedPartitions ) m_mask|=0x2;
if ( m_mNBLooseFlaggedPartitions ) m_mask|=0x10;
if ( m_mNBTightFlaggedPartitions ) m_mask|=0x20;
if ( m_mNBTight_PsVetoFlaggedPartitions ) m_mask|=0x40;
ATH_CHECK(m_noisyROTool.retrieve());
ATH_MSG_INFO("TrigLArNoiseBurstHypoTool initialization completed successfully.");
/*
if ( not m_monTool.name().empty() )
CHECK( m_monTool.retrieve() );
*/
return StatusCode::SUCCESS;
}
TrigLArNoiseBurstHypoToolInc::~TrigLArNoiseBurstHypoToolInc(){}
StatusCode TrigLArNoiseBurstHypoToolInc::decide( std::vector<CaloCellNoiseInfo>& input ) const {
for ( auto& i: input ) {
if ( passed ( m_decisionId.numeric(), i.previousDecisionIDs ) ) {
if ( decide( i ) ) {
addDecisionID( m_decisionId, i.decision );
}
}
}
return StatusCode::SUCCESS;
}
bool TrigLArNoiseBurstHypoToolInc::decide( const ITrigLArNoiseBurstHypoTool::CaloCellNoiseInfo& input ) const {
// no cells, no discussion
if ( !input.cells ) return false;
unsigned int flag = 0;
bool pass=false;
ATH_MSG_DEBUG ("Got cell container, will process it");
std::unique_ptr<LArNoisyROSummary> noisyRO = m_noisyROTool->process(input.cells, input.knownBadFEBs, input.knownMNBFEBs);
ATH_MSG_DEBUG("processed it");
if ( noisyRO->BadFEBFlaggedPartitions() ) {
ATH_MSG_DEBUG("Passed : BadFEBFlaggedPartitions");
flag |= 0x1;
}
if ( noisyRO->BadFEB_WFlaggedPartitions() ) {
ATH_MSG_DEBUG("Passed : BadFEB_WFlaggedPartitions");
flag |= 0x8;
}
if ( noisyRO->SatTightFlaggedPartitions() ) {
ATH_MSG_DEBUG("Passed : SatTightFlaggedPartitions");
flag |= 0x2;
}
if ( noisyRO->MNBLooseFlaggedPartitions() ) {
ATH_MSG_DEBUG("Passed : MNBLooseFlaggedPartions");
flag |= 0x10;
}
if ( noisyRO->MNBTightFlaggedPartitions() ) {
ATH_MSG_DEBUG("Passed : MNBTightFlaggedPartions");
flag |= 0x20;
}
ATH_MSG_DEBUG("got the flag : " << (unsigned int)flag);
if ( (flag & m_mask) != 0x0 ) {
ATH_MSG_DEBUG("LAr Noise detected : ");
pass = true;
}
else ATH_MSG_DEBUG("LAr Noise not detected!");
return pass;
}
/*
Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
*/
#ifndef TRIGCALOHYPO_TRIGLARNOISEBURSTALGOHYPOTOOLINC_H
#define TRIGCALOHYPO_TRIGLARNOISEBURSTALGOHYPOTOOLINC_H 1
//#include "GaudiKernel/IAlgTool.h"
#include "CLHEP/Units/SystemOfUnits.h"
#include "CaloEvent/CaloCellContainer.h"
#include "TrigSteeringEvent/TrigRoiDescriptor.h"
#include "AthenaBaseComps/AthAlgTool.h"
#include "AthenaMonitoringKernel/GenericMonitoringTool.h"
#include "TrigCompositeUtils/HLTIdentifier.h"
#include "TrigCompositeUtils/TrigCompositeUtils.h"
#include "TrigCaloHypo/ITrigLArNoiseBurstHypoTool.h"
#include "CaloInterface/ILArNoisyROTool.h"
/**
* @class Implementation of the CaloCell Noise Burst selection
* @brief
**/
class TrigLArNoiseBurstHypoToolInc : public extends<AthAlgTool, ITrigLArNoiseBurstHypoTool> {
public:
TrigLArNoiseBurstHypoToolInc( const std::string& type,
const std::string& name,
const IInterface* parent );
virtual ~TrigLArNoiseBurstHypoToolInc();
virtual StatusCode initialize() override;
virtual StatusCode decide( std::vector<ITrigLArNoiseBurstHypoTool::CaloCellNoiseInfo>& input ) const override;
virtual bool decide( const ITrigLArNoiseBurstHypoTool::CaloCellNoiseInfo& i ) const override;
private:
ToolHandle<ILArNoisyROTool> m_noisyROTool;
HLT::Identifier m_decisionId;
Gaudi::Property< bool > m_badFEBFlaggedPartitions { this, "BadFEBFlaggedPartitions" , true, "flag to be used for NB detection" };
Gaudi::Property< bool > m_satTightFlaggedPartitions { this, "SatTightFlaggedPartitions", true, "flag to be used for NB detection" };
Gaudi::Property< bool > m_mNBLooseFlaggedPartitions { this, "MNBLooseFlaggedPartitions", true, "flag to be used for NB detection" };
Gaudi::Property< bool > m_mNBTightFlaggedPartitions { this, "MNBTightFlaggedPartitions", true, "flag to be used for NB detection" };
Gaudi::Property< bool > m_mNBTight_PsVetoFlaggedPartitions{ this, "MNBTight_PsVetoFlaggedPartitions", true, "flag to be used for NB detection" };
//ToolHandle< GenericMonitoringTool > m_monTool { this, "MonTool", "", "Monitoring tool" };
unsigned int m_mask;
};
#endif //> !TRIGCALOHYPO_TRIGLARNOISEBURSTHYPOTOOLINC_H
#include "../TrigEFCaloHypoNoise.h" #include "../TrigEFCaloHypoNoise.h"
#include "../TrigL2JetHypo.h" #include "../TrigL2JetHypo.h"
#include "../TrigLArNoiseBurstHypoToolInc.h"
#include "../TrigLArNoiseBurstAlg.h"
DECLARE_COMPONENT( TrigEFCaloHypoNoise ) DECLARE_COMPONENT( TrigEFCaloHypoNoise )
DECLARE_COMPONENT( TrigLArNoiseBurstHypoToolInc )
DECLARE_COMPONENT( TrigLArNoiseBurstAlg )
DECLARE_COMPONENT( TrigL2JetHypo ) DECLARE_COMPONENT( TrigL2JetHypo )
...@@ -19,7 +19,38 @@ class CalibChainConfiguration(ChainConfigurationBase): ...@@ -19,7 +19,38 @@ class CalibChainConfiguration(ChainConfigurationBase):
chainSteps = [] chainSteps = []
log.debug("Assembling chain for " + self.chainName) log.debug("Assembling chain for " + self.chainName)
if self.chainPartName == 'larnoiseburst':
chainSteps.append(self.getLArNoiseBurst())
myChain = self.buildChain(chainSteps) myChain = self.buildChain(chainSteps)
return myChain return myChain
# --------------------
# LArNoiseBurst configuration
# --------------------
def getLArNoiseBurst(self):
from AthenaConfiguration.ComponentFactory import CompFactory
from TriggerMenuMT.HLTMenuConfig.Menu.MenuComponents import MenuSequence, ChainStep, RecoFragmentsPool
hypoAlg = CompFactory.TrigLArNoiseBurstAlg("NoiseBurstAlg")
from TrigCaloHypo.TrigCaloHypoConfig import TrigLArNoiseBurstHypoToolGen
from TrigT2CaloCommon.CaloDef import clusterFSInputMaker
from AthenaConfiguration.ComponentAccumulator import conf2toConfigurable
from TriggerMenuMT.HLTMenuConfig.CommonSequences.CaloSequenceSetup import cellRecoSequence
noiseBurstInputMakerAlg= conf2toConfigurable(clusterFSInputMaker())
from AthenaCommon.CFElements import parOR, seqAND
noiseBurstRecoSeq = parOR( "LArNoiseRecoSeq")
cells_sequence, cells_name = RecoFragmentsPool.retrieve(cellRecoSequence, flags=None, RoIs=noiseBurstInputMakerAlg.RoIs)
noiseBurstRecoSeq += cells_sequence
hypoAlg.CellContainerKey = cells_name
noiseBurstMenuSeq = seqAND("LArNoiseMenuSeq", [noiseBurstInputMakerAlg, noiseBurstRecoSeq])
seq = MenuSequence(
Sequence = noiseBurstMenuSeq,
Maker = noiseBurstInputMakerAlg,
Hypo = hypoAlg,
HypoToolGen = TrigLArNoiseBurstHypoToolGen)
return ChainStep(name='LArNoiseBurst', Sequences=[seq])
...@@ -384,7 +384,8 @@ def setupMenu(): ...@@ -384,7 +384,8 @@ def setupMenu():
# ChainProp(name='HLT_mb_sp600_trk45_hmt_L1RD0_FILLED', l1SeedThresholds=['FSNOSEED'], stream=[PhysicsStream], groups=MinBiasGroup), # ChainProp(name='HLT_mb_sp600_trk45_hmt_L1RD0_FILLED', l1SeedThresholds=['FSNOSEED'], stream=[PhysicsStream], groups=MinBiasGroup),
] ]
TriggerFlags.CalibSlice.signatures = TriggerFlags.CalibSlice.signatures() + [ TriggerFlags.CalibSlice.signatures = TriggerFlags.CalibSlice.signatures() + [
ChainProp(name='HLT_alfacalib_AlfaPEB_L1ALFA_ANY', l1SeedThresholds=['FSNOSEED'], stream=['ALFACalib'], groups=['RATE:ALFACalibration','BW:Detector']) ChainProp(name='HLT_alfacalib_AlfaPEB_L1ALFA_ANY', l1SeedThresholds=['FSNOSEED'], stream=['ALFACalib'], groups=['RATE:ALFACalibration','BW:Detector']),
#ChainProp(name='HLT_larnoiseburst_L1All', l1SeedThresholds=['FSNOSEED'], stream=['DISCARD'], groups=['Online', 'RATE:DISCARD', 'BW:DISCARD'])
] ]
TriggerFlags.CosmicSlice.signatures = TriggerFlags.CosmicSlice.signatures() + [ TriggerFlags.CosmicSlice.signatures = TriggerFlags.CosmicSlice.signatures() + [
] ]
...@@ -399,7 +400,6 @@ def setupMenu(): ...@@ -399,7 +400,6 @@ def setupMenu():
TriggerFlags.MonitorSlice.signatures = TriggerFlags.MonitorSlice.signatures() + [ TriggerFlags.MonitorSlice.signatures = TriggerFlags.MonitorSlice.signatures() + [
ChainProp(name='HLT_cscmon_CSCPEB_L1All', l1SeedThresholds=['FSNOSEED'], stream=['CSC'], groups=['RATE:Monitoring','BW:Other']), ChainProp(name='HLT_cscmon_CSCPEB_L1All', l1SeedThresholds=['FSNOSEED'], stream=['CSC'], groups=['RATE:Monitoring','BW:Other']),
] ]
# Random Seeded EB chains which select at the HLT based on L1 TBP bits # Random Seeded EB chains which select at the HLT based on L1 TBP bits
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment