Commit Graph

623 Commits

Author SHA1 Message Date
Jean-Paul Chaput 0e63168802 Regenerated whole doc (by mistake)... 2021-10-01 21:36:45 +02:00
Jean-Paul Chaput 0c0b426894 Follow up of PyModule_GetFilenameObject() modification. 2021-10-01 18:33:47 +02:00
Jean-Paul Chaput e11bd98f52 Correct for various warnings appearing under gcc 8.3.0 (Debian 10).
Note: We don't suppress warnings due to unused variables or functions,
      as we may need them later or in debug mode...

* Change: In Hurricane::DBo::~DBo, add a noexcept(false) because
    constructed by default destructor of derived classes seems to
    loosen it. The right solution whould be to explicitely define
    all virtual destructors (too lazy for now).
* Change: In Viewer::Script, replace the deprecated
    PyModule_GetFilename() by PyModule_GetFilenameObject(), Unicode
    support again...
2021-10-01 16:12:28 +02:00
Jean-Paul Chaput a617cea0a5 Remove deprecated C++11 throw() specifications. 2021-10-01 00:26:58 +02:00
Jean-Paul Chaput 9852c76c2c Revert from std::regex to C POXIX regex.
* Bug: In Hurricane::Backtrace(), the std::regex supplied by gcc 4.8.5
    seems to be buggy. So, for now, to compile on my reference system,
    revert to C POSIX.
2021-09-30 20:06:48 +02:00
Jean-Paul Chaput 9c71ce8a03 Updated doc of the new Python/C++ template wrapper.
* Change: In Isobar3::PyWrapper, C++ exceptions where not catcheds,
    forgot to call exceptionWrapper().
* Change: In Isobar3, remove unused pyToC<>() flavor where T is a
    simple pointer and the argument is also a simple pointer, does
    not make sense.
2021-09-26 17:27:57 +02:00
Jean-Paul Chaput 844db44ebf Rename pyTypePostModuleInit<> to pyTypePostInit<> (clearer). 2021-09-25 19:20:57 +02:00
Jean-Paul Chaput 16d1da053a Migration towards Python 3, stage 2: C++ template wrapper ready.
* New: In hurricane/configuration, the Python/C template wrapper has
    now all the needed features to mass-migrate Hurricane and the
    ToolEngines.
      The new Hurricane module is named Hurricane3 so it does not
    collides with the old one which is still used. Will do the
    same for all ToolEngines Python wrappers until migration is
    complete.
* New: In unittests/python/, create very basic unit tests for the
    Configuration & Hurricane new template wrapper.
    Note: It is almost impossible to use valgrind on them because
          it doesn't recognize correctly Python allocation mechanism.
	  To make it work, both valgrind & Python needs to be
	  recompiled with special options...
2021-09-25 17:03:14 +02:00
Jean-Paul Chaput 02777e127e Migration towards Python3, first stage: still based on C-Macros.
* New: Python/C++ API level:
  * Write a new C++/template wrapper to get rid of boost::python
  * The int & long Python type are now merged. So a C/C++ level,
    it became "PyLong_X" (remove "PyInt_X") and at Python code
    level, it became "int" (remove "long").
* Change: VLSISAPD finally defunct.
  * Configuration is now integrated as a Hurricane component,
    makes use of the new C++/template wrapper.
  * vlsisapd is now defunct. Keep it in the source for now as
    some remaining non essential code may have to be ported in
    the future.
* Note: Python code (copy of the migration howto):
  * New print function syntax print().
  * Changed "dict.has_key(k)" for "k" in dict.
  * Changed "except Exception, e" for "except Exception as e".
  * The division "/" is now the floating point division, even if
    both operand are integers. So 3/2 now gives 1.5 and no longer 1.
    The integer division is now "//" : 1 = 3//2. So have to carefully
    review the code to update. Most of the time we want to use "//".
    We must never change to float for long that, in fact, represents
    DbU (exposed as Python int type).
  * execfile() must be replaced by exec(open("file").read()).
  * iter().__next__() becomes iter(x).__next__().
  * __getslice__() has been removed, integrated to __getitem__().
  * The formating used for str(type(o)) has changed, so In Stratus,
    have to update them ("<class 'MyClass'>" instead of "MyClass").
  * the "types" module no longer supply values for default types
    like str (types.StringType) or list (types.StringType).
    Must use "isinstance()" where they were occuring.
  * Remove the 'L' to indicate "long integer" (like "12L"), now
    all Python integer are long.
