/*
 * livepatch_main.c - kernel live patch main infrastructure
 *
 * Copyright (c) 2014 SUSE
 *  Author: Miroslav Benes <mbenes@suse.cz>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/livepatch.h>
#include <linux/module.h>
#include <linux/types.h>

#include "uname_patch/livepatch_uname.h"

/* Auto expanded KLP_PATCHES_INCLUDES: */
#include "bsc1211395/livepatch_bsc1211395.h"
#include "bsc1213584/livepatch_bsc1213584.h"
#include "bsc1213587/livepatch_bsc1213587.h"
#include "bsc1214123/livepatch_bsc1214123.h"
#include "bsc1214812/livepatch_bsc1214812.h"
#include "bsc1215097/livepatch_bsc1215097.h"
#include "bsc1215118/livepatch_bsc1215118.h"
#include "bsc1215119/livepatch_bsc1215119.h"
#include "bsc1215300/livepatch_bsc1215300.h"
#include "bsc1215440/livepatch_bsc1215440.h"
#include "bsc1215442/livepatch_bsc1215442.h"
#include "bsc1215519/livepatch_bsc1215519.h"
#include "bsc1215887/livepatch_bsc1215887.h"
#include "bsc1215971/livepatch_bsc1215971.h"
#include "bsc1216044/livepatch_bsc1216044.h"
#include "bsc1216644/livepatch_bsc1216644.h"
#include "bsc1216898/livepatch_bsc1216898.h"
#include "bsc1217116/livepatch_bsc1217116.h"
#include "bsc1217522/livepatch_bsc1217522.h"
#include "bsc1218255/livepatch_bsc1218255.h"
#include "bsc1218487/livepatch_bsc1218487.h"
#include "bsc1218610/livepatch_bsc1218610.h"
#include "bsc1218613/livepatch_bsc1218613.h"
#include "bsc1218733/livepatch_bsc1218733.h"
#include "bsc1219078/livepatch_bsc1219078.h"
#include "bsc1219296/livepatch_bsc1219296.h"
#include "bsc1219432/livepatch_bsc1219432.h"
#include "bsc1219435/livepatch_bsc1219435.h"
#include "bsc1220145/livepatch_bsc1220145.h"
#include "bsc1220211/livepatch_bsc1220211.h"
#include "bsc1220828/livepatch_bsc1220828.h"
#include "bsc1220832/livepatch_bsc1220832.h"
#include "bsc1221302/livepatch_bsc1221302.h"
#include "bsc1222118/livepatch_bsc1222118.h"
#include "bsc1222685/livepatch_bsc1222685.h"
#include "bsc1222726/livepatch_bsc1222726.h"
#include "bsc1223059/livepatch_bsc1223059.h"
#include "bsc1223363/livepatch_bsc1223363.h"
#include "bsc1223514/livepatch_bsc1223514.h"
#include "bsc1223681/livepatch_bsc1223681.h"
#include "bsc1223683/livepatch_bsc1223683.h"
#include "bsc1225013/livepatch_bsc1225013.h"
#include "bsc1225310/livepatch_bsc1225310.h"


