File:  [Repository] / ECHO_content / ECHO_collection.py
Revision 1.23: download - view: text, annotated - select for diffs - revision graph
Tue Mar 30 19:12:22 2004 UTC (20 years, 1 month ago) by dwinter
Branches: MAIN
CVS tags: HEAD
graphical overview now in zpt and templates are possible

"""New version of the product started February, 8th. Without scientific classification, use content-type for further classification."""
"""Echo collection provides the classes for the ECHO content web-site.

class ECHO_collection is the basis class for an ECHO collection.

class ECHO_resource contains information on ECHO resources (e.g. an Display environment for Metadata

class ECHO_externalLink contains information on externalLinks


"""
import string
import re
import OFS.Image
from types import *
from OFS.Image import Image
from Globals import DTMLFile
from OFS.Folder import Folder
from OFS.SimpleItem import SimpleItem
from AccessControl import ClassSecurityInfo
from Globals import InitializeClass
from Globals import DTMLFile
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PageTemplates.PageTemplate import PageTemplate
from Globals import Persistent
from Acquisition import Implicit
#from psycopg import libpq
#from pyPgSQL import libpq
import xml.dom.minidom

import urllib
import xml.dom.minidom
from ECHO_graphicalOverview import javaHandler,javaScriptMain

#List of different types for the graphical linking viewer
viewClassificationListMaster=['view point','area']


def toList(field):
    """Einzelfeld in Liste umwandeln"""
    if type(field)==StringType:
        return [field]
    else:
        return field
    
def getText(nodelist):

    rc = ""
    for node in nodelist:
    	if node.nodeType == node.TEXT_NODE:
           rc = rc + node.data
    return rc


def readMetadata(url):
    """Methoden zum Auslesen der Metadateninformation zu einer Resource
    Vorerst noch Typ bib"""
    
    metadict={}
    try:
        geturl=""
        for line in urllib.urlopen(url).readlines():
            geturl=geturl+line
        
        
    except:
        return (None,"Cannot open: "+url)

    try:
        dom=xml.dom.minidom.parseString(geturl)
    except:
        return (None,"Cannot parse: "+url+"<br>"+geturl)

    metanode=dom.getElementsByTagName('bib')
    metadict['bib_type']='Book'
    if len(metanode)==0:
        metanode=dom.getElementsByTagName('archimedes')
        metadict['bib_type']='Archimedes'
        #print "HELLO"
        
    if not len(metanode)==0:    
        metacontent=metanode[0].childNodes
    
        try:
            metadict['bib_type']=getText(dom.getElementsByTagName('bib')[0].attributes['type'].childNodes)
        except:
            """nothing"""
        
        for node in metacontent:
            try:
                metadict[node.tagName.lower()]=getText(node.childNodes)
            except:
                """nothing"""

    #print metadict
    return metadict,""
    

def setECHO_collectionInformation(self,title,label,description,content_type,responsible,credits,weight,coordstrs,viewClassification=""):

        """Allegemeine Informationen zu einer ECHO Collection"""

        self.viewClassification=viewClassification

        self.label = label
        self.title=title
        self.description=description
        self.content_type=content_type
        self.responsible=responsible
        self.credits=toList(credits)
        self.weight=weight

        coords=[]
        #coordinates of for rectangles

        #print "cs", coordstrs
        if coordstrs:
            for coordstr in coordstrs:
                #print "cs", coordstr
                try:
                    temco=coordstr.split(",")
                except:
                    temco=[]
                #temco.append(angle)
                coords.append(temco)


        self.coords=coords[0:]
            

class scientificClassification(SimpleItem,Persistent,Implicit):
    """outdated will be deleeted in the next versions: subclass"""
    security=ClassSecurityInfo()
    
    def __init__(self,context,science,practice):
        self.context=context
        self.science=science
        self.practice=practice
        self.id="scientific_Classification"
        
    security.declarePublic('get_context')
    def get_context(self):
        return self.context
    
    security.declarePublic('get_science')
    def get_science(self):
        return self.science
        
    security.declarePublic('get_practice')
    def get_practice(self):
        return self.practice
    
                
class scientificInformation(Folder,Persistent,Implicit):
    """outdated will be deleted in the next versions: subclass scientificInformation"""
    security=ClassSecurityInfo()
    
    
    
    def __init__(self,source_type,period):

        self.id="scientific_Information"
        self.source_type=source_type
        self.period=period
        


    security.declarePublic('get_source_type')
    def get_source_type(self):
        return self.source_type
    
    security.declarePublic('get_period')
    def get_period(self):
        return self.period


class ECHO_resource(Folder):
    """ECHO Ressource"""
    meta_type='ECHO_resource'

    viewClassificationList=viewClassificationListMaster

    def getViewClassification(self):
        if hasattr(self,'viewClassification'):
            return self.viewClassification
        else:
            return ""
        
    def getCredits(self):
        """Ausgabe der credits"""
        if self.credits:
            return self.credits
        else:
            return []
    
    def __init__(self,id,link,metalink,title,label,description,content_type,responsible,credits,weight,coords):

        self.id = id
        """Festlegen der ID"""
        
        self.label = label
        self.link= link
        self.metalink=metalink
        self.title=title
        self.weight=weight
        self.credits=toList(credits)
        self.description=description
        self.content_type=content_type
        self.responsible=responsible
        
        if coords:
            coordsnew=[ string.split(x,",") for x in coords]
        else:
            coordsnew=[]
        
        self.coords=coordsnew


    def getCoords(self):
        try:
            return [string.join(x,",") for x in self.coords]  
        except:
            return []


    def ECHO_resource_config(self):
        """Main configuration"""

        if not hasattr(self,'weight'):
            self.weight=""
        if not hasattr(self,'coords'):
            self.coords=[]

        print "vorher",self.coords
        pt=PageTemplateFile('Products/ECHO_content/zpt/ChangeECHO_resource.zpt').__of__(self)
        return pt()
    

    def changeECHO_resource(self,metalink,link,title,label,description,content_type,responsible,weight,viewClassification="",coords=None,credits=None,RESPONSE=None):
        """Änderung der Properties"""
        
        
        coordsnew=[ string.split(x,",") for x in coords]
        
        
        setECHO_collectionInformation(self,title,label,description,content_type,responsible,credits,weight,coordsnew)

        self.coords=coordsnew[0:]
        self.link=link
        self.metalink=metalink
        
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')
            
            
    manage_options = Folder.manage_options+(
        {'label':'Main Config','action':'ECHO_resource_config'},
        {'label':'Metadata','action':'ECHO_getResourceMD'},
        {'label':'Graphics','action':'ECHO_graphicEntry'},
        )

    def getOverview(self):
        """overview graphics"""
        
        return self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['overview'])[0][1]

    def ECHO_graphicEntry(self):
        """DO nothing"""
        overview = self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['overview'])
        if overview: 
            pt=PageTemplateFile('Products/ECHO_content/zpt/ECHO_draw.zpt').__of__(self)
            return pt()
        else:
            return "NO OVERVIEW GRAPHICS"

    def ECHO_enterCoords(self,coordstr,angle="",RESPONSE=None):
        """Enter coords"""
        coords=self.coords
        temco=coordstr.split(",")
        temco.append(angle)
        coords.append(temco)
        
        self.coords=coords[0:]

        if RESPONSE is not None:
            RESPONSE.redirect('ECHO_graphicEntry')

    def ECHO_getResourceMD(self,template="yes"):
        """Einlesen der Metadaten und Anlegen dieser Metadaten als Informationen zur Resource"""
        (metadict, error)=readMetadata(self.metalink)



        if not error=="": #Fehler beim Auslesen des Metafiles
            return "ERROR:",error
        for key in metadict.keys():#Hinzufügen der Felder

            setattr(self,key,metadict[key].encode('ascii','replace'))
        

        self.metadata=metadict.keys()

        self.label=self.generate_label()
        
        if template=="yes":
            pt=PageTemplateFile('Products/ECHO_content/zpt/ECHO_resourceMD.zpt').__of__(self)
            return pt()
    
    def ECHO_getMD(self,item):
        """Ausgabe der MD"""
        return getattr(self,item)
        
    def index_html(self):
        """standard page"""
        
        return self.REQUEST.RESPONSE.redirect(self.link)

    def generate_label(self):
        """Erzeugt_standard_Label aus Template"""
        pt=getattr(self,"label_template_"+self.bib_type)

        return pt()

def manage_addECHO_resourceForm(self):
        """Form for adding a ressource"""
        pt=PageTemplateFile('Products/ECHO_content/zpt/AddECHO_resourceForm.zpt').__of__(self)
        return pt()



def manage_addECHO_resource(self,id,title,label,description,content_type,responsible,link,metalink,weight,credits=None,coords=None,RESPONSE=None):
    """addaresource"""

    newObj=ECHO_resource(id,link,metalink,title,label,description,content_type,responsible,credits,weight,coords)

    self._setObject(id,newObj)

    if RESPONSE is not None:
        RESPONSE.redirect('manage_main')
 

class ECHO_externalLink(Folder):
    """Link zu einer externen Ressource"""
    security=ClassSecurityInfo()
    meta_type='ECHO_externalLink'


    def __init__(self,id,link,title,label,description,content_type,responsible,credits,weight,coords):

        self.id = id
        """Festlegen der ID"""

        self.credits=toList(credits)
        self.label = label
        self.link= link
        self.title=title
        self.weight=weight
        self.description=description
        self.content_type=content_type
        self.responsible=responsible
        coordsnew=[ string.split(x,",") for x in coords]
        self.coords=coordsnew

    def ECHO_externalLink_config(self):
        """Main configuration"""

        if not hasattr(self,'weight'):
            self.weight=""
        if not hasattr(self,'coords'):
            
            self.coords=['']
            #print "G",self.coords

        pt=PageTemplateFile('Products/ECHO_content/zpt/ChangeECHO_externalLink.zpt').__of__(self)
        return pt()
    

    def changeECHO_externalLink(self,link,title,label,description,content_type,responsible,weight,coords=None,credits=None,RESPONSE=None):

        """Änderung der Properties"""
        coordsnew=[ string.split(x,",") for x in coords]

        setECHO_collectionInformation(self,title,label,description,content_type,responsible,credits,weight,coords)

        self.coords=coordsnew[0:]
        self.link=link
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')
            
            
    manage_options = Folder.manage_options+(
        {'label':'Main Config','action':'ECHO_externalLink_config'},
        )

    def getCredits(self):
        """Ausgabe der credits"""
        if self.credits:
            return self.credits
        else:
            return []
        
    def index_html(self):
        """standard page"""
        
        return self.REQUEST.RESPONSE.redirect(self.link)

def manage_addECHO_externalLinkForm(self):
        """Form for external Links"""
        pt=PageTemplateFile('Products/ECHO_content/zpt/AddECHO_externalLinkForm.zpt').__of__(self)
        return pt()


def manage_addECHO_externalLink(self,id,title,label,description,content_type,responsible,link,weight,coords=None,credits=None,RESPONSE=None):
    """Add an external Link"""

    newObj=ECHO_externalLink(id,link,title,label,description,content_type,responsible,credits,weight,coords)

    self._setObject(id,newObj)

    if RESPONSE is not None:
        RESPONSE.redirect('manage_main')
 
        
