Diff for /ECHO_content/VLPExtension.py between versions 1.77 and 1.92

version 1.77, 2008/09/08 18:41:34 version 1.92, 2010/02/15 19:03:28
Line 16  from stat import * Line 16  from stat import *
 from types import *  from types import *
 from Globals import package_home  from Globals import package_home
 import transaction  import transaction
   import Acquisition
   
 from Products.ECHO_content.ECHO_collection import *  from Products.ECHO_content.ECHO_collection import *
 from vlp_xmlhelpers import *  from vlp_xmlhelpers import *
Line 161  def manage_addSendMailForm(self, id, toA Line 162  def manage_addSendMailForm(self, id, toA
     return ''      return ''
   
                   
   class VLP_collectionFolder(Folder):
       """klasse fuer folder innerhalb der collection"""
       meta_type="VLP_collectionFolder"
       
 class VLP_essay(Folder):  class VLP_essay(Folder):
     """classe fr VLP essays"""      """classe fr VLP essays"""
   
Line 478  def manage_addVLP_subCollection(self,id, Line 483  def manage_addVLP_subCollection(self,id,
         if RESPONSE is not None:          if RESPONSE is not None:
                 RESPONSE.redirect('manage_main')                  RESPONSE.redirect('manage_main')
   
   from zope.publisher.interfaces import IPublishTraverse
   from zope.interface import implements
   from zope.publisher.interfaces import NotFound 
   #from zope.app import zapi 
   from zope.component import queryMultiAdapter
   try:
       from ZPublisher.BaseRequest import DefaultPublishTraverse
   except:
       pass
   
 class VLP_collection(ECHO_collection):  class VLP_collection(ECHO_collection,Acquisition.Explicit):
     """VLP spezifische Erweiterung der Collection"""      """VLP spezifische Erweiterung der Collection"""
   
           
       
       implements(IPublishTraverse)
       def findObjFromLitName(self,fileName):
           if not fileName[0:3]=="lit":
               logging.error("getOrCreateFolder wrong filename: %s"%fileName)
               return None
           
           
           restName="%08d"%int(fileName[3:])
           
           fs=(restName[0:2],restName[0:4],restName[0:6])
           
           current =self
           for f in fs:
               obj = getattr(current,f,None)
               if not obj: #subfolder existiert nicht
                   return None
               current=obj
               
           return getattr(current,fileName,None)
           
       def publishTraverse(self,request,name):
           """change the traversal if literature object"""
           
           actual_url=request['ACTUAL_URL']
           lastActual=actual_url.split("/")[-1]
           logging.debug("pub_trav:"+actual_url)
      
           if name.startswith("lit"): #umleitung wenn lit aufgerufen wirk
               # umleitung auf den eigentlichen folder nur wenn direkt der Folder litXXX oder dessen index_html methode aufgerufen wird
               if lastActual.startswith("lit") or (lastActual=="index_html") or (lastActual=="index_meta") or   (lastActual=="getTitle") or   (lastActual=="getMetaDataLink") or (lastActual=="hasTranscription") or (lastActual=="transcription"): 
                   #obj=self. ZopeFind(self,obj_ids=[name],search_sub=1)
                   ob=self.findObjFromLitName(name)
                   if not ob:
                       return "LIt not found"
                   else:
             
                       logging.debug("request:"+repr(ob))
                       request.response.setStatus(200)
                       #if (lastActual=="index_meta"):
                      #     logging.debug("index_meta requested")
                      #     return ob.index_meta
                       return ob
                   
               else: ## andern falls transversiere zum parent.
                   obj = self.aq_parent
                   return obj
           else: # mache gar nichts falls nicht lit aufgerufen wird
    
              
               tr=DefaultPublishTraverse(self, request)
               ob= tr.publishTraverse(request, name)
          
               return ob
            #raise NotFound(self.context, name, request) 
               #return repr(request)
       
     meta_type="VLP_collection"      meta_type="VLP_collection"
     manage_options=ECHO_collection.manage_options+(      manage_options=ECHO_collection.manage_options+(
         {'label':'Change Path','action':'VLP_path_configForm'},          {'label':'Change Path','action':'VLP_path_configForm'},
         {'label':'Update Library','action':'updateCollection'},          {'label':'Update Library','action':'updateCollection'},
         {'label':'Update Metadata','action':'updateCollectionMD'},          {'label':'Update Metadata','action':'updateCollectionMD'},
         )          )
       def getAllRessources(self):
           """getallressources"""
           res=self.ZopeFind(self,obj_metatypes=['VLP_resource'],search_sub=1)
           ret=[]
           for r in res:
               ret.append([r[0],r[1].absolute_url()])
   
           return ret
   
     def generateSubCollections(self,errorsTXT="",forceUpdate=False,RESPONSE=None):      def generateSubCollections(self,errorsTXT="",forceUpdate=False,RESPONSE=None):
         """erzeuge subcollectionen"""          """erzeuge subcollectionen"""
Line 503  class VLP_collection(ECHO_collection): Line 580  class VLP_collection(ECHO_collection):
         for found in founds:          for found in founds:
             try:              try:
                 litid = str(found.reference)                  litid = str(found.reference)
                 foundCol=self.ZopeFind(self,obj_ids=[litid])                  foundCol=self.findObjFromLitName(litid)
                   #foundCol=self.ZopeFind(self,obj_ids=[litid])
                 if foundCol:                  if foundCol:
                     col = foundCol[0][1]                      col = foundCol
                     logging.debug("generateSubCollections: subcollection %s exists (%s)"%(col.getId(),found.reference))                      logging.debug("generateSubCollections: subcollection %s exists (%s)"%(repr(col),found.reference))
                     if (col.title != found.titlerefdisplay) or (col.label != found.titlerefdisplay):                      logging.debug(repr([col.title,found.titlerefdisplay,col.label,found.titlerefdisplay]))
                       if (unicodify(col.title) != unicodify(found.titlerefdisplay)) or (unicodify(col.label) != unicodify(found.titlerefdisplay)):
                         # subcollection seems to have changed                              # subcollection seems to have changed    
                         logging.debug("generateSubCollections: subcollection has changed, recreating!")                          logging.debug("generateSubCollections: subcollection has changed, recreating!")
                         self.manage_delObjects([foundCol[0][0]])                          col.aq_parent.manage_delObjects([col.getId()])
                         manage_addVLP_subCollection(self,litid,found.titlerefdisplay,found.titlerefdisplay)                          manage_addVLP_subCollection(self.getOrCreateFolderForFile(litid),litid,found.titlerefdisplay,found.titlerefdisplay)
                 else:                  else:
                     logging.debug("generateSubCollections: creating new subcollection %s"%found.reference)                      logging.debug("generateSubCollections: creating new subcollection %s"%found.reference)
                     manage_addVLP_subCollection(self,litid,found.titlerefdisplay,found.titlerefdisplay)                      manage_addVLP_subCollection(self.getOrCreateFolderForFile(litid),litid,found.titlerefdisplay,found.titlerefdisplay)
                                   
                 #teste ob es Images auf dem Server gibt mit gleichem Namen (frontmatter)                  #teste ob es Images auf dem Server gibt mit gleichem Namen (frontmatter)
                 if os.path.exists(os.path.join(self.vlp_basis,litid)):                  if os.path.exists(os.path.join(self.vlp_basis,litid)):
                     logging.debug("generateSubCollections: found frontmatter in %s"%litid)                      logging.debug("generateSubCollections: found frontmatter in %s"%litid)
                     obj=getattr(self,litid)                      obj=self.findObjFromLitName(litid)
                     if not self.ZopeFind(obj,obj_ids=[litid]):                      if not self.ZopeFind(obj,obj_ids=[litid]):
                         metalink=self.REQUEST['URL1']+"/"+litid+"/"+litid+"/index_meta"                          metalink=self.REQUEST['URL1']+"/"+litid+"/"+litid+"/index_meta"
                         newObj=VLP_resource(litid,'',metalink,litid,litid,litid,'generated','book','','','','','','')                          newObj=VLP_resource(litid,'',metalink,litid,litid,litid,'generated','book','','','','','','')
Line 536  class VLP_collection(ECHO_collection): Line 615  class VLP_collection(ECHO_collection):
                 error=sys.exc_info()[0:2]                  error=sys.exc_info()[0:2]
                 logging.error("generateSubCollections: ERROR in %s"%litid)                  logging.error("generateSubCollections: ERROR in %s"%litid)
                 if RESPONSE is not None:                  if RESPONSE is not None:
                       RESPONSE.write("<p>(ERROR  updateII(%s): %s %s  TXT: %s)\n</p>"%(litid,error[0],error[1],sys.exc_info()[2]))
                     RESPONSE.write("<p>(ERROR (%s): %s %s)</p>\n"%(litid,error[0],error[1]))                      RESPONSE.write("<p>(ERROR (%s): %s %s)</p>\n"%(litid,error[0],error[1]))
                 #logging.error("generateSubCollections: %s %s"%error)                  logging.error("generateSubCollections: %s %s"%error)
                 #self.REQUEST.RESPONSE.write("(ERROR (%s): %s %s)\n"%(litid,repr(error[0]),repr(error[1])))                  self.REQUEST.RESPONSE.write("(ERROR (%s): %s %s)\n"%(litid,repr(error[0]),repr(error[1])))
                 errorsTXT+="<p>ERROR: No subcollection of %s (ERROR: %s %s)</p>\n"%(litid,error[0],error[1])                  errorsTXT+="<p>ERROR: No subcollection of %s (ERROR: %s %s)</p>\n"%(litid,error[0],error[1])
                 #errorsTXT+="<p>No subcollection of %s  "%litid+"(ERROR: %s %s)</p>"%error                  errorsTXT+="<p>No subcollection of %s  "%litid+"(ERROR: %s %s)</p>"%error
                                   
         return errorsTXT          return errorsTXT
                           
Line 555  class VLP_collection(ECHO_collection): Line 635  class VLP_collection(ECHO_collection):
         if RESPONSE is not None:          if RESPONSE is not None:
             RESPONSE.redirect('manage_main')              RESPONSE.redirect('manage_main')
   
     def updateCollection(self,forceUpdate=False,RESPONSE=None):      
         """liest verzeichnisse aus dem pfad und legt sie dann als objekte in den ordner"""      def getOrCreateFolderForFile(self,fileName):
           
           if not fileName[0:3]=="lit":
               logging.error("getOrCreateFolder wrong filename: %s"%fileName)
               return None
           
           try:
               restName="%08d"%int(fileName[3:])
           except:
               logging.error("getOrCreateFolder wrong filename: %s"%fileName)
               return None
           
           fs=(restName[0:2],restName[0:4],restName[0:6])
           
           current =self
           for f in fs:
               obj = getattr(current,f,None)
               if not obj:
                    newObj=VLP_collectionFolder(f)
                    current._setObject(f,newObj)
                    obj = getattr(current,f)
               current=obj
               
           return current
           
       def changeOrAddResources(self,forceUpdate=False,RESPONSE=None):
           """changes ord updates all resources found in the file system"""
           
         errorsTXT="<h2>Errors</h2>"          errorsTXT="<h2>Errors</h2>"
         if RESPONSE is not None:          if RESPONSE is not None:
             RESPONSE.setHeader('Content-Type','text/html')              RESPONSE.setHeader('Content-Type','text/html')
Line 581  class VLP_collection(ECHO_collection): Line 688  class VLP_collection(ECHO_collection):
                 RESPONSE.write("<p>committed</p>")                  RESPONSE.write("<p>committed</p>")
             if fileName[0:3]=="lit":              if fileName[0:3]=="lit":
                 metalink=self.REQUEST['URL1']+"/"+fileName+"/index_meta"                  metalink=self.REQUEST['URL1']+"/"+fileName+"/index_meta"
                   
                   folder=self.getOrCreateFolderForFile(fileName) #get the folder where fileName lives or should live
                   if not folder: #folder gave an error
                       continue
                 try:                  try:
                     if not hasattr(self,fileName):                      if not hasattr(folder,fileName):
                         # create new resource                          # create new resource
                         logging.debug("updateCollection: new %s"%fileName)                          logging.debug("updateCollection: new %s"%fileName)
                         if RESPONSE is not None:                          if RESPONSE is not None:
                             RESPONSE.write("<p>new: %s</p>\n"%fileName)                              RESPONSE.write("<p>new: %s</p>\n"%fileName)
                         logging.debug("new: %s \n"%fileName)                          logging.debug("new: %s \n"%fileName)
                         newObj=VLP_resource(fileName,'',metalink,fileName,fileName,fileName,'generated','book','','','','','','')                          newObj=VLP_resource(fileName,'',metalink,fileName,fileName,fileName,'generated','book','','','','','','')
                         self._setObject(fileName,newObj)                          
                           folder._setObject(fileName,newObj)
                                   
                     if RESPONSE is not None:                      if RESPONSE is not None:
                         RESPONSE.write("<p>got: %s "%fileName)                          RESPONSE.write("<p>got: %s "%fileName)
                           
                       genObj=getattr(folder,fileName)
                 logging.debug("got: %s "%fileName)                  logging.debug("got: %s "%fileName)
                     genObj=getattr(self,fileName)  
                     logging.debug("updateCollection: inspecting %s"%fileName)                      logging.debug("updateCollection: inspecting %s"%fileName)
                     # create index                      # create index
                     if hasattr(genObj,'createIndexFile'):                      if hasattr(genObj,'createIndexFile'):
Line 607  class VLP_collection(ECHO_collection): Line 720  class VLP_collection(ECHO_collection):
                         except:                          except:
                             error=sys.exc_info()[0:2]                              error=sys.exc_info()[0:2]
                             if RESPONSE is not None:                              if RESPONSE is not None:
                                 RESPONSE.write("(ERROR (%s): %s %s) "%(fileName,error[0],error[1]))                                  RESPONSE.write("(ERROR Update(%s): %s %s %s) "%(fileName,error[0],error[1],sys.exc_info()[2]))
                             errorsTXT+="<p>ERROR creating index for %s "%fileName+"(ERROR: %s %s)</p>\n"%error                              errorsTXT+="<p>ERROR creating index for %s "%fileName+"(ERROR: %s %s)</p>\n"%error
                                           
                     # update pageSizeSum for subcollections                      # update pageSizeSum for subcollections
Line 626  class VLP_collection(ECHO_collection): Line 739  class VLP_collection(ECHO_collection):
                     error=sys.exc_info()[0:2]                      error=sys.exc_info()[0:2]
                     logging.error("updateCollection: ERROR in %s (%s %s)"%(fileName,error[0],error[1]))                      logging.error("updateCollection: ERROR in %s (%s %s)"%(fileName,error[0],error[1]))
                     if RESPONSE is not None:                      if RESPONSE is not None:
                         RESPONSE.write("<p>(ERROR (%s): %s %s)</p>\n"%(fileName,error[0],error[1]))                           RESPONSE.write("(ERROR  updateII(%s): %s %s %s) "%(fileName,error[0],error[1],sys.exc_info()[2]))
                     errorsTXT+="<p>File not created:%s  (ERROR: %s %s)</p>\n"%(fileName,error[0],error[1])                      errorsTXT+="<p>File not created:%s  (ERROR: %s %s)</p>\n"%(fileName,error[0],error[1])
           return errorsTXT
        
       def updateCollection(self,forceUpdate=True,RESPONSE=None):
           """liest verzeichnisse aus dem pfad und legt sie dann als objekte in den ordner"""
                                                           
         # update subcollections              # update subcollections    
           errorsTXT=""   
           errorsTXT+=self.changeOrAddResources(forceUpdate, RESPONSE);
         errorsTXT+=self.generateSubCollections(forceUpdate=forceUpdate,RESPONSE=RESPONSE)          errorsTXT+=self.generateSubCollections(forceUpdate=forceUpdate,RESPONSE=RESPONSE)
         errorsTXT+="\n"          errorsTXT+="\n"
         if RESPONSE is not None:          if RESPONSE is not None:
Line 691  class VLP_resource(ECHO_resource,Cacheab Line 810  class VLP_resource(ECHO_resource,Cacheab
   
     meta_type="VLP_resource"      meta_type="VLP_resource"
   
       def _p_resolveConflict(self,oldstate,savedstate,newstate):
           logging.debug("updateCollection: Have to resolve conflict!")
           return newstate
   
     #vlp_basis="/mpiwg/online/permanent/vlp"      #vlp_basis="/mpiwg/online/permanent/vlp"
   
           
       
     referencetypes=[]      referencetypes=[]
   
     manage_options=ECHO_resource.manage_options+Cacheable.manage_options+(      manage_options=ECHO_resource.manage_options+Cacheable.manage_options+(
Line 703  class VLP_resource(ECHO_resource,Cacheab Line 827  class VLP_resource(ECHO_resource,Cacheab
         {'label':'Generate Library Template','action':'generateLibraryTemplateHTML'},          {'label':'Generate Library Template','action':'generateLibraryTemplateHTML'},
         )          )
   
       def getMetaDataLink(self):
           """link auf die metatdaten"""
           return self.absolute_url()+"/index_meta"
   
   
       def getTitle(self):
           """Title der Ressource"""
           title= self.ZSQLSimpleSearch("""select title from vl_literature where reference= \'%s\'  """ %self.getId())[0].title
           logging.debug(title)
           return title
   
     def getImagePath(self):      def getImagePath(self):
             """Pfad zu den Images"""              """Pfad zu den Images"""
               path=None
                           
             if os.path.isdir(os.path.join(self.vlp_basis,self.resourceID,'pageimg')):              if os.path.isdir(os.path.join(self.vlp_basis,self.resourceID,'pageimg')):
                     return os.path.join(self.vlp_basis,self.resourceID,'pageimg')                      path= os.path.join(self.vlp_basis,self.resourceID,'pageimg')
             elif os.path.isdir(os.path.join(self.vlp_basis,self.resourceID,'pages')):              elif os.path.isdir(os.path.join(self.vlp_basis,self.resourceID,'pages')):
                     return os.path.join(self.vlp_basis,self.resourceID,'pages')                      path = os.path.join(self.vlp_basis,self.resourceID,'pages')
               # workaround in some cases there seem to be no pictures in pages
               
               if os.path.isdir(os.path.join(self.vlp_basis,self.resourceID,'pagesHi')):
   
           
           pagesHi = os.listdir(os.path.join(self.vlp_basis,self.resourceID,'pagesHi'))
           if path is None:
               return os.path.join(self.vlp_basis,self.resourceID,'pagesHi')
   
               pages = os.listdir(path)
   
                   if len (pagesHi) > len(pages):
   
               countHi=0
               for p in pagesHi:
               dat,ext = os.path.splitext(p)
               if ext.lower() in [".tiff",".tif",".jpg"]:
                   countHi+=1
               count=0
               for p in pages:
               dat,ext = os.path.splitext(p)
               if ext.lower() in [".tiff",".tif",".jpg"]:
                   count+=1
               
               if countHi > count:
                           path=os.path.join(self.vlp_basis,self.resourceID,'pagesHi')
               
                           logging.error("pages < pagesHi:  %s"%self.resourceID)
               if path is None:
   
               
                   if len (os.listdir(os.path.join(self.vlp_basis,self.resourceID,'pagesHi'))) > len(os.listdir(path)):
                       
                       
                       
                       path=os.path.join(self.vlp_basis,self.resourceID,'pagesHi')
                       logging.error("pages < pagesHi:  %s"%self.resourceID)
             else:              else:
                     return "<error>no images </error>"  
           
                       logging.error("no images:  %s"%self.resourceID)
                       return None   
   
           return path 
   
                           
     def transcription(self):      def transcription(self):
Line 774  class VLP_resource(ECHO_resource,Cacheab Line 949  class VLP_resource(ECHO_resource,Cacheab
   
                     ret+="</text>"                      ret+="</text>"
                     re2=ret[0:]                      re2=ret[0:]
                     re3=re2.decode('latin-1').encode('utf-8')                      re3=self.unicodify(re2)
                     #re3=re2                      #re3=re2
                     ft=self.ZopeFind(self,obj_metatypes=['ECHO_fullText'])                      ft=self.ZopeFind(self,obj_metatypes=['ECHO_fullText'])
                                           
Line 795  class VLP_resource(ECHO_resource,Cacheab Line 970  class VLP_resource(ECHO_resource,Cacheab
             else:              else:
                     return "no: %s"%self.getId()                      return "no: %s"%self.getId()
                           
       def hasTranscription(self):
           """transcription"""
          
           if not hasattr(self,'fulltext'):
               self.copyTranscriptionFromDB()
           if not hasattr(self,'fulltext'): #still not
               return False
           
           return True 
               
     def resetMetaLink(self,all="no",RESPONSE=None):      def resetMetaLink(self,all="no",RESPONSE=None):
         """resets metalink to standard resp. in case of server change it sets to the new server url"""          """resets metalink to standard resp. in case of server change it sets to the new server url"""
         if all=="yes":          if all=="yes":
Line 863  class VLP_resource(ECHO_resource,Cacheab Line 1048  class VLP_resource(ECHO_resource,Cacheab
             RESPONSE.redirect('manage_main')              RESPONSE.redirect('manage_main')
   
   
     def index_meta(self):      def index_meta(self,RESPONSE=None):
         """index_meta"""          """index_meta"""
                   
         pt=PageTemplateFile(os.path.join(package_home(globals()),'vlp','index_meta.zpt')).__of__(self)          pt=PageTemplateFile(os.path.join(package_home(globals()),'vlp','index_meta.zpt')).__of__(self)
         pt.content_type="text/html"          pt.content_type="text/xml"      
         return pt()          x= pt.pt_render()
           #logging.debug("index_meta 4:"+x)
           if RESPONSE:
               RESPONSE.setHeader("Content-Type","text/xml")
           return x
     def file2page(self,p):      def file2page(self,p):
         """converts filename to pagenumber"""          """converts filename to pagenumber"""
         dom=xml.dom.minidom.parse(ECHO_helpers.urlopen(getattr(self,'index.xml').absolute_url()))          
           #dom=xml.dom.minidom.parse(ECHO_helpers.urlopen(getattr(self,'index.xml').absolute_url()))
           index=getattr(self,'index.xml')
    
           txt=index.pt_render()
           dom=xml.dom.minidom.parseString(txt)
                   
         for page in dom.getElementsByTagName('page'):          for page in dom.getElementsByTagName('page'):
                  # pageummer mit lo oder hi sind aequivalent                   # pageummer mit lo oder hi sind aequivalent
                  if (page.getAttribute('file')==p) or ("%slo"%page.getAttribute('file')==p) or ("%shi"%page.getAttribute('file')==p):                   if (page.getAttribute('file')==p) or ("%slo"%page.getAttribute('file')==p) or ("%shi"%page.getAttribute('file')==p):
                          return page.getAttribute('nr')                       nr=page.getAttribute('nr')
                       
                        return nr
                           
         return 0          return 0
   
Line 930  class VLP_resource(ECHO_resource,Cacheab Line 1125  class VLP_resource(ECHO_resource,Cacheab
             ret="%s: %s"%(str[0],name)              ret="%s: %s"%(str[0],name)
             return ret              return ret
   
         try:          self.imagePathFull=self.getImagePath();
             ret=os.listdir(os.path.join(self.vlp_basis,self.resourceID,'pageimg'))      self.imagePath=self.imagePathFull.split("/")[-1]
             self.imagePath='pageimg'          if (self.imagePath is None):
         except:              return None
             ret=os.listdir(os.path.join(self.vlp_basis,self.resourceID,'pages'))          
             self.imagePath='pages'  
         temp=[]          temp=[]
           ret = os.listdir(self.imagePathFull)
           
         ret.sort()          ret.sort()
         for x in ret:          for x in ret:
             if (not (x[0] in ('.',':'))) and (not x[0:4] in excludeNames):              if (not (x[0] in ('.',':'))) and (not x[0:4] in excludeNames):
Line 1055  class VLP_resource(ECHO_resource,Cacheab Line 1251  class VLP_resource(ECHO_resource,Cacheab
             zt=getattr(self,'index.xml')              zt=getattr(self,'index.xml')
             if not forceUpdate:              if not forceUpdate:
                 # check if directory is newer (self.imagePath sould be set by now)                  # check if directory is newer (self.imagePath sould be set by now)
                 imgdir = os.path.join(self.vlp_basis, self.resourceID, self.imagePath)                  path = self.getImagePath()
                   if (path is None):
                       return "CREATE INDEX FILE NOT POSSIBLE"
                   imgdir = os.path.join(path)
                 dirtime = os.path.getmtime(imgdir)                  dirtime = os.path.getmtime(imgdir)
                 zttime = zt.bobobase_modification_time()                  zttime = zt.bobobase_modification_time()
                 logging.debug("createindexfile: dir %s of %s index of %s"%(imgdir,dirtime,zttime))                  logging.debug("createindexfile: dir %s of %s index of %s"%(imgdir,dirtime,zttime))

Removed from v.1.77  
changed lines
  Added in v.1.92


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