
    j>[                       U d dl mZ d dlZd dl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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% erPd dl&Z&d dlm'Z'm(Z( d dl)m*Z* d dl+Z,d dlm-Z- e&j.        dk    rd dlm/Z/ nd dl0m/Z/ d dl1m2Z2 d dl3m4Z4 d dlm5Z5 d dl6m7Z7m8Z8m9Z9 h dZ:de;d<    G d d          Z< G d d          Z=dS )     )annotationsN)	CoroutineSequence)suppress)	Parameter	signature)TYPE_CHECKINGAnyFinal)	functions)parse_versionqualified_type_name)
from_arrow)N_INFER_DEFAULT)DuplicateErrorModuleUpgradeRequiredErrorUnsuitableSQLError)ARROW_DRIVER_REGISTRY)ODBCCursorProxySurrealDBCursorProxy)dtype_from_cursor_description)
_run_async)IterableIterator)TracebackType)ArrowDriverProperties)      )Self
TextClause)
Selectable	DataFrame)ConnectionOrCursorCursor
SchemaDict>   USEDROPALTERGRANTCREATEDELETEINSERTREVOKEUPDATEUPSERTVACUUMANALYZEREPLACEzFinal[set[str]]_INVALID_QUERY_TYPESc                  "    e Zd ZdZddZdd
ZdS )CloseAfterFrameIterzDAllows cursor close to be deferred until the last batch is returned.framesr
   cursorr&   returnNonec               "    || _         || _        d S N)_iter_frames_cursor)selfr8   r9   s      a/home/longshao/multi-rider-rag/.venv/lib/python3.11/site-packages/polars/io/database/_executor.py__init__zCloseAfterFrameIter.__init__?   s    "    Iterator[DataFrame]c              #     K   | j         E d {V  t          | j        d          r| j                                         d S d S )Nclose)r>   hasattrr?   rF   r@   s    rA   __iter__zCloseAfterFrameIter.__iter__C   sY      $$$$$$$$4<)) 	!L     	! 	!rC   N)r8   r
   r9   r&   r:   r;   )r:   rD   )__name__
__module____qualname____doc__rB   rI    rC   rA   r7   r7   <   sB        NN   ! ! ! ! ! !rC   r7   c                  n   e Zd ZU dZdZded<   dLd	ZdMdZdNdZdOdZ	e
dPd            ZdQdZe
dRd            ZdSd$Ze
dTd)            ZdUd*ZdVd.ZdVd/ZdWd2Ze
dXd5            Ze
dXd6            Ze
dXd7            Ze
dXd8            Ze
dYd9            ZdZd:Zd[d>Zd\dBZdCdDdEd]dHZddCdCedId^dKZdCS )_ConnectionExecutorzIAbstraction for querying databases with user-supplied connection objects.Fboolcan_close_cursor
connectionr%   r:   r;   c                6   t          |t                    rdn?t          |          j                            dd          d                                         | _        | j        dk    rt          |          }|                     |          | _	        d | _
        d S )Narrow_odbc_proxy.   r   	surrealdb)client)
isinstancer   typerK   splitlowerdriver_namer   _normalise_cursorr9   result)r@   rS   s     rA   rB   zConnectionExecutor.__init__Q   s     *o66Fj!!,223::1=CCEE 	
 {**-Z@@@J,,Z88rC   r   c                    | S r=   rN   rH   s    rA   	__enter__zConnectionExecutor.__enter__]   s    rC   exc_typetype[BaseException] | Noneexc_valBaseException | Noneexc_tbTracebackType | Nonec                ,   |                      | j                  r@ddlm} t	          | j        |          r#t          |                                            d S d S | j        r0t          | j        d          r| j        	                                 d S d S d S )Nr   )AsyncConnectionrF   )