class ECHO_collection(Folder, Persistent, Implicit):
    """ECHO Collection"""
    security=ClassSecurityInfo()
    meta_type='ECHO_collection'

    def createJavaScript(self):
        """CreateJava"""
        ret=javaScriptMain

        dynamical=""
        for ob in self.getGraphicCoords():
            dynamical+="""Coords.push(new Coord('%s', Img, %s));\n"""%(ob[1],ob[0])
        ret+=javaHandler%dynamical
        return ret
    
    security.declarePublic('getCreditObject')
    def getCreditObject(self,name):
        """credit id to credititem"""
        try:
            return getattr(self.partners,name)
        except:
            return ""

    security.declarePublic('ECHO_generateNavBar')
    def ECHO_generateNavBar(self):
        """Erzeuge Navigationsbar"""
        link=""
        object="self"
        ret=[]
        path=self.getPhysicalPath()
        for element in path:
            
           
            if not element=="":
                object+="."+element
                
                label=eval(object).label
                link+="/"+element
                if not label=="":
                    ret.append((label,link))
        return ret
    
    security.declarePublic('ECHO_rerenderLinksMD')
    def ECHO_rerenderLinksMD(self):
        """Rerender all Links"""
        
        for entry in self.__dict__.keys():
            object=getattr(self,entry)
            
            
            try:
                
                if object.meta_type == 'ECHO_resource':
                    
                    object.ECHO_getResourceMD(template="no")
                    
            except:
                """nothing"""
                
        return "Rerenderd all links to resources in: "+self.title

    security.declarePublic('ECHO_newViewerLink')
    

    def getCoords(self):
        try:
            
            x=  [string.join(x,",") for x in self.coords]  
            return x

        except:

            return []
        
    def __init__(self,id,title,label,description,content_type,responsible,credits,weight,sortfield,coords):
        #print "CO",coords

        self.id = id
        """Festlegen der ID"""
        self.credits=toList(credits)
        self.label = label
        self.title=title
        self.description=description
        self.content_type=content_type
        self.responsible=responsible

        self.weight=weight
        self.sortfield=sortfield
        coordsnew=[ string.split(x,",") for x in coords]
        self.coords=coordsnew


    manage_options = Folder.manage_options+(
        {'label':'Main Config','action':'ECHO_collection_config'},
        {'label':'Rerender Links','action':'ECHO_rerenderLinksMD'},
        {'label':'Graphics','action':'ECHO_graphicEntry'},

        )

    def getOverview(self):
        """overview graphics"""
        
        return self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['overview'])[0][1]
    
    
    def ECHO_graphicEntry(self):
        """DO nothing"""
        overview = self.aq_parent.ZopeFind(self.aq_parent,obj_ids=['overview'])
        
    
        if overview:
            pt=PageTemplateFile('Products/ECHO_content/zpt/ECHO_draw.zpt').__of__(self)
            return pt()
        else:
            return "NO OVERVIEW GRAPHICS"

    def ECHO_enterCoords(self,coordstr,angle="",RESPONSE=None):
        """Enter coords"""
        coords=self.coords
        temco=coordstr.split(",")
        temco.append(angle)
        coords.append(temco)
        self.coords=coords[0:]

        if RESPONSE is not None:
            RESPONSE.redirect('ECHO_graphicEntry')

    
    security.declarePublic('ECHO_collection_config')
    def ECHO_collection_config(self):
        """Main configuration"""

        if not hasattr(self,'weight'):
            self.weight=""

        if not hasattr(self,'sortfield'):
            self.sortfield="weight"
  
        if not hasattr(self,'coords'):
            self.coords=[]

        pt=PageTemplateFile('Products/ECHO_content/zpt/ChangeECHO_collection.zpt').__of__(self)
        return pt()


    security.declarePublic('changeECHO_collection')


    def changeECHO_collection(self,title,label,description,content_type,responsible,weight,credits=None,sortfield="weight",coords=None,RESPONSE=None):
        """Änderung der Properties"""

        
        coordsnew=[ string.split(x,",") for x in coords]

        setECHO_collectionInformation(self,title,label,description,content_type,responsible,credits,weight,coordsnew)
        
        self.coords=coordsnew[0:]
        self.sortfield=sortfield

        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')
            
    security.declarePublic('index_html')


    def showOverview(self):
        """overview"""
        if 'ECHO_overview.html' in self.__dict__.keys():
            return getattr(self,'ECHO_overview.html')()
        pt=PageTemplateFile('Products/ECHO_content/zpt/ECHO_content_overview.zpt').__of__(self)
        return pt()

    
    def index_html(self):
        """standard page"""
        
        if 'index.html' in self.__dict__.keys():
            return getattr(self,'index.html')()
        elif 'overview' in self.__dict__.keys():
            return self.showOverview()
            
        
        pt=PageTemplateFile('Products/ECHO_content/zpt/ECHO_content_standard.zpt').__of__(self)
        pt.content_type="text/html"
        return pt()

    def getCredits(self):
        """Ausgabe der credits"""
        if self.credits:
            return self.credits
        else:
            return []


        
    def getGraphicCoords(self):
        """Give list of coordinates"""
        subColTypes=['ECHO_collection','ECHO_externalLink','ECHO_resource']
        ids=[]
        for entry in self.__dict__.keys():
            object=getattr(self,entry)
            try:
                if object.meta_type in subColTypes:
                    for coordtemp in object.coords:
                        if len(coordtemp)>3:
                            coord=coordtemp[0:4]
                            if hasattr(object,'label') and not object.label=="":
                                ids.append([string.join(coord,", "),object.getId(),object.label,object])
                            elif hasattr(object,'title'):
                                if not object.title=="":
                                    ids.append([string.join(coord,", "),object.getId(),object.title,object])
                                else:
                                    ids.append([string.join(coord,", "),object.getId(),object.getId(),object])
                            else:
                                ids.append([string.join(coord,", "),object.getId(),object.getId(),object])
                    
            except:
                """nothing"""

        return ids
    
    def getSubCols(self,sortfield="weight"):

        subColTypes=['ECHO_collection','ECHO_externalLink','ECHO_resource']
        ids=[]
        for entry in self.__dict__.keys():
            object=getattr(self,entry)
            try:
                if object.meta_type in subColTypes:
                    ids.append(object)
                    
            except:
                """nothing"""
        try:
            sortfield=self.sortfield
        except:
            """nothing"""
            
        tmplist=[]
        for x in ids:
            if hasattr(x,sortfield):
                try:
                    x=int(x)
                except:
                    """nothing"""
                tmp=getattr(x,sortfield)
            else:
                tmp=10000000
            tmplist.append((tmp,x))
        tmplist.sort()
        return [x for (key,x) in tmplist]
     
        
        
                
    
    
