
    iu                        d 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dl	m
Z
 ej                  j                  d e e
e      j                  j                  dz                e
d      Zddd	d
dddddddddddddddddddddddd	d
ddZd Z	 d)dedededededefdZd*dedededz  fdZd+ded ed!ededz  fd"Zdefd#Zdefd$Zdefd%Zdedz  fd&Zd' Zed(k(  r e        yy),uG  
Claude Console / Anthropic API Usage Cost Extractor
=====================================================
Extracts actual API usage costs from Anthropic.

STRATEGY (Native-First Protocol):
  1. Try Admin API  (/v1/organizations/usage_report/messages + /v1/organizations/cost_report)
     - Requires an Admin API key (sk-ant-admin...) — provision at:
       https://console.anthropic.com/settings/admin-keys
  2. Fallback: Playwright browser agent against console.anthropic.com/usage

Output: /mnt/e/genesis-system/data/context_state/claude_api_usage.json

Usage:
    python3 scripts/claude_console_usage.py
    python3 scripts/claude_console_usage.py --headless false   # show browser
    python3 scripts/claude_console_usage.py --days 30          # last 30 days
    python3 scripts/claude_console_usage.py --admin-key sk-ant-admin-xxx
    N)datetimetimezone	timedelta)Pathcorez>/mnt/e/genesis-system/data/context_state/claude_api_usage.jsong      .@g     R@g     2@g      ?)inputoutputcache_write
cache_readg      @g      @g333333?g?g      @g      ?g{Gz?)zclaude-opus-4-6claude-sonnet-4-6zclaude-haiku-4-5zclaude-3-5-sonnet-20241022zclaude-3-5-haiku-20241022zclaude-3-opus-20240229c                  B   	 ddl m}   |        }t        j                  j                  d      xs t        j                  j                  d      }t        j                  j                  d      }t        j                  j                  d      }t        d      }|j                         rt        |      5 }|D ]  }|j                         }|r|j                  d	      r'd
|v s,|j                  d
      \  }}	}
|j                         }|
j                         j                  d      j                  d      }
|dk(  r|s|
}|dk(  r|s|
}|dk(  s|r|
} 	 ddd       ||||dS # t        $ r# t        j                  j                  d      }Y w xY w# 1 sw Y   ?xY w)z1Load API keys from secrets_loader or environment.r   )get_anthropic_api_keyANTHROPIC_API_KEYANTHROPIC_ADMIN_KEYANTHROPIC_ADMIN_API_KEYANTHROPIC_CONSOLE_EMAILANTHROPIC_CONSOLE_PASSWORDz(/mnt/e/genesis-system/config/secrets.env#="'N)standard_key	admin_keyconsole_emailconsole_password)secrets_loaderr   ImportErrorosenvirongetr   existsopenstrip
startswith	partition)r   r   r   r   r   secrets_envflinekey_vals              5/mnt/e/genesis-system/scripts/claude_console_usage.pyget_secretsr-   /   sy   ;8,. 

45bHa9bIJJNN#<=Mzz~~&BC ABK+ 	/! /zz|ts3$;"&.."5KCC))+C))+++C066s;C33I$'	 99-(+ <<EU+.(/	/" %&,	 5  ;zz~~&9:;	/ 	/s0   E& 3.F"A,FFF&(FFFmodelinput_tokensoutput_tokenscache_creation_tokenscache_read_tokensreturnc                 B   t         j                  |       }|sCt         j                         D ],  \  }}| j                  |j	                  d      d         s*|} n |s	t         d   }|dz  |d   z  |dz  |d   z  z   |dz  |d   z  z   |dz  |d   z  z   }t        |d	      S )
z8Estimate USD cost from token counts using known pricing.z-20r   r   i@B r   r	   r
   r      )MODEL_PRICINGr    itemsr$   splitround)	r.   r/   r0   r1   r2   pricingprefixpcosts	            r,   estimate_costr>   V   s     &G&,,. 	IFAU 3A 67	  34 
		!WW%559$(9
9	: 9,0F
F	G y(GL,A
A	B 	 q>    r   daysc                    ddl ddl| r| j                  d      syt        d| dd  d       t	        j
                  t        j                        }|t        |      z
  }|j                  d      }|j                  d	      }| d
