Ë
    Š‰ŒjÂ  ã                  óü   — d Z ddlmZ ddlZddlZddlZddlmZ dZdZ	dZ
	 d	 	 	 d d„Zd	Zd!d
„Zd"d„ZdZdZdZdZdZdZdZedœ	 	 	 d#d„Zedœd$d„Zd%d„Zddddedœ	 	 	 	 	 	 	 d&d„Z G d„ d«      Z G d„ d«      Zy)'uÂ  
Which race is ON AIR â€” the broadcast's hand-over policy.

A competition runs races back-to-back: the operator arms the next heat while the current one is still
sailing. Two rules follow, and they are the whole of this module:

  1. **Finish the race when the schedule permits it.** The broadcast stays with the race it is
     showing until the last boat finishes, or until fifteen presented race-seconds after the
     penultimate finisher. A server-side close remains the authority/fallback.
  1a. **A permanently overlapping schedule may not create an ever-growing backlog.** A race that
     starts while another ordinary race is being followed to its finish is deliberately skipped,
     not shown late afterwards. When the current race ends, the programme takes the next race whose
     gun is still in the future. A fresh producer prefers that next future start over races already
     missed; if nothing is armed ahead, it falls back to the most recently started open race.
  1b. **When there is time, the next future race is the one that starts next.** The ordinary queue is
     ordered by gun, not by the order races happened to be reported in. A race is not dropped merely
     because its fleet has not resolved yet or it is handed back unpresentable.
  1c. **An isolated finish gets room to breathe.** If the last boat finishes with no other race
     running or armed, the completed race remains on air for one presented minute. A newly armed race
     may replace it as soon as its gun is within three minutes; otherwise the minute ends on the
     waiting presentation, which retains that same Tâˆ’3 gate for the next race.
  2. **Moving on is not restarting.** The producer rebuilds the presentation for the next race on the
     SAME server and the SAME SSE connection; the renderer swaps the race in place
     (`live/web/live_feed.js` â†’ `onRaceChange`). No process restart, no page reload, no black screen.
  3. **The next race goes up with its recent past already on the wire** (`coverage_window`). The
     renderer presents a fixed delay behind the data frontier, so a race published only from the join
     gives its cursor nothing to sit on and the picture holds one frame for the whole delay. Not a
     "restart", but indistinguishable from one to a viewer â€” which is what rule 2 is actually for.

One caveat this module does not solve: the renderer fixes its world anchor, boat class and hull livery
when the scene is CONSTRUCTED (`core/web/scene.js`), from the first race it is given. Every race of one
regatta day shares those, so a day-long follow session is fine; a session handed a race at a different
course centre would keep the first race's anchor.

Both the production live producer (`serve_v3_live.py --follow`) and the sim's operator-driven bridge
(`v3/sim/bridge_3d.py`) use this â€” one policy, so the sim exercises what production does.

Pure over injected callables and an injected clock: the whole hand-over runs in tests with no servers,
sockets or sleeps.
é    )ÚannotationsN)ÚCallablei ¿ i'  é`ê  c                ó<  ‡— | xs g D �cg c]9  }|j                  d«      �&|j                  d«      €|j                  d«      dvr|‘Œ; }}t        ˆfd„|D «       d„ d¬«      }|rs|d	   }t        |d
   «      t        |d   «      }}|xs i j                  |«      }	t	        |t
        z   |	�t        |	«      t        z   n|t
        z   «      }
‰|
k  r
i |¥d|
|	dœ¥S t        ˆfd„|D «       d„ ¬«      }|r%|d	   }i |¥dt        |d   «      ‰z
  dk  rdi¥S di¥S ddiS c c}w )an  Select the race identity the start-vessel camera should show.

    This is deliberately separate from the on-air queue: a new fleet can be starting while the main
    programme stays with the previous fleet through its finish.  `rows` are the race plane's scoped
    open races.  `all_started_utc_ms` is observed GNSS evidence, never an operator or clock guess.
    ÚgunÚstopÚstate©Ú	abandonedÚ	cancelledc              3  óF   •K  — | ]  }t        |d    «      ‰k  sŒ|–— Œ y­w©r   N©Úint©Ú.0ÚrowÚnow_mss     €ú=/srv/vr/releases/25f455cc4e75/v3/broadcast/live/race_queue.pyú	<genexpr>z-select_start_camera_status.<locals>.<genexpr>F   s    øè ø€ ÒE˜3¬3¨s°5©z«?¸fÓ+D”3ÑEùó   ƒ!š!c                ó   — t        | d   «      S ©Nr   r   ©r   s    r   ú<lambda>z,select_start_camera_status.<locals>.<lambda>G   s   € ¤# c¨%¡j£/€ ó    T)ÚkeyÚreverser   Ú
