
    .hZV                       U d dl mZ d dlZd dlZd dlZd dlmZmZmZ d dlm	Z	m
Z
mZmZmZmZmZmZmZmZmZmZ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$ d d	l%m&Z& d d
l'm(Z( d dl)m*Z* er1d dl+m,Z, d dl-m.Z.m-Z- d dl/Z/d dl0Z/d dl1m2Z2 d dl3m4Z4 d dl5m6Z6 d dl7m8Z8m9Z9 nd dl:m/Z/ e#e$dZ;de<d<   dZ=de<d<   	 	 	 	 dB	 	 	 	 	 	 	 	 	 	 	 	 	 dCdZ>dDdZ?edEd       Z@e@j                  e      dFd       ZBe@j                  e      dGd       ZBe@j                  e      dHd       ZBe@j                  e      dId       ZBe@j                  e	      dJd       ZBe@j                  e
      dKd        ZBe@j                  e      dLd!       ZBe@j                  e      dMd"       ZB G d# d$      ZC G d% d&      ZDe G d' d(             ZEedNd)       ZF G d* d+ej                        ZH G d, d-eH      ZI G d. d/eH      ZJ G d0 d1eH      ZK G d2 d3eH      ZL G d4 d5eH      ZM G d6 d7eH      ZN G d8 d9eH      ZO G d: d;eI      ZP G d< d=eH      ZQ G d> d?eH      ZR G d@ dAeH      ZSy)O    )annotationsN)GtELtLtE)	AttributeBinOpBitAndBitOrCallCompareConstantEqGtInvertListNameUnaryOp)	dataclass)cachesingledispatch)TYPE_CHECKINGAnyCallable)
to_py_dateto_py_datetime)eprint)wrap_s)ComputeError)Sequence)datedatetime)DataFile)Table)IcebergType)	DataFrameSeries)	pyicebergz)dict[str, Callable[..., datetime | date]]_temporal_conversionsi  intICEBERG_TIME_TO_NSc                   ddl m} | j                  ||      }| |j                  | }|(	 t	        |      }t        |      }	|j                  |	      } ||j                               S # t        $ r}
d| }t        |      |
d}
~
ww xY w)a"  
    Take the projected columns and materialize an arrow table.

    Parameters
    ----------
    tbl
        pyarrow dataset
    with_columns
        Columns that are projected
    predicate
        pyarrow expression that can be evaluated with eval
    n_rows:
        Materialize only n rows from the arrow dataset.
    snapshot_id:
        The snapshot ID to scan from.
    batch_size
        The maximum row count for scanned pyarrow record batches.
    kwargs:
        For backward compatibility

    Returns
    -------
    DataFrame
    r   )
from_arrow)limitsnapshot_idNz*Could not convert predicate to PyIceberg: )	polarsr,   scanselect_to_ast_convert_predicate
ValueErrorfilterto_arrow)tblwith_columns	predicaten_rowsr.   kwargsr,   r0   expr_astpyiceberg_expremsgs               V/var/www/html/ai-service/venv/lib/python3.12/site-packages/polars/io/iceberg/_utils.py_scan_pyarrow_dataset_implrA   6   s    @ "88&k8:Dt{{L)	)y)H/9N
 {{>*dmmo&&  	)>ykJCS/q(	)s   A+ +	B
4BB
c                D    t        j                  | d      j                  S )a<  
    Converts a Python string to an AST.

    This will take the Python Arrow expression (as a string), and it will
    be converted into a Python AST that can be traversed to convert it to a PyIceberg
    expression.

    The reason to convert it to an AST is because the PyArrow expression
    itself doesn't have any methods/properties to traverse the expression.
    We need this to convert it into a PyIceberg expression.

    Parameters
    ----------
    expr
        The string expression

    Returns
    -------
    The AST representing the Arrow expression
    eval)mode)astparsebody)exprs    r@   r2   r2   j   s    * 99T',,,    c                "    d|  }t        |      )zJWalks the AST to convert the PyArrow expression to a PyIceberg expression.zUnexpected symbol: )r4   ar?   s     r@   r3   r3      s      s
