
    n	g\              
          d Z ddlZddlZddlmZmZ ddlmZ ddl	Z
ddlmZmZ ddlZddlmZ ddlmZ ddlmZ ddlmZ d9d	Zd
ej$                  fdZdej$                  fdZdej$                  dej$                  dej$                  dej$                  fdZdej$                  dej$                  dej$                  fdZdej$                  dej$                  dej$                  fdZdej$                  dej$                  dej$                  fdZdej$                  dej$                  dej$                  fdZdej$                  dej$                  dej$                  dej$                  fdZdej$                  dej$                  dej$                  dej$                  fdZ	 d:dedefd Zdej$                  dej$                  dej$                  fd!Zd"ej$                  dej$                  fd#Z d$ej$                  dej$                  fd%Z!d&ej$                  dej$                  fd'Z"d( Z# G d) d*ejH                        Z%d;d+Z&d"ej$                  dej$                  fd,Z d$ej$                  dej$                  fd-Z!d.e'd/e'd0e(d1e(dej$                  f
d2Z)d<d$ej$                  dej$                  fd3Z*d.e'd4ej$                  dej$                  fd5Z+d6ej$                  dej$                  fd7Z,d=d8Z-y)>z'Multi-view geometry & proejction code..    N)	rearrangerepeat)
functional)ceillog2)einsum)Float)Tensorc                 P	   t        | j                        dk(  rht        | j                  dd      |j                  dd      ||j                  dd      nd       }|d   |d   j	                  d| j                  d d       fS t        | j                        dk(  rht        | j                  dd      |j                  dd      ||j                  dd      nd       }|d   |d   j	                  d| j                  d d       fS 	 t        j                  dt
        j                        5  | j                  ddd      } |j                  ddd      }||j                  ddd      }d}|t        j                  | d d d df         }d	}|j                  |
      }||j                  dd      |z   z  }| |z  j                  dd      }||z  j                  dd      }|j                  |
      }| |z
  }	||z
  }
t        j                  |j                  d            }|	|z  j                  |
j                  ddd            }t        j                  |      \  }}}t        j                   |j                  d   | j"                        j%                  d      }|j'                  |j                  d   dd      }|d d ddfxx   t        j(                  t        j*                  |j                  |j                  ddd                        z  cc<   |j                  |j                  |j                  ddd                  }||j                  |      z
  }|j                  |       |z   }t        j                   d      d    j-                  | j/                  d      dd      j1                  |       }||d d d dd df<   t        j                   d      d    j-                  | j/                  d      dd      j1                  |       }|j                  d      |d d d ddf<   t        j                   d      d    j-                  | j/                  d      dd      j1                  |       }||z  |z  }||z
  j3                         j5                         |fcd d d        S # 1 sw Y   y xY w)N   r            cuda)device_typedtypeTgư>)min)keepdimdevice   )lenshape
procrustesflatten	unflattentorchautocastfloat32permute	ones_likeclipsum
diag_embedsqueezebmmsvdeyer   	unsqueezer   signdetexpandsizetosquaremean)S1S2weightsout
transposedepsweights_normmu1mu2X1X2diagsKUsVZRtS1_hatR_T_S_transfs                           -/home/cameronsmith/repos/flowcams/geometry.pyr   r      s    288}aAaAaQXQd19Mjno1vc!f&&q"1666
288}aAaAaQXQd19Mjno1vc!f&&q"1666 
F%--	@ 42ZZ!AZZ!AOOAa*G
?eoob2A2h&?G% Bt <S @A,##Ad#3,##Ad#3!&&3&/#X#X  !34 XNN2::a!,- ))A,1a IIaggaj3==a@HHQWWQZ!$	!B(uzz%))AEE!))Aa2B,C"DEE EE!%%		!Aa()* AEE#J  rQ 99Q<$$RWWQZ2699"=1RaR799Q<$$RWWQZ2699"=IIbM1RaR799Q<$$RWWQZ2699"=Brr	!!#((*61i42 42 42s   'M+RR%pointsc                     t        j                  | dddf   | j                        }t        j                  | |fd      S )zAppends a "1" to the coordinates of a (batch of) points of dimension DIM.

    Args:
        points: points of shape (..., DIM)

    Returns:
        points_hom: points with appended "1" dimension.
    .Nr   r   r   dim)r   r"   r   cat)rK   oness     rJ   homogenize_pointsrQ   T   s9     ??6#rr'?6==AD99fd^,,    vectorsc                     t        j                  | dddf   | j                        }t        j                  | |fd      S )zAppends a "0" to the coordinates of a (batch of) vectors of dimension DIM.

    Args:
        vectors: vectors of shape (..., DIM)

    Returns:
        vectors_hom: points with appended "0" dimension.
    .Nr   r   r   rM   )r   
