
    <i                     n	   S r SSKrSSKrSSKrSSKrSSKrSSKrSSKrSSK	J
r
JrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJrJr  \R>                  RA                  5       (       a  SSKJ!r!  OSSK"J!r!  \RF                  RH                  RK                  SSSSS	S
5      r&/ SQr'\'\(" SS5       V s/ s H  n SU -  PM
     sn -  r'\'\(" SS5       V s/ s H  n SU -  PM
     sn -  r'\RF                  RH                  RJ                  " \' Vs/ s H  oRS                  5       U4PM     sn6 r*Sr+Sr,\RZ                  " S5      r.\RZ                  " S5      r/SS jr0S r1S r2S r3S r4S r5S r6S r7S r8S r9S  r:S! r;S" r<S# r=S$ r>S% r?\" S&S'S(5      r@\" S)S*5      rA\" S+S,5      rB\" S-S.5      rC\R                  " \5S/S0S15      rE\R                  " \5S2S3S45      rF\R                  " \5S5S6S75      rG\R                  " \5S8S9S:5      rH\R                  " \5S;S<S=5      rI\R                  " \5S>S?S@5      rJ\R                  " \6SASB5      rK\R                  " \6SCSD5      rL\R                  " \7SESF5      rM\R                  " \7SGSH5      rN\R                  " \7SISJ5      rO\" SKSLSSM9rP\" SNSN5      rQ\" SOSP5      rR\R                  " \8SQSRSS5      rS\R                  " \8STSUSV5      rT\R                  " \8SWSXSY5      rU\R                  " \8SZS[S\5      rV\R                  " \8S]S^S_5      rW\R                  " \:S`SaSbSc5      rX\R                  " \:SdSeSfSg5      rY\R                  " \:ShSiSjSk5      rZ\R                  " \:SlSmSnSo5      r[\R                  " \;SpSq5      r\\R                  " \;SrSs5      r]\R                  " \;StSu5      r^\" SvSw5      r_\R                  " \?SxSySz5      r`\R                  " \?S{S|S}5      ra\R                  " \<S~S5      rb\R                  " \<SS5      rc\R                  " \<SS5      rd\R                  " \<SS5      re\R                  " \<SS5      rf\R                  " \<SS5      rg\R                  " \<SS5      rh\" SS5      ri\" SS5      rj\" SS5      rk\" SSS5      rl " S S\5      rm " S S\m5      rn " S S\m5      rogs  sn f s  sn f s  snf )a
  
Parsing for Tor extra-info descriptors. These are published by relays whenever
their server descriptor is published and have a similar format. However, unlike
server descriptors these don't contain information that Tor clients require to
function and as such aren't fetched by default.

Defined in section 2.1.2 of the `dir-spec
<https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt>`_,
extra-info descriptors contain interesting but non-vital information such as
usage statistics. Tor clients cannot request these documents for bridges.

Extra-info descriptors are available from a few sources...

* If you have 'DownloadExtraInfo 1' in your torrc...

 * control port via 'GETINFO extra-info/digest/\*' queries
 * the 'cached-extrainfo' file in tor's data directory

* Archived descriptors provided by `CollecTor <https://metrics.torproject.org/collector.html>`_.

* Directory authorities and mirrors via their DirPort.

**Module Overview:**

::

  ExtraInfoDescriptor - Tor extra-info descriptor.
    |- RelayExtraInfoDescriptor - Extra-info descriptor for a relay.
    |- BridgeExtraInfoDescriptor - Extra-info descriptor for a bridge.
    |
    +- digest - calculates the upper-case hex digest value for our content

.. data:: DirResponse (enum)

  Enumeration for known statuses for ExtraInfoDescriptor's dir_*_responses.

  =================== ===========
  DirResponse         Description
  =================== ===========
  **OK**              network status requests that were answered
  **NOT_ENOUGH_SIGS** network status wasn't signed by enough authorities
  **UNAVAILABLE**     requested network status was unavailable
  **NOT_FOUND**       requested network status was not found
  **NOT_MODIFIED**    network status unmodified since If-Modified-Since time
  **BUSY**            directory was busy
  =================== ===========

.. data:: DirStat (enum)

  Enumeration for known stats for ExtraInfoDescriptor's dir_*_direct_dl and
  dir_*_tunneled_dl.

  ===================== ===========
  DirStat               Description
  ===================== ===========
  **COMPLETE**          requests that completed successfully
  **TIMEOUT**           requests that didn't complete within a ten minute timeout
  **RUNNING**           requests still in process when measurement's taken
  **MIN**               smallest rate at which a descriptor was downloaded in B/s
  **MAX**               largest rate at which a descriptor was downloaded in B/s
  **D1-4** and **D6-9** rate of the slowest x/10 download rates in B/s
  **Q1** and **Q3**     rate of the slowest and fastest quarter download rates in B/s
  **MD**                median download rate in B/s
  ===================== ===========
    N)PGP_BLOCK_END
Descriptor
DigestHashDigestEncodingcreate_signing_key_descriptor_content_read_until_keywords_descriptor_components_value_values_parse_simple_line_parse_int_line_parse_timestamp_line_parse_forty_character_hex_parse_key_block_mappings_for_append_router_signature_random_nickname_random_fingerprint_random_date_random_crypto_blob)	lru_cache)OKok)NOT_ENOUGH_SIGSznot-enough-sigs)UNAVAILABLEunavailable)	NOT_FOUNDz	not-found)NOT_MODIFIEDznot-modified)BUSYbusy)completetimeoutrunningminmaxq1q3md      zd%i   
   )
