§
    ›Çjœ  ã                  ó$  — d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
mZmZ dZdZ G d„ de¦  «        Z G d	„ d
e¦  «        Z G d„ d¦  «        Z G d„ d¦  «        Z G d„ de¦  «        Z G d„ d¦  «        Zd„ Zd„ Zdddddœd%d$„ZdS )&uÎ  The connection to Juggler: the pipe, with no Node in between.

THE CONTRACT, read from `juggler/pipe/nsRemoteDebuggingPipe.cpp` and not
guessed:

  - messages are JSON delimited by a ZERO BYTE, not a newline
    (`ReaderLoop` accumulates until it finds `'\0'`);
  - on POSIX the descriptors are **hardwired to 3 and 4**: `const int
    readFD = 3; const int writeFD = 4;`. They are not negotiated;
  - on Windows there are NO descriptors: they are HANDLEs read from the
    environment, `GetEnvironmentVariableA("PW_PIPE_READ", ...)` plus
    `atoi`, so the value must be passed in DECIMAL and the handle must be
    made inheritable;
  - the names are from the BROWSER's point of view: its `PW_PIPE_READ` is
    what IT reads from, i.e. where WE write.

â›” And the flag `-juggler-pipe` must appear on the command line, or on
Windows the handles never get armed at all and the pipe breaks at the
launcher -> parent transition.

â›” THE READINESS SIGNAL DOES NOT TRAVEL OVER THE PIPE. The browser prints
`Juggler listening to the pipe` on stdout, and that line comes out of a
`dump()` that a `MOZILLA_OFFICIAL` build disables: a disabled `dump()`
RETURNS SUCCESSFULLY without writing. The fix lives in the Firefox source
(`30-upstream-playwright-patches.md`), not here. Anyone reading a long
timeout at launch should look there first.

State: first piece. Opens the connection, sends commands, receives
responses and events. Not yet a client: no lifecycle, no frames, no
actionability.
é    )ÚannotationsN)ÚAnyÚCallableÚOptionaló    zJuggler listening to the pipec                  ó   — e Zd ZdZdS )ÚProtocolErroru   The browser refused a command. Carries its message, not ours.

    â›” `checkScheme` is CLOSED WORLD: an undeclared field is not ignored,
    it is rejected, and it happens at RUNTIME. The browser's message is
    the only thing that says which field.
    N©Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    úYC:\Projects\Historical\venv\Lib\site-packages\invisible_playwright/_juggler/connection.pyr	   r	   .   s   € € € € € ðð ð ð r   r	   c                  ó   — e Zd ZdZdS )ÚTargetClosedErroruñ  The thing a call was aimed at is gone: a disposed object, or the
    browser itself, whose pipe has closed.

    â›” THE CLASS NAME IS THE CONTRACT, not decoration. `reply_error` puts
    `type(failure).__name__` in the error payload, and `_helper.parse_error`
    turns that exact string into the fork's `TargetClosedError` on the client
    - which is the ONLY thing `_page.py`'s `close()` swallows:

        except Exception as e:
            if is_target_closed_error(e): return

    Anything else propagates. So closing a page whose context was closed first
    - `context.close()` cascades, then a fixture teardown calls `page.close()`,
    which is an ordinary shape and not a misuse - raised a hard error here on
    2026-08-28, the day closed pages started being disposed at all.

    â›” AND IT LIVES HERE, ONE LAYER DOWN FROM WHERE IT WAS BORN, BECAUSE A
    CLOSED PIPE IS A CLOSED TARGET TOO. Until 0.15.0 the dispatcher raised
    this for a disposed guid, while the connection answered a pipe that had
    closed with a nameless error - `the pipe closed`, `the pipe is closed` -
    which `parse_error` turned into the fork's plain `Error`. The same fact,
    the browser is gone, reached a caller as two different classes, and the
    caller that had to tell "the page refused" from "the browser died" (the
    AIHawk server's retry) was reduced to matching the sentences. Measured
    2026-09-14. One class, raised by both layers, and exported from the
    public API so a caller can catch the TYPE.
    Nr
   r   r   r   r   r   7   s   € € € € € ðð ð ð r   r   c                  ó8   — e Zd ZdZdZdd„Zdd„Zdd
„Zddd„ZdS )ÚProcessOutputu‘  The browser's stdout and stderr, read for the WHOLE life of the process
    by ONE reader, keeping the last lines.

    â›” WHY IT EXISTS, measured on 2026-09-25 ([B229]). The two streams go into
    one pipe, and it used to be read only until the readiness line and never
    again. A pipe has a fixed buffer - the Windows default, since it is created
    with size 0 - so once Firefox had written a buffer's worth after startup,
    its next write BLOCKED, and so did whichever of its threads was writing.
    Forced with `devtools.console.stdout.content`: a page logging 2 KB still
    answered, one logging 8 KB never answered again, with 5085 bytes sitting
    unread in the pipe. The browser stayed alive and silent, with no error
    anywhere. Ordinary browsing on Windows writes little (76 bytes over ten
    real sites), which is why it went unseen: it is a clock that runs out in
    long sessions, on Linux where GTK and fontconfig talk, or with any log on.

    â›” ONE READER, NOT A SECOND ONE ADDED AFTER THE FIRST. Readiness is a
    question asked of this object (`wait_for_ready`), not a loop of its own on
    the same stream: two readers of one pipe split its lines between them.

    The kept lines are the only account of why a browser stopped. They were
    already what a failed STARTUP printed; now the same lines are there when
    the pipe closes in the middle of a session (`Connection.send`).
    éÈ   ÚreturnÚNonec                ó  — dd l }|| _        |                     | j        ¬¦  «        | _        t          j        ¦   «         | _        d| _        d| _	        t          j
        | j        dd¬¦  «        | _        | j                             ¦   «          d S )Nr   )ÚmaxlenFTzbrowser-output)ÚtargetÚdaemonÚname)ÚcollectionsÚ_streamÚdequeÚKEEPÚ_linesÚ	threadingÚ	ConditionÚ_cvÚ_readyÚ_eofÚThreadÚ_pumpÚ_threadÚstart)ÚselfÚstreamr   s      r   Ú__init__zProcessOutput.__init__p   s‰   € ØÐÐÐØˆŒØ!×'Ò'¨t¬yÐ'Ñ9Ô9ˆŒÝÔ&Ñ(Ô(ˆŒØˆŒØˆŒ	Ý Ô'¨t¬zÀ$Ø-=ð?ñ ?ô ?ˆŒàŒ×ÒÑÔÐÐÐr   c                ó¸  — 	 t          | j        j        d¦  «        D ]¡}|                     dd¦  «                             d¦  «        }| j        5  |                     ¦   «         r| j                             |¦  «         t          |v rd| _
        | j                             ¦   «          d d d ¦  «         n# 1 swxY w Y   Œ¢n# t          t          f$ r Y nw xY w| j        5  d| _        | j                             ¦   «          d d d ¦  «         d S # 1 swxY w Y   d S # | j        5  d| _        | j                             ¦   «          d d d ¦  «         w # 1 swxY w Y   w xY w)Nr   úutf-8Úreplacez