zeros_liker   rO   )rS   zeross     rJ   homogenize_vecsrW   a   s=     WS"1"W-gnnEE99gu%2..rR   xy_pixz
intrinsicsreturnc                 p    t        |       }t        j                  d|j                         |      }||z  }|S )aw  Unproject (lift) 2D pixel coordinates x_pix and per-pixel z coordinate
    to 3D points in camera coordinates.

    Args:
        xy_pix: 2D pixel coordinates of shape (..., 2)
        z: per-pixel depth, defined as z coordinate of shape (..., 1)
        intrinscis: camera intrinscics of shape (..., 3, 3)

    Returns:
        xyz_cam: points in 3D camera coordinates.
    ...ij,...kj->...ki)rQ   r   r   inverse)rX   rY   rZ   
xy_pix_homxyz_cams        rJ   	unprojectra   n   s8     #6*Jll/1C1C1EzRGqLGNrR   xyz_world_hom	cam2worldc                 D    t        j                  |      }t        | |      S )a  Transforms points from 3D world coordinates to 3D camera coordinates.

    Args:
        xyz_world_hom: homogenized 3D points of shape (..., 4)
        cam2world: camera pose of shape (..., 4, 4)

    Returns:
        xyz_cam: points in camera coordinates.
    )r   r^   transform_rigid)rb   rc   	world2cams      rJ   transform_world2camrg      s     i(I=)44rR   xyz_cam_homc                     t        | |      S )a  Transforms points from 3D world coordinates to 3D camera coordinates.

    Args:
        xyz_cam_hom: homogenized 3D points of shape (..., 4)
        cam2world: camera pose of shape (..., 4, 4)

    Returns:
        xyz_world: points in camera coordinates.
    )re   )rh   rc   s     rJ   transform_cam2worldrj      s     ;	22rR   xyz_homTc                 0    t        j                  d||       S )zApply a rigid-body transform to a (batch of) points / vectors.

    Args:
        xyz_hom: homogenized 3D points of shape (..., 4)
        T: rigid-body transform matrix of shape (..., 4, 4)

    Returns:
        xyz_trans: transformed points.
    r]   )r   r   )rk   rl   s     rJ   re   re      s     <<,a99rR   c           	      j    t        | t        j                  | dd df   | j                        |      S )N.r   r   )rZ   )ra   r   r"   r   )rX   rZ   s     rJ   #get_unnormalized_cam_ray_directionsro      s5     sBQBw> rR   c                 j   |Gt        j                  d      d    j                  | j                  d      dd      j	                  |       }|dd ddf   }t        | |      }||j                  dd      z  }t        |      }t        ||      }t        |d|j                  d	      
      }||dd df   fS )Nr   r   r   .r   TrN   r   z... ch -> ... num_rays ch)num_rays)
