Ë
    M/ÅeÄ�  ã                   óx  — d Z ddl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dlm
Z
 ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZ erddlmZ 	 ddlmZ  ej:                  e«      Z G d„ d«      Z de!de!fd„Z"de!de!fd„Z#defd„Z$y# e$ r dZY Œ<w xY w)z@ApacheParser is a member object of the ApacheConfigurator class.é    N)Ú
Collection)ÚDict)ÚIterable)ÚList)ÚMapping)ÚOptional)ÚPattern)ÚSet)ÚTuple)ÚTYPE_CHECKING)ÚUnion)Úerrors)Úos)Úapache_util)Ú	constants)ÚApacheConfigurator)ÚAugeasc                   óÖ  — e Zd ZU dZ ej
                  d«      Zeed<   h d£Z	e
e   ed<   	 dNdeddd	ed
eedf   ddf
d„Zdeddfd„Zdeeee   f   fd„Zde
e   fd„ZdOd„Zdee   ddfd„Zdee   ddfd„Zdededdfd„Zdeddfd„ZdOd„ZdOd„ZdOd„ZdOd „ZdOd!„ZdOd"„Z d#ed$edee   fd%„Z!d&ed'ed$ee   ddfd(„Z"d&ed)edefd*„Z#d&ed)edefd+„Z$d&e%e   d'e%e   d$eee   ef   ddfd,„Z&d&e%e   d-ed$eee   ef   ddfd.„Z'd&ed/eddfd0„Z(dPd1ed2e%e   dee   fd3„Z)	 	 dQd'ed1e%e   d2e%e   d4edee   f
d5„Z*d6ede%e   fd7„Z+defd8„Z,d#ee   dee   fd9„Z-d6ed:eee.e   f   defd;„Z/d1edefd<„Z0d1e%e   de%e   fd=„Z1d>edefd?„Z2d@eddfdA„Z3dBe%e   defdC„Z4dBe%e   defdD„Z5dBedEe6eee   f   defdF„Z7d@edeeef   fdG„Z8d@eddfdH„Z9dIeddfdJ„Z:dOdK„Z;de<eef   fdL„Z=defdM„Z>y)RÚApacheParseraÉ  Class handles the fine details of parsing the Apache Configuration.

    .. todo:: Make parsing general... remove sites-available etc...

    :ivar str root: Normalized absolute path to the server root
        directory. Without trailing slash.
    :ivar set modules: All module names that are currently enabled.
    :ivar dict loc: Location to place directives, root - configuration origin,
        default - user config file, name - NameVirtualHost,

    z\$\{[^ \}]*}Úarg_var_interpreter>   Ú*ú?ú[ú\ú]Úfnmatch_charsÚrootÚconfiguratorr   Ú	vhostrootÚversion.ÚreturnNc                 óú  — || _         t        «       | _        | j                  «       st	        j
                  d«      ‚i | _        i | _        i | _        t        j                  j                  |«      | _        d| j                  «       i| _        | j                  | j                  d   «       | j!                  «        | j#                  «        | j%                  «        | j                  j'                  | j)                  «       «       t+        j,                  | j                  «      | _        |rS| j                  t        j                  j                  |«      dz   | j                   j0                  j2                  z   «       y y )NzˆApache plugin support requires libaugeas0 and augeas-lenses version 1.2.0 or higher, please make sure you have you have those installed.r   ú/)r   Úinit_augeasÚaugÚcheck_aug_versionr   ÚNotSupportedErrorÚmodulesÚparser_pathsÚ	variablesr   ÚpathÚabspathr   Ú_find_config_rootÚlocÚ
parse_fileÚupdate_runtime_variablesÚstandardize_exclÚparse_modulesÚupdateÚ_set_locationsÚcopyÚdeepcopyÚexisting_pathsÚoptionsÚvhost_files)Úselfr   r   r   r    s        úA/usr/lib/python3/dist-packages/certbot_apache/_internal/parser.pyÚ__init__zApacheParser.__init__2   s7  € ð )ˆÔô '›=ˆŒà×%Ñ%Ô'Ü×*Ñ*ð#ó$ð $ð
 24ˆŒØ24ˆÔØ)+ˆŒô Ÿ™Ÿ™¨Ó.ˆŒ	Ø$*¨D×,BÑ,BÓ,DÐ#EˆŒØ�‰˜Ÿ™ Ñ(Ô)ð 	×%Ñ%Ô'ð 	×ÑÔð 	×ÑÔð 	�‰�‰˜×+Ñ+Ó-Ô.ô #Ÿm™m¨D×,=Ñ,=Ó>ˆÔñ Ø�O‰OœBŸG™GŸO™O¨IÓ6¸Ñ<Ø ×-Ñ-×5Ñ5×AÑAñBõ Cð ó    Úlensc           	      óp  — | j                   j                  d«      }|D ]–  }| j                   j                  |dz   «      }|sŒ$||v sŒ)dj                  |dt	        |«      dz
   | j                   j                  |dz   «      | j                   j                  |dz   «      «      }t        j                  |«      ‚ y)	zÜVerify Augeas can parse all of the lens files.

        :param str lens: lens to check for errors

        :raises .errors.PluginError: If there has been an error in parsing with
            the specified lens.

        ú/augeas//errorz/lensz@There has been an error in parsing the file {0} on line {1}: {2}é   é   z/lineú/messageN)r%   ÚmatchÚgetÚformatÚlenr   ÚPluginError)r:   r>   Úerror_filesr+   Ú	lens_pathÚmsgs         r;   Úcheck_parsing_errorsz!ApacheParser.check_parsing_errorsa   sª   € ð —h‘h—n‘nÐ%5Ó6ˆàò 	.ˆDð Ÿ™Ÿ™ T¨G¡^Ó4ˆIâ˜T YÒ.ðß ™&à˜œC ›I¨™MÐ*Ø—H‘H—L‘L ¨¡Ó0Ø—H‘H—L‘L ¨