def manage_addECHO_collectionForm(self):
        """Add collection form"""
        pt=PageTemplateFile('Products/ECHO_content/zpt/AddECHO_collectionForm.zpt').__of__(self)
        return pt()


def manage_addECHO_collection(self,id,title,label,description,content_type,responsible,weight,sortfield,coords="",credits=None,RESPONSE=None):
    """add a echo collection"""
    

    newObj=ECHO_collection(id,title,label,description,content_type,responsible,credits,weight,sortfield,coords)

    self._setObject(id,newObj)

    if RESPONSE is not None:
        RESPONSE.redirect('manage_main')

class ECHO_root(Folder,Persistent,Implicit):
    """ECHO Root Folder"""
    meta_type="ECHO_root"

    

    def ECHO_newViewerLink(self,obj=None):
        """change links (:86 faellt weg)"""

        if not obj:
            obj = self
            
        entries=obj.ZopeFind(obj,obj_metatypes=['ECHO_resource','ECHO_collection'])

        for entry in entries:
                
                if entry[1].meta_type == 'ECHO_resource':
                    
                    entry[1].link=re.sub('\:86','',entry[1].link)

                else:
                    
                    entry[1].ECHO_newViewerLink(entry[1])
                
        return "Rerenderd all links to resources in: "+self.title

    def __init__(self,id,title):
        """init"""
        self.id = id
        self.title=title

    def deleteSpace(self,str):
        """delete space at the end of a line"""
        if str[len(str)-1]==" ":
            return str[0:len(str)-1]
        else:
            return str
        
    

    # zusaetliche methoden fuer das vlp muessen in ein eigenes produkt

    def formatAscii(self,str,url=None):
        """ersetze ascii umbrueche durch <br>"""
        #url=None
        if url:
            
            retStr=""
            words=str.split("\n")
            
            for word in words:
                strUrl=url%word
                print "str",strUrl
                retStr+="""<a href="%s">%s</a><br/>"""%(strUrl,word)
            str=retStr
        if str:
            return re.sub(r"[\n]","<br/>",str)
        else:
            return ""
        
    def link2html(self,str):
        """link2html fuer VLP muss hier noch raus"""
        if str:
            print str
            str=re.sub("\&","&amp;",str)
            dom=xml.dom.minidom.parseString("<?xml version='1.0' ?><txt>"+str+"</txt>")
            links=dom.getElementsByTagName("link")
            
            print "link",links
            for link in links:
                link.tagName="a"
                ref=link.getAttribute("ref")
                if self.checkRef(ref):
                    link.setAttribute("href",self.aq_parent.absolute_url()+"/vlp_coll?id="+ref)

            return dom.toxml('utf-8')
        return ""


    def checkRef(self,ref):
        dbs={'vl_literature':'AND CD LIKE \'%lise%\'','vl_technology':'','vl_people':''}
        res=None
        for db in dbs.keys():
            #print ref,"select reference from %s where reference =\'%s\' %s"%(db,ref,dbs[db])

            res=res or self.search(var=str("select reference from %s where reference =\'%s\' %s"%(db,ref,dbs[db])))
        return res
                                    
    #Ende Methode fuer vlp

    def PgQuoteString(self,string):
        """Quote string"""
        #print "PG",string
        return libpq.PgQuoteString(string)
        
    def getPartners(self):
        """Get list of Partners. Presently only from a subfolder partners"""
        partnerTypes=['ECHO_partner']
        ids=[]
        try:
            for entry in self.partners.__dict__.keys():
                object=getattr(self.partners,entry)
                
                try:
                
                    if object.meta_type in partnerTypes:
                        ids.append(object)
                    
                except:
                    """nothing"""
        except:
            ids=[] # no partners
        return ids

    def getCollectionTree(self):
        """get the collection tree (list of triples (parent,child, depth)"""

        def getCollection(object,depth=0):
            depth+=1
            collections=[]
            for entry in object.__dict__.keys():
                element=getattr(object,entry)
                try:
                    if element.meta_type=="ECHO_collection":
                        collections.append((object,element,depth))
                        collections+=getCollection(element,depth)
                except:
                    """nothing"""
            return collections
        

        return getCollection(self)
    
    def getCollectionTreeIds(self):
        """Show the IDs of the Tree"""
        ret=[]
        for collection in self.getCollectionTree():
            ret.append((collection[0].getId(),collection[1].getId(),collection[2]))
        return ret

        
        
