#!/opt/thinlinc/libexec/python3
# -*-mode: python; coding: utf-8 -*-
#
# Copyright 2002-2014 Cendio AB.
# For more information, see http://www.cendio.com
#
# action: Mounting local drives
#
if 82 - 82: Iii1i
import sys
import threading
import os
import getopt
import stat
import base64
import hashlib
import subprocess
import time
import locale
if 87 - 87: Ii % i1i1i1111I . Oo / OooOoo * I1Ii1I1 - I1I
from thinlinc import hiveconf
import warnings
if 81 - 81: i1 + ooOOO / oOo0O00 * i1iiIII111 * IiIIii11Ii
if 84 - 84: ooo000 - Ooo0Ooo + iI1iII1I1I1i . IIiIIiIi11I1
warnings . filterwarnings ( "ignore" , ".*gssapi.*" , ImportWarning )
from thinlinc import rpc
from thinlinc . rpc import security
from thinlinc . mountclient import mount_const , mount_pack
if 98 - 98: I11iiIi11i1I % oOO
from thinlinc import sessioninfo
from thinlinc import prefix
if 31 - 31: i1I
i1I1 = 10
if 22 - 22: o00o0OO00O % I11iiIi11i1I - iI1iII1I1I1i
iiIi1 = "tl-mount-localdrives"
if 71 - 71: i1 % Iii1i
iiiIi = False
if 66 - 66: IIiIIiIi11I1 + I1I
class IIIii ( rpc . ConnectionHandler ) :
 if 13 - 13: IiIIii11Ii - Ooo0Ooo - Ii - Oo * ooo000 . i1iiIII111
 def __init__ ( self ) :
  super ( ) . __init__ ( )
  if 14 - 14: I1I / oOO
  ooOOooO0 = threading . Thread ( target = self . start , name = 'PollingThread' )
  ooOOooO0 . daemon = True
  ooOOooO0 . start ( )
  if 13 - 13: oOO
  self . default_cred = security . CredInfo ( )
  if 2 - 2: i1
 def connect ( self , host , port ) :
  self . pipe = super ( ) . connect ( ( host , port ) )
  if 22 - 22: IIiIIiIi11I1 - ooo000 / I1Ii1I1 . ooo000
 def make_call ( self , proc , arg = b'' , arg_type = '' , result_type = '' , * ,
 timeout = None ) :
  if arg and arg_type :
   IIII11 = mount_pack . MOUNTPacker ( )
   oOoo0 = getattr ( IIII11 , 'pack_%s' % arg_type )
   oOoo0 ( arg )
   arg = IIII11 . get_buffer ( )
   if 95 - 95: i1iiIII111 . Ii . IIiIIiIi11I1 % I11iiIi11i1I % I1Ii1I1
  ii1i = self . pipe . send_call ( mount_const . MOUNT_PROGRAM ,
 mount_const . MOUNT_V3 ,
 proc , arg , self . default_cred )
  I1i , i1111IIi = self . pipe . listen ( ii1i , timeout = timeout )
  if 86 - 86: i1 + ooo000 + oOo0O00 / i1iiIII111 - Iii1i . iI1iII1I1I1i
  if i1111IIi and result_type :
   ii1IiIiiII = mount_pack . MOUNTUnpacker ( i1111IIi )
   I1I111i11I = getattr ( ii1IiIiiII , 'unpack_%s' % result_type )
   return I1I111i11I ( )
  else :
   return i1111IIi
   if 85 - 85: OooOoo
 def null ( self , * , timeout = None ) :
  self . make_call ( mount_const . MOUNTPROC3_NULL , timeout = timeout )
  if 34 - 34: Oo
 def mnt ( self , dirpath , * , timeout = None ) :
  return self . make_call ( mount_const . MOUNTPROC3_MNT ,
 arg = dirpath , arg_type = 'dirpath' ,
 result_type = 'mountres3' , timeout = timeout )
  if 96 - 96: ooOOO / o00o0OO00O + i1iiIII111 / ooOOO / I11iiIi11i1I
 def export ( self , * , timeout = None ) :
  return self . make_call ( mount_const . MOUNTPROC3_EXPORT ,
 result_type = 'exports' , timeout = timeout )
  if 63 - 63: i1i1i1111I . Ooo0Ooo * ooOOO
  if 6 - 6: i1iiIII111