#C
S/rI   c                    | j                   S N)valuerL   s    r@   _rQ      s    77NrI   c                    | j                   S rN   )idrP   s    r@   rQ   rQ      s    44KrI   c                    t        | j                  t              r2t        j                  j                  t        | j                              S d|  }t        |      )NzUnexpected UnaryOp: )	
isinstanceopr   r'   expressionsNotr3   operand	TypeErrorrK   s     r@   rQ   rQ      sG    !$$$$(();AII)FGG$QC(nrI   c                "   | j                   D cg c]  }t        |       }}t        | j                        }|dk(  r|S |dk(  r|d   S |t        v rt        |   | j	                         S t        | j                  j
                        d   }|dk(  r#t        j                  j                  ||d         S |dk(  rt        j                  j                  |      S |dk(  rt        j                  j                  |      S d|}t        |      c c}w )Nfieldscalarr   isinis_nullis_nanzUnknown call: )argsr3   funcr(   	isoformatrO   r'   rW   InIsNullIsNaNr4   )rL   argra   frefr?   s         r@   rQ   rQ      s    /0vv6s#6D6166"AG|	
hAw	
#	#$Q'.88:: .q1;((++Ca99)^((//44(]((..s331%
 C
S/' 7s   Dc                    | j                   S rN   )attrrP   s    r@   rQ   rQ      s    66MrI   c                Z   t        | j                        }t        | j                        }| j                  }t	        |t
              r t        j                  j                  ||      S t	        |t              r t        j                  j                  ||      S d| d| d| }t        |      )Nz	Unknown:  )r3   leftrightrV   rU   r	   r'   rW   Andr
   OrrZ   )rL   lhsrhsrV   r?   s        r@   rQ   rQ      s    
QVV
$C
QWW
%C	
B"f$$((c22"e$$''S11#at1SE*nrI   c                   | j                   d   }t        | j                        d   }t        | j                  d         }t	        |t
              r t        j                  j                  ||      S t	        |t              r t        j                  j                  ||      S t	        |t              r t        j                  j                  ||      S t	        |t              r t        j                  j                  ||      S t	        |t              r t        j                  j!                  ||      S d| }t#        |      )Nr   zUnknown comparison: )opsr3   rn   comparatorsrU   r   r'   rW   GreaterThanr   GreaterThanOrEqualr   EqualTor   LessThanr   LessThanOrEqualrZ   )rL   rV   rr   rs   r?   s        r@   rQ   rQ      s    	
qB
QVV
$Q
'C
Q]]1-
.C"b$$00c::"c$$77SAA"b$$,,S#66"b$$--c377"c$$44S#>>$RD)nrI   c                R    | j                   D cg c]  }t        |       c}S c c}w rN   )eltsr3   )rL   r>   s     r@   rQ   rQ      s     +,662aq!222s   $c                  @    e Zd Z	 	 	 	 	 	 ddZ	 	 	 	 	 	 	 	 ddZddZy))IdentityTransformedPartitionValuesBuilderc                   dd l }ddlm} ddlm} ddlm}m}m}m	}	 |j                  }
i | _        i | _        i | _        |j                         }|j                         D ]  \  }}g }t!        |j"                        D ]a  \  }}|j$                  |
v st'        |j(                  |      s,|j+                  ||j$                  f       g | j                  |j$                  <   c || j                  |<    | j                  D ]5  }|j-                  |      }|j.                  }t1        j2                   ||j4                  j3                  |                  j7                         \  }}|| j                  |<   |j8                  r|j;                         rd|d|| j                  |<   |j=                         j?                         D ]o  }	 |j-                  |      j.                  }||k(  r%t'        ||	      rt'        ||      r>t'        |||f      rt'        |||f      r[d| d| | j                  |<   q 8 y # t@        $ r Y w xY w)	Nr   schema_to_pyarrow)IdentityTransform)
DoubleType	FloatTypeIntegerTypeLongTypez%non-primitive type: projected_type = z output_dtype = zunsupported type change: from: z, to: )!pyiceberg.schemapyiceberg.io.pyarrowr   pyiceberg.transformsr   pyiceberg.typesr   r   r   r   	field_idspartition_valuespartition_values_dtypes(partition_spec_id_to_identity_transformsspecsitems	enumeratefields	source_idrU   	transformappend
find_field
field_typeplSchemaschemapopitemis_primitive	is_nestedschemasvaluesr4   )selftableprojected_schemar'   r   r   r   r   r   r   projected_idspartition_specsspec_idspecoutfield_indexr\   field_idprojected_fieldprojected_typerQ   output_dtyper   type_this_schemas                           r@   __init__z2IdentityTransformedPartitionValuesBuilder.__init__   s`   
 	 ::	
 	
 #3"<"< =? @B$
  	5  ++-,224 
	IMGTC&/&< @"U??m3
