#coding: utf-8
import workflow
import ui
import console
import pickle
import re
import io
import time
import xml.parsers.expat
import sys
import os
import copy
import urlparse
import dialogs
from array import *
pathMain=os.getcwd()
pathMain=re.sub(r'Library.*','',pathMain)
pathMain+='Documents/'
pathDir=''
pathSave=pathMain+'Dictionary/'
textFile=list()
dict=list()
pageSize=100
#pageStyle='practice.html'
pageStyle='page.html'
#pageStyle='practice_read.html'
readMode=1
action_in = workflow.get_input()
#enum
READ=1 #режим чтения с переводом слогов по памяти
ALL=1
AUTO=0
EMPTY=-1
EDIT=1
LINK=0
CHINK_SIZE=1024*40
VALUE_SIZE=1024*20
MB=1024*1000
START_MARK='@_dict_/'
END_MARK='@_end_/'
EMPTY_MARK='_*_'
MARK=':|:'
JS=0
USER=1
TRANSLATE=1
DICT_REPORT_TEXT=2
DICT_REPORT_USER=3
FULL_REPORT=4
INDEX_RESIZE=4 #во сколько раз будет увеличиваться размер индекса
FILE_RESIZE=2 #во сколько раз будет увеличиваться размер файла
FILE_RESIZE_DELTA=100 #количество записей на которое увеличивается размер файла в дополнении к увеличению в FILE_RESIZE раз.(нужен при записи больших записей в небольшой файл)
POOL_SIZE=16384
MEMORY_LOCATION=0
MMAP_LOCATION=1
global Pref
Pref=list() #preferences
class GVector():
#protected
dataPath=''
#MemoryFile
dataMFile=''
#GVector *parent
#public
index=[] #массив индексов записей в GVector
innerData=array('L') #массив размещенный в начале файла, в который записываются внутренние переменные
#внутренние переменные
recordCount=0 #количество записей в векторе
recordArraySize=0 #размер файла учета записей
dataSize=0 #размер занимаемый актуальными данными
poolSize=0 #общий размер файла вектора
lockFlag=0 #флаг блокировки чтения-записи
indexOffset=0 #адрес размещения массива индекса записей. отсчитывается от начала файла
vectorID=0
dataLocation=0
def __init__(self):
pass
def openData(self,dataPath):
self.dataPath=dataPath
try:
open(dataPath, 'r')
except:
f=open(dataPath, 'w')
f.close()
c=os.stat(dataPath)
self.dataMFile=os.open(dataPath,os.O_RDWR)
self.poolSize=c.st_size
print 'poolSize={:,}'.format(self.poolSize)
self.init()
def init(self):
self.dataLocation=MMAP_LOCATION #флаг размещения данных в оперативной или отображаемой памяти
#cout<<" dataMFile->size()={}".format(dataMFile->size()
#проверяем является ли файл файлом GVector
if(self.poolSize<POOL_SIZE): #новый файл GVector
print 'new vector'
for i in range(16): self.innerData.append(0)
self.innerData[0]=0xfffffffa #маркер наличия GVector
self.recordArraySize=1024
self.recordCount=0
self.dataSize=(self.recordArraySize)*4+64
self.indexOffset=64
self.vectorID=0xffffffff
self.lockFlag=0
indexName="name:|:data"
#index=(uint*)(data+*indexOffset) #инициализация индекса
self.push_back(indexName) #инициализация индекса именных записей
self.recordCount=1
self.setSpace(POOL_SIZE)
self.saveData()
else:
#проверяем является ли файл файлом GVector
self.readData()
if(self.innerData[0]!=0xfffffffa):
print "no valid GVector file "+ self.dataPath
return
def saveData(self):
self.innerData[1]=self.poolSize #размер файла вектора
self.innerData[2]=self.recordCount #количество записей в векторе
self.innerData[3]=self.recordArraySize #размер файла учета записей
self.innerData[4]=self.dataSize #размер занимаемый актуальными данными
self.innerData[5]=self.lockFlag #флаг блокировки чтения-записи
self.innerData[6]=self.indexOffset #адрес размещения массива индекса записей. отсчитывается от начала файла
self.innerData[7]=self.vectorID #индех записи, в которой GVector размещен в родительском векторе
str=array.tostring(self.innerData)
os.lseek(self.dataMFile,0,os.SEEK_SET)
os.write(self.dataMFile,str)
def readData(self):
os.lseek(self.dataMFile,0,os.SEEK_SET)
str=os.read(self.dataMFile,64)
self.innerData=array('L')
self.innerData.fromstring(str)
#print self.innerData
self.poolSize=self.innerData[1] #размер файла вектора
self.recordCount=self.innerData[2] #количество записей в векторе
self.recordArraySize=self.innerData[3] #размер файла учета записей
self.dataSize=self.innerData[4] #размер занимаемый актуальными данными
self.lockFlag=self.innerData[5] #флаг блокировки чтения-записи
self.indexOffset=self.innerData[6] #адрес размещения массива индекса записей. отсчитывается от начала файла
self.vectorID=self.innerData[7] #индех записи, в которой GVector размещен в родительском векторе
def mPut(self,offset,str):
os.lseek(self.dataMFile,offset,os.SEEK_SET)
os.write(self.dataMFile,str)
def mPutInt(self,offset,value):
t=array('L')
t.append(value)
str=t.tostring()
os.lseek(self.dataMFile,offset,os.SEEK_SET)
os.write(self.dataMFile,str)
def mGet(self,offset,size):
os.lseek(self.dataMFile,offset,os.SEEK_SET)
return os.read(self.dataMFile,size)
def mGetInt(self,offset):
#print 'of {}'.format(offset)
t=array('L')
os.lseek(self.dataMFile,offset,os.SEEK_SET)
str=os.read(self.dataMFile,4)
t.fromstring(str)
return t[0]
def setSpace(self,space):
if(self.vectorID==0xffffffff):
if(self.dataLocation==MEMORY_LOCATION):
print 1
else:
os.ftruncate(self.dataMFile,space)
self.poolSize=space
else:
print 3
def close(self):
self.saveData()
os.close(self.dataMFile)
#добавление новой записи в GVector
def push_back(self,str):
size=len(str)
#проверяем достаточно ли места в массиве индекса
if(self.recordArraySize<self.recordCount+1):
self.recordArraySize=self.recordCount+1
print "resize GVector index recordArraySize={:,} recordCount={} self.poolSize={:,}".format(self.recordArraySize,self.recordCount,self.poolSize)
#увеличиваем массив индекса и записываем его как новую запись
#проверяем достаточно ли места в пуле
if(self.recordArraySize*INDEX_RESIZE+self.dataSize>self.poolSize):
newSize=self.poolSize+(self.recordArraySize+1)*INDEX_RESIZE
print 'start resize pool for index. New size={:,}'.format(newSize)
#print "vectorID_={}".format(self.vectorID
self.setSpace(newSize)
#копируем индех
s=self.mGet(self.indexOffset,(self.recordArraySize-1)*4)
self.mPut(self.dataSize,s)
self.recordArraySize=self.recordArraySize*INDEX_RESIZE
self.indexOffset=self.dataSize
self.dataSize+=self.recordArraySize*4
#cout<<" poolSize1={}".format(self.poolSize<<" dataSize={}".format(self.dataSize
#проверяем достаточно ли места в пуле для новой записи
if(self.dataSize+size+256>self.poolSize):
newSize=(self.poolSize)*FILE_RESIZE+size*FILE_RESIZE_DELTA
if(newSize<self.dataSize+size+256):
newSize=int((self.dataSize+size+256)*1.5)
print "@resize GVector file new poolSize={:,} bytes c3".format(newSize)
self.setSpace(newSize)
#записываем данныe
self.mPutInt(self.dataSize,size) #записываем длинну записи
self.mPut(self.dataSize+4,str) #копируем запись
#записываем адрес записи в индекс
self.mPutInt(self.indexOffset+self.recordCount*4,self.dataSize)
self.recordCount=self.recordCount+1
self.dataSize=self.dataSize+size+4
self.saveData()
#print "new data"
#print "innerData={}".format(self.innerData)
#print "poolSize={}".format(self.poolSize)
#print "recordCount={}".format(self.recordCount)
#print "recordArraySize={}".format(self.recordArraySize)
#print "dataSize={}".format(self.dataSize)
#print "indexOffset={}".format(self.indexOffset)
def resize(self,size,recordSize):
size+=1 #плюс именная запись
if(size>self.recordCount):
if(size>self.recordArraySize):
self.recordArraySize=size
if(self.recordArraySize+self.dataSize>self.poolSize):
newSize=self.poolSize+(self.recordArraySize+1)*INDEX_RESIZE
self.setSpace(newSize)
#копируем индех
str=self.mGet(self.indexOffset,(self.recordArraySize-1)*4)
self.mPut(self.dataSize,str)
self.recordArraySize=self.recordArraySize*INDEX_RESIZE
self.indexOffset=self.dataSize
self.dataSize+=self.recordArraySize*4
newSize=size*(recordSize+4)+self.recordArraySize*4+64
if(newSize>self.poolSize):
self.setSpace(newSize)
#инициализируем индекс записи
for i in range(self.recordCount,size):
self.mPutInt(self.indexOffset+i*4,0)
self.recordCount=size
def putStr(self,indexRecord,str):
indexRecord+=1 #пропускаем индекс именных записей
offset=self.mGetInt(self.indexOffset+indexRecord*4)
#print 'offset {}'.format(offset)
if(offset==0): #запись еще не инициализирована
size=0
else:
size=self.mGetInt(offset)
if(len(str)>size):
size=len(str)
#указаваем что место записи свободно,записываем запись на новое место и обновляем индех
if(offset>0):
self.mPutInt(offset,0)
#проверяем достаточно ли места в пуле для новой записи
if(self.dataSize+size+256>self.poolSize):
newSize=(self.poolSize)*FILE_RESIZE+size*FILE_RESIZE_DELTA
print "@resize GVector file new poolSize={:,} bytes c1".format(newSize)
self.setSpace(newSize)
#записываем данныe
self.mPutInt(self.dataSize,size) #записываем длинну записи
self.mPut(self.dataSize+4,str) #копируем запись
#записываем адрес записи в индекс
self.mPutInt(self.indexOffset+indexRecord*4,self.dataSize)
self.dataSize=self.dataSize+size+4
else:
#записываем данныe
size=len(str)
self.mPutInt(offset,size) #записываем длинну записи
self.mPut(offset+4,str) #копируем запись
self.saveData()
def getStr(self,indexRecord):
indexRecord+=1 #пропускаем индекс именных записей
if(indexRecord>=self.recordCount):
return EMPTY
offset=self.mGetInt(self.indexOffset+indexRecord*4)
#print ' offset {}'.format(offset)
size=self.mGetInt(offset)
#print ' size {}'.format(size)
if(size+offset+4>self.dataSize):
print 'index={} offset={} size={} recordCount={}'.format(indexRecord,offset,size,self.recordCount)
print "size out of range"
return EMPTY
return self.mGet(offset+4,size)
def checkIndex(self,limit):
print 'check index'
for i in range(limit):
t=self.mGetInt(self.indexOffset+i*4)
print t
d=self.mGetInt(t)
print ' d={}'.format(d)
def printStr(self,str):
t=memoryview(str)
g=t.tolist()
g=g[:25]
print g
'''
pData=pathSave+"XML_DICT/_GVectorTest.txt"
#os.unlink(pData)
v=GVector()
v.openData(pData)
print 'start'
st=v.getStr(996)
print st
#v.checkIndex(10)
sys.exit()
for i in range(1000):
#print i
#s='1234567890 wwwwwwwwwwwwwwwwwwwwwwwwwwwww 1234567890 www {}'.format(i)
#v.push_back(s)
s='1234567890 www {}'.format(i)
v.putStr(i,s)
st=v.getStr(i)
if(st!=s):
print 'no data'
print i
print 'retutn str='
v.printStr(st)
print st
break
print 'done'
sys.exit()
'''
class dictBase ():
keyTib=''
keyList=list()
data=list()
history=list()
vData=GVector()
pImdex='' #path to index file
dictKey={}
dictSize=0
fileSize=0
step=0
flagSave=0
emptyStr=''
emptyRec=EMPTY #dict of empty record index
res=''
insert=0
value=''
editMode=LINK
mainMode=TRANSLATE
id=1
def __init__(self):
pass
def openData(self,vData,pIndex):
self.vData=vData
self.pIndex=pIndex
#t1=time.time()
try:
open(pIndex, 'r')
except:
f=open(pIndex, 'w')
f.close()
f=open(pIndex, 'r')
self.keyList=f.readlines()
f.close()
i=0
for line in self.keyList:
self.dictKey[line]=i
i+=1
#t2=time.time()
#print 'time={}'.format(t2-t1)
self.emptyStr=''.zfill(CHINK_SIZE)
self.data.append('')
self.data.append('')
self.data.append('')
def close(self):
self.vData.close()
if(self.flagSave==1):
f=open(pIndex, 'w')
f.writelines(self.keyList)
f.close()
def has_key(self,key):
if(key in self.dictKey):
str=self.dictKey[key]
c=int(str)
return c
else:
return -1
def get(self,key):
self.res=''
if(len(self.keyList)==0):
print 'no data'
return self.res
i=self.has_key(key+'\n')
#print i
if(i>EMPTY):
self.res=self.vData.getStr(i)
return self.res
return self.res
def put(self,key,value):
if(self.step>1000): #progress
self.step=0
print '{} {}'.format(self.insert,len(self.keyList))
self.step+=1
self.insert+=1
i=self.has_key(key+'\n')
#print 'has key={}'.format(i)
if(i==EMPTY):
self.flagSave=1
self.dictKey[key+'\n']=len(self.keyList)
self.keyList.append(key+'\n')
self.vData.push_back(value)
else:
self.vData.putStr(i,value)
def add(self,key,value):
self.get(key)
str=self.res
if(len(str)):
str=str+END_MARK+value
else:
str=key+':|:'+value
self.put(key,str)
def push(self,key,value):
self.get(key)
str=self.res
if(len(str)):
str=value+END_MARK+str
else:
str=key+':|:'+value
self.put(key,str)
def rep(self,key,value,dName):
'''
self.get(key)
str=self.res
if(len(str)):
c=str.split(END_MARK)
str=''
for line in c:
if(dName in line):
continue
str+=line+END_MARK
str+=value
else:
str=key+':|:'+value
self.put(key,str)
'''
def saveInd(self):
with open(pIndex, 'w') as f:
f.writelines(self.keyList)
#print 'done save'
self.insert=0
self.step=0
def rem(self,key):
key_n=key+'\n'
if(key_n in self.dictKey):
self.put(key,EMPTY_MARK)
def clear(self):
f=open(pIndex, 'w')
f.close()
self.vData.resize(0,128)
self.vData.saveData()
self.keyList=list()
self.dictKey={}
def normalisation(self):
step=0
for i in range(1,len(self.keyList)):
if(step>=1000):
print i
step=0
step+=1
str=self.vData.getStr(i)
lines=str.split(MARK)
if(len(lines)<4):
continue
if(len(str)):
str=re.sub(r'^[^:]*:\|:', '',str)
if(len(str)<10):
print 'no data in str'
print i
#print str
else:
self.vData.putStr(i,str)
else:
print 'no data'
print i
def formatReport(self):
str=self.res
lines=str.split(END_MARK)
str=''
for line in lines:
line=line.replace(MARK,'<br>')
line=re.sub(r'\[c:[^\]]*\]',r'',line)
line=re.sub(r'^([^\<]*)<br>\1',r'\1',line)
#print line
#print '_____________'
if('<br>TT' in line or '<br>DK' in line):
#print line
line=line.replace('༡','@1')
line=line.replace('༢','@2')
line=line.replace('༣','@3')
line=line.replace('༤','@4')
line=line.replace('༥','@5')
line=line.replace('༦','@6')
line=line.replace('༧','@7')
line=line.replace('༨','@8')
line=line.replace('༩','@9')
line=line.replace('༠','@0')
line=re.sub(r'@([\d])@([\d])',r'@\1\2',line)
line=re.sub(r'@([\d])@([\d])',r'@\1\2',line)
line=line.replace('@','\n')
line=line.replace(' ','་྾་')
line=line.replace('།་','།')
line=line.replace('།','།\n')
line=line.replace('༼','\n༽')
line=line.replace('༽','༽\n')
line=line.replace('<br>TT','')
line=line.replace('<br>DK','')
self.data[0]=line
dictReport()
line=self.data[0]
line=line.replace('྾་',' ')
line=line.replace('྾','<br>')
line=line.replace('<c><br>','<c>')
line=line.replace('<br>།</c>','།</c>')
line+='TT'
else:
id='{}'.format(dt.id)
line='<t id="l'+id+'" onClick="edit(\'l'+id+'\')">'+line+'</t>'
dt.id+=1
str+=line+'<hr>'
self.res=str
def loadTXT(self,name,mode):
print 'load {} mode {}'.format(name,mode)
with open(pathSave+'XML_DICT/'+name+'.txt') as f:
str=f.read()
f.close()
str=str.replace('\r','\n')
d=str.split('\n')
print len(d)
if(len(name)>5):
name='YP'
i=0
m=0
if(mode=='put'):
m=1
if(mode=='roots'):
m=3
for line in d:
#print len(line)
#print line
line=line.replace(':|:YP','')
line=line.replace(' @ ','\t')
c=line.split('\t')
if (m == 3):
cd=c[0].split('་')
if len(cd) ==2:
self.get(c[0])
if self.res!='':
continue
else:
continue;
i+=1
if(len(c)>1 and len(c[0])<1048):
str=c[1]+MARK+name
if m==1 or m==3:
self.put(c[0],str)
else:
self.add(c[0],str)
#self.rep(c[0],str,':|:'+name)
else:
if(len(line)>0):
print 'no valid record '+line
print i
def export(self,path):
searchText.text='{}'.format(len(self.keyList))
with open(path,'w') as f:
res=list()
step=0
i=0
for line in self.keyList:
if(step==1000):
step=0
searchText.text='{}'.format(i)
i+=1
step+=1
key=line[0:len(line)-1]
#print key
s=self.get(key)
#print str
res.append(key+' @ '+str(s)+'\n')
f.writelines(res)
print 'done export'
# 3 handler functions
def start_element(name, attrs):
if(name=='key'):
if(attrs['ln']=='tb'):
dt.keyTib='{}'.format(attrs['key'])
else:
n=Pref[4]
#str=attrs['key']+':|:'+attrs['ln']+':|:TD'
dt.value+=attrs['key']+MARK+n+END_MARK
if(name=='rec'):
dt.value=''
#print 'Start element:', name, attrs
def end_element(name):
if(name=='rec'):
n=Pref[4]
if(len(dt.keyTib)>1 and len(dt.value)>3):
#dt.rep(dt.keyTib,dt.value,':|:'+n)
#print dt.keyTib
dt.add(dt.keyTib,dt.value)
def char_data(data):
pass
#print 'Character data:', repr(data)
def loadXML(name):
if(len(Pref)<5):
for i in range(5):
Pref.append('')
Pref[4]=name
p = xml.parsers.expat.ParserCreate()
p.StartElementHandler = start_element
p.EndElementHandler = end_element
p.CharacterDataHandler = char_data
with open(pathSave+'XML_DICT/'+name+'.xml') as f:
p.ParseFile(f)
def test(name,d_):
d_.get(name)
print d_.res
def loadDB():
print 'load DB'
#dt.clear()
'''
dt.loadTXT('MG','')
dt.saveInd()
dt.loadTXT('TD','')
dt.saveInd()
dt.loadTXT('HP','')
dt.saveInd()
dt.loadTXT('VD','')
dt.saveInd()
dt.loadTXT('GRM_','')
dt.saveInd()
dt.loadTXT('ER','')
dt.saveInd()
dt.loadTXT('IW','')
dt.saveInd()
dt.loadTXT('JW','')
dt.saveInd()
##dt.loadTXT('RB','')
#dt.saveInd()
'''
dt.loadTXT('YO','')
dt.saveInd()
dt.loadTXT('RE','')
dt.saveInd()
dt.loadTXT('MVP','')
dt.saveInd()
dt.loadTXT('MV','')
dt.saveInd()
dt.loadTXT('DR','')
dt.saveInd()
dt.loadTXT('SCD','')
dt.saveInd()
dt.loadTXT('TT','')
dt.saveInd()
dt.loadTXT('DK','')
dt.saveInd()
##dt.loadTXT('RYD','')
#dt.saveInd()
def exportAction(sender):
path=fileView['textfield2'].text
path=pathMain+path
fileView.x=1024
dk.export(path)
def selectAction(request):
if('action' in request):
action=request['action']
if (len(action)>0 and action[0]=='export'):
export()
return
def dictionary(sender):
js='readStr()'
if(mainDictView.x==0):
textAll=dictView.eval_js(js)
else:
textAll=textIn.eval_js(js)
str=htmlToText(textAll)
str+='་'
str=str.replace('་་','་')
print str
searchText.text=str
if(len(str)>1):
dictEntry()
def fullRep(sender):
str=searchText.text
if(len(str)>0):
str+='་'
str=str.replace('་་','་')
searchText.text=str
dictReport()
printHtml(dt.data[0])
dt.mainMode=FULL_REPORT
js='readText()'
textAll=textIn.eval_js(js)
#textIn.text is unicode, it is need convert it in utf-8
textAll='{}'.format(textAll)
textAll=htmlToText(textAll)
dt.data[0]=textAll
dictReport()
printHtml(dt.data[0])
#searchBtn.title='Word From Text'
dt.mainMode=DICT_REPORT_TEXT
#t2=time.time()
#printHtml(report+'\n done in {} sec'.format(t2-t1))
def translate(sender):
str=searchText.text
if(len(str)>0 and str[0]=='?'): #parse request as CGI query request
request=urlparse.parse_qs(str[1:])
selectAction(request)
return
if(len(str)>0):
str+='་'
str=str.replace('་་','་')
searchText.text=str
dictEntry()
return
dt.mainMode=TRANSLATE
js='readText()'
textAll=textIn.eval_js(js)
#textIn.text is unicode, it is need convert it in utf-8
textAll='{}'.format(textAll)
textAll=htmlToText(textAll)
dt.data[0]=textAll
dictReport()
printHtml(dt.data[0])
dt.mainMode=DICT_REPORT_TEXT
#t2=time.time()
#printHtml(report+'\n done in {} sec'.format(t2-t1))
def dictEntry():
"""report from all dictionaries in database"""
mainDictView.x=0
mainDictView.height=1024
textAll=searchText.text
textAll='{}'.format(textAll)
textAll+='་'
textAll=textAll.replace('་་','་')
dt.history.append(textAll)
dk.get(textAll)
res=''
res+='['+linkDict(textAll)+linkEdit('='+dk.res)+']་<hr>'
dt.get(textAll)
dt.formatReport()
res+=dt.res
printHTML_(res)
def dictReport():
report=''
textAll=dt.data[0]
#textAll='བ་དག་གི་འབྲས་བུའི་མཆོག་མཐར་ཐུག་པ་ནི་རང་བཞིན་རྫོགས་པ་ཆེན་པོའི་ཆོས་ཀྱི་རྣམ་གྲངས་ལས་འོད་གསལ་རྡོ་རྗེ་སྙིང་པོའི་ཐེག་པ་བླ་ན་མེད་པ་འདི་ཡིན་ཏེ་།་\n'
text=textAll.split('\n')
d=dk.dictKey
reportT=''
n=0
for n in range(0,len(text)-1):
src=text[n]
s=src
reportN=text[n+1]
rd={} #dictionary of words result
lng=len(s)
if(lng<2):
continue
if(re.search('་', reportN) == None and re.search('།', reportN) == None):
reportT=reportN
if(re.search('་', s) == None and re.search('།', s) == None):
if(re.search('[\d\[<]',src)!=None):
report+='<br><d>'+src+'</d>'
continue
s=unicode(s)
s=re.sub(u'[ _\d\ " \'\*\(\)\{\}\[\]@•#\%\&༄༅༔༴༡༢༣༤༥༦༧༨༩༠༎།༑༈༌༐༏༼༽ऀ-ॿ]',u"་",s)
s=re.sub(u'ཿ',u'ཿ་',s)
s=s+u'་།'
s=re.sub(u'་[་]+',u"་",s)
s=re.sub(u'([^་])འོ་',r"\1་(точка)་",s)
#s=re.sub(u'([^་])འམ་',r"\1་[འམ=или]་",s)
s=re.sub(u'ག་གོ་།',u"ག་(точка)་",s)
s=re.sub(u'ང་ངོ་།',u"ང་(точка)་",s)
s=re.sub(u'ད་དོ་།',u"ད་(точка)་",s)
s=re.sub(u'ན་ནོ་།',u"ན་(точка)་",s)
s=re.sub(u'བ་བོ་།',u"བ་(точка)་",s)
s=re.sub(u'མ་མོ་།',u"མ་(точка)་",s)
s=re.sub(u'ར་རོ་།',u"ར་(точка)་",s)
s=re.sub(u'ལ་ལོ་།',u"ལ་(точка)་",s)
s=re.sub(u'ས་སོ་།',u"ས་(точка)་",s)
s=re.sub(u'་ཏོ་།',u"་(точка)་",s)
s=re.sub(u'་པའང་',u"་པ་[འང=уступ.]་",s)
s=re.sub(u'་བའང་',u"་བ་[འང=очень]་",s)
s='{}'.format(s)
l=s.split('་')
res=''
resD=''
lng=len(l)
start=0
end=lng-1
i=lng
count=0
#t1=time.time()
while start<lng :
#make query string decrease end
end=lng
while end>-1 :
j=start
line=''
while j < end:
line+=l[j]+'་'
j+=1
count+=1
if (count >1000):
#print line+' {} {}'.format(start,end)
break
ld=line+'\n'
if(ld in d):
dk.get(line)
#c=str(dk.res)
c=dk.res
if(EMPTY_MARK in c):
end-=1
continue
if('__' in c):
res+='['+linkDict(line)+linkEdit('='+c)+']་<br></c><c>'
end-=1
continue
res+='['+linkDict(line)+linkEdit('='+c)+']་'
if(dt.mainMode==FULL_REPORT and start==0 and end==lng-1):
end-=1
continue
start=end-1
break
#next check big dictionary report
if(len(line)>3 and ld in dt.dictKey):
resD+='['+linkDict(line)+linkEdit('=')+'] '
ln=line+'@'
l1=ln.replace('འི་@','་')
ld=l1+'\n'
if(ld in d):
dk.get(l1)
c=dk.res
if(EMPTY_MARK in c):
end-=1
continue
res+='['+linkDict(l1)+linkEdit('='+c)+']་['+linkDict('-འི་')+linkEdit('=g.p')+']་'
rd[l1]=1
start=end-1
break
#next check big dictionary report
if(len(l1)>3 and ld in dt.dictKey):
resD+='['+linkDict(l1)+linkEdit('=')+'] '
l1=ln.replace('ས་@','་')
ld=l1+'\n'
if(ld in d):
dk.get(l1)
c=dk.res
if(EMPTY_MARK in c):
end-=1
continue
res+='['+linkDict(l1)+linkEdit('='+c)+']་['+linkDict('-ས་')+linkEdit('=i.p.')+']་'
rd[l1]=1
start=end-1
break
#next check big dictionary report
if(len(l1)>3 and ld in dt.dictKey):
resD+='['+linkDict(l1)+linkEdit('=')+'] '
l1=ln.replace('ར་@','་')
ld=l1+'\n'
if(ld in d):
dk.get(l1)
c=dk.res
if(EMPTY_MARK in c):
end-=1
continue
res+='['+linkDict(l1)+linkEdit('='+c)+']་['+linkDict('-ར་')+linkEdit('=d.l.')+']་'
rd[l1]=1
start=end-1
break
#next check big dictionary report
if(len(l1)>3 and ld in dt.dictKey):
resD+='['+linkDict(l1)+linkEdit('=')+'] '
l1=ln.replace('འོ་@','འ་')
ld=l1+'\n'
if(ld in d):
dk.get(l1)
c=dk.res
if(EMPTY_MARK in c):
end-=1
continue
res+='['+linkDict(l1)+linkEdit('='+c)+'](точка)་'
rd[l1]=1
start=end-1
break
#next check big dictionary report
if(len(l1)>3 and ld in dt.dictKey):
resD+='['+linkDict(l1)+linkEdit('=')+'] '
l1=ln.replace('འམ་@','་')
ld=l1+'\n'
if(ld in d):
dk.get(l1)
c=dk.res
if(EMPTY_MARK in c):
end-=1
continue
res+='['+linkDict(l1)+linkEdit('='+c)+']་['+linkDict('-འམ་')+linkEdit('=или')+']་'
rd[l1]=1
start=end-1
break
#next check big dictionary report
if(len(l1)>3 and ld in dt.dictKey):
resD+='['+linkDict(l1)+linkEdit('=')+'] '
end-=1
if(end==start):
res+=line
break
start+=1
res=res.replace(':|:YP','')
if(re.search('lt',src)!=None):
src='<d>'+src+'</d>'
else:
src='<tib contentEditable>'+src+'</tib>'
report+=src+'\n<d>'+reportT+'</d><br>\n<w>'+res+'\n'
if(len(resD)>10):
report+='<r>'+resD+'</r>'
report+='</w><br><br>\n'
reportT=''
if(dt.mainMode==FULL_REPORT):
res=''
for line in l:
ld=line+'་\n'
key=line+'་'
if(ld in d):
dk.get(key)
c=dk.res
res+='['+linkDict(key)+linkEdit('='+c)+']་'
res=res.replace(':|:YP','')
report+='<br><c>'+res+'</c>\n<br>'
#print report
#sys.exit()
#return
dt.data[0]=report
def linkDict(line):
s=''
id='s{}'.format(dt.id)
s='<r id="'+id+'" onClick="set(\''+id+'\')">'+line+'</r>'
dt.id+=1
return s
def linkText(line):
s=''
id='s{}'.format(dt.id)
s='<t id="'+id+'" onClick="edit(\''+id+'\')">'+line+'</t>'
dt.id+=1
return s
'''
def linkEdit(line):
#line=re.sub('^[^:]*:\|:','=',line)
s=''
id='s{}'.format(dt.id)
l=line
line=line.replace('@','')
line=line.replace('*','')
line=line.replace('%','')
if(l!=line):
s='<t id="'+id+'" onClick="edit(\''+id+'\')" onBlur="v(\''+id+'\')">'+line+'</t>'
else:
s='<t id="'+id+'" onClick="edit(\''+id+'\')" onBlur="v(\''+id+'\')"><r>'+line+'</r></t>'
dt.id+=1
return s
'''
def linkEdit(line):
#line=re.sub('^[^:]*:\|:','=',line)
s=''
id='s{}'.format(dt.id)
l=line
line=line.replace('@','')
line=line.replace('*','')
line=line.replace('%','')
s='<t id="'+id+'" style="color:#373737" onClick="edit(\''+id+'\')" onBlur="v(\''+id+'\')">'+line+'</t>'
dt.id+=1
return s
def convertDict():
with open(pathSave+"allDict_uni.txt",'w') as f:
with open(pathSave+"allDict_rus16.js",'r') as file:
for line in file:
if(('","","' in line)==False):
continue
str=line.replace('["','')
str=str.replace('","","',' @ ')
str=str.replace('"],','')
f.write(str)
def previousPage(sender):
global Pref
path=fileView['textfield1'].text
path=pathMain+'{}'.format(path)
with open(path,"r") as f:
textFile=f.readlines()
c=pageIndex.text
i=0
if('#' in c):
for line in textFile:
if(c in line):
break
i+=1
i=i/pageSize
else:
i=eval(c)-1
if(i<0):
i=len(textFile)/pageSize
page=textFile[i*pageSize:i*pageSize+pageSize]
pageIndex.text='{}'.format(i)
Pref[2]=pageIndex.text
text='<t id="t1" onClick="edit(\'t1\')">'+'<br>'.join(page)+'</t>'
searchBtn.title='Translate'
dt.mainMode=TRANSLATE
searchText.text=''
savePref()
printHtml(text)
def nextPage(sender):
global Pref
path=fileView['textfield1'].text
path=pathMain+'{}'.format(path)
with open(path,"r") as f:
textFile=f.readlines()
c=pageIndex.text
i=0
if('#' in c):
for line in textFile:
if(c in line):
break
i+=1
i=i/pageSize
else:
i=eval(c)+1
if(i>len(textFile)/pageSize):
i=0
page=textFile[i*pageSize:i*pageSize+pageSize]
pageIndex.text='{}'.format(i)
Pref[2]=pageIndex.text
text='<t id="t1" onClick="edit(\'t1\')">'+'<br>'.join(page)+'</t>'
searchBtn.title='Translate'
dt.mainMode=TRANSLATE
searchText.text=''
savePref()
printHtml(text)
def printHtml(text):
#with open(pathSave+pageStyle,"r") as f:
htmlPage=Pref[0]
str=htmlPage.replace('@@@TEXT@@@',text)
str=str.replace( chr(0),' ')
textIn.load_html(str)
def printHTML_(text):
#with open(pathSave+pageStyle,"r") as f:
htmlPage=Pref[0]
str=htmlPage.replace('@@@TEXT@@@',text)
dictView.load_html(str)
def openText():
pathField=fileView['textfield1']
path=pathField.text
path=pathMain+'{}'.format(path)
if(os.path.isfile(path)):
with open(pathSave+pageStyle,"r") as f:
htmlPage=f.read()
Pref[0]=htmlPage
with open(path,"r") as f:
textFile=f.readlines()
if(len(textFile)<1):
str='no text'
else:
if(len(textFile[0])>1024):
str='too long line'
else:
c=pageIndex.text
i=eval(c)
page=textFile[i*pageSize:i*pageSize+pageSize]
#pageIndex.text='{}'.format(i)
str='<br>'.join(page)
if(len(str)>90000):
str='too long line'
text='<t id="t1" onClick="edit(\'t1\')">'+str+'</t>'
str=htmlPage.replace('@@@TEXT@@@',text)
str=str.replace( chr(0),' ')
textIn.load_html(str)
#print str
else:
print 'not open '+ path
menu(1)
def copyText(sender):
pathField=fileView['textfield1']
path=pathField.text
path=pathMain+'{}'.format(path)
if(os.path.isfile(path)):
with open(path,"r") as f:
textFile=f.read()
dialogs.share_text(textFile)
def menu(sender):
path=fileView['textfield1'].text
path=re.sub('/[/]+','/',path)
fileView['textfield1'].text=path
tbl=fileView['tableview1']
tblD=fileView['tableview2']
path=os.path.dirname(path)
if(os.path.isdir(pathMain+path)):
listD=os.listdir(pathMain+path)
else:
path='/'
listD=os.listdir(pathMain)
fileView['textfield1'].text='/'
l=[]
ld=['...']
for line in listD:
if(os.path.isdir(pathMain+path+'/'+line)):
ld.append(line)
else:
l.append(line)
tbl.data_source.items=l
tblD.data_source.items=ld
fileView.x=0
def openDir(sender):
path=fileView['textfield1'].text
path=path.replace('#','/')
path=os.path.dirname(path)
tbl=fileView['tableview1']
tblD=fileView['tableview2']
dir=tblD.data_source.items[tblD.selected_row[1]]
if(dir=='...'):
path=os.path.dirname(path)
dir=''
listD=os.listdir(pathMain+path+'/'+dir)
c=path+'/'+dir+'/'
c=c.replace('#','/')
c=re.sub('//+','/',c)
fileView['textfield1'].text=c
l=[]
ld=['...']
for line in listD:
if(os.path.isdir(pathMain+path+'/'+dir+'/'+line)):
ld.append(line)
else:
l.append(line)
tbl.data_source.items=l
tblD.data_source.items=ld
def openFile(sender):
global Pref
tbl=fileView['tableview1']
line=tbl.data_source.items[tbl.selected_row[1]]
fileView.x=1024
path=fileView['textfield1'].text
path=os.path.dirname(path)
fileView['textfield1'].text=path+'/'+line
Pref[1]=path+'/'+line
Pref[2]='0'
pageIndex.text='0'
savePref()
openText()
def closeMenu(sender):
fileView.x=1024
def replaceRegExpFile(sender):
path=fileView['textfield1'].text
path=pathMain+'{}'.format(path)
pathRep=fileView['textfield3'].text
pathRep=pathMain+'{}'.format(pathRep)
with open(pathRep,"r") as f:
str=f.read()
dataRegExp=str.split('\n:|:\n')
path=os.path.dirname(path)
listD=os.listdir(path)
for line in listD:
print line
if(os.path.isdir(path+'/'+line)):
pass
else:
print 'start '+line
with open(path+'/'+line,"r") as f:
text=f.read()
for l in dataRegExp:
c=l.split(' --> ')
if(len(c)<2):
print 'not valid re '+l
else:
text=re.sub(c[0],c[1],text)
with open(path+'/'+line,"w") as f:
f.write(text)
print 'done '+line
def replaceRegExp(sender):
pass
def replaceRegExpText(sender):
path=fileView['textfield1'].text
path=pathMain+'{}'.format(path)
textSrc=fileView['textfield4'].text
textSrc='{}'.format(textSrc)
textRep=fileView['textfield5'].text
textRep='{}'.format(textRep)
a=re.compile(textSrc,re.M)
with open(path,"r") as f:
textFile=f.read()
textFile=unicode(textFile)
c=chr(0xA0)
textFile=re.sub(c,' ',textFile)
textFile='{}'.format(textFile)
#s=textFile[0:32]
#s=unicode(s)
#i=0
#while i<len(s):
# print '{0:x}'.format(ord(s[i]))
# i+=1
textFile=re.sub(a,textRep,textFile)
#textFile=textFile.replace(textSrc,textRep)
#textFile=textFile.replace(' ','\n')
#textFile=re.sub('།','།\n',textFile)
#textFile=re.sub(r'\n[\n]+','\n',textFile)
#textFile=re.sub(r'།\n[ ]*།\n','།\n།',textFile)
#textFile=re.sub(r' ','\n',textFile)
with open(path,"w") as f:
f.write(textFile)
openText()
fileView.x=1024
def searchInDharmabook(sender):
path=pathSave+"XML_DICT/DHARMABOOK.tab"
text=fileView['textfield6'].text
text='{}'.format(text)
res=''
i=0
with open(path,"r") as f:
for line in f:
str=line[0:1024]
if(text in str):
l=len(str)
str=str[0:str.rfind(' ')]
if(len(str)==l):
str=str[0:str.rfind('¶')]
res+=str+'\n'
i+=1
if(i>300):
break
with open(pathSave+'res_dharmabook.txt',"w") as f:
f.write(res)
fileView.x=1024
def searchInDharmabookFullText(sender):
path=pathSave+"XML_DICT/DHARMABOOK.tab"
text=fileView['textfield6'].text
text='{}'.format(text)
res=''
searchCount=0
with open(path,"r") as f:
for line in f:
index=line.find(text)
if(index!=-1):
str=line[0:256]
if(str.rfind(' ')!=-1):
str=str[0:str.rfind(' ')]
else:
if(str.rfind('¶')!=-1):
str=str[0:str.rfind('¶')]
else:
if(str.rfind('་')!=-1):
str=str[0:str.rfind('་')]
#print '{0:d}'.format(len(resList))+' found '+str
res+='\n================================\n'+str+'\n____________________________________\n'
while(index!=-1):
str=line[index-512:index]
l=len(str)
if(str.find(' ')!=-1):
str=str[str.find(' '):l]
else:
if(str.find('¶')!=-1):
str=str[str.find('¶'):l]
else:
if(str.find('་')!=-1):
str=str[str.find('་'):l]
res+=str
str=line[index:index+512]
if(str.rfind(' ')!=-1):
str=str[0:str.rfind(' ')]
else:
if(str.rfind('¶')!=-1):
str=str[0:str.rfind('¶')]
else:
if(str.rfind('་')!=-1):
str=str[0:str.rfind('་')]
res+=str+'\n\n'
searchCount+=1
if(searchCount>300):
break
index=line.find(text,index+len(text))
if(searchCount>300):
break
res=unicode(res)
c=chr(0xA0)
res=re.sub(c,' ',res)
res='{}'.format(res)
res=res.replace('¶','\n')
res=res.replace('། ','།\n')
res=res.replace('༔ ','༔ \n')
with open(pathSave+'res_dharmabookFullText.txt',"w") as f:
f.write(res)
fileView.x=1024
def exportTextByID(sender):
path=pathSave+"XML_DICT/DHARMABOOK.tab"
text=fileView['textfield6'].text
text='{}'.format(text)
with open(path,"r") as f:
for line in f:
str=line[0:128]
if(text in str):
with open(pathSave+'res_dharmabookText.txt',"w") as f:
f.write(line)
break
fileView.x=1024
def searchInFolder(sender):
print 'search'
path=fileView['textfield1'].text
path=pathMain+'{}'.format(path)
print path
str=fileView['textfield6'].text
str='{}'.format(str)
res=''
path=os.path.dirname(path)
listD=os.listdir(path)
i=0
for line in listD:
if(os.path.isdir(path+'/'+line)):
pass
else:
with open(path+'/'+line,"r") as f:
for l in f:
if (str in l):
res+=line+'\n'+l+'\n'
i+=1
if(i>100):
res=res.replace('\n\n','\n')
with open(pathSave+'res.txt',"w") as f:
f.write(res)
return
res=res.replace('\n\n','\n')
with open(pathSave+'res_1.txt',"w") as f:
f.write(res)
def searchInFileText(sender):
path=fileView['textfield1'].text
text=fileView['textfield6'].text
text='{}'.format(text)
path=pathMain+'{}'.format(path)
with open(path,"r") as f:
textFile=f.readlines()
i=0
for line in textFile:
if(text in line):
break
i+=1
i=i/pageSize
page=textFile[i*pageSize:i*pageSize+pageSize]
pageIndex.text='{}'.format(i)
text='<t id="t1" onClick="edit(\'t1\')">'+'<br>'.join(page)+'</t>'
printHtml(text)
fileView.x=1024
def searchInFile(sender):
path=fileView['textfield1'].text
text=fileView['textfield6'].text
text='{}'.format(text)
path=pathMain+'{}'.format(path)
res='test'
searchCount=0
with open(path,"r") as f:
textLines=f.readlines()
i=1
l=len(textLines)-1
while(i<l):
index=textLines[i].find(text)
if(index!=-1):
res+=textLines[i-1]+textLines[i]+textLines[i+1]+'\n༄།།\n'
searchCount+=1
i+=1
print searchCount
with open(pathSave+'res_dharmabookTextSearch.txt',"w") as f:
f.write(res)
fileView.x=1024
def close(sender):
dt.close()
view.close()
savePref()
def cmpLines(a,b):
a_=len(a.split(' @ ')[0])
b_=len(b.split(' @ ')[0])
if(a_>b_):
return -1
elif(a_<b_):
return 1
else:
return 0
def saveDict(text):
dictNew=list()
text=re.sub(r'<[^>]*>','',text)
text=text.replace('«','༼')
text=text.replace('{','༼')
text=text.replace('»','༽')
text=text.replace('}','༽')
lines=text.split('[')
for l in lines:
if ('=' in l):
continue
if ('/' in l):
#print l
c=l.split(']')
d=c[0].split('/')
if(len(d)>1):
key=d[0]+'་'
key=key.replace('་་','་')
if (d[1]=='-'):
dk.rem(key)
continue
if(len(d[0])<3 or len(d[1])<3):
continue
value=d[1]+'%'
value=value.replace('@%','%')
value=value.replace('*%','%')
value=value.replace('%%','%')
dk.put(key,value)
dk.saveInd()
def htmlToText(textAll):
textAll=textAll.replace('\n','')
textAll=textAll.replace('<br>','\n')
textAll=textAll.replace('<div>','\n')
textAll=textAll.replace(' ','')
textAll=textAll.replace('<c>','@')
textAll=textAll.replace('<r>','@')
#textAll=textAll.replace('[','@')
textAll=re.sub(r'@.*','@',textAll)
textAll=textAll.replace('@\n','')
textAll=re.sub(r'<[^>]*>','',textAll)
return textAll
def save(sender):
f = open(pathSave+'_pref.txt',"w")
pickle.dump(Pref, f)
f.close()
#textIn.text is unicode, it is need convert it in utf-8
#need rewrite with codecs
js='readText()'
if(mainDictView.x==0):
textAll=dictView.eval_js(js)
textAll='{}'.format(textAll)
saveDict(textAll)
return
textAll=textIn.eval_js(js)
#textIn.text is unicode, it is need convert it in utf-8
textAll='{}'.format(textAll)
saveDict(textAll)
def clearSearch(sender):
searchText.text=''
def closeDictView(sender):
if(len(dt.history)>0):
dt.history.pop()
if(len(dt.history)>0):
searchText.text=dt.history[len(dt.history)-1]
dt.history.pop()
dictEntry()
else:
mainDictView.x=1024
else:
mainDictView.x=1024
def setCommentaryTag(sender):
path=fileView['textfield1'].text
path=pathMain+'{}'.format(path)
with open(path,"r") as f:
textFile=f.readlines()
for key in dk.keyList:
key=key.rstrip('\n')
dk.get(key)
c=dk.res
if('__' in c):
i=0
key=key.rstrip('་')
for line in textFile:
s=unicode(line)
s=re.sub(u'[ _\d\ " \'\*\(\)\{\}\[\]@•#\%\&༄༅༔༴༡༢༣༤༥༦༧༨༩༠༎།༑༈༌༐༏༼༽ऀ-ॿ]',u"་",s)
s=re.sub(u'་[་]+',u"་",s)
s='{}'.format(s)
if(key in s):
textFile[i]='#_'+textFile[i]
break
i+=1
with open(path,"w") as f:
f.writelines(textFile)
def buildSummary(sender):
path=fileView['textfield1'].text
path=pathMain+'{}'.format(path)
res=''
with open(path,"r") as f:
for line in f:
if('#' in line):
res+=line
fileView['textfield1'].text='Dictionary/_res.txt'
path=pathMain+'Dictionary/_res.txt'
with open(path,"w") as f:
f.write(res)
openText()
def fileCopy(path1,path2):
print copy
f=open(path1, 'r')
t=f.readlines()
#print len(t)
f.close()
f=open(path2, 'w')
f.writelines(t)
f.close()
def sortDict(name):
print 'load {}'.format(name)
with open(pathSave+'XML_DICT/'+name+'.txt') as f:
str=f.read()
f.close()
str=str.replace('\r','\n')
d=str.split('\n')
print len(d)
d.sort()
i=0
s=list()
l=''
for line in d:
i+=1
line=line.replace('*','@')
line=re.sub('[\n\r\t ]*$','',line)
if(l==line):
continue
#print line+'/'
#print len(line)
#if(i==10):
#break
l=line
s.append(line+'\n')
f=open(pathSave+'XML_DICT/'+name+'_new.txt', 'w')
f.writelines(s)
f.close()
print len(s)
print 'done'
def loadPref():
global Pref
p=pathSave+'_pref_dict.txt'
try:
io.open(p,'r')
except IOError:
savePref()
with open(p,'r') as f:
Pref=pickle.load(f)
while len(Pref) < 5:
Pref.append('')
fileView['textfield1'].text=Pref[1]
if(Pref[2]==''):
Pref[2]='0'
pageIndex.text=Pref[2]
def savePref():
global Pref
p=pathSave+'_pref_dict.txt'
with open(p,'w') as f:
pickle.dump(Pref,f)
#sortDict('exportDictionary_sort')
#sys.exit()
#pData=pathSave+"XML_DICT/DHARMABOOK.bin"
#v=GVector()
#v.openData(pData)
#print v.getStr(0)
#s=' '
#print ord(s)
#dialogs.share_text('123')
#sys.exit()
pData=pathSave+"XML_DICT/_GVector.txt"
pIndex=pathSave+"XML_DICT/_GVectorIndex.txt"
pData_=pathSave+"XML_DICT/_GVector1.txt"
pIndex_=pathSave+"XML_DICT/_GVectorIndex1.txt"
#fileCopy(pData,pData_)
#fileCopy(pIndex,pIndex_)
#sys.exit()
v=GVector()
v.openData(pData)
dt=dictBase()
dk=copy.deepcopy(dt)
dt.openData(v,pIndex)
#os.unlink(pData)
#os.unlink(pIndex)
#loadDB()
#print 'done'
#s=dt.vData.getStr(88683) #88684
#print s
#v.checkIndex(20)
#test('ཀ་ཀ་',dt)
#dt.close()
#sys.exit()
dk.dictKey={}
dk.keyList=list()
dk.data=list()
#open translation dictionary
pData=pathSave+"XML_DICT/_GVectorDict.txt"
pIndex=pathSave+"XML_DICT/_GVectorDictIndex.txt"
t=GVector()
t.openData(pData)
dk.openData(t,pIndex)
#test('རྣ་',dk)
#print 'l={} t={}'.format(len(dt.keyList), t2-t1)
#print len(dt.keyList)
#dt.close()
#dk.close()
#sys.exit()
#print 'load DK'
#dk.clear()
#dk.loadTXT('word_dict','put')
#dk.loadTXT('exportDictionaryRus','roots')
#dt.close()
#dk.normalisation()
#print 'done'
#s=dk.vData.getStr(21)
#print s
#dk.close()
#sys.exit()
view = ui.load_view() #super view
textIn=view['webview1']
fileView=view['view1']
pageIndex=view['textview1']
searchText=view['textview2']
searchBtn=view['searchBtn']
mainDictView=view['mainDictView']
mainDictView.x=1024
mainDictView.y=0
dictView=mainDictView['webview1']
fileView.x=1024
fileView.y=0
view.present('fullscreen',hide_title_bar=True)
#view.present('popover')
loadPref()
openText()
#action_out = action_in
#workflow.set_output(action_out)
There are no comments yet.