
    ^j              ,          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 ddl	m	Z	 ddl
mZ ddlmZmZ ddlmZmZmZ ddlmZ dd	lmZmZmZmZmZmZ dd
lmZ ddlmZ ddl m!Z! ddl"m#Z# ddl$m%Z% ddl&m'Z'm(Z( ddl)m*Z*m+Z+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6 ddl7m8Z8m9Z9 ddl:m;Z;m<Z<  e!jz                  e>      Z?de@de@dz  deAe@e@dz  f   fdZBdeCe@   dz  dede@dz  deCe   dz  fdZDdZEee@ e8d      f   ZFee@dz   e9d      f   ZGee@dz   e9d e.e             f   ZHeeCe@   dz   e9d!d"d#      f   ZIee@dz   e9d$d%      f   ZJee@dz   e9d&      f   ZKeeL e9d'd(d)      f   ZMee@dz   e9d*      f   ZNeeCeO   dz   e9d+d,      f   ZPeeL e9d-d.      f   ZQeeCe@   dz   e9d/d0      f   ZRee@dz   e9d1d2d3      f   ZSeeLdz   e9d4      f   ZTeeLdz   e9d5      f   ZUee@ e8d6      f   ZVee@ e8d7      f   ZWeeCe@   dz   e8d8      f   ZXeeCe@    e8d9      f   ZYee@ e8d:      f   ZZeeCe@   dz   e8d;      f   Z[ee@ e8d<      f   Z\eeCe@   dz   e9d=d>d?      f   Z] e6d@      Z^dedAeddfdBZ_e^j                  dCdDdEig dFG      	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddHeFdIeYdJe+dKe-dLeJdMeIdNe]dOe*dPe,dQeHdReKdSeMdTePdUeQdeNdVe1ddf"dW       Zae^j                  dXg dYZ      	 	 	 	 ddeZd[eeL e9d\d]d^      f   d_eeOdz   e9d`dadb      f   deNdVe1ddfdc       Zbddece@e@f   deeCeAe@e@e@f      deLfdfZddgeOddfdhZede@dieece@ef      djeCe@   deeAeLe@eCeCe@eOz        f      fdkZfe^j                  dldmgZ      	 	 	 ddne[deNdVe1ddfdo       Zge^j                  dpg dqZ      	 	 	 	 	 	 	 ddreeL e9dsdtdu      f   dveeCe@   dz   e9dw e.e      dxy      f   dMeeCe@   dz   e9d!d"dz      f   d{eeO e9d|d}      f   deNdVe1d~eeCe@   dz   e9d\dd      f   ddfd       Zhe^j                  ddgZ      dd       Zie^j                  ddgZ      	 	 ddneeCe@    e8d      f   deNdVe1ddfd       Zje^j                  ddgZ      	 	 ddeZdeNdVe1ddfd       Zke^j                  dg dZ      	 	 	 ddneeCe@    e8d      f   dRee@dz   e9d      f   deNdVe1ddf
d       Zle^j                  dg dZ      	 	 	 	 	 ddeZdLeJdMeIdeeL e9dd      f   deNdVe1ddfd       Zme^j                  dUg dZ      	 	 	 	 ddeZde0de/deNdVe1ddfd       Zn e6d      Zoe^j                  eod       eoj                  dCdDdEig dG      	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddeWdeXdHeGdQeHdJe+dKe-dLeJdMeIdNe]dOe*dPe,dReKdSeMdTePdUeQdeNdVe1deRdeSddf(d       Zq e6d      Zre^j                  erd       erj                  dCdDdEidgG      	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddeVdHeFdIeYdeTdeUdJe+dKe-dLeJdMeIdNe]dOe*dPe,dQeHdReKdTePdeNdVe1ddf$d       Zserj                  dpdgZ      	 	 	 	 ddreeL e9dsdtd      f   deNdVe1d~eeCe@   dz   e9d\dd      f   ddf
d       Zterj                  ddgZ      	 	 ddeeCe@    e8d      f   deNdVe1ddfd       Zuerj                  ddgZ      	 	 dde\deNdVe1ddfd       Zverj                  ddgZ      	 	 dde\deNdVe1ddfd       Zwerj                  ddgZ      	 	 dde\deNdVe1ddfd       Zxerj                  ddgZ      	 	 dde\deNdVe1ddfd       Zyerj                  dg dZ      	 	 	 	 	 dde\dLeJdMeIdeeL e9dd      f   deNdVe1ddfd       Zz e6d¬      Z{erj                  e{d       e{j                  dCdDdEiddgG      	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddeVdeWdeXdeTdeUdHeGdQeHdJe+dKe-dLeJdMeIdNe]dOe*dPe,dReKdTePdeNdVe1deRdeSddf*dń       Z|dddeCe@   dz  dLe@dz  dece@e@f   dz  fdƄZ}deCeCe@eOz        deCe@   de@fdɄZ~ edʫ      Zdee   dedee   f   decddfdτZdej                  j                  dedee   f   deCec   dee   fd҄Zy)z@Contains commands to interact with jobs on the Hugging Face Hub.    N)CallableIterable)fnmatch)Path)EmptyQueue)	AnnotatedAnyTypeVar)urlsplit)HfApiJobHardwareJobInfoJobStageVolume	constants)TERMINAL_JOB_STAGES)CLIError)logging)_format_size)_split_mount)format_durationparse_duration   )
EnvFileOptEnvOptSecretsFileOpt
SecretsOpt
SoftChoiceSshDryRunOptSshIdentityFileOptTokenOptexec_ssh
get_hf_apiparse_env_mapparse_volumestyper_factory)ArgumentOption)_dataclass_to_dictoutjob_id	namespacereturnc                     | st        d      | j                  d      dkD  rt        d|  d      d| vr| |fS | j                  dd      \  }}|r|st        d|  d      |||k7  rt        d| d| d      ||fS )	a&  Extract namespace from job_id if provided in 'namespace/job_id' format.

    Allows users to pass job IDs copied from the Hub UI (e.g. 'username/job_id')
    instead of only bare job IDs. If the namespace is also provided explicitly via
    --namespace and conflicts, a CLIError is raised.
    zJob ID cannot be empty./r   z<Job ID must be in the form 'job_id' or 'namespace/job_id': 'z'.z(Conflicting namespace: got --namespace='z ' but job ID implies namespace='')r   countsplit)r,   r-   extracted_namespaceparsed_job_ids       c/var/www/ramen.bs-engineer-server.com/venv/lib/python3.12/site-packages/huggingface_hub/cli/jobs.py_parse_namespace_from_job_idr7   :   s     011||C1UV\U]]_`aa
&y  )/c1)=&mUV\U]]_`aa.A!A6ykAabuavvwx
 	
 ---    volumesapic                *   | syg }| D ]  }|j                  t        j                        r |j                  t	        |g      xs g        Ct        ||      \  }}}|t        d| d      t        |      j                         j                         st        d| d      |j                  ||||nd|      }|j                  d	u r5t        j                  d
