ó
    }¬j¢C  ã                   ó®  • S r SSKrSSKrSSKJr  SSKJr  Sr\R                  " S5      r	\R                  " S5      r
\R                  " S	5      r\R                  " S
5      r\R                  " S5      r\R                  " S5      r\R                  " S5      r1 Skr1 Skr/ SQr/ SQrSrS rS rS rSS jrSS jrSS jrS S jrS!S jrS rS rSS jrg)"aé  
DealerWay reader.

DealerWay (dealerway.co.uk) is a fifth auction platform, added 2026-08-24
(Mark: "similar to a4c and dealer auction"). Real reconnaissance done first
(golden rule 2), logged in with Mark present, captured against the real
Listings screen and one real car's own detail page (data/inspect/
dealerway_tab0.html, dealerway_detail.html).

The site is a React Native Web single page app: every class name is an auto
generated atomic utility ("css-175oi2r", "r-1mtiv16", ...), meaningless and
unstable, so unlike every other reader in this project this one does not
parse raw HTML text at all. Instead it runs a small JS extraction in the
page itself (_EXTRACT_JS) that walks the real DOM structurally (each card is
one real `<a href="/listings/<id>">`, found live, not guessed) and returns
one plain dict per card: its own visible text (line by line, the same shape
already proven reliable for LE Capital's plain text parsing) plus the three
status icons' own real state, read from each icon's background colour
rather than its (also meaningless) class name.

Status icon colours, confirmed against a real detail page (BU19DDL): green
(rgb(0,210,103), a tick shaped path) means the flag is clear, red
(rgb(223,3,3), a cross shaped path) means it is not. Verified two ways:
that same car's own detail page reads "No Bodywork Issues Reported" for a
green Bodywork icon, and a genuine disclosed mechanical fault ("has a
little whistle... boosts well no lights on dash no codes") for a red
Mechanical / Electrical icon. A third colour (blue, or a pale grey) is also
seen and treated as unknown, never guessed as either state.

No numeric reserve is ever shown anywhere, list or detail page (checked,
including the raw HTML for a hidden script value the way Auction4Cars
turned out to have one; none found here). The list card's own Current Bid
(once a bid exists) or Starting Price (before any bid) stands in for
reserve, the same "platform's own real figure, never a guess" reasoning
already used for Auction4Cars and Dealer Auction's own reserve stand ins.

No 1 to 5 condition grade exists either, only these pass/fail flags, so the
grade gate is skipped for this source the same way it already is for
Auction4Cars (assume_grade_ok=True in daily_run.py). Distance IS given
directly and exactly ("209 Miles Away") on every card, so the normal
distance gate applies unlike Auction4Cars or Dealer Auction.

Auctions run on their own per lot countdown (a live "DD:HH:MM:SS" string,
not a real timestamp anywhere in the page), so auction_ends_at is computed
as now() plus that duration at read time, an approximation accurate to
about the few seconds a read takes, the same shape Auction4Cars' own
countdown already uses on the cockpit.

"Bodywork Issues" has no established hard gate rule anywhere else in this
project (only a known MECHANICAL issue is a hard reject, an electrical one
stays a flag), so a bodywork issue here is also kept as a flag (car.notes),
not a rejection, until Mark says otherwise. A known Electrical or Mechanical
issue (DealerWay discloses both under one combined flag, no way to tell
them apart) maps to car.mech_issue, a hard reject, matching the existing
"any known mechanical issue rejects regardless" rule played safe.

Nothing here bids. It reads the screen only.
é    Né   )ÚCar)Úbrowserz https://dealerway.co.uk/listingsu   Â£\s*([\d,]+)z^(\d+(?:\.\d+)?)\s*Miles Away$z^([\d,]+)\s*miles$z^(19[89]\d|20[0-4]\d)$z^[A-Z0-9]{2,8}$z^(\d+):(\d+):(\d+):(\d+)$z^\d(?:\.\d)?\s*\(\d+\)$>   ÚCVTÚManualÚ	AutomaticúSemi-Automatic>   ÚDieselÚHybridÚPetrolÚElectricúPlug-in Hybrid)z
LAND ROVERzMERCEDES-BENZzMERCEDES BENZz
ALFA ROMEOzASTON MARTINz
GREAT WALL)zTest DrivenÚBodyworkúMechanical / Electricalan  
() => {
  const anchors = Array.from(document.querySelectorAll('a[href^="/listings/"]'));
  const labels = ['Test Driven', 'Bodywork', 'Mechanical / Electrical'];
  return anchors.map(a => {
    const iconStates = {};
    labels.forEach(label => {
      const labelEl = Array.from(a.querySelectorAll('div')).find(
        d => d.children.length === 0 && d.textContent.trim() === label);
      if (labelEl) {
        const row = labelEl.parentElement;
        const iconWrap = row.querySelector('div[style*=background-color]');
        const bg = iconWrap ? iconWrap.getAttribute('style') : '';
        iconStates[label] = bg.includes('0, 210, 103') ? 'ok'
          : (bg.includes('223, 3, 3') ? 'issue' : 'unknown');
      } else {
        iconStates[label] = null;
      }
    });
    return {href: a.getAttribute('href'), text: a.innerText, iconStates: iconStates};
  });
}
c                 óN   • SR                  S U R                  5        5       5      $ )NÚ c              3   óŒ   #   • U  H:  oR                  5       (       a  [        U5      S :”  a  UR                  5       OUv •  M<     g7f)é   N)ÚisupperÚlenÚ
capitalize)Ú.0Úws     Ú;/Users/stevendouglas/BidBrain/bidbrain/readers/dealerway.pyÚ	<genexpr>Ú_title_case.<locals>.<genexpr>p   s/   é € Ð^ÒT]Èq¯)©)¯+©+¼¸Q»À!»�A—L‘L”NÈÔJÒT]ùs   ‚AA)ÚjoinÚsplit)Úss    r   Ú_title_caser    o   s!   € Ø�8‰8Ñ^ÐTU×T[ÑT[ÔT]Ó^Ó^Ð^ó    c                 óà  • U =(       d    SR                  5       R                  5       n[         H[  nUR                  U5      (       d  M  U R                  5       [	        U5      S  R                  5       n[        U5      [        U5      4s  $    U =(       d    SR                  5       R                  SS5      nU(       a  US   OSn[	        U5      S:”  a  US   OSn[        U5      [        U5      4$ )NÚ r   é   r   )ÚstripÚupperÚ_MULTI_WORD_MAKESÚ
startswithr   r    r   )ÚtitleÚupÚmkÚrestÚpartsÚmakeÚmodels          r   Ú_split_make_modelr0   s   sÁ   € Ø
�+�2×	Ñ	Ó	×	$Ñ	$Ó	&€BßˆØ�=‰=˜×ÓØ—;‘;“=¤ R£ Ð*×0Ñ0Ó2ˆDÜ˜r“?¤K°Ó$5Ð5Ò5ñ  ð �[�b×ÑÓ!×'Ñ'¨¨QÓ/€EÞˆ5�Š8 "€DÜ˜E›
 Q›ˆE�!ŠH¨B€EÜ�tÓœk¨%Ó0Ð0Ð0r!   c                 ó¢   • U (       d  g [         R                  U 5      nU(       a*  [        UR                  S5      R	                  SS5      5      $ S $ )Nr$   Ú,r#   )ÚMONEYÚsearchÚintÚgroupÚreplace)r   Úms     r   Ú_moneyr9      s<   € ÞØÜ�‰�Q‹€AÞ/0Œ3ˆq�w‰w�q‹z×!Ñ! # rÓ*Ó+Ð:°dÐ:r!   c                 ó:  • [         R                  U =(       d    S5      nU(       d  gS UR                  5        5       u  p4pVU=(       d    [        R                  R	                  5       nU[        R
                  " X4XVS9-   nUR                  SS9R                  5       $ )Nr#   c              3   ó8   #   • U  H  n[        U5      v •  M     g 7f©N)r5   )r   Úxs     r   r   Ú_end_time.<locals>.<genexpr>Š   s   é € Ð$@²Z°¤S¨§V V²Zùs   ‚)ÚdaysÚhoursÚminutesÚsecondsr   )Úmicrosecond)Ú	COUNTDOWNÚmatchÚgroupsÚdatetimeÚnowÚ	timedeltar7   Ú	isoformat)Ú	countdownrH   r8   r?   r@   rA   rB   Úends           r   Ú	_end_timerM   †   sy   € Ü�‰˜	Ÿ RÓ(€AÞØÙ$@°Q·X±X´ZÓ$@Ñ!€D�Ø
×
(”×"Ñ"×&Ñ&Ó(€CØ
”×"Ò"¨À7Ñ\Ñ
\€CØ�;‰; 1ˆ;Ð%×/Ñ/Ó1Ð1r!   c                 óÚ  • U R                  S5      =(       d    SR                  5        Vs/ s H)  o"R                  5       (       d  M  UR                  5       PM+     nnU(       a	  US   S:w  a  g[        U5      S:  a  gSn[	        X4   U5      nUS-  nU[        U5      :¼  d  [
        R                  X4   5      (       d  gX4   nUS-  nSnU[        U5      :  a=  [        R                  X4   5      nU(       a  [        UR                  S5      5      nUS-  nU[        U5      :  a  US-  nU[        U5      :  a!  [        R                  X4   5      (       a  US-  nU[        U5      :¼  a  g[        X4   5      u  pšUS-  nU[        U5      :¼  a  gX4   nUS-  nU[        U5      :  a  X4   S:X  a  US-  nSnU[        U5      :  aM  [        R                  X4   5      nU(       a/  [        UR                  S5      R                  S	S5      5      nUS-  nSnU[        U5      :  a  X4   [        ;   a	  X4   nUS-  nSnU[        U5      :  a  X4   [         ;   a	  X4   nUS-  nSnU[        U5      :  a=  ["        R                  X4   5      nU(       a  [        UR                  S5      5      nUS-  n[$         H#  nU[        U5      :  d  M  X4   U:X  d  M  US-  nM%     U[        U5      :  a  X4   S
:X  a  US-  nSnU[        U5      :  a.  X4   S;   a&  US-  nU[        U5      :  a  ['        X4   5      nUS-  nU R                  S5      =(       d    0 n[)        XiX«XüUX}UU SU 3R                  5       SSU R                  SS5      -   US9n/ nUR                  S5      S:X  a  UR+                  S5        U(       a  SR-                  U5      Ul        UR                  S5      S:X  a  SUl        U$ s  snf )aS  One dict from the real page's own _EXTRACT_JS (href, text, iconStates)
turned into a Car, or None when it is not really a live auction card (a
Buy Now only listing has no "LIVE AUCTION" line at all, kept out by the
auction only rule) or its text does not match the expected shape closely
enough to trust (never guessed, held back instead).Útextr#   r   zLIVE AUCTIONNr   r$   zFRANCHISED DEALERr2   zLive Auction)zCurrent BidzStarting PriceÚ
iconStatesr   Ú	DealerWayzhttps://dealerway.co.ukÚhref)Úregr.   r/   Ú
derivativeÚyearÚmileageÚreserveÚdistance_milesÚtransmissionÚfuelÚengineÚsourceÚlisting_urlÚauction_ends_atr   Úissuez(Bodywork issues reported on the listing.r   z8Electrical or mechanical issue disclosed on the listing.)ÚgetÚ
splitlinesr%   r   rM   ÚREGrE   Ú
MILES_AWAYÚfloatr6   ÚRATINGr0   ÚMILEAGEr5   r7   ÚTRANSMISSIONSÚFUELSÚYEARÚ_STATUS_LABELSr9   r   Úappendr   ÚnotesÚ
mech_issue)ÚcardrH   ÚlnÚlinesÚiÚends_atrS   rX   r8   r.   r/   rT   rV   rY   rZ   rU   ÚlabelrW   ÚiconÚcarrl   s                        r   Ú
parse_cardrv   �   s   € ð $(§8¡8¨FÓ#3×#9°r×"EÑ"EÔ"GÓVÒ"G˜BÏ8É8Ï:‹ZˆR�X‰XŽZÑ"G€EÐVÞ�E˜!‘H Ó.ØÜ
ˆ5ƒz�Aƒ~ØØ	€AÜ˜™ #Ó&€GØˆ�F€AàŒC�‹JƒœcŸi™i¨©×1Ñ1ØØ
‰(€CØˆ�F€Aà€NØŒ3ˆu‹:ƒ~Ü×Ñ˜U™XÓ&ˆÞÜ" 1§7¡7¨1£:Ó.ˆNØ�‰FˆAð 	Œ3ˆu‹:ƒ~Ø	ˆQ‰ˆØŒ3ˆu‹:ƒ~œ&Ÿ,™, u¡x×0Ñ0Ø	ˆQ‰ˆàŒC�‹JƒØÜ# E¡HÓ-�K€DØˆ�F€AØŒC�‹JƒØØ‘€JØˆ�F€AàŒ3ˆu‹:ƒ~˜%™(Ð&9Ó9Ø	ˆQ‰ˆà€GØŒ3ˆu‹:ƒ~Ü�M‰M˜%™(Ó#ˆÞÜ˜!Ÿ'™' !›*×,Ñ,¨S°"Ó5Ó6ˆGØ�‰FˆAà€LØŒ3ˆu‹:ƒ~˜%™(¤mÓ3Ø‘xˆØ	ˆQ‰ˆØ€DØŒ3ˆu‹:ƒ~˜%™(¤eÓ+Ø‰xˆØ	ˆQ‰ˆØ€DØŒ3ˆu‹:ƒ~Ü�J‰J�u‘xÓ ˆÞÜ�q—w‘w˜q“z“?ˆDØ�‰FˆA÷
  ˆØŒs�5‹z�>˜e™h¨%Õ/Ø�‰FŠAñ  ð 	Œ3ˆu‹:ƒ~˜%™( nÓ4Ø	ˆQ‰ˆà€GØŒ3ˆu‹:ƒ~˜%™(Ð&GÓGØ	ˆQ‰ˆØŒs�5‹z‹>Ü˜U™XÓ&ˆGØ�‰FˆAà�8‰8�LÓ!×' R€DÜ
Ø %Ø¨GØ%ÀtØ�˜Q˜t˜fÐ%×+Ñ+Ó-ØØ-°·±¸ÀÓ0DÑDØñ€Cð €EØ‡x�x�
Ó˜wÓ&Ø�‰Ð?Ô@ÞØ—H‘H˜U“OˆŒ	Ø‡x�xÐ)Ó*¨gÓ5ØSˆŒØ€Jùò Ws   «O(ÁO(c                 óÔ  • U=(       d    [         R                   R                  5       nU=(       d    [         R                  R                  5       nU[         R                  " US9-   n/ nU  Hz  n[        XbS9nUc  M  UR                  (       aG  [         R                   R                  UR                  5      R                  5       nXs=::  a  U::  d  O  Mi  UR                  U5        M|     U$ )aÚ  cards is _EXTRACT_JS's own return value (a list of {href, text,
iconStates} dicts). now is the reference clock for turning a live
countdown into a real end time, defaults to datetime.now().

today restricts to lots ending within days_ahead days (None means no
date filter, used for a plain parse test). Originally kept only today
or tomorrow, the same narrow window Auction4Cars started with; found
live 2026-08-24 (Mark: "im showing no available cars however when i
search the auction site... i have 2 live auctions") that DealerWay's
own lots genuinely run several days too (a real live check found 3 of
7 real cards ending 2026-08-27, 3 days out, silently dropped by the
old window before they ever reached the gate, one of them well within
range on distance too), so widened to the same 7 day default and the
same proper INCLUSIVE RANGE check Auction4Cars was fixed to use, not
a fixed 2 date membership test (that trick only ever worked because
there were exactly two valid dates).)r?   )rH   )	rG   rH   ÚdateÚtodayrI   rv   r^   Úfromisoformatrk   )	Úcardsry   rH   Ú
days_aheadÚ
window_endÚoutrn   ru   Úend_dates	            r   Úparse_listingr€   ø   s¸   € ð" ×
(”×"Ñ"×&Ñ&Ó(€CØ×*”X—]‘]×(Ñ(Ó*€EØœ×+Ò+°Ñ<Ñ<€JØ
€CÛˆÜ˜Ñ'ˆØ‰;ÙØ××Ü×(Ñ(×6Ñ6°s×7JÑ7JÓK×PÑPÓRˆHØÕ3¨Õ3ÙØ�
‰
�3Žñ ð €Jr!   c           	      óè  • [        5       n/ n[        U5       H¿  nU R                  [        5      nU Vs/ s H  oˆR	                  S5      U;  d  M  UPM     n	nU	(       d
  U(       a    U$ UR                  S U 5       5        UR                  [        X‘US95        U R                  S5      n
U
(       d    U$  U
R                  5         U R                  S5        MÁ     U$ s  snf ! [         a       U$ f = f)a  Reads every page of the live Listings screen (the Live Auctions tab
is the page's own default, never switched to Buy Now). Pagination
clicks the real "next page" arrow, whose own aria-disabled attribute
tells us cleanly when there is no more (found live, no next page
existed at build time, so multi page clicking itself is unverified,
the disabled check itself is proven). Stops early if a click ever
returns the exact same set of listing hrefs as before, the same safety
net Dealer Auction and DealerKit's own pagination already use.rR   c              3   óB   #   • U  H  oR                  S 5      v •  M     g7f)rR   N)r`   )r   Úcs     r   r   Ú!read_all_pages.<locals>.<genexpr>)  s   é € Ð7²¨AŸ%™% Ÿ-˜-²ùs   ‚©ry   r|   zdiv[aria-disabled="false"]é°  )ÚsetÚrangeÚevaluateÚ_EXTRACT_JSr`   ÚupdateÚextendr€   Úquery_selectorÚclickÚwait_for_timeoutÚ	Exception)Úpagery   r|   Ú	max_pagesÚ
seen_hrefsr~   Ú_r{   rƒ   Ú	new_cardsÚnext_btns              r   Úread_all_pagesr—     sç   € ô “€JØ
€CÜ�9ÖˆØ—‘œkÓ*ˆÙ %ÓI¢˜1¯©¨v«¸jÑ)H—Q¡ˆ	ÐIÞžZØð €Jð 	×ÑÑ7±Ó7Ô7Ø�
‰
”= ÀJÑOÔPØ×&Ñ&Ð'CÓDˆÞØð €Jð	Ø�N‰NÔØ×!Ñ! $Ö'ñ ð €Jùò Jøô ó 	ÙØ€Jð	ús   ´CÁCÂ6!C"Ã"
C1Ã0C1c                 ó|  • [         R                  " U SUS9n UR                  (       a  UR                  S   OUR                  5       nUR	                  [
        SSS9  UR                  S5        UR                  S5      (       d  [        S	5      e[        XQUS
9UR                  5         $ ! UR                  5         f = f)NÚ	dealerway)Úheadlessr   ÚnetworkidleéÈ¯  ©Ú
wait_untilÚtimeoutiÜ  za[href^="/listings/"]z�DealerWay listings did not render any vehicles. The page may have changed or the login may have expired. Run: python3 login.py dealerway manualr…   )r   Úopen_reader_contextÚpagesÚnew_pageÚgotoÚLIST_URLr�   r�   ÚRuntimeErrorr—   Úclose)Ú
playwrightry   r|   rš   Úctxr‘   s         r   Ú	read_liver©   6  s™   € Ü
×
%Ò
% j°+ÈÑ
Q€CðØ"ŸyŸyˆs�y‰y˜Š|¨c¯l©l«nˆØ�	‰	”( }¸eˆ	ÑDØ×Ñ˜dÔ#Ø×"Ñ"Ð#:×;Ñ;Üð4ó5ð 5ô ˜d¸JÑGà�	‰	�øˆ�	‰	�ús   ˜B B) Â)B;c                 óä  ^	• U =(       d    SR                  5        Vs/ s H)  oR                  5       (       d  M  UR                  5       PM+     snm	0 nSU	4S jjnU" S5      nU(       a#  UR                  5       (       a  [        U5      US'   U" S5      nU(       a!  UR                  5       R	                  5       US'   U" S5      S	:X  a  S
US'    T	R                  S5      nUS-   [        T	5      :  a5  T	US-      S:X  a)  T	US-      S:X  a  US-   [        T	5      :  a  T	US-      US'    T	R                  S5      nUS-   [        T	5      :  a  T	US-      S:w  a  T	US-      US'    T	R                  S5      nUS-   [        T	5      :  a5  T	US-      S:X  a)  T	US-      S:X  a  US-   [        T	5      :  a  T	US-      US'   U$ s  snf ! [         a     N§f = f! [         a     N|f = f! [         a     U$ f = f)a“  Pure text parsing of a real detail page's own inner_text (so it can
be tested without a browser, the same split already used for
auction4cars.py's own _detail_fields), returning a plain dict: owners,
service_history, no_v5c, mech_issue, bodywork_issue, other_notes. A
field not found is left out of the dict entirely, never guessed, so a
caller can tell "not on this page" apart from a real empty value.r#   r$   c                 ó|   >•  TR                  U 5      nX!-   nU[        T5      :  a  TU   $ S $ ! [         a     g f = fr<   )ÚindexÚ
ValueErrorr   )rs   ÚoffsetÚidxÚjrp   s       €r   Ú_afterÚ_detail_fields.<locals>._afterP  sL   ø€ ð	Ø—+‘+˜eÓ$ˆCð ‰LˆØœs 5›z›>ˆu�Q‰xÐ3¨tÐ3øô ó 	Ùð	ús   ƒ. ®
;º;zNumber of OwnersÚownerszService RecordÚservice_historyzHas V5C LogbookÚNoTÚno_v5czElectrical or Mechanical Issuesr   zDisclosed By SellerÚYesr   rm   zBodywork IssueszNo Bodywork Issues ReportedÚbodywork_issueÚOtherÚother_notes)r$   )ra   r%   Úisdigitr5   Úlowerr¬   r   r­   )
rO   ro   r~   r±   r³   ÚserviceÚmech_idxÚbody_idxÚ	other_idxrp   s
            @r   Ú_detail_fieldsrÁ   F  s  ø€ ð $(§:¨2×"9Ñ"9Ô";ÓJÒ";˜B¿x¹x¿z‹ZˆR�X‰XŽZÑ";ÑJ€EØ
€C÷4ñ Ð&Ó'€FÞ�&—.‘.×"Ñ"Ü˜F›ˆˆH‰áÐ%Ó&€GÞØ!(§¡£×!6Ñ!6Ó!8ˆÐÑáÐÓ  DÓ(ØˆˆH‰ðØ—;‘;Ð@ÓAˆØ�a‰<œ#˜e›*Ó$¨¨x¸!©|Ñ)<Ð@UÓ)UØ˜( Q™,Ñ'¨5Ó0°XÀ±\ÄCÈÃJÓ5NØ % h°¡lÑ 3ˆC�ÑðØ—;‘;Ð0Ó1ˆØ�a‰<œ#˜e›*Ó$¨¨x¸!©|Ñ)<Ð@]Ó)]Ø$)¨(°Q©,Ñ$7ˆCÐ Ñ!ðØ—K‘K Ó(ˆ	Ø�q‰=œ3˜u›:Ó%¨%°	¸A±Ñ*>ÐBWÓ*WØ˜) a™-Ñ(¨EÓ1°iÀ!±mÄcÈ%ÃjÓ6PØ!& y°1¡}Ñ!5ˆC�Ñð €Jùò_ Køô: ó Ùðûô ó Ùðûô ó Øà€JðúsB   �F<¹F<ÃAG Ä':G Å"AG! Ç
GÇGÇ
GÇGÇ!
G/Ç.G/c                 ó  • U R                  UR                  SSS9  U R                  S5        [        U R	                  S5      5      nSU;   a
  US   Ul        SU;   a
  US   Ul        UR                  S5      (       a"  UR                  S	-   R                  5       Ul        S
U;   a
  US
   Ul
        SU;   a(  UR                  S-   US   -   R                  5       Ul        SU;   a(  UR                  S-   US   -   R                  5       Ul        U$ )a  Visits the car's own detail page for owners (the hard gate needs a
real count, never on the list card) and the free text issue
descriptions (real reasons, not just a red or green dot). Real fields
confirmed live against a captured detail page (data/inspect/
dealerway_detail.html): "Number of Owners", "Bodywork Issues",
"Electrical or Mechanical Issues" each with "Disclosed By Seller" plus
a free text line, and a separate "Other" disclosure. Never guessed:
a field not found on the page is left on the car as it was, never
invented.r›   rœ   r�   r†   Úbodyr³   r´   r¶   z No V5C logbook on the listing.rm   r¸   r   rº   )r£   r]   r�   rÁ   Ú
inner_textr³   r´   r`   rl   r%   rm   )r‘   ru   Úfieldss      r   Úenrich_from_detailrÆ     sþ   € ð 	‡I�Iˆc�o‰o¨-À€IÑGØ×Ñ˜$ÔÜ˜DŸO™O¨FÓ3Ó4€Fà�6ÓØ˜HÑ%ˆŒ
Ø˜FÓ"Ø$Ð%6Ñ7ˆÔØ‡z�z�(×ÑØ—Y‘YÐ!BÑB×IÑIÓKˆŒ	ð �vÓØ Ñ-ˆŒØ˜6Ó!Ø—Y‘Y ‘_ vÐ.>Ñ'?Ñ?×FÑFÓHˆŒ	Ø˜ÓØ—Y‘Y ‘_ v¨mÑ'<Ñ<×CÑCÓEˆŒ	à€Jr!   c                 ó6  • SSK Jn  U R                  USSS9  SU R                  =(       d    SR	                  5       ;   a  UR                  SU5      $ U R                  S	5        UR                  U R                  S
5      5      nUR                  5       US'   X$S'   U$ )zÎThe shortlist deep read of one DealerWay car page (2026-09-17): the
page's words (the same Vehicle Details, MOT and Service History blocks
_detail_fields reads), handed to bidbrain.deep_read.from_dealerway.r   )Ú	deep_readr›   rœ   r�   z/loginr#   z>DealerWay login needed. Run: python3 login.py dealerway manualr†   rÃ   Úread_atÚasked_at)
ÚbidbrainrÈ   r£   Úurlr¼   Úfailedr�   Úfrom_dealerwayrÄ   Ú	now_stamp)r‘   r]   rÊ   Ú_deepÚds        r   rÈ   rÈ   Ÿ  sˆ   € õ ,Ø‡I�Iˆk m¸U€IÑCØ�D—H‘H—N ×)Ñ)Ó+Ó+Ø�|‰|Ð\Ð^fÓgÐgØ×Ñ˜$ÔØ×Ñ˜TŸ_™_¨VÓ4Ó5€AØ—?‘?Ó$€A€i�LØ€j�MØ€Hr!   r<   )NNé   )NrÒ   é   )NrÒ   T) Ú__doc__ÚrerG   Úpricingr   r#   r   r¤   Úcompiler3   rc   rf   ri   rb   rD   re   rg   rh   r'   rj   rŠ   r    r0   r9   rM   rv   r€   r—   r©   rÁ   rÆ   rÈ   © r!   r   Ú<module>rÙ      så   ðñ9óv 
Û Ý Ý à-€à
�
Š
Ð#Ó$€Ø�ZŠZÐ9Ó:€
Ø
�*Š*Ð*Ó
+€Ø	‡z‚zÐ+Ó,€Ø‡j‚jÐ#Ó$€Ø�JŠJÐ3Ó4€	Ø	�ŠÐ.Ó	/€Ú@€ÚD€òÐ ò H€ð€ò2_ò	1ò;ô2ôeôPôBô:ò 6òrõ@r!   