Ñ!2Ó3ó	5ð ô ×(Ñ(¨Ó-Ð-ñ	.r=   c                 ó   — | j                   j                  dd«       	 | j                   j                  d«      }| j                   j	                  d«       |S # t        $ r | j                   j	                  d«       Y yw xY w)z� Checks that we have recent enough version of libaugeas.
        If augeas version is recent enough, it will support case insensitive
        regexp matchingz/test/path/testing/argÚaRgUMeNTz,/test//*[self::arg=~regexp('argument', 'i')]z
/test/pathF)r%   ÚsetrD   ÚRuntimeErrorÚremove)r:   Úmatchess     r;   r&   zApacheParser.check_aug_version{   sm   € ð
 	�‰�‰Ð-¨zÔ:ð	Ø—h‘h—n‘nØ>ó@ˆGð
 	�‰�‰˜Ô%Øˆøô	 ò 	Ø�H‰H�O‰O˜LÔ)Ùð	ús   žA Á$A=Á<A=c                 ób  — | j                   j                  d«      }| j                   j                  dd«       | j                   j                  d«      }	 | j                   j	                  «        | j                   j                  d|«       | j                   j                  d«      }t        «       }|r4|D ]/  }|j                  | j                   j                  |«      dd «       Œ1 |S # t
        t        f$ r8 | j                  |«       d| j                  _	        t        j                  d«      ‚w xY w)	a™  Lists files that have modified Augeas DOM but the changes have not
        been written to the filesystem yet, used by `self.save()` and
        ApacheConfigurator to check the file state.

        :raises .errors.PluginError: If there was an error in Augeas, in
            an attempt to save the configuration, or an error creating a
            checkpoint

        :returns: `set` of unsaved files
        z/augeas/saveÚnoopr@   Ú z-Error saving files, check logs for more info.z/augeas/events/savedrB   N)r%   rE   rO   rD   ÚsaverP   ÚIOErrorÚ_log_save_errorsr   Ú
save_notesr   rH   Úadd)r:   Ú
save_stateÚex_errsÚ
save_pathsÚ
save_filesr+   s         r;   Úunsaved_fileszApacheParser.unsaved_filesŠ   s  € ð —X‘X—\‘\ .Ó1ˆ
Ø�‰�‰�^ VÔ,à—(‘(—.‘.Ð!1Ó2ˆð	Aà�H‰H�M‰MŒOð 	�‰�‰�^ ZÔ0ð
 —X‘X—^‘^Ð$:Ó;ˆ
ä“Uˆ
ÙØ"ò 7�Ø—‘˜tŸx™xŸ|™|¨DÓ1°!°"Ð5Õ6ð7àÐøô' œgÐ&ò 	AØ×!Ñ! 'Ô*à+-ˆD×ÑÔ(Ü×$Ñ$Ø?óAð Að		Aús   ÁC' Ã'AD.c                 ó˜   — | j                  «       r:| j                  xj                  dz  c_        | j                  j                  «        yy)zÙMakes sure that all Augeas dom changes are written to files to avoid
        loss of configuration directives when doing additional augeas parsing,
        causing a possible augeas.load() resulting dom reset
        z
(autosave)N)r_   r   rY   rV   ©r:   s    r;   Úensure_augeas_statez ApacheParser.ensure_augeas_state±   s>   € ð ×ÑÔØ×Ñ×(Ò(¨LÑ8Õ(Ø×Ñ×"Ñ"Õ$ð  r=   r^   c                 óT  — d| j                   _        | j                  j                  d«      }	 | j                  j	                  «        |r@|D ]   }| j                  j                  d|z   «       Œ" | j                  j                  «        yy# t
        $ r | j                  |«       ‚ w xY w)zõSaves all changes to the configuration files.

        save() is called from ApacheConfigurator to handle the parser specific
        tasks of saving.

        :param list save_files: list of strings of file paths that we need to save.

        rU   r@   z/files/N)	r   rY   r%   rD   rV   rW   rX   rQ   Úload)r:   r^   r\   Úsfs       r;   rV   zApacheParser.save»   s“   € ð (*ˆ×ÑÔ$à—(‘(—.‘.Ð!1Ó2ˆð	Ø�H‰H�M‰MŒOñ Ø ò .�Ø—‘—‘ 	¨"¡Õ-ð.à�H‰H�M‰M�Oð øô ò 	Ø×!Ñ! 'Ô*Øð	ús   ®B ÂB'r\   c           
      óð  — | j                   j                  d«      D �cg c]	  }||vsŒ|‘Œ }}|D ]^  }t        j                  d| j                   j	                  |«      |dt        |«      dz
   | j                   j	                  |› d�«      «       Œ` t        j                  ddj                  d„ |D «       «      | j                  j                  rd	| j                  j                  › �«       yd
«       yc c}w )zfLog errors due to bad Augeas save.

        :param list ex_errs: Existing errors before save

        r@   zError %s saving %s: %srA   rB   rC   zUnable to save files: %s.%sz, c              3   ó>   K  — | ]  }|d t        |«      dz
   –— Œ y­w)rA   rB   N)rG   )Ú.0Úerrs     r;   ú	<genexpr>z0ApacheParser._log_save_errors.<locals>.<genexpr>â   s   è ø€ Ò4^Èc°S¸¼CÀ»HÀq¹LÔ5IÑ4^ùs   ‚z Save Notes: rU   N)
r%   rD   ÚloggerÚdebugrE   rG   ÚerrorÚjoinr   rY   )r:   r\   ÚeÚnew_errsri   s        r;   rX   zApacheParser._log_save_errorsÔ   sÙ   € ð  $Ÿx™xŸ~™~Ð.>Ó?ÖT˜!À1ÈGÒCS’AÐTˆÐTàò 	0ˆCÜ�L‰LØ(¨$¯(©(¯,©,°sÓ*;¸SÀÄCÈÃHÈqÁLÐ=QØ—‘—‘ ˜u HÐ-Ó.õ0ð	0ô 	�‰Ø)¨4¯9©9Ñ4^ÐU]Ô4^Ó+^Ø>B×>OÑ>O×>ZÒ>Zˆm˜D×-Ñ-×8Ñ8Ð9Ð:õ	dà`bõ	dùò Us
   ž	C3¨C3Úmain_configÚinc_pathc                 ó†  — | j                  t        d«      |«      s¦t        j                  d|t	        |«      «       | j                  t	        |«      d|«       t        j                  j                  |«      }t        j                  j                  |«      }| j                  j                  |g «      j                  |«       yy)zÃAdd Include for a new configuration file if one does not exist

        :param str main_config: file path to main Apache config file
        :param str inc_path: path of file to include

        ÚIncludezAdding Include %s to %sN)Úfind_dirÚcase_irk   rl   Úget_aug_pathÚadd_dirr   r+   ÚdirnameÚbasenamer7   Ú
setdefaultÚappend)r:   rq   rr   Únew_dirÚnew_files        r;   Úadd_includezApacheParser.add_includeå   s—   € ð �}‰}œV IÓ.°Ô9Ü�L‰LÐ2Ø!¤<°Ó#<ô>à�L‰LÜ˜[Ó)Ø˜8ô%ô
 —g‘g—o‘o hÓ/ˆGÜ—w‘w×'Ñ'¨Ó1ˆHØ×Ñ×*Ñ*¨7°BÓ7×>Ñ>¸xÕHð :r=   Úmod_namec                 óž   — |dz   | j                   vrd| j                   |dz   <   d|z   dz   | j                   vrd| j                   d|z   dz   <   yy)z%Shortcut for updating parser modules.Ú_moduleNÚmod_z.c)r(   )r:   r€   s     r;   Úadd_modzApacheParser.add_modø   sY   € à�iÑ t§|¡|Ñ3Ø15ˆD�L‰L˜ IÑ-Ñ.Ø�HÑ˜tÑ#¨4¯<©<Ñ7Ø59ˆD�L‰L˜ (Ñ*¨TÑ1Ò2ð 8r=   c                 óR   — i | _         | j                  «        | j                  «        y)zgReset the loaded modules list. This is called from cleanup to clear
        temporarily loaded modules.N)r(   Úupdate_modulesr2   ra   s    r;   Úreset_moduleszApacheParser.reset_modulesÿ   s#   € ð ˆŒØ×ÑÔØ×ÑÕr=   c                 óÌ  — i }| j                  d«      }t        |«      }d}t        |«      |k7  r›t        |«      }t        ||«      D ]r  \  }}| j	                  |«      }| j	                  |«      }|r0|r.|||<   ||t
        j                  j                  |«      dd dz   <   ŒZt        j                  d|dd «       Œt t        |«      |k7  rŒ›| j                  j                  |«       y)zãIterates on the configuration until no new modules are loaded.

        ..todo:: This should be attempted to be done with a binary to avoid
            the iteration issue.  Else... parse and enable mods at same time.

        Ú
LoadModuleéÿÿÿÿNéþÿÿÿÚcz8Could not read LoadModule directive from Augeas path: %srB   )ru   ÚiterrG   ÚzipÚget_argr   r+   rz   rk   rl   r(   r3   )	r:   ÚmodsrR   ÚiteratorÚ	prev_sizeÚ
match_nameÚmatch_filenamer€   Úmod_filenames	            r;   r2   zApacheParser.parse_modules  sá   € ð  "ˆØ—-‘- Ó-ˆÜ˜“=ˆàˆ	ä�$‹i˜9Ò$Ü˜D›	ˆIä.1Ø˜hó/(ò 	1Ñ*�
˜NàŸ<™<¨
Ó3�Ø#Ÿ|™|¨NÓ;�Ù¡Ø%1�D˜‘NØFR�DœŸ™×)Ñ)¨,Ó7¸¸Ð<¸sÑBÒCä—L‘LÐ![Ø!+¨A¨B õ1ð	1ô �$‹i˜9Ó$ð 	�‰×Ñ˜DÕ!r=   c                 ód   — | j                  «        | j                  «        | j                  «        y)zAUpdate Includes, Defines and Includes from httpd config dump dataN)Úupdate_definesÚupdate_includesr†   ra   s    r;   r0   z%ApacheParser.update_runtime_variables"  s(   € ð 	×ÑÔØ×ÑÔØ×ÑÕr=   c                 ót   — t        j                  | j                  j                  j                  «      | _        y)z>Updates the dictionary of known variables in the configurationN)r   Úparse_definesr   r8   Úget_defines_cmdr*   ra   s    r;   r—   zApacheParser.update_defines)  s&   € ä$×2Ñ2°4×3DÑ3D×3LÑ3L×3\Ñ3\Ó]ˆ�r=   c                 óæ   — | j                  d«      }t        j                  | j                  j                  j
                  «      }|r+|D ]%  }| j                  |«      rŒ| j                  |«       Œ' yy)z>Get includes from httpd process, and add them to DOM if neededrt   N)ru   r   Úparse_includesr   r8   Úget_includes_cmdÚparsed_in_currentr/   )r:   Ú_rR   Úis       r;   r˜   zApacheParser.update_includes-  se   € ð �M‰M˜)Ó$ˆä×,Ñ,¨T×->Ñ->×-FÑ-F×-WÑ-WÓXˆÙØò '�Ø×-Ñ-¨aÕ0Ø—O‘O AÕ&ñ'ð r=   c                 ó¶   — t        j                  | j                  j                  j                  «      }|D ]!  }| j                  |j                  «       «       Œ# y)z:Get loaded modules from httpd process, and add them to DOMN)r   r2   r   r8   Úget_modules_cmdr„   Ústrip)r:   rR   Úmods      r;   r†   zApacheParser.update_modules;  sG   € ô ×+Ñ+¨D×,=Ñ,=×,EÑ,E×,UÑ,UÓVˆØò 	&ˆCØ�L‰L˜Ÿ™›Õ%ñ	&r=   rR   Úargsc           	      ó†  — g }|dk(  r>t        |«      D ].  \  }}|j                  d«      sŒ|j                  ||   dd «       Œ0 |S t        |«      D ]m  \  }}|j                  d|z  «      sŒ|t        |«      dz
  k(  s||dz      j                  d|dz   z  «      rŒJ|j                  ||   dt        d|z  «        «       Œo |S )a  Filter out directives with specific number of arguments.

        This function makes the assumption that all related arguments are given
        in order.  Thus /files/apache/directive[5]/arg[2] must come immediately
        after /files/apache/directive[5]/arg[1]. Runs in 1 linear pass.

        :param str matches: Matches of all directives with arg nodes
        :param int args: Number of args you would like to filter

        :returns: List of directives that contain # of arguments.
            (arg is stripped off)

        é   ú/argNéüÿÿÿú/arg[%d])Ú	enumerateÚendswithr|   rG   )r:   rR   r¦   Úfilteredr¡   rD   s         r;   Úfilter_args_numzApacheParser.filter_args_numB  sã   € ð !ˆØ�1Š9Ü% gÓ.ò 5‘��5Ø—>‘> &Õ)Ø—O‘O G¨A¡J¨s° OÕ4ð5ð ˆô & gÓ.ò N‘��5Ø—>‘> *¨tÑ"3Õ4ð œc '›l¨QÑ.Ò/Ø '¨¨A©¡× 7Ñ 7¸