| d|j                   d|j                   d|        |j!                  |       
 |S )a  Parse `-v` specs for Jobs commands.

    Same as [`parse_volumes`] but the source side can also be a local directory: it is synced to a
    bucket via [`HfApi.sync_job_volume`] and the resulting bucket subfolder is mounted (read-only
    unless ':rw' is specified).
    N)rawz#Missing mount path in volume spec 'zC'. Expected 'LOCAL_DIR:/MOUNT_PATH[:ro|:rw]' (e.g. './data:/data').zVolume source 'z' is not an existing local directory. To mount a repo or bucket instead, use the 'hf://' syntax (e.g. 'hf://buckets/my-org/my-bucket:/data').T)	read_onlyr-   FzVolume 'zg' is mounted read-write. Once the job is over, pull back its data with:
  hf buckets sync hf://buckets/r0    )
startswithr   HF_PROTOCOLextendr&   r   r   r   
expanduseris_dirsync_job_volumer=   r+   hintsourcepathappend)	r9   r:   r-   resultraw_specrF   
mount_pathr=   volumes	            r6   _parse_and_sync_job_volumesrM   V   sK    F y445MM-
39r: )5X8(L%
I5hZ  @C  D  F|&&(//1!& *z z  $$#,#8id	 % 
 u$HH:, '228--&++aPVxY 	f78 Mr8   g?zThe Docker image to use.)helpz.Use a custom Docker image with `uv` installed.zcFlavor for the hardware. Run 'hf jobs hardware' to list available flavors. Defaults to `cpu-basic`.)rN   
click_typez-lz--labelz3Set labels. E.g. --label KEY=VALUE or --label LABELz--namezIName the Job. Stored as the `name` label. Names do not have to be unique.zPMax duration: int with s (seconds, default), m (minutes), h (hours) or d (days).z-dz--detachz3Run the Job in the background and print the Job ID.zVThe namespace where the job will be running. Defaults to the current user's namespace.z--exposezExpose a container port through the jobs proxy. Repeat the flag for multiple ports (e.g. `--expose 8000 --expose 8001`). Each exposed port is reachable on the public jobs domain; access requires an HF token with read access to the job's namespace.z--sshzMake the job's container reachable over SSH. Connect with `hf jobs ssh <job_id>`. Requires an SSH public key registered on https://huggingface.co/settings/keys.z--withz%Run with the given packages installedz-pz--pythonz5The Python interpreter to use for the run environmentz!Suspend (pause) the scheduled Jobz8Allow multiple instances of this Job to run concurrentlyzWOne of annually, yearly, monthly, weekly, daily, hourly, or a CRON schedule expression.z$UV script to run (local file or URL)zArguments for the scriptzThe command to run.zJob ID (or 'namespace/job_id')zJob IDs (or 'namespace/job_id')z2Scheduled Job ID (or 'namespace/scheduled_job_id')z-vz--volumea  Mount one or more volumes. Format: hf://[TYPE/]SOURCE:/MOUNT_PATH[:ro|:rw] or LOCAL_DIR:/MOUNT_PATH[:ro|:rw]. TYPE is one of: models, datasets, spaces, buckets. TYPE defaults to models if omitted. models, datasets and spaces are always mounted read-only. buckets are read+write by default. A local directory source is first synced to a bucket and mounted read-only by default. E.g. -v hf://datasets/org/ds:/data or -v hf://buckets/org/b:/mnt:ro or -v ./inputs:/inputszRun and manage Jobs on the Hub.jobc                 X   | j                  |j                  |j                  j                  d      D ]  }t	        j
                  |        | j                  |j                  |j                  j                        }|j                  j                  t        j                  k7  rc|j                  j                  rd|j                  j                   nd}t        d|j                   d|j                  j                   d|       t	        j
                  d|j                   d	       y
)zcStream Job logs until the Job ends, then fail the command if the Job did not complete successfully.T)r,   r-   followr,   r-   z:  zJob z finished with stage 'r1   z
 completedN)fetch_job_logsidownernamer+   textwait_for_jobstatusstager   	COMPLETEDmessager   )r:   rP   logfinalr^   s        r6   _stream_logs_and_check_statusra   6  s    !!399>>RV!W  CFFciinnEE||X///161E1EBu||++,-2ehhZ'=ell>P>P=QQRSZR[\]]HHtEHH:Z()r8   runignore_unknown_optionsT)zFhf jobs run --name hello-world python:3.12 python -c 'print("Hello!")'z1hf jobs run --detach python:3.12 python script.pyz3hf jobs run -e FOO=foo python:3.12 python script.pyz;hf jobs run --secrets HF_TOKEN python:3.12 python script.pyz^hf jobs run -v hf://org/my-model:/data -v hf://buckets/org/b:/mnt python:3.12 python script.py)context_settingsexamplesimagecommandenvsecretsrX   labelrL   env_filesecrets_fileflavortimeoutdetachexposesshtokenc                    t        ||      }t        ||      }t        |      }|j                  | |||t        ||      t	        |||      |	|
|||      }t        j                  d|j                  |j                         |:t        j                  d|j                  j                   d	|j                   d
       t        |j                  j                  t              rDdj!                  d |j                  j                  D              }t        j                  d|        t        |j                  j"                  t$              r:t        j                  d|j                  j                   d	|j                   d       |r[|j                  j                   d	|j                   }t        j                  d| d| d       t        j                  d| d       yt'        ||       y)z
