#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
'''wmgmail

WindowMaker dockapp to display gmail information.

Copyright (C) 2004 Pasi Savolainen

Licensed under the GNU General Public License.


'''

usage = '''wmgmail [options]
Available options are:
    -h, --help                  print this help
'''

import gc
import sys
import os
import signal
import time
import string
import ConfigParser
import getopt
import popen2
import threading

import pywmhelpers

import wmgsettings
import libgmail

width = 64
height = 64

xOffset = 4
yOffset = 4

lettersStartX = 0
lettersStartY = 74
letterWidth = 6
letterHeight = 8

digitsStartX = 0
digitsStartY = 64
digitWidth = 6
digitHeight = 8

letters = 'abcdefghijklmnopqrstuvwxyz'
digits = '0123456789:/-%. '

maxChars = 9

chPid = -1
chPidRecent = -1
reConfig = 1 # start with updating settings :)
Config = {}
gAccount = None
updateAt = 0
unreadMailCnt = 0
unreadMails = []
seenMails = []
reallyNewMailCount = 0
gStatusPicSize = [46-15,26-3] # size of status picture
gStatusHave = [71, 17]          # where's 'have mail' pic
gStatusNo = [103, 17]           # where's 'no mail' pic.
gStatusAt = [15, 3]             # where status pic is.


defaultConfigFile = '~/.wmgmailrc'

defaultRGBFiles = ('/usr/lib/X11/rgb.txt', '/usr/X11R6/lib/X11/rgb.txt')

# moo
err = sys.stderr.write;

# moo.

def handlerChild(signum, frame):
    global chPid, chPidRecent
    #print "got signal %s %s" % (signum, frame)
    # cleanup child
    try:
        if (signum == signal.SIGCHLD):
            #print "getting waitpid"
            if (chPid != -1):
                status = os.waitpid(chPid, os.WNOHANG)
                if status[0]: # if it was this child that was killed.
                    chPid = -1
            if (chPidRecent != -1):
                status = os.waitpid(chPidRecent, os.WNOHANG)
                if status[0]:
                    chPidRecent = -1
    except OSError:
        # no children? so get rid of them.
        chPidRecent = -1;
        chPid = -1


def handlerHUP(signum, frame):
    global reConfig
    #print "got signal %s %s" % (signum, frame)    
    reConfig = 1
    

def readConfig():
    global Config, gAccount
    lconfig = wmgsettings.getwmgmailsettings(wmgsettings.get_settingsfname())
    if Config == lconfig or lconfig['username'] == 'nobody':
        # identical settings or settings sucked. go away.
        return
    Config = lconfig
    ga = libgmail.GmailAccount(Config['username'], Config['password'])
    try:
        ga.login()
    except libgmail.GmailLoginFailure:
        print "Login Error"
    else:
        gAccount = ga;
        global updateAt
        updateAt = 0;

def forceRefresh():
    global updateAt
    # print "forced Refresh"
    updateAt = time.time() - 1;
    
def getUnread():
    """ Try initiating mail update if it's right time
    return True if did check for mail (regardless result)    
    """
    global updateAt, unreadMails, unreadMailCnt, Config, gAccount, reallyNewMailCount, seenMail
    tm = time.time()
    if gAccount is None or ( updateAt and updateAt > tm):
        # not time to update yet.
        return False
    #print "Updating message counts.."
    # TODO:set image to 'checking mail'
    try:
        unreadMails = gAccount.getMessagesByQuery('is:unread')
        #if len( newunreadMails ):
        #    for mail in unreadMails:
        #        mail.unread = 0
        #    unreadMails = newunreadMails;
        for mail in unreadMails:
            if not mail.matching_msgid in seenMails:
                seenMails.append(mail.matching_msgid)
                reallyNewMailCount += 1
        unreadMailCnt = len(unreadMails)
    except:
        print "Connection troubles: ", sys.exc_info()[0]
        
    # TODO:set image to normal

    # set next update to target time.
    # check_interval is in minutes, tm is in seconds.
    updateAt = tm + int(Config['check_interval'])*60
    return True
    

