
    /iQ[                    h   U 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dlm	Z	m
Z
mZ ddlZddlZ ee      j#                         j$                  d   Z ee      ej*                  vr"ej*                  j-                  d ee             ddlmZmZ dZg d	Zd
ed<   dZdDdZdEdZdFdZ 	 dGddd	 	 	 	 	 	 	 	 	 dHdZ!	 dGdddd	 	 	 	 	 	 	 	 	 	 	 dIdZ"	 	 	 	 	 	 	 	 	 	 	 	 dJdZ#	 	 	 	 	 	 	 	 	 	 	 	 	 	 dKdZ$	 	 	 	 	 	 	 	 	 	 	 	 	 	 dLdZ%ddddddd	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dMdZ&e'd k(  rddl(Z( ee      j#                         j$                  d   Z)e)d!z  d"z  Z*e*jW                         s ejX                  d#e* d$d%&       ne(jZ                  j]                  d'd(      j_                         Z0e0jc                         r e2e0      ndZ3 e4d)       e3r e4d*e3 d+        e"e*e3,      Z5 e4d-       e5jm                         D ]  \  Z7Z8 e4d.e7 d/e8          ee      j#                         jr                  ez  Z:e:jW                         s e;d0e: d1       e4         e4d2        e&e:d3d4d5ddd6 ejx                  d7      8      Z=e=j|                  D  cg c]  } | j~                  d9k(  s|  c} Z@e@j                  d: ;        ej                  e@D  cg c]  } | j                   c} e@D  cg c]  } | j                   c} e@D  cg c]  } | j                   c} e@D  cg c]  } | j                   c} e@D  cg c]  } | j                   c} e@D  cg c]  } | j                   c} d<      ZI eJ eK eLd eMeI      d            d eMeI      d%z
  hz        ZN e4eIj                   eJeN         j                  d=d> ?              e4d@ eMe@       dAe=j                  j                          dBe@re@d   j                  j                         ndC        yyc c} w c c} w c c} w c c} w c c} w c c} w c c} w )Na  
XGBoost implied-volatility surface model for SPY options.

Trains on historical EOD Parquet (iVolatility-style) merged with **SPY close** as the
underlying and **VIX** as a regime feature. Use :func:`generate_synthetic_chain` to
build an :class:`~RenTech.core.options_data_loader.OptionChain` compatible with
``IVolatilityLoader`` / ``vrp_backtester`` when only spot + VIX are known.

Dependencies
------------
``pandas``, ``numpy``, ``pyarrow``, ``scipy``, ``scikit-learn``, ``xgboost``, ``joblib``,
and ``yfinance`` (for default SPY/VIX panel in training).

Example
-------
>>> from pathlib import Path
>>> from RenTech.core.iv_surface_model import train_surface_model, generate_synthetic_chain
>>> metrics = train_surface_model(Path("SPY-Option-Data/spy_options_eod_combined.parquet"))
>>> chain = generate_synthetic_chain(
...     "RenTech/core/spy_iv_surface.joblib",
...     spy_price=500.0,
...     vix_level=25.0,
...     target_dte=45,
...     strike_range=0.20,
...     option_types=("P",),
... )
    )annotationsN)Path)AnyLiteralSequence   )OptionChainOptionContractzspy_iv_surface.joblib	vix_leveldte	moneynessis_callz	list[str]FEATURE_COLUMNSimplied_volatilityc                2   | | j                   rt        d|       t        | j                  t        j
                        ryt        | j                  j                  d            }d|v r| d   }nd|v r| d   }n| j                  dddf   }t        |t        j                        r,|j                  dddf   }nd| j                  v r| d   n| d   }|j                         }t        |t        j                        r|j                  dddf   }t	        j                  |d      j                  t              }t	        j                  |j                        j!                         |_        ||j                  j#                  d	          j%                         S )
uF   Single-ticker yfinance table → numeric close series indexed by date.Nzyfinance returned no rows for r   z	Adj CloseClosecoerceerrorslastkeep)empty
ValueError
isinstancecolumnspd
MultiIndexlistget_level_valuesiloc	DataFramesqueeze
to_numericastypefloatto_datetimeindex	normalize
duplicated
sort_index)rawlabellv0colsers        9/opt/rentech/trading_bot/RenTech/core/iv_surface_model.py_extract_close_seriesr3   ?   sC   
{cii9%ABB#++r}}-3;;//23#k"C^g,C((1a4.Cc2<<(((1a4.C"-"<c+#g,
++-C#r||$hhq!tn
--H
-
4
4U
;Csyy)335CI		$$&$112==??    c                   	 ddl }|j                  d| |ddd      }|j                  d| |ddd      }t        |d      j	                  d      }t        |d      j	                  d	      }t        j                  ||gd
d      j                         }|d	   j                         j                         |d	<   |j                  dg      }|S # t        $ r}t        d      |d}~ww xY w)z
    Download **SPY** and **^VIX** closes for ``[start, end)`` and return a daily frame
    indexed by date with columns ``close`` (SPY) and ``vix_close``.

    VIX is forward-filled then back-filled once so every SPY row has a level.
    r   Nz&install yfinance: pip install yfinanceSPYF)startendprogressauto_adjustthreadsz^VIXclose	vix_close   outer)axisjoin)subset)yfinanceImportErrordownloadr3   renamer   concatr,   ffillbfilldropna)	r7   r8   yfespy_rawvix_raw	spy_closer=   dfs	            r2   load_spy_vix_panelrQ   W   s    K kk%u#SXbgkhGkk&3TYchkiG%gu5<<WEI%gv6==kJI	Iy)	@	K	K	MBo++-335B{O	7)	$BI  KBCJKs   C 	C%C  C%c                   	 ddl m} t        |       j	                         }|j                  |      }d}d}t        |j                        D ]  }|j                  |dg      j                  d      }t        j                  |j                         d      j                  j                         }	|	j                         }	|	j                   r|	j#                         |	j%                         }}
||
nt#        ||
      }||nt%        ||      } ||t'        d|       t        j(                  |      t        j(                  |      fS # t        $ r}t        d      |d}~ww xY w)	zAMin/max ``date`` in the Parquet file (single-column scan, cheap).r   Nz1pyarrow required for Parquet: pip install pyarrowdater   r   r   zNo dates found in )pyarrow.parquetparquetrD   r   
expanduserParquetFilerangenum_row_groupsread_row_groupcolumnr   r(   	to_pandasdtr*   rJ   r   minmaxr   	Timestamp)parquet_pathpqrL   pathpfdmindmaxir0   slohis               r2   _parquet_date_boundsrl   m   sC   V$ ((*D		B $D $D2$$% 5F84;;A>NN3==?8<??IIKHHJ77!%%'B\rs4}\rs4}5 |t|-dV455<<r||D111%  VMNTUUVs   E	 		E#EE#   )yfinance_end_pad_daysmax_rowsc                   	 ddl m} t        |       j	                         }|j                         st        |      |St        |      \  }}|j                  d      }	|t        j                  |      z   j                  d      }
t        |	|
      }|j                         }t        j                  |j                        j                         |_        ||j                  j!                  d          }d|j"                  vsd	|j"                  vrt%        d
      g d}|j'                  |      }d|j(                  j*                  v }g }d}t-        |j.                        D ]  }||rdgng z   }|j1                  ||      }|j3                         }t        j                  |d   d      j4                  j                         |d<   t        j                  |d   d      j4                  j                         |d<   t        j6                  |d   d      |d<   t        j6                  |d   d      |d<   t        j6                  |d   d      |d<   |d   |d   z
  j4                  j8                  j;                  t<        j>                        }||d<   |jA                  |dd	g   jC                  ddi      ddd      }|d   dkD  t=        jD                  |d         z  |d   dkD  z  |d   dk\  z  |d   dkD  z  }|r7t        j6                  |d   d      jG                  d      |d<   ||d   dkD  z  }|jH                  |   j                         }|jJ                  r|d   |d   z  |d<   |d   j;                  tL              jL                  jO                         jL                  jQ                  d      j;                  t<        jR                        |d<   t        j6                  |d	   d      |d <   |t=        jD                  |d          |d   dkD  z     }t        jT                  d |d    j;                  t<        jV                        d|d   j;                  t<        jV                        d|d   j;                  t<        jV                        d|d   j;                  t<        jV                        tX        |d   j;                  t<        jV                        i      }|j[                  |       |t]        |      z  }|||k\  s n |st%        d!      t        j^                  |d"      }|+t]        |      |kD  r|j`                  d| j                         }|jc                  tX              }|}||fS # t        $ r}t        d      |d}~ww xY w)#u  
    Load options rows from Parquet, merge SPY (underlying) and VIX, engineer features.

    Filters (liquidity / sanity)
    ----------------------------
    - ``iv`` > 0  (implied volatility, stored as **decimal**, e.g. 0.25 = 25% vol)
    - ``bid`` > 0
    - calendar ``dte`` >= 1
    - ``volume`` > 0 **if** a ``volume`` column exists; otherwise that filter is **skipped**
      (the bundled ``spy_options_eod_combined.parquet`` has no volume column).

    Features
    --------
    - ``moneyness`` = strike / underlying (SPY close on ``date``)
    - ``is_call`` = 1 if call else 0
    - ``vix_level`` = VIX close on ``date``
    - ``dte`` = (expiration - date).days

    Target
    ------
    - ``implied_volatility`` ← Parquet column ``iv``

    Parameters
    ----------
    parquet_path
        Path to combined EOD Parquet.
    spy_vix
        DataFrame indexed by normalized date with ``close`` and ``vix_close``. If
        ``None``, dates are inferred from the Parquet file and yfinance is used.
    yfinance_end_pad_days
        When downloading from yfinance, extend the end date by this many days so the
        last chain dates still get a VIX print.
    max_rows
        If set, stop after accumulating this many **post-filter** rows (subsampling for
        quick experiments).

    Returns
    -------
    X, y
        ``X`` has columns :data:`FEATURE_COLUMNS`; ``y`` is the IV series aligned to ``X``.
    r   Nz%pyarrow required: pip install pyarrowz%Y-%m-%ddaysr   r   r<   r=   z5spy_vix must contain columns 'close' and 'vix_close'.)rS   
expirationstrikeoption_typebidivvolumerT   rS   r   r   rs   rt   rv   rw   r   underlying_priceTinner)left_onright_indexhow        r>   r   ru   Cr   r   zDNo training rows after filters; check Parquet and spy_vix alignment.)ignore_index)2rU   rV   rD   r   rW   is_fileFileNotFoundErrorrl   strftimer   	TimedeltarQ   copyr(   r)   r*   r+   r   r   rX   schema_arrownamesrY   rZ   r[   r]   r^   r%   rr   r&   npint64mergerF   isfinitefillnalocr   strupper
startswithint8r#   float64TARGET_COLUMNappendlenrG   r"   pop)rb   spy_vixrn   ro   rc   rL   rd   d0d1start_send_smkt	need_colsre   
has_volumechunkstotalrgcolstablerP   r   okoutfullyXs                              r2   prepare_training_datar      s   `J$ ((*D<<>%%%d+B++j)bll(=>>HHT$We4 ,,.Csyy)335CI
syy###00
1Cckk![%CPQQLI		BR__222J!#FEB%%& 5*XJ"=!!"d!3__^^BvJx@CCMMO6
>>"\*:8LOOYY[<}}R\(C8MM"U)H=5	==D(;4,"V*,0055<<RXXF5	XX+&'..AS7T.U	  
 X^kk"T(#$%y3  %yA~ $%+	- 	 ==HhGNNsSBxL"X,""BVVBZ__88X,,>)??;M*11#6::@@BFFQQRUV^^_a_f_fg9--;I;B{O,;#0EFGllR_33BJJ?r%y''

3R_33BJJ?2i=//

;r$xrzz:
 	cSEX$5k5n _``99V$/DD	H 4yy(#((*AAa4Kw  JABIJs   U3 3	V<VV*   )
model_pathrandom_statero   c          
     &   	 ddl }ddlm}m} ddlm} ddlm}	 t        | ||      \  }} |||d|d	
      \  }}}} |	dddd|d      }|j                  ||       |j                  |      }|j                  |      }t         |||            }t         |||            }t         |||            }t         |||            }|t        |      n-t        t              j                         j                   t"        z  }|j                   j%                  d	d	       |j'                  ||       ||||t)        t+        |            t)        t+        |            t-        |j                               dS # t        $ r}
t        d      |
d}
~
ww xY w)a  
    Prepare data, 80/20 train/test split, fit ``XGBRegressor``, evaluate, persist model.

    Model hyperparameters (per spec): ``n_estimators=200``, ``max_depth=5``,
    ``learning_rate=0.05``, ``n_jobs=-1``.

    Saves with **joblib** to ``model_path`` (default: :file:`spy_iv_surface.joblib` next
    to this module).

    Returns
    -------
    dict
        Keys include ``mae_train``, ``mae_test``, ``r2_train``, ``r2_test``,
        ``n_train``, ``n_test``, ``model_path``.
    r   N)mean_absolute_errorr2_score)train_test_split)XGBRegressorz`train_surface_model needs scikit-learn, xgboost, joblib. pip install scikit-learn xgboost joblibro   皙?T)	test_sizer   shuffle   rm   g?)n_estimators	max_depthlearning_raten_jobsr   	verbosity)parentsexist_ok)	mae_trainmae_testr2_trainr2_testn_trainn_testr   )joblibsklearn.metricsr   r   sklearn.model_selectionr   xgboostr   rD   r   fitpredictr'   r   __file__resolveparentDEFAULT_MODEL_FILENAMEmkdirdumpintr   r   )rb   r   r   r   ro   r   r   r   r   r   rL   r   r   X_trainX_testy_trainy_testmodelpred_trpred_temae_trmae_ter2_trr2_teout_paths                            r2   train_surface_modelr      s   .	A<( !wJDAq'7	1,($GVWf !E 
IIgwmmG$GmmF#G&w89F&vw78F(7G,-E(67+,E#-#9tJtH~?U?U?W?^?^aw?wHOO$6
KKx  s7|$c&k"(**,- E  6
 	s   E6 6	F?FFc                   d}t        j                  t        j                  |t         j                        |      }t        j                  t        j                  |t         j                        |      }t        j                  | t         j                        } t        j                  |t         j                        }t        j                  |      }t        j
                  | |z        |d|dz  z  z   |z  z   ||z  z  }|||z  z
  }||fS )z)Log-normal d1, d2; safe for array inputs.-q=dtypeg      ?r   )r   maximumasarrayr   sqrtlog)	SKTrsigmaepssqrt_tr   d2s	            r2   _d1_d2r   n  s     C


