
    Vhp                         d dl mZmZmZ eZdZdZdZd dl	Z	d dl
Z
d dlZd dlmZ d dlmZ d dlmZ d d	lmZ dad
 ZddZd Zd Zd Zd Zd Zd Zd ZddZd Zd Z e!dk(  r e         yy)    )absolute_importdivisionprint_functiona	  
module: terraform
short_description: Manages a Terraform deployment (and plans)
description:
  - Provides support for deploying resources with Terraform and pulling resource information back into Ansible.
extends_documentation_fragment:
  - community.general.attributes
attributes:
  check_mode:
    support: full
  diff_mode:
    support: full
    version_added: 8.3.0
options:
  state:
    choices: ['planned', 'present', 'absent']
    description:
      - Goal state of given stage/project.
    type: str
    default: present
  binary_path:
    description:
      - The path of a C(terraform) binary to use, relative to the 'service_path' unless you supply an absolute path.
    type: path
  project_path:
    description:
      - The path to the root of the Terraform directory with the C(vars.tf)/C(main.tf)/etc to use.
    type: path
    required: true
  plugin_paths:
    description:
      - List of paths containing Terraform plugin executable files.
      - Plugin executables can be downloaded from U(https://releases.hashicorp.com/).
      - When set, the plugin discovery and auto-download behavior of Terraform is disabled.
      - The directory structure in the plugin path can be tricky. The Terraform docs
        U(https://learn.hashicorp.com/tutorials/terraform/automate-terraform#pre-installed-plugins)
        show a simple directory of files, but actually, the directory structure has to follow the same structure you would
        see if Terraform auto-downloaded the plugins. See the examples below for a tree output of an example plugin directory.
    type: list
    elements: path
    version_added: 3.0.0
  workspace:
    description:
      - The terraform workspace to work with. This sets the E(TF_WORKSPACE) environmental variable that is used to override
        workspace selection. For more information about workspaces have a look at U(https://developer.hashicorp.com/terraform/language/state/workspaces).
    type: str
    default: default
  purge_workspace:
    description:
      - Only works with state = absent.
      - If true, the workspace will be deleted after the "terraform destroy" action.
      - The 'default' workspace will not be deleted.
    default: false
    type: bool
  plan_file:
    description:
      - The path to an existing Terraform plan file to apply. If this is not specified, Ansible will build a new TF plan and
        execute it. Note that this option is required if 'state' has the 'planned' value.
    type: path
  state_file:
    description:
      - The path to an existing Terraform state file to use when building plan. If this is not specified, the default C(terraform.tfstate)
        will be used.
      - This option is ignored when plan is specified.
    type: path
  variables_files:
    description:
      - The path to a variables file for Terraform to fill into the TF configurations. This can accept a list of paths to
        multiple variables files.
    type: list
    elements: path
    aliases: ['variables_file']
  variables:
    description:
      - A group of key-values pairs to override template variables or those in variables files. By default, only string and
        number values are allowed, which are passed on unquoted.
      - Support complex variable structures (lists, dictionaries, numbers, and booleans) to reflect terraform variable syntax
        when O(complex_vars=true).
      - Ansible integers or floats are mapped to terraform numbers.
      - Ansible strings are mapped to terraform strings.
      - Ansible dictionaries are mapped to terraform objects.
      - Ansible lists are mapped to terraform lists.
      - Ansible booleans are mapped to terraform booleans.
      - B(Note) passwords passed as variables will be visible in the log output. Make sure to use C(no_log=true) in production!.
    type: dict
  complex_vars:
    description:
      - Enable/disable capability to handle complex variable structures for C(terraform).
      - If V(true) the O(variables) also accepts dictionaries, lists, and booleans to be passed to C(terraform). Strings that
        are passed are correctly quoted.
      - When disabled, supports only simple variables (strings, integers, and floats), and passes them on unquoted.
    type: bool
    default: false
    version_added: 5.7.0
  targets:
    description:
      - A list of specific resources to target in this plan/application. The resources selected here will also auto-include
        any dependencies.
    type: list
    elements: str
    default: []
  lock:
    description:
      - Enable statefile locking, if you use a service that accepts locks (such as S3+DynamoDB) to store your statefile.
    type: bool
    default: true
  lock_timeout:
    description:
      - How long to maintain the lock on the statefile, if you use a service that accepts locks (such as S3+DynamoDB).
    type: int
  force_init:
    description:
      - To avoid duplicating infra, if a state file cannot be found this will force a C(terraform init). Generally, this should
        be turned off unless you intend to provision an entirely new Terraform deployment.
    default: false
    type: bool
  overwrite_init:
    description:
      - Run init even if C(.terraform/terraform.tfstate) already exists in O(project_path).
    default: true
    type: bool
    version_added: '3.2.0'
  backend_config:
    description:
      - A group of key-values to provide at init stage to the -backend-config parameter.
    type: dict
  backend_config_files:
    description:
      - The path to a configuration file to provide at init state to the -backend-config parameter. This can accept a list
        of paths to multiple configuration files.
    type: list
    elements: path
    version_added: '0.2.0'
  provider_upgrade:
    description:
      - Allows Terraform init to upgrade providers to versions specified in the project's version constraints.
    default: false
    type: bool
    version_added: 4.8.0
  init_reconfigure:
    description:
      - Forces backend reconfiguration during init.
    default: false
    type: bool
    version_added: '1.3.0'
  check_destroy:
    description:
      - Apply only when no resources are destroyed. Note that this only prevents "destroy" actions, but not "destroy and re-create"
        actions. This option is ignored when O(state=absent).
    type: bool
    default: false
    version_added: '3.3.0'
  parallelism:
    description:
      - Restrict concurrent operations when Terraform applies the plan.
    type: int
    version_added: '3.8.0'
notes:
  - To just run a C(terraform plan), use check mode.
requirements: ["terraform"]
author: "Ryan Scott Brown (@ryansb)"
u  
- name: Basic deploy of a service
  community.general.terraform:
    project_path: '{{ project_dir }}'
    state: present

- name: Define the backend configuration at init
  community.general.terraform:
    project_path: 'project/'
    state: "{{ state }}"
    force_init: true
    backend_config:
      region: "eu-west-1"
      bucket: "some-bucket"
      key: "random.tfstate"

- name: Define the backend configuration with one or more files at init
  community.general.terraform:
    project_path: 'project/'
    state: "{{ state }}"
    force_init: true
    backend_config_files:
      - /path/to/backend_config_file_1
      - /path/to/backend_config_file_2

- name: Disable plugin discovery and auto-download by setting plugin_paths
  community.general.terraform:
    project_path: 'project/'
    state: "{{ state }}"
    force_init: true
    plugin_paths:
      - /path/to/plugins_dir_1
      - /path/to/plugins_dir_2

- name: Complex variables example
  community.general.terraform:
    project_path: '{{ project_dir }}'
    state: present
    complex_vars: true
    variables:
      vm_name: "{{ inventory_hostname }}"
      vm_vcpus: 2
      vm_mem: 2048
      vm_additional_disks:
        - label: "Third Disk"
          size: 40
          thin_provisioned: true
          unit_number: 2
        - label: "Fourth Disk"
          size: 22
          thin_provisioned: true
          unit_number: 3
    force_init: true

### Example directory structure for plugin_paths example
# $ tree /path/to/plugins_dir_1
# /path/to/plugins_dir_1/
# └── registry.terraform.io
#     └── hashicorp
#         └── vsphere
#             ├── 1.24.0
#             │   └── linux_amd64
#             │       └── terraform-provider-vsphere_v1.24.0_x4
#             └── 1.26.0
#                 └── linux_amd64
#                     └── terraform-provider-vsphere_v1.26.0_x4
a  
outputs:
  type: complex
  description: A dictionary of all the TF outputs by their assigned name. Use RV(ignore:outputs.MyOutputName.value) to access
    the value.
  returned: on success
  sample: '{"bukkit_arn": {"sensitive": false, "type": "string", "value": "arn:aws:s3:::tf-test-bukkit"}'
  contains:
    sensitive:
      type: bool
      returned: always
      description: Whether Terraform has marked this value as sensitive.
    type:
      type: str
      returned: always
      description: The type of the value (string, int, and so on).
    value:
      type: str
      returned: always
      description: The value of the output as interpolated by Terraform.
stdout:
  type: str
  description: Full C(terraform) command stdout, in case you want to display it or examine the event log.
  returned: always
  sample: ''
command:
  type: str
  description: Full C(terraform) command built by this module, in case you want to re-run the command outside the module or
    debug a problem.
  returned: always
  sample: terraform apply ...
N)shlex_quote)integer_types)AnsibleModule)LooseVersionc                 l    t         j                  | ddg      }t        j                  |d         d   }|S )Nversion-json   terraform_version)modulerun_commandjsonloads)bin_pathextract_versionr   s      o/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/general/plugins/modules/terraform.pyget_versionr      s9    (((Iw)GHOOA$679LM    c                    |d|vrt         j                  d       t        j                  j	                  |       s%t         j                  dj                  |              t        j                  j                  |      s%t         j                  dj                  |             t        |      t        d      k  rt         j                  | ddg|z   d	|
       y t         j                  | ddgd	|
       y )N/z1Path for Terraform project can not be None or ''.msgzaPath for Terraform binary '{0}' doesn't exist on this host - check the path and try again please.zbPath for Terraform project '{0}' doesn't exist on this host - check the path and try again please.0.15.0validate	-no-colorTcheck_rccwd)	r   	fail_jsonospathexistsformatisdirr	   r   )r   project_pathr   variables_args	plan_files        r   preflight_validationr+   &  s    s,6PQ77>>(#  A  H  H  IQ  R  	S77==&  B  I  I  JV  W  	XG|H55Hj+>OZ^dpqHj+>S_`r   c                     | sg S t         j                  j                  |       s$t        j	                  dj                  |              d| gS )NzoCould not find state_file "{0}", the process will not destroy any resources, please check your state file path.z-state)r#   r$   r%   r   warnr&   )
state_files    r   _state_argsr/   3  sQ    	77>>*%  F  M  M  NX  Y  	Zj!!r   c                    | dddg}|r;|j                         D ](  \  }	}
|j                  ddj                  |	|
      g       * |r|D ]  }|j                  d|g        |r|j                  dg       |r|j                  dg       |r|D ]  }|j                  d|g        t        j	                  |d	|d