dddt        dt        dz  ffd}d| d| d} ||      }|syd| d| d}	 ||	      }
i }d}d}d}d}|j                  dg       D ]  }|j                  d      xs d}|j                  dd      }|j                  dd      }|j                  dd      }|j                  dd      }||vrdddddd||<   ||   dxx   |z  cc<   ||   dxx   |z  cc<   ||   dxx   |z  cc<   ||   dxx   |z  cc<   ||   d xx   t        |||||      z  cc<   ||z  }||z  }||z  }||z  } d}|
r1t        d! |
j                  dg       D              }t        |d"z  d#      }t        t        d$ |j!                         D              d#      }d%t	        j
                  t        j                        j#                         |||d&||||||z   |z   |z   ||d'||
d(}t        d)|d*   d+   d,       |S )-z
    Use Anthropic's Admin API to fetch usage + cost data.
    Requires an Admin API key (sk-ant-admin...).
    Docs: https://platform.claude.com/docs/en/api/usage-cost-api
    r   Nzsk-ant-adminz'[Strategy 1] Trying Admin API with key    ...r@   z%Y-%m-%dT00:00:00Zz%Y-%m-%dT23:59:59Zz
2023-06-01zapplication/json)z	x-api-keyzanthropic-versionzcontent-typeurlr3   c           	         j                   j                  |       }	 j                   j                  |d      5 }t        j                  |j                               cd d d        S # 1 sw Y   y xY w# j                  j                  $ rI}|j                         j                  dd      }t        d|j                   d|d d	         Y d }~y d }~wt        $ r}t        d
|        Y d }~y d }~ww xY w)N)headers   timeoutzutf-8replace)errorsz  HTTP z:    z	  Error: )requestRequesturlopenjsonloadsreaderror	HTTPErrordecodeprintcode	Exception)rE   reqrespebodyrG   urllibs        r,   api_getztry_admin_api.<locals>.api_get   s    nn$$S'$:		''R'8 /Dzz$))+./ / /||%% 	668??79?=DGAFF82d4Cj\23 	IaS/"	s@   A6 #A* 	A6 *A3/A6 3A6 6C7?CC7C22C7zMhttps://api.anthropic.com/v1/organizations/usage_report/messages?starting_at=z&ending_at=z!&group_by[]=model&bucket_width=1dzChttps://api.anthropic.com/v1/organizations/cost_report?starting_at=z&group_by[]=descriptiondatar.   unknownr/   r0   cache_creation_input_tokenscache_read_input_tokensg        )r/   r0   r1   r2   estimated_cost_usdr1   r2   rd   c              3   R   K   | ]  }t        |j                  d d             ! yw)r=   r   N)floatr    ).0items     r,   	<genexpr>z try_admin_api.<locals>.<genexpr>   s%      
+/E$((61%&
s   %'d      c              3   &   K   | ]	  }|d      yw)rd   N )rg   ms     r,   ri   z try_admin_api.<locals>.<genexpr>   s     ?A"#?s   anthropic_admin_api)startendr@   )r/   r0   r1   r2   total_tokenstotal_cost_usd_actualtotal_cost_usd_estimated)sourceextracted_atperiodtotalsby_modelraw_cost_responsez(  [OK] Admin API success. Total tokens: rx   rr   ,)urllib.requesturllib.errorr$   rW   r   nowr   utcr   strftimestrdictr    r>   sumr9   values	isoformat)r   r@   end_dtstart_dtstarting_at	ending_atr_   	usage_url
usage_datacost_url	cost_datary   total_inputtotal_outputtotal_cache_creationtotal_cache_readbucketr.   inpoutcccrtotal_cost_usdcents_totalestimated_totalresultrG   r^   s                             @@r,   try_admin_apir   q   s5    I00@	3IcrN3C3
GH\\(,,'F	t,,H##$89K 45I )*GS TD[ #}K	{
+	- 
 #J#}K	{
!	# 
 !I HKL.., 

7#0yjj+jj!,ZZ5q9ZZ115 /019:QR69;HUO 	'3.'(C/(/0B60+,2,,-uc3PRTV1WW-s"B). N 
3<==3L
 
 {S0!4?X__->??O
 ( X\\2<<> 
 ()%9!1',69MMP``%3(7
 &%F* 
4VH5En5UVW4X
YZMr?   emailpasswordheadlessc                    | r|st        d       t        d       y	 ddlm}m} t        d| d       i } |       5 }|j
                  j                  |d	d
g      }|j                  dddd      }|j                         }		 t        d       |	j                  ddd       t        j                  d       t        d|  d       d}
|	j                  |
d       |	j                  |
|        |	j                  d      }|r%|j                          t        j                  d       d}	 |	j                  |d       |	j                  ||       d}|	j                  |d       |	j                  |       	 |	j!                  d d!       t        d)|	j"                          t        j                  d*       t        d+       |	j                  d,dd       t        j                  d*       t'        |	      }|j)                  |       t        d-       |	j                  d.dd       t        j                  d*       t+        |	      }|j)                  |       	 |	j                  d/dd       t        j                  d*       t-        |	      }|j)                  |       |j3                          	 ddd       |syd4|d5<   t5        j6                  t8        j:                        j=                         |d6<   |S # t        $ r t        d       Y yw xY w# |$ r Y w xY w# |$ rc |	j"                  }t        d"|        d#|v sd$|v r=|	j                  d%      }|rt        d&|j%                         dd'         t        d(       Y w xY w# t.        $ r Y w xY w# t.        $ rL}t        d0|        	 d1}|	j1                  |2       t        d3|        n# t.        $ r Y nw xY wY d}~Gd}~ww xY w# |j3                          w xY w# 1 sw Y   UxY w)7z
    Log into console.anthropic.com and scrape usage/billing data.
    Falls back to this when no admin API key is available.
    uG   [Strategy 2] Skipping Playwright — no console credentials configured.zK  Set ANTHROPIC_CONSOLE_EMAIL and ANTHROPIC_CONSOLE_PASSWORD in secrets.envNr   )sync_playwrightTimeoutErrorza[Strategy 2] Playwright not installed. Run: pip install playwright && playwright install chromiumz4[Strategy 2] Launching Playwright browser (headless=z)...z--no-sandboxz--disable-dev-shm-usage)r   argsi   i  )widthheightzeMozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36)viewport