OO%69 JJU__=>=?D))%//:@ FID99'B
	I -- #	H.99(CO,77N ii!)"2"2"9"9/"JKgi A| 6BD((2!..,2H2H2J<>*==N|>OP %%h/  --/002 '-'8'8'B'M'M$
 #&66">8<&'7E #>J	3JK&'7*i9PQ ::J9K L-.0 ))(3##	$ " s   H66	IIc          
     n   	 | j                   |   }|D ]h  \  }}||   }t        | j                  |   x}	t              s+|	j                  d t        |t        |	      z
        D               |	j                  |       j y # t        $ r, | j                  D ci c]  }|d| 
 nc c}w c}| _        Y y w xY w)Nzpartition spec ID not found: c              3      K   | ]  }d   y wrN    ).0rQ   s     r@   	<genexpr>zRIdentityTransformedPartitionValuesBuilder.push_partition_values.<locals>.<genexpr>J  s     OqdOs   )	r   KeyErrorr   rU   listextendrangelenr   )
r   current_indexpartition_spec_idr   identity_transformskisource_field_idpartition_valuer   s
             r@   push_partition_valuesz?IdentityTransformedPartitionValuesBuilder.push_partition_values2  s    		"&"O"O!# #6 	/A.q1OD$9$9/$JJ&DQ OE-#f+2M,NOOo.	/  	 ..% 23D2EFF% %D! 	s   A? ?B4B$#B43B4c                   ddl m}m}m}m}m}m} i }| j                  j                         D ]  \  }}	t        |	t              r|	||<   	 | j                  |   }
t        |
|||f      r|nt        |
|      r|n|
}t        j                  |	|      }|j                  j                         rJ t        |
|      r	|t         z  }|j#                  |
      }|||<    |S # t$        $ r}d| ||<   Y d }~d }~ww xY w)Nr   )DateDatetimeDurationInt32Int64Timedtypez!failed to load partition values: )polars.datatypesr   r   r   r   r   r   r   r   rU   strr   r   r&   r   r   r*   cast	Exception)r   r   r   r   r   r   r   r   r   vr   constructor_dtypesr>   s                 r@   finishz0IdentityTransformedPartitionValuesBuilder.finishM  s   QQ*,00668 	LKHa!S! !HL#'#?#?#IL &lXx4NO  &lD9 #) & 		!+<=A ww00222!,5  22|,A$%CM5	L> 
 ! L&Gs$KCMLs   
BC	C7%C22C7N)r   r#   r   pyiceberg.schema.SchemareturnNone)r   r)   r   r)   r   zpyiceberg.typedef.Recordr   r   )r   dict[int, pl.Series | str])__name__
__module____qualname__r   r   r   r   rI   r@   r   r      sZ    MM 2M 
	M^/ / 	/
 3/ 
/6$rI   r   c                  <    e Zd Z	 	 	 	 	 	 ddZddZ	 	 	 	 	 	 ddZy)IcebergStatisticsLoaderc                   dd l }ddlm} dd l}dd l}|j
                  j                  j                         }i | _        g | _	        g | _
        || _        |j                  D ]|  }t               }	|j                         j                         D ]X  }
t!        j"                  t$              5  |	j'                  |
j)                  |j*                        j,                         d d d        Z  |j.                   ||j0                  j/                  |                  j3                         \  }}t4        j7                  |j,                  |	|      }|rT|t9        |      j:                  nd}t=        d|j>                  d|j*                  d|j,                  d|	d|d	|       tA        |j*                  |j>                  ||g g g 
      | j                  |j*                  <    y # 1 sw Y   _xY w)Nr   r   r   z&IcebergStatisticsLoader: field.name = z, field.field_id = z, field.field_type = z, field_all_types = z, field_polars_dtype = z, _load_from_bytes_impl = )r   column_namecolumn_dtypeload_from_bytes_impl
min_values
max_values
null_count)!r   r   r   r/   polars._utils.logging_utilsloggingverbosefile_column_statisticsload_as_empty_statisticsfile_lengthsprojected_filter_schemar   setr   r   
contextlibsuppressr4   addr   r   r   r   r   r   LoadFromBytesImplinit_for_field_typetyper   r   nameIcebergColumnStatisticsLoader)r   r   r   r'   r   r   r/   r   r\   field_all_typesr   rQ   field_polars_dtyper   _load_from_bytes_impls                  r@   r   z IcebergStatisticsLoader.__init__u  s   
 	 :$--''//1PR#35%')'>$,33 *	E!eO--/002 V((4 V#''(9(9%..(I(T(TUV VV %.BII!)"2"2"9"9%"@A%gi "A! $5#H#H  "$   ,7 -.77 & %zzo &)~~) *+''+ ,*&* +-)- .0,02 ;X!JJ/%9;D''7E*	V Vs   '5G  G*c                    | j                   j                  |j                         | j                  j	                         D ]  }|j                  |        y rN   )r   r   record_countr   r   push_file_statistics)r   filestatss      r@   r   z,IcebergStatisticsLoader.push_file_statistics  sH      !2!2300779 	-E&&t,	-rI   c                   dd l } |j                  d| j                  |j                        j	                         g}| j
                  j                         D ][  \  }}|j                  |      x} t        |t              rd| }t        |      |j                  ||      }	|j                  |	       ]  |j                  |d      S )Nr   r   r   z+statistics load failure for filter column: 
horizontal)how)r/   r&   r   UInt32to_framer   r   getrU   r   r   r   r   concat)
r   expected_heightidentity_transformed_valuesr   r   r   stat_builderpr?   column_stats_dfs
             r@   r   zIcebergStatisticsLoader.finish  s    
 	 BIIeT..bii@IIK#
 '+&A&A&G&G&I 	("Hl044X>>Ka%GsKC&s++*11/1EOJJ'	( ryy,//rI   N)r   r#   r   r   r   r   r   r"   r   r   )r  r)   r  r   r   pl.DataFrame)r   r   r   r   r   r   r   rI   r@   r   r   t  sK    << "9< 
	<|-00 &@0 
	0rI   r   c                  p    e Zd ZU ded<   ded<   ded<   ded<   d	ed
<   ded<   ded<   ddZ	 	 	 	 	 	 ddZy)r   r   r   pl.DataTyper   r)   r   LoadFromBytesImpl | Noner   zlist[int | None]r   list[bytes | None]r   r   c                   | j                   j                  |j                  j                  | j                               | j
                  }| j                  j                  |j                  j                  | j                               | j                  j                  |j                  j                  | j                               y y rN   )