static struct klp_object objs[] = {
	/* Auto expanded KLP_PATCHES_OBJS: */
	{
		.name = NULL,
		.funcs = (struct klp_func[]) {
			{
			  .old_name = __stringify(KLP_SYSCALL_SYM(newuname)),
			  .new_func = KLP_SYSCALL_SYM(klp_newuname),
			},
#ifdef KLP_ARCH_HAS_SYSCALL_COMPAT_STUBS
			{
			  .old_name = __stringify(KLP_SYSCALL_COMPAT_STUB_SYM(newuname)),
			  .new_func = KLP_SYSCALL_COMPAT_STUB_SYM(klp_newuname),
			},
#endif
			{ .old_name = __stringify(ipv6_rthdr_rcv), .new_func = klpp_ipv6_rthdr_rcv, },
			{ .old_name = __stringify(unix_stream_sendpage), .new_func = klpp_unix_stream_sendpage, },
			{ .old_name = __stringify(__mark_chain_precision), .new_func = klpp___mark_chain_precision, },
			{ .old_name = __stringify(check_func_arg_reg_off), .new_func = klpp_check_func_arg_reg_off, },
			{ .old_name = __stringify(do_check_common), .new_func = klpp_do_check_common, },
			{ .old_name = __stringify(check_mem_access), .new_func = klpp_check_mem_access, },
			{ .old_name = __stringify(check_stack_range_initialized), .new_func = klpp_check_stack_range_initialized, },
			{ .old_name = __stringify(vfs_read), .new_func = klpp_vfs_read, },
			{ .old_name = __stringify(do_iter_read), .new_func = klpp_do_iter_read, },
			{ .old_name = __stringify(loop_rw_iter), .new_func = klpp_loop_rw_iter, },
#if IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT)
			{ .old_name = __stringify(insn_fetch_from_user_inatomic), .new_func = klpp_insn_fetch_from_user_inatomic, },
#endif
			{ .old_name = __stringify(igmp_start_timer), .new_func = klpp_igmp_start_timer, },
			{ .old_name = __stringify(__scm_send), .new_func = klpp___scm_send, },
			{ .old_name = __stringify(ip6_dst_gc), .new_func = klpp_ip6_dst_gc, },
#if IS_ENABLED(CONFIG_SECURITY_TOMOYO)
			{ .old_name = __stringify(tomoyo_write_control), .new_func = klpp_tomoyo_write_control, },
#endif
			{ .old_name = __stringify(ip6_route_multipath_add), .new_func = klpp_ip6_route_multipath_add, },
			{ .old_name = __stringify(unix_gc), .new_func = klpp_unix_gc, },
			{ }
		}
	},
#if IS_ENABLED(CONFIG_ATM)
	{
		.name = "atm",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(do_vcc_ioctl), .new_func = klpp_do_vcc_ioctl, },
			{ }
		}
	},
#endif
#if IS_ENABLED(CONFIG_BT)
	{
		.name = "bluetooth",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(bt_sock_recvmsg), .new_func = klpp_bt_sock_recvmsg, },
			{ .old_name = __stringify(sco_sock_timeout), .new_func = klpp_sco_sock_timeout, },
			{ }
		}
	},
#endif
	{
		.name = "cifs",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(smb3_fs_context_parse_param), .new_func = klpp_smb3_fs_context_parse_param, },
			{ .old_name = __stringify(smb3_receive_transform), .new_func = klpp_smb3_receive_transform, },
			{ .old_name = __stringify(parse_server_interfaces), .new_func = klpp_parse_server_interfaces, },
			{ }
		}
	},
	{
		.name = "cls_fw",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(fw_set_parms), .new_func = klpp_fw_set_parms, },
			{ }
		}
	},
	{
		.name = "cls_u32",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(u32_set_parms), .new_func = klpp_u32_set_parms, },
			{ }
		}
	},
	{
		.name = "drm",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(drm_client_modeset_probe), .new_func = klpp_drm_client_modeset_probe, },
			{ }
		}
	},
#if IS_ENABLED(CONFIG_EXFAT_FS)
	{
		.name = "exfat",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(exfat_find_dir_entry), .new_func = klpp_exfat_find_dir_entry, },
			{ .old_name = __stringify(exfat_readdir), .new_func = klpp_exfat_readdir, },
			{ }
		}
	},
#endif
#if IS_ENABLED(CONFIG_INFINIBAND_HFI1)
	{
		.name = "hfi1",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(_pad_sdma_tx_descs), .new_func = klpp__pad_sdma_tx_descs, },
			{ }
		}
	},
