
*** Modified files in JOE when it aborted on Mon Aug 29 17:42:45 2005
*** JOE was aborted because the terminal closed

*** File '(Unnamed)'
395

*** Modified files in JOE when it aborted on Wed Aug 31 11:52:45 2005
*** JOE was aborted because the terminal closed

*** Modified files in JOE when it aborted on Wed Aug 31 11:52:45 2005
*** JOE was aborted by signal 1

*** File '(Unnamed)'
XTME

*** Modified files in JOE when it aborted on Wed Aug 31 11:57:30 2005
*** JOE was aborted because the terminal closed

*** File '(Unnamed)'
WordMap.py
WordMap.py
WordMap.py
*** File '(Unnamed)'
WordMap.py
WordMap.py

*** File '(Unnamed)'
doctype

*** File 'WordMap.py'
#
# Copyright 2001, 2002 by IVA Team and contributors
#
# This file is part of IVA.
#
# IVA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# IVA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with IVA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

"""Contains class WordMap, which represents one working Concept map"""

import AccessControl
import OFS, Globals
from OFS import SimpleItem
import types
import time
import math
from TraversableWrapper import Traversable
from Globals import Persistent
from AccessControl import ClassSecurityInfo
from Cruft import Cruft
from common import add_dtml, translate, perm_edit, perm_view, get_roles
import xml.dom.minidom
from ImportExport import Counter, DataTable, to_utf8, Exporter, Dump

try:
        from PIL import Image, ImageDraw
except:
  pass


class WordMap(
     OFS.Folder.Folder,
     Persistent,
     AccessControl.Role.RoleManager,
     Traversable,
     Cruft
     ):
    "Concept map"
    security = AccessControl.ClassSecurityInfo()
    security.declareObjectPublic()
    
        
    def __init__(self):
        "Constructor"
        self.meta_type="WordMap"
        self.initializeVariables()
        
        
    def initializeVariables(self):
        "Initialize variables at startup and on cleaning"
        self.picturesize=[600, 500] #picture size in pixels
        self.planpicturesize=[200, 200] #whole map without zooming
            #viewing area in logical units
        self.viewingbounds=[0, 0, self.picturesize[0], self.picturesize[1]]
        self.viewingcentre=[
                 (self.viewingbounds[0]+self.viewingbounds[2])/2.0,
                 (self.viewingbounds[1]+self.viewingbounds[3])/2.0,             
             ]
        self.viewcoef=1  #monitor points/logical points
        self.zoomcoef=0.5
        
       # self.wordcolor=(0, 200, 0)
#        self.wordbackgrounds=(
#          "#DB002B",
#          "#3E6090",
#          "#FFC600",
#          "#666666",
#          "#000000"
#        )
        self.wordbackgroundcolordefaultindex=0
        self.wordcolortypes=["", "", "", "", ""]
        self.linecolor=(0, 0, 200)
        self.selectedlinecolor=(200, 0, 0)
        self.backgroundcolor=(255, 255, 255)
        self.viewingboundslinecolor=(200, 200, 200)
        self.selectedarealinecolor=(255, 100, 100)
        self.leftdistance=10 #free space from picture side in pixels
        self.rightdistance=10
        self.topdistance=10
        self.bottomdistance=10
        self.movingdistanceinscreen=25