Run a Job.rr   rX   r:   r-   )rf   rg   rh   ri   labelsr9   rm   rn   rp   rq   r-   Job startedrV   urlN#Name this Job with `hf jobs labels r0    --name NAME`.
c              3   &   K   | ]	  }d |   ywz  N .0rz   s     r6   	<genexpr>zjobs_run.<locals>.<genexpr>u       F2cUF   SExposed ports are reachable at (requires an HF token with read access to the job):
Use `hf jobs ssh &` to open an SSH session into the job.Use `hf jobs logs -f &` to stream logs, or `hf jobs inspect ` to check status.Use `hf jobs wait ` to block until it finishes.)r%   r$   run_job_parse_labels_maprM   r+   rI   rV   rz   rE   rW   rX   
isinstancer[   expose_urlslistjoinssh_urlstrra   )rf   rg   rh   ri   rX   rj   rL   rk   rl   rm   rn   ro   rp   rq   r-   rr   env_mapsecrets_mapr:   rP   urlsjob_refs                         r6   jobs_runr   B  s   < C*G6K
5
!C
++ T2+FyQ  C JJ}SWW5|6syy~~6Fax~^_#**(($/yyFszz/E/EFFghlgmno#**$$c*$SYY^^$4AcffX=cdeYY^^$AcffX.(	1WX_W``rst%gY.KLM!#s+r8   logs)zhf jobs logs <job_id>zhf jobs logs -f <job_id>zhf jobs logs --tail 20 <job_id>z#hf jobs logs -f --tail 100 <job_id>)re   rR   z-fz--followzqFollow log output (stream until the job completes). Without this flag, only currently available logs are printed.tailz-nz--tailzvNumber of lines to show from the end of the logs. When combined with --follow, starts streaming from the last N lines.c                     t        | |      \  } }t        |      }|j                  | |||      }|D ]  }t        j                  |        |r%|r| d|  n| }t        j
                  d| d       yy)a  Fetch the logs of a Job.

    By default, prints currently available logs and exits (non-blocking).
    Use --follow/-f to stream logs in real-time until the job completes.
    Use --tail/-n to limit the number of lines returned (server-side when supported).

    Note: following exits when the log stream ends, regardless of whether the Job
    succeeded or failed. Run `hf jobs inspect <job_id>` to check the final status.
    rt   )r,   r-   rR   r   r0   z#Stream ended. Run `hf jobs inspect z6` to check the final status (e.g. COMPLETED or ERROR).N)r7   r$   rU   r+   rY   rE   )	r,   rR   r   r-   rr   r:   r   r_   r   s	            r6   	jobs_logsr     s    N 5VYGFI
5
!CVyVZ[D -6YKq)F6wi?uvw r8   job_propertiesfiltersc                     |D ]Z  \  }}}| j                  |      }||dk(  r  yt        |j                         |j                               }|dk(  r|r	|dk(  sW|sZ y y)z5Check if scheduled job matches all specified filters.!=F=T)getr   lower)r   r   keyop_strpatternvaluematchs          r6   _matches_filtersr     sk     ' VW""3'=~w}}7cM%Vt^ r8   nc                 F    d}d}t        |       D ]  }t        ||        y )Nz[1Az[2K)end)rangeprint)r   LINE_UP
LINE_CLEARis       r6   _clear_liner     s)    GJ1X 'g:&'r8   metrics_streamtable_headersc              #     K   |D ]J  }| |d    dt        |d   dz  d      t        d|d   z  |d   z  d	       dt        |d          d
t        |d          dt        |d          dt        |d          dg}|d   rt        |d   t              r|gdgt	        |      z  gt	        |d         dz
  z  z   }t        |t        |d               D ]R  \  }}|d   |   }||d    dt        d|d   z  |d   z  d	       dt        |d          d
t        |d          dgz  }T n!|dgt	        |      t	        |      z
  z  z  }|g}d| |f M d| g f y w)Ncpu_usage_pct%cpu_millicoresg     @@r   d   memory_used_bytesmemory_total_bytes   zB / Brx_bpszbps / tx_bpsbpsgpusrT   utilizationN/AFT)roundr   r   dictlenzipsorted)r,   r   r   metricsrowrowsgpu_idgpus           r6   _get_jobs_stats_rowsr     s     " "'(*'*+f4a8S7#677'BV:WWYZ[\\]^G$789:$|GThLi?j>kklmGH-./vl78CT6U5VVYZ
 6?z'&/4@5RD3s8O,GFO0Dq0HIID"4)@A Vfof-=)*!,S3':#;;cBV>WWYZ[\\]^#C(;$<=>d<PSThPiCjBkklm  E7c-03s8;<<C5DVT!!+", 
s   EEstatszhf jobs stats <job_id>job_idsc           	         | +g }| D ]"  }t        ||      \  }}|j                  |       $ |} t        |      }||j                         d   }| O|j	                  |      D cg c]4  }|j
                  r|j
                  j                  nddv r|j                  6 } }t        |       dk(  rt        j                  d       yg d	}t        j                  j                  t        |             5 }i }	| D ]+  }|g}
|
|d
d D cg c]  }d|v sd|v rdnd c}z  }
|
g|	|<   - t        j                         }|	D 
cg c]  }|	|   D ]  }
|
  }}}
t        t!        ||             | D cg c]  }||j#                  ||      |d }}t%        |t&        |      D ]  \  }}}|r|	j)                  |d       n||	|<   t        j                         }||z
  t*        k\  sBt-        dt        |      z          |	D 
cg c]  }|	|   D ]  }
|
  }}}
t        t!        ||             |} 	 ddd       yc c}w c c}w c c}
}w c c}w c c}
}w # 1 sw Y   yxY w)z7Fetch the resource usage statistics and metrics of JobsNrt   rX   r-   UNKNOWN)RUNNINGUPDATINGr   zNo running jobs found)	zJOB IDzCPU %zNUM CPUzMEM %z	MEM USAGEzNET I/Oz
GPU UTIL %z	GPU MEM %zGPU MEM USAGEr   r0   USAGEz-- / --z--)headersrS   )r,   r   r   )kwargs_listr   )r7   rH   r$   whoami	list_jobsr[   r\   rV   r   r+   rY   multiprocessingpool
ThreadPooltimer   	_tabulatefetch_job_metricsiflatmap_unorderedr   popSTATS_UPDATE_MIN_INTERVALr   )r   r-   rr   
parsed_idsr,   r:   rP   r   r   rows_per_job_idr   headerlast_update_time
total_rowsr   doner   nows                     r6   
jobs_statsr     s    
 	&F <VY OFIf%	& 
5
!CJJL(	 }}y}9
$'JJ

  IBYY FF
 

 7|q()
