????

Your IP : 3.141.45.217


Current Path : /opt/cloudlinux/venv/lib/python3.11/site-packages/xray/adviser/__pycache__/
Upload File :
Current File : //opt/cloudlinux/venv/lib/python3.11/site-packages/xray/adviser/__pycache__/cli_api.cpython-311.pyc

�

k�eީ��&�dZddlZddlZddlZddlZddlZddlZddlmZddl	m
Z
mZddlm
Z
mZmZmZmZddlmZddlmZddlmZmZmZmZmZmZmZmZmZm Z dd	l!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'dd
l(m)Z)ddl*m+Z+ddl,m-Z-d
dl.m/Z/d
dl0m1Z1ddl2m3Z3m4Z4ddl5m6Z6m7Z7m8Z8m9Z9m:Z:ddl;m<Z<m=Z=ddl>m?Z?m@Z@mAZAddlBmCZCmDZDmEZEmFZFddlGmHZHddlImJZJddlKmLZLmMZMddlNmOZOmPZPddlQmRZRdZSGd�de��ZTeGd�d����ZUGd �d!��ZVdS)"zB
This module contains X Ray Smart Advice local utility main class
�N)�contextmanager)�asdict�	dataclass)�Any�Tuple�Optional�List�Dict)�Enum)�LicenseApproveStatus)
�is_feature_allowed�is_subscription_pending�get_subscription_upgrade_url�get_license_approve_status�approve_license_agreement�get_license_agreement_text�get_subscriptions_info�get_user_auth_key�2is_smart_advice_notifications_disabled_server_wide�.is_smart_advice_reminders_disabled_server_wide)�docroot�is_panel_feature_supported�get_user_emails_list�panel_awp_link�	getCPName�userdomains)�
is_wp_path)�drop_privileges)�Feature�)�get_advice_instance)�SmartAdviceProgress�)�
get_client�
api_client)�advice_pending_storage�advice_processed_storage�advice_list_cache�advice_list_im360_cache�advice_reason_max_len)�	XRayError�SmartAdvicePluginError)�user_mode_advice_verification�username_verification�get_xray_exec_user)�	timestamp�	safe_move�get_user_php_version�filelock)�report_usage_action_or_error)�ClWposGetter)�get_mu_directory�"create_mu_plugins_dir_if_not_exist)�setup_plugin_symlink�prepare_system_analytics_data)�report_analytics�;c��eZdZdZdZdS)�
AdviceActions�apply�rollbackN)�__name__�
__module__�__qualname__�APPLY�ROLLBACK���K/opt/cloudlinux/venv/lib64/python3.11/site-packages/xray/adviser/cli_api.pyr=r=Hs�������E��H�H�HrFr=c�V�eZdZUeed<eed<eed<eed<eed<eed<eed<dS)	�SmartAdviceOptions�
panel_type�	panel_url�panel_emails�upgrade_url�upgrade_url_cdn�subscription�
notificationsN)r@rArB�str�__annotations__�dictrErFrGrIrIMs`��������O�O�O��N�N�N����������������������rFrIc��eZdZdZd�Zededdfd���Zedefd���Zede	defd	���Z
de	deefd
�Zede	defd���Z
de	defd
�Zde	defd�Zd�Zede	deeeffd���ZedHdedededdfd���Zde	dedefd�Zde	dededeeeffd�ZdHdefd�Zedefd���ZdId�Zd�Z de	defd �Z!				dJde	d"ed#ed$ed%ed&ed'edeefd(�Z"			dKd)ede	d"ed#ed$ed%ed&edeefd*�Z#defd+�Z$de	defd,�Z%d-�Z&d.�Z'd/�Z(e		dLd0���Z)ed1���Z*dMd3�Z+dNd4�Z,ed5���Z-d6�Z.ed7���Z/ed8���Z0de1eeffd9�Z2ed:���Z3d;�Z4dNd<�Z5d=e6ed>ede6efd?�Z7ed@edAe6ede6efdB���Z8dC�Z9dD�Z:dHde;fdE�Z<de;fdF�Z=dG�Z>dS)O�SmartAdviceUtilz%Main Smart Advice local utility classc��tjd��|_ttfD]}|�|���t
d��}|��|_dS)N�smart_advice�adviser)�logging�	getLogger�loggerr&r'�
create_dirr$�adviser_client)�self�stor�adviser_client_objects   rG�__init__zSmartAdviceUtil.__init__[sc���'��7�7���+�-E�F�	"�	"�D��O�O�D�!�!�!�!� *�9� 5� 5��?T�?T�?V�?V����rF�dpath�returnNc�p�tj�|��stj|��dSdS)zCreate dir if missingN)�os�path�isdir�mkdir)rbs rGr\zSmartAdviceUtil.create_dirds5���w�}�}�U�#�#�	��H�U�O�O�O�O�O�	�	rFc���dt��d�}|r|�|��tjt	t|���������S)z�
        Create JSON response message with result field == success
        and given keyword arguments in other fields
        :return: json packed string
        �success)�resultr0)r0�update�json�dumpsrS�sorted�items)�kwargs�initials  rG�responsezSmartAdviceUtil.responsejsW��'�Y�[�[�A�A���	#��N�N�6�"�"�"��z�$�v�g�m�m�o�o�6�6�7�7�8�8�8rF�a_idc��t�d|��S)z%Per-advice file with results of apply�/)r'�rts rG�_apply_datafilezSmartAdviceUtil._apply_datafilevs��+�3�3�T�3�3�3rFc��|�|��}tj�|��r�	t	|��5}tj|��}ddd��n#1swxYwYn]#t$rd}YnOt
j$r>t	|��5}|�	��}ddd��n#1swxYwYYnwxYwtj
|��n#tj
|��wxYw|SdS)z=Retrieve data stored in per-advice file with results of applyN)rxrerf�isfile�openrm�load�OSError�JSONDecodeError�read�unlink)r^rt�datafile�_f�datas     rG�_apply_resultszSmartAdviceUtil._apply_results{s|���'�'��-�-��
�7�>�>�(�#�#�	�	
$��(�^�^�)�r��9�R�=�=�D�)�)�)�)�)�)�)�)�)�)�)����)�)�)�)����
�
�
������'�
%�
%�
%��(�^�^�%�r��7�7�9�9�D�%�%�%�%�%�%�%�%�%�%�%����%�%�%�%���
%�����	�(�#�#�#�#���	�(�#�#�#�#�����K�	�	s}�A2�A&�A2�&A*�*A2�-A*�.A2�1C$�2C�>C$�C�B>�2C�>C	�C�C	�C�	C$�C�C$�$C:c��t�d|��S)zPer-advice pending flagrv)r&rws rG�
_pending_flagzSmartAdviceUtil._pending_flag�s��)�1�1�4�1�1�1rF�	advice_idc�f�tj�|�|����S)zIs advice in pending state)rerf�existsr�)r^r�s  rG�is_advice_pendingz!SmartAdviceUtil.is_advice_pending�s$���w�~�~�d�0�0��;�;�<�<�<rFc�2�|�|��dzS)zPer-advice progress storagez	.progress)r�)r^rts  rG�_progress_filezSmartAdviceUtil._progress_file�s���!�!�$�'�'�+�5�5rFc�x�	t|��S#t$r|j�d��YdSwxYw)Nz#Error while getting user login link�)r�	Exceptionr[�	exception)r^�usernames  rG�_get_user_awp_linkz"SmartAdviceUtil._get_user_awp_link�sN��	�!�(�+�+�+���	�	�	��K�!�!�"G�H�H�H��2�2�	���s��$9�9c�p�|j�|��}|t|dd��fS)zu
        Get advice details from API along with an
        appropriate Advice object by obtained advice type
        �advice�type)r]�advice_detailsr!)r^r�rss   rG�get_detailed_advicez#SmartAdviceUtil.get_detailed_advice�s8���&�5�5�i�@�@���,�X�h�-?��-G�H�H�H�HrFF�dstr��as_jsonc�&�|dz}t|d��5}|r<	tj||��n:#t$r|�|��YnwxYw|�|��ddd��n#1swxYwYt||��dS)z8Dump data inside given dst using .bkp file and then movez.bkp�wN)r{rm�dump�	TypeError�writer1)r�r�r��_tmp_dstr�s     rG�dump_to_filezSmartAdviceUtil.dump_to_file�s�����<��
�(�C�
 �
 �	�B��
�#��I�d�B�'�'�'�'�� �#�#�#��H�H�T�N�N�N�N�N�#�����������	�	�	�	�	�	�	�	�	�	�	����	�	�	�	�	�(�C� � � � � s1�A6�0�A6�A�A6�A�A6�6A:�=A:�currentc�T����tdtf���fd���}|��S)a
        Smart Advice apply own progress,
        based on current and previous results of 'clwpos get-progress'.
        Returns the maximum progress values among current and previous.
        Previous (latest) is stored inside a pending file-flag.
        rcc3��K��j�d��������}	t|��5}t	ditj|����}ddd��n#1swxYwYnY#tt
jf$r@}�j�dt|����t	��}Yd}~nd}~wwxYw�j�d|���|kr�n|V���
���rH�|krD�j�d�����|t���d���dSdSdS)	z}
            Get progress stored in file and return the maximum one among
            current and stored results
            zCurrent progress value: %sNz%Error during reading stored value: %szStored progress value: %szUpdating stored progress: %sT)r�rE)
r[�debugr�r{r"rmr|r}r~rQr�r�r)�progress_dst�prev�prev_stages�er�r�r^s    ���rG�resolve_progressz2SmartAdviceUtil.progress.<locals>.resolve_progress�s������
�K���:�G�D�D�D��.�.�y�9�9�L�
4��,�'�'�I�4�"5�"H�"H��	�$���"H�"H�K�I�I�I�I�I�I�I�I�I�I�I����I�I�I�I����T�1�2�
4�
4�
4���!�!�"I�"%�a�&�&�*�*�*�2�3�3�����������	
4����
�K���9�;�G�G�G�$�{�2�2�'�'��C�C�C��%�%�i�0�0�
0�W�{�5J�5J���!�!�"@�'�J�J�J��!�!�,��w���*.�"�0�0�0�0�0�
0�
0�5J�5Js;�A;�A/�#A;�/A3�3A;�6A3�7A;�;C�6C�C)rr")r^r�r�r�s``` rG�progresszSmartAdviceUtil.progress�sR�����
�	0�"5�	0�	0�	0�	0�	0�	0�	0�
��	0�4 ��!�!�!rF�_id�
advice_obj�advice_datac�*�|�|��rRd}|�||�|dd����5}|}ddd��n#1swxYwYn|dd}t��}|t	|��fS)z�
        Resolve if advice is in pending status.
        Progress is retrieved for pending advice only.
        Dummy result (0, 0) is returned for other advice states.
        �pending�metadatar�Nr��status)r�r��get_progressr"r)r^r�r�r�r��p�stagess       rG�get_current_statusz"SmartAdviceUtil.get_current_status�s����!�!�#�&�&�	+��F����s�J�$;�$;��
�+�J�7�%9�%9�:�:�
�=>���
�
�
�
�
�
�
�
�
�
�
����
�
�
�
��!��*�8�4�F�(�*�*�F��v�f�~�~�%�%s�
A�A �#A c��|j���}|�||���}	|�|���n*#t$r|j�d��YnwxYw|�|���S)z9Load validated advice list and update it before returning��extended)�current_adviceszDUnable to sync cl-smart-advice plugin during getting list of advices�r�)r]�advice_list�prepare_advices_response�sync_advices_wordpress_pluginr�r[r�rs)r^r��api_response�response_advice_lists    rGr�zSmartAdviceUtil.advice_list�s����*�6�6�8�8��#�<�<�\�T\�<�]�]��	j��.�.�|�.�L�L�L�L���	j�	j�	j��K�!�!�"h�i�i�i�i�i�	j�����}�}�"6�}�7�7�7s�A	�	$A0�/A0c	�p�|j�|��}i}|D]d}|d}||vrg||<||�|dt|d��|�|d��d����ed�|���D��}|�|���S)N�domain�website�urls�advices)r��urls_scannedr�c��g|]
\}}||d���S))r��websitesrE)�.0r�r�s   rG�
<listcomp>z5SmartAdviceUtil.get_site_statuses.<locals>.<listcomp>s%��n�n�n�?O�v�x�V��:�:�n�n�nrFr�)r]�	site_info�append�lenr�rprs)r^r�r��site_statuses_datar�r�rks       rG�get_site_statusesz!SmartAdviceUtil.get_site_statuses�s����*�4�4�X�>�>����#�	�	�G��X�&�F��/�/�/�-/�"�6�*��v�&�-�-�"�9�-� #�G�F�O� 4� 4��8�8���9K�L�L�/�/�
�
�
�
�
o�n�Se�Sk�Sk�Sm�Sm�n�n�n���}�}�&�}�)�)�)rFc	��|���}g}|D�]a}|d}|d}|�d��r|�|���>t|��}	|	j|d<|r|d}
ddd�}n |�|d|	|��\}
}|r
|	j|d	<|
|d<|	j|d
<|	j|d<t|	j|dd
��j
|d<|d
rZ|�|	j|dd
��}t|t|	j|dd
�����|d<|�|��|�|����c|S)Nr�r��IM360_�descriptionr�r)�total_stages�completed_stages�id�detailed_description�
is_premium�module_namer�r��license_status)r�rMrO)�copy�
startswithr�r!�short_descriptionr�r��is_premium_featurer�r�name�_get_subscription_statusrSrrl)
r^�from_api�status_from_microservicer�r��visible_advices�item�
advice_itself�advice_type�advice_instancer�r��subscription_statuss
             rGr�z(SmartAdviceUtil.prepare_advices_response
s����-�-�/�/�����)	)�)	)�D�!��N�M�'��/�K��%�%�h�/�/�
��&�&�t�,�,�,��1�+�>�>�O�+:�+L�M�-�(�(�
P�&�x�0��*+��C�C���!%�!8�!8��t�9L�9H�$�"P�"P�����
]�8G�8\�
�4�5�&,�M�(�#�*9�*L�M�,�'�+:�+F�M�-�(�.H��+�T�*�-=�j�-I�/K�/K�KO�
�*�+��\�*�
�&*�&C�&C�#�/��j�1A�*�1M�'O�'O�#�04�.� <�'�3�T�*�5E�j�5Q�!S�!S�1�1�1�
�n�-�

� � ��(�(�(��"�"�4�(�(�(�(��rFc�R�d}t||��rd}t||��rd}|S)zQ
        Determines current subscription status based on feature status.
        �no�activer�)r
r)r^r�r�r�s    rGr�z(SmartAdviceUtil._get_subscription_status:s@��#���k�8�4�4�	+�"*��"�;��9�9�	,�"+��"�"rFc���|�|��\}}|d}	|dr|d|d<n
|j|d<|dr|d|d<n
|j|d<|d=|�|���S)z<Load validated advice details and update it before returningr�r�r��titler�)r�r�r�rs)r^r�r�r�r�s     rGr�zSmartAdviceUtil.advice_detailsEs���(,�(@�(@��(K�(K�%��o�$�X�.�
�	���'�	Y�4A�-�4P�M�0�1�1�4C�4X�M�0�1���!�	M�+8��+A�M�-�(�(�+:�+L�M�-�(��'�"��}�}�,�}�/�/�/rF�
ACCELERATE_WP�
ignore_errors�
async_mode�source�reason�accept_terms�analytics_datac		�0�t|�|��d�����|r*tj��}	|	r|�|��S|�|||||||��}
|�t||||
|��|rd}
|
S)Nr�)r{r��closere�fork�manage_advice_status�_exec_advice_managingr4)r^�actionr�r�r�r�r�r�r��child�outputs           rG�
manage_advicezSmartAdviceUtil.manage_adviceas���
	
�T�
�
�	�
*�
*�C�0�0�6�6�8�8�8��	<��G�I�I�E��
<��0�0��;�;�;��+�+�F�I�}�j�,2�F�L�J�J���%�(���F�F�TZ�[�[�[��	��F��
rFr�c�J�	|�|��\}}	|tjjk�r�|r!t	|	j|dd��t
|	j|dd��tjkrqtj
ddd���tj�
|�|����r(tj|�|����SS|	jdi|d�d|i��\}
}|
r�|j�d��|j�|d|�	��	|�|dd|dd
|dd���n9#t,$r|j�d��Y�nwxYw�n|tjjkr�|	jdi|d��\}
}|
r�|j�d
��|r,|j�|d||dt4����n|j�|d|�	��	|�|dd|dd
|dd��n=#t,$r|j�d��YnwxYwnt7d|�����tj�
|�|����r'tj|�|����n_#tj�
|�|����r(tj|�|����wwxYw|r+|�|�|��|��|S|S)z:Execute managing advice with passed action: apply/rollbackr�r��LICENCE_TERMS_APPROVE_REQUIREDz�License approve required to use this feature. Open AccelerateWP plugin in your control panel, apply advice and accept terms and conditions to proceed with installation.)rk�textr�zApplied successfully�applied)r�r�r�r�r�z:Error while syncing cl-smart-advice plugin on advice applyzRollback successfully�reviewN)r�r�r�r�z=Error while syncing cl-smart-advice plugin on advice rollbackz/Unsupported action with advice, passed action: rE)r�r=rC�valuerr�rr�NOT_APPROVEDrmrnrerfrzr�r�r>r[r�r]�
update_advice�_sync_advicer�r�rDr?r*�
ValueErrorr�rx)r^r�r�r�r�r�r�r�r�r��
action_resultr�s            rGr�z%SmartAdviceUtil._exec_advice_managingwsv��9	9�,0�,D�,D�Y�,O�,O�)�L�/���,�2�2�2��[�-�'�3�\�*�5M�j�5Y�[�[�[�.�'�3�$�Z�0��<�>�>�AU�Ab�c�c� �:�"B�!\�'�'���Z�w�~�~�d�0�0��;�;�<�<�
9��	�$�,�,�Y�7�7�8�8�8�8�
9�O)>��(=�)[�)[��Z�@X�)[�)[�LY�)[�)[�)[�%�
�v� �l��K�%�%�&<�=�=�=��'�5�5�	�=F�=C�6�E�E�E�l��)�)�,�z�*B�:�*N�*6�z�*B�8�*L�*6�z�*B�9�*M�O�O�O�O��%�l�l�l���-�-�.j�k�k�k�k�k�l����l��=�1�7�7�7�(@��(@�(\�(\�<�PZ�C[�(\�(\�%�
�v� �o��K�%�%�&=�>�>�>��I��+�9�9�I�AI�AG�AG�H^�I^�H^�A_�:�a�a�a�a�
�+�9�9�I�AI�AG�:�I�I�I�o��)�)�,�z�*B�:�*N�*6�z�*B�8�*L�*6�z�*B�9�*M�O�O�O�O��%�o�o�o���-�-�.m�n�n�n�n�n�o����!o�&!�![�SY�![�![�\�\�\��w�~�~�d�0�0��;�;�<�<�
9��	�$�,�,�Y�7�7�8�8�8����w�~�~�d�0�0��;�;�<�<�
9��	�$�,�,�Y�7�7�8�8�8�8�
9�����	����d�2�2�9�=�=�$�
&�
&�
&��M��Ms]�BL�3AL�;F�L�$F,�(L�+F,�,BL�;J�?L�$J'�$L�&J'�'L�AM3c�(�	|j���}tt|��td�|D�������}n-#t$r t�ddgd��}YnwxYw|�|���S)z#Return advice counters for a serverc�6�g|]}|dddk�|��S)r�r�r�rE)r�r�s  rGr�z3SmartAdviceUtil.advice_counters.<locals>.<listcomp>�s9��F�F�F��#�H�-�h�7�9�D�D�$�D�D�DrF)�totalr�r	r�Nr�)r]r�rSr�r+�fromkeysrs)r^r�rks   rG�advice_counterszSmartAdviceUtil.advice_counters�s���	��.�:�:�<�<�L���,�'�'��F�F�,�F�F�F�G�G����F�F���	?�	?�	?��]�]�G�Y�#7��>�>�F�F�F�	?�����}�}�&�}�)�)�)s�A�'A;�:A;c
�~�|�|��\}}|�|||��\}}|�|j|dd��}|dkr�|�|��}|�|��}tj�|��rt
j	|��|rB|j
d|t|���t|j|dd��d�|�d|i��S|j
d|t|���t|j|dd��d�|��S)zS
        Return current status and progress of managing particular advice.
        r�r�r�)�object_cache)r�rOrMr�rE)
r�r�r�r�r�r�rerfrzr�rsrSr)	r^r�r�r�r�r�r�rk�	_progresss	         rGr�z$SmartAdviceUtil.manage_advice_status�s���)-�(@�(@��(K�(K�%��o��0�0��O�1=�?�?����#�;�;��'��j�)A�*�)M�O�O���Y����(�(��3�3�F��+�+�I�6�6�I��w�~�~�i�(�(�
%��	�)�$�$�$��

!�$�t�}�	!�!�!%�%8�"�"�"�!=�'�3�$�Z�0��<�!>�!>�	!�	!��	!�	!� �	!�	!�	!�	!��t�}�	
���0����5��+��Z�(��4�6�6�	
�	
��	
�	
�		
rFc��|j�dd���}t��}i}|D]�}|�d��}|s)|j�dt
|�����B|�d��|�d��}}t||g��s(|j�dt
|����|||<��|���D]�\}}		|�	||	|��}
|
s#tjd	t
|�����B|�|
���X#t$r#}tjd
|d|i���Yd
}~��d
}~wwxYw|�d���S)z�
        Updates incompatibilities only, but could be extended to more magic
        how to make microservice know that users/domains/websites no longer exist
        FT)�filtered�show_allr�z9Malformed advice metadata, does not have metadata key: %sr�r�zNMalformed advice metadata, does not have required username or domain field: %sz.Updated metadata for user: %s will not be sentz6Failed to update advice metadata with Smart Advice: %s�fingerprint��extraNz Advices metadata update finishedr�)r]r�r5�getr[�errorrQ�allrp�get_updated_extended_metadatarY�warning�sendr�rs)r^r��getter�user_domain_pairs�
advice_object�current_adv_metadatar�r��user�user_domain�updated_metadatar�s            rG�update_advices_metadataz'SmartAdviceUtil.update_advices_metadata�s���
�-�9�9�5�SW�9�X�X��������,�
	1�
	1�M�#0�#4�#4�Z�#@�#@� �'�
���!�!�"]�"%�m�"4�"4�6�6�6��3�7�7�
�C�C�EY�E]�E]�^f�Eg�Eg�f�H����)�*�*�
=���!�!�"r�"%�&:�";�";�=�=�=�+1��h�'�'�!2�!8�!8�!:�!:�	�	��D�+�
�#)�#G�#G��k�[j�#k�#k� �'���O�$T�VY�Z^�V_�V_�`�`�`�����,�-�-�-�-���
�
�
��
�V� !� -�q�% �!�!�!�!�
���������

�����}�}�"D�}�E�E�Es�4;E�0E�
E3�E.�.E3c
�0�|j���}|�d���}|�|��|�|��}	|�||||�|dd�����n9#t$r,|j�	dt|����YdSwxYw|���}|�t�|�t�|��}||vri||<||||<|�
|��dS)NT��
cache_only)r�r�z/Smart Advice plugin sync failed for website: %s)r]r��im360_advice�extend�get_advice_hash_map�_run_smart_advice_scriptr�r�r[r�rQ�_read_advices_cache�advice_cache_separator�_update_advices_cache)	r^r�r�r�r��im360_advice_list�advice_hash_map�cached_advices_by_site�keys	         rGrzSmartAdviceUtil._sync_advice&se���-�9�9�;�;��!�-�-��-�>�>�����0�1�1�1��2�2�?�C�C��	��)�)�(�G�V�*.�*G�*G��ae�pt�+H�+v�+v�
w�
w�
w�
w���	�	�	��K�!�!�"S�UX�Y`�Ua�Ua�b�b�b��F�F�	����"&�!9�!9�!;�!;���\�/�\��\�;Q�\�SZ�\�\���,�,�,�*,�"�3�'�&5�c�&:��s�#��"�"�#9�:�:�:�:�:s�.B
�
2C�?Cc�t�ddlm}t|��}|��j�|��}|S)Nr)�AWPProvisionAPI)�xray.adviser.awp_provision_apir2r�awp_client_api�	get_usage)r^r�r2�acc_id�	cdn_usages     rG�_get_cdn_usage_statisticsz)SmartAdviceUtil._get_cdn_usage_statistics=sE��B�B�B�B�B�B�"�8�,�,��#�O�%�%�4�>�>�v�F�F�	��rFc	��t|||��}	t|	||���|||���|�d���S)N)r�r�r��event�feature�
variant_idzAnalytics sentr�)r9r:�lowerrs)
r^r�r;r�r:r��
journey_id�	user_hashr<r�s
          rG�analytics_reportz SmartAdviceUtil.analytics_reportCs\��7�x��J�W�W���n�#,� &�����$�!(�$.�	0�	0�	0�	0��}�}�"2�}�3�3�3rFc�j�	t|��dd}t||��}n,#t$r|j�d��d}YnwxYw	t|��}n,#t$r|j�d��i}YnwxYwt
t��durdndt��durdnd���}|j	dittt��|�
|��|td	|��td
|��||�������S)
ad
        gets options:
        "panel_type": "cpanel",
        "panel_url": "https:/cpanel-foo.com/", # or https://plesk-bar.com/
        "panel_emails": "root@hosting.com,manager@hostring.com,foo@bar.com",
        "upgrade_url": "https://...",
        "upgrade_url_cdn": "https://...",
        "subscription": dict,
        "notifications": dict,
        r�Unable to get user emailsr�zCannot obtain subscription infoT�disabled_server�enabled)�email_status�reminders_statusr
�cdn)rJrKrLrMrNrOrPrE)rrr�r[r�rrSrrrsrrIrr�r)r^r�r��emailrOrPs      rG�get_optionszSmartAdviceUtil.get_optionsOs���	� ��*�*�1�-�a�0�F�(��6�:�:�E�E���	�	�	��K�!�!�"=�>�>�>��E�E�E�	����	�1�(�;�;�L�L���	�	�	��K�!�!�"C�D�D�D��L�L�L�	�����.`�.b�.b�fj�.j�.j�*�*�py�2`�2b�2b�fj�2j�2j�.�.�py�
�
�
�
�
�t�}���v��)�+�+�)-�)@�)@��)J�)J�,1�+G��X`�+a�+a�/K�E�S[�/\�/\�,8�-:�

<�
<�
<� 
� 
���	s!�+.�&A�A�A+�+&B�BTc���|s|j���}|�|���}|�|��|�|��}|���}|s|s|�d���S|�|||�|d������}|�	|��|�d���S)Nr$zNo advices found on the serverr�Tr�)�current_advices_jsonzPlugin installed)
r]r�r&r'r(r*rs�_sync_sa_pluginr�r,)r^r��im360_cachedr-�new_hash_cache_by_site�existing_hash_cache_by_site�
updated_caches       rGr�z-SmartAdviceUtil.sync_advices_wordpress_pluginws����	@�"�1�=�=�?�?�O�!�-�-��-�F�F�����0�1�1�1�!%�!9�!9�/�!J�!J��&*�&>�&>�&@�&@�#�%�	H�.I�	H��=�=�&F�=�G�G�G��,�,�"�'�!%�!>�!>��Y]�!>�!^�!^�-�
�
�
�
	
�"�"�=�1�1�1��}�}�"4�}�5�5�5rFc�z��tjd��i}|���D]�\}}|�t��\}�}|�||�|����stjd|��|||<�g|r�fd�|D��}	nd}		|��|||	��n8#t$r+|j
�dt|����Y��wxYw|||<��t|��t|��z
}
tjd��|
D]�}|�t��\}�}tjd|��	|��||d����P#t$r+|j
�dt|����Y��wxYw|S)Nz,Synchronization of smart advice plugin beginz:Website %s does not need update because cache hash matchesc�n��g|]1}|�di���d���k�/|��2S)r�r�)r)r�r�r�s  �rGr�z3SmartAdviceUtil._sync_sa_plugin.<locals>.<listcomp>�sM���,g�,g�,g�v�/5�z�z�*�b�/I�/I�/M�/M�j�/Y�/Y�]e�/e�/e�-3�/e�/e�/erFz/Smart advice plugin sync failed for website: %szNFound outdated records in cache, removing wordpress plugins for those websitesz!Removing outdated cache record %s)�advices_json)rY�inforp�splitr+�_should_sync_websiterr�r)r�r[r�rQ�set)r^�new_hash_advice_cache�existing_hash_advice_cacherK�updated_advicesr0�id_status_hashr�r��filtered_advices_by_user�orphan_hash_recordsr�s           @rGrLzSmartAdviceUtil._sync_sa_plugin�s=�����C�D�D�D���#8�#>�#>�#@�#@�	2�	2��C��*-�)�)�4J�*K�*K�'�V�X�w��,�,�^�=W�=[�=[�\_�=`�=`�a�a�
��
�Z�\_�`�`�`�'5���$��$�
0�,g�,g�,g�,g�AU�,g�,g�,g�(�(�,0�(�
��-�-�h���Ia�b�b�b�b���
�
�
���%�%�&W�Y\�]d�Ye�Ye�f�f�f���
����$2�O�C� � �"�"<�=�=��DY�@Z�@Z�Z����E�	F�	F�	F�&�		�		�C�*-�)�)�4J�*K�*K�'�V�X�w��L�<�c�B�B�B�
��-�-�h���VZ�-�[�[�[�[���
�
�
���%�%�&W�Y\�]d�Ye�Ye�f�f�f���
�����s$�'C�2C5�4C5�)F�2F8�7F8c�h�tt�d�d��5}t|��5ttd��5}tjd|��tj||d���ddd��n#1swxYwYddd��n#1swxYwYddd��dS#1swxYwYdS)Nz.lockza+r�z-Updating advice hash map cache with values %sr#��indent)r{r(r3rYr�rmr�)�new_cached_advices�lock_fd�fs   rGr,z%SmartAdviceUtil._update_advices_cache�sp��
�&�-�-�-�t�
4�
4�	7����!�!�	7�	7��&��,�,�	7�01��M�I�K]�^�^�^��I�(�!�A�6�6�6�6�		7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7����	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7����	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7�	7����	7�	7�	7�	7�	7�	7sW�B'�B�-A8�,B�8A<�<B�?A<�B�B'�B	�B'�B	�B'�'B+�.B+c�.�i}tj�t��rn	t	t��5}tj|��}ddd��n#1swxYwYn,#t$r|j�	d��i}YnwxYw|S)Nz!Unable to read advices cache json)
rerfr�r(r{rmr|r�r[r�)r^r/rcs   rGr*z#SmartAdviceUtil._read_advices_cache�s���!#��
�7�>�>�+�,�,�	,�
,��+�,�,�:��-1�Y�q�\�\�*�:�:�:�:�:�:�:�:�:�:�:����:�:�:�:����
,�
,�
,���%�%�&I�J�J�J�)+�&�&�&�
,����&�%s4�A)�A�A)�A!�!A)�$A!�%A)�)&B�Bc��||kS�NrE)�current_hash�cached_hashs  rGrVz$SmartAdviceUtil._should_sync_website�s
���{�*�*rFc��tj��}|D]`\}}|�t|�������|�|������a|���Srf)�hashlib�md5rlrQ�encode�	hexdigest)�id_status_pairs�hr�r�s    rG�	make_hashzSmartAdviceUtil.make_hash�sp���K�M�M��!0�	&�	&��I�v�
�H�H�S��^�^�*�*�,�,�-�-�-�
�H�H�V�]�]�_�_�%�%�%�%��{�{�}�}�rFc�&��i}|D]l}|d}|d}|d�t�|d�t�|d��}||vrg||<||�|d|df���m�fd�|���D��S)	a�
        Prepare fingerprints for each of the advices generated,
        grouped by the website that advice is assigned to.

        Result example:
        {
          "demo-10-194-0-9.traefik.me;demowp;/": "f43c7bcdccc28fc1ac92b2384f35f9dd"
        }

        Key is combination of domain, usernane and webiste path and
        value is hash against list of advices and their current statuses.
        r�r�r�r�r�r�r�c�|��i|]8\}}|��tt|d����������9S)c�,�t|d��S)Nr)rQ)r�s rG�<lambda>z@SmartAdviceUtil.get_advice_hash_map.<locals>.<dictcomp>.<lambda>�s��s�SW�XY�SZ�|�|�rF)r0)rp�tuplero)r�r0rnr^s   �rG�
<dictcomp>z7SmartAdviceUtil.get_advice_hash_map.<locals>.<dictcomp>�sT���
�
�
�$��_�
�����f�_�B[�B[�&\�&\�&\� ]� ]�^�^�
�
�
rF)r+r�rp)r^r�r�r�r�r�r0s`      rGr(z#SmartAdviceUtil.get_advice_hash_map�s�������	M�	M�F��j�)�H� ��*�K��h�'�C�)?�C��*�AU�C�+�C�-5�i�-@�C�C�C��(�"�"� "���
��S�M� � �+�d�"3�[��5J�!K�L�L�L�L�
�
�
�
�(0���(8�(8�
�
�
�	
rFc��t|d��5}|�|��ddd��dS#1swxYwYdS)z"
        For easy mocking
        r�N)r{r�)rf�contentrcs   rG�_save_custom_phpz SmartAdviceUtil._save_custom_php�s���
�$��_�_�	��
�G�G�G����	�	�	�	�	�	�	�	�	�	�	�	����	�	�	�	�	�	s�4�8�8c	��tj|��j�d�}d}tj�||��}gd�}d}t
jd|�d�ddd���}|j�	dd	���	d
d	���
��}	|j�dt|j����t|	��dkrd}n�t|	��dkr�|	d
kr�d
|	�d��vrd}np|	�d��rdd�|��z}nBg}
|D] }||jvr|
�|���!|
rd|	�dd�|
����}|�rC|j�d||��t%|��5tj�|��s5tj�|��stj|d���|�||��ddd��n#1swxYwYt
jdddd|d|gdd���}|j�dt|j����|j�dt|��t|j��t|����dSdS)Nz/.clwposz.php-ini)z/opt/alt/php-xray/z)/opt/cloudlinux-site-optimization-module/z/opt/cloudlinux/z-/usr/sbin/plesk bin site --show-php-settings z | /usr/bin/grep open_basedirT)r��capture_output�shellzopen_basedir =r�z
open_basedir=z!Current open_basedir settings: %sr�none�:zopen_basedir = nonez,open_basedir = {WEBSPACEROOT}{/}{:}{TMP}{/}:zopen_basedir = z0Updating open_basedir setting: %s for domain: %si�)�modez/usr/sbin/plesk�bin�sitez--update-php-settingsz	-settings�r�r{z Plesk settings update result: %sz>open_basedir setting updated for domain "%s" from "%s" to "%s")�pwd�getpwnam�pw_dirrerf�join�
subprocess�run�stdout�replace�stripr[rTrQr�rUr�r�rr�rgrhryr)
r^r�r��
clwpos_dir�
custom_php�custom_php_full�extra_paths�updated_setting�open_basedir_setting�open_basedir_setting_sanitized�
missing_paths�
extra_pathrks
             rG�_prepare_php_for_pleskz&SmartAdviceUtil._prepare_php_for_plesk�sz����X�.�.�5�?�?�?�
��
��'�,�,�z�:�>�>��
�
�
��
��)�~�a�F�a�a�a��d�$� 8� 8� 8��*>�)D�)L�)L�M]�_a�)b�)b�)j�)j��R�*!�*!�!&����	'�����<�c�BV�B]�>^�>^�_�_�_��-�.�.�!�3�3�.�O�O�
�/�
0�
0�1�
4�
4�9W�[a�9a�9a��7�=�=�c�B�B�B�B�"7���/�:�:�3�?�?�
s�"P�SV�S[�S[�\g�Sh�Sh�"h���!#�
�"-�9�9�J�!�)=�)D�D�D�%�,�,�Z�8�8�8�� �s�&r�8V�&r�&r�Y\�Ya�Ya�bo�Yp�Yp�&r�&r�O��	4��K���O�Q`�bh�i�i�i�!��*�*�
H�
H��w�~�~�o�6�6�9��7�=�=��4�4�9����%�8�8�8�8��%�%�o��G�G�G�	
H�
H�
H�
H�
H�
H�
H�
H�
H�
H�
H����
H�
H�
H�
H� �^�%6��v�G^�`f�hs�%4�%6�)-�d�D�D�D�F�
�K���?��V�]�AS�AS�T�T�T��K���^�!�&�k�k�!�"6�"=�>�>�!�/�2�2�
4�
4�
4�
4�
4�	4�	4s�6A+H-�-H1�4H1c	���|�|�g���}n|�|���}	|�||||��}n#t$rYdSwxYw	t|��5t	|d��ddd��n#1swxYwYn#t
$rYdSwxYw|�||��}tjd||��tj
|dd���}|jdkrn|j�
dt|j��t|j��t|j��dd	|j��i�
��t#d���dS)Nr��z<Updating Smart Advice plugin for website %s with advices: %sTr�rzESmart advice plugin failed with exit code: %s, stdout: %s, stderr: %srz"smart-advice-plugin-sh-returncode-rz'Smart Advice plugin installation failed)rs�!_prepare_smart_advice_script_argsrrr8r}�_get_smart_advice_script_cmdrYr�r�r��
returncoder[rrQr��stderrr,)	r^r�r�r�rS�json_string�attrs�commandrks	         rGr)z(SmartAdviceUtil._run_smart_advice_script8s������-�-�R�-�0�0�K�K��-�-�\�-�:�:�K�	��:�:�8�W�f�Va�b�b�E�E���	�	�	��F�F�	����	� ��*�*�
/�
/�$�U�1�X�.�.�.�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/����
/�
/�
/�
/����	�	�	��F�F�	�����3�3�H�e�D�D���
�T��{�	,�	,�	,����d�4�H�H�H�����!�!��K���e�!�&�"3�4�4�!�&�-�0�0�!�&�-�0�0�"/�1i�V\�Vg�1i�1i�% �	
�
!�
!�
!�)�)R�S�S�S�"�!sG�A
�

A�A�B�+B
�B�
B�B�B�B�
B'�&B'r�rSc��t��}d}d|��}|�|��}|j�d|��	t	||��}	n,#t
$r|j�d��d}	YnwxYwt|��d|z}
t|
��s*|j�d|
��td���t|��}|D]2}|�d	��|kr|�d
��}
n<�3|j�d|t|����td|�����|
s-|j�d
|��td|�����|dkrB	|�||��n*#t
$r|j�d��YnwxYwt!||
��}|std���t#||��||
|
|||	|g}|S)Nzrun.pyz*/opt/alt/php-xray/php/smart-advice-plugin/zGot panel login link: %srBr�rz<[Smart Advice Plugin]: wordpress: %s does not exist, skippedzNon-existing wordpress site�vhost�
php_binaryz*Php data for domain %s was not found in %sz%Unable to get php version for domain z)Php version for user: %s was not obtainedz)Php binary was not identified for domain �Pleskz-Setting up php for Plesk for SA plugin failedz$Unable to detect MU plugin directory)rr�r[rTrr�r�rrrr2rrrQr,r�r6r7)r^r�r�r�rS�panel�script_name�script_path�panel_user_awp_linkrH�full_website_path�php_info�php_data�php_binary_path�
mu_plugin_dir�ress                rGr�z1SmartAdviceUtil._prepare_smart_advice_script_argsXs���������P�;�P�P��"�5�5�h�?�?������3�5H�I�I�I�	�(��6�:�:�E�E���	�	�	��K�!�!�"=�>�>�>��E�E�E�	����$�F�O�O�A�.��8���+�,�,�	<��K���[�.�
0�
0�
0��:�;�;�;�'��1�1�� �	[�	[�H��|�|�G�$�$��.�.�"*�,�,�|�"<�"<����/�
�K���J�F�TW�X`�Ta�Ta�b�b�b�(�)Y�QW�)Y�)Y�Z�Z�Z��	_��K���I�&�
(�
(�
(�(�)]�U[�)]�)]�^�^�^��G���
W��+�+�H�f�=�=�=�=���
W�
W�
W���%�%�&U�V�V�V�V�V�
W����)��3D�E�E�
��	Q�(�)O�P�P�P�	+�8�]�C�C�C�
�������
���
s$�A�&B�B�
F!�!$G�Gr�r�c���ttj��rd|g}|�|��n/d|dzdz|d<d�|��}dd|ddd	|g}|S)
Nz/sbin/cagefs_enter_user�'r�� �sudoz-uz-sz	/bin/bashz-c)rr�CAGEFSr'r�)r�r�r��command_strs    rGr�z,SmartAdviceUtil._get_smart_advice_script_cmd�sr��%�g�n�5�5�	Q�,�h�7�C��J�J�u������U�1�X�~��+�E�!�H��(�(�5�/�/�K��4��4��d�K�P�C��
rFc��t��}|std���tjdt	��t||��d���S)z;
        Method with handles work with agreements.
        �)This command can only be executed as userrj)rkr0r�)r/r,rmrnr0r)r^r;�user_contexts   rG�get_agreement_textz"SmartAdviceUtil.get_agreement_text�s\��*�+�+���	V�(�)T�U�U�U��z��"���.�w��E�E�
�
���	rFc���t��}|std���|�|��\}}tjddt|��dddt|��d|jg	dd�	��}|jd
krv|j�	dt|j��t|j
��t|j��dd
|j��i���td|jz���dS)z�
        Proxy method to AWP which creates subscription
        listening for the status of module and automatic advice appy.
        r�zcloudlinux-awp-userz--userrOz--listenz--advice-idz	--featureTr�rzYCreate subscription smart advice plugin failed with exit code: %s, stdout: %s, stderr: %srz,smart-advice-plugin-subscription-returncode-rz"cloudlinux-awp-user call failed %sN)r/r,r�r�r�rQr�r�r[rr�r�)r^r�r��_r�rks      rG�create_subscriptionz#SmartAdviceUtil.create_subscription�s��
*�+�+���	V�(�)T�U�U�U�!�5�5�i�@�@���?���!��c�,�'�'����3�y�>�>���4�
!
��T�+�+�+�����!�!��K���;�!�&�"3�4�4�!�&�-�0�0�!�&�-�0�0�"/�1s�`f�`q�1s�1s�% �
�
!�
!�
!�)�)M�PV�P]�)]�^�^�^�"�!rFc�t�g}d}tj�|��s|S|r|���S	t	j|ddgdddd���}t
j|j��}|rd�|D��}n�#tj	tf$r%}|j�d|��Yd}~nld}~wtj
$r%}|j�d	|��Yd}~n:d}~wtj$r%}|j�d
|��Yd}~nd}~wwxYw|�|��|S)Nz/usr/bin/imunify360-agentzsmart-advicerPT�<)r�r{�timeout�checkc�T�g|]%}|dd�d���#|��&S)r�r�r�)r�)r�r�s  rGr�z0SmartAdviceUtil.im360_advice.<locals>.<listcomp>�sE�����!��H�~�f�-�8�8��B�B�����rFz&Unable to run IM360 advice command: %sz6Timeout expired while running IM360 advice command: %sz(Unable to parse json of IM360 advice: %s)rerfr��_im360_read_advice_cacher�r�rm�loadsr��CalledProcessErrorr}r[r��TimeoutExpiredr~�_im360_update_advice_cache)r^r%r��im360_agentrkr�r�s       rGr&zSmartAdviceUtil.im360_advice�s�����1���w�~�~�k�*�*�	��M��	3��0�0�2�2�2�	Q��^�[�.�/�$R�)-�d�B�VZ�\�\�\�F��*�V�]�3�3�K��
���%0��������-�w�7�	O�	O�	O��K�!�!�"J�A�N�N�N�N�N�N�N�N������(�	_�	_�	_��K�!�!�"Z�\]�^�^�^�^�^�^�^�^������#�	Q�	Q�	Q��K�!�!�"L�a�P�P�P�P�P�P�P�P�����	Q����	
�'�'��/�/�/��
s0�AB�D �B7�7D �	C)�)D �;D�D c��g}tj�t��s|S	t	t��5}tj|��}ddd��n#1swxYwYnd#t$r%}|j�	d|��Yd}~n:d}~wt
j
$r%}|j�	d|��Yd}~nd}~wwxYw|S)Nz:An OS error occurred while reading the cache for IM360: %sz*Unable to read IM360 json advice cache: %s)rerfr�r)r{rmr|r}r[r�r~�r^r�rcr�s    rGr�z(SmartAdviceUtil._im360_read_advice_cache�s0�����w�~�~�5�6�6�	��M�	S��-�.�.�
&�!���1����
&�
&�
&�
&�
&�
&�
&�
&�
&�
&�
&����
&�
&�
&�
&����	c�	c�	c��K�!�!�"^�`a�b�b�b�b�b�b�b�b������#�	S�	S�	S��K�!�!�"N�PQ�R�R�R�R�R�R�R�R�����	S�����
sF�A+�A�A+�A#�#A+�&A#�'A+�+
C�5B�C�'C�Cc�^�	ttd��5}tj||d���ddd��dS#1swxYwYdS#t$r&}|j�d|��Yd}~dSd}~wtj$r&}|j�d|��Yd}~dSd}~wwxYw)Nr�r#r_z;An OS error occurred while updating the cache for IM360: %sz+Unable to write IM360 json advice cache: %s)r{r)rmr�r}r[r�r~r�s    rGr�z*SmartAdviceUtil._im360_update_advice_cache�s(��	T��-�s�3�3�
/�q��	�&�!�A�.�.�.�.�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/�
/����
/�
/�
/�
/�
/�
/���	d�	d�	d��K�!�!�"_�ab�c�c�c�c�c�c�c�c�c������#�	T�	T�	T��K�!�!�"O�QR�S�S�S�S�S�S�S�S�S�����	T���sC�A	�<�A	�A�A	�A�A	�	
B,�A4�4B,�B'�'B,)F)FF)FFr�NFN)FFr�NF)NNNN)NTrf)?r@rArB�__doc__ra�staticmethodrQr\rs�intrxrr�r��boolr�r�r�r-rrS�objectr�rr�r"r�r�r�r.r�r�r�r�r�r�rr�r"rr8r@rIr�rLr,r*rVrpr
r(ryr�r)r	r�r�r�r��listr&r�r�rErFrGrUrUXs9������/�/�W�W�W���#��$�����\��
�	9�c�	9�	9�	9��\�	9��4�c�4�c�4�4�4��\�4��3��8�C�=����� �2�C�2�C�2�2�2��\�2�=�3�=�4�=�=�=�=�6�3�6�3�6�6�6�6����#�I�S�I�U�4��<�5H�I�I�I�#�"�I��!�!�#�!�S�!�4�!�D�!�!�!��\�!�#"�#�#"�0C�#"�H[�#"�#"�#"�#"�J&�c�&�v�&�(,�&�16�s�D�y�1A�&�&�&�&�"8�8�S�8�8�8�8��
*�S�
*�
*�
*���
*�.�.�.�.�`	#�	#�	#�0��0��0�0�0�0�8KP�>M�?D�,0���s��4��"&��8;��!��8<��'*��6>�c�]�����,X]�FU�GL�G�G�C�G�C�G�PT�G�*.�G�@C�G�&)�G�@D�G�QY�Z]�Q^�G�G�G�G�R*��*�*�*�*� (
�c�(
�c�(
�(
�(
�(
�T*F�*F�*F�X;�;�;�.����KO�EI�	4�	4�	4���	4��%�%���%�N6�6�6�6�,*�*�*�*�X�7�7��\�7�	&�	&�	&��+�+��\�+�����\��
�d�3��8�n�
�
�
�
�:����\��94�94�94�vT�T�T�T�@<�4�PS�9�<�dg�<�lp�qt�lu�<�<�<�<�|��s��4��9���c������\�����_�_�_�>�������B�$����� T�T�T�T�TrFrU)Wr�rmrYrerjr�r��
contextlibr�dataclassesrr�typingrrrr	r
�enumr�clwpos.user.configr�clwpos.papir
rrrrrrrrr�clcommon.cpapirrrrrr�clcommon.clwpos_libr�clcommon.clpwdr�clcommon.constr�advice_typesr!r�r"�	apiclientr$r%�internal.constantsr&r'r(r)r*�internal.exceptionsr+r,�internal.user_plugin_utilsr-r.r/�internal.utilsr0r1r2r3�analytics.utilsr4�xray.adviser.clwpos_getr5� xray.smart_advice_plugin_helpersr6r7� xray.smart_advice_plugin_managerr8r9�xray.analyticsr:r+r=rIrUrErFrG�<module>r�s�������������	�	�	�	�����
�
�
�
�����%�%�%�%�%�%�)�)�)�)�)�)�)�)�3�3�3�3�3�3�3�3�3�3�3�3�3�3�������3�3�3�3�3�3�����������������������������������������+�*�*�*�*�*�*�*�*�*�*�*�"�"�"�"�"�"�-�-�-�-�-�-�)�)�)�)�)�)�.�.�.�.�.�.�.�.���������������D�C�C�C�C�C�C�C�q�q�q�q�q�q�q�q�q�q�Q�Q�Q�Q�Q�Q�Q�Q�Q�Q�Q�Q�:�:�:�:�:�:�0�0�0�0�0�0���������a�`�`�`�`�`�`�`�+�+�+�+�+�+��������D����
�����������nT�nT�nT�nT�nT�nT�nT�nT�nT�nTrF