_is_alchemy_asyncr9   sqlalchemy.ext.asynciorj   rZ   r   _close_async_cursorrR   rG   rF   )r@   rc   re   rg   rj   s        rA   __exit__zConnectionExecutor.__exit__`   s     !!$+.. 	 >>>>>>$+77 743355666667 7" 	 wt{G'D'D 	 K	  	  	  	 rC   strc                B    dt          |           j         d| j        dS )N<z module=>)r[   rJ   r^   rH   s    rA   __repr__zConnectionExecutor.__repr__p   s'    E4::&EE0@EEEErC   dfr$   schema_overridesr'   c                    | j         fd|                                D             x}r|                     |          } | S )z&Apply schema overrides to a DataFrame.c                    g | ]<\  }}|v 	||         k    t          j        |                              |          =S rN   )Fcolcast).0ry   dtypeexisting_schemas      rA   
<listcomp>z7ConnectionExecutor._apply_overrides.<locals>.<listcomp>w   sU     
 
 
Uo%%%?33G*G*G E#JJOOE""*G*G*GrC   )schemaitemswith_columns)rt   ru   	cast_colsr}   s      @rA   _apply_overridesz#ConnectionExecutor._apply_overridess   sb     )
 
 
 
.4466
 
 
 
9 	,
 ++B	rC   c                   K   | j         rdt          | j        d          rQddlm} t          |          5  | j                                         d {V  d d d            d S # 1 swxY w Y   d S d S d S )NrF   r   )AsyncContextNotStarted)rR   rG   r9   sqlalchemy.ext.asyncio.excr   r   rF   )r@   r   s     rA   rm   z&ConnectionExecutor._close_async_cursor   s        	*WT['%B%B 	*IIIIII011 * *k'')))))))))* * * * * * * * * * * * * * * * * *	* 	* 	* 	*s    A!!A%(A%module_nameminimum_versionc           	     R   t          |           }t          t                    5  d}dD ]9}t          t	          ||d          x}t
                    rt          |          } n:|r*|t          |          k     rd|  d| }t          |          ddd           dS # 1 swxY w Y   dS )z<Check the module version against a minimum required version.N)__version__versionz)`read_database` queries require at least z	 version )
__import__r   AttributeErrorrZ   getattrro   r   r   )r   r   modmodule_versionversion_attrvermsgs          rA   _check_module_versionz(ConnectionExecutor._check_module_version   s    %%n%% 	6 	659N :  WS,%E%EEcsKK %23%7%7NE  6.=3Q3Q"Q"Qi+iiXgii0555	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6 	6s   A+BB #B driver_propertiesr   
batch_size
int | Noneiter_batchesIterable[pa.RecordBatch]c             #     K   |d         }|r|)|d         } t          | j        |                      V  dS |d         r|gng }|d         }t          | j        |          }|s || E d{V  dS 	  || }	|	sdS |	V  )zGYield Arrow data as a generator of one or more RecordBatches or Tables.fetch_batchesN	fetch_allexact_batch_sizerepeat_batch_calls)r   r`   )
r@   r   r   r   r   fetch_methodsizer   fetchmany_arrowarrows
             rA   _fetch_arrowzConnectionExecutor._fetch_arrow   s       */: 	 }4,[9L4'$+|446666666#45G#HPJ<<bD!23G!H%dk=AAO%  *?D1111111111 +OT2E  KKK	 rC   r`   r&   
is_alchemyIterable[Sequence[Any]]c                   |                                  }|r,|s(t          |d         t          t          t          f          r|nd |D             S )zCFetch row data in a single call, returning the complete result set.r   c                ,    g | ]}t          |          S rN   tupler{   rows     rA   r~   z5ConnectionExecutor._fetchall_rows.<locals>.<listcomp>   s    ---%**---rC   )fetchallrZ   listr   dict)r`   r   rowss      rA   _fetchall_rowsz!ConnectionExecutor._fetchall_rows   s\        .#.'1$q'D%;N'O'O.DD-----	
rC   c             #     K   	 |                     |          }|sdS |s(t          |d         t          t          t          f          r|V  nd |D             V  W)zDFetch row data incrementally, yielding over the complete result set.Tr   c                ,    g | ]}t          |          S rN   r   r   s     rA   r~   z6ConnectionExecutor._fetchmany_rows.<locals>.<listcomp>   s    222cuSzz222rC   N)	fetchmanyrZ   r   r   r   )r@   r`   r   r   r   s        rA   _fetchmany_rowsz"ConnectionExecutor._fetchmany_rows   sy      	3##J//D 3 3z$q'D%3FGG 3