Ø9=À¹ñ9Cõ !Dà Ÿ™¨°©
Ð3K´S¸ÀdÑ9JÓ5KÐ4KÐ(LÕMðNð ˆr=   Úaug_conf_pathÚ	directivec                 óz  — | j                  |d«      }| j                  j                  |dz   dd«       |dz   }| j                  j                  ||«       t	        |«      dk(  r#| j                  j                  |dz   |d   «       y
t        |«      D ])  \  }}| j                  j                  d	||dz   fz  |«       Œ+ y
)aâ  Adds directive and value to IfMod ssl block.

        Adds given directive and value along configuration path within
        an IfMod mod_ssl.c block.  If the IfMod block does not exist in
        the file, it is created.

        :param str aug_conf_path: Desired Augeas config path to add directive
        :param str directive: Directive you would like to add, e.g. Listen
        :param args: Values of the directive; list of str (eg. ["443"])
        :type args: list

        z	mod_ssl.cÚargr±   Fzdirective[1]r¨   r©   r   z
%s/arg[%d]N)Ú	get_ifmodr%   ÚinsertrO   rG   r¬   )r:   r°   r±   r¦   Úif_mod_pathÚnvh_pathr¡   r³   s           r;   Úadd_dir_to_ifmodsslz ApacheParser.add_dir_to_ifmodssla  s¨   € ð —n‘n ]°KÓ@ˆà�‰�‰˜ eÑ+¨[¸%Ô@Ø Ñ/ˆØ�‰�‰�X˜yÔ)Üˆt‹9˜Š>Ø�H‰H�L‰L˜ FÑ*¨D°©GÕ4ä# D›/ò D‘��3Ø—‘—‘˜\¨X°q¸1±uÐ,=Ñ=¸sÕCñDr=   r¥   c                 óš   — | j                   j                  |›d|›d�«      }|s| j                  ||«      S |d   j                  d«      d   S )a  Returns the path to <IfMod mod> and creates one if it doesn't exist.

        :param str aug_conf_path: Augeas configuration path
        :param str mod: module ie. mod_ssl.c
        :param bool beginning: If the IfModule should be created to the beginning
            of augeas path DOM tree.

        :returns: Augeas path of the requested IfModule directive that pre-existed
            or was created during the process. The path may be dynamic,
            i.e. .../IfModule[last()]
        :rtype: str

        z/IfModule/*[self::arg='z']r   r³   )r%   rD   Úcreate_ifmodÚ
rpartition)r:   r°   r¥   Úif_modss       r;   r´   zApacheParser.get_ifmod{  sR   € ð —(‘(—.‘.Ú#0²#ð#7ó 9ˆáØ×$Ñ$ ]°CÓ8Ð8ð �q‰z×$Ñ$ UÓ+¨AÑ.Ð.r=   c                 óÜ   — dj                  |«      }dj                  |«      }| j                  j                  |d«       dj                  |«      }| j                  j                  ||«       |S )a>  Creates a new <IfMod mod> and returns its path.

        :param str aug_conf_path: Augeas configuration path
        :param str mod: module ie. mod_ssl.c

        :returns: Augeas path of the newly created IfModule directive.
            The path may be dynamic, i.e. .../IfModule[last()]
        :rtype: str

        z{}/IfModule[last() + 1]z{}/IfModule[last()]/argrU   z{}/IfModule[last()]/)rF   r%   rO   )r:   r°   r¥   Úc_pathÚ
c_path_argÚretpaths         r;   rº   zApacheParser.create_ifmod‘  s]   € ð +×1Ñ1°-Ó@ˆØ.×5Ñ5°mÓDˆ
Ø�‰�‰�V˜RÔ Ø(×/Ñ/°Ó>ˆØ�‰�‰�Z Ô%Øˆr=   c                 ó  — |r|nd}| j                   j                  |dz   |«       t        |t        «      r6t	        |d«      D ]&  \  }}| j                   j                  d||fz  |«       Œ( y| j                   j                  |dz   |«       y)a�  Appends directive to the end fo the file given by aug_conf_path.

        .. note:: Not added to AugeasConfigurator because it may depend
            on the lens

        :param str aug_conf_path: Augeas configuration path to add directive
        :param str directive: Directive to add
        :param args: Value of the directive. ie. Listen 443, 443 is arg
        :type args: list or str

        rU   z/directive[last() + 1]r¨   z%s/directive[last()]/arg[%d]z/directive[last()]/argN)r%   rO   Ú
isinstanceÚlistr¬   )r:   r°   r±   r¦   r¡   Úvalues         r;   rx   zApacheParser.add_dir£  s…   € ñ *7™¸BˆØ�‰�‰�]Ð%=Ñ=¸yÔIÜ�dœDÔ!Ü% d¨AÓ.ò P‘��5Ø—‘—‘Ø2°mÀQÐ5GÑGÈõPñPð �H‰H�L‰L˜Ð)AÑAÀ4ÕHr=   ry   c                 óÈ  — |r|nd}|dz   }| j                   j                  |«      r| j                   j                  |dd«       n| j                   j                  |d«       | j                   j                  ||«       t	        |t
        «      r7t        |d«      D ]'  \  }}| j                   j                  |d|z  z   |«       Œ) y| j                   j                  |dz   |«       y)	a)  Adds the directive to the beginning of defined aug_conf_path.

        :param str aug_conf_path: Augeas configuration path to add directive
        :param str dirname: Directive to add
        :param args: Value of the directive. ie. Listen 443, 443 is arg
        :type args: list or str
        rU   z/directive[1]r±   Tr¨   r«   r©   N)r%   rE   rµ   rO   rÂ   rÃ   r¬   )r:   r°   ry   r¦   Ú	first_dirr¡   rÄ   s          r;   Úadd_dir_beginningzApacheParser.add_dir_beginningº  sº   € ñ *7™¸BˆØ! OÑ3ˆ	Ø�8‰8�<‰<˜	Ô"Ø�H‰H�O‰O˜I {°DÕ9à�H‰H�L‰L˜ KÔ0à�‰�‰�Y Ô(Ü�dœDÔ!Ü% d¨AÓ.ò B‘��5Ø—‘—‘˜Y¨°qÑ)9Ñ9¸5ÕAñBð �H‰H�L‰L˜ VÑ+¨TÕ2r=   Úcommentc                 óB   — | j                   j                  |dz   |«       y)z§Adds the comment to the augeas path

        :param str aug_conf_path: Augeas configuration path to add directive
        :param str comment: Comment content

        z/#comment[last() + 1]N)r%   rO   )r:   r°   rÈ   s      r;   Úadd_commentzApacheParser.add_commentÑ  s   € ð 	�‰�‰�]Ð%<Ñ<¸gÕFr=   r³   Ústartc                 óê   — |st        | j                  «      }| j                  j                  d|z  «      }g }|D ]6  }| j                  j	                  |«      }|sŒ!||v sŒ&|j                  |«       Œ8 |S )a  Finds a comment with specified content from the provided DOM path

        :param str arg: Comment content to search
        :param str start: Beginning Augeas path to begin looking

        :returns: List of augeas paths containing the comment content
        :rtype: list

        z%s//*[label() = '#comment'])rw   r   r%   rD   rE   r|   )r:   r³   rË   ÚcommentsÚresultsrÈ   Ú	c_contents          r;   Úfind_commentszApacheParser.find_commentsÚ  sp   € ñ Ü  §¡Ó+ˆEà—8‘8—>‘>Ð"?À%Ñ"GÓHˆàˆØò 	(ˆGØŸ™Ÿ™ WÓ-ˆIÚ˜S IÒ-Ø—‘˜wÕ'ð	(ð ˆr=   Úexcludec                 óŒ  — |st        | j                  d   «      }dt        |«      ›dt        d«      ›dt        d«      ›d�}| j                  j	                  |›d|›d�«      }|r| j                  |«      }|€d	}nd
t        |«      z  }g }|D ]´  }	| j                  j                  |	«      j                  «       }
|
dv rD|j                  | j                  ||| j                  | j                  |	d	z   «      «      |«      «       |
|j                  «       k(  sŒˆ|j                  | j                  j	                  |	|z   «      «       Œ¶ |S )a  Finds directive in the configuration.

        Recursively searches through config files to find directives
        Directives should be in the form of a case insensitive regex currently

        .. todo:: arg should probably be a list
        .. todo:: arg search currently only supports direct matching. It does
            not handle the case of variables or quoted arguments. This should
            be adapted to use a generic search for the directive and then do a
            case-insensitive self.get_arg filter

        Note: Augeas is inherently case sensitive while Apache is case
        insensitive.  Augeas 1.0 allows case insensitive regexes like
        regexp(/Listen/, "i"), however the version currently supported
        by Ubuntu 0.10 does not.  Thus I have included my own case insensitive
        transformation by calling case_i() on everything to maintain
        compatibility.

        :param str directive: Directive to look for
        :param arg: Specific value directive must have, None if all should
                    be considered
        :type arg: str or None

        :param str start: Beginning Augeas path to begin looking
        :param bool exclude: Whether or not to exclude directives based on
            variables and enabled modules

        :rtype list

        r   ú(z)|(rt   ÚIncludeOptionalú)z//*[self::directive=~regexp('z')]r©   z/*[self::arg=~regexp('%s')])ÚincludeÚincludeoptional)rw   r.   rv   r%   rD   Úexclude_dirsrE   ÚlowerÚextendru   Ú_get_include_pathr�   )r:   r±   r³   rË   rÑ   ÚregexrR   Ú
arg_suffixÚordered_matchesrD   Údir_s              r;   ru   zApacheParser.find_dirð  s9  € ñB Ü  §¡¨&Ñ!1Ó2ˆEøô %+¨9Õ$5Ü$*¨9Õ$5Ü$*Ð+<Õ$=ð?ˆð —(‘(—.‘.Ú6;ºUÐCóEˆñ Ø×'Ñ'¨Ó0ˆGàˆ;Ø‰Jà6¼À»ÑDˆJà%'ˆð ò 		KˆEØ—8‘8—<‘< Ó&×,Ñ,Ó.ˆDØÐ5Ñ5Ø×&Ñ& t§}¡}Ø˜sØ×*Ñ*¨4¯<©<¸À¹Ó+GÓHØó(ô ð
 �y—‘Ó(Ó(Ø×&Ñ& t§x¡x§~¡~°e¸jÑ6HÓ'IÕJð		Kð Ðr=   rD   c                 ó@  — | j                   j                  |«      }|sy|j                  d«      }t        j                  j                  |«      }|D ]%  }	 |j                  || j                  |dd    «      }Œ' |S # t        $ r t        j                  d|z  «      ‚w xY w)zŽUses augeas.get to get argument value and interprets result.

        This also converts all variables and parameters appropriately.

        Nú'"é   rŠ   zError Parsing variable: %s)r%   rE   r¤   r   r   ÚfindallÚreplacer*   ÚKeyErrorr   rH   )r:   rD   rÄ   r*   Úvars        r;   r�   zApacheParser.get_arg?  s©   € ð —‘—‘˜UÓ#ˆñ Øà—‘˜EÓ"ˆä ×4Ñ4×<Ñ<¸UÓCˆ	àò 	MˆCðMØŸ™ c¨4¯>©>¸#¸aÀ¸)Ñ+DÓE‘ð	Mð ˆøô ò MÜ×(Ñ(Ð)EÈÑ)KÓLÐLðMús   Á"A;Á;"Bc                 ó2   — t        | j                  d   «      S )z@
        Returns the Augeas path of root configuration.
        r   )rw   r.   ra   s    r;   Úget_root_augpathzApacheParser.get_root_augpath\  s   € ô ˜DŸH™H VÑ,Ó-Ð-r=   c                 óÄ   — d| j                   j                  «       fd| j                  fg}g }|D ].  }|D ]  }| j                  ||«      rŒ Œ |j	                  |«       Œ0 |S )z>Exclude directives that are not loaded into the configuration.ÚifmoduleÚifdefine)r(   Úkeysr*   Ú_pass_filterr|   )r:   rR   ÚfiltersÚvalid_matchesrD   Úfilter_s         r;   rØ   zApacheParser.exclude_dirsb  su   € à §¡× 1Ñ 1Ó 3Ð4°zÀ4Ç>Á>Ð6RÐSˆàˆàò 	,ˆEØ"ò ,�Ø×(Ñ(¨°Õ8Ùð,ð ×$Ñ$ UÕ+ð	,ð Ðr=   rð   c                 ó:  — |j                  «       }|j                  |d   «      }|dk7  rr|j                  d|«      }| j                  j                  |d| dz   «      }|j	                  d«      r|dd |d   v r	y||d   vry|j                  |d   |«      }|dk7  rŒry	)
zÐDetermine if directive passes a filter.

        :param str match: Augeas path
        :param list filter: list of tuples of form
            [("lowercase if directive", set of relevant parameters)]

        r   rŠ   r#   Nr©   ú!r¨   FT)rÙ   Úfindr%   rE   Ú
startswith)r:   rD   rð   Úmatch_lÚlast_match_idxÚ	end_of_ifÚ
expressions          r;   rí   zApacheParser._pass_filterp  s¬   € ð —+‘+“-ˆØ Ÿ™ g¨a¡jÓ1ˆà Ò"àŸ™ S¨.Ó9ˆIàŸ™Ÿ™ e¨J¨YÐ&7¸&Ñ&@ÓAˆJà×$Ñ$ SÔ)à˜a˜b�> W¨Q¡ZÑ/Ø à W¨Q¡ZÑ/Ø à$Ÿ\™\¨'°!©*°iÓ@ˆNð  Ó"ð  r=   c                 ó  — |j                  d«      }|j                  d«      sIt        j                  j	                  t        j                  j                  | j                  |«      «      }|S t        j                  j	                  |«      }|S )z¢Ensure paths are consistent and absolute

        :param str arg: Argument of directive

        :returns: Standardized argument path
        :rtype: str
        rá   r#   )r¤   rô   r   r+   Únormpathrn   r   )r:   r³   s     r;   Ústandard_path_from_server_rootz+ApacheParser.standard_path_from_server_root�  si   € ð �i‰i˜Óˆð �~‰~˜cÔ"ä—'‘'×"Ñ"¤2§7¡7§<¡<°·	±	¸3Ó#?Ó@ˆCð ˆ
ô —'‘'×"Ñ" 3Ó'ˆCØˆ
r=   c                 ó¾  — |€y| j                  |«      }t        j                  j                  |«      r0| j	                  t        j                  j                  |d«      «       n| j	                  |«       |j                  d«      }t        |«      D ]/  \  }}t        d„ |D «       «      sŒd| j                  |«      z  ||<   Œ1 dj                  |«      }t        |«      S )a@  Converts an Apache Include directive into Augeas path.

        Converts an Apache Include directive argument into an Augeas
        searchable path

        .. todo:: convert to use os.path.join()

        :param str arg: Argument of Include directive

        :returns: Augeas path string
        :rtype: str

        Nr   r#   c              3   ó@   K  — | ]  }|t         j                  v –— Œ y ­w©N)r   r   )rh   Úchars     r;   rj   z1ApacheParser._get_include_path.<locals>.<genexpr>Ã  s   è ø€ ÒH¸$�4œ<×5Ñ5Ô5ÑHùs   ‚z* [label()=~regexp('%s')])rû   r   r+   Úisdirr/   rn   Úsplitr¬   ÚanyÚfnmatch_to_rerw   )r:   r³   Ú	split_argÚidxr  s        r;   rÛ   zApacheParser._get_include_path   sÃ   € ð( ˆ;ØØ×1Ñ1°#Ó6ˆô �7‰7�=‰=˜ÔØ�O‰OœBŸG™GŸL™L¨¨cÓ2Õ3à�O‰O˜CÔ ð
 —I‘I˜c“Nˆ	Ü# IÓ.ò 	=‰JˆC�ÜÑHÀ%ÔHÕHð #>Ø"&×"4Ñ"4°UÓ";ñ#<�	˜#’ð		=ð �h‰h�yÓ!ˆä˜CÓ Ð r=   Úclean_fn_matchc                 ó2   — t        j                  |«      dd S )aˆ  Method converts Apache's basic fnmatch to regular expression.

        Assumption - Configs are assumed to be well-formed and only writable by
        privileged users.

        https://apr.apache.org/docs/apr/2.0/apr__fnmatch_8h_source.html

        :param str clean_fn_match: Apache style filename match, like globs

        :returns: regex suitable for augeas
        :rtype: str

        é   éýÿÿÿ)ÚfnmatchÚ	translate)r:   r  s     r;   r  zApacheParser.fnmatch_to_reÎ  s   € ô × Ñ  Ó0°°2Ð6Ð6r=   Úfilepathc                 ó  — | j                  |«      \  }}| j                  «        |r`| j                  j                  d|z  «      }|s?|r| j	                  |«       | j                  |«       | j                  j                  «        yyy)zÙParse file with Augeas

        Checks to see if file_path is parsed by Augeas
        If filepath isn't parsed, the file is added and Augeas is reloaded

        :param str filepath: Apache config file path

        z&/augeas/load/Httpd['%s' =~ glob(incl)]N)Ú_check_path_actionsrb   r%   rD   Ú_remove_httpd_transformÚ_add_httpd_transformrd   )r:   r  Úuse_newÚ
remove_oldÚinc_tests        r;   r/   zApacheParser.parse_fileß  s‚   € ð #×6Ñ6°xÓ@Ñˆ�ð 	× Ñ Ô"ñ Ø—x‘x—~‘~Ø8¸8ÑCóEˆHáñ Ø×0Ñ0°Ô:Ø×)Ñ)¨(Ô3Ø—‘—‘•ð ð r=   Úfilepc                 ó@   — |sy| j                  || j                  «      S )a<  Checks if the file path is parsed by current Augeas parser config
        ie. returns True if the file is found on a path that's found in live
        Augeas configuration.

        :param str filep: Path to match

        :returns: True if file is parsed in existing configuration tree
        :rtype: bool
        F)Ú_parsed_by_parser_pathsr)   ©r:   r  s     r;   rŸ   zApacheParser.parsed_in_currentú  s#   € ñ ØØ×+Ñ+¨E°4×3DÑ3DÓEÐEr=   c                 ó@   — |sy| j                  || j                  «      S )a[  Checks if the file path is parsed by existing Apache config.
        ie. returns True if the file is found on a path that matches Include or
        IncludeOptional statement in the Apache configuration.

        :param str filep: Path to match

        :returns: True if file is parsed in existing configuration tree
        :rtype: bool
        F)r  r7   r  s     r;   Úparsed_in_originalzApacheParser.parsed_in_original  s#   € ñ ØØ×+Ñ+¨E°4×3FÑ3FÓGÐGr=   Úpathsc           	      ó”   — |D ]C  }||   D ]9  }t        j                   |t        j                  j                  ||«      «      sŒ8  y ŒE y)znHelper function that searches through provided paths and returns
        True if file path is found in the setTF)r
  r   r+   rn   )r:   r  r  Ú	directoryÚfilenames        r;   r  z$ApacheParser._parsed_by_parser_paths  sL   € ð ò 	 ˆIØ! )Ñ,ò  �Ü—?‘? 5¬"¯'©'¯,©,°yÀ(Ó*KÕLÚñ ð	 ð r=   c                 óê   — 	 t         j                  j                  |«      }| j                  t         j                  j	                  |«         }d|v rd}nd}|dk(  }||fS # t
        $ r
 d}d}Y ||fS w xY w)aL  Determine actions to take with a new augeas path

        This helper function will return a tuple that defines
        if we should try to append the new filepath to augeas
        parser paths, and / or remove the old one with more
        narrow matching.

        :param str filepath: filepath to check the actions for

        r   FT)r   r+   rz   r)   ry   rå   )r:   r  Únew_file_matchÚexisting_matchesr  r  s         r;   r  z ApacheParser._check_path_actions  s‰   € ð
	ÜŸW™W×-Ñ-¨hÓ7ˆNØ#×0Ñ0´·±·±ÀÓ1JÑKÐØÐ&Ñ&Ø‘à�Ø'¨3Ñ.ˆJð ˜
Ð"Ð"øô ò 	ØˆGØ‰JØ˜
Ð"Ð"ð	ús   ‚AA ÁA2Á1A2c                 óf  — | j                   t        j                  j                  |«         }t        j                  j                  |«      }|D ]F  }|dz   |z   }| j                  j                  d|z  «      }| j                  j                  |d   «       ŒH | j                   j                  |«       y)z[Remove path from Augeas transform

        :param str filepath: filepath to remove
        r#   z!/augeas/load/Httpd/incl [. ='%s']r   N)r)   r   r+   ry   r%   rD   rQ   Úpop)r:   r  Úremove_basenamesÚremove_dirnameÚnameÚremove_pathÚ
remove_incs          r;   r  z$ApacheParser._remove_httpd_transform8  s—   € ð  ×,Ñ,¬R¯W©W¯_©_¸XÓ-FÑGÐÜŸ™Ÿ™¨Ó2ˆØ$ò 	+ˆDØ(¨3Ñ.°Ñ5ˆKØŸ™Ÿ™Ø3°kÑAóCˆJà�H‰H�O‰O˜J q™MÕ*ð		+ð
 	×Ñ×Ñ˜nÕ-r=   Úinclc                 óŒ  — | j                   j                  d«      }|r=| j                   j                  |d   dd«       | j                   j                  d|«       n8| j                   j                  dd«       | j                   j                  d|«       	 | j                  t
        j                  j                  |«         j                  t
        j                  j                  |«      «       y	# t        $ rM t
        j                  j                  |«      g| j                  t
        j                  j                  |«      <   Y y	w xY w)
a"  Add a transform to Augeas.

        This function will correctly add a transform to augeas
        The existing augeas.add_transform in python doesn't seem to work for
        Travis CI as it loads in libaugeas.so.0.10.0

        :param str incl: filepath to include for transform

        z /augeas/load/Httpd/incl [last()]r   r(  Fz/augeas/load/Httpd/incl[last()]z/augeas/load/Httpd/lensz	Httpd.lnsz/augeas/load/Httpd/inclN)r%   rD   rµ   rO   r)   r   r+   ry   r|   rz   rå   )r:   r(  Úlast_includes      r;   r  z!ApacheParser._add_httpd_transformG  sê   € ð !ŸH™HŸN™NÐ+MÓNˆÙà�H‰H�O‰O˜L¨™O¨V°UÔ;Ø�H‰H�L‰LÐ:¸DÕAð �H‰H�L‰LÐ2°KÔ@Ø�H‰H�L‰LÐ2°DÔ9ð	(Ø×ÑœbŸg™gŸo™o¨dÓ3Ñ4×;Ñ;Ü—‘× Ñ  Ó&õ(øäò 	(ä—‘× Ñ  Ó&ð8(ˆD×ÑœbŸg™gŸo™o¨dÓ3Ó4ð	(ús   ÂAC- Ã-AEÅEc                 ó\  — ddddddddd	| j                   d
z   | j                   dz   | j                   dz   | j                   dz   | j                   dz   | j                   dz   g}t        |d«      D ]$  \  }}| j                  j                  d|z  |«       Œ& | j                  j	                  «        y)aa  Standardize the excl arguments for the Httpd lens in Augeas.

        Note: Hack!
        Standardize the excl arguments for the Httpd lens in Augeas
        Servers sometimes give incorrect defaults
        Note: This problem should be fixed in Augeas 1.0.  Unfortunately,
        Augeas 0.10 appears to be the most popular version currently.

        z*.augnewz	*.augsavez*.dpkg-distz
*.dpkg-bakz
*.dpkg-newz
*.dpkg-oldz	*.rpmsavez*.rpmnewz*~z
/*.augsavez/*~z/*/*augsavez/*/*~z/*/*/*.augsavez/*/*/*~r¨   z/augeas/load/Httpd/excl[%d]N)r   r¬   r%   rO   rd   )r:   Úexclr¡   Úexcludeds       r;   r1   zApacheParser.standardize_exclc  s®   € ð" ˜K¨¸Ø˜l¨K¸ØØ—	‘	˜LÑ(Ø—	‘	˜EÑ!Ø—	‘	˜MÑ)Ø—	‘	˜GÑ#Ø—	‘	Ð,Ñ,Ø—	‘	˜IÑ%ð'ˆô % T¨1Ó-ò 	F‰KˆAˆxØ�H‰H�L‰LÐ6¸Ñ:¸HÕEð	Fð 	�‰�‰�r=   c                 óÐ   — | j                   d   }t        j                  j                  | j                  d«      }t        j                  j                  |«      r|}|}n|}|}|||dœS )z�Set default location for directives.

        Locations are given as file_paths
        .. todo:: Make sure that files are included

        r   z
ports.conf)ÚdefaultÚlistenr%  )r.   r   r+   rn   r   Úisfile)r:   r/  Útempr0  r%  s        r;   r4   zApacheParser._set_locationsƒ  s[   € ð —x‘x Ñ'ˆä—G‘G—L‘L §¡¨LÓ9ˆÜ�7‰7�>‰>˜$ÔØˆFØ‰DàˆFØˆDà"¨f¸dÑCÐCr=   c                 ó(  — g d¢}|D ]u  }t         j                  j                  t         j                  j                  | j                  |«      «      sŒKt         j                  j                  | j                  |«      c S  t        j                  d«      ‚)z(Find the Apache Configuration Root file.)zapache2.confz
httpd.confzconf/httpd.confz!Could not find configuration root)r   r+   r1  rn   r   r   ÚNoInstallationError)r:   Úlocationr%  s      r;   r-   zApacheParser._find_config_root–  sf   € âDˆØò 	5ˆDÜ�w‰w�~‰~œbŸg™gŸl™l¨4¯9©9°dÓ;Õ<Ü—w‘w—|‘| D§I¡I¨tÓ4Ò4ð	5ô ×(Ñ(Ð)LÓMÐMr=   ))râ   r  )r!   Nrþ   )NNT)?Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚreÚcompiler   r	   Ú__annotations__r   r
   Ústrr   Úintr<   rL   r   Úboolr   r&   r_   rb   r   rV   rX   r   r„   r‡   r2   r0   r—   r˜   r†   r¯   r¸   r´   rº   r   rx   rÇ   rÊ   rÐ   ru   r�   rè   rØ   r   rí   rû   rÛ   r  r/   rŸ   r  r   r  r  r  r  r1   r   r4   r-   © r=   r;   r   r   "   s2  … ñ
ð $. 2§:¡:¨oÓ#>Ð˜Ó>Ú8€M�3�s‘8Ó8ð =Cñ-C˜Sð -CÐ0Dð -CØð-CØ*/°°S°©/ð-CØGKó-Cð^.¨ð .°ó .ð4 5¨¨t°C©y¨Ñ#9ó ð%˜s 3™xó %óN%ð˜x¨™}ð °ó ð2d¨°©ð d¸$ó dð"I sð I°cð I¸dó Ið&: ð :¨ó :óó"ó8ó^ó'ó&ð sð °#ð ¸$¸s¹)ó ð>D°ð DÀð DÈDÐQTÉIð DÐZ^ó Dð4/ sð /°ð /¸ó /ð,¨#ð °Cð ¸Có ð$IØ% c™]ðIØ7?À±}ðIØLQÐRVÐWZÑR[Ð]`ÐR`ÑLaðIà	óIð.3¨x¸©}ð 3Àsð 3Ø % d¨3¡i° nÑ 5ð3Ø:>ó3ð.G¨ð G°sð G¸tó Gñ ð ¨X°c©]ð ÀdÈ3Áió ð, =AØ>BñM #ð M¨H°S©Mð MØ  ™ðMØ7;ðMØGKÈCÁyóMð^˜Sð  X¨c¡]ó ð:. #ó .ð H¨S¡Mð °d¸3±ió ð #ð °°c¸:Àc¹?Ð6JÑ0Kð ÐPTó ð:°#ð ¸#ó ð&,! X¨c¡]ð ,!°xÀ±}ó ,!ð\7¨Cð 7°Có 7ð"  3ð  ¨4ó  ð6F x°¡}ð F¸ó FðH¨°©ð H¸$ó Hð¨Sð ¸ÀÀdÈ3ÁiÀÑ9Pð ÐUYó ð#¨Cð #°E¸$À¸*Ñ4Eó #ð2.°ð .¸ó .ð(¨ð (°ó (ó8ð@D  S¨# X¡ó Dð&N 3ô Nr=   r   Ústringr!   c                 óX   — dj                  d„ t        j                  | «      D «       «      S )a`  Returns case insensitive regex.

    Returns a sloppy, but necessary version of a case insensitive regex.
    Any string should be able to be submitted and the string is
    escaped and then made case insensitive.
    May be replaced by a more proper /i once augeas 1.0 is widely
    supported.

    :param str string: string to make case i regex

    rU   c              3   óŽ   K  — | ]=  }|j                  «       r'd |j                  «       z   |j                  «       z   dz   n|–— Œ? y­w)r   r   N)ÚisalphaÚupperrÙ   )rh   rŒ   s     r;   rj   zcase_i.<locals>.<genexpr>«  sD   è ø€ ò FØ./�q—y‘y”{ð ˜Ÿ™›‘? Q§W¡W£YÑ.°Ò4Ø()ó*ñ Fùs   ‚AA)rn   r:  Úescape)rA  s    r;   rv   rv   Ÿ  s/   € ð �7‰7ñ FÜ35·9±9¸VÓ3DôFó Fð Fr=   Ú	file_pathc                 ó   — d| z  S )zTReturn augeas path for full filepath.

    :param str file_path: Full filepath

    z/files%sr@  )rG  s    r;   rw   rw   ¯  s   € ð ˜	Ñ!Ð!r=   c                  óÎ   — t         st        j                  d«      ‚t        t        j                  t         j
                  t         j                  z  t         j                  z  ¬«      S )z' Initialize the actual Augeas instance zProblem in Augeas installation)ÚloadpathÚflags)r   r   r4  r   ÚAUGEAS_LENS_DIRÚNONEÚNO_MODL_AUTOLOADÚENABLE_SPANr@  r=   r;   r$   r$   ¸  sT   € õ Ü×(Ñ(Ð)IÓJÐJää×*Ñ*ô �{‰{Ü×&Ñ&ñ'ä×!Ñ!ñ"ô$ð $r=   )%r9  r5   r
  Úloggingr:  Útypingr   r   r   r   r   r   r	   r
   r   r   r   Úcertbotr   Úcertbot.compatr   Úcertbot_apache._internalr   r   Ú%certbot_apache._internal.configuratorr   Úaugeasr   ÚImportErrorÚ	getLoggerr6  rk   r   r=  rv   rw   r$   r@  r=   r;   ú<module>rY     s¾   ðÙ FÛ Û Û Û 	Ý Ý Ý Ý Ý Ý Ý Ý Ý Ý  Ý å Ý Ý 0Ý .áÝHðÝð 
ˆ×	Ñ	˜8Ó	$€÷zNñ zNðzF�3ð F˜3ó Fð "˜Cð " Có "ð$�Vô $øðy ò Ø‚Fðús   Á6B/ Â/B9Â8B9