* Change in bootstrap:
  * Ported Coriolis builder (ccb) to Python3.
  * Ported Coriolis socInstaller.py to Python3.
  * Note: In PyQt4+Python3, QVariant no longer exists. Use None or
    directly convert using the python syntax: bool(x), int(x), ...
    By default, it is a string (str).
* Note: PyQt4 bindings & Python3 under SL7.
  * In order to compile user's must upgrade to my own rebuild of
    PyQt 4 & 5 bindings 4.19.21-1.el7.soc.
* Bug: In cumulus/plugins.block.htree.HTree.splitNet(), set the root
    buffer of the H-Tree to the original signal (mainly: top clock).
      Strangely, it was only done when working in full chip mode.
2021-09-19 19:41:24 +02:00
Jean-Paul Chaput f1668cec5f Disable BFD support by default.
* Change: In <tool>/CMakeLists.txt, add an USE_LIBBFD option to
    enable the link against the BFD library. Latest versions seems
    to have changed their API.
* Change: In bootstrap/ccp.by & builder/Builder.py, add an option
    "--bfd" (and self._bfd) to enable BFD support.
2021-07-17 13:01:19 +02:00
Jean-Paul Chaput 205a6877db More generic H-Tree support to accomodate the LS180 PLL internal clock.
The H-Tree support is now allowed for any net, not only the clocks and
not only top-level nets. This allow to better management of the LS180
internal clock signal.

* New: In Cell::flattenNets(Instance*,set<string>,uint64_t) new overload
    of the function to allow the user to select nets that will *not*
    be flattened. This makes the NoClockFlatten flag effectively obsolete,
    we keep it for backward compatibility.
      The net names can be of non top level ones. In that case, they must
    use the name an HyperNet will get (the Occurrence name). For example:
         "instance1.instance2.deep_net_name".
* New: In PyCell, update the wrapper for the new parameter of flattenNets(),
    new utility function pyListToStringSet() to translate a Python list into
    a C++ set of names.
* New: In EtesianEngine, add support for a list of nets to be excluded
    from the flattening procedure. Those excluded nets will also be
    excludeds from the Coloquinte nets *and* HFNS synthesis, as they
    are likely to be manageds by a H-Tree.
* Change: In AnabaticEngine::_loadGrByNet(), now also skip nets that are
    flagged as manually detailed route.
* New: In AnabaticEngine::antennaProtect(), do not try to insert diodes
    on nets that are already fixed or detaled route. This replace the
    clock exclusion.
* New: In cumulus/plugins.{block,htree,chip}, replace the concept
    of clock-tree by the more generic H-Tree. That is, we can ask the P&R
    to create H-Tree on any net of the design, not only the ones matcheds
    as clock. The net does not even need to be top-level.
      This is to manage the PLL internal clock generated by the PLL in
    the LS180 chip.
      Start to change all reference to "clock" into "H-Tree".
* Bug: In cumulus/plugins.chip.powerplanes.Builder._connectHTree(),
    there was an inversion of the H & V routing gauges to compute the
    track into which put the H-Tree center to corona edge wiring.
      This was causing tracks to be used twice, seen in the ao68000 test
    bench.
2021-05-31 00:02:23 +02:00
Jean-Paul Chaput 39231d5191 Allow to enable/disable minimal size checking in Contact CTOR. 2021-05-25 14:56:07 +02:00
Jean-Paul Chaput 90300eb651 Small typo in Cell::getComponentsUnder() Python wrapper. 2021-05-22 14:54:36 +02:00
Jean-Paul Chaput ec3c22547a Bug fixes in the VST/VHDL driver coupled with BlifParser.
* Change: In Hurricane::NetAlias, store additional data in NetAliasName,
    the external status of the former Net. When a Net::merge() is
    performed, we must keep track of whether the merged (destroyed)
    one was external and keep that information.
      Add NetAliasHook::isExternal() & NetAliasHook::setExternal()
    virtual methods.
* Change: In Net::getNet() add a new optional argument to allow the
    search of the net name in *internal* aliases. Otherwise only the
    aliases tagged as *external* will be searched.
      It was a bug that, when looking for a Plug master net by name
    we got an homonymous internal net. In that case we must only
    look for net that are (or where) part of the interface.
* New: In Vhdl::VectorSignal, when a vector contains only one bit,
    unvectorize it, like when it is non-contiguous (we use the
    isCountiguous() method to carry that information).
* New: In Vhdl::VhdlEntity, Catalog::State and NamingScheme, added
    a flag UniquifyUpperCase to uniquify the names in uppercases.
    In case of a clash with the same name in lowercase.
      Prepend 'u' before all previously uppercased letter. For
    example 'VexRiscV' becomes 'uvexuriscuv' (urgh!).
      The Catalog flags is exported to Python for use by the blif2vst
    script.
* Change: In BlifParser, Model::newOne() and Model::newZero(), return
    a new gate each time it is called instead of making just one for
    each Model. This way, if two outside nets are connected to one
    or zero they do not get merged (should work, but will be less
    clear).
* Bug: In BlifParser, Model::connectSubckts(), when looking for the
    master net in the instances models (by name), limit the search
    to the *external* aliases names.
* Change: In NamingScheme::vlogTovhdl(), reactivate the removal of
    two consecutive '_'.
* Change: In cumulus/bin/blif2vst.py, prefix the master cells
    (i.e. components) with 'cmpt_' to avoid clash names with signals
    in VHDL.
2021-04-05 23:53:44 +02:00
Jean-Paul Chaput 9230d52b64 Big bug in HyperNet_ComponentOccurrences::Locator::progress().
* Bug: In HyperNet_ComponentOccurrences::Locator::progress(), (Collection
    locator), the _netOccurrenceLocator (which progess along the various
    Net occurrences of the HyperNet) was not in synch with the
    _componentOccurrence locator of the current net. It was pointing
    to the *next* net occurrence.
      The result was the generation of a path for the net commponents
    that was incorrect (it was the path of the *next* net occurrence),
    and making Occurrence constructor throw an exception.
* Change: In Cell::flattenNets(), DeepNet::_createRoutingPads(),
    Occurrence::Occurrence() and UpdateSession, added even more trace
    informations.
2021-03-23 17:06:02 +01:00
Jean-Paul Chaput cfcd4b7115 Do not for materialization in RoutingPad::setExternalComponent().
* Bug: In RoutingPad::setExternalComponent(), we where always forcing
    the materialization of the RoutingPad (QuadTree insertion). Now
    respect the Go::enableAutoMaterialization() state.
      Forcing the materialization is equivalent to having an
    UpdateSession. So when creating large amount of RoutingPads it did
    result in huge slow down, like in HFNS algorithms.
      With this modification we go down from 6h+ to 4m for the ls180.
2021-03-23 17:05:18 +01:00
Jean-Paul Chaput 11390867f1 A more compact string representation for Hurricane::Path. 2021-03-15 23:45:33 +01:00
Jean-Paul Chaput a6492f6edc Allow Hurricane::Query to stop on master cells with designated flags.
* New: In Query & QueryStack, add a new stop criterion "stopCellFlags"
    based on the flags of the instances master cell. The instance will
    still be processed, but not it's childs. Typically used to stop
    exploring on "AbstractedSupply" cells.
      Exported in the Python interface.
* New: In Cell::Flags, new value "AbstractedSupply" to mark Cells from
    which an abstract has been built for supplies & blockages. But *not*
    for common nets. Helps reduce the recursion through the hierarchy
    when building supply line in FlattenPower.
      Export setter/getter in the Python interface.
* New: In Instance, add a "PruneMaster" filter to stop hierarchical
    exploration on instances which master cells have at least one of
    the given flags set.
* Change: In NetExternalcomponents::isInternal(), use "const Component*"
    instead of "Component*".
* Bug: In Cell::Flags, the NoFlags must be *zero*, not *one*! And we
    can reclaim that bit for future use.
* Cleanup: In Hurricane::Cell, remove changeQuadTree() related methods.
    Fusing various Cell's QuadTree is not a viable idea.
* Cleanup: In Hurricane::Instance, remove no longer used "_flags"
    attributes.
