
    Vhk                         d dl mZmZmZ eZdZdZdZd dl	m
Z
 d dlmZ d dlmZ d dlmZmZmZmZmZmZmZmZ d d	lmZmZmZmZmZ d d
lmZ d dl m!Z!  G d de"      Z#d Z$e%dk(  r e$        yy)    )absolute_importdivisionprint_functionu  
---
module: mysql_info
short_description: Gather information about MySQL or MariaDB servers
description:
- Gathers information about MySQL or MariaDB servers.

options:
  filter:
    description:
    - Limit the collected information by comma separated string or YAML list.
    - Allowable values are C(version), C(databases), C(settings), C(global_status),
      C(users), C(users_info), C(engines), C(master_status), C(slave_status), C(slave_hosts).
    - By default, collects all subsets.
    - You can use '!' before value (for example, C(!settings)) to exclude it from the information.
    - If you pass including and excluding values to the filter, for example, I(filter=!settings,version),
      the excluding values, C(!settings) in this case, will be ignored.
    type: list
    elements: str
  login_db:
    description:
    - Database name to connect to.
    - It makes sense if I(login_user) is allowed to connect to a specific database only.
    type: str
  exclude_fields:
    description:
    - List of fields which are not needed to collect.
    - "Supports elements: C(db_size), C(db_table_count). Unsupported elements will be ignored."
    type: list
    elements: str
    version_added: '0.1.0'
  return_empty_dbs:
    description:
    - Includes names of empty databases to returned dictionary.
    type: bool
    default: false

notes:
- Compatible with MariaDB or MySQL.
- Calculating the size of a database might be slow, depending on the number and size of tables in it.
  To avoid this, use I(exclude_fields=db_size).
- filters C(users_info) doesn't support MariaDB roles.

attributes:
  check_mode:
    support: full

seealso:
- module: community.mysql.mysql_variables
- module: community.mysql.mysql_db
- module: community.mysql.mysql_user
- module: community.mysql.mysql_replication

author:
- Andrew Klychkov (@Andersson007)
- Sebastian Gumprich (@rndmh3ro)
- Laurent Indermühle (@laurent-indermuehle)

extends_documentation_fragment:
- community.mysql.mysql
a  
# Display info from mysql-hosts group (using creds from ~/.my.cnf to connect):
# ansible mysql-hosts -m mysql_info

# Display only databases and users info:
# ansible mysql-hosts -m mysql_info -a 'filter=databases,users'

# Display all users privileges:
# ansible mysql-hosts -m mysql_info -a 'filter=users_info'

# Display only slave status:
# ansible standby -m mysql_info -a 'filter=slave_status'

# Display all info from databases group except settings:
# ansible databases -m mysql_info -a 'filter=!settings'

# If you encounter the "Please explicitly state intended protocol" error,
# use the login_unix_socket argument
- name: Collect all possible information using passwordless root access
  community.mysql.mysql_info:
    login_user: root
    login_unix_socket: /run/mysqld/mysqld.sock

- name: Get MySQL version with non-default credentials
  community.mysql.mysql_info:
    login_user: mysuperuser
    login_password: mysuperpass
    filter: version

- name: Collect all info except settings and users by root
  community.mysql.mysql_info:
    login_user: root
    login_password: rootpass
    filter: "!settings,!users"

- name: Collect info about databases and version using ~/.my.cnf as a credential file
  become: true
  community.mysql.mysql_info:
    filter:
    - databases
    - version

- name: Collect info about databases and version using ~alice/.my.cnf as a credential file
  become: true
  community.mysql.mysql_info:
    config_file: /home/alice/.my.cnf
    filter:
    - databases
    - version

- name: Collect info about databases including empty and excluding their sizes
  become: true
  community.mysql.mysql_info:
    config_file: /home/alice/.my.cnf
    filter:
    - databases
    exclude_fields: db_size
    return_empty_dbs: true