class I1I1 :
 def __init__ ( self , host , port ) :
  if 91 - 91: Iii1i % i1i1i1111I . OooOoo * oOO
  if 5 - 5: oOO % Ooo0Ooo / OooOoo
  if 6 - 6: Ii + I1I + i1
  if 86 - 86: IiIIii11Ii
  if 100 - 100: o00o0OO00O - OooOoo * I1Ii1I1 / Ooo0Ooo / Iii1i
  I11iIi1i = None
  for oooOOOooo in range ( i1I1 ) :
   if iiiIi :
    print ( "%s: Connecting to %s:%d..." %
 ( iiIi1 , host , port ) , file = sys . stderr )
   try :
    self . mountcl = IIIii ( )
    self . mountcl . connect ( host , port )
    self . mountcl . null ( timeout = 2 )
    if 85 - 85: i1iiIII111 - ooOOO
    return
   except rpc . RPCTimeout as I11I11I :
    I11iIi1i = rpc . RPCTimeout ( "Operation timed out" )
   except ( EOFError , OSError ) as I11I11I :
    I11iIi1i = I11I11I
    if 4 - 4: ooOOO
   time . sleep ( 1 )
   if 23 - 23: Ii + o00o0OO00O . IiIIii11Ii - i1iiIII111 * Ooo0Ooo
   if 78 - 78: ooo000 . I1I % Ii + Ooo0Ooo * Iii1i
  Ii1I1I1i = "%s: Cannot connect to client: %s" % ( iiIi1 , str ( I11iIi1i ) )
  sys . exit ( Ii1I1I1i )
  if 93 - 93: oOo0O00 % Ooo0Ooo * i1iiIII111
 def get_otp ( self , password ) :
  OooO0O00o0 = self . mountcl . mnt ( b"@getnonce" , timeout = 10 )
  if 73 - 73: oOO - oOo0O00 . oOo0O00
  if OooO0O00o0 . fhs_status != mount_const . MNT3_OK :
   print ( "%s: Failed to get nonce:" % iiIi1 ,
 mount_const . mountstat3_id [ OooO0O00o0 . fhs_status ] ,
 file = sys . stderr )
   sys . exit ( 1 )
   if 27 - 27: o00o0OO00O % i1iiIII111 * iI1iII1I1I1i - iI1iII1I1I1i
  Ii1iI1111Iii1 = OooO0O00o0 . mountinfo . fhandle
  ooooo = hashlib . md5 ( Ii1iI1111Iii1 + password ) . hexdigest ( )
  return ooooo
  if 61 - 61: iI1iII1I1I1i . i1I - ooo000 / ooo000 - i1
 def get_exports ( self ) :
  OooO0O00o0 = [ ]
  if 19 - 19: Iii1i * Ooo0Ooo . I1Ii1I1 / I11iiIi11i1I * Ii - oOO
  if 32 - 32: iI1iII1I1I1i
  if 18 - 18: I11iiIi11i1I * o00o0OO00O % iI1iII1I1I1i + o00o0OO00O
  O0OO = self . mountcl . export ( timeout = 10 )
  if 34 - 34: ooOOO * I11iiIi11i1I
  while O0OO :
   oOo0Oo = O0OO [ 0 ]
   O0ooooO = oOo0Oo . ex_dir
   OooO0O00o0 . append ( O0ooooO )
   O0OO = oOo0Oo . ex_next
   if 89 - 89: I1I * i1i1i1111I
  return OooO0O00o0
  if 54 - 54: oOO + Ooo0Ooo - I1I . Ooo0Ooo
  if 50 - 50: Iii1i * ooo000 % Iii1i - oOo0O00 + ooo000
 def gen_drive_names ( self , exports ) :
  OooO0O00o0 = { }
  if 54 - 54: oOO * i1 % i1 - Ooo0Ooo + IIiIIiIi11I1
  if 4 - 4: ooo000 + I1Ii1I1 * OooOoo - o00o0OO00O
  if 69 - 69: ooo000
  if 76 - 76: Iii1i * Ooo0Ooo . iI1iII1I1I1i / Ii / ooOOO
  if 49 - 49: iI1iII1I1I1i / i1iiIII111 + ooo000
  OoOo00 = 0
  for O0ooooO in exports :
   if 7 - 7: i1i1i1111I / Ii * Iii1i
   if O0ooooO . endswith ( b"/" ) :
    O0ooooO = O0ooooO [ : - 1 ]
    if 32 - 32: o00o0OO00O . OooOoo
    if 31 - 31: Oo - i1I
    if 28 - 28: ooOOO * I1Ii1I1 + o00o0OO00O % Oo
    if 100 - 100: Oo + i1I
    if 4 - 4: ooo000 % I1I - i1i1i1111I
   iI11i1iI1I1Ii = O0ooooO . decode ( 'utf-8' , errors = 'replace' ) . encode ( sys . getfilesystemencoding ( ) ,
   # i1iiIII111 * Ooo0Ooo . Oo - IiIIii11Ii - iI1iII1I1I1i
 errors = 'replace' ) . decode ( sys . getfilesystemencoding ( ) )
   if 91 - 91: I1Ii1I1 - I11iiIi11i1I
   if 84 - 84: oOO % iI1iII1I1I1i - Ooo0Ooo
   if 94 - 94: i1iiIII111 + i1i1i1111I / iI1iII1I1I1i + iI1iII1I1I1i / i1I
   OO , ooOOOO00O = os . path . split ( iI11i1iI1I1Ii )
   ii1 = ooOOOO00O
   if ii1 not in OooO0O00o0 :
    if 53 - 53: i1 % IIiIIiIi11I1 * IIiIIiIi11I1 * iI1iII1I1I1i
    OooO0O00o0 [ ii1 ] = O0ooooO
    continue
    if 3 - 3: oOo0O00
    if 29 - 29: i1 * i1I + IIiIIiIi11I1 + oOO
   OO , ooOOOO00O = os . path . split ( OO )
   ii1 = ooOOOO00O + "_" + ii1
   if ii1 not in OooO0O00o0 :
    OooO0O00o0 [ ii1 ] = O0ooooO
    continue
    if 68 - 68: oOO - IiIIii11Ii + iI1iII1I1I1i
    if 35 - 35: i1 + I1I . i1iiIII111
   ii1 += str ( OoOo00 )
   OoOo00 += 1
   assert ( ii1 not in OooO0O00o0 )
   OooO0O00o0 [ ii1 ] = O0ooooO
   if 16 - 16: I1Ii1I1 % I1I / IIiIIiIi11I1 * i1I + o00o0OO00O % oOo0O00
  return OooO0O00o0
  if 13 - 13: i1 + IiIIii11Ii
  if 23 - 23: oOO . ooOOO / Ii