2021-03-02 12:17:13 +01:00
Jean-Paul Chaput d942f3cb59 Add support for Rectilinear & Polygon in PyEntity_NEW(). 2021-02-17 23:22:31 +01:00
Jean-Paul Chaput 07b51b10c7 Allow to demote Net external component to "internal", export to Python. 2021-02-17 23:20:24 +01:00
Jean-Paul Chaput 48357c37a9 Added DbU::toCeil() & DbU::toFloor() for rounding on a dedicated step. 2021-02-01 16:13:16 +01:00
Jean-Paul Chaput 5f6302de44 Added HasAntenna flag to NetRoutingProperty. 2021-01-27 10:58:03 +01:00
Jean-Paul Chaput 88081fae12 Added Path::contains(Instance*) method. 2021-01-27 10:57:35 +01:00
Jean-Paul Chaput 2b0a2c88b7 More informative error message in Occurrence constructor. 2021-01-13 19:05:20 +01:00
Jean-Paul Chaput 250ef29674 Fix the smart truncate display in DbU::getValueString(). 2021-01-13 19:04:13 +01:00
Jean-Paul Chaput 3b5a0f5bd2 Again, bug fix in the Inspector support, on getSlot<> template.
The policy about how to create slots was not completly clear.
Now, only add *pointers* or *references* to class attributes,
never do a "copy by value". Reflect that change in SlotTemplate<>
various partial specializations.
  Hammer in your head that in C++ functions templates do not allow
for partial specialization. So write only *one* template for
::getSlot<>() (refdefinition simply got ignoreds, at least with gcc).

* Bug: In Slot, only one template for getSlot<> (see above).
    Adjust SlotTemplates<> to provides partial specialization only for:
    * "const Data&".
    * "Data*".
    * "const Data*".
    * "Data* const"
    * "Record*".
* Bug: In Instance::_getRecord(), suppress slot based on transient
    values "XCenter" & "YCenter".
* Bug: In CRL::ToolEngine::_getRecord(), suppress slot "Name" based
    on a transient value.
* Change: In ::getRecord(std::list<Elementt>*) (and variant), pass
    all elements to ::getSlot() as (const Element*).
2021-01-08 12:43:47 +01:00
Jean-Paul Chaput b0ae6be652 Export Cell::flattenNets() & revlevant Cell flags. 2020-12-27 12:21:14 +01:00
Jean-Paul Chaput 70d32528cd Added new utility conversions DbU::toMicrons() & DbU::fromMicrons(). 2020-12-23 11:16:38 +01:00
Jean-Paul Chaput be5483a0ad Do not skip thin (elongated) QuadTree leaves. 2020-12-04 12:14:08 +01:00
Jean-Paul Chaput 642579b444 More fix for the slow display in CellViewer.
* Change: In Hurricane::QuadTree_GosUnder::Locator::progress(), directly
    prune the elements which sizes are under the threshold. This allows
    the too small Instances to be directly skipped. This was the key
    point slowing the walktrough. We were systematically going through
    all the instances (that is consistent with the perf traces).
* Change: In Hurricane::Cell_OccurrencesUnder, add a threshold parameter
    to pass on the QuadTree (through getInstancesUnder()).
      Needed for the CellWidget selection to have the same problem as
    the display itself (select only what is displayed).
* New: In Hurricane::CellView, add two new parameters:
    1. "viewer.minimumSize" set the original size of the window, in pixels.
       (doubled for HiDPI).
    2. "viewer.pixelThreshold", the size, in pixels, under which
       components/instances will not be displayeds.
* New: In CRL/etc/cmos.misc.py, added parameters "viewer.minimumSize"
    and "viewer.pixelsThreshold".
2020-12-02 20:02:55 +01:00
Jean-Paul Chaput 7feb39d056 Separate size check for Hurricane::Contact & Hurricane::Pin.
* Change: In Hurricane::Contact, as it is the base class of Pin, a
    width *or* height can rightfully be null (according to the
    Pin orientation).
      Put the check in a Contact::_postCheck() function.
* Change: In Hurricane::Contact, replace all the "const DbU::Unit&"
    parameters by simply "DbU::Unit".
* Change: In Hurricane::Pin, add a dedicated _postCheck() function.
2020-12-02 19:12:27 +01:00
Jean-Paul Chaput e08bc9a407 Check contacts for minimal size in real mode.
* Change: In Hurricane::Contact::Contact(), check width & hieight of
    the contact against the minimal size, if below, bellow a warning
    and increase the dimension.
      May too paranoid when used on turn in same metal (no cut).
2020-11-25 21:51:43 +01:00
Jean-Paul Chaput f5ee37d2e6 Manage minimum area for VIAs in the P&R.
* New: In Hurricane::Layer, add support for a minimal area (given in
    microns). Exported in the Python interface.
* New: In Anabatic::AutoSegment::bloatStackedStrap(), method to
    enlarge too small vertically stacked VIAs. For now just create
    a square ensuring the minimal area. Potentially cause DRC error in
    some cases so needs to be refined.
* New: In Anabatic::_gutAnabatic(), check for too little stacked VIAs
    and display a report.
2020-11-16 00:55:49 +01:00
Jean-Paul Chaput a4eb811bcb Exported Layer::getTopEnclosure() in Python interface. 2020-11-14 18:51:41 +01:00
Jean-Paul Chaput e4d821e5b6 Added warnings for off foundry grids in Rectilinear::create(). 2020-11-14 18:50:42 +01:00
Jean-Paul Chaput 3a3c4fe3c5 DbU::getValueString() was truncating lambda value one decimal too short. 2020-11-14 18:49:23 +01:00
Jean-Paul Chaput c6e5583233 Documentation cleanup & rebuild.
* Change: In documentation/build.py, more PEP8 & Python 3 future compliance.
    Correct copy of the tools HTML docs on my laptop, to have a full
    offline copy of the doc.
* New: In documentation/contents/pages/check-toolkit, duplicate the doc
    from alliance-check-toolkit README. Seems it has been inadvertently
    removed at some point (?). Have to be careful to maintain in synch
    with the toolkit.
