From 0b40a402d71395b0069f82210c500b7fd80b22e1 Mon Sep 17 00:00:00 2001 From: Kalev Lember Date: Wed, 1 May 2019 12:38:20 +0200 Subject: [PATCH] Update to 3.32.2 --- .gitignore | 1 + gnome-software-rpm-ostree-fixes.patch | 536 -------------------------- gnome-software.spec | 9 +- sources | 2 +- 4 files changed, 7 insertions(+), 541 deletions(-) delete mode 100644 gnome-software-rpm-ostree-fixes.patch diff --git a/.gitignore b/.gitignore index 67bf8bc..7b190e0 100644 --- a/.gitignore +++ b/.gitignore @@ -101,3 +101,4 @@ /gnome-software-3.31.92.tar.xz /gnome-software-3.32.0.tar.xz /gnome-software-3.32.1.tar.xz +/gnome-software-3.32.2.tar.xz diff --git a/gnome-software-rpm-ostree-fixes.patch b/gnome-software-rpm-ostree-fixes.patch deleted file mode 100644 index 224b31f..0000000 --- a/gnome-software-rpm-ostree-fixes.patch +++ /dev/null @@ -1,536 +0,0 @@ -From bc561b63748bc6d62841a392903974703f59cea7 Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Fri, 19 Apr 2019 07:14:02 +0200 -Subject: [PATCH 1/8] GsApp: Add recently added quirks to - gs_app_quirk_to_string - ---- - lib/gs-app.c | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/lib/gs-app.c b/lib/gs-app.c -index 17a546731..d5a30927a 100644 ---- a/lib/gs-app.c -+++ b/lib/gs-app.c -@@ -235,6 +235,14 @@ _as_app_quirk_flag_to_string (GsAppQuirk quirk) - return "is-proxy"; - if (quirk == GS_APP_QUIRK_REMOVABLE_HARDWARE) - return "removable-hardware"; -+ if (quirk == GS_APP_QUIRK_DEVELOPER_VERIFIED) -+ return "developer-verified"; -+ if (quirk == GS_APP_QUIRK_PARENTAL_FILTER) -+ return "parental-filter"; -+ if (quirk == GS_APP_QUIRK_NEW_PERMISSIONS) -+ return "new-permissions"; -+ if (quirk == GS_APP_QUIRK_PARENTAL_NOT_LAUNCHABLE) -+ return "parental-not-launchable"; - return NULL; - } - --- -2.21.0 - - -From c21b68f47169e01f0c053b18d44aaef5fe948602 Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Wed, 24 Apr 2019 09:48:11 +0200 -Subject: [PATCH 2/8] rpm-ostree: Implement provides search - ---- - plugins/rpm-ostree/gs-plugin-rpm-ostree.c | 64 +++++++++++++++++++++++ - 1 file changed, 64 insertions(+) - -diff --git a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c -index b6b7fbd3f..b47a66a39 100644 ---- a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c -+++ b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c -@@ -1099,6 +1099,21 @@ find_package_by_name (DnfSack *sack, - return g_object_ref (pkgs->pdata[pkgs->len-1]); - } - -+static GPtrArray * -+find_packages_by_provides (DnfSack *sack, -+ gchar **search) -+{ -+ g_autoptr(GPtrArray) pkgs = NULL; -+ hy_autoquery HyQuery query = hy_query_create (sack); -+ -+ hy_query_filter_provides_in (query, search); -+ hy_query_filter_latest_per_arch (query, TRUE); -+ -+ pkgs = hy_query_run (query); -+ -+ return g_steal_pointer (&pkgs); -+} -+ - static gboolean - resolve_installed_packages_app (GsPlugin *plugin, - GPtrArray *pkglist, -@@ -1148,6 +1163,10 @@ resolve_available_packages_app (GsPlugin *plugin, - gs_app_set_origin (app, reponame); - } - -+ /* set more metadata for packages that don't have appstream data */ -+ gs_app_set_name (app, GS_APP_QUALITY_LOWEST, dnf_package_get_name (pkg)); -+ gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, dnf_package_get_summary (pkg)); -+ - return TRUE /* found */; - } - -@@ -1496,3 +1515,48 @@ out: - (void) Fclose (rpmfd); - return ret; - } -+ -+gboolean -+gs_plugin_add_search_what_provides (GsPlugin *plugin, -+ gchar **search, -+ GsAppList *list, -+ GCancellable *cancellable, -+ GError **error) -+{ -+ GsPluginData *priv = gs_plugin_get_data (plugin); -+ g_autoptr(GMutexLocker) locker = NULL; -+ g_autoptr(GPtrArray) pkglist = NULL; -+ -+ locker = g_mutex_locker_new (&priv->mutex); -+ -+ if (priv->dnf_context == NULL) -+ return TRUE; -+ -+ pkglist = find_packages_by_provides (dnf_context_get_sack (priv->dnf_context), search); -+ for (guint i = 0; i < pkglist->len; i++) { -+ DnfPackage *pkg = g_ptr_array_index (pkglist, i); -+ g_autoptr(GsApp) app = NULL; -+ -+ app = gs_plugin_cache_lookup (plugin, dnf_package_get_nevra (pkg)); -+ if (app != NULL) { -+ gs_app_list_add (list, app); -+ continue; -+ } -+ -+ /* create new app */ -+ app = gs_app_new (NULL); -+ gs_app_set_metadata (app, "GnomeSoftware::Creator", gs_plugin_get_name (plugin)); -+ gs_app_set_management_plugin (app, gs_plugin_get_name (plugin)); -+ gs_app_add_quirk (app, GS_APP_QUIRK_NEEDS_REBOOT); -+ app_set_rpm_ostree_packaging_format (app); -+ gs_app_set_kind (app, AS_APP_KIND_GENERIC); -+ gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_PACKAGE); -+ gs_app_set_scope (app, AS_APP_SCOPE_SYSTEM); -+ gs_app_add_source (app, dnf_package_get_name (pkg)); -+ -+ gs_plugin_cache_add (plugin, dnf_package_get_nevra (pkg), app); -+ gs_app_list_add (list, app); -+ } -+ -+ return TRUE; -+} --- -2.21.0 - - -From 03feb124bed19417796642d45aa883b14d21f145 Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Tue, 30 Apr 2019 14:02:21 +0200 -Subject: [PATCH 3/8] plugin event: trivial: Try harder to avoid returning NULL - unique ID - ---- - lib/gs-plugin-event.c | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/lib/gs-plugin-event.c b/lib/gs-plugin-event.c -index 2e292c0a8..cf122561d 100644 ---- a/lib/gs-plugin-event.c -+++ b/lib/gs-plugin-event.c -@@ -157,10 +157,14 @@ const gchar * - gs_plugin_event_get_unique_id (GsPluginEvent *event) - { - /* just proxy */ -- if (event->origin != NULL) -+ if (event->origin != NULL && -+ gs_app_get_unique_id (event->origin) != NULL) { - return gs_app_get_unique_id (event->origin); -- if (event->app != NULL) -+ } -+ if (event->app != NULL && -+ gs_app_get_unique_id (event->app) != NULL) { - return gs_app_get_unique_id (event->app); -+ } - - /* generate from error */ - if (event->error != NULL) { --- -2.21.0 - - -From 8915ad5da1a2a7661c211561250a56dc23f6b8ff Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Tue, 30 Apr 2019 15:02:05 +0200 -Subject: [PATCH 4/8] rpm-ostree: trivial: Update rpmostree1 dbus interface - description - ---- - plugins/rpm-ostree/org.projectatomic.rpmostree1.xml | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/plugins/rpm-ostree/org.projectatomic.rpmostree1.xml b/plugins/rpm-ostree/org.projectatomic.rpmostree1.xml -index 077002e38..6ae04a459 100644 ---- a/plugins/rpm-ostree/org.projectatomic.rpmostree1.xml -+++ b/plugins/rpm-ostree/org.projectatomic.rpmostree1.xml -@@ -281,6 +281,13 @@ - - - -+ -+ -+ -+ -+ -+ -+ - - - --- -2.21.0 - - -From 3541297e9f69c1bee0e7ed416fbe9d55e918d0e0 Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Tue, 30 Apr 2019 15:11:24 +0200 -Subject: [PATCH 5/8] rpm-ostree: Implement getting the repo list, and enabling - and disabling repos - -This also bumps the required rpm-ostree version to 2019.3 for the -required rpm-ostree DBus API. ---- - meson.build | 2 +- - plugins/rpm-ostree/gs-plugin-rpm-ostree.c | 110 ++++++++++++++++++++++ - 2 files changed, 111 insertions(+), 1 deletion(-) - -diff --git a/meson.build b/meson.build -index c08bf4901..f71ad139b 100644 ---- a/meson.build -+++ b/meson.build -@@ -161,7 +161,7 @@ if get_option('rpm_ostree') - libdnf = dependency('libdnf') - ostree = dependency('ostree-1') - rpm = dependency('rpm') -- rpm_ostree = dependency('rpm-ostree-1', version : '>= 2018.4') -+ rpm_ostree = dependency('rpm-ostree-1', version : '>= 2019.3') - endif - - if get_option('gudev') -diff --git a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c -index b47a66a39..ae2f2435f 100644 ---- a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c -+++ b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c -@@ -928,6 +928,60 @@ gs_plugin_update_app (GsPlugin *plugin, - return TRUE; - } - -+static gboolean -+gs_plugin_repo_enable (GsPlugin *plugin, -+ GsApp *app, -+ gboolean enable, -+ GCancellable *cancellable, -+ GError **error) -+{ -+ GsPluginData *priv = gs_plugin_get_data (plugin); -+ g_autofree gchar *transaction_address = NULL; -+ g_autoptr(GVariantBuilder) options_builder = NULL; -+ g_autoptr(TransactionProgress) tp = NULL; -+ -+ if (enable) -+ gs_app_set_state (app, AS_APP_STATE_INSTALLING); -+ else -+ gs_app_set_state (app, AS_APP_STATE_REMOVING); -+ -+ options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{ss}")); -+ g_variant_builder_add (options_builder, "{ss}", "enabled", enable ? "1" : "0"); -+ if (!gs_rpmostree_os_call_modify_yum_repo_sync (priv->os_proxy, -+ gs_app_get_id (app), -+ g_variant_builder_end (options_builder), -+ &transaction_address, -+ cancellable, -+ error)) { -+ gs_rpmostree_error_convert (error); -+ gs_app_set_state_recover (app); -+ gs_utils_error_add_origin_id (error, app); -+ return FALSE; -+ } -+ -+ tp = transaction_progress_new (); -+ tp->app = g_object_ref (app); -+ if (!gs_rpmostree_transaction_get_response_sync (priv->sysroot_proxy, -+ transaction_address, -+ tp, -+ cancellable, -+ error)) { -+ gs_rpmostree_error_convert (error); -+ gs_app_set_state_recover (app); -+ gs_utils_error_add_origin_id (error, app); -+ return FALSE; -+ } -+ -+ -+ /* state is known */ -+ if (enable) -+ gs_app_set_state (app, AS_APP_STATE_INSTALLED); -+ else -+ gs_app_set_state (app, AS_APP_STATE_AVAILABLE); -+ -+ return TRUE; -+} -+ - gboolean - gs_plugin_app_install (GsPlugin *plugin, - GsApp *app, -@@ -945,6 +999,10 @@ gs_plugin_app_install (GsPlugin *plugin, - if (g_strcmp0 (gs_app_get_management_plugin (app), gs_plugin_get_name (plugin)) != 0) - return TRUE; - -+ /* enable repo */ -+ if (gs_app_get_kind (app) == AS_APP_KIND_SOURCE) -+ return gs_plugin_repo_enable (plugin, app, TRUE, cancellable, error); -+ - switch (gs_app_get_state (app)) { - case AS_APP_STATE_AVAILABLE: - if (gs_app_get_source_default (app) == NULL) { -@@ -1041,6 +1099,10 @@ gs_plugin_app_remove (GsPlugin *plugin, - if (g_strcmp0 (gs_app_get_management_plugin (app), gs_plugin_get_name (plugin)) != 0) - return TRUE; - -+ /* disable repo */ -+ if (gs_app_get_kind (app) == AS_APP_KIND_SOURCE) -+ return gs_plugin_repo_enable (plugin, app, FALSE, cancellable, error); -+ - gs_app_set_state (app, AS_APP_STATE_REMOVING); - tp->app = g_object_ref (app); - -@@ -1560,3 +1622,51 @@ gs_plugin_add_search_what_provides (GsPlugin *plugin, - - return TRUE; - } -+ -+gboolean -+gs_plugin_add_sources (GsPlugin *plugin, -+ GsAppList *list, -+ GCancellable *cancellable, -+ GError **error) -+{ -+ GsPluginData *priv = gs_plugin_get_data (plugin); -+ g_autoptr(GMutexLocker) locker = NULL; -+ GPtrArray *repos; -+ -+ locker = g_mutex_locker_new (&priv->mutex); -+ -+ if (priv->dnf_context == NULL) -+ return TRUE; -+ -+ repos = dnf_context_get_repos (priv->dnf_context); -+ if (repos == NULL) -+ return TRUE; -+ -+ for (guint i = 0; i < repos->len; i++) { -+ DnfRepo *repo = g_ptr_array_index (repos, i); -+ g_autofree gchar *description = NULL; -+ g_autoptr(GsApp) app = NULL; -+ gboolean enabled; -+ -+ /* hide these from the user */ -+ if (dnf_repo_is_devel (repo) || dnf_repo_is_source (repo)) -+ continue; -+ -+ app = gs_app_new (dnf_repo_get_id (repo)); -+ gs_app_set_management_plugin (app, gs_plugin_get_name (plugin)); -+ gs_app_set_kind (app, AS_APP_KIND_SOURCE); -+ gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_PACKAGE); -+ gs_app_add_quirk (app, GS_APP_QUIRK_NOT_LAUNCHABLE); -+ -+ enabled = (dnf_repo_get_enabled (repo) & DNF_REPO_ENABLED_PACKAGES) > 0; -+ gs_app_set_state (app, enabled ? AS_APP_STATE_INSTALLED : AS_APP_STATE_AVAILABLE); -+ -+ description = dnf_repo_get_description (repo); -+ gs_app_set_name (app, GS_APP_QUALITY_LOWEST, description); -+ gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, description); -+ -+ gs_app_list_add (list, app); -+ } -+ -+ return TRUE; -+} --- -2.21.0 - - -From 8e661a5d4a6d390be8eaff57acae649918c6bf81 Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Tue, 30 Apr 2019 15:18:37 +0200 -Subject: [PATCH 6/8] repos dialog: trivial: Special-case rpm-ostree repos the - same as packagekit - ---- - src/gs-repo-row.c | 1 + - src/gs-repos-dialog.c | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/src/gs-repo-row.c b/src/gs-repo-row.c -index f3d091183..7ce7e618a 100644 ---- a/src/gs-repo-row.c -+++ b/src/gs-repo-row.c -@@ -68,6 +68,7 @@ repo_supports_removal (GsApp *repo) - /* can't remove a repo, only enable/disable existing ones */ - if (g_strcmp0 (management_plugin, "fwupd") == 0 || - g_strcmp0 (management_plugin, "packagekit") == 0 || -+ g_strcmp0 (management_plugin, "rpm-ostree") == 0 || - g_strcmp0 (management_plugin, "shell-extensions") == 0) - return FALSE; - -diff --git a/src/gs-repos-dialog.c b/src/gs-repos-dialog.c -index 3d9f7f578..478acb7d2 100644 ---- a/src/gs-repos-dialog.c -+++ b/src/gs-repos-dialog.c -@@ -135,6 +135,7 @@ repo_supports_removal (GsApp *repo) - /* can't remove a repo, only enable/disable existing ones */ - if (g_strcmp0 (management_plugin, "fwupd") == 0 || - g_strcmp0 (management_plugin, "packagekit") == 0 || -+ g_strcmp0 (management_plugin, "rpm-ostree") == 0 || - g_strcmp0 (management_plugin, "shell-extensions") == 0) - return FALSE; - --- -2.21.0 - - -From d8ebbe420d5d0642987c6c6b799f108c7b4ce709 Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Fri, 19 Apr 2019 07:17:00 +0200 -Subject: [PATCH 7/8] Add HIDE_FROM_SEARCH quirk - -This allows plugins to control if apps are discoverable or not. - -Discoverable here means that they get hidden from search results and -category views, unless they are already installed. This makes it -possible to launch and remove and update already installed apps, but -hides them otherwise. - -This is going to be used in the rpm-ostree plugin to hide package-based -desktop apps on Fedora Silverblue and only show flatpak apps by default. ---- - lib/gs-app.c | 2 ++ - lib/gs-app.h | 2 ++ - lib/gs-plugin-loader.c | 8 ++++++++ - 3 files changed, 12 insertions(+) - -diff --git a/lib/gs-app.c b/lib/gs-app.c -index d5a30927a..186ceb549 100644 ---- a/lib/gs-app.c -+++ b/lib/gs-app.c -@@ -243,6 +243,8 @@ _as_app_quirk_flag_to_string (GsAppQuirk quirk) - return "new-permissions"; - if (quirk == GS_APP_QUIRK_PARENTAL_NOT_LAUNCHABLE) - return "parental-not-launchable"; -+ if (quirk == GS_APP_QUIRK_HIDE_FROM_SEARCH) -+ return "hide-from-search"; - return NULL; - } - -diff --git a/lib/gs-app.h b/lib/gs-app.h -index f6421f0b4..cd185154e 100644 ---- a/lib/gs-app.h -+++ b/lib/gs-app.h -@@ -85,6 +85,7 @@ typedef enum { - * @GS_APP_QUIRK_PARENTAL_FILTER: The app has been filtered by parental controls, and should be hidden - * @GS_APP_QUIRK_NEW_PERMISSIONS: The update requires new permissions - * @GS_APP_QUIRK_PARENTAL_NOT_LAUNCHABLE: The app cannot be run by the current user due to parental controls, and should not be launchable -+ * @GS_APP_QUIRK_HIDE_FROM_SEARCH: The app should not be shown in search results - * - * The application attributes. - **/ -@@ -105,6 +106,7 @@ typedef enum { - GS_APP_QUIRK_PARENTAL_FILTER = 1 << 12, /* Since: 3.32 */ - GS_APP_QUIRK_NEW_PERMISSIONS = 1 << 13, /* Since: 3.32 */ - GS_APP_QUIRK_PARENTAL_NOT_LAUNCHABLE = 1 << 14, /* Since: 3.32 */ -+ GS_APP_QUIRK_HIDE_FROM_SEARCH = 1 << 15, /* Since: 3.32 */ - /*< private >*/ - GS_APP_QUIRK_LAST - } GsAppQuirk; -diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c -index ca0504a34..aa775e9ef 100644 ---- a/lib/gs-plugin-loader.c -+++ b/lib/gs-plugin-loader.c -@@ -1226,6 +1226,14 @@ gs_plugin_loader_app_is_valid (GsApp *app, gpointer user_data) - return FALSE; - } - -+ /* don't show apps with hide-from-search quirk, unless they are already installed */ -+ if (!gs_app_is_installed (app) && -+ gs_app_has_quirk (app, GS_APP_QUIRK_HIDE_FROM_SEARCH)) { -+ g_debug ("app invalid as hide-from-search quirk set %s", -+ gs_plugin_loader_get_app_str (app)); -+ return FALSE; -+ } -+ - /* don't show sources */ - if (gs_app_get_kind (app) == AS_APP_KIND_SOURCE) { - g_debug ("app invalid as source %s", --- -2.21.0 - - -From 8ff12e84acc6f2e0723d908b9c0968cfc6d57b03 Mon Sep 17 00:00:00 2001 -From: Kalev Lember -Date: Fri, 19 Apr 2019 07:31:56 +0200 -Subject: [PATCH 8/8] rpm-ostree: Set HIDE_FROM_SEARCH quirk for apps we don't - want to show - -The plan for Fedora Silverblue is to use rpm-ostree layering for things -that are non-apps (e.g. hardware support, codecs, fonts etc that -supplement the base system), and only offer apps through flatpak. - -This commit makes it so that available apps don't show up in search, but -anything already installed still gets correctly shown (so that they are -removable / launchable /updatable etc). ---- - plugins/rpm-ostree/gs-plugin-rpm-ostree.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c -index ae2f2435f..a05099265 100644 ---- a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c -+++ b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c -@@ -1229,6 +1229,19 @@ resolve_available_packages_app (GsPlugin *plugin, - gs_app_set_name (app, GS_APP_QUALITY_LOWEST, dnf_package_get_name (pkg)); - gs_app_set_summary (app, GS_APP_QUALITY_LOWEST, dnf_package_get_summary (pkg)); - -+ /* set hide-from-search quirk for available apps we don't want to show */ -+ if (!gs_app_is_installed (app)) { -+ switch (gs_app_get_kind (app)) { -+ case AS_APP_KIND_DESKTOP: -+ case AS_APP_KIND_WEB_APP: -+ case AS_APP_KIND_CONSOLE: -+ gs_app_add_quirk (app, GS_APP_QUIRK_HIDE_FROM_SEARCH); -+ break; -+ default: -+ break; -+ } -+ } -+ - return TRUE /* found */; - } - --- -2.21.0 - diff --git a/gnome-software.spec b/gnome-software.spec index de14ed1..2463532 100644 --- a/gnome-software.spec +++ b/gnome-software.spec @@ -13,16 +13,14 @@ %global __requires_exclude ^libdnf[.]so[.].*$ Name: gnome-software -Version: 3.32.1 -Release: 4%{?dist} +Version: 3.32.2 +Release: 1%{?dist} Summary: A software center for GNOME License: GPLv2+ URL: https://wiki.gnome.org/Apps/Software Source0: https://download.gnome.org/sources/gnome-software/3.32/%{name}-%{version}.tar.xz -Patch0: gnome-software-rpm-ostree-fixes.patch - BuildRequires: gcc BuildRequires: gettext BuildRequires: libxslt @@ -247,6 +245,9 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop %{_mandir}/man1/gnome-software-editor.1* %changelog +* Tue May 07 2019 Kalev Lember - 3.32.2-1 +- Update to 3.32.2 + * Fri May 03 2019 Kalev Lember - 3.32.1-4 - Update a patch to final upstream version diff --git a/sources b/sources index 1f60d0f..220b65e 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (gnome-software-3.32.1.tar.xz) = a929fb50bbbcaeaae31c9e9621eaf0c2bd35ea7a7743dceef6c26f9e557e4b5509ccef663c0d2b99e9decb7d9524026c461ebb5c0f47481d3ed1749598cb8294 +SHA512 (gnome-software-3.32.2.tar.xz) = 961c0816285cce6a3e618b02931784dd5c004b6a3c6db1c39028cf7c71b1c242dbabbdbadf013962607211eb8cf8f9f5d8a5937873976eea3264be37e0f05e69