T)Úiterr   ÚreadlineÚdecodeÚrstripr%   Ústripr"   ÚappendÚ_READYr&   Ú
notify_allÚOSErrorÚ
ValueErrorr'   )r,   ÚrawÚtexts      r   r)   zProcessOutput._pump{   s#  € ð	&Ý˜DœLÔ1°3Ñ7Ô7ð *ð *�Ø—z’z '¨9Ñ5Ô5×<Ò<¸VÑDÔD�Ø”Xð *ð *Ø—z’z‘|”|ð 1Øœ×*Ò*¨4Ñ0Ô0Ð0Ý �~�~Ø&*˜œØ”H×'Ò'Ñ)Ô)Ð)ð*ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *øð*øõ �Ð$ð 	ð 	ð 	ØˆDð	øøøð ”ð &ð &Ø �”	Ø”×#Ò#Ñ%Ô%Ð%ð&ð &ð &ñ &ô &ð &ð &ð &ð &ð &ð &ð &øøøð &ð &ð &ð &ð &ð &ø�”ð &ð &Ø �”	Ø”×#Ò#Ñ%Ô%Ð%ð&ð &ð &ñ &ô &ð &ð &ð &ð &ð &ð &øøøð &ð &ð &ð &ð &øøøs…   ‚AB? ÁAB2Â&B? Â2B6	Â6B? Â9B6	Â:B? Â>D Â?CÃD ÃCÃD Ã!DÄDÄDÄEÄ !EÅEÅEÅEÅEÅEÚtimeoutÚfloatÚboolc                óB  — t          j        ¦   «         |z   }| j        5  | j        sÛ| j        sÔ|                     ¦   «         �mt          j        ¦   «         dz   }| j        sOt          j        ¦   «         |k     r8| j                             d¦  «         | j        st          j        ¦   «         |k     °8nS|t          j        ¦   «         z
  }|dk    rn6| j                             t          |d¦  «        ¦  «         | j        s| j        ¯Ô| j        cddd¦  «         S # 1 swxY w Y   dS )a  True when the readiness line arrived within `timeout`. False when it
        did not, or when the process exited first - in which case whatever it
        managed to print is drained before answering, because the last line
        before an exit is usually the one that says why.Ng      ð?çš™™™™™©?r   )ÚtimeÚ	monotonicr%   r&   r'   ÚpollÚwaitÚmin)r,   Úprocessr>   ÚdeadlineÚdrainÚlefts         r   Úwait_for_readyzProcessOutput.wait_for_readyŒ   s\  € õ
 ”>Ñ#Ô# gÑ-ˆØŒXð 	ð 	Ø”kð 	/¨$¬)ð 	/Ø—<’<‘>”>Ð-Ý œNÑ,Ô,¨sÑ2�EØ"œið ,­D¬NÑ,<Ô,<¸uÒ,DÐ,DØœŸš dÑ+Ô+Ð+ð #œið ,­D¬NÑ,<Ô,<¸uÒ,DÐ,DàØ¥$¤.Ñ"2Ô"2Ñ2�Ø˜1’9�9ØØ”—’�c $¨™oœoÑ.Ô.Ð.ð ”kð 	/¨$¬)ð 	/ð ”;ð	ð 	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s   žC)DÄDÄDé   ÚnÚintÚlistc                ó~   — | j         5  t          | j        ¦  «        | d …         cd d d ¦  «         S # 1 swxY w Y   d S ©N)r%   rP   r"   )r,   rN   s     r   ÚtailzProcessOutput.tailŸ   s†   € ØŒXð 	*ð 	*Ý˜œÑ$Ô$ a R S SÔ)ð	*ð 	*ð 	*ð 	*ñ 	*ô 	*ð 	*ð 	*ð 	*ð 	*ð 	*ð 	*øøøð 	*ð 	*ð 	*ð 	*ð 	*ð 	*s   ˆ2²6¹6N©r   r   )r>   r?   r   r@   )rM   )rN   rO   r   rP   )	r   r   r   r   r!   r.   r)   rL   rS   r   r   r   r   r   U   sz   € € € € € ðð ð0 €Dð	ð 	ð 	ð 	ð&ð &ð &ð &ð"ð ð ð ð&*ð *ð *ð *ð *ð *ð *r   r   c                  ó2   — e Zd ZdZdd„Zdd„Zdd„Zdd„ZdS )ÚEventListenersu¯  Who is subscribed to a connection's events, and how one is delivered.

    â›” ONE IMPLEMENTATION, USED BY THE REAL CONNECTION AND BY THE FAKES. The
    tests stand a stub connection in front of `Lifecycle` and `InjectedScript`,
    and if that stub carried its own idea of what subscribing means, the tests
    would be measuring the stub. Inheriting it is what makes a green test say
    something about the code that ships.
    r   r   c                óR   — g | _         t          j        ¦   «         | _        g | _        d S rR   )Ú
_listenersr#   ÚLockÚ_listeners_lockÚhandler_errors)r,   s    r   r.   zEventListeners.__init__®   s+   € ð$ !#ˆŒÝ(œ~Ñ/Ô/ˆÔð %'ˆÔÐÐr   c                óŒ   — | j         5  || j        vr| j                             |¦  «         ddd¦  «         dS # 1 swxY w Y   dS )zÍSubscribe to every event. Registering twice is a no-op, not two
        deliveries: a handler called twice for one event announces a frame
        twice, and that reads as the browser having sent it twice.N)rZ   rX   r7   ©r,   Úfns     r   Úadd_listenerzEventListeners.add_listenerÊ   s”   € ð Ô!ð 	+ð 	+Ø˜œÐ(Ð(Ø”×&Ò& rÑ*Ô*Ð*ð	+ð 	+ð 	+ñ 	+ô 	+ð 	+ð 	+ð 	+ð 	+ð 	+ð 	+ð 	+øøøð 	+ð 	+ð 	+ð 	+ð 	+ð 	+s   ˆ$9¹=Á =c                óž   — | j         5  	 | j                             |¦  «         n# t          $ r Y nw xY wddd¦  «         dS # 1 swxY w Y   dS )u#  Unsubscribe. â›” CALLING THIS IS NOT OPTIONAL HOUSEKEEPING: it is
        the half of the fix that keeps the list from growing without bound,
        and a subscriber that forgets it leaks for the life of the browser -
        which is the defect this registry exists to close, reintroduced.N)rZ   rX   Úremover;   r]   s     r   Úremove_listenerzEventListeners.remove_listenerÒ   s¯   € ð
 Ô!ð 	ð 	ðØ”×&Ò& rÑ*Ô*Ð*Ð*øÝð ð ð Ø�ðøøøð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	s,   ˆAŠ%¤A¥
2¯A±2²AÁAÁ	AÚmethodÚstrÚparamsÚdictÚsessionúOptional[str]c                ó.  — | j         5  t          | j        ¦  «        }ddd¦  «         n# 1 swxY w Y   |D ]^}	  ||||¦  «         Œ# t          $ rA}t	          | j        ¦  «        dk     r| j                             |›d|›�¦  «         Y d}~ŒWd}~ww xY wdS )u±  Deliver one event to every subscriber, iteratively.

        â›” ONE LISTENER'S FAILURE MUST NOT COST THE OTHERS THEIR EVENT. In the
        chain this replaces, a subscriber that raised took every subscriber
        BELOW it down with the same event, because the delivery to the rest
        was the last statement of the one that raised. Here each call is
        isolated: the failure is recorded and the loop carries on.
        Né    ú: )rZ   rP   rX   Ú	ExceptionÚlenr[   r7   )r,   rc   re   rg   Úsubscribersr^   Úfailures          r   Údispatch_eventzEventListeners.dispatch_eventÝ   s  € ð Ô!ð 	0ð 	0Ý˜tœÑ/Ô/ˆKð	0ð 	0ð 	0ñ 	0ô 	0ð 	0ð 	0ð 	0ð 	0ð 	0ð 	0øøøð 	0ð 	0ð 	0ð 	0àð 	Mð 	MˆBðMØ��6˜6 7Ñ+Ô+Ð+Ð+øÝð Mð Mð MÝ�tÔ*Ñ+Ô+¨bÒ0Ð0ØÔ'×.Ò.¸6¸6¸6À7À7Ð/KÑLÔLÐLøøøøøøøøøðMøøøð	Mð 	Ms#   ˆ)©-°-¹AÁ