def Ii1Iii1IIIIIi ( hive ) :
 try :
  if 7 - 7: Oo - ooo000 . IIiIIiIi11I1
  if 10 - 10: Ii * OooOoo / oOo0O00 % i1 . Oo
  if 72 - 72: o00o0OO00O % i1 % ooo000 % iI1iII1I1I1i
  OOO00o00oo0 = sessioninfo . get_public_sessioninfo ( hive )
 except sessioninfo . GPSConnectionError as I11I11I :
  print ( "%s: %s" % ( iiIi1 , I11I11I ) , file = sys . stderr )
  print ( "%s: Trying to mount anyway" % iiIi1 , file = sys . stderr )
  return { }
  if 28 - 28: i1i1i1111I * i1 / I1Ii1I1
  if 71 - 71: I1Ii1I1
  if 1 - 1: o00o0OO00O - oOo0O00 - i1 . oOo0O00
 if 0 == len ( OOO00o00oo0 ) :
  print ( "%s: No session information matching current environment."
 % iiIi1 , file = sys . stderr )
  print ( "%s: Trying to mount anyway" % iiIi1 , file = sys . stderr )
  return { }
 elif 1 < len ( OOO00o00oo0 ) :
  print ( "%s: Multiple sessions matching current information. " "Should not happen!" % iiIi1 , file = sys . stderr )
  if 91 - 91: iI1iII1I1I1i * i1 . ooOOO
  print ( "%s: Trying to mount anyway" % iiIi1 , file = sys . stderr )
  return { }
  if 81 - 81: I1I * Oo - i1 % OooOoo * ooOOO
 OOO00o00oo0 = OOO00o00oo0 [ 0 ]
 if 19 - 19: Ii
 if "client_params" not in OOO00o00oo0 :
  print ( "%s: No client_params found" % iiIi1 , file = sys . stderr )
  return { }
  if 22 - 22: i1I % iI1iII1I1I1i + Oo
 OOO00OOo0oO0O = OOO00o00oo0 [ "client_params" ]
 if "capabilities" not in OOO00OOo0oO0O :
  if iiiIi :
   print ( "%s: Client doesn't support capabilities" % iiIi1 ,
 file = sys . stderr )
  return { }
  if 78 - 78: i1i1i1111I . i1I / i1I
 IiiI11IIi1I = OOO00OOo0oO0O [ "capabilities" ]
 if "localdrives" not in IiiI11IIi1I :
  if iiiIi :
   print ( "%s: Client has no localdrives capability, exiting."
 % iiIi1 , file = sys . stderr )
  sys . exit ( 1 )
  if 82 - 82: IIiIIiIi11I1 . Ooo0Ooo + i1iiIII111 + Oo
 I1II1I1i = IiiI11IIi1I [ "localdrives" ]
 if not isinstance ( I1II1I1i , dict ) :
  return { }
  if 59 - 59: i1iiIII111
 return I1II1I1i . get ( "aliases" , { } )
 if 33 - 33: ooo000 . Iii1i % oOO
 if 60 - 60: I1I . IiIIii11Ii % IIiIIiIi11I1 % iI1iII1I1I1i
