Commit f199c2ea authored by Tony Mai's avatar Tony Mai

update

parent 63206f90
...@@ -11,21 +11,21 @@ ...@@ -11,21 +11,21 @@
import pygame, time, evdev, select, math import pygame, time, evdev, select, math
import subprocess import subprocess
import os import os
import netifaces
def write_log(str):
global log
import wireless_copy_files_to_backup
BACKUPPATH="/backup"
file_count=None
for i in range (LOGSIZE-1, 0,-1):
lcd.blit(defaultFont.render(log[i], False, BLACK),(0, 300-(i*12)))
log[i]=log[i-1]
lcd.blit(defaultFont.render(log[i], False, WHITE),(0, 300-(i*12)))
lcd.blit(defaultFont.render(log[0], False, BLACK),(0, 300))
log[0]=str
lcd.blit(defaultFont.render(log[0], False, WHITE),(0, 300))
def get_file_count():
f=open("file_count","r")
global file_count refresh()
file_count=f.readline()
return file_count
...@@ -66,39 +66,65 @@ def refresh(): ...@@ -66,39 +66,65 @@ def refresh():
time.sleep(0.1) time.sleep(0.1)
def button(lcd,msg,x,y,w,h,ic,ac,mouse,action=None,action_param=None): def button(lcd,msg,x,y,w,h,ic,ac,mouse,action=None,next_layout=None):
if x+w > mouse[0] > x and y+h > mouse[1] > y: if x+w > mouse[0] > x and y+h > mouse[1] > y:
pygame.draw.rect(lcd, ac,(x,y,w,h)) pygame.draw.rect(lcd, ac,(x,y,w,h))
#print("clicked "+msg) lcd.fill(BLACK)
refresh()
if action != None: if action != None:
print("clicked "+msg) print("clicked "+msg)
#filename=BACKUPPATH+"/CP_"+get_file_count()
#print (filename)
#if os.path.isdir(filename):
# print ("directroy exist "+filename+" exiting..")
# return
#elif os.path.exists(filename):
# msg ("file exist "+filename+" exiting..")
# return
action() action()
global layout
layout=next_layout
layout(lcd,mouse)
return 0
else: else:
pygame.draw.rect(lcd, ic,(x,y,w,h)) pygame.draw.rect(lcd, ic,(x,y,w,h),1)
text = pygame.font.SysFont("comicsansms",25)
textSurf, textRect = text_objects(msg, text)
textRect.center = ( (x+(w/2)), (y+(h/2)) )
lcd.blit(textSurf, textRect)
return 1
def main_layout(lcd,mouse):
button(lcd,"Copy Fusion to BACKUP",5,45,230,50,WHITE,WHITE,mouse,wireless_copy_files_to_backup.run,log_layout) and \
button(lcd,"Copy Fusion to NFS",5,100,230,50,WHITE,WHITE,mouse,wireless_copy_files_to_nfs.run,log_layout) and \
button(lcd,"Network Info.",5,155,230,50,WHITE,WHITE,mouse,show_network_info,log_layout) and \
button(lcd,"Shutdown...",5,210,230,50,WHITE,WHITE,mouse,None,dialog_shutdown_layout) and \
button(lcd,"Reboot...",240,210,230,50,WHITE,WHITE,mouse,None,dialog_reboot_layout)
def dialog_shutdown_layout(lcd,mouse):
lcd.blit(defaultFont.render("Shutdown?", False, WHITE),(190, 70))
button(lcd,"Yes",65,145,140,50,WHITE,WHITE,mouse,shutdown,main_layout) and \
button(lcd,"No",265,145,140,50,WHITE,WHITE,mouse,None,main_layout)
def dialog_reboot_layout(lcd,mouse):
lcd.blit(defaultFont.render("Reboot?", False, WHITE),(190, 70))
button(lcd,"Yes",65,145,140,50,WHITE,WHITE,mouse,reboot,main_layout) and \
button(lcd,"No",265,145,140,50,WHITE,WHITE,mouse,None,main_layout)
def reboot():
os.system('shutdown -r')
exit()
def shutdown():
os.system('shutdown -P')
exit()
def show_network_info():
write_log("SSID: WAPPI")
write_log(netifaces.ifaddresses('wlan0')[netifaces.AF_INET][0]['addr'])
def log_layout(lcd,mouse):
lcd.blit(defaultFont.render("Log:", False, WHITE),(0, 0))
button(lcd,"Done",340,0,100,50,WHITE,WHITE,mouse,None,main_layout)
text = pygame.font.SysFont("comicsansms",25)
textSurf, textRect = text_objects(msg, text)
textRect.center = ( (x+(w/2)), (y+(h/2)) )
lcd.blit(textSurf, textRect)
def button_layout(lcd,mouse):
button(lcd,"Copy Fusion to BACKUP",5,45,200,30,GREEN,BLUE,mouse,wireless_copy_files_to_backup.run,"test.out")
button(lcd,"Copy Fusion to NFS",5,100,200,30,GREEN,BLUE,mouse)
button(lcd,"Clear",340,0,100,30,GREEN,BLUE,mouse)
def open_log(filename): def open_log(filename):
print ("here")
file_ptr=open(filename,"r") file_ptr=open(filename,"r")
while True: while True:
line=file_ptr.readline() line=file_ptr.readline()
...@@ -117,14 +143,36 @@ def read_log(file_ptr): ...@@ -117,14 +143,36 @@ def read_log(file_ptr):
#------------------------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------------------------
import signal
def handler(signum, frame):
pass
try:
signal.signal(signal.SIGHUP, handler)
except AttributeError:
# Windows compatibility
pass
LOGSIZE=25
log = [""]*LOGSIZE
import wireless_copy_files_to_backup
import wireless_copy_files_to_nfs
# Very important: the exact pixel size of the TFT screen must be known so we can build graphics at this exact format # Very important: the exact pixel size of the TFT screen must be known so we can build graphics at this exact format
surfaceSize = (480,320) surfaceSize = (480,320)
# Note that we don't instantiate any display! # Note that we don't instantiate any display!
pygame.init() pygame.init()
# The pygame surface we are going to draw onto.
# /!\ It must be the exact same size of the target display /!\
lcd = pygame.Surface(surfaceSize) lcd = pygame.Surface(surfaceSize)
...@@ -155,12 +203,12 @@ BLUE = (0,0,255) ...@@ -155,12 +203,12 @@ BLUE = (0,0,255)
lcd.fill(BLACK) lcd.fill(BLACK)
lcd.blit(defaultFont.render("Log:", False, WHITE),(244, 0)) #lcd.blit(defaultFont.render("Log:", False, WHITE),(244, 0))
pygame.draw.line(lcd,WHITE,(240,0),(240,480),1) #pygame.draw.line(lcd,WHITE,(240,0),(240,480),1)
lcd.blit(defaultFont.render("Log:/naaa/nbbb", False, WHITE),(244, 420)) lcd.blit(defaultFont.render("Log:", False, WHITE),(244, 420))
font_big = pygame.font.Font(None, 50) font_big = pygame.font.Font(None, 50)
...@@ -178,8 +226,12 @@ print(touch) ...@@ -178,8 +226,12 @@ print(touch)
# Even more info for curious people # Even more info for curious people
# print(touch.capabilities()) # print(touch.capabilities())
layout=main_layout
layout(lcd,(0,0))
button_layout(lcd,(0,0)) wireless_copy_files_to_backup.set_log_method(write_log)
wireless_copy_files_to_nfs.set_log_method(write_log)
refresh() refresh()
...@@ -187,17 +239,6 @@ X=0 ...@@ -187,17 +239,6 @@ X=0
Y=0 Y=0
#process,file_ptr=open_log("test.out")
#print(read_log(process,file_ptr))
#print(read_log(process,file_ptr))
#print(read_log(process,file_ptr))
#print(read_log(process,file_ptr))
#print(read_log(process,file_ptr))
#print(read_log(process,file_ptr))
#print(read_log(process,file_ptr))
#exit()
#newpid=os.fork() #newpid=os.fork()
# This loop allows us to write red dots on the screen where we touch it # This loop allows us to write red dots on the screen where we touch it
while True: while True:
...@@ -212,6 +253,7 @@ while True: ...@@ -212,6 +253,7 @@ while True:
# TODO get the right ecodes instead of int # TODO get the right ecodes instead of int
r,w,x = select.select([touch], [], []) r,w,x = select.select([touch], [], [])
#write_log(str(X))
for event in touch.read(): for event in touch.read():
...@@ -228,9 +270,9 @@ while True: ...@@ -228,9 +270,9 @@ while True:
if event.type == evdev.ecodes.EV_KEY: if event.type == evdev.ecodes.EV_KEY:
if event.code == 330 and event.value == 0: if event.code == 330 and event.value == 0:
p = getPixelsFromCoordinates((X, Y)) p = getPixelsFromCoordinates((X, Y))
button_layout(lcd,p) layout(lcd,p)
#print("TFT: {0}:{1} | Pixels: {2}:{3}".format(X, Y, p [0], p [1])) #print("TFT: {0}:{1} | Pixels: {2}:{3}".format(X, Y, p [0], p [1]))
pygame.draw.circle(lcd, RED, p , 2, 2) #pygame.draw.circle(lcd, RED, p , 2, 2)
refresh() refresh()
exit() exit()
......
#vi /lib/systemd/system/gui.service
[Unit]
Description=Gui Service
After=multi-user.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /root/gopro/python/gui.py
[Install]
WantedBy=multi-user.target
#end vi
chmod 644 /lib/systemd/system/gui.service
systemctl daemon-reload
systemctl enable gui.service
...@@ -11,19 +11,44 @@ import time ...@@ -11,19 +11,44 @@ import time
import netifaces import netifaces
BACKUPPATH="/backup" BACKUPPATH="/backup"
log_ptr=None method_ptr=None
def set_log_method(method):
global method_ptr
method_ptr=method
print("wireless_copy_giles_to_backup.set_log_method()")
def msg(str): def msg(str):
global log_ptr global method_ptr
if log_ptr!=None: if method_ptr!=None:
log_ptr=str method_ptr(str)
else: else:
print(str) print(str)
def camera_info(cam_ptr):
msg("current mode: " + "" + cam_ptr.parse_value("mode", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.Mode)))
msg("current submode: " + "" + cam_ptr.parse_value("sub_mode", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.SubMode)))
msg("current video resolution: " + "" + cam_ptr.parse_value("video_res", cam_ptr.getStatus(constants.Status.Settings, constants.Video.RESOLUTION)))
msg("current video framerate: " + "" + cam_ptr.parse_value("video_fr", cam_ptr.getStatus(constants.Status.Settings, constants.Video.FRAME_RATE)))
msg("pictures taken: " + "" + str(cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.PhotosTaken)))
msg("videos taken: " + "" + str(cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.VideosTaken)))
msg("videos left: " + "" + cam_ptr.parse_value("video_left", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.RemVideoTime)))
msg("pictures left: " + "" + str(cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.RemPhotos)))
msg("battery left: " + "" + cam_ptr.parse_value("battery", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.BatteryLevel)))
msg("space left in sd card: " + "" + cam_ptr.parse_value("rem_space", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.RemainingSpace)))
msg("camera SSID: " + "" + str(cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.CamName)))
msg("Is Recording: " + "" + cam_ptr.parse_value("recording", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.IsRecording)))
msg("Clients connected: " + "" + str(cam_ptr.getStatus( constants.Status.Status, constants.Status.STATUS.IsConnected)))
msg("camera model: " + "" + cam_ptr.infoCamera(constants.Camera.Name))
msg("firmware version: " + "" + cam_ptr.infoCamera(constants.Camera.Firmware))
msg("serial number: " + "" + cam_ptr.infoCamera(constants.Camera.SerialNumber))
def run(folder_dst=None,ptr=None): def run(folder_dst=None,ptr=None):
global BACKUPPATH #global BACKUPPATH
if (ptr): if (ptr):
log_ptr=ptr log_ptr=ptr
...@@ -47,14 +72,14 @@ def run(folder_dst=None,ptr=None): ...@@ -47,14 +72,14 @@ def run(folder_dst=None,ptr=None):
msg ("file exist "+folder_dst+" exiting..") msg ("file exist "+folder_dst+" exiting..")
return return
print ("mkdir "+folder_dst) msg ("mkdir "+folder_dst)
#os.system("mkdir "+folder_dst) #os.system("mkdir "+folder_dst)
#if not os.path.exists(folder_dst): #if not os.path.exists(folder_dst):
os.makedirs(folder_dst); os.makedirs(folder_dst);
msg("Checking wlan1...") msg("Checking wlan1...")
try: try:
print(netifaces.ifaddresses('wlan1')[netifaces.AF_INET][0]['addr']) msg(netifaces.ifaddresses('wlan1')[netifaces.AF_INET][0]['addr'])
except: except:
msg ("wlan1 not connected to Gopro SSID. exiting...") msg ("wlan1 not connected to Gopro SSID. exiting...")
return return
...@@ -70,11 +95,16 @@ def run(folder_dst=None,ptr=None): ...@@ -70,11 +95,16 @@ def run(folder_dst=None,ptr=None):
localtime = time.asctime( time.localtime(time.time()) ) localtime = time.asctime( time.localtime(time.time()) )
start_time = time.time() start_time = time.time()
msg ("Start time :" +str(localtime)) msg("Start time :" +str(localtime))
gpCam.overview() camera_info(gpCam)
#for i in range(len(output)):
# msg(output[i])
#msg(gpCam.getMedia()) #msg(gpCam.getMedia())
#msg(gpCam.getMediaInfo("file")) #msg(gpCam.getMediaInfo("file"))
gpCam.listMedia(True) output=gpCam.listMedia(True,True)
for i in range (len(output)):
msg(str(output[i]))
#exit() #exit()
data=gpCam.listMedia(True,True) data=gpCam.listMedia(True,True)
...@@ -117,7 +147,7 @@ def run(folder_dst=None,ptr=None): ...@@ -117,7 +147,7 @@ def run(folder_dst=None,ptr=None):
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) < 2: if len(sys.argv) < 2:
msg ("Usage cp_fusion_files.py <destination directory> ") msg ("Usage wireless_copy_files_to_nfs.py <destination directory> ")
exit() exit()
run(sys.argv[1]) run(sys.argv[1])
......
...@@ -10,89 +10,153 @@ import re ...@@ -10,89 +10,153 @@ import re
import time import time
if len(sys.argv) < 2: NFSPATH="/nfs/ANGELICA/videos/"
print ("Usage cp_fusion_files.py <destination directory> ") method_ptr=None
exit()
def set_log_method(method):
global method_ptr
method_ptr=method
print("wireless_copy_giles_to_backup.set_log_method()")
def msg(str):
global method_ptr
if method_ptr!=None:
method_ptr(str)
else:
print(str)
def camera_info(cam_ptr):
msg("current mode: " + "" + cam_ptr.parse_value("mode", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.Mode)))
msg("current submode: " + "" + cam_ptr.parse_value("sub_mode", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.SubMode)))
msg("current video resolution: " + "" + cam_ptr.parse_value("video_res", cam_ptr.getStatus(constants.Status.Settings, constants.Video.RESOLUTION)))
msg("current video framerate: " + "" + cam_ptr.parse_value("video_fr", cam_ptr.getStatus(constants.Status.Settings, constants.Video.FRAME_RATE)))
msg("pictures taken: " + "" + str(cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.PhotosTaken)))
msg("videos taken: " + "" + str(cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.VideosTaken)))
msg("videos left: " + "" + cam_ptr.parse_value("video_left", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.RemVideoTime)))
msg("pictures left: " + "" + str(cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.RemPhotos)))
msg("battery left: " + "" + cam_ptr.parse_value("battery", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.BatteryLevel)))
msg("space left in sd card: " + "" + cam_ptr.parse_value("rem_space", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.RemainingSpace)))
msg("camera SSID: " + "" + str(cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.CamName)))
msg("Is Recording: " + "" + cam_ptr.parse_value("recording", cam_ptr.getStatus(constants.Status.Status, constants.Status.STATUS.IsRecording)))
msg("Clients connected: " + "" + str(cam_ptr.getStatus( constants.Status.Status, constants.Status.STATUS.IsConnected)))
msg("camera model: " + "" + cam_ptr.infoCamera(constants.Camera.Name))
msg("firmware version: " + "" + cam_ptr.infoCamera(constants.Camera.Firmware))
msg("serial number: " + "" + cam_ptr.infoCamera(constants.Camera.SerialNumber))
def run(folder_dst=None,ptr=None):
#global BACKUPPATH
if (ptr):
log_ptr=ptr
os.system("umount /nfs/ANGELICA/videos")
if os.system("mount 192.168.0.2:/mnt/user/videos /nfs/ANGELICA/videos") != 0:
msg ("fail to mount 192.168.0.2:/mnt/user/videos... exiting..")
return
msg("192.168.0.2:/mnt/user/videos mounted...")
if folder_dst==None:
msg ("Generating generic folder...")
for i in range (0,1000):
folder_dst=NFSPATH+"/CP_"+str(i)
#if not(os.path.isdir(BACKUPPATH+"/CP_"+str(i))) or not(os.path.exists(BACKUPPATH+"/CP_"+str(i))):
if not(os.path.isdir(folder_dst)) or not(os.path.exists(folder_dst)):
break
if i==1000:
msg ("Can not generate CP_[0:1000]")
return
else:
msg ("Done")
elif os.path.isdir(folder_dst):
msg ("directroy exist "+folder_dst+" exiting..")
return
elif os.path.exists(folder_dst):
msg ("file exist "+folder_dst+" exiting..")
return
file_path = "/nfs/ANGELICA/videos/"+sys.argv[1]
os.system("umount /nfs/ANGELICA/videos")
if os.system("mount 192.168.0.2:/mnt/user/videos /nfs/ANGELICA/videos") != 0:
print ("fail to mount 192.168.0.2:/mnt/user/videos... exiting..")
exit()
print ("192.168.0.2:/mnt/user/videos mounted...")
if os.path.isdir(file_path):
print ("directroy exist "+file_path+" exiting..")
exit()
elif os.path.exists(file_path):
print ("file exist "+file_path+" exiting..")
exit()
os.system("mkdir "+file_path)
print ("mkdir "+file_path)
if os.system("ifconfig wlan1 | grep inet") == "":
print ("wlan1 not connected to Gopro SSID. exiting...") os.system("mkdir "+folder_dst)
exit() msg ("mkdir "+folder_dst)
gpCam = GoProCamera.GoPro() msg("Checking wlan1...")
gpCam.pair(usepin=False) try:
#gpCam.pair(usepin=True) print(netifaces.ifaddresses('wlan1')[netifaces.AF_INET][0]['addr'])
except:
msg ("wlan1 not connected to Gopro SSID. exiting...")
return
gpCam = GoProCamera.GoPro()
gpCam.pair(usepin=False)
#gpCam.pair(usepin=True)
print ("Start...")
localtime = time.asctime( time.localtime(time.time()) )
start_time = time.time()
print ("Start time :", localtime)
camera_info(gpCam)
data=gpCam.listMedia(True,True)
for i in range (len(data)):
msg(str(data[i]))
#data=gpCam.listMedia(True,True)
for i in data:
folder=i[0]
if not os.path.exists(file_path+"/"+folder):
os.makedirs(file_path+"/"+folder);
mp4_file=i[1]
lrv_file=re.sub(".MP4",".LRV",mp4_file)
msg("copy "+folder+"/"+mp4_file+" to "+file_path);
gpCam.downloadMedia(folder,mp4_file,file_path+"/"+folder+"/"+mp4_file)
msg("copy "+folder+"/"+lrv_file+" to "+file_path);
gpCam.downloadMedia(folder,lrv_file,file_path+"/"+folder+"/"+lrv_file)
if re.search("GPBK",mp4_file) or re.search("GB",mp4_file):
wav_file=re.sub(".MP4",".WAV",mp4_file)
#msg("copy "+folder+"/"+wav_file+" to "+file_path);
gpCam.downloadMedia(folder,wav_file,file_path+"/"+folder+"/"+wav_file)
if re.search("GPBK",mp4_file):
thm_file=re.sub(".MP4",".THM",mp4_file)
#msg("copy "+folder+"/"+thm_file+" to "+file_path);
gpCam.downloadMedia(folder,thm_file,file_path+"/"+folder+"/"+thm_file)
if re.search("GPFR",mp4_file):
thm_file=re.sub(".MP4",".THM",mp4_file)
#msg("copy "+folder+"/"+thm_file+" to "+file_path);
gpCam.downloadMedia(folder,thm_file,file_path+"/"+folder+"/"+thm_file)
msg ("Done")
os.system("umount /nfs/ANGELICA/videos")
localtime = time.asctime( time.localtime(time.time()) )
elapsed_time = time.time() - start_time
msg ("End time :", localtime)
hours, rem = divmod(elapsed_time, 3600)
minutes, seconds = divmod(rem, 60)
msg("Elaspse time: "+"{:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds))
print ("Start...")
localtime = time.asctime( time.localtime(time.time()) ) if __name__ == '__main__':
start_time = time.time() if len(sys.argv) < 2:
print ("Start time :", localtime) msg ("Usage wireless_copy_files_to_nfs.py <destination directory> ")
gpCam.overview() exit()
#print(gpCam.getMedia())
#print(gpCam.getMediaInfo("file"))
gpCam.listMedia(True)
data=gpCam.listMedia(True,True) run(sys.argv[1])
for i in data:
folder=i[0]
if not os.path.exists(file_path+"/"+folder):
os.makedirs(file_path+"/"+folder);
mp4_file=i[1]
lrv_file=re.sub(".MP4",".LRV",mp4_file)
print("copy "+folder+"/"+mp4_file+" to "+file_path);
gpCam.downloadMedia(folder,mp4_file,file_path+"/"+folder+"/"+mp4_file)
print("copy "+folder+"/"+lrv_file+" to "+file_path);
gpCam.downloadMedia(folder,lrv_file,file_path+"/"+folder+"/"+lrv_file)
if re.search("GPBK",mp4_file) or re.search("GB",mp4_file):
wav_file=re.sub(".MP4",".WAV",mp4_file)
#print("copy "+folder+"/"+wav_file+" to "+file_path);
gpCam.downloadMedia(folder,wav_file,file_path+"/"+folder+"/"+wav_file)
if re.search("GPBK",mp4_file):
thm_file=re.sub(".MP4",".THM",mp4_file)
#print("copy "+folder+"/"+thm_file+" to "+file_path);
gpCam.downloadMedia(folder,thm_file,file_path+"/"+folder+"/"+thm_file)
if re.search("GPFR",mp4_file):
thm_file=re.sub(".MP4",".THM",mp4_file)
#print("copy "+folder+"/"+thm_file+" to "+file_path);
gpCam.downloadMedia(folder,thm_file,file_path+"/"+folder+"/"+thm_file)
print ("Done")
os.system("umount /nfs/ANGELICA/videos")
localtime = time.asctime( time.localtime(time.time()) )
elapsed_time = time.time() - start_time
print ("End time :", localtime)
hours, rem = divmod(elapsed_time, 3600)
minutes, seconds = divmod(rem, 60)
print("Elaspse time: "+"{:0>2}:{:0>2}:{:05.2f}".format(int(hours),int(minutes),seconds))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment