diff --git a/configure.zcml b/configure.zcml
index d482317..7a60e6a 100644
--- a/configure.zcml
+++ b/configure.zcml
@@ -417,8 +417,11 @@
 
   
+      name="varsubdir" />
+
+  
 
   
   
+  
   
   
   
diff --git a/integrator/README.txt b/integrator/README.txt
index 2c931f1..662dc50 100644
--- a/integrator/README.txt
+++ b/integrator/README.txt
@@ -29,6 +29,63 @@ configuration):
   >>> len(concepts) + len(resources)
   18
 
+
+External Collections
+====================
+
+The basis of our work will be ExternalCollection objects, i.e. concepts
+of the 'extcollection' type. We use an adapter for providing the attributes
+and methods of the external collect object.
+
+  >>> from loops.concept import Concept
+  >>> from loops.setup import addObject
+  >>> from loops.integrator.collection import ExternalCollectionAdapter
+  >>> tExternalCollection = concepts['extcollection']
+  >>> coll01 = addObject(concepts, Concept, 'coll01',
+  ...                    title=u'Collection One', type=tExternalCollection)
+  >>> aColl01 = ExternalCollectionAdapter(coll01)
+
+An external collection carries a set of attributes that control the access
+to the external system:
+
+  >>> aColl01.providerName, aColl01.baseAddress, aColl01.address, aColl01.pattern
+  (None, None, None, None)
+  >>> from loops.integrator.testsetup import dataDir
+  >>> aColl01.baseAddress = dataDir
+  >>> aColl01.address = 'topics'
+
+
+Directory Collection Provider
+-----------------------------
+
+The DirectoryCollectionProvider collects files from a directory in the
+file system. The parameters (directory paths) are provided by the calling
+object, the external collection itself.
+
+  >>> from loops.integrator.collection import DirectoryCollectionProvider
+  >>> dcp = DirectoryCollectionProvider()
+
+  >>> sorted(dcp.collect(aColl01))
+  ['programming/BeautifulProgram.pdf', 'programming/zope/zope3.txt']
+
+If we provide a selective pattern we get only part of the files:
+
+  >>> aColl01.pattern = r'.*\.txt'
+  >>> sorted(dcp.collect(aColl01))
+  ['programming/zope/zope3.txt']
+
+Let's now create the corresponding resource objects.
+
+  >>> aColl01.pattern = ''
+  >>> addresses = dcp.collect(aColl01)
+  >>> res = list(dcp.createExtFileObjects(aColl01, addresses))
+  >>> len(sorted(r.__name__ for r in res))
+  2
+  >>> xf1 = res[0]
+  >>> xf1.__name__
+  u'programming/BeautifulProgram.pdf'
+
+
 Fin de partie
 =============
 
diff --git a/integrator/collection.py b/integrator/collection.py
new file mode 100644
index 0000000..b978706
--- /dev/null
+++ b/integrator/collection.py
@@ -0,0 +1,99 @@
+#
+#  Copyright (c) 2007 Helmut Merz helmutm@cy55.de
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+"""
+Concept adapter(s) for external collections, e.g. a directory in the
+file system.
+
+$Id$
+"""
+
+import os, re
+from zope.component import adapts
+from zope.interface import implements, Attribute
+from zope.cachedescriptors.property import Lazy
+from zope.schema.interfaces import IField
+from zope.traversing.api import getName, getParent
+
+from cybertools.typology.interfaces import IType
+from loops.common import AdapterBase
+from loops.interfaces import IResource, IConcept
+from loops.integrator.interfaces import IExternalCollection
+from loops.integrator.interfaces import IExternalCollectionProvider
+from loops.resource import Resource
+from loops.setup import addObject
+from loops.type import TypeInterfaceSourceList
+
+
+TypeInterfaceSourceList.typeInterfaces += (IExternalCollection,)
+
+
+class ExternalCollectionAdapter(AdapterBase):
+    """ A concept adapter for accessing an external collection.
+        May delegate access to a named utility.
+    """
+
+    implements(IExternalCollection)
+    adapts(IConcept)
+
+    _adapterAttributes = ('context', '__parent__',)
+    _contextAttributes = list(IExternalCollection) + list(IConcept)
+
+    def create(self):
+        pass
+
+    def update(self):
+        pass
+
+
+class DirectoryCollectionProvider(object):
+    """ A utility that provides access to files in a directory.
+    """
+
+    implements(IExternalCollectionProvider)
+
+    def collect(self, client):
+        directory = self.getDirectory(client)
+        pattern = re.compile(client.pattern or '.*')
+        result = []
+        for path, dirs, files in os.walk(directory):
+            if files:
+                result.extend(os.path.join(path[len(directory)+1:], f)
+                                for f in files
+                                    if pattern.match(f))
+        return result
+
+    def createExtFileObjects(self, client, addresses, extFileType=None):
+        if extFileType is None:
+            extFileType = client.context.getLoopsRoot().getConceptManager()['extfile']
+        rm = client.context.getLoopsRoot().getResourceManager()
+        directory = self.getDirectory(client)
+        for addr in addresses:
+            name = addr
+            obj = addObject(rm, Resource, name,
+                            title=addr.decode('UTF-8'), type=extFileType,
+                            externalAddress=addr,
+                            storage='fullpath',
+                            storageParams=dict(subdirectory=directory))
+            yield obj
+
+    def getDirectory(self, client):
+        baseAddress = client.baseAddress or ''
+        address = client.address or ''
+        return os.path.join(baseAddress, address)
+
diff --git a/integrator/configure.zcml b/integrator/configure.zcml
index cc0be03..ad7799a 100644
--- a/integrator/configure.zcml
+++ b/integrator/configure.zcml
@@ -6,4 +6,17 @@
    i18n_domain="zope"
    >
 
+  
+
+  
+    
+    
+  
+
+  
+
 
diff --git a/integrator/interfaces.py b/integrator/interfaces.py
index 99e4816..a80e159 100644
--- a/integrator/interfaces.py
+++ b/integrator/interfaces.py
@@ -25,8 +25,91 @@ $Id$
 from zope.interface import Interface, Attribute
 from zope import interface, component, schema
 
+from loops.util import _
+
 
 class IExternalCollection(Interface):
-    """ A collection of resources.
+    """ A collection of resources, to be used for a concept adapter.
     """
 
+    providerName = schema.TextLine(
+            title=_(u'Provider name'),
+            description=_(u'The name of a utility that provides the '
+                           'external objects; default is a directory '
+                           'collection provider'),
+            required=False)
+    baseAddress = schema.TextLine(
+            title=_(u'Base address'),
+            description=_(u'A base path or URL for accessing this collection '
+                           'on the external system'),
+            required=False)
+    address = schema.TextLine(
+            title=_(u'Relative address'),
+            description=_(u'Optional second (local) part of the '
+                           'collection\'s address'),
+            required=False)
+    pattern = schema.TextLine(
+            title=_(u'Selection pattern'),
+            description=_(u'A regular expression for selecting external objects '
+                           'that should belong to this collection'),
+            required=False)
+
+    def create():
+        """ Select external objects that should belong to a collection
+            using all the informations in the attributes,
+            create a resource of type 'extfile' for each of them,
+            and associate them with this collection.
+            Fire appropriate events.
+        """
+
+    def update():
+        """ Check for new, changed, or deleted external objects.
+            Create an 'extfile' resource for new ones, fire appropriate
+            events for new, changed, or deleted ones.
+            Resources for deleted objects are not removed but should
+            be empty; they also should receive some state change.
+        """
+
+
+class IExternalCollectionProvider(Interface):
+    """ A utility that provides access to an external collection of objects.
+    """
+
+    def collect(clientCollection):
+        """ Select objects that should belong to a collection,
+            return an iterable of local address parts of the selected external
+            objects. The object specified by the 'clientCollection' argument
+            is usually the caller of the method and should provide the
+            IExternalCollection interface.
+        """
+
+    def createExtFileObjects(clientCollection, addresses, extFileType=None):
+        """ Create a resource of type 'extFileType' (default is the
+            type with the name 'extfile') for each of the addresses
+            provided. Return the list of objects created.
+        """
+
+
+class IAutoClassifier(Interface):
+    """ An adapter that more or less automagically assigns concepts to a
+        resource using some sort of selection criteria for the concepts
+        that should be considered.
+    """
+
+
+class IOntologyExporter(Interface):
+    """ An adapter for creating an XML file with all appropriate informations
+        from the context and its children, selecting children via a
+        pattern or a set of selection criteria.
+
+        This may then be used by an external tool for classifying
+        a set of external objects.
+    """
+
+
+class IClassificationImporter(Interface):
+    """ An Adapter for importing an XML file with classification
+        information for a collection of external objects."
+    """
+
+
diff --git a/integrator/testdata/topics/programming/BeautifulProgram.pdf b/integrator/testdata/topics/programming/BeautifulProgram.pdf
new file mode 100644
index 0000000..4ec732b
Binary files /dev/null and b/integrator/testdata/topics/programming/BeautifulProgram.pdf differ
diff --git a/integrator/testdata/topics/programming/zope/zope3.txt b/integrator/testdata/topics/programming/zope/zope3.txt
new file mode 100644
index 0000000..7f90f93
--- /dev/null
+++ b/integrator/testdata/topics/programming/zope/zope3.txt
@@ -0,0 +1,5 @@
+This file carries some information about Zope 3, the open-source
+web application server.
+
+It is used as an example document for integrating external resources
+into loops.
diff --git a/integrator/testsetup.py b/integrator/testsetup.py
index 1043316..4677b04 100644
--- a/integrator/testsetup.py
+++ b/integrator/testsetup.py
@@ -4,15 +4,20 @@ Set up a loops site for testing.
 $Id$
 """
 