|i      \  }}}y )Ninit-input=falser   z-backend-config{0}={1}z-reconfigurez-upgradez-plugin-dirTTF_WORKSPACE)r    r!   environ_update)itemsextendr&   r   r   )r   r(   backend_configbackend_config_filesinit_reconfigureprovider_upgradeplugin_paths	workspacecommandkeyvalfplugin_pathrcouterrs                   r   init_pluginsrF   ;  s    =G&,,. 	HCNN!  c* 	
 % 	3ANN-q12	3'(
|$' 	9KNNM;78	9%%g,`npy_z%{LBSr   c                    dg d}| dddg}t         j                  ||      \  }}}|dk7  r$t         j                  dj                  |             |j	                  d	      D ]t  }|j                         }|s|j                  d
      r:|j                  d
d      |d<   |d   j                  |j                  d
d             a|d   j                  |       v |S )Ndefault)currentallr=   listr   r!   r   z(Failed to list Terraform workspaces:
{0}
z*  rI   rJ   )	r   r   r-   r&   splitstrip
startswithreplaceappend)	r   r(   workspace_ctxr>   rC   rD   rE   itemstripped_items	            r   get_workspace_contextrW   P  s     )"5Mfk:G%%g<%@LBS	Qw?FFsKL		$ 7

%%d+'4'<'<T2'FM)$% ''(=(=dB(GH% ''67 r   c                 R    | d||dg}t         j                  |d|      \  }}}|||fS )Nr=   r   Tr   )r   r   )r   r(   actionr=   r>   rC   rD   rE   s           r   _workspace_cmdrZ   b  s;    fiEG%%g,%OLBSsC<r   c                      t        | |d|       y )NnewrZ   r   r(   r=   s      r   create_workspacer_   h  s    8\5)<r   c                      t        | |d|       y )Nselectr]   r^   s      r   select_workspacerb   l      8\8Y?r   c                      t        | |d|       y )Ndeleter]   r^   s      r   remove_workspacerf   p  rc   r   c                    |t        j                  d      \  }}| d d  }	| d   dg}
|dk(  r|	dd  D ]  }|
j                  |        |dk(  r3|D ]  }|	j                  |        |	dd  D ]  }|
j                  |        |dk(  r|D ]  }|
j                  |        |
j	                  d	d
dd|g       |D ]  }|
j	                  d|g        |
j	                  t        |             t        j                  |
|z   |      \  }}}|dk(  r|d|||dk(  r|
fS | fS |dk(  r_t        j                  dj                  ||dj                  |
      dj                  |D cg c]  }t        |       c}                   n|dk(  r|d|||dk(  r|
fS | fS t        j                  dj                  |||dj                  |
      dj                  |D cg c]  }t        |       c}                   y c c}w c c}w )Nz.tfplan)suffixr   planplannedr   presentabsentr2   r   z-detailed-exitcodez-out-targetrL   FzUTerraform plan could not be created