instanceIdÚstarted)ÚmodeÚexpiresUtcMsÚallStartedUtcMsc              3  óF   •K  — | ]  }t        |d    «      ‰kD  sŒ|–— Œ y­wr   r   r   s     €r   r   z-select_start_camera_status.<locals>.<genexpr>S   s    øè ø€ ÒF˜S¬S°°U±«_¸vÓ-E”SÑFùr   c                ó   — t        | d   «      S r   r   r   s    r   r   z,select_start_camera_status.<locals>.<lambda>T   s   € ¤C¨¨E©
£O€ r   ©r   r!   r   Ú	countdownÚnextÚawaiting)ÚgetÚsortedÚstrr   ÚminÚSTART_CAMERA_POST_GUN_MAX_MSÚ START_CAMERA_ALL_STARTED_HOLD_MS)Úrowsr   Úall_started_utc_msr   ÚvalidÚpastÚlatestÚridr   Úall_atÚexpiryÚfutureÚchosens    `           r   Úselect_start_camera_statusr:   ;   sz  ø€ ð "šZ Rö E�SØ—‘˜“Ð*¨s¯w©w°v«Ð/FØ—‘˜Ó!Ð)CÑCò ð E€Eð Eô ÓE %ÔEÙ1¸4ôA€DáØ�a‘ˆÜ�v˜lÑ+Ó,¬c°&¸±-Ó.@ˆSˆØ$Ò*¨×/Ñ/°Ó4ˆÜ�SÔ7Ñ7àÐ*ô ˜“[Ô#CÒCØ03Ô6RÑ0RóTˆð �FŠ?ð/�fð / iÀØ'-ò/ð /ô ÓF EÔFÙ3ô5€FáØ˜‘ˆð\�&ð \Ø¬¨F°5©MÓ(:¸VÑ(CÀvÒ(M˜ñ\ð 	\ØSYñ\ð 	\à�JÐÐùò-Es   Š>D)
)zAnd now, back to the racing.zOch nu tillbaka till seglingen.)zWelcome back to the racing.u"   VÃ¤lkomna tillbaka till seglingen.)zWe are back with the racing.u   Vi Ã¤r tillbaka med seglingen.)z-Now, let's return to the action on the water.u1   Nu Ã¥tervÃ¤nder vi till hÃ¤ndelserna pÃ¥ vattnet.)z#Welcome back. We rejoin the racing.u3   VÃ¤lkomna tillbaka. Vi Ã¥tervÃ¤nder till seglingen.)z/Back to the course now, and the race continues.u,   Tillbaka till banan, dÃ¤r racet fortsÃ¤tter.)zWe return now to the racing.u"   Nu Ã¥tervÃ¤nder vi till seglingen.)z,Let's head back to the boats and the action.u0   Vi gÃ¥r tillbaka till bÃ¥tarna och hÃ¤ndelserna.)z1Back on the water now, with the race in progress.u)   Tillbaka pÃ¥ vattnet, dÃ¤r racet pÃ¥gÃ¥r.)z%Welcome back. Let's pick up the race.u,   VÃ¤lkomna tillbaka. Vi fÃ¶ljer racet vidare.c                 óT   — t         D � �cg c]  \  } }d| | |dœddddœ‘Œ c}} S c c}} w )zLThe ten short, neural-ready bridges used after an external programme insert.Úprogramme_return©ÚenÚsvÚleadÚ	structureÚreturn)ÚtypeÚtextÚi18nÚcommentaryRoleÚclaimÚprogrammeAnchor)ÚPROGRAMME_RETURN_COMMENTARYr=   s     r   Úprogramme_return_commentaryrJ   m   s?   € ô 6÷7á��Bð (°ÀBÈbÑ=QØ%°ÐPXóZó 7ð 7ùó 7s   Š$c                óB   — | st         S t        dt        | «      dz  «      S )u)  When a race goes on air, as a lead on its gun â€” the start-countdown trigger.

    Derived from the event's own sequence rather than stated, because the length is an event fact
    (root `CLAUDE.md`): TRWC and the GSYS rehearsal sail four minutes, a club Saturday commonly
    three, and the hooter presets run to ten. The race office's ARM writes that future gun at the
    beginning of this window. That edge is the programme transition: before it the model is in its
    waiting presentation; from it the full opening, course guide and first race run from race-second
    zero. Delaying the picture until the preparatory signal classified a four-minute start as a late
    join and suppressed the very opening the waiting state exists to lead into.

    Boat cameras may still need their first minute to become available. The opening and course guide
    occupy that part of the programme and do not depend on a boat-camera tile; camera availability is
    advertised separately, so it must not delay the entire broadcast state machine.

    `None` (the event publishes no length) â‡’ `PRE_START_MS`. Unlike an ARM, a lead-in has a safe
    default: joining a race three minutes before its gun is at worst early or late coverage, never a
    wrong gun, so this is not the case that must refuse rather than guess.
    r   éè  )ÚPRE_START_MSÚmaxr   )Úpre_start_ss    r   Úannounce_lead_msrP   s   s$   € ñ& ÜÐÜˆq”#�kÓ" TÑ)Ó*Ð*r   iÀÔ é-   é   é   é   é<   ©Útail_sc               ó  — 	 t        |«      }t        d„ | xs g D «       «      }|dk  s|syt	        |«      |k\  r||dz
     S |dk\  r%t	        |«      |dz
  k\  r||dz
     t        |«      z   S y# t        t        f$ r Y yw xY w)aS  The presented race second at which on-water coverage may end.

    The last verified finisher ends it at her crossing. If the last tracker or boat does not arrive,
    the penultimate crossing starts a bounded tail. The rule is fleet-size independent and returns
    ``None`` until enough boats have finished to make either statement.
    Nc              3  óš   K  — | ]C  }t        |t        t        f«      r+t        j                  t        |«      «      rt        |«      –— ŒE y ­w©N)Ú
isinstancer   ÚfloatÚmathÚisfinite)r   Úsecs     r   r   z&finish_handover_sec.<locals>.<genexpr>Ò   s:   è ø€ ò T 3Ü! #¬¬U |Ô4¼¿¹ÄuÈSÃzÔ9Rô ˜#—Jñ Tùs   ‚A	Ar   é   é   )r   Ú	TypeErrorÚ
ValueErrorr+   Úlenr\   )Úfinish_secsÚexpected_finishersrW   ÚexpectedÚvaluess        r   Úfinish_handover_secri   Æ   s£   € ðÜÐ)Ó*ˆô ñ T¨;Ò+<¸"ô Tó T€Fà�1‚}™FØÜ
ˆ6ƒ{�hÒØ�h ‘lÑ#Ð#Ø�1‚}œ˜V›¨°1©Ò4Ø�h ‘lÑ#¤e¨F£mÑ3Ð3Øøô ”zÐ"ò Ùðús   ‚A, Á,A>Á=A>©Úlag_sc               óL   — t        dt        | «      t        |«      z
  «      }||fS )u  `(coverage_start_sec, first_published_sec)` for a race joined `elapsed_s` seconds in.

    `coverage_start_sec` is where the VIEWER's coverage of this race begins â€” the cursor's second at
    the moment the hand-over lands â€” and is what the opening beats and the line-up are paced from
    (`v3/scoring/programme.py` `race_open_beats(at_sec=â€¦)`, `score_race.build_prestart_script(
    coverage_from_sec=â€¦)`). `first_published_sec` is the first elapsed second to put on the wire.

    They are the same second: publishing from the coverage start is exactly what gives the cursor
    real data to sit on. Returned as a pair anyway, because the two are DIFFERENT questions â€” one is
    editorial, one is transport â€” and a future lag/back-fill split must not silently conflate them.
    r   )rN   r   )Ú	elapsed_srk   Úfirsts      r   Úcoverage_windowro   Ý   s'   € ô �”3�y“>¤C¨£JÑ.Ó/€EØ�%ˆ<Ðr   c                ó„   — t        j                  dt        | xs d«      «      }|rt        |j	                  d«      «      S dS )uJ  The race's NUMBER for the opening beat ("Race 4. Ireland against Japan."), or None.

    Read off the race office's own label (`meta.raceName`) â€” the number the paperwork and the radio
    use â€” rather than counted by the producer, because a broadcast that started mid-day, or one
    following a course whose races are sailed out of order, would count something the audience does
    not recognise. A trailing integer is the number; anything else ("Heat A", a name with no digits)
    has none, and the opening says who is racing without numbering it instead of inventing one.
    z	(\d+)\s*$Ú r`   N)ÚreÚsearchr,   r   Úgroup)Ú	race_nameÚms     r   Úrace_number_ofrw   í   s6   € ô 	�	‰	�,¤ I¢O°Ó 4Ó5€AÙŒ3ˆq�w‰w�q‹z‹?Ð) TÐ)r   TF)ru   Ú