def manage_addECHO_root(self,id,title,RESPONSE=None):
    """Add an ECHO_root"""
    self._setObject(id,ECHO_root(id,title))
    
    if RESPONSE is not None:
        RESPONSE.redirect('manage_main')

def manage_addECHO_rootForm(self):
        """Nothing yet"""
        pt=PageTemplateFile('Products/ECHO_content/zpt/AddECHO_root.zpt').__of__(self)
        return pt()
 
class ECHO_partner(Image,Persistent):
    """ECHO Partner"""

    meta_type="ECHO_partner"

    def __init__(self, id, title,url, file, content_type='', precondition=''):
        self.__name__=id
        self.title=title
        self.url=url
        self.precondition=precondition

        data, size = self._read_data(file)
        content_type=self._get_content_type(file, data, id, content_type)
        self.update_data(data, content_type, size)

    manage_options = Image.manage_options+(
        {'label':'Partner Information','action':'ECHO_partner_config'},
        )

    def changeECHO_partner(self,url,RESPONSE=None):
        """Change main information"""
        self.url=url
        if RESPONSE is not None:
            RESPONSE.redirect('manage_main')
            
            

    def ECHO_partner_config(self):
        """Main configuration"""
        if not hasattr(self,'url'):
            self.url=""
        pt=PageTemplateFile('Products/ECHO_content/zpt/ChangeECHO_partner.zpt').__of__(self)
        return pt()

        
manage_addECHO_partnerForm=DTMLFile('dtml/ECHO_partnerAdd',globals(),
                             Kind='ECHO_partner',kind='ECHO_partner')



def manage_addECHO_partner(self, id, file,url, title='', precondition='', content_type='',
                    REQUEST=None):
    """
    Add a new ECHO_partner object.

    Creates a new ECHO_partner object 'id' with the contents of 'file'.
    Based on Image.manage_addImage
    """

    id=str(id)
    title=str(title)
    content_type=str(content_type)
    precondition=str(precondition)

    id, title = OFS.Image.cookId(id, title, file)

    self=self.this()

    # First, we create the image without data:
    self._setObject(id, ECHO_partner(id,title,url,'',content_type, precondition))

    # Now we "upload" the data.  By doing this in two steps, we
    # can use a database trick to make the upload more efficient.
    if file:
        self._getOb(id).manage_upload(file)
    if content_type:
        self._getOb(id).content_type=content_type

    if REQUEST is not None:
        try:    url=self.DestinationURL()
        except: url=REQUEST['URL1']
        REQUEST.RESPONSE.redirect('%s/manage_main' % url)
    return id



FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>