- name: Clone users from one server to another
  block:
  # Step 1
  - name: Fetch information from a source server
    delegate_to: server_source
    community.mysql.mysql_info:
      filter:
        - users_info
    register: result

  # Step 2
  # Don't work with sha256_password and cache_sha2_password
  - name: Clone users fetched in a previous task to a target server
    community.mysql.mysql_user:
      name: "{{ item.name }}"
      host: "{{ item.host }}"
      plugin: "{{ item.plugin | default(omit) }}"
      plugin_auth_string: "{{ item.plugin_auth_string | default(omit) }}"
      plugin_hash_string: "{{ item.plugin_hash_string | default(omit) }}"
      tls_requires: "{{ item.tls_requires | default(omit) }}"
      priv: "{{ item.priv | default(omit) }}"
      resource_limits: "{{ item.resource_limits | default(omit) }}"
      locked: "{{ item.locked | default(omit) }}"
      column_case_sensitive: true
      state: present
    loop: "{{ result.users_info }}"
    loop_control:
      label: "{{ item.name }}@{{ item.host }}"
    when:
      - item.name != 'root'  # In case you don't want to import admin accounts
      - item.name != 'mariadb.sys'
      - item.name != 'mysql'
      - item.name != 'PUBLIC'  # MariaDB roles are not supported
a  
server_engine:
  description: Database server engine.
  returned: if not excluded by filter
  type: str
  sample: 'MariaDB'
  version_added: '3.10.0'
version:
  description: Database server version.
  returned: if not excluded by filter
  type: dict
  sample: { "version": { "major": 5, "minor": 5, "release": 60, "suffix": "MariaDB", "full": "5.5.60-MariaDB" } }
  contains:
    major:
      description: Major server version.
      returned: if not excluded by filter
      type: int
      sample: 5
    minor:
      description: Minor server version.
      returned: if not excluded by filter
      type: int
      sample: 5
    release:
      description: Release server version.
      returned: if not excluded by filter
      type: int
      sample: 60
    suffix:
      description: Server suffix, for example MySQL, MariaDB, other or none.
      returned: if not excluded by filter
      type: str
      sample: "MariaDB"
    full:
      description: Full server version.
      returned: if not excluded by filter
      type: str
      sample: "5.5.60-MariaDB"
databases:
  description: Information about databases.
  returned: if not excluded by filter
  type: dict
  sample:
  - { "mysql": { "size": 656594, "tables": 31 }, "information_schema": { "size": 73728, "tables": 79 } }
  contains:
    size:
      description: Database size in bytes.
      returned: if not excluded by filter
      type: dict
      sample: { 'size': 656594 }
    tables:
      description: Count of tables and views in that database.
      returned: if not excluded by filter
      type: dict
      sample: { 'tables': 12 }
      version_added: '3.11.0'
settings:
  description: Global settings (variables) information.
  returned: if not excluded by filter
  type: dict
  sample:
  - { "innodb_open_files": 300, innodb_page_size": 16384 }
global_status:
  description: Global status information.
  returned: if not excluded by filter
  type: dict
  sample:
  - { "Innodb_buffer_pool_read_requests": 123, "Innodb_buffer_pool_reads": 32 }
users:
  description: Return a dictionnary of users grouped by host and with global privileges only.
  returned: if not excluded by filter
  type: dict
  sample:
  - { "localhost": { "root": { "Alter_priv": "Y", "Alter_routine_priv": "Y" } } }
users_info:
  description:
    - Information about users accounts.
    - The output can be used as an input of the M(community.mysql.mysql_user) plugin.
    - Useful when migrating accounts to another server or to create an inventory.
    - Does not support proxy privileges. If an account has proxy privileges, they won't appear in the output.
    - Causes issues with authentications plugins C(sha256_password) and C(caching_sha2_password).
      If the output is fed to M(community.mysql.mysql_user), the
      ``plugin_auth_string`` will most likely be unreadable due to non-binary
      characters.
    - The "locked" field was aded in ``community.mysql`` 3.13.
  returned: if not excluded by filter
  type: dict
  sample:
  - { "plugin_auth_string": '*1234567',
      "name": "user1",
      "host": "host.com",
      "plugin": "mysql_native_password",
      "priv": "db1.*:SELECT/db2.*:SELECT",
      "resource_limits": { "MAX_USER_CONNECTIONS": 100 },
      "tls_requires": { "SSL": null },
      "locked": false }
  version_added: '3.8.0'
engines:
  description: Information about the server's storage engines.
  returned: if not excluded by filter
  type: dict
  sample:
  - { "CSV": { "Comment": "CSV storage engine", "Savepoints": "NO", "Support": "YES", "Transactions": "NO", "XA": "NO" } }
master_status:
  description: Master status information.
  returned: if master
  type: dict
  sample:
  - { "Binlog_Do_DB": "", "Binlog_Ignore_DB": "mysql", "File": "mysql-bin.000001", "Position": 769 }
slave_status:
  description: Slave status information.
  returned: if standby
  type: dict
  sample:
  - { "192.168.1.101": { "3306": { "replication_user": { "Connect_Retry": 60, "Exec_Master_Log_Pos": 769,  "Last_Errno": 0 } } } }
slave_hosts:
  description: Slave status information.
  returned: if master
  type: dict
  sample:
  - { "2": { "Host": "", "Master_id": 1, "Port": 3306 } }
connector_name:
  description: Name of the python connector used by the module. When the connector is not identified, returns C(Unknown).
  returned: always
  type: str
  sample:
  - "pymysql"
  version_added: '3.6.0'
connector_version:
  description: Version of the python connector used by the module. When the connector is not identified, returns C(Unknown).
  returned: always
  type: str
  sample:
  - "1.0.2"
  version_added: '3.6.0'
)Decimal)AnsibleModule)CommandResolver)mysql_connectmysql_common_argument_specmysql_drivermysql_driver_fail_msgget_connector_nameget_connector_versionget_server_implementationget_server_version)privileges_getget_resource_limitsget_existing_authenticationget_user_implementationuser_is_locked)	iteritems)	to_nativec                   f    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zd Zd Zd ZddZy)
MySQL_Infoat  Class for collection MySQL instance information.

    Arguments:
        module (AnsibleModule): Object of AnsibleModule class.
        cursor (pymysql/mysql-python): Cursor class for interaction with
            the database.

    Note:
        If you need to add a new subset:
        1. add a new key with the same name to self.info attr in self.__init__()
        2. add a new private method to get the information
        3. add invocation of the new method to self.__collect()
        4. add info about the new subset to the DOCUMENTATION block
        5. add info about the new subset with an example to RETURN block
    c                     || _         || _        || _        || _        || _        t        | j                  | j                        | _        i i i i i i i i i i d
| _        y )N)
version	databasessettingsglobal_statusenginesusers
users_infomaster_statusslave_hostsslave_status)modulecursorserver_implementationserver_versionuser_implementationr   command_resolverinfo)selfr%   r&   r'   r(   r)   s         n/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/mysql/plugins/modules/mysql_info.py__init__zMySQL_Info.__init__c  sj    %:",#6  /0J0JDL_L_ `
	    c                    g }g }|r7i }|D ]x  }|j                  d      | j                  vr| j                  j                  d|z         ?|d   dk(  r!|j	                  |j                  d             h|j	                  |       z |rF| j                  ||t        |             | j                  D ]  }||v s| j                  |   ||<    |S t        t        | j                        t        |      z
        }	| j                  ||t        |	             | j                  D ]  }||vs| j                  |   ||<    |S | j                  ||t        | j                               | j                  S )zGet MySQL instance information based on filter_.

        Arguments:
            filter_ (list): List of collected subsets (e.g., databases, users, etc.),
                when it is empty, return all available information.
        !z,filter element: %s is not allowable, ignoredr   )lstripr+   r%   warnappend_MySQL_Info__collectsetlist)
r,   filter_exclude_fieldsreturn_empty_dbsinc_listexc_listpartial_infofiinot_in_exc_lists
             r-   get_infozMySQL_Info.get_infow  s[    L 	(99S>2KK$$%SVX%XYa5C<OOBIIcN3 OOB'	( ~/?XO 7AH}*.))A,Q7   #'s499~H'E"F~/?_AUV 7A(*.))A,Q7   NN>+;S^L99r/   c                 z   d|v sd|v r| j                          d|v r| j                  ||       d|v r| j                          d|v r| j                          d|v r| j	                          d|v r| j                          d|v r| j                          d	|v r| j                          d
|v r| j                          yy)zCollect all possible subsets.r   r   r   r   r   r    r!   r"   r$   r#   N)	!_MySQL_Info__get_global_variables_MySQL_Info__get_databases_MySQL_Info__get_global_status_MySQL_Info__get_engines_MySQL_Info__get_users_MySQL_Info__get_users_info_MySQL_Info__get_master_status_MySQL_Info__get_slave_status_MySQL_Info__get_slaves)r,   r9   r:   wanteds       r-   	__collectzMySQL_Info.__collect  s    *"6'')&   1ABf$$$& f6!!!#f$$$&V###%F" #r/   c                     | j                  d      }|rM|D ]G  }|d   }i | j                  d   |<   t        |      D ]   \  }}|dk7  s|| j                  d   |   |<   " I yy)zGet storage engines info.zSHOW ENGINESEnginer   N)_MySQL_Info__exec_sqlr+   r   )r,   reslineenginevnamevals         r-   __get_engineszMySQL_Info.__get_engines  s~    oon- Bh/1		)$V,"+D/ BJE3(>A		),V4U;B	B r/   c                     	 t        |t              rt        |      }|S t        |      }	 |S # t        $ r Y |S t
        $ r Y |S w xY w)zConvert unserializable data.)
isinstancer   floatint
ValueError	TypeError)r,   rU   s     r-   	__convertzMySQL_Info.__convert  s`    
	#w'Cj 
 #h 
  	
 
  	
	s   - - 	AAAc           	      4   | j                  d      }|r|D ])  }| j                  |d         | j                  d   |d   <   + | j                  d   d   j                  d      }| j                  d   d   }|d   j                  d      d	   }t	        |d   j                  d            d
kD  r|d   j                  dd
      d
   }nd}t        t        |d	         t        |d
         t        |      t        |      t        |            | j                  d<   yy)z)Get global variables (instance settings).zSHOW GLOBAL VARIABLESValuer   Variable_namer   .   -r       )majorminorreleasesuffixfullN)rP   _MySQL_Info__convertr+   splitlendictrZ   str)r,   rQ   varr   rj   rh   ri   s          r-   __get_global_variablesz!MySQL_Info.__get_global_variables  s   oo56 [>BnnSQX\>Z		*%c/&:;[ ii
+I6<<SAG 99Z(3D aj&&s+A.G 71:##C()A- ))#q1!4#''!*o'!*oG6{Y$DIIi ) r/   c                     | j                  d      }|r/|D ])  }| j                  |d         | j                  d   |d   <   + yy)zGet global status.zSHOW GLOBAL STATUSr_   r   r`   N)rP   rk   r+   )r,   rQ   rp   s      r-   __get_global_statuszMySQL_Info.__get_global_status  sR    oo23 `CG>>RUV]R^C_		/*3+?@` r/   c                     | j                   j                  d      }| j                  |      }|r<|D ]6  }t        |      D ]&  \  }}| j	                  |      | j
                  d   |<   ( 8 yy)z.Get master status if the instance is a master.zSHOW MASTER STATUSr"   N)r*   resolve_commandrP   r   rk   r+   )r,   queryrQ   rR   rT   rU   s         r-   __get_master_statuszMySQL_Info.__get_master_status	  su    %%556JKooe$ L"+D/ LJE38<s8KDIIo.u5LL r/   c                    | j                   j                  d      }| j                  |      }|r|D ]  }|d   }|| j                  d   vri | j                  d   |<   |d   }|| j                  d   |   vri | j                  d   |   |<   |d   }|| j                  d   |   |   vri | j                  d   |   |   |<   t	        |      D ]4  \  }}|dvs| j                  |      | j                  d   |   |   |   |<   6  yy)z,Get slave status if the instance is a slave.zSHOW SLAVE STATUSMaster_Hostr$   Master_PortMaster_User)ry   rz   r{   Nr*   ru   rP   r+   r   rk   )	r,   rv   rQ   rR   hostportuserrT   rU   s	            r-   __get_slave_statuszMySQL_Info.__get_slave_status  s6   %%556IJooe$ aM*tyy8868DIIn-d3M*tyy8>><>DIIn-d3D9M*tyy8>tDDBDDIIn-d3D9$?"+D/ aJE3$QQMQ^^\_M`		.1$7=dCEJaa r/   c                 :   | j                   j                  d      }| j                  |      }|rm|D ]g  }|d   }|| j                  d   vri | j                  d   |<   t	        |      D ]/  \  }}|dk7  s| j                  |      | j                  d   |   |<   1 i yy)z1Get slave hosts info if the instance is a master.zSHOW SLAVE HOSTS	Server_idr#   Nr|   )r,   rv   rQ   rR   srv_idrT   rU   s          r-   __get_slaveszMySQL_Info.__get_slaves(  s    %%556HIooe$ Vk*=!9979DIIm,V4"+D/ VJE3+BF..QTBU		-08?VV r/   c                 <   | j                  d      }|r|D ]  }|d   }|| j                  d   vri | j                  d   |<   |d   }i | j                  d   |   |<   t        |      D ]1  \  }}|dvs| j                  |      | j                  d   |   |   |<   3  yy)zGet user info.SELECT * FROM mysql.userHostr    User)r   r   N)rP   r+   r   rk   )r,   rQ   rR   r}   r   rT   rU   s          r-   __get_userszMySQL_Info.__get_users6  s    oo89 
TF|tyy11/1DIIg&t,F|13		'"4(."+D/ TJE3$44@Ds@S		'*406u=T
T r/   c           	         | j                  d      }|syt               }|D ]$  }|d   }|d   }| j                  dk(  xr | }t        | j                  |||      }|s"| j
                  j                  d|d|       _t               }|j                         D ]l  \  }	}
t        |
      d	d
hk(  st        |
      d	hk(  r&|	j                  dd      j                  dd      }|j                  |ddj                  |
             n t        |      dkD  rd|v r|j                  d       t        | j                  ||      }t        j!                  |      }| j"                  j%                  | j                  ||      }||dj                  |      ||d}|r8|j                         D ]  \  }}|dk(  s|d   |=  t        |d         dk(  r|d= |s|d= t'        | j                  ||      }|r|j)                  |d          |j+                  d      r"|d   dk(  rt-        | j                  ||      |d<   |j                  |       ' || j.                  d<   y)aM  Get user privileges, passwords, resources_limits, ...

        Query the server to get all the users and return a string
        of privileges that can be used by the mysql_user plugin.
        For instance:

        "users_info": [
            {
                "host": "users_info.com",
                "priv": "*.*: ALL,GRANT",
                "name": "users_info_adm"
            },
            {
                "host": "users_info.com",
                "priv": "`mysql`.*: SELECT/`users_info_db`.*: SELECT",
                "name": "users_info_multi"
            }
        ]
        r   Nr   r   mariadb)
maria_rolezNo privileges found for z	 on host PROXYGRANT`re   ':,rd   z	*.*:USAGE/)namer}   privresource_limitstls_requiresr   r   r   is_roleNlockedr!   )rP   r7   r'   r   r&   r%   r3   itemsr6   replacer4   joinrm   remover   rn   copyr)   get_tls_requiresr   updategetr   r+   )r,   rQ   outputrR   r   r}   r   	user_privpriv_stringdb_tabler   unquote_db_tabler   copy_ressource_limitsr   output_dictkeyvalueauthenticationss                      r-   __get_users_infozMySQL_Info.__get_users_infoF  sn   ( oo89 ?	'D<D<D 00I=Jd(G&t{{D$7SI  DRV!WX&K"+//"3 Q$ t9' 22c$iG96L#+#3#3C#<#D#DS"#M "".>#OPQ ;!#{(B"";/1$++tTJO$(IIo$>!33DDT4)L -#8 ,K "1"7"7"9 @JCz'(9:3?@ {#456!;#$56  /9$++tTRO""?1#56xx	"tI#'=(6t{{D$(OH%
 MM+&?	'B #)		,r/   c                   
 fd

fd}dg} 
d      r|j                  d        
d      r|j                  d       dj                  d	j                  |            }| j                  |      xs g }|D ]  } ||      | j                  d
   |d   <    |rL| j                  d      xs g }|D ]1  }|d   }	|	| j                  d
   vs |i       | j                  d
   |	<   3 yy)zGet info about databases.c                 4     xs dj                  |       vS )Nzdb_{})format)
field_namer9   s    r-   is_field_includedz5MySQL_Info.__get_databases.<locals>.is_field_included  s    %%Y
)C>)YYr/   c                     i } d      r"t        | j                  dd      xs d      |d<    d      r"t        | j                  dd      xs d      |d<   |S )Nsizer   table_counttables)rZ   r   )db_datar+   r   s     r-   create_db_infoz2MySQL_Info.__get_databases.<locals>.create_db_info  sY    D ("7;;vq#9#>Q?V /!$W[[1%=%B!CXKr/   zSELECT table_schema AS "name"r   z)SUM(data_length + index_length) AS "size"r   zCOUNT(table_name) as "tables"z7{} FROM information_schema.TABLES GROUP BY table_schemaz, r   r   zSHOW DATABASESDatabaseN)r4   r   r   rP   r+   )r,   r9   r:   r   query_partsrv   r   dbempty_databasesdb_namer   s    `        @r-   __get_databaseszMySQL_Info.__get_databases  s   	Z	 77V$JK]+>?IPPQUQZQZ[fQgh OOE*0b	 	DB1?1CDIIk"2f:.	D "oo.>?E2O% IZ.$))K"886DR6HDIIk*73I r/   c           	          	 | j                   j                  |       |s| j                   j                         }|S y# t        $ r5}| j                  j                  d|dt        |             Y d}~yd}~ww xY w)zExecute SQL.

        Arguments:
            ddl (bool): If True, return True or False.
                Used for queries that don't return any rows
                (mainly for DDL queries) (default False).
        TzCannot execute SQL 'z': msgNF)r&   executefetchall	Exceptionr%   	fail_jsonr   )r,   rv   ddlrQ   es        r-   
__exec_sqlzMySQL_Info.__exec_sql  sn    		]KK&kk**,
 	]KK!!uiXYl&[!\\	]s   8< 	A:+A55A:N)F)__name__
__module____qualname____doc__r.   rA   r5   rF   rk   rC   rE   rI   rJ   rK   rG   rH   rD   rP    r/   r-   r   r   Q  sY     
(,\ :B  D`La,VT Z)x"IHr/   r   c                     t               } | j                  t        d      t        dd      t        dd      t        dd             t        | d	
      }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }|j                  d   }	|j                  d   }
|j                  d   }|j                  d   }|j                  d   }|r|D cg c]  }|j                          }}|r't        |D cg c]  }|j                          c}      }t        |j                  t               t        t              }t        t              }	 t        ||||
|||||	|d      \  }}t              }t!        |      }t#        |      }t%        |||||      } |j&                  d"d|dk(  rdnd ||d!|j)                  |||       y c c}w c c}w # t        $ r2}d|d|d|
dt        |      }|j                  |       Y d }~d }~ww xY w)#Nro   )typer7   )r   elementsboolF)r   default)login_dbfilterr9   r:   T)argument_specsupports_check_moder   connect_timeout
login_userlogin_passwordclient_cert
client_keyca_certcheck_hostnameconfig_filer   r9   r:   r   
DictCursor)r   r   cursor_classz$unable to connect to database using  z5, check login_user and login_password are correct or z) has the credentials. Exception message: r   MariaDBMySQL)changedserver_engineconnector_nameconnector_versionr   )r
   r   rn   r   paramsstripr6   r   r   r   r   r   r	   r   r   r   r   r   r   	exit_jsonrA   )r   r%   r   r   r   r   ssl_certssl_keyssl_car   r   r8   r9   r:   fr   r   r&   db_connr   r   r'   r(   r)   mysqls                            r-   mainr     sc   .0M5!%0%8659	   # F
 
z	"Bmm$56O|,J]]#34N}}]+HmmL)G]]9%F]]#34N--.KmmH%G]]#34N}}%78&-.1779..@Aaggi@A23'5N-l;	'
N(3XwPR7E8GVbd 6f='/N1&9
 vv'<nNabEF RU0E0R9X_$2'8R ~~g~?OP	R? / A   +9:K[ZcdeZfh 		s$   H6HH 	I(II__main__N)&
__future__r   r   r   r   __metaclass__DOCUMENTATIONEXAMPLESRETURNdecimalr   ansible.module_utils.basicr   Iansible_collections.community.mysql.plugins.module_utils.command_resolverr   >ansible_collections.community.mysql.plugins.module_utils.mysqlr	   r
   r   r   r   r   r   r   =ansible_collections.community.mysql.plugins.module_utils.userr   r   r   r   r   ansible.module_utils.sixr   ansible.module_utils._textr   objectr   r   r   r   r/   r-   <module>r      s    A @<|\|G
R  4	 	 	  / 0G G^?RD zF r/   