STDOUT: {out}
STDERR: {err}
COMMAND: {cmd} {args} )rD   rE   cmdargsr      TzgTerraform plan failed with unexpected exit code {rc}.
STDOUT: {out}
STDERR: {err}
COMMAND: {cmd} {args})rC   rD   rE   ro   rp   )tempfilemkstemprS   remover7   r/   r   r   r"   r&   joinr   )r>   r(   r)   r.   targetsstaterp   	plan_pathrA   local_commandplan_commandcatrC   rD   rE   args                     r   
build_planr   t  s]   ''y99AJMAJ'L	qr" 	#A"	# 	 	$A  #	$qr" 	#A"	#  	#A"	# 6JFT]^_ ,YN+, J/0%%l^&C%VLBS	Qw%c5I;M<ZZSZZZ	qjqqHH\*XX>JC{3/JK	 r  	 	
 
q$S%9:L,YYRYYY
  F  M  MHH\"XX>BC{3'BC M   K Cs   G1G6c                 "   d }t        j                  |       }d|v r|d   }nt        j                  d       di fS g }g }d}|D ]  }|d   }|d   |d   d   d}	|d   |d   d	   d}
|d
   dgk(  s
|d
   ddgk(  r$|j	                  |	       |j	                  |
       d}|d
   dgk(  r|j	                  |	       d}|d
   dgk(  s|j	                  |
       d} |j                  |       |j                  |       |t        d|id|i      fS )Nc                     | d   S )Nresource )es    r   get_tf_resource_addressz)get_diff.<locals>.get_tf_resource_address  s    }r   resource_changeszBCannot find resource_changes in terraform plan, diff/check ignoredFchangeaddressbefore)r   r   afteractionsupdatere   createT)r?   data)r   r   )r   r   r   r-   rS   sortdict)diff_outputr   diff_json_outputtf_reosource_changes