first_raceÚleaving_race_nameÚresuming_from_waitingrk   c                ó  — t        | |¬«      \  }}t        |«      }|t        |xs d«      j                  «       xs d|t        |xs d«      j                  «       xs dt        |«      t	        |«      t        «       dœ}	|rd|	d<   |	S )uà  The `meta.programme` block a producer stamps on a race going on air.

    What the production layer needs in order to OPEN the race â€” which race this is, which race the
    broadcast is LEAVING to get here, whether the audience has been welcomed yet, and which second
    this broadcast's coverage of it begins (`v3/scoring/programme.py` `programme_beats`, and the
    line-up's pacing in `score_race.build_prestart_script`).

    `leaving_race_name` is the race that was on air until this moment. Only a producer knows it â€”
    the incoming feed has no memory of what preceded it â€” and without it the hand-over can only
    announce an arrival, never a departure: "Race 1007: Great Britain against Ireland" leaves a
    viewer who was following 1006 to work out for themselves that it has gone. None on the first
    race of a session, which leaves nothing.

    It rides the FEED's meta rather than a producer's boot configuration because every field is a
    fact about THIS hand-over: a producer built once at start-up cannot know which second the next
    race will be joined at. Built here so the production producer and the simulator's bridge stamp
    the same block â€” the opening is part of the hand-over policy, not of either driver.

    A race hand-over never requests a route tour. Periodic course orientation belongs to the
    waiting programme, where its narrated chapters have time to run and yield to an approaching
    start instead of producing an unreadable transition sweep.rj   rq   N)ÚcoverageStartSecÚ	raceLabelÚ
raceNumberÚleavingRaceLabelÚleavingRaceNumberÚ	firstRaceÚreturnCommentaryTÚresumingFromWaiting)ro   rw   r,   ÚstripÚboolrJ   )
rm   ru   rx   ry   rz   rk   Úcoverage_secÚ_Úrace_numberÚouts
             r   Úprogramme_metarŠ   ú   s�   € ô2 & i°uÔ=�O€L�!Ü  Ó+€KØ+ô ˜Yš_¨"Ó-×3Ñ3Ó5Ò=¸Ø%Ü #Ð$5Ò$;¸Ó <× BÑ BÓ DÒ LÈÜ!/Ð0AÓ!BÜ˜jÓ)Ü ;Ó =ñ?€Cñ Ø%)ˆÐ!Ñ"Ø€Jr   c            	      óæ   — e Zd ZdZedeeeee	e
j                  dœ	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zedd„«       Zdd„Zdd„Zdd„Zdd	„Zdd
„Zdd„Zdd„Zdd„Zddœdd„Zd d„Zd d„Zddœdd„Zddœd!d„Zy)"Ú
OnAirQueueu  The race currently ON AIR, and the ones waiting.

    Releases (a race whose start signal has gone) are `offer`ed as they happen; `take_next` returns the
    race to put up, or None to stay with the one on air. Structured scorer progress keeps it on air
    until the last finisher or bounded penultimate tail reaches the delayed viewer cursor. A legacy
    winner-only producer retains `winner_hold_s`; a server-close without a finish retains
    `min_air_s`, so an abandoned or unobservable race cannot wedge the programme.

    With nothing waiting, a complete last-boat finish stays up for one minute and then yields to the
    waiting presentation â€” the broadcast is never blank. A race newly armed inside Tâˆ’3 takes over
    directly; an earlier arm remains behind the waiting presentation until that threshold.

    **The one exception: a PRIORITISED race.** The race office marks a final, a decider or a medal
    race, and that race takes the air at `PRIORITY_LEAD_MS` before its gun even if another race is
    showing. The interrupted race returns to its start-ordered queue place; priority changes which
    race is shown now, never which accepted races are silently discarded. Among prioritised races
    the LATER gun wins the immediate cut and the earlier one remains queued.N)Úwinner_hold_sÚ	min_air_sÚpresentation_lag_sÚfinish_tail_sÚresult_visible_sÚisolated_finish_hold_sÚpost_finish_next_lead_msÚnow_fnc               ó”  — t        |«      | _        t        |€|n|«      | _        t        |«      | _        t        |«      | _        t        |«      | _        t        |«      | _        t        |«      | _        || _	        g | _
        d | _        d| _        d | _        d| _        d| _        d | _        d| _        d| _        i | _        d | _        y )Ng        F)r\   r�   rŽ   r�   r�   r‘   r’   r   r“   Ú_nowÚ_pendingÚ_on_airÚ