#endif
	{
		.name = "ip_set_hash_netportnet",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(hash_netportnet4_add), .new_func = klpp_hash_netportnet4_add, },
			{ .old_name = __stringify(hash_netportnet6_add), .new_func = klpp_hash_netportnet6_add, },
			{ .old_name = __stringify(hash_netportnet4_del_cidr), .new_func = klpp_hash_netportnet4_del_cidr, },
			{ .old_name = __stringify(hash_netportnet6_del_cidr), .new_func = klpp_hash_netportnet6_del_cidr, },
			{ .old_name = __stringify(hash_netportnet4_test), .new_func = klpp_hash_netportnet4_test, },
			{ .old_name = __stringify(hash_netportnet6_test), .new_func = klpp_hash_netportnet6_test, },
			{ }
		}
	},
	{
		.name = "ipvlan",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(ipvlan_queue_xmit), .new_func = klpp_ipvlan_queue_xmit, },
			{ }
		}
	},
#if IS_ENABLED(CONFIG_IWLWIFI)
	{
		.name = "iwlwifi",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(_iwl_dbg_tlv_time_point), .new_func = klpp__iwl_dbg_tlv_time_point, },
			{ }
		}
	},
#endif
#if IS_ENABLED(CONFIG_NFC)
	{
		.name = "nfc",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(nfc_llcp_sock_get), .new_func = klpp_nfc_llcp_sock_get, },
			{ .old_name = __stringify(nfc_llcp_get_sdp_ssap), .new_func = klpp_nfc_llcp_get_sdp_ssap, },
			{ .old_name = __stringify(nfc_llcp_rx_skb), .new_func = klpp_nfc_llcp_rx_skb, },
			{ }
		}
	},
#endif
	{
		.name = "nf_tables",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(__nf_tables_abort), .new_func = klpp___nf_tables_abort, },
			{ .old_name = __stringify(nft_immediate_init), .new_func = klpp_nft_immediate_init, },
			{ .old_name = __stringify(nft_pipapo_remove), .new_func = klpp_nft_pipapo_remove, },
			{ .old_name = __stringify(nf_tables_delrule), .new_func = klpp_nf_tables_delrule, },
			{ .old_name = __stringify(nf_tables_newrule), .new_func = klpp_nf_tables_newrule, },
			{ .old_name = __stringify(nft_del_setelem), .new_func = klpp_nft_del_setelem, },
			{ .old_name = __stringify(nft_data_init), .new_func = klpp_nft_data_init, },
			{ .old_name = __stringify(nft_exthdr_ipv6_eval), .new_func = klpp_nft_exthdr_ipv6_eval, },
			{ .old_name = __stringify(nft_exthdr_tcp_eval), .new_func = klpp_nft_exthdr_tcp_eval, },
			{ .old_name = __stringify(nft_exthdr_ipv4_eval), .new_func = klpp_nft_exthdr_ipv4_eval, },
			{ .old_name = __stringify(nft_exthdr_sctp_eval), .new_func = klpp_nft_exthdr_sctp_eval, },
			{ }
		}
	},
	{
		.name = "n_gsm",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(gsmld_open), .new_func = klpp_gsmld_open, },
			{ }
		}
	},
	{
		.name = "nvmet_tcp",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(nvmet_tcp_socket_error), .new_func = klpp_nvmet_tcp_socket_error, },
			{ .old_name = __stringify(nvmet_tcp_handle_icreq), .new_func = klpp_nvmet_tcp_handle_icreq, },
			{ }
		}
	},
#if IS_ENABLED(CONFIG_SCSI_QLA_FC)
	{
		.name = "qla2xxx",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(qla2x00_mem_alloc), .new_func = klpp_qla2x00_mem_alloc, },
			{ }
		}
	},
#endif
#if IS_ENABLED(CONFIG_DRM_QXL)
	{
		.name = "qxl",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(qxl_mode_dumb_create), .new_func = klpp_qxl_mode_dumb_create, },
			{ .old_name = __stringify(qxl_alloc_ioctl), .new_func = klpp_qxl_alloc_ioctl, },
			{ .old_name = __stringify(qxl_alloc_surf_ioctl), .new_func = klpp_qxl_alloc_surf_ioctl, },
			{ }
		}
	},
