From e31ed86a53d07f6902644cc0d063ff89b89323e3699b19b467accc92e920a6c6 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 10 Dec 2020 18:58:17 +0000 Subject: [PATCH 1/2] Accepting request 854646 from home:lwfinger:branches:Virtualization OBS-URL: https://build.opensuse.org/request/show/854646 OBS-URL: https://build.opensuse.org/package/show/Virtualization/virtualbox?expand=0&rev=579 --- linux-5.10-framebuffer-fixes.patch | 288 +++++++++++++++++++++++++++-- 1 file changed, 271 insertions(+), 17 deletions(-) diff --git a/linux-5.10-framebuffer-fixes.patch b/linux-5.10-framebuffer-fixes.patch index 9207736..f2104fb 100644 --- a/linux-5.10-framebuffer-fixes.patch +++ b/linux-5.10-framebuffer-fixes.patch @@ -2,28 +2,232 @@ Index: b/src/VBox/Additions/linux/drm/vbox_drv.h =================================================================== --- a/src/VBox/Additions/linux/drm/vbox_drv.h +++ b/src/VBox/Additions/linux/drm/vbox_drv.h -@@ -205,6 +205,13 @@ static inline void drm_gem_object_put(st - } - #endif +@@ -184,6 +184,9 @@ + #include + #include + #include ++#if RTLNX_VER_MIN(5,10,0) ++# include ++#endif -+#ifndef TTM_PL_FLAG_SYSTEM -+#define TTM_PL_FLAG_SYSTEM (1 << TTM_PL_SYSTEM) -+#endif -+#ifndef TTM_PL_FLAG_VRAM -+#define TTM_PL_FLAG_VRAM (1 << TTM_PL_VRAM) -+#endif + #include "vboxvideo_guest.h" + #include "vboxvideo_vbe.h" +@@ -453,7 +456,10 @@ int vbox_bo_create(struct drm_device *de + int vbox_gem_create(struct drm_device *dev, + u32 size, bool iskernel, struct drm_gem_object **obj); + +-int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr); ++#define VBOX_MEM_TYPE_VRAM 0x1 ++#define VBOX_MEM_TYPE_SYSTEM 0x2 + - #define DRIVER_AUTHOR VBOX_VENDOR ++int vbox_bo_pin(struct vbox_bo *bo, u32 mem_type, u64 *gpu_addr); + int vbox_bo_unpin(struct vbox_bo *bo); - #define DRIVER_NAME "vboxvideo" + static inline int vbox_bo_reserve(struct vbox_bo *bo, bool no_wait) +@@ -478,7 +484,7 @@ static inline void vbox_bo_unreserve(str + ttm_bo_unreserve(&bo->bo); + } + +-void vbox_ttm_placement(struct vbox_bo *bo, int domain); ++void vbox_ttm_placement(struct vbox_bo *bo, u32 mem_type); + int vbox_bo_push_sysram(struct vbox_bo *bo); + int vbox_mmap(struct file *filp, struct vm_area_struct *vma); + +Index: b/src/VBox/Additions/linux/drm/vbox_fb.c +=================================================================== +--- a/src/VBox/Additions/linux/drm/vbox_fb.c ++++ b/src/VBox/Additions/linux/drm/vbox_fb.c +@@ -295,7 +295,7 @@ static int vboxfb_create(struct drm_fb_h + if (ret) + return ret; + +- ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL); ++ ret = vbox_bo_pin(bo, VBOX_MEM_TYPE_VRAM, NULL); + if (ret) { + vbox_bo_unreserve(bo); + return ret; +Index: b/src/VBox/Additions/linux/drm/vbox_mode.c +=================================================================== +--- a/src/VBox/Additions/linux/drm/vbox_mode.c ++++ b/src/VBox/Additions/linux/drm/vbox_mode.c +@@ -227,7 +227,7 @@ static int vbox_crtc_set_base(struct drm + if (ret) + return ret; + +- ret = vbox_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); ++ ret = vbox_bo_pin(bo, VBOX_MEM_TYPE_VRAM, &gpu_addr); + vbox_bo_unreserve(bo); + if (ret) + return ret; Index: b/src/VBox/Additions/linux/drm/vbox_ttm.c =================================================================== --- a/src/VBox/Additions/linux/drm/vbox_ttm.c +++ b/src/VBox/Additions/linux/drm/vbox_ttm.c -@@ -373,11 +373,23 @@ void vbox_ttm_placement(struct vbox_bo * +@@ -41,6 +41,7 @@ + #define PLACEMENT_FLAGS(placement) ((placement).flags) + #endif + ++ + static inline struct vbox_private *vbox_bdev(struct ttm_bo_device *bd) + { + return container_of(bd, struct vbox_private, ttm.bdev); +@@ -125,6 +126,7 @@ static bool vbox_ttm_bo_is_vbox_bo(struc + return false; + } + ++#if RTLNX_VER_MAX(5,10,0) + static int + vbox_bo_init_mem_type(struct ttm_bo_device *bdev, u32 type, + struct ttm_mem_type_manager *man) +@@ -148,6 +150,7 @@ vbox_bo_init_mem_type(struct ttm_bo_devi + + return 0; + } ++#endif + + static void + vbox_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) +@@ -157,7 +160,7 @@ vbox_bo_evict_flags(struct ttm_buffer_ob + if (!vbox_ttm_bo_is_vbox_bo(bo)) + return; + +- vbox_ttm_placement(vboxbo, TTM_PL_FLAG_SYSTEM); ++ vbox_ttm_placement(vboxbo, VBOX_MEM_TYPE_SYSTEM); + *pl = vboxbo->placement; + } + +@@ -167,11 +170,12 @@ static int vbox_bo_verify_access(struct + return 0; + } + ++#if RTLNX_VER_MAX(5,10,0) + static int vbox_ttm_io_mem_reserve(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) + { +- struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + struct vbox_private *vbox = vbox_bdev(bdev); ++ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + + mem->bus.addr = NULL; + mem->bus.offset = 0; +@@ -194,12 +198,53 @@ static int vbox_ttm_io_mem_reserve(struc + } + return 0; + } ++#else ++static int vbox_ttm_io_mem_reserve(struct ttm_bo_device *bdev, ++ struct ttm_resource *mem) ++{ ++ struct vbox_private *vbox = vbox_bdev(bdev); ++ mem->bus.addr = NULL; ++ mem->bus.offset = 0; ++ mem->size = mem->num_pages << PAGE_SHIFT; ++ mem->start = 0; ++ mem->bus.is_iomem = false; ++ switch (mem->mem_type) { ++ case TTM_PL_SYSTEM: ++ /* system memory */ ++ return 0; ++ case TTM_PL_VRAM: ++ mem->bus.offset = mem->start << PAGE_SHIFT; ++ mem->start = pci_resource_start(vbox->dev->pdev, 0); ++ mem->bus.is_iomem = true; ++ break; ++ default: ++ return -EINVAL; ++ } ++ return 0; ++} ++#endif + ++ ++ ++#if RTLNX_VER_MIN(5,10,0) ++static void vbox_ttm_io_mem_free(struct ttm_bo_device *bdev, ++ struct ttm_resource *mem) ++{ ++} ++#else + static void vbox_ttm_io_mem_free(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) + { + } ++#endif + ++#if RTLNX_VER_MIN(5,10,0) ++static void vbox_ttm_tt_destroy(struct ttm_bo_device *bdev, struct ttm_tt *tt) ++{ ++ ttm_tt_fini(tt); ++ kfree(tt); ++} ++#else + static void vbox_ttm_backend_destroy(struct ttm_tt *tt) + { + ttm_tt_fini(tt); +@@ -209,6 +254,7 @@ static void vbox_ttm_backend_destroy(str + static struct ttm_backend_func vbox_tt_backend_func = { + .destroy = &vbox_ttm_backend_destroy, + }; ++#endif + + #if RTLNX_VER_MAX(4,17,0) && !RTLNX_RHEL_MAJ_PREREQ(7,6) && !RTLNX_SUSE_MAJ_PREREQ(15,1) && !RTLNX_SUSE_MAJ_PREREQ(12,5) && !defined(SUSE_SLE12) + static struct ttm_tt *vbox_ttm_tt_create(struct ttm_bo_device *bdev, +@@ -226,7 +272,9 @@ static struct ttm_tt *vbox_ttm_tt_create + if (!tt) + return NULL; + ++#if RTLNX_VER_MAX(5,10,0) + tt->func = &vbox_tt_backend_func; ++#endif + #if RTLNX_VER_MAX(4,17,0) && !RTLNX_RHEL_MAJ_PREREQ(7,6) && !RTLNX_SUSE_MAJ_PREREQ(15,1) && !RTLNX_SUSE_MAJ_PREREQ(12,5) && !defined(SUSE_SLE12) + if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { + #else +@@ -261,11 +309,16 @@ static void vbox_ttm_tt_unpopulate(struc + + static struct ttm_bo_driver vbox_bo_driver = { + .ttm_tt_create = vbox_ttm_tt_create, ++#if RTLNX_VER_MIN(5,10,0) ++ .ttm_tt_destroy = vbox_ttm_tt_destroy, ++#endif + #if RTLNX_VER_MAX(4,17,0) + .ttm_tt_populate = vbox_ttm_tt_populate, + .ttm_tt_unpopulate = vbox_ttm_tt_unpopulate, + #endif ++#if RTLNX_VER_MAX(5,10,0) + .init_mem_type = vbox_bo_init_mem_type, ++#endif + #if RTLNX_VER_MIN(4,10,0) || RTLNX_RHEL_MAJ_PREREQ(7,4) + .eviction_valuable = ttm_bo_eviction_valuable, + #endif +@@ -318,8 +371,13 @@ int vbox_mm_init(struct vbox_private *vb + #endif + } + ++#if RTLNX_VER_MIN(5,10,0) ++ ret = ttm_range_man_init(bdev, TTM_PL_VRAM, false, ++ vbox->available_vram_size >> PAGE_SHIFT); ++#else + ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, + vbox->available_vram_size >> PAGE_SHIFT); ++#endif + if (ret) { + DRM_ERROR("Failed ttm VRAM init: %d\n", ret); + goto err_device_release; +@@ -359,7 +417,7 @@ void vbox_mm_fini(struct vbox_private *v + #endif + } + +-void vbox_ttm_placement(struct vbox_bo *bo, int domain) ++void vbox_ttm_placement(struct vbox_bo *bo, u32 mem_type) + { + u32 c = 0; + #if RTLNX_VER_MAX(3,18,0) && !RTLNX_RHEL_MAJ_PREREQ(7,2) +@@ -372,15 +430,36 @@ void vbox_ttm_placement(struct vbox_bo * + bo->placement.placement = bo->placements; bo->placement.busy_placement = bo->placements; - if (domain & TTM_PL_FLAG_VRAM) +- if (domain & TTM_PL_FLAG_VRAM) ++ if (mem_type & VBOX_MEM_TYPE_VRAM) { +#if RTLNX_VER_MIN(5,10,0) + bo->placements[c].mem_type = TTM_PL_VRAM; + PLACEMENT_FLAGS(bo->placements[c++]) = @@ -31,8 +235,21 @@ Index: b/src/VBox/Additions/linux/drm/vbox_ttm.c +#else PLACEMENT_FLAGS(bo->placements[c++]) = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM; +- if (domain & TTM_PL_FLAG_SYSTEM) +#endif - if (domain & TTM_PL_FLAG_SYSTEM) ++ } ++ if (mem_type & VBOX_MEM_TYPE_SYSTEM) { ++#if RTLNX_VER_MIN(5,10,0) ++ bo->placements[c].mem_type = TTM_PL_SYSTEM; ++ PLACEMENT_FLAGS(bo->placements[c++]) = ++ TTM_PL_MASK_CACHING; ++#else + PLACEMENT_FLAGS(bo->placements[c++]) = + TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; +- if (!c) ++#endif ++ } ++ if (!c) { +#if RTLNX_VER_MIN(5,10,0) + bo->placements[c].mem_type = TTM_PL_SYSTEM; + PLACEMENT_FLAGS(bo->placements[c++]) = @@ -41,6 +258,43 @@ Index: b/src/VBox/Additions/linux/drm/vbox_ttm.c PLACEMENT_FLAGS(bo->placements[c++]) = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; +#endif - if (!c) - PLACEMENT_FLAGS(bo->placements[c++]) = - TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; ++ } + + bo->placement.num_placement = c; + bo->placement.num_busy_placement = c; +@@ -414,7 +493,7 @@ int vbox_bo_create(struct drm_device *de + vboxbo->bo.bdev->dev_mapping = dev->dev_mapping; + #endif + +- vbox_ttm_placement(vboxbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); ++ vbox_ttm_placement(vboxbo, VBOX_MEM_TYPE_VRAM | VBOX_MEM_TYPE_SYSTEM); + + acc_size = ttm_bo_dma_acc_size(&vbox->ttm.bdev, size, + sizeof(struct vbox_bo)); +@@ -452,7 +531,7 @@ static inline u64 vbox_bo_gpu_offset(str + #endif + } + +-int vbox_bo_pin(struct vbox_bo *bo, u32 pl_flag, u64 *gpu_addr) ++int vbox_bo_pin(struct vbox_bo *bo, u32 mem_type, u64 *gpu_addr) + { + #if RTLNX_VER_MIN(4,16,0) || RTLNX_RHEL_MAJ_PREREQ(7,6) || RTLNX_SUSE_MAJ_PREREQ(15,1) || RTLNX_SUSE_MAJ_PREREQ(12,5) || defined(SUSE_SLE12) + struct ttm_operation_ctx ctx = { false, false }; +@@ -467,7 +546,7 @@ int vbox_bo_pin(struct vbox_bo *bo, u32 + return 0; + } + +- vbox_ttm_placement(bo, pl_flag); ++ vbox_ttm_placement(bo, mem_type); + + for (i = 0; i < bo->placement.num_placement; i++) + PLACEMENT_FLAGS(bo->placements[i]) |= TTM_PL_FLAG_NO_EVICT; +@@ -540,7 +619,7 @@ int vbox_bo_push_sysram(struct vbox_bo * + if (bo->kmap.virtual) + ttm_bo_kunmap(&bo->kmap); + +- vbox_ttm_placement(bo, TTM_PL_FLAG_SYSTEM); ++ vbox_ttm_placement(bo, VBOX_MEM_TYPE_SYSTEM); + + for (i = 0; i < bo->placement.num_placement; i++) + PLACEMENT_FLAGS(bo->placements[i]) |= TTM_PL_FLAG_NO_EVICT; From c59a91288f44646a07458dff82367f4ddf3ce0fc6b2beb18f12d92be2872c739 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 12 Dec 2020 19:15:04 +0000 Subject: [PATCH 2/2] Accepting request 855487 from home:lwfinger:branches:Virtualization - Fix additional mouse control dialog issues. - Forward Hans-Peter Jansen's fixes. OBS-URL: https://build.opensuse.org/request/show/855487 OBS-URL: https://build.opensuse.org/package/show/Virtualization/virtualbox?expand=0&rev=580 --- vb-6.1.16-modal-dialog-parent.patch | 88 +++++++++++++++++++++++++++-- virtualbox.changes | 10 ++++ 2 files changed, 92 insertions(+), 6 deletions(-) diff --git a/vb-6.1.16-modal-dialog-parent.patch b/vb-6.1.16-modal-dialog-parent.patch index e41e87c..03b6bae 100644 --- a/vb-6.1.16-modal-dialog-parent.patch +++ b/vb-6.1.16-modal-dialog-parent.patch @@ -1,7 +1,7 @@ -Index: b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsExtension.cpp +Index: VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsExtension.cpp =================================================================== ---- a/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsExtension.cpp -+++ b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsExtension.cpp +--- VirtualBox-6.1.16.orig/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsExtension.cpp ++++ VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsExtension.cpp @@ -16,6 +16,7 @@ */ @@ -19,10 +19,10 @@ Index: b/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsExten QString strFilePath; if (!fileNames.isEmpty()) -Index: b/src/VBox/Frontends/VirtualBox/src/widgets/UIFilePathSelector.cpp +Index: VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/widgets/UIFilePathSelector.cpp =================================================================== ---- a/src/VBox/Frontends/VirtualBox/src/widgets/UIFilePathSelector.cpp -+++ b/src/VBox/Frontends/VirtualBox/src/widgets/UIFilePathSelector.cpp +--- VirtualBox-6.1.16.orig/src/VBox/Frontends/VirtualBox/src/widgets/UIFilePathSelector.cpp ++++ VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/widgets/UIFilePathSelector.cpp @@ -397,10 +397,10 @@ void UIFilePathSelector::selectPath() switch (m_enmMode) { @@ -45,3 +45,79 @@ Index: b/src/VBox/Frontends/VirtualBox/src/widgets/UIFilePathSelector.cpp } /* Do nothing if nothing chosen: */ +Index: VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/widgets/UIEmptyFilePathSelector.cpp +=================================================================== +--- VirtualBox-6.1.16.orig/src/VBox/Frontends/VirtualBox/src/widgets/UIEmptyFilePathSelector.cpp ++++ VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/widgets/UIEmptyFilePathSelector.cpp +@@ -232,16 +232,16 @@ void UIEmptyFilePathSelector::choose() + switch (mMode) + { + case UIEmptyFilePathSelector::Mode_File_Open: +- path = QIFileDialog::getOpenFileName (initDir, mFileFilters, parentWidget(), mFileDialogTitle); break; ++ path = QIFileDialog::getOpenFileName (initDir, mFileFilters, QApplication::activeWindow(), mFileDialogTitle); break; + case UIEmptyFilePathSelector::Mode_File_Save: + { +- path = QIFileDialog::getSaveFileName (initDir, mFileFilters, parentWidget(), mFileDialogTitle); ++ path = QIFileDialog::getSaveFileName (initDir, mFileFilters, QApplication::activeWindow(), mFileDialogTitle); + if (!path.isEmpty() && QFileInfo (path).suffix().isEmpty()) + path = QString ("%1.%2").arg (path).arg (mDefaultSaveExt); + break; + } + case UIEmptyFilePathSelector::Mode_Folder: +- path = QIFileDialog::getExistingDirectory (initDir, parentWidget(), mFileDialogTitle); break; ++ path = QIFileDialog::getExistingDirectory (initDir, QApplication::activeWindow(), mFileDialogTitle); break; + } + if (path.isEmpty()) + return; +Index: VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/medium/UIMediumSelector.cpp +=================================================================== +--- VirtualBox-6.1.16.orig/src/VBox/Frontends/VirtualBox/src/medium/UIMediumSelector.cpp ++++ VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/medium/UIMediumSelector.cpp +@@ -438,7 +438,7 @@ void UIMediumSelector::sltButtonLeaveEmp + + void UIMediumSelector::sltAddMedium() + { +- QUuid uMediumID = uiCommon().openMediumWithFileOpenDialog(m_enmMediumType, this, m_strMachineFolder); ++ QUuid uMediumID = uiCommon().openMediumWithFileOpenDialog(m_enmMediumType, QApplication::activeWindow(), m_strMachineFolder); + if (uMediumID.isNull()) + return; + repopulateTreeWidget(); +Index: VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp +=================================================================== +--- VirtualBox-6.1.16.orig/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp ++++ VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/globals/UICommon.cpp +@@ -3197,7 +3197,7 @@ void UICommon::updateMachineStorage(cons + } + else if (target.type == UIMediumTarget::UIMediumTargetType_WithFileDialog) + { +- uMediumID = openMediumWithFileOpenDialog(target.mediumType, windowManager().mainWindowShown(), ++ uMediumID = openMediumWithFileOpenDialog(target.mediumType, QApplication::activeWindow(), + strMachineFolder, false /* fUseLastFolder */); + } + else if(target.type == UIMediumTarget::UIMediumTargetType_CreateAdHocVISO) +Index: VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/medium/UIMediumManager.cpp +=================================================================== +--- VirtualBox-6.1.16.orig/src/VBox/Frontends/VirtualBox/src/medium/UIMediumManager.cpp ++++ VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/medium/UIMediumManager.cpp +@@ -486,7 +486,7 @@ void UIMediumManagerWidget::sltHandleMac + void UIMediumManagerWidget::sltAddMedium() + { + QString strDefaultMachineFolder = uiCommon().virtualBox().GetSystemProperties().GetDefaultMachineFolder(); +- uiCommon().openMediumWithFileOpenDialog(currentMediumType(), this, ++ uiCommon().openMediumWithFileOpenDialog(currentMediumType(), QApplication::activeWindow(), + strDefaultMachineFolder, true /* use most recent medium folder */); + } + +Index: VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.cpp +=================================================================== +--- VirtualBox-6.1.16.orig/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.cpp ++++ VirtualBox-6.1.16/src/VBox/Frontends/VirtualBox/src/settings/machine/UIMachineSettingsStorage.cpp +@@ -3958,7 +3958,7 @@ void UIMachineSettingsStorage::sltChoose + { + const QString strMachineFolder(QFileInfo(m_strMachineSettingsFilePath).absolutePath()); + +- QUuid uMediumId = uiCommon().openMediumWithFileOpenDialog(m_pMediumIdHolder->type(), this, strMachineFolder); ++ QUuid uMediumId = uiCommon().openMediumWithFileOpenDialog(m_pMediumIdHolder->type(), QApplication::activeWindow(), strMachineFolder); + if (uMediumId.isNull()) + return; + m_pMediumIdHolder->setId(uMediumId); diff --git a/virtualbox.changes b/virtualbox.changes index 225782d..399bfc6 100644 --- a/virtualbox.changes +++ b/virtualbox.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Sat Dec 12 19:10:34 UTC 2020 - Larry Finger + +- Fix additional mouse control dialog issues. + +------------------------------------------------------------------- +Thu Dec 10 22:57:44 UTC 2020 - Larry Finger + +- Forward Hans-Peter Jansen's fixes. + ------------------------------------------------------------------- Wed Dec 9 15:35:34 UTC 2020 - Hans-Peter Jansen