M 
			(	(W	6 '$<> 	,F$*8C^klmln^opTZ#-7f3DI4OppC'*eOF#	,  99;(7[f?SYCZ[Cc[c[
[ 	i
M:; "
 	 !"%"7"7vQZ"7"[!.
 
 #5T;O]h"i 
	'D&$##FD1*.'))+C%%)BBAJ/00?cf?[aKbcCcccc
ci
MBC#& 
	')' ''
. q \

  d9' 'sO   %9H60IH;
&I<I I,I
AI I<I
I;IIzlist | ls | ps)z
hf jobs lszhf jobs ls -az&hf jobs ls --status running,schedulingz+hf jobs ls --label env=prod --label team=mlz%hf jobs ls --all --label hf-sandbox=1allz-az--allzWShow all Jobs (default shows running and scheduling). Cannot be combined with --status.r[   z--statuszfOnly show Jobs with the given status. Comma-separated or repeated, e.g. `--status running,scheduling`.)rO   rN   z{Only show Jobs with the given `key=value` label. Repeat to require several labels, e.g. `--label env=prod --label team=ml`.limitz--limitzCMaximum number of Jobs to display. Set to 0 to show all (no limit).filterz--filterz2(Deprecated) Use `--status` and `--label` instead.c                    t        |      }|rt        j                  d| d       | r|rt        d      g }|xs g D ])  }	|j	                  d |	j                  d      D               + |r|}
n9| rd}
n4t        j                  j                  t        j                  j                  g}
i }|xs g D ].  }d|vrt        d	| d
      |j                  d      \  }}	|	||<   0 |j                  ||
|xs d      }d}|dkD  r8t        t        j                  ||dz               }t        |      |kD  rd}|d| }nt        |      }g }|D ]  }t        |      }|j!                  d      xs i }|j!                  d      xs g }|j!                  dd      |d<   |j!                  d      xs d|d<   |rdj#                  |      nd|d<   |j!                  d      r|d   dd j%                  dd      nd|d<   |j!                  d      xs i j!                  dd      |d<   t'        |j!                  d             |d!<   |j)                  |        t        j*                  |g d"d#       |rt        j,                  d$| d%       |sg|s|rJd&j#                  g d' |D        d( |j/                         D              }t        j0                  d)|        y| st        j,                  d*       yyy)+zList Jobs.

    Use `--status` to filter by status (see [`JobStage`] for possible values) and `--label` to filter by `key=value`
    labels. A Job must match every filter to be listed.
    rt   zIgnoring filter 'zc'. `-f`/`--filter` is deprecated and will be removed in a future release. Use `--status`/`--label`.z0`-a`/`--all` cannot be combined with `--status`.c              3   ^   K   | ]%  }|j                         s|j                          ' y wN)strip)r   parts     r6   r   zjobs_ps.<locals>.<genexpr>q  s     VTDJJLVs   --,Nr   zInvalid label filter 'z"': must be in the form 'key=value')r-   r[   rw   Fr   r   T	durationsrg   rV   rT   r,   docker_imager   image/spacer>   
created_at   Tcreatedr[   r\   r   running_secsruntime)r,   r   rg   r   r[   r   r   id_keyzOutput truncated to z4 Jobs. Use `--limit 0` to show all (or `--limit N`)., c              3   &   K   | ]	  }d |   yw)zstatus=Nr   )r   ss     r6   r   zjobs_ps.<locals>.<genexpr>  s     7QWQC=7r   c              3   2   K   | ]  \  }}d | d|   yw)zlabel=r   Nr   )r   kvs      r6   r   zjobs_ps.<locals>.<genexpr>  s$     :gPTPQSTVA3as;K:g   zNo jobs matched filters: zHNo running jobs. Use `-a`/`--all` to include finished (and failed) jobs.)r$   r+   warningr   rA   r3   r   r   r   
SCHEDULINGr   r   	itertoolsislicer   r*   r   r   replacer   rH   tablerE   itemsrY   )r   r[   rj   r   r-   rr   r   r:   raw_statusesr   server_statusesrw   itemr   	jobs_iter	truncatedjobs	job_itemsrP   job_itemr   cmdfilters_msgs                          r6   jobs_psr  )  s   t 5
!Cx (p p	

 vIJJ !L2 WVU[[5EVVW &	#++1183F3F3L3LM  F d?3D69[\]]ZZ_
Us	 	/RXR`\`aI IqyI$$Y	:;t9uI<DI ')I 
#%c*LL-3	ll9%+%\\$3"*,,~">"G%/2chhsmOW||\hOih|4Sb9AA#sKot&ll84:??S-immN.KL"
# IIT
 'w.bcd6))h7,7h:gX^XdXdXf:ghK HH0>?HH_`  r8   hardwarezhf jobs hardwarec                  ^   t               } | j                         }g }|D ]  }d}|j                  rG|j                  j                   d|j                  j                   d|j                  j
                   d}|j                  rd|j                  dnd}|j                  rd|j                  dz  d	nd}|j                  |j                  |j                  |j                  |j                  |j                  |||d
        t        j                  |       t        j                  d       y)z(List available hardware options for JobsrT   zx  ()$z.4ffree<   z.2f)rX   zpretty namecpuramstorageacceleratorzcost/minz	cost/hourzLUse `hf jobs run --flavor <name> ...` to request a specific hardware flavor.N)r$   list_jobs_hardwarer%  quantitymodelvramunit_cost_usdrH   rX   pretty_namer"  r#  ephemeral_storager+   r  rE   )r:   hardware_listr  hwaccelerator_infocost_min	cost_hours          r6   jobs_hardwarer2    s    ,C**,ME 
>>"$.."9"9!:"R^^=Q=Q<RRTUWUcUcUhUhTiijk131A1AQr'',-v797G7Ga((2-c23V	!~~vvvv///$&		

$ IIeHH[\r8   inspectzhf jobs inspect <job_id>z*Job IDs to inspect (or 'namespace/job_id')c                    g }| D ]"  }t        ||      \  }}|j                  |       $ |} t        |      }| D cg c]  }|j                  ||       }}t	        j
                  |D cg c]  }t        |       c}       yc c}w c c}w )z0Display detailed information on one or more Jobsrt   rS   N)r7   rH   r$   inspect_jobr+   r  r*   )r   r-   rr   r   r,   r:   r  rP   s           r6   jobs_inspectr6    s     J "8K	&!" G