def configureWMGmail():
    global chPid
    if chPid != -1:
        #print "nonnull %s" % chPid
        pid, status = os.waitpid(chPid, os.WNOHANG)
        #print "status %s %s %s" % (chPid, pid, status)
        if pid == 0 or not os.WIFEXITED(status):
            print "not exited"
            return
        chPid = -1
    #print "forking"
    chPid = os.fork()
    if chPid == 0:
        import wmgsettingsgui
        wmgsettingsgui.run_in_thread()
        sys.exit(0)

def showRecentMessages(popup = False):
    global chPidRecent
    if chPidRecent != -1:
        #print "nonnullR %s" % chPidRecent
        pid, status = os.waitpid(chPidRecent, os.WNOHANG)
        #print "statusR %s %s %s" % (chPidRecent, pid, status)
        if pid == 0 or not os.WIFEXITED(status):
            #print "Rnot exited"
            return
        chPidRecent = -1
    #print "forking Recent"
    chPidRecent = os.fork()
    if chPidRecent == 0:
        import wmgchooser
        wmgchooser.run_in_thread(unreadMails, popup)
        sys.exit(0)

def startBrowserInbox():
    #print "starting something, yeah.."
    if os.fork():
        # forked and am parent.
        return
    # forked, and is child.
    # start browser.
    cmd = wmgsettings.getwmgmailsettings(wmgsettings.get_settingsfname())['browser_command']
    cmd = cmd.replace('%s', 'http://gmail.google.com/gmail')
    os.execl(*['/bin/sh', '/bin/sh', '-c', cmd])

def execOnNewMail():
    if os.fork():
        # forked and is parent
        return
    # could have some replacements? %n -> number of new mails..
    cmd = Config['exec_command']        
    # print "execute: %s" % Config['exec_command']
    os.execl(*['/bin/sh', '/bin/sh', '-c', cmd])

def drawStatus():
    # usually no mail.
    global gStatusNo, gStatusHave, gStatusAt, gStatusPicSize
    status = gStatusNo
    if unreadMailCnt:
        # have mail
        status = gStatusHave
    pywmhelpers.copyXPMArea(*(status+gStatusPicSize+gStatusAt))

def addString(s, x, y):
    '''Convenience function around pwymhelpers.addString.'''
    try:
        pywmhelpers.addString(s, x, y, letterWidth, letterHeight, lettersStartX,
                          lettersStartY, letters, digitWidth, digitHeight,
                          digitsStartX, digitsStartY, digits, xOffset, yOffset,
                          width, height)
    except ValueError, e:        
        err('Error when painting string ("'+s+'"):\n' + str(e) + '\n')
        sys.exit(3)

def clearLine(y):
    '''Clear a line of text at position y.'''
    pywmhelpers.copyXPMArea(72, yOffset, width - 2 * xOffset, letterHeight,
                            xOffset, y + yOffset)

def getXY(line):
    '''Return the x and y positions to be used at line line.'''
    return 0, line * (letterHeight + 3) + 1

def isTrue(s):
    '''Return true if the string s can be interpreted as a true value.

    Raises ValueError if we get a string we dont like.
    '''
    trueThings = ['on', 'yes', '1', 'true']
    falseThings = ['off', 'no', '0', 'false']
    if s in trueThings:
        return 1
    elif s in falseThings:
        return 0
    raise ValueError

class ActiveArea:
    def __init__(self, num, action, coords):
        self._num = num
        self._action = action
        self._coords = coords

    def getMouseRegion(self):
        return [self._num] + self._coords;

    def _doMouseAction(self, button):
        actions = { 'config': configureWMGmail,
                    'inbox': startBrowserInbox,
                    'mailchoose': showRecentMessages,
                    'refresh': forceRefresh }
        if self._action in actions:
            #print "found and executing action %s" % self._action
            actions[self._action]()
        else:
            print "Unknown action %s" % self._action
            
    def tick1(self):
        pass
    def tick2(self):
        pass

    def mouseClicked(self, button):
        #print "mouse clicked"
        if 0 < button < 11:
            self._doMouseAction(button)
    

class WMGmail:
    def __init__(self):
        self._entrys = []
        line = 0
        tentry = [[0, 'inbox', [15,3,46,25]],
                  [1, 'config', [3,3,14,11]],
                  [2, 'mailchoose',[50,3, 60, 26]],
                  [3, 'refresh', [3,16,14,25]] ]
        for entry in tentry:
            self._entrys.append(ActiveArea(*entry))
        self._setupMouseRegions()

    def _setupMouseRegions(self):
        for area in self._entrys:
            pywmhelpers.addMouseRegion(*(area.getMouseRegion()));

    def _checkForEvents(self):
        event = pywmhelpers.getEvent()
        while not event is None:
            if event['type'] == 'destroynotify':
                sys.exit(0)
            elif event['type'] == 'buttonrelease':
                region = pywmhelpers.checkMouseRegion(event['x'], event['y'])
                button = event['button']
                if region != -1:
                    if not self._entrys[region] is None:
                        self._entrys[region].mouseClicked(button)
            event = pywmhelpers.getEvent()

    def mainLoop(self):
        global reConfig, reallyNewMailCount, Config
        counter = -1
        # clear Inbox -number.
        addString("Upd.", 32, 28)
        # draw ui for viewing pleasure
        changes = 1

        while 1:
            if changes:
                pywmhelpers.redraw()
                changes = 0
            else:
                time.sleep(0.1)

            counter += 1

            if reConfig:
                #print "rereading config"
                reConfig = 0
                readConfig()

            self._checkForEvents()
            if counter % 3 == 0:
                [e.tick1() for e in self._entrys if not e is None]
            if counter % 20 == 0:
                #addString("%4d" % ((counter/20) % 9999), 32, 28)
                [e.tick2() for e in self._entrys if not e is None]

            # every second, try to initiate mail update            
            if counter % 10 == 0 and getUnread():
                # if mail was updated, update string.
                addString("%4d" % unreadMailCnt, 32, 28)
                drawStatus()
                if Config['pop_qmp'] and reallyNewMailCount:
                    showRecentMessages(popup = True)
                if Config['exec_on_newmail'] and reallyNewMailCount:
                    execOnNewMail()
                reallyNewMailCount = 0
                changes = 1
            # collect garbage (once a 10 minute)
            if (counter % int(60*10/0.1)) == 0:
                collected = gc.collect();
                # print "Cleaning garbage, %d objects found." % collected
                if gc.garbage:
                    print "wmgmail: Uncollectable garbage found, please report this as bug: %s" % gc.garbage

                
            if counter == 999999:
                counter = -1
            # pywmhelpers.redraw()

def parseCommandLine(argv):
    '''Parse the commandline. Return a dictionary with options and values.'''
    shorts = 'ht:b:r:c:'
    longs = ['help', 'text=', 'background=', 'rgbfile=', 'configfile=']
    try:
        opts, nonOptArgs = getopt.getopt(argv[1:], shorts, longs)
    except getopt.GetoptError, e:
        err('Error when parsing commandline: ' + str(e) + '\n')
        err(usage)
        sys.exit(2)
    d = {} 
    for o, a in opts:
        if o in ('-h', '--help'):
            sys.stdout.write(usage)
            sys.exit(0)
        if o in ('-t', '--text'):
            d['textcolor'] = a
        if o in ('-b', '--background'):
            d['background'] = a
        if o in ('-r', '--rgbfile'):
            d['rgbfile'] = a
        if o in ('-c', '--configfile'):
            d['configfile'] = a
    return d

def main():
    try:
        programName = sys.argv[0].split(os.sep)[-1]
    except IndexError:
        programName = ''
    sys.argv[0] = programName
    pywmhelpers.setDefaultPixmap(new_xpm)
    pywmhelpers.openXwindow(sys.argv, width, height)
    wmgmail = WMGmail()
    wmgmail.mainLoop()

# cleanup after our children.
signal.signal(signal.SIGCHLD, handlerChild)
# signal to update from saved settings-file.
signal.signal(signal.SIGHUP, handlerHUP) 

new_xpm = \
['160 100 51 1',
' 	c None',
'.	c #000100',
'+	c #0700CE',
'@	c #1F201E',
'#	c #1600FF',
'$	c #2023D6',
'%	c #373EDC',
'&	c #0076BF',
'*	c #BC3334',
'=	c #CD3636',
'-	c #4E58E2',
';	c #DB3536',
'>	c #6E706D',
',	c #5B66E3',
'm	c #BA5152',
')	c #DD4546',
'!	c #14B3A8',
'~	c #DE5C5B',
'{	c #7E8EEE',
']	c #E67475',
'^	c #BE8787',
'/	c #8798F1',
'(	c #A2A4A1',
'_	c #EC9C9D',
':	c #A3B5F7',
'<	c #B7B7B7',
'[	c #BCBCBC',
'}	c #BEBEBE',
'|	c #C0C0C0',
'1	c #FFC514',
'2	c #C4C4C4',
'3	c #2EB457',
'4	c #FCB3B2',
'5	c #CBCBCB',
'6	c #CECECE',
'7	c #D3D3D3',
'8	c #E2D5D5',
'9	c #FACBCB',
'0	c #DFDFDF',
'a	c #E9E9E9',
'b	c #FFE2E1',
'c	c #ECECEC',
'd	c #F0F0F0',
'e	c #F1F4F0',
'f	c #FEEEEF',
'g	c #F7F7F7',
'h	c #F8F8F8',
'i	c #FAFAFA',
'j	c #FEFEFE',
'k	c #FDFFFC',
'l	c #FFFFFF',
'                                                                @###############################################################################################',
'                                                                @#!!!##...##!!!##...##...#######################################################################',
'                                                                @#!!!##...##!!!##...##...#######################################################################',
'    55555555555~;;;)_bbbbbbbbbbbbbbbbbbb9);;;)     555555555    @#!!!##...##!!!##...##...#######################################################################',
'   5kkkkkkkkkkk~;;;;;_kkkkkkkkkkkkkkkkk9);;;;)    5kkkkkkkkk5   @#!!!##.........................................................################################',
'   5kk1111kkkkk~;;;;;)]kkkkkkkkkkkkkkk4;;;;;;)(   5kkkkkkkkk5   @#!!!##.........................................................################################',
'   5k11||10kkkk~;;;;;;;~fkkkkkkkkkkkk]=;;;;;;)(   5kkkkkkkkk5   @#!!!##.........................................................################################',
'   5k1|kk0kkkkk~;;;~;;);~bkkkkkkkkkf~);;;);;;)(   5kkkkkkkkk5   @#!!!##.........................................................################################',
'   5k1|kkkkkkkk~;;;]_;;;;;9kkkkkkkf~;;);]4;;;)(   5kkkkkkkkk5   @#!!!##.........................................................################################',
'   5k11kk1kkkkk~;;;]k4=;;;;4kkkkk9);;;;4k_;;;)(   5kkkkkkkkk5   @#!!!##.........................................................################################',
'   5kk11110kkkk~;;;]kk9;;;;;_kkk4;;;;=9ek_;;;)(   5kkkkkkkkk5   @#!!!##.........................................................################################',
'   5kkk000kkkkk~;;;]kkkb;;;;;]f_=;;;~9kkk4;;;)(   5kk~kkkkkk5   @#!!!##.........................................................################################',
'    55555555555~;;;]kkkkf;;;=;;;;;;~fkkkk_;==)(   5kk~;;kkkk5   @#!!!##...##...##...##...#######################################################################',
'               ~;;;]kkkkkk];;;;;;=]fkkkkk_);;)(   5kk~;;;;kk5   @#!!!##...##...##...##!!!#######################################################################',
'               ~;;;]kkkkkkk];;;;;_kkkkkkk_===)(   5kk~;;;*;k5   @#!!!##...##...##...##!!!#######################################################################',
'               ~;;;]kkkkkkb4_);)_49kkkkkk_;==*(   5kk;;***4k5   @#!!!##...##...##...##!!!#######################################################################',
'    55555555555~;;;]kkkkf49kk9)9kk94fkkkk_===*(   5kk;**4fkk5   @#!!!###########################################################################################',
'   5kkkkkkkkkkk~;;;]kkk94bkkkkkkkkkb49kkk_==**(   5kk*fkkkkk5   @#!!!##~;;;)_bbbbbbbbbbbbbbbbbbb9);;;) 5|||20gggggggggggggggggggd2|||2(#########################',
'   5kk++++kkkkk~;;;]kf49fkkkkkkkkkkkk94fk_==**(   5kkkkkkkkk5   @#!!!##~;;;;;_kkkkkkkkkkkkkkkkk9);;;;) 5|||||0jjjjjjjjjjjjjjjjjd2||||2(#########################',
'   5kk+||+0kkkk~;;;]94fkkkkkkkkkkkkkkkf4b_==**(   5kkkkkkkkk5   @#!!!##~;;;;;)]kkkkkkkkkkkkkkk4;;;;;;)(5|||||27jjjjjjjjjjjjjjja||||||2(#########################',
'   5kk+|k+0kkkk~;;;~9kkkkkkkkkkkkkkkkkke9]****(   5kkkkkkkkk5   @#!!!##~;;;;;;;~fkkkkkkkkkkkk]=;;;;;;)(5|||||||5ijjjjjjjjjjjj7[||||||2(#########################',
'   5kk+++0kkkkk~;;;]kkkkkkkkkkkkkkkkkkkkf_=***(   5kkkkkkkkk5   @#!!!##~;;;~;;);~bkkkkkkkkkf~);;;);;;)(5|||5||2|5gjjjjjjjjji52|||2|||2(#########################',
'   5kk+|0+kkkkk~==;]kkkkkkkkkkkkkkkkkkkee_=***(   5kkkkkkkkk5   @#!!!##~;;;]_;;;;;9kkkkkkkf~;;);]4;;;)(5|||70|||||djjjjjjji5||2|7a|||2(#########################',
'   5kk+|k0+kkkk~;;*]kkkkkkkkkkkkkkkkkeeee_=***(   5kkkkkkkkk5   @#!!!##~;;;]k4=;;;;4kkkkk9);;;;4k_;;;)(5|||7ja[||||ajjjjjd2||||aj0|||2(#########################',
'   5kk00ll00kkkm===m888888888888888888888^=***(   5kkkkkkkkk5   @#!!!##~;;;]kk9;;;;;_kkk4;;;;=9ek_;;;)(5|||7jjd|||||0jjja||||[dhj0|||2(#########################',
'    55555555555****m^^^^^^^^^^^^^^^^^^^^^m****(   5kkkkkkkkk5   @#!!!##~;;;]kkkb;;;;;]f_=;;;~9kkk4;;;)(5|||7jjjg|||||7i0[|||5djjja|||2(#########################',
'                 ((((((((((((((((((((((((((((((    555555555    @#!!!##~;;;]kkkkf;;;=;;;;;;~fkkkk_;==)(5|||7jjjji|||[||||||5ijjjj0|[[2(#########################',
'                                                                @#!!!##~;;;]kkkkkk];;;;;;=]fkkkkk_);;)(5|||7jjjjjj7||||||[7ijjjjj02||2(#########################',
'                                                                @#!!!##~;;;]kkkkkkk];;;;;_kkkkkkk_===)(5|||7jjjjjjj7|||||0jjjjjjj0[[[2(#########################',
'                                                                @#!!!##~;;;]kkkkkkb4_);)_49kkkkkk_;==*(5|||7jjjjjjga02|20adjjjjjj0|[[<(#########################',
'                                                                @#!!!##~;;;]kkkkf49kk9)9kk94fkkkk_===*(5|||7jjjjiadjjd2djjdaijjjj0[[[<(#########################',
'   lkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk   @#!!!##~;;;]kkk94bkkkkkkkkkb49kkk_==**(5|||7jjjdagjjjjjjjjjgadjjj0[[<<(#########################',
'  lk+,kkkkkkk,+kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklk  @#!!!##~;;;]kf49fkkkkkkkkkkkk94fk_==**(5|||7jiadijjjjjjjjjjjjdaij0[[<<(#########################',
'  kk+-kkkkkkk-+kkkkkkkkkkkkkkkkkkkkkk&&&&&kkk&kkk&&&&&k&&&&&lk  @#!!!##~;;;]94fkkkkkkkkkkkkkkkf4b_==**(5|||7daijjjjjjjjjjjjjjjiag0[[<<(#########################',
'  kk+,k+-$+,k,+-+$:kk/$+$/k,+//+,kkkk&kkk&kk&&kkkkkkk&kkkkk&ll  @#!!!##~;;;~9kkkkkkkkkkkkkkkkkke9]****(5|||5djjjjjjjjjjjjjjjjjjhd7<<<<(#########################',
'  kk+,k++/$$k,+%{$%k:+%/%+:k$$$$kkkkk&kkk&kkk&kkkkkkk&kkkkk&ll  @#!!!##~;;;]kkkkkkkkkkkkkkkkkkkkf_=***(5|||7jjjjjjjjjjjjjjjjjjjji0[<<<(#########################',
'  kk+,k+-k-+k,+:k-+k,+:k:+,k:++:kkkkk&kkk&kkk&kkk&&&&&kk&&&&ll  @#!!!##~==;]kkkkkkkkkkkkkkkkkkkee_=***(5[[|7jjjjjjjjjjjjjjjjjjjhh0[<<<(#########################',
'  kk+-k+,k,+k,+:k-+k,+:k:+,k/++{kkkkk&kkk&kkk&kkk&kkkkkkkkk&lk  @#!!!##~;;*]kkkkkkkkkkkkkkkkkeeee_=***(5||<7jjjjjjjjjjjjjjjjjhhhh0[<<<(#########################',
'  kk+,k+,k,+k,+%{$%k:+%/%$:k$%%+:kkkk&kkk&kkk&kkk&kkkkkkkkk&lk  @#!!!##m===m888888888888888888888^=***(}[[[}ccccccccccccccccccccc6[<<<(#########################',
'  lk+,k+-k,+k,+,+$:kk/$+$/k-+::$%kkkk&&&&&kk&&&kk&&&&&k&&&&&lk  @#!!!##****m^^^^^^^^^^^^^^^^^^^^^m****(<<<<}666666666666666666666}<<<<(#########################',
'   lkkkkkkfkkkkkkkkkkkkkkkkkkfkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk   @#!!!##  (((((((((((((((((((((((((((((8((((((((((((((((((((((((((((((((#########################',
'                                                                @#!!!##                                 ########################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!###>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>###',
'                                                                @#!!!###>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>###',
'                                                                @#!!!###>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>###',
'                                                                @#!!!###>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>###',
'                                                                @#!!!###########################################################################################',
'                                                                @#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!###',
'                                                                .#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!###',
'                                                                @#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!###',
'                                                                @#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!###',
'                                                                @###############################################################################################',
'                                                                .###############################################################################################',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk############################',
'k+++++kkk+kkk+++++k+++++k+kkk+k+++++k+++++k+++++k+++++k+++++kkkkkkkkkk+kkkkkkkkkk+k+kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk############################',
'k+kkk+kk++kkkkkkk+kkkkk+k+kkk+k+kkkkk+kkkkkkkkk+k+kkk+k+kkk+kk++kkkkkk+kkkkkkkkkkkk+kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk############################',
'k+kkk+kkk+kkkkkkk+kkkkk+k+kkk+k+kkkkk+kkkkkkkkk+k+kkk+k+kkk+kk++kkkkk++kkkkkkkkkkk++kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk############################',
'k+kkk+kkk+kkk+++++kk++++k+++++k+++++k+++++kkkkk+k+++++k+++++kkkkkkkkk+kkk+++++kkkk+kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk############################',
'k+kkk+kkk+kkk+kkkkkkkkk+kkkkk+kkkkk+k+kkk+kkkkk+k+kkk+kkkkk+kkkkkkkk++kkkkkkkkkkk++kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk############################',
'k+kkk+kkk+kkk+kkkkkkkkk+kkkkk+kkkkk+k+kkk+kkkkk+k+kkk+kkkkk+kk++kkkk+kkkkkkkkkkkk+kkkkk++kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk############################',
'k+++++kk+++kk+++++k+++++kkkkk+k+++++k+++++kkkkk+k+++++k+++++kk++kkkk+kkkkkkkkkkkk+k+kkk++kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk############################',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk############################',
'################################################################################################################################################################',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'kk+++kk++++kkk++++k++++kk++++kk+++++k+++++k+kkk+kkk+kkkkkkk+k+kkk+k+kkkkk+kkk+k++++kk+++++k+++++k+++++k+++++k+++++k+++++k+kkk+k+kkk+k+kkk+k+kkk+k+kkk+k+++++kkkk',
'k+kkk+k+kkk+k+kkkkk+kkk+k+kkkkk+kkkkk+kkkkk+kkk+kkk+kkkkkkk+k+kkk+k+kkkkk++k++k+kkk+k+kkk+k+kkk+k+kkk+k+kkk+k+kkkkkkk+kkk+kkk+k+kkk+k+kkk+k+kkk+k+kkk+kkkkk+kkkk',
'k+kkk+k+kkk+k+kkkkk+kkk+k+kkkkk+kkkkk+kkkkk+kkk+kkk+kkkkkkk+k+kk+kk+kkkkk+k+k+k+kkk+k+kkk+k+kkk+k+kkk+k+kkk+k+kkkkkkk+kkk+kkk+k+kkk+k+kkk+kk+k+kk+kkk+kkkk+kkkkk',
'k+++++k++++kk+kkkkk+kkk+k++++kk++++kk+k+++k+++++kkk+kkkkkkk+k+++kkk+kkkkk+kkk+k+kkk+k+kkk+k+++++k++kk+k++++kk+++++kkk+kkk+kkk+k+kkk+k+kkk+kkk+kkk+++++kkk+kkkkkk',
'k+kkk+k+kkk+k+kkkkk+kkk+k+kkkkk+kkkkk+kkk+k+kkk+kkk+kkkkkkk+k+kk+kk+kkkkk+kkk+k+kkk+k+kkk+k+kkkkk+k+k+k+kkk+kkkkk+kkk+kkk+kkk+kk+k+kk+k+k+kk+k+kkkkkk+kk+kkkkkkk',
'k+kkk+k+kkk+k+kkkkk+kkk+k+kkkkk+kkkkk+kkk+k+kkk+kkk+kkk+kkk+k+kkk+k+kkkkk+kkk+k+kkk+k+kkk+k+kkkkk+kk++k+kkk+kkkkk+kkk+kkk+kkk+kk+k+kk++k++k+kkk+kkkkk+k+kkkkkkkk',
'k+kkk+k++++kkk++++k++++kk++++kk+kkkkk+++++k+kkk+kkk+kkkk+++kk+kkk+k++++kk+kkk+k+kkk+k+++++k+kkkkk+++++k+kkk+k+++++kkk+kkkk++++kkk+kkk+kkk+k+kkk+k+++++k+++++kkkk',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'################################################################################################################################################################',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk',
'################################################################################################################################################################',
'################################################################################################################################################################',
'################################################################################################################################################################',
'################################################################################################################################################################',
'################################################################################################################################################################',
'################################################################################################################################################################',
'################################################################################################################################################################']


if __name__ == '__main__':
    main()