_on_air_atÚ_won_atÚ_structured_progressÚ_finish_readyÚ_finish_ready_atÚ_isolated_full_finishÚ_wait_for_close_startÚ	_priorityÚ_on_air_gun)	Úselfr�   rŽ   r�   r�   r‘   r’   r“   r”   s	            r   Ú__init__zOnAirQueue.__init__:  sÉ   € ô # =Ó1ˆÔÜ°	Ð0A™}ÀyÓQˆŒÜ"'Ð(:Ó";ˆÔÜ" =Ó1ˆÔÜ %Ð&6Ó 7ˆÔÜ&+Ð,BÓ&CˆÔ#Ü(+Ð,DÓ(EˆÔ%ØˆŒ	Ø%'ˆŒØ#'ˆŒØ!$ˆŒØ%)ˆŒØ$)ˆÔ!Ø"ˆÔØ.2ˆÔð &+ˆÔ"ð &+ˆÔ"ð
 +-ˆŒØ'+ˆÕr   c                ó   — | j                   S rZ   )r˜   ©r¢   s    r   Úon_airzOnAirQueue.on_air]  s   € à�|‰|Ðr   c                ó4   — t        |«      | j                  |<   y)uÎ  The race office's `priority` flag for a race, as of this tick.

        Called every tick from the operator's rows, not only when a race is offered, because the flag
        is set on the water while racing is under way: a race marked at Tâˆ’5 is already pending, and
        one UNmarked mid-race must stop being protected at once. A queue that learned the flag only
        at `offer` would honour a decision the race office had already changed its mind about.N)r…   r    )r¢   ÚinstanceÚprioritys      r   Úset_priorityzOnAirQueue.set_prioritya  s   € ô $(¨£>ˆ�‰�xÒ r   c                óè  — t        | j                  «       dz  «      }d}| j                  D ]_  }|d   |d   }}|�| j                  j	                  |«      sŒ+|t        |«      t
        z
  k  rŒA|�t        |«      t        |d   «      kD  sŒ^|}Œa |€y| j                  �V| j                  j	                  | j                  «      r1| j                  �%t        |d   «      t        | j                  «      k  ry|S )ué  The prioritised race that may take the air *right now*, or None.

        Checked before the ordinary hand-over and independently of `done()` â€” that is the whole of
        what priority means. Three conditions, in order: the race is flagged and its Tâˆ’2 has come;
        among several such it is the one with the LATEST gun; and if the race already on air is
        itself prioritised, only a strictly later gun may cut it. An unprioritised race on air is cut
        by any of them.rL   Nr   r`   )r   r–   r—   r    r*   ÚPRIORITY_LEAD_MSr˜   r¡   )r¢   r   ÚbestÚpr¨   r   s         r   Ú
_preemptorzOnAirQueue._preemptorj  sä   € ô �T—Y‘Y“[ 4Ñ'Ó(ˆØˆØ—‘ò 	ˆAØ˜a™D ! A¡$�cˆHØˆ{ $§.¡.×"4Ñ"4°XÔ">ØØœ˜C›Ô#3Ñ3Ò3ØØˆ|œs 3›x¬#¨d°1©g«,Ó6Ø‘ð	ð ˆ<ØØ�L‰LÐ$¨¯©×);Ñ);¸D¿L¹LÔ)IØ×$Ñ$Ð0´S¸¸a¹³\ÄSÈ×IYÑIYÓEZÒ5ZØØˆr   c                ó  — | j                   D �cg c]  }|d   |k7  sŒ|‘Œ c}| _         | j                   j                  ||g|¢­«       | j                   j                  d„ ¬«       | j                  duxr || j                  k7  S c c}w )u  A released race joins the queue **in start order** (`rest` is carried through to
        `take_next` untouched â€” e.g. the sim's release base). Returns True if it has to WAIT because
        something else is on air. A re-arm of an already-waiting race supersedes its earlier release.

        THE ORDER IS THE GUN'S, NOT THE QUEUE'S. This used to append, so the order was whichever
        order races happened to be *reported* in â€” and two things reorder that against the racing:
        a race handed back because it was not ready yet (no fleet resolved) went to the BACK, behind
        races that started after it; and a race armed out of order, or re-armed to an earlier gun,
        arrived late and stayed late. Either way the broadcast could move from one race to a race
        that started after the one it skipped, which is not following the regatta.

        Sorting on every offer is trivially cheap (a queue is a handful of races) and it means the
        invariant holds by construction rather than by every caller remembering it.r   c                ó"   — | d   d u | d   xs dfS ©Nr`   r   © ©r®   s    r   r   z"OnAirQueue.offer.<locals>.<lambda>•  s   € ¨!¨A©$°$¨,¸¸!¹º	ÀÐ)B€ r   r&   N)r—   ÚappendÚsortr˜   )r¢   r¨   r   Úrestr®   s        r   ÚofferzOnAirQueue.offerƒ  s|   € ð %)§M¡MÖF˜q°Q°q±T¸XÓ5EšÒFˆŒØ�‰×Ñ˜h¨Ð3¨dÑ3Ô4ð 	�‰×ÑÑBÐÔCØ�|‰| 4Ð'ÒD¨H¸¿¹Ñ,DÐDùò Gs
   �B�Bc                óF   — | j                   D �cg c]  }|d   ‘Œ	 c}S c c}w )Nr   )r—   )r¢   r®   s     r   ÚwaitingzOnAirQueue.waiting˜  s   € Ø"Ÿm™mÖ,˜��!“Ò,Ð,ùÒ,s   �c                óÎ   — t        | j                  «       dz  «      }| j                  D ]%  }	 t        |d   «      }||z
  | j
                  k  sŒ% y y# t        t        f$ r Y Œ:w xY w)zXWhether any queued race is already running or no farther away than the post-finish lead.rL   r`   TF)r   r–   r—   rb   rc   r“   )r¢   r   Úpendingr   s       r   Ú_has_close_startzOnAirQueue._has_close_start›  sq   € ä�T—Y‘Y“[ 4Ñ'Ó(ˆØ—}‘}ò 	ˆGðÜ˜' !™*“o�ð �V‰|˜t×<Ñ<Ó<Ùð	ð øô	 œzÐ*ò Ùðús   ­AÁA$Á#A$c                ó–   — | j                   D �cg c]  }|d   |k7  sŒ|‘Œ c}| _         | j                  j                  |d«       yc c}w )u_  Forget a pending race entirely â€” for a race the RACE PLANE no longer lists.

        `offer` files and `take_next` pops, but nothing ever removed a race that stopped existing:
        an operator pruning instances under a running producer left the deleted race's entry at the
        head of a start-ordered queue (oldest gun first), where the hand-back loop re-offered it
        every poll â€” silently, its NO-BOATS refusal long since logged once â€” and every race behind
        it starved. Measured 2026-08-10: a producer that "waited" for hours behind a race that had
        been deleted at 08:05.r   N)r—   r    Úpop)r¢   r¨   r®   s      r   ÚdropzOnAirQueue.drop§  s?   € ð %)§M¡MÖF˜q°Q°q±T¸XÓ5EšÒFˆŒØ�‰×Ñ˜8 TÕ*ùò Gs
   �A�Ac                óN   — |r#| j                   €| j                  «       | _         yyy)a  Legacy result-only input used by old simulations and callers.

        Production supplies structured finisher progress through :meth:`note_finish_progress`; this
        boolean remains as an availability fallback for a scorer that cannot name its finishers.
        N)rš   r–   )r¢   Ú