* Change: <tool>/doc/*/SoC.css, use Roboto fonts when availables.
* Update: Commit the whole pre-generated docs (Doxygen, Pelican).
2020-11-12 14:22:31 +01:00
Jean-Paul Chaput 03bfc091c3 Warn for zero values in Layer.setMinimalSize() & setMinimalSpacing(). 2020-11-11 13:45:15 +01:00
Jean-Paul Chaput 61b9817421 .
Implement BasicLayer.getTop() & getBottom(), need them in real mode.
2020-11-11 13:43:26 +01:00
Jean-Paul Chaput 266409acc4 In DbU.getValueString(), use 'L' for lambdas ('l' too close of '1'). 2020-11-11 13:40:58 +01:00
Jean-Paul Chaput afa5fcd4c7 More informative error message in Hurricane::Net constructor. 2020-11-02 17:16:02 +01:00
Jean-Paul Chaput 3993f948b7 Change the way the grid is drawn in CellWidget.
* Change: In CellWidget::drawGrid(), for the "super-grid", now use
    lines instead of small crosses. The super-grid is set to 10 point
    of the snap grid in all cases (symbolic, real, foundry grid).
* New: Export CellWidget::setDbuMode() to CellViewer, and into it's
    Python wrapper.
* Bug: In CellWidget::setCell(), keep the dbuMode when loading a new
    cell instead of reverting to default.
2020-10-25 12:05:54 +01:00
Jean-Paul Chaput 79f3350eba More explicit error message in Cell.getNet() Python wrapper. 2020-10-14 14:58:32 +02:00
Jean-Paul Chaput 8f0a8e5a3a Added support for loading user defined global routing in Anabatic.
* New: In Hurricane::NetRoutingProperty, add and change the meaning
    of the following flags:
      - ManualGlobalRoute : now means that a global routing *trunk*
        is present, made of "gmetalh", "gmetalv" & "gcontact".
      - Manualdetailroute : added, get the former meaning of
        ManualGlobalRoute, that is, the detailed routing is
	already present for this net, but can be changed by the
	detailed router. Implies that it respect the Terminal,
	HTee & VTee structuration.
* New: Add Anabatic::Diskstra::loadFixedGlobal(), to account
    a manually global net into the edges capacities.
* New: In Anabatic::Edges::ripup(), exclude manually global routed
    segments from the ripup. Change the segment sorting function
    so that thoses segments are put in head of list (considered
    as "smaller").
* Change: In AnabaticEngine::setupPreRouteds(), now detect manual
    global routed and manual detail routed signals, and tag them
    accordingly.
* New: In AnabaticEngine::Configuration & Session, add proxies
    for the global routing layers ("gmetalh", "gmetalv", "gcontact").
* New: In Anabatic::Constants, add flags for global fixed and
    detail routed nets.
* Change: In KatanaEngine::updateEstimateDensity(), now use int64_t
    for flute coordinates.
* New: Add CRL::RoutingGauge::hasLayer(), to know if a layer is
    managed by the gauge (comparison by mask).
2020-09-30 11:55:39 +02:00
Jean-Paul Chaput ea94175eb4 In Entity, add Python bindings for "isBound()" and "getId()". 2020-09-30 11:50:09 +02:00
Jean-Paul Chaput e53113ebb1 Just some manic code beatification. 2020-09-14 11:15:15 +02:00
Jean-Paul Chaput f00b8cd667 Allow RoutingPad::getPlugOccurrence() to build upon a Pin.
* Change: In Hurricane::RoutingPad::getPlugOccurrence(), it was
    forbidden to rebuild the Occurrence over anything other than
    Plug. But as we now also uses Pins, it becomes useful to
    rebuild the Occurrence on a Pin. The name of the function
    stays, even if its less meaningful now.
2020-09-11 12:56:35 +02:00
Jean-Paul Chaput 3e6d5622e8 Improvement on Python interface of Occurrence, Point & CellViewer.
* Bug: In Isobar::PyOccurrence, use "compare by value" instead of
    "compare by pointer" for the Python comparison function. So we
    really can compare identical Occurrences.
* New: In Isobar::PyPoint, export the "manhattanDistance()" function.
* New: In Isobal::PyCellViewer, add the following funtions to the
    exported interface:
    - "select()"
    - "unselect()"
    - "unselectAll()"
    - "reframe()"
    - "setShowSelection()"
    So now we can easily highlight components from Python (to ease
    debug).
* New: In Hurricane::CellViewer, create a proxy for the CellWidget
    "reframe()" function.
2020-09-11 12:55:51 +02:00
Jean-Paul Chaput 0b5ce309eb Implement QuadTree pruning to speedup the display of huge designs.
When displaying big designs, the drawing was very slow because all
the graphical objects were browsed *before* deciding if they were
big enough for display. So we introduce a new mode of working of
the QuadTree to that the ones with areas *below* a certain thresold
just get skipped. Of course, the previous behavior must be preserved
(when the threhsold is zero or negative) as most of the time, we
*want* *all* the objects under an area, not only the biggest ones.
For now, in CellWidget, the visibility threshold is set to 20 pixels.
With this, we can display the Libre-SOC "test_issuer" of 100Kgates
in between 20 to 30s.

* New: In Hurricane::QuadTree_GosUnder collection & locator, add a
    "threshold" argument so that QuadTree which both area sides are
    below that lenght will be ignored (no walkthrough at all).
      Zero (or negative) threshold means  that no QuadTree will be
    pruned, we get back to the previous behavior.
* New: In Hurricane::Slice::getComponentsUnder(), add the threshold
    argument (with a default to 0).
* New: In Hurricane::Cell::getInstancesUnder(), add the threshold
    argument (with a default to 0).
* New: In Hurricane::Query, added support for the threshold parameter.
    In doQuery(), instances that have *both* side under the threshold
    are pruned (slightly different from QuadTree areas).
* New: In Hurricane::CellWidget::_redraw(), set the visibility
    threshold to 20 pixels (arbitrary, must be parametrized).
* New: In Hurricane::Cell, added destroyPhysical() method.
    Remove *all* physical components and the DeepNets (so make
    a virtual *unflatten*) in the correct dependency order.
    In particular, RoutingPads, that relies on Occurrence over
    physical components must be destroyeds *before* the entity
    they are based on is destroyed.
2020-08-27 19:14:44 +02:00
Jean-Paul Chaput 083e58d953 Add CRL::Catalog and Net::getRoutingPads() to the Python interface.
* New: In CRL::PyAllianceFramework, export getCatalog(), in PyCatalog,
    export the getState(name) method and add a PyCatalog_Link().
    In PyCatalogState, add PyCatalogState_Link(), cannot use the
    macro because of the C++ name resolution operator (Catalog::State).
* New: In Isobar, export the RoutingPads collection to the Python interface.
* New: In Hurricane::Net, export the getRoutingPads() method to the
    Python interface (hence the need of the previous export).
2020-08-21 16:00:50 +02:00