5
!CNUVFCOO6YO?VDVII$73!#&78 W7   B+B
cancelzhf jobs cancel <job_id>c                     t        | |      \  } }t        |      }|j                  | |       t        j                  d|        y)zCancel a Jobrt   rS   zJob cancelledrV   N)r7   r$   
cancel_jobr+   rI   )r,   r-   rr   r:   s       r6   jobs_cancelr<    s=     5VYGFI
5
!CNN&IN6JJ6*r8   wait)zhf jobs wait <job_id>z"hf jobs wait <job_id_1> <job_id_2>z"hf jobs ls -q | xargs hf jobs waitz,Job IDs to wait for (or 'namespace/job_id').zTMax time to wait: int with s (seconds, default), m (minutes), h (hours) or d (days).c           
      *   g }t               }| D ]3  }t        ||      \  }}|j                  |       |j                  |       5 t	        |      dkD  r3t        ddj                  d t        |t              D              z         |j                         }|t        |      nd}	t        |      }
t        j                  dt	        |       d	      }	 |
j                  ||	|
      }|j!                  t	        |       d       t        j"                  |D cg c]C  }|j$                  t        |j                  j&                        |j                  j(                  dE c}       |D cg c],  }|j                  j&                  t*        j,                  k7  s+|. }}|r<t        t	        |       dt	        |       ddj                  d |D              z         y# t        $ r" |j!                  d       t        d| d      dw xY wc c}w c c}w )a  Wait for one or more Jobs to reach a terminal state.

    Blocks until every Job has finished, then exits with code 0 if all Jobs completed
    successfully, or a non-zero exit code if any Job was canceled, errored or deleted.

    All Jobs must belong to the same namespace.
    r   z0All Job IDs must be in the same namespace, got: r  c              3   2   K   | ]  }t        |        y wr   )r   )r   nss     r6   r   zjobs_wait.<locals>.<genexpr>  s     FBBFr  )r   Nrt   zWaiting for z Job(s) to finish...)rn   r-   z
Timed out.zTimed out after z waiting for Job(s) to finish.z Job(s) finished.)rV   r\   r^   z of z' Job(s) did not complete successfully: c              3   h   K   | ]*  }|j                    d |j                  j                   d , yw)r  r  N)rV   r[   r\   )r   rP   s     r6   r   zjobs_wait.<locals>.<genexpr>(  s,     KS366("SZZ%5%5$6a8Ks   02)setr7   rH   addr   r   r   r   r   r   r   r$   r+   r[   rZ   TimeoutErrorr   r  rV   r\   r^   r   r]   )r   rn   r-   rr   r   
namespacesr,   	parsed_idparsed_namespacetimeout_secsr:   r[   r  rP   faileds                  r6   	jobs_waitrJ    s   > JJ )&B69&U#	#)$'() :>iiF&*EFFG
 	
  I.5.A>'*tL
5
!CZZ,s:&77KLMF]
LIV KK3t9+./0IIhlmadcffs3::+;+;'<I[I[\mn!LcSZZ%5%59K9K%KcLFL6{m4D	{*QRiiKFKKL
 	
   ]L!)'2PQRX\\]
 nLs   G AH+,HH+Hrw   )z*hf jobs labels <job_id> --name training-v2z8hf jobs labels <job_id> --label env=prod --label team=mlzhf jobs labels <job_id> --clearclearz--clearzRemove all labels from the job.c                 f   |s||st        d      |s||rt        d      t        | |      \  } }t        |      }|,|s*|j                  | |      j                  xs i }i |d|i}nt        ||      xs i }|j                  | ||      }	t        j                  d	|	j                  
       y)zfUpdate labels on a Job. Passing --label replaces all existing labels; passing --name alone keeps them.NePlease set a name with --name or at least one label with --label. To remove all labels, pass --clear.lCannot set a name or labels and clear them at the same time. Please use --name/--label or --clear, not both.rt   rS   rX   ru   )r,   rw   r-   Labels updatedr:  )
r   r7   r$   r5  rw   r   update_job_labelsr+   rI   rV   )
r,   rX   rj   rK  r-   rr   r:   current_labelsrw   rP   s
             r6   jobs_labelsrR  ,  s    " T\%s
 	
 	!uz
 	
 5VYGFI
5
!C)LSSYWY1N1FD1"5t4:


vf	

