gL imddlmZddlmZmZddlZddlmZddlm Z ddl m Z ddl m ZddlmZe rdd lmZmZmZmZdd lmZmZdd lmZmZmZed Zed ZedZedZ ddeeee ddZ!edZ"edZ#dddee"e#ddZ$edZ%d9dZ&d:dZ' d; d) annotations)ABCabstractmethodN)dedent) TYPE_CHECKING get_option)format) pprint_thing)IterableIteratorMappingSequence)Dtype WriteBuffer) DataFrameIndexSeriesa max_cols : int, optional When to switch from the verbose to the truncated output. If the DataFrame has more than `max_cols` columns, the truncated output is used. By default, the setting in ``pandas.options.display.max_info_columns`` is used.aR show_counts : bool, optional Whether to show the non-null counts. By default, this is shown only if the DataFrame is smaller than ``pandas.options.display.max_info_rows`` and ``pandas.options.display.max_info_columns``. A value of True always shows the counts, and False never shows the counts.a >>> int_values = [1, 2, 3, 4, 5] >>> text_values = ['alpha', 'beta', 'gamma', 'delta', 'epsilon'] >>> float_values = [0.0, 0.25, 0.5, 0.75, 1.0] >>> df = pd.DataFrame({"int_col": int_values, "text_col": text_values, ... "float_col": float_values}) >>> df int_col text_col float_col 0 1 alpha 0.00 1 2 beta 0.25 2 3 gamma 0.50 3 4 delta 0.75 4 5 epsilon 1.00 Prints information of all columns: >>> df.info(verbose=True) RangeIndex: 5 entries, 0 to 4 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 int_col 5 non-null int64 1 text_col 5 non-null object 2 float_col 5 non-null float64 dtypes: float64(1), int64(1), object(1) memory usage: 248.0+ bytes Prints a summary of columns count and its dtypes but not per column information: >>> df.info(verbose=False) RangeIndex: 5 entries, 0 to 4 Columns: 3 entries, int_col to float_col dtypes: float64(1), int64(1), object(1) memory usage: 248.0+ bytes Pipe output of DataFrame.info to buffer instead of sys.stdout, get buffer content and writes to a text file: >>> import io >>> buffer = io.StringIO() >>> df.info(buf=buffer) >>> s = buffer.getvalue() >>> with open("df_info.txt", "w", ... encoding="utf-8") as f: # doctest: +SKIP ... f.write(s) 260 The `memory_usage` parameter allows deep introspection mode, specially useful for big DataFrames and fine-tune memory optimization: >>> random_strings_array = np.random.choice(['a', 'b', 'c'], 10 ** 6) >>> df = pd.DataFrame({ ... 'column_1': np.random.choice(['a', 'b', 'c'], 10 ** 6), ... 'column_2': np.random.choice(['a', 'b', 'c'], 10 ** 6), ... 'column_3': np.random.choice(['a', 'b', 'c'], 10 ** 6) ... }) >>> df.info() RangeIndex: 1000000 entries, 0 to 999999 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 column_1 1000000 non-null object 1 column_2 1000000 non-null object 2 column_3 1000000 non-null object dtypes: object(3) memory usage: 22.9+ MB >>> df.info(memory_usage='deep') RangeIndex: 1000000 entries, 0 to 999999 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 column_1 1000000 non-null object 1 column_2 1000000 non-null object 2 column_3 1000000 non-null object dtypes: object(3) memory usage: 165.9 MBz DataFrame.describe: Generate descriptive statistics of DataFrame columns. DataFrame.memory_usage: Memory usage of DataFrame columns.rz and columns)klasstype_sub max_cols_subshow_counts_sub examples_sub see_also_subversion_added_suba >>> int_values = [1, 2, 3, 4, 5] >>> text_values = ['alpha', 'beta', 'gamma', 'delta', 'epsilon'] >>> s = pd.Series(text_values, index=int_values) >>> s.info() Index: 5 entries, 1 to 5 Series name: None Non-Null Count Dtype -------------- ----- 5 non-null object dtypes: object(1) memory usage: 80.0+ bytes Prints a summary excluding information about its values: >>> s.info(verbose=False) Index: 5 entries, 1 to 5 dtypes: object(1) memory usage: 80.0+ bytes Pipe output of Series.info to buffer instead of sys.stdout, get buffer content and writes to a text file: >>> import io >>> buffer = io.StringIO() >>> s.info(buf=buffer) >>> s = buffer.getvalue() >>> with open("df_info.txt", "w", ... encoding="utf-8") as f: # doctest: +SKIP ... f.write(s) 260 The `memory_usage` parameter allows deep introspection mode, specially useful for big Series and fine-tune memory optimization: >>> random_strings_array = np.random.choice(['a', 'b', 'c'], 10 ** 6) >>> s = pd.Series(np.random.choice(['a', 'b', 'c'], 10 ** 6)) >>> s.info() RangeIndex: 1000000 entries, 0 to 999999 Series name: None Non-Null Count Dtype -------------- ----- 1000000 non-null object dtypes: object(1) memory usage: 7.6+ MB >>> s.info(memory_usage='deep') RangeIndex: 1000000 entries, 0 to 999999 Series name: None Non-Null Count Dtype -------------- ----- 1000000 non-null object dtypes: object(1) memory usage: 55.3 MBzp Series.describe: Generate descriptive statistics of Series. Series.memory_usage: Memory usage of Series.rz .. versionadded:: 1.4.0 a Print a concise summary of a {klass}. This method prints information about a {klass} including the index dtype{type_sub}, non-null values and memory usage. {version_added_sub} Parameters ---------- verbose : bool, optional Whether to print the full summary. By default, the setting in ``pandas.options.display.max_info_columns`` is followed. buf : writable buffer, defaults to sys.stdout Where to send the output. By default, the output is printed to sys.stdout. Pass a writable buffer if you need to further process the output. {max_cols_sub} memory_usage : bool, str, optional Specifies whether total memory usage of the {klass} elements (including the index) should be displayed. By default, this follows the ``pandas.options.display.memory_usage`` setting. True always show memory usage. False never shows memory usage. A value of 'deep' is equivalent to "True with deep introspection". Memory usage is shown in human-readable units (base-2 representation). Without deep introspection a memory estimation is made based in column dtype and number of rows assuming values consume the same memory amount for corresponding dtypes. With deep memory introspection, a real memory usage calculation is performed at the cost of computational resources. See the :ref:`Frequently Asked Questions ` for more details. {show_counts_sub} Returns ------- None This method prints a summary of a {klass} and returns None. See Also -------- {see_also_sub} Examples -------- {examples_sub} c<t|d|j|S)a Make string of specified length, padding to the right if necessary. Parameters ---------- s : Union[str, Dtype] String to be formatted. space : int Length to force string to be of. Returns ------- str String coerced to given length. Examples -------- >>> pd.io.formats.info._put_str("panda", 6) 'panda ' >>> pd.io.formats.info._put_str("panda", 4) 'pand' N)strljust)sspaces \/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/pandas/io/formats/info.py_put_strr#%s. q6&5>   &&cLdD]}|dkr |d|d|cS|dz}|d|dS)a{ Return size in human readable format. Parameters ---------- num : int Size in bytes. size_qualifier : str Either empty, or '+' (if lower bound). Returns ------- str Size in human readable format. Examples -------- >>> _sizeof_fmt(23028, '') '22.5 KB' >>> _sizeof_fmt(23028, '+') '22.5+ KB' )bytesKBMBGBTBg@z3.1f z PB)numsize_qualifierxs r" _sizeof_fmtr0?sQ0/ <$Z/q4 4 v $Z's ++r$c | td}|S)z5Get memory usage based on inputs and display options.zdisplay.memory_usager) memory_usages r"_initialize_memory_usager3^s!"89 r$ceZdZUdZded<ded<eeddZeeddZeeddZ eedd Z edd Z edd Z e dd Z y ) _BaseInfoaj Base class for DataFrameInfo and SeriesInfo. Parameters ---------- data : DataFrame or Series Either dataframe or series. memory_usage : bool or str, optional If "deep", introspect the data deeply by interrogating object dtypes for system-level memory consumption, and include it in the returned values. DataFrame | Seriesdata bool | strr2cy)z Dtypes. Returns ------- dtypes : sequence Dtype of each of the DataFrame's columns (or one series column). Nr,selfs r"dtypesz_BaseInfo.dtypesxr$cy)!Mapping dtype - number of counts.Nr,r:s r" dtype_countsz_BaseInfo.dtype_countsr=r$cy)BSequence of non-null counts for all columns or column (if series).Nr,r:s r"non_null_countsz_BaseInfo.non_null_countsr=r$cy)z Memory usage in bytes. Returns ------- memory_usage_bytes : int Object's total memory usage in bytes. Nr,r:s r"memory_usage_bytesz_BaseInfo.memory_usage_bytesr=r$cHt|j|jdS)z0Memory usage in a form of human readable string. )r0rEr.r:s r"memory_usage_stringz_BaseInfo.memory_usage_strings%d55t7J7JKLBOOr$cd}|jrC|jdk7r4d|jvs$|jjj rd}|S)Nrdeepobject+)r2r@r7index_is_memory_usage_qualified)r;r.s r"r.z_BaseInfo.size_qualifiersM     F*  1 11yyAAC%(Nr$cyNr,)r;bufmax_colsverbose show_countss r"renderz_BaseInfo.renders r$NreturnzIterable[Dtype]rWMapping[str, int]rW Sequence[int]rWintrWr rQWriteBuffer[str] | NonerR int | NonerS bool | NonerTrbrWNone)__name__ __module__ __qualname____doc____annotations__propertyrr<r@rCrErHr.rUr,r$r"r5r5gs     00QQ  PP   %     !     r$r5ceZdZdZ d d dZed dZeddZeddZeddZ eddZ edd Z dd Z y) DataFrameInfoz0 Class storing dataframe-specific info. Nc2||_t||_yrPr7r3r2r;r7r2s r"__init__zDataFrameInfo.__init__s $ 4\Br$c,t|jSrP)_get_dataframe_dtype_countsr7r:s r"r@zDataFrameInfo.dtype_countss*49955r$c.|jjS)z Dtypes. Returns ------- dtypes Dtype of each of the DataFrame's columns. r7r<r:s r"r<zDataFrameInfo.dtypessyyr$c.|jjS)zz Column names. Returns ------- ids : Index DataFrame's column names. )r7columnsr:s r"idszDataFrameInfo.idssyy   r$c,t|jSz#Number of columns to be summarized.)lenrvr:s r" col_countzDataFrameInfo.col_counts488}r$c6|jjS)rBr7countr:s r"rCzDataFrameInfo.non_null_countssyy  r$cv|jdk(}|jjd|jS)NrJTrMrJ)r2r7sumr;rJs r"rEz DataFrameInfo.memory_usage_bytess5  F*yy%%Dt%<@@BBr$cDt||||}|j|y)N)inforRrSrT)_DataFrameInfoPrinter to_bufferr;rQrRrSrTprinters r"rUzDataFrameInfo.renders*(#   #r$rP)r7rr2bool | str | NonerWrcrXrVrWrr\rZr_) rdrerfrgrorir@r<rvrzrCrErUr,r$r"rkrks+/CC(C  C66     ! !!!CC%    !  r$rkceZdZdZ d d dZddddd d dZed dZeddZeddZ edd Z y) SeriesInfoz- Class storing series-specific info. Nc2||_t||_yrPrmrns r"rozSeriesInfo.__init__s ! 4\Br$)rQrRrSrTc\| tdt|||}|j|y)NzIArgument `max_cols` can only be passed in DataFrame.info, not Series.info)rrSrT) ValueError_SeriesInfoPrinterrrs r"rUzSeriesInfo.rendersA  5 %#  #r$c8|jjgSrPr|r:s r"rCzSeriesInfo.non_null_counts$s !""r$c0|jjgSrPrsr:s r"r<zSeriesInfo.dtypes(s   !!r$cDddlm}t||jS)Nr)r)pandas.core.framerrqr7)r;rs r"r@zSeriesInfo.dtype_counts,s/*9TYY+?@@r$cZ|jdk(}|jjd|S)zMemory usage in bytes. Returns ------- memory_usage_bytes : int Object's total memory usage in bytes. rJTr)r2r7rs r"rEzSeriesInfo.memory_usage_bytes2s.  F*yy%%Dt%<A3EFFr$cFt|j|jkDS)zDCheck if number of columns to be summarized does not exceed maximum.)boolrzrRr:s r"exceeds_info_colsz'_DataFrameInfoPrinter.exceeds_info_colsssDNNT]]233r$cXtt|j|jkDS)zACheck if number of rows to be summarized does not exceed maximum.)rryr7rr:s r"exceeds_info_rowsz'_DataFrameInfoPrinter.exceeds_info_rowsxs C NT]]233r$c.|jjSrxrrzr:s r"rzz_DataFrameInfoPrinter.col_count}yy"""r$c<|td|jdzS|S)Nzdisplay.max_info_columnsr)r rz)r;rRs r"rz*_DataFrameInfoPrinter._initialize_max_colss$  8$..1:LM Mr$cT|%t|j xr |j S|SrP)rrrr;rTs r"rz-_DataFrameInfoPrinter._initialize_show_countss0  D222Q4;Q;Q7QR R r$c*|jr!t|j|jS|jdurt |jS|j rt |jSt|j|jS)z[ Create instance of table builder based on verbosity and display settings. r with_countsFr)rS_DataFrameTableBuilderVerboserrT _DataFrameTableBuilderNonVerboserr:s r"rz+_DataFrameInfoPrinter._create_table_buildersz <<0YY ,, \\U "3C C  # #3C C0YY ,, r$)NNN) rrkrRrarSrbrTrbrWrcr\rWr)rRrarWr]rTrbrWr)rW_DataFrameTableBuilder) rdrerfrgrorirrrrzrrrr,r$r"rrQs $ $##' E E E E ! E  EGG4444##  r$rc<eZdZdZ d ddZddZd dZy) raClass for printing series info. Parameters ---------- info : SeriesInfo Instance of SeriesInfo. verbose : bool, optional Whether to print the full summary. show_counts : bool, optional Whether to show the non-null counts. Ncn||_|j|_||_|j||_yrP)rr7rSrrT)r;rrSrTs r"roz_SeriesInfoPrinter.__init__s0  II  77 Dr$c|js |j!t|j|jSt |jS)zF Create instance of table builder based on verbosity. rr)rS_SeriesTableBuilderVerboserrT_SeriesTableBuilderNonVerboser:s r"rz(_SeriesInfoPrinter._create_table_buildersB <<4<</-YY ,,  1dii@ @r$c |y|S)NTr,rs r"rz*_SeriesInfoPrinter._initialize_show_countss   r$)NN)rrrSrbrTrbrWrc)rW_SeriesTableBuilderr)rdrerfrgrorrr,r$r"rrsJ  $#' E E E! E  E Ar$rceZdZUdZded<ded<eddZeddZeddZ edd Z edd Z edd Z edd Z dd ZddZddZy)rz* Abstract builder for info table. list[str]_linesr5rcy)z-Product in a form of list of lines (strings).Nr,r:s r"rz_TableBuilderAbstract.get_linesr=r$c.|jjSrPrr7r:s r"r7z_TableBuilderAbstract.datasyy~~r$c.|jjS)z*Dtypes of each of the DataFrame's columns.)rr<r:s r"r<z_TableBuilderAbstract.dtypessyyr$c.|jjS)r?)rr@r:s r"r@z"_TableBuilderAbstract.dtype_countssyy%%%r$c@t|jjS)z Whether to display memory usage.)rrr2r:s r"display_memory_usagez*_TableBuilderAbstract.display_memory_usagesDII**++r$c.|jjS)z/Memory usage string with proper size qualifier.)rrHr:s r"rHz)_TableBuilderAbstract.memory_usage_stringsyy,,,r$c.|jjSrP)rrCr:s r"rCz%_TableBuilderAbstract.non_null_countssyy(((r$cr|jjtt|jy)z>Add line with string representation of dataframe to the table.N)rappendrtyper7r:s r"add_object_type_linez*_TableBuilderAbstract.add_object_type_lines! 3tDII/0r$c~|jj|jjj y)z,Add line with range of indices to the table.N)rrr7rM_summaryr:s r"add_index_range_linez*_TableBuilderAbstract.add_index_range_lines% 499??3356r$ct|jjDcgc]\}}|d|dd}}}|jj ddj |ycc}}w)z2Add summary line with dtypes present in dataframe.(d)zdtypes: z, N)sortedr@itemsrrjoin)r;keyvalcollected_dtypess r"add_dtypes_linez%_TableBuilderAbstract.add_dtypes_linesq/5T5F5F5L5L5N.O "*#sse1SG1    Xdii0@&A%BCD sA+NrWr)rWr6rVrXrr^rZrWrc)rdrerfrgrhrrrir7r<r@rrHrCrrrr,r$r"rrs  O<<  &&,,--))17Er$rcxeZdZdZd dZd dZd dZed dZe ddZ e ddZ e ddZ d d Z y )rz Abstract builder for dataframe info table. Parameters ---------- info : DataFrameInfo. Instance of DataFrameInfo. c||_yrPrr;rs r"roz_DataFrameTableBuilder.__init__s #' r$cg|_|jdk(r|j|jS|j|jS)Nr)rrz_fill_empty_info_fill_non_empty_infor:s r"rz _DataFrameTableBuilder.get_linessE >>Q   ! ! #{{  % % '{{r$c|j|j|jjdt |j j dy)z;Add lines to the info table, pertaining to empty dataframe.zEmpty rGN)rrrrrr7rdr:s r"rz'_DataFrameTableBuilder._fill_empty_infosD !!# !!# VDO$<$<#=R@Ar$cyz?Add lines to the info table, pertaining to non-empty dataframe.Nr,r:s r"rz+_DataFrameTableBuilder._fill_non_empty_infor=r$c.|jjS)z DataFrame.rr:s r"r7z_DataFrameTableBuilder.data#yy~~r$c.|jjS)zDataframe columns.)rrvr:s r"rvz_DataFrameTableBuilder.ids(syy}}r$c.|jjS)z-Number of dataframe columns to be summarized.rr:s r"rzz _DataFrameTableBuilder.col_count-rr$cT|jjd|jyz!Add line containing memory usage.zmemory usage: NrrrHr:s r"add_memory_usage_linez,_DataFrameTableBuilder.add_memory_usage_line2" ^D,D,D+EFGr$N)rrkrWrcrr)rWrrr\)rdrerfrgrorrrrrir7rvrzrr,r$r"rrso(B NN##Hr$rc eZdZdZddZddZy)rz> Dataframe info table builder for non-verbose output. c|j|j|j|j|jr|j yyr)rradd_columns_summary_linerrrr:s r"rz5_DataFrameTableBuilderNonVerbose._fill_non_empty_info<sL !!# !!# %%'   $ $  & & ( %r$cn|jj|jjdy)NColumnsname)rrrvrr:s r"rz9_DataFrameTableBuilderNonVerbose.add_columns_summary_lineEs& 488,,),<=r$Nr)rdrerfrgrrr,r$r"rr7s)>r$rceZdZUdZdZded<ded<ded<d ed <eedd Zedd Z dd Z ddZ ddZ eddZ eddZddZddZddZddZddZy)_TableBuilderVerboseMixinz( Mixin for verbose info output. z rSPACINGzSequence[Sequence[str]]strrowsr[gross_column_widthsrrcy).Headers names of the columns in verbose table.Nr,r:s r"headersz!_TableBuilderVerboseMixin.headersSr=r$cR|jDcgc] }t|c}Scc}w)z'Widths of header columns (only titles).)rryr;cols r"header_column_widthsz._TableBuilderVerboseMixin.header_column_widthsXs %)LL1SC111s$c|j}t|j|Dcgc] }t| c}Scc}w)zAGet widths of columns containing both headers and actual content.)_get_body_column_widthsziprmax)r;body_column_widthswidthss r"_get_gross_column_widthsz2_TableBuilderVerboseMixin._get_gross_column_widths]sE!99;d779KL  L   s;ctt|j}|Dcgc]}td|Dc}Scc}w)z$Get widths of table content columns.c32K|]}t|ywrP)ry).0r/s r" zD_TableBuilderVerboseMixin._get_body_column_widths..hs(qCF(s)listr rr )r;strcolsrs r"r z1_TableBuilderVerboseMixin._get_body_column_widthses4+/T\\0B+C4;* sA6 c |jD]i}|jjt||jDcgc]\}}t ||c}}}|j j|kycc}}wrP)rrrr rr#rr)r;rowrr& body_lines r"add_body_linesz(_TableBuilderVerboseMixin.add_body_linessr<< *C ))0338P8P/Q+^S.1I KK  y ) *sA: c#<K|jD] }|d yw)z7Iterator with string representation of non-null counts.z non-nullN)rC)r;r}s r"_gen_non_null_countsz._TableBuilderVerboseMixin._gen_non_null_countss()) &EG9% % &sc#HK|jD]}t|yw)z5Iterator with string representation of column dtypes.N)r<r )r;dtypes r" _gen_dtypesz%_TableBuilderVerboseMixin._gen_dtypess$[[ &Eu% % & "NrWz Sequence[str]rZrWzIterator[Sequence[str]]rrWz Iterator[str])rdrerfrgrrhrirrrrr rrrr"r(r,r.r1r,r$r"rrIsGS $$&& ==22 = 3LLOO( +*& &r$rcfeZdZdZ d dZd dZed dZd dZddZ ddZ ddZ dd Z y )rz: Dataframe info table builder for verbose output. c||_||_t|j|_|j |_yrPrrrrrrrr;rrs r"roz&_DataFrameTableBuilderVerbose.__init__7  &04T^^5E0F 262O2O2Q r$c|j|j|j|j|j |j |j |jr|jyyr) rrrr"r(r,rrrr:s r"rz2_DataFrameTableBuilderVerbose._fill_non_empty_infosp !!# !!# %%'  !    $ $  & & ( %r$c*|jrgdSgdS)r) # ColumnNon-Null Countr)r=r>rrr:s r"rz%_DataFrameTableBuilderVerbose.headerss   ? ?))r$cV|jjd|jdy)NzData columns (total z columns):)rrrzr:s r"rz6_DataFrameTableBuilderVerbose.add_columns_summary_lines# 1$..1ALMr$c#Kt|j|j|jEd{y7wr)r _gen_line_numbers _gen_columnsr1r:s r"rz6_DataFrameTableBuilderVerbose._gen_rows_without_countss<  " " $           s;AAAc#Kt|j|j|j|j Ed{y7wr)r rCrDr.r1r:s r"rz3_DataFrameTableBuilderVerbose._gen_rows_with_countssH  " " $      % % '        sA A A Ac#TKt|jD] \}}d|yw)z6Iterator with string representation of column numbers.r+N) enumeraterv)r;i_s r"rCz/_DataFrameTableBuilderVerbose._gen_line_numberss-dhh' DAqaS'M s&(c#HK|jD]}t|yw)z4Iterator with string representation of column names.N)rvr rs r"rDz*_DataFrameTableBuilderVerbose._gen_columnss$88 $Cs# # $r2N)rrkrrrWrcrr3r4r5) rdrerfrgrorrirrrrrCrDr,r$r"rrsa R R R  R )** N   $r$rcLeZdZdZddZd dZed dZd dZe d dZ y) rz Abstract builder for series info table. Parameters ---------- info : SeriesInfo. Instance of SeriesInfo. c||_yrPrrs r"roz_SeriesTableBuilder.__init__s $ r$cHg|_|j|jSrP)rrr:s r"rz_SeriesTableBuilder.get_liness  !!#{{r$c.|jjS)zSeries.rr:s r"r7z_SeriesTableBuilder.datarr$cT|jjd|jyrrr:s r"rz)_SeriesTableBuilder.add_memory_usage_linerr$cyz>*:;z-_get_dataframe_dtype_counts..Ms affr$)r< value_countsgroupbyr)dfs r"rqrqHs, 99 ! ! # + +,< = A A CCr$)r z str | Dtyper!r]rWr)r-floatr.rrWrrP)r2rrWr8)rarrWrY)8 __future__rabcrrrtextwraprtypingrpandas._configr pandas.io.formatsr rpandas.io.formats.printingr collections.abcr r rrpandas._typingrrpandasrrrframe_max_cols_subrframe_examples_subframe_see_also_subframe_sub_kwargsseries_examples_subseries_see_also_subseries_sub_kwargsINFO_DOCSTRINGr#r0r3r5rkrrrrrrrrrrrrrqr,r$r"rus"  %+3 @?QSlB&&&&9;|4&''6.0f'4,@'+#P P fFIFR9=9=x00$M0M`(-(V5EC5Ep0H20Hf>'=>$Z& 5Z&z?$$: