changeset 0:bca61e893fcc

first checkin of MPIWGWeb r2 branch from CVS into mercurial
author casties
date Thu, 10 Jan 2013 17:52:13 +0100
parents
children 1f2760ed3efe
files BeautifulSoup.py MPIWGFeature.py MPIWGFolder.py MPIWGHelper.py MPIWGLink.py MPIWGProjects.py MPIWGRoot.py MPIWGStaff.py MPIWGStaff.py_old MPIWGTemplate.py REFRESH.TXT SrvTxtUtils.py __init__.py bibliography.py blank.gif cleanDBUp.py nameSplitter.py updatePersonalWWW.py updateSQL/agenda.xml updateSQL/berlinkalender.xml updateSQL/fm.jar updateSQL/personalwww.xml updateSQL/preprints.xml version.txt wikisqldumpToSQL.py wikixml2sql.py xmlhelper.py zpt/AddMPIWGFeature.zpt zpt/AddMPIWGFolder.zpt zpt/AddMPIWGLink.zpt zpt/AddMPIWGTemplate.zpt zpt/MPIWGFeatureChangeWeight.zpt zpt/MPIWGFeatureConfig.zpt zpt/MPIWGFeature_template_intro.zpt zpt/MPIWGFeature_template_main.zpt zpt/MPIWGFolderChangeWeight.zpt zpt/MPIWGFolderConfig.zpt zpt/MPIWGLinkChange.zpt zpt/MPIWGNamesForm.zpt zpt/MPIWGProject_index.zpt zpt/MPIWGProject_manageImagesForm.zpt zpt/MPIWGProject_managePublicationsForm.zpt zpt/MPIWGProject_manageRelatedProjectsForm.zpt zpt/MPIWGProject_newfile.zpt zpt/MPIWGProject_versionManageForm.zpt zpt/MPIWGTemplateChangeWeight.zpt zpt/MPIWG_standardPage_template_standard.zpt zpt/addMPIWGProjectForm.zpt zpt/addMPIWGRootForm.zpt zpt/addMPIWGStaffForm.zpt zpt/addPublications.zpt zpt/addPublicationsBib.zpt zpt/bibliography.zpt zpt/changeMPIWGRootForm.zpt zpt/changePublications_special.zpt zpt/editAdditionalLinks.zpt zpt/editAwards.zpt zpt/editBibliographyEntry.zpt zpt/editCV.zpt zpt/editDownloads.zpt zpt/editHistoricalNames.zpt zpt/editImageStaff.zpt zpt/editMPIWGStaff.zpt zpt/editMPIWGStaff_main.zpt zpt/editMainData.zpt zpt/editProfile.zpt zpt/editPublications.zpt zpt/editTalks.zpt zpt/editTeaching.zpt zpt/edit_MPIWGBasis.zpt zpt/edit_MPIWGBasisNeu.zpt zpt/edit_MPIWGDisciplinesThemes.zpt zpt/edit_MPIWGDisciplinesThemesNeu.zpt zpt/edit_MPIWGKeywords.zpt zpt/edit_MPIWGProjectNeu.zpt zpt/edit_MPIWGProject_main.zpt zpt/edit_MPIWGRelatedPublications.zpt zpt/edit_MPIWGStaff.zpt zpt/edit_imageForm.zpt zpt/edit_project_error_relatedProject.zpt zpt/edit_publicationForm.zpt zpt/edit_relatedProjectForm.zpt zpt/harvest_main.zpt zpt/harvest_members_main.zpt zpt/members_main.zpt zpt/newBibliographyEntry.zpt zpt/newBibliographyEntryDocType.zpt zpt/no_project.zpt zpt/previewFrame.zpt zpt/projectImageView.zpt zpt/project_main.zpt zpt/publications_full_main.zpt zpt/showExtendedProjectBibliography.zpt zpt/showNewDBEntries.zpt zpt/talks_full_main.zpt zpt/teaching_full_main.zpt zpt/updatePersonalwww.zpt zpt/updatePersonalwww_check.zpt
diffstat 97 files changed, 12109 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BeautifulSoup.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,2014 @@
+"""Beautiful Soup
+Elixir and Tonic
+"The Screen-Scraper's Friend"
+http://www.crummy.com/software/BeautifulSoup/
+
+Beautiful Soup parses a (possibly invalid) XML or HTML document into a
+tree representation. It provides methods and Pythonic idioms that make
+it easy to navigate, search, and modify the tree.
+
+A well-formed XML/HTML document yields a well-formed data
+structure. An ill-formed XML/HTML document yields a correspondingly
+ill-formed data structure. If your document is only locally
+well-formed, you can use this library to find and process the
+well-formed part of it.
+
+Beautiful Soup works with Python 2.2 and up. It has no external
+dependencies, but you'll have more success at converting data to UTF-8
+if you also install these three packages:
+
+* chardet, for auto-detecting character encodings
+  http://chardet.feedparser.org/
+* cjkcodecs and iconv_codec, which add more encodings to the ones supported
+  by stock Python.
+  http://cjkpython.i18n.org/
+
+Beautiful Soup defines classes for two main parsing strategies:
+
+ * BeautifulStoneSoup, for parsing XML, SGML, or your domain-specific
+   language that kind of looks like XML.
+
+ * BeautifulSoup, for parsing run-of-the-mill HTML code, be it valid
+   or invalid. This class has web browser-like heuristics for
+   obtaining a sensible parse tree in the face of common HTML errors.
+
+Beautiful Soup also defines a class (UnicodeDammit) for autodetecting
+the encoding of an HTML or XML document, and converting it to
+Unicode. Much of this code is taken from Mark Pilgrim's Universal Feed Parser.
+
+For more than you ever wanted to know about Beautiful Soup, see the
+documentation:
+http://www.crummy.com/software/BeautifulSoup/documentation.html
+
+Here, have some legalese:
+
+Copyright (c) 2004-2010, Leonard Richardson
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above
+    copyright notice, this list of conditions and the following
+    disclaimer in the documentation and/or other materials provided
+    with the distribution.
+
+  * Neither the name of the the Beautiful Soup Consortium and All
+    Night Kosher Bakery nor the names of its contributors may be
+    used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, DAMMIT.
+
+"""
+from __future__ import generators
+
+__author__ = "Leonard Richardson (leonardr@segfault.org)"
+__version__ = "3.2.0"
+__copyright__ = "Copyright (c) 2004-2010 Leonard Richardson"
+__license__ = "New-style BSD"
+
+from sgmllib import SGMLParser, SGMLParseError
+import codecs
+import markupbase
+import types
+import re
+import sgmllib
+try:
+  from htmlentitydefs import name2codepoint
+except ImportError:
+  name2codepoint = {}
+try:
+    set
+except NameError:
+    from sets import Set as set
+
+#These hacks make Beautiful Soup able to parse XML with namespaces
+sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*')
+markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match
+
+DEFAULT_OUTPUT_ENCODING = "utf-8"
+
+def _match_css_class(str):
+    """Build a RE to match the given CSS class."""
+    return re.compile(r"(^|.*\s)%s($|\s)" % str)
+
+# First, the classes that represent markup elements.
+
+class PageElement(object):
+    """Contains the navigational information for some part of the page
+    (either a tag or a piece of text)"""
+
+    def setup(self, parent=None, previous=None):
+        """Sets up the initial relations between this element and
+        other elements."""
+        self.parent = parent
+        self.previous = previous
+        self.next = None
+        self.previousSibling = None
+        self.nextSibling = None
+        if self.parent and self.parent.contents:
+            self.previousSibling = self.parent.contents[-1]
+            self.previousSibling.nextSibling = self
+
+    def replaceWith(self, replaceWith):
+        oldParent = self.parent
+        myIndex = self.parent.index(self)
+        if hasattr(replaceWith, "parent")\
+                  and replaceWith.parent is self.parent:
+            # We're replacing this element with one of its siblings.
+            index = replaceWith.parent.index(replaceWith)
+            if index and index < myIndex:
+                # Furthermore, it comes before this element. That
+                # means that when we extract it, the index of this
+                # element will change.
+                myIndex = myIndex - 1
+        self.extract()
+        oldParent.insert(myIndex, replaceWith)
+
+    def replaceWithChildren(self):
+        myParent = self.parent
+        myIndex = self.parent.index(self)
+        self.extract()
+        reversedChildren = list(self.contents)
+        reversedChildren.reverse()
+        for child in reversedChildren:
+            myParent.insert(myIndex, child)
+
+    def extract(self):
+        """Destructively rips this element out of the tree."""
+        if self.parent:
+            try:
+                del self.parent.contents[self.parent.index(self)]
+            except ValueError:
+                pass
+
+        #Find the two elements that would be next to each other if
+        #this element (and any children) hadn't been parsed. Connect
+        #the two.
+        lastChild = self._lastRecursiveChild()
+        nextElement = lastChild.next
+
+        if self.previous:
+            self.previous.next = nextElement
+        if nextElement:
+            nextElement.previous = self.previous
+        self.previous = None
+        lastChild.next = None
+
+        self.parent = None
+        if self.previousSibling:
+            self.previousSibling.nextSibling = self.nextSibling
+        if self.nextSibling:
+            self.nextSibling.previousSibling = self.previousSibling
+        self.previousSibling = self.nextSibling = None
+        return self
+
+    def _lastRecursiveChild(self):
+        "Finds the last element beneath this object to be parsed."
+        lastChild = self
+        while hasattr(lastChild, 'contents') and lastChild.contents:
+            lastChild = lastChild.contents[-1]
+        return lastChild
+
+    def insert(self, position, newChild):
+        if isinstance(newChild, basestring) \
+            and not isinstance(newChild, NavigableString):
+            newChild = NavigableString(newChild)
+
+        position =  min(position, len(self.contents))
+        if hasattr(newChild, 'parent') and newChild.parent is not None:
+            # We're 'inserting' an element that's already one
+            # of this object's children.
+            if newChild.parent is self:
+                index = self.index(newChild)
+                if index > position:
+                    # Furthermore we're moving it further down the
+                    # list of this object's children. That means that
+                    # when we extract this element, our target index
+                    # will jump down one.
+                    position = position - 1
+            newChild.extract()
+
+        newChild.parent = self
+        previousChild = None
+        if position == 0:
+            newChild.previousSibling = None
+            newChild.previous = self
+        else:
+            previousChild = self.contents[position-1]
+            newChild.previousSibling = previousChild
+            newChild.previousSibling.nextSibling = newChild
+            newChild.previous = previousChild._lastRecursiveChild()
+        if newChild.previous:
+            newChild.previous.next = newChild
+
+        newChildsLastElement = newChild._lastRecursiveChild()
+
+        if position >= len(self.contents):
+            newChild.nextSibling = None
+
+            parent = self
+            parentsNextSibling = None
+            while not parentsNextSibling:
+                parentsNextSibling = parent.nextSibling
+                parent = parent.parent
+                if not parent: # This is the last element in the document.
+                    break
+            if parentsNextSibling:
+                newChildsLastElement.next = parentsNextSibling
+            else:
+                newChildsLastElement.next = None
+        else:
+            nextChild = self.contents[position]
+            newChild.nextSibling = nextChild
+            if newChild.nextSibling:
+                newChild.nextSibling.previousSibling = newChild
+            newChildsLastElement.next = nextChild
+
+        if newChildsLastElement.next:
+            newChildsLastElement.next.previous = newChildsLastElement
+        self.contents.insert(position, newChild)
+
+    def append(self, tag):
+        """Appends the given tag to the contents of this tag."""
+        self.insert(len(self.contents), tag)
+
+    def findNext(self, name=None, attrs={}, text=None, **kwargs):
+        """Returns the first item that matches the given criteria and
+        appears after this Tag in the document."""
+        return self._findOne(self.findAllNext, name, attrs, text, **kwargs)
+
+    def findAllNext(self, name=None, attrs={}, text=None, limit=None,
+                    **kwargs):
+        """Returns all items that match the given criteria and appear
+        after this Tag in the document."""
+        return self._findAll(name, attrs, text, limit, self.nextGenerator,
+                             **kwargs)
+
+    def findNextSibling(self, name=None, attrs={}, text=None, **kwargs):
+        """Returns the closest sibling to this Tag that matches the
+        given criteria and appears after this Tag in the document."""
+        return self._findOne(self.findNextSiblings, name, attrs, text,
+                             **kwargs)
+
+    def findNextSiblings(self, name=None, attrs={}, text=None, limit=None,
+                         **kwargs):
+        """Returns the siblings of this Tag that match the given
+        criteria and appear after this Tag in the document."""
+        return self._findAll(name, attrs, text, limit,
+                             self.nextSiblingGenerator, **kwargs)
+    fetchNextSiblings = findNextSiblings # Compatibility with pre-3.x
+
+    def findPrevious(self, name=None, attrs={}, text=None, **kwargs):
+        """Returns the first item that matches the given criteria and
+        appears before this Tag in the document."""
+        return self._findOne(self.findAllPrevious, name, attrs, text, **kwargs)
+
+    def findAllPrevious(self, name=None, attrs={}, text=None, limit=None,
+                        **kwargs):
+        """Returns all items that match the given criteria and appear
+        before this Tag in the document."""
+        return self._findAll(name, attrs, text, limit, self.previousGenerator,
+                           **kwargs)
+    fetchPrevious = findAllPrevious # Compatibility with pre-3.x
+
+    def findPreviousSibling(self, name=None, attrs={}, text=None, **kwargs):
+        """Returns the closest sibling to this Tag that matches the
+        given criteria and appears before this Tag in the document."""
+        return self._findOne(self.findPreviousSiblings, name, attrs, text,
+                             **kwargs)
+
+    def findPreviousSiblings(self, name=None, attrs={}, text=None,
+                             limit=None, **kwargs):
+        """Returns the siblings of this Tag that match the given
+        criteria and appear before this Tag in the document."""
+        return self._findAll(name, attrs, text, limit,
+                             self.previousSiblingGenerator, **kwargs)
+    fetchPreviousSiblings = findPreviousSiblings # Compatibility with pre-3.x
+
+    def findParent(self, name=None, attrs={}, **kwargs):
+        """Returns the closest parent of this Tag that matches the given
+        criteria."""
+        # NOTE: We can't use _findOne because findParents takes a different
+        # set of arguments.
+        r = None
+        l = self.findParents(name, attrs, 1)
+        if l:
+            r = l[0]
+        return r
+
+    def findParents(self, name=None, attrs={}, limit=None, **kwargs):
+        """Returns the parents of this Tag that match the given
+        criteria."""
+
+        return self._findAll(name, attrs, None, limit, self.parentGenerator,
+                             **kwargs)
+    fetchParents = findParents # Compatibility with pre-3.x
+
+    #These methods do the real heavy lifting.
+
+    def _findOne(self, method, name, attrs, text, **kwargs):
+        r = None
+        l = method(name, attrs, text, 1, **kwargs)
+        if l:
+            r = l[0]
+        return r
+
+    def _findAll(self, name, attrs, text, limit, generator, **kwargs):
+        "Iterates over a generator looking for things that match."
+
+        if isinstance(name, SoupStrainer):
+            strainer = name
+        # (Possibly) special case some findAll*(...) searches
+        elif text is None and not limit and not attrs and not kwargs:
+            # findAll*(True)
+            if name is True:
+                return [element for element in generator()
+                        if isinstance(element, Tag)]
+            # findAll*('tag-name')
+            elif isinstance(name, basestring):
+                return [element for element in generator()
+                        if isinstance(element, Tag) and
+                        element.name == name]
+            else:
+                strainer = SoupStrainer(name, attrs, text, **kwargs)
+        # Build a SoupStrainer
+        else:
+            strainer = SoupStrainer(name, attrs, text, **kwargs)
+        results = ResultSet(strainer)
+        g = generator()
+        while True:
+            try:
+                i = g.next()
+            except StopIteration:
+                break
+            if i:
+                found = strainer.search(i)
+                if found:
+                    results.append(found)
+                    if limit and len(results) >= limit:
+                        break
+        return results
+
+    #These Generators can be used to navigate starting from both
+    #NavigableStrings and Tags.
+    def nextGenerator(self):
+        i = self
+        while i is not None:
+            i = i.next
+            yield i
+
+    def nextSiblingGenerator(self):
+        i = self
+        while i is not None:
+            i = i.nextSibling
+            yield i
+
+    def previousGenerator(self):
+        i = self
+        while i is not None:
+            i = i.previous
+            yield i
+
+    def previousSiblingGenerator(self):
+        i = self
+        while i is not None:
+            i = i.previousSibling
+            yield i
+
+    def parentGenerator(self):
+        i = self
+        while i is not None:
+            i = i.parent
+            yield i
+
+    # Utility methods
+    def substituteEncoding(self, str, encoding=None):
+        encoding = encoding or "utf-8"
+        return str.replace("%SOUP-ENCODING%", encoding)
+
+    def toEncoding(self, s, encoding=None):
+        """Encodes an object to a string in some encoding, or to Unicode.
+        ."""
+        if isinstance(s, unicode):
+            if encoding:
+                s = s.encode(encoding)
+        elif isinstance(s, str):
+            if encoding:
+                s = s.encode(encoding)
+            else:
+                s = unicode(s)
+        else:
+            if encoding:
+                s  = self.toEncoding(str(s), encoding)
+            else:
+                s = unicode(s)
+        return s
+
+class NavigableString(unicode, PageElement):
+
+    def __new__(cls, value):
+        """Create a new NavigableString.
+
+        When unpickling a NavigableString, this method is called with
+        the string in DEFAULT_OUTPUT_ENCODING. That encoding needs to be
+        passed in to the superclass's __new__ or the superclass won't know
+        how to handle non-ASCII characters.
+        """
+        if isinstance(value, unicode):
+            return unicode.__new__(cls, value)
+        return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
+
+    def __getnewargs__(self):
+        return (NavigableString.__str__(self),)
+
+    def __getattr__(self, attr):
+        """text.string gives you text. This is for backwards
+        compatibility for Navigable*String, but for CData* it lets you
+        get the string without the CData wrapper."""
+        if attr == 'string':
+            return self
+        else:
+            raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__.__name__, attr)
+
+    def __unicode__(self):
+        return str(self).decode(DEFAULT_OUTPUT_ENCODING)
+
+    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
+        if encoding:
+            return self.encode(encoding)
+        else:
+            return self
+
+class CData(NavigableString):
+
+    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
+        return "<![CDATA[%s]]>" % NavigableString.__str__(self, encoding)
+
+class ProcessingInstruction(NavigableString):
+    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
+        output = self
+        if "%SOUP-ENCODING%" in output:
+            output = self.substituteEncoding(output, encoding)
+        return "<?%s?>" % self.toEncoding(output, encoding)
+
+class Comment(NavigableString):
+    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
+        return "<!--%s-->" % NavigableString.__str__(self, encoding)
+
+class Declaration(NavigableString):
+    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
+        return "<!%s>" % NavigableString.__str__(self, encoding)
+
+class Tag(PageElement):
+
+    """Represents a found HTML tag with its attributes and contents."""
+
+    def _invert(h):
+        "Cheap function to invert a hash."
+        i = {}
+        for k,v in h.items():
+            i[v] = k
+        return i
+
+    XML_ENTITIES_TO_SPECIAL_CHARS = { "apos" : "'",
+                                      "quot" : '"',
+                                      "amp" : "&",
+                                      "lt" : "<",
+                                      "gt" : ">" }
+
+    XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS)
+
+    def _convertEntities(self, match):
+        """Used in a call to re.sub to replace HTML, XML, and numeric
+        entities with the appropriate Unicode characters. If HTML
+        entities are being converted, any unrecognized entities are
+        escaped."""
+        x = match.group(1)
+        if self.convertHTMLEntities and x in name2codepoint:
+            return unichr(name2codepoint[x])
+        elif x in self.XML_ENTITIES_TO_SPECIAL_CHARS:
+            if self.convertXMLEntities:
+                return self.XML_ENTITIES_TO_SPECIAL_CHARS[x]
+            else:
+                return u'&%s;' % x
+        elif len(x) > 0 and x[0] == '#':
+            # Handle numeric entities
+            if len(x) > 1 and x[1] == 'x':
+                return unichr(int(x[2:], 16))
+            else:
+                return unichr(int(x[1:]))
+
+        elif self.escapeUnrecognizedEntities:
+            return u'&amp;%s;' % x
+        else:
+            return u'&%s;' % x
+
+    def __init__(self, parser, name, attrs=None, parent=None,
+                 previous=None):
+        "Basic constructor."
+
+        # We don't actually store the parser object: that lets extracted
+        # chunks be garbage-collected
+        self.parserClass = parser.__class__
+        self.isSelfClosing = parser.isSelfClosingTag(name)
+        self.name = name
+        if attrs is None:
+            attrs = []
+        elif isinstance(attrs, dict):
+            attrs = attrs.items()
+        self.attrs = attrs
+        self.contents = []
+        self.setup(parent, previous)
+        self.hidden = False
+        self.containsSubstitutions = False
+        self.convertHTMLEntities = parser.convertHTMLEntities
+        self.convertXMLEntities = parser.convertXMLEntities
+        self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities
+
+        # Convert any HTML, XML, or numeric entities in the attribute values.
+        convert = lambda(k, val): (k,
+                                   re.sub("&(#\d+|#x[0-9a-fA-F]+|\w+);",
+                                          self._convertEntities,
+                                          val))
+        self.attrs = map(convert, self.attrs)
+
+    def getString(self):
+        if (len(self.contents) == 1
+            and isinstance(self.contents[0], NavigableString)):
+            return self.contents[0]
+
+    def setString(self, string):
+        """Replace the contents of the tag with a string"""
+        self.clear()
+        self.append(string)
+
+    string = property(getString, setString)
+
+    def getText(self, separator=u""):
+        if not len(self.contents):
+            return u""
+        stopNode = self._lastRecursiveChild().next
+        strings = []
+        current = self.contents[0]
+        while current is not stopNode:
+            if isinstance(current, NavigableString):
+                strings.append(current.strip())
+            current = current.next
+        return separator.join(strings)
+
+    text = property(getText)
+
+    def get(self, key, default=None):
+        """Returns the value of the 'key' attribute for the tag, or
+        the value given for 'default' if it doesn't have that
+        attribute."""
+        return self._getAttrMap().get(key, default)
+
+    def clear(self):
+        """Extract all children."""
+        for child in self.contents[:]:
+            child.extract()
+
+    def index(self, element):
+        for i, child in enumerate(self.contents):
+            if child is element:
+                return i
+        raise ValueError("Tag.index: element not in tag")
+
+    def has_key(self, key):
+        return self._getAttrMap().has_key(key)
+
+    def __getitem__(self, key):
+        """tag[key] returns the value of the 'key' attribute for the tag,
+        and throws an exception if it's not there."""
+        return self._getAttrMap()[key]
+
+    def __iter__(self):
+        "Iterating over a tag iterates over its contents."
+        return iter(self.contents)
+
+    def __len__(self):
+        "The length of a tag is the length of its list of contents."
+        return len(self.contents)
+
+    def __contains__(self, x):
+        return x in self.contents
+
+    def __nonzero__(self):
+        "A tag is non-None even if it has no contents."
+        return True
+
+    def __setitem__(self, key, value):
+        """Setting tag[key] sets the value of the 'key' attribute for the
+        tag."""
+        self._getAttrMap()
+        self.attrMap[key] = value
+        found = False
+        for i in range(0, len(self.attrs)):
+            if self.attrs[i][0] == key:
+                self.attrs[i] = (key, value)
+                found = True
+        if not found:
+            self.attrs.append((key, value))
+        self._getAttrMap()[key] = value
+
+    def __delitem__(self, key):
+        "Deleting tag[key] deletes all 'key' attributes for the tag."
+        for item in self.attrs:
+            if item[0] == key:
+                self.attrs.remove(item)
+                #We don't break because bad HTML can define the same
+                #attribute multiple times.
+            self._getAttrMap()
+            if self.attrMap.has_key(key):
+                del self.attrMap[key]
+
+    def __call__(self, *args, **kwargs):
+        """Calling a tag like a function is the same as calling its
+        findAll() method. Eg. tag('a') returns a list of all the A tags
+        found within this tag."""
+        return apply(self.findAll, args, kwargs)
+
+    def __getattr__(self, tag):
+        #print "Getattr %s.%s" % (self.__class__, tag)
+        if len(tag) > 3 and tag.rfind('Tag') == len(tag)-3:
+            return self.find(tag[:-3])
+        elif tag.find('__') != 0:
+            return self.find(tag)
+        raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag)
+
+    def __eq__(self, other):
+        """Returns true iff this tag has the same name, the same attributes,
+        and the same contents (recursively) as the given tag.
+
+        NOTE: right now this will return false if two tags have the
+        same attributes in a different order. Should this be fixed?"""
+        if other is self:
+            return True
+        if not hasattr(other, 'name') or not hasattr(other, 'attrs') or not hasattr(other, 'contents') or self.name != other.name or self.attrs != other.attrs or len(self) != len(other):
+            return False
+        for i in range(0, len(self.contents)):
+            if self.contents[i] != other.contents[i]:
+                return False
+        return True
+
+    def __ne__(self, other):
+        """Returns true iff this tag is not identical to the other tag,
+        as defined in __eq__."""
+        return not self == other
+
+    def __repr__(self, encoding=DEFAULT_OUTPUT_ENCODING):
+        """Renders this tag as a string."""
+        return self.__str__(encoding)
+
+    def __unicode__(self):
+        return self.__str__(None)
+
+    BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|"
+                                           + "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)"
+                                           + ")")
+
+    def _sub_entity(self, x):
+        """Used with a regular expression to substitute the
+        appropriate XML entity for an XML special character."""
+        return "&" + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ";"
+
+    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING,
+                prettyPrint=False, indentLevel=0):
+        """Returns a string or Unicode representation of this tag and
+        its contents. To get Unicode, pass None for encoding.
+
+        NOTE: since Python's HTML parser consumes whitespace, this
+        method is not certain to reproduce the whitespace present in
+        the original string."""
+
+        encodedName = self.toEncoding(self.name, encoding)
+
+        attrs = []
+        if self.attrs:
+            for key, val in self.attrs:
+                fmt = '%s="%s"'
+                if isinstance(val, basestring):
+                    if self.containsSubstitutions and '%SOUP-ENCODING%' in val:
+                        val = self.substituteEncoding(val, encoding)
+
+                    # The attribute value either:
+                    #
+                    # * Contains no embedded double quotes or single quotes.
+                    #   No problem: we enclose it in double quotes.
+                    # * Contains embedded single quotes. No problem:
+                    #   double quotes work here too.
+                    # * Contains embedded double quotes. No problem:
+                    #   we enclose it in single quotes.
+                    # * Embeds both single _and_ double quotes. This
+                    #   can't happen naturally, but it can happen if
+                    #   you modify an attribute value after parsing
+                    #   the document. Now we have a bit of a
+                    #   problem. We solve it by enclosing the
+                    #   attribute in single quotes, and escaping any
+                    #   embedded single quotes to XML entities.
+                    if '"' in val:
+                        fmt = "%s='%s'"
+                        if "'" in val:
+                            # TODO: replace with apos when
+                            # appropriate.
+                            val = val.replace("'", "&squot;")
+
+                    # Now we're okay w/r/t quotes. But the attribute
+                    # value might also contain angle brackets, or
+                    # ampersands that aren't part of entities. We need
+                    # to escape those to XML entities too.
+                    val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val)
+
+                attrs.append(fmt % (self.toEncoding(key, encoding),
+                                    self.toEncoding(val, encoding)))
+        close = ''
+        closeTag = ''
+        if self.isSelfClosing:
+            close = ' /'
+        else:
+            closeTag = '</%s>' % encodedName
+
+        indentTag, indentContents = 0, 0
+        if prettyPrint:
+            indentTag = indentLevel
+            space = (' ' * (indentTag-1))
+            indentContents = indentTag + 1
+        contents = self.renderContents(encoding, prettyPrint, indentContents)
+        if self.hidden:
+            s = contents
+        else:
+            s = []
+            attributeString = ''
+            if attrs:
+                attributeString = ' ' + ' '.join(attrs)
+            if prettyPrint:
+                s.append(space)
+            s.append('<%s%s%s>' % (encodedName, attributeString, close))
+            if prettyPrint:
+                s.append("\n")
+            s.append(contents)
+            if prettyPrint and contents and contents[-1] != "\n":
+                s.append("\n")
+            if prettyPrint and closeTag:
+                s.append(space)
+            s.append(closeTag)
+            if prettyPrint and closeTag and self.nextSibling:
+                s.append("\n")
+            s = ''.join(s)
+        return s
+
+    def decompose(self):
+        """Recursively destroys the contents of this tree."""
+        self.extract()
+        if len(self.contents) == 0:
+            return
+        current = self.contents[0]
+        while current is not None:
+            next = current.next
+            if isinstance(current, Tag):
+                del current.contents[:]
+            current.parent = None
+            current.previous = None
+            current.previousSibling = None
+            current.next = None
+            current.nextSibling = None
+            current = next
+
+    def prettify(self, encoding=DEFAULT_OUTPUT_ENCODING):
+        return self.__str__(encoding, True)
+
+    def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
+                       prettyPrint=False, indentLevel=0):
+        """Renders the contents of this tag as a string in the given
+        encoding. If encoding is None, returns a Unicode string.."""
+        s=[]
+        for c in self:
+            text = None
+            if isinstance(c, NavigableString):
+                text = c.__str__(encoding)
+            elif isinstance(c, Tag):
+                s.append(c.__str__(encoding, prettyPrint, indentLevel))
+            if text and prettyPrint:
+                text = text.strip()
+            if text:
+                if prettyPrint:
+                    s.append(" " * (indentLevel-1))
+                s.append(text)
+                if prettyPrint:
+                    s.append("\n")
+        return ''.join(s)
+
+    #Soup methods
+
+    def find(self, name=None, attrs={}, recursive=True, text=None,
+             **kwargs):
+        """Return only the first child of this Tag matching the given
+        criteria."""
+        r = None
+        l = self.findAll(name, attrs, recursive, text, 1, **kwargs)
+        if l:
+            r = l[0]
+        return r
+    findChild = find
+
+    def findAll(self, name=None, attrs={}, recursive=True, text=None,
+                limit=None, **kwargs):
+        """Extracts a list of Tag objects that match the given
+        criteria.  You can specify the name of the Tag and any
+        attributes you want the Tag to have.
+
+        The value of a key-value pair in the 'attrs' map can be a
+        string, a list of strings, a regular expression object, or a
+        callable that takes a string and returns whether or not the
+        string matches for some custom definition of 'matches'. The
+        same is true of the tag name."""
+        generator = self.recursiveChildGenerator
+        if not recursive:
+            generator = self.childGenerator
+        return self._findAll(name, attrs, text, limit, generator, **kwargs)
+    findChildren = findAll
+
+    # Pre-3.x compatibility methods
+    first = find
+    fetch = findAll
+
+    def fetchText(self, text=None, recursive=True, limit=None):
+        return self.findAll(text=text, recursive=recursive, limit=limit)
+
+    def firstText(self, text=None, recursive=True):
+        return self.find(text=text, recursive=recursive)
+
+    #Private methods
+
+    def _getAttrMap(self):
+        """Initializes a map representation of this tag's attributes,
+        if not already initialized."""
+        if not getattr(self, 'attrMap'):
+            self.attrMap = {}
+            for (key, value) in self.attrs:
+                self.attrMap[key] = value
+        return self.attrMap
+
+    #Generator methods
+    def childGenerator(self):
+        # Just use the iterator from the contents
+        return iter(self.contents)
+
+    def recursiveChildGenerator(self):
+        if not len(self.contents):
+            raise StopIteration
+        stopNode = self._lastRecursiveChild().next
+        current = self.contents[0]
+        while current is not stopNode:
+            yield current
+            current = current.next
+
+
+# Next, a couple classes to represent queries and their results.
+class SoupStrainer:
+    """Encapsulates a number of ways of matching a markup element (tag or
+    text)."""
+
+    def __init__(self, name=None, attrs={}, text=None, **kwargs):
+        self.name = name
+        if isinstance(attrs, basestring):
+            kwargs['class'] = _match_css_class(attrs)
+            attrs = None
+        if kwargs:
+            if attrs:
+                attrs = attrs.copy()
+                attrs.update(kwargs)
+            else:
+                attrs = kwargs
+        self.attrs = attrs
+        self.text = text
+
+    def __str__(self):
+        if self.text:
+            return self.text
+        else:
+            return "%s|%s" % (self.name, self.attrs)
+
+    def searchTag(self, markupName=None, markupAttrs={}):
+        found = None
+        markup = None
+        if isinstance(markupName, Tag):
+            markup = markupName
+            markupAttrs = markup
+        callFunctionWithTagData = callable(self.name) \
+                                and not isinstance(markupName, Tag)
+
+        if (not self.name) \
+               or callFunctionWithTagData \
+               or (markup and self._matches(markup, self.name)) \
+               or (not markup and self._matches(markupName, self.name)):
+            if callFunctionWithTagData:
+                match = self.name(markupName, markupAttrs)
+            else:
+                match = True
+                markupAttrMap = None
+                for attr, matchAgainst in self.attrs.items():
+                    if not markupAttrMap:
+                         if hasattr(markupAttrs, 'get'):
+                            markupAttrMap = markupAttrs
+                         else:
+                            markupAttrMap = {}
+                            for k,v in markupAttrs:
+                                markupAttrMap[k] = v
+                    attrValue = markupAttrMap.get(attr)
+                    if not self._matches(attrValue, matchAgainst):
+                        match = False
+                        break
+            if match:
+                if markup:
+                    found = markup
+                else:
+                    found = markupName
+        return found
+
+    def search(self, markup):
+        #print 'looking for %s in %s' % (self, markup)
+        found = None
+        # If given a list of items, scan it for a text element that
+        # matches.
+        if hasattr(markup, "__iter__") \
+                and not isinstance(markup, Tag):
+            for element in markup:
+                if isinstance(element, NavigableString) \
+                       and self.search(element):
+                    found = element
+                    break
+        # If it's a Tag, make sure its name or attributes match.
+        # Don't bother with Tags if we're searching for text.
+        elif isinstance(markup, Tag):
+            if not self.text:
+                found = self.searchTag(markup)
+        # If it's text, make sure the text matches.
+        elif isinstance(markup, NavigableString) or \
+                 isinstance(markup, basestring):
+            if self._matches(markup, self.text):
+                found = markup
+        else:
+            raise Exception, "I don't know how to match against a %s" \
+                  % markup.__class__
+        return found
+
+    def _matches(self, markup, matchAgainst):
+        #print "Matching %s against %s" % (markup, matchAgainst)
+        result = False
+        if matchAgainst is True:
+            result = markup is not None
+        elif callable(matchAgainst):
+            result = matchAgainst(markup)
+        else:
+            #Custom match methods take the tag as an argument, but all
+            #other ways of matching match the tag name as a string.
+            if isinstance(markup, Tag):
+                markup = markup.name
+            if markup and not isinstance(markup, basestring):
+                markup = unicode(markup)
+            #Now we know that chunk is either a string, or None.
+            if hasattr(matchAgainst, 'match'):
+                # It's a regexp object.
+                result = markup and matchAgainst.search(markup)
+            elif hasattr(matchAgainst, '__iter__'): # list-like
+                result = markup in matchAgainst
+            elif hasattr(matchAgainst, 'items'):
+                result = markup.has_key(matchAgainst)
+            elif matchAgainst and isinstance(markup, basestring):
+                if isinstance(markup, unicode):
+                    matchAgainst = unicode(matchAgainst)
+                else:
+                    matchAgainst = str(matchAgainst)
+
+            if not result:
+                result = matchAgainst == markup
+        return result
+
+class ResultSet(list):
+    """A ResultSet is just a list that keeps track of the SoupStrainer
+    that created it."""
+    def __init__(self, source):
+        list.__init__([])
+        self.source = source
+
+# Now, some helper functions.
+
+def buildTagMap(default, *args):
+    """Turns a list of maps, lists, or scalars into a single map.
+    Used to build the SELF_CLOSING_TAGS, NESTABLE_TAGS, and
+    NESTING_RESET_TAGS maps out of lists and partial maps."""
+    built = {}
+    for portion in args:
+        if hasattr(portion, 'items'):
+            #It's a map. Merge it.
+            for k,v in portion.items():
+                built[k] = v
+        elif hasattr(portion, '__iter__'): # is a list
+            #It's a list. Map each item to the default.
+            for k in portion:
+                built[k] = default
+        else:
+            #It's a scalar. Map it to the default.
+            built[portion] = default
+    return built
+
+# Now, the parser classes.
+
+class BeautifulStoneSoup(Tag, SGMLParser):
+
+    """This class contains the basic parser and search code. It defines
+    a parser that knows nothing about tag behavior except for the
+    following:
+
+      You can't close a tag without closing all the tags it encloses.
+      That is, "<foo><bar></foo>" actually means
+      "<foo><bar></bar></foo>".
+
+    [Another possible explanation is "<foo><bar /></foo>", but since
+    this class defines no SELF_CLOSING_TAGS, it will never use that
+    explanation.]
+
+    This class is useful for parsing XML or made-up markup languages,
+    or when BeautifulSoup makes an assumption counter to what you were
+    expecting."""
+
+    SELF_CLOSING_TAGS = {}
+    NESTABLE_TAGS = {}
+    RESET_NESTING_TAGS = {}
+    QUOTE_TAGS = {}
+    PRESERVE_WHITESPACE_TAGS = []
+
+    MARKUP_MASSAGE = [(re.compile('(<[^<>]*)/>'),
+                       lambda x: x.group(1) + ' />'),
+                      (re.compile('<!\s+([^<>]*)>'),
+                       lambda x: '<!' + x.group(1) + '>')
+                      ]
+
+    ROOT_TAG_NAME = u'[document]'
+
+    HTML_ENTITIES = "html"
+    XML_ENTITIES = "xml"
+    XHTML_ENTITIES = "xhtml"
+    # TODO: This only exists for backwards-compatibility
+    ALL_ENTITIES = XHTML_ENTITIES
+
+    # Used when determining whether a text node is all whitespace and
+    # can be replaced with a single space. A text node that contains
+    # fancy Unicode spaces (usually non-breaking) should be left
+    # alone.
+    STRIP_ASCII_SPACES = { 9: None, 10: None, 12: None, 13: None, 32: None, }
+
+    def __init__(self, markup="", parseOnlyThese=None, fromEncoding=None,
+                 markupMassage=True, smartQuotesTo=XML_ENTITIES,
+                 convertEntities=None, selfClosingTags=None, isHTML=False):
+        """The Soup object is initialized as the 'root tag', and the
+        provided markup (which can be a string or a file-like object)
+        is fed into the underlying parser.
+
+        sgmllib will process most bad HTML, and the BeautifulSoup
+        class has some tricks for dealing with some HTML that kills
+        sgmllib, but Beautiful Soup can nonetheless choke or lose data
+        if your data uses self-closing tags or declarations
+        incorrectly.
+
+        By default, Beautiful Soup uses regexes to sanitize input,
+        avoiding the vast majority of these problems. If the problems
+        don't apply to you, pass in False for markupMassage, and
+        you'll get better performance.
+
+        The default parser massage techniques fix the two most common
+        instances of invalid HTML that choke sgmllib:
+
+         <br/> (No space between name of closing tag and tag close)
+         <! --Comment--> (Extraneous whitespace in declaration)
+
+        You can pass in a custom list of (RE object, replace method)
+        tuples to get Beautiful Soup to scrub your input the way you
+        want."""
+
+        self.parseOnlyThese = parseOnlyThese
+        self.fromEncoding = fromEncoding
+        self.smartQuotesTo = smartQuotesTo
+        self.convertEntities = convertEntities
+        # Set the rules for how we'll deal with the entities we
+        # encounter
+        if self.convertEntities:
+            # It doesn't make sense to convert encoded characters to
+            # entities even while you're converting entities to Unicode.
+            # Just convert it all to Unicode.
+            self.smartQuotesTo = None
+            if convertEntities == self.HTML_ENTITIES:
+                self.convertXMLEntities = False
+                self.convertHTMLEntities = True
+                self.escapeUnrecognizedEntities = True
+            elif convertEntities == self.XHTML_ENTITIES:
+                self.convertXMLEntities = True
+                self.convertHTMLEntities = True
+                self.escapeUnrecognizedEntities = False
+            elif convertEntities == self.XML_ENTITIES:
+                self.convertXMLEntities = True
+                self.convertHTMLEntities = False
+                self.escapeUnrecognizedEntities = False
+        else:
+            self.convertXMLEntities = False
+            self.convertHTMLEntities = False
+            self.escapeUnrecognizedEntities = False
+
+        self.instanceSelfClosingTags = buildTagMap(None, selfClosingTags)
+        SGMLParser.__init__(self)
+
+        if hasattr(markup, 'read'):        # It's a file-type object.
+            markup = markup.read()
+        self.markup = markup
+        self.markupMassage = markupMassage
+        try:
+            self._feed(isHTML=isHTML)
+        except StopParsing:
+            pass
+        self.markup = None                 # The markup can now be GCed
+
+    def convert_charref(self, name):
+        """This method fixes a bug in Python's SGMLParser."""
+        try:
+            n = int(name)
+        except ValueError:
+            return
+        if not 0 <= n <= 127 : # ASCII ends at 127, not 255
+            return
+        return self.convert_codepoint(n)
+
+    def _feed(self, inDocumentEncoding=None, isHTML=False):
+        # Convert the document to Unicode.
+        markup = self.markup
+        if isinstance(markup, unicode):
+            if not hasattr(self, 'originalEncoding'):
+                self.originalEncoding = None
+        else:
+            dammit = UnicodeDammit\
+                     (markup, [self.fromEncoding, inDocumentEncoding],
+                      smartQuotesTo=self.smartQuotesTo, isHTML=isHTML)
+            markup = dammit.unicode
+            self.originalEncoding = dammit.originalEncoding
+            self.declaredHTMLEncoding = dammit.declaredHTMLEncoding
+        if markup:
+            if self.markupMassage:
+                if not hasattr(self.markupMassage, "__iter__"):
+                    self.markupMassage = self.MARKUP_MASSAGE
+                for fix, m in self.markupMassage:
+                    markup = fix.sub(m, markup)
+                # TODO: We get rid of markupMassage so that the
+                # soup object can be deepcopied later on. Some
+                # Python installations can't copy regexes. If anyone
+                # was relying on the existence of markupMassage, this
+                # might cause problems.
+                del(self.markupMassage)
+        self.reset()
+
+        SGMLParser.feed(self, markup)
+        # Close out any unfinished strings and close all the open tags.
+        self.endData()
+        while self.currentTag.name != self.ROOT_TAG_NAME:
+            self.popTag()
+
+    def __getattr__(self, methodName):
+        """This method routes method call requests to either the SGMLParser
+        superclass or the Tag superclass, depending on the method name."""
+        #print "__getattr__ called on %s.%s" % (self.__class__, methodName)
+
+        if methodName.startswith('start_') or methodName.startswith('end_') \
+               or methodName.startswith('do_'):
+            return SGMLParser.__getattr__(self, methodName)
+        elif not methodName.startswith('__'):
+            return Tag.__getattr__(self, methodName)
+        else:
+            raise AttributeError
+
+    def isSelfClosingTag(self, name):
+        """Returns true iff the given string is the name of a
+        self-closing tag according to this parser."""
+        return self.SELF_CLOSING_TAGS.has_key(name) \
+               or self.instanceSelfClosingTags.has_key(name)
+
+    def reset(self):
+        Tag.__init__(self, self, self.ROOT_TAG_NAME)
+        self.hidden = 1
+        SGMLParser.reset(self)
+        self.currentData = []
+        self.currentTag = None
+        self.tagStack = []
+        self.quoteStack = []
+        self.pushTag(self)
+
+    def popTag(self):
+        tag = self.tagStack.pop()
+
+        #print "Pop", tag.name
+        if self.tagStack:
+            self.currentTag = self.tagStack[-1]
+        return self.currentTag
+
+    def pushTag(self, tag):
+        #print "Push", tag.name
+        if self.currentTag:
+            self.currentTag.contents.append(tag)
+        self.tagStack.append(tag)
+        self.currentTag = self.tagStack[-1]
+
+    def endData(self, containerClass=NavigableString):
+        if self.currentData:
+            currentData = u''.join(self.currentData)
+            if (currentData.translate(self.STRIP_ASCII_SPACES) == '' and
+                not set([tag.name for tag in self.tagStack]).intersection(
+                    self.PRESERVE_WHITESPACE_TAGS)):
+                if '\n' in currentData:
+                    currentData = '\n'
+                else:
+                    currentData = ' '
+            self.currentData = []
+            if self.parseOnlyThese and len(self.tagStack) <= 1 and \
+                   (not self.parseOnlyThese.text or \
+                    not self.parseOnlyThese.search(currentData)):
+                return
+            o = containerClass(currentData)
+            o.setup(self.currentTag, self.previous)
+            if self.previous:
+                self.previous.next = o
+            self.previous = o
+            self.currentTag.contents.append(o)
+
+
+    def _popToTag(self, name, inclusivePop=True):
+        """Pops the tag stack up to and including the most recent
+        instance of the given tag. If inclusivePop is false, pops the tag
+        stack up to but *not* including the most recent instqance of
+        the given tag."""
+        #print "Popping to %s" % name
+        if name == self.ROOT_TAG_NAME:
+            return
+
+        numPops = 0
+        mostRecentTag = None
+        for i in range(len(self.tagStack)-1, 0, -1):
+            if name == self.tagStack[i].name:
+                numPops = len(self.tagStack)-i
+                break
+        if not inclusivePop:
+            numPops = numPops - 1
+
+        for i in range(0, numPops):
+            mostRecentTag = self.popTag()
+        return mostRecentTag
+
+    def _smartPop(self, name):
+
+        """We need to pop up to the previous tag of this type, unless
+        one of this tag's nesting reset triggers comes between this
+        tag and the previous tag of this type, OR unless this tag is a
+        generic nesting trigger and another generic nesting trigger
+        comes between this tag and the previous tag of this type.
+
+        Examples:
+         <p>Foo<b>Bar *<p>* should pop to 'p', not 'b'.
+         <p>Foo<table>Bar *<p>* should pop to 'table', not 'p'.
+         <p>Foo<table><tr>Bar *<p>* should pop to 'tr', not 'p'.
+
+         <li><ul><li> *<li>* should pop to 'ul', not the first 'li'.
+         <tr><table><tr> *<tr>* should pop to 'table', not the first 'tr'
+         <td><tr><td> *<td>* should pop to 'tr', not the first 'td'
+        """
+
+        nestingResetTriggers = self.NESTABLE_TAGS.get(name)
+        isNestable = nestingResetTriggers != None
+        isResetNesting = self.RESET_NESTING_TAGS.has_key(name)
+        popTo = None
+        inclusive = True
+        for i in range(len(self.tagStack)-1, 0, -1):
+            p = self.tagStack[i]
+            if (not p or p.name == name) and not isNestable:
+                #Non-nestable tags get popped to the top or to their
+                #last occurance.
+                popTo = name
+                break
+            if (nestingResetTriggers is not None
+                and p.name in nestingResetTriggers) \
+                or (nestingResetTriggers is None and isResetNesting
+                    and self.RESET_NESTING_TAGS.has_key(p.name)):
+
+                #If we encounter one of the nesting reset triggers
+                #peculiar to this tag, or we encounter another tag
+                #that causes nesting to reset, pop up to but not
+                #including that tag.
+                popTo = p.name
+                inclusive = False
+                break
+            p = p.parent
+        if popTo:
+            self._popToTag(popTo, inclusive)
+
+    def unknown_starttag(self, name, attrs, selfClosing=0):
+        #print "Start tag %s: %s" % (name, attrs)
+        if self.quoteStack:
+            #This is not a real tag.
+            #print "<%s> is not real!" % name
+            attrs = ''.join([' %s="%s"' % (x, y) for x, y in attrs])
+            self.handle_data('<%s%s>' % (name, attrs))
+            return
+        self.endData()
+
+        if not self.isSelfClosingTag(name) and not selfClosing:
+            self._smartPop(name)
+
+        if self.parseOnlyThese and len(self.tagStack) <= 1 \
+               and (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs)):
+            return
+
+        tag = Tag(self, name, attrs, self.currentTag, self.previous)
+        if self.previous:
+            self.previous.next = tag
+        self.previous = tag
+        self.pushTag(tag)
+        if selfClosing or self.isSelfClosingTag(name):
+            self.popTag()
+        if name in self.QUOTE_TAGS:
+            #print "Beginning quote (%s)" % name
+            self.quoteStack.append(name)
+            self.literal = 1
+        return tag
+
+    def unknown_endtag(self, name):
+        #print "End tag %s" % name
+        if self.quoteStack and self.quoteStack[-1] != name:
+            #This is not a real end tag.
+            #print "</%s> is not real!" % name
+            self.handle_data('</%s>' % name)
+            return
+        self.endData()
+        self._popToTag(name)
+        if self.quoteStack and self.quoteStack[-1] == name:
+            self.quoteStack.pop()
+            self.literal = (len(self.quoteStack) > 0)
+
+    def handle_data(self, data):
+        self.currentData.append(data)
+
+    def _toStringSubclass(self, text, subclass):
+        """Adds a certain piece of text to the tree as a NavigableString
+        subclass."""
+        self.endData()
+        self.handle_data(text)
+        self.endData(subclass)
+
+    def handle_pi(self, text):
+        """Handle a processing instruction as a ProcessingInstruction
+        object, possibly one with a %SOUP-ENCODING% slot into which an
+        encoding will be plugged later."""
+        if text[:3] == "xml":
+            text = u"xml version='1.0' encoding='%SOUP-ENCODING%'"
+        self._toStringSubclass(text, ProcessingInstruction)
+
+    def handle_comment(self, text):
+        "Handle comments as Comment objects."
+        self._toStringSubclass(text, Comment)
+
+    def handle_charref(self, ref):
+        "Handle character references as data."
+        if self.convertEntities:
+            data = unichr(int(ref))
+        else:
+            data = '&#%s;' % ref
+        self.handle_data(data)
+
+    def handle_entityref(self, ref):
+        """Handle entity references as data, possibly converting known
+        HTML and/or XML entity references to the corresponding Unicode
+        characters."""
+        data = None
+        if self.convertHTMLEntities:
+            try:
+                data = unichr(name2codepoint[ref])
+            except KeyError:
+                pass
+
+        if not data and self.convertXMLEntities:
+                data = self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref)
+
+        if not data and self.convertHTMLEntities and \
+            not self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref):
+                # TODO: We've got a problem here. We're told this is
+                # an entity reference, but it's not an XML entity
+                # reference or an HTML entity reference. Nonetheless,
+                # the logical thing to do is to pass it through as an
+                # unrecognized entity reference.
+                #
+                # Except: when the input is "&carol;" this function
+                # will be called with input "carol". When the input is
+                # "AT&T", this function will be called with input
+                # "T". We have no way of knowing whether a semicolon
+                # was present originally, so we don't know whether
+                # this is an unknown entity or just a misplaced
+                # ampersand.
+                #
+                # The more common case is a misplaced ampersand, so I
+                # escape the ampersand and omit the trailing semicolon.
+                data = "&amp;%s" % ref
+        if not data:
+            # This case is different from the one above, because we
+            # haven't already gone through a supposedly comprehensive
+            # mapping of entities to Unicode characters. We might not
+            # have gone through any mapping at all. So the chances are
+            # very high that this is a real entity, and not a
+            # misplaced ampersand.
+            data = "&%s;" % ref
+        self.handle_data(data)
+
+    def handle_decl(self, data):
+        "Handle DOCTYPEs and the like as Declaration objects."
+        self._toStringSubclass(data, Declaration)
+
+    def parse_declaration(self, i):
+        """Treat a bogus SGML declaration as raw data. Treat a CDATA
+        declaration as a CData object."""
+        j = None
+        if self.rawdata[i:i+9] == '<![CDATA[':
+             k = self.rawdata.find(']]>', i)
+             if k == -1:
+                 k = len(self.rawdata)
+             data = self.rawdata[i+9:k]
+             j = k+3
+             self._toStringSubclass(data, CData)
+        else:
+            try:
+                j = SGMLParser.parse_declaration(self, i)
+            except SGMLParseError:
+                toHandle = self.rawdata[i:]
+                self.handle_data(toHandle)
+                j = i + len(toHandle)
+        return j
+
+class BeautifulSoup(BeautifulStoneSoup):
+
+    """This parser knows the following facts about HTML:
+
+    * Some tags have no closing tag and should be interpreted as being
+      closed as soon as they are encountered.
+
+    * The text inside some tags (ie. 'script') may contain tags which
+      are not really part of the document and which should be parsed
+      as text, not tags. If you want to parse the text as tags, you can
+      always fetch it and parse it explicitly.
+
+    * Tag nesting rules:
+
+      Most tags can't be nested at all. For instance, the occurance of
+      a <p> tag should implicitly close the previous <p> tag.
+
+       <p>Para1<p>Para2
+        should be transformed into:
+       <p>Para1</p><p>Para2
+
+      Some tags can be nested arbitrarily. For instance, the occurance
+      of a <blockquote> tag should _not_ implicitly close the previous
+      <blockquote> tag.
+
+       Alice said: <blockquote>Bob said: <blockquote>Blah
+        should NOT be transformed into:
+       Alice said: <blockquote>Bob said: </blockquote><blockquote>Blah
+
+      Some tags can be nested, but the nesting is reset by the
+      interposition of other tags. For instance, a <tr> tag should
+      implicitly close the previous <tr> tag within the same <table>,
+      but not close a <tr> tag in another table.
+
+       <table><tr>Blah<tr>Blah
+        should be transformed into:
+       <table><tr>Blah</tr><tr>Blah
+        but,
+       <tr>Blah<table><tr>Blah
+        should NOT be transformed into
+       <tr>Blah<table></tr><tr>Blah
+
+    Differing assumptions about tag nesting rules are a major source
+    of problems with the BeautifulSoup class. If BeautifulSoup is not
+    treating as nestable a tag your page author treats as nestable,
+    try ICantBelieveItsBeautifulSoup, MinimalSoup, or
+    BeautifulStoneSoup before writing your own subclass."""
+
+    def __init__(self, *args, **kwargs):
+        if not kwargs.has_key('smartQuotesTo'):
+            kwargs['smartQuotesTo'] = self.HTML_ENTITIES
+        kwargs['isHTML'] = True
+        BeautifulStoneSoup.__init__(self, *args, **kwargs)
+
+    SELF_CLOSING_TAGS = buildTagMap(None,
+                                    ('br' , 'hr', 'input', 'img', 'meta',
+                                    'spacer', 'link', 'frame', 'base', 'col'))
+
+    PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea'])
+
+    QUOTE_TAGS = {'script' : None, 'textarea' : None}
+
+    #According to the HTML standard, each of these inline tags can
+    #contain another tag of the same type. Furthermore, it's common
+    #to actually use these tags this way.
+    NESTABLE_INLINE_TAGS = ('span', 'font', 'q', 'object', 'bdo', 'sub', 'sup',
+                            'center')
+
+    #According to the HTML standard, these block tags can contain
+    #another tag of the same type. Furthermore, it's common
+    #to actually use these tags this way.
+    NESTABLE_BLOCK_TAGS = ('blockquote', 'div', 'fieldset', 'ins', 'del')
+
+    #Lists can contain other lists, but there are restrictions.
+    NESTABLE_LIST_TAGS = { 'ol' : [],
+                           'ul' : [],
+                           'li' : ['ul', 'ol'],
+                           'dl' : [],
+                           'dd' : ['dl'],
+                           'dt' : ['dl'] }
+
+    #Tables can contain other tables, but there are restrictions.
+    NESTABLE_TABLE_TAGS = {'table' : [],
+                           'tr' : ['table', 'tbody', 'tfoot', 'thead'],
+                           'td' : ['tr'],
+                           'th' : ['tr'],
+                           'thead' : ['table'],
+                           'tbody' : ['table'],
+                           'tfoot' : ['table'],
+                           }
+
+    NON_NESTABLE_BLOCK_TAGS = ('address', 'form', 'p', 'pre')
+
+    #If one of these tags is encountered, all tags up to the next tag of
+    #this type are popped.
+    RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript',
+                                     NON_NESTABLE_BLOCK_TAGS,
+                                     NESTABLE_LIST_TAGS,
+                                     NESTABLE_TABLE_TAGS)
+
+    NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS,
+                                NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
+
+    # Used to detect the charset in a META tag; see start_meta
+    CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M)
+
+    def start_meta(self, attrs):
+        """Beautiful Soup can detect a charset included in a META tag,
+        try to convert the document to that charset, and re-parse the
+        document from the beginning."""
+        httpEquiv = None
+        contentType = None
+        contentTypeIndex = None
+        tagNeedsEncodingSubstitution = False
+
+        for i in range(0, len(attrs)):
+            key, value = attrs[i]
+            key = key.lower()
+            if key == 'http-equiv':
+                httpEquiv = value
+            elif key == 'content':
+                contentType = value
+                contentTypeIndex = i
+
+        if httpEquiv and contentType: # It's an interesting meta tag.
+            match = self.CHARSET_RE.search(contentType)
+            if match:
+                if (self.declaredHTMLEncoding is not None or
+                    self.originalEncoding == self.fromEncoding):
+                    # An HTML encoding was sniffed while converting
+                    # the document to Unicode, or an HTML encoding was
+                    # sniffed during a previous pass through the
+                    # document, or an encoding was specified
+                    # explicitly and it worked. Rewrite the meta tag.
+                    def rewrite(match):
+                        return match.group(1) + "%SOUP-ENCODING%"
+                    newAttr = self.CHARSET_RE.sub(rewrite, contentType)
+                    attrs[contentTypeIndex] = (attrs[contentTypeIndex][0],
+                                               newAttr)
+                    tagNeedsEncodingSubstitution = True
+                else:
+                    # This is our first pass through the document.
+                    # Go through it again with the encoding information.
+                    newCharset = match.group(3)
+                    if newCharset and newCharset != self.originalEncoding:
+                        self.declaredHTMLEncoding = newCharset
+                        self._feed(self.declaredHTMLEncoding)
+                        raise StopParsing
+                    pass
+        tag = self.unknown_starttag("meta", attrs)
+        if tag and tagNeedsEncodingSubstitution:
+            tag.containsSubstitutions = True
+
+class StopParsing(Exception):
+    pass
+
+class ICantBelieveItsBeautifulSoup(BeautifulSoup):
+
+    """The BeautifulSoup class is oriented towards skipping over
+    common HTML errors like unclosed tags. However, sometimes it makes
+    errors of its own. For instance, consider this fragment:
+
+     <b>Foo<b>Bar</b></b>
+
+    This is perfectly valid (if bizarre) HTML. However, the
+    BeautifulSoup class will implicitly close the first b tag when it
+    encounters the second 'b'. It will think the author wrote
+    "<b>Foo<b>Bar", and didn't close the first 'b' tag, because
+    there's no real-world reason to bold something that's already
+    bold. When it encounters '</b></b>' it will close two more 'b'
+    tags, for a grand total of three tags closed instead of two. This
+    can throw off the rest of your document structure. The same is
+    true of a number of other tags, listed below.
+
+    It's much more common for someone to forget to close a 'b' tag
+    than to actually use nested 'b' tags, and the BeautifulSoup class
+    handles the common case. This class handles the not-co-common
+    case: where you can't believe someone wrote what they did, but
+    it's valid HTML and BeautifulSoup screwed up by assuming it
+    wouldn't be."""
+
+    I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = \
+     ('em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong',
+      'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b',
+      'big')
+
+    I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ('noscript',)
+
+    NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS,
+                                I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS,
+                                I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS)
+
+class MinimalSoup(BeautifulSoup):
+    """The MinimalSoup class is for parsing HTML that contains
+    pathologically bad markup. It makes no assumptions about tag
+    nesting, but it does know which tags are self-closing, that
+    <script> tags contain Javascript and should not be parsed, that
+    META tags may contain encoding information, and so on.
+
+    This also makes it better for subclassing than BeautifulStoneSoup
+    or BeautifulSoup."""
+
+    RESET_NESTING_TAGS = buildTagMap('noscript')
+    NESTABLE_TAGS = {}
+
+class BeautifulSOAP(BeautifulStoneSoup):
+    """This class will push a tag with only a single string child into
+    the tag's parent as an attribute. The attribute's name is the tag
+    name, and the value is the string child. An example should give
+    the flavor of the change:
+
+    <foo><bar>baz</bar></foo>
+     =>
+    <foo bar="baz"><bar>baz</bar></foo>
+
+    You can then access fooTag['bar'] instead of fooTag.barTag.string.
+
+    This is, of course, useful for scraping structures that tend to
+    use subelements instead of attributes, such as SOAP messages. Note
+    that it modifies its input, so don't print the modified version
+    out.
+
+    I'm not sure how many people really want to use this class; let me
+    know if you do. Mainly I like the name."""
+
+    def popTag(self):
+        if len(self.tagStack) > 1:
+            tag = self.tagStack[-1]
+            parent = self.tagStack[-2]
+            parent._getAttrMap()
+            if (isinstance(tag, Tag) and len(tag.contents) == 1 and
+                isinstance(tag.contents[0], NavigableString) and
+                not parent.attrMap.has_key(tag.name)):
+                parent[tag.name] = tag.contents[0]
+        BeautifulStoneSoup.popTag(self)
+
+#Enterprise class names! It has come to our attention that some people
+#think the names of the Beautiful Soup parser classes are too silly
+#and "unprofessional" for use in enterprise screen-scraping. We feel
+#your pain! For such-minded folk, the Beautiful Soup Consortium And
+#All-Night Kosher Bakery recommends renaming this file to
+#"RobustParser.py" (or, in cases of extreme enterprisiness,
+#"RobustParserBeanInterface.class") and using the following
+#enterprise-friendly class aliases:
+class RobustXMLParser(BeautifulStoneSoup):
+    pass
+class RobustHTMLParser(BeautifulSoup):
+    pass
+class RobustWackAssHTMLParser(ICantBelieveItsBeautifulSoup):
+    pass
+class RobustInsanelyWackAssHTMLParser(MinimalSoup):
+    pass
+class SimplifyingSOAPParser(BeautifulSOAP):
+    pass
+
+######################################################
+#
+# Bonus library: Unicode, Dammit
+#
+# This class forces XML data into a standard format (usually to UTF-8
+# or Unicode).  It is heavily based on code from Mark Pilgrim's
+# Universal Feed Parser. It does not rewrite the XML or HTML to
+# reflect a new encoding: that happens in BeautifulStoneSoup.handle_pi
+# (XML) and BeautifulSoup.start_meta (HTML).
+
+# Autodetects character encodings.
+# Download from http://chardet.feedparser.org/
+try:
+    import chardet
+#    import chardet.constants
+#    chardet.constants._debug = 1
+except ImportError:
+    chardet = None
+
+# cjkcodecs and iconv_codec make Python know about more character encodings.
+# Both are available from http://cjkpython.i18n.org/
+# They're built in if you use Python 2.4.
+try:
+    import cjkcodecs.aliases
+except ImportError:
+    pass
+try:
+    import iconv_codec
+except ImportError:
+    pass
+
+class UnicodeDammit:
+    """A class for detecting the encoding of a *ML document and
+    converting it to a Unicode string. If the source encoding is
+    windows-1252, can replace MS smart quotes with their HTML or XML
+    equivalents."""
+
+    # This dictionary maps commonly seen values for "charset" in HTML
+    # meta tags to the corresponding Python codec names. It only covers
+    # values that aren't in Python's aliases and can't be determined
+    # by the heuristics in find_codec.
+    CHARSET_ALIASES = { "macintosh" : "mac-roman",
+                        "x-sjis" : "shift-jis" }
+
+    def __init__(self, markup, overrideEncodings=[],
+                 smartQuotesTo='xml', isHTML=False):
+        self.declaredHTMLEncoding = None
+        self.markup, documentEncoding, sniffedEncoding = \
+                     self._detectEncoding(markup, isHTML)
+        self.smartQuotesTo = smartQuotesTo
+        self.triedEncodings = []
+        if markup == '' or isinstance(markup, unicode):
+            self.originalEncoding = None
+            self.unicode = unicode(markup)
+            return
+
+        u = None
+        for proposedEncoding in overrideEncodings:
+            u = self._convertFrom(proposedEncoding)
+            if u: break
+        if not u:
+            for proposedEncoding in (documentEncoding, sniffedEncoding):
+                u = self._convertFrom(proposedEncoding)
+                if u: break
+
+        # If no luck and we have auto-detection library, try that:
+        if not u and chardet and not isinstance(self.markup, unicode):
+            u = self._convertFrom(chardet.detect(self.markup)['encoding'])
+
+        # As a last resort, try utf-8 and windows-1252:
+        if not u:
+            for proposed_encoding in ("utf-8", "windows-1252"):
+                u = self._convertFrom(proposed_encoding)
+                if u: break
+
+        self.unicode = u
+        if not u: self.originalEncoding = None
+
+    def _subMSChar(self, orig):
+        """Changes a MS smart quote character to an XML or HTML
+        entity."""
+        sub = self.MS_CHARS.get(orig)
+        if isinstance(sub, tuple):
+            if self.smartQuotesTo == 'xml':
+                sub = '&#x%s;' % sub[1]
+            else:
+                sub = '&%s;' % sub[0]
+        return sub
+
+    def _convertFrom(self, proposed):
+        proposed = self.find_codec(proposed)
+        if not proposed or proposed in self.triedEncodings:
+            return None
+        self.triedEncodings.append(proposed)
+        markup = self.markup
+
+        # Convert smart quotes to HTML if coming from an encoding
+        # that might have them.
+        if self.smartQuotesTo and proposed.lower() in("windows-1252",
+                                                      "iso-8859-1",
+                                                      "iso-8859-2"):
+            markup = re.compile("([\x80-\x9f])").sub \
+                     (lambda(x): self._subMSChar(x.group(1)),
+                      markup)
+
+        try:
+            # print "Trying to convert document to %s" % proposed
+            u = self._toUnicode(markup, proposed)
+            self.markup = u
+            self.originalEncoding = proposed
+        except Exception, e:
+            # print "That didn't work!"
+            # print e
+            return None
+        #print "Correct encoding: %s" % proposed
+        return self.markup
+
+    def _toUnicode(self, data, encoding):
+        '''Given a string and its encoding, decodes the string into Unicode.
+        %encoding is a string recognized by encodings.aliases'''
+
+        # strip Byte Order Mark (if present)
+        if (len(data) >= 4) and (data[:2] == '\xfe\xff') \
+               and (data[2:4] != '\x00\x00'):
+            encoding = 'utf-16be'
+            data = data[2:]
+        elif (len(data) >= 4) and (data[:2] == '\xff\xfe') \
+                 and (data[2:4] != '\x00\x00'):
+            encoding = 'utf-16le'
+            data = data[2:]
+        elif data[:3] == '\xef\xbb\xbf':
+            encoding = 'utf-8'
+            data = data[3:]
+        elif data[:4] == '\x00\x00\xfe\xff':
+            encoding = 'utf-32be'
+            data = data[4:]
+        elif data[:4] == '\xff\xfe\x00\x00':
+            encoding = 'utf-32le'
+            data = data[4:]
+        newdata = unicode(data, encoding)
+        return newdata
+
+    def _detectEncoding(self, xml_data, isHTML=False):
+        """Given a document, tries to detect its XML encoding."""
+        xml_encoding = sniffed_xml_encoding = None
+        try:
+            if xml_data[:4] == '\x4c\x6f\xa7\x94':
+                # EBCDIC
+                xml_data = self._ebcdic_to_ascii(xml_data)
+            elif xml_data[:4] == '\x00\x3c\x00\x3f':
+                # UTF-16BE
+                sniffed_xml_encoding = 'utf-16be'
+                xml_data = unicode(xml_data, 'utf-16be').encode('utf-8')
+            elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') \
+                     and (xml_data[2:4] != '\x00\x00'):
+                # UTF-16BE with BOM
+                sniffed_xml_encoding = 'utf-16be'
+                xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8')
+            elif xml_data[:4] == '\x3c\x00\x3f\x00':
+                # UTF-16LE
+                sniffed_xml_encoding = 'utf-16le'
+                xml_data = unicode(xml_data, 'utf-16le').encode('utf-8')
+            elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and \
+                     (xml_data[2:4] != '\x00\x00'):
+                # UTF-16LE with BOM
+                sniffed_xml_encoding = 'utf-16le'
+                xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8')
+            elif xml_data[:4] == '\x00\x00\x00\x3c':
+                # UTF-32BE
+                sniffed_xml_encoding = 'utf-32be'
+                xml_data = unicode(xml_data, 'utf-32be').encode('utf-8')
+            elif xml_data[:4] == '\x3c\x00\x00\x00':
+                # UTF-32LE
+                sniffed_xml_encoding = 'utf-32le'
+                xml_data = unicode(xml_data, 'utf-32le').encode('utf-8')
+            elif xml_data[:4] == '\x00\x00\xfe\xff':
+                # UTF-32BE with BOM
+                sniffed_xml_encoding = 'utf-32be'
+                xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8')
+            elif xml_data[:4] == '\xff\xfe\x00\x00':
+                # UTF-32LE with BOM
+                sniffed_xml_encoding = 'utf-32le'
+                xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8')
+            elif xml_data[:3] == '\xef\xbb\xbf':
+                # UTF-8 with BOM
+                sniffed_xml_encoding = 'utf-8'
+                xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8')
+            else:
+                sniffed_xml_encoding = 'ascii'
+                pass
+        except:
+            xml_encoding_match = None
+        xml_encoding_match = re.compile(
+            '^<\?.*encoding=[\'"](.*?)[\'"].*\?>').match(xml_data)
+        if not xml_encoding_match and isHTML:
+            regexp = re.compile('<\s*meta[^>]+charset=([^>]*?)[;\'">]', re.I)
+            xml_encoding_match = regexp.search(xml_data)
+        if xml_encoding_match is not None:
+            xml_encoding = xml_encoding_match.groups()[0].lower()
+            if isHTML:
+                self.declaredHTMLEncoding = xml_encoding
+            if sniffed_xml_encoding and \
+               (xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode',
+                                 'iso-10646-ucs-4', 'ucs-4', 'csucs4',
+                                 'utf-16', 'utf-32', 'utf_16', 'utf_32',
+                                 'utf16', 'u16')):
+                xml_encoding = sniffed_xml_encoding
+        return xml_data, xml_encoding, sniffed_xml_encoding
+
+
+    def find_codec(self, charset):
+        return self._codec(self.CHARSET_ALIASES.get(charset, charset)) \
+               or (charset and self._codec(charset.replace("-", ""))) \
+               or (charset and self._codec(charset.replace("-", "_"))) \
+               or charset
+
+    def _codec(self, charset):
+        if not charset: return charset
+        codec = None
+        try:
+            codecs.lookup(charset)
+            codec = charset
+        except (LookupError, ValueError):
+            pass
+        return codec
+
+    EBCDIC_TO_ASCII_MAP = None
+    def _ebcdic_to_ascii(self, s):
+        c = self.__class__
+        if not c.EBCDIC_TO_ASCII_MAP:
+            emap = (0,1,2,3,156,9,134,127,151,141,142,11,12,13,14,15,
+                    16,17,18,19,157,133,8,135,24,25,146,143,28,29,30,31,
+                    128,129,130,131,132,10,23,27,136,137,138,139,140,5,6,7,
+                    144,145,22,147,148,149,150,4,152,153,154,155,20,21,158,26,
+                    32,160,161,162,163,164,165,166,167,168,91,46,60,40,43,33,
+                    38,169,170,171,172,173,174,175,176,177,93,36,42,41,59,94,
+                    45,47,178,179,180,181,182,183,184,185,124,44,37,95,62,63,
+                    186,187,188,189,190,191,192,193,194,96,58,35,64,39,61,34,
+                    195,97,98,99,100,101,102,103,104,105,196,197,198,199,200,
+                    201,202,106,107,108,109,110,111,112,113,114,203,204,205,
+                    206,207,208,209,126,115,116,117,118,119,120,121,122,210,
+                    211,212,213,214,215,216,217,218,219,220,221,222,223,224,
+                    225,226,227,228,229,230,231,123,65,66,67,68,69,70,71,72,
+                    73,232,233,234,235,236,237,125,74,75,76,77,78,79,80,81,
+                    82,238,239,240,241,242,243,92,159,83,84,85,86,87,88,89,
+                    90,244,245,246,247,248,249,48,49,50,51,52,53,54,55,56,57,
+                    250,251,252,253,254,255)
+            import string
+            c.EBCDIC_TO_ASCII_MAP = string.maketrans( \
+            ''.join(map(chr, range(256))), ''.join(map(chr, emap)))
+        return s.translate(c.EBCDIC_TO_ASCII_MAP)
+
+    MS_CHARS = { '\x80' : ('euro', '20AC'),
+                 '\x81' : ' ',
+                 '\x82' : ('sbquo', '201A'),
+                 '\x83' : ('fnof', '192'),
+                 '\x84' : ('bdquo', '201E'),
+                 '\x85' : ('hellip', '2026'),
+                 '\x86' : ('dagger', '2020'),
+                 '\x87' : ('Dagger', '2021'),
+                 '\x88' : ('circ', '2C6'),
+                 '\x89' : ('permil', '2030'),
+                 '\x8A' : ('Scaron', '160'),
+                 '\x8B' : ('lsaquo', '2039'),
+                 '\x8C' : ('OElig', '152'),
+                 '\x8D' : '?',
+                 '\x8E' : ('#x17D', '17D'),
+                 '\x8F' : '?',
+                 '\x90' : '?',
+                 '\x91' : ('lsquo', '2018'),
+                 '\x92' : ('rsquo', '2019'),
+                 '\x93' : ('ldquo', '201C'),
+                 '\x94' : ('rdquo', '201D'),
+                 '\x95' : ('bull', '2022'),
+                 '\x96' : ('ndash', '2013'),
+                 '\x97' : ('mdash', '2014'),
+                 '\x98' : ('tilde', '2DC'),
+                 '\x99' : ('trade', '2122'),
+                 '\x9a' : ('scaron', '161'),
+                 '\x9b' : ('rsaquo', '203A'),
+                 '\x9c' : ('oelig', '153'),
+                 '\x9d' : '?',
+                 '\x9e' : ('#x17E', '17E'),
+                 '\x9f' : ('Yuml', ''),}
+
+#######################################################################
+
+
+#By default, act as an HTML pretty-printer.
+if __name__ == '__main__':
+    import sys
+    soup = BeautifulSoup(sys.stdin)
+    print soup.prettify()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPIWGFeature.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,151 @@
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Globals import package_home
+import string
+import re
+import os
+import logging
+from OFS.Folder import Folder
+from AccessControl import ClassSecurityInfo
+from MPIWGHelper import *
+
+class MPIWGFeature(Folder):
+    """special object for feature texts on the MPIWG website """
+
+    meta_type="MPIWGFeature"
+
+    manage_options=Folder.manage_options+(
+        {'label':'Change Weight','action':'changeWeightForm'},
+        {'label':'Main Config','action':'changeForm'},
+        )
+
+    changeWeightForm = PageTemplateFile('zpt/MPIWGFeatureChangeWeight', globals())
+    changeForm = PageTemplateFile('zpt/MPIWGFeatureConfig', globals())
+
+    def __init__(self, id, title=None, weight=0):
+        self.id = str(id)
+        self.weight = weight
+        if title is None:
+            self.title = id
+        else:
+            self.title = title
+
+        # add language folder and sample templates
+        self.manage_addFolder('en')
+        folder = getattr(self, 'en')
+        introid = 'intro.pt'
+        folder._setObject(introid, ZopePageTemplate(introid))
+        intro = getattr(folder,introid)
+        intro.pt_edit(open(os.path.join(package_home(globals()),'zpt/MPIWGFeature_template_intro.zpt')).read(),'text/html')
+        mainid = 'main.pt'
+        folder._setObject(mainid, ZopePageTemplate(mainid))
+        main = getattr(folder,mainid)
+        main.pt_edit(open(os.path.join(package_home(globals()),'zpt/MPIWGFeature_template_main.zpt')).read(),'text/html')        
+
+
+    def index_html(self):
+        """default index page"""
+        return self.getMain()
+    
+    def getFullTitle(self):
+        """returns the full title (from main.pt)"""
+        # get Language from MPIWGRoot
+        lang = self.getLang()
+        dir = getattr(self, lang, self.en)
+        pt = getattr(dir, 'main.pt')
+        t = pt.title
+        if not t:
+            t = self.title
+            
+        return t
+
+    def getIntro(self, **args):
+        """returns the intro as PageTemplate"""
+        # get Language from MPIWGRoot
+        lang = self.getLang()
+        dir = getattr(self, lang, self.en)
+        pt = getattr(dir, 'intro.pt')
+        return pt(**args)
+
+    def getMain(self, **args):
+        """returns the main part as PageTemplate"""
+        # get Language from MPIWGRoot
+        lang = self.getLang()
+        dir = getattr(self, lang, self.en)
+        pt = getattr(dir, 'main.pt')
+        return pt(**args)
+    
+    def getFrontpageImg(self):
+        """returns the image object for the frontpage"""
+        img = getattr(self, 'img-frontpage.jpg')
+        return img
+
+    def getFrontpageImgUrl(self):
+        """returns the URL of the image object for the frontpage"""
+        img = getattr(self, 'img-frontpage.jpg')
+        return img.absolute_url()
+        
+    def getFrontpageThumb(self):
+        """returns the image object for the frontpage thumbnail"""
+        img = getattr(self, 'img-frontthumb.jpg')
+        return img
+        
+    def getFrontpageThumbUrl(self):
+        """returns the URL of the image object for the frontpage thumbnail"""
+        img = getattr(self, 'img-frontthumb.jpg')
+        return img.absolute_url()
+        
+    def getThumbImg(self):
+        """returns the image object for the sidebar thumbnail"""
+        img = getattr(self, 'img-thumb.jpg')
+        return img
+        
+    def getThumbImgUrl(self):
+        """returns the URL of the image object for the sidebar thumbnail"""
+        img = getattr(self, 'img-thumb.jpg')
+        return img.absolute_url()
+
+    def changeWeight(self,weight,RESPONSE=None):
+        """change weight"""
+        self.weight=weight
+        if RESPONSE is not None:
+            RESPONSE.redirect('manage_main')
+
+    def changeMPIWGFeature(self, title=None, weight=None, RESPONSE=None):
+        """change everything"""
+        if title is not None:
+            self.title = title
+        if weight is not None:
+            self.weight = weight
+        if RESPONSE is not None:
+            RESPONSE.redirect('manage_main')
+       
+    def getBreadcrumbs(self):
+        """return list of breadcrumbs from here to the root"""
+        crumbs = [(self.getFullTitle(), self.absolute_url(), self)]
+        parent = self.aq_parent
+        if hasattr(parent, 'getBreadcrumbs'):
+            if self.title:
+                return parent.getBreadcrumbs() + crumbs
+            else:
+                # if there's no title, skip this level
+                return parent.getBreadcrumbs()
+            
+        return crumbs
+    
+    getSection = getSection
+
+    getSubSection = getSubSection
+    
+
+def manage_addMPIWGFeatureForm(self):
+    """Form for adding"""
+    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt/AddMPIWGFeature.zpt')).__of__(self)
+    return pt()
+
+def manage_addMPIWGFeature(self, id, title=None,weight=0,RESPONSE=None):
+    "Add a MPIWG Feature object"
+    newObj=MPIWGFeature(id,title,weight)
+    self.Destination()._setObject(id,newObj)
+    if RESPONSE is not None:
+        RESPONSE.redirect('manage_main')
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPIWGFolder.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,74 @@
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+import logging
+from OFS.Folder import Folder
+from AccessControl import ClassSecurityInfo
+from MPIWGHelper import *
+
+
+class MPIWGFolder(Folder):
+    """special Folder object for MPIWG website """
+
+    meta_type="MPIWGFolder"
+
+    manage_options=Folder.manage_options+(
+        {'label':'Change Weight','action':'changeWeightForm'},
+        {'label':'Main Config','action':'changeForm'},
+        )
+
+    changeWeightForm = PageTemplateFile('zpt/MPIWGFolderChangeWeight', globals())
+    changeForm = PageTemplateFile('zpt/MPIWGFolderConfig', globals())
+
+    def __init__(self, id, title=None, weight=0, canonicalName=None):
+        self.id = str(id)
+        self.weight = weight
+        if title is None:
+            self.title = id
+        else:
+            self.title = title
+            
+        if canonicalName is None:
+            self.canonicalName = self.id
+        else:
+            self.canonicalName = canonicalName
+
+    def changeWeight(self,weight,RESPONSE=None):
+        """change weight"""
+        self.weight=weight
+        if RESPONSE is not None:
+            RESPONSE.redirect('manage_main')
+
+    def deleteObject(self,id):
+        """ delete an object inside the MPIWGFolder """
+        if self.hasObject(id):
+            self._delObject(id)
+
+    def changeMPIWGFolder(self, title=None, weight=None, canonicalName=None, RESPONSE=None):
+        """change everything"""
+        if title is not None:
+            self.title = title
+        if weight is not None:
+            self.weight = weight
+        if canonicalName is not None:
+            self.canonicalName = canonicalName
+        if RESPONSE is not None:
+            RESPONSE.redirect('manage_main')
+       
+    getBreadcrumbs = getBreadcrumbs
+    
+    getSection = getSection
+
+    getSubSection = getSubSection
+    
+
+def manage_addMPIWGFolderForm(self):
+    """Form for adding"""
+    pt=PageTemplateFile('zpt/AddMPIWGFolder', globals()).__of__(self)
+    return pt()
+
+def manage_addMPIWGFolder(self, id, title=None,weight=0,RESPONSE=None):
+    "Add a MPIWG Folder."
+    newObj=MPIWGFolder(id,title,weight)
+    self.Destination()._setObject(id,newObj)
+    if RESPONSE is not None:
+        RESPONSE.redirect('manage_main')
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPIWGHelper.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,166 @@
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+
+import logging
+
+definedFields=['WEB_title','xdata_01','xdata_02','xdata_03','xdata_04','xdata_05','xdata_06','xdata_07','xdata_08','xdata_09','xdata_10','xdata_11','xdata_12','xdata_13','WEB_project_header','WEB_project_description','WEB_related_pub']
+
+checkFields = ['xdata_01']
+
+#ersetzt logging
+def logger(txt,method,txt2):
+    """logging""" 
+    logging.info(txt+ txt2)
+                 
+def getTextFromNode(nodename):
+    
+    nodelist=nodename.childNodes
+    rc = ""
+    for node in nodelist:
+        if node.nodeType == node.TEXT_NODE:
+           rc = rc + node.data
+    return rc
+
+def getTemplate(self, tpName):
+    """get a template file either form the instance or from the product"""
+    #ext=self.ZopeFind(self.aq_parent,obj_ids=[tpName])
+    if hasattr(self,tpName):
+        pt = getattr(self,tpName)
+    else:
+        pt=PageTemplateFile('zpt/'+tpName, globals()).__of__(self)
+    assert(pt)
+    return pt
+
+def sortStopWordsF(self,xo,yo):
+    if not hasattr(self,'_v_stopWords'):
+        self._v_stopWords=self.stopwords_en.data.split("\n")
+    
+    x=unicodify(xo[1])
+    y=unicodify(yo[1])
+    
+    strx=x.split(" ")
+    stry=y.split(" ")
+    
+    for tmp in strx:
+        if tmp.lower() in self._v_stopWords:
+            del strx[strx.index(tmp)]
+    
+    for tmp in stry:
+        if tmp.lower() in self._v_stopWords:
+            del stry[stry.index(tmp)]
+            
+    return cmp(" ".join(strx)," ".join(stry))
+    
+def sortStopWords(self):
+    return lambda x,y : sortStopWordsF(self,x,y)
+    
+def sortF(x,y):
+    try:
+        return cmp(x[1],y[1])
+    except:
+        try:
+            return cmp(str(x[1]),str(y[1]))
+        except:           
+            
+            return 0 
+    
+def sortI(x,y):
+    xsplit=x[1].split(".")
+    ysplit=y[1].split(".")
+    xret=""
+    yret=""
+    try:
+        for i in range(5):
+            try:
+                yret=yret+"%04i"%int(xsplit[i])
+            except:
+                yret=yret+"%04i"%0
+
+            try:
+                xret=xret+"%04i"%int(ysplit[i])
+            except:
+                xret=xret+"%04i"%0
+                
+        
+        return cmp(int(yret),int(xret))
+    except:
+        return cmp(x[1],y[1])
+
+
+def unicodify(s):
+    """decode str (utf-8 or latin-1 representation) into unicode object"""
+    if not s:
+        return u""
+    if isinstance(s, str):
+        try:
+            return s.decode('utf-8')
+        except:
+            return s.decode('latin-1')
+    else:
+        return s
+
+def utf8ify(s):
+    """encode unicode object or string into byte string in utf-8 representation.
+       assumes string objects to be utf-8"""
+    if not s:
+        return ""
+    if isinstance(s, str):
+        return s
+    else:
+        return s.encode('utf-8')
+
+
+def shortenString(s, l, ellipsis='...'):
+    """returns a string of length l (or l-1) by omitting characters in the middle of s, replacing with ellipsis."""
+    l1 = int((l - len(ellipsis)) / 2)
+    return "%s%s%s"%(s[:l1],ellipsis,s[-l1:])
+
+
+#
+# navigation methods (should better be a mixin class)
+#
+def getBreadcrumbs(self):
+    """return list of breadcrumbs from here to the root"""
+    crumbs = [(self.title, self.absolute_url(), self)]
+    parent = self.aq_parent
+    if hasattr(parent, 'getBreadcrumbs'):
+        if self.title:
+            return parent.getBreadcrumbs() + crumbs
+        else:
+            # if there's no title, skip this level
+            return parent.getBreadcrumbs()
+        
+    return crumbs
+
+
+def getSection(self, crumbs=None):
+    """returns the current section name"""
+    # use breadcrumbs if available
+    if crumbs is not None and len(crumbs) > 0:
+        return crumbs[0][2].getId()
+
+    p = self
+    sec = None
+    # descend parents to the root (and remember the last id)
+    while p is not None and p.meta_type != 'MPIWGRoot':
+        sec = p.getId()
+        p = p.aq_parent
+    
+    return sec
+
+def getSubSection(self, crumbs=None):
+    """returns the current subsection name"""
+    # use breadcrumbs if available
+    if crumbs is not None and len(crumbs) > 1:
+        return crumbs[1][2].getId()
+
+    p = self
+    sec = None
+    subsec = None
+    # descend parents to the root (and remember the last id)
+    while p is not None and p.meta_type != 'MPIWGRoot':
+        subsec = sec
+        sec = p.getId()
+        p = p.aq_parent
+    
+    return subsec
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPIWGLink.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,121 @@
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PageTemplates.PageTemplate import PageTemplate
+from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+from Products.ZSQLExtend.ZSQLExtend import ZSQLExtendFolder
+from Products.ZCatalog.CatalogPathAwareness import CatalogAware
+from OFS.Image import Image
+from Globals import package_home
+import urllib
+import MPIWGStaff
+import string
+import re
+import os
+from types import *
+import logging
+import xmlhelper # Methoden zur Verwaltung der projekt xml
+from OFS.SimpleItem import SimpleItem
+from OFS.Folder import Folder
+from Products.ZSQLMethods.SQL import SQLConnectionIDs
+from AccessControl import ClassSecurityInfo
+from bibliography import *
+import time
+import xml.dom.minidom
+import sys
+from Ft.Xml.XPath import Evaluate
+from Ft.Xml.XPath.Context import Context
+from Ft.Xml.Domlette import NonvalidatingReader,PrettyPrint, Print
+from Ft.Xml import EMPTY_NAMESPACE
+import copy
+import updatePersonalWWW
+import MPIWGStaff
+
+from MPIWGHelper import *
+class MPIWGLink(SimpleItem):
+    """create a symbolic link to another page"""
+
+    meta_type="MPIWGLink"
+    
+    def isActiveItem(self):
+        """teste ob ausgewaehlt"""
+        #url1 beim link anstelle von url1, da link jeweils index_html als url hat.
+        if self.absolute_url()==self.REQUEST['URL1']:
+            return "aktiv"
+        else:
+            return ""
+
+    def __init__(self,id,link,title='',weight=''):
+        """init mpiwglink"""
+        self.id=id
+        self.link=link
+        self.title=title
+        self.weight=weight
+
+    def getObj(self):
+        """bekomme original"""
+       ##  objpath=self.link.replace("/",".")
+##         if objpath[0]!=".":
+##             objpath="."+objpath
+
+##         print objpath
+##         return eval("self"+objpath)
+
+
+        splitted=self.link.lstrip().split("/")
+        obj=self
+        for x in splitted:
+            if not x=="":
+              obj=getattr(obj,x)
+            
+        return obj
+
+    def getWeight(self):
+        if self.linkWeight and self.linkWeight!="":
+            return self.linkWeight
+        else:
+            return self.getObj().weight
+
+    manage_options=(
+        {'label':'main config','action':'changeLinkForm'},
+        )+SimpleItem.manage_options
+
+
+    def changeLinkForm(self):
+        """change MPIWG link"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','MPIWGLinkChange.zpt')).__of__(self)
+        return pt()
+
+    def changeLink(self,link,title,weight,RESPONSE=None):
+        """change links"""
+        self.link=link
+        self.title=title
+        self.weight=weight
+
+        if RESPONSE is not None:
+            RESPONSE.redirect('manage')
+
+    def index_html(self,**argv):
+        """index"""
+
+
+
+        try:
+            return self.getObj().pt_render(extra_context={'here':self})
+        except:
+            self.REQUEST.RESPONSE.redirect(self.getObj().absolute_url())
+                                       
+
+
+def manage_addMPIWGLinkForm(self):
+    """Form for adding link"""
+    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt/AddMPIWGLink.zpt')).__of__(self)
+    return pt()
+
+def manage_addMPIWGLink(self,id,link,title,weight,RESPONSE=None):
+    """add link"""
+    newObj=MPIWGLink(id,link,title,weight)
+
+    self._setObject(id,newObj)
+    
+    if RESPONSE is not None:
+        RESPONSE.redirect('manage_main')
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPIWGProjects.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,1751 @@
+"""This contains the class MPIWG Projects
+for organizing and maintaining the different project pages
+
+$author dwinter   - last change  26.06.2008
+
+"""
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+from Products.ZCatalog.CatalogPathAwareness import CatalogAware
+from Products.MPIWGBibliography.BibliographyManager import BibliographyManager
+from OFS.Image import Image
+from Globals import package_home
+import urllib
+import re
+import os 
+import email
+from types import *
+import logging
+import xmlhelper # Methoden zur Verwaltung der projekt xml
+from OFS.SimpleItem import SimpleItem
+from OFS.Folder import Folder
+from OFS.Image import Image
+from AccessControl import ClassSecurityInfo
+from AccessControl import getSecurityManager
+from bibliography import *
+import time
+from OFS.Cache import Cacheable
+import xmlrpclib
+#import xml.dom.minidom
+import sys
+#from Ft.Xml.XPath import Evaluate
+#from Ft.Xml.XPath.Context import Context
+#from Ft.Xml.Domlette import NonvalidatingReader,PrettyPrint, Print
+#from Ft.Xml import EMPTY_NAMESPACE
+#import copy
+#import updatePersonalWWW
+
+#import MPIWGStaff
+
+from MPIWGHelper import *
+
+import MPIWGRoot
+import MPIWGLink
+import MPIWGTemplate
+
+import transaction
+
+# die folgenden Klassen sind jetzt in einzelne Files ausgelagert aus Kompatibilitaetsgruenden, bleiben die Klassen hier noch drin.
+# Sonst funktionieren die alten Webseiten nicht mehr.
+
+class MPIWGRoot(MPIWGRoot.MPIWGRoot):
+    """depricated"""
+    
+class MPIWGLink(MPIWGLink.MPIWGLink):
+    """depricated"""
+    
+class MPIWGTemplate(MPIWGTemplate.MPIWGTemplate):
+    """depricated"""
+    
+class MPIWGProject_publication(Folder):
+    """publications object fuer project"""
+
+    meta_type="MPIWGProject_publication"
+    def redirect(self,RESPONSE,url):
+        """mache ein redirect mit einem angehaengten time stamp um ein reload zu erzwingen"""
+        
+        timeStamp=time.time()
+        
+        if url.find("?")>-1: #giebt es schon parameter
+            addStr="&time=%s"
+        else:
+            addStr="?time=%s"
+            
+        RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT')
+        logging.debug(email.Utils.formatdate()+' GMT')
+        RESPONSE.redirect(url+addStr%timeStamp)
+
+    def hasLinkToBookPage(self,mode="not_cached"):
+        """teste ob eingebener link zu einer MPIWG Book page geht"""
+        
+        
+        logging.debug("MPIWGProject_publication - begin hasLinkToBookPage")
+        if (getattr(self,'link','')==''):
+            return False #es gibt keinen link
+        
+        logging.debug("MPIWGProject_publication - begin hasLinkToBookPage:"+self.link)
+        server = xmlrpclib.ServerProxy(self.link)
+        
+        if(mode=="cached"):
+            if (hasattr(self,"_v_hasLinkToBookPage")):
+                logging.debug("haslink cached")
+                return self._v_hasLinkToBookPage
+        
+        try:
+            server.getImageUrls()
+            logging.debug("MPIWGProject_publication - end TRUE")
+            self._v_hasLinkToBookPage=True
+            return True
+        except:
+            logging.debug("MPIWGProject_publication - end FALSE ")
+            self._v_hasLinkToBookPage=True
+            return False
+        
+    
+    
+    def getImageUrls(self,mode="not_cached"):
+        """get the image urls"""
+        
+        if (getattr(self,'link','')==''):
+            return [] #es gibt keinen link
+        
+        server = xmlrpclib.ServerProxy(self.link)
+        
+        
+        if(mode=="cached"):
+            if (hasattr(self,"_v_imageUrls")):
+                logging.debug("getImageURL cached")
+                return self._v_imageUrls
+       
+        try:
+            urls = server.getImageUrls()
+            ret=[]
+            for url in urls:
+                url = os.path.join(self.link,url)
+                ret.append(url)
+           
+        except:
+            self._v_imageUrls=[]
+            return []
+        self._v_imageUrls=ret[0:]
+        return ret
+        
+    def editPublication(self,text=None,image1=None,image2=None,description=None,link=None,RESPONSE=None):
+        """edit a publication"""
+
+        if (not text) and (not description):
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_publicationForm.zpt')).__of__(self)
+            return pt()
+
+       
+        if text:
+            self.text=text[0:]
+        
+        if description:
+            self.description=description
+        
+        if link:
+            self.link=link[0:]
+        
+        if image1:
+            if hasattr(self,'publicationImage1'):
+                self.publicationImage1.manage_upload(image1)
+            else:
+                nO = Image('publicationImage1','',image1)
+                self._setObject('publicationImage1',nO)
+                
+        if image2:
+            if hasattr(self,'publicationImage2'):
+                self.publicationImage2.manage_upload(image2)
+            else:
+                nO = Image('publicationImage2','',image2)
+                self._setObject('publicationImage2',nO)
+                   
+
+        self.ZCacheable_invalidate()
+        if RESPONSE:
+            self.redirect(RESPONSE,"../managePublications")
+
+class MPIWGProject_relatedProject(Folder):
+    """publications object fuer project"""
+
+    meta_type="MPIWGProject_relatedProject"
+    def redirect(self,RESPONSE,url):
+        """mache ein redirect mit einem angehaengten time stamp um ein reload zu erzwingen"""
+        
+        timeStamp=time.time()
+        
+        if url.find("?")>-1: #giebt es schon parameter
+            addStr="&time=%s"
+        else:
+            addStr="?time=%s"
+            
+        RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT')
+        logging.debug(email.Utils.formatdate()+' GMT')
+        RESPONSE.redirect(url+addStr%timeStamp)
+
+        
+    def editRelatedProject(self,link=None,RESPONSE=None):
+        """edit a publication"""
+
+        if (not link):
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_relatedProjectForm.zpt')).__of__(self)
+            return pt()
+
+       
+       
+      
+        
+        # hole die id des projektes
+        splitted=link.split("/")
+        
+        #teste ob es das project gibt
+        if len(splitted)<1:
+            self.redirect(RESPONSE,'errorRelatedProjects?link='+link)
+        
+        objid=splitted[-1]
+        object = getattr(self.projects,objid,None)
+        
+        if object==None:
+            self.redirect(RESPONSE,'errorRelatedProjects?link='+link)
+        
+      
+
+        
+       
+        self.orginallink=link[0:]
+        self.objid=objid[0:]
+    
+        self.projectWEB_title=object.getContent('WEB_title')[0:]
+       
+        self.enabled=True;
+        self.ZCacheable_invalidate()
+       
+        if RESPONSE:
+            self.redirect(RESPONSE,"../manageRelatedProjects")
+
+class MPIWGProject_image(Image):
+    """Images for Projects"""
+
+    meta_type="MPIWGProject_image"
+
+    def showImage(self,imageUrl=None):
+        """show Images at an extra page"""
+        self.getContent('WEB_project_description',filter='yes') #get the content and store image infos into session
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','projectImageView.zpt')).__of__(self)
+        return pt()
+    
+    def editImage(self,file=None,caption=None,RESPONSE=None):
+        """edit the Image"""
+        if (not file) and (not caption):
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_imageForm.zpt')).__of__(self)
+            return pt()
+
+        if file and (not file.filename.lstrip().rstrip()==""):
+            self.manage_upload(file)
+
+        if caption:
+            self.caption=caption[0:]
+
+        if RESPONSE:
+            self.redirect(RESPONSE,"../manageImages")
+
+class MPIWGProject(CatalogAware,Folder,Cacheable):
+    """Class for Projects"""
+    
+    def _p_resolveConflict(self, oldState, savedState, newState):
+        return newState
+
+    security=ClassSecurityInfo()
+    meta_type='MPIWGProject'
+    default_catalog='ProjectCatalog'
+    
+    def redirect(self,RESPONSE,url):
+        """mache ein redirect mit einem angehaengten time stamp um ein reload zu erzwingen"""
+        
+        timeStamp=time.time()
+        
+        if url.find("?")>-1: #giebt es schon parameter
+            addStr="&time=%s"
+        else:
+            addStr="?time=%s"
+            
+        RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT')
+        logging.debug(email.Utils.formatdate()+' GMT')
+        RESPONSE.redirect(url+addStr%timeStamp)
+
+    def decode(self,str):
+        """return unicode object"""
+        return unicodify(str)
+ 
+    def sortedByPlace(self,metatype):
+        """find metatype and sort by place"""
+        def sort(x,y):
+            return cmp(getattr(x[1],'place',0),getattr(y[1],'place',0))
+
+        logging.debug("MPIWGProjects begin: sorted by place: "+ metatype)
+        founds=self.ZopeFind(self,obj_metatypes=[metatype]);
+        
+        founds.sort(sort)
+        logging.debug("MPIWGProjects end: sorted by place: "+ metatype)
+        return founds
+    
+
+    def copyPublicationsToList(self,RESPONSE=None):
+        """copy publications in to list"""
+
+        publicationTxt=self.getContent('WEB_related_pub')
+
+        pubSplits=publicationTxt.split("<p>")
+
+        for pubSplit in pubSplits:
+            pubSplit=pubSplit.replace("</p>","")
+            self.addPublication(pubSplit)
+
+        setattr(self,"WEB_related_pub_copied",True);
+        
+        if RESPONSE:
+                
+            self.redirect(RESPONSE,'managePublications')
+        
+    def hasRelatedPublicationsOldVersion(self):
+        """teste ob es related publications gibt"""
+        
+        ret = True;
+        if (self.getContent('WEB_related_pub')==''):
+            ret=False;  #nichts im alten feld
+        logging.debug("webrel:"+repr(ret))
+        if (getattr(self,'WEB_related_pub_copied',False)):
+            ret=False; # alte daten sind schon kopiert worden
+        
+        logging.debug("webrel_copied:"+repr(ret))
+        publications=self.ZopeFind(self,obj_metatypes=['MPIWGProject_publication']);
+        
+        if(len(publications)>0):
+            ret=False; # es gibt publicationen in der neuen liste
+      
+        
+        logging.debug("len(publ)"+repr(ret))
+        
+        return ret;
+    
+    def hasRelatedDigitalSources(self):
+        """test ob es digital sources gibt"""
+        
+        
+        ret = (self.getContent('xdata_11').lstrip().rstrip()=='')
+            
+      
+      
+        return not ret;
+            
+        
+    
+    
+    def copyImageToMargin(self,RESPONSE=None):  
+        """copy inline images to marginal images"""
+        
+        
+        #getImages from WEB_project_description
+        description=self.getContent('WEB_project_description')
+        
+        text2=description
+        splitted=text2.split("""<p class="picture">""")
+        
+        imageURLs=[]
+        imageCaptions=[]
+        for split in  splitted[1:]:
+                tmp=split.split("</p>")
+                #return repr(splitted[1])
+                
+                try:
+                        imageURLs.append(tmp[0].split("\"")[1].encode('utf-8'))
+                except:
+                    
+                    try:
+                        imageURLs.append(tmp[0].split("src=")[1].split(" ")[0].encode('utf-8'))
+                    except:
+                        imageURLs.append("")
+                
+                split2="</p>".join(tmp[1:])
+
+
+                splitted=split2.split("""<p class="picturetitle">""")
+                if len(splitted)>1:
+                    tmp=splitted[1].split("</p>")
+                    imageCaptions.append(tmp[0].encode('utf-8'))
+
+
+                else:
+                    #keine caption
+
+                    imageCaptions.append("")
+  
+     
+        #eintragen:
+        for imageURL in imageURLs:
+            filename=imageURL.split("/")[-1]
+            #lege neues images object an, mit leerem bild
+
+            if self.ZopeFind(self,obj_ids=[filename]):
+                #existiert das bild schon, dann neuen filenamen
+                filename="project_image_"+filename
+            
+            self.addImage(None,imageCaptions[imageURLs.index(imageURL)],filename=filename)
+            #hole die bilddaten aus der url
+            url=self.absolute_url()+"/"+imageURL
+            #url=self.absolute_url()+"/"+filename
+        
+            try:#relative url
+                data=urllib.urlopen(url).read()
+            except:
+                try:#absolute
+                    data=urllib.urlopen(self.imageURL).read()
+                except:
+                    logger("MPIWG Project",logging.ERROR,"can't open: %s"%url)
+            
+            obj=getattr(self,filename)
+            obj.update_data(data)
+        
+        if RESPONSE:
+        
+            self.redirect(RESPONSE,'manageImages')
+            
+    def manageImages(self,imageName=None,op=None):
+        """managage images"""
+
+
+        if imageName and op:
+            if op=='up':
+                images=self.getImages()
+                for image in images:
+                    if image[0]==imageName:
+                        nr=images.index(image)
+                        if not nr==0:
+                            images[nr-1][1].place+=1
+                            images[nr][1].place-=1
+                        pass
+            elif op=='down':
+                images=self.getImages()
+                for image in images:
+                    if image[0]==imageName:
+                        nr=images.index(image)
+                        if not (nr==len(images)-1):
+                            images[nr+1][1].place-=1
+                            images[nr][1].place+=1
+                        pass
+
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','MPIWGProject_manageImagesForm.zpt')).__of__(self)
+        return pt()
+
+    def managePublications(self,pubName=None,op=None):
+        """managage images"""
+
+
+        if pubName and op:
+            if op=='up':
+                publications=self.getPublications()
+                for publication in publications:
+                    if publication[0]==pubName:
+                        nr=publications.index(publication)
+                        if not nr==0:
+                            publications[nr-1][1].place+=1
+                            publications[nr][1].place-=1
+                        pass
+            elif op=='down':
+                publications=self.getPublications()
+                for publication in publications:
+                    if publication[0]==pubName:
+                        nr=publications.index(publication)
+                        if not (nr==len(publications)-1):
+                            publications[nr+1][1].place-=1
+                            publications[nr][1].place+=1
+                        pass
+
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','MPIWGProject_managePublicationsForm.zpt')).__of__(self)
+        return pt()
+    
+    def manageRelatedProjects(self,pubName=None,op=None):
+        """managage relatedProjectd"""
+
+
+        if pubName and op:
+            if op=='up':
+                relatedProjects=self.getRelatedProjects()
+                for project in relatedProjects:
+                    if project[0]==pubName:
+                        nr=relatedProjects.index(project)
+                        if not nr==0:
+                            relatedProjects[nr-1][1].place+=1
+                            relatedProjects[nr][1].place-=1
+                        pass
+            elif op=='down':
+                relatedProjects=self.getRelatedProjects()
+                for project in relatedProjects:
+                    if project[0]==pubName:
+                        nr=relatedProjects.index(project)
+                        if not (nr==len(relatedProjects)-1):
+                            relatedProjects[nr+1][1].place-=1
+                            relatedProjects[nr][1].place+=1
+                        pass
+
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','MPIWGProject_manageRelatedProjectsForm.zpt')).__of__(self)
+        return pt()
+    
+    
+    def hasExtendedPublicationList(self):
+        """test if extended publication list exists"""
+        if not hasattr(self,"publicationList"):
+            return False
+        else:
+            return True
+        
+    def createExtendedPublicationList(self,RESPONSE=None):
+        """erzeuge erweiterte publications liste"""
+        pl = BibliographyManager("publicationList","","institutsbiblio",self.connection_id)
+        self._setObject("publicationList", pl)
+        
+    
+        zt=ZopePageTemplate('index.html')
+        pl._setObject('index.html',zt)
+        default_content_fn = os.path.join(package_home(globals()),
+                                              'zpt/showExtendedProjectBibliography.zpt')
+        text = open(default_content_fn).read()
+        zt.pt_edit(text, 'text/html')
+
+    
+        if RESPONSE:
+            self.redirect(RESPONSE,"managePublications")
+
+            
+    def getPublications(self):
+        """get all Publications"""
+        def sort_images(x,y):
+            return cmp(getattr(x[1],'place',0),getattr(y[1],'place',0))
+
+        publications=self.ZopeFind(self,obj_metatypes=['MPIWGProject_publication'])
+        
+        publications.sort(sort_images)
+        return publications
+
+    def getRelatedProjects(self):
+        """get all Publications"""
+        def sort_images(x,y):
+            return cmp(getattr(x[1],'place',0),getattr(y[1],'place',0))
+
+        publications=self.ZopeFind(self,obj_metatypes=['MPIWGProject_relatedProject'])
+        
+        publications.sort(sort_images)
+        return publications
+
+    def addPublication(self,text,RESPONSE=None):
+        """add an MPIWG_Publication"""
+        number=self.getLastPublicationNumber()+1
+        name="publication_"+str(number)
+        while hasattr(self,name):
+            number+=1
+            name="publication_"+str(number)
+        
+        newPublication=MPIWGProject_publication(name)
+
+        self._setObject(name,newPublication)
+        obj=getattr(self,name)
+        obj.text=text[0:]
+        obj.enabled=True;
+        obj.place=self.getLastPublicationNumber()+1
+        obj.id=name
+        self.ZCacheable_invalidate()
+        if RESPONSE is not None:
+        
+            self.redirect(RESPONSE,'managePublications')
+
+    def errorRelatedProjects(self,link):
+        """error creating a related project"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_project_error_relatedProject.zpt')).__of__(self)
+        return pt(link=link)
+
+    def addRelatedProject(self,link,RESPONSE=None):
+        """add an MPIWG_Publication"""
+
+        
+        
+        number=self.getLastPublicationNumber()+1
+        name="RelatedProject"+str(number)
+        while hasattr(self,name):
+            number+=1
+            name="RelatedProject_"+str(number)
+        
+        # hole die id des projektes
+        splitted=link.split("/")
+        
+        #teste ob es das project gibt
+        if len(splitted)<1:
+            self.redirect(RESPONSE,'errorRelatedProjects?link='+link)
+        
+        objid=splitted[-1]
+        object = getattr(self.projects,objid,None)
+        
+        if object==None:
+            self.redirect(RESPONSE,'errorRelatedProjects?link='+link)
+            return
+        
+        newPublication=MPIWGProject_relatedProject(name)
+
+        self._setObject(name,newPublication)
+        obj=getattr(self,name)
+        obj.orginallink=link[0:]
+        obj.objid=objid[0:]
+        logging.debug("add relobj:objid"+repr(obj.objid))
+        obj.projectWEB_title=object.getContent('WEB_title')[0:]
+        logging.debug("add relobj:webtitle"+repr(obj.projectWEB_title))
+        obj.enabled=True;
+        obj.place=self.getLastRelatedProjectNumber()+1
+        obj.id=name
+        self.ZCacheable_invalidate()
+        if RESPONSE is not None:
+        
+            self.redirect(RESPONSE,'manageRelatedProjects')
+
+ 
+    
+    def getLastPublicationNumber(self):
+        publications=self.getPublications()
+       
+        if not publications:
+            return 0
+        else:
+            return getattr(publications[-1][1],'place',0)
+        
+    def getLastRelatedProjectNumber(self):
+        publications=self.getRelatedProjects()
+        
+        if not publications:
+            return 0
+        else:
+            return getattr(publications[-1][1],'place',0)
+        
+    def deletePublication(self,id,RESPONSE=None):
+            """delete Publication id"""
+            self.manage_delObjects([id])
+            self.ZCacheable_invalidate()
+            if RESPONSE:
+        
+                self.redirect(RESPONSE,'managePublications')
+              
+    def deleteRelatedProject(self,id,RESPONSE=None):
+            """delete Publication id"""
+            self.manage_delObjects([id])
+            self.ZCacheable_invalidate()
+            if RESPONSE:
+        
+                self.redirect(RESPONSE,'manageRelatedProjects')
+              
+    def getImages(self):
+        """get all Images"""
+
+        def sort_images(x,y):
+            return cmp(getattr(x[1],'place',0),getattr(y[1],'place',0))
+
+
+        if (getattr(self,'imageURL','')!='') or  (getattr(self,'imagecap','')!='')  :
+            try:
+                self.addImage(None,getattr(self,'imagecap',''),RESPONSE=None,filename=getattr(self,'imageURL',''))
+            except:
+                pass
+            self.imageURL=''
+            self.imagecap=''
+
+        images=self.ZopeFind(self,obj_metatypes=['MPIWGProject_image'])
+        
+        images.sort(sort_images)
+        return images
+
+    def getLastImageNumber(self):
+        images=self.getImages()
+        
+        if not images:
+            return 0
+        else:
+            return getattr(images[-1][1],'place',0)
+        
+    def deleteImage(self,id,RESPONSE=None):
+        """delete Image id"""
+        try:
+                self.manage_delObjects([id])
+        except:
+                logging.error("ERROR MPIWG: %s %s"%sys.exc_info()[0:2])
+        if RESPONSE:
+            self.redirect(RESPONSE,'manageImages')
+
+
+ 
+    def hasChildren(self,date=None,onlyActive=1,onlyArchived=1):
+        """check if project has children"""
+        
+        ct=self.getContexts(childs=self.getContent('xdata_05'),
+                                 depth=1,date=date,onlyActive=onlyActive)
+        
+        if ct and len(ct)>0:
+             return True
+        else:
+             return False
+
+         
+    def addImage(self,fileHd,caption,RESPONSE=None,filename=None):
+        """add an MPIWG_Project_image"""
+
+        if not filename:
+            filename=fileHd.filename
+
+        if not fileHd:
+            fileHd=file(os.path.join(package_home(globals()),'blank.gif'))
+            
+        newImage=MPIWGProject_image(filename,filename,fileHd)
+
+        self._setObject(filename,newImage)
+        obj=getattr(self,filename)
+        obj.caption=caption[0:]
+        obj.enabled=True;
+        obj.place=self.getLastImageNumber()+1
+        obj.id=filename
+
+        if RESPONSE is not None:
+            
+            self.redirect(RESPONSE,'manageImages')
+
+    def PrincipiaSearchSource(self):
+        """Return cataloguable key for ourselves."""
+        return str(self)
+
+    def versionHeader(self):
+        """version Header, gibt header text entsprechend der aktuellen version aus"""
+        
+        actualTime=time.localtime()
+        retTXT="""<h2>This is an outdated version, for the actual version please refer to <a href="%s">%s</a></h2>"""
+        s=self.aq_parent.absolute_url()
+        #print getattr(self,'archiveTime',actualTime)
+        if getattr(self,'archiveTime',actualTime)< actualTime:
+            return retTXT%(s,s)
+        else:
+            return ""
+
+    def getActualVersion(self,date=None):
+        """actuelle version"""
+        def sortProjectsByTime(x,y):
+            return cmp(x[1].archiveTime,y[1].archiveTime)
+
+        if not date:
+            if self.isActual():
+                return self
+            else:
+                return None
+
+        #suche ob aeltere versionen vorhanden sind
+
+        finds=self.ZopeFind(self,obj_metatypes=['MPIWGProject'])
+        if not finds: #wenn nicht dann teste ob die aktuelle version schon existiert hat.
+            ad=getattr(self,'creationTime','20050101000000')
+            if int(date)>int(ad):
+                return self
+            else:
+                return None
+
+
+        else:
+            finds.sort(sortProjectsByTime)
+
+        for find in finds:
+            #gehe durch die alten Projekte und finde das entprechende
+            if (int(find[1].archiveTime) > int(date)) and (int(date)>int(getattr(find[1],'creationTime','20050101000000'))):
+                return find[1]
+
+        #kein passendes gefunden, dann teste ob das aktuelle in frage kommt
+        ad=getattr(self,'creationTime','20050101000000')
+        
+        if int(date)>int(ad):
+        
+            return self
+        else:
+            return None
+          
+        
+    def isActual(self):
+        """gibt 1 zurueck wenn aktuell, 0 sonst"""
+        actualTime=time.localtime()
+        
+        
+        #print getattr(self,'archiveTime',actualTime)
+        if getattr(self,'archiveTime',actualTime)< actualTime:
+            return 0
+        else:
+            return 1
+        
+    def isActualForIndex(self): #isActual kann nicht indiziert werden, da intern fom ZCAtalog verwendete Funktion
+        """gibt 1 zurueck wenn aktuell, 0 sonst"""
+        actualTime=time.localtime()
+        
+        
+        #print getattr(self,'archiveTime',actualTime)
+        if getattr(self,'archiveTime',actualTime)< actualTime:
+            return 0
+        else:
+            return 1
+        
+    def copyObjectToArchive(self):
+        """kopiere aktuelles objekt ins archiv"""
+        logging.info("copytoarchive 1")
+        cb=self.aq_parent.manage_copyObjects(self.getId())
+        logging.info("copytoarchive 2")
+        self.manage_pasteObjects(cb)
+        logging.info("copytoarchive 3")
+        actualTime=time.localtime()
+        
+        self.manage_renameObject(self.getId(),self.getId()+"_"+time.strftime("%Y%m%d%H%M%S",actualTime))
+        logging.info("copytoarchive 4")
+        obj=getattr(self,self.getId()+"_"+time.strftime("%Y%m%d%H%M%S",actualTime))
+        obj.setArchiveTime(time.strftime("%Y%m%d%H%M%S",actualTime))
+        logging.info("copytoarchive 5")
+        ids=[x[0] for x in self.ZopeFind(obj,obj_metatypes=['MPIWGProject'])]
+        logging.info("copytoarchive 6")
+        obj.manage_delObjects(ids)
+        logging.info("copytoarchive 7")
+        
+    def setArchiveTime(self,time):
+        """set Archive Time"""
+        self.archiveTime=time[0:]
+        
+    def delArchiveTime(self):
+        """delete archive time"""
+        del self.archiveTime
+
+    def versionManageForm(self):
+        """version Manage form:currently only set to invisible"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','MPIWGProject_versionManageForm.zpt')).__of__(self)
+        return pt()
+
+    def versionManage(self,invisible=None,RESPONSE=None):
+        """version Manage form:currently only set to invisible"""
+        self.invisible=invisible
+
+        if RESPONSE is not None:
+            
+            self.redirect(RESPONSE,'manage_main')
+
+   
+    def crossLinker(self):
+        """experimental crosslinker"""
+        splitted=self.WEB_project_description[0].split()
+        new=[]
+        for split in splitted:
+            try:
+                found=self.DescriptionCatalog({'fulltext':split})
+          
+                if len(found)>1:
+             
+                    new.append("<a href=%s>%s</a>"%(split,split))
+                else:
+                    new.append(split)
+            except:
+                new.append(split)
+        return " ".join(new)
+            
+            
+
+
+    def generateTemplate(self,RESPONSE=None):
+        """Erzeuge Template fuer defined fields not_used"""
+
+        id="index_html"
+        title=id
+        if self._getOb('index_html'):
+            self._delObject('index_html')
+
+        
+        newObj=ZopePageTemplate(id,'TEXT')
+        self._setObject(id,newObj)
+        #self.manage_addPageTemplate(id,title)
+        if RESPONSE is not None:
+            self.redirect(RESPONSE,'manage_main')
+            
+    def __init__(self, id, argv=None):
+        """initiere classe"""
+
+        self.creationTime=time.strftime("%Y%m%d%H%M%S",time.localtime())[0:]
+        self.id=id
+        self.title=id
+        self.isActiveFlag=True #Flag is true is the project is still active, False if accomplished
+        self.responsibleScientistsList=[] # enthaelt die Lister der verantwortlichen Wissenschaftler in der Form (NAME, KEY), key ist "" flass Wissenschaftler nicht an unserem Haus
+        
+        if argv:
+            for arg in definedFields:
+                try:
+                        setattr(self,arg,argv[arg])
+                except:
+                        setattr(self,arg,"")
+        else:
+            for arg in definedFields:
+                setattr(self,arg,'')
+            
+    manage_options = Folder.manage_options+(
+        {'label':'Load New File','action':'loadNewFileForm'},
+        {'label':'Edit ProjectInfo','action':'editMPIWGProjectForm'},
+        {'label':'Edit BasisInfo','action':'editMPIWGBasisForm'},
+        {'label':'Edit Publications','action':'editMPIWGRelatedPublicationsForm'},
+        {'label':'Edit Themes & Disciplines','action':'editMPIWGDisciplinesThemesForm'},
+        {'label':'Versionmanager','action':'versionManageForm'},
+        )
+
+
+    def isActiveProject(self):
+        """check if the project is still active, default is true, set to false is the project is accomplished"""
+        return getattr(self,'isActiveFlag',True)
+ 
+    def isArchivedProject(self):
+        """check if the project is archived"""
+        
+        completed=self.getCompletedAt()
+       
+       #completed leer 
+        if completed=="" :
+            return False;
+        if completed == 0:
+            return False;
+        
+        
+        return True
+        
+        
+    def setActiveFlag(self,status=True):
+        """set the active flag"""
+        self.isActiveFlag=status
+        
+    def setCompletedAt(self,date):
+        """set the date of completion, date should be in the form DD.MM.YYYY or MM.YYYY or YYYY"""
+        #logging.info("DATE:"+repr(date))
+        transformedDate=self.transformDate(date);
+        #logging.info("transformed"+repr(transformedDate))
+        if transformedDate is not None:
+            setattr(self,"completedAt",transformedDate)
+            return True;
+        else:
+            return False;
+    
+    def setStartedAt(self,date):
+        """set the date of start, date should be in the form DD.MM.YYYY or MM.YYYY or YYYY"""
+        #logging.info("DATE:"+repr(date))
+        transformedDate=self.transformDate(date);
+        #logging.info("transformed"+repr(transformedDate))
+        if transformedDate is not None:
+            setattr(self,"startedAt",transformedDate)
+            return True;
+        else:
+            return False;
+
+    def getCompletedAt(self):
+        """gibt das transformierte Datum zurueck, an dem das Projekt beendet wurde."""
+        date=getattr(self,'completedAt','')
+      
+        if date:
+            return self.reTransformDate(date);
+        else:
+            return ""
+            # test ob parent abgeschlossen ist
+            try:          #TODO: ersetzte try except durch vernuenftige abfrage  
+                ct=self.getContexts(parents=self.getContent('xdata_05'),depth=1)
+                if (len(ct)>0): #is there are parent
+                        return ct[0][0].getCompletedAt()
+                return '';
+            except:
+                return '';
+        
+    def getStartedAt(self):
+        """gibt das transformierte Datum zurueck, an dem Projekt begonnen wurde."""
+        date=getattr(self,'startedAt','')
+        if date:
+            return self.reTransformDate(date);
+        else:
+            return '';
+        
+    def reTransformDate(self,date):
+        """transformiert , transformdate zurueck"""
+        year=int(date/10000)
+        month=int((date-year*10000)/100)
+        day=int((date-year*10000-month*100))
+        if (day==0) and (month==0):
+            return """%s"""%year;
+        if day==0 :
+            return """%s.%s"""%(month,year);
+        
+        return """%s.%s.%s"""%(day,month,year);
+        
+        
+    def transformDate(self,date):
+        """transformiert ein Datum von DD.MM.YYYY, MM.YYYY,YYYY nach  YYYYMMDD, alle nicht angebenen Werte
+        werden auf 0 gesetzt, es wird null zurueckgegeben falls das Datum ungueltig ist""" 
+   
+        if (date==None):
+            return None;
+        
+          
+        if (date.lstrip().rstrip()=="" ) :
+            return "";
+        
+        splitted=date.split(".")
+        length=len(splitted)
+        year=0
+        month=0
+        day=0
+        if length > 3:
+            return "";
+        if length==3:
+            day = int(splitted[0])
+        if length>1:
+            month=int(splitted[length-2])
+        
+        if length > 0:
+            try:
+                year = int(splitted[length-1])
+            except:
+                pass
+        
+       ## logging.info("month:"+(month))
+        if not (0<=month<13):
+            return None;
+        
+        if not(0<=day<32):
+            return None;
+        
+        if (year>0) and (year<1900): #jahr nicht vierstellig eingegeben
+            year=2000+year;
+        return year*10000+month*100+day
+        
+        
+    
+    def checkDate(self,date):
+        """teste ob zum Zeitpunkt date eine andere version existierte"""
+        
+
+        def sortProjectsByTime(x,y):
+            return cmp(x[1].archiveTime,y[1].archiveTime)
+
+        #suche ob aeltere versionen vorhanden sind
+
+        finds=self.ZopeFind(self,obj_metatypes=['MPIWGProject'])
+        if not finds: #wenn nicht dann teste ob die aktuelle version schon existiert hat.
+            ad=getattr(self,'creationTime','20050101000000')
+            if int(date)>int(ad):
+                return self.REQUEST['URL1']+"/"+self.getId()
+            else:
+                return self.REQUEST['URL1']+"/no_project"
+
+
+        else:
+            finds.sort(sortProjectsByTime)
+
+        for find in finds:
+            #gehe durch die alten Projekte und finde das entprechende
+            if (int(find[1].archiveTime) > int(date)) and (int(date)>int(getattr(find[1],'creationTime','20050101000000'))):
+                return self.REQUEST['URL1']+"/"+find[1].getId()
+
+        #kein passendes gefunden, dann teste ob das aktuelle in frage kommt
+        ad=getattr(self,'creationTime','20050101000000')
+        
+        if int(date)>int(ad):
+        
+            return self.REQUEST['URL1']+"/"+self.getId()
+        else:
+            return self.REQUEST['URL1']+"/no_project"
+        
+            
+    def no_project(self):
+        """warnung: project noch nicht existent"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','no_project')).__of__(self)
+        return pt()
+    
+  
+    def harvest_page(self,context=None,mode="normal"):
+        """seite fuer harvesting fuer die Projektsuche"""
+       
+        if not context:
+            context=self
+            
+        if self.isActiveProject() and self.isActual():
+             templates = self.en.getHarvestCache()
+            
+             ext=getattr(self,"harvest_main",None)
+             if ext:
+                 rendered = getattr(self,ext.getId())()
+                 templates[self.absolute_url()]=rendered
+                 transaction.commit()
+                 return rendered
+                 
+
+             pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','harvest_main')).__of__(context)    
+             
+             rendered = pt()
+             templates[self.absolute_url()]=rendered
+             transaction.commit()
+             return rendered
+                 
+ 
+      
+    def index_html(self,request=True,context=None):
+        """show homepage"""
+    
+        bound_names={}
+         
+        if not context:
+            context=self
+        if request:
+            if self.REQUEST.has_key('date') and self.REQUEST.SESSION.get('MPI_redirected',None)==None:
+                self.REQUEST.SESSION['MPI_redirected']=1
+                self.REQUEST.RESPONSE.redirect(self.checkDate(self.REQUEST['date'])+"?date="+self.REQUEST['date'])
+            else:
+                self.REQUEST.SESSION['MPI_redirected']=None
+        
+        #ext=self.ZopeFind(self.aq_parent,obj_ids=["project_main"])
+      
+   
+        request2=getattr(self,'REQUEST',None)
+        
+        if request2 is not None:
+            response = request2.response
+            if not response.headers.has_key('content-type'):
+                response.setHeader('content-type', 'text/html')
+
+        security = getSecurityManager()
+        bound_names['user'] = security.getUser()
+      
+        # Retrieve the value from the cache.
+        keyset = None
+        if self.ZCacheable_isCachingEnabled():
+            
+            # Prepare a cache key.
+            keyset = {'here': self, 'params':request2['QUERY_STRING']}
+                      
+            result = self.ZCacheable_get(keywords=keyset)
+           
+            if result is not None:
+                # Got a cached value.
+                return result
+        
+        pt = getTemplate(self, "project_main")
+         # Execute the template in a new security context.
+        security.addContext(self)
+
+        try:
+            #logging.debug("index_html pt=%s"%repr(pt))
+            result = pt.pt_render(extra_context=bound_names)
+            #logging.debug("index_html result=%s"%repr(result))
+            if keyset is not None:
+                # Store the result in the cache.
+                self.ZCacheable_set(result, keywords=keyset)
+               
+            return result
+        finally:
+            security.removeContext(self)
+       
+
+      
+    def index_html_old(self,request=True,context=None):
+        """show homepage"""
+        if not context:
+            context=self
+        if request:
+            if self.REQUEST.has_key('date') and self.REQUEST.SESSION.get('MPI_redirected',None)==None:
+                self.REQUEST.SESSION['MPI_redirected']=1
+                self.REQUEST.RESPONSE.redirect(self.checkDate(self.REQUEST['date'])+"?date="+self.REQUEST['date'])
+            else:
+                self.REQUEST.SESSION['MPI_redirected']=None
+        
+        #ext=self.ZopeFind(self.aq_parent,obj_ids=["project_main"])
+      
+        ext=getattr(self,"project_main",None)
+        if ext:
+            return getattr(self,ext.getId())()
+        
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','project_main')).__of__(context)    
+
+        return pt()
+
+    
+    def getDataFields(self):
+        """giveListofDatafields"""
+        ret=[]
+        for x in range(1,14):
+            if not x in [6,10,9]: # not used fields
+                ret.append('xdata_%02i'%x)
+        return ret
+            
+    def getDefinedFields(self):
+        """show all defined fields"""
+        
+        return definedFields
+
+    def getAttribute(self,field):
+        """get attrbiute"""
+        return getattr(self,field)
+
+    def getContent(self,field,filter=None):
+        """Inhalt des Feldes"""
+        #logging.debug("getContent field=%s filter=%s"%(field,filter))
+        
+        if field=="short_title":
+                text = self.getContent("xdata_07")
+                if text=="":
+                        text = self.getContent("WEB_title")
+                return text
+
+        text=u''
+
+        for x in getattr(self,field):
+            
+            try:
+                text +=x
+            except:
+                text = x
+            
+        
+
+        try:
+            if text[len(text)-1]==";":
+                text=text[0:len(text)-1]
+          
+                
+        except:
+            pass
+        
+        if text=='': ## wozu die folgenden Zeilen??
+            text2=text
+        else:
+            text2=re.sub(r';([^\s])','; \g<1>',text)
+       
+        if field=="WEB_project_description":##Jedenfalls darf letzteres nicht gemacht werden, falls normaler text
+            text2=text
+            
+        #teste ob ergebnis leer und header dann nehme title
+        
+        if (text2=='') and (field=='WEB_project_header'):
+            return self.getContent('WEB_title')
+
+        if filter:
+            splitted=text2.split("""<p class="picture">""")
+            if len(splitted)>1:
+                tmp=splitted[1].split("</p>")
+                #return repr(splitted[1])
+                try:
+                        self.imageURL=tmp[0].split("\"")[1].encode('utf-8')
+                except:
+                    try:
+                        self.imageURL=tmp[0].split("src=")[1].split(" ")[0].encode('utf-8')
+                    except:
+                        self.imageURL=""
+
+                split2="</p>".join(tmp[1:])
+
+                text3=splitted[0]+split2
+
+                splitted=text3.split("""<p class="picturetitle">""")
+                if len(splitted)>1:
+                    tmp=splitted[1].split("</p>")
+                    self.imagecap=tmp[0].encode('utf-8')
+                
+                    split4="".join(tmp[1:])
+
+                    text5=splitted[0]+split4
+                else:
+                    #keine caption
+                    text5=text3
+            else:
+                #kein bild
+                text5=text2
+        else:
+            text5=text2
+
+        #teste ob WEB_project_description und keine fuehrenden p tags
+        if (len(text5)>4) and (not text5[0:3]=='<p>') and (field=='WEB_project_description'):
+            text5= "<p>"+text5+"</p>"
+
+
+        #filter image
+        
+        text5=text5.lstrip().rstrip() #loescher leerzeichen und einzelndes br
+        if (text5=="<br>") or (text5=="<br/>"):
+            text5=""
+
+        #logging.debug("getcontent: field=%s filter=%s -> %s"%(field,filter,repr(text5)))
+        return unicodify(text5)
+        #return utf8ify(text5) # return as utf-8 byte string
+
+
+    def showImagesOfPage(self,imageUrl=None):
+        """show Images of project"""
+        self.getContent('WEB_project_description',filter='yes') #get the content and store image infos into session
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','projectImageView.zpt')).__of__(self)
+        return pt()
+        
+    
+    def show_html(self):
+        """simple index"""
+        #return "HI"
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','MPIWGProject_index.zpt')).__of__(self)
+        return pt()
+
+    def saveFromPreview(self):
+        """save content aus preview"""
+        self.WEB_project_description=self.previewTemplate.WEB_project_description[0:]
+        self.REQUEST.RESPONSE.redirect("./index.html")
+        
+    def saveEditedContent(self,kupu=None,preview=None):
+        """save Edited content"""
+        #logging.debug("saveEditedContent kupu=%s preview=%s"%(kupu,preview))
+
+        if preview:
+            kupu=preview
+        #find content of body tags
+        start=kupu.find("<body>")
+        end=kupu.find("</body>")
+        newcontent= kupu[start+6:end]
+     
+        if preview:
+            return self.preview(newcontent)
+
+        self.copyObjectToArchive()
+        self.ZCacheable_invalidate()
+        self.WEB_project_description=newcontent[0:]
+       
+        self.REQUEST.RESPONSE.redirect("./index.html")
+        
+        return True
+
+    security.declareProtected('View management screens','edit')
+    def edit(self,western=None):
+        """Edit pages"""
+        if western:
+            self.REQUEST.RESPONSE.setCookie("MP_debug_code","western",path="/")
+
+            
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGProjectNeu.zpt')).__of__(self)
+        return pt()
+    
+    edit_MPIWGProject_main = PageTemplateFile('zpt/edit_MPIWGProject_main', globals())
+
+    def getPathStyle(self, path, selected, style=""):
+        """returns a string with the given style + 'sel' if path == selected."""
+
+        if path == selected:
+            return style + 'sel'
+        else:
+            return style    
+
+    def getLabel(self):
+        """returns label (or title) of this project"""
+        l = self.getContent('xdata_07')
+        if l:
+            return l
+        l = self.getContent('WEB_title')
+        if l:
+            return l
+        return self.title
+
+    def getBreadcrumbs(self):
+        """return list of breadcrumbs from here to the root"""
+        crumbs = []
+        # skip direct parent Folder /projects/
+        parent = self.aq_parent.aq_parent
+        # get parents breadcrumbs
+        if hasattr(parent, 'getBreadcrumbs'):
+            crumbs = parent.getBreadcrumbs()
+        
+        # try to get acquisition URL from parent
+        if hasattr(parent, 'absolute_url'):
+            baseUrl = "%s/%s/"%(parent.absolute_url(), 'projects')
+        else:
+            baseUrl = "/en/research/projects/"
+            
+        # add in the internal project hierarchy
+        
+        ct=self.getContexts(parents=self.getContent('xdata_05'))
+        # start with grandparents
+        ct.reverse()
+        for c in ct:
+            label = shortenString(c[0].getLabel(), 13)
+            crumbs.append((label, baseUrl+c[0].getId(), c[0]))            
+
+        # add this project
+        crumbs.append((self.getLabel(), baseUrl+self.getId(), self))
+            
+        return crumbs
+
+    def getRootProject(self):
+        """returns the root (=top level) project of the current project"""
+        
+        ct=self.getContexts(parents=self.getContent('xdata_05'))
+        if len(ct) > 0:
+            return ct[-1][0]
+        else:
+            return self        
+
+
+    def preview(self,description):
+        """preview"""
+        #logging.debug("preview description=%s"%description)
+        tmpPro=getattr(self,"previewTemplate",None)
+        if not tmpPro:
+            tmpPro=MPIWGProject("previewTemplate")
+            self._setObject("previewTemplate",tmpPro)
+        for field in definedFields:
+            setattr(tmpPro,field,getattr(self,field))
+        tmpPro.WEB_project_description=description[0:]
+        tmpPro.invisible=True
+        pt=PageTemplateFile('zpt/previewFrame.zpt',globals()).__of__(self)
+        return pt()
+
+        #return self.REQUEST.RESPONSE.redirect(self.REQUEST['URL1']+"/previewTemplate")
+        
+
+    def getWebProject_description(self):
+        """get description"""
+        debug = self.REQUEST.cookies.get("MP_debug_code",None)
+        
+        if debug and debug=="western":
+            return """
+            <html>
+            <head>
+            <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+            </head>
+            <body>%s</body>
+            </html>
+            """%self.WEB_project_description[0]
+        
+        return """
+            <html>
+            <head>
+            <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+            </head>
+            <body>%s</body>
+            </html>
+            """%self.getContent('WEB_project_description')
+        
+        
+        
+    def editMPIWGProjectForm(self):
+        """editform"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGProject.zpt')).__of__(self)
+        return pt()
+
+    def isResponsibleScientist(self,key):
+        """teste ob eine Person in der Liste der respl. scientists auftaucht"""
+        #logging.info("XXXXXXXXXXXXX"+repr(self.responsibleScientistsList))
+  
+        
+        keys = [unicodify(x[1]) for x in getattr(self,"responsibleScientistsList",[])]
+        #logging.error("RESP. SCIEN:%s"%getattr(self,"responsibleScientistsList",[]))
+        #logging.error("RESP. SCIEN:%s"%unicodify(key))
+        
+        if unicodify(key) in keys:
+            return True
+        else:
+            return False
+        
+    def getPersonKeyList(self):
+        """gibt die key Liste der beteiligten Personen zurueck (utf8 codiert)"""
+        #logging.error("getPersonKeyList:%s"%getattr(self,'responsibleScientistsList',[]))
+        try:
+            return [utf8ify(x[1]) for x in getattr(self,'responsibleScientistsList',[])]
+        except:
+            return[]
+        
+       
+    def myCapitalize(self,txt):
+        """kapitalisiere auch Namen mit -"""
+        splitted=[x.capitalize() for x in txt.split("-")]
+        return "-".join(splitted)
+    
+    def getNamesOrdered(self,list):
+        """Sortiert die Liste nach der Reihenfolge in xdata_01"""
+        
+        nameList=self.getContent('xdata_01')
+        if nameList.find(";")>-1: # rate Trenner ist ;
+            names=nameList.split(";")  
+        else:
+            names=nameList.split(",")
+            
+        self._v_names=[]
+        for name in names:
+            self._v_names.append(name.rstrip().lstrip())
+            
+            
+        def sort(x,y):
+            try:
+                return cmp(self._v_names.index(x[0]),self._v_names.index(y[0]))
+            except:
+                return 0
+            
+        list.sort(sort)
+        
+        return list
+        
+        ##nameList=nameList.replace(";",",") # falls ; als Trenner ersetze    
+        
+        
+        
+        
+    def identifyNames(self,nameList):
+        """Bekommt eine Komma oder Semikolon getrennte Liste mit Name der Form Vorname MittelName(n) Nachname
+        und ordnet diese dann Mitarbeiter IDs zu falls es schone eine Liste gibt wird im Projekte gibt wird diese Upgedated.
+        @param nameList
+        """
+        
+        if nameList.find(";")>-1: # rate Trenner ist ;
+          names=nameList.split(";")  
+          
+        else:
+            names=nameList.split(",")
+            
+        ##nameList=nameList.replace(";",",") # falls ; als Trenner ersetze    
+        returnNamesDict={}
+
+       
+        for name in names:
+            name=name.lstrip().rstrip()
+            nameSplitted = name.split(" ")
+            if len(nameSplitted)>1:  #vor und nachname angegeben)
+              
+                lastname=nameSplitted[-1]
+                firstname=nameSplitted[0]
+            else:
+                firstname =""
+                lastname=nameSplitted[0]
+               
+            #finde Mitarbeiter mit den entsprechenden Name
+            
+            firstname=self.myCapitalize(firstname).encode('utf-8')
+            lastname=self.myCapitalize(lastname).encode('utf-8')
+            logging.info("Search: %s %s %s"%(name,repr(firstname),repr(lastname)))
+            try:
+                cataloggedNames=self.MembersCatalog(firstName=firstname,lastName=lastname)
+            except:
+                cataloggedNames=[]
+                logging.error("ERROR: identifyNames %s %s"%sys.exc_info()[0:2])
+            
+            #Teste ob die ensprechenden Namen schon der Liste zu geordnet sind
+            #if not hasattr(self,'responsibleScientistsList'):
+            #     self.responsibleScientistsList={}
+            # 
+            # if name in self.responsibleScientistsList.values()
+            
+            if len(cataloggedNames)>0:
+               returnNamesDict[name]=cataloggedNames
+            else:
+                returnNamesDict[name]=[]
+       
+        logging.error("id: %s"%repr(returnNamesDict))
+        return returnNamesDict
+        
+    def editMPIWGProject(self,RESPONSE=None,fromEdit=None):
+        """edit the project and archive the old version"""
+        
+        self.copyObjectToArchive() # archive the object
+        self.ZCacheable_invalidate()
+
+        for x in definedFields:
+            if self.REQUEST.has_key(x):
+                
+                setattr(self,x,[self.REQUEST[x].decode('utf-8')])
+
+        
+       
+
+        completedAt = self.REQUEST.get('completedAt')
+        if not self.setCompletedAt(completedAt):
+            RESPONSE.redirect('./editMPIWGBasisEditor?error="dateWrong')
+  
+        startedAt = self.REQUEST.get('startedAt')
+        if not self.setStartedAt(startedAt):
+            RESPONSE.redirect('./editMPIWGBasisEditor?error="dateWrong')
+        
+        if self.REQUEST.has_key('historicalNames'):
+            self.en.changeHistoricalNames(self.getId(),self.REQUEST['historicalNames'].split("\n"))
+        
+        if self.REQUEST.has_key('active'):
+            self.setActiveFlag(True)
+        else:
+            self.setActiveFlag(False)
+        
+        self.responsibleScientistsList=[] # setze die Liste der verantwortlichen Wissenschaftler zurueck
+        
+        names={}
+        keys={}
+        tmpList=[]
+        for key in self.REQUEST.keys(): #gehe durch das Formular
+            splitted=key.split("_")
+            if splitted[0]=="responsibleScientist": #wenn es ein Feld der Form reponsibleScientist_nr_KEY gibt
+                nr=splitted[2]
+                if splitted[1]=="name":
+                    names[nr]=self.REQUEST[key]
+                elif splitted[1]=="key":
+                    keys[nr]=self.REQUEST[key]
+                
+         
+        for nr in names.keys():#schreibe keys und namen in die Liste, stelle ausserdem sicher, dass name unicode
+             tmpList.append((unicodify(names[nr]),unicodify(keys.get(nr,""))))
+             
+        self.responsibleScientistsList=tmpList
+        
+        self.reindex_object()
+        if fromEdit and (RESPONSE is not None):
+            #RESPONSE.redirect('./editMPIWGBasisEditor')
+            return self.editMPIWGBasisEditor(identifiedNames=self.identifyNames(self.decode(self.REQUEST.get('xdata_01',''))))
+            
+        else:
+            if RESPONSE is not None:
+                RESPONSE.redirect('manage_main')
+
+
+
+    security.declareProtected('View managment screens','editMPIWGDisciplinesThemesEditor')
+    def editMPIWGDisciplinesThemesEditor(self):
+        """edit from edit"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGDisciplinesThemesNeu.zpt')).__of__(self)
+        return pt()
+        
+    
+    def editMPIWGDisciplinesThemesForm(self):
+        """edit the disciplines and themes Form"""
+     
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGDisciplinesThemes.zpt')).__of__(self)
+        return pt()
+
+    def editMPIWGDisciplinesThemes(self,disciplines=None,themes=None,RESPONSE=None,fromEdit=None):
+        """edit disciplin and form"""
+        if disciplines:
+            if type(disciplines) is StringType:
+                self.xdata_09=disciplines
+            else:
+                self.xdata_09=";".join(disciplines)
+        else:
+                self.xdata_09=""
+        if themes:
+            if type(themes) is StringType:
+                self.xdata_10=themes
+            else:
+                self.xdata_10=";".join(themes)
+        else:
+            self.xdata_10=""
+
+        if fromEdit and (RESPONSE is not None):
+            self.redirect(RESPONSE,'./editMPIWGDisciplinesThemesEditor')
+
+        else:
+            if RESPONSE is not None:
+                RESPONSE.redirect('manage_main')
+
+
+    def isChecked(self,wert,list):
+        """check if wert is in ; seperated list"""
+
+        #felder sind manchmnal als liste mit einem element definiert
+        if type(list) is StringType or UnicodeType: 
+            splitted=list.split(";")
+        else:
+            splitted=list[0].split(";")
+
+        splitted=[y.rstrip().lstrip() for y in splitted]
+        
+        for x in splitted:
+            x=re.sub(r"[^A-z ]","",x)
+            if (not x==u'') and x in wert:
+                return 1
+        return 0
+
+    security.declareProtected('View management screens','editMPIWGBasisEditor')
+    def editMPIWGBasisEditor(self, identifiedNames=None):
+                            
+        """editform"""
+        if not identifiedNames:
+            identifiedNames=self.identifyNames(self.getContent('xdata_01'))
+           # identifiedNames=self.getFullNameEntries()
+        
+        logging.error("IdentifiedNames: %s"% repr(identifiedNames))
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGBasisNeu.zpt')).__of__(self)
+        return pt(identifiedNames=identifiedNames)
+
+    security.declareProtected('View management screens','editMPIWGBasisForm')
+    def editMPIWGBasisForm(self):
+        """editform"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGBasis.zpt')).__of__(self)
+        return pt()
+
+    security.declareProtected('View management screens','editMPIWGRelatedPublicationsForm')
+    def editMPIWGRelatedPublicationsForm(self):
+        """Edit related Publications"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGRelatedPublications.zpt')).__of__(self)
+        return pt()
+        
+    
+    def loadNewFileForm(self):
+        """Neues XML-File einlesen"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','MPIWGProject_newfile.zpt')).__of__(self)
+        return pt()
+
+    def loadNewFile(self,RESPONSE=None):
+        """einlesen des neuen files"""
+        fileupload=self.REQUEST['fileupload']
+        if fileupload:
+            file_name=fileupload.filename
+            filedata=fileupload.read()
+
+            argv=xmlhelper.proj2hash(filedata)
+            #print argv.keys()
+            for arg in definedFields:
+                
+                #print arg,argv[arg],getattr(self,arg)
+                try:
+                    temp=argv[arg][0:]
+                    #old=getattr(self,arg)
+                    setattr(self,arg,temp)
+                    #print old,getattr(self,arg)
+                except:
+                    """nothing"""
+                    
+        if RESPONSE is not None:
+            RESPONSE.redirect('manage_main')
+
+    def tagTheProject(self,RESPONSE=None):
+        """TAG"""
+        id=self.getId();
+        tmpl =getattr(self.thesaurus,"main.html")
+        if RESPONSE:
+            RESPONSE.redirect("./thesaurus/main.html?project="+id)
+        return
+        
+def manage_addMPIWGProjectForm(self):
+    """form for adding the project"""
+    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMPIWGProjectForm.zpt')).__of__(self)
+    return pt()
+
+def manage_addMPIWGProject(self,id,RESPONSE=None):
+    """method to add a project"""
+    #print argv
+    fileupload=self.REQUEST.get('fileupload',None)
+    if fileupload:
+
+        file_name=fileupload.filename
+        filedata=fileupload.read()
+        
+        argv=xmlhelper.proj2hash(filedata)
+        
+        #print argv
+        newObj=MPIWGProject(id,argv)
+    else:
+        newObj=MPIWGProject(id)
+
+    self._setObject(id,newObj)
+
+    
+    if RESPONSE is not None:
+        RESPONSE.redirect('manage_main')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPIWGRoot.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,1648 @@
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PageTemplates.PageTemplate import PageTemplate
+from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+from Products.ZSQLExtend.ZSQLExtend import ZSQLExtendFolder
+from Products.ZCatalog.CatalogPathAwareness import CatalogAware
+from OFS.Image import Image
+from Globals import package_home
+import urllib
+import MPIWGStaff
+import string
+import re
+import os
+from types import *
+import logging
+import xmlhelper # Methoden zur Verwaltung der projekt xml
+from OFS.SimpleItem import SimpleItem
+from OFS.Folder import Folder
+from Products.ZSQLMethods.SQL import SQLConnectionIDs
+from AccessControl import ClassSecurityInfo
+from bibliography import *
+import time
+import xml.dom.minidom
+import sys
+import transaction
+
+#from Ft.Xml.XPath import Evaluate
+#from Ft.Xml.XPath.Context import Context
+#from Ft.Xml.Domlette import NonvalidatingReader,PrettyPrint, Print
+#from Ft.Xml import EMPTY_NAMESPACE
+import copy
+import updatePersonalWWW
+import MPIWGStaff
+from MPIWGHelper import *
+from BeautifulSoup import BeautifulSoup, Comment
+from ZODB import FileStorage, DB
+from ZEO import ClientStorage
+
+def sortWeight(x,y):
+    x1=int(getattr(x[1],'weight','0'))
+    y1=int(getattr(y[1],'weight','0'))
+    return cmp(x1,y1)
+
+
+class MPIWGRoot(ZSQLExtendFolder):
+    """Stammordner fuer den Web-Server"""
+
+    _v_harvestCache=None
+    meta_type='MPIWGRoot'
+
+    fieldLabels={'WEB_title':'WEB_Title',
+                 'xdata_01':'Responsible Scientists',
+                 'xdata_02':'Department',
+                 'xdata_03':'Historical Persons',
+                 'xdata_04':'Time period',
+                 'xdata_05':'Sorting number',
+                 'xdata_06':'Keywords',
+                 'xdata_07':'Short title',
+                 'xdata_08':'Other involved scholars' ,
+                 'xdata_09':'Disciplines',
+                 'xdata_10':'Themes',
+                 'xdata_11':'Object Digitallibrary',
+                 'xdata_12':'Cooperation partners',
+                 'xdata_13':'Funding institutions',
+                 'WEB_project_header':'WEB_project_header',
+                 'WEB_project_description':'WEB_project_description',
+                 'WEB_related_pub':'WEB_related_pub'}
+    
+    # (is this used?)
+    folders=['MPIWGProject','Folder','ECHO_Navigation']
+    # language of this instance
+    lang = 'en'
+    # types of objects that show up in navigation
+    nav_meta_types = ['MPIWGTemplate','MPIWGLink','MPIWGFolder']
+
+    manage_options = Folder.manage_options+(
+        {'label':'Update personal homepages','action':'updatePersonalwww_html'},
+        {'label':'Reindex catalogs','action':'reindexCatalogs'},
+        {'label':'Main config','action':'changeMPIWGRootForm'},
+        {'label':'add e-mails','action':'showNewDBEntries'},
+        #{'label':'update the institutsbibliography','action':'updateInstitutsbiliography'},
+        #{'label':'Edit Historical Persons','action':'editHistoricalPersonsForm'},
+        #{'label':'Store Historical Persons','action':'storeHistoricalPersons'},
+        )
+    
+
+    def getHarvestCachePort(self):
+        return getattr(self,"harvestPort",29999)
+    
+    def getHarvestCacheServer(self):
+        return getattr(self,"harvestServer","localhost")
+   
+    
+    def getHarvestCache(self):
+        logging.debug("CACHE:"+repr(self._v_harvestCache))
+        if self._v_harvestCache==None:
+             #storage = FileStorage.FileStorage('/tmp/'+self.getId()+'test-filestorage.fs')
+             addr = self.getHarvestCacheServer(), self.getHarvestCachePort()
+             storage = ClientStorage.ClientStorage(addr)
+             db = DB(storage)
+             self._v_harvestDV=db
+             self._v_harvestDV=db
+             conn = db.open()
+             dbroot = conn.root()
+             if not dbroot.has_key('templates'):
+                 from BTrees.OOBTree import OOBTree
+                 dbroot['templates'] = OOBTree()
+                 
+             self._v_harvestCache = dbroot['templates']
+        logging.debug("CACHE2:"+repr(self._v_harvestCache))            
+        return self._v_harvestCache
+    
+    
+    
+    def __del__(self):
+         if self._v_harvestCache!=None:
+             self._v_harvestDV.close();
+             
+    def getGetNeighbourhood(self,obj, wordStr, length=100,tagging=True):
+        """finde umgebung um die worte in wordStr, zurueckgegeben wird eine Array mit den Umgebungen von Fundstellen der Worte
+        alle Tags werden entfernt, die Fundstellen werden mit <span class="found">XX</span> getaggt, die Umgebungen werden 
+        case insensitive gesucht
+        @param wordStr: string mit Worten getrennt durch Leerzeichen, Phrasen sind mit " gekennzeichnet
+                        "eine phrase", "*"  bezeichnet wildcards und wird ignoriert"
+        @param length: optional, default wert 100, 2*length ist die groesse der Umgebung
+        @param tagging: optional default wert true, kein span tag wird erzweugt falls tag=false
+        """
+        
+        ret=[] # nimmt das Array auf, dass spaeter zurueckgegeben wird
+        ranges=[] #Array mit tupeln x,y wobei x die Position des Anfang und y des Endes der i-ten Umgebung angiebt
+        
+        wordStr=wordStr.lstrip().rstrip()
+        
+        def isInRanges(nr,length):
+            """test ob eine gegeben Position nr schon irgendwo in einer Umgebung ist, gibt den Index des ersten Wertes aus ranges zurueck, 
+            -1, wenn kein Treffer
+            
+            @param nr: Position die geprueft werden soll
+            @param length: Laenge des Wortes das geprueft werden soll
+            """
+            for x in ranges:
+                if (x[0]<=nr) and (nr < (x[1]-length)):
+                    return ranges.index(x)
+            return -1
+                
+        # deal with phrases, in Phrasen werden die Leerzeichen durch "_" ersetzt.
+        def rep_empty(str):
+            x= re.sub(" ","_",str.group(0))
+            return re.sub("\"","",x)
+            
+        wordStr=re.sub("\".*?\"", rep_empty,wordStr)#ersetze leerzeichen in " " durch "_" und loesche "
+        
+        #deal with wildcards, for our purposes it is enough to delete the wildcard 
+        wordStr=wordStr.replace("*","")
+        
+        words=wordStr.split(" ")
+        #if not words is ListType:
+        #   words=[words]
+        
+        
+        txtCache = self.en.getHarvestCache();
+        txt=  txtCache.get(obj.absolute_url(),None)
+       
+        if txt==None:
+            
+            logging.debug("NO CACHE for: "+obj.absolute_url())
+            txt=obj.harvest_page(mode="slim")
+        
+        
+        if not txt:
+            return ret
+        
+        soup = BeautifulSoup(txt)
+        
+        comments = soup.findAll(text=lambda text:isinstance(text, Comment))
+        [comment.extract() for comment in comments]
+        
+        txt = ''.join(soup.findAll(text=True))
+        
+        
+        #txt=re.sub("<.*?>", "", txt) # loesche alle Tags
+        for word in words:
+            word=re.sub("_"," ",word) # ersetze zurueck "_" durch " "
+            pos=0
+            
+            n=txt.lower().count(word.lower()) # wie oft tritt das Wort auf
+
+            for i in range(n):
+                pos=txt.lower().find(word.lower(),pos)
+
+                if pos > 0:
+                    x=max(0,pos-length)
+                    y=min(len(txt),pos+length)
+                  
+                    
+                    #is word already in one of the results
+                    nr=isInRanges(pos,len(word))
+                    if nr >=0:# word ist in einer schon gefunden Umgebung, dann vergroessere diese
+                        x=min(ranges[nr][0],x)
+                        y=max(ranges[nr][1],y)
+              
+                    str=txt[x:y]
+                    if x!=0: #add dots if in the middle of text
+                        str="..."+str
+                    
+                    if y!=len(txt): #add dots if in the middle of text
+                        str=str+"..."
+                        
+                        
+                
+                    if nr >=0: # word ist in einer schon gefunden Umgebung
+                        ranges[nr]=(x,y) # neue Position der Umgebung
+
+                        ret[nr]=str # neue Umgebung
+                    else: # andernfalls neue Umgebung hinzufuegen
+                        ranges.append((x,y))
+
+                        ret.append(str)
+                    
+                    pos=pos+len(word)
+                else:
+                    break;
+                
+        # now highlight everything        
+        if tagging:
+            for x in range(len(ret)):
+                for word in words:
+                    repl=re.compile(word,re.IGNORECASE)
+                    ret[x]=repl.sub(""" <span class="found">%s</span>"""%word.upper(),ret[x])
+
+        return ret
+    def copyAllImagesToMargin(self):
+        """tranformiere alle Bilder in die Margins"""
+        projects=self.getTree()
+        ret=""
+        for project in projects:
+            proj=project[3]
+            try:
+                persons=proj.copyImageToMargin();
+            except:
+                logging.error("Cannnot do: %s"%repr(project))
+                
+    def transformProjectsToId(self):
+        """trnasformiere zu ID, Hilfsfunktion die die alten Templates analysiert und mit der neuen Liste
+        verantwortlicher Personen versieht"""
+        projects=self.getTree()
+        ret=""
+        for project in projects:
+            
+            proj=project[3]
+            persons=proj.identifyNames(proj.getContent('xdata_01'))
+            if not hasattr(proj,'responsibleScientistsList'):
+                        proj.responsibleScientistsList=[]
+                        
+            for person in persons.items():
+              
+                if len(person[1]) >1: #nicht eindeutig
+                    ret+="nicht eindeutig ---  %s:  %s\n"%(proj.getId(),person[0])
+                    
+                elif len(person[1]) ==0: #kein eintrage
+                    ret+="kein eintrag---  %s:  %s\n"%(proj.getId(),person[0])
+                    proj.responsibleScientistsList.append((person[0],""))
+                else:           
+                    proj.responsibleScientistsList.append((person[0],person[1][0].getObject().getKey()))
+        
+        return ret
+          
+                
+    def harvestProjects(self):
+        """harvest"""
+        folder="/tmp"
+        try:
+            os.mkdir("/tmp/harvest_MPIWG")
+        except:
+            pass
+        founds=self.ZopeFind(self.aq_parent.projects,obj_metatypes=['MPIWGProject'],search_sub=1)
+        for found in founds:
+            txt=found[1].harvest_page()
+        
+            if txt and (txt != ""):
+                name=found[0].replace("/","_")
+                fh=file("/tmp/harvest_MPIWG/"+name,"w")
+                fh.write(txt)
+                fh.close()
+                
+    def decode(self,str):
+        """decoder"""
+
+        if not str:
+            return ""
+        if type(str) is StringType:
+            try:            
+                return str.decode('utf-8')
+            except:
+                return str.decode('latin-1')
+        else:
+            return str
+
+
+    def getat(self,array,idx=0,default=None):
+        """return array element idx or default (but no exception)"""
+        if len(array) <= idx:
+            return default
+        else:
+            return array[idx]
+        
+    def getLang(self):
+        """returns the default language"""
+        return self.lang
+
+    def browserCheck(self):
+        """check the browsers request to find out the browser type"""
+        bt = {}
+        ua = self.REQUEST.get_header("HTTP_USER_AGENT")
+        bt['ua'] = ua
+        bt['isIE'] = False
+        bt['isN4'] = False
+        if string.find(ua, 'MSIE') > -1:
+            bt['isIE'] = True
+        else:
+            bt['isN4'] = (string.find(ua, 'Mozilla/4.') > -1)
+
+        try:
+            nav = ua[string.find(ua, '('):]
+            ie = string.split(nav, "; ")[1]
+            if string.find(ie, "MSIE") > -1:
+                bt['versIE'] = string.split(ie, " ")[1]
+        except: pass
+
+        bt['isMac'] = string.find(ua, 'Macintosh') > -1
+        bt['isWin'] = string.find(ua, 'Windows') > -1
+        bt['isIEWin'] = bt['isIE'] and bt['isWin']
+        bt['isIEMac'] = bt['isIE'] and bt['isMac']
+        bt['staticHTML'] = False
+
+        return bt
+
+
+    def versionHeaderEN(self):
+        """version header text"""
+        
+        date= self.REQUEST.get('date',None)
+        if date:
+            txt="""<h2>This pages shows the project which existed at %s</h2>"""%str(date)
+            return txt
+        return ""
+
+    def versionHeaderDE(self):
+        """version header text"""
+        date= self.REQUEST.get('date',None)
+        if date:
+            txt="""<h2>Auf dieser Seite finden Sie die Projekte mit Stand vom %s</h2>"""%str(date)
+        return ""
+    
+        
+    def createOrUpdateId_raw(self):
+        """create sequence to create ids for bibliography"""
+        debug=None
+        #suche groesste existierende id
+        founds=self.ZSQLQuery("select id from bibliography")
+        
+        if founds:
+            ids=[int(x.id[1:]) for x in founds]
+            maximum=max(ids)
+            
+            id_raw=self.ZSQLQuery("select nextval('id_raw')",debug=debug)
+            
+            if id_raw:
+                self.ZSQLQuery("drop sequence id_raw",debug=debug)
+            
+            self.ZSQLQuery("create sequence id_raw start %i"%(maximum+1),debug=debug)
+        
+    
+    def queryLink(self,link):
+        """append querystring to the link"""
+        return "%s?%s"%(link,self.REQUEST.get('QUERY_STRING',''))
+
+    def getKategory(self,url):
+        """kategorie"""
+        splitted=url.split("/")
+        return splitted[4]
+
+    def generateUrlProject(self,url,project=None):
+        """erzeuge aus absoluter url, relative des Projektes"""
+        if project:
+            splitted=url.split("/")
+            length=len(splitted)
+            short=splitted[length-2:length]
+            
+            base=self.REQUEST['URL3']+"/"+"/".join(short)
+
+        else:
+            findPart=url.find("/projects/")
+            base=self.REQUEST['URL1']+"/"+url[findPart:]
+
+                
+        return base
+    
+    def isNewCapital(self,text=None,reset=None):
+        
+        if text:
+            text=text.upper()
+        if reset:
+            self.REQUEST['capital']="A"
+            return True
+        else:
+            if len(text)>0 and not (text[0]==self.REQUEST['capital']):
+                self.REQUEST['capital']=text[0]
+                return True
+            else:
+                return False
+    
+    def subNavStatic(self,obj):
+        """subnav" von self"""
+        subs=self.ZopeFind(obj,obj_metatypes=['MPIWGTemplate','MPIWGLink'])
+        subret=[]
+
+        for x in subs:
+            if not(x[1].title==""):
+                subret.append(x)
+        subret.sort(sortWeight)
+        return subret
+    
+    def subNav(self,obj):
+        """return sub-navigation elements i.e. below sections"""
+        # get section -> parent should be MPIWGRoot
+        p = obj
+        sec = None
+        # descend parents to the root (and remember the last id)
+        while p is not None and p.meta_type != 'MPIWGRoot':
+            sec = p
+            p = p.aq_parent
+    
+        subsecs = sec.objectItems(self.nav_meta_types)
+        subsecs = [s for s in subsecs if s[1].title != ""]
+        subsecs.sort(sortWeight)
+        return subsecs
+                
+    def isType(self,object,meta_type):
+        """teste ob ein object vom meta_type ist."""
+        return (object.meta_type==meta_type)
+    
+    def isActive(self,name):
+        """teste ob subnavigation aktiv"""
+        for part in self.REQUEST['URL'].split("/"):
+            if part==name:
+                return True
+        return False
+        
+    
+    def getSections(self):
+        """returns a list of all sections i.e. top-level MPIWGFolders"""
+        secs = self.objectItems(['MPIWGFolder'])
+        secs.sort(sortWeight)
+        #logging.debug("root: %s secs: %s"%(repr(self.absolute_url()), repr(secs)))
+        # return pure list of objects
+        return [s[1] for s in secs]
+
+    def getSectionStyle(self, name, style=""):
+        """returns a string with the given style + '-sel' if the current section == name"""
+        if self.getSection() == name:
+            return style + '-sel'
+        else:
+            return style    
+
+    def getFeatures(self, num=None):
+        """returns a list of the last num Features"""
+        dir = getattr(self, 'features')
+        features = dir.objectItems(['MPIWGFeature'])
+        features.sort(sortWeight)
+        if num is not None:
+            # take only the last num elements
+            features = features[-num:]
+        # return pure list of objects
+        return [f[1] for f in features]
+
+
+    def getMPIWGRoot(self):
+        """returns the MPIWG root"""
+        return self
+
+    def MPIWGrootURL(self):
+        """returns the URL to the root"""
+        return self.absolute_url()
+        
+    def upDateSQL(self,fileName):
+        """updates SQL databases using fm.jar"""
+        fmJarPath=os.path.join(package_home(globals()), 'updateSQL/fm.jar')
+        xmlPath=os.path.join(package_home(globals()), "updateSQL/%s"%fileName)
+        logger("MPIWG Web",logging.INFO,"java -classpath %s -Djava.awt.headless=true Convert %s"%(fmJarPath,xmlPath))
+        ret=os.popen("java -classpath %s -Djava.awt.headless=true Convert %s"%(fmJarPath,xmlPath),"r").read()
+        logger("MPIWG Web",logging.INFO,"result convert: %s"%ret)
+        return 1
+    
+    def patchProjects(self,RESPONSE):
+        """patch"""
+        projects=self.ZopeFind(self.projects,obj_metatypes=['MPIWGProject'])
+        for project in projects:
+                tmp=project[1].WEB_project_description[0].replace("/CD/projects/","")[0:]
+                setattr(project[1],'WEB_project_description',[tmp[0:]])
+                RESPONSE.write("<p>%s</p>\n"%project[0])
+            
+    def replaceNotEmpty(self,format,field):
+        """replace not empty"""
+        if field and (not field.lstrip()==''):
+            return self.decode(format%field)
+        else:
+            return ""
+        
+
+    def isActiveMember(self,key):
+        """tested ob Mitarbeiter key ist aktiv"""
+        key=utf8ify(key)
+        ret=self.getat(self.ZSQLInlineSearch(_table='personal_www',
+                                            _op_key='eq',key=key,
+                                            _op_publish_the_data='eq',
+                                            publish_the_data='yes'))
+        
+        logging.info("ACTIVE_MEMBER  %s"%ret)
+        if ret:
+            return True
+        else:
+            return False
+        
+    def isActual(self,project):
+        """checke if project is actual"""
+        actualTime=time.localtime()
+        
+        if hasattr(project,'getObject'): #obj ist aus einer catalogTrefferList
+            obj=project.getObject()
+        else:
+            obj=project
+            
+        if getattr(obj,'archiveTime',actualTime)< actualTime:
+            return False
+        else:
+            return True
+        
+    def redirectIndex_html(self,request):
+        #return request['URL1']+'/index_html'
+        
+        return urllib.urlopen(request['URL1']+'/index_html').read()
+
+    
+    def formatBibliography(self,here,found):
+        """format"""
+        return formatBibliography(here,found)
+    
+    def getValue(self,fieldStr):
+        """Inhalt des Feldes"""
+        
+        if type(fieldStr)==StringType:
+            field=fieldStr
+        else:
+            field=fieldStr[0]
+        try:
+            if field[len(field)-1]==";":
+                field=field[0:len(field)-1]
+        except:
+
+            """nothing"""
+        field=re.sub(r';([^\s])','; \g<1>',field)
+        return field.encode('utf-8')
+
+
+    
+    def sortedNames(self,list):
+        """sort names"""
+
+        def sortLastName(x_c,y_c):
+            try:
+                x=urllib.unquote(x_c).encode('utf-8','ignore')
+            except:
+                x=urllib.unquote(x_c)
+
+            try:
+                y=urllib.unquote(y_c).encode('utf-8','ignore')
+            except:
+                x=urllib.unquote(y_c)
+                
+
+            
+            try:
+                last_x=x.split()[len(x.split())-1]
+                last_y=y.split()[len(y.split())-1]
+
+            except:
+
+                last_x=""
+                last_y=""
+            
+            
+            
+            if last_x<last_y:
+                return 1
+            elif last_x>last_y:
+                return -1
+            else:
+                return 0
+            
+        list.sort(sortLastName)
+        list.reverse()
+        
+        return list
+    
+    def __init__(self, id, title):
+        """init"""
+        self.id=id
+        self.title=title
+
+    def removeStopWords(self,xo):
+        """remove stop words from xo"""
+        if not hasattr(self,'_v_stopWords'):
+            self._v_stopWords=self.stopwords_en.data.split("\n")
+    
+        x=str(xo)
+    
+        strx=x.split(" ")
+  
+        for tmp in strx:
+     
+            if tmp.lower() in self._v_stopWords:
+                del strx[strx.index(tmp)]
+
+        return " ".join(strx)
+    
+    def urlQuote(self,str):
+        """quote"""
+        return urllib.quote(str)
+
+    def urlUnQuote(self,str):
+        """quote"""
+        return urllib.unquote(str)
+    
+        
+
+    def getProjectsByFieldContent(self,fieldName,fieldContentsEntry, date=None):
+        """gib alle Projekte aus mit Value von field mit fieldName enthaelt ein Element der Liste fieldContents"""
+        def sort(x,y):
+                return cmp(x.WEB_title[0],y.WEB_title[0])
+
+        if type(fieldContentsEntry) is StringType:
+            fieldContentsTmp=[fieldContentsEntry]
+        else:
+            fieldContentsTmp=fieldContentsEntry
+
+        fieldContents=[]
+        for x in fieldContentsTmp:
+            fieldContents.append(" AND ".join(x.split()))
+        projects=self.ProjectCatalog({fieldName:string.join(fieldContents,' AND')})
+        #print projects
+        #ret=[x for x in projects]
+        ret=[]
+        for x in projects:
+            obj=x.getObject()
+            obj=obj.getActualVersion(date)
+            if obj and (not getattr(obj,'invisible',None)):
+                #if not (x in ret):
+                    ret.append(x)
+
+        ret.sort(sort)
+        return ret
+
+    def changeMPIWGRootForm(self):
+        """edit"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changeMPIWGRootForm')).__of__(self)
+        return pt()
+
+    def changeMPIWGRoot(self,title,connection_id,coneServiceURL,harvestPort,harvestServer,lang=None,autocommit=None,RESPONSE=None):
+        """change"""
+        self.title=title
+        self.connection_id=connection_id
+        #self.disciplineList=disciplineList
+        #self.themesList=themesList
+        self.coneServiceURL=coneServiceURL
+        self.harvestServer=harvestServer
+        try:
+            self.harvestPort=int(harvestPort)
+        except:
+            logging.error("couldn't change port!: no number:"+harvestPort)
+        
+        if lang is not None:
+            self.lang = lang
+
+        self.autocommit = (autocommit == "on")
+        if RESPONSE is not None:
+            RESPONSE.redirect('manage_main')
+
+
+    def getContexts(self,childs=None,parents=None,depth=None,date=None,onlyActive=True):
+        """childs alle childs, alle parents"""
+        ret=[]
+    
+        if parents:
+            pnums=parents.split(".")
+            while len(pnums) > 1:
+                pnums.pop()
+                parentId=string.join(pnums,".")
+        
+                for project in self.getProjectFields('xdata_05',sort='int',date=date):
+                    if project[1]==parentId:
+                        ret.append(project)
+                
+                if (depth is not None) and (len(ret) >= depth):
+                    break
+
+        if childs:
+            for project in self.getProjectFields('xdata_05',sort='int',date=date):
+                searchStr=childs+"(\..*)"
+               
+                if (onlyActive and project[0].isActiveProject()) or (not onlyActive):
+                    if re.match(searchStr,project[1]):
+                        
+                        if depth:
+    
+                            if int(depth)>=len(project[1].split("."))-len(childs.split(".")):
+                        
+                                ret.append(project)
+                        else:
+                            ret.append(project)
+        
+        #logging.debug("getContexts: childs=%s parents=%s depth=%s => %s"%(childs,parents,depth,repr(ret)))
+     
+        return ret
+
+
+    def getAllProjectsAndTagsAsCSV(self,archived=1,RESPONSE=None):
+        """alle projekte auch die nicht getaggten"""
+        retList=[]
+        headers=['projectId','sortingNumber','projectName','scholars','startedAt','completedAt','lastChangeThesaurusAt','lastChangeProjectAt','projectCreatedAt','persons','places','objects']
+        headers.extend(list(self.thesaurus.tags.keys()))
+        retList.append("\t".join(headers))
+        if not hasattr(self,'thesaurus'):
+            return "NON thesaurus (there have to be a MPIWGthesaurus object, with object ID thesaurus)"
+        
+        projectTags = self.thesaurus.getProjectsAndTags()
+        for project in self.getProjectFields('WEB_title_or_short'):
+            proj = project[0]
+            p_name = project[1]
+            retProj=[]
+            #if (not proj.isArchivedProject() and archived==1) or (proj.isArchivedProject() and archived==2):
+            retProj.append(self.utf8ify(proj.getId()))
+            retProj.append(self.utf8ify(proj.getContent('xdata_05')))
+            retProj.append(self.utf8ify(p_name))  
+            retProj.append(self.utf8ify(proj.getContent('xdata_01')))
+            retProj.append(self.utf8ify(proj.getStartedAt()))
+            retProj.append(self.utf8ify(proj.getCompletedAt()))
+            changeDate=self.thesaurus.lastChangeInThesaurus.get(proj.getId(),'') 
+            n = re.sub("[:\- ]","",str(changeDate))
+            retProj.append(n)
+            retProj.append(self.utf8ify(getattr(proj,'creationTime','20050101000000')))  
+            retProj.append("")#TODO: project created at   
+            retProj.append(";".join([person[1] for person in self.thesaurus.getPersonsFromProject(proj.getId())]))
+            retProj.append(";".join([person[1] for person in self.thesaurus.getHistoricalPlacesFromProject(proj.getId())]))
+            retProj.append(";".join([person[1] for person in self.thesaurus.getObjectsFromProject(proj.getId())]))
+            retProj+=self.thesaurus.getTags(proj.getId(),projectTags)
+            retList.append("\t".join(retProj))
+        
+        if RESPONSE:
+            
+            RESPONSE.setHeader('Content-Disposition','attachment; filename="ProjectsAndTags.tsv"')
+            RESPONSE.setHeader('Content-Type', "application/octet-stream")
+      
+        return "\n".join(retList);
+    
+    
+    
+  
+    def getProjectFields(self,fieldName,date=None,folder=None,sort=None):
+        """getListofFieldNames"""
+        ret=[]
+    
+        objects=self.ZopeFind(self.projects,obj_metatypes=['MPIWGProject'],search_sub=0)
+
+                
+        for object in objects:
+            obj=object[1]
+            obj=obj.getActualVersion(date)
+            if obj and (not getattr(obj,'invisible',None)):
+                if fieldName=="WEB_title_or_short":
+
+                    if len(obj.getContent('xdata_07'))<3: # hack weil z.Z. manchmal noch ein Trennzeichen ; oder , im Feld statt leer
+                        fieldNameTmp="WEB_title"
+                    else:
+                        fieldNameTmp="xdata_07"
+                else:
+                    fieldNameTmp=fieldName
+
+                ret.append((obj,obj.getContent(fieldNameTmp)))
+
+        
+        if sort=="int":
+            ret.sort(sortI)
+        elif sort=="stopWords":
+ 
+            ret.sort(sortStopWords(self))
+            
+        else:
+            ret.sort(sortF)
+        
+        return ret
+
+    def showNewProjects(self):
+        projects=[]
+        for objs in self.getProjectFields('WEB_title_or_short'): # Get all Projets
+            if objs[0].xdata_05 and (objs[0].xdata_05[0] == ""):
+                
+                projects.append(objs)
+                
+        return projects
+    
+        
+    def updatePublicationDB(self,personId=None):
+        """updates the publication db, i.e. copy year and type into the main table"""
+        
+        if personId:
+            founds = self.ZSQLInlineSearch(_table="publications",key_main=personId)
+        else:
+            founds = self.ZSQLInlineSearch(_table="publications")
+            
+        for found in founds:
+                        
+            if found.id_institutsbibliographie and (not found.id_institutsbibliographie =="") and (not found.id_institutsbibliographie =="0"):
+                
+                entries = self.ZSQLInlineSearch(_table="institutsbiblio",id=found.id_institutsbibliographie)
+                for entry in entries:
+                    self.ZSQLChange(_table='publications',_identify='oid=%s' % found.oid,year=entry.year,referencetype=entry.reference_type)
+                    
+            if found.id_gen_bib and (not found.id_gen_bib ==""):
+                entries = self.ZSQLInlineSearch(_table="bibliography",id=found.id_gen_bib)
+                for entry in entries:
+                    self.ZSQLChange(_table='publications',_identify='oid=%s' % found.oid,year=entry.year,referencetype=entry.reference_type)
+                    
+        return True        
+    
+    def showNewDBEntries(self):
+        """zeige neue Eintraege in der Datenbank ohne e-mail adressen bzw. fuer die noch kein Object angelegt wurde"""
+        
+        qstr="select * from personal_www where web_object_created='no' and not key=''"
+        res=self.ZSQLQuery(qstr)
+        
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','showNewDBEntries.zpt')).__of__(self)
+        return pt(newEntries=res)
+   
+    def createNewStaffObjects(self,RESPONSE):
+        """create new staff object"""
+        
+        memberFolder=getattr(self,'members')
+        args=self.REQUEST.form
+        arg_k=args.keys()
+        arg_k.remove("submit")
+        ret=""
+        for key in arg_k:
+            k=self.urlUnQuote(key)
+          
+            qstr="select * from personal_www where key=%s"%self.ZSQLQuote(k)
+            res=self.ZSQLQuery(qstr)[0]
+            if args[key]!="": #email-adresse wurde eingetragen
+                #create the object
+                e_mail=args[key]
+                try:
+                    newObj=MPIWGStaff.MPIWGStaff(e_mail,res.last_name,res.first_name,k)
+                    memberFolder._setObject(e_mail,newObj)
+                    obj=getattr(memberFolder,e_mail)
+                    obj.reindex_object()
+                    ret+="Created %s \n"%e_mail
+                    created=True
+                except:
+                    msg="Cannot create new user %s (%s %s)"%(e_mail,sys.exc_info()[0],sys.exc_info()[1])
+                    logging.error(msg)
+                    ret+=msg+"\n"
+                    created=False
+                
+                if created:
+                    qstr="update personal_www set web_object_created='yes',e_mail='%s@mpiwg-berlin.mpg.de' where key=%s"%(e_mail,self.ZSQLQuote(k))
+                    self.ZSQLQuery(qstr)
+        
+        return ret
+                   
+        
+    def generateNewPersonEntry(self,data):
+        """generate a new person entry for data, neue personen werden zunaechst nur in der datenbank angelegt """
+        
+        #memberFolder=getattr(self,'members')
+        #create the object
+        
+#        try:
+#            newObj=MPIWGStaff.MPIWGStaff(urllib.quote(data['key']),data['last_name'].encode('utf-8'),data['first_name'].encode('utf-8')) 
+#            memberFolder._setObject(urllib.quote(data['key']),newObj)
+#        except:
+#            return False, "Cannot create new user %s (%s %s)"%(data['key'],sys.exc_info()[0],sys.exc_info()[1])
+#        
+        
+        #create the new entry in the database
+        
+        
+        result,msg=MPIWGStaff.createNewDBEntry(self,data['publish_the_data'],data['key'],data['last_name'],
+                                  data['first_name'],data['titles_new'],data['status'],"",
+                                  "",data['date_from'],data['date_to'],
+                                  data['department'],'',data['funded_by'],
+                                  data['e_mail2'],data['current_work'],"yes",data['date_stay_at_mpiwg'],data['group'],"no",data['current_work'])
+        
+        return result,msg
+ 
+    def updatePersonEntry(self,data,ignoreEntries=None):
+        """update an person entry from data. but ignore all fields in ignore Entries"""
+        if ignoreEntries is None:
+            ignoreEntries = []
+            
+        #ignoreEntries.append('current_work') # TODO:updatecurrent work
+        logging.debug("updatePersonEntry: data=%s ignoreEntries=%s"%(repr(data),repr(ignoreEntries)))
+        
+        if data['date_to']=="": # wenn date_to leer
+             data['date_to']="date_none"
+        
+        if data['date_from']=="": # wenn date_fromleer
+             data['date_from']="date_none"
+        msg=""
+   
+        
+        #eintragen
+         
+        columns=data.keys()
+        for x in ignoreEntries:
+            logging.debug("updatePersonEntry: ignoring %s"%x)
+            try: #falls in ignore entries felder sind, die nicht in columns sind, fange den fehler ab
+                columns.remove(x)
+            except:
+                pass
+
+        
+        insert=[]
+        for key in columns:
+            if data[key]=="date_none": # date_none eintrag wird zu null uebersetzt
+                insert.append('%s=null'%key)
+            else:
+                insert.append(""" "%s"=%s"""%(key,self.ZSQLQuote(data[key])))
+            
+        insertStr=",".join(insert)
+        queryStr="update personal_www SET %s where key='%s'"%(insertStr,data['key'])
+        self.ZSQLQuery("SET DATESTYLE TO 'German'")
+        self.ZSQLQuery(queryStr)
+       
+        #currentwork
+        #if not (txt==""):
+        #    queryStr="INSERT INTO current_work (id_main,current,publish) VALUES ('%s','%s','%s')"%(id,txt,txt_p)
+        #
+        #    self.ZSQLQuery(queryStr)
+        
+        return True,msg
+
+
+    def updatePersonalwww_doIt(self):
+        """do the update"""
+        args=self.REQUEST.form
+        resultSet=self.REQUEST.SESSION['personal_www']['resultSet']
+        news=self.REQUEST.SESSION['personal_www']['news']
+        conflicts=self.REQUEST.SESSION['personal_www']['conflicts']
+        logging.debug("updatePersonalwww_doIt: args=%s\n  resultSet=%s\n  news=%s\n  conflicts=%s"%(args,resultSet,news,conflicts))
+        
+        ret="<html><body>"
+        # generate the new entry
+      
+        if news and (len(news)>0):
+            ret+="<h2>Hinzugef&uuml;gt</h2>"
+            ret+="<p>Neueintr&auml;ge erscheinen erst auf der Homepage, wenn ihnen eine e-mail Adresse zugeordnet wurde.</p>"
+            ret+="<ul>"
+            
+        for new in news:
+            if args.has_key(self.urlQuote(new.encode('utf-8'))): # entry was selected
+                result,msg=self.generateNewPersonEntry(resultSet[new])
+                if not result:
+                    logging.error("Error (generateNewPersonEntry) %s"%msg)
+                    ret+="<li>ERROR: %s %s"%(new.encode('utf-8'),msg)
+                else:
+                    ret+="<li>OK: %s"%(new.encode('utf-8'))
+                    
+        if news and (len(news)>0):
+            ret+="<p>Neueintr&auml;ge erscheinen erst auf der Homepage, wenn ihnen eine e-mail Adresse zugeordnet wurde.</p>"
+            ret+="</ul>"     
+        
+        # update
+
+        if len(conflicts.keys())>0:
+            ret+="<h2>&Auml;nderung des Benutzers &uuml;bernehmen</h2>"
+            ret+="<p>Wenn n&ouml;tig in Filemaker-db &auml;ndern:</p>"
+            
+        # konflicte   
+        for conflict in conflicts.keys():
+            ignoreEntries=[]
+            displayIgnored=[]
+            for cf in conflicts[conflict]:
+                if args[conflict.encode('utf-8')+'_'+cf[0]]=="stored": #use the stored one
+                    ignoreEntries.append(cf[0])  #so ignore field cf[0]       
+                    displayIgnored.append(cf)
+                    
+            if len(displayIgnored)>0:
+                ret+="<h3>%s</h3>"%conflict.encode('utf-8')
+                ret+="<table border='1'>"
+                for iE in displayIgnored:
+                    ret+="<tr><td>%s</td><td>%s</td><td>%s</td>"%(iE[0].encode('utf-8'),iE[1].encode('utf-8'),iE[2].encode('utf-8'))
+                ret+="</table>"
+                
+            self.updatePersonEntry(resultSet[conflict],ignoreEntries=ignoreEntries)
+         
+         # rest
+        cl=list(conflicts.keys())
+        
+        for key in resultSet.keys():
+             if key not in cl:
+                 self.updatePersonEntry(resultSet[key])
+        return ret+"</body></html>"
+                     
+
+    def updateInstitutsbiliography(self):
+        """update the Institutsbibliogrpahy"""
+        self.upDateSQL('personalwww.xml')
+        return "<html><body>DONE</body></html>"
+
+
+    
+
+    def updatePersonalwww_html(self):
+        """update form for the homepages web form"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','updatePersonalwww.zpt')).__of__(self)
+        return pt()
+
+    
+    def updatePersonalwww(self,uploadfile):
+        """update personalwww
+        @param uploadfile: file handle auf das file
+        """
+        dsn=self.getConnectionObj().connection_string
+        #dsn="dbname=personalwww"
+        resultSet=updatePersonalWWW.importFMPXML(uploadfile)
+        news,conflicts=updatePersonalWWW.checkImport(dsn, resultSet)
+
+        self.REQUEST.SESSION['personal_www']={}
+        self.REQUEST.SESSION['personal_www']['resultSet']=resultSet
+        self.REQUEST.SESSION['personal_www']['news']=news
+        self.REQUEST.SESSION['personal_www']['conflicts']=conflicts
+        
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','updatePersonalwww_check.zpt')).__of__(self)
+        return pt()
+    
+
+     
+    def reindexCatalogs(self,RESPONSE=None):
+        """reindex members and project catalog"""
+        
+        
+        try:
+            
+            self.ProjectCatalog.manage_catalogReindex(self.REQUEST,RESPONSE,self.REQUEST['URL1'])
+            logger("MPIWG Root (reindexCatalog: projects)",logging.INFO,"DONE")
+        except:
+            logger("MPIWG Root (reindexCatalog: projects)",logging.WARNING," %s %s"%sys.exc_info()[:2])
+        
+        try:
+            
+            self.MembersCatalog.manage_catalogReindex(self.REQUEST,RESPONSE,self.REQUEST['URL1'])
+            logger("MPIWG Root (reindexCatalog: members)",logging.INFO,"DONE")
+        except:
+            logger("MPIWG Root (reindexCatalog: members)",logging.WARNING," %s %s"%sys.exc_info()[:2])
+        
+        try:
+            
+            self.fulltextProjectsMembers.manage_catalogReindex(self.REQUEST,RESPONSE,self.REQUEST['URL1'])
+            logger("MPIWG Root (reindexCatalog: fulltextProjectsMembers)",logging.INFO,"DONE")
+        except:
+            logger("MPIWG Root (reindexCatalog: fulltextProjectsMembers)",logging.WARNING," %s %s"%sys.exc_info()[:2])
+            
+        
+        
+        
+        
+        
+        if RESPONSE:
+            RESPONSE.redirect('manage_main')
+
+        
+        
+
+    def getAllMembers(self):
+        #ret=[]
+        
+        def sorter(x,y):
+            return cmp(x[0].lower(),y[0].lower())
+                    
+        results=self.MembersCatalog({'isPublished':True})
+       
+        ret=[(unicodify(", ".join([proj.lastName, proj.firstName])), proj.getKey) for proj in results]
+        
+        ret.sort(sorter)
+        return ret
+    
+    
+    def printAllMembers(self):
+        """print"""
+        members=self.getAllMembers()
+        ret=""
+        for x in members:
+            ret+="<p>%s</p>"%x
+        return ret
+    
+        
+    def makeList(self,entry):
+        """makes a list out of one entry or repeat a list"""
+        if type(entry) is StringType:
+            return [entry]
+        else:
+            return entry
+
+    def getTreeRSS(self,dep=None,date=None,onlyActive=1,onlyArchived=0):
+        """generateTree"""
+        rss="""<?xml version="1.0" encoding="utf-8"?>
+                 <rss version="2.0">
+                   <channel>"""
+        
+        for obj in self.getTree(dep, date, onlyActive, onlyArchived):
+            linkStr="""<link>http://www.mpiwg-berlin.mpg.de/en/research/projects/%s</link>"""
+            rss+="""<item>"""
+            rss+=linkStr%obj[3].getId()
+            rss+="""</item>"""
+            if hasattr(obj[3],'publicationList'):
+	        rss+="""<item>"""
+                rss+=linkStr%(obj[3].getId()+"/publicationList");
+                rss+="""</item>"""
+        rss+="""</channel>
+        </rss>"""
+
+        
+        return rss
+
+    def getTree(self,dep=None,date=None,onlyActive=0,onlyArchived=0):
+        """generate Tree from project list
+        als Liste, jeder Eintrag ist ein Tupel ,(Tiefe, ProjektNummer,ProjektObject
+        onlyActive = 0  : alle Projekte
+        onlyActive = 1 : nur active Projekte
+        onlyActive = 2: nur inactive Projekte
+        
+        onlyArchived=0: alle Projekte
+        onlyArchived= 1 : nur aktuelle Projekte
+        onlyArchived = 2: nur archivierte Projekte
+        
+        department fuer das Tree geholt werden soll
+        """
+
+        returnListTmp=[]
+        returnList=[]
+        
+        for project in self.getProjectFields('xdata_05',sort="int",date=date): # get Projects sorted by xdata_05
+
+            for idNr in project[1].split(";"): # more than one number
+                if not idNr=="":
+                    splittedId=idNr.split(".")
+                    depth=len(splittedId)
+                    nr=idNr
+                    #title=project[0].WEB_title
+                    title=[project[0].getContent('WEB_title')]
+                    #print title
+                    
+                    if idNr[0]=="x": # kompatibilitaet mit alter Konvention, x vor der Nummer macht project inactive
+                        project[0].setActiveFlag(False)
+                   
+                    if (not dep) or (splittedId[0]==dep): #falls dep gesetzt ist nur dieses hinzufuegen.
+                        
+                        if (onlyActive==0):
+                            returnListTmp.append((depth,nr,title,project[0]))
+                        elif (onlyActive==1) and project[0].isActiveProject(): #nur active projekte
+                            returnListTmp.append((depth,nr,title,project[0]))
+                        elif (onlyActive==2) and (not project[0].isActiveProject()): #nur active projekte
+                            returnListTmp.append((depth,nr,title,project[0]))
+                   
+                   
+        #filter jetzt die Liste nach Archived oder nicht
+        for entry in returnListTmp:
+                    if (onlyArchived==0):
+                            returnList.append(entry)
+                    elif (onlyArchived==1) and (not entry[3].isArchivedProject()): #nur active projekte
+                            returnList.append(entry)
+                    elif (onlyArchived==2) and (entry[3].isArchivedProject()): #nur active projekte
+                            returnList.append(entry)
+                   
+        
+        return returnList
+
+
+        
+    def changePosition(self,treeId,select,RESPONSE=None):
+        """Change Postion Entry"""
+        numbers=[]
+
+        # Suche hoechste bisherige nummer
+        projects=self.getProjectFields('xdata_05') # get Projects sorted by xdata_05
+        #print "pj",projects
+        for project in projects: #suche alle subtrees der treeId
+            #print treeId
+            
+            founds=re.match(treeId+"\.(.*)",project[1].split(";")[0])
+            if founds:
+                #print "x",founds.group(0),len(founds.group(0).split("."))
+                if len(founds.group(0).split("."))==len(treeId.split("."))+1: # nur ein punkt mehr, d.h. untere ebene
+                    try:
+                        numbers.append(int(founds.group(0).split(".")[len(founds.group(0).split("."))-1]))
+                    except:
+                        numbers.append(int(0))
+
+        try:
+            highest=max(numbers)
+        except:
+            highest=0
+        projects=self.showNewProjects()
+        for i in self.makeList(select):
+            highest+=10
+            projects[int(i)][0].xdata_05=treeId+"."+str(highest)
+
+
+        if RESPONSE is not None:
+            RESPONSE.redirect('showTree')
+        
+    def changeTree(self,RESPONSE=None):
+        """change the complete tree"""
+        form=self.REQUEST.form
+        hashList={}
+        onlyArchived=int(form.get("onlyArchived",0))
+        onlyActive=int(form.get("onlyActive",0))
+        dep=form.get("dep",None)
+        
+        fields=self.getTree(dep=dep,onlyArchived=onlyArchived,onlyActive=onlyActive)
+        
+        logging.info("GOT TREE!----------------------------------------------------")
+        for field in form.keys():
+            
+            splitted=field.split('_')
+            if (len(splitted)>1) and (splitted[1]=="runningNumber"): #feld hat die Form Nummer_name und runnignNumber
+            
+                
+                nr=int(splitted[0]) # nummer des Datensatzes
+                currentEntry = fields[nr]
+            
+                if form.has_key(str(nr)+'_active'): # active flag is set
+                    fields[nr][3].setActiveFlag(True)
+                else:
+                    fields[nr][3].setActiveFlag(False)
+                    
+                #nummer hat sich geaendert
+                
+                entryChanged = False;
+                
+                if isinstance(fields[nr][3].xdata_05,list): #for some reasons somtimes the content of the field is a list with one entry.
+                    fields[nr][3].xdata_05=fields[nr][3].xdata_05[0]
+                    
+                if not (fields[nr][3].xdata_05==form[str(nr)+'_number']):
+                    logging.info("Changed!Number+++++++++++++++++++++++++++++++++")
+                    logging.info(repr(fields[nr][3].xdata_05)+" ---> "+ repr(form[str(nr)+'_number']))
+                    fields[nr][3].xdata_05=form[str(nr)+'_number']
+                    entryChanged = True
+                    
+                #completed har sich geaendert
+                          
+                td = fields[nr][3].transformDate # hole die funktion zum transformieren des datums
+                  
+                if not (td(fields[nr][3].getCompletedAt())==td(form[str(nr)+'_completed'])):
+                    fields[nr][3].setCompletedAt(form[str(nr)+'_completed'])
+                    logging.info(repr(td(fields[nr][3].getCompletedAt()))+" ---> "+ repr(td(form[str(nr)+'_completed'])))
+                    logging.info("Changed!Completed+++++++++++++++++++++++++++++++++")
+                    entryChanged = True
+                
+                if not (td(fields[nr][3].getStartedAt())==td(form[str(nr)+'_started'])):
+                    fields[nr][3].setStartedAt(form[str(nr)+'_started'])
+            
+                    logging.info(repr(td(fields[nr][3].getStartedAt()))+" ---> "+ repr(td(form[str(nr)+'_started'])))
+                    logging.info("Changed!Started+++++++++++++++++++++++++++++++++")
+                    entryChanged = True
+                
+                
+                if entryChanged:
+                    logging.info("Changed!+++++++++++++++++++++++++++++++++")
+                    fields[nr][3].copyObjectToArchive()
+                
+                    
+        if RESPONSE is not None:
+            RESPONSE.redirect('showTree')
+
+    def getProjectWithId(self,id):
+        fields=self.getProjectFields('xdata_05')
+        for field in fields:
+            if field[1]==id:
+                return field[0]
+
+        return None
+            
+        
+            
+        
+    def getRelativeUrlFromPerson(self,list):
+        """get urls to person list"""
+        ret=[]
+        persons=list.split(";")
+        for person in persons:
+            
+            if len(person)>1: #nicht nur Trennzeichen
+                splitted=person.split(",")
+                if len(splitted)==1:
+                    splitted=person.split(" ")
+                splittedNew=[re.sub(r'\s(.*)','$1',split) for split in splitted]
+                if splittedNew[0]=='':
+                    del splittedNew[0]
+                search=string.join(splittedNew,' AND ')
+                
+                if not search=='':
+
+                    try:
+                        proj=self.MembersCatalog({'title':search})
+                    except:
+                        proj=None
+
+                if proj:
+                    #ret.append("<a href=%s >%s</a>"%(proj[0].absolute_url,person.encode('utf-8')))
+                    ret.append("<a href=%s >%s</a>"%('members/'+proj[0].id+'/index.html',person))
+                else:
+                    #ret.append("%s"%person.encode('utf-8'))
+                    ret.append("%s"%person)
+        return string.join(ret,";")
+        
+    def getMemberIdFromKey(self,key):
+        """gibt die ensprechende id  im members Ordner zum key"""
+        
+        if key=="":
+            return ""
+        try:
+            key=utf8ify(key)
+            catalogged=self.MembersCatalog({'getKey':key})
+            if len(catalogged)==0:
+                return ""
+            else:
+                return catalogged[0].getObject().getId()
+        
+        except:
+            return ""
+
+            
+
+    def getProjectsOfMembers(self,date=None):
+        """give tuple member /projects"""
+        ret=[]
+        members=self.getAllMembers()
+        logging.debug("X %s"%repr(members))
+        #return str(members)
+        for x in members:
+            #logging.debug("X %s"%repr(x))
+            projects=self.getProjectsOfMember(key=x[1],date=date)
+            if len(projects)>0:
+                ret.append((x[0],projects))
+            
+        return ret
+
+    def getProjectsOfMember(self,key=None,date=None,onlyArchived=1,onlyActive=1):
+        """get projects of a member
+    
+        @param key: (optional) Key zur Idenfikation des Benutzer
+        @param date: (optional) Version die zum Zeitpunkt date gueltig war
+        @param onlyArchived: 
+        onlyArchived=0: alle Projekte
+        onlyArchived= 1 : nur aktuelle Projekte
+        onlyArchived = 2: nur archivierte Projekte
+        """
+        # TODO: Die ganze Loesung
+        def sortP(x,y):
+            """sort by sorting number"""
+            return cmp(x.WEB_title,y.WEB_title)
+        
+        ret=[]  
+        if key:     
+            logging.debug("MPIWGROOT (getProjectsOfMember):"+key)
+            proj=self.ProjectCatalog({'getPersonKeyList':utf8ify(key)})
+        else:
+            return ret # key muss definiert sein
+        
+        #logging.debug("MPIWGROOT (getProjectsOfMember):"+repr(proj))
+        if proj:
+            proj2=[]
+            for x in proj:
+                #logging.error("proj:%s"%repr(x.getPath()))
+                if (not getattr(x.getObject(),'invisible',None)) and (getattr(x.getObject(),'archiveTime','')==''):   
+                      proj2.append(x)
+
+        else:
+            proj2=[]
+            
+       
+       
+        proj2.sort(sortP)
+
+        projectListe=[]
+        #logging.error("getprojectsofmember proj2: %s"%repr(proj2))
+        for proj in proj2:   
+            obj=proj.getObject()
+            add=False
+            if onlyArchived==1: #nur aktuell projecte
+                if not obj.isArchivedProject():
+                    add=True
+            elif onlyArchived==2: #nur archivierte
+                if obj.isArchivedProject():
+                    add=True
+            else: #alle
+               add=True 
+               
+            if onlyActive==1: #nur active projecte
+                if obj.isActiveProject():
+                    add=add & True
+                else:
+                    add=add & False
+                
+            elif onlyArchived==2: #nur nicht aktvive
+                if not obj.isActiveProject():
+                    add=add & True
+            else: #alle
+               add=add & True
+                    
+            if add:
+                projectListe.append(obj)
+                
+        #logging.error("getprojectsofmember projectliste: %s"%repr(projectListe))
+        return projectListe
+     
+    def givePersonList(self,name):
+        """check if person is in personfolder and return list of person objects"""
+        
+        splitted=name.split(",")
+        if len(splitted)==1:
+            splitted=name.lstrip().rstrip().split(" ")
+        splittedNew=[split.lstrip() for split in splitted]
+        
+        if splittedNew[0]=='':
+            del splittedNew[0]
+        search=string.join(splittedNew,' AND ')
+        
+        if not search=='':
+            proj=self.MembersCatalog({'title':search})
+
+        if proj:
+            return [[x.lastName,x.firstName] for x in proj]
+        else:
+            return []
+            
+##         splitted=name.split(",") # version nachname, vorname...
+##         if len(splitted)>1:
+##             lastName=splitted[0] 
+##             firstName=splitted[1]
+##         else: 
+##             splitted=name.split(" ") #version vorname irgenwas nachnamae
+        
+##             lastName=splitted[len(splitted)-1]
+##             firstName=string.join(splitted[0:len(splitted)-1])
+
+##         objs=[]
+
+        #print  self.members 
+      ##   for x in self.members.__dict__:
+##             obj=getattr(self.members,x)
+##             if hasattr(obj,'lastName') and hasattr(obj,'firstName'):
+                
+##                 if (re.match(".*"+obj.lastName+".*",lastName) or re.match(".*"+lastName+".*",obj.lastName)) and (re.match(".*"+obj.firstName+".*",firstName) or re.match(".*"+firstName+".*",obj.firstName)):
+                    
+##                     objs.append((obj,lastName+", "+firstName))
+
+        
+##        return objs
+
+
+    def personCheck(self,names):
+        """all persons for list"""
+        #print "names",names
+        splitted=names.split(";")
+        ret={}
+        for name in splitted:
+
+            if not (name==""):
+                try:
+                    ret[name]=self.givePersonList(name)
+                except:
+                    """NOTHIHN"""
+        #print "RET",ret
+        return ret
+
+    def giveCheckList(self,person,fieldname):
+        """return checklist"""
+        #print "GCL",fieldname
+        if fieldname=='xdata_01':
+            x=self.personCheck(person.getContent(fieldname))
+            #print "GCLBACKX",x
+            return x
+        
+
+    def isCheckField(self,fieldname):
+        """return chechfield"""
+        
+        return (fieldname in checkFields)
+
+    
+    def generateNameIndex(self):
+        """erzeuge einen index verwendeter personen"""
+        import psycopg
+        o = psycopg.connect('dbname=authorities user=dwinter password=3333',serialize=0) 
+        results={}
+        print self.fulltext.historicalNames.items()
+        for nameItem in self.fulltext.historicalNames.items(): #gehe durch alle namen des lexikons
+            
+            c = o.cursor() 
+            name=nameItem[0]
+            print "check",name
+            c.execute("select lastname,firstname from persons where lower(lastname) = '%s'"%quote(name))
+            tmpres=c.fetchall()
+            firstnames=[result[1] for result in tmpres] # find all firstnames
+            if tmpres:
+                lastname=tmpres[0][0]
+                
+            for found in self.fulltext({'names':name}):
+                if found.getObject().isActual():
+                    for nh in found.getObject().getGetNeighbourhood(name, length=50,tagging=False): #hole umgebung
+                        #schaue nun ob der vorname hinter oder vor dem name ist
+                        position=nh.find(lastname)
+                        # vorher
+                        #print "NH",nh
+                        bevorS=nh[0:position].split()
+                        #print "BV",bevorS
+                        if len(bevorS)>1:
+                            try:
+                                bevor=[bevorS[-1],bevorS[-2]]
+                            except:
+                                bevor=[bevorS[0]]
+                        else:
+                            bevor=[]
+                        #nachher
+                        behindS= re.split("[,|;| ]",nh[position:]) 
+                        #print "BH",behindS
+                        if len(behindS)>2:
+                            try:
+                                behind=behindS[1:3]
+                            except:
+                                behind=[bevorS[1]]
+                        else:
+                            behind=[]
+                        for firstname in firstnames:
+                            if firstname in bevor+behind: #Namen wie mit Adelspraedikaten werden so erstmal nich gefunden
+                                id="%s,%s"%(lastname,firstname)
+                                if not results.has_key(id):
+                                    results[id]=[]
+                                objId=found.getObject().getId()
+                                if not (objId in results[id]):
+                                    print "d %s for %s"%(id,objId)    
+                                    results[id].append(objId)    
+            self.nameIndex=results
+        return results
+                    
+    def editNameIndexHTML(self):
+        """edit the name index"""
+        if not hasattr(self,'nameIndexEdited'): # falls editierter index noch nicht existiert, kopiere automatisch erstellten
+            self.nameIndexEdited=copy.copy(self.nameIndex)
+            print "huh"
+        #self.nameIndexEdited=copy.copy(self.nameIndex)
+        #print self.nameIndexEdited
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editHistoricalNames.zpt')).__of__(self)
+        return pt()
+    
+    def getNamesInProject(self,projectId):
+        """get all names ofnameIndexEdited which are references in projec with projectId"""
+        
+        ret=[]
+        for name in self.nameIndexEdited.keys():
+            if projectId in self.nameIndexEdited[name]:
+                ret.append(name)
+        
+        return ret
+    
+    def editNameIndex(self,RESPONSE=None,name=None,occurrances=None,submit=None):
+        """edit the index"""
+        nI=self.nameIndexEdited # mI introduced to make sure that changes to nameIndexEdited are know to ZODB
+        if submit=="delete":
+           
+
+            dh=getattr(self,'deletedHistoricalNames',{})
+            
+            if type(dh) is ListType:
+                dh={}
+            if not dh.has_key(name):
+                dh[name]=occurrances.split("\n")
+            else:
+                dh[name]+=occurrances.split("\n")
+            
+            self.deletedHistoricalNames=dh
+            
+            del self.nameIndexEdited[name]
+            
+        
+        elif (submit=="change"):
+            
+            nI[name]=occurrances.split("\n")[0:]
+            
+        elif (submit=="add"):
+            if not nI.has_key(name):
+                nI[name]=occurrances.split("\n")
+            else:
+                nI[name]+=occurrances.split("\n")
+    
+        self.nameIndexEdited=nI
+   
+      
+        if RESPONSE is not None:
+            RESPONSE.redirect('editNameIndexHTML')
+        
+    
+    
+    def restoreIndex(self):
+        """restore"""
+        self.nameIndexEdited=self.nameIndex
+        return "done"
+    
+
+    def sortResults(self,results):
+        """search the catalog and give results back sorted by meta_type"""
+        ret = {}
+        logging.debug(results())
+        for result in results():
+            metaType = result.meta_type
+            resultList= ret.get(metaType,[])
+            resultList.append(result)
+            ret[metaType]=resultList
+        
+        logging.debug(ret)
+        return ret
+        
+            
+def manage_addMPIWGRootForm(self):
+    """form for adding the root"""
+    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMPIWGRootForm.zpt')).__of__(self)
+    return pt()
+
+def manage_addMPIWGRoot(self,id,title,connection_id="",RESPONSE=None):
+    """add a root folder"""
+    newObj=MPIWGRoot(id,title)
+    self._setObject(id,newObj)
+    ob=getattr(self,id)
+    setattr(ob,'connection_id',connection_id)
+    if RESPONSE is not None:
+        RESPONSE.redirect('manage_main')
+        
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPIWGStaff.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,1004 @@
+"""This file contains the classes for the organization of the staff"""
+# TODO: pruefe ob die id der einzelnen tabellen, wie id in publications noch benutzt werden
+# TODO: pruefe ob die bibliographischen felder in publications noch benutzt werden
+# TODO: wird username gebraucht?
+
+from OFS.Folder import Folder
+from Products.ZSQLExtend.ZSQLExtend import ZSQLExtendFolder
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PageTemplates.PageTemplate import PageTemplate
+from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+from Products.ZCatalog.CatalogPathAwareness import CatalogAware
+from Products.versionedFile.extVersionedFile import extVersionedFileFolder
+from AccessControl import getSecurityManager
+
+import os
+import logging
+import bibliography
+import email
+from Globals import package_home
+from Products.PythonScripts.standard import sql_quote
+from types import *
+from AccessControl import ClassSecurityInfo
+import time
+import logging
+import email
+import re
+from OFS.Cache import Cacheable
+import urllib2
+import transaction
+import SrvTxtUtils
+
+from MPIWGHelper import *
+#ersetzt logging
+def logger(txt,method,txt2):
+    """logging""" 
+    logging.info(txt+ txt2)
+
+departmentList="Renn\nRheinberger\nDaston\nKlein\nSibum\nIT\nInstitut\nBibliothek"
+coneService="http://127.0.0.1:8280/MetaDataManagerRestlet/cone/" # kann in MPIWGRoot konfiguriert werden.
+
+
+
+def createNewDBEntry(self,publish_the_data,key,name,vorname,titles_new,position,e_mail,e_mail_p,date_from,date_to,abteilung,heimat_inst,funded_by="",e_mail2="",txt="",txt_p="no",stay_at_mpiwg="",group="",web_object_created="no",current_work=""):
+        """lege person in der datenbank an"""
+
+        if date_to=="": # wenn date_to leer
+             date_to="date_none"
+        
+        if date_from=="": # wenn date_fromleer
+             date_from="date_none"
+        msg=""
+        #test ob id schon existiert
+        if self.ZSQLQuery("select key from personal_www where key='%s'"%id):
+            return False,"ERROR:key%s already exists"%key
+        
+        #eintragen
+        columnlist="""publish_the_data,key,last_name,first_name,titles_new,status,e_mail,e_mail_p,date_from,date_to,department,home_inst,funded_by,e_mail2,date_stay_at_mpiwg,web_object_created,"group",current_work,current_work_p """
+        insertTuple=(publish_the_data,key,name,vorname,titles_new,position,e_mail,e_mail_p,date_from,date_to,abteilung,heimat_inst,funded_by,e_mail2,stay_at_mpiwg,web_object_created,group,current_work,"yes")
+        
+        insert=[]
+        for element in insertTuple:
+            if element=="date_none": # date_none eintrag wird zu null uebersetzt
+                insert.append('null')
+            else:
+                insert.append("%s"%self.ZSQLQuote(element))
+            
+        insertStr=",".join(insert)
+        queryStr="INSERT INTO personal_www (%s) VALUES (%s)"%(columnlist,insertStr)
+        self.ZSQLQuery("SET DATESTYLE TO 'German'")
+        self.ZSQLQuery(queryStr)
+        logging.info("QQQQ %s:"%queryStr)
+        #currentwork
+        #if not (current_work==""):
+        #    queryStr="INSERT INTO current_work (key_main,current,publish) VALUES ('%s',%s,'%s')"%(key,self.ZSQLQuote(current_work),"yes")
+
+        #  self.ZSQLQuery(queryStr)
+        
+        return True,msg
+class MPIWGStaff(CatalogAware,ZSQLExtendFolder,Cacheable):
+    """Staff"""
+
+    meta_type="MPIWGStaff"
+    default_catalog='MembersCatalog'
+    departmentList=departmentList
+    #_v_cone=None;
+    security=ClassSecurityInfo()
+    
+    def redirect(self,RESPONSE,url):
+        """mache ein redirect mit einem angehaengten time stamp um ein reload zu erzwingen"""
+        
+        timeStamp=time.time()
+        
+        if url.find("?")>-1: #giebt es schon parameter
+            addStr="&time=%s"
+        else:
+            addStr="?time=%s"
+            
+        RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT')
+        logging.error(email.Utils.formatdate()+' GMT')
+        RESPONSE.redirect(url+addStr%timeStamp)
+        
+    def getKeyUTF8(self):
+        """get db_key utf8"""
+        logging.debug("KEY - MPIWGStaff 1:"+self.getKey())
+        logging.debug("KEY - MPIWGStaff 2 :"+utf8ify(self.getKey()))
+        
+        return utf8ify(self.getKey())
+    
+    def setKey(self,key):
+	"""set key"""
+	self.key=key
+
+    def rmKey(self):
+        """rm"""
+        self.key=None
+        return ""
+
+    def getKey(self):
+        """get database key"""
+        
+
+        if getattr(self,'key',None):
+            logging.debug("KEY - MPIWGStaff 4:"+self.key)
+            #logging.error("SAVED KEY:%s"%self.key)
+            return unicodify(self.key.lower())
+            #return self.key.lower()
+        
+        #fuer alt faelle ohne key
+        #logging.error("NEW KEY:%s"%(self.firstName+'_'+self.lastName).lower().replace(' ',''))
+        return (self.firstName+'_'+self.lastName).lower().replace(' ','')
+        
+    def getConnectionObj(self):
+         """returns connection id (from root)"""
+         try:
+             root = self.getMPIWGRoot()
+             return root.getConnectionObj()
+         except:
+             return self.en.getConnectionObj()
+
+    def isPublished(self):
+        """gib publications status aus der datenbank aus"""
+        key=self.getKey()
+        query="select count(publish_the_data) from personal_www where lower(key)='%s' and publish_the_data='yes'"%key
+        
+        res = self.ZSQLQuery(query)
+        
+        if res and res[0].count>0:
+            return True
+        else:
+            return False
+        
+ 
+  
+    def updateDBEntry(self,publish_the_data,date_from,date_to,DBid=None,stay_at_mpiwg="",position="",abteilung=""): 
+        """zpddatedb"""
+        if not DBid:
+                    DBid=self.getDBId()
+        
+ 
+        self.ZSQLQuery("SET DATESTYLE TO 'German'")
+
+        test=self.ZSQLQuery("select id from personal_www where id='%s' "%DBid)
+
+        
+        if test and (len(test)>0): #dataset exists
+            logger("MPIWG Web",logging.INFO,'UPDATE: _table="personal_www",_identify="id=%s"'%DBid+',publish_the_data=%s'%publish_the_data+',date_from=%s'%date_from+',date_to=%s'%date_to+',stay_at_mpiwg=%s'%stay_at_mpiwg+',position=%s'%position)
+            self.ZSQLChange(_table="personal_www",_identify="id=%s"%DBid,publish_the_data=publish_the_data,
+                                   date_from=date_from,
+                                   date_to=date_to,stay_at_mpiwg=stay_at_mpiwg,position=position,abteilung=abteilung)
+            return True
+        else:
+            return False
+          
+    def getPublicationSelectionMode(self):
+        """get publication selection mode, default 'priority'"""
+        return getattr(self,'publicationSelectionMode','priority')
+        
+    def changePublicationSelectionMode(self,publicationSelectionMode,RESPONSE=None):
+        """change PublicationSelectionMode"""
+        
+        self.publicationSelectionMode=publicationSelectionMode
+        self.ZCacheable_invalidate()
+        if RESPONSE:
+            self.redirect(RESPONSE,"editPublications")
+            
+    
+    def downloadCV(self,RESPONSE):
+        """download cv file"""
+        ob=self._getOb("downloadableFiles")._getOb("cv.pdf")
+        
+        RESPONSE.redirect(ob.absolute_url()+"/download")
+    
+    def getLastUpdateCV(self):
+        """getDate of Last Update"""
+        try:
+                ob=self._getOb("downloadableFiles")._getOb("cv.pdf")
+                return ob.getLastChangeDate()
+        except:
+                return "No file yet!"
+    def getLastUpdatePublications(self):
+        """getDate of Last Update"""
+        try:
+                ob=self._getOb("downloadableFiles")._getOb("publications.pdf")
+                return ob.getLastChangeDate()
+        except:
+                return "No file yet!"
+    def downloadPublications(self,RESPONSE):
+        """download publications"""
+        ob=self._getOb("downloadableFiles")._getOb("publications.pdf")
+        
+        RESPONSE.redirect(ob.absolute_url()+"/download")
+   
+    def changeDownloads(self,cv_pdf=None,cv_publish=None,publications_pdf=None,publications_publish=None,RESPONSE=None):
+        """"change the downloadable files"""
+        self.ZCacheable_invalidate()
+        if not hasattr(self,'downloadableFiles'):
+           
+            extFolder =  extVersionedFileFolder()
+            extFolder.id = "downloadableFiles"
+            self._setObject(extFolder.id,extFolder)
+            
+        ob = self._getOb("downloadableFiles")
+        
+        if cv_publish:
+            self.cv_publish=cv_publish
+            
+        if publications_publish:
+            self.publications_publish=publications_publish
+            
+        if cv_pdf:
+            if not hasattr(ob,"cv.pdf"):
+                ob.addFile("",cv_pdf,newName="cv.pdf")
+            
+            else:
+                cvFile = getattr(ob,"cv.pdf")
+                cvFile.addContentObject("","",file=cv_pdf)
+        
+        if publications_pdf:
+            if not hasattr(ob,"publications.pdf"):
+                ob.addFile("",cv_pdf,newName="publications.pdf")
+            
+            else:
+                cvFile = getattr(ob,"publications.pdf")
+                cvFile.addContentObject("","",file=publications_pdf)
+        
+        if RESPONSE:
+            self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER'])
+    
+
+    def getPublishImage(self):
+        """publish the image??, default no"""
+        return getattr(self,'publishImage','no')
+    
+    def updateImage(self,publishImage,file=None,rename=None,RESPONSE=None):
+        """update image"""
+
+        if file and not(file.filename==""):
+            if self.getImageObj():
+                              self.getImageObj().updateImage(file,_rename=None,RESPONSE=None)
+            else:
+                # create new image object
+                xp = file.filename.rfind('.')
+                if xp > 0:
+                    ext = file.filename[xp:]
+                    #fn = self.getId()+ext
+                    fn = self.getId()
+                    logger("MPWIG STAFF", logging.INFO, "new filename: %s"%fn)
+                    self.getImageFolder().addImage2(file,fileName=fn)
+                else:
+                    logger("MPWIG STAFF", logging.ERROR, "uploaded filename %s has no extension!"%file.filename)
+            
+        self.publishImage=publishImage
+        
+        if RESPONSE:
+            self.redirect(RESPONSE,"edit")
+            
+    def getImageFolder(self):
+        """getImageFolder"""
+        #TODO: make place of staff image folder configurable
+        
+        try:
+            return self.getPhysicalRoot().www_neu.images.staff_images
+        except: 
+            logger("MPWIG STAFF", logging.ERROR, "image folder not found: has to be add /www_neu/staff_images") 
+            return None
+        
+    def getImageObj(self):
+        """getImage"""
+        imageFolder=self.getImageFolder()
+        
+        if not imageFolder: return None
+        
+        image=getattr(imageFolder,self.getId(),None)
+
+        if not image:
+            for suffix in ['jpg','tif']:
+                
+                image=getattr(imageFolder,self.getId()+"."+suffix,None)
+                if image:
+                    break
+        return image
+            
+    def getImageUrl(self):
+        """getImageUrl"""
+        image=self.getImageObj()
+        if not image:
+            return None
+        else:
+            return self.getImageObj().absolute_url()+"/image"
+    
+    def PrincipiaSearchSource(self):
+        """Return cataloguable key for ourselves."""
+        return str(self)
+
+    manage_options = Folder.manage_options+(
+        {'label':'Edit','action':'changeMPIWGStaffForm'},
+        {'label':'Change Publications Special','action':'changePublications_specialForm'},
+        ) + Cacheable.manage_options
+    
+    __manager_id = "ramCache"
+    def __init__(self,id, lastName,firstName,key):
+        """init"""
+        self.id=id
+        self.title=key
+        self.lastName=lastName
+        self.firstName=firstName
+        self.key=key
+    
+    def getPersonID(self):
+        """gibt den ID fuer die Person zurueck"
+        im Moment ist personID = id, i.e. e-mail
+        """
+        return self.id
+
+    def getConeUrl(self):
+        """gibt coneURL zurueck"""
+        
+        self.coneService=getattr(self, "coneServiceURL",coneService)
+        logging.debug("coneservice:"+self.coneService)
+        
+        if getattr(self,'_v_cone',None)==None:
+            try:  
+                
+                self._v_cone=SrvTxtUtils.getHttpData(self.coneService+self.getPersonID())
+                #cone = urllib2.urlopen(self.coneService+self.getPersonID())              
+                #self._v_cone=cone.read()
+                if self._v_cone==None:
+                    self._v_cone=""
+            except:
+                self._v_cone=""
+                return ""
+            
+        return self._v_cone
+           
+           
+        
+        
+    def harvest_page_old(self,context=None):
+        """geharvestete seite = verschlankte version von members_main"""
+        #pt = getTemplate(self, "harvest_members_main")
+        
+        if not self.isPublished():
+            return ""
+        if not context:
+            context=self
+            
+        
+        ext=getattr(self,"harvest_members_main",None)
+        if ext:
+            return getattr(self,ext.getId())()
+        
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','harvest_members_main')).__of__(context)    
+
+
+        return pt()
+
+    def harvest_page(self,mode="normal"):
+        """harvest"""
+        logging.debug("AAAAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
+        if not self.isPublished():
+            return 
+        st = getattr(self.en.staff.members,self.getId()).index_html(mode)
+        
+        templates = self.en.getHarvestCache()
+        #templates = getattr(self,'getHarvestCache',self.en.getHarvestCache)()
+        rendered = st
+        templates[self.absolute_url()]=rendered
+        transaction.commit()
+        return rendered
+	
+        
+    
+    def index_html(self,mode="normal"):
+        """show homepage"""
+    
+        bound_names={}
+        request = self.REQUEST
+        if request is not None:
+            response = request.response
+            if not response.headers.has_key('content-type'):
+                response.setHeader('content-type', 'text/html')
+
+        security = getSecurityManager()
+        bound_names['user'] = security.getUser()
+
+        # Retrieve the value from the cache.
+        keyset = None
+        if self.ZCacheable_isCachingEnabled():
+            
+            # Prepare a cache key.
+            keyset = {'here': self}
+                      
+            result = self.ZCacheable_get(keywords=keyset)
+           
+            if result is not None:
+                # Got a cached value.
+                return result
+        
+        # look for individual page
+        if self.hasObject("index.html"):
+            pt = getattr(self, "index.html")
+        # else use template
+        else:
+            if mode=="slim":
+                pt = getTemplate(self, "members_main_slim")
+            else:
+                pt = getTemplate(self, "members_main")
+        # Execute the template in a new security context.
+        security.addContext(self)
+
+        try:
+            result = pt.pt_render(extra_context=bound_names)
+            if keyset is not None:
+                # Store the result in the cache.
+                self.ZCacheable_set(result, keywords=keyset)
+               
+            return result
+        finally:
+            security.removeContext(self)
+       
+
+   
+    def changePublications_specialForm(self):
+        """Priority publications manual field"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changePublications_special.zpt')).__of__(self)
+        return pt()
+        
+    def changePublications_special(self,usePublicationsSpecial=None,specialPublicationsField=None,RESPONSE=None):
+        """change publications special params"""
+        self.ZCacheable_invalidate()
+        if usePublicationsSpecial:
+          self.usePublicationsSpecial=True
+         
+        else:
+          self.usePublicationsSpecial=False
+
+        self.specialPublicationsField=specialPublicationsField[0:]
+
+        if RESPONSE is not None:
+            self.redirect(RESPONSE,'manage_main')
+
+        
+    def publications_full(self):
+        """show publication"""
+        pt=getTemplate(self, "publications_full_main")
+        return pt()
+
+    def talks_full(self):
+        """show talks"""
+        pt=getTemplate(self, 'talks_full_main')
+        return pt()
+
+    def teaching_full(self):
+        """show talks"""
+        pt=getTemplate(self, 'teaching_full_main')
+        return pt()
+    
+    def changeMPIWGStaffForm(self):
+        """change form"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGStaff.zpt')).__of__(self)
+        return pt()
+    
+    security.declareProtected('View management screens','changeMPIWGStaff')
+    def changeMPIWGStaff(self,lastName,firstName,key=None,RESPONSE=None):
+        """change it"""
+        self.ZCacheable_invalidate()
+        self.title="%s, %s"%(lastName,firstName)
+        self.lastName=lastName
+        self.firstName=firstName
+        if key:
+            self.key = key
+            
+        
+        if RESPONSE is not None:
+            self.redirect(RESPONSE,'manage_main')
+            
+    security.declareProtected('View management screens','edit')
+    def edit(self):
+        """Edit the pages"""
+        #TODO: zusammenspiel mit apache, redirect auf 18080 rausnehmen bzw. zumindest verallgemeinern
+        #if self.REQUEST['SERVER_URL']=="http://www.mpiwg-berlin.mpg.de":
+        #        redURL="http://xserve04.mpiwg-berlin.mpg.de:18080/www_neu/de/mitarbeiter/members/%s/edit"%self.getId()
+        #
+        #        self.REQUEST.RESPONSE.redirect(redURL)
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editMPIWGStaff.zpt')).__of__(self)
+        
+        
+        logging.debug("XX:"+email.Utils.formatdate().split("-")[0]+'GMT')
+        return pt()
+
+    mainEditFile=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editMPIWGStaff_main.zpt'))
+    addPublicationsBib=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addPublicationsBib.zpt'))
+
+    def getPathStyle(self, path, selected, style=""):
+        """returns a string with the given style + 'sel' if path == selected."""
+
+        if path == selected:
+            return style + 'sel'
+        else:
+            return style    
+
+
+    def getLabel(self):
+        """returns a label for this object"""
+        return self.title
+
+    def getBreadcrumbs(self):
+        """return list of breadcrumbs from here to the root"""
+        crumbs = []
+        # skip direct parent Folder /members/
+        parent = self.aq_parent.aq_parent
+        # get parents breadcrumbs
+        logging.debug("getbreadcrumbs-: title=%s self=%s parent=%s"%(self.title, repr(self), repr(parent)))
+        if hasattr(parent, 'getBreadcrumbs'):
+            logging.debug("getbreadcrumbs: recurse to %s"%parent)
+            crumbs = parent.getBreadcrumbs()
+        
+        # try to get acquisition URL from parent
+        if hasattr(parent, 'absolute_url'):
+            baseUrl = "%s/%s/"%(parent.absolute_url(), 'members')
+        else:
+            baseUrl = "/en/staff/members/"
+            
+        # add this
+        crumbs.append((self.getLabel(), baseUrl+self.getId(), self))
+            
+        return crumbs
+
+
+    def changeCurrentWork(self,current_work,key,publish="yes",RESPONSE=None):
+        """change current work"""
+        
+        query="UPDATE personal_www SET current_work =%s WHERE key='%s'"
+         
+        self.ZSQLQuery(query%(self.ZSQLQuote(current_work),key))
+       
+        query="UPDATE personal_www SET current_work_p =%s WHERE key='%s'"
+         
+        self.ZSQLQuery(query%(self.ZSQLQuote(publish),key))
+        self.ZCacheable_invalidate()
+        if RESPONSE:
+            self.redirect(RESPONSE,"edit")
+        
+    security.declareProtected('View management screens','changeResearch')
+    def changeResearch(self,noredirect=None,RESPONSE=None):
+        """change the research entries"""
+        self.ZCacheable_invalidate()
+        newEntries={}
+        key_main=self.REQUEST.form['key_main']
+
+        mainfieldL=self.REQUEST.form['main_fields'].split(",")
+        mainfield={}
+        for x in mainfieldL:
+            tmp=x.split('__')
+            mainfield[tmp[0]]=tmp[1]
+        for field in self.REQUEST.form.keys():
+            splittedField=field.split("__")
+            if len(splittedField)<3:
+                pass #kein datenbank eintrag
+
+            elif splittedField[2]=='new': # store new entries
+                if not newEntries.has_key(splittedField[0]):
+                    newEntries[splittedField[0]]={}
+                    
+                newEntries[splittedField[0]][splittedField[1]]=self.REQUEST.form[field]
+
+            else:
+                query="UPDATE %s "%splittedField[0]
+                query+="SET %s = '%s' "%(splittedField[1],sql_quote(self.REQUEST.form[field]))
+                query+="WHERE oid = '%s' "%sql_quote(splittedField[2])
+                
+                self.ZSQLQuery(query)
+
+
+        #new entries
+        for newEntry in newEntries.keys():
+            query="INSERT INTO %s "%newEntry
+            keys=['key_main']
+            values=["'"+sql_quote(key_main)+"'"]
+            for key in newEntries[newEntry].keys():
+                keys.append(key)
+                values.append("'"+sql_quote(newEntries[newEntry][key])+"'")
+
+
+            keystring=",".join(keys)
+                
+            valuestring=",".join(values)
+                
+            query+=" (%s) "%keystring
+            query+="VALUES (%s)"%valuestring
+            if not (newEntries[newEntry][mainfield[newEntry]].lstrip().rstrip()==""):
+                self.ZSQLQuery(query)
+
+        if not noredirect:
+            self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER'])
+            
+    security.declareProtected('View management screens','editCV')    
+    def editCV(self,cv=None,oid=None,RESPONSE=None):
+         """edit Cv"""
+
+         if (not oid):
+             pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editCV.zpt')).__of__(self)
+             return pt()
+        
+         query="UPDATE personal_www SET cv =%s WHERE oid='%s'"
+         self.ZCacheable_invalidate()
+         self.ZSQLQuery(query%(self.ZSQLQuote(cv),oid))
+        
+         if RESPONSE:
+            self.redirect(RESPONSE,"editCV")
+            
+    
+    def getProfile(self):
+        """get the profile"""
+	self.REQUEST.RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT')
+      
+        founds=self.ZSQLInlineSearchU(_table='personal_www',key=self.getKeyUTF8())
+        html="""<html><body>%s</body></html>"""
+        if founds.profile and founds.profile != "":
+           
+            return html%founds.profile
+        else:
+                        
+            return html%self.generateProfileForPerson(founds)
+            
+    def editProfile(self,oid=None,RESPONSE=None, kupu=None, preview=None):
+         """edit Profile, new entry replaces CD, current work and research interests"""
+        
+         if (not oid):
+             pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editProfile.zpt')).__of__(self)
+             return pt()
+        
+         self.ZCacheable_invalidate() 
+         
+         
+         if preview:
+             pass
+             #TODO: not supported yet
+             #kupu=preview
+             # find content of body tags
+        
+         start=kupu.find("<body>")
+         end=kupu.find("</body>")
+         
+         newcontent= kupu[start+6:end]
+            
+            
+         
+        
+         if preview: 
+            #TODO: not supported yet
+            if RESPONSE:
+                self.redirect(RESPONSE,"editProfile")
+            
+            #return self.preview(newcontent)
+
+         query="UPDATE personal_www SET profile=%s WHERE oid='%s'"       
+         self.ZSQLQuery(query%(self.ZSQLQuote(newcontent),oid))
+         logging.error("PROFILE:"+query%(self.ZSQLQuote(newcontent),oid))
+         if RESPONSE:
+            self.redirect(RESPONSE,"editProfile")
+
+
+
+    def generateProfileForPerson(self,person):
+        """erzeugt ein automatisches Profil aus den alten Eintraegen  CV, Current work, und research interests"""
+        
+        ret=""
+        #founds=self.ZSQLInlineSearch(_table='research_interest',key_main=person.getKeyUTF8())
+        founds=self.ZSQLInlineSearch(_table='research_interest',key_main=person.key)
+        if founds:
+            ret="<p class=\"bio_section_header\">Research interests: </p><br/>"
+        for found in self.sortPriority(founds):
+            ret+=found.interest+"<br/>"
+        
+        
+        if (person.current_work) and (not person.current_work==""):
+            ret+="<p class=\"bio_section_header\">Current work: </p><br/>"
+      
+            ret+=person.current_work+"<br/>"
+    	if (person.cv) and (not person.cv==""):
+            ret+="<p class=\"bio_section_header\">Curriculum Vitae: </p><br/>"
+	    ret+=self.formatAscii(person.cv)
+        
+        return ret
+    security.declareProtected('View management screens','editDownloads')
+    def editDownloads(self):    
+        """editiere die Downloads von der Webseite"""
+        
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editDownloads.zpt')).__of__(self)
+        return pt()
+    
+    security.declareProtected('View management screens','editAdditionalLinks.zpt')
+    def editAdditionalLinks(self):    
+        """editiere die Downloads von der Webseite"""
+        
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editAdditionalLinks.zpt')).__of__(self)
+        return pt()
+    
+    
+    security.declareProtected('View management screens','editAwards')    
+    def editAwards(self,awards=None,oid=None,RESPONSE=None):
+         """edit a awards"""
+     
+         if (not oid):
+             pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editAwards.zpt')).__of__(self)
+             return pt()
+         self.ZCacheable_invalidate()
+         query="UPDATE personal_www SET awards =%s WHERE oid='%s'"
+      
+         self.ZSQLQuery(query%(self.ZSQLQuote(awards),oid))
+        
+        
+         if RESPONSE:
+            self.redirect(RESPONSE,"editAwards")
+
+    security.declareProtected('View management screens','editTalks')    
+    def editTalks(self):
+        """edit talks"""
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editTalks.zpt')).__of__(self)
+        return pt()
+        
+    security.declareProtected('View management screens','editTeaching')    
+    def editTeaching(self):
+        """edit Teaching"""
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editTeaching.zpt')).__of__(self)
+        return pt()
+        
+    def getDocTypes(self):
+        finds = self.ZopeFind(self.metadata.main.meta.bib,obj_metatypes=["OSAS_MetadataMapping__neu"])
+
+        list= [x[0] for x in finds]
+        return "\n".join(list)
+
+    security.declareProtected('View management screens','editMainData')    
+    def editMainData(self,REQUEST=None,RESPONSE=None):
+        """edit main data"""
+        self.ZCacheable_invalidate()
+        argv=REQUEST.form
+        
+        if not argv.has_key('last_name'):
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editMainData.zpt')).__of__(self)
+            return pt() 
+        else:
+            self.ZSQLChange(argv,_table="personal_www",_identify="lower(key)=%s"%utf8ify(self.getKey().lower()),USE_FORM="yes")
+            # aendere auch dien enstsprechen infos in der instance
+            self.changeMPIWGStaff(argv['last_name'],argv['first_name']);
+            
+            
+            
+            self.reindex_object()
+            
+            
+            
+            if RESPONSE:
+                self.redirect(RESPONSE,"editMainData")
+                
+    security.declareProtected('View management screens','newBibliogrpaphy')    
+    def newBibliography(self,_docType=None, _addEntry=None,RESPONSE=None,**argv):
+        
+        """add an entry to the bibliography"""
+        if not _docType: #kein docType
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','newBibliographyEntryDocType.zpt')).__of__(self)
+            return pt() 
+        elif _docType and not _addEntry: #doctype aber keine daten
+            self.REQUEST['_docType']=_docType
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','newBibliographyEntry.zpt')).__of__(self)
+            return pt() 
+        else: #doctype und daten
+            try:
+                newId=self.ZSQLSimpleSearch("select nextval('id_raw')")[0].nextval
+            except:#id_raw existiert nich, dann neu erzeugen
+                
+                self.createOrUpdateId_raw()
+                newId=self.ZSQLSimpleSearch("select nextval('id_raw')")[0].nextval
+                                
+            bookId="b%06i" % newId
+            
+            self.ZSQLAdd(argv,_table="bibliography",reference_type=_docType,id=bookId)
+
+            self.ZSQLAdd(_useRequest=False,_table="publications",id_gen_bib=bookId,key_main=self.getDBId(),publish='yes')
+            self.updatePublicationDB(personId=self.getDBId())
+            
+        
+        if RESPONSE:
+            self.redirect(RESPONSE,"editPublications")
+            
+        return True
+    
+    security.declareProtected('View management screens','editImage')    
+    def editImage(self):
+        """edit images"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editImageStaff.zpt')).__of__(self)
+        return pt()
+    
+    security.declareProtected('View management screens','editBibliography')    
+    def editBibliography(self):
+        """edit the bibliography"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editBibliographyEntry.zpt')).__of__(self)
+        return pt()
+    
+      
+    security.declareProtected('View management screens','editPublications')    
+    def editPublications(self):
+        """edit the bibliographie"""
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editPublications.zpt')).__of__(self)
+        return pt()
+    
+    def changeSortingMode(self,sortingMode,RESPONSE=None,REQUEST=None):
+        """change sorting mode"""
+        self.ZCacheable_invalidate()
+        self.sortingMode=sortingMode
+        
+        if RESPONSE and REQUEST:
+            self.redirect(RESPONSE,REQUEST['HTTP_REFERER'])
+
+        return True
+
+    def getSortingMode(self):
+        """get sorting mode"""
+        mode=getattr(self,'sortingMode','priority')
+        if mode=="year":
+            return "year DESC"
+        else:
+            return mode
+        
+    def integer(self,value):
+        try:
+            return int(value)
+        except:
+            return 0
+        
+    security.declareProtected('View management screens','changePublications')    
+    def changePublications(self,RESPONSE=None):
+        """change the publication list"""
+        self.changeResearch(noredirect=True)
+        self.ZCacheable_invalidate()
+        #self.updatePublicationDB(personId=self.getDBId())
+        self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER'])
+        
+
+  
+    security.declareProtected('View management screens','addPublications')    
+    def addPublications(self,submit=None,REQUEST=None,noredirect=None,RESPONSE=None):
+        """add publications"""
+
+        #setzte flag ob aufruf aus suchformular
+        
+        if REQUEST.get("QUERY_STRING",None) and (not submit):
+            self.REQUEST.set('fromSearch','1')
+        else:
+            self.REQUEST.set('fromSearch','0')
+             
+        if not submit or (not (submit == "add")):
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addPublications.zpt')).__of__(self)
+            return pt()
+        
+        #new entries
+        entries = REQUEST.form.get('addEntries',None)
+        if not (type(entries) is ListType):
+            entries=[entries]
+        
+        
+        for bibId in entries: 
+            query="INSERT INTO %s " % "publications"
+            query+="(key_main,id_institutsbibliographie,publish) "
+            query+="VALUES ('%s','%s','yes')" %(sql_quote(self.getKey()),sql_quote(bibId))
+            
+            #self.ZSQLAdd(_table="publications",id_institutsbibliographie=bibId,id_main=self.getDBId(),publish='yes')
+            self.ZSQLQuery(query)
+     
+        self.updatePublicationDB(personId=self.getKey())
+        
+        if not noredirect:
+            
+            self.redirect(RESPONSE,"./editPublications")
+            
+            return True
+        
+    
+    def getDBId(self):
+        """get id from the personal database"""
+        
+        #in der neuen version ist definitions gemaess der key der Datenbank gleich dem key im Object.
+        # TODO: remove all occurences of getDBId and replaces it by getKey
+        return self.getKey()
+        
+#        search=self.ZSQLInlineSearch(_table='personal_www',key=self.getKey(),publish_the_data='yes')
+#        if search:#name existiert und published, dann nimm diesen falls es mehrereeventuell nich publizierte datensaetze gibt.
+#            return search[0].id
+#        else:#nicht publiziert dann nimm einen davon
+#            search2=self.ZSQLInlineSearch(_table='personal_www',username=self.getId())
+#            if search2:
+#                return search2[0].id
+#            else:
+#                return None
+        
+    
+    
+    formatBiblHelp=bibliography.formatBiblHelp
+    
+    def sortBibliography(self,list,sortingMode=None,max=None):
+        if not sortingMode:
+            sortingMode=self.getSortingMode()
+    
+        if sortingMode == "year":
+            l= self.sortYear(list)
+        else:
+            l=self.sortPriority(list)
+        
+        if max:
+            return l[0:min(len(l),max)]
+        else:
+            return l
+        
+    def sortPriority(self,list):
+        def sort(x,y):
+            try:
+                xInt=int(x.priority)
+            except:
+                xInt=0
+            try:
+                yInt=int(y.priority)
+            except:
+                yInt=0
+
+            return cmp(xInt,yInt)
+
+        if not list:
+            return []
+        tmp=[x for x in list]
+        tmp.sort(sort)           
+        
+        return tmp
+
+    def sortYear(self,list):
+        #TODO: sort TO APPEAR and TO BE PUBLISHED etc...
+        
+        def sort(x,y):
+            try:
+                xInt=int(x.year)
+            except:
+                xInt=0
+            try:
+                yInt=int(y.year)
+            except:
+                yInt=0
+
+            return cmp(yInt,xInt)
+            
+            
+        tmp=[x for x in list]
+        
+        tmp.sort(sort)           
+        return tmp
+    
+    def deleteField(self,table,oid,RESPONSE=None):
+        """delete entry"""
+        query="DELETE FROM %s WHERE oid = '%s'"%(table,oid)
+
+        self.ZSQLQuery(query)
+        self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER'])
+        
+    
+def manage_addMPIWGStaffForm(self):
+    """form for adding the project"""
+    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMPIWGStaffForm.zpt')).__of__(self)
+    return pt()
+
+def manage_addMPIWGStaff(self,id,lastName,firstName,RESPONSE=None):
+    """add it"""
+    newObj=MPIWGStaff(id,lastName,firstName)
+
+    self._setObject(id,newObj)
+
+
+    if RESPONSE is not None:
+        self.redirect(RESPONSE,'manage_main')
+
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPIWGStaff.py_old	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,996 @@
+"""This file contains the classes for the organization of the staff"""
+# TODO: pruefe ob die id der einzelnen tabellen, wie id in publications noch benutzt werden
+# TODO: pruefe ob die bibliographischen felder in publications noch benutzt werden
+# TODO: wird username gebraucht?
+
+from OFS.Folder import Folder
+from Products.ZSQLExtend.ZSQLExtend import ZSQLExtendFolder
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Products.PageTemplates.PageTemplate import PageTemplate
+from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+from Products.ZCatalog.CatalogPathAwareness import CatalogAware
+from Products.versionedFile.extVersionedFile import extVersionedFileFolder
+from AccessControl import getSecurityManager
+
+import os
+import logging
+import bibliography
+import email
+from Globals import package_home
+from Products.PythonScripts.standard import sql_quote
+from types import *
+from AccessControl import ClassSecurityInfo
+import time
+import logging
+import email
+import re
+from OFS.Cache import Cacheable
+import urllib2
+import transaction
+import SrvTxtUtils
+
+from MPIWGHelper import *
+#ersetzt logging
+def logger(txt,method,txt2):
+    """logging""" 
+    logging.info(txt+ txt2)
+
+departmentList="Renn\nRheinberger\nDaston\nKlein\nSibum\nIT\nInstitut\nBibliothek"
+coneService="http://127.0.0.1:8280/MetaDataManagerRestlet/cone/" # kann in MPIWGRoot konfiguriert werden.
+
+
+
+def createNewDBEntry(self,publish_the_data,key,name,vorname,titles_new,position,e_mail,e_mail_p,date_from,date_to,abteilung,heimat_inst,funded_by="",e_mail2="",txt="",txt_p="no",stay_at_mpiwg="",group="",web_object_created="no",current_work=""):
+        """lege person in der datenbank an"""
+
+        if date_to=="": # wenn date_to leer
+             date_to="date_none"
+        
+        if date_from=="": # wenn date_fromleer
+             date_from="date_none"
+        msg=""
+        #test ob id schon existiert
+        if self.ZSQLQuery("select key from personal_www where key='%s'"%id):
+            return False,"ERROR:key%s already exists"%key
+        
+        #eintragen
+        columnlist="""publish_the_data,key,last_name,first_name,titles_new,status,e_mail,e_mail_p,date_from,date_to,department,home_inst,funded_by,e_mail2,date_stay_at_mpiwg,web_object_created,"group",current_work,current_work_p """
+        insertTuple=(publish_the_data,key,name,vorname,titles_new,position,e_mail,e_mail_p,date_from,date_to,abteilung,heimat_inst,funded_by,e_mail2,stay_at_mpiwg,web_object_created,group,current_work,"yes")
+        
+        insert=[]
+        for element in insertTuple:
+            if element=="date_none": # date_none eintrag wird zu null uebersetzt
+                insert.append('null')
+            else:
+                insert.append("%s"%self.ZSQLQuote(element))
+            
+        insertStr=",".join(insert)
+        queryStr="INSERT INTO personal_www (%s) VALUES (%s)"%(columnlist,insertStr)
+        self.ZSQLQuery("SET DATESTYLE TO 'German'")
+        self.ZSQLQuery(queryStr)
+        logging.info("QQQQ %s:"%queryStr)
+        #currentwork
+        #if not (current_work==""):
+        #    queryStr="INSERT INTO current_work (key_main,current,publish) VALUES ('%s',%s,'%s')"%(key,self.ZSQLQuote(current_work),"yes")
+
+        #  self.ZSQLQuery(queryStr)
+        
+        return True,msg
+class MPIWGStaff(CatalogAware,ZSQLExtendFolder,Cacheable):
+    """Staff"""
+
+    meta_type="MPIWGStaff"
+    default_catalog='MembersCatalog'
+    departmentList=departmentList
+    #_v_cone=None;
+    security=ClassSecurityInfo()
+    
+    def redirect(self,RESPONSE,url):
+        """mache ein redirect mit einem angehaengten time stamp um ein reload zu erzwingen"""
+        
+        timeStamp=time.time()
+        
+        if url.find("?")>-1: #giebt es schon parameter
+            addStr="&time=%s"
+        else:
+            addStr="?time=%s"
+            
+        RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT')
+        logging.error(email.Utils.formatdate()+' GMT')
+        RESPONSE.redirect(url+addStr%timeStamp)
+        
+    def getKeyUTF8(self):
+        """get db_key utf8"""
+        logging.debug("KEY - MPIWGStaff:"+self.getKey())
+        logging.debug("KEY - MPIWGStaff:"+utf8ify(self.getKey()))
+        
+        return utf8ify(self.getKey())
+    
+    def setKey(self,key):
+	"""set key"""
+	self.key=key
+
+    def getKey(self):
+        """get database key"""
+        if hasattr(self,'key'):
+            #logging.error("SAVED KEY:%s"%self.key)
+            return unicodify(self.key.lower())
+            #return self.key.lower()
+        
+        #fuer alt faelle ohne key
+        #logging.error("NEW KEY:%s"%(self.firstName+'_'+self.lastName).lower().replace(' ',''))
+        return (self.firstName+'_'+self.lastName).lower().replace(' ','')
+        
+    def getConnectionObj(self):
+         """returns connection id (from root)"""
+         try:
+             root = self.getMPIWGRoot()
+             return root.getConnectionObj()
+         except:
+             return self.en.getConnectionObj()
+
+    def isPublished(self):
+        """gib publications status aus der datenbank aus"""
+        key=self.getKey()
+        query="select count(publish_the_data) from personal_www where lower(key)='%s' and publish_the_data='yes'"%key
+        
+        res = self.ZSQLQuery(query)
+        
+        if res and res[0].count>0:
+            return True
+        else:
+            return False
+        
+ 
+  
+    def updateDBEntry(self,publish_the_data,date_from,date_to,DBid=None,stay_at_mpiwg="",position="",abteilung=""): 
+        """zpddatedb"""
+        if not DBid:
+                    DBid=self.getDBId()
+        
+ 
+        self.ZSQLQuery("SET DATESTYLE TO 'German'")
+
+        test=self.ZSQLQuery("select id from personal_www where id='%s' "%DBid)
+
+        
+        if test and (len(test)>0): #dataset exists
+            logger("MPIWG Web",logging.INFO,'UPDATE: _table="personal_www",_identify="id=%s"'%DBid+',publish_the_data=%s'%publish_the_data+',date_from=%s'%date_from+',date_to=%s'%date_to+',stay_at_mpiwg=%s'%stay_at_mpiwg+',position=%s'%position)
+            self.ZSQLChange(_table="personal_www",_identify="id=%s"%DBid,publish_the_data=publish_the_data,
+                                   date_from=date_from,
+                                   date_to=date_to,stay_at_mpiwg=stay_at_mpiwg,position=position,abteilung=abteilung)
+            return True
+        else:
+            return False
+          
+    def getPublicationSelectionMode(self):
+        """get publication selection mode, default 'priority'"""
+        return getattr(self,'publicationSelectionMode','priority')
+        
+    def changePublicationSelectionMode(self,publicationSelectionMode,RESPONSE=None):
+        """change PublicationSelectionMode"""
+        
+        self.publicationSelectionMode=publicationSelectionMode
+        self.ZCacheable_invalidate()
+        if RESPONSE:
+            self.redirect(RESPONSE,"editPublications")
+            
+    
+    def downloadCV(self,RESPONSE):
+        """download cv file"""
+        ob=self._getOb("downloadableFiles")._getOb("cv.pdf")
+        
+        RESPONSE.redirect(ob.absolute_url()+"/download")
+    
+    def getLastUpdateCV(self):
+        """getDate of Last Update"""
+        try:
+                ob=self._getOb("downloadableFiles")._getOb("cv.pdf")
+                return ob.getLastChangeDate()
+        except:
+                return "No file yet!"
+    def getLastUpdatePublications(self):
+        """getDate of Last Update"""
+        try:
+                ob=self._getOb("downloadableFiles")._getOb("publications.pdf")
+                return ob.getLastChangeDate()
+        except:
+                return "No file yet!"
+    def downloadPublications(self,RESPONSE):
+        """download publications"""
+        ob=self._getOb("downloadableFiles")._getOb("publications.pdf")
+        
+        RESPONSE.redirect(ob.absolute_url()+"/download")
+   
+    def changeDownloads(self,cv_pdf=None,cv_publish=None,publications_pdf=None,publications_publish=None,RESPONSE=None):
+        """"change the downloadable files"""
+        self.ZCacheable_invalidate()
+        if not hasattr(self,'downloadableFiles'):
+           
+            extFolder =  extVersionedFileFolder()
+            extFolder.id = "downloadableFiles"
+            self._setObject(extFolder.id,extFolder)
+            
+        ob = self._getOb("downloadableFiles")
+        
+        if cv_publish:
+            self.cv_publish=cv_publish
+            
+        if publications_publish:
+            self.publications_publish=publications_publish
+            
+        if cv_pdf:
+            if not hasattr(ob,"cv.pdf"):
+                ob.addFile("",cv_pdf,newName="cv.pdf")
+            
+            else:
+                cvFile = getattr(ob,"cv.pdf")
+                cvFile.addContentObject("","",file=cv_pdf)
+        
+        if publications_pdf:
+            if not hasattr(ob,"publications.pdf"):
+                ob.addFile("",cv_pdf,newName="publications.pdf")
+            
+            else:
+                cvFile = getattr(ob,"publications.pdf")
+                cvFile.addContentObject("","",file=publications_pdf)
+        
+        if RESPONSE:
+            self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER'])
+    
+
+    def getPublishImage(self):
+        """publish the image??, default no"""
+        return getattr(self,'publishImage','no')
+    
+    def updateImage(self,publishImage,file=None,rename=None,RESPONSE=None):
+        """update image"""
+
+        if file and not(file.filename==""):
+            if self.getImageObj():
+                              self.getImageObj().updateImage(file,_rename=None,RESPONSE=None)
+            else:
+                # create new image object
+                xp = file.filename.rfind('.')
+                if xp > 0:
+                    ext = file.filename[xp:]
+                    #fn = self.getId()+ext
+                    fn = self.getId()
+                    logger("MPWIG STAFF", logging.INFO, "new filename: %s"%fn)
+                    self.getImageFolder().addImage2(file,fileName=fn)
+                else:
+                    logger("MPWIG STAFF", logging.ERROR, "uploaded filename %s has no extension!"%file.filename)
+            
+        self.publishImage=publishImage
+        
+        if RESPONSE:
+            self.redirect(RESPONSE,"edit")
+            
+    def getImageFolder(self):
+        """getImageFolder"""
+        #TODO: make place of staff image folder configurable
+        
+        try:
+            return self.getPhysicalRoot().www_neu.images.staff_images
+        except: 
+            logger("MPWIG STAFF", logging.ERROR, "image folder not found: has to be add /www_neu/staff_images") 
+            return None
+        
+    def getImageObj(self):
+        """getImage"""
+        imageFolder=self.getImageFolder()
+        
+        if not imageFolder: return None
+        
+        image=getattr(imageFolder,self.getId(),None)
+
+        if not image:
+            for suffix in ['jpg','tif']:
+                
+                image=getattr(imageFolder,self.getId()+"."+suffix,None)
+                if image:
+                    break
+        return image
+            
+    def getImageUrl(self):
+        """getImageUrl"""
+        image=self.getImageObj()
+        if not image:
+            return None
+        else:
+            return self.getImageObj().absolute_url()+"/image"
+    
+    def PrincipiaSearchSource(self):
+        """Return cataloguable key for ourselves."""
+        return str(self)
+
+    manage_options = Folder.manage_options+(
+        {'label':'Edit','action':'changeMPIWGStaffForm'},
+        {'label':'Change Publications Special','action':'changePublications_specialForm'},
+        ) + Cacheable.manage_options
+    
+    __manager_id = "ramCache"
+    def __init__(self,id, lastName,firstName,key):
+        """init"""
+        self.id=id
+        self.title=key
+        self.lastName=lastName
+        self.firstName=firstName
+        self.key=key
+    
+    def getPersonID(self):
+        """gibt den ID fuer die Person zurueck"
+        im Moment ist personID = id, i.e. e-mail
+        """
+        return self.id
+
+    def getConeUrl(self):
+        """gibt coneURL zurueck"""
+        
+        self.coneService=getattr(self, "coneServiceURL",coneService)
+        logging.debug("coneservice:"+self.coneService)
+        
+        if getattr(self,'_v_cone',None)==None:
+            try:  
+                
+                self._v_cone=SrvTxtUtils.getHttpData(self.coneService+self.getPersonID())
+                #cone = urllib2.urlopen(self.coneService+self.getPersonID())              
+                #self._v_cone=cone.read()
+                if self._v_cone==None:
+                    self._v_cone=""
+            except:
+                self._v_cone=""
+                return ""
+            
+        return self._v_cone
+           
+           
+        
+        
+    def harvest_page_old(self,context=None):
+        """geharvestete seite = verschlankte version von members_main"""
+        #pt = getTemplate(self, "harvest_members_main")
+        
+        if not self.isPublished():
+            return ""
+        if not context:
+            context=self
+            
+        
+        ext=getattr(self,"harvest_members_main",None)
+        if ext:
+            return getattr(self,ext.getId())()
+        
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','harvest_members_main')).__of__(context)    
+
+
+        return pt()
+
+    def harvest_page(self,mode="normal"):
+        """harvest"""
+        logging.debug("AAAAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
+        if not self.isPublished():
+            return 
+        st = getattr(self.en.staff.members,self.getId()).index_html(mode)
+        
+        templates = self.en.getHarvestCache()
+        #templates = getattr(self,'getHarvestCache',self.en.getHarvestCache)()
+        rendered = st
+        templates[self.absolute_url()]=rendered
+        transaction.commit()
+        return rendered
+	
+        
+    
+    def index_html(self,mode="normal"):
+        """show homepage"""
+    
+        bound_names={}
+        request = self.REQUEST
+        if request is not None:
+            response = request.response
+            if not response.headers.has_key('content-type'):
+                response.setHeader('content-type', 'text/html')
+
+        security = getSecurityManager()
+        bound_names['user'] = security.getUser()
+
+        # Retrieve the value from the cache.
+        keyset = None
+        if self.ZCacheable_isCachingEnabled():
+            
+            # Prepare a cache key.
+            keyset = {'here': self}
+                      
+            result = self.ZCacheable_get(keywords=keyset)
+           
+            if result is not None:
+                # Got a cached value.
+                return result
+        
+        # look for individual page
+        if self.hasObject("index.html"):
+            pt = getattr(self, "index.html")
+        # else use template
+        else:
+            if mode=="slim":
+                pt = getTemplate(self, "members_main_slim")
+            else:
+                pt = getTemplate(self, "members_main")
+        # Execute the template in a new security context.
+        security.addContext(self)
+
+        try:
+            result = pt.pt_render(extra_context=bound_names)
+            if keyset is not None:
+                # Store the result in the cache.
+                self.ZCacheable_set(result, keywords=keyset)
+               
+            return result
+        finally:
+            security.removeContext(self)
+       
+
+   
+    def changePublications_specialForm(self):
+        """Priority publications manual field"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','changePublications_special.zpt')).__of__(self)
+        return pt()
+        
+    def changePublications_special(self,usePublicationsSpecial=None,specialPublicationsField=None,RESPONSE=None):
+        """change publications special params"""
+        self.ZCacheable_invalidate()
+        if usePublicationsSpecial:
+          self.usePublicationsSpecial=True
+         
+        else:
+          self.usePublicationsSpecial=False
+
+        self.specialPublicationsField=specialPublicationsField[0:]
+
+        if RESPONSE is not None:
+            self.redirect(RESPONSE,'manage_main')
+
+        
+    def publications_full(self):
+        """show publication"""
+        pt=getTemplate(self, "publications_full_main")
+        return pt()
+
+    def talks_full(self):
+        """show talks"""
+        pt=getTemplate(self, 'talks_full_main')
+        return pt()
+
+    def teaching_full(self):
+        """show talks"""
+        pt=getTemplate(self, 'teaching_full_main')
+        return pt()
+    
+    def changeMPIWGStaffForm(self):
+        """change form"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','edit_MPIWGStaff.zpt')).__of__(self)
+        return pt()
+    
+    security.declareProtected('View management screens','changeMPIWGStaff')
+    def changeMPIWGStaff(self,lastName,firstName,key=None,RESPONSE=None):
+        """change it"""
+        self.ZCacheable_invalidate()
+        self.title="%s, %s"%(lastName,firstName)
+        self.lastName=lastName
+        self.firstName=firstName
+        if key:
+            self.key = key
+            
+        
+        if RESPONSE is not None:
+            self.redirect(RESPONSE,'manage_main')
+            
+    security.declareProtected('View management screens','edit')
+    def edit(self):
+        """Edit the pages"""
+        #TODO: zusammenspiel mit apache, redirect auf 18080 rausnehmen bzw. zumindest verallgemeinern
+        #if self.REQUEST['SERVER_URL']=="http://www.mpiwg-berlin.mpg.de":
+        #        redURL="http://xserve04.mpiwg-berlin.mpg.de:18080/www_neu/de/mitarbeiter/members/%s/edit"%self.getId()
+        #
+        #        self.REQUEST.RESPONSE.redirect(redURL)
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editMPIWGStaff.zpt')).__of__(self)
+        
+        
+        logging.debug("XX:"+email.Utils.formatdate().split("-")[0]+'GMT')
+        return pt()
+
+    mainEditFile=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editMPIWGStaff_main.zpt'))
+    addPublicationsBib=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addPublicationsBib.zpt'))
+
+    def getPathStyle(self, path, selected, style=""):
+        """returns a string with the given style + 'sel' if path == selected."""
+
+        if path == selected:
+            return style + 'sel'
+        else:
+            return style    
+
+
+    def getLabel(self):
+        """returns a label for this object"""
+        return self.title
+
+    def getBreadcrumbs(self):
+        """return list of breadcrumbs from here to the root"""
+        crumbs = []
+        # skip direct parent Folder /members/
+        parent = self.aq_parent.aq_parent
+        # get parents breadcrumbs
+        logging.debug("getbreadcrumbs-: title=%s self=%s parent=%s"%(self.title, repr(self), repr(parent)))
+        if hasattr(parent, 'getBreadcrumbs'):
+            logging.debug("getbreadcrumbs: recurse to %s"%parent)
+            crumbs = parent.getBreadcrumbs()
+        
+        # try to get acquisition URL from parent
+        if hasattr(parent, 'absolute_url'):
+            baseUrl = "%s/%s/"%(parent.absolute_url(), 'members')
+        else:
+            baseUrl = "/en/staff/members/"
+            
+        # add this
+        crumbs.append((self.getLabel(), baseUrl+self.getId(), self))
+            
+        return crumbs
+
+
+    def changeCurrentWork(self,current_work,key,publish="yes",RESPONSE=None):
+        """change current work"""
+        
+        query="UPDATE personal_www SET current_work =%s WHERE key='%s'"
+         
+        self.ZSQLQuery(query%(self.ZSQLQuote(current_work),key))
+       
+        query="UPDATE personal_www SET current_work_p =%s WHERE key='%s'"
+         
+        self.ZSQLQuery(query%(self.ZSQLQuote(publish),key))
+        self.ZCacheable_invalidate()
+        if RESPONSE:
+            self.redirect(RESPONSE,"edit")
+        
+    security.declareProtected('View management screens','changeResearch')
+    def changeResearch(self,noredirect=None,RESPONSE=None):
+        """change the research entries"""
+        self.ZCacheable_invalidate()
+        newEntries={}
+        key_main=self.REQUEST.form['key_main']
+
+        mainfieldL=self.REQUEST.form['main_fields'].split(",")
+        mainfield={}
+        for x in mainfieldL:
+            tmp=x.split('__')
+            mainfield[tmp[0]]=tmp[1]
+        for field in self.REQUEST.form.keys():
+            splittedField=field.split("__")
+            if len(splittedField)<3:
+                pass #kein datenbank eintrag
+
+            elif splittedField[2]=='new': # store new entries
+                if not newEntries.has_key(splittedField[0]):
+                    newEntries[splittedField[0]]={}
+                    
+                newEntries[splittedField[0]][splittedField[1]]=self.REQUEST.form[field]
+
+            else:
+                query="UPDATE %s "%splittedField[0]
+                query+="SET %s = '%s' "%(splittedField[1],sql_quote(self.REQUEST.form[field]))
+                query+="WHERE oid = '%s' "%sql_quote(splittedField[2])
+                
+                self.ZSQLQuery(query)
+
+
+        #new entries
+        for newEntry in newEntries.keys():
+            query="INSERT INTO %s "%newEntry
+            keys=['key_main']
+            values=["'"+sql_quote(key_main)+"'"]
+            for key in newEntries[newEntry].keys():
+                keys.append(key)
+                values.append("'"+sql_quote(newEntries[newEntry][key])+"'")
+
+
+            keystring=",".join(keys)
+                
+            valuestring=",".join(values)
+                
+            query+=" (%s) "%keystring
+            query+="VALUES (%s)"%valuestring
+            if not (newEntries[newEntry][mainfield[newEntry]].lstrip().rstrip()==""):
+                self.ZSQLQuery(query)
+
+        if not noredirect:
+            self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER'])
+            
+    security.declareProtected('View management screens','editCV')    
+    def editCV(self,cv=None,oid=None,RESPONSE=None):
+         """edit Cv"""
+
+         if (not oid):
+             pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editCV.zpt')).__of__(self)
+             return pt()
+        
+         query="UPDATE personal_www SET cv =%s WHERE oid='%s'"
+         self.ZCacheable_invalidate()
+         self.ZSQLQuery(query%(self.ZSQLQuote(cv),oid))
+        
+         if RESPONSE:
+            self.redirect(RESPONSE,"editCV")
+            
+    
+    def getProfile(self):
+        """get the profile"""
+	self.REQUEST.RESPONSE.setHeader('Last-Modified',email.Utils.formatdate().split("-")[0]+'GMT')
+      
+        founds=self.ZSQLInlineSearchU(_table='personal_www',key=self.getKeyUTF8())
+        html="""<html><body>%s</body></html>"""
+        if founds.profile and founds.profile != "":
+           
+            return html%founds.profile
+        else:
+                        
+            return html%self.generateProfileForPerson(founds)
+            
+    def editProfile(self,oid=None,RESPONSE=None, kupu=None, preview=None):
+         """edit Profile, new entry replaces CD, current work and research interests"""
+        
+         if (not oid):
+             pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editProfile.zpt')).__of__(self)
+             return pt()
+        
+         self.ZCacheable_invalidate() 
+         
+         
+         if preview:
+             pass
+             #TODO: not supported yet
+             #kupu=preview
+             # find content of body tags
+        
+         start=kupu.find("<body>")
+         end=kupu.find("</body>")
+         
+         newcontent= kupu[start+6:end]
+            
+            
+         
+        
+         if preview: 
+            #TODO: not supported yet
+            if RESPONSE:
+                self.redirect(RESPONSE,"editProfile")
+            
+            #return self.preview(newcontent)
+
+         query="UPDATE personal_www SET profile=%s WHERE oid='%s'"       
+         self.ZSQLQuery(query%(self.ZSQLQuote(newcontent),oid))
+         logging.error("PROFILE:"+query%(self.ZSQLQuote(newcontent),oid))
+         if RESPONSE:
+            self.redirect(RESPONSE,"editProfile")
+
+
+
+    def generateProfileForPerson(self,person):
+        """erzeugt ein automatisches Profil aus den alten Eintraegen  CV, Current work, und research interests"""
+        
+        ret=""
+        #founds=self.ZSQLInlineSearch(_table='research_interest',key_main=person.getKeyUTF8())
+        founds=self.ZSQLInlineSearch(_table='research_interest',key_main=person.key)
+        if founds:
+            ret="<p class=\"bio_section_header\">Research interests: </p><br/>"
+        for found in self.sortPriority(founds):
+            ret+=found.interest+"<br/>"
+        
+        
+        if (person.current_work) and (not person.current_work==""):
+            ret+="<p class=\"bio_section_header\">Current work: </p><br/>"
+      
+            ret+=person.current_work+"<br/>"
+    	if (person.cv) and (not person.cv==""):
+            ret+="<p class=\"bio_section_header\">Curriculum Vitae: </p><br/>"
+	    ret+=self.formatAscii(person.cv)
+        
+        return ret
+    security.declareProtected('View management screens','editDownloads')
+    def editDownloads(self):    
+        """editiere die Downloads von der Webseite"""
+        
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editDownloads.zpt')).__of__(self)
+        return pt()
+    
+    security.declareProtected('View management screens','editAdditionalLinks.zpt')
+    def editAdditionalLinks(self):    
+        """editiere die Downloads von der Webseite"""
+        
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editAdditionalLinks.zpt')).__of__(self)
+        return pt()
+    
+    
+    security.declareProtected('View management screens','editAwards')    
+    def editAwards(self,awards=None,oid=None,RESPONSE=None):
+         """edit a awards"""
+     
+         if (not oid):
+             pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editAwards.zpt')).__of__(self)
+             return pt()
+         self.ZCacheable_invalidate()
+         query="UPDATE personal_www SET awards =%s WHERE oid='%s'"
+      
+         self.ZSQLQuery(query%(self.ZSQLQuote(awards),oid))
+        
+        
+         if RESPONSE:
+            self.redirect(RESPONSE,"editAwards")
+
+    security.declareProtected('View management screens','editTalks')    
+    def editTalks(self):
+        """edit talks"""
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editTalks.zpt')).__of__(self)
+        return pt()
+        
+    security.declareProtected('View management screens','editTeaching')    
+    def editTeaching(self):
+        """edit Teaching"""
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editTeaching.zpt')).__of__(self)
+        return pt()
+        
+    def getDocTypes(self):
+        finds = self.ZopeFind(self.metadata.main.meta.bib,obj_metatypes=["OSAS_MetadataMapping__neu"])
+
+        list= [x[0] for x in finds]
+        return "\n".join(list)
+
+    security.declareProtected('View management screens','editMainData')    
+    def editMainData(self,REQUEST=None,RESPONSE=None):
+        """edit main data"""
+        self.ZCacheable_invalidate()
+        argv=REQUEST.form
+        
+        if not argv.has_key('last_name'):
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editMainData.zpt')).__of__(self)
+            return pt() 
+        else:
+            self.ZSQLChange(argv,_table="personal_www",_identify="lower(key)=%s"%utf8ify(self.getKey().lower()),USE_FORM="yes")
+            # aendere auch dien enstsprechen infos in der instance
+            self.changeMPIWGStaff(argv['last_name'],argv['first_name']);
+            
+            
+            
+            self.reindex_object()
+            
+            
+            
+            if RESPONSE:
+                self.redirect(RESPONSE,"editMainData")
+                
+    security.declareProtected('View management screens','newBibliogrpaphy')    
+    def newBibliography(self,_docType=None, _addEntry=None,RESPONSE=None,**argv):
+        
+        """add an entry to the bibliography"""
+        if not _docType: #kein docType
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','newBibliographyEntryDocType.zpt')).__of__(self)
+            return pt() 
+        elif _docType and not _addEntry: #doctype aber keine daten
+            self.REQUEST['_docType']=_docType
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','newBibliographyEntry.zpt')).__of__(self)
+            return pt() 
+        else: #doctype und daten
+            try:
+                newId=self.ZSQLSimpleSearch("select nextval('id_raw')")[0].nextval
+            except:#id_raw existiert nich, dann neu erzeugen
+                
+                self.createOrUpdateId_raw()
+                newId=self.ZSQLSimpleSearch("select nextval('id_raw')")[0].nextval
+                                
+            bookId="b%06i" % newId
+            
+            self.ZSQLAdd(argv,_table="bibliography",reference_type=_docType,id=bookId)
+
+            self.ZSQLAdd(_useRequest=False,_table="publications",id_gen_bib=bookId,key_main=self.getDBId(),publish='yes')
+            self.updatePublicationDB(personId=self.getDBId())
+            
+        
+        if RESPONSE:
+            self.redirect(RESPONSE,"editPublications")
+            
+        return True
+    
+    security.declareProtected('View management screens','editImage')    
+    def editImage(self):
+        """edit images"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editImageStaff.zpt')).__of__(self)
+        return pt()
+    
+    security.declareProtected('View management screens','editBibliography')    
+    def editBibliography(self):
+        """edit the bibliography"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editBibliographyEntry.zpt')).__of__(self)
+        return pt()
+    
+      
+    security.declareProtected('View management screens','editPublications')    
+    def editPublications(self):
+        """edit the bibliographie"""
+
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','editPublications.zpt')).__of__(self)
+        return pt()
+    
+    def changeSortingMode(self,sortingMode,RESPONSE=None,REQUEST=None):
+        """change sorting mode"""
+        self.ZCacheable_invalidate()
+        self.sortingMode=sortingMode
+        
+        if RESPONSE and REQUEST:
+            self.redirect(RESPONSE,REQUEST['HTTP_REFERER'])
+
+        return True
+
+    def getSortingMode(self):
+        """get sorting mode"""
+        mode=getattr(self,'sortingMode','priority')
+        if mode=="year":
+            return "year DESC"
+        else:
+            return mode
+        
+    def integer(self,value):
+        try:
+            return int(value)
+        except:
+            return 0
+        
+    security.declareProtected('View management screens','changePublications')    
+    def changePublications(self,RESPONSE=None):
+        """change the publication list"""
+        self.changeResearch(noredirect=True)
+        self.ZCacheable_invalidate()
+        #self.updatePublicationDB(personId=self.getDBId())
+        self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER'])
+        
+
+  
+    security.declareProtected('View management screens','addPublications')    
+    def addPublications(self,submit=None,REQUEST=None,noredirect=None,RESPONSE=None):
+        """add publications"""
+
+        #setzte flag ob aufruf aus suchformular
+        
+        if REQUEST.get("QUERY_STRING",None) and (not submit):
+            self.REQUEST.set('fromSearch','1')
+        else:
+            self.REQUEST.set('fromSearch','0')
+             
+        if not submit or (not (submit == "add")):
+            pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addPublications.zpt')).__of__(self)
+            return pt()
+        
+        #new entries
+        entries = REQUEST.form.get('addEntries',None)
+        if not (type(entries) is ListType):
+            entries=[entries]
+        
+        
+        for bibId in entries: 
+            query="INSERT INTO %s " % "publications"
+            query+="(key_main,id_institutsbibliographie,publish) "
+            query+="VALUES ('%s','%s','yes')" %(sql_quote(self.getKey()),sql_quote(bibId))
+            
+            #self.ZSQLAdd(_table="publications",id_institutsbibliographie=bibId,id_main=self.getDBId(),publish='yes')
+            self.ZSQLQuery(query)
+     
+        self.updatePublicationDB(personId=self.getKey())
+        
+        if not noredirect:
+            
+            self.redirect(RESPONSE,"./editPublications")
+            
+            return True
+        
+    
+    def getDBId(self):
+        """get id from the personal database"""
+        
+        #in der neuen version ist definitions gemaess der key der Datenbank gleich dem key im Object.
+        # TODO: remove all occurences of getDBId and replaces it by getKey
+        return self.getKey()
+        
+#        search=self.ZSQLInlineSearch(_table='personal_www',key=self.getKey(),publish_the_data='yes')
+#        if search:#name existiert und published, dann nimm diesen falls es mehrereeventuell nich publizierte datensaetze gibt.
+#            return search[0].id
+#        else:#nicht publiziert dann nimm einen davon
+#            search2=self.ZSQLInlineSearch(_table='personal_www',username=self.getId())
+#            if search2:
+#                return search2[0].id
+#            else:
+#                return None
+        
+    
+    
+    formatBiblHelp=bibliography.formatBiblHelp
+    
+    def sortBibliography(self,list,sortingMode=None,max=None):
+        if not sortingMode:
+            sortingMode=self.getSortingMode()
+    
+        if sortingMode == "year":
+            l= self.sortYear(list)
+        else:
+            l=self.sortPriority(list)
+        
+        if max:
+            return l[0:min(len(l),max)]
+        else:
+            return l
+        
+    def sortPriority(self,list):
+        def sort(x,y):
+            try:
+                xInt=int(x.priority)
+            except:
+                xInt=0
+            try:
+                yInt=int(y.priority)
+            except:
+                yInt=0
+
+            return cmp(xInt,yInt)
+
+        if not list:
+            return []
+        tmp=[x for x in list]
+        tmp.sort(sort)           
+        
+        return tmp
+
+    def sortYear(self,list):
+        #TODO: sort TO APPEAR and TO BE PUBLISHED etc...
+        
+        def sort(x,y):
+            try:
+                xInt=int(x.year)
+            except:
+                xInt=0
+            try:
+                yInt=int(y.year)
+            except:
+                yInt=0
+
+            return cmp(yInt,xInt)
+            
+            
+        tmp=[x for x in list]
+        
+        tmp.sort(sort)           
+        return tmp
+    
+    def deleteField(self,table,oid,RESPONSE=None):
+        """delete entry"""
+        query="DELETE FROM %s WHERE oid = '%s'"%(table,oid)
+
+        self.ZSQLQuery(query)
+        self.redirect(RESPONSE,self.REQUEST['HTTP_REFERER'])
+        
+    
+def manage_addMPIWGStaffForm(self):
+    """form for adding the project"""
+    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','addMPIWGStaffForm.zpt')).__of__(self)
+    return pt()
+
+def manage_addMPIWGStaff(self,id,lastName,firstName,RESPONSE=None):
+    """add it"""
+    newObj=MPIWGStaff(id,lastName,firstName)
+
+    self._setObject(id,newObj)
+
+
+    if RESPONSE is not None:
+        self.redirect(RESPONSE,'manage_main')
+
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MPIWGTemplate.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,140 @@
+from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
+from Products.PageTemplates.PageTemplateFile import PageTemplateFile
+from Globals import package_home
+import string
+import re
+import os
+import logging
+from OFS.Folder import Folder
+from AccessControl import ClassSecurityInfo
+from MPIWGHelper import *
+from ZODB import FileStorage, DB
+import transaction
+
+# dummy definitions for backwards compatibility
+import MPIWGFeature
+
+class MPIWGFeature(MPIWGFeature.MPIWGFeature):
+    """deprecated! use class in MPIWGFeature.py"""
+
+import MPIWGFolder
+
+class MPIWGFolder(MPIWGFolder.MPIWGFolder):
+    """deprecated! use class in MPIWGFolder.py"""
+
+
+
+class MPIWGTemplate(ZopePageTemplate):
+    """Create a layout Template for different purposes"""
+
+    meta_type="MPIWGTemplate"
+
+    manage_options=ZopePageTemplate.manage_options+(
+        {'label':'Change Weight','action':'changeWeightForm'},
+        )
+
+    def changeWeightForm(self):
+        """change weight form"""
+        pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt','MPIWGTemplateChangeWeight.zpt')).__of__(self)
+        return pt()
+
+    def changeWeight(self,weight,RESPONSE=None):
+        """change weight"""
+        self.weight=weight
+        if RESPONSE is not None:
+            RESPONSE.redirect('manage')
+
+        
+    def __init__(self, id, text=None, content_type="text/html",MPIWGType=None):
+        self.id = str(id)
+        self.ZBindings_edit(self._default_bindings)
+        if text is None:
+            self._default_content_fn = os.path.join(package_home(globals()),
+                                               'zpt/MPIWG_%s_template_standard.zpt'%MPIWGType)
+            text = open(self._default_content_fn).read()
+        self.pt_edit(text, content_type)
+
+    
+    def isActiveItem(self):
+        """teste ob ausgewaehlt"""
+        if self.absolute_url()==self.REQUEST['URL']:
+            return "aktiv"
+        else:
+            return ""
+    
+    getBreadcrumbs = getBreadcrumbs
+    getSection = getSection
+    getSubSection = getSubSection
+    
+    def harvest_page(self,mode="normal"):
+        """harvest main"""
+        
+       
+
+        # Ensure that a 'userdb' key is present
+        # in the root
+       
+        templates = self.en.getHarvestCache()
+        #templates = getattr(self,'getHarvestCache',self.en.getHarvestCache)()
+        try:
+            rendered = self.pt_render()
+            templates[self.absolute_url()]=rendered
+            logging.debug("harvest:"+self.absolute_url())
+            transaction.commit()
+            return rendered
+        except:
+            logging.error("cannot harvest: %s"%self.absolute_url())
+        
+        
+       
+        
+        
+                     
+def manage_addMPIWGTemplateForm(self):
+    """Form for adding"""
+    pt=PageTemplateFile(os.path.join(package_home(globals()),'zpt/AddMPIWGTemplate.zpt')).__of__(self)
+    return pt()
+
+
+
+def manage_addMPIWGTemplate(self, MPIWGType,id, text="",title=None,weight=0,REQUEST=None):
+    "Add a Page Template with optional file content."
+    if type(MPIWGType)==StringType:
+        MPIWGTypes=[MPIWGType]
+    else:
+        MPIWGTypes=MPIWGType
+        
+    for singleType in MPIWGTypes:
+
+
+        if REQUEST is None:
+            self._setObject(id, MPIWGTemplate(id, text,EchoType=singleType))
+            ob = getattr(self, id)
+            
+            if title:
+                ob.pt_setTitle(title)
+            return ob
+        else:
+            file = REQUEST.form.get('file')
+            headers = getattr(file, 'headers', None)
+            if headers is None or not file.filename:
+                zpt = MPIWGTemplate(id,MPIWGType=singleType)
+            else:
+                zpt = MPIWGTemplate(id, file, headers.get('content_type'))
+
+            self._setObject(id, zpt)
+            ob = getattr(self, id)
+            if title:
+                ob.pt_setTitle(title)
+
+            try:
+                u = self.DestinationURL()
+            except AttributeError:
+                u = REQUEST['URL1']
+
+    ob = getattr(self, id)
+    ob.weight=weight
+    
+    REQUEST.RESPONSE.redirect(u+'/manage_main')
+    return ''
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SrvTxtUtils.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,134 @@
+"""Utility methods for handling XML, reading HTTP, etc"""
+
+from App.ImageFile import ImageFile
+from App.Common import rfc1123_date
+
+import sys
+import os
+import stat
+import urllib
+import urllib2
+import logging
+
+
+srvTxtUtilsVersion = "1.5"
+
+def getInt(number, default=0):
+    """returns always an int (0 in case of problems)"""
+    try:
+        return int(number)
+    except:
+        return int(default)
+
+def getAt(array, idx, default=None):
+    """returns element idx from array or default (in case of problems)"""
+    try:
+        return array[idx]
+    except:
+        return default
+
+def unicodify(s):
+    """decode str (utf-8 or latin-1 representation) into unicode object"""
+    if not s:
+        return u""
+    if isinstance(s, str):
+        try:
+            return s.decode('utf-8')
+        except:
+            return s.decode('latin-1')
+    else:
+        return s
+
+def utf8ify(s):
+    """encode unicode object or string into byte string in utf-8 representation.
+       assumes string objects to be utf-8"""
+    if not s:
+        return ""
+    if isinstance(s, str):
+        return s
+    else:
+        return s.encode('utf-8')
+
+def getText(node, recursive=0):
+    """returns all text content of a node and its subnodes"""
+    if node is None:
+        return ''
+    
+    # ElementTree:
+    text = node.text or ''
+    for e in node:
+        if recursive:
+            text += getText(e)
+        else:
+            text += e.text or ''
+        if e.tail:
+            text += e.tail
+
+    # 4Suite:
+    #nodelist=node.childNodes
+    #text = ""
+    #for n in nodelist:
+    #    if n.nodeType == node.TEXT_NODE:
+    #       text = text + n.data
+    
+    return text
+
+
+
+def getHttpData(url, data=None, num_tries=3, timeout=10, noExceptions=False):
+    """returns result from url+data HTTP request"""
+    # we do GET (by appending data to url)
+    if isinstance(data, str) or isinstance(data, unicode):
+        # if data is string then append
+        url = "%s?%s"%(url,data)
+    elif isinstance(data, dict) or isinstance(data, list) or isinstance(data, tuple):
+        # urlencode
+        url = "%s?%s"%(url,urllib.urlencode(data))
+    
+    response = None
+    errmsg = None
+    for cnt in range(num_tries):
+        try:
+            logging.debug("getHttpData(#%s %ss) url=%s"%(cnt+1,timeout,url))
+            if sys.version_info < (2, 6):
+                # set timeout on socket -- ugly :-(
+                import socket
+                socket.setdefaulttimeout(float(timeout))
+                response = urllib2.urlopen(url)
+            else:
+                # timeout as parameter
+                response = urllib2.urlopen(url,timeout=float(timeout))
+            # check result?
+            break
+        except urllib2.HTTPError, e:
+            logging.error("getHttpData: HTTP error(%s): %s"%(e.code,e))
+            errmsg = str(e)
+            # stop trying
+            break
+        except urllib2.URLError, e:
+            logging.error("getHttpData: URLLIB error(%s): %s"%(e.reason,e))
+            errmsg = str(e)
+            # stop trying
+            #break
+
+    if response is not None:
+        data = response.read()
+        response.close()
+        return data
+    
+    if noExceptions:
+        return None
+    
+    raise IOError("ERROR fetching HTTP data from %s: %s"%(url,errmsg))
+    #return None
+
+
+def refreshingImageFileIndexHtml(self, REQUEST, RESPONSE):
+    """index_html method for App.ImageFile that updates the file info for each request."""
+    stat_info = os.stat(self.path)
+    self.size = stat_info[stat.ST_SIZE]
+    self.lmt = float(stat_info[stat.ST_MTIME]) or time.time()
+    self.lmh = rfc1123_date(self.lmt)
+    # call original method
+    return ImageFile.index_html(self, REQUEST, RESPONSE)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/__init__.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,69 @@
+import MPIWGProjects
+import MPIWGStaff
+import MPIWGLink
+import MPIWGTemplate
+import MPIWGFeature
+import MPIWGFolder
+import MPIWGRoot
+
+from nameSplitter import nameSplitter
+
+def initialize(context):
+    """initialize MPIWGWeb"""
+    context.registerClass(
+        MPIWGProjects.MPIWGProject,
+        constructors = (
+          MPIWGProjects.manage_addMPIWGProjectForm,
+          MPIWGProjects.manage_addMPIWGProject
+          )
+        )
+
+    context.registerClass(
+        MPIWGLink.MPIWGLink,
+        constructors = (
+          MPIWGLink.manage_addMPIWGLinkForm,
+          MPIWGLink.manage_addMPIWGLink
+          )
+        )
+
+   
+    context.registerClass(
+        MPIWGRoot.MPIWGRoot,
+        constructors = (
+          MPIWGRoot.manage_addMPIWGRootForm,
+          MPIWGRoot.manage_addMPIWGRoot
+          )
+        )
+
+    context.registerClass(
+        MPIWGTemplate.MPIWGTemplate,
+        constructors = (
+          MPIWGTemplate.manage_addMPIWGTemplateForm,
+          MPIWGTemplate.manage_addMPIWGTemplate
+          )
+        )
+
+    context.registerClass(
+        MPIWGFolder.MPIWGFolder,
+        constructors = (
+          MPIWGFolder.manage_addMPIWGFolderForm,
+          MPIWGFolder.manage_addMPIWGFolder
+          )
+        )
+
+    context.registerClass(
+        MPIWGFeature.MPIWGFeature,
+        constructors = (
+          MPIWGFeature.manage_addMPIWGFeatureForm,
+          MPIWGFeature.manage_addMPIWGFeature
+          )
+        )
+
+    context.registerClass(
+        MPIWGStaff.MPIWGStaff,
+        constructors = (
+          MPIWGStaff.manage_addMPIWGStaffForm,
+          MPIWGStaff.manage_addMPIWGStaff
+          )
+        )
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bibliography.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,95 @@
+#TO DO author_semi_kolon etc. ersetzen durch Funktionen
+def formatBibliography(self,found):
+    ret=""
+    if found.id_institutsbibliographie and (not found.id_institutsbibliographie==''):
+        ret+=formatBiblHelp(self,found,table='institutsbiblio',id=found.id_institutsbibliographie)
+    else:
+        ret+=formatBiblHelp(self,found,table='bibliography',id=found.id_gen_bib)
+    return ret
+
+def CRListToSemicolon(list):
+    if list:
+        return "; ".join(list.split("\n"))
+    else:
+        return None
+    
+def getBib(value):
+    if value:
+        return value
+    else:
+        return ""
+    
+def formatBiblHelp(self,found,table,id,foundIB=None):
+    ret=""
+    if not foundIB:
+        try:
+            foundIB=self.ZSQLInlineSearch(_table=table,id=id,_op_id="eq")[0]
+
+        except:
+            return ret
+    
+    if foundIB.reference_type.lower()=='journal article':
+        ret+=getBib(CRListToSemicolon(foundIB.author))+". &quot;"+getBib(foundIB.title)+". &quot; "+"<i>%s</i>"%getBib(foundIB.secondary_title)+" "+getBib(foundIB.volume)+" ("
+        if not self.ZSQLisEmpty(foundIB.number):
+            ret+=foundIB.number+"&nbsp;"
+
+        if foundIB.year:
+            ret+=getattr(foundIB,'year','')
+        ret+=")"
+        if foundIB.pages and (not foundIB.pages)=='':
+            ret+=": "+foundIB.pages+"."
+
+    elif foundIB.reference_type.lower()=='edited book':
+        if foundIB.author:
+            ret+=CRListToSemicolon(foundIB.author)+" (Editor/s). " 
+        if foundIB.title and (not foundIB.title==""):
+            ret+="<i>"+foundIB.title+"</i>. "
+        if foundIB.place_published and (not foundIB.place_published==''):
+            ret+=foundIB.place_published+": "
+        if foundIB.publisher and (not foundIB.publisher==''):
+            ret+=foundIB.publisher+", "
+        ret+=getBib(foundIB.year)+"."
+
+    elif foundIB.reference_type.lower()=='book section' or foundIB.reference_type.lower()=='in book':
+        ret+=getBib(CRListToSemicolon(foundIB.author))+". &quot;"+getBib(foundIB.title)+".&quot; In: <i>"+getBib(foundIB.secondary_title)+"</i>"
+        if (CRListToSemicolon(foundIB.secondary_author)) and (not CRListToSemicolon(foundIB.secondary_author)==''):
+            ret+=", eds.: "+CRListToSemicolon(foundIB.secondary_author)
+        ret+=". "
+        if foundIB.pages and (not foundIB.pages)=='':
+            ret+=foundIB.pages+". "
+        if foundIB.place_published and (not foundIB.place_published==''):
+            ret+=foundIB.place_published+": "
+        if foundIB.publisher and (not foundIB.publisher==''):
+            ret+=foundIB.publisher+", "
+        ret+=getBib(foundIB.year)+"."
+
+   
+    elif foundIB.reference_type.lower()=='book':
+        ret+=getBib(CRListToSemicolon(foundIB.author))+". <i>"+getBib(foundIB.title)+"</i>. "
+#       if foundIB.pages and (not foundIB.pages==''):
+#%            ret+=foundIB.pages+". "
+        if foundIB.place_published and (not foundIB.place_published==''):
+            ret+=foundIB.place_published+": "
+        if foundIB.publisher and (not foundIB.publisher==''):
+            ret+=foundIB.publisher+", "
+        ret+=getBib(foundIB.year)+"."
+
+    elif foundIB.reference_type.lower()=='newspaper article':
+        ret+=CRListToSemicolon(foundIB.author)+". &quot;"+foundIB.title+".&quot; <i>"+foundIB.secondary_title+"</i>, "
+        ret+=foundIB.date+"."+foundIB.year+","
+        if foundIB.pages and (not foundIB.pages==''):
+            ret+=foundIB.pages+". "
+    elif foundIB.reference_type.lower()=='magazine article':
+        ret+=CRListToSemicolon(getBib(foundIB.author))+". &quot;"+getBib(foundIB.title)+".&quot; <i>"+getBib(foundIB.secondary_title)+"</i>, "
+	if foundIB.date:
+	        ret+=getBib(foundIB.date)+"."
+	if foundIB.year:
+		ret+=foundIB.year+","
+        if foundIB.pages and (not getBib(foundIB.pages)==''):
+            ret+=foundIB.pages+". "
+
+
+
+            
+            
+    return ret
Binary file blank.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cleanDBUp.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,51 @@
+"""loesche alle doppelten Personeneintraege aus personal_www"""
+try:
+    import psycopg2 as psycopg
+    psyco = 2
+except:
+    import psycopg
+    psyco = 1
+    
+
+dsn="dbname=personalwww host=xserve02a user=mysql password=e1nste1n"
+dbCon = psycopg.connect(dsn)
+db = dbCon.cursor()
+
+#find all keys
+
+qstr="select key from personal_www group by key"
+db.execute(qstr)
+res=db.fetchall()
+keys=[x[0] for x in res]
+print keys
+for key in keys:
+    qstr="select id,publish_the_data from personal_www where key='%s' "%key
+    db.execute(qstr)
+    res=db.fetchall()
+
+    deleteL={} #use hash to generate an unique list of keys
+    foundPublish=None
+    for x in res:
+        if x[1]=="yes":
+            foundPublish=x[1]
+        else:
+            deleteL[x[0]]=True
+  
+    delete=deleteL.keys()
+    if (len(delete)>0) and (not foundPublish): #keiner auf publish, loesche alle bis auf den letzten 
+        del delete[-1]
+    
+    
+    for x in delete:
+        if x is not None:
+            qstr="delete from personal_www where id='%s'" %x
+        
+            print qstr
+            db.execute(qstr)
+    dbCon.commit()
+    
+
+
+
+
+      
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nameSplitter.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,80 @@
+"""
+name splitter
+"""
+
+from Products.ZCTextIndex.ISplitter import ISplitter
+from Products.ZCTextIndex.PipelineFactory import element_factory
+
+
+
+import re
+from types import StringType
+
+def getSupportedEncoding(encodings):
+    for encoding in encodings:
+        try:
+            unicode('A', encoding)
+            return encoding
+        except:
+            pass
+    return 'utf-8'
+
+# CJK charsets ranges, see this following pages:
+#
+# http://jrgraphix.net/research/unicode_blocks.php?block=87
+# http://jrgraphix.net/research/unicode_blocks.php?block=85
+# http://jrgraphix.net/research/unicode_blocks.php?block=95
+# http://jrgraphix.net/research/unicode_blocks.php?block=76
+# http://jrgraphix.net/research/unicode_blocks.php?block=90
+
+"""
+splitter for lastnames in database
+
+"""
+import re
+
+def quote(str):
+    str=str.replace("'","\\\'")
+    return str
+class nameSplitter:
+
+    default_encoding = "utf-8"
+
+    def process(self, lsttmp):
+        import psycopg
+        result = []
+        o = psycopg.connect('dbname=authorities user=dwinter password=3333',serialize=0) 
+        c = o.cursor() 
+#        replaceStr="<>;.:(),"
+        lst=" ".join(lsttmp)
+#        for x in replaceStr:
+#            lst=lst.replace(x," ")
+        lst=re.sub("[<|>|;|.|:|\(|\|)|,]", " ", lst)
+        for s in lst.split():
+
+            if type(s) is not StringType: # not unicode
+                s = s.decode(self.default_encoding)
+
+            if s not in result: # check for database entry
+
+                #c.execute("select lastname from persons where lower(lastname) = '%s'"%quote(s.lower()))
+                c.execute("select lastname from persons where lastname = '%s'"%quote(s))
+                if c.fetchone():
+                    print "found",s
+                    result.append(s)
+        return result
+
+ 
+try:
+    element_factory.registerFactory('Word Splitter',
+          'MPIWG Name Splitter', nameSplitter)
+except:
+    # in case the splitter is already registered, ValueError is raised
+    pass
+
+if __name__ == '__main__':
+   a = 'abc def\U00CE\U00D2\U00D3\U00C7\U00B5\U00C4 \U00DC\U00C3\U00A1\U00A3'
+   u = unicode(a, 'gbk')
+   s = authorSplitter()
+   print s.process([u])
+   print s.process([u], 1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/updatePersonalWWW.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,391 @@
+import psycopg2 as psycopg
+psyco = 2
+    
+import logging
+from MPIWGHelper import unicodify, utf8ify
+
+from xml import sax
+from xml.sax.handler import ContentHandler
+
+# namespace for FileMaker8
+fm_ns = 'http://www.filemaker.com/fmpxmlresult'
+
+# list of fields that are taken from XML and checked against DB as conflicts
+#checkFields=['key','first_name','last_name','title','home_inst','current_work','e_mail2']
+checkFields=['key','first_name','last_name','title','titles_new','home_inst','current_work']
+
+
+def sql_quote(v):
+    # quote dictionary
+    quote_dict = {"\'": "''", "\\": "\\\\"}
+    for dkey in quote_dict.keys():
+        if v.find(dkey) >= 0:
+            v=quote_dict[dkey].join(v.split(dkey))
+    return "'%s'"%v
+
+def SimpleSearch(curs,query, args=None):
+    """execute sql query and return data"""
+    logging.debug("executing: "+query)
+    if psyco == 1:
+        query = query.encode("UTF-8")
+        #if args is not None:
+        #    args = [ sql_quote(a) for a in args ]
+    #logging.debug(query)
+    #logging.debug(args)
+
+    curs.execute(query, args)
+    logging.debug("sql done")
+    try:
+        return curs.fetchall()
+    except:
+        return None
+    
+class xml_handler(ContentHandler):
+    
+    def __init__(self):
+        '''
+        SAX handler to import FileMaker XML file (FMPXMLRESULT format) into the table.
+        @param dsn: database connection string
+        @param table: name of the table the xml shall be imported into
+        '''
+        
+        # set up parser
+        self.result={}
+        self.event = None
+#        self.top_dispatcher = { 
+#            (saxtools.START_ELEMENT, fm_ns, u'METADATA'): 
+#            self.handle_meta_fields,
+#            (saxtools.START_ELEMENT, fm_ns, u'RESULTSET'): 
+#            self.handle_data,
+#            }
+        
+        # connect database
+      
+      
+
+      
+        self.dbIDs = {}
+        self.rowcnt = 0
+             
+        self.currentName=None
+      
+        self.newDataset = []
+        self.conflicts = []
+        self.ok = []
+        self.fieldNames=[]
+        self.currentRow={}
+        self.currentTag=""
+        return
+
+    def startElement(self, name, attrs):
+        logging.debug(name)
+        if (name.lower() == "field") :
+            self.handle_meta_fields(attrs)
+        if (name.lower() == "row") :
+            logging.debug("handleROW")
+            self.currentRow={} # new Row
+            self.currentData=0
+        
+        
+        if (name.lower()=="data"):
+               
+            self.currentName=self.fieldNames[self.currentData]
+            self.currentData+=1
+            self.currentTag="data"
+            logging.debug("currentData"+str(self.currentData))
+            logging.debug("currentName"+str(self.currentName))
+            self.currentRow[self.currentName]="" #anlegen des eintrages 
+            
+    def endElement(self,name):
+        if (name.lower() == "data") :
+            self.currentTag=""
+        if (name.lower() == "row"):
+            self.handle_end_row()
+            
+    def characters(self,content):
+        
+        if self.currentName is not None:
+            logging.debug(self.currentName+"    "+content)
+            contentTmp = self.currentRow.get(self.currentName,'') #gibt es schon einen Inhalt, dann dieses hinzufuegen (in einem Tag kann u.U. der characters handler mehrfach aufgerufen werden.)      
+            self.currentRow[self.currentName]=contentTmp+content;
+
+
+    def handle_end_row(self):
+        
+        logging.debug("edd ROW")
+
+        if self.result.has_key(self.currentRow['key']):
+             logging.error("Key %s not unique"%self.currentRow['key'])
+      
+        logging.debug("currentrow:"+self.currentName)
+        logging.debug("currentname:"+self.currentRow['key'])
+        
+        if self.currentName is not None:
+            self.result[self.currentRow['key']]=self.currentRow.copy()
+#      
+#       
+#        return
+
+    def handle_meta_fields(self,attrs):
+      
+        #First round through the generator corresponds to the
+        #start element event
+        logging.debug("START -FIELD")
+        name = attrs.get('NAME')
+        name=name.replace(" ","_")# make sure no spaces
+        self.fieldNames.append(name)
+     
+        self.update_fields = self.fieldNames
+        
+        logging.debug("xml-fieldnames:"+repr(self.fieldNames))
+        # get list of fields in db table
+     
+        #print "upQ: ", self.updQuery
+        #print "adQ: ", self.addQuery
+                        
+        return
+
+#    def handle_meta_field(self, end_condition):
+#        name = self.params.get((None, u'NAME'))
+#        yield None
+#        #Element closed.  Wrap up
+#        name=name.replace(" ","_")# make sure no spaces
+#        self.fieldNames.append(name)
+#        logging.debug("FIELD name: "+name)
+#        return
+
+#    def handle_data(self, end_condition):
+#        dispatcher = {
+#            (saxtools.START_ELEMENT, fm_ns, u'ROW'):
+#            self.handle_row,
+#            }
+#        #First round through the generator corresponds to the
+#        #start element event
+#        logging.debug("START RESULTSET")
+#        self.rowcnt = 0
+#        yield None
+#    
+#        #delegate is a generator that handles all the events "within"
+#        #this element
+#        delegate = None
+#        while not self.event == end_condition:
+#            delegate = saxtools.tenorsax.event_loop_body(
+#                dispatcher, delegate, self.event)
+#            yield None
+#        
+#        #Element closed.  Wrap up
+#        logging.debug("END RESULTSET")
+#      
+#        
+#  
+#        return
+
+#    def handle_row(self, end_condition):
+#        dispatcher = {
+#            (saxtools.START_ELEMENT, fm_ns, u'COL'):
+#            self.handle_col,
+#            }
+#        logging.debug("START ROW")
+#        self.dataSet = {}
+#        self.colIdx = 0
+#        yield None
+#    
+#        #delegate is a generator that handles all the events "within"
+#        #this element
+#        delegate = None
+#        while not self.event == end_condition:
+#            delegate = saxtools.tenorsax.event_loop_body(
+#                dispatcher, delegate, self.event)
+#            yield None
+#        
+#        #Element closed.  Wrap up
+#        logging.debug("END ROW")
+#        self.rowcnt += 1
+#        # process collected row data
+#        update=False
+#        id_val=''
+#        
+#        if self.result.has_key(self.dataSet['key']):
+#            logging.error("Key %s not unique"%self.dataSet['key'])
+#        
+#        self.result[self.dataSet['key']]=self.dataSet
+#      
+#       
+#        return
+
+#    def handle_col(self, end_condition):
+#        dispatcher = {
+#            (saxtools.START_ELEMENT, fm_ns, u'DATA'):
+#            self.handle_data_tag,
+#            }
+#        #print "START COL"
+#        yield None
+#        #delegate is a generator that handles all the events "within"
+#        #this element
+#        delegate = None
+#        while not self.event == end_condition:
+#            delegate = saxtools.tenorsax.event_loop_body(
+#                dispatcher, delegate, self.event)
+#            yield None
+#        #Element closed.  Wrap up
+#        #print "END COL"
+#        self.colIdx += 1
+#        return
+#
+#    def handle_data_tag(self, end_condition):
+#        #print "START DATA"
+#        content = u''
+#        yield None
+#        # gather child elements
+#        while not self.event == end_condition:
+#            if self.event[0] == saxtools.CHARACTER_DATA:
+#                content += self.params
+#            yield None
+#        #Element closed.  Wrap up
+#        field = self.fieldNames[self.colIdx]
+#        self.dataSet[field.lower()] = content
+#        #print "  DATA(", field, ") ", repr(content)
+#        return
+
+
+def checkImport(dsn,resultSet):
+    #now connect to the database
+    logging.info("dsn: %s"%dsn)
+    dbCon = psycopg.connect(dsn)
+    db = dbCon.cursor()
+    
+    
+    qstr="select key from personal_www"
+    
+    results=SimpleSearch(db,qstr)
+  
+    keys=[]
+    for x in results:
+        if x[0]:
+            keys.append(unicodify(x[0]))
+            
+  
+    #first step detect new entries and conflicts
+    new=[]
+    conflicts={}
+
+    for x in resultSet.iterkeys():
+       
+        if x not in keys:
+           
+            new.append(x)
+            
+        else:
+        
+            conflict,ret=checkForConflicts(db,resultSet[x],x)
+            if conflict:
+                conflicts[x]=ret
+
+    return new,conflicts
+
+def importFMPXML(filename):
+    '''
+        method to import FileMaker XML file (FMPXMLRESULT format) into the table.
+        @param filename: xmlfile filename
+       
+        '''
+   
+    parser = sax.make_parser()
+    #The "consumer" is our own handler
+    consumer = xml_handler()
+    #Initialize Tenorsax with handler
+    #handler = saxtools.tenorsax(consumer)
+    #Resulting tenorsax instance is the SAX handler 
+    parser.setContentHandler(consumer)
+    #parser.setFeature(sax.handler.feature_namespaces, 1)
+    parser.parse(filename)  
+    resultSet=consumer.result # xml now transformed into an dictionary
+    
+    return resultSet
+  
+    
+
+def checkForConflicts(cursor,dataSet,key):
+    
+    ret=[]
+    fields=",".join(checkFields)
+    
+    qstr="select %s from personal_www where key='%s'"%(fields,key)
+    
+  
+    sr=SimpleSearch(cursor,qstr)
+    
+    if not sr:
+        return True, None
+    
+    i=0
+    retValue=False
+    
+    for checkField in checkFields:
+        dbValueR=sr[0][i]
+        if dbValueR:
+            dbValue=unicodify(dbValueR)
+        else:
+            dbValue=""
+            
+        if checkField in dataSet:
+            setValue=dataSet[checkField]
+            logging.debug( "             %s %s %s %s"%(repr(key),checkField,repr(dbValue),repr(setValue)))
+            if dbValue.strip().rstrip()!=setValue.lstrip().rstrip():
+                ret.append((checkField,dbValue,setValue))
+                retValue=True
+                
+        else:
+            logging.warning("unknown field %s in data file!"%checkField)
+            
+        i+=1
+    
+    return retValue,ret
+    
+    
+##
+## public static int main()
+##
+
+if __name__ == "__main__":
+    
+
+  
+    loglevel = logging.DEBUG
+   
+    
+    logging.basicConfig(level=loglevel, 
+                        format='%(asctime)s %(levelname)s %(message)s',
+                        datefmt='%H:%M:%S')
+    
+    resultSet=importFMPXML(filename="/Users/dwinter/Desktop/personalwww.xml")
+    news,conflicts=checkImport(dsn="dbname=personalwww user=www password=e1nste1n", resultSet=resultSet)
+    
+    
+    print "new"
+    print len(news),news
+    print "-----------"
+    print "conflicts"
+    print conflicts
+    
+#    update_fields = None
+#    
+#    if options.update_fields:
+#        update_fields = [string.strip(s) for s in options.update_fields.split(',')]
+#    
+#    parser = sax.make_parser()
+#    #The "consumer" is our own handler
+#    consumer = xml_handler(dsn=options.dsn,table=options.table,
+#                 update_fields=update_fields,id_field=options.id_field,
+#                 sync_mode=options.sync_mode)
+#    #Initialize Tenorsax with handler
+#    handler = saxtools.tenorsax(consumer)
+#    #Resulting tenorsax instance is the SAX handler 
+#    parser.setContentHandler(handler)
+#    parser.setFeature(sax.handler.feature_namespaces, 1)
+#    parser.parse(options.filename)  
+#    
+#    
+#    print "DONE!"
+
+  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/updateSQL/agenda.xml	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<convert>
+  <source>
+    <database>
+      <url>jdbc:fmpro:http://itgroup.mpiwg-berlin.mpg.de:8050</url>
+      <user>dwinter</user>
+      <password>e1nste1n</password>
+      <delimiter></delimiter>
+      <mode>convert</mode>
+      <usenormantounicodemapper>false</usenormantounicodemapper>
+      <table name = "Agenda" layout = "" id = "" indexList ="">
+         <select>select * from "Agenda"</select>
+      </table>
+    </database>
+  </source>
+
+  <destination>
+    <database>
+      <url>jdbc:postgresql://xserve04.mpiwg-berlin.mpg.de/personalwww</url>
+      <user>www</user>
+      <password>3333</password>
+      <delimiter>//</delimiter>
+      <mode></mode>
+      <usenormantounicodemapper>false</usenormantounicodemapper>
+    </database>
+  </destination>
+</convert>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/updateSQL/berlinkalender.xml	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<convert>
+  <source>
+    <database>
+      <url>jdbc:fmpro:http://itgroup.mpiwg-berlin.mpg.de:8050</url>
+      <user>dwinter</user>
+      <password>e1nste1n</password>
+      <delimiter></delimiter>
+      <mode>convert</mode>
+      <usenormantounicodemapper>false</usenormantounicodemapper>
+      <table name = "WWW_berlinkalender" layout = "" id = "" indexList ="">
+         <select>select * from "WWW_berlinkalender"</select>
+      </table>
+    </database>
+  </source>
+
+  <destination>
+    <database>
+      <url>jdbc:postgresql://xserve04.mpiwg-berlin.mpg.de/personalwww</url>
+      <user>www</user>
+      <password>3333</password>
+      <delimiter>//</delimiter>
+      <mode></mode>
+      <usenormantounicodemapper>false</usenormantounicodemapper>
+    </database>
+  </destination>
+</convert>
Binary file updateSQL/fm.jar has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/updateSQL/personalwww.xml	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<convert>
+  <source>
+    <database>
+      <url>jdbc:fmpro:http://141.14.237.74:8050</url>
+      <user>dwinter</user>
+      <password>e1nste1n</password>
+      <delimiter></delimiter>
+      <mode>convert</mode>
+      <usenormantounicodemapper>false</usenormantounicodemapper>
+      <table name = "institutsbiblio" layout = "" id = "" indexList ="">
+         <select>select * from "institutsbiblio"</select>
+      </table>
+    </database>
+  </source>
+
+  <destination>
+    <database>
+      <url>jdbc:postgresql://xserve04.mpiwg-berlin.mpg.de/personalwww_test2</url>
+      <user>www</user>
+      <password>3333</password>
+      <delimiter>//</delimiter>
+      <mode></mode>
+      <usenormantounicodemapper>false</usenormantounicodemapper>
+    </database>
+  </destination>
+</convert>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/updateSQL/preprints.xml	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<convert>
+  <source>
+    <database>
+      <url>jdbc:fmpro:http://itgroup.mpiwg-berlin.mpg.de:8050</url>
+      <user>dwinter</user>
+      <password>e1nste1n</password>
+      <delimiter></delimiter>
+      <mode>convert</mode>
+      <usenormantounicodemapper>false</usenormantounicodemapper>
+      <table name = "WWW_preprints" layout = "" id = "" indexList ="">
+         <select>select "autor","titel","nr","verweis berechnet","online","online version","PDF","pdf download","www anmerkung", "freigegeben" from "WWW_preprints"</select>
+      </table>
+    </database>
+  </source>
+
+  <destination>
+    <database>
+      <url>jdbc:postgresql://tuxserve01.mpiwg-berlin.mpg.de/personalwww</url>
+      <user>www</user>
+      <password>3333</password>
+      <delimiter>//</delimiter>
+      <mode></mode>
+      <usenormantounicodemapper>false</usenormantounicodemapper>
+    </database>
+  </destination>
+</convert>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/version.txt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,1 @@
+MPIWGWeb 1.3.1
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wikisqldumpToSQL.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,35 @@
+import psycopg
+
+o = psycopg.connect('dbname=authorities user=dwinter password=3333',serialize=0) 
+c = o.cursor() 
+
+import re
+
+def quote(str):
+    str=str.replace("'","\\\'")
+    str=str.replace("@","\\\'")
+    return str#.encode('utf-8')
+
+filename="/Users/dwinter/Desktop/dewiki-20060908-categorylinks.sql"
+txt=file(filename).read()
+datas=re.findall("(VALUES.*)",txt)
+for data in datas:
+    print data
+    txt=data.replace("VALUES","")
+    data=re.findall("\((.*?)\)",txt)
+    print len(data)
+    for result in data:
+        result=result.replace("\\\'","@")
+        
+        new=re.findall("\'(.*?)\'",result)
+        if len(new)>1:
+            if (len(new)>0) and ((new[0]=='Mann') or (new[0]=="Frau")):
+                try:
+                    firstname=new[1].split(",")[1].lstrip()
+                except:
+                    firstname=""
+                lastname=new[1].split(",")[0].lstrip()
+                
+                print "INSERT into persons (firstname,lastname) VALUES ('%s','%s')"% (quote(firstname),quote(lastname))
+                c.execute("INSERT into persons (firstname,lastname) VALUES ('%s','%s')"% (quote(firstname),quote(lastname)))
+                c.commit()
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wikixml2sql.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,51 @@
+import xml.parsers.expat
+import psycopg
+
+filename="mann.xml"
+
+# 3 handler functions
+global toggle
+toggle=False
+
+global c
+
+def quote(str):
+    str=str.replace("'","\\\'")
+    return str.encode('utf-8')
+
+def start_element(name, attrs):
+    global toggle
+    if name=="title":
+        toggle=True
+def end_element(name):
+    global toggle
+    if name=="title":
+        toggle=False
+def char_data(data):
+    global toggle
+    global c
+    if toggle:
+        splitted=data.split()
+        if splitted >1:
+            lastname=splitted[-1]
+            firstname=" ".join(splitted[0:-1])
+        else:
+            lastname=splitted[0]
+            firstname=""
+        print "INSERT into persons (firstname,lastname) VALUES ('%s','%s')"% (quote(firstname),quote(lastname))
+        c.execute("INSERT into persons (firstname,lastname) VALUES ('%s','%s')"% (quote(firstname),quote(lastname)))
+        c.commit()
+    
+    
+o = psycopg.connect('dbname=authorities user=dwinter password=3333',serialize=0) 
+c = o.cursor() 
+
+p = xml.parsers.expat.ParserCreate()
+
+p.StartElementHandler = start_element
+p.EndElementHandler = end_element
+p.CharacterDataHandler = char_data
+fh=file(filename)
+p.ParseFile(fh)
+
+o.close()
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xmlhelper.py	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,242 @@
+
+from sys import argv
+
+import string
+import xml.dom.minidom
+#import Ft.Xml.XLink.Processor
+#import Ft.Xml.XLink.XLinkElements
+#
+#from Ft.Xml import XPath
+#from Ft.Xml.XPath import Evaluate
+#from Ft.Xml.XLink import XLINK_NAMESPACE
+#from Ft.Xml.XLink import XLinkElements
+
+#from Ft.Xml.Domlette import NonvalidatingReader,InputSource
+#from Ft.Xml import EMPTY_NAMESPACE
+
+#from Ft.Lib import Uri
+
+from xml.etree import ElementTree
+import logging
+
+xml2html={'WEB_normal':('<p>','</p>'),'Normal':('<p>','</p>'),'WEB_picture':('<p class=\"picture\">','</p>'),'WEB_figuretitle':('<p class=\"picturetitle\">','</p>'),'WEB_bibliography':('<p><i>','</i></p>'),'Web_kursiv':('<i>','</i>'),'WEB_kursiv':('<i>','</i>'),'WEB_hyperlink':('',''),'Hyperlink':('','')}
+
+def addToDict(dict,name,value):
+    if name=="":
+        return 0
+    else:
+        
+        if not dict.has_key(name):
+            dict[name]=[] # als array anlegen
+
+        dict[name].append(value)
+        return 1    
+
+def proj2hash(xmlstring):
+    """wandelt xml-files fuer die projekte in ein hash"""
+    
+    #dom=xml.dom.minidom.parseString(xmlstring)
+    
+    tree = ElementTree.fromstring(xmlstring)
+    
+
+    pars = tree.findall(".//part[0]/par")
+
+    list={}
+
+    #gettitle
+    #part= dom.getElementsByTagName('part')[0]
+    #pars=part.getElementsByTagName('par')
+    #pars=Evaluate('par',dom.getElementsByTagName('part')[0])
+    logging.debug(pars)
+    for par in pars:
+        logging.debug(par)
+        className=par.attrib['class']
+        #.getAttribute('class')
+        content=par.text
+        addToDict(list,className,content)
+             
+    list.update(parseTable(tree.find('.//{http://www.w3.org/HTML/1998/html4}table'))) # Parse the Table
+
+    #evaluate level 1
+    sections = tree.findall(".//part[0]/section")
+    #sections=Evaluate('section',dom.getElementsByTagName('part')[0])# Parse all Sections
+    #sections=Evaluate('section',dom.getElementsByTagName('part')[0])# Parse all Sections
+    #print sections,dom.getElementsByTagName('part')[0]
+    for section in sections:
+
+        sec=parseSection(section)
+        if sec[0]=="WEB_project_header": # Sonderfall project
+
+            addToDict(list,'WEB_project_header',sec[1]) # store title
+            addToDict(list,'WEB_project_description',sec[2]) #store description
+        else: # no information in heading
+
+            addToDict(list,sec[0],sec[2])
+
+    #evaluate higher level sections
+    sections = tree.findall(".//part[0]/section/section")
+    #sections=Evaluate('section/section',dom.getElementsByTagName('part')[0])
+
+    for section in sections:
+        logging.debug("sections2:"+repr(section))
+        sec=parseSection(section)
+        
+        if sec[0]=="WEB_project_header": # Sonderfall project
+            addToDict(list,'WEB_project_header',sec[1]) # store title
+            addToDict(list,'WEB_project_description',sec[2]) #store description
+        else: # no information in heading
+            addToDict(list,sec[0],sec[2])
+
+    
+    return list
+
+
+def parseSection(section):
+    type=""
+    header=""
+    #for heading in section.childNodes:
+    
+    heading=section.find(".//heading")
+       # if getattr(heading,'tagName','')=="heading":
+    
+    
+    type=heading.attrib['class']
+    logging.debug("parseSection (class):"+type)
+    header=heading.text
+    logging.debug("parseSection (header):"+header)
+    
+    if type=="": # falls heading fehlt, pruefe ob erster par richtig
+        par=section.find(".//par")
+        #par=section.getElementsByTagName('par')[0]
+        type=par.attrib['class']
+        header=par.text
+        
+    #print section.childNodes
+    pars=section.findall(".//par")
+    #pars=Evaluate('par',section)
+    content=par2html(pars)
+    
+    return (type,header,content)
+
+def parseTable(table):
+    fields={}
+    rows=table.findall('.//{http://www.w3.org/HTML/1998/html4}tr')
+    #rows=table.getElementsByTagName('html:tr')
+    for row in rows:
+        logging.debug("ROW")
+        cols=row.findall('.//{http://www.w3.org/HTML/1998/html4}td')
+        #cols=row.getElementsByTagName('html:td')
+        
+        #Name des Datenfeldes einlesen
+        try:
+            field=cols[0].find('.//par').attrib['class']
+            #field=cols[0].getElementsByTagName('par')[0].getAttribute('class')
+            #print "field",field
+        except:
+            logging.debug("error")
+            field=""
+
+        #Wandeln der Eintrge in HTML
+        
+        pars=cols[1].findall('.//par')
+        #pars=cols[1].getElementsByTagName('par')
+
+        
+        html=par2html(pars,tags=("",";"))
+        logging.debug("field:"+field)
+        logging.debug("html:"+html)
+        addToDict(fields,field,html)
+        #print fields
+    return fields
+
+def par2html(pars,tags=None):
+    #html=""
+    logging.debug("part2html:"+repr(pars))
+    if pars is None:
+        return ""
+    for par in pars:
+        logging.debug("part2html:"+repr(par))
+        if not tags:
+            try:
+                tag=xml2html[par.attrib['class']]
+            except:
+                tag=('<p>','</p>')
+        else:
+            tag=tags
+        
+        content=par.text
+        if content is None:
+            content=""
+        logging.debug("part2html:"+content)
+        #print "CONTETN",content
+        
+        #print par.getAttribute('class'),node
+        try:
+            html=html+tag[0]+content+tag[1]
+        except:
+            html=tag[0]+content+tag[1]
+
+    try:    
+        return html
+    except:
+        return ""
+
+def getXlink(nodes):
+    """searches xlinks and gives them back as html"""
+    ret=""
+    for node in nodes:
+        if node.attributes:
+            if 'xlink:type' in node.attributes.keys(): #is a xlink?
+                ret +=xlink2html(node)
+    return ret
+    
+def xlink2html(xlink):
+    ret=""
+    attributes=xlink.attributes
+    
+    if xlink.tagName.lower()=="image":
+        ret +="<img src=%s />"%xlink.getAttribute('xlink:href')
+    elif xlink.tagName.lower()=="link":
+        ret +="<a href='%s' >%s</a>"%(xlink.getAttribute('xlink:href'),getText(xlink.childNodes))
+    
+        
+        
+    
+    return ret
+
+def getText(nodelist):
+    
+    rc = u''
+    for node in nodelist:
+        if node.nodeType == node.TEXT_NODE:
+            #print "node",node
+            #print "NODE",node.data.encode('utf-8','ignore'),"V"
+            #print "HALII"
+            try:
+                try:
+                    #rc += node.data.encode('utf-8','ignore')
+                    rc += node.data
+                                        
+                except:
+                    #rc= node.data.encode('utf-8','ignore')
+                    rc=node.data
+            except:
+                rc="ERROR"
+                #node.data.decode('utf-8','ignore')
+                print "ERROR"
+            node.data.encode('utf-8','ignore')
+            #print "RC",rc
+        elif node.tagName =="inline":
+            rc+=par2html([node])
+        elif node.attributes:
+
+            if 'xlink:type' in node.attributes.keys(): #is a xlink?
+                rc +=xlink2html(node)
+    #print "RWT",rc        
+    return rc
+
+
+#filename=argv[1]
+#fileString=file(filename).read()
+#print proj2hash(fileString)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/AddMPIWGFeature.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,28 @@
+<html>
+<body>
+<h2>Create MPIWGWeb Feature object</h2>
+
+
+
+<form method="post" action="manage_addMPIWGFeature">
+<table>
+<tr>
+	<td><b>ID</b></td>
+	<td><input type="text" size="40" name="id"></td>
+</tr>
+<tr>
+	<td><i>Title</i></td>
+	<td><input type="text" size="40" name="title"></td>
+</tr>
+<tr>
+	<td><i>Weight</i></td>
+	<td><input type="text" size="40" name="weight"></td>
+</tr>
+
+</table>
+
+<input type="submit" value="create">
+
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/AddMPIWGFolder.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,28 @@
+<html>
+<body>
+<h2>Generate Folder for MPIWGWeb</h2>
+
+
+
+<form method="post" action="manage_addMPIWGFolder">
+<table>
+<tr>
+	<td><b>ID</b></td>
+	<td><input type="text" size="40" name="id"></td>
+</tr>
+<tr>
+	<td><i>Title</i></td>
+	<td><input type="text" size="40" name="title"></td>
+</tr>
+<tr>
+	<td><i>Weight</i></td>
+	<td><input type="text" size="40" name="weight"></td>
+</tr>
+
+</table>
+
+<input type="submit" value="create">
+
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/AddMPIWGLink.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,12 @@
+<html>
+<body>
+<h2>Change MPIWG Link</h2>
+<form action="manage_addMPIWGLink" method="post">
+<p>Id:<input name="id" size="30"></p>
+<p>Title:<input name="title" size="100"></p>
+<p>Link:<input name="link" size="100"></p>
+<p>Weight:<input name="weight"  size="100"></p>
+<p><input type="submit" value="submit"></p>
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/AddMPIWGTemplate.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,32 @@
+<html>
+<body>
+<h2>Generate Templates for MPIWGWeb</h2>
+
+
+
+<form method="post" action="manage_addMPIWGTemplate">
+<table>
+<tr>
+	<td><b>ID</b></td>
+	<td><input type="text" size="40" name="id"></td>
+</tr>
+<tr>
+	<td><i>Title</i></td>
+	<td><input type="text" size="40" name="title"></td>
+</tr>
+<tr>
+	<td><i>Weight</i></td>
+	<td><input type="text" size="40" name="weight"></td>
+</tr>
+
+</table>
+<h2>Type</h2>
+<input type="radio" checked name="MPIWGType" value="standardPage">Standard Page<br>
+
+
+
+<input type="submit" value="create">
+
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGFeatureChangeWeight.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,7 @@
+<html>
+<h2>Change Weight</h2>
+<form action="changeWeight" method="pro">
+<input tal:attributes="value here/weight|string:0" name="weight"><br>
+<input type="submit">
+</form>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGFeatureConfig.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,8 @@
+<html>
+<h2>Change MPIWG Feature</h2>
+<form action="changeMPIWGFeature" method="pro">
+Title: <input tal:attributes="value here/title|nothing" name="title"><br>
+Weight: <input tal:attributes="value here/weight|string:0" name="weight"><br>
+<input type="submit">
+</form>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGFeature_template_intro.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html metal:use-macro="here/main_template/macros/page">
+ <tal:block metal:fill-slot="body">
+    <!-- Insert here the main text -->
+
+
+    
+    <!-- Don't change from here -->
+  </tal:block>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGFeature_template_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html metal:use-macro="here/main_template/macros/page">
+ <tal:block metal:fill-slot="body">
+    <!-- Insert here the main text -->
+
+
+    
+    <!-- Don't change from here -->
+  </tal:block>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGFolderChangeWeight.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,7 @@
+<html>
+<h2>Change Weight</h2>
+<form action="changeWeight" method="pro">
+<input tal:attributes="value here/weight|string:0" name="weight"><br>
+<input type="submit">
+</form>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGFolderConfig.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,9 @@
+<html>
+<h2>Change MPIWG Folder</h2>
+<form action="changeMPIWGFolder" method="pro">
+Title: <input tal:attributes="value here/title|nothing" name="title"><br>
+Weight: <input tal:attributes="value here/weight|string:0" name="weight"><br>
+CanonicalName: <input tal:attributes="value here/canonicalName|nothing" name="canonicalName"><br>
+<input type="submit">
+</form>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGLinkChange.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,11 @@
+<html>
+<body>
+<h2>Change MPIWG Link</h2>
+<form action="changeLink" method="post">
+<p>Title:<input name="title" tal:attributes="value here/title" size="100"></p>
+<p>Link:<input name="link" tal:attributes="value here/link" size="100"></p>
+<p>Weight:<input name="weight" tal:attributes="value here/weight" size="100"></p>
+<p><input type="submit"></p>
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGNamesForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,20 @@
+<html>
+<head>
+   <title>The title</title>
+</head>
+<body>
+
+<div>
+
+<h1>Upload list of Names</h1>
+<p>Komma separated list: email,lastname,firstname</p>
+<form method="post" action="importNames" enctype="multipart/form-data">
+<p>Folder</p>
+<input name="folderName">
+<p>File:</p>
+<input type="file" name="fileupload"/>
+<input type="submit">
+</form>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGProject_index.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,13 @@
+<html>
+<body>
+<table border="1">
+<tr tal:repeat="field here/getDefinedFields">
+<td valign="top" tal:content="field"/>
+<!--<td tal:repeat="attr python:here.getAttribute(field)" tal:content="structure python:attr.encode('ascii','ignore')"/>-->
+<td tal:repeat="attr python:here.getAttribute(field)" tal:content="structure python:attr"/>
+</tr>
+</table>
+</body>
+</html>
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGProject_manageImagesForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,44 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:images" />
+<tal:block metal:fill-slot="body">
+  <table tal:condition="python:here.getImages()">
+    <tr><th/><th>Image</th><th>Caption</th><th/></tr>
+    <tal:block tal:repeat="image here/getImages">
+      <tr>
+        <td>
+          <a tal:attributes="href python:here.absolute_url()+'/manageImages?imageName='+image[0]+'&op=up'">up</a><br>
+          <a tal:attributes="href python:here.absolute_url()+'/manageImages?imageName='+image[0]+'&op=down'">down</a>
+        </td>
+        <td tal:condition="not:python:image[1].height==''" tal:content="structure python:image[1].tag(scale=250.0 / image[1].height)" />
+	<td tal:condition="python:image[1].height==''" tal:content="python:image[1].height"/>
+        <td tal:content="structure python:getattr(image[1],'caption','')" />
+        <td>
+          <a tal:attributes="href python:image[1].getId()+'/editImage'">Edit</a><br/>
+          <a tal:attributes="href python:'deleteImage?id='+image[1].getId()">Delete</a>
+        </td>
+      </tr>
+    </tal:block>
+  </table>
+  
+  <h3>Add an Image</h3>
+  
+  <form action="addImage" method="post" enctype="multipart/form-data">
+  <table>
+    <tr><th>Image</th><th>Caption</th></tr>
+    <tr>
+      <td><input name="fileHd" type="file" len="50"/></td>
+      <td><textarea name="caption" rows="3" cols="60"></textarea></td>
+    </tr>
+  </table>
+  <p><input type="submit" value="submit"/></p>
+  </form>
+  
+  <p>(if the marginal image from your current project description is not occuring in this list, click <a href="copyImageToMargin">here</a>.)</p>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGProject_managePublicationsForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:publications" />
+<tal:block metal:fill-slot="body">
+  <table>
+    <tal:block tal:repeat="publication here/getPublications">
+      <tr>
+        <td>
+          <a tal:attributes="href python:here.absolute_url()+'/managePublications?pubName='+publication[0]+'&op=up'">up</a><br>
+          <a tal:attributes="href python:here.absolute_url()+'/managePublications?pubName='+publication[0]+'&op=down'">down</a>
+        </td>
+        <td tal:content="structure python:getattr(publication[1],'text','')" />
+        <td>
+          <a tal:attributes="href python:publication[1].getId()+'/editPublication'">Edit</a><br/> 
+          <a tal:attributes="href python:'deletePublication?id='+publication[1].getId()">Delete</a>
+        </td>
+      </tr>
+    </tal:block>
+  </table>
+
+  <h3>Add a publication</h3>
+  <form action="addPublication" method="post">
+    <textarea name="text" rows="3" cols="80"></textarea>
+    <p><input type="submit" value="submit"/></p>
+  </form>
+  <p>(If the publications from your current project description are not showing in this list, click <a href="copyPublicationsToList">here</a> to copy them.)</p>
+<h3><tal:x condition="python:here.hasExtendedPublicationList()">
+		<a href="publicationList/editEntries">
+		Manage Extended Publication List</a>
+		</tal:x>
+		<tal:x condition="not:python:here.hasExtendedPublicationList()">
+		<a href="createExtendedPublicationList">
+		Create Extended Publication List</a>
+		</tal:x>
+</h3>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGProject_manageRelatedProjectsForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,35 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:relatedProjects" />
+<tal:block metal:fill-slot="body">
+  <table>
+    <tal:block tal:repeat="publication here/getRelatedProjects">
+      <tr>
+        <td>
+          <a tal:attributes="href python:here.absolute_url()+'/manageRelatedProjects?pubName='+publication[0]+'&op=up'">up</a><br>
+          <a tal:attributes="href python:here.absolute_url()+'/manageRelatedProjects?pubName='+publication[0]+'&op=down'">down</a>
+        </td>
+        <td tal:content="structure python:getattr(publication[1],'objid','')" />
+        <td tal:content="structure python:getattr(publication[1],'projectWEB_title','')" />
+        <td>
+          <a tal:attributes="href python:publication[1].getId()+'/editRelatedProject'">Edit</a><br/> 
+          <a tal:attributes="href python:'deleteRelatedProject?id='+publication[1].getId()">Delete</a>
+        </td>
+      </tr>
+    </tal:block>
+  </table>
+
+  <h3>Add related projects</h3>
+  <p>Please add the link to the project you want to add a relation to.</p>
+  <form action="addRelatedProject" method="post">
+    <input name="link" size="100">
+    <p><input type="submit" value="submit"/></p>
+  </form>
+ 
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGProject_newfile.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,18 @@
+<html>
+<head>
+   <title>The title</title>
+</head>
+<body>
+
+<div>
+
+<h1>Project-Upload</h1>
+<form method="post" action="loadNewFile" enctype="multipart/form-data">
+
+<p>File:</p>
+<input type="file" name="fileupload"/>
+<input type="submit">
+</form>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGProject_versionManageForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,5 @@
+<h1>Set invisible</h1>
+<form action="versionManage">
+<input type="checkbox" name="invisible">Invisible<br/>
+<input type="submit" value="submit">
+</form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWGTemplateChangeWeight.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,7 @@
+<html>
+<h2>Change Weight</h2>
+<form action="changeWeight" method="pro">
+<input tal:attributes="value here/weight|string:0" name="weight"><br>
+<input type="submit">
+</form>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/MPIWG_standardPage_template_standard.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html metal:use-macro="here/main_template/macros/page">
+ <tal:block metal:fill-slot="body">
+    <!-- Insert here the main text -->
+
+
+    
+    <!-- Don't change from here -->
+  </tal:block>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/addMPIWGProjectForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,19 @@
+<html>
+<head>
+   <title>The title</title>
+</head>
+<body>
+
+<div>
+
+<h1>Project-Upload</h1>
+<form method="post" action="manage_addMPIWGProject" enctype="multipart/form-data">
+<p>ID:</p>
+<input name="id">
+<p>File:</p>
+<input type="file" name="fileupload"/>
+<input type="submit">
+</form>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/addMPIWGRootForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,35 @@
+<html>
+<head>
+   <title>The title</title>
+</head>
+<body>
+
+<div>
+
+<h1>Project-Upload</h1>
+<form method="post" action="manage_addMPIWGRoot">
+<p>ID:</p>
+<input name="id">
+<p>Title:</p>
+<input name="title"/>
+<p>Discipline list (seperated by CR)
+<textarea name="disciplineList" cols=50 rows=20></textarea>
+</p>
+<p>Themes List (seperated by CR)
+<textarea name="themesList" cols=50 rows=20></textarea>
+</p>
+<!--<div class="form-element">
+    
+    <select name="connection_id">
+     
+     <tal:block tal:repeat="id python:here.SQLConnectionIDs()">
+                <option  tal:condition="python:getattr(here,'connection_id','')==id"  tal:attributes="value id" selected tal:content="id"/>
+                <option  tal:condition="not:python:getattr(here,'connection_id','')==id"  tal:attributes="value id" tal:content="id"/>
+            </tal:block>
+    </select>
+</div>-->
+<input type="submit">
+</form>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/addMPIWGStaffForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,22 @@
+<html>
+<head>
+   <title>The title</title>
+</head>
+<body>
+
+<div>
+
+<h1>Add a staff member</h1>
+<form method="post" action="manage_addMPIWGStaff">
+<p>ID = emailname
+<input name="id"></p>
+<p>LastName:
+<input name="lastName"/></p>
+<p>FirstName:
+<input name="firstName"/></p>
+
+<input type="submit">
+</form>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/addPublications.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:publications" />
+
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+
+  <h3>Add entries from the <i>Institutsbibliographie</i></h3>
+  <p>On this page you can search the Institutsbibliographie for your publications and add them to the list of publications that appears on your staff-page.</p>
+  <form name="search" action="addPublications" method="get">
+  <table>
+    <tr>
+      <td>Author</td>
+      <td tal:content="structure python:here.ZSQLsearchOptions(fieldname='author')" />
+      <td><input name="author" len="30"></td>
+    </tr>
+    <tr>
+      <td>Title</td>
+      <td tal:content="structure python:here.ZSQLsearchOptions(fieldname='title')" />
+      <td><input name="title" len="30"></td>
+    </tr>
+  </table>
+  <input type="submit" value="search">
+  </form>
+  <form name="add" action="addPublications" method="get">
+  <input type="hidden" value="add" name="mode">
+  <tal:block tal:condition="python:here.REQUEST.get('fromSearch','0')=='1'">
+    <table>
+      <tr tal:repeat="foundb python:here.ZSQLFind(_table='institutsbiblio')">
+        <td><input type="checkbox" tal:attributes="value python:str(foundb.id)" name="addEntries"></td>
+        <td tal:content="structure python:here.decode(here.formatBiblHelp(None,'','',foundb))" />
+      </tr>
+    </table>
+    <input type="submit" value="add" name="submit">
+  </tal:block>
+  </form>
+  <!-- <h3><a href="newBibliography">Add a separate entry</a></h3> -->
+  <h3><a href="editPublications">Back to publication list</a></h3>
+</tal:block>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/addPublicationsBib.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,21 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:publications" />
+
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+
+  <h3>Add Publications</h3>
+  <p> There are two ways to add publications to your list. </p>
+  <ol> 
+    <li> Publications that were created and released at the MPIWG are stored in a database, the <u>Instituts-Bibliographie</u>.<br/> In 
+         that case you can <b>search for and add them</b> <a href="addPublications"><img src="images/arr_right.gif" border="0"/> here</a>. </li>
+    <li> If you want to add publications that <u>have not been released at the MPIWG</u>,<br/> you may need to <b>add separate entries</b> 
+         <a href="newBibliography"><img src="images/arr_right.gif" border="0"/> here</a>.</li>
+  </ol>
+  <!-- <h3><a href="newBibliography">Add a separate entry</a></h3> -->
+  <h3><a href="editPublications">Back to publication list</a></h3>
+</tal:block>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/bibliography.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,55 @@
+<tal:block tal:condition="not:python=here.ZSQLisEmpty(found.id_institutsbibliographie)" 
+	   tal:define="foundIB python:ZSQLInlineSearch(_table='institutsbiblio',id=found.id_institutsbibliographie)[0]">
+
+  <tal:block tal:condition="python:foundIB.reference_type.lower()=='journal article'">
+    <span tal:replace="foundIB/author_semi_colon"/>&quot;<span tal:replace="foundIB/title"/>&quot;
+    <i><span tal:replace="foundIB/secondary_title"/></i>
+    <span tal:replace="foundIB/volume"/>&quot;
+    (<span tal:condition
+
+ret=""
+if not found.id_institutsbibliographie=='':
+    foundIB=here.ZSQLInlineSearch(_table='institutsbiblio',id=found.id_institutsbibliographie)[0]
+    if foundIB.reference_type.lower()=='journal article':
+        ret+=foundIB.author_semi_colon+"&quot;"+foundIB.title+"&quot;"+"<i>%s</i>"%foundIB.secondary_title+foundIB.volume+"&quot;("
+        if not foundIB.number=='':
+            ret+=foundIB.number+"&nbsp;"
+        ret+=foundIB.year+")"
+        if not foundIB.pages=='':
+            ret+=": "+foundIB.pages+"."
+        
+        
+<!--
+[FMP-Field: Author_semi_colon]. &quot;[FMP-Field: Title].&quot <i>[FMP-Field: Secondary Title]</i> [FMP-Field: Volume] ([FMP-If: Number.neq.][FMP-Field: Number] [/FMP-If][FMP-Field: year])[FMP-If: pages.neq.]: [FMP-Field: pages][/FMP-IF]. 
+[FMP-elseif: Reference Type.eq.Edited Book]
+[FMP-Field: Author_semi_colon] (Editor/s). <i>[FMP-Field: Title]</i>. [FMP-If: Place Published.neq.][FMP-Field: Place Published]: [/FMP-if][FMP-if: publisher.neq.][FMP-Field: Publisher], [/FMP-If][FMP-Field: year].
+[FMP-elseif: Reference Type.eq.Book Section]
+[FMP-Field: Author_semi_colon]. &quot;[FMP-Field: Title].&quot In <i>[FMP-Field: Secondary Title]</i>[FMP-If: Secondary_Author_semi_colon.neq.], eds.: [FMP-Field: Secondary_Author_semi_colon][/FMP-if]. [FMP-If: Pages.neq.][FMP-Field: Pages].[/FMP-If][FMP-If: Place Published.neq.][FMP-Field: Place Published][/FMP-IF][FMP-If: Publisher.neq.]: [FMP-Field: Publisher],[/FMP-If] [FMP-Field: Year].
+[FMP-elseif: Reference Type.eq.Book]
+[FMP-Field: Author_semi_colon]. <i>[FMP-Field: Title]</i>. [FMP-Field: Place Published]: [FMP-Field: Publisher], [FMP-Field: year].
+[FMP-elseif: Reference Type.eq.Newspaper Article]
+[FMP-Field: Author_semi_colon]. &quot;[FMP-Field: Title].&quot <i>[FMP-Field: Secondary Title]</i>, [FMP-Field: Date].[FMP-Field: Year], [FMP-Field: Pages].
+[/FMP-if]
+[/FMP-InlineAction]
+
+
+
+
+[FMP-else]
+
+
+[FMP-InlineAction: -db=bibliography, ID="{Field: ID_gen_bib}", -find]
+[FMP-IF: Reference Type.eq.Journal Article] 
+[FMP-Field: Author_semi_colon]. &quot;[FMP-Field: Title].&quot <i>[FMP-Field: Secondary Title]</i> [FMP-Field: Volume] ([FMP-If: Number.neq.][FMP-Field: Number] [/FMP-If][FMP-Field: year])[FMP-If: Pages.neq.]: [FMP-Field: Pages][/FMP-IF]. 
+[FMP-else][FMP-IF: Reference Type.eq.Edited Book]
+[FMP-Field: Author_semi_colon] (Editor/s). <i>[FMP-Field: Title]</i>. [FMP-If: Place Published.neq.][FMP-Field: Place Published]: [/FMP-if][FMP-if: publisher.neq.][FMP-Field: Publisher], [/FMP-If][FMP-Field: year].
+[FMP-else][FMP-IF: Reference Type.eq.Book Section]
+[FMP-Field: Author_semi_colon]. &quot;[FMP-Field: Title].&quot In <i>[FMP-Field: Secondary Title]</i>[FMP-If: Secondary_Author_semi_colon.neq.], eds.: [FMP-Field: Secondary_Author_semi_colon][/FMP-if]. [FMP-If: Pages.neq.][FMP-Field: Pages].[/FMP-If][FMP-If: Place Published.neq.][FMP-Field: Place Published][/FMP-IF][FMP-If: Publisher.neq.]: [FMP-Field: Publisher],[/FMP-If] [FMP-Field: Year].
+[FMP-else][FMP-IF: Reference Type.eq.Book]
+[FMP-Field: Author_semi_colon]. <i>[FMP-Field: Title]</i>. [FMP-Field: Place Published]: [FMP-Field: Publisher], [FMP-Field: year].
+[FMP-else][FMP-IF: Reference Type.eq.Newspaper Article]
+[FMP-Field: Author_semi_colon]. &quot;[FMP-Field: Title].&quot <i>[FMP-Field: Secondary Title]</i>, [FMP-Field: Date].[FMP-Field: Year], [FMP-Field: Pages].
+[/FMP-if][/FMP-if][/FMP-if][/FMP-if][/FMP-if]
+[/FMP-InlineAction]
+[/FMP-IF] 
+-->
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/changeMPIWGRootForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,58 @@
+<html>
+<head>
+   <title>The title</title>
+</head>
+<body>
+
+<div>
+
+<h1>Change MPIWGRoot</h1>
+<form method="post" action="changeMPIWGRoot">
+
+<p>Title:<br/>
+<input tal:attributes="value python:getattr(here,'title','')" name="title"/>
+</p>
+<p>Default language:<br/>
+<input tal:attributes="value python:getattr(here,'lang','en')" name="lang"/>
+</p>
+
+<p>Cone Service URL:<br/>
+<input size="100" tal:attributes="value python:getattr(here,'coneServiceURL','http://virtuoso.mpiwg-berlin.mpg.de:8080/MetaDataManagerRestlet/cone/')" name="coneServiceURL"/>
+</p>
+<p>Harvester ZEO server:<br/>
+<input tal:attributes="value python:here.getHarvestCacheServer()" name="harvestServer"/>
+</p>
+<p>Harvester ZEO server port:<br/>
+<input tal:attributes="value python:here.getHarvestCachePort()" name="harvestPort"/>
+</p>
+<!--
+<p>Discipline list (seperated by CR)<br>
+<textarea name="disciplineList" cols=50 rows=20  tal:content="python:getattr(here,'disciplineList','')" ></textarea>
+</p>
+<p>Themes List (seperated by CR)<br>
+<textarea name="themesList" cols=50 rows=20 tal:content="python:getattr(here,'themesList','')"></textarea>
+</p>
+-->
+
+
+<p>
+<div class="form-element">
+    
+    <select name="connection_id">
+     
+     <tal:block tal:repeat="id python:here.SQLConnectionIDs()[0]">
+                <option  tal:condition="python:getattr(here,'connection_id','')==id"  tal:attributes="value id" selected tal:content="id"/>
+                <option  tal:condition="not:python:getattr(here,'connection_id','')==id"  tal:attributes="value id" tal:content="id"/>
+            </tal:block>
+    </select>
+    </div>
+
+    <p class="form-label">Autocommit</p>
+    <p>
+      <input type="checkbox" name="autocommit" tal:attributes="checked here/autocommit | nothing"/> autocommit (don't use when you want transactions)
+    </p>
+<input type="submit">
+</form>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/changePublications_special.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,11 @@
+<html>
+<body>
+<h2>Change free text field publication overview for front page</h2>
+<form action="changePublications_special" method="post">
+<input type="checkbox" name="usePublicationsSpecial" value="1">Use free text field<br>
+<textarea name="specialPublicationsField" cols="80" rows="40" tal:content="python:getattr(here,'specialPublicationsField','')"></textarea>
+<br>
+<input type="submit" value="submit">
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editAdditionalLinks.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,72 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:additionalLink" />
+<p>You can add links to documents or project websites you want to provide and are relevant for
+presenting your work and research interests</p>
+
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+  <form action="changeResearch" method="post">
+  <input type="hidden" name="key_main" tal:attributes="value python:here.decode(person.key)">
+  <input type="hidden" name="main_fields" value="additionalLink__title">
+  <table tal:define="founds2 python:here.ZSQLInlineSearch(_table='additionalLink',key_main=person.key)" >
+   <tal:x tal:repeat="found2 python:here.sortPriority(founds2)">
+    <tr class="fliesstext">
+      <td>Text over Link</td>
+      <td><input tal:attributes="name python:'additionalLink__title__'+str(found2.oid); 
+				     value python:here.decode(found2.title)" size="80" /> </td>
+	</tr>
+	<tr>
+		<td>Url</td>
+     	<td><input tal:attributes="name python:'additionalLink__link__'+str(found2.oid); 
+				     value python:here.decode(found2.link)" size="80" /></td>
+	</tr>
+	<tr>
+      <td valign="top">Priority <input tal:attributes="name python:'additionalLink__priority__'+str(found2.oid);
+				     value python:here.decode(found2.priority)"
+        size="3" />
+      </td>
+      <td valign="top">Publish 
+        <tal:x tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'additionalLink__published__'+str(found2.oid),
+			     yes_no_list,
+			     boxType='radio',
+			     checked=found2.published)" />
+      &nbsp;&nbsp;<a tal:attributes="href python:'deleteField?table=additionalLink&oid=%s'%found2.oid">delete this link</a>
+      </td>
+    </tr>
+    <tr>
+    	<td colspan="2"><hr/></td>
+   	</tr>
+    </tal:x>
+    <tr >
+      <td colspan="2"><b>Add new link</b></td>
+    </tr>
+    <tr>
+   		<td>Text over Link</td>
+   		<td><input tal:attributes="name python:'additionalLink__title__new'" size="80"/></td>
+    </tr>
+    <tr>
+    	<td>Url</td>
+     	<td><input tal:attributes="name python:'additionalLink__link__new'" size="80" /></td>
+    </tr>
+    <tr>
+      <td>Priority <input tal:attributes="name python:'additionalLink__priority__new'" size="3"></td>
+      <td valign="top">Publish
+        <tal:x tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'additionalLink__published__new',
+			     yes_no_list,
+			     boxType='radio',
+			     checked='yes')" />
+			     </td>
+    </tr>
+  </table>
+  <input type="submit" value="submit">
+
+  </form>
+  <p>Please contact the IT Group <a href="mailto:itgroup@mpiwg-berlin.mpg.de">itgroup@mpiwg-berlin.mpg.de</a>, if you intend
+  to link to documents not available in the net and if you want to publish these.</p>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editAwards.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,17 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+  <tal:block metal:fill-slot="navsel" tal:define="global menusel string:awards"/>
+
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+
+<form action="editAwards" method="post">
+<input type="hidden" name="oid" tal:attributes="value person/oid">
+<textarea name="awards" tal:content="python:person.awards" cols=80 rows=10>
+</textarea>
+<br>
+<input type="submit" value="submit">
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editBibliographyEntry.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:publications" />
+<tal:block metal:fill-slot="body">
+<tal:block
+    tal:define="found python:here.ZSQLInlineSearchU(_table='bibliography',id=here.REQUEST['id']);
+        mapping python:here.metadata.main.meta.bib.generateMappingForType(type=found.reference_type)">
+
+  <h3>Edit a separate publication</h3>
+
+    <form action="ZSQLChange" method="get">
+    <input type="hidden" name="-format" value="editPublications">
+    <input type="hidden" name="-identify" tal:attributes="value python:'oid='+str(found.oid)">
+    <input type="hidden" name="-table" value="bibliography">
+    <table>
+      <tal:block tal:repeat="mapElement python:mapping.keys()">
+        <tr tal:condition="python:mapping[mapElement][1]!=''">
+          <td tal:content="python:mapping[mapElement][1].encode('utf-8')"/>
+          <td><input size="80" tal:attributes="value python:getattr(found,mapElement); name mapElement" />
+        </tr>
+      </tal:block>
+    </table>
+    <input type="submit" value="change" />
+    </form>
+
+    <h3><a href="editPublications">Back to publication list</a></h3>
+
+  </tal:block>
+  </tal:block>
+</body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editCV.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+  <tal:block metal:fill-slot="navsel" tal:define="global menusel string:cv"/>
+
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+<form action="editCV" method="post">
+<input type="hidden" name="oid" tal:attributes="value person/oid">
+<textarea name="cv" tal:content="python:person.cv" cols=80 rows=10>
+</textarea>
+<br>
+<input type="submit" value="submit">
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editDownloads.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:downloads" />
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+<p>Here you can upload your CV and and publication list to be downloaded from your homepage.</p>
+<p>The documents should be in <b>PDF format</b>. Add the add bottom of this page you find <a href="#templates">templates</a> for OpenOffice and
+Word to make it easier for you to create these documents.</p>
+<form action="changeDownloads" method="post" enctype="multipart/form-data">
+<h2>Your CV</h2>
+<p><input type="file" name="cv_pdf"/></p>
+<p>Remember that documents should be in <b>PDF format</b>. <br/><input type="submit" value="Upload the file"/></p>
+<p><a href="downloadCV">Download the CV currently stored at the server.</a> (last update:<span tal:content="here/getLastUpdateCV"/>)</p>
+<p>publish: <tal:x tal:content="structure python:here.ZSQLSelectionFromCRList(
+           'cv_publish',
+           yes_no_list,
+           boxType='radio',
+           checked=getattr(here,'cv_publish','no'))" /></p>
+
+<h2>Publication list</h2>
+<p><input type="file" name="publications_pdf"/></p>
+<p>Remember that documents should be in <b>PDF format</b>. <br/><input type="submit" value="Upload the file"/></p>
+<p><a href="downloadPublications">Download the publicaton list currently stored at the server. </a>(last update:<span tal:content="here/getLastUpdatePublications"/>)</p>
+<p>publish: <tal:x tal:content="structure python:here.ZSQLSelectionFromCRList(
+           'publications_publish',
+           yes_no_list,
+           boxType='radio',
+           checked=getattr(here,'publications_publish','no'))" /></p>
+
+<p><input type="submit" value="Update"/></p>
+
+</form>
+<br/> <br/>
+<a name="templates"/><h3>Download Templates:</h3>
+<ul>
+  <li>For OpenOffice Writer:
+    <ul>
+      <li><a href="downloads/publications_template.ott">Publication List</a> </li>
+	  <li><a href="downloads/CV_template.ott">CV</a></li>
+    </ul>	
+  </li>
+  <li>For Ms Word:
+    <ul>
+	 <li><a href="downloads/Vorlage_Publikation.dot">Publication List</a></li>
+	 <li><a href="downloads/Beispiel_CV.doc">CV</a></li>
+    </ul>
+  </li>
+</ul>
+</tal:block>
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editHistoricalNames.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,43 @@
+<h2> Edit historical names </h2>
+
+<tal:block tal:define="names here/nameIndexEdited/keys; dummy python:names.sort()">
+<table>
+   <tal:x tal:repeat="name names">
+	<form action="editNameIndex" method="post">
+   	<tr>
+         <td tal:content="name">NAME</td>
+         <td>
+         	<input type="hidden" name="name" tal:attributes="value name">
+         	<textarea cols=50 rows=5 name="occurrances" tal:content="python:'\n'.join(here.nameIndexEdited[name])">OCCURENCES</textarea>
+         </td>
+         <td>
+         	<a target="names" tal:attributes="href python:'misc/search/namesMentioned?name=%s'%name">Show occurances</a>
+         </td>
+         <td>
+         	<input type="submit" value="delete" name="submit">
+         	<input type="submit" value="change" name="submit">
+         <tr>
+    </tr>	
+    </form>
+   </tal:x>
+   </table>
+   <h2>Add name</h2>
+   <table>
+   <form action="editNameIndex" method="post">
+   <tr>
+         <td><input name="name" size=50>
+         </td>
+         <td>
+         	<textarea cols=50 rows=5 name="occurrances"></textarea>
+         </td>
+         
+         <td>
+         	<input type="submit" value="add" name="submit">
+         	
+         <tr>
+    </tr>	
+   </form>
+   </table>
+   
+    <!-- Don't change from here -->
+  </tal:block>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editImageStaff.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,29 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+  <tal:block metal:fill-slot="navsel" tal:define="global menusel string:image"/>
+
+  <tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+ <form action="updateImage" method="post" enctype="multipart/form-data">
+  	<p>Show this photo on the homepage: <span tal:replace="structure python:here.ZSQLSelectionFromCRList(
+			     'publishImage',
+			     yes_no_list,
+			     boxType='radio',
+			     checked=here.getPublishImage())"/>
+  	</p>
+    <p>
+    <span tal:condition="here/getImageObj" tal:replace="structure python:here.getImageObj().thumb()"/></p>	
+
+<!-- 
+    <p>Filename:<input type="file" name="file" size="30"></p>
+    <p>Images should not be too big. Allowed formats: JPEG, TIFF or PNG. Files must have proper extension *.jpg, *.tif or *.png.</p>
+-->    
+    <p>Please contact the IT-support (support@mpiwg-berlin.mpg.de) to upload a picture for you.</p>
+    
+    <input type="submit"/>
+  </form>
+    
+ </tal:block>
+ </body>
+ </html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editMPIWGStaff.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,42 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:research" />
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+
+  <form action="changeCurrentWork" method="post">
+  <input type="hidden" name="key" tal:attributes="value person/key"/>
+   <h3>Short entry</h3>
+  <p>This entry appears only in the staff lists at: <a href="../staff/fullist.html">Fullist</a> and the
+  lists of members of you department</p>
+  <table tal:define="found2 python:person">
+    <tr>
+      <th />
+      <th>Show</th>
+    </tr>
+    <tr class="fliesstext">
+      <td><input tal:attributes="name python:'current_work';
+				     value python:here.decode(found2.current_work)" size="80" />
+      </td>
+      <td
+        tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'publish',
+			     yes_no_list,
+			     boxType='radio',
+			     checked=found2.current_work_p)" />
+    </tr>
+  </table>
+  <input type="submit" value="submit"/>
+ 
+  <h3>Research interests</h3>
+  <p>This entry isn't displayed anymore, please describe your research interests in your <a href="editProfile">Profile</a></p>
+
+  </form>
+  <h3>Projects</h3>
+  <p>Projects cannot be edited from this pages. Entries are automatically generated.</p>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editMPIWGStaff_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:define-macro="page">
+<head>
+  <tal:block tal:define="global person python:here.ZSQLInlineSearchU(_table='personal_www',key=here.getKeyUTF8())"/>
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <link rel="stylesheet" href="editstaff.css" type="text/css"/>  
+  <metal:x metal:define-slot="javascript"/>
+</head>
+<body onload="kupu = startKupu();">
+  <h2 class="title">Edit homepage of <span tal:replace="python:here.decode(person.first_name)"/> <span tal:replace="python:here.decode(person.last_name)"/></h2>
+  <metal:block metal:define-slot="navsel"/>
+   <p>Please contact the support group <a href="mailto:support@mpiwg-berlin.mpg.de">support@mpiwg-berlin.mpg.de (Tel. 247)</a>, if you need any help.</p>
+  
+  <div class="mainnav">
+    <span tal:attributes="class python:here.getPathStyle('maindata', menusel, 'mainmenu')"><a href="editMainData">Contact</a></span>
+    <span tal:attributes="class python:here.getPathStyle('cv', menusel, 'mainmenu')"><a href="editProfile">Profile</a></span>
+    <span tal:attributes="class python:here.getPathStyle('publications', menusel, 'mainmenu')"><a href="editPublications">Publications</a></span>
+    <span tal:attributes="class python:here.getPathStyle('research', menusel, 'mainmenu')"><a href="edit">Research: short entry</a></span>
+    <span tal:attributes="class python:here.getPathStyle('image', menusel, 'mainmenu')"><a href="editImage">Photo</a></span>
+    <span tal:attributes="class python:here.getPathStyle('downloads', menusel, 'mainmenu')"><a href="editDownloads">Edit 
+downloads</a></span>
+    <!--  <span tal:attributes="class python:here.getPathStyle('cv', menusel, 'mainmenu')"><a href="editCV">Curriculum Vitae</a></span>-->
+    
+    <!--  <span tal:attributes="class python:here.getPathStyle('awards', menusel, 'mainmenu')"><a href="editAwards">Awards</a></span>-->
+    <span tal:attributes="class python:here.getPathStyle('talks', menusel, 'mainmenu')"><a href="editTalks">Talks</a></span>
+    <span tal:attributes="class python:here.getPathStyle('teaching', menusel, 'mainmenu')"><a href="editTeaching">Teaching</a></span>
+    <span tal:attributes="class python:here.getPathStyle('additionalLink', menusel, 'mainmenu')"><a href="editAdditionalLinks">Additional links</a></span>
+ 
+    
+    
+    <span class="mainmenu"><a tal:attributes="href python:'http://www.mpiwg-berlin.mpg.de/en/staff/members/'+here.getId()+'/index_html'" target="_blank">View</a></span>
+  </div>
+  <div class="content">
+  <tal:block metal:define-slot="body"/>
+   </div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editMainData.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,103 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+  <tal:block metal:fill-slot="navsel" tal:define="global menusel string:maindata"/>
+  <tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno';
+  global person python:here.ZSQLInlineSearchU(_table='personal_www',key=here.getKeyUTF8())"
+  >
+  <form action="editMainData" method="get">
+  <table>
+  	<tr>
+  		<td><b>Name</b></td>
+  		<td><input size="30" tal:attributes="value python:here.unicodify(person.last_name)" name="last_name"></td>
+  	</tr>
+  	<tr>
+  		<td><b>First Name</b></td>
+  		<td><input size="30" tal:attributes="value python:here.decode(person.first_name)" name="first_name"></td>
+  	</tr>
+  	<tr>
+  	 	<td><b>Academic degrees and position</b></td>
+  		<td><textarea  tal:content="python:here.decode(person.titles_new)" name="titles_new" cols="60" rows="3"/></td>
+  	</tr>
+  	<tr>
+  		<td><b>Status</b></td>
+  		<td tal:content="python:here.decode(person.status)"/>
+  	</tr>
+  	<tr>
+  		<td><b>Department</b></td>
+  		<td tal:content="python:here.decode(person.department)"/>
+  	</tr>
+  	<tr>
+  		<td><b>Stay</b></td>
+  		<td><span tal:content="python:here.decode(person.date_from)"/> to
+  		  <span tal:content="python:here.decode(person.date_to)"/>
+  		</td>
+  	<tr>
+  		<td><b>Funded by (external funding)</b></td>
+  		<td><input size="30" tal:attributes="value python:here.decode(person.funded_by)" name="funded_by"></td>
+  	</tr>
+  	
+<!--  	<tr>
+  	 	<td><b>Home institution</b></td>
+  		<td><input size="30" tal:attributes="value python:here.decode(person.home_inst)" name="home_inst"></td>
+  	</tr>-->
+ </table>
+ <table>
+    <tr><th></th><th></th><th align="left">show</th></tr>
+ 	<tr>
+ 		<td><b>email (MPIWG)</b></td>
+ 		<td tal:content="python:here.decode(person.e_mail)"/>
+ 		<td valign="top" tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'e_mail_p',
+			     yes_no_list,
+			     boxType='radio',
+			     checked=person.e_mail_p)"/>
+ 	</tr>
+ 	<tr>
+ 		<td><b>email (additional)</b></td>
+ 		<td><input size="30" name="e_mail2" tal:attributes="value python:here.decode(person.e_mail2)"></td>
+ 		<td valign="top" tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'e_mail2_p',
+			     yes_no_list,
+			     boxType='radio',
+			     checked=person.e_mail2_p)"/>
+ 	</tr>
+ 	<tr>
+ 		<td><b>Room</b></td>
+ 		<td><input size="30" name="room_no" tal:attributes="value python:here.decode(person.room_no)"></td>
+ 		<td>(never published)</td>
+ 	</tr>
+ 	
+<!-- 	<tr>
+ 		<td><b>Private homepage</b></td>
+ 		<td><input size="30" name="private_homepage" tal:attributes="value python:here.decode(person.private_homepage)"></td>
+ 		<td>&nbsp;</td>
+ 	</tr>
+ -->	
+ 	<tr>
+ 		<td><b>Telephone</b></td>
+ 		<td><input size="30" name="telefon" tal:attributes="value python:here.decode(person.telefon)"></td>
+ 		<td valign="top" tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'telefon_p',
+			     yes_no_list,
+			     boxType='radio',
+			     checked=person.telefon_p)"/>
+ 	</tr>
+ 	<tr>
+ 		<td><b>Fax</b></td>
+ 		<td><input size="30" name="fax" tal:attributes="value python:here.decode(person.fax)"></td>
+ 		<td valign="top" tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'fax_p',
+			     yes_no_list,
+			     boxType='radio',
+			     checked=person.fax_p)"/>
+ 	</tr>
+ </table>
+ <input type="submit" value="submit">
+ </form>
+ <p>To add references to your homepage at other institutions plese use <a href="editAdditionalLinks">the additional links tab</a></p>
+ </tal:block>
+ </body>
+ </html>
+ 
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editProfile.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,83 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<metal:x metal:fill-slot="javascript">
+<metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" use-macro="here/kupuEditor/kupumacros/macros/head">
+  <metal:macros fill-slot="bootstrap-editor">
+    <script type="text/javascript" src="/kupuEditor/kupuinit_form.js"> </script>
+    <script type="text/javascript" src="/kupuEditor/kupustart_form.js"> </script>
+  </metal:macros>
+</metal:macros>
+</metal:x>
+<body>
+  <tal:block metal:fill-slot="navsel" tal:define="global menusel string:cv"/>
+
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+<form action="editProfile" method="post">
+<input type="hidden" name="oid" tal:attributes="value person/oid">
+<tal:x condition="python:(person.profile is None) | (person.profile=='')">
+<p>You haven't edited your profile yet, this entry is  generated automatically from you old CV entry, your current work entry, and research interests entry from you old profile! </p>
+	
+</tal:x>
+
+
+
+    <div><span class="kupu-tb-buttongroup">
+	<button type="button" id="kupu-preview-button" title="preview: alt-p" accesskey="p">Preview</button>
+      </span>
+      <span class="kupu-tb-buttongroup">
+	<button type="button" id="kupu-save-button" title="save: alt-s" accesskey="s">Publish</button>
+      </span>
+    </div>
+  <metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" use-macro="here/kupuEditor/kupumacros/macros/xmlconfig">
+    <metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" fill-slot="dst">saveEditedContent</metal:macros>
+  </metal:macros>
+  <metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" use-macro="here/kupuEditor/kupumacros/macros/fulleditor">
+       
+    <!--  <metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" fill-slot="tb_select_styles">
+       <span id="kupu-tb-styles"/>
+     </metal:macros>
+      <metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" fill-slot="buttongroup_subsuper">
+       <span id="kupu-bg-subsuper"/>
+       <span id="kupu-subscript-button"/>
+       <span id="kupu-superscript-button"/>
+       </metal:macros>
+       
+       <metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" fill-slot="buttongroup_justify">
+       <span id="kupu-justifyleft-button"/>
+       <span id="kupu-justifycenter-button"/>
+       <span id="kupu-justifyright-button"/>
+       </metal:macros>
+       <metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" fill-slot="buttongroup_list">
+       <span id="kupu-list-ol-addbutton"/>    
+       <span id="kupu-list-ul-addbutton"/>
+       
+       </metal:macros>
+       <metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" fill-slot="buttongroup_indent"/>
+       -->
+   
+    <metal:macros fill-slot="toolbox_properties">
+      <div class="kupu-toolbox" id="kupu-toolbox-properties"><input type="hidden" class="wide" id="kupu-properties-title" /> <input
+        type="hidden" class="wide" id="kupu-properties-description" /></div>
+    </metal:macros>
+    <metal:macros fill-slot="toolbox_tables">
+      <div class="kupu-toolbox" id="kupu-toolbox-properties"><input type="hidden" class="wide" id="kupu-table-classchooser" /> <input
+        type="hidden" class="wide" id="kupu-table-newrows" /> <input type="hidden" class="wide" id="kupu-table-newcols" /></div>
+    </metal:macros>
+    <metal:macros fill-slot="editorframe">
+      
+        <iframe class="kupu-editor-iframe" id="kupu-editor" frameborder="0" scrolling="auto" src="fulldoc"
+          tal:attributes="src python:here.REQUEST['URL1']+'/getProfile?time='+here.REQUEST.get('time','0')"> 
+        </iframe>
+      
+    </metal:macros>
+  </metal:macros>
+
+
+  </form>
+
+
+<br/>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editPublications.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,232 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:publications" />
+
+<tal:block metal:fill-slot="body"
+  tal:define="yes_no_list python:'yes\nno'; sortingMode python:'year\npriority'">
+
+
+
+
+  <h2>Publication list</h2>
+  <p>(You can not change entries from the <i>Institutsbibliographie</i> here)</p>
+  <form action="changeSortingMode" method="post">
+  <p>Sort by:</p>
+  <table>
+    <td valign="top"
+      tal:content="structure python:here.ZSQLSelectionFromCRList(
+           'sortingMode',
+           sortingMode,
+           boxType='radio',
+           checked=here.getSortingMode())" />
+    <td><input type="submit" value="change"></td>
+  </table>
+  </form>
+
+  <form action="changePublications" method="post">
+  <input type="hidden" name="key_main" tal:attributes="value python:here.decode(person.key)">
+  <input type="hidden" name="main_fields"
+    value="publications__title,publications__publish">
+
+  <tal:block
+    tal:define="books python:here.ZSQLSimpleSearch('select *,oid from publications where lower(key_main)=\'%s\' and lower(referencetype)in (\'book\') and publish=\'yes\' order by priority'%here.getKey().lower());
+			     edited_books python:here.ZSQLSimpleSearch('select *,oid from publications where lower(key_main)=\'%s\' and lower(referencetype)in (\'edited book\') and publish=\'yes\' order by priority'%here.getKey().lower());
+			     not_displayed python:here.ZSQLSimpleSearch('select *,oid from publications where lower(key_main)=\'%s\' and publish=\'no\' order by priority'%here.getKey().lower());
+			     articles python:here.ZSQLSimpleSearch('select *,oid from publications where lower(key_main)=\'%s\' and lower(referencetype) not in (\'book\',\'edited book\') and publish=\'yes\' order by priority'%here.getKey().lower())">
+
+    <tal:block tal:condition="books">
+      <h3>Books</h3>
+      <table>
+        <tr>
+          <th />
+          <th />
+          <th>Priority</th>
+          <th align="left" width="100">Show</th>
+        </tr>
+        <tal:x tal:repeat="found python:here.sortBibliography(books)">
+        <tr>
+          <td><a tal:condition="python:found.id_gen_bib and (not found.id_gen_bib=='')"
+            tal:attributes="href python:'editBibliography?id=%s'%found.id_gen_bib">edit</a>
+          <a
+            tal:attributes="href python:'deleteField?table=publications&oid=%s'%found.oid">delete</a></td>
+          <td><span tal:replace="structure python:here.formatBibliography(here,here.decode(found))" /></td>
+          <td valign="top"><input
+            tal:attributes="name python:'publications__priority__'+str(found.oid);
+				     value python:here.integer(found.priority)"
+            size="3" /></td>
+          <td valign="top"
+            tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'publications__publish__'+str(found.oid),
+			     yes_no_list,
+			     boxType='radio',
+			     checked=found.publish)" />
+			    
+        </tr>
+        <tr>
+        <td>&nbsp;</td>
+        <td valign="top"><em>Link:</em><input
+            tal:attributes="name python:'publications__link__'+str(found.oid);
+				     value python:getattr(found,'link','')"
+            size="150" /></td>
+        <td>&nbsp;</td>
+        <td>&nbsp;</td>
+        </tr>
+         </tal:x>
+      </table>
+    </tal:block>
+
+    <tal:block tal:condition="edited_books">
+      <h3>Edited Books</h3>
+      <table>
+        <tr>
+          <th/>
+          <th/>
+          <th>Priority</th>
+          <th align="left" width="100">Show</th>
+        </tr>
+        <tal:x tal:repeat="found python:here.sortBibliography(edited_books)">
+        <tr>
+          <td><a tal:condition="python:found.id_gen_bib and (not found.id_gen_bib=='')"
+            tal:attributes="href python:'editBibliography?id=%s'%found.id_gen_bib">edit</a>
+          <a
+            tal:attributes="href python:'deleteField?table=publications&oid=%s'%found.oid">delete</a></td>
+          <td><span tal:replace="structure python:here.formatBibliography(here,here.decode(found))" /></td>
+          <td valign="top"><input
+            tal:attributes="name python:'publications__priority__'+str(found.oid);
+			   		value python:here.integer(found.priority)"
+            size="3" /></td>
+          <td valign="top"
+            tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'publications__publish__'+str(found.oid),
+			     yes_no_list,
+			     boxType='radio',
+			     checked=found.publish)" />
+        </tr>
+        <tr>
+        <td>&nbsp;</td>
+        <td valign="top"><em>Link:</em><input
+            tal:attributes="name python:'publications__link__'+str(found.oid);
+				     value python:getattr(found,'link','')"
+            size="150" /></td>
+        <td>&nbsp;</td>
+        <td>&nbsp;</td>
+        </tr>
+         </tal:x>
+      </table>
+    </tal:block>
+    
+   <tal:block tal:condition="articles">
+      <h3>Articles and Chapters</h3>
+      <table>
+        <tr>
+          <th/>
+          <th/>
+          <th>Priority</th>
+          <th align="left" width="100">Show</th>
+        </tr>
+        <tal:x tal:repeat="found python:here.sortBibliography(articles)">
+        <tr>
+          <td><a tal:condition="python:found.id_gen_bib and (not found.id_gen_bib=='')"
+            tal:attributes="href python:'editBibliography?id=%s'%found.id_gen_bib">edit</a>
+          <a
+            tal:attributes="href python:'deleteField?table=publications&oid=%s'%found.oid">delete</a></td>
+          <td><span tal:replace="structure python:here.formatBibliography(here,here.decode(found))" /></td>
+          <td valign="top"><input
+            tal:attributes="name python:'publications__priority__'+str(found.oid);
+				     value python:here.integer(found.priority)"
+            size="3" /></td>
+          <td valign="top"
+            tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'publications__publish__'+str(found.oid),
+			     yes_no_list,
+			     boxType='radio',
+			     checked=found.publish)" />
+        </tr>
+        <tr>
+        <td>&nbsp;</td>
+        <td valign="top"><em>Link:</em><input
+            tal:attributes="name python:'publications__link__'+str(found.oid);
+				     value python:getattr(found,'link','')"
+            size="150" /></td>
+        <td>&nbsp;</td>
+        <td>&nbsp;</td>
+        </tr>
+         </tal:x>
+      </table>
+    </tal:block>
+
+  <tal:block tal:condition="not_displayed">
+    <h3>Currently not shown</h3>
+    <table>
+      <tr>
+        <th />
+        <th />
+        <th>Priority</th>
+        <th align="left" width="100">Show</th>
+      </tr>
+      <tal:x tal:repeat="found python:here.sortBibliography(not_displayed)">
+      <tr>
+        <td><a
+          tal:attributes="href python:'deleteField?table=publications&oid=%s'%found.oid">delete</a></td>
+        <td><span tal:replace="structure python:here.formatBibliography(here,here.decode(found))" /></td>
+        <td valign="top"><input
+          tal:attributes="name python:'publications__priority__'+str(found.oid);
+		   				     value python:here.integer(found.priority)"
+          size="3" /></td>
+        <td valign="top"
+          tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'publications__publish__'+str(found.oid),
+			     yes_no_list,
+			     boxType='radio',
+			     checked=found.publish)" />
+      </tr>
+      <tr>
+        <td>&nbsp;</td>
+        <td valign="top"><em>Link:</em><input
+            tal:attributes="name python:'publications__link__'+str(found.oid);
+				     value python:getattr(found,'link','')"
+            size="150" /></td>
+        <td>&nbsp;</td>
+        <td>&nbsp;</td>
+        </tr>
+         </tal:x>
+    </table>
+    </tal:block>
+    
+  </tal:block>
+   <input type="submit" value="change">
+  </form>
+
+<br/> <br/> <br/> 
+  
+  <form action="changePublicationSelectionMode" method="post">
+
+    <h3>Select the 5 publications to be displayed in the first part of your homepage</h3>
+    <p>Choose the first 5 of my list following the order of</p>
+    <table tal:define="sm python:here.getPublicationSelectionMode()">
+      <tr tal:condition="python:sm=='priority'">
+	<td><span><input type="radio" name="publicationSelectionMode" value="year" />year</span>
+	  <span><input checked type="radio" name="publicationSelectionMode" value="priority" />priority</span></td>
+	<td><input type="submit" value="change"></td>
+	</tr>
+      <tr tal:condition="not:python:sm=='priority'">
+	<td><span><input checked type="radio" name="publicationSelectionMode" value="year" />
+	    year</span> <span><input type="radio" name="publicationSelectionMode"
+				     value="priority" /> priority</span></td>
+	<td><input type="submit" value="change"></td>
+	</tr>
+      </table>
+      </form>
+      
+      <br/><br/>
+      <h3><a href="addPublicationsBib">Add Publications to your list</a></h3>
+   <!--   <h4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="addPublications">Add 
+entries from the Institutsbibliographie</a></h4>
+      <h4>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="newBibliography">Add an entry that cannot be found in the 
+Institutsbibliographie</a></h4> -->
+
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editTalks.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,66 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:talks" />
+
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+  <form action="changeResearch" method="post">
+  <input type="hidden" name="key_main" tal:attributes="value python:here.decode(person.key)">
+  <input type="hidden" name="main_fields" value="talks__title">
+  <table tal:define="founds2 python:here.ZSQLInlineSearch(_table='talks',key_main=person.key)">
+    <tr>
+      <th>Date</th>
+      <th>Title/Place/Link</th>
+      <th>Priority</th>
+      <th>Show</th>
+    </tr>
+    <tr class="fliesstext" tal:repeat="found2 python:here.sortPriority(founds2)">
+      <td valign="top">
+        <input tal:attributes="name python:'talks__date__'+str(found2.oid); 
+				     value found2/date" size="10" />
+      </td>
+      <td>
+        <input tal:attributes="name python:'talks__title__'+str(found2.oid); 
+				     value python:here.decode(found2.title)" size="80" /><br>
+        <input tal:attributes="name python:'talks__place__'+str(found2.oid); 
+				     value python:here.decode(found2.place)" size="80" /><br>
+        <input tal:attributes="name python:'talks__link__'+str(found2.oid); 
+				     value python:here.decode(found2.link)" size="80" />
+      </td>
+      <td valign="top">
+        <input tal:attributes="name python:'talks__priority__'+str(found2.oid); value found2/priority" size="3" />
+      </td>
+      <td valign="top"
+        tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'talks__published__'+str(found2.oid),
+			     yes_no_list,
+			     boxType='radio',
+			     checked=found2.published)" />
+      <td>
+        <a tal:attributes="href python:'deleteField?table=talks&oid=%s'%found2.oid">delete</a>
+      </td>
+    </tr>
+    <tr colspan="4">
+      <td>Add new</td>
+    </tr>
+    <tr>
+      <td valign="top"><input tal:attributes="name python:'talks__date__new'" size="10" /></td>
+      <td><input tal:attributes="name python:'talks__title__new'" size="80"> <br>
+      <input tal:attributes="name python:'talks__place__new'" size="80" /> <br>
+      <input tal:attributes="name python:'talks__link__new'" size="80" /></td>
+      <td><input tal:attributes="name python:'talks__priority__new'" size="3"></td>
+      <td valign="top"
+        tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'talks__published__new',
+			     yes_no_list,
+			     boxType='radio',
+			     checked='yes')" />
+    </tr>
+  </table>
+  <input type="submit" value="submit">
+
+  </form>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/editTeaching.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,63 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:teaching" />
+
+<tal:block metal:fill-slot="body" tal:define="yes_no_list python:'yes\nno'">
+  <form action="changeResearch" method="post">
+  <input type="hidden" name="key_main" tal:attributes="value python:here.decode(person.key)">
+  <input type="hidden" name="main_fields" value="teaching__title">
+  <table tal:define="founds2 python:here.ZSQLInlineSearch(_table='teaching',key_main=person.key)">
+    <tr>
+      <th>Date</th>
+      <th>Title/Place/Link</th>
+      <th>Priority</th>
+      <th>Show</th>
+    </tr>
+    <tr class="fliesstext" tal:repeat="found2 python:here.sortPriority(founds2)">
+      <td valign="top"><input tal:attributes="name python:'teaching__date__'+str(found2.oid); 
+				     value python:here.decode(found2.date)" size="10" />
+      </td>
+
+      <td><input tal:attributes="name python:'teaching__title__'+str(found2.oid); 
+				     value python:here.decode(found2.title)" size="80" /> <br>
+      <input tal:attributes="name python:'teaching__place__'+str(found2.oid); 
+				     value python:here.decode(found2.place)" size="80" /> <br>
+      <input tal:attributes="name python:'teaching__link__'+str(found2.oid); 
+				     value python:here.decode(found2.link)" size="80" /></td>
+
+      <td valign="top"><input tal:attributes="name python:'teaching__priority__'+str(found2.oid);
+				     value found2/priority"
+        size="3" /></td>
+      <td valign="top"
+        tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'teaching__published__'+str(found2.oid),
+			     yes_no_list,
+			     boxType='radio',
+			     checked=found2.published)" />
+      <td><a tal:attributes="href python:'deleteField?table=teaching&oid=%s'%found2.oid">delete</a></td>
+    </tr>
+    <tr colspan="4">
+      <td>Add new</td>
+    </tr>
+    <tr>
+      <td valign="top"><input tal:attributes="name python:'teaching__date__new'" size="10" /></td>
+      <td><input tal:attributes="name python:'teaching__title__new'" size="80"> <br>
+      <input tal:attributes="name python:'teaching__place__new'" size="80" /> <br>
+      <input tal:attributes="name python:'teaching__link__new'" size="80" /></td>
+      <td><input tal:attributes="name python:'teaching__priority__new'" size="3"></td>
+      <td valign="top"
+        tal:content="structure python:here.ZSQLSelectionFromCRList(
+			     'teaching__published__new',
+			     yes_no_list,
+			     boxType='radio',
+			     checked='yes')" />
+    </tr>
+  </table>
+  <input type="submit" value="submit">
+
+  </form>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_MPIWGBasis.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,47 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+</head>
+<body>
+<form method="POST" action="editMPIWGProject">
+<h2>Basis Information for <span tal:replace="here/getId"/></h2>
+<table>
+<tr>
+<td>Project Title</td>
+<td><input tal:attributes="name python:'WEB_title'; value python:here.getContent('WEB_title')" size=100/></td>
+</tr>
+<tal:block tal:repeat="field here/getDataFields">
+<tr>
+<td tal:content="python:here.fieldLabels[field]"/>
+<td> <input tal:attributes="name field; value python:here.getContent(field)" size=100/></td>
+</tr>
+<tr tal:condition="python:here.isCheckField(field)">
+<td colspan=2 height="20">
+<tal:block  tal:define="checkList python:here.giveCheckList(here,field)">
+<tal:block  repeat="item checkList/keys">
+<span tal:replace="item"/>:
+<tal:block tal:condition="python:len(checkList[item])>0">
+found
+</tal:block>
+<tal:block tal:condition="not:python:len(checkList[item])>0">
+<font color="#ff0000">not found</font>
+</tal:block>
+
+
+<!--<input tal:repeat="prop python:checkList[item]" 
+       type="radio" 
+       tal:attributes="name python:'val_%s'%field; value python:prop[0].getId()" 
+       tal:content="python:prop[1]"/>-->
+</tal:block>
+<br>
+</tal:block>
+</td>
+</tr>
+</tal:block>
+</table>
+
+  
+<input type="submit">
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_MPIWGBasisNeu.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,127 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:basis" />
+<tal:block metal:fill-slot="body">
+  <form method="POST" action="editMPIWGProject">
+  <input type="hidden" name="fromEdit" value="yes" />
+  <table>
+    <tr>
+      <td><b>Project Title</b></td>
+      <td>
+        <input tal:attributes="name python:'WEB_title'; value python:here.getContent('WEB_title')" size="80"/>
+      </td>
+    </tr>
+    <tal:block tal:repeat="field here/getDataFields">
+      <tr>
+        <td><b tal:content="python:here.fieldLabels[field]"/></td>
+        <td><input tal:attributes="name field; value python:here.getContent(field)" size=80 /></td>
+      </tr>
+      <tr tal:condition="python:here.isCheckField(field)">
+        <td/>
+        <td><tal:block tal:define="checkList python:here.giveCheckList(here,field)">
+          <tal:block repeat="item checkList/keys">
+            <span tal:replace="item" />: 
+            <tal:block tal:condition="python:len(checkList[item])>0">found</tal:block> 
+            <tal:block tal:condition="not:python:len(checkList[item])>0"><font color="#ff0000">not found</font></tal:block>
+          </tal:block>
+          <br>
+        </tal:block></td>
+      </tr>
+    </tal:block>
+<!--    <tr>
+     <td><b>Historical names (new)</b><br/>
+     Please names enter as <br>
+      LASTNAME,FIRSTNAME <br/>or LASTNAME,FIRSTNAME MIDDLE.. <br> with 
+     <em>no space</em> before FIRSTNAME
+     </td>
+     <td><textarea name="historicalNames" tal:content="python:'\n'.join(here.getNamesInProject(here.getId()))" rows="10" cols="30">NAMES</textarea>
+     </td>
+    </tr> 
+    -->
+        <tr tal:define="hasChildren python:here.hasChildren()">
+    	<td>Project is visible</td>
+    	 <tal:x tal:condition="python:hasChildren and here.isActiveProject()" >
+	      <td>visible (status cannot be changed, because the project has visible children.)
+	       <input tal:attributes="name python:'active'" value="true" type="hidden">
+	      </td>
+	     </tal:x>
+    	 <tal:x tal:condition="python:(not hasChildren) or (hasChildren and not here.isActiveProject())">
+	      <td tal:condition="python:here.isActiveProject()" >
+			<input tal:attributes="name python:'active'" value="true" checked type="checkbox">
+		
+	      </td>
+	      <td tal:condition="not:python:here.isActiveProject()">
+		    <input tal:attributes="name python:'active'" value="true" type="checkbox">
+	    	<tal:x tal:condition="python:hasChildren" >
+			 	 WARNING: This project is not visible, but has visible children.
+			</tal:x>
+	      </td>
+	    </tal:x>
+	 </tr>
+	 <tr>
+	 	<td>Completed at:</td>
+	 	<td>
+			<input tal:attributes="name python:'completedAt';
+								   value python:here.getCompletedAt()"
+								   type="text" len="15"/>
+			(format dd.mm.yyyy or mm.yyyy or yyyy)
+			</td>
+	</tr>
+		 <tr>
+	 	<td>Startet at:</td>
+	 	<td>
+			<input tal:attributes="name python:'startedAt';
+								   value python:here.getStartedAt()"
+								   type="text" len="15"/>
+			(format dd.mm.yyyy or mm.yyyy or yyyy)
+			</td>
+	</tr>
+	 	
+  </table>
+ 
+  
+  <h2>Names</h2>
+  <table tal:define="global count python:0">
+ 
+<tr tal:repeat="identifiedName python:options.get('identifiedNames',{}).items()">
+		<tal:x tal:define="global count python:count+1"/>
+  		<td><input type="hidden" tal:attributes="value python:here.decode(identifiedName[0]);
+  												 name python:'responsibleScientist_name_%s'%count"/>
+  			<span tal:replace="python:identifiedName[0]"/></td>
+  		<td>
+  		<table>
+  		<tr tal:repeat="member python:identifiedName[1]">
+  		 	<tal:y define="memberObj member/getObject">
+  				<td tal:content="python:here.decode(memberObj.getKey())"/>
+  				<td tal:content="python:memberObj.getId()"/>
+  				<tal:x condition="python:here.isResponsibleScientist(memberObj.getKey())">
+  					<td><input type="checkbox" tal:attributes="name python:'responsibleScientist_key_%s'%count;
+  																			value python:here.decode(memberObj.getKey())"
+  												checked/></td>
+  					
+ 				</tal:x>
+ 				<tal:x condition="not:python:here.isResponsibleScientist(memberObj.getKey())">
+  					<td><input type="checkbox"  tal:attributes="name python:'responsibleScientist_key_%s'%count;
+  																			value python:here.decode(memberObj.getKey())"
+  												/></td>
+  				
+ 				</tal:x>
+  			
+  			</tal:y>
+  		</tr>
+  		</table>
+  		
+  		</td>
+	</tr>
+
+  	</table>	
+  	<p><input type="submit" value="change"/></p>
+  </form>
+  	
+  </tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_MPIWGDisciplinesThemes.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,30 @@
+<html>
+<body>
+<h2>Edit Disciplines and themes: <span tal:replace="python:here.WEB_title[0]"/></h2>
+<h3>Disciplines</h3>
+<form method="post" action="editMPIWGDisciplinesThemes">
+<tal:block tal:replace="python:here.getContent('xdata_09')"/>
+
+<tal:block tal:repeat="discipline here/getDisciplineList">
+  <tal:block tal:condition="python:here.isChecked(discipline,here.getContent('xdata_09'))">
+    <input tal:attributes="value discipline" name="disciplines" type="checkbox" checked><span tal:replace="discipline"/>
+  </tal:block>
+  <tal:block tal:condition="not:python:here.isChecked(discipline,here.getContent('xdata_09'))">
+    <input tal:attributes="value discipline" name="disciplines" type="checkbox"><span tal:replace="discipline"/>
+  </tal:block>
+</tal:block>
+<br>
+<h3>Themes</h3>
+<tal:block tal:repeat="theme here/getThemeList">
+  <tal:block tal:condition="python:here.isChecked(theme,here.getContent('xdata_10'))">
+    <input tal:attributes="value theme" name="themes" type="checkbox" checked><span tal:replace="theme"/>
+  </tal:block>
+  <tal:block tal:condition="not:python:here.isChecked(theme,here.getContent('xdata_10'))">
+    <input tal:attributes="value theme" name="themes" type="checkbox"><span tal:replace="theme"/>
+  </tal:block><br>
+</tal:block>
+<br>
+<input type="submit" value="change">
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_MPIWGDisciplinesThemesNeu.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,38 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:themes" />
+<tal:block metal:fill-slot="body">
+  <h3>Disciplines</h3>
+  <form method="post" action="editMPIWGDisciplinesThemes">
+  <input type="hidden" name="fromEdit" value="yes" />
+  <ul class="plain" tal:repeat="discipline here/getDisciplineList">
+    <li tal:condition="python:here.isChecked(discipline,here.getContent('xdata_09'))">
+      <input tal:attributes="value discipline" name="disciplines" type="checkbox" checked>
+      <span tal:replace="discipline" />
+    </li>
+    <li tal:condition="not:python:here.isChecked(discipline,here.getContent('xdata_09'))">
+      <input tal:attributes="value discipline" name="disciplines" type="checkbox">
+      <span tal:replace="discipline" />
+    </li>
+  </ul>
+  <br>
+  <h3>Themes</h3>
+  <ul class="plain" tal:repeat="theme here/getThemeList">
+    <li tal:condition="python:here.isChecked(theme,here.getContent('xdata_10'))">
+      <input tal:attributes="value theme" name="themes" type="checkbox" checked>
+      <span tal:replace="theme" />
+    </li>
+    <li tal:condition="not:python:here.isChecked(theme,here.getContent('xdata_10'))">
+      <input tal:attributes="value theme" name="themes" type="checkbox">
+      <span tal:replace="theme" />
+    </li>
+  </ul>
+  <p><input type="submit" value="change"/></p>
+  </form>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_MPIWGKeywords.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,44 @@
+<html>
+<body>
+<form method="POST" action="editMPIWGProject">
+<h2>Basis Information</h2>
+<table>
+<tr>
+<td>Project Title</td>
+<td><input tal:attributes="name python:'WEB_title'; value python:here.getContent('WEB_title')" size=100/></td>
+</tr>
+<tal:block tal:repeat="field here/getDataFields">
+<tr>
+<td tal:content="field"/>
+<td> <input tal:attributes="name field; value python:here.getContent(field)" size=100/></td>
+</tr>
+<tr tal:condition="python:here.isCheckField(field)">
+<td colspan=2 height="20">
+<tal:block  tal:define="checkList python:here.giveCheckList(here,field)">
+<tal:block  repeat="item checkList/keys">
+<span tal:replace="item"/>:
+<tal:block tal:condition="python:len(checkList[item])>0">
+found
+</tal:block>
+<tal:block tal:condition="not:python:len(checkList[item])>0">
+<font color="#ff0000">not found</font>
+</tal:block>
+
+
+<!--<input tal:repeat="prop python:checkList[item]" 
+       type="radio" 
+       tal:attributes="name python:'val_%s'%field; value python:prop[0].getId()" 
+       tal:content="python:prop[1]"/>-->
+</tal:block>
+<br>
+</tal:block>
+</td>
+</tr>
+</tal:block>
+</table>
+
+  
+<input type="submit">
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_MPIWGProjectNeu.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,60 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page" xmlns:metal="http://xml.zope.org/namespaces/metal" >
+<head>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:description" />
+</head>
+<body>
+<tal:block metal:fill-slot="body">
+  <form action="saveEditedContent" method="POST">
+    <div>
+      <span class="kupu-tb-buttongroup">
+        <button type="button" id="kupu-preview-button" title="preview: alt-p" accesskey="p">Preview</button>
+      </span>
+      <span class="kupu-tb-buttongroup">
+        <button type="button" id="kupu-save-button" title="save: alt-s" accesskey="s">Publish</button>
+      </span>
+    </div>
+    <metal:macros use-macro="here/kupuEditor/kupumacros/macros/xmlconfig">
+      <metal:macros fill-slot="dst">saveEditedContent</metal:macros>
+    </metal:macros>
+    <metal:macros use-macro="here/kupuEditor/kupumacros/macros/fulleditor">
+      <metal:macros fill-slot="tb_select_styles">
+        <select id="kupu-tb-styles">
+          <option xmlns:i18n="http://xml.zope.org/namespaces/i18n" value="P" i18n:translate="">
+            Normal
+          </option>
+          <option value="H3">
+            <span xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:translate="">Heading</span>
+          </option>
+        </select>
+      </metal:macros>
+      <metal:macros fill-slot="toolbox_properties">
+        <div class="kupu-toolbox" id="kupu-toolbox-properties">
+          <input type="hidden" class="wide" id="kupu-properties-title"/> 
+          <input type="hidden" class="wide" id="kupu-properties-description"/>
+        </div>
+      </metal:macros>
+      <metal:macros fill-slot="toolbox_tables">
+        <div class="kupu-toolbox" id="kupu-toolbox-properties">
+          <input type="hidden" class="wide" id="kupu-table-classchooser"/> 
+          <input type="hidden" class="wide" id="kupu-table-newrows" />
+          <input type="hidden" class="wide" id="kupu-table-newcols" />
+        </div>
+      </metal:macros>
+      <metal:macros fill-slot="editorframe">
+        <tal:block tal:condition="not:python:here.REQUEST.get('fromPreview',None)">
+          <iframe class="kupu-editor-iframe" id="kupu-editor" frameborder="0" scrolling="auto" src="fulldoc"
+            tal:attributes="src python:here.absolute_url()+'/getWebProject_description'"> </iframe>
+        </tal:block>
+        <tal:block tal:condition="python:here.REQUEST.get('fromPreview',None)">
+          <iframe class="kupu-editor-iframe" id="kupu-editor" frameborder="0" scrolling="auto" src="fulldoc"
+            tal:attributes="src python:here.absolute_url()+'/previewTemplate/getWebProject_description'"> </iframe>
+        </tal:block>
+      </metal:macros>
+    </metal:macros>
+    <p></p>
+  </form>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_MPIWGProject_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,31 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:define-macro="page">
+<head>
+<metal:macros xmlns:metal="http://xml.zope.org/namespaces/metal" use-macro="here/kupuEditor/kupumacros/macros/head">
+  <metal:macros fill-slot="bootstrap-editor">
+    <script type="text/javascript" src="/kupuEditor/kupuinit_form.js"> </script>
+    <script type="text/javascript" src="/kupuEditor/kupustart_form.js"> </script>
+  </metal:macros>
+</metal:macros>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="stylesheet" href="edit.css" type="text/css"/>  
+</head>
+<body onload="kupu = startKupu();">
+  <h3 tal:condition="not:here/isActiveProject">(!!Project is not visible!!)</h3>
+  <h2 class="title">Edit project <i tal:content="python:here.getContent('WEB_title')"/></h2>
+  <metal:block metal:define-slot="navsel"/>
+  <div class="mainnav">
+    <span tal:attributes="class python:here.getPathStyle('basis', menusel, 'mainmenu')"><a href="editMPIWGBasisEditor">Basic information</a></span>
+    <span tal:attributes="class python:here.getPathStyle('description', menusel, 'mainmenu')"><a href="edit">Project description</a></span>
+    <span tal:attributes="class python:here.getPathStyle('images', menusel, 'mainmenu')"><a href="manageImages">Images</a></span>
+    <span tal:attributes="class python:here.getPathStyle('publications', menusel, 'mainmenu')"><a href="managePublications">Publications</a></span>
+    <span tal:attributes="class python:here.getPathStyle('relatedProjects', menusel, 'mainmenu')"><a href="manageRelatedProjects">Related Projects</a></span>
+    <span tal:attributes="class python:here.getPathStyle('themes', menusel, 'mainmenu')"><a href="tagTheProject">Tags</a></span>
+    <span class="mainmenu"><a target="_blank" href="index_html">View</a></span>
+  </div>
+  <div class="content">
+  <tal:block metal:define-slot="body"/>
+  </div>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_MPIWGRelatedPublications.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,17 @@
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=utf-8">
+</head>
+<body>
+<form method="POST" action="editMPIWGProject">
+
+<h3>Edit Related Publications</h3>
+
+<span tal:replace="structure python:here.Epoz('WEB_related_pub', data=here.getContent('WEB_related_pub'), toolbox='/toolbox', lang='en', path='', widget='', style='width: 600px; height: 500px; border: 1px solid #000000;', button='background-color: #EFEFEF; border: 1px solid #A0A0A0; cursor: pointer; margin-right: 1px; margin-bottom: 1px;', css='', charset='utf-8')"/>
+
+
+  
+<input type="submit">
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_MPIWGStaff.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,25 @@
+<html>
+<head>
+   <title>The title</title>
+</head>
+<body>
+
+<div>
+
+<h1>Edit</h1>
+<h2>!Please use this form only if you really know what you do, for the change of names the
+../edit methods should be used!</h2>
+<form method="post" action="changeMPIWGStaff">
+
+<p>LastName:
+<input name="lastName" tal:attributes="value here/lastName"/></p>
+<p>FirstName:
+<input name="firstName" tal:attributes="value here/firstName"/></p>
+
+<p>Key:
+<input name="key" tal:attributes="value here/getKey"/></p>
+<input type="submit">
+</form>
+</div>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_imageForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,29 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:images" />
+<tal:block metal:fill-slot="body">
+  <h3>Edit Image</h3>
+  <form action="editImage" method="post" enctype="multipart/form-data">
+  <table>
+    <tr><th>Image</th><th>Caption</th></tr>
+    <tr>
+      <td><div tal:content="structure python:here.tag(scale=250.0 / here.height)"/></td>
+      <td><textarea tal:content="structure python:getattr(here,'caption','')" name="caption" rows="3" cols="60"></textarea></td>
+    </tr>
+    <tr>
+      <td><p>Upload new image:<input type="file" name="file" len="50"/></p></td>
+    </tr>
+  </table>
+  <p>
+  <input type="submit" value="submit"/>
+  </p>
+  </form>
+  
+  <h3><a href="../manageImages">Back to image list</a></h3>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_project_error_relatedProject.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,13 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page" xmlns:metal="http://xml.zope.org/namespaces/metal" >
+<head>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:description" />
+</head>
+<body>
+<tal:block metal:fill-slot="body">
+  <h3>Error: Adding a project</h3>
+  <span tal:replace="options/link"/> is not a link to an MPIWG project.
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_publicationForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,62 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:publications" />
+<tal:block metal:fill-slot="body">
+  <h3>Edit a publication</h3>
+  
+  <form action="editPublication" method="post" enctype="multipart/form-data">
+  <p>Bibliographical entry</p>
+    <textarea tal:content="structure python:getattr(here,'text','')" name="text" rows="3" cols="80"></textarea>
+    
+  <p>Link</p>
+  	<input size="100"  tal:attributes="value python:getattr(here,'link','')" name="link">
+  
+  <h4>Images</h4>
+  <p>To display images on the you should use book pages. The link above has to be a link to a book page.</p>
+  
+  <tal:x tal:condition="python:here.hasLinkToBookPage()" tal:define="url python:here.getImageUrls()">
+  	  <p>Image 1 (e.g. Cover)</p>
+
+  <p tal:condition="python:len(url)>0">
+  	<img tal:attributes="src python:url[0]" height="100"/>
+  </p>
+  
+  <p>Image 2 (e.g. Table of Contents)</p>
+  <p tal:condition="python:len(url)>1">
+  	<img tal:attributes="src python:url[1]" height="100"/>
+  	</p>
+   
+  </tal:x>
+  <p tal:condition="not:python:here.hasLinkToBookPage()">
+   Link is not a link to a bookPage
+  </p>
+  
+  
+  <!-- 
+  <p>Image 1 (e.g. Cover)</p>
+  <p tal:condition="python:hasattr(here,'publicationImage1')">
+  	<img tal:attributes="src python:here.publicationImage1.absolute_url()" height="100"/>
+  	</p>
+   <p>Upload new image:<input type="file" name="image1" len="50"/></p>
+  <p>Image 2 (e.g. Table of Contents)</p>
+  <p tal:condition="python:hasattr(here,'publicationImage2')">
+  	<img tal:attributes="src python:here.publicationImage2.absolute_url()" height="100"/>
+  	</p>
+   <p>Upload new image:<input type="file" name="image2" len="50"/></p>
+  
+ -->
+  <h3>Descriptive Text</h3>
+  <p>
+  <textarea tal:content="structure python:getattr(here,'description','')" name="description" rows="10" cols="80"></textarea>
+  </p>
+  <p><input type="submit" value="submit"/></p>
+  </form>
+  
+  <h3><a href="managePublications">Back to publication list</a></h3>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/edit_relatedProjectForm.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/edit_MPIWGProject_main/macros/page">
+<head>
+</head>
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:publications" />
+<tal:block metal:fill-slot="body">
+  <h3>Edit related projects</h3>
+   <table><tr>
+   <td>Project id:</td>
+     <td tal:content="structure python:getattr(here,'objid','')" />
+     </tr>
+     <tr>  <td>WEB title:</td>
+        <td tal:content="structure python:getattr(here,'projectWEB_title','')" />
+     </tr>
+  </table>
+  <form action="editRelatedProject" method="post" enctype="multipart/form-data">
+ 
+  <p>Link</p>
+  	<input size="100"  tal:attributes="value python:getattr(here,'orginallink','')" name="link">
+  
+  <input type="submit" value="change"/>
+  
+  <h3><a href="manageRelatedProjects">Back to related projects list</a></h3>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/harvest_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,56 @@
+<html>
+
+<body>
+
+      <tal:block tal:replace="structure here/versionHeader"/>
+      <h1 tal:content="structure python:here.getContent('WEB_project_header')">History of Scientific Objectivity, 18th-19th Cs</h1>
+     
+      <p><i tal:content="structure python:here.getContent('xdata_01')">Names of responsible persons </i></p>
+      <p tal:condition="not:python:here.getContent('xdata_08')==''">Other involved scholars: <i tal:content="structure python:here.getContent('xdata_08')">Scholars </i></p>
+      <p tal:condition="not:python:here.getContent('xdata_12')==''">Cooperation Partners: <i tal:content="structure python:here.getContent('xdata_12')">Partners </i></p>
+      <br/>
+
+      <div class="indent" tal:content="structure python:here.getContent('WEB_project_description')">
+	<p>
+		In the middle decades of the nineteenth century objectivity established itself as a (if not the) cardinal epistemic virtue in the sciences. From astronomy to paleontology to physiology, new ways of making images, assessing error, and designing experiments were enlisted in the service of objectivity. 
+	</p>
+	<p>
+		This triumph of objectivity over rival epistemic virtues like truth and certainty is all the more remarkable because objectivity had emerged only decades before. Only circa 1850 did the modern sense of "objectivity" make its way into dictionaries in the major European languages. The ideals and practices associated with objectivity in the sciences emerge at roughly the same time. 
+	</p>
+	<p>
+		The story of how objectivity became so central to science is one of actions as well as words. Objectivity changed how science was done in concrete, specific ways. Photography, self-registering instruments, the method of least squares, and machines for measuring the personal equations of observers were all examples of these new scientific practices of objectivity 
+	</p>
+      </div>
+
+<tal:comment>  
+      <tal:block tal:condition="not:python:here.getContent('xdata_11')==''">
+	<h2>Related items at the digital research library</h2>
+	<p tal:content="structure python:here.getContent('xdata_11')">
+				Item 1 
+				<br>
+				Item 2 
+				<br>
+				Item 3 
+				<br>
+	</p>
+      </tal:block>
+
+      <tal:block tal:condition="not:python:here.getContent('WEB_related_pub')==''">
+	<h2> Related Publications</h2> 
+
+	<p tal:define="pub python:here.getContent('WEB_related_pub')" tal:content="structure pub">
+		"Die Kultur der wissenschaftlichen Objektivit&auml;t," in: Michael Hagner, ed., Ansichten der Wissenschaftsgeschichte (Frankfurt am Main: Fischer Taschenbuchverlag GmbH, 2001): 137-158. 
+		<br>
+		(with Peter Galison), "The Image of Objectivity," Representations no. 40 (Fall 1992): 81-128. Translated into German (2002) 
+		<br>
+		"Objectivity and the Escape from Perspective," Social Studies of Science 22(1992): 597-618 
+	</p>
+      </tal:block>
+
+      <tal:block tal:condition="not:python:here.getContent('xdata_13')==''">
+	<h2>Funding Institutions</h2>
+	  <p tal:content="structure python:here.getContent('xdata_13')">Funding </p>
+      </tal:block>
+</tal:comment>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/harvest_members_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html>
+  <body>
+
+<div class="haupttext">
+     <p>&nbsp;</p>
+    <tal:block tal:define="found python:here.ZSQLInlineSearchU(_table='personal_www',key=here.getKeyUTF8(),publish_the_data='yes')">
+     <tal:block tal:condition="found">
+
+      <tal:block tal:define="founds2 python:here.ZSQLInlineSearch(_table='current_work',id_main=found.id,publish='yes')" tal:condition="founds2">	
+	<h1>Current work</h1>
+
+	  <p class="fliesstext" tal:repeat="found2 founds2">
+	    <span tal:replace="found2/current"/>
+	  </p>
+
+      </tal:block>
+
+      <tal:block tal:define="founds2 python:here.ZSQLInlineSearch(_table='research_interest',id_main=found.id,published='yes')" tal:condition="founds2">	
+	<h1>Research interests</h1>
+	<ul class="liste">
+	  <li tal:repeat="found2 founds2">
+	    <span tal:replace="found2/interest"/>
+	  </li>
+	</ul>
+      </tal:block>
+   
+
+<!-- Curriculum vitae -->  
+      <tal:block tal:condition="not:python:here.ZSQLisEmpty(found.cv)">
+	<h1>Curriculum vitae</h1>
+	<p class="fliesstext" tal:content="structure python:here.formatAscii(found.cv)"> [FMP-Field: CV] </p>
+      </tal:block>
+
+<!-- Awards -->  
+      <tal:block tal:condition="not:python:here.ZSQLisEmpty(found.awards)">
+	<h1>Awards</h1>
+	<p class="fliesstext"  tal:content="structure python:here.formatAscii(found.awards)"> [FMP-Field: awards, break] </p>
+      </tal:block>
+
+<!-- Selected publications -->
+     <tal:block tal:condition="here/usePublicationsSpecial|python:False">  
+     <h1>Selected publications</h1>
+	<ul class="liste">
+        <tal:block tal:replace="structure here/specialPublicationsField"/>
+	  <li>
+	    <a tal:attributes="href python:'publications_full?-table=personal_www&amp;id='+found.id">more</a> 
+	  </li>
+	</ul>
+      </tal:block>
+
+      <tal:block tal:condition="not:here/usePublicationsSpecial|python:False">  
+      <tal:block tal:condition="python:here.ZSQLInlineSearch(storename='search3',_table='publications',id_main=found.id,_max=10000,publish='yes')">
+	<h1>Selected publications</h1>
+
+	<ul class="liste">
+	  <li tal:repeat="found3 python:here.sortBibliography(here.ZSQLInlineSearch(storename='search3',_table='publications',id_main=found.id,_max=10000,publish='yes'),here.getPublicationSelectionMode())">
+	    <span tal:replace="structure python:here.en.formatBibliography(here,found3)"/>
+	  </li>
+	  <li tal:condition="python:here.ZSQLFoundCount(storename='search3')>5">
+	    <a tal:attributes="href python:'publications_full?-table=personal_www&amp;id='+found.id">more</a> 
+	  </li>
+	</ul>
+      </tal:block>
+      </tal:block>
+<!-- Talks -->  
+      <tal:block tal:define="founds4 python:here.ZSQLInlineSearch(storename='search4',_table='talks',id_main=found.id,_max=10000,_sort='priority',published='yes')" tal:condition="founds4">
+	<h1>Talks and presentations</h1>
+	<ul class="liste">
+	  <li tal:repeat="found4 python:here.sortPriority(founds4)">
+	    <span tal:condition="not:python:here.ZSQLisEmpty(found4.link)">
+	      <a tal:attributes="href found4/link"><span tal:replace="found4/date"/> &#150; <span tal:replace="found4/place"/> &#150; <span tal:replace="found4/title"/></a>
+	    </span>
+	    <span tal:condition="python:here.ZSQLisEmpty(found4.link)">
+	      <span tal:replace="found4/date"/> &#150; <span tal:replace="found4/place"/> &#150; <span tal:replace="found4/title"/>
+	    </span>
+	  </li>
+	  <li tal:condition="python:here.ZSQLFoundCount(storename='search4')>5">
+	    <a tal:attributes="href python:'talks_full?-table=personal_www&amp;id='+found.id">more</a>
+	  </li>
+	</ul>
+      </tal:block>
+
+<!-- >Teaching activities -->  
+      <tal:block tal:define="founds5 python:here.ZSQLInlineSearch(storename='search5',_table='teaching',id_main=found.id,_max=1000,_sort='priority')" tal:condition="founds5">
+	<h1>Teaching activities</h1>
+	<ul class="liste">
+	  <li tal:repeat="found5 python:here.sortPriority(founds5)">
+	    <span tal:condition="not:python:here.ZSQLisEmpty(found5.link)"> 
+	      <a tal:attributes="href found5/link"><span tal:replace="found5/date"/> &#150; <span tal:replace="found5/place"/> &#150; <span tal:replace="found5/title"/>
+	      </a>
+	    </span>
+            <span tal:condition="python:here.ZSQLisEmpty(found5.link)">
+		<span tal:replace="found5/date"/> &#150; <span tal:replace="found5/place"/> &#150; <span tal:replace="found5/title"/>
+	    </span>
+	  </li>
+	  <li tal:condition="python:here.ZSQLFoundCount(storename='search5')>5" class="p_indent"><a tal:attributes="href python:'teaching_full?-table=personal_www&amp;id='+found.id">more</a>
+	  </li>
+	</ul>
+      </tal:block>
+      </tal:block>
+    </tal:block>
+</div>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/members_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,100 @@
+<html metal:use-macro="here/main_template/macros/page">
+<head>
+<title tal:content="template/title">The title</title>
+</head>
+<body>
+
+<tal:block metal:fill-slot="body" tal:define="found python:here.ZSQLInlineSearch(_table='personal_www',username=here.getId())[0]">
+<table class="center">
+	  <td valign="top" width="610"> 
+	    
+           <div id="NameTitle" style="position:absolute; width:365px; height:37px; z-index:3; left: 161px; top: 63px; visibility: visible"> 
+          <h2><span tal:replace="found/title"/> <span tal:replace="found/vorname"/> <span tal:replace="found/name"/></h2>
+	 </div>
+        <div id="Position" style="position:absolute; width:365px; height:30px; z-index:5; left: 161px; top: 115px; visibility: visible"> 
+          <h3><span tal:replace="found/position"/></h3>
+      </div>
+        <div id="StayAtMpiwg" style="position:absolute; width:365px; height:32px; z-index:6; left: 161px; top: 158px; visibility: visible"> 
+          <p class="p_noindent">Residence:<br>
+          <span tal:replace="found/stay_at_mpiwg"/></p>
+      </div>
+        <div id="Adress" style="position:absolute; width:365px; height:90px; z-index:4; left: 161px; top: 210px"> 
+          <p class="p_noindent">&nbsp;<br>
+          &nbsp;<br>
+          &nbsp;<br>
+          &nbsp;</p>
+        </div>
+<!-- middle right (PIM) -->
+        <div id="ContactsImg" style="position:absolute; width:355px; height:114px; z-index:1; left: 286px; top: 220px; visibility: visible;"> 
+        <table width="400" border="0">
+            <tr> 
+              <td rowspan="4" width="48"><img src="images/EmailResponseOrg.gif" width="40" height="49" align="middle"><img src="bilder/leer.gif" width="1" height="100" align="middle"> 
+              </td>
+	    <tal:block tal:condition="python:found.telefon_p=='yes'">
+	    <td width="84" height="25"> 
+                <p>tel.:</p>
+            </td>
+            <td width="180" height="25"> 
+               <p  class="p_noindent" tal:content="found/telefon">[FMP-Field: telefon]</p>
+           </td>
+           </tal:block>
+          </tr>
+          <tr> 
+	     <tal:block tal:condition="python:found.e_mail_p=='yes'">
+            <td width="84" height="25"> 
+                <p>email:</p>
+            </td>
+            <td width="180" height="25"> 
+                <p class="p_noindent"> <a tal:attributes="href python:'mailto:'+found.e_mail" tal:content="found/e_mail">[FMP-Field: e_mail]</a></p>
+            </td>
+	    </tal:block>
+          </tr>
+          <tr> 
+	    <tal:block tal:condition="python:found.fax_p=='yes'">
+	      <td width="84" height="25"> 
+                <p>fax:</p>
+			</td>
+             <td width="180" height="25">               
+           <p  class="p_noindent" tal:content="found/fax">[FMP-Field: fax]</p>          
+              </td>
+	     </tal:block>
+          </tr>
+          <tr> 
+	    <tal:block tal:condition="not:python:here.ZSQLisEmpty(found.private_homepage)">
+            <td width="84" height="25"> 
+                <p>homepage:</p>
+            </td>
+              <td width="180" height="25"> 
+                <p class="p_noindent"><a tal:attributes="href found/private_homepage" target="_new" tal:content="found/private_homepage">[FMP-Field: private_homepage]</a></p>
+            </td>   
+	      </tal:block>
+          </tr>
+        </table>
+<!-- middle right (PIM) END -->
+</div>
+        <!-- bottom right -->
+
+        <div id="Daten" style="position:absolute; z-index:10; left: 173px; top: 350px; width: 578px; height: 589px; visibility: visible"> 
+
+          <div id="Teaching" style="position:relative; width:581px; z-index:14;"> 
+            <img src="images/en/Fieldnames72_NBProjectsMPI.jpg" width="211" height="33"> 
+            <p> </p>
+	    <tal:block tal:repeat="projects python:here.getProjectsOfMember(email=here.getId())">
+            <p tal:repeat="project python:projects[1]" class="p_noindent"> <a tal:attributes="href python:project.absolute_url+'/index.html'"><span tal:replace="python:project.WEB_title[0].encode('utf-8')"/></a></p>
+            <br/>
+		</tal:block>							
+            <p> 
+
+              &nbsp;</p>
+          </div>
+      
+
+</table>
+</tal:block>
+  </body>
+</html>
+<!-- to be done institutsbiliographie integrieren
+images
+
+published yes or no abfragen
+-->
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/newBibliographyEntry.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,29 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:publications" />
+<tal:block metal:fill-slot="body" tal:define="mapping python:here.metadata.main.meta.bib.generateMappingForType(type=here.REQUEST['_docType'])">
+	<h3>Add a separate publication</h3>	
+	<p>Type: <b tal:content="python:here.REQUEST['_docType']"/></p>
+	<form action="" method="get">
+	<input type="hidden" name="-format" value="editPublications">
+	<input type="hidden" name="-table" value="bibliography">
+	<input type="hidden" name="_docType" tal:attributes="value here/REQUEST/_docType">
+	<input type="hidden" name="_addEntry" value="yes">
+	<table>
+		<tal:block tal:repeat="mapElement python:here.metadata.main.meta.bib.getFields()">
+		<tr tal:condition="python:mapping[mapElement][1]!=''">
+			<td tal:content="python:mapping[mapElement][1].encode('utf-8')"/>
+			
+			<td>
+			<input size="80" tal:attributes="name mapElement"/>
+		</tr>
+		</tal:block>
+	</table>
+	<input type="submit" value="add"/>
+  </form>
+  </tal:block>
+</body>
+</html>
+				
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/newBibliographyEntryDocType.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html metal:use-macro="here/mainEditFile/macros/page">
+<body>
+<tal:block metal:fill-slot="navsel" tal:define="global menusel string:publications" />
+<tal:block metal:fill-slot="body">
+<h2>Add a separate publication</h2>
+
+<form method="get" action="newBibliography">
+<span>Type of publication: </span>
+<span tal:replace="structure python:here.ZSQLOptionsFromCRList('_docType',here.getDocTypes())"/>
+<input type="submit" value="submit">
+</form>
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/no_project.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,7 @@
+<html metal:use-macro="here/main_template/macros/page">
+<body metal:fill-slot="body">
+<p>This page didn't exit at the selected time!</p>
+<p>There is an actual version at:</p>
+<p><a tal:attributes="href python:here.REQUEST['URL1']" Tal:content="python:here.REQUEST['URL1']"/></p>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/previewFrame.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,10 @@
+<html>
+<body>
+<h2>Preview</h2>
+<p>
+<a tal:attributes="href python:here.REQUEST['URL1']+'/edit?fromPreview=True'">Edit</a>
+<a tal:attributes="href python:here.REQUEST['URL1']+'/saveFromPreview'">Save and Publish</a>
+</p>
+<iframe tal:attributes="src python:here.REQUEST['URL1']+'/previewTemplate'" width="100%" height="100%"></iframe>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/projectImageView.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <title tal:content="here/title_or_id"/>
+    <link rel="stylesheet" type="text/css" href="http://www.mpiwg-berlin.mpg.de/en/mpiwg.css" />
+    <link rel="shortcut icon" href="http://www.mpiwg-berlin.mpg.de/favicon.ico" />
+  </head>
+  <body>
+    <div id="wrapper">
+    <div class="content">
+      <div align="left" tal:define="imTag python:getattr(here,'tag',None)">
+        <img tal:condition="imTag" tal:replace="structure python:imTag()">
+      </div>
+      <p tal:content="structure python:getattr(here,'caption','')">J.-A.-D. Ingres: Mme Moitessier, 1856. l/Lw. 120 x 92,1 cm. London, National Gallery.</p>
+    </div>
+    </div>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/project_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+        "http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd">
+<html metal:use-macro="here/main_template/macros/page">
+<head>
+	<title> Max Planck Institute for the History of Science </title> 
+</head>
+<body>
+<tal:block metal:fill-slot="body">
+      <tal:block tal:replace="structure here/versionHeader"/>
+      <h1 tal:content="structure python:here.getContent('WEB_project_header')">History of Scientific Objectivity, 18th-19th Cs</h1>
+     
+      <p><i tal:content="structure python:here.getUrlFromPerson(here.getContent('xdata_01'))">Names of responsible persons </i></p>
+      <p tal:condition="not:python:here.getContent('xdata_08')==''">Other involved scholars: <i tal:content="structure python:here.getUrlFromPerson(here.getContent('xdata_08'))">Scholars </i></p>
+      <p tal:condition="not:python:here.getContent('xdata_12')==''">Cooperation Partners: <i tal:content="structure python:here.getContent('xdata_12')">Partners </i></p>
+      <br/>
+
+      <div class="indent" tal:content="structure python:here.getContent('WEB_project_description')">
+	<p>
+		In the middle decades of the nineteenth century objectivity established itself as a (if not the) cardinal epistemic virtue in the sciences. From astronomy to paleontology to physiology, new ways of making images, assessing error, and designing experiments were enlisted in the service of objectivity. 
+	</p>
+	<p>
+		This triumph of objectivity over rival epistemic virtues like truth and certainty is all the more remarkable because objectivity had emerged only decades before. Only circa 1850 did the modern sense of "objectivity" make its way into dictionaries in the major European languages. The ideals and practices associated with objectivity in the sciences emerge at roughly the same time. 
+	</p>
+	<p>
+		The story of how objectivity became so central to science is one of actions as well as words. Objectivity changed how science was done in concrete, specific ways. Photography, self-registering instruments, the method of least squares, and machines for measuring the personal equations of observers were all examples of these new scientific practices of objectivity 
+	</p>
+      </div>
+
+      <tal:block tal:define="contexts python:here.getContexts(parents=here.getContent('xdata_05'),depth=1)" tal:condition="contexts">
+	<h2>This activity is part of</h2>
+	<ul type="none">
+	  <li tal:repeat="context contexts">
+	    <a tal:content="python:context[0].getContent('WEB_title')" tal:attributes="href python:context[0].absolute_url()+'/index.html'"/>
+	  </li>
+	</ul>
+      </tal:block>
+
+      <tal:block tal:define="contexts python:here.getContexts(childs=here.getContent('xdata_05'),depth=1)" tal:condition="contexts">
+	<h2>Research activities covered by this activity</h2>
+	<ul type="none">
+	  <li tal:repeat="context contexts">
+	    <a tal:content="python:context[0].getContent('WEB_title')" tal:attributes="href python:context[0].absolute_url()+'/index_html'"/>
+	  </li>
+	</ul>
+      </tal:block>
+
+      <tal:block tal:condition="not:python:here.getContent('xdata_11')==''">
+	<h2>Related items at the digital research library</h2>
+	<p tal:content="structure python:here.getContent('xdata_11')">
+				Item 1 
+				<br>
+				Item 2 
+				<br>
+				Item 3 
+				<br>
+	</p>
+      </tal:block>
+
+      <tal:block tal:condition="not:python:here.getContent('WEB_related_pub')==''">
+	<h2> Related Publications</h2> 
+
+	<p tal:define="pub python:here.getContent('WEB_related_pub')" tal:content="structure pub">
+		"Die Kultur der wissenschaftlichen Objektivit&auml;t," in: Michael Hagner, ed., Ansichten der Wissenschaftsgeschichte (Frankfurt am Main: Fischer Taschenbuchverlag GmbH, 2001): 137-158. 
+		<br>
+		(with Peter Galison), "The Image of Objectivity," Representations no. 40 (Fall 1992): 81-128. Translated into German (2002) 
+		<br>
+		"Objectivity and the Escape from Perspective," Social Studies of Science 22(1992): 597-618 
+	</p>
+      </tal:block>
+
+      <tal:block tal:condition="not:python:here.getContent('xdata_13')==''">
+	<h2>Funding Institutions</h2>
+	  <p tal:content="structure python:here.getContent('xdata_13')">Funding </p>
+      </tal:block>
+
+</tal:block>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/publications_full_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,69 @@
+<html metal:use-macro="here/main_template/macros/page">
+<head>
+<title tal:content="template/title">The title</title>
+</head>
+<body>
+
+<tal:block metal:fill-slot="body" tal:define="found python:here.ZSQLFind()[0]">
+<table>
+	  <td valign="top" width="610"> 
+        <div id="Photo" style="position:absolute; width:200px; height:265px; z-index:2; left:483px; top:61px; visibility:visible"> 
+       [FMP-if: image .neq.] 
+               <b><img src="http://www.mpiwg-berlin.mpg.de/[FMP-Image: image]"></b> 
+      [FMP-else]&nbsp;[/FMP-if] 
+       </div>
+      <div id="NameTitle" style="position:absolute; width:323px; height:37px; z-index:3; left: 161px; top: 63px; visibility: visible"> 
+          <h3><span tal:replace="found/title"/> <span tal:replace="found/vorname"/> <span tal:replace="found/name"/></h3>
+      </div>
+        <div id="Position" style="position:absolute; width:323px; height:30px; z-index:5; left: 161px; top: 115px; visibility: visible"> 
+          <h4><span tal:replace="found/position"/></h4>
+      </div>
+        <div id="StayAtMpiwg" style="position:absolute; width:323px; height:32px; z-index:6; left: 161px; top: 158px; visibility: visible"> 
+          <p>Residence:<br>
+          <span tal:replace="found/stay_at_mpiwg"/></p>
+      </div>
+        <div id="Adress" style="position:absolute; width:323px; height:90px; z-index:4; left: 161px; top: 210px"> 
+          <p>Max Planck Institute for the History of Science<br>
+          Wilhelmstra&szlig;e 44<br>
+          D - 10117 Berlin<br>
+          Germany</p>
+	  <p class="p_indent"> <img src="bilder/RightArrowSmall.jpg" width="17" height="9" border="0"> 
+              <a tal:attributes="href python:'members/'+found.username"> 
+              main </a> </p>
+        </div>
+	 
+          
+            
+<!-- middle right (PIM) -->
+        <div id="ContactsImg" style="position:absolute; width:355px; height:114px; z-index:1; left: 286px; top: 329px; visibility: visible;"> 
+        <table width="400" border="0">
+           
+          <div id="Conferences" style="position:relative; width:581px; z-index:15;"> 
+            <img src="images/en/Fieldnames72_NBPublications.jpg" width="211" height="33"> 
+	    <p/>
+	    <tal:block tal:repeat="found3 python:here.ZSQLInlineSearch(storename='search3',_table='publications',id_main=found.id,_sort='priority')">
+            <p class="p_indent"> <img src="bilder/RightArrowSmall.jpg" width="17" height="9" border="0"> 
+	      <span tal:replace="structure python:here.formatBibliography(here,found3)"/>
+            <p> 
+	    </tal:block>
+	   
+            <!--<p class="p_indent"> <a href="institutsbiblio/FMPro?-db=personal-www&amp;-max=1&amp;-Lay=ALL&amp;-format=search_inst_bib.html&amp;ID=[FMP-Field: ID]&amp;-Error=null.html&amp;-find" target="_new"> 
+              search the institute's bibliography </a> -->
+              <!-- Please do not delete -->
+              &nbsp; 
+            <p> 
+              <!-- Please do not delete -->
+              &nbsp;</p>
+            </div>
+	 
+	
+</table>
+</tal:block>
+  </body>
+</html>
+<!-- to be done institutsbiliographie integrieren
+images
+weitere seiten fuer mehr als 5 treffer (publ./talks/teaching)
+bilbiography einfuegen
+published yes or no abfragen
+-->
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/showExtendedProjectBibliography.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,3 @@
+<html metal:use-macro="here/projects/extendedBibliography/macros/page">
+  
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/showNewDBEntries.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,25 @@
+<html tal:define="newEntries options/newEntries">
+<body>
+<h2>New entries</h2>
+<form action="createNewStaffObjects">
+<table border="1">
+  <tr>
+    <th>First name</th>
+    <th>Last name</th>
+    <th>Department</th>
+    <th>Stay from</th>
+    <th>e_mail (without @)</th>
+  <tr tal:repeat="newEntry newEntries">
+    <td tal:content="python:here.decode(newEntry.first_name)" />
+    <td tal:content="python:here.decode(newEntry.last_name)" />
+    <td tal:content="python:here.decode(newEntry.department)"/>
+    <td tal:content="python:here.decode(newEntry.date_from)"/>
+    <td><input tal:attributes="name python:here.urlQuote(newEntry.key)" size="20"/></td>
+  </tr>
+</table>
+<p>
+  <input type="submit" name="submit">
+</p>
+</form>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/talks_full_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,71 @@
+<html metal:use-macro="here/main_template/macros/page">
+<head>
+<title tal:content="template/title">The title</title>
+</head>
+<body>
+
+<tal:block metal:fill-slot="body" tal:define="found python:here.ZSQLFind()[0]">
+<table>
+	  <td valign="top" width="610"> 
+        <div id="Photo" style="position:absolute; width:200px; height:265px; z-index:2; left:483px; top:61px; visibility:visible"> 
+       [FMP-if: image .neq.] 
+               <b><img src="http://www.mpiwg-berlin.mpg.de/[FMP-Image: image]"></b> 
+      [FMP-else]&nbsp;[/FMP-if] 
+       </div>
+      <div id="NameTitle" style="position:absolute; width:323px; height:37px; z-index:3; left: 161px; top: 63px; visibility: visible"> 
+          <h3><span tal:replace="found/title"/> <span tal:replace="found/vorname"/> <span tal:replace="found/name"/></h3>
+      </div>
+        <div id="Position" style="position:absolute; width:323px; height:30px; z-index:5; left: 161px; top: 115px; visibility: visible"> 
+          <h4><span tal:replace="found/position"/></h4>
+      </div>
+        <div id="StayAtMpiwg" style="position:absolute; width:323px; height:32px; z-index:6; left: 161px; top: 158px; visibility: visible"> 
+          <p>Residence:<br>
+          <span tal:replace="found/stay_at_mpiwg"/></p>
+      </div>
+        <div id="Adress" style="position:absolute; width:323px; height:90px; z-index:4; left: 161px; top: 210px"> 
+          <p>Max Planck Institute for the History of Science<br>
+          Wilhelmstra&szlig;e 44<br>
+          D - 10117 Berlin<br>
+          Germany</p>
+	  <p class="p_indent"> <img src="bilder/RightArrowSmall.jpg" width="17" height="9" border="0"> 
+              <a tal:attributes="href python:'members/'+found.username"> 
+              main </a> </p>
+        </div>
+	 
+          
+            
+<!-- middle right (PIM) -->
+        <div id="ContactsImg" style="position:absolute; width:355px; height:114px; z-index:1; left: 286px; top: 329px; visibility: visible;"> 
+        <table width="400" border="0">
+           <tal:block tal:define="founds4 python:here.ZSQLInlineSearch(storename='search4',_table='talks',id_main=found.id,_sort='priority')">
+        
+	  <div tal:condition="founds4" id="Publications" style="position:relative; width:581px; z-index:16;"> 
+            <img src="images/en/Fieldnames72_NBTalksPres.jpg" width="211" height="33"> 
+            <p> </p>
+	    <tal:block tal:repeat="found4 founds4">
+            
+            <p tal:condition="not:python:here.ZSQLisEmpty(found4.link)" class="p_indent"> <a tal:attributes="href found4/link"><img src="bilder/RightArrowSmall.jpg" width="17" height="9" border="0">&nbsp; 
+              <span tal:replace="found4/date"/> &#150; <span tal:replace="found4/place"/> &#150; <span tal:replace="found4/title"/>
+              </a></p>
+
+            <p tal:condition="python:here.ZSQLisEmpty(found4.link)" class="p_indent"><img src="bilder/RightArrowSmall.jpg" width="17" height="9" border="0">&nbsp; 
+	      <span tal:replace="found4/date"/> &#150; <span tal:replace="found4/place"/> &#150; <span tal:replace="found4/title"/>
+            </p>
+            </tal:block>
+            
+            <p> 
+              <!-- Please do not delete -->
+              &nbsp;</p>
+            </div>
+	 </tal:block>
+	
+</table>
+</tal:block>
+  </body>
+</html>
+<!-- to be done institutsbiliographie integrieren
+images
+weitere seiten fuer mehr als 5 treffer (publ./talks/teaching)
+bilbiography einfuegen
+published yes or no abfragen
+-->
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/teaching_full_main.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,62 @@
+<html metal:use-macro="here/main_template/macros/page">
+<head>
+<title tal:content="template/title">The title</title>
+</head>
+<body>
+
+<tal:block metal:fill-slot="body" tal:define="found python:here.ZSQLFind()[0]">
+<table>
+	  <td valign="top" width="610"> 
+        <div id="Photo" style="position:absolute; width:200px; height:265px; z-index:2; left:483px; top:61px; visibility:visible"> 
+       [FMP-if: image .neq.] 
+               <b><img src="http://www.mpiwg-berlin.mpg.de/[FMP-Image: image]"></b> 
+      [FMP-else]&nbsp;[/FMP-if] 
+       </div>
+      <div id="NameTitle" style="position:absolute; width:323px; height:37px; z-index:3; left: 161px; top: 63px; visibility: visible"> 
+          <h3><span tal:replace="found/title"/> <span tal:replace="found/vorname"/> <span tal:replace="found/name"/></h3>
+      </div>
+        <div id="Position" style="position:absolute; width:323px; height:30px; z-index:5; left: 161px; top: 115px; visibility: visible"> 
+          <h4><span tal:replace="found/position"/></h4>
+      </div>
+        <div id="StayAtMpiwg" style="position:absolute; width:323px; height:32px; z-index:6; left: 161px; top: 158px; visibility: visible"> 
+          <p>Residence:<br>
+          <span tal:replace="found/stay_at_mpiwg"/></p>
+      </div>
+        <div id="Adress" style="position:absolute; width:323px; height:90px; z-index:4; left: 161px; top: 210px"> 
+          <p>Max Planck Institute for the History of Science<br>
+          Wilhelmstra&szlig;e 44<br>
+          D - 10117 Berlin<br>
+          Germany</p>
+	  <p class="p_indent"> <img src="bilder/RightArrowSmall.jpg" width="17" height="9" border="0"> 
+              <a tal:attributes="href python:'members/'+found.username"> 
+              main </a> </p>
+        </div>
+	 
+          
+            
+<!-- middle right (PIM) -->
+        <div id="ContactsImg" style="position:absolute; width:355px; height:114px; z-index:1; left: 286px; top: 329px; visibility: visible;"> 
+        <table width="400" border="0">
+        
+	  <tal:block tal:define="founds5 python:here.ZSQLInlineSearch(storename='search5',_table='teaching',id_main=found.id,_max=5,_sort='priority')">
+         
+          <div tal:condition="founds5" id="Teaching" style="position:relative; width:581px; z-index:18;"> 
+            <img src="images/en/Fieldnames72_NBTeaching.jpg" width="211" height="33"> 
+            <p> </p>
+	    <tal:block tal:repeat="found5 founds5">
+            
+              <p tal:condition="not:python:here.ZSQLisEmpty(found5.link)" class="p_indent"> <a tal:attributes="href found4/link"><img src="bilder/RightArrowSmall.jpg" width="17" height="9" border="0">&nbsp; 
+		  <span tal:replace="found5/date"/> &#150; <span tal:replace="found5/place"/> &#150; <span tal:replace="found5/title"/>
+              </a></p>
+
+              <p  tal:condition="python:here.ZSQLisEmpty(found5.link)" class="p_indent"><img src="bilder/RightArrowSmall.jpg" width="17" height="9" border="0">&nbsp; 
+	      <span tal:replace="found5/date"/> &#150; <span tal:replace="found5/place"/> &#150; <span tal:replace="found5/title"/>
+               </p>
+	    </tal:block>
+</div>
+	</tal:block>
+</table>
+</tal:block>
+  </body>
+</html>
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/updatePersonalwww.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,14 @@
+<html>
+  <head>
+    <title>update personal_www from filemaker output</title>
+    <meta http-equiv="content-type" content="text/html;charset=utf-8">
+  </head>
+  <body>
+    <h2>update personal www from filemaker output</h2>
+    <p>To update from filemaker upload an xml-export file from filemaker.</p>
+    <form action="updatePersonalwww" enctype="multipart/form-data" method="POST"> 
+      <input type="file" name="uploadfile">
+      <input type="submit" value="upload"> 
+   </form>
+  </body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/zpt/updatePersonalwww_check.zpt	Thu Jan 10 17:52:13 2013 +0100
@@ -0,0 +1,55 @@
+<html tal:define="news here/REQUEST/SESSION/personal_www/news;
+                  conflicts here/REQUEST/SESSION/personal_www/conflicts;
+                  resultSet here/REQUEST/SESSION/personal_www/resultSet;"
+	>
+	<body>
+		<h1>Check upload</h1>
+		<form method="post" action="updatePersonalwww_doIt">
+		<h2>New</h2>
+		<table>
+			<tr tal:repeat="new news">
+				<td><span tal:replace="python:resultSet[new]['first_name']">first</span>
+					<span tal:replace="python:resultSet[new]['last_name']">last</span> 
+				</td>	
+				<td>
+					<input type="checkbox" tal:attributes="name python:here.urlQuote(new.encode('utf-8'))" checked="True" value="new"/>
+				</td>
+			</tr>
+		</table>
+		
+		<h2>Conflicts</h2>
+		<table border="1">
+			<tr tal:repeat="conflict python:conflicts.keys()">
+				<td valign="top"><span tal:replace="python:resultSet[conflict]['first_name']">first</span>
+					<span tal:replace="python:resultSet[conflict]['last_name']">last</span> 
+				</td>	
+				<td>
+						<tal:x repeat="cf python:conflicts[conflict]">
+						<table border="1">
+							<tr>
+								<td bgcolor="green" colspan="3"><span tal:replace="python:cf[0]">feld</span></td>
+							</tr>
+							<tr>
+								<td valign="top"><input type="radio" tal:attributes="name python:conflict+'_'+cf[0]" value="stored" grant all privilege checked="True"></td>
+								<td valign="top">stored:</td>
+								<td><span tal:replace="python:cf[1]">stored value</span></td>
+							</tr>
+							<tr>
+								<td valign="top"><input type="radio" tal:attributes="name python:conflict+'_'+cf[0]" value="xml" ></td>
+								<td valign="top">xml-file:</td>
+								<td><span tal:replace="python:cf[2]">value from xml-file</span></td>
+							</tr>
+							<!--  <tr>
+								<td valign="top"><input type="radio" tal:attributes="name python:conflict+'_'+cf[0]" value="reject"></td>
+								<td valign="top">reject</td>
+								<td>&nbsp;</td>
+							</tr>-->
+						</table>	
+					</tal:x>
+				</td>
+			</tr>
+		</table>
+		<input type="submit">
+		</form>
+	</body>
+</html>
\ No newline at end of file