Skip to content

Commit

Permalink
Merge pull request #278 from vvolkl/fccsw-v0.9
Browse files Browse the repository at this point in the history
v0.9 release branch: Namespace changes and fixes for LCG_92 compatibility
  • Loading branch information
vvolkl authored Jan 23, 2018
2 parents 7520fe6 + 014758e commit 498c583
Show file tree
Hide file tree
Showing 163 changed files with 1,174 additions and 1,544 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ install(FILES ${CMAKE_BINARY_DIR}/fccrun
RENAME run)

gaudi_project(FCCSW HEAD
USE Gaudi v28r2 )
USE Gaudi v29r2 )
4 changes: 1 addition & 3 deletions Detector/DetCommon/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@ find_package(DD4hep COMPONENTS DDG4 DDSegmentation REQUIRED)
find_package(Geant4)
include(${Geant4_USE_FILE})

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${DD4hep_ROOT}/cmake )
include( DD4hep )

find_package(ROOT COMPONENTS MathCore GenVector Geom REQUIRED)

gaudi_install_headers(DetCommon)
gaudi_add_library(DetCommon
src/*.cpp
INCLUDE_DIRS DD4hep ROOT Geant4 DetSegmentation
LINK_LIBRARIES GaudiKernel DD4hep ROOT Geant4 DetSegmentation ${DD4hep_COMPONENT_LIBRARIES}
LINK_LIBRARIES GaudiKernel DD4hep ROOT Geant4 DetSegmentation
PUBLIC_HEADERS DetCommon)

install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/compact DESTINATION Detector/DetCommon)
Expand Down
20 changes: 10 additions & 10 deletions Detector/DetCommon/DetCommon/DetUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#define DETCOMMON_DETUTILS_H

// FCCSW
#include "DetSegmentation/GridPhiEta.h"
#include "DetSegmentation/FCCSWGridPhiEta.h"

// DD4hep
#include "DD4hep/DetFactoryHelper.h"
Expand All @@ -26,11 +26,11 @@
e.g. returns <layer name="2"/> when called with (detector, "layer", "name", "1") */
namespace det {
namespace utils {
DD4hep::XML::Component getNodeByStrAttr(const DD4hep::XML::Handle_t& mother, const std::string& nodeName,
dd4hep::xml::Component getNodeByStrAttr(const dd4hep::xml::Handle_t& mother, const std::string& nodeName,
const std::string& attrName, const std::string& attrValue);

/// try to get attribute with double value, return defaultValue if attribute not found
double getAttrValueWithFallback(const DD4hep::XML::Component& node, const std::string& attrName,
double getAttrValueWithFallback(const dd4hep::xml::Component& node, const std::string& attrName,
const double& defaultValue);

/** Retrieves the cellID based on the position of the step and the detector segmentation.
Expand All @@ -40,7 +40,7 @@ double getAttrValueWithFallback(const DD4hep::XML::Component& node, const std::s
* or the middle of the step.
*/

uint64_t cellID(const DD4hep::Geometry::Segmentation& aSeg, const G4Step& aStep, bool aPreStepPoint = true);
uint64_t cellID(const dd4hep::Segmentation& aSeg, const G4Step& aStep, bool aPreStepPoint = true);

/** Get neighbours in many dimensions.
* @param[in] aDecoder Handle to the bitfield decoder.
Expand All @@ -49,7 +49,7 @@ uint64_t cellID(const DD4hep::Geometry::Segmentation& aSeg, const G4Step& aStep,
* @param[in] aCellId ID of cell.
* return Vector of neighbours.
*/
std::vector<uint64_t> neighbours(DD4hep::DDSegmentation::BitField64& aDecoder,
std::vector<uint64_t> neighbours(dd4hep::DDSegmentation::BitField64& aDecoder,
const std::vector<std::string>& aFieldNames,
const std::vector<std::pair<int, int>>& aFieldExtremes,
uint64_t aCellId);
Expand All @@ -59,7 +59,7 @@ std::vector<uint64_t> neighbours(DD4hep::DDSegmentation::BitField64& aDecoder,
* @param[in] aFieldNames Names of the fields for which extremes are found.
* return Vector of pairs (min,max)
*/
std::vector<std::pair<int, int>> bitfieldExtremes(DD4hep::DDSegmentation::BitField64& aDecoder,
std::vector<std::pair<int, int>> bitfieldExtremes(dd4hep::DDSegmentation::BitField64& aDecoder,
const std::vector<std::string>& aFieldNames);

/** Get the half widths of the box envelope (TGeoBBox).
Expand All @@ -81,7 +81,7 @@ CLHEP::Hep3Vector tubeDimensions(uint64_t aVolumeId);
* @param[in] aSeg Handle to the segmentation of the volume.
* return Array of the number of cells in (X, Y).
*/
std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentation::CartesianGridXY& aSeg);
std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::CartesianGridXY& aSeg);

/** Get the number of cells for the volume and a given Cartesian XYZ segmentation.
* For an example see: Test/TestReconstruction/tests/options/testcellcountingXYZ.py.
Expand All @@ -90,7 +90,7 @@ std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentati
* @param[in] aSeg Handle to the segmentation of the volume.
* return Array of the number of cells in (X, Y, Z).
*/
std::array<uint, 3> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentation::CartesianGridXYZ& aSeg);
std::array<uint, 3> numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::CartesianGridXYZ& aSeg);

/** Get the number of cells for the volume and a given Phi-Eta segmentation.
* It is assumed that the volume has a cylindrical shape (and full azimuthal coverage)
Expand All @@ -101,7 +101,7 @@ std::array<uint, 3> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentati
* @param[in] aSeg Handle to the segmentation of the volume.
* return Array of the number of cells in (phi, eta).
*/
std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentation::GridPhiEta& aSeg);
std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::FCCSWGridPhiEta& aSeg);

/** Get the number of cells for the volume and a given R-phi segmentation.
* It is assumed that the volume has a cylindrical shape - TGeoTube (and full azimuthal coverage)
Expand All @@ -112,7 +112,7 @@ std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentati
* @param[in] aSeg Handle to the segmentation of the volume.
* return Array of the number of cells in (r, phi).
*/
std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentation::PolarGridRPhi& aSeg);
std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::PolarGridRPhi& aSeg);