diff_afterdiff_beforechangedrU   item_changetf_before_statetf_after_states              r   get_diffr     sj    zz+. --/0BCXYbyJKG$ 8n'+I$x.QYBZ[&*9ohPWAXYy!hZ/;y3IhX`Ma3a/n-Gy!hZ//Gy!hZ/n-G!$ 01OO/O0D%
#  r   c                  D  *+ t        t        d[i dt        dd      dt        d      dt        dd	      d
t        dd      dt        dd      dt        dg d      dt        d      dt        dd      dt        dgdd      dt        d      dt        d      dt        ddg       dt        dd      d t        d!      d"t        dd      d#t        d      d$t        dd	      d%t        dd      d&t        dd      d't        dd      d(t        d!      d)t        dd      dd*dgfgd+      at        j                  j	                  d      } t        j                  j	                  d      }t        j                  j	                  d      }t        j                  j	                  d
      }t        j                  j	                  d      }t        j                  j	                  d      }t        j                  j	                  d      xs i }t        j                  j	                  d      }t        j                  j	                  d      }t        j                  j	                  d      }	t        j                  j	                  d      }
t        j                  j	                  d"      }t        j                  j	                  d#      }t        j                  j	                  d$      }t        j                  j	                  d%      }t        j                  j	                  d&      }t        j                  j	                  d'      }t        j                  j	                  d)      }||g}nt        j                  d,d-      g}t        |d.         }t        |      t        d/      k  rd0}d1}nd2}d3}|rU|s>t        j                  j                  t        j                  j                  | d4d5            st        |d.   | ||||||       t        |d.   |       }|d6   |k7  r(||d7   vrt        |d.   | |       nt        |d.   | |       |dk(  r|j!                  |       n|d8k(  r|j!                  |       |dk(  rPt        j                  j	                  d(      1|j#                  d9t        j                  j	                  d(      z         d: **+fd;+g }|r|j%                         D ]  \  }}t'        |t              r*|j!                  d<d=j)                  | +|            g       @t'        |t*              r*|j!                  d<d>j)                  | +|            g       zt'        |t,              r$|j!                  d<d>j)                  ||      g       |j!                  d<d>j)                  | *|            g        n;|j%                         D ](  \  }}|j!                  d<d>j)                  ||      g       * |r|D ]  }|j!                  d?|g        t/        |d.   | ||       t        j                  j	                  d      Bt        j                  j	                  d      r|j#                  d@       n|j#                  dA       t        j                  j	                  d       1|j#                  dBt        j                  j	                  d       z         t        j                  j	                  d      xs g D ]  }|j!                  dC|g        dD\  }}dE\  }}|d8k(  r|j!                  |       n|dk(  r|	rt1        t        j                  j                  | dFz   |	z         t        j                  j                  |	      g      r|j#                  |	       nt        j3                  dGj)                  |	      H       ngt5        || ||
t        j                  j	                  d      |||	      \  }	}}}}|dk(  r|rdI|v rt        j3                  dJH       |j#                  |	       t               } t        j6                  st        j8                  r|d8k(  r8dKg}!t5        || ||
t        j                  j	                  d      ||!|	      \  }	}}}}|d.   dLdM|	g}"t        j;                  |"d| N      \  }#}$}t=        |$      \  }} |#d.k7  rp|d6   |k7  rt        |d.   | |d6          t        j3                  |j?                         |#||jA                         ||jA                         dOj                  |      P       |rt        j8                  s|d*k7  rt        j;                  |d| N      \  }#}}|#d.k7  rp|d6   |k7  rt        |d.   | |d6          t        j3                  |j?                         |#||jA                         ||jA                         dOj                  |      P       dQ|vr|d8k(  rdR|vrd}|d.   dSdTdMgtC        |
      z   }%t        j;                  |%| U      \  }#}&}'i }(|#dVk(  r&t        jE                  dWj)                  |&|'             nR|#d.k7  r8t        j3                  dXj)                  |#|&|'      dOj                  |%      Y       ntG        jH                  |&      }(|d6   |k7  rt        |d.   | |d6          |d8k(  r|dk7  r|du rtK        |d.   | |       |||(||dOj                  |      || dZ})t        jL                  d[i |) y )\Nr(   Tr$   )requiredtypebinary_path)r   r<   rK   )r   elementsr=   strrH   )r   rH   purge_workspaceboolFrw   rk   )rk   rl   rj   )rH   choices	variablesr   complex_varsvariables_filesvariables_file)aliasesr   r   r*   r.   rv   )r   r   rH   locklock_timeoutint
force_initr8   r9   r:   overwrite_initcheck_destroyparallelismr;   rj   )argument_specrequired_ifsupports_check_mode	terraform)r   r   r   )destroyr   z-force)applyr   r2   z-auto-approve=true)r   r   -auto-approve)r   r   r2   r   z
.terraformzterraform.tfstaterI   rJ   rl   z-parallelism=%dc                     t        | t              rBdj                  | j                  dd      j                  dd            j                  dd      S t        | t              r| ry	y
t        |       S )Nz
"{string}"\z\\"z\")stringrM   z\ntruefalse)
isinstancer   r&   rR   r   )varss    r   format_argszmain.<locals>.format_args+  sf    dC &&dll4.H.P.PQTV[.\&]eefjlqrrd#4yr   c           	         g }t        | t              r| j                         D ]  \  }}t        |t              r(|j                  dj	                  | |                   >t        |t
              r(|j                  dj	                  | |                   vt        |t        t        t        t        f      r(|j                  dj	                  | |                   t        j                  d        t        | t
              rg }| D ]  }t        |t              r'|j                  dj	                   |                   :t        |t
              r'|j                  dj	                   |                   qt        |t        t        t        t        f      r|j                   |             t        j                  d        |j                  dj	                  dj                  |                   dj                  |      S )	N{0}={{{1}}}r3   zTSupported types are, dictionaries, lists, strings, integer_types, boolean and float.r   z{{{0}}}z{0}z[{0}],)r   r   r6   rS   r&   rK   r   floatr   r   r   r"   ru   )r   ret_outkvl_outrU   r   process_complex_argss         r   r   z"main.<locals>.process_complex_args5  s   dD!

 	A1a&NN=#7#7;OPQ;R#ST4(NN9#3#3A7KA7N#OPM5#t#DENN9#3#3A{1~#FG $$)$  A	A dD!E 	AdD)LL!1!12Ft2L!MNd+LL.B4.H!IJsM5$&GHLLT!23 $$)$  A	A NN7>>#((5/:;xx  r   z-varr   r3   z	-var-filez
-lock=truez-lock=falsez-lock-timeout=%dsrm   )TF)rN   rN   r   z=Could not find plan_file "{0}", check the path and try again.r   z	- destroyzAborting command because it would destroy some resources. Consider switching the 'check_destroy' to false to suppress this errorz-destroyshowr   r   rn   )r   rC   stdoutstdout_linesstderrstderr_linesro   z 0 added, 0 changedz 0 destroyedoutputr   rL   r   zcCould not get Terraform outputs. This usually means none have been defined.
stdout: {0}
stderr: {1}zKFailure when getting Terraform outputs. Exited {0}.
stdout: {1}
stderr: {2})r   r>   )rw   r=   outputsr   r   r>   r   diffr   )'r   r   r   paramsgetget_bin_pathr   r	   r#   r$   isfileru   rF   rW   r_   rb   r7   rS   r6   r   r&   rK   r   r+   anyr"   r   _diff
check_moder   r   rstrip
splitlinesr/   r-   r   r   rf   	exit_json),r(   r   r<   r=   r   rw   r   r   r   r*   r.   r   r8   r9   r:   r   r   r;   r>   checked_versionDESTROY_ARGS
APPLY_ARGSrT   r)   r   r   rA   r}   needs_applicationr   rD   rE   result_diffplan_absent_argsdiff_commandrC   r   outputs_commandoutputs_textoutputs_errr   resultr   r   s,                                             @@r   mainr     s
    
t&9
&)
 6F;
 y9	

 !fe<
 y2RS
 '
 659
 !*:);&SYZ
 '
 (
 fubA
 640
 5*
 7
   V,!
" "&6F!C#
$ "vu=%
&  VT:'
( FE:)
* %(+
, "vu=-
0 y;-89 5F: ==$$^4L}}  /H==$$^4L!!+.Imm''(9:OMMg&E!!+.4"I==$$^4Lmm''(9:O!!+.I""<0J""<0J]]&&'78N!==,,-CD}}(();<]]&&'78NMM%%o6M}}(();<*&&{T&BC!'!*-OO$|H'==9Q
@L
\<Yl0m!n\>CWYik{  ~J  LU  V)'!*lCMY9,M%00WQZyAWQZyA	z"	(	|$	fmm//>J(6==+<+<]+KKL!: NOO% 	DAq!T"%%!((,@,CD'  At$%%$$Q(<Q(?@'  As#%%$$Q*' 
 %%$$QA7' '	0 OO% 	DAq!!  A&# 	   	4A!!;"23	4 \?NS}} ,==V$NN<(NN=)}}(4*V]]->->~-NNOmm	*0b '	1~&' "-wHC~&	)		|c1I=>y@YZ[NN9%!`!g!ghq!rs:DWl\jlvEK]]EVEVW`Eachjtv;A7	$c3I-K34F "j ky!&K||v((H *|>HR^`npzIOIZIZ[dIegln~  AJ?K;I(#sG
FGY?%11,T`1aK'47Y'94 \=;ST"S*-..*:3*-..*:!$'!2  4
 !2!2u	7I))'E|)TC7Y'94 \=;ST"S*-..*:3*-..*:!$'!2  4
 !+EX4E_bIbGqz8['B[Q[E\\O$*$6$6L$6$Y!BkG	Qw{  C  C  DP  R]  ^  	_	q88>r<Q\8]HH_- 	 	/
 **\* Y9,\=3KLY)348O\9= 88G$	F vr   __main__)NN)N)"
__future__r   r   r   r   __metaclass__DOCUMENTATIONEXAMPLESRETURNr#   r   rr   ansible.module_utils.six.movesr   ansible.module_utils.sixr   ansible.module_utils.basicr   Bansible_collections.community.general.plugins.module_utils.versionr	   r   r   r+   r/   rF   rW   rZ   r_   rb   rf   r   r   r   __name__r   r   r   <module>r      s    A @aFBH
B 
   6 2 4 [	
a"|*$=@@6r(V{| zF r   