#        self.currentFontName="courB24.pil"
        
           #word placing in picture. Each word have x and y coordinate
           #at example [[10, 10], [10, 20], [10, 30]]
        self.wordplaces=[]         
           #in self.relationnumbers each element is a array, where index means starting vertex and
           #value point to end vertex. At example [[1], [0, 2], [1]]
        self.relationnumbers=[] 
        self.wordids=[] #word object indexes in OFS
        self.newwordidnr=0
        self.newedgeidnr=0
        self.startingvertex=None #Central vertex index in graph at example 2
          #self.parentarray displays way to starting vertex
          #at example [1, 2, -1] means, that way from vertex 0 to
          #startingvertex (here 2) goes (0, 1) and (1, 2).  In place 2
          #are value -1, because we allready are in vertex 2
        self.parentarray=[] #Parent vertex in trees
        self.distancegrouparray=None #Each element presents list of
                              #vertexes in same distance from start vertex
          #active action number
          #0 - horizontal tree; 1-move
        self.activeaction=0 
        self.selectedmovevertex=None #vertex selected to move
        self.selectedwords=[] #word indexes
        self.selectededge=None
        self.selectingdistance=3 #distance in points selecting with mouse
        self.selectedarea=None #[x, y, w, h] if present
        self.selectedareafirstclick=None  #[x, y] if present
        self.menustates={'edit':0, 'select':0, 'zoom':0}

        self.picturefilenames=["wm_kursor", "wm_margistus", "wm_luuppluss", #0, 1, 2
                "wm_luupmiinus", "wm_lisaseos", "wm_kustutus",              #3, 4, 5
                "wm_horpuu", "wm_kiirpuu", "wm_noolv",                      #6, 7, 8
                "wm_noolp", "wm_nooly", "wm_noola",                         #9, 10, 11
                "wm_margistusnool", "wm_margistus", 
                "wm_margistusmaha",
                "wm_margistusloika",    
                "wm_margistuskopeeri", "wm_margistuskleebi",              
                "wm_margistusv", "wm_margistusp",                         
                "wm_margistusy", "wm_margistusa",
                "wm_lisaseos", "wm_margistusnool", "wm_luuppluss",              #22                          
                "wm_luuptyhi", "wm_piltsuuremaks", "wm_piltvaiksemaks"
            ]                     
          #which picture is with border
        self.pictureselections=[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,         #0-11
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,                                       #12-20
        ]                                        
        self.menuicons=(22, 23, 24)
        self.additionalpictures=[]
        self.selectpictures=[12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
        self.picturehints=[
          "Click with mouse",
          "Select area",
          "Zoom bigger",
          "Zoom Smaller",
          "Add edge",
          "Delete",
          "Horizontal tree",
          "Circle tree",
          "View left",
          "Viev right",
          "View up",
          "View down",
          "Select multiple words",
          "Select area words",
          "Unselect all",
          "Cut",
          "Copy",
          "Paste",
          "Move left",
          "Move right",
          "Move up",
          "Move down",
          "Edit menu",
          "Select menu",
          "Zoom menu",
          "Zoom to bounds",
          "Increase picture",
          "Decrease picture"
        ]
        wds=self.objectValues('MapWord')
        for wd in wds:
          self._delObject(wd.id)
        edges=self.objectValues('MapEdge')
        for eg in edges:
          self._delObject(eg.id)
        self.title=""
        self.description=""
 #       self.fontnames=["small", "medium", "large"]
        self.fontfiles=[None, "courB14.pil", "courB24.pil"]
        self.fontindex=0
        
        
    security.declareProtected(perm_view, 'getTitle')
    def getTitle(self):
        "getter"
        return self.title.strip()
    
    security.declareProtected(perm_view, 'getDescription')    
    def getDescription(self):
        "getter"
        return self.description

    security.declareProtected(perm_view, 'getFontIndex')        
    def getFontIndex(self):
        "getter"
        return self.fontindex
    
#    security.declareProtected(perm_view, 'getWordBackgroundColors')
#    def getWordBackgroundColors(self):
#        "getter"
#        return self.wordbackgrounds
        
    security.declareProtected(perm_view, 'getWordBackgroundColorIndex')
    def getWordBackgroundColorIndex(self):
        "getter"
        return self.wordbackgroundcolordefaultindex
        

    security.declareProtected(perm_view, 'getWordColorTypes')
    def getWordColorTypes(self):
        "getter"
        return self.wordcolortypes
        
     

    security.declareProtected(perm_view, 'getWordColorType')
    def getWordColorType(self, index):
        "getter"
        try:
          return self.wordcolortypes[index]
        except:
          return ""
        
    security.declareProtected(perm_view, 'getMapWords')
    def getMapWords(self):
        "getter"
        return self.objectValues('MapWord')
        
    security.declareProtected(perm_view, 'getMapEdges')
    def getMapEdges(self):
        "getter"
        return self.objectValues('MapEdge')
        
    security.declareProtected(perm_edit, 'add_new_wordmap')
    def add_new_wordmap(self):
        "we're not adding new wordmap. In class WordmapFolder returns 1"
        return 0
        return 1

        

    security.declareProtected(perm_edit, 'wordmaps_management_page_handler')    
    def wordmaps_management_page_handler(self, REQUEST, title, description, font, colorindex, wordcolortype, redirect=1):
        "Data saving"
        self.title=title
        self.description=description
        self.fontindex=int(font)
        nr=len(self.wordcolortypes)
        self.wordcolortypes=[]
        for i in range(nr):
          self.wordcolortypes.append(wordcolortype[i])
        self.wordbackgroundcolordefaultindex=int(colorindex)
        if redirect:
           REQUEST.RESPONSE.redirect(self.find_course().wordmaps.absolute_url()+'/wordmaps_index_html')
        
        
    security.declareProtected(perm_view, 'countPictures')
    def countPictures(self):
        "Number of pictures in words and edges"
        nr=0
        for e in self.objectValues(('MapWord', 'MapEdge')):
           if e.hasPicture(): nr+=1
        return nr        

    security.declareProtected(perm_view, 'getAdditionalPictures')
    def getMenuState(self, type):
        "Is menu open"
        return self.menustates[type]
        

    def changeMenuState(self, type):
        "on/off"
        if self.menustates[type]:
           self.menustates[type]=0
        else:
           self.menustates[type]=1
           
    security.declareProtected(perm_view, 'getNewEdgeID')
    def getNewEdgeID(self):
        "ID nr for new edge in map"
        self.newedgeidnr+=1
        return self.newedgeidnr
    
    security.declareProtected(perm_view, 'getNewWordID')
    def getNewWordID(self):
        "ID nr for new word in map"
        self.newwordidnr+=1
        return self.newwordidnr
    

    security.declareProtected(perm_view, 'getAdditionalPictures')
    def getAdditionalPictures(self):
        "Additional menu"
        return self.additionalpictures
        

    security.declareProtected(perm_view, 'getIconByNr')
    def getIconByNr(self, pnr):
        "Returns the file name"
        iconname='images/'+self.picturefilenames[int(pnr)]
        if self.isIconSelected(pnr):
            iconname+="_bw"
        return iconname
        
#    def getIconStyle(self, nr):
#        "Style for HTML page"
#        t= "background-image: url('"+self.getIconByNr(nr)+"'); height: 30px; width: 30px; "+\
#           "background-repeat: no-repeat; background-color: white;"
#        if self.isIconSelected(nr):
#           t+="border-style: solid;"
#        else:
#        t+="border-style: none;"
#        return t
           
           
    def getIconHTML(self, REQUEST, nr):
        "HTML for image icons"
        st=""
#        if self.isIconSelected(nr):
#          st="border: medium solid black;"
        t="<a href='wmapindex_handler?pnr="+str(nr)+\
           "' title='"+translate(self, self.picturehints[nr], target=self.giveLanguage(REQUEST))+\
           "'><img src='"+self.getIconByNr(nr)+"' style='"+st+"' alt='"+translate(self, self.picturehints[nr], target=self.giveLanguage(REQUEST))+"'/></a>"
        return t

    security.declareProtected(perm_view, 'isIconSelected')
    def isIconSelected(self, pnr):
        "yes/no"
        return self.pictureselections[int(pnr)]

    security.declareProtected(perm_view, 'getIconHint')
    def getIconHint(self, pnr):
       "Hint to picture"
       return self.picturehints[int(pnr)]

    security.declareProtected(perm_view, 'getSelectedWords')
    def getSelectedWords(self):
       "Selected word indexes in map"
       return self.selectedwords

    security.declareProtected(perm_view, 'makeCopy')
    def makeCopy(self):
        "Copy of self with same main data"
        import copy
        newmap=WordMap()
        #newmap.words=copy.copy(self.words)
        newmap.wordplaces=[]
        for p in self.wordplaces:
           newmap.wordplaces.append(copy.copy(p))
        newmap.relationnumbers=[]
        for n in self.relationnumbers:
           newmap.relationnumbers.append(copy.copy(n))
        newmap.parentarray=copy.copy(self.parentarray)
        newmap.wordids=copy.copy(self.wordids)
        newmap.wordcolortypes=copy.copy(self.wordcolortypes)
        wds=self.objectValues('MapWord')
        for w in wds:
          nw=w.makeCopy()
          nw.id=w.id
          newmap._setObject(nw.id, nw)
        edges=self.objectValues('MapEdge')
        for e in edges:
          ne=e.makeCopy()
          ne.id=e.id
          newmap._setObject(ne.id, ne) 
        newmap.newwordidnr=self.newwordidnr
        newmap.newedgeidnr=self.newedgeidnr
        newmap.title=self.title
        newmap.description=self.description
        newmap.fontindex=self.fontindex
        newmap.wordbackgroundcolordefaultindex=self.wordbackgroundcolordefaultindex
        return newmap
        
    security.declareProtected(perm_view, 'addChildMap')
    def addChildMap(self, copying=0, wordsonly=0):
        "Adds child map to current map"
        nr=self.getNewWordMapNr()
        if copying:
          m=self.makeCopy()
        else:
          if wordsonly:
            m=WordMap()
            for wd in self.objectValues('MapWord'):
              m.addWord(wd.title)
          else:
            m=WordMap()
        m.id='map'+str(nr)
        self._setObject(m.id, m)
        return str(nr)
        
    def addChildMap_handler(self, REQUEST):
       "Adds child map and redirects to index"
       self.addChildMap(copying=1)
       REQUEST.RESPONSE.redirect(self.absolute_url())
       
        
    security.declareProtected(perm_view, 'getChildMaps')
    def getChildMaps(self):
        "Child maps of current map"
        return self.objectValues('WordMap')
        

    security.declareProtected(perm_view, 'readData')
    def readData(self, kogum):
        """Parameetrina saadavas assotsiatiivmassiivis on votmeteks solmede ID-d
        iga elemendi kyljes olevas assotsiatiivmassiivis on votmeteks solmede
        ID-d kuhu vastavalt kohalt viidatakse ning vaartusteks seose tyybid. 
        Salvestatase arvuline massiiv, kus iga elemendi kohal olevas massiivis
        on kirjas arvud, millega vastaval solmel seos"""
        tulemus=[]
        votmed=kogum.keys()
        votmed.sort()
        for i in range(len(votmed)):
            self.addWord(votmed[i])
        for i in range(len(votmed)):
            abi=[]
            element=votmed[i]      
            for x in kogum[element].keys():
                self.addEdge(i, votmed.index(x))
#                abi.append(votmed.index(x))
       
#            for arv in range(len(votmed)):
#                for x in kogum[votmed[arv]].keys():
#                    if x==votmed[i] and arv not in abi:
#                        abi.append(arv)
#            tulemus.append(abi)
        self.wordplaces=[] #sonade paiknemine graafis
        for i in range(len(votmed)):
            self.wordplaces.append([0, i*10]) #algul yksteise alla
#        self.relationnumbers=tulemus #elementide vahelised seosed
        #self.sonagr=kogum  #koik andmed
#        self.words=votmed #graafis olevad sonad
    
    security.declareProtected(perm_view, 'calculateDistances')
    def calculateDistances(self, nr):
        "Luuakse massiiv kaugused naitamaks, mitme serva kaugusel on iga tipp tipust nr"
        abi=[]
        vanem=[]
        for i in range(len(self.relationnumbers)): 
            abi.append(-1)
            vanem.append(-1)
        abi[nr]=0
        jarjekord=[]
        jarjekord.append(nr)
        self.distancegrouparray=[]
        while len(jarjekord)>0:
            uuritav=jarjekord.pop(0)
            if len(self.distancegrouparray)<=abi[uuritav]:
                self.distancegrouparray.append([])
            self.distancegrouparray[abi[uuritav]].append(uuritav)
            for x in self.relationnumbers[uuritav]:
                if abi[x]==-1:
                    abi[x]=abi[uuritav]+1
                    vanem[x]=uuritav
                    jarjekord.append(x)
        self.kaugused=abi
        self.suurimkaugus=0
        for k in self.kaugused:
            if k>self.suurimkaugus:
                self.suurimkaugus=k
        self.startingvertex=nr
        self.parentarray=vanem
    
      
    security.declareProtected(perm_view, 'calculateHorizontalTree')
    def calculateHorizontalTree(self):
        "Luuakse pilt, kus peaelement hakkab vasakult keskelt, alamelemendid hargnevad"
        tulpadearv=len(self.distancegrouparray)
        tulbalaius=(self.viewingbounds[2]-self.leftdistance*1.0/self.viewcoef-self.rightdistance*1.0/self.viewcoef)/tulpadearv
        sonax=self.viewingbounds[0]+self.leftdistance/self.viewcoef
        for distance in range(len(self.distancegrouparray)):
            sonutulbas=len(self.distancegrouparray[distance])
            reavahe=(self.viewingbounds[3]-self.topdistance*1.0/self.viewcoef-self.bottomdistance*1.0/self.viewcoef)/sonutulbas
            sonay=self.viewingbounds[1]+self.topdistance*1.0/self.viewcoef+reavahe*1.0/2
            for sonanr in range(sonutulbas):
                self.wordplaces[self.distancegrouparray[distance][sonanr]]=[sonax, sonay]
                sonay+=reavahe
            sonax+=tulbalaius


    security.declareProtected(perm_view, 'calculateCircleTree')
    def calculateCircleTree(self):
        "Tree, where are central word and others around him in circles"
        centerx=self.viewingcentre[0]
        centery=self.viewingcentre[1]
        maxr=min(self.viewingbounds[2]-self.leftdistance*1.0/self.viewcoef-self.rightdistance*1.0/self.viewcoef, 
             self.viewingbounds[3]-self.topdistance*1.0/self.viewcoef-self.bottomdistance*1.0/self.viewcoef)/2
        r=0
        dr=maxr/(len(self.distancegrouparray)-1)
        for distance in range(len(self.distancegrouparray)):
            import random
            startangle=random.random()*6.28
            angle=startangle
            deltaangle=6.28/len(self.distancegrouparray[distance])
            for nr in self.distancegrouparray[distance]:
              self.wordplaces[nr]=[centerx+r*math.cos(angle), centery+r*math.sin(angle)]
              angle+=deltaangle
            r+=dr              
                      
    security.declareProtected(perm_view, 'calculateCircleTree')
    def calculateRayCircleTree(self):
        "Each new word will be centre of new circle"
        centerx=self.viewingcentre[0]
        centery=self.viewingcentre[1]
        maxr=min(self.viewingbounds[2]-self.leftdistance*1.0/self.viewcoef-self.rightdistance*1.0/self.viewcoef, 
             self.viewingbounds[3]-self.topdistance*1.0/self.viewcoef-self.bottomdistance*1.0/self.viewcoef)/2.0
        r=0
        dr=maxr/(len(self.distancegrouparray)-1)
        if not self.distancegrouparray: return
        self.wordplaces[self.distancegrouparray[0][0]]=[centerx, centery]
        if len(self.distancegrouparray)==1: return
        startangle=3.14/4
        angle=startangle
        deltaangle=6.28/len(self.distancegrouparray[1])
        angles=[0]*len(self.wordplaces)
        r+=dr
        for nr in self.distancegrouparray[1]:
           self.wordplaces[nr]=[centerx+r*math.cos(angle), centery+r*math.sin(angle)]
           angles[nr]=angle
           angle+=deltaangle
        distance=2
        while distance<len(self.distancegrouparray):
          for parent in self.distancegrouparray[distance-1]:
           v=[]
           for nr in self.distancegrouparray[distance]:
              if self.parentarray[nr]==parent:
                  v.append(nr)
           if len(v)>0:
               deltaangle=3.14/len(v)
               angle=deltaangle/2-3.14/2+angles[parent]
               for nr in v:
                   self.wordplaces[nr]= \
                     [
                       self.wordplaces[parent][0]+dr*math.cos(angle), 
                       self.wordplaces[parent][1]+dr*math.sin(angle) 
                     ]
                   angles[nr]=(angles[parent]+angle)/2.0
                   angle+=deltaangle
          distance+=1     
           
           
                      
    security.declareProtected(perm_view, 'clearPicture')    
    def clearPicture(self, g, psize=None):
        "Pildile joonistatakse taustavarviga ristkylik"
        if psize is None: psize=self.picturesize
        g.setink(self.backgroundcolor)
        g.setfill(1)
        g.rectangle((0, 0, psize[0], psize[1]))
        g.setfill(0)
#        g.setink(self.wordcolor)
        
    security.declareProtected(perm_view, 'pictureX')            
    def pictureX(self, worldx, vcentre=None, vcoef=None, psize=None):
        "From world coordinates to picture coordinates"
        if vcentre is None: vcentre=self.viewingcentre
        if vcoef is None: vcoef=self.viewcoef
        if psize is None: psize=self.picturesize
        return (worldx-vcentre[0])*vcoef+psize[0]/2.0
    
    security.declareProtected(perm_view, 'pictureY')            
    def pictureY(self, worldy, vcentre=None, vcoef=None, psize=None):
        "From world coordinates to picture coordinates"
        if vcentre is None: vcentre=self.viewingcentre
        if vcoef is None: vcoef=self.viewcoef
        if psize is None: psize=self.picturesize
        return (worldy-vcentre[1])*vcoef+psize[1]/2.0
        
    security.declareProtected(perm_view, 'worldX')            
    def worldX(self, picturex, vcentre=None, vcoef=None, psize=None):
        "From picture coordinates to world coordinates"
        if vcentre is None: vcentre=self.viewingcentre
        if vcoef is None: vcoef=self.viewcoef
        if psize is None: psize=self.picturesize
        return (picturex-psize[0]/2.0)/vcoef+vcentre[0]
    
    security.declareProtected(perm_view, 'worldY')            
    def worldY(self, picturey, vcentre=None, vcoef=None, psize=None):
        "From picture coordinates to world coordinates"
        if vcentre is None: vcentre=self.viewingcentre
        if vcoef is None: vcoef=self.viewcoef
        if psize is None: psize=self.picturesize
        return (picturey-psize[1]/2.0)/vcoef+vcentre[1]
    
    security.declareProtected('View', 'drawWords')
    def drawWords(self, g, vcentre=None, vcoef=None, psize=None, pilt=None, withicons=1, font=None):
        "Koostatakse sonadest pilt"
#        g.setink(self.wordcolor)
        for i in range(len(self.wordids)):
            wd=getattr(self, self.wordids[i])
            if wd.hasPicture() and withicons:
             try:
              f=open("pilt.jpg", "w+b")
              f.write(wd.getPicture())
              f.close()
              p=Image.open("pilt.jpg")
              kast=p.getbbox()
              pilt.paste(p , [
                              int(kast[0]+self.pictureX(self.wordplaces[i][0], vcentre, vcoef, psize)), 
                              int(kast[1]+self.pictureY(self.wordplaces[i][1], vcentre, vcoef, psize)+15),
                              int(kast[2]+self.pictureX(self.wordplaces[i][0], vcentre, vcoef, psize)), 
                              int(kast[3]+self.pictureY(self.wordplaces[i][1], vcentre, vcoef, psize)+15),
                             ])
             except:
               print "pildiprobleem"
            g.rectangle(
             (
             self.pictureX(self.wordplaces[i][0], vcentre, vcoef, psize), 
             self.pictureY(self.wordplaces[i][1], vcentre, vcoef, psize), 
             self.pictureX(self.wordplaces[i][0], vcentre, vcoef, psize)+g.textsize(getattr(self, self.wordids[i]).title, font=font)[0], 
             self.pictureY(self.wordplaces[i][1], vcentre, vcoef, psize)+g.textsize(getattr(self, self.wordids[i]).title, font=font)[1]
             ),
#             fill="rgb(255, 140, 85)"
             fill=self.getWordBackgroundColors()[getattr(self, self.wordids[i]).backgroundcolorindex]
            )
            g.text(
              (
                self.pictureX(self.wordplaces[i][0], vcentre, vcoef, psize),
                self.pictureY(self.wordplaces[i][1], vcentre, vcoef, psize)
              ), 
              #Kuna PIL ei tunnista unicodet
              getattr(self, self.wordids[i]).title.encode('iso-8859-1'),
              fill="rgb(255, 255, 255)",
              font=font
            )
        for wi in self.selectedwords:
            g.rectangle((
             self.pictureX(self.wordplaces[wi][0], vcentre, vcoef, psize)-2, 
             self.pictureY(self.wordplaces[wi][1], vcentre, vcoef, psize)-2, 
             self.pictureX(self.wordplaces[wi][0], vcentre, vcoef, psize)+g.textsize(getattr(self, self.wordids[wi]).title, font=font)[0]+2, 
             self.pictureY(self.wordplaces[wi][1], vcentre, vcoef, psize)+g.textsize(getattr(self, self.wordids[wi]).title, font=font)[1]+2
            ))
      

    security.declareProtected(perm_view, 'drawEdges')    
    def drawEdges(self, g, vcentre=None, vcoef=None, psize=None, pilt=None, withicons=1, font=None):
        "Sonade vahele tommatakse jooned"
        g.setink(self.linecolor)
        sele=self.getSelectedEdge()
        if sele:
          print sele.startword, sele.endword
        for nr in range(len(self.wordids)):
            for sihtnr in self.relationnumbers[nr]:
                g.setink(self.linecolor)
                e=self.getEdge(self.wordids[nr], self.wordids[sihtnr])
                if sele and e.startword==sele.startword and e.endword==sele.endword:
                   g.setink(self.selectedlinecolor)
                g.line((
                  self.pictureX(self.wordplaces[nr][0], vcentre, vcoef, psize), 
                  self.pictureY(self.wordplaces[nr][1], vcentre, vcoef, psize),
                  self.pictureX(self.wordplaces[sihtnr][0], vcentre, vcoef, psize), 
                  self.pictureY(self.wordplaces[sihtnr][1], vcentre, vcoef, psize)
                ))
                if e.startword==self.wordids[nr]:
                  if e.startarrow:
                    self.drawArrow(g, self.wordplaces[nr][0], self.wordplaces[nr][1],
                                      self.wordplaces[sihtnr][0], self.wordplaces[sihtnr][1], 
                                       vcentre, vcoef, psize)
                  if e.endarrow:
                    self.drawArrow(g, self.wordplaces[sihtnr][0], self.wordplaces[sihtnr][1],
                                      self.wordplaces[nr][0], self.wordplaces[nr][1], 
                                       vcentre, vcoef, psize)
                  if e.weight>1:
                    self.drawWidthLine(g,self.wordplaces[sihtnr][0],
                                             self.wordplaces[sihtnr][1],
                                             self.wordplaces[nr][0],
                                             self.wordplaces[nr][1],
                                             e.weight, vcentre, vcoef, psize
                                             )
#                  for linenr in range(int(e.weight)):
#                     self.drawParallelLine(g, self.wordplaces[sihtnr][0], self.wordplaces[sihtnr][1],
#                                            self.wordplaces[nr][0], self.wordplaces[nr][1], linenr,
#                                            vcentre, vcoef, psize)

                  if withicons and e.text_in_line.strip():                
                   g.rectangle(
                      (
                         self.pictureX((self.wordplaces[nr][0]+self.wordplaces[sihtnr][0])/2, vcentre, vcoef, psize), 
                         self.pictureY((self.wordplaces[nr][1]+self.wordplaces[sihtnr][1])/2, vcentre, vcoef, psize), 
                         self.pictureX((self.wordplaces[nr][0]+self.wordplaces[sihtnr][0])/2, vcentre, vcoef, psize)+g.textsize(e.text_in_line, font=font)[0], 
                         self.pictureY((self.wordplaces[nr][1]+self.wordplaces[sihtnr][1])/2, vcentre, vcoef, psize)+g.textsize(e.text_in_line, font=font)[1]
                      ),
                      fill="rgb(255, 255, 255)"
                   )
     
                   g.text(
                    (
                     self.pictureX((self.wordplaces[nr][0]+self.wordplaces[sihtnr][0])/2),
                     self.pictureY((self.wordplaces[nr][1]+self.wordplaces[sihtnr][1])/2)
                    ),
                    e.text_in_line.encode('iso-8859-1'),
                    font=font
                   )
                  if e.hasPicture() and withicons:
                      try:
                          f=open("pilt.jpg", "w+b")
                          f.write(e.getPicture())
                          f.close()
                          p=Image.open("pilt.jpg")
                          kast=p.getbbox()
                          pilt.paste(p , [
                              int(kast[0]+self.pictureX((self.wordplaces[nr][0]+self.wordplaces[sihtnr][0])/2, vcentre, vcoef, psize)), 
                              int(kast[1]+self.pictureY((self.wordplaces[nr][1]+self.wordplaces[sihtnr][1])/2, vcentre, vcoef, psize)+15),
                              int(kast[2]+self.pictureX((self.wordplaces[nr][0]+self.wordplaces[sihtnr][0])/2, vcentre, vcoef, psize)), 
                              int(kast[3]+self.pictureY((self.wordplaces[nr][1]+self.wordplaces[sihtnr][1])/2, vcentre, vcoef, psize)+15),
                             ])
                      except:
                          print "pildiprobleem joonel"
                    

          
          
    security.declareProtected(perm_view, 'drawArrow')    
    def drawArrow(self, g, x1, y1, x2, y2, vcentre=None, vcoef=None, psize=None):
        "Draws the arrow to x1, y1"
        px1=self.pictureX(x1, vcentre, vcoef, psize)
        py1=self.pictureY(y1, vcentre, vcoef, psize)
        px2=self.pictureX(x2, vcentre, vcoef, psize)
        py2=self.pictureY(y2, vcentre, vcoef, psize)
        dx=px2-px1
        dy=py2-py1
        linelength=math.sqrt(dx*dx+dy*dy)
        arrowlength=10.0
        arrowangle=3.14/10
        acoef=arrowlength/linelength
        ax=dx*acoef
        ay=dy*acoef
        p1=self.rotatePoint(ax, ay, arrowangle)
        p2=self.rotatePoint(ax, ay, -arrowangle)
        g.line((px1, py1, px1+p1[0], py1+p1[1]))
        g.line((px1, py1, px1+p2[0], py1+p2[1]))
        
    
        
    security.declareProtected(perm_view, 'drawWidthLine')    
    def drawWidthLine(self, g, x1, y1, x2, y2, w, vcentre=None, vcoef=None, psize=None):
        "Draws line with specified width"
        px1=self.pictureX(x1, vcentre, vcoef, psize)
        py1=self.pictureY(y1, vcentre, vcoef, psize)
        px2=self.pictureX(x2, vcentre, vcoef, psize)
        py2=self.pictureY(y2, vcentre, vcoef, psize)
        dx=px2-px1
        dy=py2-py1
        linelength=math.sqrt(dx*dx+dy*dy)
        for i in range(int(linelength)):
          g.ellipse((px1+(i*1.0/linelength)*dx-w/2.0, 
                    py1+(i*1.0/linelength)*dy-w/2.0, 
                    px1+(i*1.0/linelength)*dx+w/2.0, 
                    py1+(i*1.0/linelength)*dy+w/2.0)
                   )        


    security.declareProtected(perm_view, 'drawParallelLine')    
    def drawParallelLine(self, g, x1, y1, x2, y2, nr, vcentre=None, vcoef=None, psize=None):
        "Draws parrallel line to increase line width"
        px1=self.pictureX(x1, vcentre, vcoef, psize)
        py1=self.pictureY(y1, vcentre, vcoef, psize)
        px2=self.pictureX(x2, vcentre, vcoef, psize)
        py2=self.pictureY(y2, vcentre, vcoef, psize)
        dx=px2-px1
        dy=py2-py1
        linelength=math.sqrt(dx*dx+dy*dy)
        arrowlength=nr
        arrowangle=3.14/2
        acoef=arrowlength/linelength
        ax=dx*acoef
        ay=dy*acoef
        p1=self.rotatePoint(ax, ay, arrowangle)
  #      p2=self.rotatePoint(ax, ay, -arrowangle)
        g.line((px1+p1[0], py1+p1[1], px2+p1[0], py2+p1[1]))
        g.line((px1-p1[0], py1-p1[1], px2-p1[0], py2-p1[1]))
  #      g.line((px1, py1, px1+p2[0], py1+p2[1]))
        
    def rotatePoint(self, x, y, angle):
        "Rotates point by angle over 0, 0"
        p=[0, 0]
        p[0]=x*math.cos(angle)-y*math.sin(angle)
        p[1]=y*math.cos(angle)+x*math.sin(angle)
        return p

    def getFontName(self):
        if hasattr(self, 'currentFontName'):
          if self.fontindex==1:
            return self.currentFontName
        return None

    def loadCurrentFont(self):
        "Loading font. Needs .pil and .pbm files for font"
        fontname=self.fontfiles[self.fontindex]
        try:
                import ImageFont
                import os
                font=ImageFont.ImageFont()
                insthome = Globals.INSTANCE_HOME
                filename=insthome+"/Products/iva/"+fontname
                file = open(filename, "rb")

                for ext in (".png", ".gif", ".pbm"):
                   try:
                       fullname = os.path.splitext(filename)[0] + ext
                       image = Image.open(fullname)
                   except:
                       pass
                   else:
                       if image and image.mode in ("1", "L"):
                          break
                else:
                   raise IOError("cannot find glyph data file")


                font._load_pilfont_data(file, image)
                return font
        except:
                return None

    security.declareProtected(perm_view, 'makePicture')
    def makePicture(self, type="normal"):
        "Joonistuskasud sobivas jarjekorras"
        from PIL import Image, ImageDraw
        font=None
        if type=="normal":
          psize=self.picturesize
          vcoef=self.viewcoef
          vcentre=self.viewingcentre
          font=self.loadCurrentFont()

        if type=="plan":
          psize=self.planpicturesize
          b=self.getBounds()
          #???
          if self.viewingbounds[0]+self.viewingbounds[2]>b[0]+b[2]:
            b[2]=self.viewingbounds[0]+self.viewingbounds[2]-b[0]
          if self.viewingbounds[1]+self.viewingbounds[3]>b[1]+b[3]:
            b[3]=self.viewingbounds[1]+self.viewingbounds[3]-b[1]
          if self.viewingbounds[0]<b[0]:
            b[2]+=b[0]-self.viewingbounds[0]
            b[0]=self.viewingbounds[0]
          if self.viewingbounds[1]<b[1]:
            b[3]+=b[1]-self.viewingbounds[1]
            b[1]=self.viewingbounds[1]
          vcentre=[b[0]+b[2]/2.0, b[1]+b[3]/2.0]
          try:
            vcoef=min(psize[0]*1.0/b[2], psize[1]*1.0/b[3])
          except:
            vcoef=1 #if bounds=0
        pilt=Image.new('RGB', psize)
        g=ImageDraw.ImageDraw(pilt)
        self.clearPicture(g, psize)
        if type=="normal":
          self.drawEdges(g, vcentre, vcoef, psize, pilt, font=font)
          self.drawWords(g, vcentre, vcoef, psize, pilt, font=font)
        if type=="plan":
          self.drawWords(g, vcentre, vcoef, psize, pilt, withicons=0)
          self.drawEdges(g, vcentre, vcoef, psize, pilt, withicons=0)
          g.setink(self.viewingboundslinecolor)
          g.rectangle((
            self.pictureX(self.viewingbounds[0], vcentre, vcoef, psize),
            self.pictureY(self.viewingbounds[1], vcentre, vcoef, psize),
            self.pictureX(self.viewingbounds[0]+self.viewingbounds[2], vcentre, vcoef, psize)-1,
            self.pictureY(self.viewingbounds[1]+self.viewingbounds[3], vcentre, vcoef, psize)-1            
          ))
        if self.selectedareafirstclick:
          g.setink(self.selectedarealinecolor)
          g.rectangle((
             self.pictureX(self.selectedareafirstclick[0], vcentre, vcoef, psize),
             self.pictureY(self.selectedareafirstclick[1], vcentre, vcoef, psize),
             self.pictureX(self.selectedareafirstclick[0], vcentre, vcoef, psize)+2,
             self.pictureY(self.selectedareafirstclick[1], vcentre, vcoef, psize)+2,
          ))          
        if self.selectedarea:
          g.setink(self.selectedarealinecolor)
          g.rectangle((
            self.pictureX(self.selectedarea[0], vcentre, vcoef, psize),
            self.pictureY(self.selectedarea[1], vcentre, vcoef, psize),
            self.pictureX(self.selectedarea[0]+self.selectedarea[2], vcentre, vcoef, psize)-1,
            self.pictureY(self.selectedarea[1]+self.selectedarea[3], vcentre, vcoef, psize)-1                      
          ))
        pilt2=pilt.resize(psize, Image.ANTIALIAS)
        return pilt2          
#        return pilt
                     

    security.declareProtected(perm_view, 'findWordInPicture')
    def findWordInPicture(self, x, y):
        "Valitud kohal asuva sona jarjekorranumber. Puudumisel -1"
        from PIL import Image, ImageDraw
        pilt=Image.new('RGB', self.picturesize)
        g=ImageDraw.ImageDraw(pilt)
        leitud=-1
        x=float(x)
        y=float(y)
        font=self.loadCurrentFont()
        for nr in range(len(self.wordplaces)):
            if x>=self.wordplaces[nr][0] and x<=self.wordplaces[nr][0]+g.textsize(getattr(self, self.wordids[nr]).title, font=font)[0]/self.viewcoef and \
               y>=self.wordplaces[nr][1] and y<=self.wordplaces[nr][1]+g.textsize(getattr(self, self.wordids[nr]).title, font=font)[1]/self.viewcoef:
                  leitud=nr
        return leitud 

    def findEdgeInPicture(self, x, y):
        "Returns edge in place or None"
        x=float(x)
        y=float(y)
        for p1 in range(len(self.wordids)):
          for p2 in range(len(self.wordids)):
            if p2 in self.relationnumbers[p1] or p1 in self.relationnumbers[p2]:
              x1=self.wordplaces[p1][0]
              y1=self.wordplaces[p1][1]
              x2=self.wordplaces[p2][0]
              y2=self.wordplaces[p2][1]
              a=y2-y1
              b=x1-x2
              c=y1*(x2-x1)-x1*(y2-y1)
              import math
              try:
               d=abs(a*x+b*y+c)/math.sqrt(a*a+b*b)
               if d<self.selectingdistance:
                if x>=min(x1, x2)-self.selectingdistance and x<=max(x1, x2)+self.selectingdistance and  \
                   y>=min(y1, y2)-self.selectingdistance and y<=max(y1, y2)+self.selectingdistance: 
                  return [p1, p2]
              except:
               pass
        return None
      

    security.declareProtected(perm_view, 'getPicture')
    def getPicture(self, REQUEST):
        "Pilt ekraanile"
        import cStringIO
        puhver=cStringIO.StringIO()
        self.makePicture().save(puhver, 'gif')
        REQUEST.RESPONSE.setHeader("Content-type", "image/gif")  
        return puhver.getvalue()
        
    security.declareProtected(perm_view, 'getPlanPicture')
    def getPlanPicture(self, REQUEST):
        "Small picture where visible viewing area location in map"
        import cStringIO
        puhver=cStringIO.StringIO()
        self.makePicture("plan").save(puhver, 'gif')
        REQUEST.RESPONSE.setHeader("Content-type", "image/gif")  
        return puhver.getvalue()

    
    def savePicture(self, failinimi='pilt.gif'):
        "Pildi salvestus faili"
        self.makePicture().save(failinimi, 'gif')
        
    security.declareProtected(perm_view, 'zoomToBounds')
    def zoomToBounds(self):
        "Set all words visible"
        self.viewingbounds=self.getBounds()
        self.viewingcentre[0]=self.viewingbounds[0]+self.viewingbounds[2]/2.0
        self.viewingcentre[1]=self.viewingbounds[1]+self.viewingbounds[3]/2.0
        self.viewcoef=min(self.picturesize[0]*1.0/self.viewingbounds[2], self.picturesize[1]*1.0/self.viewingbounds[3])


    security.declareProtected(perm_view, 'recalculateViewingBounds')
    def recalculateViewingBounds(self):
        "Recalculates viewing bounds using viewingcentre, picture size and viewcoef"        
        self.viewingbounds=[
          self.viewingcentre[0]-self.picturesize[0]/2.0/self.viewcoef,
          self.viewingcentre[1]-self.picturesize[1]/2.0/self.viewcoef,
          self.picturesize[0]*1.0/self.viewcoef,
          self.picturesize[1]*1.0/self.viewcoef
        ]

    security.declareProtected(perm_view, 'calculateZoomWithPoint')
    def calculateZoomWithPoint(self, x, y, direction='bigger'):
        "Calculates new displaying properties using user click data"
        self.viewingcentre=[x, y]
        if direction=="bigger": self.viewcoef*=(1+self.zoomcoef)
        if direction=="smaller": self.viewcoef/=(1.0+self.zoomcoef)
        self.recalculateViewingBounds()
        
    security.declareProtected(perm_view, 'checkPlanPlacing')
    def checkPlanPlacing(self, REQUEST):
        "If user changes location clicking to plan"
        if hasattr(REQUEST, 'plan1.x') and hasattr(REQUEST, 'plan1.y'):
          psize=self.planpicturesize
          b=self.getBounds()
          vcentre=[b[0]+b[2]/2.0, b[1]+b[3]/2]
          vcoef=min(psize[0]*1.0/b[2], psize[1]*1.0/b[3])
          self.viewingcentre[0]=self.worldX(int(getattr(REQUEST, 'plan1.x')), vcentre, vcoef, psize)
          self.viewingcentre[1]=self.worldY(int(getattr(REQUEST, 'plan1.y')), vcentre, vcoef, psize)
          self.recalculateViewingBounds()
          
          
    security.declareProtected(perm_edit, 'checkNewWords')
    def checkNewWords(self, REQUEST):
        "Add new words to picture, if they exists"
        if hasattr(REQUEST, 'newwords'):
          if len(REQUEST.newwords)>0:
             wds=REQUEST.newwords.split(",")
             for wd in wds:
               if len(wd)>0:
                self.addWord(wd.strip(), creator=self.firstAndLast(str(REQUEST.AUTHENTICATED_USER)))
                self.selectSoloIcon(0)
                
    security.declareProtected(perm_view, 'checkSampleData')
    def checkSampleData(self, REQUEST):
        "If sample data button is pressed"
        if hasattr(REQUEST, 'sampledata'):
           self.setSampleData()
                
    security.declareProtected(perm_view, 'checkClearAll')
    def checkClearAll(self, REQUEST):
        "If sample data button is pressed"
        if hasattr(REQUEST, 'clearall'):
           self.initializeVariables()
                
    security.declareProtected(perm_view, 'checkCommands')
    def checkCommands(self, REQUEST):
        "Check commands from Web page"
        if hasattr(REQUEST, 'actionnr'):
           self.setActiveAction(REQUEST.actionnr)
#        self.checkViewpointMoving(REQUEST)
        if hasattr(REQUEST, 'pnr'):
          self.wmap_pichandler(REQUEST, REQUEST.pnr)
        self.checkPlanPlacing(REQUEST)
        self.checkNewWords(REQUEST)
        self.checkSampleData(REQUEST)
        self.checkClearAll(REQUEST)
        self.selectedarea=None
          
    def wmap_pichandler(self, REQUEST, pnr):
        "Icon click handler"
        pnr=int(pnr)
        self.additionalpictures=[]
        if pnr>=8 and pnr<=11: #arrows
            if pnr==8: self.viewingcentre[0]-=self.viewingbounds[2]/2.0
            if pnr==9: self.viewingcentre[0]+=self.viewingbounds[2]/2.0
            if pnr==10: self.viewingcentre[1]-=self.viewingbounds[3]/2.0
            if pnr==11: self.viewingcentre[1]+=self.viewingbounds[3]/2.0
            self.recalculateViewingBounds()            
        if pnr==6:
            self.selectSoloIcon(6)
            self.activeaction=0 #Horizontal tree
        if pnr==7:
            self.selectSoloIcon(7)
            self.activeaction=6 #RayCircleTree
            
        if pnr==2:
            self.selectSoloIcon(2)
#            self.activeaction=7 #Zoom Bigger
        if pnr==3:
            self.selectSoloIcon(3)
#            self.activeaction=8 #Zoom smaller
            
        if pnr==4:
            self.selectSoloIcon(4)
            self.activeaction=2 #Add edge
            
        if pnr==5:  #removebuttonclick
            if self.selectededge:
                self.removeEdge(self.selectededge[0], self.selectededge[1])
                self.selectededge=None
            else:    
                self.hideSelectedWords()
            self.selectSoloIcon(5)
            
        if pnr==1:
            self.selectSoloIcon(1)
            self.activeaction=9 #Select area
            self.pictureselections[12]=1
            
        if pnr==0:
            self.selectSoloIcon(0)
            self.closeMenus()
            self.activeaction=11 #Selecting arrow
            
        if pnr==12:
            self.selectSoloIcon(12)
        if pnr==13: #Selection area submenu
            self.selectSoloIcon(13)
            self.selectedarea=None
            self.selectedareafirstclick=None
            
        if pnr==14: #unselect all
            self.selectedwords=[]
            
        if pnr==18: #Selection move left
            self.moveSelection(-1,  0)
            
        if pnr==19: #Selection move right
            self.moveSelection( 1,  0)
            
        if pnr==20: #Selection move up
            self.moveSelection( 0, -1)
            
        if pnr==21: #Selection move down
            self.moveSelection( 0,  1)
            
        if pnr==22: #Edit menu
            self.closeMenus()
            self.pictureselections[22]=1
            self.selectSoloIcon(4)
            #self.pictureselections[22]=1-self.pictureselections[22]
            #if self.pictureselections[22]:
            #  self.selectSoloIcon(4)
            #else:  
            # if self.pictureselections[4] or \
            #   self.pictureselections[6] or \
            #   self.pictureselections[7]:
            #     self.selectSoloIcon(0)

        if pnr==23: #Select menu
            self.closeMenus()
            self.pictureselections[23]=1
            self.selectSoloIcon(12)
            #self.pictureselections[23]=1-self.pictureselections[23]
            #if self.pictureselections[23]:
            #  self.selectSoloIcon(12)
            #else:
            #  if self.pictureselections[12] or \
            #     self.pictureselections[13]:
            #        self.selectSoloIcon(0)

        if pnr==24: #Zoom menu
            self.closeMenus()
            self.pictureselections[24]=1
            self.selectSoloIcon(2)
            #self.pictureselections[24]=1-self.pictureselections[24]
            #if self.pictureselections[24]:
            #   self.selectSoloIcon(2)
            #else:
            #   if self.pictureselections[2] or \
            #      self.pictureselections[3]:
            #         self.selectSoloIcon(0)
        
        if pnr==25: #zoom to bounds
           self.zoomToBounds()
           self.selectSoloIcon(0)


    def selectSoloIcon(self, pnr):
        "Only this icon will be selected"
        for i in range(len(self.pictureselections)):
          if i not in self.menuicons:
            self.pictureselections[i]=0
        self.pictureselections[int(pnr)]=1
        self.selectededge=None
        
    security.declareProtected(perm_view, 'closeMenus')
    def closeMenus(self):
        "All menus will be closed"
        for nr in self.menuicons:
          self.pictureselections[nr]=0


    security.declareProtected(perm_view, 'wmapindex_handler')
    def wmapindex_handler(self, REQUEST):
        "ZPT form handler"
        self.checkCommands(REQUEST)
        if hasattr(REQUEST, 'map1.x') and hasattr(REQUEST, 'map1.y'):
             x=self.worldX(int(getattr(REQUEST, 'map1.x')))
             y=self.worldY(int(getattr(REQUEST, 'map1.y')))
             if self.pictureselections[6]:
                 self.startHorizontalTreeCalculation(x, y)
#             if self.activeaction==1:
#                 self.startMoving(x, y)
             if self.pictureselections[4]:
                 self.addEdgeInPicture(REQUEST, x, y)
#             if self.activeaction==3:
#                 self.removeEdgeFromPicture(x, y)
             if self.pictureselections[5]:
                  self.removeFromPicture(x, y)
#             if self.activeaction==5:
#                 self.startCircleTreeCalculation(x, y)
             if self.pictureselections[7]:
                 self.startRayCircleTreeCalculation(x, y)
             if self.pictureselections[2]:
                 self.calculateZoomWithPoint(x, y, "bigger")
             if self.pictureselections[3]:
                 self.calculateZoomWithPoint(x, y, "smaller")
             if self.pictureselections[12] or self.pictureselections[0]:
                 self.selectingPointerClick(x, y)
             if self.pictureselections[13]:
                 self.selectedAreaClick(x, y)
        REQUEST.RESPONSE.redirect('wmapindex')
        
    def moveSelection(self, dx, dy):
       "Move selected words"
       dx*=self.movingdistanceinscreen/self.viewcoef
       dy*=self.movingdistanceinscreen/self.viewcoef
       for wi in self.selectedwords:
         self.wordplaces[wi][0]+=dx
         self.wordplaces[wi][1]+=dy          
        
    security.declareProtected(perm_view, 'selectArrow')
    def selectArrow(self, x, y):
        "Selecting with arrow"
        self.selectedwords=[]
        self.selectededge=None
        wi=self.findWordInPicture(x, y)
        if wi!=-1:
          self.selectedwords.append(wi)
          return
        self.selectededge=self.findEdgeInPicture(x, y)
          


    security.declareProtected(perm_view, 'removeFromPicture')
    def removeFromPicture(self, x, y):
        "Removing selected things"
        sona=self.findWordInPicture(x, y)
        if sona!=-1:
          self.removeWord(sona)
        if not self.selectededge:
          self.selectededge=self.findEdgeInPicture(x, y)
        if self.selectededge:
          self.removeEdge(self.selectededge[0], self.selectededge[1])
          self.selectededge=None
           

    security.declareProtected(perm_view, 'addEdgeInPicture')
    def addEdgeInPicture(self, REQUEST, x, y):
        "Adding edge"
        sona=self.findWordInPicture(x, y)
        if sona==-1:
          self.selectedwords=[]
          return
        if not self.selectedwords:
          self.selectedwords.append(sona)
          return
        self.addEdge(self.selectedwords[0], sona, self.firstAndLast(str(REQUEST.AUTHENTICATED_USER)))
        self.selectedwords=[]
        
    security.declareProtected(perm_view, 'addEdge')
    def addEdge(self, word1, word2, creator=""):
        "Adding edge data"
        wordmin=word1
        wordmax=word2
        if word1>word2:
            wordmin=word2
            wordmax=word1
        if wordmax not in self.relationnumbers[wordmin]:
            self.relationnumbers[wordmin].append(wordmax)
        if wordmin not in self.relationnumbers[wordmax]:
            self.relationnumbers[wordmax].append(wordmin)
            
        egid='eg'+str(self.getNewEdgeID())
        eg=MapEdge(self.wordids[word1], self.wordids[word2], creator)
        eg.id=egid
        self._setObject(egid, eg)
        
                    
    security.declareProtected(perm_view, 'removeEdgeFromPicture')
    def removeEdgeFromPicture(self, x, y):
        "Removing edge in coordinaates"
        e=self.findEdgeInPicture(x, y)
        if e is None:
          self.selectededge=None
          return
        if e==self.selectededge:
          self.removeEdge(e[0], e[1])
          self.selectededge=None
          return
        self.selectededge=e

    security.declareProtected(perm_view, 'removeEdge')
    def removeEdge(self, word1, word2):
        "Kylje eemaldus"
        if word1 in self.relationnumbers[word2]:
          self.relationnumbers[word2].remove(word1)
        if word2 in self.relationnumbers[word1]:
          self.relationnumbers[word1].remove(word2)
        sw=self.wordids[word1]
        ew=self.wordids[word2]
        for eg in self.objectValues('MapEdge'):
          if (eg.startword==sw and eg.endword==ew) or \
             (eg.startword==ew and eg.endword==sw):
               self._delObject(eg.id)
                          

    def getSelectedEdge(self):
        "Get selected edge from OFS or None if no edge selected"
        if self.selectededge:
          eg= self.getEdge(self.wordids[self.selectededge[0]], self.wordids[self.selectededge[1]])
          return eg
        return None 
                          
        

    security.declareProtected(perm_view, 'hideSelectedWords')
    def hideSelectedWords(self):
       "Removing word edges and set word content empty"
       while self.selectedwords:
         wordnr=self.selectedwords.pop()
         self.removeWord(wordnr)
       
       
    security.declareProtected(perm_view, 'removeWord')
    def removeWord(self, wordnr):
       "Remove word and recalculate all edge indexes bigger the word"
       self.wordplaces.pop(wordnr)
       while self.relationnumbers[wordnr]:
          nr=self.relationnumbers[wordnr].pop()
          self.removeEdge(wordnr, nr)
       self.relationnumbers.pop(wordnr)
       for rn in self.relationnumbers:
         for i in range(len(rn)):
           if rn[i]>wordnr:
             rn[i]-=1
       if wordnr in self.selectedwords:
          self.selectedwords.remove(wordnr)
       for i in range(len(self.selectedwords)):
         if self.selectedwords[i]>wordnr:
            self.selectedwords[i]-=1
       self._delObject(self.wordids[wordnr])
       self.wordids.pop(wordnr)
             
          
    security.declareProtected(perm_view, 'addWord')
    def addWord(self, word, creator=""):
        "Add word to graph and picture"
        #self.words.append(word)
        wdid='wd'+str(self.getNewWordID())
        wdobj=MapWord(word, creator=creator, backgroundcolorindex=self.wordbackgroundcolordefaultindex)
        wdobj.id=wdid
        self._setObject(wdid, wdobj)
        self.wordids.append(wdid)
        self.relationnumbers.append([])
        x=self.viewingbounds[0]+self.leftdistance*1.0/self.viewcoef
        y=self.viewingbounds[1]+self.topdistance*1.0/self.viewcoef
        while self.findWordInPicture(x, y)>=0:
          y+=1.0/self.viewcoef
        self.wordplaces.append([x, y])

    security.declareProtected(perm_view, 'startHorizontalTreeCalculation')    
    def startHorizontalTreeCalculation(self, x, y):
       "Hiirevajutusest saadud andmed"
       sona=self.findWordInPicture(x, y)
       if sona!=-1:
          self.calculateDistances(sona)
          self.calculateHorizontalTree()
          self.selectedwords=[sona,]
    

    security.declareProtected(perm_view, 'startCircleTreeCalculation')    
    def startCircleTreeCalculation(self, x, y):
       "Hiirevajutusest saadud andmed"
       sona=self.findWordInPicture(x, y)
       if sona!=-1:
          self.calculateDistances(sona)
          self.calculateCircleTree()


    security.declareProtected(perm_view, 'startRayCircleTreeCalculation')    
    def startRayCircleTreeCalculation(self, x, y):
       "Hiirevajutusest saadud andmed"
       sona=self.findWordInPicture(x, y)
       if sona!=-1:
          self.calculateDistances(sona)
          self.calculateRayCircleTree()
          self.selectedwords=[sona,]


         
    security.declareProtected(perm_view, 'selectingPointerClick')
    def selectingPointerClick(self, x, y):
        "Mouse click, when selecting function is active"
        self.selectededge=self.findEdgeInPicture(x, y)
        if self.selectededge:
           self.selectedwords=[]
           return
        wi=self.findWordInPicture(x, y)
        if wi!=-1:
               if wi in self.selectedwords:
                   self.selectedwords.remove(wi)
               else:
                 if self.pictureselections[12]: #if select arrow in selection submenu
                   self.selectedwords.append(wi)
                 if self.pictureselections[0]:
                   self.selectedwords=[wi]
        else:
             if len(self.selectedwords)==1 and not self.selectededge:
               self.wordplaces[self.selectedwords[0]][0]=x
               self.wordplaces[self.selectedwords[0]][1]=y
               self.selectedwords=[]

    security.declareProtected(perm_view, 'selectedAreaClick')
    def selectedAreaClick(self, x, y):
        "Mouse click, when selecting function is active"
        if self.selectedareafirstclick is None and self.selectedarea is None:
          self.selectedareafirstclick=[x, y]
          return
        if self.selectedareafirstclick is not None and \
           self.selectedarea is None:
             minx=min(self.selectedareafirstclick[0], x)
             maxx=max(self.selectedareafirstclick[0], x)
             miny=min(self.selectedareafirstclick[1], y)
             maxy=max(self.selectedareafirstclick[1], y)
             #self.selectedarea=[             
             #  minx, miny, maxx-minx, maxy-miny
             #]
             self.selectedareafirstclick=None
             for wi in range(len(self.wordplaces)):
                if (
                    self.wordplaces[wi][0]>=minx and
                    self.wordplaces[wi][0]<=maxx and
                    self.wordplaces[wi][1]>=miny and
                    self.wordplaces[wi][1]<=maxy
                  ):
                    if wi not in self.selectedwords:
                        self.selectedwords.append(wi)
             return
        if self.selectedarea:
            if not self.isInSelectedArea(x, y):
                self.selectedareafirstclick=[x, y]
            self.selectedarea=None
            
          
    security.declareProtected(perm_view, 'isInSelectedArea')
    def isInSelectedArea(self, x, y):
       "test, is point in selected area"
       if not self.selectedarea: return 0
       if x>=self.selectedarea[0] and x<=self.selectedarea[0]+self.selectedarea[2] and \
          y>=self.selectedarea[1] and y<=self.selectedarea[1]+self.selectedarea[3]:
             return 1
       return 0
       
    security.declareProtected(perm_view, 'moveSelectedArea')
    def moveSelectedArea(self, x, y):
       "Left upper point of area to specified value. Moving all words in area"
       words=self.findWordsInSelectedArea()
       if words:
         dx=x-self.selectedarea[0]
         dy=y-self.selectedarea[1]
         for nr in words:
            self.wordplaces[nr][0]+=dx
            self.wordplaces[nr][1]+=dy
       self.selectedarea=None       
       
    security.declareProtected(perm_view, 'findWordsInSelectedArea')
    def findWordsInSelectedArea(self):
       "List of word indexes"
       result=[]
       for nr in range(len(self.wordplaces)):
         if self.isInSelectedArea(self.wordplaces[nr][0], self.wordplaces[nr][1]):
            result.append(nr)            
       return result
       

    security.declareProtected(perm_view, 'toString')
    def toString(self):
       "Vahetulemused statistika tarbeks"
       t= " relationnumbers:" +str(self.relationnumbers) +\
          " selectededge: "+str(self.selectededge)+str(self.getSelectedEdge())+str(self.wordids)+\
          str(self.getEdge(2, 4))+str(self.selectedwords)
       return t
       
    def getBounds(self):
       "Minimal rectangle to place words. x, y, width, height"
       if len(self.wordplaces)==0:
         return [0, 0, self.picturesize[0], self.picturesize[1]]
       minx=maxx=self.wordplaces[0][0]
       miny=maxy=self.wordplaces[0][1]
       pilt=Image.new('RGB', [5, 5])
       g=ImageDraw.ImageDraw(pilt)
       for nr in range(len(self.wordplaces)):
         place=self.wordplaces[nr]
         if place[0]<minx: minx=place[0]
         if place[0]+g.textsize(getattr(self, self.wordids[nr]).title)[0]>maxx: 
              maxx=place[0]+g.textsize(getattr(self, self.wordids[nr]).title)[0]
         if place[1]<miny: miny=place[1]
         if place[1]+g.textsize(getattr(self,self.wordids[nr]).title)[1]>maxy: 
              maxy=place[1]+g.textsize(getattr(self, self.wordids[nr]).title)[1]
#       if self.viewingbounds[0]<minx: minx=self.viewingbounds[0]
#       if self.viewingbounds[1]<miny: miny=self.viewingbounds[1]
#       if self.viewingbounds[0]+self.viewingbounds[2]>maxx: 
#          maxx=self.viewingbounds[0]+self.viewingbounds[2]
#       if self.viewingbounds[1]+self.viewingbounds[3]>maxy: 
#          maxy=self.viewingbounds[1]+self.viewingbounds[3]
       return [minx, miny, maxx-minx, maxy-miny]
       
    security.declareProtected(perm_view, 'isAllWordsVisible')
    def areAllWordsVisible(self):
        "True if nothing is invisible in big picture"
        visible=1
        b=self.getBounds()
        vb=self.viewingbounds
        if b[0]<vb[0]: visible=0
        if b[1]<vb[1]: visible=0
        if b[0]+b[2]>vb[0]+vb[2]: visible=0
        if b[1]+b[3]>vb[1]+vb[3]: visible=0
        return visible
   

#    security.declareProtected(perm_view, 'getActions')
#    def getActions(self):
#        "Return available actions list"
#        a=[
#          "Horizontal tree",
#          "Move word",
#          "Add edge",
#          "Remove edge",
#          "Remove word",
#          "Circle tree",
#          "Ray Circle tree",
#          "Zoom bigger",
#          "Zoom smaller",
#          "Select area",
#          "Move area"
#        ]
#        return a
        
        
    def getPictureSelections(self):
       "for test"
       return self.pictureselections
       
    security.declareProtected(perm_view, 'getActiveAction')
    def getActiveAction(self):
        "Current action"
        return "ac: "+str(self.activeaction)
    

    security.declareProtected(perm_view, 'setActiveAction')
    def setActiveAction(self, action):
       "setting property"
       self.activeaction=int(action)
       return self.activeaction


    def list_parents_to_top():
        "For breadgrumbs"
        return []


    security.declareProtected(perm_view, 'setSampleData')
    def setSampleData(self):
        "algandmed"
        gr={
         "Tallinn": {
           "Aegviidu": "", 
           "Valkla": "", 
           "Maardu": "", 
           "Rakvere": "", 
           "Kuressaare": "", 
         },
         "Aegviidu": {},
         "Valkla": {},
         "Maardu":{},
         "Rakvere": {"Roela": ""},
         "Roela": {}, 
         "Kuressaare":{"Kihelkonna": "", "Mustjala": ""}, 
         "Kihelkonna": {}, 
         "Mustjala": {"Tagala":""}, 
         "Tagala": {}, 
        }
        self.initializeVariables()
        self.readData(gr)
        self.calculateDistances(3)
        self.calculateHorizontalTree()
        self.selectedwords=[]
        return gr
        
    security.declareProtected(perm_view, 'getWordmapTree')
    def getWordmapTree(self):
       "Wordmaps to root"
       result=[]
       map=self
       while map.meta_type=='WordMap':
         result.append(map)
         map=map.aq_parent
       result.reverse()
       return result
       
    security.declareProtected(perm_view, 'get_name')
    def get_name(self):
       "name to breadgrumbs"
       return ""
       
    security.declareProtected(perm_view, 'canEdit')
    def canEdit(self, REQUEST):
        "Can current user edit the wordmap"
        return 1
       
    security.declareProtected(perm_view, 'getMonoSelectedWordPage')
    def getMonoSelectedWordPage(self, REQUEST):
        "Returns word view/edit page if exactly one word selected"
        if len(self.selectedwords)==1:
           return getattr(self, self.wordids[self.selectedwords[0]]).wordmaps_word_page(self, REQUEST)
        return ""
        
    security.declareProtected(perm_view, 'getSelectedEdgePage')
    def getSelectedEdgePage(self, REQUEST):
        "Returns word view/edit page if exactly one word selected"
        if not self.selectededge: return ""
        e=self.getEdge(self.wordids[self.selectededge[0]], self.wordids[self.selectededge[1]])
        if e:
          return e.wordmaps_edge_page(self, REQUEST)
        return ""
        
    security.declareProtected(perm_view, 'getEdgesStartedAtWdID')
    def getEdgesStartedAtWdID(self, wdid):
        "Returns list of edges"
        result=[]
        edges=self.objectValues('MapEdge')
        for e in edges:
           if e.startword==wdid: result.append(e)
        return result

    security.declareProtected(perm_view, 'getEdgesEndedAtWdID')
    def getEdgesEndedAtWdID(self, wdid):
        "Returns list of edges"
        result=[]
        edges=self.objectValues('MapEdge')
        for e in edges:
           if e.endword==wdid: result.append(e)
        return result

    security.declareProtected(perm_view, 'getEdgesWithWdID')
    def getEdgesWithWdId(self, wdid):
        "Edges connected to this word at start or at end"
        edges1=self.getEdgesStartedAtWdID(self, wdid)
        edges2=self.getEdgesEndedAtWdID(self, wdid)
        for e in edges2:
            edges1.append(e)
        return edges1
        
    
    security.declareProtected(perm_view, 'getEdge')
    def getEdge(self, wdid1, wdid2):
        "Edge with this ids"
        edges=self.objectValues('MapEdge')
        for e in edges:
          if (wdid1==e.startword and wdid2==e.endword) or \
             (wdid1==e.endword   and wdid2==e.startword) :
               return e
        return None
        
        
    
    security.declareProtected(perm_view, 'wordList')
    def wordList(self):
       "Words in map as text"
       t="id,title,description,creator,modifier\n"
       for w in self.objectValues('MapWord'):
          t+=str(w.id)+","+w.getTitle()+","+w.getDescription()+","+w.creator+","+w.modifier+"\n"
       return t
       
    security.declareProtected(perm_view, 'edgeList')
    def edgeList(self):
       "Edges in map as text"
       t="id,startword,endword,textinline,startarrow,endarrow,weight, type,creator,modifier\n"
       for e in self.objectValues("MapEdge"):
         t+=str(e.id)+","+e.getStartWordTitle()+","+e.getEndWordTitle()+","+e.getTextInLine()+","+\
           str(e.getStartArrow())+","+str(e.getEndArrow())+","+str(e.getWeight())+","+\
           e.getTypes()[e.getType()]+","+e.creator+","+e.modifier+"\n"
       return t   
       
    security.declareProtected(perm_view, 'edgeList')
    def dataList(self):
      "Words and edges in map as text"
      return "Nodes:\n"+self.wordList()+"\nLinks:\n"+self.edgeList()
       
    def statRiPro(self):
        "RiPro puhul loendatakse kokku koik laused, mis on saanud hinnanguks 1-3 punkti"
        n=0
        for eg in self.objectValues('MapEdge'):
          if int(eg.weight)>0: n=n+1
        return n
           
    def statVnet(self):
        "Seoste arv jagatud moistete arvuga"
        if len(self.objectValues('MapWord'))==0:
          return "No words"
        try:
          return len(self.objectValues('MapEdge'))*1.0/len(self.objectValues('MapWord'))
        except:
          return "?"
        
    def statZentral(self):
        "Suurim seoste arv moiste kohta"
        n=0
        for x in self.relationnumbers:
           if len(x)>n: n=len(x)
        return n
        
    def statFach(self):
        "Hinnangute keskmine"
        s=0
        if self.statAlPro()==0:
           return "No edges"
        for eg in self.getMapEdges():
           s+=eg.weight
        return s*1.0/self.statAlPro()
        
    def statAlPro(self):
        "Seoste arv"
        return len(self.getMapEdges())
        
    def statInsel(self):
        "Saarekeste arv"
        kogus=len(self.getMapWords())
        if kogus==0: return 0
        saared=[]
        
        for i in range(kogus): saared.append(-1)
        saar=0
        veel=1
        while veel:
         koht=0
         while (koht<kogus) and saared[koht]!=-1: koht=koht+1
         if koht<kogus:
          saar=saar+1
          puhver=[koht,]
          while puhver: 
           print str(puhver)
           uuritav=puhver.pop()
           saared[uuritav]=saar
           for x in self.relationnumbers[uuritav]:
             if saared[x]==-1 and (x not in puhver):
              puhver.append(x)
         else:
           veel=0
        return saar  
        
    def statMapChar(self):
        "Kokkuvote"
        try:
           return 0.5*self.statFach()+0.4*self.statAlPro()+0.1*self.statVnet()
        except:
           return "Calculating problem"
        
        
        
    
    def wordmapStatistics(self):
        "Priit Reiska"
        t=""
        t+="RiPro: "+str(self.statRiPro())
        t+="\nVnet: "+str(self.statVnet())
        t+="\nZentral: "+str(self.statZentral())
        t+="\nFach: "+str(self.statFach())
        t+="\nInsel: "+str(self.statInsel())
        t+="\nMapChar: "+str(self.statMapChar())
              
        return t
        
        
    def wordmaps_weight_page_handler(self, REQUEST):
        "Handler"
        for eg in self.objectValues("MapEdge"):
            eg.weight=int(getattr(REQUEST, eg.id))
        REQUEST.RESPONSE.redirect('wordmaps_assessment_results')
      
       
    security.declareProtected(perm_view, 'XTMExport')
    def XTMExport(self):
        "Export to XTM XML format"
        from xml.dom import implementation, EMPTY_NAMESPACE
        from xml.dom.ext import PrettyPrint
#        doctype = implementation.createDocumentType("topicMap", "-//TopicMaps.Org//DTD XML Topic Map (XTM) 1.0//EN",
#                                                                 "http://www.topicmaps.org/xtm/#dtd")
#        dok=implementation.createDocument(EMPTY_NAMESPACE, "topicMap", doctype)
        dok=implementation.createDocument(EMPTY_NAMESPACE, "topicMap", None)
        dok.setAttribute("xmlns", "http://www.topicmaps.org/xtm/1.0/")
#        dok.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink")
        juur=dok.documentElement
        mapprop=dok.createElement('topic')
        juur.appendChild(mapprop)
        mapprop.setAttribute("id", "mapprop")
        baseName=dok.createElement("baseName")
        mapprop.appendChild(baseName)
        baseNameString=dok.createElement("baseNameString")
        baseName.appendChild(baseNameString)
        baseNameStringData=dok.createTextNode(self.title)
        baseNameString.appendChild(baseNameStringData)

        occurence=dok.createElement("occurence")
        mapprop.appendChild(occurence)
        occurence.setAttribute("id", "description")
        resourceData=dok.createElement("resourceData")
        occurence.appendChild(resourceData)
        resourceDataData=dok.createTextNode(self.description)
        resourceData.appendChild(resourceDataData)

        occurence=dok.createElement("occurence")
        mapprop.appendChild(occurence)
        occurence.setAttribute("id", "fontindex")
        resourceData=dok.createElement("resourceData")
        occurence.appendChild(resourceData)
        resourceDataData=dok.createTextNode(str(self.fontindex))
        resourceData.appendChild(resourceDataData)

        occurence=dok.createElement("occurence")
        mapprop.appendChild(occurence)
        occurence.setAttribute("id", "wordbackgroundcolordefaultindex")
        resourceData=dok.createElement("resourceData")
        occurence.appendChild(resourceData)
        resourceDataData=dok.createTextNode(str(self.wordbackgroundcolordefaultindex))
        resourceData.appendChild(resourceDataData)

        for t in self.wordcolortypes:
            occurence=dok.createElement("occurence")
            mapprop.appendChild(occurence)
            occurence.setAttribute("id", "wordcolortype")
            resourceData=dok.createElement("resourceData")
            occurence.appendChild(resourceData)
            resourceDataData=dok.createTextNode(t)
            resourceData.appendChild(resourceDataData)


        for wd in self.objectValues('MapWord'):
           wel=dok.createElement('topic')
           wel.setAttribute("id", wd.id)
           juur.appendChild(wel)
           baseName=dok.createElement("baseName")
           wel.appendChild(baseName)
           baseNameString=dok.createElement("baseNameString")
           baseName.appendChild(baseNameString)
           baseNameStringData=dok.createTextNode(wd.title)
           baseNameString.appendChild(baseNameStringData)

           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "description")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(wd.description)
           resourceData.appendChild(resourceDataData)

           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "creator");
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(wd.creator)
           resourceData.appendChild(resourceDataData)
           
           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "modifier")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(wd.modifier)
           resourceData.appendChild(resourceDataData)

           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "latexcode")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(wd.latexcode)
           resourceData.appendChild(resourceDataData)
           
           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "backgroundcolorindex")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(str(wd.backgroundcolorindex))
           resourceData.appendChild(resourceDataData)
           
           ind=self.wordids.index(wd.id)

           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "x")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(str(self.wordplaces[ind][0]))
           resourceData.appendChild(resourceDataData)
           
           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "y")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(str(self.wordplaces[ind][1]))
           resourceData.appendChild(resourceDataData)
           


           if wd.pilt:
             import base64
             occurence=dok.createElement("occurence")
             wel.appendChild(occurence)
             occurence.setAttribute("id", "picture")
             resourceData=dok.createElement("resourceData")
             occurence.appendChild(resourceData)
             resourceDataData=dok.createTextNode(base64.encodestring(wd.pilt))
             resourceData.appendChild(resourceDataData)

           
        for eg in self.objectValues("MapEdge"):
           association=dok.createElement("association")
           association.setAttribute("id", eg.id)
           juur.appendChild(association)
           member=dok.createElement("member")
           association.appendChild(member)
           topicRef=dok.createElement("topicRef")
           member.appendChild(topicRef)
           topicRef.setAttribute("xlink:href", "#"+eg.startword)
           member=dok.createElement("member")
           association.appendChild(member)
           topicRef=dok.createElement("topicRef")
           member.appendChild(topicRef)
           topicRef.setAttribute("xlink:href", "#"+eg.endword)

           wel=dok.createElement('topic')
           wel.setAttribute("id", eg.id+"-topic")
           juur.appendChild(wel)
           
           subjectIdentity=dok.createElement("subjectIdentity")
           wel.appendChild(subjectIdentity)
           subjectIndicatorRef=dok.createElement("subjectIndicatorRef")
           subjectIdentity.appendChild(subjectIndicatorRef)
           subjectIndicatorRef.setAttribute("xlink:href", "#"+eg.id)
           
           baseName=dok.createElement("baseName")
           wel.appendChild(baseName)
           baseNameString=dok.createElement("baseNameString")
           baseName.appendChild(baseNameString)
           baseNameStringData=dok.createTextNode(eg.text_in_line)
           baseNameString.appendChild(baseNameStringData)

           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "description")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(eg.description)
           resourceData.appendChild(resourceDataData)

           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "creator");
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(eg.creator)
           resourceData.appendChild(resourceDataData)
           
           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "modifier")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(eg.modifier)
           resourceData.appendChild(resourceDataData)

           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "latexcode")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(eg.latexcode)
           resourceData.appendChild(resourceDataData)
           
           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "startarrow")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(str(eg.startarrow))
           resourceData.appendChild(resourceDataData)
           
           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "endarrow")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(str(eg.endarrow))
           resourceData.appendChild(resourceDataData)
           
           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "type")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(str(eg.type))
           resourceData.appendChild(resourceDataData)
           
           occurence=dok.createElement("occurence")
           wel.appendChild(occurence)
           occurence.setAttribute("id", "weight")
           resourceData=dok.createElement("resourceData")
           occurence.appendChild(resourceData)
           resourceDataData=dok.createTextNode(str(eg.weight))
           resourceData.appendChild(resourceDataData)
           
           if eg.pilt:
             import base64
             occurence=dok.createElement("occurence")
             wel.appendChild(occurence)
             occurence.setAttribute("id", "picture")
             resourceData=dok.createElement("resourceData")
             occurence.appendChild(resourceData)
             resourceDataData=dok.createTextNode(base64.encodestring(eg.pilt))
             resourceData.appendChild(resourceDataData)
           
           
        dump=Dump()
        PrettyPrint(dok, stream=dump)
        return dump.getdata()
        
        
    security.declareProtected(perm_view, 'XTMExportWWW')
    def XTMExportWWW(self, REQUEST):
        "Output to web"
        REQUEST.RESPONSE.setHeader("Content-type", "text/xml")
        return self.XTMExport()

    def get_text(self,elem):
        res=u''
        for line in elem.childNodes:
                res += line.nodeValue
        return res
        #return to_utf8(res)
    def get_attr(self,elem,name):
        return elem.getAttribute(name)
        #return to_utf8(elem.getAttribute(name))



    security.declareProtected(perm_edit, 'XTMImport')
    def XTMImport(self, data):
        "Import as XTM XML"
        dok=xml.dom.minidom.parseString(data)
        self.initializeVariables()
        self.wordcolortypes=[]
        mapprop=dok.getElementsByTagName("topic")[0]
        if mapprop.getAttribute("id")=="mapprop":
              bname=mapprop.getElementsByTagName("baseName")[0]
              bstr=bname.getElementsByTagName("baseNameString")[0]
              self.title=self.get_text(bstr)
              for oc in mapprop.getElementsByTagName("occurence"):
                rd=oc.getElementsByTagName("resourceData")[0]
                id=self.get_attr(oc, "id")
                txt=self.get_text(rd)   
                if id=="description": self.description=txt
                if id=="fontindex": self.fontindex=int(txt)
                if id=="wordbackgroundcolordefaultindex":
                   self.wordbackgroundcolordefaultindex=int(txt)
                if id=="wordcolortype":
                   self.wordcolortypes.append(txt)
           
        for t in dok.getElementsByTagName("topic"):
           if t.getAttribute("id").startswith("wd"):
              bname=t.getElementsByTagName("baseName")[0]
              bstr=bname.getElementsByTagName("baseNameString")[0]
              wd=MapWord(self.get_text(bstr))
              wd.id=str(t.getAttribute("id"))
              self._setObject(wd.id, wd)
              idnr=int(wd.id[2:])
              if self.newwordidnr<idnr: self.newwordidnr=idnr
              self.wordids.append(wd.id)              
              self.relationnumbers.append([])
              for oc in t.getElementsByTagName("occurence"):
                rd=oc.getElementsByTagName("resourceData")[0]
                id=self.get_attr(oc, "id")
                txt=self.get_text(rd)   
                if id=="description": wd.description=txt
                if id=="creator": wd.creator=txt
                if id=="modifier": wd.modifier=txt
                if id=="latexcode": wd.latexcode=txt             
                if id=="backgroundcolorindex":
                   wd.backgroundcolorindex=int(txt)
                if id=="x": x=float(txt)
                if id=="y": 
                   y=float(txt)
                   self.wordplaces.append([x, y])
                if id=="picture":
                   import base64
                   wd.pilt=base64.decodestring(txt)
                   
        for a in dok.getElementsByTagName("association"):
            id=str(self.get_attr(a, "id"))
            sw=a.getElementsByTagName("member")[0].getElementsByTagName("topicRef")[0].getAttribute("xlink:href")[1:]
            ew=a.getElementsByTagName("member")[1].getElementsByTagName("topicRef")[0].getAttribute("xlink:href")[1:]
            eg=MapEdge(sw, ew)
            eg.id=id
            idnr=int(id[2:])
            if self.newedgeidnr<idnr: self.newedgeidnr=idnr
            
            self._setObject(eg.id, eg) 
            six=self.wordids.index(sw)
            eix=self.wordids.index(ew)
            self.relationnumbers[six].append(eix)
            self.relationnumbers[eix].append(six)
            at=a.nextSibling.nextSibling
            eg.text_in_line=self.get_text(at.getElementsByTagName("baseName")[0].getElementsByTagName("baseNameString")[0])
            for oc in at.getElementsByTagName("occurence"):
                rd=oc.getElementsByTagName("resourceData")[0]
                id=self.get_attr(oc, "id")
                txt=self.get_text(rd)   
                if id=="description": eg.description=txt
                if id=="creator": eg.creator=txt
                if id=="modifier": eg.modifier=txt
                if id=="latexcode": eg.latexcode=txt             
                if id=="startarrow": eg.startarrow=int(txt)
                if id=="endarrow": eg.endarrow=int(txt)
                if id=="type": eg.type=int(txt)
                if id=="weight": eg.weight=float(txt)
                if id=="picture":
                   import base64
                   eg.pilt=base64.decodestring(txt)
                   
        
        
    security.declareProtected(perm_edit, 'XTMImportWWW')
    def XTMImportWWW(self, REQUEST,  datafile):
       "Import from web"
       if len(datafile.filename)>0:
           self.XTMImport(datafile.read()) 
           REQUEST.RESPONSE.redirect('wmapindex')
       return self.message_dialog_error(
          self, REQUEST, 
          title='No data',
          message='No XML data submitted',
          action='wordmaps_managing_page'
       )

    security.declareProtected(perm_view, 'index_html')
    def index_html(self, REQUEST):
       "Index file"
       REQUEST.RESPONSE.redirect(self.absolute_url()+'/wmapindex')
#       return self.wmapindex(self, REQUEST)    



class MapWord(
     OFS.SimpleItem.Item,
     Persistent,
     AccessControl.Role.RoleManager,
     Traversable,
     Cruft
     ):
    "Word in concept map"
    security = AccessControl.ClassSecurityInfo()
    security.declareObjectPublic()
    
    security.declareProtected(perm_view, 'index_html')
    def __init__(self, title, description="", creator="", modifier="", backgroundcolorindex=0):
       "Initialize word"
       self.meta_type="MapWord"
       self.title=title
       self.pilt=None
       self.latexcode=""
       self.description=description
       self.creator=creator
       self.modifier=modifier
       self.backgroundcolorindex=backgroundcolorindex
       
    def makeCopy(self):
        "Copy of word"
        nw=MapWord(self.title, self.description)
        nw.pilt=self.pilt
        nw.latexcode=self.latexcode
        nw.backgroundcolorindex=self.backgroundcolorindex
        return nw
       
    security.declareProtected(perm_view, 'getTitle')
    def getTitle(self):
       "Title"
       return self.title
      
    security.declareProtected(perm_view, 'getDescription')
    def getDescription(self):
       "Description"
       return self.description
       
    security.declareProtected(perm_view, 'getWordBackgroundColorIndex')
    def getWordBackgroundColorIndex(self):
       "Background color index"
       return self.backgroundcolorindex
       
    security.declareProtected(perm_view, 'wordmaps_word_page_handler')
    def wordmaps_word_page_handler(self, REQUEST, title, description, t1=None, pildifail=None, valik=None, colorindex=0):
       "Save changes"
       self.title=title
       self.description=description
       self.modifier=self.firstAndLast(str(REQUEST.AUTHENTICATED_USER))
       self.backgroundcolorindex=int(colorindex)
       if t1:
         self.latexcode=t1
       if t1:
        try:
         t="\\documentclass[12pt]{article}\n"
         t+="\\pagestyle{empty}\n"
         t+="\\begin{document}\n"
         t+="\\begin{displaymath}\n"
         t+=t1+"\n"
         t+="\\end{displaymath}\n"
         t+="\\end{document}"
         failinimi=str(REQUEST.AUTHENTICATED_USER)
         f=open(failinimi+".tex", "w")
         f.write(t)
         f.close()
         import os
         insthome = Globals.INSTANCE_HOME                         
         os.system("python "+insthome+"/Products/iva/textogif.py "+failinimi+".tex >/dev/null 2>/dev/null")
         f3=open(failinimi+".gif", "r")
         self.pilt=f3.read()
         f3.close() 
         #return tekst
        except:
         print "latexprobleem"
       if pildifail:
           if len(pildifail.filename)>0:
             self.pilt=pildifail.read()  
             self.latexcode=""

             f=open("pilt.jpg", "w+b")
             f.write(self.pilt)
             f.close()
             p=Image.open("pilt.jpg")
             kast=p.getbbox()
             if max(kast)>150:
               p.thumbnail((150, 150), Image.ANTIALIAS)
               p.save("pilt.gif", "GIF")
               f=open("pilt.gif")
               self.pilt=f.read()
               f.close()            


       if valik:
           if valik=="0":
              pass
           elif valik=="-1":
              self.pilt=None
              self.latexcode=""
           else:
              self.pilt=getattr(self.aq_parent, valik).pilt
              self.latexcode=""
         
       REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())
       
    def hasPicture(self):
       "Is picture in word"
       if hasattr(self, 'pilt'):
          if self.pilt:
             return 1
       return 0
       
    def getPicture(self):
       "Gives picture if exists"
       if self.hasPicture():
         return self.pilt
       return "Pole"
       
    def canEdit(self, REQUEST):
        "Can user edit whole wordmap"
        return self.aq_parent.canEdit(REQUEST)
      
      
    
class MapEdge(
     OFS.SimpleItem.Item,
     Persistent,
     AccessControl.Role.RoleManager,
     Traversable,
     Cruft
     ):
    "Edge in concept map"
    security = AccessControl.ClassSecurityInfo()
    security.declareObjectPublic()
    
    security.declareProtected(perm_view, '__init__')
    def __init__(self, startword, endword, creator="", modifier=""):
        "Initialize edge"
        self.meta_type="MapEdge"
        self.startword=startword
        self.endword=endword
        self.creator=creator
        self.modifier=modifier
        self.pilt=None
        self.latexcode=""
       
        self.types=[
         "Connected",
         "Contains",
         "Uses",
         "Test",
         "Other"
        ]
        self.title=startword+"-"+endword
        self.startarrow=0
        self.endarrow=0
        self.text_in_line=""
        self.description=""
        self.type=0
        self.weight=1.0
        
    def makeCopy(self):
        "Copy of egde"
        ne=MapEdge(self.startword, self.endword)
        ne.types=self.types
        ne.title=self.title
        ne.startarrow=self.startarrow
        ne.text_in_line=self.text_in_line
        ne.description=self.description
        ne.type=self.type
        ne.weight=self.weight
        ne.pilt=self.pilt
        ne.latexcode=self.latexcode
        return ne
    security.declareProtected(perm_view, 'reverse')
    def reverse(self):
        "Changes edge direction"
        temp=self.startword
        self.startword=self.endword
        self.endword=temp

    security.declareProtected(perm_view, 'getTypes')
    def getTypes(self):
        "Get available connection types"
        return self.types
       
    security.declareProtected(perm_view, 'getType')
    def getType(self):
        "Get current connection type"
        return self.type    
       
    security.declareProtected(perm_view, 'getStartWordTitle')
    def getStartWordTitle(self):
        "starting word title"
        return getattr(self.aq_parent, self.startword).title    
       
    security.declareProtected(perm_view, 'getEndWordTitle')
    def getEndWordTitle(self):
        "ending word title"
        return getattr(self.aq_parent, self.endword).title    
       

    security.declareProtected(perm_view, 'getTitle')
    def getTitle(self):
        "Title of edge"
        return self.getStartWordTitle()+' - '+self.getEndWordTitle()

    security.declareProtected(perm_view, 'getTextInLine')
    def getTextInLine(self):
        "Returns text visible in arrow line"
        return self.text_in_line
        
    security.declareProtected(perm_view, 'getDescription')
    def getDescription(self):
        "Returns the description of the edge"
        return self.description

    security.declareProtected(perm_view, 'getWeight')
    def getWeight(self):
        "Returns weight of the edge"
        return self.weight

    security.declareProtected(perm_view, 'getStartArrow')
    def getStartArrow(self):
        "Is start arrow for edge"
        return self.startarrow

    security.declareProtected(perm_view, 'getEndArrow')
    def getEndArrow(self):
        "Returns weight of the edge"
        return self.endarrow

    def hasPicture(self):
       "Is picture in word"
       if hasattr(self, 'pilt'):
          if self.pilt:
             return 1
       return 0
       
    def getPicture(self):
       "Gives picture if exists"
       if self.hasPicture():
         return self.pilt
       return "Pole"
       


        
    security.declareProtected(perm_view, 'wordmaps_edge_page_handler')
    def wordmaps_edge_page_handler(self, REQUEST, textinline, description, weight, type, startarrow=0, endarrow=0, t1=None, pildifail=None, valik=None):
        "Data saving"
        self.text_in_line=textinline
        self.description=description
        self.weight=float(weight)
        self.type=int(type)
        self.startarrow=int(startarrow)
        self.endarrow=int(endarrow)
        self.modifier=self.firstAndLast(str(REQUEST.AUTHENTICATED_USER))
        if t1:
         self.latexcode=t1
         try:
          t="\\documentclass[12pt]{article}\n"
          t+="\\pagestyle{empty}\n"
          t+="\\begin{document}\n"
          t+="\\begin{displaymath}\n"
          t+=t1+"\n"
          t+="\\end{displaymath}\n"
          t+="\\end{document}"
          failinimi=str(REQUEST.AUTHENTICATED_USER)
          f=open(failinimi+".tex", "w")
          f.write(t)
          f.close()
          import os
          insthome = Globals.INSTANCE_HOME                         
          os.system("python "+insthome+"/Products/iva/textogif.py "+failinimi+".tex >/dev/null 2>/dev/null")
          f3=open(failinimi+".gif", "r")
          self.pilt=f3.read()
          f3.close() 
         except:
          print "seosega latexprobleem"
        
        if pildifail:
           if len(pildifail.filename)>0:
             self.pilt=pildifail.read()  
             self.latexcode=""

             #test if picture is small enough
             f=open("pilt.jpg", "w+b")
             f.write(self.pilt)
             f.close()
             p=Image.open("pilt.jpg")
             kast=p.getbbox()
             if max(kast)>150:
               p.thumbnail((150, 150), Image.ANTIALIAS)
               p.save("pilt.gif", "GIF")
               f=open("pilt.gif")
               self.pilt=f.read()
               f.close()            

        if valik:
           if valik=="0":
              pass
           elif valik=="-1":
              self.pilt=None
              self.latexcode=""
           else:
              self.pilt=getattr(self.aq_parent, valik).pilt
              self.latexcode=""
         

        REQUEST.RESPONSE.redirect(self.aq_parent.absolute_url())