RCJJCFF+r8   )zhf jobs ssh <job_id>zhf jobs ssh <job_id> --dry-runz)hf jobs ssh <job_id> -i ~/.ssh/id_ed25519identity_filedry_runc                    t        | |      \  } }t        |      }|j                  | |      }|j                  j                  t        d      |j                  j                  t        v r0t        d|j                   d|j                  j                   d      |j                  j                  t        j                  k7  rt        j                  d|j                   d	|j                  j                   d
      }|j                  |j                  |t        j                  g      }|j                  j                  t        j                  k7  rA|j                  d       t        d|j                   d|j                  j                   d      |j                  d       t        |j                  j                        }t        |j                    d|j"                   |j$                  ||       y)a   SSH into a running Job.

    If the Job is not yet running, waits until it reaches the RUNNING state before
    connecting. Requires the Job to be started with SSH enabled (`hf jobs run --ssh ...`)
    and your SSH public key to be registered at https://huggingface.co/settings/keys.
    rt   rS   Nz[SSH is not enabled on this job. Start a job with SSH support using `hf jobs run --ssh ...`.zCannot SSH into job 'z%': job has already finished (stage: 'z').zWaiting for job 'z' to be running (stage: 'z')...)r,   r-   stageszJob finished.z1': job finished before reaching RUNNING (stage: 'zJob is running.@)portrS  rT  )r7   r$   r5  r[   r   r   r\   r   rV   r   r   r+   rZ   r   r   r#   usernamehostnamerX  )	r,   rS  rT  r-   rr   r:   rP   r[   r   s	            r6   jobs_sshr[  Q  s   * 5VYGFI
5
!C
//9/
=C
zz!tuu
zz...svvh6[\_\f\f\l\l[mmpqrr
zz8+++/x7PQTQ[Q[QaQaPbbghicff	8K[K[J\]::x///KK('x/`adakakaqaq`rruv  	%&szz))*G
Ag../0\\#	r8   zFRun UV scripts (Python with inline dependencies) on HF infrastructure.uvru   )z,hf jobs uv run --name my-script my_script.pyz$hf jobs uv run --detach my_script.pyz1hf jobs uv run ml_training.py --flavor a10g-smallz+hf jobs uv run --with transformers train.pyzNhf jobs uv run -v hf://org/my-model:/data -v hf://buckets/org/b:/mnt script.pyscriptscript_argswith_pythonc                    t        ||	      }t        ||
      }t        |      }|j                  | |xs g |||||t        ||      t	        |||      |||||      }t        j                  d|j                  |j                         |:t        j                  d|j                  j                   d	|j                   d
       t        |j                  j                  t              rDdj!                  d |j                  j                  D              }t        j                  d|        t        |j                  j"                  t$              r:t        j                  d|j                  j                   d	|j                   d       |r[|j                  j                   d	|j                   }t        j                  d| d| d       t        j                  d| d       yt'        ||       y)8Run a UV script (local file or URL) on HF infrastructurert   ru   rv   )r]  r^  dependenciesr`  rf   rh   ri   rw   r9   rm   rn   rp   rq   r-   rx   ry   Nr{   r0   r|   r}   c              3   &   K   | ]	  }d |   ywr   r   r   s     r6   r   zjobs_uv_run.<locals>.<genexpr>  r   r   r   r   r   r   r   r   r   r   )r%   r$   
run_uv_jobr   rM   r+   rI   rV   rz   rE   rW   rX   r   r[   r   r   r   r   r   ra   )r]  r^  rf   rm   rh   ri   rX   rj   rL   rk   rl   rn   ro   rp   rq   r-   rr   r_  r`  r   r   r:   rP   r   r   s                            r6   jobs_uv_runrf    s   B C*G6K
5
!C
..%2 T2+FyQ  C  JJ}SWW5|6syy~~6Fax~^_#**(($/yyFszz/E/EFFghlgmno#**$$c*$SYY^^$4AcffX=cdeYY^^$AcffX.(	1WX_W``rst%gY.KLM!#s+r8   z,Create and manage scheduled Jobs on the Hub.	scheduledzRhf jobs scheduled run "0 0 * * *" --name daily-script python:3.12 python script.pyschedulesuspendconcurrencyc                    t        ||
      }t        ||      }t        |      }|j                  ||| ||||t        ||      t	        |	||      ||||      }t        j                  d|j                         |:t        j                  d|j                  j                   d	|j                   d
       t        j                  d|j                  j                   d	|j                   d       y)zSchedule a Job.rt   ru   rv   )rf   rg   rh  ri  rj  rh   ri   rw   r9   rm   rn   rp   r-   Scheduled Job createdr:  N7Name this scheduled Job with `hf jobs scheduled labels r0   r|   Use `hf jobs scheduled inspect ` to view its details.)r%   r$   create_scheduled_jobr   rM   r+   rI   rV   rE   rW   rX   )rh  rf   rg   ri  rj  rh   ri   rX   rj   rL   rk   rl   rm   rn   rp   r-   rr   r   r   r:   scheduled_jobs                        r6   scheduled_runrr    s    2 C*G6K
5
!C,, T2+FyQ - M JJ&=+;+;<|EmFYFYF^F^E__`anaqaq`r  sA  B	
 HH.}/B/B/G/G.H-JZJZI[[qrsr8   zhf jobs scheduled lsz1Show all scheduled Jobs (default hides suspended)z>Filter output based on conditions provided (format: key=value)c                    t        |      }|j                  |      }g }|xs g D ]  }d|v ra|j                  dd      \  }}	|j                  d      rd}
|dd }nd}
|j	                  |j                         |
|	j                         f       ht        j                  d	| d
        g }|D ]  }|j                  xs d}| s|r|j                  j                  xs d}|j                  j                  xs g }|rdj                  |      nd}|j                  |t        |      |d}t        ||      s|j	                  |        g }|D ]  }t!        |      }|j#                  d      xs i }|j#                  d      xs i }|j#                  d      }|j#                  d      xs g }|j#                  d      xs d|d<   |rdj                  |      nd|d<   |r)|j#                  d      r|d   dd j%                  dd      nd|d<   |j#                  d      r|d   dd j%                  dd      nd|d<   |j#                  d      xs d|d<   |j	                  |        t        j&                  |g dd       |s2|r0dj                  d  |D              }t        j(                  d!|        |r;|d"   d   }t        j*                  d#| d$       t        j*                  d%| d&       yy)'zList scheduled Jobsrt   r   r   r   !r   Nz Ignoring invalid filter format 'z'. Use key=value format.Fr   r>   )rV   rf   ri  rg   job_specr[   last_jobrg   r   r   atr   r   last_runnext_job_run_atnext_runri  )rV   rh  r   rg   ry  r{  ri  rV   r   r  c              3   4   K   | ]  \  }}}| | |   y wr   r   )r   r  or  s       r6   r   zscheduled_ps.<locals>.<genexpr>K  s"     DAq1#aSDs   z#No scheduled jobs matched filters: r   rn  z(` to view details about a scheduled job.zUse `hf jobs scheduled trigger z)` to trigger a scheduled job immediately.)r$   list_scheduled_jobsr3   endswithrH   r   r+   r	  ri  rv  r   rg   r   rV   r   r   r*   r   r  r  rY   rE   )r   r-   rr   r   r:   scheduled_jobsr   fr   r   opfiltered_jobsrq  ri  image_or_spacer  command_strpropsr  sjr  rv  status_dictrw  r  first_item_ids                             r6   scheduled_psr     s   , 5
!C,,y,AN*,G\r X!8aJC||C #2hNNCIIKU[[];<KK:1#=UVWX M' 
,''05w&//<<E$$,,2'*chhsm$''.SQX\fqrw/]+
, #%E !"%88J'-2hhx(.B??:.ll9%+&ll>:Ce]+.#((3-EYDLQYQ]Q]^bQc8D>#2.66sC@inZEP__UfEgK)*3B/77SAmr 	Z ((9-6YT II_
 WiiDGDD6{mDEa2=/Aijk2=/Ajkl r8   zhf jobs scheduled inspect <id>scheduled_job_idsz>Scheduled Job IDs to inspect (or 'namespace/scheduled_job_id')c                    g }| D ]"  }t        ||      \  }}|j                  |       $ |} t        |      }| D cg c]  }|j                  ||       }}t	        j
                  |D cg c]  }t        |       c}       yc c}w c c}w )z:Display detailed information on one or more scheduled Jobsrt   scheduled_job_idr-   N)r7   rH   r$   inspect_scheduled_jobr+   r  r*   )	r  r-   rr   r   r,   r:   r  r  rq  s	            r6   scheduled_inspectr  S  s     J# "8K	&!" #