has_winners     r   Únote_resultzOnAirQueue.note_result³  s$   € ñ ˜$Ÿ,™,Ð.ØŸ9™9›;ˆD�Lð /ˆ:r   c               ó|  — t        |t        «      syd| _        | j                  €| j	                  «       | _        |j                  d«      xs g D �cg c]#  }t        |t        «      r|j                  d«      ‘Œ% }}	 t        |j                  d«      xs d«      }|D �cg c]8  }t        |t        t        f«      r t        j                  t        |«      «      r|‘Œ: }}t        ||| j                  ¬«      }|�¤t        |t        t        f«      r�t        j                  t        |«      «      rnt        |«      | j                  z
  |k\  rR| j                  s>| j	                  «       | _        |dkD  xr t#        |«      |k\  xr | j$                   | _        d| _        yyyyyc c}w # t        t        f$ r d}Y �Œw xY wc c}w )aa  Update the lag-aware last/penultimate hand-over gate from the scorer's live result.

        ``frontier_sec`` is source race-time. The viewer presents ``frontier - lag``; requiring it to
        reach the target is what prevents a 15-second source-side timeout from cutting away before
        the audience has even seen the penultimate finish.
        NTÚ	finishersÚ	finishSecÚexpectedFinishersr   rV   )r[   Údictr›   rš   r–   r*   r   rb   rc   r\   r]   r^   ri   r�   r�   rœ   r�   rd   r—   rž   )	r¢   ÚresultÚfrontier_secr   re   rg   r_   Úverified_finishersÚtargets	            r   Únote_finish_progresszOnAirQueue.note_finish_progress¼  s§  € ô ˜&¤$Ô'ØØ$(ˆÔ!Ø�<‰<ÐØŸ9™9›;ˆDŒLØ8>¿
¹
À;Ó8OÒ8UÐSUö 1°Ü$ S¬$Ô/ð —w‘w˜{Õ+ð 1ˆð 1ð	Ü˜6Ÿ:™:Ð&9Ó:Ò?¸aÓ@ˆHð .9ö ^ cÜ!+¨C´#´u°Ô!>Ä4Ç=Á=ÔQVÐWZÓQ[ÔC\ò "ð ^Ðð ^ä$Ø˜¨$×*<Ñ*<ô>ˆàÐ¤:¨l¼SÄ%¸LÔ#IÜ—M‘M¤%¨Ó"5Ô6Ü˜,Ó'¨$×*AÑ*AÑAÀVÒKØ×%Ò%Ø(,¯	©	«�Ô%à˜q‘LÒ^¤SÐ);Ó%<ÀÑ%HÒ^ÐQU×Q^ÑQ^ÐM^ð Ô*à!%ˆDÕð Lð 7ð $JÐùò1øô œ:Ð&ò 	Ø‹Hð	üò^s   Á(FÁ<F! Â=F9Æ!F6Æ5F6F©Úoverc               ó`  — | j                   €y| j                  «       }| j                  ry| j                  €y|| j                  z
  }| j                  rB| j                  «       r|| j                  k\  S |t        | j                  | j                  «      k\  S || j                  k\  S | j                  r9t        |xr, | j                  duxr || j                  z
  | j                  k\  «      S | j                  �|| j                  z
  | j                  k\  S |xr || j                  z
  | j                  k\  S )u×  Has the race on air finished its story â€” a scored winner plus the hold on the finish, or it
        closed without one (`over`) and has had its minimum airtime?

        Answered whether or not anything is waiting, because the two cases differ: with a race queued
        the producer hands over to it; with NOTHING queued it must return to the waiting presentation
        rather than sit frozen on the result for ever (`release()`). Nothing on air â‡’ trivially done.NTF)r˜   r–   rœ   r�   rž   r½   r‘   rN   r’   r›   r…   rš   r�   r™   rŽ   )r¢   rÏ   ÚnowÚelapseds       r   ÚdonezOnAirQueue.doneÛ  s&  € ð �<‰<ÐØØ�i‰i‹kˆØ×ÒØ×$Ñ$Ð,ØØ˜D×1Ñ1Ñ1ˆGØ×)Ò)ð ×(Ñ(Ô*Ø" d×&;Ñ&;Ñ;Ð;Ø¤# d×&;Ñ&;¸T×=XÑ=XÓ"YÑYÐYØ˜d×3Ñ3Ñ3Ð3Ø×$Ò$ô ˜ò E §¡°TÐ!9ò EØ $§,¡,Ñ.°$×2DÑ2DÑDóFð Fà�<‰<Ð#Ø˜Ÿ™Ñ%¨×);Ñ);Ñ;Ð;ØÒ?˜˜dŸo™oÑ-°·±Ñ?Ð?r   c                ót   — d| _         d| _        d| _        d| _        d| _        d| _        d| _        d| _        y)u¼   Nothing is on air any more â€” the producer went back to the waiting presentation. The next
        release goes up immediately instead of queueing behind a race that is no longer showing.NF)r˜   r¡   rš   r›   rœ   r�   rž   rŸ   r¥   s    r   ÚreleasezOnAirQueue.releaseú  sB   € ð ˆŒØˆÔØˆŒØ$)ˆÔ!Ø"ˆÔØ $ˆÔØ%*ˆÔ"Ø%*ˆÕ"r   c                óJ   — | j                   }| j                  «        || _        y)uV   Release an expired isolated finish while retaining its Tâˆ’3 gate in the waiting view.N)rž   rÕ   rŸ   )r¢   Úkeep_close_start_gates     r   Úrelease_to_waitingzOnAirQueue.release_to_waiting  s   € à $× :Ñ :ÐØ�‰ŒØ%:ˆÕ"r   c               ó˜   — | j                   �| j                  |¬«      sy| j                  sy| j                  xr | j	                  «        S )u  Whether the completed on-air race should yield to the waiting presentation now.

        An ordinary completed race does so only when no race is queued. An isolated full finish also
        does so when its minute has expired but every newly armed race is still outside Tâˆ’3.
        rÎ   FT)r˜   rÓ   r—   rž   r½   )r¢   rÏ   s     r   Úwaiting_view_duezOnAirQueue.waiting_view_due  sE   € ð �<‰<Ð t§y¡y°d yÔ';ØØ�}Š}ØØ×)Ñ)ÒI°$×2GÑ2GÓ2IÐ.IÐIr   c               ó  — | j                  «       }|�ë| j                  j                  |«       | j                  �l| j                  |d   k7  rZ| j                  �N| j                  j                  | j                  | j                  f«       | j                  j                  d„ ¬«       |d   |d   c| _        | _        | j                  «       dc| _        | _	        d\  | _
        | _        d| _        d| _        d| _        |S | j                  €$| j                  r| j                  «       syd| _        | j                  r| j!                  |¬«      sy| j                  �| j                  r| j                  «       syt#        | j                  «       d	z  «      }| j                  €x| j                  D �cg c]  }|d   €Œ	t#        |d   «      |k  sŒ|‘Œ }}|rEt%        |d
„ ¬«      }| j                  j                  |«       | j                  j'                  d|«       | j                  j)                  d«      }|d   |d   c| _        | _        | j                  «       dc| _        | _	        d\  | _
        | _        d| _        d| _        d| _        |S c c}w )uK  The race that started NEXT, or None to stay put. `over` = the on-air race closed WITHOUT a
        scored winner.

        Always the head of a start-ordered queue, so the broadcast follows the regatta in the order it
        is sailed and never steps over a race. A race the caller then finds it cannot present yet must
        be handed back with `release()` + `offer()`, which returns it to its own place â€” NOT to the
        back of the queue, and never simply dropped.

        **A prioritised race jumps this entirely** (`_preemptor`), whether or not the race on air is
        done. The interrupted race is re-queued at its original gun: the flag means "show this now",
        not "erase the programme item currently showing". Once the producer has accepted a race into
        its live programme, no later gun may silently erase it.Nr   c                ó"   — | d   d u | d   xs dfS r²   r³   r´   s    r   r   z&OnAirQueue.take_next.<locals>.<lambda>.  s   € °!°A±$¸$°,ÀÀ!ÁÂ	ÈÐ1J€ r   r&   r`   )FFFrÎ   rL   c                ó   — t        | d   «      S ©Nr`   r   r´   s    r   r   z&OnAirQueue.take_next.<locals>.<lambda>L  s   € ´C¸¸!¹³I€ r   )r¯   r—   Úremover˜   r¡   rµ   r¶   r–   r™   rš   r›   rœ   r�   rž   rŸ   r½   rÓ   r   r-   Úinsertr¿   )r¢   rÏ   Úprer   r®   r    ÚoldestÚnxts           r   Ú	take_nextzOnAirQueue.take_next  sB  € ð �o‰oÓˆØˆ?Ø�M‰M× Ñ  Ô%Ø—‘Ð(¨T¯\©\¸SÀ¹VÒ-CØ×(Ñ(Ð4ð —‘×$Ñ$ d§l¡l°D×4DÑ4DÐ%EÔFØ—‘×"Ñ"Ñ'JÐ"ÔKØ-0°©V°S¸±VÐ*ˆDŒL˜$Ô*Ø,0¯I©I«K¸Ð)ˆDŒO˜Tœ\Ø<HÑ9ˆDÔ% tÔ'9Ø$(ˆDÔ!Ø).ˆDÔ&Ø).ˆDÔ&ØˆJð �<‰<Ð D×$>Ò$>Ø×(Ñ(Ô*ØØ).ˆDÔ&Ø�}Š} D§I¡I°4 IÔ$8Øð �<‰<Ð#¨×(BÒ(BÈ4×K`ÑK`ÔKbØÜ�T—Y‘Y“[ 4Ñ'Ó(ˆØ�<‰<Ðð
 #'§-¡-Ö\˜Q°1°Q±4Ñ3CÌÈAÈaÉDË	ÐU[ÓH[’qÐ\ˆGÐ\ÙÜ˜WÑ*=Ô>�Ø—‘×$Ñ$ VÔ,Ø—‘×$Ñ$ Q¨Ô/Ø�m‰m×Ñ Ó"ˆØ),¨Q©°°Q±Ð&ˆŒ�dÔ&Ø(,¯	©	«°TÐ%ˆŒ˜œØ8DÑ5ˆÔ! 4Ô#5Ø $ˆÔØ%*ˆÔ"Ø%*ˆÔ"Øˆ
ùò ]s   Æ,
J	Æ7J	Ç	J	)r�   r\   rŽ   úfloat | Noner�   r\   r�   r\   r‘   r\   r’   r\   r“   r   r”   zCallable[[], float]rB   ÚNone)rB   ú
str | None)r¨   r,   r©   r…   rB   ræ   )rB   útuple | None)r¨   r,   rB   r…   )rB   z	list[str])rB   r…   )r¨   r,   rB   ræ   )rÂ   r…   rB   ræ   )rÉ   zdict | NonerÊ   rå   rB   ræ   )rÏ   r…   rB   r…   )rB   ræ   )rÏ   r…   rB   rè   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚRESULT_HOLD_SÚPRESENTATION_LAG_SÚFINISH_TAIL_SÚRESULT_VISIBLE_SÚISOLATED_FINISH_HOLD_SÚPOST_FINISH_NEXT_LEAD_MSÚtimer£   Úpropertyr¦   rª   r¯   r¸   rº   r½   rÀ   rÃ   rÍ   rÓ   rÕ   rØ   rÚ   rä   r³   r   r   rŒ   rŒ   '  sÖ   „ ñPð$ 2?ÐZ^Ø-?Ø(5Ø+;Ø1GØ1IØ/3¯y©yñ!,Ø%*ð!,à %ð!,ð $)ð!,ð */ð	!,ð
 ,/ð!,ð -ð!,ð >Bó!,ðF òó ðó2óó2Eó*-ó
ó
+ó'ó&ð> $)õ @ó>
+ó;ð 05õ 
Jð ).ö >r   rŒ   c            
      óº   — e Zd ZdZdddddddd	d
dœ	Zddedddœ	 	 	 	 	 	 	 	 	 dd„Zdd„Zedd„«       Z	dd„Z
dd„Zd d„Zd!d„Zd"d„Zdd„Zdd„Zd#d„Zd$d„Zd%d„Zy)&ÚStartedRacesu  The operator's races on one course, reported as they GO OFF.

    `list_instances()` returns the management rows (`store.list_race_instances(...)` or the wire rows of
    `GET /v3/manage/instances`); `poll()` returns every race whose START SEQUENCE has begun since the
    last call â€” gun set, no stop, not abandoned or cancelled, and now within `lead_ms` of the gun â€”
    oldest gun first, so the queue airs them in the order they are sailed. `closed()` answers the other
    half of the hand-over: whether the race on air has been stopped or abandoned by the operator.

    A race goes on air DURING its pre-start rather than at its gun: the sequence IS broadcast material
    (the opening, course guide, countdown, fleet setting up and line approach), and waiting for the
    gun would put the race on screen already started. Specifically it joins on the race office's
    start-countdown trigger (`announce_lead_ms`) at the beginning of the event's declared sequence.
    A race scheduled further out than that simply waits until its sequence reaches that point.

    A race whose gun is MOVED after it was reported is reported again (the operator re-armed it); one
    that is stopped and re-armed likewise. That is what makes it safe to leave the producer running for
    a whole regatta day.)r   Úinstance_idÚid)ÚofficialStartUtcMsÚofficial_start_utc_ms)ÚofficialStopUtcMsÚofficial_stop_utc_ms)Ú	raceStateÚ
