Releases: acts-project/acts
Releases · acts-project/acts
v39.1.0
39.1.0
🚀 Features
- Detray material collection (#4065) by @asalzburger
- Make layer envelope configurable in Gen1 geometry building (#4067) by @benjaminhuth
- Introduce G4Trap converter (#4072) by @asalzburger
- Allow propagator initialization to fail (#4036) by @andiwand
🐛 Bug Fixes
- Remove unused SubspaceTests (#4063) by @paulgessinger
- GeoModel recording again (#4066) by @asalzburger
- Centre from confex face in Annulus (#4071) by @paulgessinger
- Missing thread sync in CUDA connected components (#4080) by @benjaminhuth
- Require CUDA_STANDARD 20 in Plugins/Cuda (#4084) by @wdconinc
🚜 Refactor
- Remove redundant logical in covariance helper (#4033) by @AJPfleger
- Simplify track selection logic in AlignmentAlgorithm (#3934) by @AJPfleger
- Disentangle stepper state creation and initialization (#4069) by @andiwand
- Clean navigator state creation (#4070) by @andiwand
- Add back DD4hep field access (#4073) by @paulgessinger
- Delete non-compile tests (#4076) by @paulgessinger
- Decouple stepping from navigation (#4039) by @andiwand
ProtoLayer
can (optionally) hold mutable surfaces (#4030) by @paulgessinger
📚 Documentation
🧪 Testing
- Python test fixes: GSF + EDM4hep (#4088) by @paulgessinger
🛠️ Build
- Add cmake helper function for header compilation (#4083) by @paulgessinger
- Use CONFIG mode for onnxruntime (#4086) by @paulgessinger
⚙️ Miscellaneous Tasks
- Fix clang-tidy config file format (#4062) by @paulgessinger
- Pre-commit check for type_t uses
--fix
(#4082) by @paulgessinger - Readability-redundant-smartptr-get (#4064) by @paulgessinger
- Update particle data script (#4081) by @paulgessinger
v39.0.0
39.0.0
🚀 Features
- Support negative tolerance for euclidean + chi2 tests (#4000) by @paulgessinger
- 🚨 BREAKING: Allow trimming other non measurement track states (#3993) by @andiwand
- Adding extra bit to measurment writer (#4007) by @asalzburger
- Add support for CUDA streams in GNN plugin (#4012) by @benjaminhuth
- Add buffered reader (#4018) by @benjaminhuth
- Add CUDA connected components & track building (#4015) by @benjaminhuth
- Allow multiple aliases for one whiteboard entry in Examples (#4035) by @andiwand
- Plane surface merging (#4037) by @ssdetlab
- Introducing common ProtoAxis concept (#4034) by @asalzburger
- 🚨 BREAKING: Updates to GBTS for Athena Implementation (#3882) by @Rosie-Hasan
- Adding json conversion and unit test for
ProtoAxis
(#4045) by @asalzburger - Adding cuboid volume stack (#4040) by @ssdetlab
- Adding planar portal link (#4044) by @ssdetlab
- Acts::Extent python binding improved (#4050) by @asalzburger
- Allow tracksummary plots on detector subparts (#4058) by @benjaminhuth
- Add TensorRT support for GNNs (#4016) by @benjaminhuth
- Add chi2 cut option for outliers to KF fitter function (#4059) by @benjaminhuth
🐛 Bug Fixes
- User-defined literal operator syntax (to make clang20 happy) (#3992) by @flg
- Optimize EDM4hep particle reading (#3978) by @paulgessinger
- Missing parameter of particle selector in python bindings (#4010) by @benjaminhuth
- Some blocker reported sonar-cloud issues (#4009) by @asalzburger
- 🚨 BREAKING: Make BinUtility constructor explicit (#3953) by @paulgessinger
- Use forced approach for
MultiStepperSurfaceReached
(#4025) by @andiwand - Reset component state in
MultiEigenStepperLoop
overMultiStepperSurfaceReached
(#4027) by @andiwand - Add portal visualization to
TrackingVolume
(#4029) by @paulgessinger - Off-by-one error in WhiteBoard levenshtein implementation (#4032) by @paulgessinger
- Fix enum conversion error in Podio plugin (#4041) by @stephenswat
- Fix initialization bug for direct navigator backward mode (#4051) by @benjaminhuth
- ScoreBasedAmbiguityResolution to avoid very high score. (#4052) by @Ragansu
- Sequencer run with 0 threads or 0 events (#4053) by @paulgessinger
- Write correct tracks to file for refitting, prevent FPE (#3999) by @benjaminhuth
- EDM4hepReader sets number of hits on particles (#4056) by @paulgessinger
◀️ Revert
- "ci: Use CERN registry cache in GitLab CI" (#4022) by @paulgessinger
🚜 Refactor
- Add new concepts for Eigen types (#3966) by @stephenswat
- 🚨 BREAKING: Remove
MagneticFieldProvider::getFieldGradient
(#3983) by @andiwand - 🚨 BREAKING: Revise stepper state creation (#3987) by @andiwand
- 🚨 BREAKING: Revise stepper update functions and constrained step types (#3986) by @andiwand
- Remove cugraph, refactor GNN plugin cmake (#4014) by @benjaminhuth
- 🚨 BREAKING: Decouple navigation and stepping (#3449) by @andiwand
- 🚨 BREAKING: Strongly typed enum for
ConstrainedStep::Type
and capital initial letter (#4013) by @andiwand - 🚨 BREAKING: Make Direction constructor explicit (#3973) by @paulgessinger
- 🚨 BREAKING: Explicit BoundaryTolerance constructors (#3974) by @paulgessinger
- Split particle selection in Examples (#3969) by @andiwand
- 🚨 BREAKING: Move source link creation, track state creation, measurement selection into a single unit outside of the CKF (#3825) by @goetzgaycken
- 🚨 BREAKING: Move GBTS to experimental namespace (#4048) by @Rosie-Hasan
- Add hits range property to
ParticleSelector
(#4057) by @paulgessinger - Cleanup and logging improvements in fitting algorithms (#4060) by @benjaminhuth
🧪 Testing
- Bounds regression tests (#4001) by @paulgessinger
- Add tests for return values from
IAxis::visit
(#4006) by @paulgessinger
🛠️ Build
- Only install python files for enabled components (#4004) by @paulgessinger
- CMake find directives, policy grouping (#4026) by @paulgessinger
- 🚨 BREAKING: Make third-party libraries system dependencies (#3949) by @stephenswat
⚙️ Miscellaneous Tasks
- Newline after
#pragma once
(#3997) by @andiwand - Make use of algebra shorthands (#3998) by @andiwand
- Cleanup some surface code (#3991) by @andiwand
- Use correct keys for the gitlab caches (#4008) by @paulgessinger
- Use CERN registry cache in GitLab CI (#4019) by @paulgessinger
- 🚨 BREAKING: Rename BinningValue to AxisDirection (#4005) by @asalzburger
- Use CERN registry cache in GitLab CI - round 2 (#4023) by @paulgessinger
- Run unit test + downstream on main ubuntu build (gitlab) (#4020) by @paulgessinger
v38.2.0
38.2.0
🚀 Features
- Add monadic functions to
Result
(#3957) by @stephenswat - Make TransformRange fulfill range concept (#3971) by @paulgessinger
- Gen3 blueprint geometry construction (#3869) by @paulgessinger
🐛 Bug Fixes
- Distinguish between hits and measurements in
ParticleSelector
in Examples (#3947) by @andiwand - Typo in variable in vertex muon scan script (#3959) by @AJPfleger
- Checkout branch in ExaTrk CI (#3967) by @stephenswat
- Workaround Pythia8 race condition in ttbar physmon (#3965) by @andiwand
- Typo in json digitization config (#3960) by @AJPfleger
- Ensure correct order of uniform distribution limits (#3976) by @benjaminhuth
- Update full_chain_test.py to follow full_chain_odd.py (#3956) by @timadye
- Update full_chain_odd_LRT.py to follow full_chain_odd.py (#3977) by @delitez
🚜 Refactor
- Remove
SurfaceSortingAlgorithm
from Examples (#3952) by @andiwand - Rework detector handling in Examples (#3498) by @andiwand
- Combine GSF actor and aborter (#3984) by @andiwand
- (fatras) Remove nuclear interaction (#3935) by @AJPfleger
⚙️ Miscellaneous Tasks
- Lint updates (#3958) by @paulgessinger
- Reenable some ExaTrkX tests (#3395) by @benjaminhuth
- Sonar fixes after detector refactor (#3968) by @paulgessinger
- Clean event generator includes in Examples (#3964) by @andiwand
- Enable standard library assertions in debug builds (#3759) by @benjaminhuth
- Update .gitignore (#3979) by @paulgessinger
- Some magnetic field code cleanup (#3982) by @andiwand
- Clean codespell ignore list (#3961) by @AJPfleger
- Adjust target limit after reset in Core CKF (#3985) by @andiwand
v38.1.0
38.1.0
🚀 Features
- Compatibility for EDM4hep <
0.99
& >=0.99
(#3921) by @paulgessinger - Adding G4 stepping (#3812) by @asalzburger
- Introduction obj simhit writer (#3180) by @asalzburger
- Add a multi-region constant B-field provider (#3927) by @stephenswat
- Safe inverse for dynamic matrices (#3945) by @AJPfleger
- Move spline to helper in Visualization (#3950) by @asalzburger
- TGeo python binding (#3885) by @asalzburger
🐛 Bug Fixes
- Remove
final
on template derived classes (#3923) by @paulgessinger - Explicitly disable paging in pre-commit hook (#3928) by @stephenswat
- Add hit count in root dump reader (#3929) by @benjaminhuth
- Remove BoundCylinderToZPhi final, add exception (#3926) by @paulgessinger
- Test and fix broken
TrackHelpers
for chi2 and unbiased track state (#3937) by @andiwand - Consistent
std::int32_t
in AdaptiveGridTrackDensity (#3933) by @AJPfleger - OneAPI 2025 Fixes, main branch (2024.12.04.) (#3938) by @krasznaa
- Remove narrowing conversion from
std::size_t
toint
(#3932) by @AJPfleger
🚜 Refactor
- Modernise map utils (#3615) by @AJPfleger
- Replace
long unsigned int
withstd::size_t
(#3930) by @AJPfleger - Brace-enclosed initializers for pair/tuple returns (#3931) by @AJPfleger
- Create particle/simhit to measurement maps in
DigitizationAlgorithm
in Examples (#3944) by @andiwand - Move MLAmbiguitySolver to Core (#3272) by @Corentin-Allaire
- (gx2f) Put parts into separate compile units (#3946) by @AJPfleger
📚 Documentation
- Update zenodo record (#3940) by @CarloVarni
- Change to 6x6 track parameter covariance to include time (#3941) by @andiwand
⚙️ Miscellaneous Tasks
- Add LCG 106a job (#3918) by @paulgessinger
- Clean up a few includes and imports (#3925) by @jmcarcell
v38.0.0
38.0.0
🚀 Features
- Add a benchmark executable for Track EDM (#3834) by @paulgessinger
- Add optional context type getter (#3853) by @paulgessinger
- (geo) Add Gen3 hierarchy search to
lowestTrackingVolume
(#3818) by @paulgessinger - Free parameter estimation from seed (#3832) by @andiwand
- Full_chain_test.py config with command-line options (#3811) by @timadye
- Track parameters lookup estimation examples (#3823) by @ssdetlab
- (util) Add
overloaded
helper (#3816) by @paulgessinger - Add statistics to propagation (#3450) by @andiwand
- Update GNN plugin (#3876) by @benjaminhuth
- Use RootTracksummaryWriter without truth information (#3886) by @benjaminhuth
- Helpers to calculate residuals, chi2 and unbiased states (#3877) by @andiwand
- Allow copy of measurements in Examples (#3911) by @andiwand
- Add JSON detector element (#3851) by @benjaminhuth
🐛 Bug Fixes
- Drop
removeNeutral
from particle pre-selection in Examples (#3830) by @andiwand - Track selector printouts to be in line with actual cuts (#3815) by @pbutti
- Remove false-positive warning in GCC14 (#3817) by @paulgessinger
- OneAPI 2025 Fixes, main branch (2024.11.11.) (#3846) by @krasznaa
- Make
SeedingPerformanceWriter
thread-safe (#3850) by @andiwand - Silence compiler warning in tbb header about old-style casts. (#3824) by @goetzgaycken
- TryAllNavigationPolicy config exposed to python (#3822) by @paulgessinger
RandomSeed
with 32 bit in Examples (#3860) by @andiwand- Potential Out of Bounds in Root file reading (#3870) by @dave7895
- Estimate entry size before sorting in ROOT readers (#3871) by @andiwand
- User
localtime_r
instead oflocaltime
(#3872) by @paulgessinger - Add check on expected measurements on surface before marking as hole (#3892) by @pbutti
- Boost progress include fails on next boost major release (#3896) by @AJPfleger
- Change MTJ test dynamic column names (#3914) by @paulgessinger
🚜 Refactor
- Remove
CalculateResiduals.hpp
(#3837) by @andiwand - Fuse initial and final sim particles in Examples (#3804) by @andiwand
- Use mathematical constants from
std::numbers
(#3781) by @AJPfleger - (gx2f) Pull out material counting (#3839) by @AJPfleger
- Expose IMaterialDecorator::decorate to python (#3819) by @paulgessinger
- 🚨 BREAKING: Remove free parameter estimation function (#3802) by @paulgessinger
- (gx2f) Make function to update parameter (#3840) by @AJPfleger
- (gx2f) Make material work for |eta| > 2 (#3726) by @AJPfleger
- 🚨 BREAKING: Use
consteval
onhashString
(#3833) by @paulgessinger - Remove Tesla conversion in
estimateTrackParamsFromSeed
(#3835) by @andiwand - 🚨 BREAKING: Rewrote the ambiguity solver for clarity and added Optional Hits Selector (#3805) by @Ragansu
- 🚨 BREAKING: Remove
bFieldMin
fromestimateTrackParamsFromSeed
(#3863) by @andiwand - Digitization cleanup in Examples (#3865) by @andiwand
- Reduce abort output in GX2F to DEBUG (#3888) by @paulgessinger
- 🚨 BREAKING: Deduplicate
estimateTrackParamsFromSeed
code (#3866) by @andiwand - Avoid
new
/delete
in a number of places. (#3828) by @paulgessinger - 🚨 BREAKING: Explicit
isPresent()
in cylinder volume builder (#3796) by @AJPfleger - 🚨 BREAKING: Single type/alias for intersection status (#3898) by @andiwand
- Remove custom scalar in classes (#3894) by @AJPfleger
- 🚨 BREAKING: Remove alias
IntersectionStatus::missed
(#3899) by @andiwand - 🚨 BREAKING: Remove
ActsScalar
(#3873) by @AJPfleger - Allow TrackState measurement setting without extra initialization (#3907) by @paulgessinger
- Convert to bound state also on empty sensitive surfaces. (#3855) by @goetzgaycken
- Cleanup some more detector code in Examples (#3908) by @andiwand
- Reworked
HitSelector
in Examples (#3836) by @andiwand - Allow track selection without reference surface (#3791) by @benjaminhuth
- 🚨 BREAKING: Clean track EDM projector (#3605) by @andiwand
- Replace
ParticleSmearing
withTrackParameterSmearing
in Examples (#3784) by @andiwand
📚 Documentation
- Adding cvarni to citation (#3867) by @CarloVarni
- (sphinx) Remove outdated warnings from ignore list (#3878) by @AJPfleger
- Remove http-relics for license (#3902) by @AJPfleger
🧪 Testing
- Enable commented checks in bounding box tests (#3829) by @AJPfleger
🛠️ Build
- LC_ALL=C for DD4hep in setup (#3844) by @paulgessinger
- Make Boost 1.85 a hard failure when building the Examples (#3843) by @paulgessinger
- Update
FindFilesystem.cmake
(#3905) by @paulgessinger
⚙️ Miscellaneous Tasks
- Add check for mathematical constants (no macros) (#3774) by @AJPfleger
- Remove
M_PI
relics (#3845) by @AJPfleger - Remove redundant cmake flags (#3842) by @AJPfleger
- Remove obsolete requirements file for exatrkx tests (#3848) by @AJPfleger
- Update PR template (#3858) by @paulgessinger
- Move requirements file for fpe-masks (#3884) by @AJPfleger
- Bump Python requirements (#3875) by @AJPfleger
- Add action for all pip requirements updates (#3883) by @AJPfleger
- Add milestone workflow (#3887) by @paulgessinger
- Cleanup some Geant4 Examples code (#3895) by @andiwand
- Wrong directory formating in update-pip bot (#3903) by @AJPfleger
- 🚨 BREAKING: Clean some Material code (#3897) by @andiwand
- Replace some couts with logger (#3912) by @AJPfleger
- (physmon) Make configuration of all the fitters the same (#3916) by @AJPfleger
v37.4.0
37.4.0
🚀 Features
- Add standalone digitization coordinates converter (#3765) by @ntadej
- Log-uniform p/pt distributions for Examples (#3790) by @andiwand
- Logger passed to Gbts and Orthogonal seeders (#3807) by @CarloVarni
- ProxyAccessor constructor can now be constexpr (#3757) by @timadye
🐛 Bug Fixes
- AddAmbiguityResolution writeTrackSummary/writeTrackStates (#3809) by @timadye
- Restore Orthogonal seedfinder default constructor (#3827) by @paulgessinger
- Default label for GraphViz::Node (#3821) by @paulgessinger
- DummyLogger can now be cloned (#3831) by @paulgessinger
🚜 Refactor
- Remove
pythia8
prefix from root files in Examples (#3798) by @andiwand - Remove
TruthSeedSelector
from Examples (#3808) by @andiwand - FPE safe eta/theta conversion (#3788) by @andiwand
- Rename PortalShell connect outer to fill (#3820) by @paulgessinger
- (gx2f) Container to represent the mathematical gx2f-system (#3806) by @AJPfleger
v37.3.0
37.3.0
🚀 Features
🐛 Bug Fixes
- Make callable args universal references (#3789) by @paulgessinger
- Remove a number of Sonar issues (#3780) by @paulgessinger
- Do not use requires in class EDM definition (#3731) by @CarloVarni
- Protect TrackSelector against eta=nan (#3785) by @timadye
- MeasSel error output, config check (#3794) by @paulgessinger
- Require TBB to be found by cmake (#3507) by @benjaminhuth
- Wrong definition of the constraint (#3803) by @CarloVarni
🚜 Refactor
- Rework random parameter and covariance generation (#3777) by @andiwand
- Replace
fabs(
andsqrtf(
withstd::abs
andstd::sqrt(
(#3787) by @AJPfleger - Improve log in seeding (#3792) by @CarloVarni
- (gx2f) Analyse temporary track in an extra function (#3799) by @AJPfleger
- (gx2f) Improve logging (#3801) by @AJPfleger
- Tweak
Sequencer
alias handling and logging in Examples (#3793) by @andiwand
🛠️ Build
- Unconditionally load Boost in CMake config (#3779) by @stephenswat
⚙️ Miscellaneous Tasks
- Bump dependency tarball version to v5 (#3782) by @paulgessinger
- Dependency URL not set correctly (#3786) by @AJPfleger
- (tests) Brush over surface tests (#3783) by @AJPfleger
- Update PR template, add cut-off marker (#3741) by @paulgessinger
- Change coverage badge from codecov to sonarcloud (#3797) by @AJPfleger
v37.2.0
37.2.0
🚀 Features
- Track parameters json converter (#3724) by @ssdetlab
- Make it possible to turn off warnings in GSF (#3739) by @benjaminhuth
- Add tracking efficiency vs z0 (#3764) by @ntadej
- Add
AngleHelpers.hpp
to help with eta/theta conversions (#3767) by @andiwand - (nav) Gen3 Navigation policies and factory (#3760) by @paulgessinger
🐛 Bug Fixes
- Handle Fatras immediate abort edge case (#3744) by @andiwand
- Fix nMeasurements() comment (#3740) by @timadye
- TrackSelector remove broken m_noEtaCuts (#3640) by @timadye
- Don't use
mp.get_context("spawn")
in test (#3753) by @paulgessinger - Move
default
constructor impl in CPP file (#3752) by @paulgessinger #include <algorithm>
in HoughTransformUtils forstd::sort
(#3758) by @wdconinc- TrackFinding: skip second pass if out of bounds (#3751) by @paulgessinger
- DetrayMaterialConversion for Gen2 (#3748) by @asalzburger
- Potential segfault in AthenaDumpReader (#3721) by @benjaminhuth
- Guarantee angle periodicity after KF filtering and smoothing (#3684) by @andiwand
- Make
DataHandle
type check more robust (#3768) by @andiwand - Improve
TrackParameterHelpers.hpp
(#3766) by @andiwand
🚜 Refactor
- Explicit
hasStackTraces()
in FPE (#3727) by @AJPfleger - Group all ROOT writers together (#3746) by @andiwand
- Rework particle selection in Examples (#3742) by @andiwand
- Rename
VertexPerformanceWriter
toVertexNTupleWriter
(#3745) by @andiwand - Rename
TrackFinderPerformanceWriter
in Examples (#3737) by @andiwand - Rename
CKFPerformanceWriter
in Examples (#3763) by @andiwand - Explicit constructors (non-core) (#3761) by @AJPfleger
- Use structured bindings (#3632) by @AJPfleger
- Generalizing telescope seeding interface (#3725) by @ssdetlab
🧪 Testing
⚙️ Miscellaneous Tasks
- Use
TrackFitterPerformance
writer for CKF (#3735) by @andiwand - Download dependencies as tarball (#3520) by @paulgessinger
- Reset
ccache
caches (#3771) by @andiwand - Fix license header in pre commit hooks (#3773) by @andiwand
- Update exclude list for unused files (#3776) by @AJPfleger
- Tweak DD4hep log level (#3778) by @andiwand
v37.1.0
37.1.0
🚀 Features
- GeoModel changes for Gen1 ITk (#3685) by @benjaminhuth
- Add some SVG glue code to help displaying proto material (#3692) by @asalzburger
- (util) Add builder class for "chain" delegates (#3696) by @paulgessinger
- Update AthenaDumpReader, allow reading only SPs (#3709) by @benjaminhuth
- Add GeoSimplePolygonBrep to GeoModelToDetectorVolume (#3713) by @Matthewharri
- Delayed Grid construction for Portals (#3718) by @paulgessinger
- Adding dot graph possibility (#3730) by @asalzburger
- Allow reflection of track parameters (#3682) by @andiwand
- Add
estimateTrackParamCovariance
to Core (#3683) by @andiwand
🐛 Bug Fixes
material_recoding.py
conditional loading of GeoModel (#3703) by @paulgessinger- Copy whole trackstate did not copy calibrated (#3693) by @benjaminhuth
- 3ul instead of 3 for size_t (#3706) by @CarloVarni
- Fix name BranchState (#3707) by @timadye
- Adapt scripts to GeoModel updates (#3711) by @asalzburger
- CylVolStack resizing issue (#3715) by @paulgessinger
- Make charge smearing optional in digi config (#3710) by @stephenswat
- (geo) CylVolStack reuses gaps if exist (#3716) by @paulgessinger
- Incorrect sanity check in TrackingVolume removed (#3734) by @paulgessinger
- Implement
DirectNavigator
direction handling (#3702) by @andiwand - FPE monitoring boost discovery, addr2line fallback (#3747) by @paulgessinger
🚜 Refactor
- Set convertMaterial as configurable (#3604) by @galocco
- (geo) Geometry visualization update (#3681) by @paulgessinger
- (geo) Teach ProtoLayer to respect local coordinate system (#3697) by @paulgessinger
- Remove quick math helpers (#3701) by @andiwand
- Do not insert space points if not inside grid boundaries (#3698) by @CarloVarni
- Z and r axis in grid for seeding are Open instead of Bound (#3712) by @CarloVarni
- Only compute middle range once per bin (#3714) by @CarloVarni
- Python binding bits and pieces (#3717) by @paulgessinger
- Combine material, measurement and hole handling in Core CKF
filter
(#3723) by @andiwand - Add some requirements (#3720) by @CarloVarni
- Integrate source link container into measurements container in Examples (#3732) by @andiwand
📚 Documentation
- Add comment on computation of impact parameter from the doublet (#3728) by @CarloVarni
⚡ Performance
- Avoid allocations in
TrapezoidBounds::inside
(#3705) by @andiwand std::sqrt
overstd::hypot
in Core (#3694) by @andiwand
🧪 Testing
- Add GeoModel plugin to Downstream project test (#3704) by @paulgessinger
🛠️ Build
- Use correct GM variables in cmake config (#3699) by @paulgessinger
- Pick up GeoModel v6 or v7 (#3736) by @paulgessinger
⚙️ Miscellaneous Tasks
- Remove some unnecessary includes (#3700) by @jmcarcell
- Add pre-commit check for leftover git conflict markers (#3708) by @benjaminhuth
- Physmon for KF and GSF refitting (#3733) by @andiwand