#endif
	{
		.name = "raid456",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(grow_one_stripe), .new_func = klpp_grow_one_stripe, },
			{ .old_name = __stringify(drop_one_stripe), .new_func = klpp_drop_one_stripe, },
			{ .old_name = __stringify(raid5_set_cache_size), .new_func = klpp_raid5_set_cache_size, },
			{ .old_name = __stringify(raid5_cache_count), .new_func = klpp_raid5_cache_count, },
			{ }
		}
	},
#if IS_ENABLED(CONFIG_NET_SCH_HFSC)
	{
		.name = "sch_hfsc",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(hfsc_change_class), .new_func = klpp_hfsc_change_class, },
			{ }
		}
	},
#endif
	{
		.name = "sch_qfq",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(qfq_dequeue), .new_func = klpp_qfq_dequeue, },
			{ .old_name = __stringify(qfq_enqueue), .new_func = klpp_qfq_enqueue, },
			{ }
		}
	},
	{
		.name = "tls",
		.funcs = (struct klp_func[]) {
			{ .old_name = __stringify(bpf_exec_tx_verdict), .new_func = klpp_bpf_exec_tx_verdict, },
			{ .old_name = __stringify(tls_encrypt_done), .new_func = klpp_tls_encrypt_done, },
			{ }
		}
	},
	{ }
};

static struct klp_patch patch = {
	.mod = THIS_MODULE,
	.objs = objs,
	.replace = true,
};