5
!C !2 	!!3Cy!YN  IInU]!-0UV	 Vr7  deletezhf jobs scheduled delete <id>r  c                     t        | |      \  } }t        |      }|j                  | |       t        j                  d|        y)zDelete a scheduled Job.rt   r  zScheduled Job deletedr:  N)r7   r$   delete_scheduled_jobr+   rI   r  r-   rr   r:   s       r6   scheduled_deleter  l  F     #??OQZ"[i
5
!C.>)TJJ&+;<r8   zhf jobs scheduled suspend <id>c                     t        | |      \  } }t        |      }|j                  | |       t        j                  d|        t        j
                  d|  d       y)z Suspend (pause) a scheduled Job.rt   r  zScheduled Job suspendedr:  zUse `hf jobs scheduled resume z` to resume it.N)r7   r$   suspend_scheduled_jobr+   rI   rE   r  s       r6   scheduled_suspendr  y  s^     #??OQZ"[i
5
!C/?9UJJ(-=>HH-.>-?OPr8   resumezhf jobs scheduled resume <id>c                     t        | |      \  } }t        |      }|j                  | |       t        j                  d|        y)z!Resume (unpause) a scheduled Job.rt   r  zScheduled Job resumedr:  N)r7   r$   resume_scheduled_jobr+   rI   r  s       r6   scheduled_resumer    r  r8   triggerzhf jobs scheduled trigger <id>c                 ,   t        | |      \  } }t        |      }|j                  | |      }t        j                  d|j
                  |j                         t        j                  d|j                  j                   d|j
                   d       y)	zJTrigger a scheduled Job to run immediately (does not change the schedule).rt   r  zScheduled Job triggeredry   r   r0   z` to stream logs.N)
r7   r$   trigger_scheduled_jobr+   rI   rV   rz   rE   rW   rX   )r  r-   rr   r:   rP   s        r6   scheduled_triggerr    s|     #??OQZ"[i
5
!C

#
#5EQZ
#
[CJJ(SVVAHH$SYY^^$4AcffX=NOPr8   )z1hf jobs scheduled labels <id> --name daily-scriptz>hf jobs scheduled labels <id> --label env=prod --label team=mlz%hf jobs scheduled labels <id> --clearz)Remove all labels from the scheduled job.c                 z   |s||st        d      |s||rt        d      t        | |      \  } }t        |      }|6|s4|j                  | |      j                  j
                  xs i }i |d|i}nt        ||      xs i }|j                  | ||      }	t        j                  d	|	j                  
       y)zpUpdate labels on a scheduled Job. Passing --label replaces all existing labels; passing --name alone keeps them.NrM  rN  rt   r  rX   ru   )r  rw   r-   rO  r:  )r   r7   r$   r  rv  rw   r   update_scheduled_job_labelsr+   rI   rV   )
r  rX   rj   rK  r-   rr   r:   rQ  rw   rq  s
             r6   scheduled_labelsr    s    " T\%s
 	
 	!uz
 	
 #??OQZ"[i
5
!C %%7GS\%]ffmmsqs 	 2N1FD1"5t4:33)&I 4 M JJM$4$45r8   z)Schedule UV scripts on HF infrastructure.zBhf jobs scheduled uv run "0 0 * * *" --name daily-script script.pyz<hf jobs scheduled uv run "0 0 * * *" script.py --with pandasc                    t        ||      }t        ||      }t        |      }|j                  ||xs g | |||||||t        |
|	      t	        |||      ||||      }t        j                  d|j                         |	:t        j                  d|j                  j                   d	|j                   d
       t        j                  d|j                  j                   d	|j                   d       y)rb  rt   ru   rv   )r]  r^  rh  ri  rj  rc  r`  rf   rh   ri   rw   r9   rm   rn   rp   r-   rl  r:  Nrm  r0   r|   rn  ro  )r%   r$   create_scheduled_uv_jobr   rM   r+   rI   rV   rE   rW   rX   )rh  r]  r^  ri  rj  rf   rm   rh   ri   rX   rj   rL   rk   rl   rn   rp   r-   rr   r_  r`  r   r   r:   rP   s                           r6   scheduled_uv_runr    s    > C*G6K
5
!C

%
%%2 T2+FyQ! & C$ JJ&3662|J399>>JZZ[\_\b\b[ccqrsHH.syy~~.>axG]^_r8   c                    | s|yi }| xs g D ]$  }d|v r|j                  dd      n|df\  }}|||<   & |d|v rt        d      ||d<   |S )a  Parse label key-value pairs from CLI arguments.

    Args:
        labels: List of label strings in KEY=VALUE format. If KEY only, then VALUE is set to empty string.

    Returns:
        Dictionary mapping label keys to values, or None if no labels or name provided.
    Nr   r   rT   rX   z4--name and --label name=... cannot both be provided.)r3   r   )rw   rX   
labels_map	label_varr   r   s         r6   r   r     s}     dl!#J\r  	03y0@Y__S!,yRTo
U
3  ZQRR!
6r8   r   r   c           
         t        g | | D cg c]  }t        d |D               }}t        t        j                         j                  t        |      dz        }t        |      t        |      z   |kD  r|j                  t        |            }||xx   dz  cc<   t        |      t        |      z   |k  r#|t        |      z
  t        |      z
  ||   z   ||<   t        |      t        |      z   |kD  r dt        |      z  j                  | }g }|j                   |j                  |        |j                   |j                  |D cg c]  }d|z  	 c}        | D ]r  }	t        |	|      D 
cg c];  \  }
}t        t        |
            |kD  rt        |
      d|dz
   dz   n
t        |
      = }}
}|j                   |j                  |        t d	j                  |      S c c}w c c}w c c}}
w )
z
    Inspired by:

    - stackoverflow.com/a/8356620/593036
    - stackoverflow.com/questions/9535954/printing-lists-as-tabular-data
    c              3   D   K   | ]  }t        t        |              y wr   )r   r   )r   xs     r6   r   z_tabulate.<locals>.<genexpr>*  s     /ac#a&k/s       r   z{{:{}}} -N   z...r}   )r   maxshutilget_terminal_sizecolumnsr   sumindexformatrH   r   r   )r   r   col
col_widthsterminal_widthcol_to_minimize
row_formatlineswr   r  	col_widthrow_format_argss                r6   r   r   #  s    <?;N;Ng;NOC#/3//OJO113;;S\B=NON
g,Z
(>
9$**3z?;?#)#w<#j/)^;*83z?*JSQX\*Y\fgv\w*wJ'	 g,Z
(>
9
 4*s7|+33Z@JE	LL"""G,-	LL"""j$AS1W$ABC : !$C 4
9 033q6{Y/FCF?Y]#e+CPQFR
 
 	&Z&&89: 99U# P %B
s   G*G/6A G4r   queuefunc.kwargsc                 @     |di |D ]  }| j                  |        y )Nr   )put)r  r  r  rI   s       r6   _write_generator_to_queuer  A  s#    .. 		&r8   r   r   c          	   #   6  K   t               }|D cg c]  }| j                  t        |||f       }}	 	 	 |j                  d       c c}w # t        $ r' t        d |D              r|j                         rY nY 5w xY wn# t        $ r Y nw xY w	 |D cg c]  }|j                  d       nc c}w c} y# t        j                  $ r Y yw xY w# 	 |D cg c]  }|j                  d       nc c}w c} w # t        j                  $ r Y w w xY wxY ww)a;  
    Takes a function that returns an iterable of items, and run it in parallel using threads to return the flattened iterable of items as they arrive.

    This is inspired by those three `map()` variants, and is the mix of all three:

    * `imap()`: like `map()` but returns an iterable instead of a list of results
    * `imap_unordered()`: like `imap()` but the output is sorted by time of arrival
    * `flatmap()`: like `map()` but given a function which returns a list, `flatmap()` returns the flattened list that is the concatenation of all the output lists
    g?)rn   c              3   <   K   | ]  }|j                           y wr   )ready)r   async_results     r6   r   z%iflatmap_unordered.<locals>.<genexpr>\  s     N|))+Ns   N)
r   apply_asyncr  r   r   r   emptyKeyboardInterruptr   rD  )r   r  r   r  r  async_resultsr  s          r6   r   r   F  s     gEfqr\bT%%&?%vAVWrMriii--  s
  NNNSXS^S^S` 	@MN\d+NN++ 			@MN\d+NN++ 		s   D ADB A 