user_agentz(  Navigating to console.anthropic.com...z#https://console.anthropic.com/loginnetworkidlei0u  )
wait_untilrJ      z  Logging in as rC   zGinput[type="email"], input[name="email"], input[placeholder*="email" i]i:  rI   z2button:has-text("Continue"), button[type="submit"]z.input[type="password"], input[name="password"]'  zLbutton[type="submit"], button:has-text("Log in"), button:has-text("Sign in")z**/console.anthropic.com/**i N  z#  Current URL after login attempt: loginauthz.error, [role="alert"], .alertz  Login error: rM   z?  WARNING: May require 2FA or SSO. Trying to continue anyway...z  Post-login URL:    z  Navigating to usage page...#https://console.anthropic.com/usagez$  Navigating to billing/cost page....https://console.anthropic.com/settings/billingz"https://console.anthropic.com/costz  Playwright error: z:/mnt/e/genesis-system/data/context_state/console_debug.png)pathz  Screenshot saved to: playwright_browserru   rv   )rW   playwright.sync_apir   r   r   chromiumlaunchnew_contextnew_pagegototimesleepwait_for_selectorfillquery_selectorclickwait_for_urlrE   
inner_text_scrape_usage_pageupdate_scrape_billing_page_scrape_cost_pagerY   
screenshotcloser   r~   r   r   r   )r   r   r   r   	PWTimeoutr   r<   browsercontextpage	email_selcontinue_btnpass_sel
submit_selcurrent_urlerror_elr   billing_datar   r\   screenshot_paths                        r,   try_playwright_browserr      s   
 WX[\R
 
@
$
OPF		 aa**## ";< $ 
 %%#s3L & 

 !U	<=II;_dIeJJqM $UG3/0 bI""9e"<IIi'  ../cdL""$

1 HH&&x&?		(H-
 hJ"":u"=JJz"]!!"?!O &txxj12JJqM 12II;_dIeJJqM+D1JMM*% 89IIFS`joIpJJqM/5LMM,'		>=bg	h

1-d3	i( MMOCaF +F8%\\(,,7AACF>Ma  qrZ    	]"hh;K=IJk)V{-B#223STH0C0C0Eds0K/LMN[\	]H    	(,-"^_5//@AB 	 MMOCa as   K2 AO?B$N)%L&N5LCNANO?2L	L	LNLNA$N <N?N  N	NNNN	O'O"*"OO"	OO"OO"O*"O''O**O<<O??P	c                 L   di i}	 | j                  dd       | j                  d      xs d}| j                  d      }g }|D ]v  }|j                  d      }|D ]^  }|j                  d	      }|D 	cg c]   }	|	j                         j                         " }
}	|
sBt	        |
      sN|j                  |
       ` x i }g d
}|D ]n  \  }}| j                  |      }|s|dd D cg c]?  }|j                         j                         s"|j                         j                         A }}|sj|||<   p | j                  |dd ||dd d|d<   t        dt        |       dt        |              |S c c}	w c c}w # t        $ r}t        |      |d   d<   Y d}~|S d}~ww xY w)z*Extract token usage data from /usage page.
usage_pager   r   rI   r]    tabletrtd, th))z[data-testid*="usage"]usage_widget)z[class*="usage"]usage_class)z[class*="metric"]metric_class)z[class*="cost"]
cost_class)z[class*="token"]token_classN
   rB   i  )rE   tableselementspage_text_previewz  Scraped usage page: z table rows, text length rT   wait_for_load_stater   query_selector_allr#   anyappendrE   rW   lenrY   r   )r   r`   	body_textr   
table_datar   rowsrowcellscellrow_datausage_elementsselectors_to_trysellabelr   eltextsr\   s                      r,   r   r   n  s   "D+-   > OOF+1r	 ((1
 	0E++D1D 0..x8BGH$DOO-335HHH%%h/	0	0 
 + 	2JC..s3H;CCR=dRBMMOLaLaLc..0dd,1N5)	2 88 "o&!*5D!1	
\ 	&s:&77PQTU^Q_P`ab K; I  e  -&)!f\7#K-sU   A+E> 1%E4E> E> '6E> E> %#E9	 E9)E> .AE> 4
E> >	F#FF#c                    di i}	 | j                  dd       | j                  d      xs d}ddl}|j                  d	|      }|j                  d
|      }| j	                  d      }g }|D ]v  }|j	                  d      }	|	D ]^  }
|
j	                  d      }|D cg c]   }|j                         j                         " }}|sBt        |      sN|j                  |       ` x | j                  |dd |dd |dd |dd d|d<   t        dt        |       d       |S c c}w # t        $ r}t        |      |d   d<   Y d}~|S d}~ww xY w)z5Extract billing/cost data from settings/billing page.billing_pager   r   rI   r]   r   r   Nz\$[\d,]+\.?\d*z)(?i)credit[s]?\s*[:\-]?\s*\$?[\d,]+\.?\d*r   r   r   rB   r     )rE   dollar_amounts_foundcredit_mentionsr   r   z  Scraped billing page: z $ amounts foundrT   )r   r   refindallr   r#   r   r   rE   rW   r   rY   r   )r   r`   r   r   dollar_amountsr   r   r   r   r   r   r   crow_textr\   s                  r,   r   r     sy   BD/   >OOF+1r	 	$5yA**%QS\]((1
 	0E++D1D 0..x8<ABqALLN002BBH%%h/	0	0 88$23B$7.s3 "o!*5D!1 
^ 	(^)<(==MNO K C  /(+A^W%K/s7   BD$ %D>D$ D$ AD$ D$ $	E	-EE	c                 8   di i}	 | j                  dd       | j                  d      xs d}| j                  d      }g }|D ]v  }|j                  d      }|D ]^  }|j                  d	      }|D 	cg c]   }	|	j                         j                         " }
}	|
sBt	        |
      sN|j                  |
       ` x | j                  |d
d |d
d d|d<   t        dt        |       d       |S c c}	w # t        $ r}t        |      |d   d<   Y d
}~|S d
}~ww xY w)zExtract data from /cost page.	cost_pager   r   rI   r]   r   r   r   r   N   r   )rE   r   r   z  Scraped cost page: z table rowsrT   r   )r   r`   r   r   r   r   r   r   r   r   r   r\   s               r,   r   r     s;   D,   >OOF+1r	((1
 	0E++D1D 0..x8<ABqALLN002BBH%%h/	0	0 88 "o!*5D!1
[
 	%c*o%6kBC K C  ,%(V['"K,s7   A+C4 1%C/C4 C4 'AC4 /C4 4	D=DDc                     t        d      } t        d      }| j                         s|j                         syt        d       dt        j                  t
        j                        j                         dd}|j                         rn	 t        |      5 }|j                         j                         }ddd       r9	 t        j                  |      }||d