class WordmapFolder(
     OFS.Folder.Folder,
     Persistent,
     AccessControl.Role.RoleManager,
     Traversable,
     Cruft
     ):
    "Holding set of wordmaps"

    security = AccessControl.ClassSecurityInfo()
    security.declareObjectPublic()
    
    def __init__(self):
        "Constructor"
        self.wordmapnr=0

    security.declareProtected(perm_view, 'getNewWordmapNr')
    def getNewWordMapNr(self):
        "Return growing number"
        self.wordmapnr+=1
        return self.wordmapnr


    security.declareProtected(perm_edit, 'addNewWordMap')
    def addNewWordMap(self):
        "Makes new course level wordmap"
        nr=self.getNewWordMapNr()
        m=WordMap()
        m.id='map'+str(nr)
        self._setObject(m.id, m)
        return m

    security.declareProtected(perm_view, 'getWordMaps')
    def getWordMaps(self):
        "Wordmaps in this course"
        return self.objectValues('WordMap')

    security.declareProtected(perm_edit, 'addWordMap_handler')
    def addWordMap_handler(self, REQUEST):
        "Adds new wordmap and redirects to index page"
        self.addNewWordMap()
        REQUEST.RESPONSE.redirect(self.absolute_url()+'/wordmaps_index_html')

    security.declareProtected(perm_edit, 'wordmaps_index_html_handler')
    def wordmaps_index_html_handler(self, REQUEST, wm=(), delete=None, assessment=None, settings=None):
        "Main page handler"
        if not wm:
          REQUEST.RESPONSE.redirect('wordmaps_index_html')
        if delete:
          return self.wordmaps_delete_confirm(REQUEST, wm)
        if assessment:
          REQUEST.RESPONSE.redirect(self.absolute_url()+"/"+wm+"/wordmaps_weight_page")
        if settings:
          REQUEST.RESPONSE.redirect(self.absolute_url()+"/"+wm+"/wordmaps_managing_page")

    security.declareProtected(perm_edit,'wordmaps_delete_confirm')
    def wordmaps_delete_confirm(self, REQUEST, wm=()):
        "Confirm deleting selected wordmaps"
        if not wm:
           REQUEST.RESPONSE.redirect('wordmaps_index_html')
           return
        return self.message_dialog2(self,REQUEST,
                        title="Confirmation",
                        message="Are you sure you want to delete wordmap?",
                        option1_name="cancel",
                        option1_value="Cancel",
                        option2_value="Delete",
                        option2_name="confirmation",
                        extra_value_name='delete',
                        extra_values = ('yes',),
                        item_name='wm',
                        item_value=wm,
                        handler="wordmaps_delete_handler")
        

    security.declareProtected(perm_edit,'wordmaps_delete_handler')
    def wordmaps_delete_handler(self, REQUEST, wm=(), cancel=None):
        "Deleting selected wordmaps"
        if not cancel:
            if type(wm) is types.StringType:
                wm=(wm,)
            for w in wm:
                self.wordmaps._delObject(w)
        REQUEST.RESPONSE.redirect(self.absolute_url()+'/wordmaps_index_html')

    def getWordmapTreeNode(self, map):
        "HTML for one node" 
        #Kuluks nuputada miski PT analoog
        st="<li><a href='"+map.absolute_url()+"' title='"+map.title+"'>"+map.id+"</a>"
        st+=" <a href='"+map.absolute_url()+"/wordmaps_managing_page'>*</a><br>"
        st+="<img src='"+map.absolute_url()+"/getPlanPicture' />"
        st+="</li>"
        if map.getChildMaps():
          st+="<ul>"
          for m in map.getChildMaps():
             st+=self.getWordmapTreeNode(m)
          st+="</ul>"
        return st

    security.declareProtected(perm_view, 'getWordmapTree')
    def getWordmapTree(self):
        "Maps with child maps HTML"
        st="<ul>"
        for m in self.objectValues('WordMap'):
           st+=self.getWordmapTreeNode(m)
        st+="</ul>"
        return st
        
    def XTMNewImportWWW(self, REQUEST, datafile, importfile=None):
       "New wordmap via importing"
       if not importfile:
          REQUEST.RESPONSE.redirect('wordmaps_index_html')
          return
       if len(datafile.filename)>0:
          m=self.addNewWordMap()
          m.XTMImport(datafile.read())
          REQUEST.RESPONSE.redirect('wordmaps_index_html')
          return
       else:
        return self.message_dialog_error(
          self, REQUEST, 
          title='No data',
          message='No XML data submitted',
          action='wordmaps_index_html'
        )

    security.declareProtected(perm_edit, 'add_new_wordmap')
    def add_new_wordmap(self):
        "we're adding new wordmap. In class WordMap returns 0"
        return 1
        
    security.declareProtected(perm_edit, 'getFontNames')
    def getFontNames(self):
        "Names used in wordmap settings"
        return ["small", "medium", "large"]
        
    def getWordBackgroundColors(self):
        "Background colors used for words"
        return (
          "#DB002B",
          "#3E6090",
          "#FFC600",
          "#666666",
          "#000000"
        )
        
    security.declareProtected(perm_edit, 'wordmaps_adding_page_handler')
    def wordmaps_adding_page_handler(self, REQUEST):
        "Adding new wordmap"
        from input_checks import is_valid_title
        if not is_valid_title(REQUEST.title):
            return self.message_dialog(
               message='Invalid title',
               action='wordmaps_managing_page?'+REQUEST.QUERY_STRING
            )
        m=self.addNewWordMap()
        m.wordmaps_management_page_handler(REQUEST, REQUEST.get('title', 'untitled'), 
            REQUEST.get('description',''), REQUEST.get('font',0), REQUEST.get('colorindex',0), 
            REQUEST.wordcolortype, redirect=0)
        REQUEST.RESPONSE.redirect('wordmaps_index_html')
        
#        return "olemas"

    security.declareProtected(perm_view, 'hasWordmaps')
    def hasWordmaps(self):
	""" Do we have wordmaps """
	return len(self.getWordMaps())>0
        
    security.declareProtected(perm_view, 'index_html')
    def index_html(self, REQUEST):
        "index page"
        REQUEST.RESPONSE.redirect(self.absolute_url()+'/wordmaps_index_html')

if __name__=="__main__":
    ""