r   r   null_value_countsr  r   r   r   lower_boundsr   upper_bounds)r   r   s     r@   r   z2IcebergColumnStatisticsLoader.push_file_statistics  s    t5599$--HI$$0OO""4#4#4#8#8#GHOO""4#4#4#8#8#GH 1rI   c                    dd l }| j                  }t        | j                        |k(  sJ  |j                  | d| j                  |j
                        j                         }| j                  Y||n |j                  d || j                        }|j                  |j                  | d      |j                  | d            S t        | j                        |k(  sJ t        | j                        |k(  sJ | j                  j                         rt        | j                  j!                  | j                        }| j                  j!                  | j                        }|`|j"                  | j                  k(  sJ |j%                  d ||j                         z
        }|j'                  |      }|j'                  |      }|j                  |j                  | d      |j                  | d            S )Nr   _ncr   _min_max)r/   r   r   r   r&   r   r   r   repeatr   r8   aliasr   r   r   NotImplementedErrorload_from_bytesr   extend_constant	fill_null)	r   r  r  r   cr   r   r   r   s	            r@   r   z$IcebergColumnStatisticsLoader.finish  s   
 	4??#666bii1#S	4??"))DMMO$$, /: ,RYYt_D<M<MN  ##AGGqcJ$7A3d9LMM4??#6664??#666&&(%%..>>tO
..>>tO
&2.448I8IIII*E*U*Uo(C(G(G(II+' 5>>zJJ4>>zJJs$Z(**:*:aS:*F
 	
rI   Nr  )r  r)   r  zpl.Series | Noner   r	  )r   r   r   __annotations__r   r   r   rI   r@   r   r     sR    M22  """"I*
*
 &6*
 
	*
rI   r   c                     ddl m} m}m}m}m}m}m}m}m	}m
}	m}
 |t        |f|t        |f|
t        |
f|t        |f|	t         |	f|t"        |f|t$        ||ff|t&        |f| t(        | f|t*        |f|t,        |fiS )Nr   
BinaryTypeBooleanTypeDateTypeDecimalType	FixedTyper   r   
StringTypeTimestampTypeTimestamptzTypeTimeType)r   r   r!  r"  r#  r$  r   r   r%  r&  r'  r(  LoadBooleanFromBytesLoadDateFromBytesLoadTimeFromBytesLoadTimestampFromBytesLoadTimestamptzFromBytesLoadInt32FromBytesLoadInt64FromBytesLoadStringFromBytesLoadBinaryFromBytesLoadDecimalFromBytesLoadFixedFromBytesr  s              r@   _bytes_loader_lookupr4    s    
     	*K8$h/$h/.>2OD(+6%+'>?(*5(*5*K8&	2 rI   c                  \    e Zd ZddZe	 	 	 	 	 	 	 	 dd       Zej                  dd       Zy)r   c                    || _         y rN   )polars_dtype)r   r7  s     r@   r   zLoadFromBytesImpl.__init__3  s
    (rI   c                    t               j                  t        |             x}y |\  }t        fd|D              r ||      S d S )Nc              3  6   K   | ]  }t        |        y wrN   )rU   )r   xallowed_field_typess     r@   r   z8LoadFromBytesImpl.init_for_field_type.<locals>.<genexpr>D  s     O!:a!45Os   )r4  r  r   all)current_field_typeall_field_typesr   r   loader_implr;  s        @r@   r   z%LoadFromBytesImpl.init_for_field_type6  s\     &'++D1C,DEEAN+,(( OOO *+	
 	
rI   c                     y)z(`bytes_values` should be of binary type.Nr   )r   byte_valuess     r@   r  z!LoadFromBytesImpl.load_from_bytesH  s    rI   N)r7  r  r   r   )r=  r$   r>  zset[IcebergType]r   r  r   r  rA  r  r   z	pl.Series)	r   r   r   r   staticmethodr   abcabstractmethodr  r   rI   r@   r   r   2  s[    ) 
'
 *
 (	

 
"
 
" 	7 7rI   r   c                      e Zd ZddZy)r1  c                F    dd l } |j                  ||j                        S Nr   r   )r/   r&   Binaryr   rA  r   s      r@   r  z#LoadBinaryFromBytes.load_from_bytesN  s    ryyBII66rI   NrB  r   r   r   r  r   rI   r@   r1  r1  M  s    7rI   r1  c                      e Zd ZddZy)r*  c                    dd l } |j                  ||j                        j                  j	                  |j
                  d      j                  |j                        S Nr   r   littler   
endianness)r/   r&   rI  binreinterpretr   r   r   rJ  s      r@   r  z!LoadDateFromBytes.load_from_bytesU  sC     BIIk3S288AT"'']	
rI   NrB  rK  r   rI   r@   r*  r*  T      
rI   r*  c                      e Zd ZddZy)r+  c                    dd l } |j                  ||j                        j                  j	                  |j
                  d      t        z  j                  |j                        S rN  )	r/   r&   rI  rR  rS  r   r*   r   r   rJ  s      r@   r  z!LoadTimeFromBytes.load_from_bytes`  sY     BIIk377CChh8 D  !! $rww-	rI   NrB  rK  r   rI   r@   r+  r+  _  s    rI   r+  c                      e Zd ZddZy)r,  c                    dd l } |j                  ||j                        j                  j	                  |j
                  d      j                   |j                  d            S )Nr   r   rO  rP  usr/   r&   rI  rR  rS  r   r   r   rJ  s      r@   r  z&LoadTimestampFromBytes.load_from_bytesl  sK     BIIk3S288AT+"++d#$	