2::arzz2C8AJJrzz%rzz:C@E


1BJJ'A


1BJJ'AWWQZF
&&Q-1sUAX~-2
2uv~	FB	efn	Br6Mr4   c                   ddl m} t        j                  | t        j                        } t        j                  |t        j                        }t        j                  |t        j                        }t        j                  |t        j                        }t        | ||||      \  }}t        j                  | |z        }	t        |t              r|j                         j                  d      }
|
r-| |j                  |      z  ||	z  |j                  |      z  z
  }n.||	z  |j                  |       z  | |j                  |       z  z
  }t        j                  |t        j                        S t        j                  |t              } t        j                  d t        g      |      }
| |j                  |      z  ||	z  |j                  |      z  z
  }||	z  |j                  |       z  | |j                  |       z  z
  }t        j                  |
||      j!                  t        j                        S )u  
    Vectorized Black–Scholes **option price per share** (multiply by 100 for contract $).

    Parameters
    ----------
    S
        Spot (e.g. SPY price).
    K
        Strike(s).
    T
        Time to expiry in **years** (e.g. ``dte / 365.0``).
    r
        Continuously compounded risk-free rate (default in callers often ``0.04``).
    sigma
        Annualized volatility as a decimal (matches XGBoost target IV scale).
    option_type
        ``'C'`` / ``'P'`` or an array of ``'C'``/``'P'`` per row.

    Returns
    -------
    np.ndarray
        Theoretical premium **per share** (same units as typical EOD ``mid`` in this repo).
    r   normr   r   c                R    t        |       j                         j                  d      S )Nr   )r   r   r   xs    r2   <lambda>z)synthetic_black_scholes.<locals>.<lambda>  s    SV\\^%>%>s%C r4   )otypes)scipy.statsr   r   r   r   r   expr   r   r   r   cdfobject	vectorizeboolwherer&   )r   r   r   r   r   ru   r   r   r   discr   priceotpcpps                  r2   synthetic_black_scholesr    s   > !


1BJJ'A


1BJJ'A


1BJJ'AJJuBJJ/EAq!Q&FB661"q&>D+s###%005$q4x$((2,'>>EHtxx},q488RC=/@@Ezz%rzz22 
Kv	.BSbllCTFSTVWG	
TXXb\	AHtxx|3	3B	
TDHHbSM	!A"$5	5B88GR$++BJJ77r4   c                   ddl m} d}t        j                  ||      }t        j                  ||      }t	        | ||||      \  }}	t        j
                  | |z        }
t        j                  |      }|j                  |      }|| |z  |z  z  }| |z  |z  }|dz  }t        j                  ||j                  |      |j                  |      dz
        }|  |z  |z  d|z  z  ||z  |
z  |j                  |	      z  z
  }|  |z  |z  d|z  z  ||z  |
