| 90af4772 | 30-Oct-2025 |
Alexander Hansen <alexander.hansen@9elements.com> |
(a)server: support object_path overloads
In order to support safer handling of object paths, directly support overloads for passing `const sdbusplus::message::object_path&` in addition to the `char*
(a)server: support object_path overloads
In order to support safer handling of object paths, directly support overloads for passing `const sdbusplus::message::object_path&` in addition to the `char* path` functions.
Tested:
New unit tests have been added for server and aserver, for both regular and property-provided constructors.
Change-Id: I63cb16f4cce75f99ebbbd5ced44ef4a219c7a74a Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
show more ...
|
| 034fbc69 | 09-Feb-2026 |
Alexander Hansen <alexander.hansen@9elements.com> |
common.hpp: include dependencies
Add header dependencies to common.hpp.
Previously, common.hpp did not include dependencies on e.g. enum members.
For example 'xyz.openbmc_project.Inventory.Item.PC
common.hpp: include dependencies
Add header dependencies to common.hpp.
Previously, common.hpp did not include dependencies on e.g. enum members.
For example 'xyz.openbmc_project.Inventory.Item.PCIeDevice' has
``` properties: ... - name: GenerationInUse type: enum[xyz.openbmc_project.Inventory.Item.PCIeSlot.Generations] default: "Unknown" description: > The PCIe interface generation in use by the device. ... ``` which caused following generated code ``` struct properties_t { ... sdbusplus::common::xyz::openbmc_project::inventory::item::PCIeSlot::Generations generation_in_use = sdbusplus::common::xyz::openbmc_project::inventory::item::PCIeSlot::Generations ::Unknown; ... } ``` but the header was not included, leading to compilation failures and include order issues [1].
Tested:
`build/gen/xyz/openbmc_project/Inventory/Item/PCIeDevice/common.hpp` now includes the common header for `PCIeSlot` as expected.
`build/gen/xyz/openbmc_project/Telemetry/ReportManager/common.hpp` now includes the common header for 'Report' as expected.
References:
[1] https://gerrit.openbmc.org/c/openbmc/telemetry/+/86640/comment/ded1078b_c0e65a93/
Change-Id: If6aaef6526fea30179866418c65ff16f4fcdc422 Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
show more ...
|
| c6fee5a9 | 20-Oct-2025 |
Alexander Hansen <alexander.hansen@9elements.com> |
expose DBus interface signal names as symbols
Enable a way to access the signal names of a given DBus interface as a constexpr symbol via the header.
4 use-cases:
- printing error / debug logs wit
expose DBus interface signal names as symbols
Enable a way to access the signal names of a given DBus interface as a constexpr symbol via the header.
4 use-cases:
- printing error / debug logs with the signal name. e.g. 'received signal ${SIGNAL_NAME}'
- matching on DBus signals in applications which do not yet use the PDI generated bindings.
- preventing typos in DBus signal names
- estimating the impact of removing a given DBus signal from an interface. When using these symbols, it would cause a build failure in applications relying on the existence of that signal.
This change is similar to [1] and goes into the same direction.
Tested: Newly written unit test passes.
References: [1] d2571922bfdb4f6b41ba4fbc45b8a4272793fd40
Change-Id: I9c20d744955c883302f349c5351dbdba1753466b Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
show more ...
|
| 4aa58f5a | 16-Oct-2025 |
Alexander Hansen <alexander.hansen@9elements.com> |
expose DBus interface method names as symbols
Enable a way to access the method names of a given DBus interface as a constexpr symbol via the header.
4 use-cases:
- printing error / debug logs wit
expose DBus interface method names as symbols
Enable a way to access the method names of a given DBus interface as a constexpr symbol via the header.
4 use-cases:
- printing error / debug logs with the method name. e.g. 'error calling ${METHOD_NAME}'
- accessing DBus methods in applications which do not yet use the PDI generated bindings.
- preventing typos in DBus method names
- estimating the impact of removing a given DBus method from an interface. When using these symbols, it would cause a build failure in applications relying on the existence of that method.
This change is similar to [1] and goes into the same direction.
Tested: Newly written unit test passes.
References: [1] d2571922bfdb4f6b41ba4fbc45b8a4272793fd40
Change-Id: Id423c3a668dd1a8346040f4380476d5e02468ddb Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
show more ...
|
| d2571922 | 02-Oct-2025 |
Alexander Hansen <alexander.hansen@9elements.com> |
expose DBus interface property names as symbols
Enable a way to access the property names of a given DBus interface as a constexpr symbol via the header [1]
4 use-cases:
- printing error / debug l
expose DBus interface property names as symbols
Enable a way to access the property names of a given DBus interface as a constexpr symbol via the header [1]
4 use-cases:
- printing error / debug logs with the property name. e.g. '${property} missing from configuration'
- accessing DBus properties in applications which do not yet use the PDI generated bindings.
- preventing typos in DBus property names
- estimating the impact of removing a given DBus property from an interface. When using these symbols, it would cause a build failure in applications relying on the existence of that property.
Tested: a newly added unit test is using this feature.
References: [1] https://discordapp.com/channels/775381525260664832/867820390406422538/1423317550732673206
Change-Id: I7b2906b6b1b445c3a49868ff1d50ced6ccaa5336 Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
show more ...
|
| 871cc336 | 10-Oct-2025 |
Matt Spinler <spinler@us.ibm.com> |
sdbus++: Append 'common' namespace to enums
When an enum is used as a method arg, the generated aserver.hpp wasn't compiling because the "xyz::openbmc_project::" namespace wasn't found as a type in
sdbus++: Append 'common' namespace to enums
When an enum is used as a method arg, the generated aserver.hpp wasn't compiling because the "xyz::openbmc_project::" namespace wasn't found as a type in these two places:
``` Control/Failover/aserver.hpp:78:133: error: template argument 1 is invalid [-Wtemplate-body] 78 | using value_types = std::tuple<xyz::openbmc_project::control::Failover::Requester, std::map<std::string, std::variant<bool>>>; ```
and ``` Control/Failover/aserver.hpp:97:49: error: parse error in template argument list [-Wtemplate-body] 97 | utility::tuple_to_array(message::types::type_id<xyz::openbmc_project::control::Failover::Requester, std::map<std::string, std::variant<bool>>>()); ```
Fix this by updating property.py to append the sdbusplus::common namespace to enums to make them fully qualified, i.e:
``` using value_types = std::tuple<sdbusplus::common::xyz::openbmc_project::control::Failover::Requester, std::map<std::string, std::variant<bool>>>; ```
This applies to enums used everywhere. I didn't see a way to only make the change for the 2 spots listed above.
Tested: * The aserver.hpp properly compiles now. * A full image still builds.
Change-Id: I0083b1d442e1aed0242b4c5522b3fe93aa67f06b Signed-off-by: Matt Spinler <spinler@us.ibm.com>
show more ...
|
| ed24aa51 | 26-Aug-2025 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: convert from setup.py to pyproject.toml
Python setup.py files are deprecated in favor of newer pyproject.toml and with later versions of Python this is both a warning and can be a failure d
sdbus++: convert from setup.py to pyproject.toml
Python setup.py files are deprecated in favor of newer pyproject.toml and with later versions of Python this is both a warning and can be a failure due to incorrect SPDX license directives. Convert to pyproject robotically by using:
``` uvx setuptools-py2cfg >> setup.cfg uvx ini2toml[full] setup.cfg >> pyproject.toml ```
Tested: Ran `uv build --sdist` with `setup.py` and `pyproject.toml` and confirmed same results (other than obvious changes due to install of the setuptools directives).
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: Id62a63c3d9f061d632eab504a76b0c13be8a8b08
show more ...
|
| a0fe02ca | 10-Mar-2025 |
Alexander Hansen <alexander.hansen@9elements.com> |
aserver: constructor to initialize properties
Functions like 'emit_added()' do not work correctly if properties are not initialized. Often, the initial values for the properties of an interface are
aserver: constructor to initialize properties
Functions like 'emit_added()' do not work correctly if properties are not initialized. Often, the initial values for the properties of an interface are known, such as
- Software Version Interface - Software ActivationProgress Interface - Software ApplyTime Interface - ...
How was this previously handled?
- Write a wrapper class for the specific aserver class. This allows to initialize the properties, as they are protected members. Example [2]
- Write a wrapper class and provide methods to get/set the variables. This is done in [1]
- Set each property with a method call, which emits 'PropertyChanged' signal by default, not ideal. This also does not work if the interface is ever refactored to have additional properties.
To facilitate using these interfaces without having to write a wrapper class to inherit from them, and to avoid having to manually set each property, which can easily be forgotten, provide a constructor to allow for passing a struct with values for all the properties.
Tested: Unit tests pass, but still needs to be build-tested against openbmc/openbmc. The concern there is mostly due to an added template parameter.
References: [1] https://github.com/openbmc/sdbusplus/blob/da8574d5888b2c1622f5482a47adc7a12ffa0d0e/example/calculator-aserver.cpp#L44 [2] https://github.com/openbmc/phosphor-bmc-code-mgmt/blob/4983b138ea8fc70bd66fe4d30500e6252629fa5d/common/src/software.cpp#L29
Change-Id: I873cbca97ae16b19bfbf622303f4d52e2563a62c Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com> Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
show more ...
|
| 7a3a521a | 20-Mar-2025 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: events: fix Redfish registry type for enums
Fix two issues with the Redfish registry generation: 1. Enums should be strings (and not numbers) in the MessageArgs. 2. Enums have a com
sdbus++: events: fix Redfish registry type for enums
Fix two issues with the Redfish registry generation: 1. Enums should be strings (and not numbers) in the MessageArgs. 2. Enums have a complex type which requires do a "type_tuple" processing before attempting to look up the Registry type.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: Ieda935f553dd73a22eedbe9ab87f0950554b95a2
show more ...
|
| 0cfa35a5 | 23-Jan-2025 |
Alexander Hansen <alexander.hansen@9elements.com> |
Fix uninitialized property, aserver instance
Had some
"conditional move or branch depends on uninitialized value",
and digging revealed this. The 'property.py' is modified to zero-initialize the p
Fix uninitialized property, aserver instance
Had some
"conditional move or branch depends on uninitialized value",
and digging revealed this. The 'property.py' is modified to zero-initialize the properties [1].
The newly introduced test cases show that the uninitialized value only occurred on the aserver instance for some reason.
Without this patch, one of these tests would fail.
The patch is more of a band-aid than anything else, since zero-initialization or default constructing sdbusplus::message::object_path is actually not a valid object path [2].
So there needs to be another patch to add some default constructor there.
While doing this, found that the
- interface.server.hpp.mako - interface.aserver.hpp.mako
use a different template to define the properties, which is confusing. Cleaned that up so they declare their properties in the same way.
Tested: Unit tests pass
References: [1] https://en.cppreference.com/w/cpp/language/zero_initialization [2] https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-object-path
Change-Id: I6ec5823f24fe9430546fc119e83e647ae2b3f8c9 Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>
show more ...
|
| 3ab4e58d | 26-Feb-2025 |
Igor Kanyuka <ifelmail@gmail.com> |
Add generation description for Registries
The script generates Registries, and it does not add descriptions. In spite it's not required, it's a good idea to have a description of what the registry i
Add generation description for Registries
The script generates Registries, and it does not add descriptions. In spite it's not required, it's a good idea to have a description of what the registry is. Generate the field from the registry name.
Testing: Put the modified script in phosphor-dbus-interfaces, built the project and then generated registries in bmcweb from generated Jsons. They got description fields populated: ``` $ git diff diff --git a/redfish-core/include/registries/openbmc_logging_message_registry.hpp b/redfish-core/include/registries/openbmc_logging_message_registry.hpp index 0333b4fd..b8f6f772 100644
Change-Id: I81c919fe1947949cbf69c5cb4481131fc8e0ee6f
--- a/redfish-core/include/registries/openbmc_logging_message_registry.hpp +++ b/redfish-core/include/registries/openbmc_logging_message_registry.hpp @@ -27,7 +27,7 @@ const Header header = { 1, "OpenBMC Message Registry for xyz.openbmc_project.Logging", "en", - "", + "OpenBMC Message Registry for xyz.openbmc_project.Logging", "OpenBMC_Logging", "OpenBMC", }; diff --git a/redfish-core/include/registries/openbmc_state_cable_message_registry.hpp b/redfish-core/include/registries/openbmc_state_cable_message_registry.hpp index 30f96254..2dee3e63 100644 --- a/redfish-core/include/registries/openbmc_state_cable_message_registry.hpp +++ b/redfish-core/include/registries/openbmc_state_cable_message_registry.hpp @@ -27,7 +27,7 @@ const Header header = { 0, "OpenBMC Message Registry for xyz.openbmc_project.State.Cable", "en", - "", + "OpenBMC Message Registry for xyz.openbmc_project.State.Cable", "OpenBMC_StateCable", "OpenBMC", }; diff --git a/redfish-core/include/registries/openbmc_state_leak_detector_group_message_registry.hpp b/redfish-core/include/registries/openbmc_state_leak_detector_group_message_registry.hpp index 4bf1e251..32d3498b 100644 --- a/redfish-core/include/registries/openbmc_state_leak_detector_group_message_registry.hpp +++ b/redfish-core/include/registries/openbmc_state_leak_detector_group_message_registry.hpp @@ -27,7 +27,7 @@ const Header header = { 0, "OpenBMC Message Registry for xyz.openbmc_project.State.Leak.DetectorGroup", "en", - "", + "OpenBMC Message Registry for xyz.openbmc_project.State.Leak.DetectorGroup", "OpenBMC_StateLeakDetectorGroup", "OpenBMC", }; ```
Change-Id: I8ed7b1117ba32bc545758175ccababf55527d363 Signed-off-by: Igor Kanyuka <ifelmail@gmail.com>
show more ...
|
| 9e5ffe19 | 19-Feb-2025 |
Igor Kanyuka <ifelmail@gmail.com> |
Add default value for message Resolution
According to the spec [1] the Resolution is required, but in the generator code it's added only if it's defined in the source. Use default value "None." if i
Add default value for message Resolution
According to the spec [1] the Resolution is required, but in the generator code it's added only if it's defined in the source. Use default value "None." if it's not defined.
[1] https://redfish.dmtf.org/schemas/v1/MessageRegistry.v1_6_3.json
Change-Id: I91ac6504c69bc2c0f0018a6e39a67563079fc983 Signed-off-by: Igor Kanyuka <ifelmail@gmail.com>
show more ...
|
| 4415a72d | 19-Feb-2025 |
Igor Kanyuka <ifelmail@gmail.com> |
Fix key name for MessageRegistry
Message registry stores messages in the Messages property. The generator uses the Message property instead. Fix this.
See the spec [1]
And other registries [2] and
Fix key name for MessageRegistry
Message registry stores messages in the Messages property. The generator uses the Message property instead. Fix this.
See the spec [1]
And other registries [2] and [3].
[1] https://redfish.dmtf.org/schemas/v1/MessageRegistry.v1_6_3.json [2] https://raw.githubusercontent.com/openbmc/bmcweb/refs/heads/master/redfish-core/include/registries/openbmc.json [2] https://redfish.dmtf.org/registries/Environmental.1.1.0.json
Change-Id: I3f8073f1b5c8085059d0335cc7ff3625cd26f756 Signed-off-by: Igor Kanyuka <ifelmail@gmail.com>
show more ...
|
| dd6efd17 | 01-Feb-2025 |
Patrick Williams <patrick@stwcx.xyz> |
meson: reformat with meson formatter
Apply the `meson format` results.
Change-Id: I024144165b08c727dd9621842f1a497830247155 Signed-off-by: Patrick Williams <patrick@stwcx.xyz> |
| 6bb7a8c9 | 23-Jan-2025 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: remove `PropertiesVariant` for empty properties
A previous commit changed behavior to always add `PropertiesVariant` even when there were no properties (and to use `variant<monostate>`). Th
sdbus++: remove `PropertiesVariant` for empty properties
A previous commit changed behavior to always add `PropertiesVariant` even when there were no properties (and to use `variant<monostate>`). The missing `PropertiesVariant` was used by some other repositories to detect if an interface had properties or not. Adding an empty `PropertiesVariant` breaks this expectation.
Switch back to having no type defined when there are no properties. Also, move the new `properties_t` over to the common template for consistency with the `PropertiesVariant` definition and for potential use elsewhere.
Fixes: 8aea1d814330 ("sdbus++: generate `properties` method for client harness") Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: I75b36412fe42eb44d5a638c6a8ad7a3ee9b835e3
show more ...
|
| 8aea1d81 | 17-Jan-2025 |
Adin Scannell <adin@scannell.ca> |
sdbus++: generate `properties` method for client harness
This uses the existing proxy `get_all_properties` method and allows for more efficient fetching of all properties in one shot. A struct is ge
sdbus++: generate `properties` method for client harness
This uses the existing proxy `get_all_properties` method and allows for more efficient fetching of all properties in one shot. A struct is generated for each type, and each field is initialized with its default value (but is not guaranteed to be deserialized).
As errors are less detectable (e.g. perhaps an expected property did not come through?), I considered whether the values in the struct should all be `std::optional`. However, given how other methods are used, it feels like this would result in a crash and assertion failure rather than saving anyone time and effort. The wrong type is detected a suitable exception is thrown in those cases.
Change-Id: Iff7712bd17db39f1ee5699f867e9f17a54eea21b Signed-off-by: Adin Scannell <adin@scannell.ca>
show more ...
|
| 5265a86b | 15-Jan-2025 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: events: fix OEM format in Redfish registry
Fix the following: - OEM fields should be identified with "Oem" in Redfish. - The top-level "Oem" section should be an object and not array
sdbus++: events: fix OEM format in Redfish registry
Fix the following: - OEM fields should be identified with "Oem" in Redfish. - The top-level "Oem" section should be an object and not array of objects.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: Ic63e6e728b5d58d7e6f0fb51f1c018cda2c3e613
show more ...
|
| 74eea519 | 03-Jan-2025 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++-gen-meson: leverage `install_dir` for custom targets
Meson has had a `install_dir` directive on `custom_target` which allows specifying per-output where the file should be installed. Leverag
sdbus++-gen-meson: leverage `install_dir` for custom targets
Meson has had a `install_dir` directive on `custom_target` which allows specifying per-output where the file should be installed. Leveraging this greatly simplifies the meson in consumers (such as phosphor-dbus-interfaces) and makes the install less error-prone.
The previous method for installing was to use a `install_subdir` call with large exclude lists (so that markdown did not end up in the include tree). The result of this was that many empty directories were created in the include, markdown, and registry install paths.
Using this method reduces by 25% the meson content in phosphor-dbus-interfaces.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: I2b03116f517caa75de902ac7e44e6923d6652cad
show more ...
|
| 31607399 | 02-Jan-2025 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: events: add meson support for registry generation
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: Ia8b95c291256726fdb729bcf886fa7f664ead4a5 |
| e598c595 | 02-Jan-2025 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: events: generate Redfish registry
Create an initial Redfish Message Registry from an events.yaml file. This includes a few OEM properties under "OpenBMC_Mapping" in order to give hints to
sdbus++: events: generate Redfish registry
Create an initial Redfish Message Registry from an events.yaml file. This includes a few OEM properties under "OpenBMC_Mapping" in order to give hints to bmcweb on how to do: - Map OpenBMC Events to Redfish Events. - Map AdditionalData fields to MessageArgs.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: I7260c2344a8509bbcad7a6653ccf2b3578427e45
show more ...
|
| ae0a8384 | 17-Nov-2024 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: events: improve bad enum diagnostics
When unpacking an event from JSON, if a bad enum value was given a generic STL exception resulted:
``` terminate called after throwing an instance of '
sdbus++: events: improve bad enum diagnostics
When unpacking an event from JSON, if a bad enum value was given a generic STL exception resulted:
``` terminate called after throwing an instance of 'std::bad_optional_access' ```
Improve this by using the sdbusplus `InvalidEnumString` exception: ``` terminate called after throwing an instance of 'sdbusplus::exception::InvalidEnumString' ```
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: I746f7265c8cf97e9a123915a123a4749d31e560c
show more ...
|
| fe1ebd43 | 09-Nov-2024 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: events: add object_path include
Event metadata often includes object_path. Add the header file into the generated events.hpp files.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Cha
sdbus++: events: add object_path include
Event metadata often includes object_path. Add the header file into the generated events.hpp files.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: Ia3da51483d25c6f65e6bcf977d47f65d59a37748
show more ...
|
| 17e54abc | 06-Nov-2024 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: events: adjust schema for metadata
Switch the preferred format of metadata from SNAKE_CASE to CamelCase. This has no affect on the metadata names in the phosphor-logging object as those wil
sdbus++: events: adjust schema for metadata
Switch the preferred format of metadata from SNAKE_CASE to CamelCase. This has no affect on the metadata names in the phosphor-logging object as those will still be generated as SNAKE_CASE.
SNAKE_CASE is a lossy format. Consider `BMC_ADDRESS`; it cannot be identified if BMC is an acronym or a word. Our conversion functions will convert this to `bmcaddress` when becoming a camelCase format since there is special handling for acronyms and this will appear equivalent to an acronym.
All of the generators for events are explicit to use `foo.camelCase` or `foo.SNAKE_CASE` as appropriate, so switching to CamelCase has little effect. The primary thing it does is make the event class member variables named sanely: `numberOfLogs` rather than `numberoflogs`.
This will require a minor edit to the few events that are defined in phosphor-dbus-interfaces already, which will be done at the same time.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: I10310986b9214aec99a3c7eabecf55f7054cdad0
show more ...
|
| b08d14dd | 05-Nov-2024 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: events: unpack an event from JSON
Generate code necessary to unpack a generated event from its JSON representation.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: I7a28617f
sdbus++: events: unpack an event from JSON
Generate code necessary to unpack a generated event from its JSON representation.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: I7a28617f3f0374968609328a44587b655a9141c1
show more ...
|
| 1800045e | 01-Nov-2024 |
Patrick Williams <patrick@stwcx.xyz> |
sdbus++: events: schema: explicitly prohibit unspecified properties
Modify the schema so that properties that do not belong are called out as a schema violation. It was easy for someone to accident
sdbus++: events: schema: explicitly prohibit unspecified properties
Modify the schema so that properties that do not belong are called out as a schema violation. It was easy for someone to accidentally add 'severity' on events, which should only be specified on errors. Adding it to the schema to prohibit makes it clearer what the expectations are.
Signed-off-by: Patrick Williams <patrick@stwcx.xyz> Change-Id: I3decce5cddce2ce7215f7351339157a2597fdb0b
show more ...
|