race_state)ÚcourseIdÚ	course_id)ÚownerUserIdÚowner_user_idÚownerUsername)Úname)r©   )ÚpreliminaryWinnerTeamIdÚpreliminary_winner_team_id)	rø   r   r   r	   ÚcourseÚownerr  r©   ÚpreliminaryN)r   r  Úlead_msÚpre_start_forr   c               óÄ   — || _         |xs d | _        |xs d | _        t        |«      | _        || _        i | _        |xs d„ | _        i | _        i | _	        ddddœ| _
        y )Nc                 óB   — t        t        j                  «       dz  «      S )NrL   )r   ró   r³   r   r   r   z'StartedRaces.__init__.<locals>.<lambda>—  s   € ¬#¬d¯i©i«k¸DÑ.@Ó*A€ r   r   )ÚlistedÚin_scopeÚeligible)Ú_listr   r  r   r
  Ú_pre_start_forÚ_pre_start_cacheÚ_now_msÚ	_reportedÚ_rowsÚ
last_stats)r¢   Úlist_instancesr   r  r
  r  r   s          r   r£   zStartedRaces.__init__€  sn   € ð $ˆŒ
ð #Ò* dˆŒØ’]˜dˆŒ
ô ˜7“|ˆŒð ,ˆÔØ79ˆÔØÒBÑ"AˆŒØ)+ˆŒØ&(ˆŒ
ð
 &'°AÀ1ÑEˆ�r   c                ó  — | j                   €| j                  S || j                  vr	 | j                  |«      | j                  |<   | j                  |   }|rt	        |«      S | j                  S # t        $ r | j                  cY S w xY w)uh  This race's own lead-in â€” `announce_lead_ms` of its event's sequence, else `lead_ms`.

        Per race rather than per producer: a broadcast following an operator can see races from more
        than one event, and their sequences need not agree. Memoised because a race does not change
        event, and this is asked of every race on every poll.
        )r  r
  r  Ú	ExceptionrP   )r¢   r÷   rá   s      r   Úlead_forzStartedRaces.lead_for   sŒ   € ð ×ÑÐ&Ø—<‘<ÐØ˜d×3Ñ3Ñ3ð$Ø59×5HÑ5HÈÓ5U�×%Ñ% kÑ2ð ×#Ñ# KÑ0ˆÙ(+Ô Ó$Ð=°·±Ð=øô ò $Ø—|‘|Ò#ð$ús   ¨A. Á.BÂBc                ó˜   — | j                   |   D ]8  }t        |t        «      r||v sŒ||   c S t        ||«      sŒ,t	        ||«      c S  y rZ   )Ú_FIELDSr[   rÈ   ÚhasattrÚgetattr)Úclsr   r   r  s       r   Ú_getzStartedRaces._get±  sQ   € à—K‘K Ñ$ò 	*ˆDÜ˜#œtÔ$Ø˜3’;Ø˜t™9Ò$Ü˜˜dÕ#Ü˜s DÓ)Ò)ð	*ð r   c                ón  — i }d}| j                  «       xs g D ]ë  }| j                  |d«      }|€Œ|dz  }| j                  �!| j                  |d«      d | j                  fvrŒJ| j                  �!| j                  |d«      d | j                  fvrŒw| j                  |d«      | j                  |d«      | j                  |d«      | j                  |d	«      t	        | j                  |d