z  |j                  |	       z  z   }t        j                  |||      dz  }||||fS )uS   Delta, gamma, vega (per +1 vol point ≈ 0.01), theta (per year / 365 ≈ per day).r   r   r   g      Y@      ?       @     v@)
r   r   r   r   r   r   r   pdfr   r   )r   r   r   r   r   r   r   r   r   r   r   r   pdf1gamma
vega_sharevegadelta
theta_call	theta_putthetas                       r2   _bs_greeks_rowr    sQ    !
C


1cAJJuc"EAq!Q&FB661"q&>DWWQZF88B<DAI&'ETF"JDHHWdhhrlDHHRL3,>?E dU"cFl3a!edlTXXb\6QQJT	E!S6\2QUT\DHHbSM5QQIHHWj)4u<E%$$r4   r   r  g{Gz?)r   PgQ?)strike_rangestrike_stepr   as_ofoption_typesspread_fractionc                  	 ddl }
t        | t        t        f      r|
j                  |       }n| }|/t        j                  j                  d      j                         }n#t        j                  |      j                         }|dk  rt        d      |t        j                  t        |            z   }t        |      dz  }|d	|z
  z  }|d	|z   z  }t        j                  t!        j"                  |      t!        j$                  |      |z   |t        j&                  
      }||dkD     }g }|D ]  }t        |      j)                         j+                  d      }|r.t        j,                  t/        |      t        j&                  
      n-t        j0                  t/        |      t        j&                  
      }|t        |      z  }t        j2                  t        j4                  t/        |      t        |      t        j&                  
      t        j4                  t/        |      t        |      t        j&                  
      ||d      }|j7                  |      }t        j8                  |j;                  t        j&                        dd      }t        j<                  |t        |      t        j&                  
      }t        j<                  ||t        j&                  
      }t        j4                  t/        |      |rdndt>        
      }tA        ||||||      }t        jB                  |d      }t        jD                  |gt/        |      z  tF        
      }tI        ||||||      \  }}} }!|	dz  }"t        j8                  |d	|"z
  z  dd      }#|d	|"z   z  }$|rdnd}%tK        t/        |            D ]  }&|jM                  tO        ||t        ||&         |%t        |#|&         t        |$|&         t        ||&         t        ||&         t        ||&         t        ||&         t        | |&         t        |!|&                       ! tQ        ||      S # t        $ r}t        d      |d}~ww xY w)u  
    Build an :class:`OptionChain` using XGBoost-predicted IVs and Black–Scholes quotes.

    Parameters
    ----------
    model_or_path
        Fitted ``XGBRegressor`` or path to a ``joblib`` file saved by
        :func:`train_surface_model`.
    spy_price
        Spot for moneyness and pricing.
    vix_level
        VIX close (or scenario level) fed into the model.
    target_dte
        Target **calendar** days to expiration; ``expiration = as_of + target_dte`` days.
    strike_range
        Fractional width around spot: strikes run from ``S*(1-range)`` to ``S*(1+range)``.
    strike_step
        Strike grid step in **dollars** (e.g. ``1.0`` for fine SPY strikes).
    r
        Risk-free rate for BS (default 4%).
    as_of
        Chain date; default **today** (normalized).
    option_types
        Which sides to synthesize (default both calls and puts).
    spread_fraction
        Half bid–ask width as a fraction of mid: ``bid = mid*(1-f/2)``, ``ask = mid*(1+f/2)``.

    Returns
    -------
    OptionChain
        Populated with synthetic ``OptionContract`` rows (``mid`` from BS, ``iv`` from model,
        greeks from analytical BS).
    r   Nz#joblib required: pip install joblib)tzr>   ztarget_dte must be >= 1rq   r  r  r   r   r   g-C6?g      @r  r~   r  )rS   rs   rt   ru   rv   askmidrw   r  r  r  r  )r  	contracts))r   rD   r   r   r   loadr   ra   nowr*   r   r   r   r'   r   arangemathfloorceilr   r   r   onesr   zerosr#   r   r   clipr&   	full_liker   r  r   arrayr   r  rY   r   r
   r	   )'model_or_path	spy_pricer   
target_dter  r  r   r  r  r  r   rL   r   rs   r   rj   rk   strikesrowsopt	want_callis_call_intr   X_prediv_hatr   Tarrr  r  is_call_arrr  r  r  r  halfrv   r  letterrh   s'                                          r2   generate_synthetic_chainr7    s   \H -#t-M*}  D )335U#--/A~2333z?;;JjE!A	cL(	)B	cL(	)Bii

