Commit graph

7103 commits

Author SHA1 Message Date
Pekka Paalanen 9c267e5b55 tests: move viewport creation into helpers
There will be a new test program using viewports and would like to share this
bit of code.

There are two behavioral changes:
- Compositor wp_viewporter interface version is no longer checked.
- client_create_viewport() does not leak the viewporter object.

test_viewporter_double_create needs to call bind_to_singleton_global() itself
so that the viewporter object still exists when the error event arrives.
Otherwise error verification fails.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-03-11 17:11:03 +02:00
Pekka Paalanen 9f53edd461 pixman-renderer: half-fix bilinear sampling on edges
When weston-desktop-shell uses a solid color for the wallpaper, it creates a
1x1 buffer and uses wp_viewport to scale that up to fullscreen. It's a very
nice memory saving optimization.

If you also have output scale != buffer scale, it means pixman-renderer chooses
bilinear filter. Arguably pixman-renderer should choose bilinear filter also
when wp_viewport implies scaling, but it does not. As w-d-s always sets buffer
scale from output scale, triggering the bilinear filter needs some effort.

What happens when you sample with bilinear filter from a 1x1 buffer, stretching
it to cover a big area? Depends on the repeat mode. The default repeat mode is
NONE, which means that samples outside of the buffer come out as (0,0,0,0).
Bilinear filter makes it so that every sampling point on the 1x1 buffer except
the very center is actually a mixture of the pixel value and (0,0,0,0). The
resulting color is no longer opaque, but the renderer and damage tracking
assume it is. This leads to the issue 373.

Fix half of the issue by using repeat mode PAD which corresponds to OpenGL
CLAMP_TO_EDGE. GL-renderer already uses CLAMP_TO_EDGE always.

This is only a half-fix, because composite_clipped() cannot actually be fixed.
It relies on repeat mode NONE to work. It would need a whole different approach
to rendering potentially non-axis-aligned regions exactly like GL-renderer.

Fixes: https://gitlab.freedesktop.org/wayland/weston/issues/373

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-03-11 15:57:45 +02:00
Daniel Stone 5450456da2 compositor: Fail on invalid transform for headless
As in aaf35586f4, we want to fail when we are passed an invalid
transform name, not just blindly configure on using the normal
transform. The previous commit missed the callsite from the headless
backend's command-line parsing.

Fix this so that headless fails when an invalid transform is specified
on the command line.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2020-03-11 10:38:08 +00:00
Pekka Paalanen 536873c58e tests: print image difference statistics
When a test fails and it produces a difference image, also compute the min/max
per-channel signed difference statistics. These numbers can be used to adjust
the fuzz needed for fuzzy_match_pixels() to pass. Otherwise one would have to
manually inspect the reference and result images and figure out the values.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-03-10 13:40:00 +00:00
Daniel Stone 1c0507b12a compositor: Use weston_head transform for output default
If the output only has a single weston_head attached to it, take its
declared transform as the default transform.