def i1iII1 ( ) :
 print ( "Usage:" , sys . argv [ 0 ] , "[-h] [-v]" , file = sys . stderr )
 print ( """
    -h    Display this help
    -v    Verbose mode
""" , file = sys . stderr )
 sys . exit ( 1 )
 if 63 - 63: Iii1i
 if 81 - 81: I1Ii1I1 / oOO + oOO . i1i1i1111I - i1
def I1iO0OOOOoO0o ( ) :
 locale . setlocale ( locale . LC_ALL , "" )
 if 50 - 50: I11iiIi11i1I % OooOoo
 global TLPREFIX
 TLPREFIX = prefix . get_tl_prefix ( )
 if 9 - 9: i1iiIII111 - ooOOO % Iii1i
 if 37 - 37: i1I + IIiIIiIi11I1 % iI1iII1I1I1i / IIiIIiIi11I1 % i1iiIII111 + oOO
 try :
  Oo0o0Oo , o0O0OO0 = getopt . getopt ( sys . argv [ 1 : ] , "hv" )
 except getopt . GetoptError :
  if 84 - 84: Ii - OooOoo
  i1iII1 ( )
 for oo0Oo0oO0 , iII11I1iI in Oo0o0Oo :
  if oo0Oo0oO0 == "-h" :
   i1iII1 ( )
  if oo0Oo0oO0 == "-v" :
   global iiiIi
   iiiIi = True
 if o0O0OO0 :
  i1iII1 ( )
  if 87 - 87: i1iiIII111 - IIiIIiIi11I1 * Ii % i1i1i1111I % i1
  if 81 - 81: i1 + i1i1i1111I * Oo - Oo * I1Ii1I1 - oOo0O00
 prefix . assert_in_session ( )
 iiIIIIi = prefix . get_tl_session_dir ( )
 if 32 - 32: i1I - I1Ii1I1 * I1Ii1I1 / o00o0OO00O . ooo000
 IiiI1III1iI = [ os . path . join ( TLPREFIX , "bin" , "tl-umount-localdrives" ) ]
 IiiI1III1iI . append ( "-l" )
 if iiiIi :
  IiiI1III1iI . append ( "-v" )
  if 37 - 37: I1Ii1I1 % iI1iII1I1I1i . i1I + Ooo0Ooo + ooOOO * iI1iII1I1I1i
 if iiiIi :
  print ( "%s: Calling tl-umount-localdrives to remove any stale " "mounts" % iiIi1 , file = sys . stderr )
  if 39 - 39: IIiIIiIi11I1 - Oo
 subprocess . call ( IiiI1III1iI )
 if 31 - 31: IiIIii11Ii % oOo0O00 % oOo0O00 * Iii1i
 if 85 - 85: Iii1i + Ii % IIiIIiIi11I1 % oOo0O00
 I1i1I = hiveconf . open_hive ( os . path . join ( TLPREFIX , "etc" , "thinlinc.hconf" ) )
 if 87 - 87: OooOoo * Oo * Ii * iI1iII1I1I1i + i1I . IiIIii11Ii
 iI1Iii = prefix . get_tl_sessnum ( iiIIIIi )
 I1IiIII1Ii = sessioninfo . get_tunnel_port ( I1i1I , iI1Iii , "nfs" )
 if 60 - 60: OooOoo
 if 97 - 97: ooo000 * oOO
 if not os . path . exists ( iiIIIIi ) :
  sys . exit ( "%s: %s does not exist. Quitting." %
 ( iiIi1 , iiIIIIi ) )
  if 47 - 47: ooo000
 if os . stat ( iiIIIIi ) [ stat . ST_UID ] != os . getuid ( ) :
  sys . exit ( "%s: %s is not owned by you. Quitting." %
 ( iiIi1 , iiIIIIi ) )
  if 2 - 2: Oo % IiIIii11Ii - ooOOO
  if 75 - 75: IiIIii11Ii * i1 . Iii1i - o00o0OO00O
 oo0O0O0Ooooo = Ii1Iii1IIIIIi ( I1i1I )
 if 39 - 39: Oo . oOO / ooo000 / iI1iII1I1I1i
 if 48 - 48: oOO * i1I - OooOoo * Oo - o00o0OO00O - Ooo0Ooo
 if 36 - 36: IiIIii11Ii
 if 28 - 28: i1 - Oo + IiIIii11Ii * oOO
 if 83 - 83: ooo000 . I1I + Oo
 oo000ooOoo0o = os . path . join ( iiIIIIi , "vncpasswd" )
 with open ( oo000ooOoo0o , 'rb' ) as iiiIi1iIii1 :
  o0o = base64 . encodebytes ( iiiIi1iIii1 . read ( ) [ : 8 ] )
  if 17 - 17: IiIIii11Ii
 o0o = o0o [ : - 1 ]
 del oo000ooOoo0o
 if 31 - 31: Iii1i + ooOOO / OooOoo . Ooo0Ooo * I11iiIi11i1I
 if 15 - 15: IIiIIiIi11I1 . IiIIii11Ii - i1I % iI1iII1I1I1i . i1 % o00o0OO00O
 if 6 - 6: I11iiIi11i1I * iI1iII1I1I1i + Iii1i * IIiIIiIi11I1 . Ooo0Ooo - Oo
 if 63 - 63: i1i1i1111I - i1iiIII111 . OooOoo % OooOoo . o00o0OO00O + i1I
 O0OO00Oo0o0 = os . path . join ( iiIIIIi , "drives" )
 if not os . path . exists ( O0OO00Oo0o0 ) :
  if iiiIi :
   print ( "%s: Creating %s" % ( iiIi1 , O0OO00Oo0o0 ) ,
 file = sys . stderr )
  os . mkdir ( O0OO00Oo0o0 , 0o755 )
  if 84 - 84: I1I * iI1iII1I1I1i - Ooo0Ooo / iI1iII1I1I1i + ooo000
  if 54 - 54: i1iiIII111 . i1iiIII111 - ooOOO * OooOoo + IIiIIiIi11I1 * i1i1i1111I
 iIi = os . path . join ( os . path . expanduser ( "~" ) , "thindrives" )
 if os . path . islink ( iIi ) :
  os . unlink ( iIi )
  os . symlink ( O0OO00Oo0o0 , iIi )
 elif os . path . exists ( iIi ) :
  print ( "%s: Cannot create link %s" % ( iiIi1 , iIi ) ,
 file = sys . stderr )
 else :
  if 96 - 96: OooOoo + Ii % oOO % i1iiIII111 % Oo * Ooo0Ooo
  os . symlink ( O0OO00Oo0o0 , iIi )
  if 46 - 46: Ii - o00o0OO00O + IiIIii11Ii + i1I . I1I % OooOoo
  if 85 - 85: Oo / oOO + Oo + ooOOO
 I11111i111 = I1i1I . get_string_list ( "/utils/tl-mount-localdrives/mount_args" ,
 [ "-o" , "soft,intr,actimeo=2,rsize=524288,wsize=524288,timeo=50,retrans=1" ] )
 if 35 - 35: I1Ii1I1
 if 35 - 35: i1iiIII111 + Iii1i + OooOoo / ooo000 % OooOoo . Iii1i
 if 12 - 12: I1I % Ooo0Ooo - i1iiIII111 - IiIIii11Ii / i1iiIII111 + i1I
 if 77 - 77: Ii
 try :
  ii1iII1II1I = I1I1 ( "127.0.0.1" , I1IiIII1Ii )
  if 54 - 54: I11iiIi11i1I / IiIIii11Ii . Ooo0Ooo
  I11I11IiiI1i = ii1iII1II1I . gen_drive_names ( ii1iII1II1I . get_exports ( ) )
 except rpc . RPCTimeout :
  sys . exit ( "%s: Timeout when mounting local drives." % iiIi1 )
  if 1 - 1: I1I + OooOoo
 for ( ii1 , O0ooooO ) in I11I11IiiI1i . items ( ) :
  ii1 = oo0O0O0Ooooo . get ( ii1 , ii1 )
  OooO0Oo = os . path . join ( O0OO00Oo0o0 , ii1 )
  if not os . path . exists ( OooO0Oo ) :
   if iiiIi :
    print ( "%s: Creating %s" % ( iiIi1 , OooO0Oo ) ,
 file = sys . stderr )
   try :
    os . mkdir ( OooO0Oo , 0o755 )
   except FileExistsError :
    pass
   except OSError as I11I11I :
    sys . exit ( "%s: Unable to create %s: %s, exiting" %
 ( iiIi1 , OooO0Oo , str ( I11I11I ) ) )
    if 17 - 17: i1 % oOO % IiIIii11Ii * i1i1i1111I
    if 51 - 51: Ooo0Ooo . iI1iII1I1I1i . i1iiIII111 . Ooo0Ooo % ooo000 % Ooo0Ooo
  ooOo0O0O = [ ]
  ooOo0O0O . append ( os . path . join ( TLPREFIX , "libexec" , "tl-mount-personal" ) )
  if 12 - 12: i1 . i1I - I11iiIi11i1I - i1i1i1111I
  if 51 - 51: i1iiIII111 * i1iiIII111 / I1Ii1I1
  i1iII11iii = "mountport=%d,port=%d" % ( I1IiIII1Ii , I1IiIII1Ii )
  ooOo0O0O . append ( "-o" )
  ooOo0O0O . append ( i1iII11iii )
  if 19 - 19: I1Ii1I1 / OooOoo % i1i1i1111I
  if 23 - 23: iI1iII1I1I1i - i1I % i1I - o00o0OO00O * i1iiIII111 + OooOoo
  ooOo0O0O . extend ( I11111i111 )
  if 57 - 57: IIiIIiIi11I1
  if 57 - 57: ooOOO + Ii % I11iiIi11i1I + oOo0O00 . iI1iII1I1I1i - Ii
  try :
   Ii1i11 = ii1iII1II1I . get_otp ( o0o ) . encode ( 'utf-8' )
  except rpc . RPCTimeout :
   sys . exit ( "%s: Timeout when mounting local drives." % iiIi1 )
  ooOo0O0O . append ( b"localhost:@otp:" + Ii1i11 + O0ooooO )
  if 65 - 65: i1I - Ii % i1I - I1I
  if 42 - 42: I11iiIi11i1I - Ii / Oo - i1i1i1111I + I11iiIi11i1I
  ooOo0O0O . append ( OooO0Oo )
  if 83 - 83: i1 . iI1iII1I1I1i
  if iiiIi :
   print ( "%s: Running %s" % ( iiIi1 , ooOo0O0O ) , file = sys . stderr )
   if 57 - 57: o00o0OO00O % IiIIii11Ii / oOo0O00 + Ooo0Ooo - i1iiIII111
  with subprocess . Popen ( ooOo0O0O , universal_newlines = True ,
 stdin = subprocess . PIPE ,
 stdout = subprocess . PIPE ,
 stderr = subprocess . STDOUT ) as IIi :
   IIi . wait ( )
   O000oO = IIi . stdout . read ( )
   if 11 - 11: OooOoo * oOo0O00 + ooo000 * o00o0OO00O / i1i1i1111I
  if O000oO :
   print ( "%s: %s" % ( iiIi1 , O000oO ) , file = sys . stderr )
   if 40 - 40: i1iiIII111 - I11iiIi11i1I / Ooo0Ooo . IiIIii11Ii % Iii1i
   if 47 - 47: I1I / IIiIIiIi11I1 + I1I
if __name__ == "__main__" :
 I1iO0OOOOoO0o ( )
# dd678faae9ac167bc83abf78e5cb2f3f0688d3a3
