
    jGz                       d Z ddlmZ ddlZddlmZ ddlZddlZddlm	Z	 ddl
mZmZmZ er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mZ ddlmZ ddl
mZmZ ddl Z ddl!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z' ddl(m)Z)m*Z* ddl+m,Z, ddl-m.Z. ddl/m0Z0m1Z2 ddl3m1Z4 ddl5m1Z6 ddl7m8Z8m9Z9m:Z: ddl;m<Z< ddl=m>Z> ddl?m@Z@ ddlAmBZBmCZC ddlDmEZE ddlFmGZGmHZH ddlImJZJmKZKmLZLmMZMmNZNmOZOmPZPmQZQmRZRmSZS ddlTZTddlUmVZVmWZW ddlXmYZZm[Z\ ddl]mYZ^m_Z_ ddl`mac mbc mcZb dd ldmeZemfZf dd!lgmYZhmiZi dd"ljmkZk dd#llmmZm ddlnZTdd$lompZp ddlqZT ep        d%ard%Zsd&Ztd'Zu ej                  ew      Zxd:d(Zydd;d)Zzdd<d*Z{d=d+Z|d>d,Z}d>d-Z~d?d.Zd?d/Zd@d0Zd>d1Z	 dA	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dBd2Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dC	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dDd5Zdddddddd3d3d3d3deud3d3dddddd3d6d7dddd4d3f	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dEd8Z ed9      Zy)FzLibp2p Python implementation.    )annotationsN)Path)is_quic_multiaddr)TYPE_CHECKINGAnycastPortDemultiplexer)ed25519)serialization)QUICTransport)QUICTransportConfig)MappingSequence)version)LiteralOptional)IHostINetworkServiceIPeerRouting
IPeerStoreISecureTransport
ITransport)ChannelBridgeListenerEventBus)ResourceManager)KeyPair)Ed25519PrivateKeycreate_new_key_pair)r   )TMuxerOptions	TProtocolTSecurityOptions)	BasicHost)
RoutedHost)Swarm)ConnectionConfigRetryConfig)ID)	PeerStorecreate_signed_peer_record)
create_sync_peerstorecreate_async_peerstorecreate_sync_sqlite_peerstorecreate_async_sqlite_peerstorecreate_sync_memory_peerstorecreate_async_memory_peerstorecreate_sync_leveldb_peerstorecreate_async_leveldb_peerstorecreate_sync_rocksdb_peerstorecreate_async_rocksdb_peerstore)PLAINTEXT_PROTOCOL_IDInsecureTransport)PROTOCOL_ID	Transport)r7   TLSTransport)MPLEX_PROTOCOL_IDMplex)r7   Yamux)TCP)TransportUpgrader)setup_loggingYAMUXMPLEX   c                b    | j                         }|t        t        fvrt        d|  d      |ay)z
    Set the default multiplexer protocol to use.

    :param muxer_name: Either "YAMUX" or "MPLEX"
    :raise ValueError: If an unsupported muxer name is provided
    Unknown muxer: . Use 'YAMUX' or 'MPLEX'.N)upperMUXER_YAMUXMUXER_MPLEX
ValueErrorDEFAULT_MUXER)
muxer_namemuxer_uppers     2/Users/sumanjeet/code/py-libp2p/libp2p/__init__.pyset_default_muxerrN      s9     ""$K;44?:,6OPQQM    c                   | j                   }|dk(  rt        |t              sJ |j                         }t        j                  j                  |      }|j                  t        j                  j                  t        j                  j                  t        j                               }t        j                  j                  j                   j#                  |       y	 t%        d|       )ab  
    Persist a private key to disk in PEM format.

    Currently supports only Ed25519 keys. Writes the key to a predefined
    path for later retrieval.

    :param key_pair: KeyPair object containing private and public keys.
    :param type: Type of key to save (default: "ed25519").
    :raises ValueError: if an unsupported key type is provided.
    r   encodingformatencryption_algorithmunsupported key type: N)private_key