+import os
 from zope import component
 
 from loops import util
+from loops.interfaces import IExternalFile
 from loops.concept import Concept
 from loops.resource import Resource
 from loops.integrator.interfaces import IExternalCollection
 from loops.knowledge.setup import SetupManager as KnowledgeSetupManager
+from loops.setup import SetupManager, addObject
 from loops.tests.setup import TestSite as BaseTestSite
 
+dataDir = os.path.join(os.path.dirname(__file__), 'testdata')
+
 
 class TestSite(BaseTestSite):
 
@@ -24,9 +29,12 @@ class TestSite(BaseTestSite):
         concepts, resources, views = self.baseSetup()
 
         tType = concepts.getTypeConcept()
-
-        tExtFile = concepts['extfile'] = Concept(u'External File')
-        tExtCollection = concepts['extcollection'] = Concept(u'External Collection')
+        tExtFile = addObject(concepts, Concept, 'extfile',
+                                title=u'External File', type=tType,
+                                typeInterface=IExternalFile)
+        tExtCollection = addObject(concepts, Concept, 'extcollection',
+                                title=u'External Collection', type=tType,
+                                typeInterface=IExternalCollection)
 
         self.indexAll(concepts, resources)
         return concepts, resources, views
diff --git a/organize/interfaces.py b/organize/interfaces.py
index 02e9994..e7cd780 100644
--- a/organize/interfaces.py
+++ b/organize/interfaces.py
@@ -27,7 +27,6 @@ from zope import interface, component, schema
 from zope.app import zapi
 from zope.app.principalannotation import annotations
 from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
-from zope.i18nmessageid import MessageFactory
 from zope.security.proxy import removeSecurityProxy
 
 from cybertools.organize.interfaces import IPerson as IBasePerson
diff --git a/resource.py b/resource.py
index a9b4857..dbda046 100644
--- a/resource.py
+++ b/resource.py
@@ -315,12 +315,20 @@ class ExternalFileAdapter(FileAdapter):
         self.context._storageParams = value
     storageParams = property(getStorageParams, setStorageParams)
 
-    @Lazy
-    def externalAddress(self):
+    def getExternalAddress(self):
+        return getattr(self.context, '_externalAddress', self.context.__name__)
+    def setExternalAddress(self, addr):
+        # TODO (?) - use intId as default?
+        self.context._externalAddress = addr
+    externalAddress = property(getExternalAddress, setExternalAddress)
+
+    #@Lazy
+    #def externalAddress(self):
         # or is this an editable attribute?
         # or some sort of subpath set during import?
         # anyway: an attribute of the context object.
-        return self.context.__name__
+        # TODO: use intId and store in special attribute for later reuse
+        #return self.context.__name__
 
     def setData(self, data):
         storageParams = self.storageParams