r   r)   r-   r.   r/   ro   normrW   rj   r   )rX   rZ   rc   cam_origin_worldray_dirs_cam
rd_cam_homrd_world_homs          rJ   get_world_rays_ry      s     IIaL&--fkk!nRCFFvN	 !bqb"- 7vzJL,"3"3D"3"IIL !.J 'z9=L/1LWcWhWhikWln \#rr'222rR   c           	      2   t        | j                        dk(  rnt        | j                  dd      |j                  dd      ||j                  dd      nd       }|D cg c]!  }|j	                  d| j                  d d       # c}S t        | ||      S c c}w )Nr   r   r   r   )r   r   ry   r   r   )rX   rZ   rc   r5   xs        rJ   get_world_raysr|      s    
 6<<!fnnQq1*2D2DQq2Idmdy)J[J[\]^_J`  @D  E9<=AAfll2A./==6*Y77 >s   &By_resolutionx_resolutionc           	          t        j                  t        j                  dd||      t        j                  dd| |            \  }}t        j                  |j	                         |j	                         gd      j                  ddd      }|S )a  For an image with y_resolution and x_resolution, return a tensor of pixel coordinates
    normalized to lie in [0, 1], with the origin (0, 0) in the top left corner,
    the x-axis pointing right, the y-axis pointing down, and the bottom right corner
    being at (1, 1).

    Returns:
        xy_pix: a meshgrid of values from [0, 1] of shape
                (y_resolution, x_resolution, 2)
    r   r   )stepsr   r   rM   r   )r   meshgridlinspacestackfloatr!   )r}   r~   r   ijrX   s         rJ   get_opencv_pixel_coordinatesr      sq     >>q!<?q!<?DAq
 [[!'')QWWY/R8@@AqIFMrR   c                     t        |j                        t        | j                        k(  r|j                  d      }t        j                  d|| dddf         }|dddf   }||dz   z  }|dddf   |fS )	a9  Projects homogenized 3D points xyz_cam_hom in camera coordinates
    to pixel coordinates.

    Args:
        xyz_cam_hom: 3D points of shape (..., 4)
        intrinsics: camera intrinscics of shape (..., 3, 3)

    Returns:
        xy: homogeneous pixel coordinates of shape (..., 3) (final coordinate is 1)
    r   z...ij,...j->...i.Nr   r   gh㈵>r   )r   r   r*   r   r   )rh   rZ   xywrY   s       rJ   projectr      s     :c+"3"344AUAUVWAXj
,,):{377K
LCCHA
T
CsBQBw<?rR   r{   c                 p    t        j                  |       }| dkD  }t        j                  | |         ||<   |S z[
    Returns torch.sqrt(torch.max(0, x))
    but with a zero subgradient where x is 0.
    r   r   rU   sqrtr{   retpositive_masks      rJ   _sqrt_positive_partr     s:     

1
CEMAm$45CJrR   matrixc                 <   | j                  d      dk7  s| j                  d      dk7  rt        d| j                   d      | j                  dd }t        j                  | j                  |dz         d      \	  }}}}}}}}	}
t        t        j                  d	|z   |z   |
z   d	|z   |z
  |
z
  d	|z
  |z   |
z
  d	|z
  |z
  |
z   gd            }t        j                  t        j                  |d
   dz  |	|z
  ||z
  ||z
  gd      t        j                  |	|z
  |d   dz  ||z   ||z   gd      t        j                  ||z
  ||z   |d   dz  ||	z   gd      t        j                  ||z
  ||z   |	|z   |d   dz  gd      gd      }t        j                  d      j                  |j                  |j                        }|d|d   j                  |      z  z  }|t        j                  |j                  d      d      dkD  ddf   j                  |dz         S )z
    Convert rotations given as rotation matrices to quaternions.
    Args:
        matrix: Rotation matrices as tensor of shape (..., 3, 3).
    Returns:
        quaternions with real part first, as tensor of shape (..., 4).
    r   r   rr   Invalid rotation matrix shape .N	   rM         ?.r   r   .r   .r   .r   皙?r   r          @.Nr   num_classes      ?r   r.   
ValueErrorr   r   unbindreshaper   r   tensorr/   r   r   maxFone_hotargmaxr   	batch_dimm00m01m02m10m11m12m20m21m22q_absquat_by_rijkflrquat_candidatess                  rJ   matrix_to_quaternionr     s8    {{2!v{{2!39&,,qIJJSb!I27,,y4'(b3/Cc3S#sC  c	C#%c	C#%c	C#%c	C#%	 	

E ;;KKv!+S3Yc	39MSUVKKsE&MQ$6c	39MSUVKKsC#IuV}/A39MSUVKKsC#IsSy%-1:LMSUV		
 L ,,s


U[[

FC"cE),<,@,@,E&EFO
 			%,,2,&A6<a?gi$ rR   quaternionsc                    t        j                  | d      \  }}}}d| | z  j                  d      z  }t        j                  d|||z  ||z  z   z  z
  |||z  ||z  z
  z  |||z  ||z  z   z  |||z  ||z  z   z  d|||z  ||z  z   z  z
  |||z  ||z  z
  z  |||z  ||z  z
  z  |||z  ||z  z   z  d|||z  ||z  z   z  z
  f	d      }|j	                  | j
                  dd dz         S )z
    Convert rotations given as quaternions to rotation matrices.
    Args:
        quaternions: quaternions with real part first,
            as tensor of shape (..., 4).
    Returns:
        Rotation matrices as tensor of shape (..., 3, 3).
    r   r   r   Nr   r   )r   r   r$   r   r   r   )r   rr   r   ktwo_sos          rJ   quaternion_to_matrixr   E  s4    k2.JAq!Q;,11"55EQQ''QUQU]#QUQU]#QUQU]#QQ''QUQU]#QUQU]#QUQU]#QQ''
	
 		A 99[&&s+f455rR   c                    t        | j                        dk(  r=t        j                  t	        | |      D cg c]  \  }}t        |||       c}}      S t        | d dd df         }t        |d dd df         }||z  j                  d      }t        j                  |j                  dd            }|t        j                  d|z
  |z        z  |t        j                  ||z        z  z   t        j                  |      z  }	t        |	      }
t        j                  | d ddf   |d ddf   |      }t        j                  d      }|
|d dd df<   ||d ddf<   |j                         S c c}}w )Nr   r   rM   r   r   r   )r   r   r   r   zipcamera_interpr   r$   acosclampsinr   lerpr)   r   )camera1camera2rD   cam1cam2q1q2	cos_angleangleq_interpolatedrotation_interpolatedtranslation_interpolatedcam_interpolateds                rJ   r   r   a  sn   
7==1{{GT[H\]94M$tA6]^^	gbqb"1"fo	.B	gbqb"1"fo	.B
 b!$IJJyr1-.E599a!eu_55UYYq5y=Q8QQUZU^U^_dUeeN0@  %zz'"1"R%.'"1"R%.!Lyy|1RaRU4RaRU  "") ^s   E1
c                        e Zd ZU eed<   dededef fdZdeedf   deedf   fd	Z	e
d
        Ze
deedf   fd       Z xZS )NearFarPlanePosEncd_neard_farnum_samplesc                 B   t         |           ||k  sJ || _        ||z
  }||z  }dt        j                  z  |z  }d|z  }t        t        t        |                  }t        j                  |      j                          }	d|	z  |z  }
| j                  d|
d       y )Nr   r   frequenciesF)
persistent)super__init__r   r   piintr   r   aranger   register_buffer)selfr   r   r   total_rangesampling_periodsampling_frequencyhighest_frequencynum_frequenciesoctavesr   	__class__s              rJ   r   zNearFarPlanePosEnc.__init__}  s     	~fn &3\O; 11 d4#456 <<06688j#44]KEJrR   rK   zbatch pointr[   zbatch point embedded_dimc                 4   || j                   z
  }t        || j                  d      }t        j                  t        j
                  t        j                  |      t        j                  |      fd      j                  dd      |j                  d      fd      S )Nz... p, m -> ... p mr   rr   )
r   r   r   r   rO   r   r   cosr   r*   )r   rK   offset_pointsscaled_pointss       rJ   forwardzNearFarPlanePosEnc.forward  s     ,}d.>.>@UVyy%++uyy'?=AY&Z\^_gghjkmnouoo  AC  pD  E  FH  I  	IrR   c                 8    t        | j                        dz  dz   S )Nr   r   )r   r   r   s    rJ   d_outzNearFarPlanePosEnc.d_out  s    4##$q(1,,rR   z
 frequencyc                 B    dt         j                  z  | j                  z  S )Nr   )r   r   r   r   s    rJ   periodszNearFarPlanePosEnc.periods  s    588|d....rR   )__name__
__module____qualname__r   __annotations__r   r   r	   r
   r   propertyr   r   __classcell__)r   s   @rJ   r   r   z  s    M!K!K !K 	!KFIfm+,I 
v11	2I - - /v|34 / /rR   r   c                    | j                   \  }}|j                   \  }}| j                  d      }|j                  d      }	| |z
  }
||	z
  }|
dz  j                         }|dz  j                         }t        j                  |      }t        j                  |      }|
|z  }
||z  }||k  r/t        j
                  |t        j                  |||z
        fd      }t        j                  |
j                  |      }t        j                  j                  |d      \  }}}|j                  }t        j                  ||j                        }|dk7  ret        j                  j                  |      dk  }||k7  r>|d d dfxx   dz  cc<   |dxx   dz  cc<   t        j                  ||j                        }|j                         }|r0||z  |z  }d|dz  z
  }||z  t        j                  ||      z  |z   }n2d}d||z  z   d|z  |z  |z  z
  }|t        j                  ||      z  |z   }||k  r|d |d d f   }||t        j                  |	|      z  z
  }|||d	}|||fS )
Nr   r   F)full_matricesbestr   r   r   )rotationscaletranslation)r   r1   r$   npr   concatenaterV   dotrl   linalgr(   r,   )XYscaling
reflectionnmnymymuXmuYX0Y0ssXssYnormXnormYAr?   r@   VtrA   rl   have_reflectiontraceTAbdrB   ctforms                                rJ   numpy_procrustesr"    sF   
''CAaGGEBr
&&)C
&&)C	
SB	
SBr6,,.Cr6,,.C GGCLEGGCLE %KB%KB	Av^^R!QrT!23A6 	rttRAYY]]15]1FAa
A
q!##AV ))--*Q. (adGrMGbERKEq!##AeegG eOe# 
N 'M"&&Q-'#- CK!g+-55"&&Q-#% 
Avcrc!eHasAA 1A6E a;rR   c                 p    t        j                  |       }| dkD  }t        j                  | |         ||<   |S r   r   r   s      rJ   r   r     s:    
 

1
CEMAm$45CJrR   c                 <   | j                  d      dk7  s| j                  d      dk7  rt        d| j                   d      | j                  dd }t        j                  | j                  |dz         d      \	  }}}}}}}}	}
t        t        j                  d	|z   |z   |
z   d	|z   |z
  |
z
  d	|z
  |z   |
z
  d	|z
  |z
  |
z   gd            }t        j                  t        j                  |d
   dz  |	|z
  ||z
  ||z
  gd      t        j                  |	|z
  |d   dz  ||z   ||z   gd      t        j                  ||z
  ||z   |d   dz  ||	z   gd      t        j                  ||z
  ||z   |	|z   |d   dz  gd      gd      }t        j                  d      j                  |j                  |j                        }|d|d   j                  |      z  z  }|t        j                  |j                  d      d      dkD  ddf   j                  |dz         S )z
    Convert rotations given as rotation matrices to quaternions.

    Args:
        matrix: Rotation matrices as tensor of shape (..., 3, 3).

    Returns:
        quaternions with real part first, as tensor of shape (..., 4).
    r   r   rr   r   r   Nr   rM   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   s                  rJ   r   r   	  s@    {{2!v{{2!39&,,qIJJSb!I27,,y4'(b3/Cc3S#sC  c	C#%c	C#%c	C#%c	C#%	 	

E ;; KKv!+S3Yc	39MSUV KKsE&MQ$6c	39MSUV KKsC#IuV}/A39MSUV KKsC#IsSy%-1:LMSUV	
 L( ,,s


U[[

FC"cE),<,@,@,E&EFO
 			%,,2,&A6<a?gi$ rR   axis
other_axis
horizontal
tait_bryanc                    dddd|    \  }}|r||}}| |z   dv }||k(  r t        j                  |d|f   |d|f         S |r!t        j                  |d|f    |d|f         S t        j                  |d|f   |d|f          S )a  
    Extract the first or third Euler angle from the two members of
    the matrix which are positive constant times its sine and cosine.

    Args:
        axis: Axis label "X" or "Y or "Z" for the angle we are finding.
        other_axis: Axis label "X" or "Y or "Z" for the middle axis in the
            convention.
        data: Rotation matrices as tensor of shape (..., 3, 3).
        horizontal: Whether we are looking for the angle for the third axis,
            which means the relevant entries are in the same row of the
            rotation matrix. If not, they are in the same column.
        tait_bryan: Whether the first and third axes in the convention differ.

    Returns:
        Euler Angles in radians for each matrix in data as a tensor
        of shape (...).
    )r   r   )r   r   )r   r   )r
  r  rB   )XYYZZX.)r   atan2)r%  r&  datar'  r(  i1i2evens           rJ   _angle_from_tanr2  F  s    , V4T:FBRB:"44DT{{4R=$sBw-88{{DbM>4R=99;;tCG}tCG}n55rR   c                 ~   dt         dt        fd} ||d         } ||d         }||k7  }|r(t        j                  | d||f   ||z
  dv rdnd	z        }nt        j                  | d||f         }t        |d   |d
   | d|f   d|      |t        |d   |d
   | d|ddf   d|      f}t        j                  |d      S )a,  
    Convert rotations given as rotation matrices to Euler angles in radians.

    Args:
        matrix: Rotation matrices as tensor of shape (..., 3, 3).
        convention: Convention string of three uppercase letters.

    Returns:
        Euler angles in radians as tensor of shape (..., 3).
    letterr[   c                 <    | dk(  ry| dk(  ry| dk(  ryt        d      )Nr
  r   r  r   rB   r    letter must be either X, Y or Z.)r   )r4  s    rJ   _index_from_letterz2matrix_to_euler_angles.<locals>._index_from_letterq  s,    S=S=S=;<<rR   r   r   .)r   r   g      r   r   FNTr   )strr   r   asinr   r2  r   )r   
conventionr7  i0r0  r(  central_angler   s           rJ   matrix_to_euler_anglesr=  e  s    =3 =3 = 
JqM	*B	JqM	*BrJ

3B;27g+=43G
 

6#r2+#67 	qM:a=&b/5*	
 	qM:a=&b!*<dJ	
	A ;;q"rR   r   c           	         t        j                  |      }t        j                  |      }t        j                  |      }t        j                  |      }| dk(  r|||||| |||f	}n/| dk(  r||||||| ||f	}n| dk(  r|| |||||||f	}nt        d      t        j                  |d      j                  |j                  dz         S )aM  
    Return the rotation matrices for one of the rotations about an axis
    of which Euler angles describe, for each value of the angle given.

    Args:
        axis: Axis label "X" or "Y or "Z".
        angle: any shape tensor of Euler angles in radians

    Returns:
        Rotation matrices as tensor of shape (..., 3, 3).
    r
  r  rB   r6  r   r   )	r   r   r   r"   rU   r   r   r   r   )r%  r   r   r   onezeroR_flats          rJ   _axis_angle_rotationrB    s     ))E
C
))E
C
//%
 CE"Ds{tT4sdD#sC	tS$TC4sC	tT3T4sC;<<;;vr"**5;;+?@@rR   euler_anglesc                     d}t        |t        j                  | d            D cg c]  \  }}t        ||       }}}t        j                  t        j                  |d   |d         |d         S c c}}w )aW  
    Convert rotations given as Euler angles in radians to rotation matrices.

    Args:
        euler_angles: Euler angles in radians as tensor of shape (..., 3).
        convention: Convention string of three uppercase letters from
            {"X", "Y", and "Z"}.

    Returns:
        Rotation matrices as tensor of shape (..., 3, 3).
    XYZr   r   r   r   )r   r   r   rB  matmul)rC  r:  r   ematricess        rJ   euler_angles_to_matrixrI    st     J 
ELLr$BCAq 	Q"H 
 <<Xa[(1+>LLs   A2c                    t        j                  g | j                  d d | j                  d      dd j	                         }d|d<   | j                  d      dk(  rAt        j
                  | dd df   | dd df   j                  dd	
      z  | ddd f   fd      }  | j                  d      dk(  rt        nt        | dd df         |dd dd df<   | ddd f   |z  |dd ddf<   |S )Nrr   r   r   ).r   r   r      .Trq      r   )	r   rV   r   r.   r   rO   rt   rI  r   )poses_r  posess      rJ   lift_to_posesrP    s   KK?cr*?6;;r??1?Q?DDFEE){{2%))VCG_VCG_=Q=QVXae=Q=f-fgmnqrtrunugv,wxz"{6^&++b/12D.J^`fgjknlnkngn`opE#bqb!)c"#gu,E#bqb)LrR   )N)cpu)Tr  )rE  )r   ).__doc__r   torchvisioneinopsr   r   torch.nnr   r   numpyr  mathr   r   nnr   	jaxtypingr	   r
   r   rQ   rW   ra   rg   rj   re   ro   ry   r|   r   r   r   r   r   r   r   Moduler   r"  r8  boolr2  r=  rB  rI  rP   rR   rJ   <module>r]     s   -  $ $       C2L
-ell 
-
/U\\ 
/LL"\\7<||
\\(5<<5,1LL5
\\5 33*/,,3
\\3
:U\\ 
:ell 
:u|| 
:LL&+ll
\\3LL33 ||3 \\	368LL88 ||8 \\	8  . 5<< ELL "	5<< 	ELL 	2  2 %,, 2 f6ell 6u|| 68#24/ 4/nKZ5<< ELL ;  ; %,, ; z6
66266DH6
\\6>'5<< 'ell 'TAs A5<< AELL A8M M%,, M&rR   