isinstancer   to_bytesr   from_private_bytesprivate_bytesr   EncodingPEMPrivateFormatPKCS8NoEncryptionlibp2putilspathsED25519_PATHwrite_bytesrI   )key_pairtypepvt_keyraw
crypto_keypems         rM   save_keypairrk      s     ""G
g'899""$C 22EEcJJ**&//33$2288%2%?%?%A + C LL++77<5dV<==rO   c                (   | dk(  rt         j                  j                  j                  }|j	                         sy|j                         }t        j                  |d      }t        |t        j                        sJ |j                  t        j                  j                  t        j                  j                  t        j                               }t        j                   |      }|j#                         }t%        ||      S 	 t'        d|        )aJ  
    Load a private key from disk and reconstruct its KeyPair.

    Currently supports only Ed25519 keys. Returns None if the key file does
    not exist.

    :param type: Type of key to load (default: "ed25519").
    :return: KeyPair object if found, or None.
    :raises ValueError: if an unsupported key type is provided.
    r   N)passwordrQ   rU   )r`   ra   rb   rc   exists
read_bytesr   load_pem_private_keyrW   r   r   rZ   r[   Rawr]   r_   
from_bytesget_public_keyr   rI   )rf   pathrj   ri   rh   rg   pub_keys          rM   load_keypairrv      s     <<%%22D;;=//#C&;;J
 j'*C*CDD**&//33$2266%2%?%?%A + C (2237G,,.G7G,,5dV<==rO   c                     t         S )z_
    Returns the currently selected default muxer.

    :return: Either "YAMUX" or "MPLEX"
    )rJ    rO   rM   get_default_muxerry      s
     rO   c                 R    t        t              t        t        t              t        iS )zn
    Returns muxer options with Yamux as the primary choice.

    :return: Muxer options with Yamux first
    )r!   YAMUX_PROTOCOL_IDr<   r:   r;   rx   rO   rM   create_yamux_muxer_optionr|      $     	#$e#$e rO   c                 R    t        t              t        t        t              t        iS )zn
    Returns muxer options with Mplex as the primary choice.

    :return: Muxer options with Mplex first
    )r!   r:   r;   r{   r<   rx   rO   rM   create_mplex_muxer_optionr      r}   rO   c                     t               S N)create_new_rsa_key_pairrx   rO   rM   generate_new_rsa_identityr     s    "$$rO   c                     t               S )z
    Generate a new Ed25519 identity key pair.

    Ed25519 is preferred for better interoperability with other libp2p implementations
    (e.g., Rust, Go) which often disable RSA support.
    )create_new_ed25519_key_pairrx   rO   rM   generate_new_ed25519_identityr     s     '((rO   c                D    | j                   }t        j                  |      S r   )
public_keyr(   from_pubkey)re   r   s     rM   generate_peer_id_fromr     s    $$J>>*%%rO   c                 <    t         dk(  r
t               S t               S )z
    Returns the default muxer options based on the current default muxer setting.

    :return: Muxer options with the preferred muxer first
    rA   )rJ   r   r|   rx   rO   rM   get_default_muxer_optionsr     s     (**(**rO   c                x   |t        |      S ||nt        }g }|rot               }|D ]5  }|j                         D cg c]  }|j                   }}d}d|v rd|vrd|vrt               }nd|v sd|v r.| t        j                  d       d || j                  |	|      }nd|v sd|v rd	d
l	m
}  |||
|      }nkd|v r2d	dlm} | t        j                  d        || j                        }n5d|v r1d	dlm} | t        j                  d        || j                        }|t        |      }||vs|j!                  |       |j#                  |       8 |r(t%        d |D              s || j                  |	|      g}|s|r$|j#                   || j                  |	|             |r d	d
l	m
} |j#                   |||
|             |r@d	dlm} | t        j                  d       n"|j#                   || j                               |s|s|j#                  t                      |S c c}w )u[  
    Build the ordered list of transports for the Swarm's TransportManager.

    Priority:
    1. Explicit ``transports`` list — used as-is (highest priority).
    2. ``listen_addrs`` inspection — auto-detects which transports are needed
       by inspecting **every** address (not just the first one).
    3. ``enable_*`` flags — coarse-grained control when no addresses given.
    4. Default fallback: TCP only.

    :param key_pair: The host's key pair (needed by QUIC for TLS).
    :param listen_addrs: The multiaddrs the host will listen on.
    :param transports: Explicit transport list, or ``None`` to auto-build.
    :param enable_quic: Whether to create a QUIC transport when auto-building.
    :param enable_webrtc: Whether to create a WebRTC transport when auto-building.
    :param enable_tcp: Whether to include a TCP transport when auto-building.
    :param enable_websocket: Whether to include a WebSocket transport.
    :param enable_autotls: Whether to enable AutoTLS in QUIC/WebSocket transports.
    :param upgrader: The upgrader passed to WebSocket transport at construction.
    :param quic_config: Optional QUIC transport configuration.
    :param tls_client_config: TLS client context for WebSocket.
    :param tls_server_config: TLS server context for WebSocket.
    :returns: Ordered list of :class:`~libp2p.abc.ITransport` instances.
    Ntcpwswssquiczquic-v1z.QUIC transport requires key_pair (private_key))configenable_autotlsr   )WebsocketTransport)tls_client_configtls_server_configzwebrtc-direct)WebRTCDirectTransportz0WebRTC transport requires key_pair (private_key))rV   webrtc)WebRTCPrivateTransportc              3  L   K   | ]  }t        |      j                  d k(    yw)r   N)rf   __name__).0ts     rM   	<genexpr>z._build_transports_for_swarm.<locals>.<genexpr>  s     "W147#3#3#F"Ws   "$)listr   set	protocolsnamer=   loggerwarningrV   $libp2p.transport.websocket.transportr   !libp2p.transport.webrtc.transportr   )libp2p.transport.webrtc.private_transportr   rf   addappendany)re   listen_addrs
transportsenable_quicenable_webrtc
enable_tcpenable_websocketr   upgraderquic_configr   r   
quic_class_QUICTransportresultseen_classesaddrpr   transport_objr   r   r   clss                           rM   _build_transports_for_swarmr      sT   R J $.#9Z}N!F"%%  ,	-D)-)9:A:I:/3M	!d)&;Y@V #9$	Y(>#NN#ST .((&#1!
 "ey&8S 2&7&7!
 !I-S#NN#UV 5(BVBV WY&\#NN#UV 68CWCW X$}%C,&  %m,Y,	-b s"WPV"WW((&#1F MM((&#1 OMM"&7&7 OQR3@T@TUVVMM#% Mo ;s   H7FTc                6   | 
t               } t        |       }t        |t              r|nd}t	               }|xst t
        t        | |j                        t        t        | |	      t        t        j                        t        j                  |       t        t              t        | |      i}|0|j!                         }|t"        t$        fvrt'        d| d      |}nt(        }||}n|t$        k(  rt+               }n
t-               }t/        ||      }t1        | |||||
||	||||t2              }t4        j7                  d	|D cg c]  }t9        |      j:                   c}       |xs
 t=               }|j?                  ||        d}i } |rd
dl m!}! i }"|D ]  }#	 |#jE                         D $ch c]  }$|$jF                   }%}$d|%vr0|#jI                  d      xs |#jI                  d      }&|#jI                  d      }'|&|'jtK        |&      tM        |'      f}(|"jO                  |(g       jQ                  |%        |"jU                         D ]W  \  \  })}*}+tW        d |+D              },tW        d |+D              }-|,s0|-s3 |!|)|*      | |)|*f<   t4        j7                  d|)|*       Y d
dl,m-}.  |.|       }/t]        ||||||||||/
      }0|	 d
dl/m0}1  |1       }||0jc                  |       |0S c c}w c c}$w # tR        $ r Y lw xY w# tR        $ r d}Y <w xY w)uN  
    Create a swarm instance with multi-transport support.

    The swarm can listen on and dial over multiple transports simultaneously
    (TCP, WebSocket, QUIC), mirroring go-libp2p's architecture.

    Transport selection priority (highest to lowest):

    1. **Explicit ``transports`` list** — used as-is; all other transport
       parameters are ignored.
    2. **``listen_addrs`` inspection** — each address is inspected to determine
       which transports are needed (TCP, WebSocket, QUIC).  All detected
       transport types are created and registered.
    3. **``enable_*`` flags** — coarse-grained control when no addresses are
       provided (``enable_quic``, ``enable_websocket``, ``enable_tcp``).
    4. **Default fallback** — TCP only.

    :param key_pair: optional choice of the ``KeyPair``
    :param muxer_opt: optional choice of stream muxer
    :param sec_opt: optional choice of security upgrade
    :param peerstore_opt: optional peerstore
    :param muxer_preference: optional explicit muxer preference (``"YAMUX"`` or
        ``"MPLEX"``)
    :param listen_addrs: optional list of multiaddrs to listen on.  **All**
        addresses are inspected to determine which transports to create.
    :param transports: explicit list of transport instances to register.  When
        provided, all ``enable_*`` flags and ``listen_addrs``-based detection
        are bypassed.
    :param enable_quic: include a QUIC transport when auto-building (deprecated;
        prefer passing ``listen_addrs`` with QUIC addresses or ``transports``).
    :param enable_autotls: enable AutoTLS for QUIC / WebSocket transports.
    :param enable_tcp: include a TCP transport when auto-building (default True).
    :param enable_websocket: include a WebSocket transport when auto-building.
    :param retry_config: optional connection retry configuration.
    :param connection_config: optional connection configuration.
    :param tls_client_config: TLS client context for WebSocket transport.
    :param tls_server_config: TLS server context for WebSocket transport.
    :param resource_manager: optional resource manager for connection/stream limits.
    :param psk: optional pre-shared key for PSK encryption.
    :return: a Swarm instance implementing INetworkService.

    Examples::

        # TCP only (default)
        swarm = new_swarm()

        # TCP + WebSocket + QUIC auto-detected from listen_addrs
        swarm = new_swarm(listen_addrs=[
            Multiaddr("/ip4/0.0.0.0/tcp/4001"),
            Multiaddr("/ip4/0.0.0.0/tcp/4002/ws"),
            Multiaddr("/ip4/0.0.0.0/udp/4003/quic-v1"),
        ])

        # Explicit transport list
        swarm = new_swarm(transports=[TCP(), QUICTransport(kp.private_key)])

    Note: Yamux (/yamux/1.0.0) is the preferred stream multiplexer
          due to its improved performance and features.
          Mplex (/mplex/6.7.0) is retained for backward compatibility
          but may be deprecated in the future.

    Note: Ed25519 keys are used by default for better interoperability with
          other libp2p implementations (Rust, Go) which often disable RSA support.
    N)noise_privkey)r   )	peerstorerD   rE   )secure_transports_by_protocolmuxer_transports_by_protocol)re   r   r   r   r   r   r   r   r   r   r   r   r   znew_swarm: using transports: %sr   r	   r   ip4ip6c              3  0   K   | ]  }d |vxr d|v  ywr   r   Nrx   r   pss     rM   r   znew_swarm.<locals>.<genexpr>w  s%       79B25?2    c              3  0   K   | ]  }d |v xs d|v   ywr   rx   r   s     rM   r   znew_swarm.<locals>.<genexpr>z  s      Hr2u{2Hr   z:new_swarm: created PortDemultiplexer for shared port %s:%d)TransportManager)port_demuxers)r   retry_configconnection_configpskmetric_send_channel	event_bustransport_managernew_resource_manager)2r   r   rW   r   create_new_x25519_key_pairNOISE_PROTOCOL_IDNoiseTransportrV   TLS_PROTOCOL_IDr9   r!   secior(   r8   r5   r6   rF   rG   rH   rI   rJ   r   r|   r>   r   r   r   debugrf   r   r)   add_key_pairlibp2p.transport.cmuxr
   r   r   value_for_protocolstrint
setdefaultr   	Exceptionitemsr   libp2p.transport.managerr   r%   libp2p.rcmgrr   set_resource_manager)2re   	muxer_optsec_optpeerstore_optmuxer_preferencer   r   r   r   r   r   r   r   r   r   r   resource_managerr   r   r   id_optquic_transport_optnoise_key_pairr   	temp_prefactive_preferencer   r   transport_listr   r   
port_demuxr   _ConnMgrport_protosr   r   protoshost_valport_valkeyhostport
proto_setshas_plain_tcphas_wsr   r   swarm_new_rms2                                                     rM   	new_swarmr     s   r  12"8,F.89JL_.`*fj 01N KR K>N$>$>
 	~
 	%((U__X6'(*;+
V! #$**,	[+66!"2!33LM  &) '0$++D+F(+D+F( &C%AH 1!#)%&++ N LL)#12aa		2
 ,I68, J>@MG >@  	D*...*:;Q!&&;;&++E2 6..u5   2259#x'78}c(m4&&sB/66v>	$ )4(9(9(; 	$LT4*  =G  M HZHHF.6tT.BtTl+P	 :(}E!!+/+E 	$D&y #""#34La 	3* <  R  	$#	$sH   K0
K:0K5K:
9K:7K:L
 5K::	LL
LLg      $@   c                   |s|t         j                  d       t               }d\  }}|
r2t        j                  d      \  }}|j                  t        |             |	 ddlm}  |       }|r||} n|} t        di d|d|d	| d
|d|d|d|	d|d|d| d|d|d|d|d|d|d|d|d|}!|t        |!||||||||||      S t        |!|||||||||||      S # t        $ r d}Y w xY w)u`	  
    Create a new libp2p host based on the given parameters.

    The host can listen on and dial over multiple transports simultaneously
    (TCP, WebSocket, QUIC), mirroring go-libp2p's architecture.

    Transport selection priority (highest to lowest):

    1. ``transports`` — explicit list, used as-is.
    2. ``listen_addrs`` inspection — all addresses are inspected.
    3. ``enable_*`` flags.
    4. Default: TCP only.

    :param key_pair: optional choice of the ``KeyPair``
    :param muxer_opt: optional choice of stream muxer
    :param sec_opt: optional choice of security upgrade
    :param peerstore_opt: optional peerstore
    :param disc_opt: optional discovery
    :param muxer_preference: optional explicit muxer preference
    :param listen_addrs: optional list of multiaddrs to listen on.  **All**
        addresses are inspected to determine which transports to create.
    :param enable_mDNS: whether to enable mDNS discovery
    :param bootstrap: optional list of bootstrap peer addresses as strings
    :param enable_quic: optional choice to use QUIC for transport
    :param enable_autotls: optional choice to use AutoTLS for security
    :param quic_transport_opt: optional configuration for quic transport
    :param tls_client_config: optional TLS client configuration for WebSocket transport
    :param tls_server_config: optional TLS server configuration for WebSocket transport
    :param resource_manager: optional resource manager for connection/stream limits
    :type resource_manager: :class:`libp2p.rcmgr.ResourceManager` or None
    :param psk: optional pre-shared key (PSK)
    :param bootstrap_allow_ipv6: if True, bootstrap accepts IPv6+TCP addresses
    :param bootstrap_dns_timeout: DNS resolution timeout in seconds per attempt
    :param bootstrap_dns_max_retries: max DNS resolution retries with backoff
    :param connection_config: optional connection configuration for connection manager
    :param announce_addrs: if set, these replace listen addrs in get_addrs()
    :param transports: explicit list of transport instances to register.  When
        provided, all ``enable_*`` flags and ``listen_addrs``-based detection
        are bypassed.
    :param enable_tcp: include a TCP transport when auto-building (default True).
    :param enable_websocket: include a WebSocket transport when auto-building.
    :return: return a host instance
    Nz?QUIC config provided but QUIC not enabled, ignoring QUIC config)NNd   r   r   r   r   re   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )networkrouterenable_mDNSenable_upnp	bootstrapr   r   bootstrap_allow_ipv6bootstrap_dns_timeoutbootstrap_dns_max_retriesannounce_addrs)r  r  r  r  negotiate_timeoutr   metric_recv_channelr   r  r  r  r	  rx   )r   r   r   trioopen_memory_channelregister_listenerr   r   r   r   r   r$   r#   )"re   r   r   r   disc_optr   r   r  r  r   enable_metricsr  r
  r   r   r   r   r   r   r   r  r  r  r   r	  r   r   r   r   r   r  r   effective_configr   s"                                     rM   new_hostr    s   X -9XY 