<   t        d|j                  dd              | j                         ri }t#               }	g }
t        |       5 }|D ]  }|j                         }|s	 t        j                  |      }|j                  dd      }|j                  |d      dz   ||<   |j                  di       j                  dd      }|r|dk7  r|	j%                  |       |
j'                  |        	 ddd       |
dd }
t)        |j+                               |t-        |	      |
d|d<   ddddd|d<   |S # 1 sw Y   XxY w# t        j                  $ rK t        dd	      D ]6  }	 t        j                  |d|        } n# t        j                  $ r Y 4w xY w i }Y w xY w# t         $ r}t        d|        i |d
<   Y d}~d}~ww xY w# t        j                  $ r Y w xY w# 1 sw Y   xY w)z
    Estimate usage from the local observability events log.
    This data is less accurate (no token counts) but always available.
    The observability_logger.py tracks tool calls but NOT token usage directly.
    z5/mnt/e/genesis-system/data/observability/events.jsonlz5/mnt/e/genesis-system/data/observability/metrics.jsonNz0[Strategy 3] Reading local observability data...local_observability_estimatezToken/cost data NOT available from local observability. This shows tool call counts only. For actual costs, provision an Admin API key at https://console.anthropic.com/settings/admin-keys)ru   rv   noter   r   tool_call_metricsz  Total tool calls tracked: total_tool_callsr   z)  Warning: Could not parse metrics file: 
event_typera   agent
session_idr   )total_eventsby_typeunique_sessionsrecent_eventsevent_summaryuH   UNAVAILABLE — observability logger tracks tool calls, not token countszTo get real cost data:
1. Go to https://console.anthropic.com/settings/admin-keys
2. Create an Admin API key (starts with sk-ant-admin...)
3. Add to secrets.env: ANTHROPIC_ADMIN_KEY=sk-ant-admin-xxx
4. Re-run this scriptr   r   )methodaction_requiredconsole_urlbilling_urlcost_estimation)r   r!   rW   r   r~   r   r   r   r"   rS   r#   rQ   rR   JSONDecodeErrorranger    rY   setaddr   r   r   r   )events_filemetrics_filer`   r'   contentmetricstrimr\   event_countssession_idsr  r(   eventetypesesss                  r,   try_local_observabilityr#    s    NOKOPL(;(;(=	
<= 1 X\\2<<>@		D 	+l# +q&&(..*+ %"jj1G -4()4W[[ASUV5W4XYZ e+ 	! zz| JJt,E!IIlI>E*6*:*:5!*Dq*HL' 99Wb155lBGD	 1#-!((/	& &bc*   3 3 56#";/*	!
_ ]$ =GD	 KQ+ + ++ 
% !&a %%&*jj4%&AG!#33 %$%	% #%
%  	+=aSAB(*D$%	+2 ++ 	 	s   	I7 H	3
I7 >H #I7 J;9B
J!J;	HI7 "I49II4I*'I4)I**I40I7 3I44I7 7	J JJ!J84J;7J88J;;Kc            	         t        j                  d      } | j                  dt        dd       | j                  dt        dd	       | j                  d
t        d d       | j                  ddd       | j                  dt        t	        t
              dt
         d       | j                         }|j                  j                         dv}t        |j                        }|j                  j                  dd       t               }|j                  xs |d   }t        d       t        d       t        d       t        d|j                    d       t        d|rd|d d z   dz   nd        t        d |d!   xs d        t        d"|        t                d }|rt#        ||j                   #      }| |j$                  st'        |d!   |d$   |%      }|