22T222222	3rC   SchemaDict | Noneinfer_schema_length&DataFrame | Iterator[DataFrame] | Nonec                   ddl m 	  j                            d          rdn j        }t	          j        |g           }t          |d          D ]\  }}|d         x}	rK|dk    rdn j        }
	                      |
|	           n$# t          $ r |t          |          k     rY U w xY w|r$|d	         r|sd
 j         d}t          |           fd                     |||          D             }|r|nt          |          c S n5# t          $ r(d}t          fd|D                       s Y dndww xY wdS )z5Return resultset data in Arrow format for frame init.r   r#   adbc_adbcrW   )startr   adbc_driver_managerr   zCannot set `iter_batches` for z- without also setting a non-zero `batch_size`c              3     K   | ]=}t          |          r                    |pi           nt          |           V  >dS ))ru   N)rZ   r   r   )r{   batchr$   ru   r@   s     rA   	<genexpr>z1ConnectionExecutor._from_arrow.<locals>.<genexpr>   su       	 	  "%33ND))%2B2HbJJJ#E<LMMM	 	 	 	 	 	rC   )r   r   )zdoes not support Apache Arrowz$Apache Arrow format is not supportedc              3  :   K   | ]}|t                    v V  d S r=   )ro   )r{   eerrs     rA   r   z1ConnectionExecutor._from_arrow.<locals>.<genexpr>   s-      BBqCHH}BBBBBBrC   N)polarsr$   r^   
startswithr   get	enumerater   r   len
ValueErrorr   next	Exceptionany)r@   r   r   ru   r   driverdriver_properties_listir   r   driver_to_checkr   r8   arrow_not_supportedr$   r   s   `  `          @@rA   _from_arrowzConnectionExecutor._from_arrow   sA    	%$$$$$2	 *55g>>TDDT  &;%>vr%J%J"(12HPQ(R(R(R #@ #@$$+,=>>3  2861A1A--tGW $
22?CHHHH5   s#9::::$H
   *%&89*BL*G9I G G G  %S//)	 	 	 	 	 	 "&!2!2)%1#- "3 " "		 	 	 ".?vv4<<???G#@H  	 	 	# BBBB.ABBBBB     	 ts=   A'D 4B
D B,(D *B,,A#D 
ED>>Ec                  ddl m |r|sd}t          |          t          | j        x}t
                    x}rt          | j                  | _        	 t          | j        d          rQ| j        dk    x}r{t          | j        d          rd | j        j	        j
        D             }	nxt          | j        d          rd	 | j        j        j        D             }	nGd
| j        }t          |          t          | j        d          rd | j        j
        D             }	ng }	|                     |	pi           d |	D             fd|r|                     | j        ||          n|                     | j        |          gD             }
|r|
nt!          |
          	 |r|                                 S S 	 |r|                                 dS dS # |r|                                 w w xY w)z.Return resultset data row-wise for frame init.r   r#   zFCannot set `iter_batches` without also setting a non-zero `batch_size`r   
sqlalchemyr9   c                2    g | ]}|d          |dd         fS r   rW   NrN   r{   ds     rA   r~   z1ConnectionExecutor._from_rows.<locals>.<listcomp>  s5     ' ' './QqT1QRR5M' ' 'rC   	_metadatac                    g | ]}|d fS r=   rN   )r{   ks     rA   r~   z1ConnectionExecutor._from_rows.<locals>.<listcomp>   s    &U&U&UQ4y&U&U&UrC   z0Unable to determine metadata from query result; descriptionc                2    g | ]}|d          |dd         fS r   rN   r   s     rA   r~   z1ConnectionExecutor._from_rows.<locals>.<listcomp>&  s(    "R"R"RQAaD!ABB%="R"R"RrC   )r   ru   c                    g | ]\  }}|S rN   rN   )r{   nm_s      rA   r~   z1ConnectionExecutor._from_rows.<locals>.<listcomp>.  s    !>!>!>Q"!>!>!>rC   c              3  <   K   | ]} |pd d          V  d S )Nr   )datar   ru   r   orientrN   )r{   r   r$   r   result_columnsru   s     rA   r   z0ConnectionExecutor._from_rows.<locals>.<genexpr>/  s^          I!-5)9,?$       rC   )r   r   )r   N)r   r$   r   rZ   r`   r   r   rG   r^   r9   r   r   keys_inject_type_overridesr   r   r   rF   )r@   r   r   ru   r   r   original_resultis_asyncr   cursor_descr8   r$   r   s      ``      @@rA   
_from_rowszConnectionExecutor._from_rows  s    	%$$$$$ 	"
 	"X  S//!!T["@/)LLL8 	2$T[11DK-	(t{J// (@"&"2l"BC: %t{H55 .' '37;3E3Q' ' ' !k:: .&U&U$+:O:T&U&U&U`QUQ\``(oo-T[-88 %"R"R$+:Q"R"R"RKK"$K#'#>#> +&6&<" $? $ $  "?!>+!>!>!>       (W,, K'1'1 -    #11$+*1UUV  $ ".?vv4<<?  (%%''''(  (%%'''''( (x (%%''''(s   EG G3r   list[tuple[str, Any]]c                    t                      }|D ]O\  }}||v rd|d}t          |          |||vrt          |          }||||<   |                    |           P|S )a  
        Attempt basic dtype inference from a cursor description.

        Notes
        -----
        This is limited; the `type_code` description attr may contain almost anything,
        from strings or python types to driver-specific codes, classes, enums, etc.
        We currently only do the additional inference from string/python type values.
        (Further refinement will require per-driver module knowledge and lookups).
        zcolumn z2 appears more than once in the query/result cursor)setr   r   add)r@   r   ru   
dupe_checkr   descr   r|   s           rA   r   z)ConnectionExecutor._inject_type_overridesG  s     UU
# 	 	HBZXXXX$S)))!b0@&@&@5d;;$+0$R(NN2rC   connr
   c                `    	 ddl m}m}m} t	          | |||f          S # t
          $ r Y dS w xY w)z2Check if the given connection is SQLALchemy async.r   )rj   AsyncSessionasync_sessionmakerF)rl   rj   r   r   rZ   ImportError)r   rj   r   r   s       rA   rk   z$ConnectionExecutor._is_alchemy_asyncc  su    		          d_lDV$WXXX 	 	 	55	s    
--c                    ddl m} t          | |          rdS 	 ddlm} t          | |          S # t
          $ r Y dS w xY w)z5Check if the given connection is a SQLAlchemy Engine.r   )EngineT)AsyncEngineF)sqlalchemy.enginer   rZ   rl   r   r   )r   r   r   s      rA   _is_alchemy_enginez%ConnectionExecutor._is_alchemy_engineq  sv     	-,,,,,dF## 	4	::::::dK000 	 	 	55	s   0 
>>c                f    t          |           j                            dd          d         dk    S )zCCheck if the given connection is a SQLAlchemy object (of any kind).rV   rW   r   r   )r[   rK   r\   )r   s    rA   _is_alchemy_objectz%ConnectionExecutor._is_alchemy_object  s-     Dzz$**32215EErC   c                    ddl m} ddlm}m} t          | |||f          rdS 	 ddl m} t          | |          S # t          $ r Y dS w xY w)z=Check if the given connection is a SQLAlchemy Session object.r   )r   )SessionsessionmakerT)r   F)rl   r   sqlalchemy.ormr   r   rZ   r   r   )r   r   r   r   r   s        rA   _is_alchemy_sessionz&ConnectionExecutor._is_alchemy_session  s     	87777788888888d\7LABB 	4	AAAAAAd$6777 	 	 	55	s   ; 
A	A	c                    	 ddl m} t          | |          rdS ddlm} t          | |          S # t
          $ r Y dS w xY w)z8Check if the given result is a SQLAlchemy Result object.r   )CursorResultT)AsyncResultF)r   r  rZ   rl   r  r   )r`   r  r  s      rA   _is_alchemy_resultz%ConnectionExecutor._is_alchemy_result  st    
	666666&,// t::::::fk222 	 	 	55	s   0 0 