BÁ7BÂBNrT   )rc   rd   re   rf   rg   rh   r   r   )r   r   r   r   r.   r_   rb   rp   r   r   r   rV   rV   ¤   st   € € € € € ðð ð'ð 'ð 'ð 'ð8+ð +ð +ð +ð	ð 	ð 	ð 	ðMð Mð Mð Mð Mð Mr   rV   c                  ój   ‡ — e Zd ZdZdˆ fd„	Zdd„Zdd	„Zdd„Z	 	 d d!d„Z	 	 d"d#d„Z	d$d„Z
d%d&d„Zˆ xZS )'Ú
Connectionz&A pipe to an already-launched Firefox.Nc                óŠ  •— t          ¦   «                              ¦   «          || _        || _        || _        d| _        i | _        t          j        ¦   «         | _	        t          j        ¦   «         | _
        d| _        d | _        d | _        t          j        | j        d¬¦  «        | _        | j                             ¦   «          d S )Nr   FT)r   r   )Úsuperr.   Ú_to_browserÚ_from_browserÚ_processÚ_next_idÚ_pendingr#   rY   Ú_lockÚ_write_lockÚ_closedÚ_errorÚoutputr(   Ú
_read_loopÚ_readerr+   )r,   Ú
to_browserÚfrom_browserrH   Ú	__class__s       €r   r.   zConnection.__init__ô   s©   ø€ Ý‰Œ×ÒÑÔÐØ%ˆÔØ)ˆÔØˆŒØˆŒØ)+ˆŒÝ”^Ñ%Ô%ˆŒ
õ %œ>Ñ+Ô+ˆÔØˆŒØ/3ˆŒð 04ˆŒÝ Ô'¨t¬ÀtÐLÑLÔLˆŒØŒ×ÒÑÔÐÐÐr   r   r   c           	     ó®  — d}	 | j         spt          j        | j        d¦  «        }|snS||z  }t          |v r>|                     t          d¦  «        \  }}|r|                      |¦  «         t          |v °>| j         ¯pn# t          $ r}|| _        Y d }~nd }~ww xY wd| _         | j	        5  t          | j                             ¦   «         ¦  «        }| j                             ¦   «          d d d ¦  «         n# 1 swxY w Y   |D ]3\  }}|                     ddddœi¦  «         |                     ¦   «          Œ4d S # d| _         | j	        5  t          | j                             ¦   «         ¦  «        }| j                             ¦   «          d d d ¦  «         n# 1 swxY w Y   |D ]3\  }}|                     ddddœi¦  «         |                     ¦   «          Œ4w xY w)	Nr   i   é   TÚerrorr   zthe pipe closed)r   Úmessage)r|   ÚosÚreadrv   ÚNULÚsplitÚ_deliverr:   r}   rz   rP   ry   ÚvaluesÚclearr7   Úset)r,   ÚbufferÚchunkr<   ÚeÚpendingÚreadyÚboxs           r   r   zConnection._read_loop  sµ  € Øˆð	Ø”lð +Ýœ Ô 2°EÑ:Ô:�Øð ØØ˜%‘�Ý˜V�m�mØ"(§,¢,­s°AÑ"6Ô"6‘K�C˜Øð +ØŸš cÑ*Ô*Ð*õ ˜V�m�mð ”lð +øøõ ð 	ð 	ð 	ØˆDŒKˆKˆKˆKˆKˆKøøøøð	øøøð  ˆDŒLð ”ð &ð &Ý˜tœ}×3Ò3Ñ5Ô5Ñ6Ô6�Ø”×#Ò#Ñ%Ô%Ð%ð&ð &ð &ñ &ô &ð &ð &ð &ð &ð &ð &øøøð &ð &ð &ð &ð &ð ð ‘
��sð —
’
˜GÐ.AØ1Bð&Dð &Dð Eñ Fô Fð Fà—	’	‘”��ðð øð  ˆDŒLð ”ð &ð &Ý˜tœ}×3Ò3Ñ5Ô5Ñ6Ô6�Ø”×#Ò#Ñ%Ô%Ð%ð&ð &ð &ñ &ô &ð &ð &ð &ð &ð &ð &øøøð &ð &ð &ð &ð &ð ð ‘
��sð —
’
˜GÐ.AØ1Bð&Dð &Dð Eñ Fô Fð Fà—	’	‘”��ðøøøsh   „A7A< Á;D7 Á<
BÂBÂD7 ÂBÂD7 Â(A C4Ã4C8Ã;C8Ä7GÅA FÆGÆFÆGÆFÆ:Gr<   Úbytesc                ó0  — 	 t          j        |                     d¦  «        ¦  «        }n# t          $ r Y d S w xY w|                     d¦  «        }|€X|                     d¦  «        }|r?|                      ||                     d¦  «        pi |                     d¦  «        ¦  «         d S | j        5  | j                             |d ¦  «        }d d d ¦  «         n# 1 swxY w Y   |�0|\  }}| 	                    |¦  «         | 
                    ¦   «          d S d S )Nr0   Úidrc   re   Ú	sessionId)ÚjsonÚloadsr4   rl   Úgetrp   rz   ry   Úpopr7   r�   )r,   r<   ÚmsgÚmsg_idrc   Úentryr”   r•   s           r   rŒ   zConnection._deliver*  sa  € ð	Ý”*˜SŸZšZ¨Ñ0Ô0Ñ1Ô1ˆCˆCøÝð 	ð 	ð 	ØˆFˆFð	øøøà—’˜‘”ˆØˆ>Ø—W’W˜XÑ&Ô&ˆFØð :ð& ×#Ò# F¨C¯GªG°HÑ,=Ô,=Ð,CÀØ$'§G¢G¨KÑ$8Ô$8ñ:ô :ð :àˆFØŒZð 	4ð 	4Ø”M×%Ò% f¨dÑ3Ô3ˆEð	4ð 	4ð 	4ñ 	4ô 	4ð 	4ð 	4ð 	4ð 	4ð 	4ð 	4øøøð 	4ð 	4ð 	4ð 	4àÐØ‰JˆE�3Ø�JŠJ�s‰OŒOˆOØ�IŠI‰KŒKˆKˆKˆKð Ðs   ‚'* ª
8·8Â1CÃCÃ Crd   c                ó�  — g }d}| j         �-	 | j                              ¦   «         }n# t          $ r d}Y nw xY w|�|                     d|z  ¦  «         | j        �| j                             ¦   «         ng }|r5|                     dd                     d„ |D ¦   «         ¦  «        z   ¦  «         |rdd                     |¦  «        z   ndS )zõThe exit code and the browser's last lines, when there are any.

        "the pipe is closed" alone names neither: it is what a browser that
        crashed, one that was killed and one that was closed on purpose all
        look like from here.Nzthe browser exited with code %szits last output:
ú
c              3  ó    K  — | ]	}d |z   V — Œ
dS ©z    Nr   ©Ú.0Úrs     r   ú	<genexpr>z)Connection._why_closed.<locals>.<genexpr>`  s&   è è € Ð9SÐ9SÈ¸&À1¹*Ð9SÐ9SÐ9SÐ9SÐ9SÐ9Sr   z
  Ú )rw   rE   rl   r7   r~   rS   Újoin)r,   ÚpartsÚcoderS   s       r   Ú_why_closedzConnection._why_closedO  sî   € ð ˆØˆØŒ=Ð$ðØ”}×)Ò)Ñ+Ô+��øÝð ð ð Ø���ðøøøàÐØ�LŠLÐ:¸TÑAÑBÔBÐBØ%)¤[Ð%<ˆtŒ{×ÒÑ!Ô!Ð!À"ˆØð 	UØ�LŠLÐ-°·	²	Ð9SÐ9SÈdÐ9SÑ9SÔ9SÑ0SÔ0SÑSÑTÔTÐTØ05Ð=�˜Ÿš UÑ+Ô+Ñ+Ð+¸2Ð=s   �' §6µ6ç      >@rc   re   úOptional[dict]rg   rh   r>   r?   r   c                óJ  — | j         r-t          d| j        pd›|                      ¦   «         ›�¦  «        ‚| j        5  | xj        dz  c_        | j        }g }t          j        ¦   «         }||f| j        |<   d d d ¦  «         n# 1 swxY w Y   |||pi dœ}|r||d<   |  	                    |¦  «         | 
                    |¦  «        sN| j        5  | j                             |d ¦  «         d d d ¦  «         n# 1 swxY w Y   t          d||fz  ¦  «        ‚|d         }	d|	v rq|	d         }
|
                     d	¦  «        d
k    r(t          |›d|
                     d|
¦  «        ›�¦  «        ‚t          |›d|
                     d|
¦  «        ›�¦  «        ‚|	                     d¦  «        S )Nzthe pipe is closed: r©   r…   ©r˜   rc   re   r™   ze%s: no response in %.0fs. If this is the FIRST command, look at the readiness signal before the pipe.r   r†   r   r   rk   r‡   Úresult)r|   r   r}   r­   rz   rx   r#   ÚEventry   Ú_writerF   r�   r	   rœ   )r,   rc   re   rg   r>   rŸ   r•   r”   rž   Úresponser’   s              r   ÚsendzConnection.sendd  s`  € àŒ<ð 	OÝ#Ð#Ø'+¤{Ð'8°bÐ'8¸$×:JÒ:JÑ:LÔ:LÐ:Lð%Nñ Oô Oð OàŒZð 	1ð 	1ØˆMŒM˜QÑˆMŒMØ”]ˆFð  ˆCÝ”OÑ%Ô%ˆEØ%*¨C LˆDŒM˜&Ñ!ð)	1ð 	1ð 	1ñ 	1ô 	1ð 	1ð 	1ð 	1ð 	1ð 	1ð 	1øøøð 	1ð 	1ð 	1ð 	1ð* "¨V¸v¸|ÈÐLÐLˆØð 	'Ø&ˆC�ÑØ�Š�CÑÔÐà�zŠz˜'Ñ"Ô"ð 	%Ø”ð 0ð 0Ø”×!Ò! &¨$Ñ/Ô/Ð/ð0ð 0ð 0ñ 0ô 0ð 0ð 0ð 0ð 0ð 0ð 0øøøð 0ð 0ð 0ð 0åð@à˜7Ð#ñ$ñ%ô %ð %ð �q”6ˆØ�hÐÐØ˜Ô!ˆAØ�uŠu�V‰}Œ}Ð 3Ò3Ð3Ý'°F°F°F¸A¿EºEÀ)ÈQÑ<OÔ<OÐ<OÐ(PÑQÔQÐQÝ¨F¨F¨F°A·E²E¸)ÀQÑ4GÔ4GÐ4GÐ HÑIÔIÐIØ�|Š|˜HÑ%Ô%Ð%s#   ¼9BÂBÂBÃC4Ã4C8Ã;C8c                óÌ   — | j         rdS | j        5  | xj        dz  c_        | j        }ddd¦  «         n# 1 swxY w Y   |||pi dœ}|r||d<   |                      |¦  «         dS )u¡  Send a command and do NOT wait for its reply.

        â›” THIS IS THE ONLY WAY TO SEND FROM INSIDE AN EVENT HANDLER. Handlers
        run on the reader thread, and `send` blocks until the reader thread
        delivers the reply - so a `send` from a handler waits for a message
        that only the waiting thread could receive. That is a deadlock, not a
        slowdown, and the file-chooser path already pays for it with a helper
        thread. A screencast acknowledges every frame from the handler that
        received it; a thread per frame would be absurd, and a queue would be
        a second reader. So the ack goes out here, with an id the browser
        will answer and nobody will wait for: `_deliver` drops a reply whose
        id is not pending.

        It is not for commands whose RESULT matters, and not for commands
        whose FAILURE matters either: an error reply is dropped with the rest.
        Nr…   r±   r™   )r|   rz   rx   r´   )r,   rc   re   rg   rŸ   rž   s         r   ÚpostzConnection.post’  sÆ   € ð$ Œ<ð 	ØˆFØŒZð 	#ð 	#ØˆMŒM˜QÑˆMŒMØ”]ˆFð	#ð 	#ð 	#ñ 	#ô 	#ð 	#ð 	#ð 	#ð 	#ð 	#ð 	#øøøð 	#ð 	#ð 	#ð 	#ð "¨V¸v¸|ÈÐLÐLˆØð 	'Ø&ˆC�ÑØ�Š�CÑÔÐÐÐs   ‘5µ9¼9rž   rf   c                óØ   — t          j        |¦  «                             d¦  «        t          z   }| j        5  t          j        | j        |¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )Nr0   )rš   ÚdumpsÚencoderŠ   r{   rˆ   Úwriteru   )r,   rž   Údatas      r   r´   zConnection._write®  s¤   € ÝŒz˜#‰Œ×%Ò% gÑ.Ô.µÑ4ˆØÔð 	-ð 	-ÝŒH�TÔ% tÑ,Ô,Ð,ð	-ð 	-ð 	-ñ 	-ô 	-ð 	-ð 	-ð 	-ð 	-ð 	-ð 	-ð 	-øøøð 	-ð 	-ð 	-ð 	-ð 	-ð 	-s   ·AÁA#Á&A#ç      @c                ó  — d| _         | j        | j        fD ]'}	 t          j        |¦  «         Œ# t
          $ r Y Œ$w xY w| j        }|sdS t          j        ¦   «         |z   }| 	                    ¦   «         €Vt          j        ¦   «         |k     r?t          j
        d¦  «         | 	                    ¦   «         €t          j        ¦   «         |k     °?| 	                    ¦   «         €(	 |                     ¦   «          dS # t
          $ r Y dS w xY wdS )uâ  Closes the pipe and waits for the browser to exit on its own.

        â›” Do NOT start from `terminate()`, and the reason is measured in
        this project: on Windows the pid that `Popen` returns is the
        LAUNCHER stub, which exits after about a second, so by the time
        of the kill the browser's tree is no longer its child and
        survives. Counted in one day: 88 orphaned processes.

        The clean path goes through the contract:
        `nsRemoteDebuggingPipe::ReaderLoop` calls `Disconnected` when the
        read returns zero, and Juggler shuts the browser down. Closing
        the pipe IS the exit command. `terminate()` remains only as a
        last resort, for whatever did not die on its own.
        TNrB   )r|   ru   rv   rˆ   Úcloser:   rw   rC   rD   rE   ÚsleepÚ	terminate)r,   r>   ÚfdÚprI   s        r   rÀ   zConnection.close³  s  € ð ˆŒØÔ# TÔ%7Ð8ð 	ð 	ˆBðÝ”˜‘”��øÝð ð ð Ø�ðøøøàŒMˆØð 	ØˆFÝ”>Ñ#Ô# gÑ-ˆØ�fŠf‰hŒhÐ¥4¤>Ñ#3Ô#3°hÒ#>Ð#>ÝŒJ�tÑÔÐð �fŠf‰hŒhÐ¥4¤>Ñ#3Ô#3°hÒ#>Ð#>à�6Š6‰8Œ8ÐðØ—’‘”���øÝð ð ð Ø��ðøøøð Ðs   ™.®
;º;ÃC4 Ã4
DÄDrR   rT   )r<   r–   r   r   )r   rd   )NNr®   )
rc   rd   re   r¯   rg   rh   r>   r?   r   r   )NN)rc   rd   re   r¯   rg   rh   r   r   )rž   rf   r   r   )r¾   )r>   r?   r   r   )r   r   r   r   r.   r   rŒ   r­   r¶   r¸   r´   rÀ   Ú__classcell__)rƒ   s   @r   rr   rr   ñ   sð   ø€ € € € € Ø0Ð0ðð ð ð ð ð ð2ð ð ð ð:#ð #ð #ð #ðJ>ð >ð >ð >ð* :>Ø=Að,&ð ,&ð ,&ð ,&ð ,&ð\ :>Ø&*ðð ð ð ð ð8-ð -ð -ð -ð
ð ð ð ð ð ð ð ð r   rr   c                  óB   — e Zd ZdZdZdd„Zd	„ Zdd„Zddd„Zdd„Z	e	Z
dS )Ú_WindowsProcessas  The four things `launch` and `Connection.close` ask of a process,
    over a raw process handle.

    It exists because `subprocess.Popen` cannot name the DESKTOP a process is
    created on: CPython's `STARTUPINFO` carries `dwFlags`, `wShowWindow`, the
    three std handles and `lpAttributeList`, and nothing else - `lpDesktop`
    is not reachable from it. The hidden-desktop launch needs exactly that
    field, so the spawn below calls `CreateProcessW` itself and this is the
    handle it gives back, with the same surface the Popen used to have:
    `pid`, `poll()`, `returncode`, `wait()`, `terminate()`, `stdout`.
    i  ÚhandlerO   Úpidr   r   c                ó>   — || _         || _        || _        d | _        d S rR   )Ú_handlerÉ   ÚstdoutÚ
returncode)r,   rÈ   rÉ   rÌ   s       r   r.   z_WindowsProcess.__init__æ  s"   € ØˆŒØˆŒØˆŒØ)-ˆŒˆˆr   c                ó8   — dd l }|                     dd¬¦  «        S )Nr   Úkernel32T©Úuse_last_error)ÚctypesÚWinDLL)r,   rÒ   s     r   Ú	_kernel32z_WindowsProcess._kernel32ì  s!   € ØˆˆˆØ�}Š}˜Z¸ˆ}Ñ=Ô=Ð=r   úOptional[int]c                óÎ  — | j         €Ø| j        rÑdd l}ddlm} |                     d¦  «        }|                      ¦   «         }|                     |                     | j        ¦  «        |                     |¦  «        ¦  «        r]|j	        | j
        k    rMt          |j	        ¦  «        | _         |                     |                     | j        ¦  «        ¦  «         d| _        | j         S )Nr   ©Úwintypes)rÍ   rË   rÒ   rØ   ÚDWORDrÔ   ÚGetExitCodeProcessÚHANDLEÚbyrefÚvalueÚSTILL_ACTIVErO   ÚCloseHandle)r,   rÒ   rØ   r¬   Úk32s        r   rE   z_WindowsProcess.pollð  sÑ   € ØŒ?Ð" t¤|Ð"ØˆMˆMˆMØ'Ð'Ð'Ð'Ð'Ð'Ø—>’> !Ñ$Ô$ˆDØ—.’.Ñ"Ô"ˆCØ×%Ò% h§o¢o°d´lÑ&CÔ&CØ&,§l¢l°4Ñ&8Ô&8ñ:ô :ð !à”J $Ô"3Ò3Ð3Ý"% d¤j¡/¤/�”Ø—’ §¢°´Ñ =Ô =Ñ>Ô>Ð>Ø �”ØŒÐr   Nr>   úOptional[float]c                ó~  — ddl m} | j        €p| j        ri|€dnt	          |dz  ¦  «        }|                      ¦   «                              |                     | j        ¦  «        |                     |¦  «        ¦  «         |  	                    ¦   «         }|€)t          j        t          | j        ¦  «        |pd¦  «        ‚|S )Nr   r×   l   ÿÿ iè  )rÒ   rØ   rÍ   rË   rO   rÔ   ÚWaitForSingleObjectrÛ   rÙ   rE   Ú
subprocessÚTimeoutExpiredrd   rÉ   )r,   r>   rØ   Úmsr¬   s        r   rF   z_WindowsProcess.waitþ  s¶   € Ø#Ð#Ð#Ð#Ð#Ð#ØŒ?Ð" t¤|Ð"Ø&˜��µC¸À$¹Ñ4GÔ4GˆBØ�NŠNÑÔ×0Ò0°·²ÀÄÑ1NÔ1NØ19·²ÀÑ1CÔ1CñEô Eð Eà�yŠy‰{Œ{ˆØˆ<ÝÔ+­C°´©M¬M¸7¸<ÀaÑHÔHÐHØˆr   c                óö   — |                       ¦   «         €b| j        r]ddlm} |                      ¦   «                              |                     | j        ¦  «        |                     d¦  «        ¦  «         d S d S d S )Nr   r×   r…   )rE   rË   rÒ   rØ   rÔ   ÚTerminateProcessrÛ   ÚUINT)r,   rØ   s     r   rÂ   z_WindowsProcess.terminate	  s‡   € Ø�9Š9‰;Œ;Ð 4¤<ÐØ'Ð'Ð'Ð'Ð'Ð'Ø�NŠNÑÔ×-Ò-¨h¯oªo¸d¼lÑ.KÔ.KØ.6¯mªm¸AÑ.>Ô.>ñ@ô @ð @ð @ð @ð ÐÐÐr   )rÈ   rO   rÉ   rO   r   r   )r   rÕ   rR   )r>   rá   r   rO   rT   )r   r   r   r   rÞ   r.   rÔ   rE   rF   rÂ   Úkillr   r   r   rÇ   rÇ   ×  sŽ   € € € € € ð
ð 
ð €Lð.ð .ð .ð .ð>ð >ð >ðð ð ð ð	ð 	ð 	ð 	ð 	ð@ð @ð @ð @ð €D€D€Dr   rÇ   c                óô  ‡%‡&‡'‡(— ddl Š'ddl}ddlŠ&ddl mŠ( ddlm} ‰'                     dd¬¦  «        }ˆ&fd„}‰&                     dd¦  «        \  }}‰&                     dd¦  «        \  }	}
 ||¦  «         ||