2		"(C[XZXbXbcGgk"G!#D /HNN$//4	AJbggc'l"**=PRPXPXY\]dYemomwmwPxeI..	WWS\53C2::Vwws7|U:->bjjQ&&	
 v&rzz2D#>LL%	"2"**E||GQbjj9WWS\)3FK%a$62Fjjc"hh	{S\9F$21gtQP[$\!ueT$ggcS4Z(#t4S4Z !ss7|$ 	AKK) , &c!fc!fc!fVAY'a/a/a/tAw	?/b Ud33S  H?@aGHs   Q 	Q9(Q44Q9__main__zSPY-Option-Dataz spy_options_eod_combined.parquetzParquet not found at z; train step skipped.r>   )
stacklevelIV_SURFACE_MAX_ROWS zDTraining XGBoost IV surface model (this may take several minutes)...z"  (subsample: IV_SURFACE_MAX_ROWS=)r   zTraining metrics:z  z: zNo model at z; training must succeed first.u>   Synthetic 45-DTE put chain — SPY = $500, VIX = 25 (scenario)g     @@g      9@-   )r  z
2012-06-15)r*  r   r+  r  r  r  r  r  c                    | j                   S N)rt   cs    r2   r   r     s
    QXX r4   )key)rt   rv   r  r  rw   r  Fc                
    | dS )Nz.4f r   s    r2   r   r     s    RSTWQX r4   )r)   float_formatz
Total synthetic puts: z  |  as_of=z  exp=zn/a)r-   pd.DataFramer.   r   returnz	pd.Series)r7   r   r8   r   rG  rF  )rb   
str | PathrG  z!tuple[pd.Timestamp, pd.Timestamp]r?  )
rb   rH  r   pd.DataFrame | Nonern   r   ro   
int | NonerG  ztuple[pd.DataFrame, pd.Series])rb   rH  r   rI  r   zstr | Path | Noner   r   ro   rJ  rG  zdict[str, Any])r   
np.ndarrayr   rK  r   rK  r   r'   r   rK  rG  ztuple[np.ndarray, np.ndarray])r   float | np.ndarrayr   rL  r   rL  r   r'   r   rL  ru   zstr | np.ndarrayrG  rK  )r   rK  r   rK  r   rK  r   r'   r   rK  r   rK  rG  z5tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray])r)  r   r*  r'   r   r'   r+  r   r  r'   r  r'   r   r'   r  zpd.Timestamp | Noner  zSequence[Literal['C', 'P']]r  r'   rG  r	   )T__doc__
__future__r   r!  syswarningspathlibr   typingr   r   r   numpyr   pandasr   r   r   r   
_REPO_ROOTr   rd   insert RenTech.core.options_data_loaderr	   r
   r   r   __annotations__r   r3   rQ   rl   r   r   r   r  r  r7  __name__os_repo_pqr   warnenvirongetstrip_max_envisdigitr   	_max_rowsprint_metricsitemskvr   _model_path
SystemExitra   _chainr  ru   _putssortr#   rt   rv   r  r  rw   r  _dfsortedsetrY   r   _idxr"   	to_stringr  rS   rs   r@  s   0r2   <module>rs     s  8 #  
   ) )   (^##%--a0
z?#(("HHOOAs:' H 1 I I$@0,2@ $(M "#MM M 	M
 M $Mn $(F %)FF F "	F
 F F F\  	
  #&686868 68 	68
 68 "68 68r%%% % 	%
 % % ;%X !%0:!y4y4y4 y4 	y4 y4 y4 y4 y4 .y4 y4 y4@ zN""$,,Q/E
#
#&H
HC;;=-cU2GHUVW::>>"7<BBD%-%5%5%7CMT	TU6ykCD&sY?!"NN$ 	!DAqBqcA3- 	! x.((*114JJK <}4RSTT	G	
JK%bll<(	F ((A1AMMS,@QAE	JJ%J&
",,)./Aqxx/#()aAEE)#()aAEE)#()aAEE)!&'A144'',-!agg-	
	C #eAs3x+,3s8a</@@AD	#((6$<
 
*
*EY
*
Z[	$SZLFLL<M<M<O;PPVuzW\]^W_WjWjWoWoWq  AF  WG  H  Ie F B 0)))'-s0   P'PP*P
P P%5P*P/