With the previous patches, this allows a device declaring the KMS 'panel
orientation' property (e.g. through DeviceTree) to autoconfigure to the
correct display rotation when running Weston.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2020-03-06 21:50:38 +00:00
Lucas Stach 72e7a1ed48 backend-drm: Parse KMS panel orientation property, apply to weston_head
The KMS 'panel orientation' property allows the driver to statically
declare a fixed rotation of an output device. Now that weston_head has a
transform member, plumb the KMS property through to weston_head so the
compositor can make a smarter choice out of the box.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
[daniels: Extracted from one of Lucas's patches]
Signed-off-by: Daniel Stone <daniels@collabora.com>
2020-03-06 21:50:38 +00:00
Lucas Stach a69cb711cc libweston: Add transform to weston_head
Like physical size, subpixel arrangement, etc, transform advises of a
physical transform of a head, if present.

This commit adds the transform member and setter to weston_head, however
it is currently unused.

Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
[daniels: Extracted from one of Lucas's patches.]
Signed-off-by: Daniel Stone <daniels@collabora.com>
2020-03-06 21:50:38 +00:00
Daniel Stone aaf35586f4 compositor: Fail output configuration on invalid transform
If an invalid transformation is provided for an output, fail the output
configuration rather than continuing on using whatever we chose as the
default transform.

After !383, this will result in configurations using the old definition
failing and exiting, rather than continuing on the wrong way around.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2020-03-06 21:50:38 +00:00
Daniel Stone 31af69d868 compositor: Fix default transforms when output section declared
Regardless of the default transform passed in, weston_parse_transform
would always return 'normal' if there was an output section. This is
because, if a section was declared for that output, it would ask
weston_config for the transform, with the default being 'normal'.

Fix it so we return the passed-in default transform when we have a
matching output section without a transform key. If the transform is
declared but invalid, we can remove the line resetting to the default
transform, because we've already set the default transform up top.

Signed-off-by: Daniel Stone <daniels@collabora.com>
2020-03-06 21:47:51 +00:00
Guillaume Champagne 467e6b9883 backend-rdp: enable undefined functions errors.
b_lundef was overriden for the RDP backend since it triggered linking
errors due to functions that were defined in a missing dependency. This
issue was fixed, so the override is removed. The global project's
linker parameters are now applied to the RDP backend.

Signed-off-by: Guillaume Champagne <champagne.guillaume.c@gmail.com>
2020-03-05 14:43:58 +00:00
Guillaume Champagne 7f42b350de backend-rdp: fix unresolved symbols errors
The RDP backend uses functions defined by the Windows Portable Runtime
library (WinPR). The library's code is contained within FreeRDP
repository, but it is packaged as its own library (seperate pkg-config
file).

WinPR is added as a dependency to the RDP backend. The version 2.0 is
choosen as the version to on since the backend depends on FreeRDP 2.0.

Signed-off-by: Guillaume Champagne <champagne.guillaume.c@gmail.com>
2020-03-05 14:43:58 +00:00
Pekka Paalanen 147e67c425 tests: add buffer transform tests
This patch continues the buffer and output transforms testing by iterating
through a representative selection of buffer transforms and scales.

For more details, see the previous patch "tests: add output transform tests".

https://gitlab.freedesktop.org/wayland/weston/issues/52

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-28 16:02:10 +02:00
Pekka Paalanen 97359ba5c5 tests: add output transform tests
This goes through all output transforms with two different buffer transforms
and verifies the visual output against reference images.

This commit introduces a new test input image 'basic-test-card.png'. It is a
small image with deliberately odd and indivisible dimensions to provoke bad
assumptions about image sizes. It contains red, green and blue areas which are
actually text that makes it very obvious if you have e.g. color channels
swapped. It has a white thick circle to highlight aspect ratio issues, and an
orange cross to show a mixed color. The white border is for contrast and a 1px
wide detail. The whole design makes it clear if the image happens to be rotated
or flipped in any way.

The image has one pixel wide transparent border so that bilinear sampling
filter near the edges of the image would produce the same colors with both
Pixman- and GL-renderers which handle the out-of-image samples fundamentally
differently: Pixman assumes (0, 0, 0, 0) samples outside of the image, while
GL-renderer clamps sample coordinates to the edge essentially repeating the
edge pixels.

It would have been "easy" to create a full matrix of
every output scale & transform x every buffer scale & transform, but that
would have resulted in 2 renderers * 8 output transforms * 3 output scales *
8 buffer transforms * 3 buffer scales = 1152 test cases that would have all
ran strictly serially because our test harness has no parallelism inside one
test program. That would have been slow to run, and need a lot more reference
images too.

Instead, I chose to iterate separately through all output scales & transforms
(this patch) and all buffer scales & transforms (next patch). This limits the
number of test cases in this patch to 56, and allows the two test programs to
run in parallel.

I did not even pick all possible scale & transform combinations here, but just
what I think is a representative sub-set to hopefully exercise all the code
paths.

https://gitlab.freedesktop.org/wayland/weston/issues/52

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-28 15:07:51 +02:00
Pekka Paalanen 20026a55d6 tests: expand allowed pixel fuzz for GL
Running with Mesa 20.1.0-devel (git-c7617d8908) GL renderer:
Radeon RX 550 Series (POLARIS11, DRM 3.27.0, 4.19.0-2-amd64, LLVM 8.0.1)

I found output-tranform test (a future patch) to produce exactly this much more
difference between Pixman and GL rendererers.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 16:08:42 +02:00
Pekka Paalanen 080d85b8fb tests: implement client_destroy()
It turns out that if the client is not explicitly destroyed, it will remain
connected until the compositor shuts down because there is no more a client
process that would terminate.

Usually this is not a problem, but if a test file has multiple screenshooting
tests, the windows from earlier tests in the file will remain on screen. That
is not wanted, hence implement client destruction.

To properly destroy a client, we also need a list of outputs. They used to be
simply leaked. This does not fix wl_registry.global_remove for wl_outputs, that
is left for a time when a test will actually need that.

This patch makes only ivi-shell-app test use the new client_destroy() to show
that it actually works. The added log scopes prove it: destroy requests get
sent. Sprinkling client_destroy() around in all other tests is left for a time
when it is actually necessary.

ivi-shell-app is a nicely simple test doing little else, hence I picked it.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 16:08:42 +02:00
Pekka Paalanen 444f1a8e22 tests: re-order test naming pattern
The string from get_test_name() can be used for writing screenshot files and
others. Starting the name with the fixture number makes an alphabetized listing
of output files look unorganized.

Let's change the test name to begin with the test (source) name with fixture
and element numbers as suffixes. That makes a file listing easier to look
through, when you have multiple tests each saving multiple screenshot files.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 16:08:42 +02:00
Pekka Paalanen 1eb30468ea tests: add get_test_fixture_index()
A future test wants to access the fixture data array for the currently running
fixture index to log the test description. This patch provides access to the
array index.

Rather than adding more gloabl variables, I changed the type of the existing
one which feels slightly cleaner.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 16:08:42 +02:00
Pekka Paalanen 0ce5a19b7e tests: add scale and transform compositor options
With these, a test can initialize the headless-backend with non-default scale
and transform which allows testing output scales and transforms.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 16:08:42 +02:00
Pekka Paalanen dd84ecf44d compositor: add scale cmdline option for headless
The test suite wants to start using different output scales, and this is the
easiest API to configure it.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 16:08:42 +02:00
Pekka Paalanen 636fc15f20 tests: allow verify_screen_content() w/o ref image
Allow the reference image to be NULL or missing so that it does not even
attempt to load a reference image or compare it. You cannot just point the
reference image to an arbitrary image because the comparison functions can
abort due to size mismatch. This makes bootstrapping new tests easier when you
do not yet have a reference image.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 16:08:42 +02:00
Pekka Paalanen 7009806b94 tests: rename check_screen() to verify_screen_content() + doc
The old name felt too... short.

The return type is changed to bool; fits better for a success/failure.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 16:08:42 +02:00
Pekka Paalanen 9b682302b8 tests: move check_screen() into client helpers
This will be useful in more tests.

No changes to the code, aside from dropping one 'static'.

Copyright 2017 is taken from git-blame of the moved code.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 16:08:42 +02:00
Pekka Paalanen 8060d826b7 Redefine output rotations
It was discovered in issue #99 that the implementations of the 90 and 270
degree rotations were actually the inverse of what the Wayland specification
spelled out. This patch fixes the libweston implementation to follow the
specification.

As a result, the behaviour of the the weston.ini transform key also changes. To
force all users to re-think their configuration, the transform key values are
also changed. Since Weston and libweston change their behaviour, the handling
of clients' buffer transform changes too.

All the functions had their 90/270 cases simply swapped, probably due to
confusion of whether WL_OUTPUT_TRANSFORM_* refers to rotating the monitor or
the content.

Hint: a key to understanding weston_matrix_rotate_xy(m, c, s) is that the
rotation matrix is formed as

  c -s
  s  c

that is, it's column-major. This fooled me at first.

Fixing window.c fixes weston-terminal and weston-transformed.

In simple-damage, window_get_transformed_ball() is fixed to follow the proper
transform definitions, but the fix to the viewport path in redraw() is purely
mechanical.  The viewport path looks broken to me in the presence of any
transform, but it is not this patch's job to fix it.

Screen-share fix just repeats the general code fix pattern, I did not even try
to understand that bit.

https://gitlab.freedesktop.org/wayland/weston/issues/99

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 11:08:48 +00:00
Pekka Paalanen 0df4477924 libweston: document weston_transformed_*()
Clarifies which direction the transformation happens. All exported function
need documentation.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 11:08:48 +00:00
Pekka Paalanen 8555877c6c clients: transformed does not recognize -d
It has no such command line option.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-27 11:08:48 +00:00
Veeresh Kadasani 9cb81e440a ivi-application: fix grammar
Signed-off-by: Veeresh Kadasani <external.vkadasani@jp.adit-jv.com>
2020-02-26 15:06:46 +00:00
ahe 401b8767e9 fullscreen-shell/fullscreen-shell.c: prevent seat_created() from being called with l == NULL 2020-02-26 14:19:21 +01:00
Pekka Paalanen ea3b7857f2 Revert "CI: do not attempt to test GL-renderer"
This reverts commit 1eae54714f.

We install a fixed Mesa into the CI image, so these tests can pass now.

Fixes: https://gitlab.freedesktop.org/wayland/weston/issues/358

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-18 15:24:38 +02:00
Pekka Paalanen 8bd46c75f9 CI: build a Mesa shapshot for getImage/putImage on pbuffer swrast
c7617d8908
is necessary for running GL-renderer with llvmpipe in Gitlab CI.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-18 15:24:38 +02:00
Scott Anderson 4ed62d47cc gl-renderer: Move EGL display creation to egl-glue.c
It makes more sense for it to be there instead.

Signed-off-by: Scott Anderson <scott.anderson@collabora.com>
2020-02-18 18:11:26 +13:00
Scott Anderson 4ed58b1d47 gl-renderer: Move platform extension checks to EGL client setup
This removes the duplicate checks for EGL_EXT_platform_base.

Signed-off-by: Scott Anderson <scott.anderson@collabora.com>
2020-02-18 18:06:52 +13:00
Scott Anderson 7725415478 gl-renderer: Move get_platform_display to EGL client setup
This is to put more of the EGL client extension handling in the same
place. This also adds a boolean to check if EGL_EXT_platform_base is
supported, similar to other extensions we check.

Signed-off-by: Scott Anderson <scott.anderson@collabora.com>
2020-02-18 17:41:06 +13:00
Scott Anderson dddb592cfb gl-renderer: Move EGL client extension handling earlier
EGL client extensions are not tied to the EGLDisplay we create, and have
an effect on how we create the EGLDisplay. Since we're using this to
look for EGL_EXT_platform_base, it makes more sense for this to be near
the start of the GL renderer initialization.

Signed-off-by: Scott Anderson <scott.anderson@collabora.com>
2020-02-18 17:38:27 +13:00
Simon Ser 598d3a15b7
clients/window: fail earlier when frame_create fails
This adds a new NULL check to fail earlier when frame_create fails. This can
happen because PNG files couldn't be loaded from the data directory.

Signed-off-by: Simon Ser <contact@emersion.fr>
2020-02-10 15:49:20 +01:00
Leandro Ribeiro d65483ec75 weston-log-wayland: make stream_destroy() use weston_log_subscriber_release()
Make stream_destroy() use weston_log_subscriber_release().
This avoids code duplication and allow us to destroy
weston_log_subscriber_get_only_subscription(), since it's
being used only in this case and it's internal.

Calls for weson_log_subscriber_release() leads to
weston_log_debug_wayland_to_destroy(), which should not
send an error event when the stream has already been closed.

Also, stream_destroy() shouldn't lead to an event error, as
it is a wl_resource destroy handler. So close the stream before
calling weston_log_subscriber_release() in stream_destroy()

Signed-off-by: Leandro Ribeiro <leandrohr@riseup.net>
2020-02-10 10:53:50 +00:00
Leandro Ribeiro 9aaaf96a6a compositor: destroy log context only after the destruction of subscribers
Before commit "weston-log: destroy subscriptions with
destruction of subscribers", we had to destroy subscribers
before the log context. Currently there's no required order,
both are valid.

But since we've created log context before the subscribers,
we can destroy it after them. This is a style change and
also a prove that now this order is valid as well.

Signed-off-by: Leandro Ribeiro <leandrohr@riseup.net>
2020-02-10 10:53:50 +00:00
Leandro Ribeiro 97d2d69909 weston-log: share code between weston_log_scope_destroy() and weston_log_subscriber_release()
Both weston_log_scope_destroy() and weston_log_subscriber_release()
have calls for destroy_subscription(). We can move this call to
weston_log_subscription_destroy() without losing anything and
avoiding repetition.

Signed-off-by: Leandro Ribeiro <leandrohr@riseup.net>
2020-02-10 10:53:50 +00:00
Leandro Ribeiro 23491cd931 weston-log: destroy subscriptions with destruction of subscribers
The subscription is directly related to both the log scope and
the subscriber. It makes no sense to destroy one of them and
keep the subscriptions living.

We only had code to destroy subscription with
the destruction of log scopes. Add code to destroy
subscriptions with destruction of subscribers.

Signed-off-by: Leandro Ribeiro <leandrohr@riseup.net>
2020-02-10 10:53:50 +00:00
Leandro Ribeiro 1ded661aac weston-log: merge functions that destroy different types of subscribers
Log subscriber API is not type-safe. File and flight recorder
subscribers are created with functions that return
weston_log_subscriber objects. But there's a problem: to destroy
these objects you have to call the right function for each type
of subscriber, and a user calling the wrong destroy function
wouldn't get a warning.

Merge functions that destroy different types of subscribers, making
the log subscriber API type-safe.

Signed-off-by: Leandro Ribeiro <leandrohr@riseup.net>
2020-02-10 10:53:50 +00:00
Leandro Ribeiro 8c02ea1069 weston-log: rename weston_log_subscriber::destroy to destroy_subscription
weston_log_subscriber has a member named destroy. There are
other structs (weston_output, for instance) that have this
member, and by convention it is a pointer to a function
that destroys the struct.

In weston_log_subscriber it is being used to destroy
subscriptions of the debug protocol, and not the subscriber,
so this name is misleading. Rename it to destroy_subscription.

Signed-off-by: Leandro Ribeiro <leandrohr@riseup.net>
2020-02-10 10:53:50 +00:00
Philipp Zabel 4b1de0112b build: add rpath to modules that use symbols from libexec_weston
The cms-static, desktop-shell, hmi-controller, ivi-shell, and screen-share
modules use symbols from libexec_weston, e.g.:

  $ ldd /usr/lib/x86_64-linux-gnu/weston/desktop-shell.so | grep "not found"
  	libexec_weston.so.0 => not found

Loading these modules from weston happens to work because the weston executable
itself links against libexec_weston, and has an rpath set. Still, these modules
depend on a library in a non-standard location. Adding an rpath could help
static checkers to make sure all shared objects' dependencies are present.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
2020-02-06 09:00:42 +00:00
Pekka Paalanen 741fca40b5 tests: run subsurface-shot on GL too
This adds the necessary fuzz to image matching to let GL-renderer pass.
The difference is due to rounding. weston-test-desktop-shell.c uses

weston_surface_set_color(dts->background_surface, 0.16, 0.32, 0.48, 1.);

to set the background color. Pixman-renderer will truncate those to uint8, but
GL-renderer seems to round instead, which causes the +1 in background color
channel values.

	0.16 * 255 = 40.8
	0.32 * 255 = 81.6
	0.48 * 255 = 122.4

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-05 11:13:51 +00:00
Pekka Paalanen 1eae54714f CI: do not attempt to test GL-renderer
Because of https://gitlab.freedesktop.org/mesa/mesa/issues/2219 it would crash,
so disable GL-renderer.

https://gitlab.freedesktop.org/wayland/weston/issues/358 shall revert this.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-05 11:13:51 +00:00
Pekka Paalanen 1618697dc3 build: add test-gl-renderer option
This shall be used by CI due to https://gitlab.freedesktop.org/mesa/mesa/issues/2219

It defaults to true, meaning that people by default will be running the
GL-renderer tests. It works fine on hardware drivers, just not llvmpipe.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-05 11:13:51 +00:00
Pekka Paalanen 007ab1e5a4 tests: add range argument for fuzzy image matching
The fuzzy range will be used with GL-renderer testing, as it may produce
slightly different images than Pixman-renderer yet still correct results.

Such allowed differences are due to different rounding.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-05 11:13:51 +00:00
Pekka Paalanen 8fc4b59bfd weston-log-flight-rec: allow re-running a compositor
weston_primary_flight_recorder_ring_buffer needs to be cleared on destruction
of the subscriber it was assigned from so that a compositor and be re-executed
in-process (static variables do not get re-initialized automatically).

This will be used by the test harness when it will execute wet_main() multiple
times in the same process. Otherwise it would hit the assert in
weston_log_subscriber_create_flight_rec().

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
2020-02-05 11:13:51 +00:00
Sebastian Wick f0d3a61491 shared: guard all the seal logic behind HAVE_MEMFD_CREATE
The initial version of os_ro_anonymous_file missed two guards around the
seal logic which leads to a compilation error on older systems.

Also make the check for a read-only file symmetric in
os_ro_anonymous_file_get_fd and os_ro_anonymous_file_put_fd.

Signed-off-by: Sebastian Wick <sebastian@sebastianwick.net>
2020-02-05 10:40:25 +01:00
Guillaume Champagne 7bce28b543 tests: release resources on compositor destruction
Releases touch devices and seat if they were allocated, clean up the
layers and free the weston_test structure.

Signed-off-by: Guillaume Champagne <champagne.guillaume.c@gmail.com>
2020-02-04 13:30:19 +00:00
Guillaume Champagne 9096dee405 headless: fix uninitialized variable
`no_outputs` is declared on the stack and left uninitialized if no
weston option changing its value is provided.

Signed-off-by: Guillaume Champagne <champagne.guillaume.c@gmail.com>
2020-02-04 13:30:19 +00:00
Daniel Stone d76947b666 gl-renderer: Avoid double-free on init failure
If gl-renderer fails its initialisation, we return to compositor
teardown, which will try to free the renderer if ec->renderer was set.
This is unfortunate when we've already torn it down whilst failing
gl-renderer init, so just clear the renderer member so we don't try to
tear down twice.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Reported-by: Emil Velikov <emil.velikov@collabora.com>
2020-02-03 20:01:21 +00:00