B D+B ;B ?B  B C 	BC BC B; B21	B; :D;CDCDDC=C43	C=<D=DDDDD)NNNNNNNNNFNFNN)FNNN)NNN)FNNr   NNN)r.   N)NN)NNFNN)NFNN)NNNNNNNNNNNFNFNNNN)NNNNNNNNNNNNNN)NNNNNNNNNNNNNNNNNN)__doc__r  r   multiprocessing.poolr  r   collections.abcr   r   r   pathlibr   r  r   r   typingr	   r
   r   urllib.parser   huggingface_hubr   r   r   r   r   r   huggingface_hub._jobs_apir   huggingface_hub.errorsr   huggingface_hub.utilsr   $huggingface_hub.utils._cache_managerr   huggingface_hub.utils._hf_urisr   huggingface_hub.utils._parsingr   r   
_cli_utilsr   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   
_frameworkr(   r)   _outputr*   r+   
get_logger__name__loggerr   tupler7   r   rM   r   ImageArgImageOpt	FlavorOpt	LabelsOptNameOpt
TimeoutOptbool	DetachOptNamespaceOptint	ExposeOptSshEnabledOptWithOpt	PythonOpt
SuspendOptConcurrencyOptScheduleArg	ScriptArgScriptArgsArg
CommandArgJobIdArg	JobIdsArgScheduledJobIdArgJobVolumesOptjobs_clira   rg   r   r   r   r   r   r   r   r  r2  r6  r<  rJ  rR  r[  uv_app	add_grouprf  scheduled_apprr  r  r  r  r  r  r  r  scheduled_uv_appr  r   r   r   r  r   r   r   r   r8   r6   <module>r      s<   G      .    * * ! T T 9 + ) = 7 J    ) , 
		H	%. .t .cSVY]S]oH^ .8)#Y)',)9<t)	&\D)X    ' $J
= $J
rk*	 I
B	 $J
X $J
_
 
B	 $J
e I
 G	 
 p I
4 $J
D	 4K
0
 4K
G f 3	 I' I"
 - I.	 A  I
e	
 ?@	*u 	*7 	*t 	* 
	.5  
  #'"!1,1,1, 
1, 	1,
 1, 1, 1, 1, !1, 1, 1, 1, 1, 
1, 1,  !1," 
#1,
1,h 

  $ 	 	"'&x&x E	
	&x d
 J	
	&x$ %&x& '&x( 
)&x&xRT#s(^ d5cSVCW>X ]a '3 '4 '!)$sCx.!9JNs)eD#tDsO44568 
'%=$>?"A'A'A' A' 
	A' @A'H 
  	$ 	 	 	 	" 	Sxa	j	
	
xa S	D!(+y	
	xa" S	D O	
	#xa2 V	
	3xa@ AxaB CxaD S	DE	
	ExaT 
Uxa	xav 
*(:';<] =]6 
)'A&BC #9S	=	
	9 9 9 
9 D9* 
(&?%@A #	+	+	+ 	+ 
		+ B	+ 

  ( 	"4
S	?	
	4
 d
g	
	4
 4
 4
 
4
4
n 
   X]",,
, , T6)2STTU	,
 , , 
,,: 
	   )-!"##%# # 	#
 # 
##L 
d	e   6  % 	.5  
 "& #'"'7,7,7, 7, 	7,
 
7, 7, 7, 7, 7, 7, !7, 7, 7, 7, 
7,  !7," #7,$ %7,& '7,( 
)7,
7,t #QR   ={  3 	.5bc   "& #'"#,t,t,t ,t 	,t
  ,t 
,t ,t ,t ,t ,t ,t !,t ,t ,t ,t  !,t" #,t$ 
%,t
,t^ '3I2JK 	" 	%Om	D	
	
Om Om Om S	DQ	
	Om& 
'Om LOmd y,L+MN #W S	Q	
	W W W 
W OW0 x+J*KL #	='	=	= 	= 
		= M	= y,L+MN #
Q'
Q
Q 
Q 
	
Q O
Q x+J*KL #	='	=	= 	= 
		= M	= y,L+MN #
Q'
Q
Q 
Q 
	
Q O
Q    bg"6'6
6 6 T6)2]^^_	6
 6 6 
66B !&QR    (t  4 	.5LF   "&"& #'")0`0`0` 0` 	0`
  0` 0` 0` 
0` 0` 0` 0` 0` 0` !0` 0`  !0`" #0`$ %0`& '0`( )0`* 
+0`0`l GK d3i$. t tTWY\T\~`dOd ,DcCi) DI # 6 CLU1X Xc8A;>N5O Y] bf 




)
)
3#
$ d	
 a[r8   