rI   NrB  rK  r   rI   r@   r,  r,  k  rT  rI   r,  c                      e Zd ZddZy)r-  c                    dd l } |j                  ||j                        j                  j	                  |j
                  d      j                   |j                  dd            S )Nr   r   rO  rP  rY  UTC)	time_zonerZ  rJ  s      r@   r  z(LoadTimestamptzFromBytes.load_from_bytesw  sM     BIIk3S288AT+"++de45	
rI   NrB  rK  r   rI   r@   r-  r-  v  rT  rI   r-  c                      e Zd ZddZy)r)  c                    dd l } |j                  ||j                        j                  j	                  |j
                  d      j                  |j                        S rN  )r/   r&   rI  rR  rS  UInt8r   BooleanrJ  s      r@   r  z$LoadBooleanFromBytes.load_from_bytes  sD     BIIk3S288AT"**	
rI   NrB  rK  r   rI   r@   r)  r)    rT  rI   r)  c                      e Zd ZddZy)r2  c                    dd l }ddlm} | j                  }t	        ||j
                        sJ |j                  J t        |j                  ||j                  |j                              S )Nr   )PySeries)
bytes_list	precisionscale)
r/   polars._plrre  r7  rU   Decimalrg  r   (_import_decimal_from_iceberg_binary_reprrh  )r   rA  r   re  r   s        r@   r  z$LoadDecimalFromBytes.load_from_bytes  sh    (!!%,,,***==&//kk > 
 	
rI   NrB  rK  r   rI   r@   r2  r2    s    
rI   r2  c                      e Zd Zy)r3  N)r   r   r   r   rI   r@   r3  r3    s    rI   r3  c                      e Zd ZddZy)r.  c                    dd l } |j                  ||j                        j                  j	                  |j
                  d      S rN  )r/   r&   rI  rR  rS  r   rJ  s      r@   r  z"LoadInt32FromBytes.load_from_bytes  s>    ryyBII6::FF((x G 
 	
rI   NrB  rK  r   rI   r@   r.  r.    s    
rI   r.  c                      e Zd ZddZy)r/  c                .   dd l } |j                  ||j                        }|j                  j	                  |j
                  d      j                  |j                  j	                  |j                  d      j                  |j
                              S rN  )	r/   r&   rI  rR  rS  r   r  r   r   )r   rA  r   r   s       r@   r  z"LoadInt64FromBytes.load_from_bytes  sp    BIIk3uu  rxxH EOOEEBHHBGGQ
 	
rI   NrB  rK  r   rI   r@   r/  r/    rT  rI   r/  c                      e Zd ZddZy)r0  c                x    dd l } |j                  ||j                        j                  |j                        S rH  )r/   r&   rI  r   StringrJ  s      r@   r  z#LoadStringFromBytes.load_from_bytes  s+    ryyBII6;;BIIFFrI   NrB  rK  r   rI   r@   r0  r0    s    GrI   r0  )NNNN)r7   r#   r8   zlist[str] | Noner9   z
str | Noner:   
int | Noner.   rt  r;   r   r   zDataFrame | Series)rH   r   r   zast.expr)rL   r   r   r   )rL   r   r   r   )rL   r   r   r   )rL   r   r   r   )rL   r   r   r   )rL   r   r   r   )rL   r   r   r   )rL   r   r   r   )rL   r   r   r   )r   zhdict[type[IcebergType], tuple[type[LoadFromBytesImpl], type[IcebergType] | Sequence[type[IcebergType]]]])T
__future__r   rD  rE   r   _astr   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   dataclassesr   	functoolsr   r   typingr   r   r   polars._reexport	_reexportr   polars._utils.convertr   r   r   r   polars._utils.wrapr   polars.exceptionsr   collections.abcr   r!   r    r'   r   pyiceberg.manifestr"   pyiceberg.tabler#   r   r$   r/   r%   r&   polars._dependenciesr(   r  r*   rA   r2   r3   registerrQ   r   r   r   r4  ABCr   r1  r*  r+  r,  r-  r)  r2  r3  r.  r/  r0  r   rI   r@   <module>r     s   " 
 
       " + / /  < ( % *('+%+((. $D @ 
  C 
 &* "1'	1'"1' 1' 	1'
 1' 1' 1'h-0   X& ' T" # W% & T" #. Y' ( U# $ W% &( T"3 #3O OdY0 Y0x :
 :
 :
|  D7 767+ 7
) 
	) 	
. 

0 

, 

, 
$ 3, 2
* 

* 
G+ GrI   