keys-on-cli
quadrismegistus 4 years ago
parent 18ba159a97
commit db46ee8a65

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

@ -1,8 +1,7 @@
# basic config
from .art import *
from .constants import *
from .utils import *
from .cli.artcode import *
# common python imports
import os,sys

@ -23,6 +23,35 @@ ART_TELEPHONE = '''
"-.;_..--""
'''
ART_PHONE_SM1 = """
.----------------.
/ _H______H_ \@,
\____/ \____/ @,
/ \ `@
| LI LI LI | ,@
| LI LI LI | ,@'
| LI LI LI | ,@'
| LI LI LI |@@'
jgs \ /'
`----------'
"""
ART_ROTARY2="""
_______________
/ \
| .---------. |@
'---' .-----. '---'@
.' /6 5_4 3\ '. @
| |7 /...\ 2| | @
| |8 \___/ 1| | @
| \_9_0_)\/ | @@
/==|_____________|@@@@
H-------------------@@
H ) || || ( @@
H / || || \ @
H |----''---''----|
=/ |_______________|
"""
ART_KEY = """
@ -182,4 +211,75 @@ ART_PAYPHONE = """
| |'--'| | OoO
| '----' |
jgs \_________________/
"""
"""
####
# code
###
from PIL import Image
ASCII_CHARS = [ '#', '?', '%', '.', 'S', '+', '.', '*', ':', ',', '@']
def scale_image(image, new_width=100):
"""Resizes an image preserving the aspect ratio.
"""
(original_width, original_height) = image.size
aspect_ratio = original_height/float(original_width)
new_height = int(aspect_ratio * new_width)
new_image = image.resize((new_width, new_height))
return new_image
def convert_to_grayscale(image):
return image.convert('L')
def map_pixels_to_ascii_chars(image, range_width=25):
"""Maps each pixel to an ascii char based on the range
in which it lies.
0-255 is divided into 11 ranges of 25 pixels each.
"""
pixels_in_image = list(image.getdata())
pixels_to_chars = [ASCII_CHARS[pixel_value//range_width] for pixel_value in
pixels_in_image]
return "".join(pixels_to_chars)
def convert_image_to_ascii(image, new_width=50):
image = scale_image(image)
image = convert_to_grayscale(image)
pixels_to_chars = map_pixels_to_ascii_chars(image)
len_pixels_to_chars = len(pixels_to_chars)
image_ascii = [pixels_to_chars[index: index + new_width] for index in
range(0, len_pixels_to_chars, new_width)]
return "\n".join(image_ascii)
def handle_image_conversion(image_filepath):
image = None
try:
image = Image.open(image_filepath)
except Exception as e:
# print "Unable to open image file {image_filepath}.".format(image_filepath=image_filepath)
# print e
return
image_ascii = convert_image_to_ascii(image)
print(image_ascii)
if __name__=='__main__':
import sys
image_file_path = sys.argv[1]
handle_image_conversion(image_file_path)

@ -3,7 +3,7 @@ from komrade import *
from komrade.backend.crypt import *
from abc import ABC, abstractmethod
class KomradeKey(ABC):
class KomradeKey(ABC,Logger):
@abstractmethod
def encrypt(self,msg,**kwargs): pass
@abstractmethod
@ -31,14 +31,23 @@ class KomradeSymmetricKey(KomradeKey):
return self.cell.encrypt(msg,**kwargs)
def decrypt(self,msg,**kwargs):
return self.cell.decrypt(msg,**kwargs)
def getpass_status(passphrase=None):
while not passphrase:
passphrase1 = getpass(f'@Keymaker: What is a *memorable* pass word or phrase? Do not write it down.\n@{name}: ')
passphrase2 = getpass(f'@Keymaker: Could you repeat that?')
if passphrase1!=passphrase2:
self.status('@Keymaker: Those passwords didn\'t match. Please try again.',clear=False,pause=False)
else:
return passphrase1
class KomradeSymmetricKeyWithPassphrase(KomradeSymmetricKey):
def __init__(self,passphrase=DEBUG_DEFAULT_PASSPHRASE, why=WHY_MSG):
self.passphrase=passphrase
if not self.passphrase:
self.passphrase=getpass.getpass(why)
self.passphrase=getpass_status if SHOW_LOG else getpass.getpass(why)
#return self.passphrase
@property
def data(self): return KEY_TYPE_SYMMETRIC_WITH_PASSPHRASE.encode('utf-8')
@ -70,20 +79,36 @@ class KomradeAsymmetricKey(KomradeKey):
def data(self): return self.key
class KomradeAsymmetricPublicKey(KomradeAsymmetricKey):
def __init__(self,pubkey,privkey=None):
self.pubkey=pubkey
self.privkey=privkey
@property
def key(self): return self.pubkey
@property
def data(self): return self.pubkey
def __repr__(self): return f'''[Asymmetric Public Key] ({self.discreet})'''
def __repr__(self): return f'''[Asymmetric Public Key] ({self.data_b64.decode()})'''
class KomradeAsymmetricPrivateKey(KomradeAsymmetricKey):
def __init__(self,privkey,pubkey=None):
self.pubkey=pubkey
self.privkey=privkey
@property
def data(self): return self.privkey
@property
def key(self): return self.privkey
def __repr__(self): return f'''[Asymmetric Private Key] ({self.discreet})'''
def make_key_discreet(data,len_start=10,len_end=10,ellipsis='.',show_len=True):
def make_key_discreet(data,chance_bowdlerize=0.5):
import random
if not data: return '?'
if not isBase64(data): data=b64encode(data)
key=data.decode()
return ''.join((k if random.random()<chance_bowdlerize else '-') for k in key)
def make_key_discreet1(data,len_start=10,len_end=10,ellipsis='.',show_len=True):
if not data: return '?'
if not isBase64(data): data=b64encode(data)
data=data.decode()
@ -92,7 +117,7 @@ def make_key_discreet(data,len_start=10,len_end=10,ellipsis='.',show_len=True):
if len_end: dstr+=data[-len_end:]
return f'{dstr}' #' (+{len(data)-len_start-len_end})'
class KomradeEncryptedKey(object):
class KomradeEncryptedKey(Logger):
def __init__(self,data): self.data=data
@property
def data_b64(self): return b64encode(self.data).decode()
@ -338,6 +363,8 @@ class Keymaker(Logger):
key_types = dict([(k,key_types[k]) for k in keys_to_gen])
if not name: name=self.name
print('forging!')
# show user what's happening
self.log(f'''
Keymaker ({self}) is forging new keys for {name}
@ -352,6 +379,7 @@ Keymaker ({self}) is forging new keys for {name}
I will also be using these key types to do so:
{dict_format(key_types,tab=4)}
''')
# gen decryptor keys!
@ -359,7 +387,7 @@ Keymaker ({self}) is forging new keys for {name}
# gen encrypted keys!
keychain = self.gen_encr_keys(keychain,keys_to_gen,passphrase=passphrase)
self.log('I built this keychain!',dict_format(keychain,tab=2))
# self.status('@Keymaker: I ended up building these keys:',keychain)
# save keys!
# get URI id to save under (except for pubkeys, accessible by name)
@ -370,6 +398,9 @@ Keymaker ({self}) is forging new keys for {name}
keys_returned = self.return_keychain(keychain,keys_to_return)
self.log('I am returning this keychain:',dict_format(keys_returned,tab=2))
print('done forging!')
return (uri_id,keys_returned)

@ -97,6 +97,37 @@ def test_torpy():
import random
def test_slow_func(n,t=1,m=10):
for x in range(m):
print(f'Thread #{n}: it #{x} of {m}, sleeping {m} sec..')
yield x
# time.sleep(t)
def test_threads():
from multiprocessing.pool import ThreadPool
pool = ThreadPool(processes=2)
for x in pool.imap_unordered(test_slow_func, [1,2,3]):
for y in x:
print(y,'?')
print(x,'...')
async def test_slow_func(n,t=1,m=10):
for x in range(m):
print(f'Thread #{n}: it #{x} of {m}, sleeping {m} sec..')
yield x
asyncio.sleep(t)
# test async
async def test_async():
return await asyncio.gather(*[await test_slow_func(n) for n in range(3)])

@ -30,7 +30,7 @@ class Persona(Caller):
return self.pubkey and self.privkey
def exists_on_server(self):
answer = self.ring_ring({
answer = self.phone.ring_ring({
'_route':'does_username_exist',
'name':self.name
})
@ -47,61 +47,8 @@ class Persona(Caller):
if name and not self.name: self.name=name
if not name and self.name: name=self.name
if not name and not self.name: name=''
# ring ring!
ticks = ['*ring*','*ring ring*','*ring*']
self.status(None,ART_OLDPHONE3,3,pause=False,ticks = ticks)
# hello, op?
self.status(f'\n\n@{name if name else "?"}: Uh yes hello, Operator? I would like to join Komrade, the socialist network. Could you patch me through?',clear=True,pause=True)
while not name:
name=self.status(('name','@TheOperator: Of course, Komrade ...?\n@'),clear=False).get('vals',{}).get('name')
print()
self.name=name
self.status(f"@TheOperator: Of course, Komrade @{name}. A fine name. First, though, let me see if by an awkward accident someone has already taken this name.",clear=False)
# does username exist
res = self.exists_on_server()
self.status('I got this result',res,clear=False)
stop
exit()
self.status([
'''@TheOperator: I could, it's not safe yet. Your information will be exposed all over the internet. You should forge your encryption keys first.''',
f'@{name}: Fine, but how do I do that?',
'@TheOperator: Visit the Keymaker.'
])
# ring ring!
self.status([None,ART_KEY,2],pause=False)
# some info
res = self.status([
# ART_KEY,
f'{ART_KEY}@{name}: Dear @Keymaker, I would like to forge a new set of keys.',
f'''@Keymaker: We will make two. A matching, "asymmetric" pair:''',
'\t1) A "public key" you can share with anyone.',
'\t2) A "private key" other no one can ever, ever see.',
'With both together, you can communicate privately and securely with anyone who also has their own key pair.'
])
while not passphrase:
passphrase1 = getpass(f'What is a *memorable* pass word or phrase? Do not write it down.\n@{name}: ')
passphrase2 = getpass(f'Could you repeat that?')
if passphrase1!=passphrase2:
self.status('Those passwords didn\'t match. Please try again.',clear=False,pause=False)
else:
passphrase=passphrase1
# if not name or name=='?': self.name = name = res['vals'].get('name')
res = self.status([
('passphrase',f'\nWhat is a memorable pass word or phrase? \n@{name}: ',getpass) if not passphrase else False
('passphrase2',f'\Could you repeat that? \n@{name}: ',getpass) if not passphrase else False
],clear=False)
if not passphrase:
p1,p2=res.get('passphrase'),res.get('passphrase2')
# if p1!=p2
# passphrase = passphrase
if not passphrase: passphrase=getpass('Enter a memorable password: ')
# make and save keys locally
uri_id,keys_returned = self.forge_new_keys(
@ -119,8 +66,7 @@ class Persona(Caller):
}
self.log('sending to server:',dict_format(data,tab=2))
# msg_to_op = self.compose_msg_to(data, self.op)
# ring operator
# call from phone since I don't have pubkey on record on Op yet
resp_msg_obj = self.phone.ring_ring(data)
@ -144,9 +90,9 @@ class Persona(Caller):
def test_register():
import random
num = random.choice(list(range(0,1000)))
# botname=f'marx{str(num).zfill(3)}'
# marxbot = Persona(botname)
marxbot=Persona()
botname=f'marx{str(num).zfill(3)}'
marxbot = Persona(botname)
# marxbot=Persona()
marxbot.register()
if __name__=='__main__':

@ -0,0 +1,285 @@
ART_TELEPHONE = '''
..--""""----..
.-" ..--""""--.j-.
.-" .-" .--.""--..
.-" .-" ..--"-. \/ ;
.-" .-"_.--..--"" ..--' "-. :
.' .' / `. \..--"" __ _ \ ;
:.__.-" \ / .' ( )"-. Y
; ;: ( ) ( ). \
.': /:: : \ \
.'.-"\._ _.-" ; ; ( ) .-. ( ) \
" `.""" .j" : : \ ; ; \
bug /"""""/ ; ( ) "" :.( ) \
/\ / : \ \`.: _ \
: `. / ; `( ) (\/ :" \ \
\ `. : "-.(_)_.' t-' ;
\ `. ; ..--":
`. `. : ..--"" :
`. "-. ; ..--"" ;
`. "-.:_..--"" ..--"
`. : ..--""
"-. : ..--""
"-.;_..--""
'''
ART_PHONE_SM1 = """
.----------------.
/ _H______H_ \@,
\____/ \____/ @,
/ \ `@
| LI LI LI | ,@
| LI LI LI | ,@'
| LI LI LI | ,@'
| LI LI LI |@@'
jgs \ /'
`----------'
"""
ART_ROTARY2="""
_______________
/ \
| .---------. |@
'---' .-----. '---'@
.' /6 5_4 3\ '. @
| |7 /...\ 2| | @
| |8 \___/ 1| | @
| \_9_0_)\/ | @@
/==|_____________|@@@@
H-------------------@@
H ) || || ( @@
H / || || \ @
H |----''---''----|
=/ |_______________|
"""
ART_KEY = """
8 8 8 8 ,ooo.
8a8 8a8 oP ?b
d888a888zzzzzzzzzzzzzzzzzzzz8 8b
`""^""' ?o___oP'
"""
ART_OLDPHONE = """
__
/` _`\
| (_()| .-.
\_ _/_/ \
||=[_] |
|| | | |
||/ \ |
||`---' /
.--'||-.___.'
/` .-||-.
'-/`.____.`\
jgs '.______.'
"""
ART_OLDPHONE2="""
_|~|/|
( | | |
/_|_|\|
| |
| |~|
| | |
| | |
| |-|
| | \
| |__|
|_|_
/ ~-_
/ ~-_
|___________|
"""
ART_ROTARY = """
_...----..._
,-' ,-. `-.
,' ,-. ( 4 ) ,-. `.
,' ( 5 ) `-' ( 3 ) `.
/ ,-. `-',-'' ``-.`-' ,-. \
/ ( 6 ) ,' `. ( 2 ) \
: `-' / FEUER \ `-' :
| ,-. : ________ : ,-. |
|( 7 ) | |________| | ( 1 )|
| `-' : ; `-' |
: ,-. \ NOTRUF / ;
\ ( 8 ) `. ,'(`. /
\ `-' ,-.`-..__..-' \ `-./
`. ( 9 ) ,-. \ ,'
`. `-' ( 0 ) ,'`
`-._ `-' _.-'
```----''' SSt
"""
ART_PHONE_DIAGRAM = """
________
.' / / )
/ /##/ /|
/ `--' / |
/__ __ __ / |
//_//_//_// / __
//_//_//_// / \`.___ Listening end
//_//_//_// /
//_//_//_// /__
/ / / \`.___ Buttons
/ .-. / /
/ /#/ / /
/ `-' / /__
/ .====. / / \`.___ Speaking end
|`--------' /
\ , .'__
`-//----' \`.___ Disconnect button
//
"""
ART_OLDPHONE3 = """
__ _
.: .' '.
/: / \_
;: ; ,-'/`:\
|: | | |():|
;: ; '-.\_:/
\: \ /`
':_'._.'
||
/__\
.---. {====}
.' _,"-,__|:: |
/ ((O)=;--.:: |
; `|: | |:: |
| |: | |:: |
| |: | |:: |
| |: | |:: |
| |: | |:: |
| |: | |:: |
| /:'__\ |:: |
| [______]|:: |
| `----` |:: |__
| _.--|:: | ''--._
; .' __{====}__ '.
\ .'_.-'._ `""` _.'-._ '.
'--'/` `''''` `\ '.__
jgs '._ _.'
`""--......--""`
"""
ART_OLDPHONE4 = """
__
/` _`\
| (_()| .-.
\_ _/_/ \
||=[_] |
|| | | |
||/ \ |
||`---' /
.--'||-.___.'
/` .-||-.
'-/`.____.`\
jgs '.______.'
"""
ART_PAYPHONE = """
_________________
/ __ \
| (__) |
| |
| .-----. .--. |
| | | / \ |
| '-----' \ / |
| | | |
| LI LI LI | | |
| LI LI LI | | |Oo
| LI LI LI | | |`Oo
| LI LI LI | | | Oo
| | | | Oo
| .------. / \ | oO
| | | \ / | Oo
| '------' '-oO | oO
| .---Oo | Oo
| || ||`Oo oO
| |'--'| | OoO
| '----' |
jgs \_________________/
"""
####
# code
###
from PIL import Image
ASCII_CHARS = [ '#', '?', '%', '.', 'S', '+', '.', '*', ':', ',', '@']
def scale_image(image, new_width=100):
"""Resizes an image preserving the aspect ratio.
"""
(original_width, original_height) = image.size
aspect_ratio = original_height/float(original_width)
new_height = int(aspect_ratio * new_width)
new_image = image.resize((new_width, new_height))
return new_image
def convert_to_grayscale(image):
return image.convert('L')
def map_pixels_to_ascii_chars(image, range_width=25):
"""Maps each pixel to an ascii char based on the range
in which it lies.
0-255 is divided into 11 ranges of 25 pixels each.
"""
pixels_in_image = list(image.getdata())
pixels_to_chars = [ASCII_CHARS[pixel_value//range_width] for pixel_value in
pixels_in_image]
return "".join(pixels_to_chars)
def convert_image_to_ascii(image, new_width=100):
image = scale_image(image)
image = convert_to_grayscale(image)
pixels_to_chars = map_pixels_to_ascii_chars(image)
len_pixels_to_chars = len(pixels_to_chars)
image_ascii = [pixels_to_chars[index: index + new_width] for index in
range(0, len_pixels_to_chars, new_width)]
return "\n".join(image_ascii)
def handle_image_conversion(image_filepath):
image = None
try:
image = Image.open(image_filepath)
except Exception as e:
# print "Unable to open image file {image_filepath}.".format(image_filepath=image_filepath)
# print e
return
image_ascii = convert_image_to_ascii(image)
print(image_ascii)
if __name__=='__main__':
import sys
image_file_path = sys.argv[1]
handle_image_conversion(image_file_path)

@ -0,0 +1,155 @@
import os,sys; sys.path.append(os.path.abspath(os.path.join(os.path.abspath(os.path.join(os.path.dirname(__file__),'..')),'..')))
from komrade import *
from komrade.backend import *
import art
class CLI(Logger):
ROUTES = {
'help':'see help messages',
'register':'register new user',
'login':'log back in'
}
def __init__(self):
self.name=''
self.cmd=''
async def run(self,inp,name=''):
if name: self.name=name
clear_screen()
self.boot()
self.help()
if inp: self.route(inp)
while True:
try:
inp=input()
except KeyboardInterrupt:
exit()
self.route(inp)
await asyncio.sleep(0.5)
def route(self,inp):
inp=inp.strip()
if not inp.startswith('/'): return
cmd=inp.split()[0]
dat=inp[len(cmd):].strip()
cmd=cmd[1:]
if cmd in self.ROUTES and hasattr(self,cmd):
f=getattr(self,cmd)
return f(dat)
def boot(self):
print(art.text2art(CLI_TITLE,font=CLI_FONT))
def help(self):
print()
for cmd,info in self.ROUTES.items():
print(f' /{cmd}: {info}')
print('\n')
def intro(self):
self.status(None,)
## routes
def register(self,name=None):
# defaults
if name and not self.name: self.name=name
if not name and self.name: name=self.name
if not name and not self.name: name=''
# self.status(None,ART_PAYPHONE,3,pause=False) #,ticks = None)
# hello, op?
nm=name if name else '?'
self.status(
f'\n\n@{nm}: Uh yes hello, Operator? I would like to join Komrade, the socialist network. Could you patch me through?',clear=False)
while not name:
name=self.status(('name','@TheTelephone: Of course, Komrade...?\n@')).get('vals').get('name').strip()
print()
self.name = name
self.persona = Persona(name)
self.status(
f'@TheTelephone: Of course, Komrade @{name}. A fine name.',
'''@TheTelephone: However, I'm just the local operator who lives on your device; my only job is to communicate with the remote operator securely.''',
'''Komrade @TheOperator lives on the deep web. She's the one you want to speak with.''',
f'''@{name}: Hm, ok. Well, could you patch me through to the remote operator then?''',
f'''@{TELEPHONE_NAME}: I could, but it's not safe yet. Your information could be exposed. You need to forge your encryption keys first.''',
f'@{name}: Fine, but how do I do that?',
f'@{TELEPHONE_NAME}: Visit the Keymaker.',
clear=False,pause=True)
### KEYMAKER
self.status(None,ART_KEY,3,pause=False,clear=False)
# convo
self.status('',
f'@{name}: Hello, Komrade @Keymaker? I would like help forging a new set of keys.',
f'@Keymaker: Of course, Komrade @{name}.',
'''We will make three keys. First, a matching, "asymmetric" pair.''',
'\t1) A "public key" you can share with anyone.',
'\t2) A "private key" other no one can ever, ever see.',
'With both together, you can communicate privately and securely with anyone who also has their own key pair.',
'We will use the use the iron-clad Elliptic Curve algorthm to generate the keypair, accessed via a high-level cryptography library, Themis (https://github.com/cossacklabs/themis).',
)
# make and save keys locally
self.log(f'{KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT + KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER}!!!!!')
uri_id,keys_returned = self.persona.forge_new_keys(
name=name,
passphrase=None,
keys_to_save = [],
keys_to_return = KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_CLIENT + KEYMAKER_DEFAULT_KEYS_TO_SAVE_ON_SERVER
)
self.status('got back',dict_format(keys_returned))
#self.log(f'my new uri is {uri_id} and I got new keys!: {dict_format(keys_returned)}')
self.status(
'Generating public key now: ',5,'\n\t',repr(KomradeAsymmetricPublicKey(keychain['pubkey'])),'\n\n',
'Generating private key now: ',5,'\n\t',repr(KomradeAsymmetricPrivateKey(keychain['privkey'])),
clear=False,pause=False,end=' ',speed=2
)
# save the ones we should on server
data = {
**{'name':name, 'passphrase':self.crypt_keys.hash(passphrase.encode()), ROUTE_KEYNAME:'register_new_user'},
**keys_returned
}
self.log('sending to server:',dict_format(data,tab=2))
# msg_to_op = self.compose_msg_to(data, self.op)
# ring operator
# call from phone since I don't have pubkey on record on Op yet
resp_msg_obj = self.phone.ring_ring(data)
self.log('register got back from op:',dict_format(resp_msg_obj,tab=2))
def run_cli():
cli = CLI()
asyncio.run(cli.run('/register',name='elon'))
if __name__=='__main__':
run_cli()
# asyncio.run(test_async())

@ -157,7 +157,7 @@ PAUSE_LOGGER = True
ALLOW_CLEARNET = True
DEBUG_DEFAULT_PASSPHRASE = 'all your base are belong to us'
DEBUG_DEFAULT_PASSPHRASE = None # 'all your base are belong to us'
ROUTE_KEYNAME = '_route'
@ -182,5 +182,9 @@ DEFAULT_USER_SETTINGS = {
'visibility':VISIBILITY_TYPE_SEMIPUBLIC
}
SHOW_LOG = False
SHOW_STATUS = True
SHOW_LOG = True
SHOW_STATUS = True
CLI_TITLE = 'KOMRADE'
CLI_FONT = 'colossal'

@ -33,7 +33,7 @@ def do_pause():
def dict_format(d, tab=0):
def repr(v):
def reppr(v):
if type(v)==bytes and not isBase64(v):
return b64encode(v)
return v
@ -46,7 +46,7 @@ def dict_format(d, tab=0):
v = repr(v)
# s.append('%s%r: %s (%s),\n' % (' '*tab, k, v, type(v).__name__))
s.append('%s%r: %s,\n\n' % (' '*tab, k, repr(v)))
s.append('%s%r: %s,\n\n' % (' '*tab, k, reppr(v)))
s.append('%s}' % (' '*tab))
return ''.join(s)
@ -67,7 +67,8 @@ class Logger(object):
# except KeyboardInterrupt:
exit()
def status(self,*msg,pause=True,clear=True,ticks=[],tab=2):
def status(self,*msg,pause=True,clear=False,ticks=[],tab=2,speed=2,end=None):
import random
if not SHOW_STATUS: return
# if len(msg)==1 and type(msg[0])==str:
# msg=[x for x in msg[0].split('\n\n')]
@ -78,10 +79,10 @@ class Logger(object):
plen = para if type(para)==int or type(para)==float else None
if type(para) in {int,float}:
plen=int(para)
for i in range(plen):
for i in range(plen * speed):
tick = ticks[i] if i<len(ticks) else '.'
print(tick,end=' ',flush=True)
time.sleep(1)
print(tick,end=end if end else ' ',flush=True)
time.sleep(random.random() / speed)
elif para is None:
clear_screen()
elif para is False:
@ -99,11 +100,11 @@ class Logger(object):
elif para is 0:
do_pause()
elif pause:
print(para,flush=True)
print(para,flush=True,end=end if end else '\n')
paras+=[para]
do_pause()
else:
print(para,flush=True)
print(para,flush=True,end=end if end else '\n')
paras+=[para]
return {'paras':paras, 'vals':res}

Loading…
Cancel
Save