«      «      | j                  |d«      dœ||<   Œí || j
                  d<   t        |«      | j
                  d<   || _        |S )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  rd   r  )r¢   r0   r  r   r5   s        r   Ú	_snapshotzStartedRaces._snapshot»  s1  € ØˆØˆØ—J‘J“LÒ& Bò 	GˆCØ—)‘)˜C Ó&ˆCØˆ{ØØ�a‰KˆFØ�~‰~Ð)¨d¯i©i¸¸XÓ.FÈtÐUY×UcÑUcÐNdÑ.dØØ�z‰zÐ%¨$¯)©)°C¸Ó*AÈ$ÐPT×PZÑPZÐI[Ñ*[ØØ $§	¡	¨#¨uÓ 5¸t¿y¹yÈÈfÓ?UØ"&§)¡)¨C°Ó"9À4Ç9Á9ÈSÐRXÓCYÜ%)¨$¯)©)°C¸Ó*DÓ%EØ(,¯	©	°#°}Ó(EñGˆD�ŠIð	Gð %+ˆ�‰˜Ñ!Ü&)¨$£iˆ�‰˜
Ñ#ØˆŒ
Øˆr   c                ó   — || j                   v S )uÏ  Does the race plane still LIST this race (as of the last snapshot)?

        The other half of `OnAirQueue.drop`: the queue cannot know a race was deleted â€” only the
        watcher reads the plane â€” so the follow loop asks here before re-offering a race it had to
        hand back. Distinct from `closed()`: a stopped race existed and is over; a vanished race
        was deleted out from under the broadcast (an operator's prune) and must simply be let go.)r  )r¢   r÷   s     r   ÚlistszStartedRaces.listsÐ  s   € ð ˜dŸj™jÐ(Ð(r   c                ó¬  — | j                  «       }g }d}| j                  «       j                  «       D ]ƒ  \  }}|d   |d   |d   }}}|�|€|dv s|| j                  |«      z
  |kD  rŒ5|dz  }| j                  j                  |«      |k(  rŒY|| j                  |<   |j                  |t        |«      f«       Œ… || j                  d<   t        |d„ ¬	«      S )
zv`[(instance_id, gun_ms)]` for every race whose start sequence has begun since the last poll,
        oldest gun first.r   r   r   r	   r
   r`   r  c                ó   — | d   S rÞ   r³   r´   s    r   r   z#StartedRaces.poll.<locals>.<lambda>ô  s
   € ¨¨1©€ r   r&   )
r  r#  Úitemsr  r  r*   rµ   r   r  r+   )	r¢   rÑ   r‰   r  r5   r   r   r   r	   s	            r   ÚpollzStartedRaces.pollÙ  sæ   € ð �l‰l‹nˆØˆØˆØŸ™Ó(×.Ñ.Ó0ò 	(‰HˆC�Ø" 5™z¨3¨v©;¸¸G¹�u�ˆCð �˜tÐ/°5Ð<VÑ3VØ˜TŸ]™]¨3Ó/Ñ/°#Ò5Øð ˜‰MˆHØ�~‰~×!Ñ! #Ó&¨#Ò-ØØ"%ˆD�N‰N˜3ÑØ�J‰J˜œS ›X�Õ'ð'	(ð( '/ˆ�‰˜
Ñ#Ü�c™~Ô.Ð.r   c           
     óš   — | j                   j                  «       D ��ci c]   \  }}|t        |j                  d«      «      “Œ" c}}S c c}}w )u–  `{instance_id: priority}` from the last snapshot â€” every race the watcher can see, not only
        the ones that just started.

        The producer feeds this into `OnAirQueue.set_priority` on every tick, which is what makes a
        flag set (or cleared) mid-race take effect. Reads the snapshot rather than re-listing, so it
        costs nothing and cannot disagree with the poll it was taken from.r©   )r  r(  r…   r*   ©r¢   r5   r   s      r   Ú
prioritieszStartedRaces.prioritiesö  s>   € ð @D¿z¹z×?OÑ?OÓ?Q×R±8°3¸�”T˜#Ÿ'™' *Ó-Ó.Ñ.ÓRÐRùÓRs   ž%Ac                ó‚   — | j                   j                  «       D ��cg c]  \  }}d|it        |«      ¥‘Œ c}}S c c}}w )zIScoped race-plane rows for the independent start-vessel overlay selector.r   )r  r(  rÈ   r+  s      r   Ústart_camera_rowszStartedRaces.start_camera_rowsÿ  s5   € àAEÇÁ×AQÑAQÓAS×T±X°S¸#�˜sÐ0¤d¨3£iÒ0ÓTÐTùÓTs   ž;c                ó^   — | j                   j                  |«      }|€y|d   duxs |d   dv S )zUTrue once the operator has stopped or abandoned this race (the last snapshot's view).NFr   r	   r
   ©r  r*   ©r¢   r÷   r   s      r   ÚclosedzStartedRaces.closed  s:   € à�j‰j�n‰n˜[Ó)ˆØˆ;ØØ�6‰{ $Ð&ÒT¨#¨g©,Ð:TÐ*TÐTr   c                ód   — | j                   j                  |«      }t        |duxr |d   dv «      S )aä  True only when the race plane explicitly says this race must not be presented.

        A stop timestamp is deliberately *not* cancellation.  Normal completed races receive the
        same timestamp, and an overlapping race may finish while it waits behind the programme race.
        Removing every stopped pending race silently skipped that completed race.  Only the race
        office's explicit abandoned/cancelled state authorises dropping it from the broadcast queue.
        Nr	   r
   )r  r*   r…   r1  s      r   r   zStartedRaces.cancelled
  s4   € ð �j‰j�n‰n˜[Ó)ˆÜ�C˜t�OÒR¨¨G©Ð8RÐ(RÓSÐSr   c                ó„   — | j                   j                  |«      xs i }|j                  d«      |j                  d«      fS )zLThe race plane's preliminary winner and stop time from the current snapshot.r	  r   r0  r1  s      r   Úpreliminary_resultzStartedRaces.preliminary_result  s5   € à�j‰j�n‰n˜[Ó)Ò/¨RˆØ�w‰w�}Ó% s§w¡w¨v£Ð6Ð6r   c                óâ   — | j                  «       }| j                  j                  «       D �cg c]   }|d   �|d   |kD  r|d   €|d   dvr|d   ‘Œ" }}|rt        t	        |«      «      S dS c c}w )a  The earliest FUTURE gun on the plane (last snapshot): a race ARMED and counting down,
        None when nothing is. This is both the waiting picture's recall signal and the programme
        transition: the same ARM that recalls an idle excursion starts the full race presentation.r   Nr   r	   r
   )r  r  rh   r   r-   )r¢   rÑ   r   Úgunss       r   Únext_gun_mszStartedRaces.next_gun_ms  s‡   € ð �l‰l‹nˆØ&*§j¡j×&7Ñ&7Ó&9ö \˜sØ�u‘:Ð)¨c°%©j¸3Ò.>Ø˜‘KÐ'¨C°©LÐ@ZÑ,Zð �E“
ð \ˆð \ñ "&Œs”3�t“9‹~Ð/¨4Ð/ùò\s   ­%A,c                óJ   — | j                   j                  |«      }|r|d   S d S )Nr  r0  r1  s      r   Úname_ofzStartedRaces.name_of$  s%   € Ø�j‰j�n‰n˜[Ó)ˆÙ!ˆs�6‰{Ð+ tÐ+r   )r  zCallable[[], list]r   rç   r  rç   r
  r   r  z"Callable[[str], int | None] | Noner   zCallable[[], int] | NonerB   ræ   )r÷   r,   rB   r   )r   r,   )rB   zdict[str, dict])r÷   r,   rB   r…   )rB   zlist[tuple[str, int]])rB   zdict[str, bool]©rB   ú
list[dict])r÷   r,   rB   ztuple[str | None, int | None])rB   ú
int | None)r÷   r,   rB   rç   )ré   rê   rë   rì   r  rM   r£   r  Úclassmethodr!  r#  r%  r)  r,  r.  r2  r   r5  r8  r:  r³   r   r   rö   rö   Y  sÆ   „ ñð< 9ØEØDØ3Ð?XØIÐS\Ø(ØWñY€Gð W[Ø%)¸,ØEIØ48ñFØ"ðFØ47ðFà BðFð 2ðFð >BóFó@>ð" òó ðóó*)ó/ó:SóUóUó	Tó7ó
0ô,r   rö   rZ   )r0   r<  r   r   r1   zdict[str, int] | NonerB   rÈ   r;  )rO   r=  rB   r   )re   zlist[float] | tuple[float, ...]rf   r   rW   r\   rB   rå   )rm   r   rk   r   rB   ztuple[int, int])ru   rç   rB   r=  )rm   r   ru   rç   rx   r…   ry   rç   rz   r…   rk   r   rB   rÈ   )rì   Ú
__future__r   r]   rr   ró   Úcollections.abcr   rM   r/   r.   r:   rI   rJ   rP   r¬   rí   rî   rï   rð   rñ   rò   ri   ro   rw   rŠ   rŒ   rö   r³   r   r   ú<module>rA     s  ðñ'õP #ã Û 	Û Ý $ð €ð
 $*Ð  Ø%Ð ð LPð Ø3Hð ØTXó ðHÐ ó7ó+ð< Ð ð  €ð Ð ð €ð Ð ð Ð ð
 #Ð ð ,9ñØ#(ðØ=Ióð. 5Gõ ó 
*ð ?CÐW[Ø37Ø16Ø 2ñ*Ø&0ð*à*.ð*ð ð*ð 8<ó*÷Zoñ o÷d	M,ò M,r   