¦  «        }
}‰&                     dd¦  «        \  }} ||¦  «        }‰&                     ¦   «         }‰& 	                    |||dd‰&j
        ¦  «        }‰&                     dd¦  «        \  }} ||¦  «        }‰&                     |¦  «         t          |¦  «        }|                     |d¦  «        }t          t          |¦  «        ¦  «        |d	<   t          t          |
¦  «        ¦  «        |d
<    G ˆ'ˆ(fd„d‰'j        ¦  «        Š% G ˆ%ˆ'fd„d‰'j        ¦  «        } G ˆ(fd„d‰'j        ¦  «        }‰'j        ‰(j        ‰(j        ‰'                     ‰'j        ¦  «        f|j        _        ‰'j        ‰(j        ‰'j        ‰'j        ‰'j        ‰'j        ‰'j        f|j        _        ‰(j        ‰(j        ‰'j        ‰'j        ‰(j        ‰(j        ‰'j        ‰(j        ‰'j        ‰'                     |¦  «        f
|j        _         ‰(j        dz  ||
|||¦  «        }‰'                     d¦  «        }|                     ddd‰'                     |¦  «        ¦  «         ‰'                     |j        ¦  «        }|                     |dd‰'                     |¦  «        ¦  «        s'‰'                      ‰' !                    ¦   «         ¦  «        ‚d}|                     |d||‰' "                    |¦  «        dd¦  «        s'‰'                      ‰' !                    ¦   «         ¦  «        ‚ |¦   «         }‰' "                    |¦  «        |j#        _$        d|j#        _%        ||j#        _&        ||j#        _'        ||j#        _(        |r||j#        _)        ‰' *                    |‰'j        ¦  «        |_+        tY          d¦  «        }| -                    d„ t]          | /                    ¦   «         d„ ¬¦  «        D ¦   «         ¦  «        |z   |z   }‰' 0                    |tc          |¦  «        dz   ¦  «        }‰' 0                    te          j3        | g|z   ¦  «        ¦  «        }d\  }} |¦   «         }|                     d|ddd||z  |d‰'                     |¦  «        ‰'                     |¦  «        ¦
  «
        } ‰' !                    ¦   «         }!| 4                    |¦  «         ||
|||fD ]}"‰&                     |"¦  «         Œ| sa|	||fD ]}"‰&                     |"¦  «         Œtk          |!d| ›|rd|z  nd›d‰' 6                    |!¦  «         7                    ¦   «         ›�¦  «        ‚|                     |j8        ¦  «         ts          j:        | ;                    |tr          j<        ¦  «        d¦  «        }#t{          t          |j>        ¦  «        t          |j?        ¦  «        |#¦  «        }$| ;                    |d¦  «        | ;                    |	tr          j<        ¦  «        |$fS )uz  `CreateProcessW` by hand, for the one field `subprocess` cannot set.

    The browser is created on the desktop named by `INVPW_DESKTOP` when the
    session asked to be hidden (`invisible_core._headless`), and on the
    caller's own desktop otherwise. That variable is consumed HERE and does
    not reach the browser: the engine never reads it.

    Everything else is what the `Popen` call used to do, made explicit:
    exactly five handles are inherited - the two Juggler pipe ends, the
    child's end of the stdout pipe, a second handle to that same end for
    stderr, and the read end of a pipe for stdin - through
    `PROC_THREAD_ATTRIBUTE_HANDLE_LIST`, so a second session starting in the
    same instant cannot hand its pipe ends to this browser and lose the
    ability to notice its own closing. `bInheritHandles=TRUE` with that list
    inherits those five and nothing else.

    â›” THE THREE STD HANDLES ARE SHAPED FOR FIREFOX'S LAUNCHER, and the first
    draft of this function got two of them wrong. `firefox.exe` runs first as
    a launcher that creates the real browser with a handle list of its own,
    built from its stdin, stdout and stderr plus the Juggler pipe
    (`browser/app/winlauncher/LauncherProcessWin.cpp`, `ProcThreadAttributes.h`).
    That list takes only DISK and PIPE handles, silently drops anything else
    while still naming it as a std handle, and is never de-duplicated - and
    Windows refuses a handle list with the same handle twice. A NUL device for
    stdin (a CHAR handle) and one handle for both stdout and stderr made the
    launcher's `CreateProcessW` fail with ERROR_INVALID_PARAMETER (Event Log,
    `LauncherProcessWin.cpp:580`); the launcher then disabled itself for that
    path in the registry (`|Browser` = 0) and ran on as the browser itself,
    so the session worked and `tests/test_first_launch_from_a_new_path.py`
    was the only thing that saw it. `Popen` never tripped it because CPython
    duplicates every std handle separately. So: stdin is the read end of a
    pipe whose write end is closed at once (EOF, and a PIPE type), and stderr
    is its own duplicate of the stdout pipe.
    r   Nr×   )ÚDESKTOP_ENVrÏ   TrÐ   c                ó˜   •— ‰                      ¦   «         }‰                     || |dd‰j        ¦  «        }‰                     | ¦  «         |S )u†  â›” CPython's `_winapi.CreatePipe` calls Windows' CreatePipe with
        NULL security attributes, so the handles are NOT inheritable.
        Passing them in the handle list as they were made `CreateProcess`
        fail with `WinError 87 - The parameter is incorrect`, which does
        not name the cause. They get duplicated asking for inheritance,
        and the original is closed.r   T)ÚGetCurrentProcessÚDuplicateHandleÚDUPLICATE_SAME_ACCESSrß   )ÚhÚcurrent_processÚnewÚ_winapis      €r   Úinheritablez#_spawn_windows.<locals>.inheritable>  sV   ø€ ð "×3Ò3Ñ5Ô5ˆØ×%Ò% o°q¸/Ø&'¨¨wÔ/LñNô Nˆà×Ò˜AÑÔÐØˆ
r   ÚPW_PIPE_READÚPW_PIPE_WRITEc                  ó4  •— e Zd Zd”j        fd”j        fd”j        fd”j        fd”j        fd”j        fd”j        fd”j        fd	”j        fd
”j        fd”j        fd”j        fd”j        fd”j        fd” j        fd”j        fd”j        fd”j        fgZdS )ú$_spawn_windows.<locals>.STARTUPINFOWÚcbÚ
lpReservedÚ	lpDesktopÚlpTitleÚdwXÚdwYÚdwXSizeÚdwYSizeÚdwXCountCharsÚdwYCountCharsÚdwFillAttributeÚdwFlagsÚwShowWindowÚcbReserved2ÚlpReserved2Ú	hStdInputÚ
hStdOutputÚ	hStdErrorN)	r   r   r   rÙ   ÚLPWSTRÚWORDÚc_void_prÛ   Ú_fields_)rÒ   rØ   s   €€r   ÚSTARTUPINFOWrù   h  sÅ   ø€ € € € € Ø˜8œ>Ð*¨\¸8¼?Ð,KØ  (¤/Ð2°YÀÄÐ4PØ˜HœNÐ+¨e°X´^Ð-DØ ¤Ð/°)¸X¼^Ð1LØ$ h¤nÐ5Ø$ h¤nÐ5Ø&¨¬Ð7Ø ¤Ð/°-ÀÄÐ1OØ" H¤MÐ2Ø" F¤OÐ4Ø  (¤/Ð2Ø! 8¤?Ð3Ø  (¤/Ð2ð4ˆˆˆr   r  c                  ó*   •— e Zd Zd” fd”j        fgZdS )ú&_spawn_windows.<locals>.STARTUPINFOEXWÚStartupInfoÚlpAttributeListN)r   r   r   r  r  )r  rÒ   s   €€r   ÚSTARTUPINFOEXWr  w  s(   ø€ € € € € Ø" LÐ1Ø&¨¬Ð8ð:ˆˆˆr   r  c                  óT   •— e Zd Zd” j        fd” j        fd” j        fd” j        fgZdS )ú+_spawn_windows.<locals>.PROCESS_INFORMATIONÚhProcessÚhThreadÚdwProcessIdÚ
dwThreadIdN)r   r   r   rÛ   rÙ   r  r×   s   €r   ÚPROCESS_INFORMATIONr  {  s=   ø€ € € € € Ø ¤Ð1°I¸x¼Ð3OØ" H¤NÐ3Ø! 8¤>Ð2ð4ˆˆˆr   r  é   r…   i  é   c              3  ó    K  — | ]	}d |z  V — Œ
dS )z%s=%sNr   )r¦   Úkvs     r   r¨   z!_spawn_windows.<locals>.<genexpr>¨  s>   è è € ð Hð H b�W˜r‘\ð Hð Hð Hð Hð Hð Hr   c                ó6   — | d                               ¦   «         S )Nr   )Úupper)r   s    r   ú<lambda>z _spawn_windows.<locals>.<lambda>©  s   € ¸¸1¼¿º¹¼€ r   )Úkey)i   i   zCreateProcessW failed for z on desktop %rr©   rk   Úrb)@rÒ   Úmsvcrtrô   rØ   Úinvisible_corerì   rÓ   Ú
CreatePiperî   rï   rð   rß   rf   r�   rd   rO   Ú	Structurer  rÙ   ÚPOINTERÚc_size_tÚ!InitializeProcThreadAttributeListÚargtypesÚUpdateProcThreadAttributeÚLPCWSTRr  ÚBOOLÚCreateProcessWrÛ   rÜ   Úcreate_string_bufferrÝ   ÚWinErrorÚget_last_errorÚsizeofr  rú   r  r	  r
  r  rü   Úcastr  Úchrrª   ÚsortedÚitemsÚcreate_unicode_bufferrm   rä   Úlist2cmdlineÚDeleteProcThreadAttributeListr:   ÚFormatErrorr6   r  rˆ   ÚfdopenÚopen_osfhandleÚO_RDONLYrÇ   r  r  ))Ú
executableÚargvÚenvr&  rì   rà   rõ   Úits_readÚ	our_writeÚour_readÚ	its_writeÚout_readÚ	out_writerò   Ú	err_writeÚin_readÚin_writeÚdesktopr  r  Ú	inheritedÚsizeÚattrsÚ!proc_thread_attribute_handle_listÚsiÚnulÚblockÚ	env_blockÚcmdlineÚcreate_unicode_environmentÚextended_startupinfo_presentÚpiÚokÚerrrñ   rÌ   rÄ   r  rô   rÒ   rØ   s)                                        @@@@r   Ú_spawn_windowsr\    s%  øøøø€ ðF €M€M€MØ€M€M€MØ€N€N€NØÐÐÐÐÐà*Ð*Ð*Ð*Ð*Ð*à
�-Š-˜
°4ˆ-Ñ
8Ô
8€Cðð ð ð ð ð  "×,Ò,¨Q°Ñ2Ô2Ñ€HˆiØ!×,Ò,¨Q°Ñ2Ô2Ñ€HˆiØ%˜+ hÑ/Ô/°°¸YÑ1GÔ1Gˆi€Hð
 "×,Ò,¨Q°Ñ2Ô2Ñ€HˆiØ�˜IÑ&Ô&€IØ×/Ò/Ñ1Ô1€OØ×'Ò'¨¸Ø(7¸¸DØ(/Ô(EñGô G€Ið  ×*Ò*¨1¨aÑ0Ô0Ñ€GˆXØˆk˜'Ñ"Ô"€GØ×Ò˜Ñ!Ô!Ð!å
ˆs‰)Œ)€CØ�gŠg�k 4Ñ(Ô(€Gå�c (™mœmÑ,Ô,€CˆÑÝ�s 9™~œ~Ñ.Ô.€CˆÑð4ð 4ð 4ð 4ð 4ð 4ð 4ð 4�vÔ'ñ 4ô 4ð 4ð:ð :ð :ð :ð :ð :ð :ð :˜Ô)ñ :ô :ð :ð4ð 4ð 4ð 4ð 4ð 4ð 4˜fÔ.ñ 4ô 4ð 4ð 	Œ˜œ¨¬Ø�Š�v”Ñ'Ô'ð6)€CÔ)Ô2ð 	Œ˜œ¨¬¸&¼/ØŒ˜œ¨&¬/ð.;€CÔ!Ô*ð 	Ô˜(œ/¨6¬?¸F¼OØŒ�x”~ v¤¸Ô8HØŒ˜ŸšÐ(;Ñ<Ô<ð#>€CÔÔð
 %�” 1Ñ$ h°	¸9Ø&/°ñ:ô :€Ià�?Š?˜1ÑÔ€DØ×)Ò)¨$°°1°f·l²lÀ4Ñ6HÔ6HÑIÔIÐIØ×'Ò'¨¬
Ñ3Ô3€EØ×0Ò0°¸¸1¸f¿lºlÈ4Ñ>PÔ>PÑQÔQð 7Ø�oŠo˜f×3Ò3Ñ5Ô5Ñ6Ô6Ð6Ø(/Ð%Ø×(Ò(Ø�1Ð7¸Ø�MŠM˜)Ñ$Ô$ d¨Dñ2ô 2ð 7ð �oŠo˜f×3Ò3Ñ5Ô5Ñ6Ô6Ð6à	ˆÑ	Ô	€BØŸš nÑ5Ô5€B„NÔØ"€B„NÔØ&€B„NÔØ )€B„NÔØ(€B„NÔØð +Ø#*ˆŒÔ ØŸš U¨F¬OÑ<Ô<€BÔõ ˆa‰&Œ&€CØ�HŠHð Hð HÝ˜CŸIšI™KœKÐ-EÐ-EÐFÑFÔFðHñ Hô Hñ Hô HØJMñNØPSñT€Eà×,Ò,¨UµC¸±J´JÀ±NÑCÔC€Ià×*Ò*ÝÔ  ¨tÑ 3Ñ4Ô4ñ6ô 6€Gà?MÑ<ÐÐ <Ø	Ð	Ñ	Ô	€BØ	×	Ò	Øˆg�t˜T 4Ø"Ð%AÑAØ�4˜Ÿš bÑ)Ô)¨6¯<ª<¸Ñ+;Ô+;ñ
=ô 
=€Bð ×
Ò
Ñ
!Ô
!€CØ×%Ò% eÑ,Ô,Ð,ð ˜	 9¨i¸ÐAð ð ˆØ×Ò˜AÑÔÐÐØð .Ø˜I xÐ0ð 	#ð 	#ˆAØ×Ò Ñ"Ô"Ð"Ð"Ý�c�cØˆJ¸ÐGÐ)¨GÑ3Ð3ÀRÐGÐGØ×Ò˜sÑ#Ô#×)Ò)Ñ+Ô+Ð+ð-ñ .ô .ð 	.ð ‡O‚O�B”JÑÔÐÝŒY�v×,Ò,¨Xµr´{ÑCÔCÀTÑJÔJ€FÝ�˜BœKÑ(Ô(­#¨b¬nÑ*=Ô*=¸vÑFÔF€AØ×!Ò! )¨QÑ/Ô/Ø×!Ò! (­B¬KÑ8Ô8¸!ð=ð =r   c           	     ó0  ‡‡— t          j        ¦   «         \  Š}t          j        ¦   «         \  }Šˆˆfd„}t          j        | g|z   ||‰‰ddft          j        t          j        ¬¦  «        }t          j        ‰¦  «         t          j        ‰¦  «         |||fS )uq  â›” IT WAS BROKEN, AND THE DOCSTRING HAD GUESSED WHICH HALF.

    This leg was written from `nsRemoteDebuggingPipe.cpp` and never executed
    until 2026-08-28. The symptom on the first run: the browser starts, prints
    `Juggler listening to the pipe`, stays alive - and the very first write
    raises `BrokenPipeError`. A live process with no reader on the other end.

    â›” THE CAUSE, MEASURED RATHER THAN REASONED. CPython's close-all-fds
    sweep runs AFTER `preexec_fn`, so the two descriptors this function creates
    with `dup2` are closed again before `exec` unless they are in the keep
    list. A four-line experiment reported it exactly:

        with preexec_fn + pass_fds(its_read, its_write) ->  alive=[3]
        with 3 and 4 also kept                          ->  alive=[3, 4]

    Fd 3 survived only by accident: the first `os.pipe()` in the parent
    happened to return 3, so it was already in the keep list and the `dup2`
    onto it was a no-op. Fd 4 was created by `dup2` and swept away - which is
    why the browser could ANNOUNCE itself (it had a read end on 3) and never
    receive anything (nothing owned the read end of OUR pipe once 4 died).

    â›” The remedy is to name 3 and 4 in `pass_fds` as well. They are not open
    in the parent and do not have to be: that list is a set of NUMBERS the
    child's sweep spares, not a set of parent handles.
    c                 ó„   •— ‰df‰dffD ]5\  } }| |k    rt          j        | |¦  «         t          j        |d¦  «         Œ6d S )Né   é   T)rˆ   Údup2Úset_inheritable)Úsourcer   rD  rG  s     €€r   Úfix_descriptorsz%_spawn_posix.<locals>.fix_descriptorsä  sb   ø€ ð$ !)¨!˜}¨y¸!¨nÐ=ð 	-ð 	-‰NˆF�FØ˜ÒÐÝ”˜ Ñ'Ô'Ð'ÝÔ˜v tÑ,Ô,Ð,Ð,ð	-ð 	-r   r_  r`  )rC  Ú