>>c                >   | j         dk    r|                     |          r|S |j        j        dk    r2d| _         |j                                                                        S |j        j        dk    r	d| _         |S |                     |          rd| _        |                                S |S t          |d          r+t          |j        x}          r
 |            n|}d| _        |S t          |d          r|S d	t          |          d
}t          |          )zCNormalise a connection object such that we have the query executor.r   zdatabricks-sql-python
databricksduckdb_engineduckdbTr9   executezUnrecognised connection type z!; no 'execute' or 'cursor' method)r^   r   enginer   raw_connectionr9   r   rR   connectrG   callabler   	TypeError)r@   r   r9   r   s       rA   r_   z$ConnectionExecutor._normalise_cursor  s?   |++''--   ;%)@@@'3D$;5577>>@@@['?::'/D$K,,T22  ,0D)<<>>)KT8$$ 	!)DK*?&!@!@LVVXXXfF$(D!MT9%% 	K+,?,E,E + + + 	 nnrC   queryr!   optionsc                  K   |                      | j                  }|r| j                                        n| j        }t          |dd           |j        |fi | d{V S |4 d{V }|rt          |d          s|j        } |j        |fi | d{V }|cddd          d{V  S # 1 d{V swxY w Y   dS )z5Execute a query using an async SQLAlchemy connection.sync_connectionNr	  )r   r9   beginr   r	  rG   session)r@   r  r  
is_sessionr9   r   r`   s          rA   _sqlalchemy_async_executez,ConnectionExecutor._sqlalchemy_async_execute  s     --dk::
(2C""$$$ 6,d33?'99999999999 	 	 	 	 	 	 	T $'$	":": $|'4<9999999999F		 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   ,/B..
B8;B8str | TextClause | Selectabledict[str, Any]9tuple[Any, dict[str, Any], str | TextClause | Selectable]c                   ddl m} ddlm} ddlm} d}d}t          | j        |          r6d|v r2d|vr.|                                }|	                    d          |d<   d}|
                    |          }|                     | j                  }	|	st          |t                    rt          | j        d          rl| j        j        }t          ||          rt          |          }t          |t                     r+t#          d	 |D                       st%          |          ||<   n t          |t                    r ||          }||	r| j        n| j        j        }|||fS )
z<Prepare a query for execution using a SQLAlchemy connection.r   )r   )textr    
parametersNparamsexec_driver_sqlc              3  N   K   | ] }t          |t          t          f          V  !d S r=   )rZ   r   r   r{   ps     rA   r   z7ConnectionExecutor._sqlalchemy_setup.<locals>.<genexpr>  sA       4 412
1tUm,,4 4 4 4 4 4rC   )r   r   sqlalchemy.sqlr  sqlalchemy.sql.elementsr!   rZ   r9   copypopr   rk   r   rG   r  ro   r   allr   r  r	  )
r@   r  r  r   r  r!   	param_keycursor_executer  r   s
             rA   _sqlalchemy_setupz$ConnectionExecutor._sqlalchemy_setup  s    	+*****''''''666666 	t{G,,	!''''llnnG 'L 9 9GH IY''))$+66	 68,,	  %677	 
 "[8N%,, #E

&$'' 3 4 46<4 4 4 1 1 3 &+6]]	"s## 	 DKKE!2:S..@S  w--rC   NT)r  select_queries_onlydict[str, Any] | Noner*  c                  |rtt          |t                    r_t          j        dt          j        dd|                    }|sdn|                    d          x}t          v r| d}t          |          pi |                     | j	                  r| 
                    |          \  }}n| j	        j        }	 t          |          j        }n# t          $ r i }Y nw xY wr+t          d |                                D                       r
 ||fi }	nfd|pD             }
 ||g|
R  }	|	|	d	u r| j	        n|	}	| j        d
k    r|                     |	          r|	j	        }	|	| _        | S )z-Execute a query and reference the result set.z\w{3,}z/\*(.|[\r\n])*?\*/ r   z( statements are not valid 'read' queriesc              3  T   K   | ]#}|j         t          j        t          j        fv V  $d S r=   )kindr   KEYWORD_ONLYPOSITIONAL_OR_KEYWORDr   s     rA   r   z-ConnectionExecutor.execute.<locals>.<genexpr>  sH       
 
 Fy-y/NOO
 
 
 
 
 
rC   c              3  4   K   | ]}r|v |         V  d S r=   rN   )r{   or  s     rA   r   z-ConnectionExecutor.execute.<locals>.<genexpr>$  s=       " " "KLPW<<
<<<<" "rC   NTr  )rZ   ro   researchsubgroupr5   r   r   r9   r)  r	  r   r  r   r   valuesr^   r  r`   )r@   r  r  r*  q
query_typer   r(  r  r`   positional_optionss     `        rA   r	  zConnectionExecutor.execute  s     	.:eS#9#9 	.	)RV,A2u%M%MNNA()9bbqwwqzz9
>RRR#MMM(----R""4;// 	1-1-C-CE7-S-S*NGUU![0N	~..9FF 	 	 	FFF	  		@# 
 
]]__
 
 
 
 
 		@ $^E55W55FF" " " "%+%6w" " " $^E?,>???F "(6T>>x''D,C,CF,K,K']Fs   >C C"!C")r   r   ru   r   DataFrame | Iterator[DataFrame]c               ,   | j         d}t          |          | j        }|o|x}rd| _        | j        | j        fD ]9} |||||          }	|	&|r d t          |	| j                   D             }	|	c S :d| j        d| j        }t          |          )	z
        Convert the result set to a DataFrame.

        Wherever possible we try to return arrow-native data directly; only
        fall back to initialising with row-level data if no other option.
        Nz.cannot return a frame before executing a queryF)r   r   ru   r   c              3     K   | ]}|V  d S r=   rN   )r{   rt   s     rA   r   z/ConnectionExecutor.to_polars.<locals>.<genexpr>T  s6              rC   )r9   zCurrently no support for z connection )	r`   RuntimeErrorrR   r   r   r7   r^   r9   NotImplementedError)
r@   r   r   ru   r   r   	can_closedefer_cursor_close
frame_initframes
             rA   	to_polarszConnectionExecutor.to_polars1  s	    ;BCs###)	"."<9= 	*$)D! O
 	 	J J%)!1$7	  E  %  "5!#';# # #  E  ! X(8WWWW 	 "#&&&rC   )rS   r%   r:   r;   )r:   r   )rc   rd   re   rf   rg   rh   r:   r;   )r:   ro   )rt   r$   ru   r'   r:   r$   )r:   r;   )r   ro   r   ro   r:   r;   )r   r   r   r   r   rQ   r:   r   )r`   r&   r   rQ   r:   r   )r`   r&   r   r   r   rQ   r:   r   )
r   r   r   rQ   ru   r   r   r   r:   r   )r   r   ru   r'   r:   r'   )r   r
   r:   rQ   )r`   r
   r:   rQ   )r   r
   r:   r&   )r  r!   r  r
   r:   r
   )r  r  r  r  r:   r  )r  r  r  r+  r*  rQ   r:   r   )