extra-info	publishedrouter-signature)!read-historywrite-historygeoip-db-digestgeoip6-db-digestbridge-stats-end
bridge-ipsdirreq-stats-enddirreq-v2-ipsdirreq-v3-ipsdirreq-v2-reqsdirreq-v3-reqsdirreq-v2-sharedirreq-v3-sharedirreq-v2-respdirreq-v3-respdirreq-v2-direct-dldirreq-v3-direct-dldirreq-v2-tunneled-dldirreq-v3-tunneled-dldirreq-read-historydirreq-write-historyentry-stats-end	entry-ipscell-stats-endcell-processed-cellscell-queued-cellscell-time-in-queuecell-circuits-per-decileconn-bi-directexit-stats-endexit-kibibytes-writtenexit-kibibytes-readexit-streams-openedz^(.*) \(([0-9]+) s\)( .*)?$z^[a-zA-Z0-9\?]{2}$Fc              +     #     U(       d6  [        SU 5      n[        R                  " SS5      S   nU[        XPS5      -  nO[        SU S5      nU(       am  US   R                  S5      (       a  USS nU(       a$  [	        [
        R                  S	U5      U40 UD6v   O%[        [
        R                  S	U5      U40 UD6v   OgM  7f)
a^  
Iterates over the extra-info descriptors in a file.

:param file descriptor_file: file with descriptor content
:param bool is_bridge: parses the file as being a bridge descriptor
:param bool validate: checks the validity of the descriptor's content if
  **True**, skips these checks otherwise
:param dict kwargs: additional arguments for the descriptor constructor

:returns: iterator for :class:`~stem.descriptor.extrainfo_descriptor.ExtraInfoDescriptor`
  instances in the file

:raises:
  * **ValueError** if the contents is malformed and validate is **True**
  * **IOError** if the file can't be read
Tr0    r*   r   router-digests   @typeN    )r	   r   split
startswithBridgeExtraInfoDescriptorbytesjoinRelayExtraInfoDescriptor)descriptor_file	is_bridgevalidatekwargsextrainfo_contentblock_end_prefixs         ^/home/james-whalen/.local/lib/python3.13/site-packages/stem/descriptor/extrainfo_descriptor.py_parse_filerc      s     $ 	./A?S ',,S!4Q7/0@SWXX.QUV	1		(	(	2	2-ab1	'

38I(JH_X^__&uzz#7H'I8^W]^^) 	s   CCc                    U < SU< 3n[         R                  U5      nU(       d  [        SU < SU< 35      eUR                  5       u  pEnU(       a  USS nUR	                  5       (       d  [        U < SU< 35      e [
        R                  R                  R                  U5      nU[        U5      U4$ ! [         a    [        U < SU< 35      ef = f)a(  
Parses a 'YYYY-MM-DD HH:MM:SS (NSEC s) *' entry.

:param str keyword: line's keyword
:param str content: line content to be parsed

:returns: **tuple** of the form (timestamp (**datetime**), interval
  (**int**), remaining content (**str**))

:raises: **ValueError** if the content is malformed
rS   z
Malformed z line: r*   Nz" line's interval wasn't a number: z# line's timestamp wasn't parsable: )
_timestamp_rematch
ValueErrorgroupsisdigitstemutil	str_tools_parse_timestampint)keywordcontentlinecontent_matchtimestamp_strinterval	remainder	timestamps           rb   _parse_timestamp_and_intervalrw      s     W	%$%%g.-	
>
??'4';';'=$-9!"I					
$O
PPR		##44]CIc(mY..	 R
'4P
QQRs    6B7 7Cc                    [        SU5      nUR                  5       n[        U5      S:  a  [        SU-  5      e[        R
                  R                  R                  US   5      (       d  [        SUS   -  5      e[        R
                  R                  R                  US   5      (       d  [        SUS   -  5      eUS   U l	        US   U l
        g )Nr.      z3Extra-info line must have two values: extra-info %sr   z0Extra-info line entry isn't a valid nickname: %sr*   z6Tor relay fingerprints consist of forty hex digits: %s)r   rV   lenrg   rj   rk   	tor_toolsis_valid_nicknameis_valid_fingerprintnicknamefingerprint)
descriptorentriesvalueextra_info_comps       rb   _parse_extra_info_liner      s     w
'%KKM/A
JUR
SS99001CDD
G/Z[J\\
]]9933OA4FGG
MP_`aPbb
cc'***1-*rU   c                 .   0 n[        SU5       GH|  nSu  pEpgSU;  a  UnGOcUR                  5       n[        U5      S:  a  [        SU-  5      e[        U5      S:  a  [        SU-  5      eSUS   ;  a  [        S	U-  5      eUS
   nUS   R	                  SS5      u  pY[
        R                  R                  R                  U5      (       a-  [
        R                  R                  R                  USS9(       a  [        SU-  5      e[
        R                  R                  R                  U	5      (       d  [        SU-  5      eUR                  S5      R                  S5        [        U	5      n[        U5      S:  a  USS  O/ nXVU4X$'   GM     X l        g )N	transport)NNNNrS   r*   z:Transport line is missing its transport name: transport %sry   z>Transport line is missing its address:port value: transport %s:zDTransport line's address:port entry is missing a colon: transport %sr   T)allow_bracketsz4Transport line has a malformed address: transport %sz1Transport line has a malformed port: transport %s[]   )r   rV   rz   rg   rsplitrj   rk   
connectionis_valid_ipv4_addressis_valid_ipv6_addressis_valid_portlstriprstriprn   r   )
r   r   
transportsr   nameaddressportargs
value_compport_strs
             rb   _parse_transport_liner     s    *{G,e 6D4
%d ;;=j	Z1	UX]]^^z?QY\aabbjm#_bgghh]d$Q-..sA6gYY!!77@@YY!!77RV7WORWWXXyy##11(;;LuTUUnnS  %]d":!3Z^dt,J= -@ $rU   c                     [        SU5      n[        SU5      u  p4n0 n[        SUSS9 H)  u  pxUR                  5       (       a  [	        U5      OUXg'   M+     [        U SU5        [        U SU5        [        U SU5        g )Npadding-countsT)require_valuepadding_counts_endpadding_counts_intervalpadding_counts)r   rw   r   ri   rn   setattr)	r   r   r   rv   rt   ru   countskvs	            rb   _parse_padding_counts_liner   6  s     !7
+%#@AQSX#Y )y&,iNda))++A1FI O 
**I6	*/:	*&/rU   c           
      ^   [        X5      n0 n0 nU S;   nU(       a  [        O[        n	U(       a  SOSn
[        XSS9 HU  u  pUR	                  5       (       d  [        U < SU
< SU < SU< 35      eX;   a  [        U5      Xk'   MH  [        U5      X{'   MW     [        X1U5        [        X2U5        g )	N)r>   r?   STATUSSTAT,dividerz lines should contain z=COUNT mappings: rS   )r   DirResponseDirStatr   ri   rg   rn   r   )ro   recognized_counts_attrunrecognized_counts_attrr   r   r   recognized_countsunrecognized_countsis_response_statskey_setkey_typestatuscounts                rb   _parse_dirreq_liner   E  s    

"%!EE,K''*X($WsCmf==??WV^`ginopp"%e*$'J! D 
*.?@	*0CDrU   c           	          [        X5      nUR                  S5      (       d  [        U < SU < SU< 35      e[        US S 5      S:  a  [        SU < SU< 35      e[	        X![        US S 5      S-  5        g )N%z lines should be a percentage: rS   r   zNegative percentage value: d   )r   endswithrg   floatr   )ro   	attributer   r   r   s        rb   _parse_dirreq_share_liner   ]  sm    

"%			
'SXY
ZZU3BZ1
7EJ
KK 
*uSbz!2S!89rU   c           
         [        X5      n/ S pSU(       a3  UR                  S5       H  n UR                  [        U5      5        M      [        X!U5        U(       a  Ueg ! [         a    [	        SU < SU < SU< 35      n M\  f = f)Nr   zNon-numeric entry in z
 listing: rS   )r   rV   appendr   rg   r   )ro   r   r   r   r   excentrys          rb   _parse_cell_liner   j  s     
"%T3
S!_ 	uU|$ " 
*)
I 	  _WgW\]^_s   A!BBc                 d    [        U [        X5      5      u  pVn[        X1U5        [        X2U5        g N)rw   r   r   )ro   end_attributeinterval_attributer   r   rv   rt   _s           rb   "_parse_timestamp_and_interval_liner     s.     9&BZ[)q	*Y/	*(3rU   c                    [        SU5      n[        SU5      u  p4nUR                  S5      n[        U5      S:w  d`  US   R	                  5       (       aH  US   R	                  5       (       a0  US   R	                  5       (       a  US   R	                  5       (       d  [        SU-  5      eX0l        X@l        [        US   5      U l	        [        US   5      U l
        [        US   5      U l        [        US   5      U l        g )	NrM   r      r   r*   ry   r   zJconn-bi-direct line should end with four numeric values: conn-bi-direct %s)r   rw   rV   rz   ri   rg   conn_bi_direct_endconn_bi_direct_intervalrn   conn_bi_direct_belowconn_bi_direct_readconn_bi_direct_writeconn_bi_direct_both)r   r   r   rv   rt   ru   statss          rb   _parse_conn_bi_direct_liner     s     !7
+%#@AQSX#Y )y
//#
%Z1_U1X--//E!H4D4D4F4F5QR8K[K[K]K]bghibjbrbrbtbt
adii
jj"+'/$$'aM*!#&uQx=* $'aM*!#&uQx=* rU   c                 8   [        X5      n[        X5      u  pxn	/ n
U	(       a+   U	R                  S5       Vs/ s H  n[        U5      PM     n
n[        XAU5        [        XBU5        [        XCU
5        g s  snf ! [         a    [	        U < SU < SU< 35      ef = f)Nr   z line has non-numeric values: rS   )r   rw   rV   rn   rg   r   )ro   r   r   values_attributer   r   r   rv   rt   ru   history_valuesr   s               rb   _parse_history_liner     s     
"%#@#P )y.\090DE0DuE
0DnE 
*Y/	*(3	*7 F \'7TYZ[[\s   A8 A3A8 3A8 8!Bc           	      x   [        X5      0 pT[        XSS9 H  u  pgUS:w  a.  [        R                  R                  R                  U5      (       a  UR                  5       (       d  [        SU < SU < SU< 35      eUR                  5       (       a  [        U5      OUn[        U5      XV'   M     [        X!U5        g )Nr   r   otherEntries in z% line should only be PORT=N entries: rS   )
r   r   rj   rk   r   r   ri   rg   rn   r   )ro   r   r   r   r   port_mappingsr   stats           rb   _parse_port_count_liner     s      12!'C@jd		 4 4 B B4 H HQUQ]Q]Q_Q_T[]dfklmm3t9DDd)M A 
*/rU   c           	          [        X5      0 pT[        XSS9 HX  u  pg[        R                  U5      (       a  UR	                  5       (       d  [        SU < SU < SU< 35      e[        U5      XV'   MZ     [        X!U5        g )Nr   r   r   z# line should only be CC=N entries: rS   )r   r   
_locale_rerf   ri   rg   rn   r   )ro   r   r   r   r   locale_usagelocaler   s           rb   _parse_geoip_to_count_liner     sl     w0"$WsCmfF##5==??RY[bdijkku:L	 D 
*.rU   c                     [        SU5      0 p2[        SUSS9 HE  u  pEUR                  5       (       d  [        R                  " SU< SU< 35      e[        U5      X4'   MG     X0l        g )Nbridge-ip-versionsr   r   z#IP protocol count was non-numeric (z): bridge-ip-versions )r   r   ri   rj   ProtocolErrorrn   ip_versions)r   r   r   r   protocolr   s         rb   _parse_bridge_ip_versions_liner     s_    2G<b&';UcRoh==??bginoppJK	 S 'rU   c                     [        SU5      0 p2[        SUSS9 HE  u  pEUR                  5       (       d  [        R                  " SU< SU< 35      e[        U5      X4'   MG     X0l        g )Nbridge-ip-transportsr   r   z!Transport count was non-numeric (z): bridge-ip-transports )r   r   ri   rj   r   rn   ip_transports)r   r   r   r   r   r   s         rb    _parse_bridge_ip_transports_liner     s`     6@"&'=uPSToh==??bginopp!%jM	 U +rU   c                 V   [        X5      S 0 pvnUc  OVUS:X  a  [        SU -  5      eSU;   a  UR                  SS5      u  pOUS p [        U5      n[	        X	5       H	  u  pXU
'   M     [        X1U5        [        X2U5        g ! [         a    [        SU < SU< SU < SU< 35      ef = f)N z'%s' line was blankrS   r*   'z' stat was non-numeric (z): )r   rg   rV   rn   r   r   )ro   stat_attributeextra_attributer   r   r   r   extra
stat_valueru   keyvals               rb   _parse_hs_statsr     s     g/ru%
]{
*W4
55
e|#kk#q1j)#T)h_d "'5Cj 6 
*d+	*u-  h':W^`efgghs   B &B(identity-ed25519ed25519_certificatezED25519 CERTmaster-key-ed25519ed25519_certificate_hashr3   geoip_db_digestr4   geoip6_db_digestr>   dir_v2_responsesdir_v2_responses_unknownr?   dir_v3_responsesdir_v3_responses_unknownr@   dir_v2_direct_dldir_v2_direct_dl_unknownrA   dir_v3_direct_dldir_v3_direct_dl_unknownrB   dir_v2_tunneled_dldir_v2_tunneled_dl_unknownrC   dir_v3_tunneled_dldir_v3_tunneled_dl_unknownr<   dir_v2_sharer=   dir_v3_sharerI   cell_processed_cellsrJ   cell_queued_cellsrK   cell_time_in_queuerL   cell_circuits_per_decile)allow_negativer/   geoip-start-timegeoip_start_timerH   cell_stats_endcell_stats_intervalrF   entry_stats_endentry_stats_intervalrN   exit_stats_endexit_stats_intervalr5   bridge_stats_endbridge_stats_intervalr7   dir_stats_enddir_stats_intervalr1   read_history_endread_history_intervalread_history_valuesr2   write_history_endwrite_history_intervalwrite_history_valuesrD   dir_read_history_enddir_read_history_intervaldir_read_history_valuesrE   dir_write_history_enddir_write_history_intervaldir_write_history_valuesrO   exit_kibibytes_writtenrP   exit_kibibytes_readrQ   exit_streams_openedhidserv-stats-endhs_stats_endhidserv-rend-relayed-cellshs_rend_cellshs_rend_cells_attrhidserv-dir-onions-seenhs_dir_onions_seenhs_dir_onions_seen_attrr8   
dir_v2_ipsr9   
dir_v3_ipsr:   dir_v2_requestsr;   dir_v3_requestsgeoip-client-originsgeoip_client_originsrG   	entry_ipsr6   
bridge_ipsrouter-sig-ed25519ed25519_signaturerouter-digest-sha256router_digest_sha256rT   _digestr0   	signature	SIGNATUREc                   B  ^  \ rS rSrSr0 SS\4_SS\4_SS\4_SS\4_SS\4_S	0 \	4_S
S\
4_SS\
4_SS\
4_SS\
4_SS\
4_SS\
4_SS\4_SS\4_SS\4_SS\4_SS\4_0 SS\4_SS\4_SS\4_SS\4_SS\4_SS\4_SS\4_SS\4_SS\4_SS\4_SS\4_S S\4_S!S\4_S"S\4_S#S\4_S$S\4_S%S\4_E0 S&S\4_S'S\4_S(S\4_S)S\4_S*S\4_S+S\4_S,S\4_S-S\4_S.S\4_S/S\4_S0S\4_S1S\4_S2S\4_S3S\ 4_S4S\ 4_S5S\ 4_S6S\!4_E0 S7S\!4_S8S\"4_S9S\#4_S:S\#4_S;S\$4_S<S\%4_S=S\&4_S>S\'4_S?S\(4_S@0 \(4_SAS\)4_SB0 \)4_SC0 \*4_SDS\*4_SES\*4_SFS\+4_SGS\+4_ES\,4S\-4S\.4S\/4S\04SH.Er10 SI\_SJ\_SK\_S	\	_SL\_SM\_SN\_SO\_SP\_SQ\_SR\_SS\_ST\_SU\_SV\_SW\_S\_0 SX\-_SY\_SZ\!_S[\#_S\\+_S]\_S^\
_S_\_S`\_Sa\_Sb\ _Sc\$_Sd\%_Se\&_Sf\'_Sg\(_Sh\)_E\*\\\\\.\"\,\/\0Si.
Er2SpU 4Sj jjr3\4Rj                  \6Rn                  4Sk jr8Sl r9Sm r:Sn r;Sor<U =r=$ )qExtraInfoDescriptori0  a  
Extra-info descriptor document.

:var str nickname: **\*** relay's nickname
:var str fingerprint: **\*** identity key fingerprint
:var datetime published: **\*** time in UTC when this descriptor was made
:var str geoip_db_digest: sha1 of the geoIP database file for IPv4 addresses
:var str geoip6_db_digest: sha1 of the geoIP database file for IPv6 addresses
:var dict transport: **\*** mapping of transport methods to their (address,
  port, args) tuple, these usually appear on bridges in which case all of
  those are **None**

**Bi-directional connection usage:**

:var datetime conn_bi_direct_end: end of the sampling interval
:var int conn_bi_direct_interval: seconds per interval
:var int conn_bi_direct_below: connections that read/wrote less than 20 KiB
:var int conn_bi_direct_read: connections that read at least 10x more than wrote
:var int conn_bi_direct_write: connections that wrote at least 10x more than read
:var int conn_bi_direct_both: remaining connections

**Bytes read/written for relayed traffic:**

:var datetime read_history_end: end of the sampling interval
:var int read_history_interval: seconds per interval
:var list read_history_values: bytes read during each interval

:var datetime write_history_end: end of the sampling interval
:var int write_history_interval: seconds per interval
:var list write_history_values: bytes written during each interval

**Cell relaying statistics:**

:var datetime cell_stats_end: end of the period when stats were gathered
:var int cell_stats_interval: length in seconds of the interval
:var list cell_processed_cells: measurement of processed cells per circuit
:var list cell_queued_cells: measurement of queued cells per circuit
:var list cell_time_in_queue: mean enqueued time in milliseconds for cells
:var int cell_circuits_per_decile: mean number of circuits in a decile

**Directory Mirror Attributes:**

:var datetime dir_stats_end: end of the period when stats were gathered
:var int dir_stats_interval: length in seconds of the interval
:var dict dir_v2_ips: mapping of locales to rounded count of requester ips
:var dict dir_v3_ips: mapping of locales to rounded count of requester ips
:var float dir_v2_share: percent of total directory traffic it expects to serve
:var float dir_v3_share: percent of total directory traffic it expects to serve
:var dict dir_v2_requests: mapping of locales to rounded count of requests
:var dict dir_v3_requests: mapping of locales to rounded count of requests

:var dict dir_v2_responses: mapping of :data:`~stem.descriptor.extrainfo_descriptor.DirResponse` to their rounded count
:var dict dir_v3_responses: mapping of :data:`~stem.descriptor.extrainfo_descriptor.DirResponse` to their rounded count
:var dict dir_v2_responses_unknown: mapping of unrecognized statuses to their count
:var dict dir_v3_responses_unknown: mapping of unrecognized statuses to their count

:var dict dir_v2_direct_dl: mapping of :data:`~stem.descriptor.extrainfo_descriptor.DirStat` to measurement over DirPort
:var dict dir_v3_direct_dl: mapping of :data:`~stem.descriptor.extrainfo_descriptor.DirStat` to measurement over DirPort
:var dict dir_v2_direct_dl_unknown: mapping of unrecognized stats to their measurement
:var dict dir_v3_direct_dl_unknown: mapping of unrecognized stats to their measurement

:var dict dir_v2_tunneled_dl: mapping of :data:`~stem.descriptor.extrainfo_descriptor.DirStat` to measurement over ORPort
:var dict dir_v3_tunneled_dl: mapping of :data:`~stem.descriptor.extrainfo_descriptor.DirStat` to measurement over ORPort
:var dict dir_v2_tunneled_dl_unknown: mapping of unrecognized stats to their measurement
:var dict dir_v3_tunneled_dl_unknown: mapping of unrecognized stats to their measurement

**Bytes read/written for directory mirroring:**

:var datetime dir_read_history_end: end of the sampling interval
:var int dir_read_history_interval: seconds per interval
:var list dir_read_history_values: bytes read during each interval

:var datetime dir_write_history_end: end of the sampling interval
:var int dir_write_history_interval: seconds per interval
:var list dir_write_history_values: bytes read during each interval

**Guard Attributes:**

:var datetime entry_stats_end: end of the period when stats were gathered
:var int entry_stats_interval: length in seconds of the interval
:var dict entry_ips: mapping of locales to rounded count of unique user ips

**Exit Attributes:**

:var datetime exit_stats_end: end of the period when stats were gathered
:var int exit_stats_interval: length in seconds of the interval
:var dict exit_kibibytes_written: traffic per port (keys are ints or 'other')
:var dict exit_kibibytes_read: traffic per port (keys are ints or 'other')
:var dict exit_streams_opened: streams per port (keys are ints or 'other')

**Hidden Service Attributes:**

:var datetime hs_stats_end: end of the sampling interval
:var int hs_rend_cells: rounded count of the RENDEZVOUS1 cells seen
:var int hs_rend_cells_attr: **\*** attributes provided for the hs_rend_cells
:var int hs_dir_onions_seen: rounded count of the identities seen
:var int hs_dir_onions_seen_attr: **\*** attributes provided for the hs_dir_onions_seen

**Padding Count Attributes:**

:var dict padding_counts: **\*** padding parameters
:var datetime padding_counts_end: end of the period when padding data is being collected
:var int padding_counts_interval: length in seconds of the interval

**Bridge Attributes:**

:var datetime bridge_stats_end: end of the period when stats were gathered
:var int bridge_stats_interval: length in seconds of the interval
:var dict bridge_ips: mapping of locales to rounded count of unique user ips
:var datetime geoip_start_time: replaced by bridge_stats_end (deprecated)
:var dict geoip_client_origins: replaced by bridge_ips (deprecated)
:var dict ip_versions: mapping of ip protocols to a rounded count for the number of users
:var dict ip_versions: mapping of ip transports to a count for the number of users

**\*** attribute is either required when we're parsed with validation or has
a default value, others are left as **None** if undefined

.. versionchanged:: 1.4.0
   Added the hs_stats_end, hs_rend_cells, hs_rend_cells_attr,
   hs_dir_onions_seen, and hs_dir_onions_seen_attr attributes.

.. versionchanged:: 1.6.0
   Added the padding_counts, padding_counts_end, and padding_counts_interval
   attributes.
r~   Nr   r/   r   r   r   r   r   r   r   r   r   r  r  r  r   r!  r"  r  r  r  r  r  r  r  r  r4  r5  r
  r  r6  r7  r   r   r   r  r  r  r  r  r  r  r  r	  r#  r$  r%  r&  r'  r(  r  r  r:  r  r  r)  r*  r+  r-  r/  r0  r2  r3  r   r   r   r  r  )r;  r  r9  r   r   r.   r3   r4   rL   r>   r?   r@   rA   rB   rC   r<   r=   rI   rJ   rK   r  rH   rF   rN   r5   r7   rM   r1   r2   rD   rE   rO   rP   rQ   r,  r.  r1  )
r   r8   r9   r:   r;   r8  rG   r6   r   r   c                 x  > [         [        U ]  X(       + S9  [        X5      nU(       Ga
  U R	                  5        H  nXC;  d  M
  [        SU-  5      e   U R	                  5       [        -    H)  nXC;   d  M
  [        X4   5      S:  d  M  [        SU-  5      e   U R                  5       nU(       a.  U[        UR                  5       5      S   :w  a  [        SU-  5      eU R                  5       nU(       a.  U[        UR                  5       5      S   :w  a  [        SU-  5      eU R                  X25        g	X0l        g	)
a  
Extra-info descriptor constructor. By default this validates the
descriptor's content as it's parsed. This validation can be disabled to
either improve performance or be accepting of malformed data.

:param str raw_contents: extra-info content provided by the relay
:param bool validate: checks the validity of the extra-info descriptor if
  **True**, skips these checks otherwise

:raises: **ValueError** if the contents is malformed and validate is True
)	lazy_loadz,Extra-info descriptor must have a '%s' entryr*   z?The '%s' entry can only appear once in an extra-info descriptorr   z2Extra-info descriptor must start with a '%s' entryr   z%Descriptor must end with a '%s' entryN)superrD  __init__r
   _required_fieldsrg   SINGLE_FIELDSrz   _first_keywordlistkeys_last_keyword_parse_entries)selfraw_contentsr^   r   ro   expected_first_keywordexpected_last_keyword	__class__s          rb   rH  ExtraInfoDescriptor.__init__7  s    

t-l-U$\<G**,'!IGST
T - **,}<'#g&6"7!";\_ffg
g =  $224	$:d7<<>>RST>U$UMPffgg"002	#8D<PQS<T#T@CXXYY
kk'$mrU   c                     [        S5      e)a  
Digest of this descriptor's content. These are referenced by...

  * **Server Descriptors**

    * Referer: :class:`~stem.descriptor.server_descriptor.ServerDescriptor` **extra_info_digest** attribute
    * Format: **SHA1/HEX**

  * **Server Descriptors**

    * Referer: :class:`~stem.descriptor.server_descriptor.ServerDescriptor` **extra_info_sha256_digest** attribute
    * Format: **SHA256/BASE64**

.. versionchanged:: 1.8.0
   Added the hash_type and encoding arguments.

:param stem.descriptor.DigestHash hash_type: digest hashing algorithm
:param stem.descriptor.DigestEncoding encoding: digest encoding

:returns: **hashlib.HASH** or **str** based on our encoding argument
zUUnsupported Operation: this should be implemented by the ExtraInfoDescriptor subclass)NotImplementedErrorrQ  	hash_typeencodings      rb   digestExtraInfoDescriptor.digest\  s    . u
vvrU   c                     [         $ r   )REQUIRED_FIELDSrQ  s    rb   rI  $ExtraInfoDescriptor._required_fieldsu  s    rU   c                     g)Nr.    r`  s    rb   rK  "ExtraInfoDescriptor._first_keywordx  s    rU   c                     g)Nr0   rc  r`  s    rb   rN  !ExtraInfoDescriptor._last_keyword{  s    rU   )rP  )F)>__name__
__module____qualname____firstlineno____doc__r   _parse_published_line_parse_geoip_db_digest_line_parse_geoip6_db_digest_liner   r   _parse_read_history_line_parse_write_history_line_parse_cell_stats_end_line _parse_cell_processed_cells_line_parse_cell_queued_cells_line_parse_cell_time_in_queue_line%_parse_cell_circuits_per_decline_line_parse_dirreq_stats_end_line_parse_dirreq_v2_ips_line_parse_dirreq_v3_ips_line_parse_dirreq_v2_share_line_parse_dirreq_v3_share_line_parse_dirreq_v2_reqs_line_parse_dirreq_v3_reqs_line_parse_dirreq_v2_resp_line_parse_dirreq_v3_resp_line_parse_dirreq_v2_direct_dl_line_parse_dirreq_v3_direct_dl_line!_parse_dirreq_v2_tunneled_dl_line!_parse_dirreq_v3_tunneled_dl_line_parse_dirreq_read_history_line _parse_dirreq_write_history_line_parse_entry_stats_end_line_parse_entry_ips_line_parse_exit_stats_end_line"_parse_exit_kibibytes_written_line_parse_exit_kibibytes_read_line_parse_exit_streams_opened_line$_parse_hidden_service_stats_end_line-_parse_hidden_service_rend_relayed_cells_line*_parse_hidden_service_dir_onions_seen_liner   _parse_bridge_stats_end_line_parse_bridge_ips_line_parse_geoip_start_time_line _parse_geoip_client_origins_liner   r   
ATTRIBUTESPARSER_FOR_LINErH  r   SHA1r   HEXr\  rI  rK  rN  __static_attributes____classcell__)rU  s   @rb   rD  rD  0  s   ||W-.WD01W $-.W 9:	W
 ;<W "+,W 4!;<W &@AW T#=>W D"<=W T#=>W D"<=W 78W  d$<=!W" D":;#W& $ 9:'W( t%>?)W* T#<=+W. t78/W0 D"<=1W2 T#CD3W4 $ =>5W6 4!?@7W8 'L M9W< d89=W> 4!=>?W@ 423AWB 423CWD T67EWF T67GWH 89IWJ 89KWL 9:MWN 9:OWP 'A BQWR 'A BSWT >?UWV >?WWX 'F GYWZ 'F G[W\ 4!BC]W^ 4!BC_W` !4)J"KaWb !4)J"KcWf T#BCgWh  $(G!HiWj &EFkWn d$DEoWp !4)I"JqWr 'G HsWv 9:wWx T#>?yWz $-.{W~ t78W@ D"<=AWB t%GHCWD D"ABEWF D"ABGWJ T?@KWL dIJMWN 2LMOWP 4!KLQWR $NOSWV r56WWX 4!;<YWZ &@A[W^ ;<_W` d$@AaWb /0;<!#CD89<=mW*r-(-2- 4- &	-
  E- 0- 0- :- :- >- >- 2- 2- <- 6-  8!-" &#-$ 4%-& 0'-( 2)-* 0+-, 4--. 4/-0 01-2 ,3-4 .5-6 :7-8 <9-: @;-< :=-> :?-@ =A-B !"OC-D IE-F 1..00<&(8<Y-/^#J  *>;M;M w2 rU   rD  c                       \ rS rSrSrSr\" \R                  40 S\	4S\
4S\4S.D6r\" \R                  40 \	\
\S.D6r\SS j5       r\SS	 j5       r\" 5       \R$                  \R(                  4S
 j5       rSrg)r[   i  aG  
Relay extra-info descriptor, constructed from data such as that provided by
'GETINFO extra-info/digest/\*', cached descriptors, and metrics
(`specification <https://gitweb.torproject.org/torspec.git/tree/dir-spec.txt>`_).

:var ed25519_certificate str: base64 encoded ed25519 certificate
:var ed25519_signature str: signature of this document using ed25519
:var str signature: **\*** signature for this extrainfo descriptor

**\*** attribute is required when we're parsed with validation

.. versionchanged:: 1.5.0
   Added the ed25519_certificate and ed25519_signature attributes.
r.   N)r   r=  rA  )r   r<  r0   rc  c           	      4   S[        5       < S[        5       < 34S[        5       44nU(       a  SnU(       aI  U(       a  SU;   a  [        S5      eUc
  [	        5       n[        XU5      S-   n[        XdR                  5      $ [        XUS[        S5      445      $ )	Nr.   rS   r/   Tr0   zBCannot sign the descriptor if a router-signature has been provideds   
router-signature
rB  )	r   r   r   rg   r   r   r   privater   )clsattrexcludesignsigning_keybase_headerrp   s          rb   rp    RelayExtraInfoDescriptor.content  s      0 24G4IJKLN#K
 d	$,]^^		(*#D;?BYYg%g/B/BCC 	0=>> 	 	rU   c                 0    U " U R                  XXE5      US9$ )N)r^   )rp   )r  r  r  r^   r  r  s         rb   createRelayExtraInfoDescriptor.create  s    s{{4$<RRrU   c                 x   U[         R                  :X  aC  U R                  SS9n[        R                  R                  [        R                  " U5      U5      $ U[         R                  :X  aB  [        R                  R                  [        R                  " U R                  5       5      U5      $ [        SU-  5      e)Nz
router-signature
)endzJExtrainfo descriptor digests are only available in sha1 and sha256, not %s)r   r  _content_rangerj   r   _encode_digesthashlibsha1SHA256sha256	get_bytesrX  )rQ  rZ  r[  rp   s       rb   r\  RelayExtraInfoDescriptor.digest  s    JOO# ##*@#Ag__++GLL,A8LL	j''	' __++GNN4>>;K,LhWW lox xyyrU   )Nrc  FN)Nrc  TFN)rg  rh  ri  rj  rk  TYPE_ANNOTATION_NAMEdictrD  r  _parse_identity_ed25519_line_parse_router_sig_ed25519_line_parse_router_signature_liner  classmethodrp   r  r   r   r  r   r  r\  r  rc  rU   rb   r[   r[     s     &'22  ">? >?457 * ,<< 484A / 	 	. S S ;)>;M;M z zrU   r[   c                       \ rS rSrSrSr\" \R                  40 S\	4S\
4S\4S.D6r\" \R                  40 \	\
\S.D6r\SS j5       r\R                   \R$                  4S	 jrS
 rS rSrg)rX   i  a{  
Bridge extra-info descriptor (`bridge descriptor specification
<https://metrics.torproject.org/collector.html#bridge-descriptors>`_)

:var str ed25519_certificate_hash: sha256 hash of the original identity-ed25519
:var str router_digest_sha256: sha256 digest of this document

.. versionchanged:: 1.5.0
   Added the ed25519_certificate_hash and router_digest_sha256 attributes.
zbridge-extra-infoN)r   r?  r@  )r   r>  rT   rc  c                     U(       a  [        SU R                  -  5      e[        XSS[        5       -  4S[	        5       44S[        5       445      $ )NzSigning of %s not implementedr.   zec2bridgereaac65a3 %sr/   rT   )rX  rg  r   r   r   )r  r  r  r  s       rb   rp   !BridgeExtraInfoDescriptor.content  s]     ?#,, NOOt,/B/DDELN#/ +-. rU   c                     U[         R                  :X  a   U[        R                  :X  a  U R                  $ U[         R
                  :X  a   U[        R                  :X  a  U R                  $ [        SU< SU< 35      e)NzOBridge extrainfo digests are only available as sha1/hex and sha256/base64, not /)	r   r  r   r  r@  r  BASE64r?  rX  rY  s      rb   r\   BridgeExtraInfoDescriptor.digest  so    JOO#N4F4F(F\\	j''	'H8M8M,M&&&  {D  FN  !O  P  PrU   c                 l    S/nS/n[        U[         Vs/ s H  o3U;  d  M
  UPM     sn-   5      $ s  snf )Nr0   rT   )tupler_  )rQ  excluded_fieldsincluded_fieldsfs       rb   rI  *BridgeExtraInfoDescriptor._required_fields  sA    O
 O #[!?BZA#[[\\#[s   	1
1
c                     g r   rc  r`  s    rb   rN  'BridgeExtraInfoDescriptor._last_keyword  s    rU   )Nrc  F)rg  rh  ri  rj  rk  r  r  rD  r  _parse_master_key_ed25519_line _parse_router_digest_sha256_line_parse_router_digest_liner  r  rp   r   r  r   r  r\  rI  rN  r  rc  rU   rb   rX   rX     s    	 -'22 !%'E F!#CD/07 * ,<< 8<.A / 	 	  *>;M;M P	]rU   rX   )FF)prk  	functoolsr  restem.prereqrj   stem.util.connectionstem.util.enumstem.util.str_toolsstem.descriptorr   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   r   prereq_is_lru_cache_availabler   stem.util.lru_cacherk   enumEnumr   	dir_statsrangeupperr   r_  rJ  compilere   r   rc   rw   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  rm  rn  partialr}  r~  r  r  r  r  ry  rz  rr  rs  rt  ru  rl  r  rq  r  r  r  rv  ro  rp  r  r  r  r  r  r  r  r  rw  rx  r{  r|  r  r  r  r  r  r  r  rD  r[   rX   )ir   s   00rb   <module>r     sM  @D   	         0 ;;&&((!+ iinn!!( " O	 	q!-Aeai- -	 	q".Aeai. .	
))..

Kt 4K
L"H 

:;ZZ-.
&RRD."+$\0E0
:,41$8$0/(	'	+.6  00BDY[ij !34HJd!e 89JL]^ 9:LN`a &../ACSUg  jD  E &../ACSUg  jD  E "+"3"34FH]_q  tN  #O "+"3"34FH]_q  tN  #O $-$5$56HJacw  zV  %W !$-$5$56HJacw  zV  %W !'//0HJ[]kl '//0HJ[]kl #,#4#45EG]_u#v   ) 1 12BDWYl m !*!2!23CEY[o!p (78RTn  BG  )H %-k;G 45GI[\ &../QSceu  xM  N '//0RTegx  {Q  R &../QSceu  xM  N (001SUgi{  ~U   V (001SUgix  {O   P $,,-@.Rdf}  @U  V %--.A?Tg  jB  DZ  [ "+"3"34GI^`v  yT  Vo  #p #,#4#45HJ`by  |X  Zt  $u  %.%6%67MOg  jB  &C ""+"3"34JLacx"y "+"3"34JLacx"y '<=PR`'a $090A0A/So  rA  CW  1X --6->->Pik  B[  .\ *%--.H/[gh %--.H/[gh &../IK[]no &../IK[]no #,#4#45OQgi  $A  !))*DkS^_ "**+E|Uab !34HJ]!^ #56LNd#e  6	R /0BKQ\] L* L^
Iz2 IzX: 3 :g ..Ks   3R(R-R2