I 0:,,373K3KC3P00##$9:M$NO 	$D&y )5-, #  	
  $ & * " + , , *  0  !$ %& '( *)E. ##-!5"7&?)
 	
 +)/13";% c  	$#	$s    C' 'C54C5r`   )rK   zLiteral['YAMUX', 'MPLEX']returnNone)re   r   rf   r   r  r  )rf   r   r  KeyPair | None)r  r   )r  r    )r  r   )re   r   r  r(   r   )re   r   r   $Sequence[multiaddr.Multiaddr] | Noner   Sequence[ITransport] | Noner   boolr   r  r   r  r   r  r   r  r   r>   r   QUICTransportConfig | Noner   ssl.SSLContext | Noner   r  r   ztype | Noner  zlist[ITransport])NNNNNNNFFFTFNNNNNNNN)*re   r  r   TMuxerOptions | Noner   TSecurityOptions | Noner   IPeerStore | Noner    Literal['YAMUX', 'MPLEX'] | Noner   r  r   r  r   r  r   r  r   r  r   r  r   r  r   zRetryConfig | Noner   z-ConnectionConfig | QUICTransportConfig | Noner   r  r   r  r   ResourceManager | Noner   
str | Noner   z"trio.MemorySendChannel[Any] | Noner   zEventBus | Noner  r   ):re   r  r   r  r   r  r   r  r  zIPeerRouting | Noner   r  r   r  r  r  r  r  r   r  r  r  r  zlist[str] | Noner
  r   r   r  r   r  r   r  r   r  r   r  r   r  r   r   r  r  r  floatr  r   r   zConnectionConfig | Noner	  r  r   r  r   r  r   r  r  r   )__doc__
__future__r   loggingpathlibr   sslr  libp2p.transport.quic.utilsr   typingr   r   r   r   r
   )cryptography.hazmat.primitives.asymmetricr   cryptography.hazmat.primitivesr   libp2p.transport.quic.transportr   libp2p.transport.quic.configr   collections.abcr   r   importlib.metadatar   	__versionr   r   	multiaddr
libp2p.abcr   r   r   r   r   r   libp2p.eventsr   r   r   r   libp2p.crypto.keysr   libp2p.crypto.ed25519r   r   r   libp2p.crypto.rsar   libp2p.crypto.x25519r   libp2p.custom_typesr    r!   r"   libp2p.host.basic_hostr#   libp2p.host.routed_hostr$   libp2p.network.swarmr%   libp2p.network.configr&   r'   libp2p.peer.idr(   libp2p.peer.peerstorer)   r*   libp2p.peer.persistentr+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r`   "libp2p.security.insecure.transportr5   r6   libp2p.security.noise.transportr7   r   r8   r   libp2p.security.tls.transportr   r9   libp2p.security.secio.transportsecurityr   	transportlibp2p.stream_muxer.mplex.mplexr:   r;   libp2p.stream_muxer.yamux.yamuxr{   r<   libp2p.transport.tcp.tcpr=   libp2p.transport.upgraderr>   libp2p.utilslibp2p.utils.loggingr?   libp2p.utils.pathsrJ   rG   rH   DEFAULT_NEGOTIATE_TIMEOUT	getLoggerr   r   rN   rk   rv   ry   r|   r   r   r   r   r   r   r   r  __version__rx   rO   rM   <module>rO     s   # "   
  9 + +7 = 8 9 < 4
   ) S 
   
 0 /      			8	$ ><%>P		%)&
	+2 #KK6K ,K 	K
 K K K K  K ,K -K -K K K^  $&*'+'+9=9=.2 "'+GK/3/3/3>B!%/ss#s %s %	s
 7s 7s ,s s s s s s  %!s" E#s$ -%s& -'s( -)s* 
+s, <-s. /s0 1sn  $&*'+'+$(9=9=  "&659/3/3/3!&#'%&15;?.2"=aa#a %a %	a
 "a 7a 7a a a a a  a a a a  3!a" -#a$ -%a& -'a( 
)a* +a, !-a.  #/a0 /1a2 93a6 ,7a: ;a< =a> ?aF !rO   