t)               }|:d&t+        j,                  t.        j0                        j3                         d'd(d)d*d+d,}t5        |d-      5 }t7        j8                  ||d.t        /       d d d        t                t        d       t        d0|        t        d1|j;                  d2d3              d4|v r|d4   }t                t        d5       t        d6|j;                  d7d8      d9       t        d:|j;                  d;d8      d9       t        d<|j;                  d=d8      d9       t        d>|j;                  d?d8      d9       t        d@|j;                  dAd8      d9       t                |j;                  dB      }	|j;                  dC      }
|	t        dD|	dE       |
t        dF|
dE       t                dG|v rt        dH       t=        |dG   j?                               D ]e  \  }}t        dI| dJ       t        dK|j;                  d;d8      |j;                  d=d8      z   dL       t        dM|j;                  dNd8      dO       g nldP|v r|dP   }t                t        dQ       t        dR|j;                  dSd8              t        dT|j;                  dUd8              t        dV|j;                  dWd8              dX|v rEt=        |dX   j?                         dY dZ      d d[ }t        d\d]jA                  d^ |D                     t                t        d_       t        d`       nda|v sdb|v rt                t        dc       da|v r|da   }dd|v rt        de|dd   d df         db|v rH|db   }|j;                  dgg       }|r/t        dhtC        |              |d d[ D ]  }t        dI|         t        d       |S # 1 sw Y   lxY w)iNz-Extract Claude API usage costs from Anthropic)descriptionz--daysr  z)Number of days to look back (default: 30))typedefaulthelpz
--headlesstruez$Run browser headless (default: true)z--admin-keyz2Override Anthropic Admin API key (sk-ant-admin...)z--no-browser
store_truez Skip Playwright browser fallback)actionr(  z--outputzOutput JSON path (default: ))false0noT)parentsexist_okr   z<============================================================z#Claude Console Usage Cost ExtractorzPeriod: last z dayszAdmin key: zSET (rB   z...)zNOT SETzConsole email: r   zOutput: rD   r   )r   r   r   nonezKAll strategies failed. No admin key, no browser credentials, no local data.zProvision Admin API key at https://console.anthropic.com/settings/admin-keys then add ANTHROPIC_ADMIN_KEY=sk-ant-admin-xxx to /mnt/e/genesis-system/config/secrets.envzfAdd ANTHROPIC_CONSOLE_EMAIL and ANTHROPIC_CONSOLE_PASSWORD to /mnt/e/genesis-system/config/secrets.envz<View costs at https://console.anthropic.com/settings/billing)	admin_apir   manual)ru   rv   rT   r  wr   )indentr'  zResult saved to: zSource strategy: ru   ra   rx   zUSAGE SUMMARY:z  Total tokens:        rr   r   z>15,z  Input tokens:        r/   z  Output tokens:       r0   z  Cache creation:      r1   z  Cache read:          r2   rs   rt   z  ACTUAL COST (USD):   $z>13.4fz  ESTIMATED COST:      $ry   z  BY MODEL:z    :z      tokens: r{   z      est. cost: $rd   z.4fr  u<   TOOL CALL SUMMARY (local observability — no token counts):z  Total tool calls: r  z  Successful:       success_countz  Failed:           failure_countby_toolc                     | d   S )Nr   rm   )xs    r,   <lambda>zmain.<locals>.<lambda>  s
    QqT r?   )r)   reverse   z  Top tools:z, c              3   2   K   | ]  \  }}| d | d  yw)(r,  Nrm   )rg   tr   s      r,   ri   zmain.<locals>.<genexpr>  s      +HDAqqc1#QK+Hs   z2  NOTE: Actual API costs require an Admin API key.z;  Action: https://console.anthropic.com/settings/admin-keysr   r   zBROWSER SCRAPE RESULTS:r   z  Dollar amounts found: r   r   z  Usage table rows: )"argparseArgumentParseradd_argumentintr   OUTPUT_PATH
parse_argsr   lowerr   r	   parentmkdirr-   r   rW   r@   r   
no_browserr   r#  r   r~   r   r   r   r"   rQ   dumpr    sortedr7   joinr   )parserr   r   output_pathsecretsr   r   r'   rB  actual	estimatedr.   statsrn   topbpupr   r   s                      r,   mainrY  N  s   $$CF sBH  J
3C  E
CQ  S
|?  A

c+6F:;-qI  KD}}""$,@@Ht{{#KTD9mG6'+"6I	(O	
/0	(O	M$))E
*+	KY)CR.069IV
WX	OGO4A	B
CD	H[M
"#	GF ytyy9 ~doo'/*/0
 ~(*~$LL6@@Bb?B Y 	
( 
k3	 41		&!As34 
G	(O	k]
+,	fjj9=>
?@ 68'na(@'FGH'na(@'FGH'oq(A$'GHI'.Eq(I$'OPQ'.A1(Ed'KLM./EE45	,VFO<= ,Yv,>?@-  &vj'9'?'?'A B UuUG1o&uyy'BUYY_`Ea'abc&def*5995I1+Mc*RSTU
 
	&&'LM$QUU+=q%A$BCD$QUU?A%>$?@A$QUU?A%>$?@A>9++->4PQSRSTC.$))+HC+H"HIBCKL	6	!\V%;'(V#'B%+04J1KCR1P0QRS6!%BVVHb)F,S[M:;!"1: (CD,'( 
(OMA4 4s   2V::W__main__)r   r   )r  )T) __doc__rC  rQ   r   sysr   r   r   r   pathlibr   r   insertr   __file__rJ  rG  r6   r-   rF  rf   r>   r   r   boolr   r   r   r   r#  rY  __name__rm   r?   r,   <module>rb     s  (   	 
  2 2  3tH~,,33f<= >ST */%PUeij*.%QUeij*.4QUeij,0ERVfj"k,0TRVfj"k,1USXhl"m$P LM C  ),EHQV6wS w wTD[ w||# | | |PTW[P[ |~/ /d $  Ft @d dVGT zF r?   