static int __init klp_patch_init(void)
{
	int retval;

	pr_info("livepatch: initializing\n");

	retval = klp_patch_uname_init();
	if (retval)
		return retval;

	/* Auto expanded KLP_PATCHES_INIT_CALLS: */
	retval = livepatch_bsc1211395_init();
	if (retval)
		goto err_bsc1211395;

	retval = livepatch_bsc1213584_init();
	if (retval)
		goto err_bsc1213584;

	retval = livepatch_bsc1213587_init();
	if (retval)
		goto err_bsc1213587;

	retval = livepatch_bsc1214123_init();
	if (retval)
		goto err_bsc1214123;

	retval = livepatch_bsc1214812_init();
	if (retval)
		goto err_bsc1214812;

	retval = livepatch_bsc1215097_init();
	if (retval)
		goto err_bsc1215097;

	retval = livepatch_bsc1215118_init();
	if (retval)
		goto err_bsc1215118;

	retval = livepatch_bsc1215119_init();
	if (retval)
		goto err_bsc1215119;

	retval = livepatch_bsc1215300_init();
	if (retval)
		goto err_bsc1215300;

	retval = livepatch_bsc1215440_init();
	if (retval)
		goto err_bsc1215440;

	retval = livepatch_bsc1215442_init();
	if (retval)
		goto err_bsc1215442;

	retval = livepatch_bsc1215519_init();
	if (retval)
		goto err_bsc1215519;

	retval = livepatch_bsc1215887_init();
	if (retval)
		goto err_bsc1215887;

	retval = livepatch_bsc1215971_init();
	if (retval)
		goto err_bsc1215971;

	retval = livepatch_bsc1216044_init();
	if (retval)
		goto err_bsc1216044;

	retval = livepatch_bsc1216644_init();
	if (retval)
		goto err_bsc1216644;

	retval = livepatch_bsc1216898_init();
	if (retval)
		goto err_bsc1216898;

	retval = livepatch_bsc1217116_init();
	if (retval)
		goto err_bsc1217116;

	retval = livepatch_bsc1217522_init();
	if (retval)
		goto err_bsc1217522;

	retval = livepatch_bsc1218255_init();
	if (retval)
		goto err_bsc1218255;

	retval = livepatch_bsc1218487_init();
	if (retval)
		goto err_bsc1218487;

	retval = livepatch_bsc1218610_init();
	if (retval)
		goto err_bsc1218610;

	retval = livepatch_bsc1218613_init();
	if (retval)
		goto err_bsc1218613;

	retval = livepatch_bsc1218733_init();
	if (retval)
		goto err_bsc1218733;

	retval = livepatch_bsc1219078_init();
	if (retval)
		goto err_bsc1219078;

	retval = livepatch_bsc1219296_init();
	if (retval)
		goto err_bsc1219296;

	retval = livepatch_bsc1219432_init();
	if (retval)
		goto err_bsc1219432;

	retval = livepatch_bsc1219435_init();
	if (retval)
		goto err_bsc1219435;

	retval = livepatch_bsc1220145_init();
	if (retval)
		goto err_bsc1220145;

	retval = livepatch_bsc1220211_init();
	if (retval)
		goto err_bsc1220211;

	retval = livepatch_bsc1220828_init();
	if (retval)
		goto err_bsc1220828;

	retval = livepatch_bsc1220832_init();
	if (retval)
		goto err_bsc1220832;

	retval = livepatch_bsc1221302_init();
	if (retval)
		goto err_bsc1221302;

	retval = livepatch_bsc1222118_init();
	if (retval)
		goto err_bsc1222118;

	retval = livepatch_bsc1222685_init();
	if (retval)
		goto err_bsc1222685;

	retval = livepatch_bsc1222726_init();
	if (retval)
		goto err_bsc1222726;

	retval = livepatch_bsc1223059_init();
	if (retval)
		goto err_bsc1223059;

	retval = livepatch_bsc1223363_init();
	if (retval)
		goto err_bsc1223363;

	retval = livepatch_bsc1223514_init();
	if (retval)
		goto err_bsc1223514;

	retval = livepatch_bsc1223681_init();
	if (retval)
		goto err_bsc1223681;

	retval = livepatch_bsc1223683_init();
	if (retval)
		goto err_bsc1223683;

	retval = livepatch_bsc1225013_init();
	if (retval)
		goto err_bsc1225013;

	retval = livepatch_bsc1225310_init();
	if (retval)
		goto err_bsc1225310;

	retval = klp_enable_patch(&patch);
	if (!retval)
		return retval;

	/* Auto expanded KLP_PATCHES_INIT_ERR_HANDLERS: */
	livepatch_bsc1225310_cleanup();
err_bsc1225310:
	livepatch_bsc1225013_cleanup();
err_bsc1225013:
	livepatch_bsc1223683_cleanup();
err_bsc1223683:
	livepatch_bsc1223681_cleanup();
err_bsc1223681:
	livepatch_bsc1223514_cleanup();
err_bsc1223514:
	livepatch_bsc1223363_cleanup();
err_bsc1223363:
	livepatch_bsc1223059_cleanup();
err_bsc1223059:
	livepatch_bsc1222726_cleanup();
err_bsc1222726:
	livepatch_bsc1222685_cleanup();
err_bsc1222685:
	livepatch_bsc1222118_cleanup();
err_bsc1222118:
	livepatch_bsc1221302_cleanup();
err_bsc1221302:
	livepatch_bsc1220832_cleanup();
err_bsc1220832:
	livepatch_bsc1220828_cleanup();
err_bsc1220828:
	livepatch_bsc1220211_cleanup();
err_bsc1220211:
	livepatch_bsc1220145_cleanup();
err_bsc1220145:
	livepatch_bsc1219435_cleanup();
err_bsc1219435:
	livepatch_bsc1219432_cleanup();
err_bsc1219432:
	livepatch_bsc1219296_cleanup();
err_bsc1219296:
	livepatch_bsc1219078_cleanup();
err_bsc1219078:
	livepatch_bsc1218733_cleanup();
err_bsc1218733:
	livepatch_bsc1218613_cleanup();
err_bsc1218613:
	livepatch_bsc1218610_cleanup();
err_bsc1218610:
	livepatch_bsc1218487_cleanup();
err_bsc1218487:
	livepatch_bsc1218255_cleanup();
err_bsc1218255:
	livepatch_bsc1217522_cleanup();
err_bsc1217522:
	livepatch_bsc1217116_cleanup();
err_bsc1217116:
	livepatch_bsc1216898_cleanup();
err_bsc1216898:
	livepatch_bsc1216644_cleanup();
err_bsc1216644:
	livepatch_bsc1216044_cleanup();
err_bsc1216044:
	livepatch_bsc1215971_cleanup();
err_bsc1215971:
	livepatch_bsc1215887_cleanup();
err_bsc1215887:
	livepatch_bsc1215519_cleanup();
err_bsc1215519:
	livepatch_bsc1215442_cleanup();
err_bsc1215442:
	livepatch_bsc1215440_cleanup();
err_bsc1215440:
	livepatch_bsc1215300_cleanup();
err_bsc1215300:
	livepatch_bsc1215119_cleanup();
err_bsc1215119:
	livepatch_bsc1215118_cleanup();
err_bsc1215118:
	livepatch_bsc1215097_cleanup();
err_bsc1215097:
	livepatch_bsc1214812_cleanup();
err_bsc1214812:
	livepatch_bsc1214123_cleanup();
err_bsc1214123:
	livepatch_bsc1213587_cleanup();
err_bsc1213587:
	livepatch_bsc1213584_cleanup();
err_bsc1213584:
	livepatch_bsc1211395_cleanup();
err_bsc1211395:

	return retval;
}

