ó
    
5¯j7[  ã            	       óJ  • S r SSKrSSKrSSKJr  \R
                  " S5      rSrSrSr	S\
S	\
4S
 jrS\
4S jr\R
                  " S5      rS\
4S jr\R
                  " S\R                  5      rS\
4S jrSS jrS rS rS	\4S jrS\S\S	\4S jr  SS\S\S\S\4S jjrg) a   
CompMatch: BidBrain's own comp based suggested bid engine (named 2026-08-25,
Mark: "give the ai suggested bid a name so i can come back to improve
later"). Learned from BidBrain's own real history (Mark 2026-08-24: "the
original vision for BB was to use ai to understand from our own data our
best sellers... to make educated bids", then, once the Didn't win data
existed, "lets try and build a AI suggested bid to add to the slider that
should win the car based on both won and lost (but sold for) data").
Refined 2026-08-25, same conversation: "compare year, transmission, engine
size, mileage so that the ai is comparing as similar cars as it can".

Deliberately simple and explainable rather than a real trained model: a
suggestion is the 70th percentile of real winning prices among the closest
real comps for that make and model, ranked by how similar their own
mileage, year, transmission and engine size are to the car being priced,
using only whichever of those a comp and the target car both happen to
have (never a guess, never a penalty for a historical gap). A won
purchase's own winning_bid is exactly as real a data point as a lost
auction's own sold_for, both are the true price that won that specific
car; db.bid_comps_full() already combines them with whatever else is
known about each one.

Never a gate, never touches pricing.py's own formula. A suggestion is
shown only when there is real comparable history (min_samples), otherwise
none, the same "hold back rather than guess" spirit as the rest of this
project.
é    N)Údatez(\d\.\d)é   gq=
×£p>@gÍÌÌÌÌÌð?ÚnameÚreturnc                 ó„  • U =(       d    SR                  5       R                  5       nU(       d  gUS   USS p2US:X  a  SnUS:X  a  U(       a  US   S:X  a  USS nU(       d  U$ US:X  a*  U(       a#  US   S	:X  a  USS nU(       a  US   S
:X  a  USS nU(       d  U$ US   nUS:X  a0  [        R                  " SU5      nU(       a  UR	                  S5      nObUS:X  aN  [        R                  " SU5      =(       d    [        R                  " SU5      nU(       a  UR	                  S5      nOUS:X  a  US:X  a  SnU SU 3$ )aò  A coarse "Make Model" grouping key from a free text vehicle name
(for example "Mercedes A 180 D AMG Line Premium Auto" and "Mercedes A
180 D Sport Premium Auto" both key to "MERCEDES A"), the first two
words, upper cased. Checked live against the real combined history
2026-08-24: 55 of 113 real distinct keys already carry 5 or more real
comps, 31 carry 10 or more, without needing anything finer. A one word
name (should not happen in practice, defensive only) keys on itself.

Canonicalised 2026-08-25, the same real problem render.py's own
_model_family/_canon_make_map already solved for the cockpit's Make
and Model filters, found live to be splitting real comp groups so
badly that whole models never got a suggestion at all: BMW comp
names carry the engine badge as the model word ("118D", "320D"), so
every BMW comp keyed to its own tiny badge group while a live "BMW 1
Series" car keyed to "BMW 1" and found ZERO of the 27 real 1 Series
comps on file; Mercedes was split three ways ("MERCEDES A" 34,
"MERCEDES A180" 7, "MERCEDES-BENZ A-CLASS" 8, one real model, 51
comps once merged); a live "MG Motor UK ZS" keyed to "MG MOTOR" and
missed the real "MG ZS" group; and a handful of comps carry
Motorway's own truncated "Insig" for Insignia. Same regex shapes as
render._model_family (deliberately duplicated, not imported, this
module stays pure and render depends the other way), applied to the
one combined name string both comps and live cars key through, so
both sides always land on the same canonical group.Ú r   é   NzMERCEDES-BENZÚMERCEDESÚBENZÚMGÚMOTORÚUKÚBMWz^(\d)\d{2}[A-Z]{0,2}$z^([A-Z]{1,3})-?CLASS$z^([A-Z]{1,3})\d{3}$ÚVAUXHALLÚINSIGÚINSIGNIAÚ )ÚupperÚsplitÚreÚmatchÚgroup)r   ÚpartsÚmakeÚrestÚmodelÚms         Ú5/Users/stevendouglas/BidBrain/bidbrain/bid_suggest.pyÚ	model_keyr   F   sC  € ð2 �Z�R×ÑÓ ×&Ñ&Ó(€EÞØØ�q‘˜5  ˜9ˆ$ØˆÓØˆØˆzÓžd t¨A¡w°&Ó'8ð �A�BˆxˆÞØˆKØˆtƒ|ž  a¡¨GÓ!3à�A�BˆxˆÞ�D˜‘G˜t“OØ˜˜�8ˆDÞØˆØ�‰G€EØˆuƒ}ô �HŠHÐ-¨uÓ5ˆÞØ—G‘G˜A“JˆEøØ	�Ó	ô �HŠHÐ-¨uÓ5×`¼¿ºÐBXÐZ_Ó9`ˆÞØ—G‘G˜A“JˆEøØ	�Ó	 ¨Ó 0ØˆØˆV�1�U�GÐÐó    Útextc                 ó„   • [         R                  U =(       d    S5      nU(       a  [        UR                  S5      5      $ S$ )zÞThe engine size in litres parsed out of a free text engine string
("2.0 TDI", "1.6 Diesel Automatic"), or None when no plain X.X figure
is found. Never guessed from anything else (a badge like "320d" is not
parsed as 3.2).r   r	   N)Ú_ENGINE_LITRES_REÚsearchÚfloatr   )r!   r   s     r   Úengine_litresr&   ˆ   s2   € ô
 	× Ñ  §¨Ó,€AÞ !Œ5�—‘˜“ÓÐ+ tÐ+r    z^[A-Z]{2}(\d{2})[A-Z]{3}$Úregc                 ó  • U =(       d    SR                  5       R                  SS5      n [        R                  U 5      nU(       d  g[	        UR                  S5      5      nSUs=::  a  S::  a   SU-   $   SUs=::  a  S::  a  O  gSUS-
  -   $ g)	a¥  A real registration year straight off a current format UK plate's
own age identifier (Mark 2026-08-25, "make sure the age and mileage
are being considered", checked live: sightings only covers 5 of 1038
real comps, far too sparse, while 980 of 1038 real regs already match
this format). Format is AA99AAA: the two digits are 01-50 for a plate
issued March to August of 2000+that figure, or 51-99 for one issued
September to February of 2000+(that figure minus 50). Whole year
only, not the exact month, which is all the comparison model needs.
None for any other plate shape (an older letter prefix or suffix
style, a private plate, or an invalid 00 identifier), never guessed.r   r   Nr	   é2   iÐ  é3   éc   )r   ÚreplaceÚ_REG_AGE_REr   Úintr   )r'   r   Úds      r   Úyear_from_regr0   ”   s„   € ð �9�"×
Ñ
Ó
×
%Ñ
% c¨2Ó
.€CÜ×Ñ˜#Ó€AÞØÜˆA�G‰G�A‹J‹€AØˆA…|�„|Ø�a‰xˆð à	ˆQ…}�"…}àð �q˜2‘v‰ÐØr    z<\b(Automatic|Auto|DSG|Tiptronic|S[\s-]?Tronic|PDK|CVT|S-A)\bc                 óP   • [         R                  U =(       d    S5      (       a  S$ S$ )aÔ  "Automatic" when the platform's own free text vehicle name carries
a real automatic/semi-automatic badge (Auto, DSG, Tiptronic, S Tronic,
PDK, CVT, or Motorway's own "S-A" abbreviation for Semi-Automatic,
checked live: 120 of 1038 real comp names carry one of these), the
same "Automatic" or "Semi auto" or nothing pricing.py's own
_gearbox_label already uses for a live car, collapsed to one bucket
here since a comp's exact semi vs full automatic split is not needed
for the similarity match, only automatic vs manual is. Never returns
"Manual": these names never spell that out (0 of 1038 do), so an
unlabelled car is left unknown rather than assumed manual, the same
"never guess" rule as everywhere else in this module.r   Ú	AutomaticN)Ú_AUTO_NAME_REr$   )r   s    r   Útransmission_from_namer4   ¯   s#   € ô (×.Ñ.¨t¯z°r×:Ñ:ˆ;ÐDÀÐDr    c                 óÌ   •  [         R                  " U =(       d    SSS 5      nU=(       d    [         R                  " 5       U-
  R                  [
        -  $ ! [         a     gf = f)a  How many months ago a comp's own sale happened, from its date_bid
(lost bids) or bought_date (purchases), both plain YYYY-MM-DD strings.
None when the date is missing or unreadable, never guessed. today is
overridable for tests only, the same convention as pricing.assess.r   Né
   )r   ÚfromisoformatÚ
ValueErrorÚtodayÚdaysÚ_DAYS_PER_MONTH)Ú	date_textr9   r/   s      r   Úcomp_age_monthsr=   ¾   sY   € ð
Ü×Ò 	§¨R°°"Ð5Ó6ˆð ×"”d—j’j“l aÑ'×-Ñ-´Ñ?Ð?øô ó Ùðús   ‚"A Á
A#Á"A#c                 ó†   • [        U =(       d    S5      R                  5       R                  5       n U (       d  gSU ;   a  S$ S$ )ap  Manual vs automatic, the two buckets the hard transmission gate
actually compares on. Semi-automatic buckets WITH automatic: it is an
automatic from a buyer's (and a value) point of view, and pricing.py's
own class rules already treat "Automatic or Semi automatic" as one
family (the no automatic Fords rule). Manual stays pure, nothing else
ever buckets into it, so Mark's own "never mix manual and auto" hard
gate is fully respected, this only stops the 13 real Semi-automatic
comps (and every live Semi-automatic car, 24 on the 2026-08-25 list)
being stranded in a third bucket too small to ever match anything.
Checked live: the only real values anywhere in the data are Manual,
Automatic, Semi-automatic and None, but matched on the word rather
than exact equality so a future "6 speed manual" style string could
never silently bucket as automatic. None (unknown) stays None.r   NÚmanualÚ	automatic)ÚstrÚstripÚlower)Úts    r   Ú
_tx_bucketrE   Ê   s:   € ô 	ˆA�G�‹×ÑÓ×"Ñ"Ó$€AÞØØ 1“}ˆ8Ð5¨+Ð5r    c                 óè   • U (       d  g[        U 5      S:X  a  U S   $ [        U 5      S-
  US-  -  n[        U5      [        [        U5      S-   [        U 5      S-
  5      pCX#-
  nX   X   X   -
  U-  -   $ )a
  Linear interpolated percentile of an already sorted list, pct 0-100.
Plain and deterministic rather than statistics.quantiles, which
changes its own boundary behaviour across small sample sizes in a way
that is harder to reason about for a business figure like this.Nr	   r   g      Y@)Úlenr.   Úmin)Úsorted_valuesÚpctÚkÚloÚhiÚfracs         r   Ú_percentilerO   Þ   sƒ   € ö
 ØÜ
ˆ=Ó˜QÓØ˜QÑÐÜ	ˆ]Ó	˜aÑ	 C¨%¡KÑ0€AÜ�‹V”Sœ˜Q› !™¤S¨Ó%7¸!Ñ%;Ó<ˆØ‰6€DØÑ Ñ 1°MÑ4EÑ EÈÑMÑMÐMr    c                 óÊ   • 0 nU  HZ  nUR                  S5      b  UR                  S5      (       d  M-  UR                  [        US   5      / 5      R                  U5        M\     U$ )z»Groups db.bid_comps_full()'s own rows (name, amount, retail,
mileage, year, transmission, engine, any but name and amount may be
None) by model_key. Returns {model_key: [comp dict, ...]}.Úamountr   )ÚgetÚ
setdefaultr   Úappend)Ú
comps_fullÚpoolÚcs      r   Ú
build_poolrX   í   sY   € ð €DÛˆØ�5‰5�‹?Ñ"¨!¯%©%°¯-©-ÙØ�‰œ	 ! F¡)Ó,¨bÓ1×8Ñ8¸Ö;ñ ð €Kr    ÚtargetÚcompc           
      óÌ  • SnU R                  S5      (       a=  UR                  S5      (       a'  U[        SS[        U S   US   -
  5      S-  -
  5      -  nU R                  S5      (       a=  UR                  S5      (       a'  U[        SS[        U S   US   -
  5      S-  -
  5      -  nU R                  S5      (       aq  UR                  S5      (       a[  [        U S   5      R	                  5       R                  5       [        US   5      R	                  5       R                  5       :X  a  US-  n[        U R                  S	5      5      [        UR                  S	5      5      pCU(       a'  U(       a   U[        SS[        X4-
  5      S
-  -
  5      -  nU R                  S5      (       a=  UR                  S5      (       a'  U[        SS[        U S   US   -
  5      S-  -
  5      -  nU$ )a¸  A similarity score between the car being priced and one real comp,
both plain dicts with mileage/year/transmission/engine/grade. Only
ever scores a factor when BOTH sides have it, so a gap in the
historical record never counts against (or for) a comp, it just
carries less weight. Mileage is weighted heaviest, it is the single
biggest real driver of what a specific car is worth within a model;
transmission is a binary match (Mark 2026-08-25: "if its manual or
auto as auto will be worth more"); engine size, year and condition
grade all taper off gently rather than a hard cutoff, since a comp a
year, half a litre or one grade off is still a useful data point,
just a slightly less exact one.ç        Úmileageg       @g     LÍ@Úyearg      ð?g      @ÚtransmissionÚengineg333333ã?Úgradeç      à?)rR   ÚmaxÚabsrA   rB   rC   r&   )rY   rZ   ÚscoreÚt_litÚc_lits        r   Ú_similarityrh   ù   s�  € ð €EØ‡z�z�)×Ñ §¡¨)×!4Ñ!4Ø”�S˜#¤ F¨9Ñ$5¸¸Y¹Ñ$GÓ HÈ7Ñ RÑRÓSÑSˆØ‡z�z�&×Ñ˜dŸh™h v×.Ñ.Ø”�S˜#¤ F¨6¡N°T¸&±\Ñ$AÓ BÀSÑ HÑHÓIÑIˆØ‡z�z�.×!Ñ! d§h¡h¨~×&>Ñ&>Üˆv�nÑ%Ó&×,Ñ,Ó.×4Ñ4Ó6¼#¸dÀ>Ñ>RÓ:S×:YÑ:YÓ:[×:aÑ:aÓ:cÓcØ�S‰LˆEÜ  §¡¨HÓ!5Ó6¼ÀdÇhÁhÈxÓFXÓ8Yˆ5Þ–Ø”�S˜#¤ E¡MÓ 2°SÑ 8Ñ8Ó9Ñ9ˆØ‡z�z�'×Ñ˜tŸx™x¨×0Ñ0Ø”�S˜#¤ F¨7¡O°d¸7±mÑ$CÓ DÀsÑ JÑJÓKÑKˆØ€Lr    rV   Úmin_samplesÚtop_nÚmin_ratio_samplesc                 óâ  ^^• [        [        U SS5      =(       d    S S[        U SS5      =(       d    S 35      nUR                  U/ 5      n[        U SS5      [        U SS5      [        U SS5      [        U S	S5      [        U S
S5      S.n	Sn
U	R                  S5      (       aB  [        U	S   5      nU Vs/ s H%  n[        UR                  S5      5      U:X  d  M#  UPM'     nnSn
U Vs0 s H(  n[	        U5      [        UR                  S5      U5      _M*     snmU Vs/ s H.  nT[	        U5         c  M  T[	        U5         [        ::  d  M,  UPM0     nn[        U5      U:  a  gU4S jmU Vs/ s H  n[        Xœ5      U4PM     nn[        S U 5       5      nXâ:¼  a8  UR                  U4S jS9  US[        X25        VVs/ s H  u  püUPM	     nnnSnOUnU
nUSS  Vs/ s Hv  nUR                  S5      UR                  S5      UR                  S5      UR                  S5      UR                  S5      UR                  S5      UR                  S5      S.PMx     nn[        S U 5       5      nU(       a_  [        U5      U:¼  aP  [        U[        US5      -  5      n[        U5      [        R                   " U5      U-  [#        UU5      USUU:„  U
US.$ [        S U 5       5      n[        [        US5      5      n[        U5      [        R                   " U5      U(       a  [#        UU5      OUUS[%        U5      =(       a    UU:„  U
US.$ s  snf s  snf s  snf s  snf s  snnf s  snf )aþ  The suggested bid for this exact car (needs make, model, and
ideally mileage/year/transmission/engine/grade, any of which may be
blank), ranked against real comps for its make and model by how
closely each one's own mileage, year, transmission, engine size and
condition grade matches, not just "same model" (Mark 2026-08-25: "as
similar as it can").

Narrows to the closest top_n comps only once there is real similarity
signal to rank on (at least min_samples comps that share at least one
comparable field with this car), otherwise falls back to every real
comp for the model, the same plain "what did this model actually go
for" figure the original build used, so an early, still sparsely
enriched history never gets narrowed down to fewer than the reliable
floor.

Within that same closest cohort, when car_retail (this car's own real
Cazana retail value) is known AND at least min_ratio_samples of the
cohort also carry a real retail figure of their own, the suggestion
is computed as a % of retail rather than a flat price (Mark
2026-08-25: "if we also knew that a 3 series winning bid was 90% of
cazana retail... having this info should improve the accuracy"): the
70th percentile of each comp's own winning-price-over-its-own-retail
ratio, applied to THIS car's own retail value, so two comps of very
different spec (and so very different retail) are compared on how
competitively each one actually sold relative to its own worth,
rather than treated as equally comparable raw prices. Falls back to
the plain raw-price percentile whenever this car's own retail is not
yet known (no Cazana match) or too few comps in the cohort carry one.

Whatever the source, the final figure is never allowed to exceed this
car's own retail value when it is known (Mark 2026-08-25, a real
car found live: "the ai bids are way off atm... manual is worth
less than automatic, more mileage = low value, new the car means
its worth more". Investigated: for the model in question 14 of 25
real comps showed a winning price ABOVE their own retail, most
likely stale or mismatched historical Cazana lookups rather than
dealers genuinely overpaying at that scale, but regardless of the
cause, a suggestion to pay more than a car is actually worth can
never be sound buying advice, so it is capped, the same "play safe"
discipline as the rest of this project). The same implausible-ratio
comps (over MAX_PLAUSIBLE_RATIO) are also excluded from every % of
retail calculation in the first place, not just clamped at the end:
checked live, they badly distort a same-model comparison, before
excluding them 3 of 4 real models with enough automatic-vs-other
data showed automatics selling for LESS of their own retail than
everything else, backwards from reality; after excluding them, 3 of
4 correctly showed automatics selling for more, matching Mark's own
"auto will be worth more".

Manual and automatic are NEVER mixed together, a hard gate, not a
soft preference (Mark 2026-08-25, first "really considering what %
of cazana retail each make model and transmission each car
achieves", then, once the first version of this still sometimes
fell back to a mixed pool when there was not quite enough of one
transmission: "the suggested bid must hard gate respect the
difference between manual and auto, it would be better to have less
data than inc auto and manual together"). Whenever this car's own
transmission is known (virtually always true for a live car read
straight off a platform), candidates are narrowed to ONLY comps that
ALSO have a known, matching transmission, before anything else runs,
with NO fallback to a mixed pool, ever, even if that leaves too
little data to suggest anything at all, in which case this returns
None rather than guess from a diluted comparison. Only when this
car's own transmission is genuinely unknown (should be rare) does
the gate not apply, there is nothing to respect the difference
against. Deliberately never a CROSS-model adjustment either (tried,
checked live, rejected: it mixed in whichever models happen to get
badged "Auto" in their own listing name, a real confound, different
models, not the same model on two gearboxes, and gave a backwards,
wrong signal), always compared within one model at a time.

The transmission match is on the manual vs automatic BUCKET
(_tx_bucket), not the exact platform string: Semi-automatic is an
automatic for value purposes and matches the automatic comps, manual
stays pure either way, so the hard gate above is fully intact.

A comp older than COMP_MAX_AGE_MONTHS, or with no readable sale date
at all, never contributes a price figure, ratio or raw (see the
constant's own comment for the measured month by month drift that
forced this: today's Cazana retail against a years old sale price
systematically inflates an old comp's own ratio, and an old raw
amount is a price from a market and a car age that no longer exist).
An undated comp is excluded rather than assumed recent, hold back
rather than guess. Within the window, fresher comps also rank
slightly ahead of equally specced older ones.

Returns {"n", "median", "suggested", "like_for_like", "ratio_based",
"capped", "transmission_matched"}, or None when there is not even
min_samples worth of recent enough comps left for this model (and
this car's own transmission, once the hard gate applies) at all,
never a guess off a handful of cars.r   r   r   r   r]   Nr^   r_   r`   ra   )r]   r^   r_   r`   ra   FTr   c                 óN   >• [        SST[        U 5         S[        -  -  -
  5      $ )Nr\   rb   é   )rc   ÚidÚCOMP_MAX_AGE_MONTHS)rW   Úagess    €r   Ú_recencyÚ%suggest_bid_for_car.<locals>._recency�  s(   ø€ Ü�3˜˜d¤2 a£5™k¨QÔ1DÑ-DÑEÑEÓFÐFr    c              3   ó:   #   • U  H  u  pUS :”  d  M  Sv •  M     g7f)r   r	   N© )Ú.0ÚsÚ_s      r   Ú	<genexpr>Ú&suggest_bid_for_car.<locals>.<genexpr>“  s   é € Ð1¢™˜¨1¨q©5—1‘1¢ùs   ‚’	c                 ó(   >• U S   T" U S   5      -   * $ )Nr   r	   ru   )Úpairrr   s    €r   Ú<lambda>Ú%suggest_bid_for_car.<locals>.<lambda>•  s   ø€  t¨A¡w±¸$¸q¹'Ó1BÑ'BÑ%Cr    )Úkeyé   r   rQ   Úretail)r   rQ   r�   r]   r^   r_   r   c              3   óº   #   • U  HQ  nUR                  S 5      (       d  M  UR                  S5      c  M/  US   US    -  [        ::  d  MD  US   US    -  v •  MS     g7f)r�   rQ   N)rR   ÚMAX_PLAUSIBLE_RATIO©rv   rW   s     r   ry   rz   ¦  s[   é € ð K²s°!ØŸ™˜hŸó .Ø,-¯E©E°(«Oó .à˜8™ q¨¡{Ñ2Ô6IÑIó .�A�h‘K ! H¡+Ö-²sùs   ‚A A´AÁ	AéF   )ÚnÚmedianÚ	suggestedÚlike_for_likeÚratio_basedÚcappedÚtransmission_matchedÚcompsc              3   ó>   #   • U  H  n[        US    5      v •  M     g7f)rQ   N)r%   r„   s     r   ry   rz   µ  s   é € Ð5²¨A”U˜1˜X™;×'Ð'²ùs   ‚)r   ÚgetattrrR   rE   ro   r=   rp   rG   rh   ÚsumÚsortrc   ÚsortedÚroundrO   Ú
statisticsr‡   rH   Úbool)ÚcarrV   ri   rj   Ú
car_retailrk   r9   r   Ú
candidatesrY   rŒ   ÚwantrW   ÚscoredÚranked_nrx   Úuser‰   Ú
comps_usedÚratiosrˆ   Úamountsrr   rq   s                         @@r   Úsuggest_bid_for_carr      sj  ù€ ôz ”w˜s F¨BÓ/×5°2Ð6°a¼ÀÀWÈbÓ8Q×8WÐUWÐ7XÐYÓ
Z€CØ—‘˜#˜rÓ"€Jä˜3 	¨4Ó0Ü˜˜V TÓ*Ü  ^°TÓ:Ü˜#˜x¨Ó.Ü˜˜g tÓ,ñ€Fð !ÐØ‡z�z�.×!Ñ!Ü˜& Ñ0Ó1ˆÙ!+ÓY¢˜A¬z¸!¿%¹%ÀÓ:OÓ/PÐTXÑ/X—a¡ˆ
ÐYØ#ÐáBLÓMÂ*¸QŒBˆq‹E”? 1§5¡5¨£=°%Ó8Ò8Á*ÑM€DÙ'ó UšZ˜Øœ"˜Q›%‘[ó Ø15´b¸³e±Ô@SÑ1S÷ ™Z€Jð Uô ˆ:ƒ˜Ó$ØõGá3=Ó>²:¨aŒ{˜6Ó% qÓ)±:€FÐ>ÜÑ1¡Ó1Ó1€HØÓØ�‰ÔCˆÑDØ#Ð$<¤S¨Ó%<Ñ=Ô>Ò=‘T�Q‹qÑ=ˆÑ>Ø‰àˆØ,ˆð ˜r ™7ó$ò #�að Ÿ5™5 ›=°A·E±E¸(³OÈqÏuÉuÐU]ËØŸe™e IÓ.¸¿¹¸f»Ø#$§5¡5¨Ó#8À!Ç%Á%ÈÃ-ôQñ #ð ð $ô ñ K±só Kó K€Fö ”c˜&“kÐ%6Ó6Ü˜*¤{°6¸2Ó'>Ñ>Ó?ˆ	ä�V“Ü ×'Ò'¨Ó/°*Ñ<Ü˜Y¨
Ó3Ø*ØØ *Ñ,Ø$8Øñ	
ð 		
ô Ñ5±Ó5Ó5€GÜ”k '¨2Ó.Ó/€Iä�‹XÜ×#Ò# GÓ,Þ3=”S˜ JÔ/À9Ø&ØÜ�zÓ"×= y°:Ñ'=Ø 4Øñ	ð 	ùòq Zùò NùòUùò ?ùó ?ùò$s7   Â6"MÃMÃ*/MÄ MÄ7MÅMÅ1M!ÇM&Ç$A=M,)N)é   é   Né   N)Ú__doc__r   r”   Údatetimer   Úcompiler#   rp   r;   rƒ   rA   r   r&   r-   r0   ÚIr3   r4   r=   rE   rO   ÚdictrX   r%   rh   r.   r    ru   r    r   Ú<module>r©      s  ðñó8 
Û Ý à—J’J˜{Ó+Ð ð* Ð à€ð Ð ð?�Cð ?˜Cô ?ðD,˜ô ,ð �jŠjÐ5Ó6€ð�sô ð. —
’
ØCÀRÇTÁTóK€ðE ô Eô	@ò6ò(Nð	˜dô 	ð˜ð  Dð ¨Uô ð8 MOØLPñk 4ð k°cð kÀcð kØ=@ökr    