r   rQ   r   r   ru   r   r   r   r:   r<  )rJ   rK   rL   rM   rR   __annotations__rB   rb   rn   rs   staticmethodr   rm   r   r   r   r   r   r   r   rk   r   r   r   r  r_   r  r)  r	  r   rE  rN   rC   rA   rP   rP   J   s        SS #""""
  
  
  
            F F F F 	 	 	 \	* * * * 6 6 6 \6       2 
 
 
 \
3 3 3 3? ? ? ?B@( @( @( @(D       8    \    \ F F F \F    \    \" " " "H    ). ). ). ).^ *.$(- - - - - -d #!%.2*9/' /' /' /' /' /' /' /'rC   rP   )>
__future__r   r4  collections.abcr   r   
contextlibr   inspectr   r   typingr	   r
   r   r   r   rx   polars._utils.variousr   r   polars.convertr   polars.datatypesr   polars.exceptionsr   r   r   "polars.io.database._arrow_registryr   "polars.io.database._cursor_proxiesr   r   polars.io.database._inferencer   polars.io.database._utilsr   sysr   r   typesr   pyarrowpar   version_infor   typing_extensionsr#  r!   sqlalchemy.sql.expressionr"   r$   polars._typingr%   r&   r'   r5   rF  r7   rP   rN   rC   rA   <module>r]     s   " " " " " " " 				 / / / / / / / /       ( ( ( ( ( ( ( ( , , , , , , , , , , ! ! ! ! ! ! D D D D D D D D % % % % % % , , , , , ,         
 E D D D D D T T T T T T T T G G G G G G 0 0 0 0 0 0 FJJJ22222222######HHHHHH
7""******222222444444      EEEEEEEEEE) ) )     "! ! ! ! ! ! ! !V' V' V' V' V' V' V' V' V' V'rC   