static void __exit klp_patch_cleanup(void)
{
	pr_info("livepatch: removed\n");

	/* Auto expanded KLP_PATCHES_CLEANUP_CALLS: */
	livepatch_bsc1211395_cleanup();
	livepatch_bsc1213584_cleanup();
	livepatch_bsc1213587_cleanup();
	livepatch_bsc1214123_cleanup();
	livepatch_bsc1214812_cleanup();
	livepatch_bsc1215097_cleanup();
	livepatch_bsc1215118_cleanup();
	livepatch_bsc1215119_cleanup();
	livepatch_bsc1215300_cleanup();
	livepatch_bsc1215440_cleanup();
	livepatch_bsc1215442_cleanup();
	livepatch_bsc1215519_cleanup();
	livepatch_bsc1215887_cleanup();
	livepatch_bsc1215971_cleanup();
	livepatch_bsc1216044_cleanup();
	livepatch_bsc1216644_cleanup();
	livepatch_bsc1216898_cleanup();
	livepatch_bsc1217116_cleanup();
	livepatch_bsc1217522_cleanup();
	livepatch_bsc1218255_cleanup();
	livepatch_bsc1218487_cleanup();
	livepatch_bsc1218610_cleanup();
	livepatch_bsc1218613_cleanup();
	livepatch_bsc1218733_cleanup();
	livepatch_bsc1219078_cleanup();
	livepatch_bsc1219296_cleanup();
	livepatch_bsc1219432_cleanup();
	livepatch_bsc1219435_cleanup();
	livepatch_bsc1220145_cleanup();
	livepatch_bsc1220211_cleanup();
	livepatch_bsc1220828_cleanup();
	livepatch_bsc1220832_cleanup();
	livepatch_bsc1221302_cleanup();
	livepatch_bsc1222118_cleanup();
	livepatch_bsc1222685_cleanup();
	livepatch_bsc1222726_cleanup();
	livepatch_bsc1223059_cleanup();
	livepatch_bsc1223363_cleanup();
	livepatch_bsc1223514_cleanup();
	livepatch_bsc1223681_cleanup();
	livepatch_bsc1223683_cleanup();
	livepatch_bsc1225013_cleanup();
	livepatch_bsc1225310_cleanup();

}

module_init(klp_patch_init);
module_exit(klp_patch_cleanup);

MODULE_LICENSE("GPL");
MODULE_INFO(livepatch, "Y");
MODULE_INFO(klpgitrev, "f9b4e188433f60c7819c60a5f5a855297cbada80");
