diff --git a/Configuration/AlCa/python/autoCondPhase2.py b/Configuration/AlCa/python/autoCondPhase2.py
index cf3d19a1e2092..051990d54abea 100644
--- a/Configuration/AlCa/python/autoCondPhase2.py
+++ b/Configuration/AlCa/python/autoCondPhase2.py
@@ -19,7 +19,8 @@
## T23: Phase2 tilted tracker. Outer Tracker (v8.0.0): same as T21. Inner Tracker: Based on (v6.1.5) (T21), but with 3D sensors in TBPX L1 + TBPX L2 + TFPX R1.
## T25: Phase2 tilted tracker. Outer Tracker (v8.0.0): same as T24/T21. Inner Tracker (v7.0.2): Based on (v6.1.5) (T24/T21), but with 3D sensors in TBPX L1.
## T26: Phase2 tilted tracker. Outer Tracker (v8.0.0): same as T24/T21. Inner Tracker (v7.0.3): Based on (v6.1.5) (T24/T21), but with 3D sensors in TBPX L1 and 50x50 pixel aspect ratio in TFPX and TEPX.
-##
+## T27: Phase2 tilted tracker. Outer Tracker (v8.0.0): same as T24/T21. Inner Tracker: with bricked pixels
+## T30: Phase2 tilted tracker, exploratory geometry *only to be used in D91 for now*. Outer Tracker (v8.0.1): based on v8.0.0 with updated TB2S spacing. Inner Tracker (v6.4.0): based on v6.1.5 but TFPX with more realistic module positions
#combines in a single dict of dict the tags defined below
allTags={}
@@ -32,6 +33,7 @@
'T25' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_T25_v0_mc' ,SiPixelLARecord,connectionString, "", "2021-03-16 20:00:00.000"] ), ), #uH = 0.053/T (TBPX L2,L3,L4), uH=0.0/T (TBPX L1 TEPX+TFPX)
'T26' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_T25_v0_mc' ,SiPixelLARecord,connectionString, "", "2021-03-16 20:00:00.000"] ), ), #uH = 0.053/T (TBPX L2,L3,L4), uH=0.0/T (TBPX L1 TEPX+TFPX)
'T27' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_T25_v0_mc' ,SiPixelLARecord,connectionString, "", "2021-03-16 20:00:00.000"] ), ), #uH = 0.053/T (TBPX L2,L3,L4), uH=0.0/T (TBPX L1 TEPX+TFPX)
+ 'T30' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_IT_v6.4.0_25x100_v1_mc' ,SiPixelLARecord,connectionString, "", "2021-11-22 21:00:00.000"] ), ), #uH = 0.053/T (TBPX), uH=0.0/T (TEPX+TFPX)
}
allTags["LAWidth"] = {
@@ -42,6 +44,7 @@
'T25' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_T19_mc_forWidthEmpty' ,SiPixelLARecord,connectionString, "forWidth", "2020-02-23 14:00:00.000"] ), ), # uH=0.0/T (fall-back to offset)
'T26' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_T19_mc_forWidthEmpty' ,SiPixelLARecord,connectionString, "forWidth", "2020-02-23 14:00:00.000"] ), ), # uH=0.0/T (fall-back to offset)
'T27' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_T19_mc_forWidthEmpty' ,SiPixelLARecord,connectionString, "forWidth", "2020-02-23 14:00:00.000"] ), ), # uH=0.0/T (fall-back to offset)
+ 'T30' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_IT_v6.4.0_25x100_empty_mc' ,SiPixelLARecord,connectionString, "forWidth", "2021-11-29 20:00:00.000"] ), ), # uH=0.0/T (fall-back to offset)
}
allTags["LAfromAlignment"] = {
@@ -52,6 +55,7 @@
'T25' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_T19_mc_forWidthEmpty' ,SiPixelLARecord,connectionString, "fromAlignment", "2020-02-23 14:00:00.000"] ), ), # uH=0.0/T (not in use)
'T26' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_T19_mc_forWidthEmpty' ,SiPixelLARecord,connectionString, "fromAlignment", "2020-02-23 14:00:00.000"] ), ), # uH=0.0/T (not in use)
'T27' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_T19_mc_forWidthEmpty' ,SiPixelLARecord,connectionString, "fromAlignment", "2020-02-23 14:00:00.000"] ), ), # uH=0.0/T (not in use)
+ 'T30' : ( ','.join( [ 'SiPixelLorentzAngle_phase2_IT_v6.4.0_25x100_empty_mc' ,SiPixelLARecord,connectionString, "fromAlignment", "2021-11-29 20:00:00.000"] ), ), # uH=0.0/T (fall-back to offset)
}
allTags["SimLA"] = {
@@ -62,6 +66,7 @@
'T25' : ( ','.join( [ 'SiPixelSimLorentzAngle_phase2_T25_v0_mc' ,SiPixelSimLARecord,connectionString, "", "2021-03-16 20:00:00.000"] ), ), #uH = 0.053/T (TBPX L2,L3,L4), uH=0.0/T (TBPX L1 TEPX+TFPX)
'T26' : ( ','.join( [ 'SiPixelSimLorentzAngle_phase2_T25_v0_mc' ,SiPixelSimLARecord,connectionString, "", "2021-03-16 20:00:00.000"] ), ), #uH = 0.053/T (TBPX L2,L3,L4), uH=0.0/T (TBPX L1 TEPX+TFPX)
'T27' : ( ','.join( [ 'SiPixelSimLorentzAngle_phase2_T25_v0_mc' ,SiPixelSimLARecord,connectionString, "", "2021-03-16 20:00:00.000"] ), ), #uH = 0.053/T (TBPX L2,L3,L4), uH=0.0/T (TBPX L1 TEPX+TFPX)
+ 'T30' : ( ','.join( [ 'SiPixelSimLorentzAngle_phase2_IT_v6.4.0_25x100_v1_mc' ,SiPixelSimLARecord,connectionString, "", "2021-12-03 16:00:00.000"] ), ), #uH = 0.053/T (TBPX), uH=0.0/T (TEPX+TFPX)
}
allTags["GenError"] = {
@@ -71,6 +76,7 @@
'T23' : ( ','.join( [ 'SiPixelGenErrorDBObject_phase2_IT_v7.0.0_25x100_v2_mc' ,SiPixelGenErrorRecord,connectionString, "", "2021-04-17 20:00:00"] ), ), # cell is 25um (local-x) x 100um (local-y) , VBias=350V, 3D pixels in TBPX L1+L2 and TFPX R1
'T25' : ( ','.join( [ 'SiPixelGenErrorDBObject_phase2_IT_v7.0.2_25x100_v2_mc' ,SiPixelGenErrorRecord,connectionString, "", "2021-04-17 20:00:00"] ), ), # cell is 25um (local-x) x 100um (local-y) , VBias=350V, 3D pixels in TBPX L1
'T26' : ( ','.join( [ 'SiPixelGenErrorDBObject_phase2_IT_v7.0.3_mixed_v2_mc' ,SiPixelGenErrorRecord,connectionString, "", "2021-04-17 20:00:00"] ), ), # TBPX cells are 25um (local-x) x 100um (local-y), TFPX TEPX 50 um x 50 um , VBias=350V, 3D pixels in TBPX L1
+ 'T30' : ( ','.join( [ 'SiPixelGenErrorDBObject_phase2_IT_v6.4.0_25x100_v1_mc',SiPixelGenErrorRecord,connectionString, "", "2021-11-22 21:00:00"] ), ), # cell is 25um (local-x) x 100um (local-y) , VBias=350V
}
allTags["Template"] = {
@@ -80,6 +86,7 @@
'T23' : ( ','.join( [ 'SiPixelTemplateDBObject_phase2_IT_v7.0.0_25x100_v2_mc' ,SiPixelTemplatesRecord,connectionString, "", "2021-04-17 20:00:00"] ), ), # cell is 25um (local-x) x 100um (local-y) , VBias=350V, 3D pixels in TBPX L1+L2 and TFPX R1
'T25' : ( ','.join( [ 'SiPixelTemplateDBObject_phase2_IT_v7.0.2_25x100_v2_mc' ,SiPixelTemplatesRecord,connectionString, "", "2021-04-17 20:00:00"] ), ), # cell is 25um (local-x) x 100um (local-y) , VBias=350V, 3D pixels in TBPX L1
'T26' : ( ','.join( [ 'SiPixelTemplateDBObject_phase2_IT_v7.0.3_mixed_v2_mc' ,SiPixelTemplatesRecord,connectionString, "", "2021-04-17 20:00:00"] ), ), # TBPX cells are 25um (local-x) x 100um (local-y), TFPX TEPX 50 um x 50 um , VBias=350V, 3D pixels in TBPX L1
+ 'T30' : ( ','.join( [ 'SiPixelTemplateDBObject_phase2_IT_v6.4.0_25x100_v1_mc',SiPixelTemplatesRecord,connectionString, "", "2021-11-22 21:00:00"] ), ), # cell is 25um (local-x) x 100um (local-y) , VBias=350V
}
##
@@ -95,6 +102,7 @@
'T25' : ( ','.join( [ 'SiPhase2OuterTrackerLorentzAngle_v0_mc' ,TrackerLARecord,connectionString, "", "2020-07-19 17:00:00.000"] ), ), #uH = 0.07/T
'T26' : ( ','.join( [ 'SiPhase2OuterTrackerLorentzAngle_v0_mc' ,TrackerLARecord,connectionString, "", "2020-07-19 17:00:00.000"] ), ), #uH = 0.07/T
'T27' : ( ','.join( [ 'SiPhase2OuterTrackerLorentzAngle_v0_mc' ,TrackerLARecord,connectionString, "", "2020-07-19 17:00:00.000"] ), ), #uH = 0.07/T
+ 'T30' : ( ','.join( [ 'SiPhase2OuterTrackerLorentzAngle_v0_mc' ,TrackerLARecord,connectionString, "", "2020-07-19 17:00:00.000"] ), ), #uH = 0.07/T
}
allTags["SimOTLA"] = {
@@ -105,6 +113,7 @@
'T25' : ( ','.join( [ 'SiPhase2OuterTrackerLorentzAngleSim_v0_mc' ,TrackerSimLARecord,connectionString, "", "2020-07-19 17:00:00.000"] ), ), #uH = 0.07/T
'T26' : ( ','.join( [ 'SiPhase2OuterTrackerLorentzAngleSim_v0_mc' ,TrackerSimLARecord,connectionString, "", "2020-07-19 17:00:00.000"] ), ), #uH = 0.07/T
'T27' : ( ','.join( [ 'SiPhase2OuterTrackerLorentzAngleSim_v0_mc' ,TrackerSimLARecord,connectionString, "", "2020-07-19 17:00:00.000"] ), ), #uH = 0.07/T
+ 'T30' : ( ','.join( [ 'SiPhase2OuterTrackerLorentzAngleSim_v0_mc' ,TrackerSimLARecord,connectionString, "", "2020-07-19 17:00:00.000"] ), ), #uH = 0.07/T
}
'''
##
@@ -123,7 +132,7 @@
activeKeys = ["LA","LAWidth","SimLA","LAfromAlignment","GenError","Template"]#,"SimOTLA","OTLA"]
# list of geometries supported
-activeDets = ["T15","T21","T22","T23","T25","T26","T27"]
+activeDets = ["T15","T21","T22","T23","T25","T26","T27","T30"]
phase2GTs = {}
for det in activeDets:
appendedTags = ()
diff --git a/Configuration/Geometry/python/GeometryDD4hepExtended2026D91Reco_cff.py b/Configuration/Geometry/python/GeometryDD4hepExtended2026D91Reco_cff.py
new file mode 100644
index 0000000000000..bc83cd55a3ca5
--- /dev/null
+++ b/Configuration/Geometry/python/GeometryDD4hepExtended2026D91Reco_cff.py
@@ -0,0 +1,60 @@
+import FWCore.ParameterSet.Config as cms
+
+# This config was generated automatically using generate2026Geometry.py
+# If you notice a mistake, please update the generating script, not just this config
+
+from Configuration.Geometry.GeometryDD4hepExtended2026D91_cff import *
+
+# tracker
+from Geometry.CommonTopologies.globalTrackingGeometry_cfi import *
+from RecoTracker.GeometryESProducer.TrackerRecoGeometryESProducer_cfi import *
+from Geometry.TrackerGeometryBuilder.TrackerAdditionalParametersPerDet_cfi import *
+from Geometry.TrackerGeometryBuilder.trackerParameters_cff import *
+from Geometry.TrackerNumberingBuilder.trackerTopology_cfi import *
+from Geometry.TrackerGeometryBuilder.idealForDigiTrackerGeometry_cff import *
+trackerGeometry.applyAlignment = cms.bool(False)
+
+# calo
+from Geometry.CaloEventSetup.HGCalV9Topology_cfi import *
+from Geometry.HGCalGeometry.HGCalGeometryESProducer_cfi import *
+from Geometry.CaloEventSetup.CaloTopology_cfi import *
+from Geometry.CaloEventSetup.CaloGeometryBuilder_cfi import *
+CaloGeometryBuilder = cms.ESProducer("CaloGeometryBuilder",
+ SelectedCalos = cms.vstring("HCAL",
+ "ZDC",
+ "EcalBarrel",
+ "TOWER",
+ "HGCalEESensitive",
+ "HGCalHESiliconSensitive",
+ "HGCalHEScintillatorSensitive"
+ )
+)
+from Geometry.EcalAlgo.EcalBarrelGeometry_cfi import *
+from Geometry.HcalEventSetup.HcalGeometry_cfi import *
+from Geometry.HcalEventSetup.CaloTowerGeometry_cfi import *
+from Geometry.HcalEventSetup.CaloTowerTopology_cfi import *
+from Geometry.HcalCommonData.hcalDDDRecConstants_cfi import *
+from Geometry.HcalEventSetup.hcalTopologyIdeal_cfi import *
+from Geometry.CaloEventSetup.EcalTrigTowerConstituents_cfi import *
+from Geometry.EcalMapping.EcalMapping_cfi import *
+from Geometry.EcalMapping.EcalMappingRecord_cfi import *
+
+# muon
+from Geometry.MuonNumbering.muonNumberingInitialization_cfi import *
+from RecoMuon.DetLayers.muonDetLayerGeometry_cfi import *
+from Geometry.GEMGeometryBuilder.gemGeometry_cfi import *
+from Geometry.CSCGeometryBuilder.idealForDigiCscGeometry_cff import *
+from Geometry.DTGeometryBuilder.idealForDigiDtGeometry_cff import *
+
+# forward
+from Geometry.ForwardGeometry.ForwardGeometry_cfi import *
+
+# timing
+from RecoMTD.DetLayers.mtdDetLayerGeometry_cfi import *
+from Geometry.MTDGeometryBuilder.mtdParameters_cff import *
+from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cff import *
+from Geometry.MTDNumberingBuilder.mtdTopology_cfi import *
+from Geometry.MTDGeometryBuilder.mtdGeometry_cfi import *
+from Geometry.MTDGeometryBuilder.idealForDigiMTDGeometry_cff import *
+mtdGeometry.applyAlignment = cms.bool(False)
+
diff --git a/Configuration/Geometry/python/GeometryDD4hepExtended2026D91_cff.py b/Configuration/Geometry/python/GeometryDD4hepExtended2026D91_cff.py
new file mode 100644
index 0000000000000..8c66e78d3be6d
--- /dev/null
+++ b/Configuration/Geometry/python/GeometryDD4hepExtended2026D91_cff.py
@@ -0,0 +1,16 @@
+import FWCore.ParameterSet.Config as cms
+
+# This config was generated automatically using generate2026Geometry.py
+# If you notice a mistake, please update the generating script, not just this config
+
+from Configuration.Geometry.GeometryDD4hep_cff import *
+DDDetectorESProducer.confGeomXMLFiles = cms.FileInPath("Geometry/CMSCommonData/data/dd4hep/cmsExtendedGeometry2026D91.xml")
+
+from Geometry.TrackerNumberingBuilder.trackerNumberingGeometry_cfi import *
+from Geometry.EcalCommonData.ecalSimulationParameters_cff import *
+from Geometry.HcalCommonData.hcalDDDSimConstants_cff import *
+from Geometry.HGCalCommonData.hgcalV15ParametersInitialization_cfi import *
+from Geometry.HGCalCommonData.hgcalNumberingInitialization_cfi import *
+from Geometry.MuonNumbering.muonGeometryConstants_cff import *
+from Geometry.MuonNumbering.muonOffsetESProducer_cff import *
+from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cff import *
diff --git a/Configuration/Geometry/python/GeometryExtended2026D91Reco_cff.py b/Configuration/Geometry/python/GeometryExtended2026D91Reco_cff.py
new file mode 100644
index 0000000000000..c18aba20cb3bd
--- /dev/null
+++ b/Configuration/Geometry/python/GeometryExtended2026D91Reco_cff.py
@@ -0,0 +1,60 @@
+import FWCore.ParameterSet.Config as cms
+
+# This config was generated automatically using generate2026Geometry.py
+# If you notice a mistake, please update the generating script, not just this config
+
+from Configuration.Geometry.GeometryExtended2026D91_cff import *
+
+# tracker
+from Geometry.CommonTopologies.globalTrackingGeometry_cfi import *
+from RecoTracker.GeometryESProducer.TrackerRecoGeometryESProducer_cfi import *
+from Geometry.TrackerGeometryBuilder.TrackerAdditionalParametersPerDet_cfi import *
+from Geometry.TrackerGeometryBuilder.trackerParameters_cff import *
+from Geometry.TrackerNumberingBuilder.trackerTopology_cfi import *
+from Geometry.TrackerGeometryBuilder.idealForDigiTrackerGeometry_cff import *
+trackerGeometry.applyAlignment = cms.bool(False)
+
+# calo
+from Geometry.CaloEventSetup.HGCalV9Topology_cfi import *
+from Geometry.HGCalGeometry.HGCalGeometryESProducer_cfi import *
+from Geometry.CaloEventSetup.CaloTopology_cfi import *
+from Geometry.CaloEventSetup.CaloGeometryBuilder_cfi import *
+CaloGeometryBuilder = cms.ESProducer("CaloGeometryBuilder",
+ SelectedCalos = cms.vstring("HCAL",
+ "ZDC",
+ "EcalBarrel",
+ "TOWER",
+ "HGCalEESensitive",
+ "HGCalHESiliconSensitive",
+ "HGCalHEScintillatorSensitive"
+ )
+)
+from Geometry.EcalAlgo.EcalBarrelGeometry_cfi import *
+from Geometry.HcalEventSetup.HcalGeometry_cfi import *
+from Geometry.HcalEventSetup.CaloTowerGeometry_cfi import *
+from Geometry.HcalEventSetup.CaloTowerTopology_cfi import *
+from Geometry.HcalCommonData.hcalDDDRecConstants_cfi import *
+from Geometry.HcalEventSetup.hcalTopologyIdeal_cfi import *
+from Geometry.CaloEventSetup.EcalTrigTowerConstituents_cfi import *
+from Geometry.EcalMapping.EcalMapping_cfi import *
+from Geometry.EcalMapping.EcalMappingRecord_cfi import *
+
+# muon
+from Geometry.MuonNumbering.muonNumberingInitialization_cfi import *
+from RecoMuon.DetLayers.muonDetLayerGeometry_cfi import *
+from Geometry.GEMGeometryBuilder.gemGeometry_cfi import *
+from Geometry.CSCGeometryBuilder.idealForDigiCscGeometry_cff import *
+from Geometry.DTGeometryBuilder.idealForDigiDtGeometry_cff import *
+
+# forward
+from Geometry.ForwardGeometry.ForwardGeometry_cfi import *
+
+# timing
+from RecoMTD.DetLayers.mtdDetLayerGeometry_cfi import *
+from Geometry.MTDGeometryBuilder.mtdParameters_cff import *
+from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cff import *
+from Geometry.MTDNumberingBuilder.mtdTopology_cfi import *
+from Geometry.MTDGeometryBuilder.mtdGeometry_cfi import *
+from Geometry.MTDGeometryBuilder.idealForDigiMTDGeometry_cff import *
+mtdGeometry.applyAlignment = cms.bool(False)
+
diff --git a/Configuration/Geometry/python/GeometryExtended2026D91_cff.py b/Configuration/Geometry/python/GeometryExtended2026D91_cff.py
new file mode 100644
index 0000000000000..f99f64bf1c04b
--- /dev/null
+++ b/Configuration/Geometry/python/GeometryExtended2026D91_cff.py
@@ -0,0 +1,14 @@
+import FWCore.ParameterSet.Config as cms
+
+# This config was generated automatically using generate2026Geometry.py
+# If you notice a mistake, please update the generating script, not just this config
+
+from Geometry.CMSCommonData.cmsExtendedGeometry2026D91XML_cfi import *
+from Geometry.TrackerNumberingBuilder.trackerNumberingGeometry_cfi import *
+from Geometry.EcalCommonData.ecalSimulationParameters_cff import *
+from Geometry.HcalCommonData.hcalDDDSimConstants_cff import *
+from Geometry.HGCalCommonData.hgcalV15ParametersInitialization_cfi import *
+from Geometry.HGCalCommonData.hgcalNumberingInitialization_cfi import *
+from Geometry.MuonNumbering.muonGeometryConstants_cff import *
+from Geometry.MuonNumbering.muonOffsetESProducer_cff import *
+from Geometry.MTDNumberingBuilder.mtdNumberingGeometry_cff import *
diff --git a/Configuration/Geometry/python/dict2026Geometry.py b/Configuration/Geometry/python/dict2026Geometry.py
index 416fb78c4f4fc..61e5716bea2d2 100644
--- a/Configuration/Geometry/python/dict2026Geometry.py
+++ b/Configuration/Geometry/python/dict2026Geometry.py
@@ -525,7 +525,42 @@
'trackerGeometry.applyAlignment = cms.bool(False)',
],
"era" : "phase2_tracker, phase2_brickedPixels, phase2_squarePixels, trackingPhase2PU140",
- }
+ },
+ "T30" : {
+ 1 : [
+ 'Geometry/TrackerCommonData/data/PhaseII/TFPXTEPXReordered/trackerParameters.xml',
+ 'Geometry/TrackerCommonData/data/pixfwdCommon.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_2021_02/pixfwd.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/OuterTracker616_2020_04/pixbar.xml',
+ 'Geometry/TrackerCommonData/data/trackermaterial.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/OuterTracker616_2020_04/otst.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/tracker.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixel.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/TiltedTracker404/trackerbar.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/TiltedTracker404/trackerfwd.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_2021_02/trackerStructureTopology.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelStructureTopology.xml',
+ 'Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_2021_02/trackersens.xml',
+ 'Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelsens.xml',
+ 'Geometry/TrackerRecoData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/trackerRecoMaterial.xml',
+ 'Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_2021_02/trackerProdCuts.xml',
+ 'Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelProdCuts.xml',
+ 'Geometry/TrackerSimData/data/trackerProdCutsBEAM.xml',
+ ],
+ "sim" : [
+ 'from Geometry.TrackerNumberingBuilder.trackerNumberingGeometry_cfi import *',
+ ],
+ "reco" : [
+ 'from Geometry.CommonTopologies.globalTrackingGeometry_cfi import *',
+ 'from RecoTracker.GeometryESProducer.TrackerRecoGeometryESProducer_cfi import *',
+ 'from Geometry.TrackerGeometryBuilder.TrackerAdditionalParametersPerDet_cfi import *',
+ 'from Geometry.TrackerGeometryBuilder.trackerParameters_cff import *',
+ 'from Geometry.TrackerNumberingBuilder.trackerTopology_cfi import *',
+ 'from Geometry.TrackerGeometryBuilder.idealForDigiTrackerGeometry_cff import *',
+ 'trackerGeometry.applyAlignment = cms.bool(False)',
+ ],
+ "era" : "phase2_tracker, trackingPhase2PU140",
+ }
}
@@ -1712,6 +1747,7 @@
("O9","T24","C17","M10","F6","I15") : "D88",
("O7","T28","C14","M9","F8","I13") : "D89",
("O7","T29","C14","M9","F8","I13") : "D90",
+ ("O9","T30","C17","M10","F6","I15") : "D91",
}
deprecatedDets = set([ "D1", "D2", "D3", "D5", "D6" , "D7", "D4", "D8" , "D9", "D12", "D13", "D15", "D10", "D11", "D14", "D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23", "D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31", "D32", "D33", "D34", "D36", "D37", "D38", "D39", "D40", "D42", "D35", "D41", "D43", "D44", "D45", "D46", "D48", "D47", "D50", "D51", "D52", "D53", "D54", "D55", "D56", "D57", "D58", "D59", "D61", "D62", "D63", "D64", "D65", "D66", "D67", "D69", "D71", "D72", "D73", "D74", "D75"])
diff --git a/Configuration/PyReleaseValidation/python/relval_2026.py b/Configuration/PyReleaseValidation/python/relval_2026.py
index 5e20568ad2d32..b0f39ca6945bc 100644
--- a/Configuration/PyReleaseValidation/python/relval_2026.py
+++ b/Configuration/PyReleaseValidation/python/relval_2026.py
@@ -42,6 +42,7 @@
numWFIB.extend([39434.0,39434.5,39434.501,39434.502]) #2026D88, pixelTrackingOnly, Patatrack local reconstruction on CPU, Patatrack local reconstruction on GPU
numWFIB.extend([39834.0]) #2026D89
numWFIB.extend([40234.0]) #2026D90
+numWFIB.extend([40634.0]) #2026D91
for numWF in numWFIB:
workflows[numWF] = _upgrade_workflows[numWF]
diff --git a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py
index 2f7a8f5fe7342..53bd619981942 100644
--- a/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py
+++ b/Configuration/PyReleaseValidation/python/upgradeWorkflowComponents.py
@@ -65,6 +65,8 @@
'2026D89PU',
'2026D90',
'2026D90PU',
+ '2026D91',
+ '2026D91PU',
]
# pre-generation of WF numbers
@@ -1595,6 +1597,13 @@ def condition(self, fragment, stepList, key, hasHarvest):
'Era' : 'Phase2C11I13T27M9',
'ScenToRun' : ['GenSimHLBeamSpot','DigiTrigger','RecoGlobal', 'HARVESTGlobal'],
},
+ '2026D91' : {
+ 'Geom' : 'Extended2026D91',
+ 'HLTmenu': '@fake2',
+ 'GT' : 'auto:phase2_realistic_T30',
+ 'Era' : 'Phase2C11I13M9',
+ 'ScenToRun' : ['GenSimHLBeamSpot','DigiTrigger','RecoGlobal', 'HARVESTGlobal'],
+ },
}
# standard PU sequences
diff --git a/Configuration/StandardSequences/python/GeometryConf.py b/Configuration/StandardSequences/python/GeometryConf.py
index c31d01c24cdd2..40534fb471590 100644
--- a/Configuration/StandardSequences/python/GeometryConf.py
+++ b/Configuration/StandardSequences/python/GeometryConf.py
@@ -69,4 +69,5 @@
'Extended2026D88' : 'Extended2026D88,Extended2026D88Reco',
'Extended2026D89' : 'Extended2026D89,Extended2026D89Reco',
'Extended2026D90' : 'Extended2026D90,Extended2026D90Reco',
+ 'Extended2026D91' : 'Extended2026D91,Extended2026D91Reco',
}
diff --git a/Geometry/CMSCommonData/data/dd4hep/cmsExtendedGeometry2026D91.xml b/Geometry/CMSCommonData/data/dd4hep/cmsExtendedGeometry2026D91.xml
new file mode 100644
index 0000000000000..7f8b33632f4d1
--- /dev/null
+++ b/Geometry/CMSCommonData/data/dd4hep/cmsExtendedGeometry2026D91.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Geometry/CMSCommonData/python/cmsExtendedGeometry2026D91XML_cfi.py b/Geometry/CMSCommonData/python/cmsExtendedGeometry2026D91XML_cfi.py
new file mode 100644
index 0000000000000..8a336fe576bf1
--- /dev/null
+++ b/Geometry/CMSCommonData/python/cmsExtendedGeometry2026D91XML_cfi.py
@@ -0,0 +1,130 @@
+import FWCore.ParameterSet.Config as cms
+
+# This config was generated automatically using generate2026Geometry.py
+# If you notice a mistake, please update the generating script, not just this config
+
+XMLIdealGeometryESSource = cms.ESSource("XMLIdealGeometryESSource",
+ geomXMLFiles = cms.vstring(
+ 'Geometry/CMSCommonData/data/materials/2021/v1/materials.xml',
+ 'Geometry/CMSCommonData/data/rotations.xml',
+ 'Geometry/CMSCommonData/data/extend/v2/cmsextent.xml',
+ 'Geometry/CMSCommonData/data/cavernData/2021/v1/cavernData.xml',
+ 'Geometry/CMSCommonData/data/cms/2026/v5/cms.xml',
+ 'Geometry/CMSCommonData/data/cmsMother.xml',
+ 'Geometry/CMSCommonData/data/eta3/etaMax.xml',
+ 'Geometry/CMSCommonData/data/cmsTracker.xml',
+ 'Geometry/CMSCommonData/data/caloBase/2026/v7/caloBase.xml',
+ 'Geometry/CMSCommonData/data/cmsCalo.xml',
+ 'Geometry/CMSCommonData/data/muonBase/2026/v5/muonBase.xml',
+ 'Geometry/CMSCommonData/data/cmsMuon.xml',
+ 'Geometry/CMSCommonData/data/mgnt.xml',
+ 'Geometry/CMSCommonData/data/beampipe/2026/v3/beampipe.xml',
+ 'Geometry/CMSCommonData/data/cmsBeam/2026/v1/cmsBeam.xml',
+ 'Geometry/CMSCommonData/data/muonMB.xml',
+ 'Geometry/CMSCommonData/data/muonMagnet.xml',
+ 'Geometry/CMSCommonData/data/cavern/2021/v1/cavern.xml',
+ 'Geometry/CMSCommonData/data/cavernFloor/2017/v1/cavernFloor.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/TFPXTEPXReordered/trackerParameters.xml',
+ 'Geometry/TrackerCommonData/data/pixfwdCommon.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_2021_02/pixfwd.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/OuterTracker616_2020_04/pixbar.xml',
+ 'Geometry/TrackerCommonData/data/trackermaterial.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/OuterTracker616_2020_04/otst.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/tracker.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixel.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/TiltedTracker404/trackerbar.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/TiltedTracker404/trackerfwd.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_2021_02/trackerStructureTopology.xml',
+ 'Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelStructureTopology.xml',
+ 'Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_2021_02/trackersens.xml',
+ 'Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelsens.xml',
+ 'Geometry/TrackerRecoData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/trackerRecoMaterial.xml',
+ 'Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_2021_02/trackerProdCuts.xml',
+ 'Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelProdCuts.xml',
+ 'Geometry/TrackerSimData/data/trackerProdCutsBEAM.xml',
+ 'Geometry/EcalCommonData/data/eregalgo/2026/v2/eregalgo.xml',
+ 'Geometry/EcalCommonData/data/ectkcable/2026/v1/ectkcable.xml',
+ 'Geometry/EcalCommonData/data/ectkcablemat/2026/v2/ectkcablemat.xml',
+ 'Geometry/EcalCommonData/data/ebalgo.xml',
+ 'Geometry/EcalCommonData/data/ebcon/2021/v1/ebcon.xml',
+ 'Geometry/EcalCommonData/data/ebrot.xml',
+ 'Geometry/HcalCommonData/data/hcalrotations.xml',
+ 'Geometry/HcalCommonData/data/hcal/v2/hcalalgo.xml',
+ 'Geometry/HcalCommonData/data/hcalbarrelalgo.xml',
+ 'Geometry/HcalCommonData/data/hcalcablealgo/v2/hcalcablealgo.xml',
+ 'Geometry/HcalCommonData/data/hcalouteralgo.xml',
+ 'Geometry/HcalCommonData/data/hcalforwardalgo.xml',
+ 'Geometry/HcalCommonData/data/hcalSimNumbering/NoHE/hcalSimNumbering.xml',
+ 'Geometry/HcalCommonData/data/hcalRecNumbering/NoHE/hcalRecNumbering.xml',
+ 'Geometry/HcalCommonData/data/average/hcalforwardmaterial.xml',
+ 'Geometry/HGCalCommonData/data/hgcalMaterial/v2/hgcalMaterial.xml',
+ 'Geometry/HGCalCommonData/data/hgcal/v16/hgcal.xml',
+ 'Geometry/HGCalCommonData/data/hgcalcell/v16/hgcalcell.xml',
+ 'Geometry/HGCalCommonData/data/hgcalwafer/v16/hgcalwafer.xml',
+ 'Geometry/HGCalCommonData/data/hgcalEE/v16/hgcalEE.xml',
+ 'Geometry/HGCalCommonData/data/hgcalHEsil/v16/hgcalHEsil.xml',
+ 'Geometry/HGCalCommonData/data/hgcalHEmix/v16/hgcalHEmix.xml',
+ 'Geometry/HGCalCommonData/data/hgcalCons/v16/hgcalCons.xml',
+ 'Geometry/HGCalCommonData/data/hgcalConsData/v16/hgcalConsData.xml',
+ 'Geometry/MuonCommonData/data/mbCommon/2021/v1/mbCommon.xml',
+ 'Geometry/MuonCommonData/data/mb1/2015/v2/mb1.xml',
+ 'Geometry/MuonCommonData/data/mb2/2015/v2/mb2.xml',
+ 'Geometry/MuonCommonData/data/mb3/2015/v2/mb3.xml',
+ 'Geometry/MuonCommonData/data/mb4/2015/v2/mb4.xml',
+ 'Geometry/MuonCommonData/data/mb4Shield/2021/v1/mb4Shield.xml',
+ 'Geometry/MuonCommonData/data/muonYoke/2026/v2/muonYoke.xml',
+ 'Geometry/MuonCommonData/data/mf/2026/v8/mf.xml',
+ 'Geometry/MuonCommonData/data/csc/2021/v2/csc.xml',
+ 'Geometry/MuonCommonData/data/rpcf/2026/v3/rpcf.xml',
+ 'Geometry/MuonCommonData/data/gemf/TDR_BaseLine/gemf.xml',
+ 'Geometry/MuonCommonData/data/gem11/TDR_BaseLine/gem11.xml',
+ 'Geometry/MuonCommonData/data/gem21/TDR_Eta16/gem21.xml',
+ 'Geometry/MuonCommonData/data/mfshield/2026/v6/mfshield.xml',
+ 'Geometry/MuonCommonData/data/ge0/TDR_Dev/v4/ge0.xml',
+ 'Geometry/MuonCommonData/data/ge0shield/2026/v1/ge0shield.xml',
+ 'Geometry/ForwardCommonData/data/forwardshield/2026/v4/forwardshield.xml',
+ 'Geometry/ForwardCommonData/data/brmrotations.xml',
+ 'Geometry/ForwardCommonData/data/brm/2026/v1/brm.xml',
+ 'Geometry/ForwardCommonData/data/zdcmaterials.xml',
+ 'Geometry/ForwardCommonData/data/lumimaterials.xml',
+ 'Geometry/ForwardCommonData/data/zdcrotations.xml',
+ 'Geometry/ForwardCommonData/data/lumirotations.xml',
+ 'Geometry/ForwardCommonData/data/zdc.xml',
+ 'Geometry/ForwardCommonData/data/zdclumi.xml',
+ 'Geometry/ForwardCommonData/data/cmszdc.xml',
+ 'Geometry/MTDCommonData/data/mtdMaterial/v3/mtdMaterial.xml',
+ 'Geometry/MTDCommonData/data/btl/v1/btl.xml',
+ 'Geometry/MTDCommonData/data/etl/v7/etl.xml',
+ 'Geometry/MTDCommonData/data/mtdParameters/v3/mtdStructureTopology.xml',
+ 'Geometry/MTDCommonData/data/mtdParameters/v2/mtdParameters.xml',
+ )+
+ cms.vstring(
+ 'Geometry/MuonCommonData/data/muonNumbering/TDR_DeV/v5/muonNumbering.xml',
+ 'Geometry/EcalSimData/data/PhaseII/ecalsens.xml',
+ 'Geometry/HcalCommonData/data/hcalsens/NoHE/hcalsenspmf.xml',
+ 'Geometry/HcalSimData/data/hf.xml',
+ 'Geometry/HcalSimData/data/hfpmt.xml',
+ 'Geometry/HcalSimData/data/hffibrebundle.xml',
+ 'Geometry/HcalSimData/data/CaloUtil/2026/v2c/CaloUtil.xml',
+ 'Geometry/HGCalSimData/data/hgcsensv15.xml',
+ 'Geometry/MuonSimData/data/PhaseII/v2/muonSens.xml',
+ 'Geometry/DTGeometryBuilder/data/dtSpecsFilter.xml',
+ 'Geometry/CSCGeometryBuilder/data/cscSpecsFilter.xml',
+ 'Geometry/CSCGeometryBuilder/data/cscSpecs.xml',
+ 'Geometry/RPCGeometryBuilder/data/2026/v1/RPCSpecs.xml',
+ 'Geometry/GEMGeometryBuilder/data/v12/GEMSpecsFilter.xml',
+ 'Geometry/GEMGeometryBuilder/data/v12/GEMSpecs.xml',
+ 'Geometry/ForwardCommonData/data/brmsens.xml',
+ 'Geometry/ForwardSimData/data/zdcsens.xml',
+ 'Geometry/MTDSimData/data/v2/mtdsens.xml',
+ 'Geometry/HcalSimData/data/HcalProdCuts/2021/v1/HcalProdCuts.xml',
+ 'Geometry/EcalSimData/data/EcalProdCuts.xml',
+ 'Geometry/HGCalSimData/data/hgcProdCutsv15.xml',
+ 'Geometry/MuonSimData/data/muonProdCuts/2026/v2/muonProdCuts.xml',
+ 'Geometry/ForwardSimData/data/zdcProdCuts.xml',
+ 'Geometry/ForwardSimData/data/ForwardShieldProdCuts.xml',
+ 'Geometry/MTDSimData/data/v2/mtdProdCuts.xml',
+ 'Geometry/CMSCommonData/data/FieldParameters.xml',
+ ),
+ rootNodeName = cms.string('cms:OCMS')
+)
diff --git a/Geometry/TrackerCommonData/data/PhaseII/TFPXTEPXReordered/trackerParameters.xml b/Geometry/TrackerCommonData/data/PhaseII/TFPXTEPXReordered/trackerParameters.xml
new file mode 100644
index 0000000000000..e280a9eaefc59
--- /dev/null
+++ b/Geometry/TrackerCommonData/data/PhaseII/TFPXTEPXReordered/trackerParameters.xml
@@ -0,0 +1,45 @@
+
+
+
+
+ 80, 52, 0, 0, 2, 8
+
+
+ 20, 12, 2, 0xF, 0xFF, 0x3FF
+
+
+ 23, 19, 18, 12, 10, 2, 0x3, 0xF, 0x1, 0x3F, 0x3, 0xFF
+
+
+ 14, 12, 10, 4, 2, 0, 0x7, 0x3, 0x3, 0x3F, 0x3, 0x3
+
+
+ 23, 18, 12, 10, 2, 0, 0x3, 0xF, 0x3F, 0x3, 0xFF, 0x3
+
+
+ 20, 18, 10, 2, 0, 0xF, 0x3, 0xFF, 0xFF, 0x3
+
+
+ 18, 14, 12, 8, 5, 2, 0, 0x3, 0xF, 0x3, 0xF, 0x7, 0x7, 0x3
+
+
+ -1, 23, -1,
+ 23, -1, 18,
+
+ 20, 19, 14,
+ 18, 20, 14,
+
+ 12, 18, 4,
+ 10, 10, 8,
+
+ 2, 10, 2,
+ 2, 2, 5,
+
+ 0, 2, 0,
+ 0, 0, 2,
+
+ -1, 0, -1,
+ -1, -1, 0
+
+
+
diff --git a/Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixel.xml b/Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixel.xml
new file mode 100644
index 0000000000000..655c2fcf6f029
--- /dev/null
+++ b/Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixel.xml
@@ -0,0 +1,19128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+98.5,134.722,170.944,-152.833,-116.611,-81.5,-45.2778,-9.05556,27.1667,63.3889
+-8.5,-2,0.7,2.5,6.61,-8.5,-2,0.7,2.5,6.61
+53.31,52.76,52.73,52.78,53.08,53.31,52.76,52.73,52.78,53.08
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+116.611,152.833,-170.944,-134.722,-98.5,-63.3889,-27.1667,9.05556,45.2778,81.5
+-6.61,-2.5,-0.7,2,8.5,-6.61,-2.5,-0.7,2,8.5
+53.08,52.78,52.73,52.76,53.31,53.08,52.78,52.73,52.76,53.31
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.325,118.638,140.952,163.265,-174.422,-152.108,-129.795,-107.482,-83.675,-61.3617,-39.0483,-16.735,5.57833,27.8917,50.205,72.5183
+-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48,-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.482,129.795,152.108,174.422,-163.265,-140.952,-118.638,-96.325,-72.5183,-50.205,-27.8917,-5.57833,16.735,39.0483,61.3617,83.675
+-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32,-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+99,128.455,157.909,-172.636,-143.182,-113.727,-81,-51.5455,-22.0909,7.36364,36.8182,66.2727
+-9.00002,-5.73,-2.45,0.82,4.09,7.36,-9.00002,-5.73,-2.45,0.82,4.09,7.36
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+113.727,143.182,172.636,-157.909,-128.455,-99,-66.2727,-36.8182,-7.36364,22.0909,51.5455,81
+-7.36,-4.09,-0.82,2.45,5.73,9.00002,-7.36,-4.09,-0.82,2.45,5.73,9.00002
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.625,118.858,141.092,163.325,-174.442,-152.208,-129.975,-107.742,-83.375,-61.1417,-38.9083,-16.675,5.55833,27.7917,50.025,72.2583
+-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74,-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74
+139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03,139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.742,129.975,152.208,174.442,-163.325,-141.092,-118.858,-96.625,-72.2583,-50.025,-27.7917,-5.55833,16.675,38.9083,61.1417,83.375
+-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62,-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62
+140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84,140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+98.5,134.722,170.944,-152.833,-116.611,-81.5,-45.2778,-9.05556,27.1667,63.3889
+-8.5,-2,0.7,2.5,6.61,-8.5,-2,0.7,2.5,6.61
+53.31,52.76,52.73,52.78,53.08,53.31,52.76,52.73,52.78,53.08
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+116.611,152.833,-170.944,-134.722,-98.5,-63.3889,-27.1667,9.05556,45.2778,81.5
+-6.61,-2.5,-0.7,2,8.5,-6.61,-2.5,-0.7,2,8.5
+53.08,52.78,52.73,52.76,53.31,53.08,52.78,52.73,52.76,53.31
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.325,118.638,140.952,163.265,-174.422,-152.108,-129.795,-107.482,-83.675,-61.3617,-39.0483,-16.735,5.57833,27.8917,50.205,72.5183
+-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48,-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.482,129.795,152.108,174.422,-163.265,-140.952,-118.638,-96.325,-72.5183,-50.205,-27.8917,-5.57833,16.735,39.0483,61.3617,83.675
+-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32,-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+99,128.455,157.909,-172.636,-143.182,-113.727,-81,-51.5455,-22.0909,7.36364,36.8182,66.2727
+-9.00002,-5.73,-2.45,0.82,4.09,7.36,-9.00002,-5.73,-2.45,0.82,4.09,7.36
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+113.727,143.182,172.636,-157.909,-128.455,-99,-66.2727,-36.8182,-7.36364,22.0909,51.5455,81
+-7.36,-4.09,-0.82,2.45,5.73,9.00002,-7.36,-4.09,-0.82,2.45,5.73,9.00002
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.625,118.858,141.092,163.325,-174.442,-152.208,-129.975,-107.742,-83.375,-61.1417,-38.9083,-16.675,5.55833,27.7917,50.025,72.2583
+-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74,-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74
+139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03,139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.742,129.975,152.208,174.442,-163.325,-141.092,-118.858,-96.625,-72.2583,-50.025,-27.7917,-5.55833,16.675,38.9083,61.1417,83.375
+-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62,-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62
+140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84,140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+98.5,134.722,170.944,-152.833,-116.611,-81.5,-45.2778,-9.05556,27.1667,63.3889
+-8.5,-2,0.7,2.5,6.61,-8.5,-2,0.7,2.5,6.61
+53.31,52.76,52.73,52.78,53.08,53.31,52.76,52.73,52.78,53.08
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+116.611,152.833,-170.944,-134.722,-98.5,-63.3889,-27.1667,9.05556,45.2778,81.5
+-6.61,-2.5,-0.7,2,8.5,-6.61,-2.5,-0.7,2,8.5
+53.08,52.78,52.73,52.76,53.31,53.08,52.78,52.73,52.76,53.31
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.325,118.638,140.952,163.265,-174.422,-152.108,-129.795,-107.482,-83.675,-61.3617,-39.0483,-16.735,5.57833,27.8917,50.205,72.5183
+-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48,-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.482,129.795,152.108,174.422,-163.265,-140.952,-118.638,-96.325,-72.5183,-50.205,-27.8917,-5.57833,16.735,39.0483,61.3617,83.675
+-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32,-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+99,128.455,157.909,-172.636,-143.182,-113.727,-81,-51.5455,-22.0909,7.36364,36.8182,66.2727
+-9.00002,-5.73,-2.45,0.82,4.09,7.36,-9.00002,-5.73,-2.45,0.82,4.09,7.36
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+113.727,143.182,172.636,-157.909,-128.455,-99,-66.2727,-36.8182,-7.36364,22.0909,51.5455,81
+-7.36,-4.09,-0.82,2.45,5.73,9.00002,-7.36,-4.09,-0.82,2.45,5.73,9.00002
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.625,118.858,141.092,163.325,-174.442,-152.208,-129.975,-107.742,-83.375,-61.1417,-38.9083,-16.675,5.55833,27.7917,50.025,72.2583
+-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74,-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74
+139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03,139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.742,129.975,152.208,174.442,-163.325,-141.092,-118.858,-96.625,-72.2583,-50.025,-27.7917,-5.55833,16.675,38.9083,61.1417,83.375
+-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62,-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62
+140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84,140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+98.5,134.722,170.944,-152.833,-116.611,-81.5,-45.2778,-9.05556,27.1667,63.3889
+-8.5,-2,0.7,2.5,6.61,-8.5,-2,0.7,2.5,6.61
+53.31,52.76,52.73,52.78,53.08,53.31,52.76,52.73,52.78,53.08
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+116.611,152.833,-170.944,-134.722,-98.5,-63.3889,-27.1667,9.05556,45.2778,81.5
+-6.61,-2.5,-0.7,2,8.5,-6.61,-2.5,-0.7,2,8.5
+53.08,52.78,52.73,52.76,53.31,53.08,52.78,52.73,52.76,53.31
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.325,118.638,140.952,163.265,-174.422,-152.108,-129.795,-107.482,-83.675,-61.3617,-39.0483,-16.735,5.57833,27.8917,50.205,72.5183
+-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48,-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.482,129.795,152.108,174.422,-163.265,-140.952,-118.638,-96.325,-72.5183,-50.205,-27.8917,-5.57833,16.735,39.0483,61.3617,83.675
+-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32,-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+99,128.455,157.909,-172.636,-143.182,-113.727,-81,-51.5455,-22.0909,7.36364,36.8182,66.2727
+-9.00002,-5.73,-2.45,0.82,4.09,7.36,-9.00002,-5.73,-2.45,0.82,4.09,7.36
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+113.727,143.182,172.636,-157.909,-128.455,-99,-66.2727,-36.8182,-7.36364,22.0909,51.5455,81
+-7.36,-4.09,-0.82,2.45,5.73,9.00002,-7.36,-4.09,-0.82,2.45,5.73,9.00002
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.625,118.858,141.092,163.325,-174.442,-152.208,-129.975,-107.742,-83.375,-61.1417,-38.9083,-16.675,5.55833,27.7917,50.025,72.2583
+-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74,-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74
+139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03,139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.742,129.975,152.208,174.442,-163.325,-141.092,-118.858,-96.625,-72.2583,-50.025,-27.7917,-5.55833,16.675,38.9083,61.1417,83.375
+-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62,-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62
+140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84,140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+98.5,134.722,170.944,-152.833,-116.611,-81.5,-45.2778,-9.05556,27.1667,63.3889
+-8.5,-2,0.7,2.5,6.61,-8.5,-2,0.7,2.5,6.61
+53.31,52.76,52.73,52.78,53.08,53.31,52.76,52.73,52.78,53.08
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+116.611,152.833,-170.944,-134.722,-98.5,-63.3889,-27.1667,9.05556,45.2778,81.5
+-6.61,-2.5,-0.7,2,8.5,-6.61,-2.5,-0.7,2,8.5
+53.08,52.78,52.73,52.76,53.31,53.08,52.78,52.73,52.76,53.31
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.325,118.638,140.952,163.265,-174.422,-152.108,-129.795,-107.482,-83.675,-61.3617,-39.0483,-16.735,5.57833,27.8917,50.205,72.5183
+-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48,-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.482,129.795,152.108,174.422,-163.265,-140.952,-118.638,-96.325,-72.5183,-50.205,-27.8917,-5.57833,16.735,39.0483,61.3617,83.675
+-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32,-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+99,128.455,157.909,-172.636,-143.182,-113.727,-81,-51.5455,-22.0909,7.36364,36.8182,66.2727
+-9.00002,-5.73,-2.45,0.82,4.09,7.36,-9.00002,-5.73,-2.45,0.82,4.09,7.36
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+113.727,143.182,172.636,-157.909,-128.455,-99,-66.2727,-36.8182,-7.36364,22.0909,51.5455,81
+-7.36,-4.09,-0.82,2.45,5.73,9.00002,-7.36,-4.09,-0.82,2.45,5.73,9.00002
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.625,118.858,141.092,163.325,-174.442,-152.208,-129.975,-107.742,-83.375,-61.1417,-38.9083,-16.675,5.55833,27.7917,50.025,72.2583
+-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74,-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74
+139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03,139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.742,129.975,152.208,174.442,-163.325,-141.092,-118.858,-96.625,-72.2583,-50.025,-27.7917,-5.55833,16.675,38.9083,61.1417,83.375
+-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62,-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62
+140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84,140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+98.5,134.722,170.944,-152.833,-116.611,-81.5,-45.2778,-9.05556,27.1667,63.3889
+-8.5,-2,0.7,2.5,6.61,-8.5,-2,0.7,2.5,6.61
+53.31,52.76,52.73,52.78,53.08,53.31,52.76,52.73,52.78,53.08
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+116.611,152.833,-170.944,-134.722,-98.5,-63.3889,-27.1667,9.05556,45.2778,81.5
+-6.61,-2.5,-0.7,2,8.5,-6.61,-2.5,-0.7,2,8.5
+53.08,52.78,52.73,52.76,53.31,53.08,52.78,52.73,52.76,53.31
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.325,118.638,140.952,163.265,-174.422,-152.108,-129.795,-107.482,-83.675,-61.3617,-39.0483,-16.735,5.57833,27.8917,50.205,72.5183
+-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48,-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.482,129.795,152.108,174.422,-163.265,-140.952,-118.638,-96.325,-72.5183,-50.205,-27.8917,-5.57833,16.735,39.0483,61.3617,83.675
+-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32,-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+99,128.455,157.909,-172.636,-143.182,-113.727,-81,-51.5455,-22.0909,7.36364,36.8182,66.2727
+-9.00002,-5.73,-2.45,0.82,4.09,7.36,-9.00002,-5.73,-2.45,0.82,4.09,7.36
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+113.727,143.182,172.636,-157.909,-128.455,-99,-66.2727,-36.8182,-7.36364,22.0909,51.5455,81
+-7.36,-4.09,-0.82,2.45,5.73,9.00002,-7.36,-4.09,-0.82,2.45,5.73,9.00002
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.625,118.858,141.092,163.325,-174.442,-152.208,-129.975,-107.742,-83.375,-61.1417,-38.9083,-16.675,5.55833,27.7917,50.025,72.2583
+-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74,-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74
+139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03,139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.742,129.975,152.208,174.442,-163.325,-141.092,-118.858,-96.625,-72.2583,-50.025,-27.7917,-5.55833,16.675,38.9083,61.1417,83.375
+-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62,-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62
+140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84,140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+98.5,134.722,170.944,-152.833,-116.611,-81.5,-45.2778,-9.05556,27.1667,63.3889
+-8.5,-2,0.7,2.5,6.61,-8.5,-2,0.7,2.5,6.61
+53.31,52.76,52.73,52.78,53.08,53.31,52.76,52.73,52.78,53.08
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+116.611,152.833,-170.944,-134.722,-98.5,-63.3889,-27.1667,9.05556,45.2778,81.5
+-6.61,-2.5,-0.7,2,8.5,-6.61,-2.5,-0.7,2,8.5
+53.08,52.78,52.73,52.76,53.31,53.08,52.78,52.73,52.76,53.31
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.325,118.638,140.952,163.265,-174.422,-152.108,-129.795,-107.482,-83.675,-61.3617,-39.0483,-16.735,5.57833,27.8917,50.205,72.5183
+-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48,-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.482,129.795,152.108,174.422,-163.265,-140.952,-118.638,-96.325,-72.5183,-50.205,-27.8917,-5.57833,16.735,39.0483,61.3617,83.675
+-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32,-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+99,128.455,157.909,-172.636,-143.182,-113.727,-81,-51.5455,-22.0909,7.36364,36.8182,66.2727
+-9.00002,-5.73,-2.45,0.82,4.09,7.36,-9.00002,-5.73,-2.45,0.82,4.09,7.36
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+113.727,143.182,172.636,-157.909,-128.455,-99,-66.2727,-36.8182,-7.36364,22.0909,51.5455,81
+-7.36,-4.09,-0.82,2.45,5.73,9.00002,-7.36,-4.09,-0.82,2.45,5.73,9.00002
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.625,118.858,141.092,163.325,-174.442,-152.208,-129.975,-107.742,-83.375,-61.1417,-38.9083,-16.675,5.55833,27.7917,50.025,72.2583
+-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74,-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74
+139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03,139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.742,129.975,152.208,174.442,-163.325,-141.092,-118.858,-96.625,-72.2583,-50.025,-27.7917,-5.55833,16.675,38.9083,61.1417,83.375
+-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62,-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62
+140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84,140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+98.5,134.722,170.944,-152.833,-116.611,-81.5,-45.2778,-9.05556,27.1667,63.3889
+-8.5,-2,0.7,2.5,6.61,-8.5,-2,0.7,2.5,6.61
+53.31,52.76,52.73,52.78,53.08,53.31,52.76,52.73,52.78,53.08
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+116.611,152.833,-170.944,-134.722,-98.5,-63.3889,-27.1667,9.05556,45.2778,81.5
+-6.61,-2.5,-0.7,2,8.5,-6.61,-2.5,-0.7,2,8.5
+53.08,52.78,52.73,52.76,53.31,53.08,52.78,52.73,52.76,53.31
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.325,118.638,140.952,163.265,-174.422,-152.108,-129.795,-107.482,-83.675,-61.3617,-39.0483,-16.735,5.57833,27.8917,50.205,72.5183
+-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48,-6.33,-4.64,-2.95,-1.27,0.42,2.11,3.79,5.48
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.482,129.795,152.108,174.422,-163.265,-140.952,-118.638,-96.325,-72.5183,-50.205,-27.8917,-5.57833,16.735,39.0483,61.3617,83.675
+-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32,-5.48,-3.8,-2.11,-0.42,1.26,2.95,4.64,6.32
+73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+99,128.455,157.909,-172.636,-143.182,-113.727,-81,-51.5455,-22.0909,7.36364,36.8182,66.2727
+-9.00002,-5.73,-2.45,0.82,4.09,7.36,-9.00002,-5.73,-2.45,0.82,4.09,7.36
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+113.727,143.182,172.636,-157.909,-128.455,-99,-66.2727,-36.8182,-7.36364,22.0909,51.5455,81
+-7.36,-4.09,-0.82,2.45,5.73,9.00002,-7.36,-4.09,-0.82,2.45,5.73,9.00002
+105,105,105,105,105,105,105,105,105,105,105,105
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+96.625,118.858,141.092,163.325,-174.442,-152.208,-129.975,-107.742,-83.375,-61.1417,-38.9083,-16.675,5.55833,27.7917,50.025,72.2583
+-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74,-6.63,-4.86,-3.09,-1.33,0.44,2.21,3.97,5.74
+139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03,139.84,140.23,140.64,141.07,141.29,140.85,140.43,140.03
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+107.742,129.975,152.208,174.442,-163.325,-141.092,-118.858,-96.625,-72.2583,-50.025,-27.7917,-5.55833,16.675,38.9083,61.1417,83.375
+-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62,-5.74,-3.98,-2.21,-0.44,1.32,3.09,4.86,6.62
+140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84,140.03,140.43,140.85,141.29,141.07,140.64,140.23,139.84
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 0*mm
+
+
+
+
+
+
diff --git a/Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelStructureTopology.xml b/Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelStructureTopology.xml
new file mode 100644
index 0000000000000..31352a60a8729
--- /dev/null
+++ b/Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelStructureTopology.xml
@@ -0,0 +1,1185 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/tracker.xml b/Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/tracker.xml
new file mode 100644
index 0000000000000..56e6dd0ee2128
--- /dev/null
+++ b/Geometry/TrackerCommonData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/tracker.xml
@@ -0,0 +1,33485 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.8981*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.95877*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.64218*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -3.75278*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.5*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -5.60117*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.04705*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -4.76701*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 8.595*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -8.595*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 8.595*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -8.595*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.55*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 8.595*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -8.595*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 8.595*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -8.595*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, 7.495*mm
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0*mm, 0*mm, -7.495*mm
+
+
+
+
+
+
diff --git a/Geometry/TrackerCommonData/plugins/DDTrackerIrregularRingAlgo.cc b/Geometry/TrackerCommonData/plugins/DDTrackerIrregularRingAlgo.cc
new file mode 100644
index 0000000000000..edc9aa306d27c
--- /dev/null
+++ b/Geometry/TrackerCommonData/plugins/DDTrackerIrregularRingAlgo.cc
@@ -0,0 +1,249 @@
+///////////////////////////////////////////////////////////////////////////////
+// File: DDTrackerIrregularRingAlgo.cc
+// Description: Tilts and positions n copies of a module at prescribed phi
+// values within a ring. The module can also be flipped if requested.
+///////////////////////////////////////////////////////////////////////////////
+
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+#include "DetectorDescription/Core/interface/DDCurrentNamespace.h"
+#include "DetectorDescription/Core/interface/DDSplit.h"
+#include "DetectorDescription/Core/interface/DDRotationMatrix.h"
+#include "DetectorDescription/Core/interface/DDTransform.h"
+#include "DetectorDescription/Core/interface/DDTypes.h"
+#include "DetectorDescription/Core/interface/DDAlgorithm.h"
+#include "DetectorDescription/Core/interface/DDAlgorithmFactory.h"
+#include "DataFormats/Math/interface/angle_units.h"
+
+#include
+#include
+
+/*
+ Tilts and positions n copies of a module at prescribed phi values
+ within a ring. The module can also be flipped if requested.
+
+ (radius, Phi, Z) refers to the cylindrical coordinates in the global frame of reference.
+
+ A module's tilt angle is defined with respect to the global frame of reference's Z axis.
+ Example, in the outer tracker : For a straight barrel module, tiltAngle = 0°.
+ For a module in the endcaps, tiltAngle = 90°.
+ tiltAngle ∈ [0, 90°].
+ Please note that parameter tiltAngle has to be set regardless of any sign consideration,
+ to the absolute value of the module's tilt angle.
+
+ == Example of use : ==
+
+
+
+
+
+
+
+
+
+
+ 0,0,-5.45415
+
+
+
+
+*/
+
+using namespace std;
+using namespace angle_units::operators;
+
+class DDTrackerIrregularRingAlgo : public DDAlgorithm {
+public:
+ // Constructor and Destructor
+ DDTrackerIrregularRingAlgo();
+ ~DDTrackerIrregularRingAlgo() override;
+
+ void initialize(const DDNumericArguments& nArgs,
+ const DDVectorArguments& vArgs,
+ const DDMapArguments& mArgs,
+ const DDStringArguments& sArgs,
+ const DDStringVectorArguments& vsArgs) override;
+
+ void execute(DDCompactView& cpv) override;
+
+private:
+ int n; //Number of copies
+ int startCopyNo; //Start Copy number
+ int incrCopyNo; //Increment in Copy number
+ double rangeAngle; //Range in Phi angle
+ double startAngle; //Start Phi angle
+ double radius; //Radius
+ vector center; //Phi values
+ vector phiAngles;
+ vector radiusValues;
+ vector yawAngles;
+ bool isZPlus; //Is Z positive ?
+ double tiltAngle; //Module's tilt angle (absolute value)
+ bool isFlipped; //Is the module flipped ?
+
+ string idNameSpace; //Namespace of this and ALL sub-parts
+ string childName; //Child name
+};
+
+DDTrackerIrregularRingAlgo::DDTrackerIrregularRingAlgo() {
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo info: Creating an instance";
+}
+
+DDTrackerIrregularRingAlgo::~DDTrackerIrregularRingAlgo() = default;
+
+void DDTrackerIrregularRingAlgo::initialize(const DDNumericArguments& nArgs,
+ const DDVectorArguments& vArgs,
+ const DDMapArguments&,
+ const DDStringArguments& sArgs,
+ const DDStringVectorArguments&) {
+ n = int(nArgs["N"]);
+ startCopyNo = int(nArgs["StartCopyNo"]);
+ incrCopyNo = int(nArgs["IncrCopyNo"]);
+ rangeAngle = nArgs["RangeAngle"];
+ startAngle = nArgs["StartAngle"];
+ radius = nArgs["Radius"];
+ center = vArgs["Center"];
+ yawAngles = vArgs["yawAngleValues"];
+ phiAngles = vArgs["phiAngleValues"];
+ radiusValues = vArgs["radiusValues"];
+ isZPlus = bool(nArgs["IsZPlus"]);
+ tiltAngle = nArgs["TiltAngle"];
+ isFlipped = bool(nArgs["IsFlipped"]);
+
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo debug: Parameters for position"
+ << "ing:: n " << n << " Start, Range " << convertRadToDeg(startAngle) << " "
+ << convertRadToDeg(rangeAngle) << " Radius " << radius << " Centre " << center[0] << ", "
+ << center[1] << ", " << center[2];
+
+ idNameSpace = DDCurrentNamespace::ns();
+ childName = sArgs["ChildName"];
+
+ DDName parentName = parent().name();
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo debug: Parent " << parentName << "\tChild " << childName
+ << " NameSpace " << idNameSpace;
+}
+
+void DDTrackerIrregularRingAlgo::execute(DDCompactView& cpv) {
+ DDRotation flipRot, tiltRot, phiOwnAxisRot, phiRot, globalRot; // Identity
+ DDRotationMatrix flipMatrix, tiltMatrix, phiOwnAxisRotMatrix, phiRotMatrix, globalRotMatrix; // Identity matrix
+ string rotstr = "RTrackerRingAlgo";
+
+ // flipMatrix calculus
+ if (isFlipped) {
+ string flipRotstr = rotstr + "Flip";
+ flipRot = DDRotation(DDName(flipRotstr, idNameSpace));
+ if (!flipRot) {
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: " << flipRotstr
+ << "\t90., 180., "
+ << "90., 90., "
+ << "180., 0.";
+ flipRot = DDrot(DDName(flipRotstr, idNameSpace), 90._deg, 180._deg, 90._deg, 90._deg, 180._deg, 0.);
+ }
+ flipMatrix = flipRot.matrix();
+ }
+ // tiltMatrix calculus
+ if (isZPlus) {
+ string tiltRotstr = rotstr + "Tilt" + to_string(convertRadToDeg(tiltAngle)) + "ZPlus";
+ tiltRot = DDRotation(DDName(tiltRotstr, idNameSpace));
+ if (!tiltRot) {
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: " << tiltRotstr
+ << "\t90., 90., " << convertRadToDeg(tiltAngle) << ", 180., "
+ << 90. - convertRadToDeg(tiltAngle) << ", 0.";
+ tiltRot = DDrot(DDName(tiltRotstr, idNameSpace), 90._deg, 90._deg, tiltAngle, 180._deg, 90._deg - tiltAngle, 0.);
+ }
+ tiltMatrix = tiltRot.matrix();
+ if (isFlipped) {
+ tiltMatrix *= flipMatrix;
+ }
+ } else {
+ string tiltRotstr = rotstr + "Tilt" + to_string(convertRadToDeg(tiltAngle)) + "ZMinus";
+ tiltRot = DDRotation(DDName(tiltRotstr, idNameSpace));
+ if (!tiltRot) {
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: " << tiltRotstr
+ << "\t90., 90., " << convertRadToDeg(tiltAngle) << ", 0., "
+ << 90. + convertRadToDeg(tiltAngle) << ", 0.";
+ tiltRot = DDrot(DDName(tiltRotstr, idNameSpace), 90._deg, 90._deg, tiltAngle, 0., 90._deg + tiltAngle, 0.);
+ }
+ tiltMatrix = tiltRot.matrix();
+ if (isFlipped) {
+ tiltMatrix *= flipMatrix;
+ }
+ }
+
+ // Loops for all phi values
+ DDName mother = parent().name();
+ DDName child(DDSplit(childName).first, DDSplit(childName).second);
+ double theta = 90._deg;
+ int copy = startCopyNo;
+ //double phi = startAngle;
+
+ for (int i = 0; i < n; i++) {
+ // phiRotMatrix calculus
+ //double phix = phi;
+ //double phix_ownaxis = 0._deg;
+ double phix = convertDegToRad(phiAngles.at(i));
+ double phix_ownaxis = convertDegToRad(yawAngles.at(i));
+ radius = radiusValues.at(i);
+ double phiy = phix + 90._deg;
+ double phiy_ownaxis = phix_ownaxis + 90._deg;
+ double phideg = convertRadToDeg(phix);
+ double phideg_ownaxis = convertRadToDeg(phix_ownaxis);
+ if (phideg_ownaxis != 0) {
+ string phiOwnAxisRotstr = rotstr + "PhiOwnAxis" + to_string(phideg_ownaxis * 10.);
+ phiOwnAxisRot = DDRotation(DDName(phiOwnAxisRotstr, idNameSpace));
+ if (!phiOwnAxisRot) {
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: " << phiOwnAxisRotstr
+ << "\t90., " << convertRadToDeg(phix_ownaxis) << ", 90.,"
+ << convertRadToDeg(phiy_ownaxis) << ", 0., 0.";
+ phiOwnAxisRot = DDrot(DDName(phiOwnAxisRotstr, idNameSpace), theta, phix_ownaxis, theta, phiy_ownaxis, 0., 0.);
+ }
+ phiOwnAxisRotMatrix = phiOwnAxisRot.matrix();
+ }
+ if (phideg != 0) {
+ string phiRotstr = rotstr + "Phi" + to_string(phideg * 10.);
+ phiRot = DDRotation(DDName(phiRotstr, idNameSpace));
+ if (!phiRot) {
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: " << phiRotstr
+ << "\t90., " << convertRadToDeg(phix) << ", 90.," << convertRadToDeg(phiy)
+ << ", 0., 0.";
+ phiRot = DDrot(DDName(phiRotstr, idNameSpace), theta, phix, theta, phiy, 0., 0.);
+ }
+ phiRotMatrix = phiRot.matrix();
+ }
+
+ // globalRot def
+ string globalRotstr = rotstr + "Phi" + to_string(phideg * 10.) + "Tilt" + to_string(convertRadToDeg(tiltAngle));
+ if (isZPlus) {
+ globalRotstr += "ZPlus";
+ if (isFlipped) {
+ globalRotstr += "Flip";
+ }
+ } else {
+ globalRotstr += "ZMinus";
+ if (isFlipped) {
+ globalRotstr += "Flip";
+ }
+ }
+ globalRot = DDRotation(DDName(globalRotstr, idNameSpace));
+ if (!globalRot) {
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new "
+ << "rotation: " << globalRotstr;
+ globalRotMatrix = phiOwnAxisRotMatrix * phiRotMatrix * tiltMatrix;
+ globalRot = DDrot(DDName(globalRotstr, idNameSpace), make_unique(globalRotMatrix));
+ }
+
+ // translation def
+ double xpos = radius * cos(phix) + center[0];
+ double ypos = radius * sin(phix) + center[1];
+ double zpos = center[2];
+ DDTranslation tran(xpos, ypos, zpos);
+
+ // Positions child with respect to parent
+ cpv.position(child, mother, copy, tran, globalRot);
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo test " << child << " number " << copy << " positioned in "
+ << mother << " at " << tran << " with " << globalRot;
+
+ copy += incrCopyNo;
+ }
+}
+
+DEFINE_EDM_PLUGIN(DDAlgorithmFactory, DDTrackerIrregularRingAlgo, "track:DDTrackerIrregularRingAlgo");
diff --git a/Geometry/TrackerCommonData/plugins/dd4hep/DDTrackerIrregularRingAlgo.cc b/Geometry/TrackerCommonData/plugins/dd4hep/DDTrackerIrregularRingAlgo.cc
new file mode 100644
index 0000000000000..740e049c453ee
--- /dev/null
+++ b/Geometry/TrackerCommonData/plugins/dd4hep/DDTrackerIrregularRingAlgo.cc
@@ -0,0 +1,115 @@
+#include "DD4hep/DetFactoryHelper.h"
+#include "DataFormats/Math/interface/CMSUnits.h"
+#include "DetectorDescription/DDCMS/interface/DDPlugins.h"
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+
+using namespace std;
+using namespace dd4hep;
+using namespace cms;
+using namespace cms_units::operators;
+
+namespace {
+ long algorithm(Detector& /* description */, cms::DDParsingContext& ctxt, xml_h e) {
+ DDNamespace ns(ctxt, e, true);
+ DDAlgoArguments args(ctxt, e);
+ Volume mother = ns.volume(args.parentName());
+ string childName = args.value("ChildName");
+ Volume child = ns.volume(childName);
+
+ string parentName = args.parentName();
+ int n = args.value("N");
+ int startCopyNo = args.value("StartCopyNo");
+ int incrCopyNo = args.value("IncrCopyNo");
+ double rangeAngle = args.value("RangeAngle");
+ double startAngle = args.value("StartAngle");
+ double radius = args.value("Radius");
+ vector center = args.value >("Center");
+ vector phiAngles = args.value >("phiAngleValues");
+ vector radiusValues = args.value >("radiusValues");
+ vector yawAngles = args.value >("yawAngleValues");
+ bool isZPlus = args.value("IsZPlus") == 1;
+ double tiltAngle = args.value("TiltAngle");
+ bool isFlipped = args.value("IsFlipped") == 1;
+
+ edm::LogVerbatim("TrackerGeom") << "DDTrackerIrregularRingAlgo debug: Parameters for position"
+ << "ing:: n " << n << " Start, Range " << convertRadToDeg(startAngle) << " "
+ << convertRadToDeg(rangeAngle) << " Radius " << radius << " Centre " << center[0]
+ << ", " << center[1] << ", " << center[2];
+
+ edm::LogVerbatim("TrackerGeom") << "DDTrackerIrregularRingAlgo debug: Parent " << parentName << "\tChild "
+ << childName << " NameSpace " << ns.name();
+
+ Rotation3D flipMatrix, tiltMatrix, phiRotMatrix, globalRotMatrix, phiOwnAxisRotMatrix; // Identity matrix
+
+ // flipMatrix calculus
+ if (isFlipped) {
+ edm::LogVerbatim("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: "
+ << "\t90., 180., "
+ << "90., 90., "
+ << "180., 0.";
+ flipMatrix = makeRotation3D(90._deg, 180._deg, 90._deg, 90._deg, 180._deg, 0._deg);
+ }
+ // tiltMatrix calculus
+ if (isZPlus) {
+ edm::LogVerbatim("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: "
+ << "\t90., 90., " << convertRadToDeg(tiltAngle) << ", 180., "
+ << convertRadToDeg(90._deg - tiltAngle) << ", 0.";
+ tiltMatrix = makeRotation3D(90._deg, 90._deg, tiltAngle, 180._deg, 90._deg - tiltAngle, 0._deg);
+ if (isFlipped) {
+ tiltMatrix *= flipMatrix;
+ }
+ } else {
+ edm::LogVerbatim("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: "
+ << "\t90., 90., " << convertRadToDeg(tiltAngle) << ", 0., "
+ << convertRadToDeg(90._deg + tiltAngle) << ", 0.";
+ tiltMatrix = makeRotation3D(90._deg, 90._deg, tiltAngle, 0._deg, 90._deg + tiltAngle, 0._deg);
+ if (isFlipped) {
+ tiltMatrix *= flipMatrix;
+ }
+ }
+
+ // Loops for all phi values
+ double theta = 90._deg;
+ int copy = startCopyNo;
+
+ for (int i = 0; i < n; ++i) {
+ // phiRotMatrix calculus
+ double phix = convertDegToRad(phiAngles.at(i));
+ double phix_ownaxis = convertDegToRad(yawAngles.at(i));
+ radius = radiusValues.at(i);
+ double phiy = phix + 90._deg;
+ double phiy_ownaxis = phix_ownaxis + 90._deg;
+ if (phix_ownaxis != 0.) {
+ LogDebug("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: "
+ << "\t90., " << convertRadToDeg(phix_ownaxis) << ", 90.,"
+ << convertRadToDeg(phiy_ownaxis) << ", 0., 0.";
+ phiOwnAxisRotMatrix = makeRotation3D(theta, phix_ownaxis, theta, phiy_ownaxis, 0., 0.);
+ }
+ if (phix != 0.) {
+ edm::LogVerbatim("TrackerGeom") << "DDTrackerIrregularRingAlgo test: Creating a new rotation: "
+ << "\t90., " << convertRadToDeg(phix) << ", 90.," << convertRadToDeg(phiy)
+ << ", 0., 0.";
+ phiRotMatrix = makeRotation3D(theta, phix, theta, phiy, 0., 0.);
+ }
+
+ globalRotMatrix = phiOwnAxisRotMatrix * phiRotMatrix * tiltMatrix;
+
+ // translation def
+ double xpos = radius * cos(phix) + center[0];
+ double ypos = radius * sin(phix) + center[1];
+ double zpos = center[2];
+ Position tran(xpos, ypos, zpos);
+
+ // Positions child with respect to parent
+ mother.placeVolume(child, copy, Transform3D(globalRotMatrix, tran));
+ edm::LogVerbatim("TrackerGeom") << "DDTrackerIrregularRingAlgo test " << child.data()->GetName() << " number "
+ << copy << " positioned in " << mother.data()->GetName() << " at " << tran
+ << " with " << globalRotMatrix;
+
+ copy += incrCopyNo;
+ }
+ return s_executed;
+ }
+} // namespace
+// first argument is the type from the xml file
+DECLARE_DDCMS_DETELEMENT(DDCMS_track_DDTrackerIrregularRingAlgo, ::algorithm)
diff --git a/Geometry/TrackerNumberingBuilder/README.md b/Geometry/TrackerNumberingBuilder/README.md
index a121cad0ac5fe..a913640060c55 100644
--- a/Geometry/TrackerNumberingBuilder/README.md
+++ b/Geometry/TrackerNumberingBuilder/README.md
@@ -8,6 +8,7 @@ The predefined DetId schemas available in this package are:
* The Run 1 (aka _present_) detector DetId schema
* The Phase 1 detector DetId schema where the pixel detector is replaced by the upgraded one
* The Phase 2 upgrade detector DetId schema where both the strip and the pixel detectors are replaced by the upgraded ones - TDR-like
+* The Phase 2 upgrade reordered detector DetId schema, where the strip detector is replaced by the upgraded one (TDR-like), as is the pixel detector. This differs from the full TDR-like Phase2 DetId schema to account for a re-ordering in the pixel endcaps.
In the table below the DetId levels which are in normal font represents _real_ hierarchy levels which are present
also in the `GeometricDet` tree which is build in parallel to the DetId assignment. Those levels which are in _italic_ font are _fake_ levels and are not known by the GeometricDet tree.
@@ -176,6 +177,24 @@ With this subdetector, the flat geometry is compatible using just the central ba
The configuration names for this detid schema are `trackerNumberingGeometry_cfi` (to run on geometry built from xml files) or `trackerNumberingGeometryDB_cfi` (to run on geometry from DB) for `TrackerGeometricDetESModule` and `trackerTopology2023Constants_cfi` for `TrackerTopology`
The xml description of tracker parameters for this detid schema is in [Geometry/TrackerCommonData/data/PhaseII/trackerParameters.xml](../TrackerCommonData/data/PhaseII/trackerParameters.xml
+### Phase 2 Upgrade Detector DetId schema modified to account for the re-ordering of the pixel
+Only the subdetector 2 schema is different wrt the original Phase 2 upgrade DetIdSchema
+
+* Subdetector 2: (`DetId::subDetId() == PixelSubdetector::PixelEndcap`): Phase2 Pixel Forward
+
+| Name | start bit | hex mask | bit size | `TrackerTopology` method | Notes |
+|------|-----------|-----------|----|-----|-----|
+| subdetector part | 23 | 0x3 | 2 | pxfSide(id) or side(id) | 1=FPIX- 2=FPIX+ |
+| DoubleDisk | 19 | 0xF | 4 |pxfDisk(id) or layer(id) | increasing abs(z) |
+| _SubDisk_ | 18 | 0x1 | 1 | | increasing abs(z) |
+| _SingleRing_ | 12 | 0x3F | 6 | pxfBlade(id) | increasing r |
+| Panel | 10 | 0x3 | 2 | pxfPanel(id) | always 1 |
+| Module | 2 | 0xFF | 8 | pxfModule(id) | increasing phi |
+| _not used_ | 0 | 0x3 | 2 | | |
+
+The configuration names for this detid schema are `trackerNumberingGeometry_cfi` (to run on geometry built from xml files) or `trackerNumberingGeometryDB_cfi` (to run on geometry from DB) for `TrackerGeometricDetESModule` and `trackerTopology2023Constants_cfi` for `TrackerTopology`
+The xml description of tracker parameters for this detid schema is in [Geometry/TrackerCommonData/data/PhaseII/TFPXTEPXReordered/trackerParameters.xml](../TrackerCommonData/data/PhaseII/TFPXTEPXReordered/trackerParameters.xml
+
### Subdetector `GeometricDet` Enumerators
diff --git a/Geometry/TrackerNumberingBuilder/interface/GeometricDet.h b/Geometry/TrackerNumberingBuilder/interface/GeometricDet.h
index 4bfa6158506a1..a8f58a46170d5 100644
--- a/Geometry/TrackerNumberingBuilder/interface/GeometricDet.h
+++ b/Geometry/TrackerNumberingBuilder/interface/GeometricDet.h
@@ -77,7 +77,9 @@ class GeometricDet {
OTPhase2Wheel = 209,
PixelPhase2FullDisk = 217,
PixelPhase2ReducedDisk = 227,
- PixelPhase2TDRDisk = 237
+ PixelPhase2TDRDisk = 237,
+ PixelPhase2DoubleDisk = 347,
+ PixelPhase2SubDisk = 357
} GeometricEnumType;
// Constructors from Filtered View (called while looping over DD).
diff --git a/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2DoubleDiskBuilder.cc b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2DoubleDiskBuilder.cc
new file mode 100644
index 0000000000000..a72aef365171b
--- /dev/null
+++ b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2DoubleDiskBuilder.cc
@@ -0,0 +1,47 @@
+#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2DoubleDiskBuilder.h"
+#include "DetectorDescription/Core/interface/DDFilteredView.h"
+#include "DetectorDescription/DDCMS/interface/DDFilteredView.h"
+#include "Geometry/TrackerNumberingBuilder/interface/GeometricDet.h"
+#include "Geometry/TrackerNumberingBuilder/plugins/ExtractStringFromDDD.h"
+#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2SubDiskBuilder.h"
+#include "DataFormats/DetId/interface/DetId.h"
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+#include
+#include
+
+using namespace std;
+
+template
+void CmsTrackerPixelPhase2DoubleDiskBuilder::buildComponent(FilteredView& fv,
+ GeometricDet* g,
+ const std::string& s) {
+ CmsTrackerPixelPhase2SubDiskBuilder theCmsTrackerPixelPhase2SubDiskBuilder;
+ GeometricDet* subdet = new GeometricDet(&fv,
+ CmsTrackerLevelBuilder::theCmsTrackerStringToEnum.type(
+ ExtractStringFromDDD::getString(s, &fv)));
+
+ switch (CmsTrackerLevelBuilder::theCmsTrackerStringToEnum.type(
+ ExtractStringFromDDD::getString(s, &fv))) {
+ case GeometricDet::PixelPhase2SubDisk:
+ theCmsTrackerPixelPhase2SubDiskBuilder.build(fv, subdet, s);
+ break;
+ default:
+ edm::LogError("CmsTrackerPixelPhase2DoubleDiskBuilder")
+ << " ERROR - I was expecting a SubDisk, I got a " << ExtractStringFromDDD::getString(s, &fv);
+ }
+ g->addComponent(subdet);
+}
+
+template
+void CmsTrackerPixelPhase2DoubleDiskBuilder::sortNS(FilteredView& fv, GeometricDet* det) {
+ GeometricDet::ConstGeometricDetContainer& comp = det->components();
+
+ std::sort(comp.begin(), comp.end(), CmsTrackerLevelBuilderHelper::isLessModZ);
+
+ for (uint32_t i = 0; i < comp.size(); i++) {
+ det->component(i)->setGeographicalID(i);
+ }
+}
+
+template class CmsTrackerPixelPhase2DoubleDiskBuilder;
+template class CmsTrackerPixelPhase2DoubleDiskBuilder;
diff --git a/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2DoubleDiskBuilder.h b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2DoubleDiskBuilder.h
new file mode 100644
index 0000000000000..0dbd77f5f3377
--- /dev/null
+++ b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2DoubleDiskBuilder.h
@@ -0,0 +1,18 @@
+#ifndef Geometry_TrackerNumberingBuilder_CmsTrackerPixelPhase2DoubleDiskBuilder_H
+#define Geometry_TrackerNumberingBuilder_CmsTrackerPixelPhase2DoubleDiskBuilder_H
+
+#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerLevelBuilder.h"
+#include "FWCore/ParameterSet/interface/types.h"
+#include
+
+/**
+ * Class which contructs Phase2 Pixel Tracker/Discs.
+ */
+template
+class CmsTrackerPixelPhase2DoubleDiskBuilder : public CmsTrackerLevelBuilder {
+private:
+ void sortNS(FilteredView&, GeometricDet*) override;
+ void buildComponent(FilteredView&, GeometricDet*, const std::string&) override;
+};
+
+#endif
diff --git a/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2EndcapBuilder.cc b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2EndcapBuilder.cc
index a4048eaa41502..cc8d4f03e634a 100644
--- a/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2EndcapBuilder.cc
+++ b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2EndcapBuilder.cc
@@ -4,6 +4,7 @@
#include "DataFormats/DetId/interface/DetId.h"
#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPhase2TPDiskBuilder.h"
#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2DiskBuilder.h"
+#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2DoubleDiskBuilder.h"
#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerOTDiscBuilder.h"
#include "FWCore/MessageLogger/interface/MessageLogger.h"
#include "DetectorDescription/Core/interface/DDFilteredView.h"
@@ -18,6 +19,7 @@ void CmsTrackerPixelPhase2EndcapBuilder::buildComponent(FilteredVi
const std::string& s) {
CmsTrackerPhase2TPDiskBuilder theCmsTrackerPhase2DiskBuilder;
CmsTrackerPixelPhase2DiskBuilder theCmsTrackerPixelPhase2DiskBuilder;
+ CmsTrackerPixelPhase2DoubleDiskBuilder theCmsTrackerPixelPhase2DoubleDiskBuilder;
CmsTrackerOTDiscBuilder theCmsTrackerOTDiscBuilder;
GeometricDet* subdet = new GeometricDet(&fv,
@@ -34,6 +36,9 @@ void CmsTrackerPixelPhase2EndcapBuilder::buildComponent(FilteredVi
case GeometricDet::PixelPhase2TDRDisk:
theCmsTrackerPixelPhase2DiskBuilder.build(fv, subdet, s);
break;
+ case GeometricDet::PixelPhase2DoubleDisk:
+ theCmsTrackerPixelPhase2DoubleDiskBuilder.build(fv, subdet, s);
+ break;
case GeometricDet::OTPhase2Wheel:
theCmsTrackerOTDiscBuilder.build(fv, subdet, s);
break;
diff --git a/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2SubDiskBuilder.cc b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2SubDiskBuilder.cc
new file mode 100644
index 0000000000000..c6d97ffdcc4e1
--- /dev/null
+++ b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2SubDiskBuilder.cc
@@ -0,0 +1,64 @@
+#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2SubDiskBuilder.h"
+#include "DetectorDescription/Core/interface/DDFilteredView.h"
+#include "DetectorDescription/DDCMS/interface/DDFilteredView.h"
+#include "Geometry/TrackerNumberingBuilder/interface/GeometricDet.h"
+#include "Geometry/TrackerNumberingBuilder/plugins/ExtractStringFromDDD.h"
+#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2RingBuilder.h"
+#include "DataFormats/DetId/interface/DetId.h"
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+#include
+#include
+
+using namespace std;
+
+template
+void CmsTrackerPixelPhase2SubDiskBuilder::buildComponent(FilteredView& fv,
+ GeometricDet* g,
+ const std::string& s) {
+ CmsTrackerPixelPhase2RingBuilder theCmsTrackerPixelPhase2RingBuilder;
+ GeometricDet* subdet = new GeometricDet(&fv,
+ CmsTrackerLevelBuilder::theCmsTrackerStringToEnum.type(
+ ExtractStringFromDDD::getString(s, &fv)));
+
+ switch (CmsTrackerLevelBuilder::theCmsTrackerStringToEnum.type(
+ ExtractStringFromDDD::getString(s, &fv))) {
+ case GeometricDet::panel:
+ theCmsTrackerPixelPhase2RingBuilder.build(fv, subdet, s);
+ break;
+ default:
+ edm::LogError("CmsTrackerPixelPhase2SubDiskBuilder")
+ << " ERROR - I was expecting a Panel, I got a " << ExtractStringFromDDD::getString(s, &fv);
+ }
+ g->addComponent(subdet);
+}
+
+template
+void CmsTrackerPixelPhase2SubDiskBuilder::sortNS(FilteredView& fv, GeometricDet* det) {
+ GeometricDet::ConstGeometricDetContainer& comp = det->components();
+
+ switch (det->components().front()->type()) {
+ case GeometricDet::panel:
+ // nothing to be done because the rings (here named panels) are already sorted ??
+ break;
+ default:
+ edm::LogError("CmsTrackerPixelPhase2Builder")
+ << "ERROR - wrong SubDet to sort..... " << det->components().front()->type();
+ }
+
+ GeometricDet::GeometricDetContainer rings;
+ uint32_t totalrings = comp.size();
+
+ for (uint32_t rn = 0; rn < totalrings; rn++) {
+ rings.emplace_back(det->component(rn));
+ uint32_t blade = rn + 1;
+ uint32_t panel = 1;
+ uint32_t temp = (blade << 2) | panel;
+ rings[rn]->setGeographicalID(temp);
+ }
+
+ det->clearComponents();
+ det->addComponents(rings);
+}
+
+template class CmsTrackerPixelPhase2SubDiskBuilder;
+template class CmsTrackerPixelPhase2SubDiskBuilder;
diff --git a/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2SubDiskBuilder.h b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2SubDiskBuilder.h
new file mode 100644
index 0000000000000..7d2040b4cc74f
--- /dev/null
+++ b/Geometry/TrackerNumberingBuilder/plugins/CmsTrackerPixelPhase2SubDiskBuilder.h
@@ -0,0 +1,18 @@
+#ifndef Geometry_TrackerNumberingBuilder_CmsTrackerPixelPhase2SubDiskBuilder_H
+#define Geometry_TrackerNumberingBuilder_CmsTrackerPixelPhase2SubDiskBuilder_H
+
+#include "Geometry/TrackerNumberingBuilder/plugins/CmsTrackerLevelBuilder.h"
+#include "FWCore/ParameterSet/interface/types.h"
+#include
+
+/**
+ * Class which contructs Phase2 Pixel Tracker/Discs.
+ */
+template
+class CmsTrackerPixelPhase2SubDiskBuilder : public CmsTrackerLevelBuilder {
+private:
+ void sortNS(FilteredView&, GeometricDet*) override;
+ void buildComponent(FilteredView&, GeometricDet*, const std::string&) override;
+};
+
+#endif
diff --git a/Geometry/TrackerNumberingBuilder/plugins/TrackerTopologyEP.cc b/Geometry/TrackerNumberingBuilder/plugins/TrackerTopologyEP.cc
index 6bd4aea78a887..c042c51d0d264 100644
--- a/Geometry/TrackerNumberingBuilder/plugins/TrackerTopologyEP.cc
+++ b/Geometry/TrackerNumberingBuilder/plugins/TrackerTopologyEP.cc
@@ -77,16 +77,30 @@ void TrackerTopologyEP::fillParameters(const PTrackerParameters& ptp,
pxbVals.ladderMask_ = ptp.vitems[0].vpars[4]; // 0xFF
pxbVals.moduleMask_ = ptp.vitems[0].vpars[5]; // 0x3F
- pxfVals.sideStartBit_ = ptp.vitems[1].vpars[0];
- pxfVals.diskStartBit_ = ptp.vitems[1].vpars[1];
- pxfVals.bladeStartBit_ = ptp.vitems[1].vpars[2];
- pxfVals.panelStartBit_ = ptp.vitems[1].vpars[3];
- pxfVals.moduleStartBit_ = ptp.vitems[1].vpars[4];
- pxfVals.sideMask_ = ptp.vitems[1].vpars[5];
- pxfVals.diskMask_ = ptp.vitems[1].vpars[6];
- pxfVals.bladeMask_ = ptp.vitems[1].vpars[7];
- pxfVals.panelMask_ = ptp.vitems[1].vpars[8];
- pxfVals.moduleMask_ = ptp.vitems[1].vpars[9];
+ if (ptp.vitems[1].vpars.size() >
+ 11) { //Tracker with subdisk hierarchy level (additional hierarchy level wrt original)
+ pxfVals.sideStartBit_ = ptp.vitems[1].vpars[0];
+ pxfVals.diskStartBit_ = ptp.vitems[1].vpars[1];
+ pxfVals.bladeStartBit_ = ptp.vitems[1].vpars[3];
+ pxfVals.panelStartBit_ = ptp.vitems[1].vpars[4];
+ pxfVals.moduleStartBit_ = ptp.vitems[1].vpars[5];
+ pxfVals.sideMask_ = ptp.vitems[1].vpars[6];
+ pxfVals.diskMask_ = ptp.vitems[1].vpars[7];
+ pxfVals.bladeMask_ = ptp.vitems[1].vpars[9];
+ pxfVals.panelMask_ = ptp.vitems[1].vpars[10];
+ pxfVals.moduleMask_ = ptp.vitems[1].vpars[11];
+ } else { //Original tracker
+ pxfVals.sideStartBit_ = ptp.vitems[1].vpars[0];
+ pxfVals.diskStartBit_ = ptp.vitems[1].vpars[1];
+ pxfVals.bladeStartBit_ = ptp.vitems[1].vpars[2];
+ pxfVals.panelStartBit_ = ptp.vitems[1].vpars[3];
+ pxfVals.moduleStartBit_ = ptp.vitems[1].vpars[4];
+ pxfVals.sideMask_ = ptp.vitems[1].vpars[5];
+ pxfVals.diskMask_ = ptp.vitems[1].vpars[6];
+ pxfVals.bladeMask_ = ptp.vitems[1].vpars[7];
+ pxfVals.panelMask_ = ptp.vitems[1].vpars[8];
+ pxfVals.moduleMask_ = ptp.vitems[1].vpars[9];
+ }
// TEC: 6
tecVals.sideStartBit_ = ptp.vitems[5].vpars[0];
diff --git a/Geometry/TrackerNumberingBuilder/src/CmsTrackerStringToEnum.cc b/Geometry/TrackerNumberingBuilder/src/CmsTrackerStringToEnum.cc
index e4e9a1653885c..4ab5c08965341 100644
--- a/Geometry/TrackerNumberingBuilder/src/CmsTrackerStringToEnum.cc
+++ b/Geometry/TrackerNumberingBuilder/src/CmsTrackerStringToEnum.cc
@@ -41,6 +41,10 @@ CmsTrackerStringToEnum::Impl::Impl() {
GeometricDet::PixelPhase2ReducedDisk));
_map.insert(std::pair("PixelPhase2EndcapTDRDisk",
GeometricDet::PixelPhase2TDRDisk));
+ _map.insert(std::pair("PixelPhase2EndcapDoubleDisk",
+ GeometricDet::PixelPhase2DoubleDisk));
+ _map.insert(std::pair("PixelPhase2EndcapSubDisk",
+ GeometricDet::PixelPhase2SubDisk));
_map.insert(std::pair("Phase2OTEndcap", GeometricDet::OTPhase2EndCap));
_map.insert(
@@ -113,6 +117,9 @@ CmsTrackerStringToEnum::Impl::Impl() {
_reverseMap.insert(
std::pair(GeometricDet::PixelPhase2ReducedDisk, "Disk"));
_reverseMap.insert(std::pair(GeometricDet::PixelPhase2TDRDisk, "Disk"));
+ _reverseMap.insert(
+ std::pair(GeometricDet::PixelPhase2DoubleDisk, "Disk"));
+ _reverseMap.insert(std::pair(GeometricDet::PixelPhase2SubDisk, "Disk"));
_reverseMap.insert(std::pair(GeometricDet::panel, "Panel"));
//
// done
diff --git a/Geometry/TrackerRecoData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/trackerRecoMaterial.xml b/Geometry/TrackerRecoData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/trackerRecoMaterial.xml
new file mode 100644
index 0000000000000..debf08e96b7f5
--- /dev/null
+++ b/Geometry/TrackerRecoData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/trackerRecoMaterial.xml
@@ -0,0 +1,587 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelProdCuts.xml b/Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelProdCuts.xml
new file mode 100644
index 0000000000000..6a32fdb629718
--- /dev/null
+++ b/Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelProdCuts.xml
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelsens.xml b/Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelsens.xml
new file mode 100644
index 0000000000000..6be99c8274233
--- /dev/null
+++ b/Geometry/TrackerSimData/data/PhaseII/Tracker_DD4hep_compatible_OT801_IT640/pixelsens.xml
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/L1Trigger/TrackerDTC/python/ProducerES_cfi.py b/L1Trigger/TrackerDTC/python/ProducerES_cfi.py
index 7aab7c7432d5c..49fc6367ba94a 100644
--- a/L1Trigger/TrackerDTC/python/ProducerES_cfi.py
+++ b/L1Trigger/TrackerDTC/python/ProducerES_cfi.py
@@ -7,7 +7,7 @@
XMLLabel = cms.string ("geomXMLFiles" ), # label of ESProducer/ESSource
XMLPath = cms.string ("Geometry/TrackerCommonData/data/PhaseII/" ), # compared path
XMLFile = cms.string ("tracker.xml" ), # compared filen ame
- XMLVersions = cms.vstring("TiltedTracker613", "TiltedTracker613_MB_2019_04", "OuterTracker616_2020_04", "OuterTracker800_2020_07", "Tracker_DD4hep_compatible_2021_02" ) # list of supported versions
+ XMLVersions = cms.vstring("TiltedTracker613", "TiltedTracker613_MB_2019_04", "OuterTracker616_2020_04", "OuterTracker800_2020_07", "Tracker_DD4hep_compatible_2021_02", "Tracker_DD4hep_compatible_OT801_IT640" ) # list of supported versions
),
# Parameter to check if Process History is consistent with process configuration
diff --git a/RecoTracker/TkDetLayers/src/DetGroupElementZLess.h b/RecoTracker/TkDetLayers/src/DetGroupElementZLess.h
new file mode 100644
index 0000000000000..9ee913b1addb6
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/DetGroupElementZLess.h
@@ -0,0 +1,13 @@
+#ifndef TkDetLayers_DetGroupElementZLess_h
+#define TkDetLayers_DetGroupElementZLess_h
+
+#pragma GCC visibility push(hidden)
+class DetGroupElementZLess {
+public:
+ bool operator()(DetGroup a, DetGroup b) {
+ return (std::abs(a.front().det()->position().z()) < std::abs(b.front().det()->position().z()));
+ }
+};
+
+#pragma GCC visibility pop
+#endif
diff --git a/RecoTracker/TkDetLayers/src/GeometricSearchTrackerBuilder.cc b/RecoTracker/TkDetLayers/src/GeometricSearchTrackerBuilder.cc
index d19f04bc4ab0b..f646e38d2c808 100644
--- a/RecoTracker/TkDetLayers/src/GeometricSearchTrackerBuilder.cc
+++ b/RecoTracker/TkDetLayers/src/GeometricSearchTrackerBuilder.cc
@@ -5,6 +5,7 @@
#include "Phase2OTBarrelLayerBuilder.h"
#include "PixelForwardLayerBuilder.h"
#include "Phase2EndcapLayerBuilder.h"
+#include "Phase2EndcapLayerDoubleDiskBuilder.h"
#include "TIBLayerBuilder.h"
#include "TOBLayerBuilder.h"
#include "TIDLayerBuilder.h"
@@ -25,6 +26,7 @@ GeometricSearchTracker *GeometricSearchTrackerBuilder::build(const GeometricDet
PixelForwardLayerBuilder aPixelForwardLayerBuilder;
PixelForwardLayerBuilder aPhase1PixelForwardLayerBuilder;
Phase2EndcapLayerBuilder aPhase2EndcapLayerBuilder;
+ Phase2EndcapLayerDoubleDiskBuilder aPhase2EndcapLayerDoubleDiskBuilder;
TIBLayerBuilder aTIBLayerBuilder;
TOBLayerBuilder aTOBLayerBuilder;
TIDLayerBuilder aTIDLayerBuilder;
@@ -116,12 +118,17 @@ GeometricSearchTracker *GeometricSearchTrackerBuilder::build(const GeometricDet
theNegPxlFwdLayers.push_back(aPhase1PixelForwardLayerBuilder.build(thisGeomDet, theGeomDetGeometry));
else if (thisGeomDet->type() == GeometricDet::PixelPhase2TDRDisk)
theNegPxlFwdLayers.push_back(aPhase2EndcapLayerBuilder.build(thisGeomDet, theGeomDetGeometry, false));
+ else if (thisGeomDet->type() == GeometricDet::PixelPhase2DoubleDisk)
+ theNegPxlFwdLayers.push_back(aPhase2EndcapLayerDoubleDiskBuilder.build(thisGeomDet, theGeomDetGeometry));
} else if (thisGeomDet->positionBounds().z() > 0) {
if (thisGeomDet->type() == GeometricDet::PixelPhase2FullDisk ||
thisGeomDet->type() == GeometricDet::PixelPhase2ReducedDisk)
thePosPxlFwdLayers.push_back(aPhase1PixelForwardLayerBuilder.build(thisGeomDet, theGeomDetGeometry));
else if (thisGeomDet->type() == GeometricDet::PixelPhase2TDRDisk)
thePosPxlFwdLayers.push_back(aPhase2EndcapLayerBuilder.build(thisGeomDet, theGeomDetGeometry, false));
+ else if (thisGeomDet->type() == GeometricDet::PixelPhase2DoubleDisk)
+ thePosPxlFwdLayers.push_back(aPhase2EndcapLayerDoubleDiskBuilder.build(thisGeomDet, theGeomDetGeometry));
+
} else {
edm::LogError("TkDetLayers") << "In PixelPhase2EndCap the disks are neither PixelPhase2FullDisk nor "
"PixelPhase2ReducedDisk nor PixelPhase2TDRDisk...";
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapLayer.cc b/RecoTracker/TkDetLayers/src/Phase2EndcapLayer.cc
index a8a66d13e7c13..fc93afe7a5437 100644
--- a/RecoTracker/TkDetLayers/src/Phase2EndcapLayer.cc
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapLayer.cc
@@ -10,8 +10,6 @@
#include
#include "DetGroupMerger.h"
-//#include "CommonDet/DetLayout/src/DetLessR.h"
-
using namespace std;
typedef GeometricSearchDet::DetWithState DetWithState;
@@ -34,13 +32,7 @@ const std::vector& Phase2EndcapLayer::components() co
void Phase2EndcapLayer::fillRingPars(int i) {
const BoundDisk& ringDisk = static_cast(theComps[i]->surface());
- float ringMinZ = std::abs(ringDisk.position().z()) - ringDisk.bounds().thickness() / 2.;
- float ringMaxZ = std::abs(ringDisk.position().z()) + ringDisk.bounds().thickness() / 2.;
- RingPar tempPar;
- tempPar.thetaRingMin = ringDisk.innerRadius() / ringMaxZ;
- tempPar.thetaRingMax = ringDisk.outerRadius() / ringMinZ;
- tempPar.theRingR = (ringDisk.innerRadius() + ringDisk.outerRadius()) / 2.;
- ringPars.push_back(tempPar);
+ ringPars.push_back(tkDetUtil::fillRingParametersFromDisk(ringDisk));
}
Phase2EndcapLayer::Phase2EndcapLayer(vector& rings, const bool isOT)
@@ -66,27 +58,7 @@ Phase2EndcapLayer::Phase2EndcapLayer(vector& rings, con
}
BoundDisk* Phase2EndcapLayer::computeDisk(const vector& rings) const {
- float theRmin = rings.front()->specificSurface().innerRadius();
- float theRmax = rings.front()->specificSurface().outerRadius();
- float theZmin = rings.front()->position().z() - rings.front()->surface().bounds().thickness() / 2;
- float theZmax = rings.front()->position().z() + rings.front()->surface().bounds().thickness() / 2;
-
- for (vector::const_iterator i = rings.begin(); i != rings.end(); i++) {
- float rmin = (**i).specificSurface().innerRadius();
- float rmax = (**i).specificSurface().outerRadius();
- float zmin = (**i).position().z() - (**i).surface().bounds().thickness() / 2.;
- float zmax = (**i).position().z() + (**i).surface().bounds().thickness() / 2.;
- theRmin = min(theRmin, rmin);
- theRmax = max(theRmax, rmax);
- theZmin = min(theZmin, zmin);
- theZmax = max(theZmax, zmax);
- }
-
- float zPos = (theZmax + theZmin) / 2.;
- PositionType pos(0., 0., zPos);
- RotationType rot;
-
- return new BoundDisk(pos, rot, new SimpleDiskBounds(theRmin, theRmax, theZmin - zPos, theZmax - zPos));
+ return tkDetUtil::computeDisk(rings);
}
Phase2EndcapLayer::~Phase2EndcapLayer() {
@@ -100,217 +72,18 @@ void Phase2EndcapLayer::groupedCompatibleDetsV(const TrajectoryStateOnSurface& s
const Propagator& prop,
const MeasurementEstimator& est,
std::vector& result) const {
- std::array const& ringIndices = ringIndicesByCrossingProximity(startingState, prop);
- if (ringIndices[0] == -1 || ringIndices[1] == -1 || ringIndices[2] == -1) {
- edm::LogError("TkDetLayers") << "TkRingedForwardLayer::groupedCompatibleDets : error in CrossingProximity";
- return;
- }
-
- //order is: rings in front = 0; rings in back = 1
- //rings should be already ordered in r
- //if the layer has 1 ring, it does not matter
- //FIXME: to be optimized once the geometry is stable
- std::vector ringOrder(theRingSize);
- std::fill(ringOrder.begin(), ringOrder.end(), 1);
- if (theRingSize > 1) {
- if (fabs(theComps[0]->position().z()) < fabs(theComps[1]->position().z())) {
- for (int i = 0; i < theRingSize; i++) {
- if (i % 2 == 0)
- ringOrder[i] = 0;
- }
- } else if (fabs(theComps[0]->position().z()) > fabs(theComps[1]->position().z())) {
- std::fill(ringOrder.begin(), ringOrder.end(), 0);
- for (int i = 0; i < theRingSize; i++) {
- if (i % 2 == 0)
- ringOrder[i] = 1;
- }
- } else {
- throw DetLayerException("Rings in Endcap Layer have same z position, no idea how to order them!");
- }
- }
-
- auto index = [&ringIndices, &ringOrder](int i) { return ringOrder[ringIndices[i]]; };
-
- std::vector closestResult;
- theComps[ringIndices[0]]->groupedCompatibleDetsV(startingState, prop, est, closestResult);
- // if the closest is empty, use the next one and exit: inherited from TID !
- if (closestResult.empty()) {
- theComps[ringIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, result);
- return;
- }
-
- DetGroupElement closestGel(closestResult.front().front());
- float rWindow = computeWindowSize(closestGel.det(), closestGel.trajectoryState(), est);
-
- // check if next ring and next next ring are found and if there is overlap
-
- bool ring1ok = ringIndices[1] != -1 && overlapInR(closestGel.trajectoryState(), ringIndices[1], rWindow);
- bool ring2ok = ringIndices[2] != -1 && overlapInR(closestGel.trajectoryState(), ringIndices[2], rWindow);
-
- // look for the two rings in the same plane (are they only two?)
-
- // determine if we are propagating from in to out (0) or from out to in (1)
-
- int direction = 0;
- if (startingState.globalPosition().z() * startingState.globalMomentum().z() > 0) {
- if (prop.propagationDirection() == alongMomentum)
- direction = 0;
- else
- direction = 1;
- } else {
- if (prop.propagationDirection() == alongMomentum)
- direction = 1;
- else
- direction = 0;
- }
-
- if ((index(0) == index(1)) && (index(0) == index(2))) {
- edm::LogInfo("AllRingsInOnePlane") << " All rings: " << ringIndices[0] << " " << ringIndices[1] << " "
- << ringIndices[2] << " in one plane. Only the first two will be considered";
- ring2ok = false;
- }
-
- if (index(0) == index(1)) {
- if (ring1ok) {
- std::vector ring1res;
- theComps[ringIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, ring1res);
- DetGroupMerger::addSameLevel(std::move(ring1res), closestResult);
- }
- if (ring2ok) {
- std::vector ring2res;
- theComps[ringIndices[2]]->groupedCompatibleDetsV(startingState, prop, est, ring2res);
- DetGroupMerger::orderAndMergeTwoLevels(
- std::move(closestResult), std::move(ring2res), result, index(0), direction);
- return;
- } else {
- result.swap(closestResult);
- return;
- }
- } else if (index(0) == index(2)) {
- if (ring2ok) {
- std::vector ring2res;
- theComps[ringIndices[2]]->groupedCompatibleDetsV(startingState, prop, est, ring2res);
- DetGroupMerger::addSameLevel(std::move(ring2res), closestResult);
- }
- if (ring1ok) {
- std::vector ring1res;
- theComps[ringIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, ring1res);
- DetGroupMerger::orderAndMergeTwoLevels(
- std::move(closestResult), std::move(ring1res), result, index(0), direction);
- return;
- } else {
- result.swap(closestResult);
- return;
- }
- } else {
- std::vector ring12res;
- if (ring1ok) {
- std::vector ring1res;
- theComps[ringIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, ring1res);
- ring12res.swap(ring1res);
- }
- if (ring2ok) {
- std::vector ring2res;
- theComps[ringIndices[2]]->groupedCompatibleDetsV(startingState, prop, est, ring2res);
- DetGroupMerger::addSameLevel(std::move(ring2res), ring12res);
- }
- if (!ring12res.empty()) {
- DetGroupMerger::orderAndMergeTwoLevels(
- std::move(closestResult), std::move(ring12res), result, index(0), direction);
- return;
- } else {
- result.swap(closestResult);
- return;
- }
- }
-}
-
-std::array Phase2EndcapLayer::ringIndicesByCrossingProximity(const TrajectoryStateOnSurface& startingState,
- const Propagator& prop) const {
- typedef HelixForwardPlaneCrossing Crossing;
- typedef MeasurementEstimator::Local2DVector Local2DVector;
-
- HelixPlaneCrossing::PositionType startPos(startingState.globalPosition());
- HelixPlaneCrossing::DirectionType startDir(startingState.globalMomentum());
- PropagationDirection propDir(prop.propagationDirection());
- float rho(startingState.transverseCurvature());
-
- // calculate the crossings with the ring surfaces
- // rings are assumed to be sorted in R !
-
- Crossing myXing(startPos, startDir, rho, propDir);
-
- std::vector ringCrossings;
- ringCrossings.reserve(theRingSize);
- // vector ringXDirections;
-
- for (int i = 0; i < theRingSize; i++) {
- const BoundDisk& theRing = static_cast(theComps[i]->surface());
- pair pathlen = myXing.pathLength(theRing);
- if (pathlen.first) {
- ringCrossings.push_back(GlobalPoint(myXing.position(pathlen.second)));
- // ringXDirections.push_back( GlobalVector( myXing.direction(pathlen.second )));
- } else {
- // TO FIX.... perhaps there is something smarter to do
- //throw DetLayerException("trajectory doesn't cross TID rings");
- ringCrossings.push_back(GlobalPoint(0., 0., 0.));
- // ringXDirections.push_back( GlobalVector( 0.,0.,0.));
- }
- }
-
- //find three closest rings to the crossing
-
- std::array closests = findThreeClosest(ringCrossings);
-
- return closests;
+ tkDetUtil::groupedCompatibleDetsV(startingState, prop, est, result, theRingSize, theComps, ringPars);
}
float Phase2EndcapLayer::computeWindowSize(const GeomDet* det,
const TrajectoryStateOnSurface& tsos,
const MeasurementEstimator& est) const {
- const Plane& startPlane = det->surface();
- MeasurementEstimator::Local2DVector maxDistance = est.maximalLocalDisplacement(tsos, startPlane);
- return maxDistance.y();
-}
-
-std::array Phase2EndcapLayer::findThreeClosest(std::vector ringCrossing) const {
- std::array theBins = {{-1, -1, -1}};
- theBins[0] = 0;
- float initialR = ringPars[0].theRingR;
- float rDiff0 = std::abs(ringCrossing[0].perp() - initialR);
- float rDiff1 = -1.;
- float rDiff2 = -1.;
- for (int i = 1; i < theRingSize; i++) {
- float ringR = ringPars[i].theRingR;
- float testDiff = std::abs(ringCrossing[i].perp() - ringR);
- if (testDiff < rDiff0) {
- rDiff2 = rDiff1;
- rDiff1 = rDiff0;
- rDiff0 = testDiff;
- theBins[2] = theBins[1];
- theBins[1] = theBins[0];
- theBins[0] = i;
- } else if (rDiff1 < 0 || testDiff < rDiff1) {
- rDiff2 = rDiff1;
- rDiff1 = testDiff;
- theBins[2] = theBins[1];
- theBins[1] = i;
- } else if (rDiff2 < 0 || testDiff < rDiff2) {
- rDiff2 = testDiff;
- theBins[2] = i;
- }
- }
-
- return theBins;
+ return tkDetUtil::computeYdirWindowSize(det, tsos, est);
}
-bool Phase2EndcapLayer::overlapInR(const TrajectoryStateOnSurface& tsos, int index, double ymax) const {
- // assume "fixed theta window", i.e. margin in local y = r is changing linearly with z
- float tsRadius = tsos.globalPosition().perp();
- float thetamin = (max(0., tsRadius - ymax)) / (std::abs(tsos.globalPosition().z()) + 10.f); // add 10 cm contingency
- float thetamax = (tsRadius + ymax) / (std::abs(tsos.globalPosition().z()) - 10.f);
-
- // do the theta regions overlap ?
-
- return !(thetamin > ringPars[index].thetaRingMax || ringPars[index].thetaRingMin > thetamax);
+bool Phase2EndcapLayer::overlapInR(const TrajectoryStateOnSurface& tsos,
+ int index,
+ double ymax,
+ std::vector ringParams) const {
+ return tkDetUtil::overlapInR(tsos, index, ymax, ringParams);
}
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapLayer.h b/RecoTracker/TkDetLayers/src/Phase2EndcapLayer.h
index 1cacb0f846d08..1ff1b490d3338 100644
--- a/RecoTracker/TkDetLayers/src/Phase2EndcapLayer.h
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapLayer.h
@@ -3,6 +3,7 @@
#include "TrackingTools/DetLayers/interface/RingedForwardLayer.h"
#include "Phase2EndcapRing.h"
+#include "TkDetUtil.h"
#include
#include
@@ -44,15 +45,10 @@ class Phase2EndcapLayer final : public RingedForwardLayer {
// private methods for the implementation of groupedCompatibleDets()
BoundDisk* computeDisk(const std::vector& rings) const __attribute__((cold));
- std::array ringIndicesByCrossingProximity(const TrajectoryStateOnSurface& startingState,
- const Propagator& prop) const;
-
- // bool isCompatible( const TrajectoryStateOnSurface& ms,
- // const MeasurementEstimator& est) const;
-
- std::array findThreeClosest(std::vector) const __attribute__((hot));
-
- bool overlapInR(const TrajectoryStateOnSurface& tsos, int i, double ymax) const __attribute__((hot));
+ bool overlapInR(const TrajectoryStateOnSurface& tsos,
+ int i,
+ double ymax,
+ std::vector ringParams) const __attribute__((hot));
float computeWindowSize(const GeomDet* det,
const TrajectoryStateOnSurface& tsos,
@@ -65,10 +61,7 @@ class Phase2EndcapLayer final : public RingedForwardLayer {
const bool isOuterTracker;
mutable std::atomic*> theComponents;
std::vector theComps;
- struct RingPar {
- float theRingR, thetaRingMin, thetaRingMax;
- };
- std::vector ringPars;
+ std::vector ringPars;
int theRingSize;
};
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDisk.cc b/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDisk.cc
new file mode 100644
index 0000000000000..36f6b54dcc9ca
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDisk.cc
@@ -0,0 +1,190 @@
+#include "Phase2EndcapLayerDoubleDisk.h"
+
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+
+#include "DataFormats/GeometrySurface/interface/SimpleDiskBounds.h"
+
+#include "TrackingTools/DetLayers/interface/DetLayerException.h"
+#include "TrackingTools/GeomPropagators/interface/HelixForwardPlaneCrossing.h"
+
+#include
+#include "DetGroupMerger.h"
+
+using namespace std;
+
+const std::vector& Phase2EndcapLayerDoubleDisk::components() const {
+ throw cms::Exception("Phase2EndcapLayerDoubleDisk::components() is not implemented");
+}
+
+void Phase2EndcapLayerDoubleDisk::fillSubDiskPars(int i) {
+ const BoundDisk& subDiskDisk = static_cast(theComps[i]->surface());
+ SubDiskPar tempPar;
+ tempPar.theSubDiskZ = std::abs(subDiskDisk.position().z());
+ subDiskPars.push_back(tempPar);
+}
+
+Phase2EndcapLayerDoubleDisk::Phase2EndcapLayerDoubleDisk(vector& subDisks)
+ : RingedForwardLayer(true), theComponents{nullptr} {
+ theSubDisksSize = subDisks.size();
+ LogDebug("TkDetLayers") << "Number of subdisks in Phase2 IT EC layer is " << theSubDisksSize << std::endl;
+ setSurface(computeDisk(subDisks));
+
+ for (unsigned int i = 0; i != subDisks.size(); ++i) {
+ theComps.push_back(subDisks[i]);
+ fillSubDiskPars(i);
+ theBasicComps.insert(
+ theBasicComps.end(), (*subDisks[i]).basicComponents().begin(), (*subDisks[i]).basicComponents().end());
+ }
+
+ LogDebug("TkDetLayers") << "==== DEBUG Phase2EndcapLayer =====";
+ LogDebug("TkDetLayers") << "r,zed pos , thickness, innerR, outerR: " << this->position().perp() << " , "
+ << this->position().z() << " , " << this->specificSurface().bounds().thickness() << " , "
+ << this->specificSurface().innerRadius() << " , " << this->specificSurface().outerRadius();
+}
+
+BoundDisk* Phase2EndcapLayerDoubleDisk::computeDisk(const vector& subDisks) const {
+ return tkDetUtil::computeDisk(subDisks);
+}
+
+Phase2EndcapLayerDoubleDisk::~Phase2EndcapLayerDoubleDisk() {
+ for (auto c : theComps)
+ delete c;
+
+ delete theComponents.load();
+}
+
+void Phase2EndcapLayerDoubleDisk::groupedCompatibleDetsV(const TrajectoryStateOnSurface& startingState,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ std::vector& result) const {
+ std::array const& subDiskIndices = subDiskIndicesByCrossingProximity(startingState, prop);
+
+ //order subdisks in z
+ //Subdisk near in z: 0, Subdisk far in z: 1
+ std::vector subDiskOrder(theSubDisksSize);
+ std::fill(subDiskOrder.begin(), subDiskOrder.end(), 1);
+ if (theSubDisksSize > 1) {
+ if (std::abs(theComps[0]->position().z()) < std::abs(theComps[1]->position().z())) {
+ for (int i = 0; i < theSubDisksSize; i++) {
+ if (i % 2 == 0)
+ subDiskOrder[i] = 0;
+ }
+ } else if (std::abs(theComps[0]->position().z()) > std::abs(theComps[1]->position().z())) {
+ std::fill(subDiskOrder.begin(), subDiskOrder.end(), 0);
+ for (int i = 0; i < theSubDisksSize; i++) {
+ if (i % 2 == 0)
+ subDiskOrder[i] = 1;
+ }
+ } else {
+ throw DetLayerException("SubDisks in Endcap Layer have same z position, no idea how to order them!");
+ }
+ }
+
+ auto index = [&subDiskIndices, &subDiskOrder](int i) { return subDiskOrder[subDiskIndices[i]]; };
+
+ std::vector closestResult;
+ theComps[subDiskIndices[0]]->groupedCompatibleDetsV(startingState, prop, est, closestResult);
+ // if the closest is empty, use the next one and exit: inherited from TID !
+ if (closestResult.empty()) {
+ theComps[subDiskIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, result);
+ return;
+ }
+
+ // check if next subdisk is found
+
+ bool subdisk1ok = subDiskIndices[1] != -1;
+
+ // determine if we are propagating from in to out (0) or from out to in (1)
+
+ int direction = 0;
+ if (startingState.globalPosition().z() * startingState.globalMomentum().z() > 0) {
+ if (prop.propagationDirection() == alongMomentum)
+ direction = 0;
+ else
+ direction = 1;
+ } else {
+ if (prop.propagationDirection() == alongMomentum)
+ direction = 1;
+ else
+ direction = 0;
+ }
+
+ if (index(0) == index(1)) {
+ if (subdisk1ok) {
+ std::vector subdisk1res;
+ theComps[subDiskIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, subdisk1res);
+ DetGroupMerger::addSameLevel(std::move(subdisk1res), closestResult);
+ result.swap(closestResult);
+ return;
+ }
+ } else {
+ std::vector subdisk1res;
+ if (subdisk1ok) {
+ theComps[subDiskIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, subdisk1res);
+ }
+ if (!subdisk1res.empty()) {
+ DetGroupMerger::orderAndMergeTwoLevels(
+ std::move(closestResult), std::move(subdisk1res), result, index(0), direction);
+ return;
+ } else {
+ result.swap(closestResult);
+ return;
+ }
+ }
+}
+
+std::array Phase2EndcapLayerDoubleDisk::subDiskIndicesByCrossingProximity(
+ const TrajectoryStateOnSurface& startingState, const Propagator& prop) const {
+ typedef HelixForwardPlaneCrossing Crossing;
+ typedef MeasurementEstimator::Local2DVector Local2DVector;
+
+ HelixPlaneCrossing::PositionType startPos(startingState.globalPosition());
+ HelixPlaneCrossing::DirectionType startDir(startingState.globalMomentum());
+ PropagationDirection propDir(prop.propagationDirection());
+ float rho(startingState.transverseCurvature());
+
+ // calculate the crossings with the subdisk surfaces
+
+ Crossing myXing(startPos, startDir, rho, propDir);
+
+ std::vector subDiskCrossings;
+ subDiskCrossings.reserve(theSubDisksSize);
+
+ for (int i = 0; i < theSubDisksSize; i++) {
+ const BoundDisk& theSubDisk = static_cast(theComps[i]->surface());
+ pair pathlen = myXing.pathLength(theSubDisk);
+ if (pathlen.first) {
+ subDiskCrossings.push_back(GlobalPoint(myXing.position(pathlen.second)));
+ } else {
+ // TO FIX.... perhaps there is something smarter to do
+ subDiskCrossings.push_back(GlobalPoint(0., 0., 0.));
+ }
+ }
+
+ //find two closest subdisks to the crossing
+
+ return findTwoClosest(subDiskCrossings);
+}
+
+std::array Phase2EndcapLayerDoubleDisk::findTwoClosest(std::vector subDiskCrossing) const {
+ std::array theBins = {{-1, -1}};
+ theBins[0] = 0;
+ float initialZ = subDiskPars[0].theSubDiskZ;
+ float zDiff0 = std::abs(subDiskCrossing[0].z() - initialZ);
+ float zDiff1 = -1.;
+ for (int i = 1; i < theSubDisksSize; i++) {
+ float subDiskZ = subDiskPars[i].theSubDiskZ;
+ float testDiff = std::abs(subDiskCrossing[i].z() - subDiskZ);
+ if (testDiff < zDiff0) {
+ zDiff1 = zDiff0;
+ zDiff0 = testDiff;
+ theBins[1] = theBins[0];
+ theBins[0] = i;
+ } else if (zDiff1 < 0 || testDiff < zDiff1) {
+ zDiff1 = testDiff;
+ theBins[1] = i;
+ }
+ }
+
+ return theBins;
+}
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDisk.h b/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDisk.h
new file mode 100644
index 0000000000000..2f92e9957f72c
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDisk.h
@@ -0,0 +1,60 @@
+#ifndef TkDetLayers_Phase2EndcapLayerDoubleDisk_h
+#define TkDetLayers_Phase2EndcapLayerDoubleDisk_h
+
+#include "TrackingTools/DetLayers/interface/RingedForwardLayer.h"
+#include "Phase2EndcapSubDisk.h"
+#include
+#include
+
+/** A concrete implementation for Phase 2 Endcap/Forward layer
+ * built out of Phase2EndcapRings
+ */
+
+#pragma GCC visibility push(hidden)
+class Phase2EndcapLayerDoubleDisk final : public RingedForwardLayer {
+public:
+ Phase2EndcapLayerDoubleDisk(std::vector& subDisks);
+ ~Phase2EndcapLayerDoubleDisk() override;
+
+ // Default implementations would not properly manage memory
+ Phase2EndcapLayerDoubleDisk(const Phase2EndcapLayerDoubleDisk&) = delete;
+ Phase2EndcapLayerDoubleDisk& operator=(const Phase2EndcapLayerDoubleDisk&) = delete;
+
+ // GeometricSearchDet interface
+
+ const std::vector& basicComponents() const override { return theBasicComps; }
+
+ const std::vector& components() const override;
+
+ void groupedCompatibleDetsV(const TrajectoryStateOnSurface& tsos,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ std::vector& result) const override;
+
+ // DetLayer interface
+ SubDetector subDetector() const override { return GeomDetEnumerators::subDetGeom[GeomDetEnumerators::P2PXEC]; }
+
+private:
+ // private methods for the implementation of groupedCompatibleDets()
+ BoundDisk* computeDisk(const std::vector& subDisks) const;
+
+ std::array subDiskIndicesByCrossingProximity(const TrajectoryStateOnSurface& startingState,
+ const Propagator& prop) const;
+
+ std::array findTwoClosest(std::vector) const;
+
+ void fillSubDiskPars(int i);
+
+private:
+ std::vector theBasicComps;
+ mutable std::atomic*> theComponents;
+ std::vector theComps;
+ struct SubDiskPar {
+ float theSubDiskZ;
+ };
+ std::vector subDiskPars;
+ int theSubDisksSize;
+};
+
+#pragma GCC visibility pop
+#endif
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDiskBuilder.cc b/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDiskBuilder.cc
new file mode 100644
index 0000000000000..49c02ae2a7e73
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDiskBuilder.cc
@@ -0,0 +1,22 @@
+#include "Phase2EndcapLayerDoubleDiskBuilder.h"
+#include "Phase2EndcapSubDiskBuilder.h"
+
+using namespace edm;
+using namespace std;
+
+Phase2EndcapLayerDoubleDisk* Phase2EndcapLayerDoubleDiskBuilder::build(const GeometricDet* aPhase2EndcapLayerDoubleDisk,
+ const TrackerGeometry* theGeomDetGeometry) {
+ LogTrace("TkDetLayers") << "Phase2EndcapLayerDoubleDiskBuilder::build";
+ const auto& theSubDisks = aPhase2EndcapLayerDoubleDisk->components();
+ LogTrace("TkDetLayers") << "theSubDisks.size(): " << theSubDisks.size();
+
+ Phase2EndcapSubDiskBuilder myBuilder;
+ vector thePhase2EndcapSubDisks;
+ thePhase2EndcapSubDisks.reserve(theSubDisks.size());
+
+ for (vector::const_iterator it = theSubDisks.begin(); it != theSubDisks.end(); it++) {
+ thePhase2EndcapSubDisks.push_back(myBuilder.build(*it, theGeomDetGeometry));
+ }
+
+ return new Phase2EndcapLayerDoubleDisk(thePhase2EndcapSubDisks);
+}
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDiskBuilder.h b/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDiskBuilder.h
new file mode 100644
index 0000000000000..c60bd5b64e483
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapLayerDoubleDiskBuilder.h
@@ -0,0 +1,22 @@
+#ifndef TkDetLayerDoubleDisks_Phase2EndcapLayerDoubleDiskBuilder_h
+#define TkDetLayerDoubleDisks_Phase2EndcapLayerDoubleDiskBuilder_h
+
+#include "Phase2EndcapLayerDoubleDisk.h"
+
+#include "FWCore/Framework/interface/ESHandle.h"
+#include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h"
+#include "Geometry/TrackerNumberingBuilder/interface/GeometricDet.h"
+
+/** A concrete builder for Phase2EndcapLayerDoubleDisk
+ */
+
+#pragma GCC visibility push(hidden)
+class Phase2EndcapLayerDoubleDiskBuilder {
+public:
+ Phase2EndcapLayerDoubleDiskBuilder(){};
+ Phase2EndcapLayerDoubleDisk* build(const GeometricDet* aPhase2EndcapLayerDoubleDisk,
+ const TrackerGeometry* theGeomDetGeometry) __attribute__((cold));
+};
+
+#pragma GCC visibility pop
+#endif
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapRing.cc b/RecoTracker/TkDetLayers/src/Phase2EndcapRing.cc
index 4ad8c52833160..0b55fae0b325b 100644
--- a/RecoTracker/TkDetLayers/src/Phase2EndcapRing.cc
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapRing.cc
@@ -15,17 +15,12 @@
#include "TkDetUtil.h"
#include "DataFormats/GeometryVector/interface/VectorUtil.h"
+#include "DetGroupElementZLess.h"
+
using namespace std;
typedef GeometricSearchDet::DetWithState DetWithState;
-class DetGroupElementZLess {
-public:
- bool operator()(DetGroup a, DetGroup b) {
- return (fabs(a.front().det()->position().z()) < fabs(b.front().det()->position().z()));
- }
-};
-
Phase2EndcapRing::Phase2EndcapRing(vector& innerDets,
vector& outerDets,
const vector& innerDetBrothers,
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRing.cc b/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRing.cc
new file mode 100644
index 0000000000000..a6e913d71b50e
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRing.cc
@@ -0,0 +1,155 @@
+#include "Phase2EndcapSingleRing.h"
+
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+
+#include "TrackingTools/DetLayers/interface/DetLayerException.h"
+#include "TrackingTools/DetLayers/interface/MeasurementEstimator.h"
+#include "TrackingTools/GeomPropagators/interface/HelixForwardPlaneCrossing.h"
+#include "TrackingTools/DetLayers/interface/rangesIntersect.h"
+#include "TrackingTools/DetLayers/interface/ForwardRingDiskBuilderFromDet.h"
+
+#include "LayerCrossingSide.h"
+#include "DetGroupMerger.h"
+#include "CompatibleDetToGroupAdder.h"
+
+#include "TkDetUtil.h"
+#include "DataFormats/GeometryVector/interface/VectorUtil.h"
+
+#include "DetGroupElementZLess.h"
+
+using namespace std;
+
+typedef GeometricSearchDet::DetWithState DetWithState;
+
+Phase2EndcapSingleRing::Phase2EndcapSingleRing(vector& allDets)
+ : GeometricSearchDet(true), theDets(allDets.begin(), allDets.end()) {
+ theDisk = ForwardRingDiskBuilderFromDet()(theDets);
+
+ theBinFinder = BinFinderType(theDets.front()->surface().position().phi(), theDets.size());
+
+#ifdef EDM_ML_DEBUG
+ LogDebug("TkDetLayers") << "DEBUG INFO for Phase2EndcapSingleRing";
+ for (vector::const_iterator it = theDets.begin(); it != theDets.end(); it++) {
+ LogDebug("TkDetLayers") << "Det detId,phi,z,r: " << (*it)->geographicalId().rawId() << " , "
+ << (*it)->surface().position().phi() << " , " << (*it)->surface().position().z() << " , "
+ << (*it)->surface().position().perp();
+ }
+
+#endif
+}
+
+Phase2EndcapSingleRing::~Phase2EndcapSingleRing() = default;
+
+const vector& Phase2EndcapSingleRing::components() const {
+ throw DetLayerException("Phase2EndcapSingleRing doesn't have GeometricSearchDet components");
+}
+
+pair Phase2EndcapSingleRing::compatible(const TrajectoryStateOnSurface&,
+ const Propagator&,
+ const MeasurementEstimator&) const {
+ edm::LogError("TkDetLayers") << "temporary dummy implementation of Phase2EndcapSingleRing::compatible()!!";
+ return pair();
+}
+
+void Phase2EndcapSingleRing::groupedCompatibleDetsV(const TrajectoryStateOnSurface& tsos,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ std::vector& result) const {
+ SubLayerCrossing crossing;
+
+ crossing = computeCrossing(tsos, prop.propagationDirection());
+
+ if (!crossing.isValid())
+ return;
+
+ std::vector closestResult;
+
+ addClosest(tsos, prop, est, crossing, closestResult);
+ if (closestResult.empty())
+ return;
+
+ DetGroupElement closestGel(closestResult.front().front());
+
+ float phiWindow = tkDetUtil::computeWindowSize(closestGel.det(), closestGel.trajectoryState(), est);
+
+ searchNeighbors(tsos, prop, est, crossing, phiWindow, closestResult, false);
+
+ DetGroupMerger::addSameLevel(std::move(closestResult), result);
+}
+
+SubLayerCrossing Phase2EndcapSingleRing::computeCrossing(const TrajectoryStateOnSurface& startingState,
+ PropagationDirection propDir) const {
+ auto rho = startingState.transverseCurvature();
+
+ HelixPlaneCrossing::PositionType startPos(startingState.globalPosition());
+ HelixPlaneCrossing::DirectionType startDir(startingState.globalMomentum());
+ HelixForwardPlaneCrossing crossing(startPos, startDir, rho, propDir);
+
+ pair frontPath = crossing.pathLength(*theDisk);
+ if (!frontPath.first)
+ return SubLayerCrossing();
+
+ GlobalPoint gFrontPoint(crossing.position(frontPath.second)); //There is only one path
+
+ int frontIndex = theBinFinder.binIndex(gFrontPoint.barePhi());
+ SubLayerCrossing frontSLC(0, frontIndex, gFrontPoint);
+
+ return frontSLC;
+}
+
+bool Phase2EndcapSingleRing::addClosest(const TrajectoryStateOnSurface& tsos,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ const SubLayerCrossing& crossing,
+ vector& result) const {
+ const vector& sub(subLayer(crossing.subLayerIndex()));
+
+ const GeomDet* det(sub[crossing.closestDetIndex()]);
+
+ bool firstgroup = CompatibleDetToGroupAdder::add(*det, tsos, prop, est, result);
+
+ return firstgroup;
+}
+
+void Phase2EndcapSingleRing::searchNeighbors(const TrajectoryStateOnSurface& tsos,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ const SubLayerCrossing& crossing,
+ float window,
+ vector& result,
+ bool checkClosest) const {
+ const GlobalPoint& gCrossingPos = crossing.position();
+
+ const vector& sLayer(subLayer(crossing.subLayerIndex()));
+
+ int closestIndex = crossing.closestDetIndex();
+ int negStartIndex = closestIndex - 1;
+ int posStartIndex = closestIndex + 1;
+
+ if (checkClosest) { // must decide if the closest is on the neg or pos side
+ if (Geom::phiLess(gCrossingPos.barePhi(), sLayer[closestIndex]->surface().phi())) {
+ posStartIndex = closestIndex;
+ } else {
+ negStartIndex = closestIndex;
+ }
+ }
+
+ const BinFinderType& binFinder = theBinFinder;
+
+ typedef CompatibleDetToGroupAdder Adder;
+ int half = sLayer.size() / 2; // to check if dets are called twice....
+ for (int idet = negStartIndex; idet >= negStartIndex - half; idet--) {
+ const GeomDet& neighborDet = *sLayer[binFinder.binIndex(idet)];
+ if (!tkDetUtil::overlapInPhi(gCrossingPos, neighborDet, window))
+ break;
+ if (!Adder::add(neighborDet, tsos, prop, est, result))
+ break;
+ }
+ for (int idet = posStartIndex; idet < posStartIndex + half; idet++) {
+ const GeomDet& neighborDet = *sLayer[binFinder.binIndex(idet)];
+ if (!tkDetUtil::overlapInPhi(gCrossingPos, neighborDet, window))
+ break;
+ if (!Adder::add(neighborDet, tsos, prop, est, result))
+ break;
+ }
+}
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRing.h b/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRing.h
new file mode 100644
index 0000000000000..2f00a63909161
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRing.h
@@ -0,0 +1,69 @@
+#ifndef TkDetLayers_Phase2EndcapSingleRing_h
+#define TkDetLayers_Phase2EndcapSingleRing_h
+
+#include "TrackingTools/DetLayers/interface/GeometricSearchDet.h"
+#include "Utilities/BinningTools/interface/PeriodicBinFinderInPhi.h"
+#include "SubLayerCrossings.h"
+#include "DataFormats/GeometrySurface/interface/BoundDisk.h"
+
+/** A concrete implementation for Phase2 SubDisk rings
+ */
+
+#pragma GCC visibility push(hidden)
+class Phase2EndcapSingleRing final : public GeometricSearchDet {
+public:
+ Phase2EndcapSingleRing(std::vector& allDets);
+ ~Phase2EndcapSingleRing() override;
+
+ // GeometricSearchDet interface
+ const BoundSurface& surface() const override { return *theDisk; }
+
+ const std::vector& basicComponents() const override { return theDets; }
+
+ const std::vector& components() const override;
+
+ std::pair compatible(const TrajectoryStateOnSurface&,
+ const Propagator&,
+ const MeasurementEstimator&) const override;
+
+ void groupedCompatibleDetsV(const TrajectoryStateOnSurface& tsos,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ std::vector& result) const override;
+
+ //Extension of interface
+ virtual const BoundDisk& specificSurface() const { return *theDisk; }
+
+private:
+ // private methods for the implementation of groupedCompatibleDets()
+
+ SubLayerCrossing computeCrossing(const TrajectoryStateOnSurface& tsos, PropagationDirection propDir) const;
+
+ bool addClosest(const TrajectoryStateOnSurface& tsos,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ const SubLayerCrossing& crossing,
+ std::vector& result) const;
+
+ void searchNeighbors(const TrajectoryStateOnSurface& tsos,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ const SubLayerCrossing& crossing,
+ float window,
+ std::vector& result,
+ bool checkClosest) const;
+
+ const std::vector& subLayer(int ind) const { return theDets; }
+
+private:
+ std::vector theDets;
+
+ ReferenceCountingPointer theDisk;
+
+ typedef PeriodicBinFinderInPhi BinFinderType;
+
+ BinFinderType theBinFinder;
+};
+
+#pragma GCC visibility pop
+#endif
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRingBuilder.cc b/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRingBuilder.cc
new file mode 100644
index 0000000000000..75292555254f8
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRingBuilder.cc
@@ -0,0 +1,24 @@
+#include "Phase2EndcapSingleRingBuilder.h"
+#include "TrackingTools/DetLayers/interface/DetLayerException.h"
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+
+using namespace edm;
+using namespace std;
+
+Phase2EndcapSingleRing* Phase2EndcapSingleRingBuilder::build(const GeometricDet* aPhase2EndcapSingleRing,
+ const TrackerGeometry* theGeomDetGeometry) {
+ vector allGeometricDets = aPhase2EndcapSingleRing->components();
+ vector compGeometricDets;
+ vector allDets;
+
+ for (vector::const_iterator compGeometricDets = allGeometricDets.begin();
+ compGeometricDets != allGeometricDets.end();
+ compGeometricDets++) {
+ const GeomDet* theGeomDet = theGeomDetGeometry->idToDet((*compGeometricDets)->geographicalId());
+ allDets.push_back(theGeomDet);
+ }
+
+ LogDebug("TkDetLayers") << "Phase2EndcapSingleRingBuilder with #Modules: " << allGeometricDets.size() << std::endl;
+
+ return new Phase2EndcapSingleRing(allDets);
+}
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRingBuilder.h b/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRingBuilder.h
new file mode 100644
index 0000000000000..9c6357da7ed91
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapSingleRingBuilder.h
@@ -0,0 +1,22 @@
+#ifndef TkDetLayers_Phase2EndcapSingleRingBuilder_h
+#define TkDetLayers_Phase2EndcapSingleRingBuilder_h
+
+#include "Phase2EndcapSingleRing.h"
+
+#include "FWCore/Framework/interface/ESHandle.h"
+#include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h"
+#include "Geometry/TrackerNumberingBuilder/interface/GeometricDet.h"
+
+/** A concrete builder for Phase2EndcapSingleRing
+ */
+
+#pragma GCC visibility push(hidden)
+class Phase2EndcapSingleRingBuilder {
+public:
+ Phase2EndcapSingleRingBuilder(){};
+ Phase2EndcapSingleRing* build(const GeometricDet* aPhase2EndcapSingleRing, const TrackerGeometry* theGeomDetGeometry)
+ __attribute__((cold));
+};
+
+#pragma GCC visibility pop
+#endif
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapSubDisk.cc b/RecoTracker/TkDetLayers/src/Phase2EndcapSubDisk.cc
new file mode 100644
index 0000000000000..f3bbf560bc13f
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapSubDisk.cc
@@ -0,0 +1,73 @@
+#include "Phase2EndcapSubDisk.h"
+
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+
+#include "DataFormats/GeometrySurface/interface/SimpleDiskBounds.h"
+
+#include "TrackingTools/DetLayers/interface/DetLayerException.h"
+#include "TrackingTools/GeomPropagators/interface/HelixForwardPlaneCrossing.h"
+
+#include
+#include "DetGroupMerger.h"
+
+using namespace std;
+
+const std::vector& Phase2EndcapSubDisk::components() const {
+ throw cms::Exception("Phase2EndcapSubDisk::components() is not implemented");
+}
+
+void Phase2EndcapSubDisk::fillRingPars(int i) {
+ const BoundDisk& ringDisk = static_cast(theComps[i]->surface());
+ ringPars.push_back(tkDetUtil::fillRingParametersFromDisk(ringDisk));
+}
+
+Phase2EndcapSubDisk::Phase2EndcapSubDisk(vector& rings)
+ : RingedForwardLayer(true), theComponents{nullptr} {
+ theRingSize = rings.size();
+ LogDebug("TkDetLayers") << "Number of rings in Phase2EndcapSubDisk is " << theRingSize << std::endl;
+ setSurface(computeDisk(rings));
+
+ for (unsigned int i = 0; i != rings.size(); ++i) {
+ theComps.push_back(rings[i]);
+ fillRingPars(i);
+ theBasicComps.insert(
+ theBasicComps.end(), (*rings[i]).basicComponents().begin(), (*rings[i]).basicComponents().end());
+ }
+
+ LogDebug("TkDetLayers") << "==== DEBUG Phase2EndcapSubDisk =====";
+ LogDebug("TkDetLayers") << "r,zed pos , thickness, innerR, outerR: " << this->position().perp() << " , "
+ << this->position().z() << " , " << this->specificSurface().bounds().thickness() << " , "
+ << this->specificSurface().innerRadius() << " , " << this->specificSurface().outerRadius();
+}
+
+BoundDisk* Phase2EndcapSubDisk::computeDisk(const vector& rings) const {
+ return tkDetUtil::computeDisk(rings);
+}
+
+Phase2EndcapSubDisk::~Phase2EndcapSubDisk() {
+ for (auto c : theComps)
+ delete c;
+
+ delete theComponents.load();
+}
+
+void Phase2EndcapSubDisk::groupedCompatibleDetsV(const TrajectoryStateOnSurface& startingState,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ std::vector& result) const {
+ tkDetUtil::groupedCompatibleDetsV(startingState, prop, est, result, theRingSize, theComps, ringPars);
+ return;
+}
+
+float Phase2EndcapSubDisk::computeWindowSize(const GeomDet* det,
+ const TrajectoryStateOnSurface& tsos,
+ const MeasurementEstimator& est) const {
+ return tkDetUtil::computeYdirWindowSize(det, tsos, est);
+}
+
+bool Phase2EndcapSubDisk::overlapInR(const TrajectoryStateOnSurface& tsos,
+ int index,
+ double ymax,
+ std::vector ringParams) const {
+ return tkDetUtil::overlapInR(tsos, index, ymax, ringParams);
+}
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapSubDisk.h b/RecoTracker/TkDetLayers/src/Phase2EndcapSubDisk.h
new file mode 100644
index 0000000000000..07c4f5edb13f3
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapSubDisk.h
@@ -0,0 +1,62 @@
+#ifndef TkDetLayers_Phase2EndcapSubDisk_h
+#define TkDetLayers_Phase2EndcapSubDisk_h
+
+#include "TrackingTools/DetLayers/interface/RingedForwardLayer.h"
+#include "Phase2EndcapSingleRing.h"
+#include "TkDetUtil.h"
+#include
+#include
+
+/** A concrete implementation for Phase 2 Endcap/Forward layer
+ * built out of Phase2EndcapSingleRings
+ * this class is used for the inner tracker
+ */
+
+#pragma GCC visibility push(hidden)
+class Phase2EndcapSubDisk final : public RingedForwardLayer {
+public:
+ Phase2EndcapSubDisk(std::vector& rings);
+ ~Phase2EndcapSubDisk() override;
+
+ // Default implementations would not properly manage memory
+ Phase2EndcapSubDisk(const Phase2EndcapSubDisk&) = delete;
+ Phase2EndcapSubDisk& operator=(const Phase2EndcapSubDisk&) = delete;
+
+ // GeometricSearchDet interface
+
+ const std::vector& basicComponents() const override { return theBasicComps; }
+
+ const std::vector& components() const override;
+
+ void groupedCompatibleDetsV(const TrajectoryStateOnSurface& tsos,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ std::vector& result) const override;
+
+ // DetLayer interface
+ SubDetector subDetector() const override { return GeomDetEnumerators::subDetGeom[GeomDetEnumerators::P2PXEC]; }
+
+private:
+ // private methods for the implementation of groupedCompatibleDets()
+ BoundDisk* computeDisk(const std::vector& rings) const;
+
+ bool overlapInR(const TrajectoryStateOnSurface& tsos,
+ int i,
+ double ymax,
+ std::vector ringParams) const;
+
+ float computeWindowSize(const GeomDet* det,
+ const TrajectoryStateOnSurface& tsos,
+ const MeasurementEstimator& est) const;
+
+ void fillRingPars(int i);
+
+ std::vector theBasicComps;
+ mutable std::atomic*> theComponents;
+ std::vector theComps;
+ std::vector ringPars;
+ int theRingSize;
+};
+
+#pragma GCC visibility pop
+#endif
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapSubDiskBuilder.cc b/RecoTracker/TkDetLayers/src/Phase2EndcapSubDiskBuilder.cc
new file mode 100644
index 0000000000000..1e8449fc3d298
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapSubDiskBuilder.cc
@@ -0,0 +1,24 @@
+#include "Phase2EndcapSubDiskBuilder.h"
+#include "Phase2EndcapSingleRingBuilder.h"
+
+using namespace edm;
+using namespace std;
+
+Phase2EndcapSubDisk* Phase2EndcapSubDiskBuilder::build(const GeometricDet* aPhase2EndcapSubDisk,
+ const TrackerGeometry* theGeomDetGeometry) {
+ LogTrace("TkDetLayers") << "Phase2EndcapSubDiskBuilder::build";
+ vector theGeometricRings = aPhase2EndcapSubDisk->components();
+ LogTrace("TkDetLayers") << "theGeometricRings.size(): " << theGeometricRings.size();
+
+ Phase2EndcapSingleRingBuilder myBuilder;
+ vector thePhase2EndcapSingleRings;
+
+ for (vector::const_iterator it = theGeometricRings.begin(); it != theGeometricRings.end();
+ it++) {
+ // if we are in the phaseII OT, it will use the brothers to build pt modules
+ // if we are in the phaseII pixel detector, it will not
+ thePhase2EndcapSingleRings.push_back(myBuilder.build(*it, theGeomDetGeometry));
+ }
+
+ return new Phase2EndcapSubDisk(thePhase2EndcapSingleRings);
+}
diff --git a/RecoTracker/TkDetLayers/src/Phase2EndcapSubDiskBuilder.h b/RecoTracker/TkDetLayers/src/Phase2EndcapSubDiskBuilder.h
new file mode 100644
index 0000000000000..4de35541d7879
--- /dev/null
+++ b/RecoTracker/TkDetLayers/src/Phase2EndcapSubDiskBuilder.h
@@ -0,0 +1,22 @@
+#ifndef TkDetLayers_Phase2EndcapSubDiskBuilder_h
+#define TkDetLayers_Phase2EndcapSubDiskBuilder_h
+
+#include "Phase2EndcapSubDisk.h"
+
+#include "FWCore/Framework/interface/ESHandle.h"
+#include "Geometry/TrackerGeometryBuilder/interface/TrackerGeometry.h"
+#include "Geometry/TrackerNumberingBuilder/interface/GeometricDet.h"
+
+/** A concrete builder for Phase2EndcapSubDisk
+ */
+
+#pragma GCC visibility push(hidden)
+class Phase2EndcapSubDiskBuilder {
+public:
+ Phase2EndcapSubDiskBuilder(){};
+ Phase2EndcapSubDisk* build(const GeometricDet* aPhase2EndcapSubDisk, const TrackerGeometry* theGeomDetGeometry)
+ __attribute__((cold));
+};
+
+#pragma GCC visibility pop
+#endif
diff --git a/RecoTracker/TkDetLayers/src/SubLayerCrossings.h b/RecoTracker/TkDetLayers/src/SubLayerCrossings.h
index 93ef80c23c1c6..db24cd635e09b 100644
--- a/RecoTracker/TkDetLayers/src/SubLayerCrossings.h
+++ b/RecoTracker/TkDetLayers/src/SubLayerCrossings.h
@@ -6,9 +6,11 @@
#pragma GCC visibility push(hidden)
class SubLayerCrossing {
public:
- SubLayerCrossing() {}
- SubLayerCrossing(int sli, int cdi, const GlobalPoint& pos) : pos_(pos), subLayerIndex_(sli), closestDetIndex_(cdi) {}
+ SubLayerCrossing() : isValid_(false) {}
+ SubLayerCrossing(int sli, int cdi, const GlobalPoint& pos)
+ : pos_(pos), subLayerIndex_(sli), closestDetIndex_(cdi), isValid_(true) {}
+ bool isValid() { return isValid_; }
int subLayerIndex() const { return subLayerIndex_; }
int closestDetIndex() const { return closestDetIndex_; }
const GlobalPoint& position() const { return pos_; }
@@ -17,6 +19,7 @@ class SubLayerCrossing {
GlobalPoint pos_;
int subLayerIndex_;
int closestDetIndex_;
+ bool isValid_;
};
class SubLayerCrossings {
diff --git a/RecoTracker/TkDetLayers/src/TkDetUtil.cc b/RecoTracker/TkDetLayers/src/TkDetUtil.cc
index aa3a5654c965d..c100fa8fc42fa 100644
--- a/RecoTracker/TkDetLayers/src/TkDetUtil.cc
+++ b/RecoTracker/TkDetLayers/src/TkDetUtil.cc
@@ -68,4 +68,67 @@ namespace tkDetUtil {
return phiWindow;
}
+ float computeYdirWindowSize(const GeomDet* det,
+ const TrajectoryStateOnSurface& tsos,
+ const MeasurementEstimator& est) {
+ const Plane& startPlane = det->surface();
+ MeasurementEstimator::Local2DVector maxDistance = est.maximalLocalDisplacement(tsos, startPlane);
+ return maxDistance.y();
+ }
+
+ std::array findThreeClosest(const std::vector& ringParams,
+ const std::vector& ringCrossing,
+ const int ringSize) {
+ std::array theBins = {{-1, -1, -1}};
+ theBins[0] = 0;
+ float initialR = ringParams[0].theRingR;
+ float rDiff0 = std::abs(ringCrossing[0].perp() - initialR);
+ float rDiff1 = -1.;
+ float rDiff2 = -1.;
+ for (int i = 1; i < ringSize; i++) {
+ float ringR = ringParams[i].theRingR;
+ float testDiff = std::abs(ringCrossing[i].perp() - ringR);
+ if (testDiff < rDiff0) {
+ rDiff2 = rDiff1;
+ rDiff1 = rDiff0;
+ rDiff0 = testDiff;
+ theBins[2] = theBins[1];
+ theBins[1] = theBins[0];
+ theBins[0] = i;
+ } else if (rDiff1 < 0 || testDiff < rDiff1) {
+ rDiff2 = rDiff1;
+ rDiff1 = testDiff;
+ theBins[2] = theBins[1];
+ theBins[1] = i;
+ } else if (rDiff2 < 0 || testDiff < rDiff2) {
+ rDiff2 = testDiff;
+ theBins[2] = i;
+ }
+ }
+
+ return theBins;
+ }
+
+ bool overlapInR(const TrajectoryStateOnSurface& tsos, int index, double ymax, const std::vector& ringParams) {
+ // assume "fixed theta window", i.e. margin in local y = r is changing linearly with z
+ float tsRadius = tsos.globalPosition().perp();
+ float thetamin =
+ (std::max(0., tsRadius - ymax)) / (std::abs(tsos.globalPosition().z()) + 10.f); // add 10 cm contingency
+ float thetamax = (tsRadius + ymax) / (std::abs(tsos.globalPosition().z()) - 10.f);
+
+ // do the theta regions overlap ?
+
+ return !(thetamin > ringParams[index].thetaRingMax || ringParams[index].thetaRingMin > thetamax);
+ }
+
+ RingPar fillRingParametersFromDisk(const BoundDisk& ringDisk) {
+ float ringMinZ = std::abs(ringDisk.position().z()) - ringDisk.bounds().thickness() / 2.;
+ float ringMaxZ = std::abs(ringDisk.position().z()) + ringDisk.bounds().thickness() / 2.;
+ RingPar tempPar;
+ tempPar.thetaRingMin = ringDisk.innerRadius() / ringMaxZ;
+ tempPar.thetaRingMax = ringDisk.outerRadius() / ringMinZ;
+ tempPar.theRingR = (ringDisk.innerRadius() + ringDisk.outerRadius()) / 2.;
+ return tempPar;
+ }
+
} // namespace tkDetUtil
diff --git a/RecoTracker/TkDetLayers/src/TkDetUtil.h b/RecoTracker/TkDetLayers/src/TkDetUtil.h
index 5b48c79a49e47..52747296547db 100644
--- a/RecoTracker/TkDetLayers/src/TkDetUtil.h
+++ b/RecoTracker/TkDetLayers/src/TkDetUtil.h
@@ -6,6 +6,16 @@
#include "DataFormats/GeometryVector/interface/GlobalPoint.h"
#include "TrackingTools/DetLayers/interface/rangesIntersect.h"
#include "DataFormats/GeometryVector/interface/VectorUtil.h"
+#include "DataFormats/GeometrySurface/interface/BoundDisk.h"
+#include "TrackingTools/DetLayers/interface/RingedForwardLayer.h"
+#include "DataFormats/GeometrySurface/interface/SimpleDiskBounds.h"
+#include "TrackingTools/DetLayers/interface/DetLayerException.h"
+
+#include "TrackingTools/GeomPropagators/interface/HelixForwardPlaneCrossing.h"
+
+#include "DataFormats/GeometrySurface/interface/SimpleDiskBounds.h"
+
+#include "DetGroupMerger.h"
class GeomDet;
class Plane;
@@ -15,6 +25,10 @@ class TrajectoryStateOnSurface;
namespace tkDetUtil {
+ struct RingPar {
+ float theRingR, thetaRingMin, thetaRingMax;
+ };
+
inline bool overlapInPhi(float phi, const GeomDet& det, float phiWindow) {
std::pair phiRange(phi - phiWindow, phi + phiWindow);
return rangesIntersect(phiRange, det.surface().phiSpan(), [](auto x, auto y) { return Geom::phiLess(x, y); });
@@ -30,6 +44,219 @@ namespace tkDetUtil {
const TrajectoryStateOnSurface& ts,
const Plane& plane);
+ float computeYdirWindowSize(const GeomDet* det,
+ const TrajectoryStateOnSurface& tsos,
+ const MeasurementEstimator& est);
+
+ std::array findThreeClosest(const std::vector& ringParams,
+ const std::vector& ringCrossing,
+ const int ringSize);
+
+ bool overlapInR(const TrajectoryStateOnSurface& tsos, int index, double ymax, const std::vector& ringParams);
+
+ RingPar fillRingParametersFromDisk(const BoundDisk& ringDisk);
+
+ template
+ std::array ringIndicesByCrossingProximity(const TrajectoryStateOnSurface& startingState,
+ const Propagator& prop,
+ const int ringSize,
+ const T& diskComponents,
+ const std::vector& ringParams) {
+ typedef HelixForwardPlaneCrossing Crossing;
+ typedef MeasurementEstimator::Local2DVector Local2DVector;
+
+ HelixPlaneCrossing::PositionType startPos(startingState.globalPosition());
+ HelixPlaneCrossing::DirectionType startDir(startingState.globalMomentum());
+ PropagationDirection propDir(prop.propagationDirection());
+ float rho(startingState.transverseCurvature());
+
+ // calculate the crossings with the ring surfaces
+ // rings are assumed to be sorted in R !
+
+ Crossing myXing(startPos, startDir, rho, propDir);
+
+ std::vector ringCrossings;
+ ringCrossings.reserve(ringSize);
+
+ for (int i = 0; i < ringSize; i++) {
+ const BoundDisk& theRing = static_cast(diskComponents[i]->surface());
+ std::pair pathlen = myXing.pathLength(theRing);
+ if (pathlen.first) {
+ ringCrossings.push_back(GlobalPoint(myXing.position(pathlen.second)));
+ } else {
+ // TO FIX.... perhaps there is something smarter to do
+ ringCrossings.push_back(GlobalPoint(0., 0., 0.));
+ }
+ }
+
+ //find three closest rings to the crossing
+
+ std::array closests = findThreeClosest(ringParams, ringCrossings, ringSize);
+
+ return closests;
+ }
+
+ template
+ void groupedCompatibleDetsV(const TrajectoryStateOnSurface& startingState,
+ const Propagator& prop,
+ const MeasurementEstimator& est,
+ std::vector& result,
+ const int ringSize,
+ const std::vector& diskComponents,
+ const std::vector& ringParams) {
+ std::array const& ringIndices =
+ ringIndicesByCrossingProximity(startingState, prop, ringSize, diskComponents, ringParams);
+ if (ringIndices[0] == -1 || ringIndices[1] == -1 || ringIndices[2] == -1) {
+ edm::LogError("TkDetLayers") << "TkRingedForwardLayer::groupedCompatibleDets : error in CrossingProximity";
+ return;
+ }
+
+ //order is: rings in front = 0; rings in back = 1
+ //rings should be already ordered in r
+ //if the layer has 1 ring, it does not matter
+ //FIXME: to be optimized once the geometry is stable
+ std::vector ringOrder(ringSize);
+ std::fill(ringOrder.begin(), ringOrder.end(), 1);
+ if (ringSize > 1) {
+ if (std::abs(diskComponents[0]->position().z()) < std::abs(diskComponents[1]->position().z())) {
+ for (int i = 0; i < ringSize; i++) {
+ if (i % 2 == 0)
+ ringOrder[i] = 0;
+ }
+ } else if (std::abs(diskComponents[0]->position().z()) > std::abs(diskComponents[1]->position().z())) {
+ std::fill(ringOrder.begin(), ringOrder.end(), 0);
+ for (int i = 0; i < ringSize; i++) {
+ if (i % 2 == 0)
+ ringOrder[i] = 1;
+ }
+ } else {
+ throw DetLayerException("Rings in Endcap Layer have same z position, no idea how to order them!");
+ }
+ }
+
+ auto index = [&ringIndices, &ringOrder](int i) { return ringOrder[ringIndices[i]]; };
+
+ std::vector closestResult;
+ diskComponents[ringIndices[0]]->groupedCompatibleDetsV(startingState, prop, est, closestResult);
+ // if the closest is empty, use the next one and exit: inherited from TID !
+ if (closestResult.empty()) {
+ diskComponents[ringIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, result);
+ return;
+ }
+
+ DetGroupElement closestGel(closestResult.front().front());
+ float rWindow = computeYdirWindowSize(closestGel.det(), closestGel.trajectoryState(), est);
+
+ // check if next ring and next next ring are found and if there is overlap
+
+ bool ring1ok =
+ ringIndices[1] != -1 && overlapInR(closestGel.trajectoryState(), ringIndices[1], rWindow, ringParams);
+ bool ring2ok =
+ ringIndices[2] != -1 && overlapInR(closestGel.trajectoryState(), ringIndices[2], rWindow, ringParams);
+
+ // look for the two rings in the same plane (are they only two?)
+
+ // determine if we are propagating from in to out (0) or from out to in (1)
+
+ int direction = 0;
+ if (startingState.globalPosition().z() * startingState.globalMomentum().z() > 0) {
+ if (prop.propagationDirection() == alongMomentum)
+ direction = 0;
+ else
+ direction = 1;
+ } else {
+ if (prop.propagationDirection() == alongMomentum)
+ direction = 1;
+ else
+ direction = 0;
+ }
+
+ if ((index(0) == index(1)) && (index(0) == index(2))) {
+ edm::LogInfo("AllRingsInOnePlane") << " All rings: " << ringIndices[0] << " " << ringIndices[1] << " "
+ << ringIndices[2] << " in one plane. Only the first two will be considered";
+ ring2ok = false;
+ }
+
+ if (index(0) == index(1)) {
+ if (ring1ok) {
+ std::vector ring1res;
+ diskComponents[ringIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, ring1res);
+ DetGroupMerger::addSameLevel(std::move(ring1res), closestResult);
+ }
+ if (ring2ok) {
+ std::vector ring2res;
+ diskComponents[ringIndices[2]]->groupedCompatibleDetsV(startingState, prop, est, ring2res);
+ DetGroupMerger::orderAndMergeTwoLevels(
+ std::move(closestResult), std::move(ring2res), result, index(0), direction);
+ return;
+ } else {
+ result.swap(closestResult);
+ return;
+ }
+ } else if (index(0) == index(2)) {
+ if (ring2ok) {
+ std::vector ring2res;
+ diskComponents[ringIndices[2]]->groupedCompatibleDetsV(startingState, prop, est, ring2res);
+ DetGroupMerger::addSameLevel(std::move(ring2res), closestResult);
+ }
+ if (ring1ok) {
+ std::vector ring1res;
+ diskComponents[ringIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, ring1res);
+ DetGroupMerger::orderAndMergeTwoLevels(
+ std::move(closestResult), std::move(ring1res), result, index(0), direction);
+ return;
+ } else {
+ result.swap(closestResult);
+ return;
+ }
+ } else {
+ std::vector ring12res;
+ if (ring1ok) {
+ std::vector ring1res;
+ diskComponents[ringIndices[1]]->groupedCompatibleDetsV(startingState, prop, est, ring1res);
+ ring12res.swap(ring1res);
+ }
+ if (ring2ok) {
+ std::vector ring2res;
+ diskComponents[ringIndices[2]]->groupedCompatibleDetsV(startingState, prop, est, ring2res);
+ DetGroupMerger::addSameLevel(std::move(ring2res), ring12res);
+ }
+ if (!ring12res.empty()) {
+ DetGroupMerger::orderAndMergeTwoLevels(
+ std::move(closestResult), std::move(ring12res), result, index(0), direction);
+ return;
+ } else {
+ result.swap(closestResult);
+ return;
+ }
+ }
+ }
+
+ template
+ BoundDisk* computeDisk(const std::vector& structures) {
+ float theRmin = structures.front()->specificSurface().innerRadius();
+ float theRmax = structures.front()->specificSurface().outerRadius();
+ float theZmin = structures.front()->position().z() - structures.front()->surface().bounds().thickness() / 2;
+ float theZmax = structures.front()->position().z() + structures.front()->surface().bounds().thickness() / 2;
+
+ for (typename std::vector::const_iterator i = structures.begin(); i != structures.end(); i++) {
+ float rmin = (**i).specificSurface().innerRadius();
+ float rmax = (**i).specificSurface().outerRadius();
+ float zmin = (**i).position().z() - (**i).surface().bounds().thickness() / 2.;
+ float zmax = (**i).position().z() + (**i).surface().bounds().thickness() / 2.;
+ theRmin = std::min(theRmin, rmin);
+ theRmax = std::max(theRmax, rmax);
+ theZmin = std::min(theZmin, zmin);
+ theZmax = std::max(theZmax, zmax);
+ }
+
+ float zPos = (theZmax + theZmin) / 2.;
+ Plane::PositionType pos(0., 0., zPos);
+ Plane::RotationType rot;
+
+ return new BoundDisk(pos, rot, new SimpleDiskBounds(theRmin, theRmax, theZmin - zPos, theZmax - zPos));
+ }
+
} // namespace tkDetUtil
#pragma GCC visibility pop