preexec_fnÚpass_fdsrÌ   Ústderr)rˆ   Úpiperä   ÚPopenÚPIPEÚSTDOUTrÀ   )	rA  rB  rC  rE  rF  rd  rÄ   rD  rG  s	          @@r   Ú_spawn_posixrl  Ç  sµ   øø€ õ4 œ'™)œ)Ñ€HˆiÝœ'™)œ)Ñ€Hˆið-ð -ð -ð -ð -ð -õ. 	Ô˜*˜¨Ñ,°#Ø$3ð
 $,¨Y¸¸1Ð"=Ý *¤½
Ô8Ið	Kñ 	Kô 	K€Aõ „HˆXÑÔÐÝ„HˆYÑÔÐØ�h Ð!Ð!r   Tg      N@)ÚheadlessÚ
argv_extrarC  Úready_timeoutrA  rd   Úprofile_dirrm  r@   rn  úOptional[list]rC  r¯   ro  r?   r   c          	     óÌ  — dg}|r|                      d¦  «         n|ddgz  }|d|dgz  }|t          |pg ¦  «        z  }|                      d¦  «         t          |€t          j        n|¦  «        }t
          j        d	k    rt          nt          } || ||¦  «        \  }	}
}t          |j
        ¦  «        }|                     ||¦  «        }|                     ¦   «         �gd
                     d„ |                     ¦   «         D ¦   «         ¦  «        pd}t          d|j        ›dd                     | g|z   ¦  «        ›d|›�¦  «        ‚t#          |	|
|¦  «        }||_        ||_        |S )zKLaunches Firefox over the pipe and returns an already-ready
    connection.z
-no-remotez	-headlessz-wait-for-browserz-foregroundz-profilez-juggler-pipez-silentNÚwin32r¢   c              3  ó    K  — | ]	}d |z   V — Œ
dS r¤   r   r¥   s     r   r¨   zlaunch.<locals>.<genexpr>1  s&   è è € Ð=Ð=¨!˜& 1™*Ð=Ð=Ð=Ð=Ð=Ð=r   z    (nothing)zTthe browser exited during startup, before the protocol could be used.
  exit code : z
  command   : ú z
  it printed:
)r7   rP   rf   rˆ   ÚenvironÚsysÚplatformr\  rl  r   rÌ   rL   rE   rª   rS   ÚRuntimeErrorrÍ   rr   Ú
ready_seenr~   )rA  rp  rm  rn  rC  ro  rB  Úfull_envÚspawnr�   r‚   rÄ   r~   ÚseenÚcodaÚcs                   r   Úlaunchr€    sˆ  € ð
 ˆ>€DØð 5Ø�Š�KÑ Ô Ð Ð àÐ$ mÐ4Ñ4ˆØˆZ˜ oÐ6Ñ6€DØ�D�Ð!˜rÑ"Ô"Ñ"€DØ‡K‚K�	ÑÔÐå # +•B”J�J°3Ñ7Ô7€HÝ!œl¨gÒ5Ð5�NˆN½<€EØ"' %¨
°D¸(Ñ"CÔ"CÑ€J�˜aõ ˜1œ8Ñ$Ô$€FØ× Ò   MÑ2Ô2€Dð 	‡v‚v�x„xÐØ�yŠyÐ=Ð=¨v¯{ª{©}¬}Ð=Ñ=Ô=Ñ=Ô=ÐPÀˆÝˆlð Œ|ˆ|ˆ|˜SŸXšX z l°TÑ&9Ñ:Ô:Ð:Ð:¸D¸DðBñCô Cð 	Cõ 	�:˜|¨QÑ/Ô/€AØ€A„LØ€A„HØ€Hr   )rA  rd   rp  rd   rm  r@   rn  rq  rC  r¯   ro  r?   r   rr   )r   Ú
__future__r   rš   rˆ   rä   rw  r#   rC   Útypingr   r   r   rŠ   r8   ry  r	   rl   r   r   rV   rr   rÇ   r\  rl  r€  r   r   r   ú<module>rƒ     sû  ððð ð> #Ð "Ð "Ð "Ð "Ð "à €€€Ø 	€	€	€	Ø Ð Ð Ð Ø 
€
€
€
Ø Ð Ð Ð Ø €€€Ø *Ð *Ð *Ð *Ð *Ð *Ð *Ð *Ð *Ð *à€Ø	(€ðð ð ð ð �Lñ ô ð ðð ð ð ð ˜	ñ ô ð ð<L*ð L*ð L*ð L*ð L*ñ L*ô L*ð L*ð^JMð JMð JMð JMð JMñ JMô JMð JMðZað að að að a�ñ aô að aðL8ð 8ð 8ð 8ð 8ñ 8ô 8ð 8ðvr=ð r=ð r=ðj>"ð >"ð >"ðB CGØ'+À4Ø!%ð1ð 1ð 1ð 1ð 1ð 1ð 1ð 1r   