/** Get the number of the volumes containing a given name.
* For an example see: Test/TestReconstruction/tests/options/testcellcountingXYZ.py.
Expand Down
11 changes: 11 additions & 0 deletions Detector/DetCommon/bin/TGeoExporter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

#include "DD4hep/Detector.h"
#include "TGeoManager.h"

int main(int argc, char *argv[]) {
std::string filename = argv[1];
auto lcdd = &(dd4hep::Detector::getInstance());
lcdd->fromCompact(filename);
gGeoManager->Export((filename + ".root").c_str());

}
42 changes: 21 additions & 21 deletions Detector/DetCommon/src/DetUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@

namespace det {
namespace utils {
DD4hep::XML::Component getNodeByStrAttr(const DD4hep::XML::Handle_t& mother, const std::string& nodeName,
dd4hep::xml::Component getNodeByStrAttr(const dd4hep::xml::Handle_t& mother, const std::string& nodeName,
const std::string& attrName, const std::string& attrValue) {
for (DD4hep::XML::Collection_t xCompColl(mother, nodeName.c_str()); nullptr != xCompColl; ++xCompColl) {
for (dd4hep::xml::Collection_t xCompColl(mother, nodeName.c_str()); nullptr != xCompColl; ++xCompColl) {
if (xCompColl.attr<std::string>(attrName.c_str()) == attrValue) {
return static_cast<DD4hep::XML::Component>(xCompColl);
return static_cast<dd4hep::xml::Component>(xCompColl);
}
}
// in case there was no xml daughter with matching name
return DD4hep::XML::Component(nullptr);
return dd4hep::xml::Component(nullptr);
}

double getAttrValueWithFallback(const DD4hep::XML::Component& node, const std::string& attrName,
double getAttrValueWithFallback(const dd4hep::xml::Component& node, const std::string& attrName,
const double& defaultValue) {
if (node.hasAttr(_Unicode(attrName.c_str()))) {
return node.attr<double>(attrName.c_str());
Expand All @@ -32,9 +32,9 @@ double getAttrValueWithFallback(const DD4hep::XML::Component& node, const std::s
}
}

uint64_t cellID(const DD4hep::Geometry::Segmentation& aSeg, const G4Step& aStep, bool aPreStepPoint) {
DD4hep::Simulation::Geant4VolumeManager volMgr = DD4hep::Simulation::Geant4Mapping::instance().volumeManager();
DD4hep::Geometry::VolumeManager::VolumeID volID = volMgr.volumeID(aStep.GetPreStepPoint()->GetTouchable());
uint64_t cellID(const dd4hep::Segmentation& aSeg, const G4Step& aStep, bool aPreStepPoint) {
dd4hep::sim::Geant4VolumeManager volMgr = dd4hep::sim::Geant4Mapping::instance().volumeManager();
dd4hep::VolumeID volID = volMgr.volumeID(aStep.GetPreStepPoint()->GetTouchable());
if (aSeg.isValid()) {
G4ThreeVector global;
if (aPreStepPoint) {
Expand All @@ -44,15 +44,15 @@ uint64_t cellID(const DD4hep::Geometry::Segmentation& aSeg, const G4Step& aStep,
}
G4ThreeVector local =
aStep.GetPreStepPoint()->GetTouchable()->GetHistory()->GetTopTransform().TransformPoint(global);
DD4hep::Geometry::Position loc(local.x() * MM_2_CM, local.y() * MM_2_CM, local.z() * MM_2_CM);
DD4hep::Geometry::Position glob(global.x() * MM_2_CM, global.y() * MM_2_CM, global.z() * MM_2_CM);
DD4hep::Geometry::VolumeManager::VolumeID cID = aSeg.cellID(loc, glob, volID);
dd4hep::Position loc(local.x() * MM_2_CM, local.y() * MM_2_CM, local.z() * MM_2_CM);
dd4hep::Position glob(global.x() * MM_2_CM, global.y() * MM_2_CM, global.z() * MM_2_CM);
dd4hep::VolumeID cID = aSeg.cellID(loc, glob, volID);
return cID;
}
return volID;
}

std::vector<uint64_t> neighbours(DD4hep::DDSegmentation::BitField64& aDecoder,
std::vector<uint64_t> neighbours(dd4hep::DDSegmentation::BitField64& aDecoder,
const std::vector<std::string>& aFieldNames,
const std::vector<std::pair<int, int>>& aFieldExtremes,
uint64_t aCellId) {
Expand All @@ -74,7 +74,7 @@ std::vector<uint64_t> neighbours(DD4hep::DDSegmentation::BitField64& aDecoder,
return std::move(neighbours);
}

std::vector<std::pair<int, int>> bitfieldExtremes(DD4hep::DDSegmentation::BitField64& aDecoder,
std::vector<std::pair<int, int>> bitfieldExtremes(dd4hep::DDSegmentation::BitField64& aDecoder,
const std::vector<std::string>& aFieldNames) {
std::vector<std::pair<int, int>> extremes;
int width = 0;
Expand All @@ -90,16 +90,16 @@ std::vector<std::pair<int, int>> bitfieldExtremes(DD4hep::DDSegmentation::BitFie
}

CLHEP::Hep3Vector envelopeDimensions(uint64_t aVolumeId) {
DD4hep::Geometry::VolumeManager volMgr = DD4hep::Geometry::LCDD::getInstance().volumeManager();
auto pvol = volMgr.lookupPlacement(aVolumeId);
dd4hep::VolumeManager volMgr = dd4hep::Detector::getInstance().volumeManager();
auto pvol = volMgr.lookupVolumePlacement(aVolumeId);
auto solid = pvol.volume().solid();
// get the envelope of the shape
TGeoBBox* box = (dynamic_cast<TGeoBBox*>(solid.ptr()));
// get half-widths
return CLHEP::Hep3Vector(box->GetDX(), box->GetDY(), box->GetDZ());
}

std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentation::CartesianGridXY& aSeg) {
std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::CartesianGridXY& aSeg) {
// // get half-widths
auto halfSizes = envelopeDimensions(aVolumeId);
// get segmentation cell widths
Expand All @@ -111,7 +111,7 @@ std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentati
return {cellsX, cellsY};
}

std::array<uint, 3> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentation::CartesianGridXYZ& aSeg) {
std::array<uint, 3> numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::CartesianGridXYZ& aSeg) {
// // get half-widths
auto halfSizes = envelopeDimensions(aVolumeId);
// get segmentation cell widths
Expand All @@ -126,8 +126,8 @@ std::array<uint, 3> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentati
}

CLHEP::Hep3Vector tubeDimensions(uint64_t aVolumeId) {
DD4hep::Geometry::VolumeManager volMgr = DD4hep::Geometry::LCDD::getInstance().volumeManager();
auto pvol = volMgr.lookupPlacement(aVolumeId);
dd4hep::VolumeManager volMgr = dd4hep::Detector::getInstance().volumeManager();
auto pvol = volMgr.lookupVolumePlacement(aVolumeId);
auto solid = pvol.volume().solid();
// get the envelope of the shape
TGeoConeSeg* tube = (dynamic_cast<TGeoConeSeg*>(solid.ptr()));
Expand All @@ -138,7 +138,7 @@ CLHEP::Hep3Vector tubeDimensions(uint64_t aVolumeId) {
return CLHEP::Hep3Vector(tube->GetRmin1(), tube->GetRmax1(), tube->GetDZ());
}

std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentation::GridPhiEta& aSeg) {
std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::FCCSWGridPhiEta& aSeg) {
// get half-widths,
auto tubeSizes = tubeDimensions(aVolumeId);
// get segmentation number of bins in phi
Expand All @@ -151,7 +151,7 @@ std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentati
return {phiCellNumber, cellsEta};
}

std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const DD4hep::DDSegmentation::PolarGridRPhi& aSeg) {
std::array<uint, 2> numberOfCells(uint64_t aVolumeId, const dd4hep::DDSegmentation::PolarGridRPhi& aSeg) {
// get half-widths,
auto tubeSizes = tubeDimensions(aVolumeId);
// get segmentation cell width
Expand Down
5 changes: 2 additions & 3 deletions Detector/DetCommon/src/Disc_geo.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#include "DD4hep/DetFactoryHelper.h"

using namespace std;
using namespace DD4hep;
using namespace DD4hep::Geometry;
using namespace dd4hep;

/**
Simple cylinder using Tube to be used to define cylinder composed of 1 single material
@author Clement Helsens
**/
static Ref_t create_element(LCDD& lcdd, xml_h e, SensitiveDetector /*sens*/) {
static Ref_t create_element(Detector& lcdd, xml_h e, SensitiveDetector /*sens*/) {
xml_det_t x_det = e;
string name = x_det.nameStr();
DetElement cylinder(name, x_det.id());
Expand Down
36 changes: 18 additions & 18 deletions Detector/DetCommon/src/LayeredCone_geo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,40 @@ Expected xml structure:
</detector>
@author: Joschka Lingemann
*/
static DD4hep::Geometry::Ref_t createLayeredCone(DD4hep::Geometry::LCDD& lcdd,
DD4hep::XML::Handle_t xmlElement,
DD4hep::Geometry::SensitiveDetector /*sensDet*/) {
DD4hep::XML::DetElement xmlDet = static_cast<DD4hep::XML::DetElement>(xmlElement);
static dd4hep::Ref_t createLayeredCone(dd4hep::Detector& lcdd,
dd4hep::xml::Handle_t xmlElement,
dd4hep::SensitiveDetector /*sensDet*/) {
dd4hep::xml::DetElement xmlDet = static_cast<dd4hep::xml::DetElement>(xmlElement);
std::string name = xmlDet.nameStr();
DD4hep::Geometry::DetElement detElement(name, xmlDet.id());
DD4hep::Geometry::Volume experimentalHall = lcdd.pickMotherVolume(detElement);
dd4hep::DetElement detElement(name, xmlDet.id());
dd4hep::Volume experimentalHall = lcdd.pickMotherVolume(detElement);
xml_comp_t dimensions(xmlDet.dimensions());
DD4hep::Geometry::Cone envelope(
dd4hep::Cone envelope(
dimensions.dz(), dimensions.rmin1(), dimensions.rmax1(), dimensions.rmin2(), dimensions.rmax2());
DD4hep::Geometry::Volume envVolume(name, envelope, lcdd.material(dimensions.materialStr()));
dd4hep::Volume envVolume(name, envelope, lcdd.material(dimensions.materialStr()));
envVolume.setVisAttributes(lcdd.invisible());
// Create layer cylinders with their respective material, etc
auto layers = xmlElement.children(_Unicode(layer));
auto numLayers = xmlElement.numChildren(_Unicode(layer), true);
// Joschka: Although this is awkward, it was the only way to loop through children I could find
DD4hep::XML::Handle_t layer(layers.reset());
dd4hep::xml::Handle_t layer(layers.reset());
for (unsigned layerIdx = 0; layerIdx < numLayers; ++layerIdx) {
DD4hep::XML::DetElement layerDet = static_cast<DD4hep::XML::DetElement>(layer);
DD4hep::Geometry::Cone layerShape(
dd4hep::xml::DetElement layerDet = static_cast<dd4hep::xml::DetElement>(layer);
dd4hep::Cone layerShape(
layerDet.dz(), layerDet.rmin1(), layerDet.rmax1(), layerDet.rmin2(), layerDet.rmax2());
std::string layerName = DD4hep::XML::_toString(layerIdx, "layer%d");
DD4hep::Geometry::Volume layerVolume(layerName, layerShape, lcdd.material(layer.attr<std::string>("material")));
DD4hep::Geometry::Position transLayer(0., 0., layerDet.z_offset());
envVolume.placeVolume(layerVolume, DD4hep::Geometry::Transform3D(DD4hep::Geometry::RotationZ(0.), transLayer));
std::string layerName = dd4hep::xml::_toString(layerIdx, "layer%d");
dd4hep::Volume layerVolume(layerName, layerShape, lcdd.material(layer.attr<std::string>("material")));
dd4hep::Position transLayer(0., 0., layerDet.z_offset());
envVolume.placeVolume(layerVolume, dd4hep::Transform3D(dd4hep::RotationZ(0.), transLayer));
if (layer.hasAttr("vis")) {
layerVolume.setVisAttributes(lcdd, layerDet.visStr());
}
layer.m_node = layers.next();
}

DD4hep::Geometry::Position trans(0., 0., dimensions.z_offset());
DD4hep::Geometry::PlacedVolume envPhys =
experimentalHall.placeVolume(envVolume, DD4hep::Geometry::Transform3D(DD4hep::Geometry::RotationZ(0.), trans));
dd4hep::Position trans(0., 0., dimensions.z_offset());
dd4hep::PlacedVolume envPhys =
experimentalHall.placeVolume(envVolume, dd4hep::Transform3D(dd4hep::RotationZ(0.), trans));
envPhys.addPhysVolID("system", xmlDet.id());
detElement.setPlacement(envPhys);
detElement.setVisAttributes(lcdd, xmlDet.visStr(), envVolume);
Expand Down
34 changes: 17 additions & 17 deletions Detector/DetCommon/src/SimpleBox.cpp
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
#include "DD4hep/DetFactoryHelper.h"

namespace det {
static DD4hep::Geometry::Ref_t createSimpleBox(DD4hep::Geometry::LCDD& aLcdd,
DD4hep::XML::Handle_t aXmlElement,
DD4hep::Geometry::SensitiveDetector aSensDet) {
DD4hep::XML::DetElement x_det = aXmlElement;
static dd4hep::Ref_t createSimpleBox(dd4hep::Detector& aLcdd,
dd4hep::xml::Handle_t aXmlElement,
dd4hep::SensitiveDetector aSensDet) {
dd4hep::xml::DetElement x_det = aXmlElement;
std::string name = x_det.nameStr();
DD4hep::XML::Dimension dim(x_det.dimensions());
DD4hep::XML::Dimension pos(x_det.position());
DD4hep::XML::Dimension rot(x_det.rotation());
DD4hep::Geometry::Material mat(aLcdd.material(x_det.materialStr()));
DD4hep::Geometry::DetElement det(name, x_det.id());
DD4hep::Geometry::Volume det_vol(name + "_vol", DD4hep::Geometry::Box(dim.x(), dim.y(), dim.z()), mat);
DD4hep::Geometry::Volume mother = aLcdd.pickMotherVolume(det);
DD4hep::Geometry::Transform3D transform(
DD4hep::Geometry::Rotation3D(DD4hep::Geometry::RotationZYX(rot.z(), rot.y(), rot.x())),
DD4hep::Geometry::Position(pos.x(), pos.y(), pos.z()));
DD4hep::Geometry::PlacedVolume phv = mother.placeVolume(det_vol, transform);
dd4hep::xml::Dimension dim(x_det.dimensions());
dd4hep::xml::Dimension pos(x_det.position());
dd4hep::xml::Dimension rot(x_det.rotation());
dd4hep::Material mat(aLcdd.material(x_det.materialStr()));
dd4hep::DetElement det(name, x_det.id());
dd4hep::Volume det_vol(name + "_vol", dd4hep::Box(dim.x(), dim.y(), dim.z()), mat);
dd4hep::Volume mother = aLcdd.pickMotherVolume(det);
dd4hep::Transform3D transform(
dd4hep::Rotation3D(dd4hep::RotationZYX(rot.z(), rot.y(), rot.x())),
dd4hep::Position(pos.x(), pos.y(), pos.z()));
dd4hep::PlacedVolume phv = mother.placeVolume(det_vol, transform);

det_vol.setVisAttributes(aLcdd, x_det.visStr());
det_vol.setLimitSet(aLcdd, x_det.limitsStr());
det_vol.setRegion(aLcdd, x_det.regionStr());
if (x_det.isSensitive()) {
DD4hep::Geometry::SensitiveDetector sd = aSensDet;
DD4hep::XML::Dimension sd_typ = x_det.child(_U(sensitive));
dd4hep::SensitiveDetector sd = aSensDet;
dd4hep::xml::Dimension sd_typ = x_det.child(_U(sensitive));
det_vol.setSensitiveDetector(aSensDet);
sd.setType(sd_typ.typeStr());
}
Expand Down
Loading

0 comments on commit 498c583

Please sign in to comment.