diff --git a/bt5/erp5_safeimage/ExtensionTemplateItem/ERP5SafeImage_Selenium.py b/bt5/erp5_safeimage/ExtensionTemplateItem/ERP5SafeImage_Selenium.py
new file mode 100644
index 0000000000000000000000000000000000000000..1fcd8a01b04b85fa06fbf3828f0e67ab45f2d60d
--- /dev/null
+++ b/bt5/erp5_safeimage/ExtensionTemplateItem/ERP5SafeImage_Selenium.py
@@ -0,0 +1,51 @@
+import Image as PIL_Image
+import os
+import transaction
+from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
+
+
+class FileUpload(file):
+  """Act as an uploaded file.
+  """
+  __allow_access_to_unprotected_subobjects__ = 1
+  def __init__(self, path, name):
+    self.filename = name
+    file.__init__(self, path)
+    self.headers = {}
+
+def makeFilePath(name):
+ # return os.path.join(os.path.dirname(__file__), 'tmp', name)
+  return name
+
+def makeFileUpload(name, as_name=None):
+  if as_name is None:
+    as_name = name
+  path = makeFilePath(name)
+  return FileUpload(path, as_name)
+
+
+def uploadImage(self):
+    portal = self.getPortalObject()
+    image = portal.restrictedTraverse('portal_skins/erp5_safeimage/img/image_test.jpg')
+    path_image = "tmp/selenium_image_test.jpg"
+    fd = os.open(path_image, os.O_CREAT | os.O_RDWR)
+    os.write(fd,str(image.data))
+    os.close(fd)
+    tile_image_transformed = makeFileUpload(path_image)
+    tile_transformed = self.image_module.newContent(portal_type='Image Tile Transformed',
+          title='testTileTransformed', id='testTileTransformed',
+          file=tile_image_transformed, filename='testTileTransformed')
+    if tile_transformed:
+      return True
+    else:
+      return False
+
+def cleanUp(self):
+    portal = self.getPortalObject()
+    print "exists path: %r" %os.path.exists("tmp/selenium_image_test.jpg")
+    if os.path.exists("tmp/selenium_image_test.jpg"):
+      print "REMOVE IMAGE: %s" %(os.remove("tmp/selenium_image_test.jpg"))
+      portal.image_module.manage_delObjects(ids=['testTileTransformed'])
+      return True
+    else:
+      return False
diff --git a/bt5/erp5_safeimage/ExtensionTemplateItem/ERP5ZoomifyImage.py b/bt5/erp5_safeimage/ExtensionTemplateItem/ERP5ZoomifyImage.py
new file mode 100644
index 0000000000000000000000000000000000000000..64117892a6d4df4a741515d090b5081606edb659
--- /dev/null
+++ b/bt5/erp5_safeimage/ExtensionTemplateItem/ERP5ZoomifyImage.py
@@ -0,0 +1,576 @@
+##############################################################################
+# Copyright (C) 2005  Adam Smith  asmith@agile-software.com
+# 
+# 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
+##############################################################################
+
+import os, sys, shutil, tempfile
+import Image
+from cStringIO import StringIO
+from zLOG import LOG,ERROR,INFO,WARNING
+from OFS.Image import File, Image
+import os, transaction
+from AccessControl import getSecurityManager, ClassSecurityInfo
+from Globals import package_home
+import Image as PIL_Image
+import thread
+import random
+import base64
+from OFS.Folder import Folder 
+
+class ZoomifyBase:
+
+  _v_imageFilename = ''
+  format = ''
+  originalWidth = 0
+  originalHeight = 0
+  _v_scaleInfo = []
+  numberOfTiles = 0
+  _v_tileGroupMappings = {}
+  qualitySetting = 80
+  tileSize = 256
+  my_file = StringIO() 
+
+  def openImage(self):
+    """ load the image data """
+
+    pass
+    return
+
+  def getImageInfo(self):
+    """ """
+
+    image = self.openImage()
+    self.format = image.format
+    self.originalWidth, self.originalHeight = image.size
+    image = None
+    width, height = (self.originalWidth, self.originalHeight)
+    self._v_scaleInfo = [(width, height)]
+    while (width > self.tileSize) or (height > self.tileSize):
+      width, height = (width / 2, height / 2)
+      self._v_scaleInfo.insert(0, (width, height))
+    totalTiles=0
+    tier, rows, columns = (0,0,0)
+    for tierInfo in self._v_scaleInfo:
+      rows = height/self.tileSize
+      if height % self.tileSize > 0:
+        rows +=1
+      columns = width/self.tileSize
+      if width%self.tileSize > 0:
+        columns += 1
+      totalTiles += rows * columns
+      tier += 1
+
+  def getImageMetadata(self):
+    """ given an image name, load it and extract metadata """
+
+    image = self.openImage()
+    self.format = image.format
+    self.originalWidth, self.originalHeight = image.size
+    image = None
+    # get scaling information
+    width, height = (self.originalWidth, self.originalHeight)
+    self._v_scaleInfo = [(width, height)]
+    while (width > self.tileSize) or (height > self.tileSize):
+      width, height = (width / 2, height / 2)
+      self._v_scaleInfo.insert(0, (width, height))
+    # tile and tile group information
+    self.preProcess()
+    return
+
+  def createDataContainer(self, imageName):
+    """ create a container for tile groups and tile metadata """
+
+    pass
+    return
+
+  def getAssignedTileContainerName(self, tileFileName=None):
+    """ return the name of the tile group for the indicated tile """
+    if tileFileName:
+      if hasattr(self, '_v_tileGroupMappings') and self._v_tileGroupMappings:
+        containerName = self._v_tileGroupMappings.get(tileFileName, None)
+        if containerName:
+          return containerName
+    x = self.getNewTileContainerName()
+    return x
+
+  def getNewTileContainerName(self, tileGroupNumber=0):
+    """ return the name of the next tile group container """
+
+    return 'TileGroup' + str(tileGroupNumber)
+
+  def createTileContainer(self, tileContainerName=None):
+    """ create a container for the next group of tiles within the data container """
+
+    pass
+    return
+
+  def getTileFileName(self, scaleNumber, columnNumber, rowNumber):
+    """ get the name of the file the tile will be saved as """
+
+    return '%s-%s-%s.jpg' % (str(scaleNumber), str(columnNumber), str(rowNumber))
+
+  def getFileReference(self, scaleNumber, columnNumber, rowNumber):
+    """ get the full path of the file the tile will be saved as """
+
+    pass
+    return
+
+  def getNumberOfTiles(self):
+    """ get the number of tiles generated 
+        Should this be implemented as a safeguard, or just use the count of 
+        tiles gotten from processing? (This would make subclassing a little
+        easier.) """
+
+    return self.numberOfTiles
+
+  def getXMLOutput(self):
+    """ create xml metadata about the tiles """
+
+    numberOfTiles = self.getNumberOfTiles()
+    xmlOutput = '<IMAGE_PROPERTIES WIDTH="%s" HEIGHT="%s" NUMTILES="%s" NUMIMAGES="1" VERSION="1.8" TILESIZE="%s" />'
+    xmlOutput = xmlOutput % (str(self.originalWidth),
+            str(self.originalHeight), str(numberOfTiles), str(self.tileSize))
+    return xmlOutput
+
+  def saveXMLOutput(self):
+    """ save xml metadata about the tiles """
+
+    pass
+    return
+
+  def saveTile(self, image, scaleNumber, column, row):
+    """ save the cropped region """
+
+    pass
+    return
+
+  def processImage(self):
+    """ starting with the original image, start processing each row """
+    tier=(len(self._v_scaleInfo) -1)
+    row = 0
+    ul_y, lr_y = (0,0)
+    root, ext = os.path.splitext(self._v_imageFilename)
+    if not root:
+      root = self._v_imageFilename
+    ext = '.jpg'
+    image = self.openImage()
+    while row * self.tileSize < self.originalHeight:
+      ul_y = row * self.tileSize
+      if (ul_y + self.tileSize) < self.originalHeight:
+        lr_y = ul_y + self.tileSize
+      else:
+        lr_y = self.originalHeight
+      print "Going to open image"
+      imageRow = image.crop([0, ul_y, self.originalWidth, lr_y])
+      saveFilename = root + str(tier) + '-' + str(row) +  ext
+      if imageRow.mode != 'RGB':
+        imageRow = imageRow.convert('RGB')
+      imageRow.save(os.path.join(tempfile.gettempdir(), saveFilename),
+                                                        'JPEG', quality=100)
+      print "os path exist : %r" % os.path.exists(os.path.join(
+                                        tempfile.gettempdir(), saveFilename))
+      if os.path.exists(os.path.join(tempfile.gettempdir(), saveFilename)): 
+        self.processRowImage(tier=tier, row=row)
+      row += 1
+
+  def processRowImage(self, tier=0, row=0):
+    """ for an image, create and save tiles """
+
+    print '*** processing tier: ' + str(tier) + ' row: ' + str(row)
+    tierWidth, tierHeight = self._v_scaleInfo[tier]
+    rowsForTier = tierHeight/self.tileSize
+    if tierHeight % self.tileSize > 0:
+      rowsForTier +=1
+    root, ext = os.path.splitext(self._v_imageFilename)  
+    if not root:
+      root = self._v_imageFilename
+    ext = '.jpg'
+    imageRow = None
+    if tier == (len(self._v_scaleInfo) -1):
+      firstTierRowFile = root + str(tier) + '-' + str(row) + ext
+      if os.path.exists(os.path.join(tempfile.gettempdir(),firstTierRowFile)):
+        imageRow = PIL_Image.open(os.path.join(tempfile.gettempdir(), 
+                                                    firstTierRowFile))
+    else:
+      # create this row from previous tier's rows
+      imageRow = PIL_Image.new('RGB', (tierWidth, self.tileSize))
+      firstRowFile = root + str(tier+1) + '-' + str(row + row) + ext
+      firstRowWidth, firstRowHeight = (0,0)
+      secondRowWidth, secondRowHeight = (0,0)
+      if os.path.exists(os.path.join(tempfile.gettempdir(),firstRowFile)):
+        firstRowImage = PIL_Image.open(os.path.join(tempfile.gettempdir(),
+                                                         firstRowFile))
+        firstRowWidth, firstRowHeight = firstRowImage.size
+        imageRow.paste(firstRowImage, (0,0))
+        os.remove(os.path.join(tempfile.gettempdir(), firstRowFile))
+      secondRowFile = root + str(tier+1) + '-' + str(row + row +1) + ext
+      # there may not be a second row at the bottom of the image...
+      if os.path.exists(os.path.join(tempfile.gettempdir(), secondRowFile)):
+        secondRowImage = PIL_Image.open(os.path.join(tempfile.gettempdir(),
+                                                        secondRowFile))
+        secondRowWidth, secondRowHeight = secondRowImage.size
+        imageRow.paste(secondRowImage, (0, firstRowHeight))
+        os.remove(os.path.join(tempfile.gettempdir(), secondRowFile))
+      # the last row may be less than self.tileSize...
+      if (firstRowHeight + secondRowHeight) < (self.tileSize*2):
+        imageRow = imageRow.crop((0, 0, tierWidth,
+                               (firstRowHeight+secondRowHeight)))
+    if imageRow:
+      # cycle through columns, then rows
+      column = 0
+      imageWidth, imageHeight = imageRow.size
+      ul_x, ul_y, lr_x, lr_y = (0,0,0,0) # final crop coordinates
+      while not ((lr_x == imageWidth) and (lr_y == imageHeight)):
+        # set lower right cropping point
+        if (ul_x + self.tileSize) < imageWidth:
+          lr_x = ul_x + self.tileSize
+        else:
+          lr_x = imageWidth
+        if (ul_y + self.tileSize) < imageHeight:
+          lr_y = ul_y + self.tileSize
+        else:
+          lr_y = imageHeight
+        self.saveTile(imageRow.crop([ul_x, ul_y, lr_x, lr_y]), tier,
+                                                        column, row)
+        self.numberOfTiles += 1
+        # set upper left cropping point
+        if (lr_x == imageWidth):
+          ul_x=0
+          ul_y = lr_y
+          column = 0
+        else:
+          ul_x = lr_x
+          column += 1
+      if tier > 0:
+        # a bug was discovered when a row was exactly 1 pixel in height
+        # this extra checking accounts for that
+        if imageHeight > 1:
+          tempImage = imageRow.resize((imageWidth/2, imageHeight/2),
+                                                     PIL_Image.ANTIALIAS)
+          tempImage.save(os.path.join(tempfile.gettempdir(), root + str(tier)
+                                       + '-' + str(row) + ext))
+          tempImage = None
+      rowImage = None
+      if tier > 0:
+        if row % 2 != 0:
+          self.processRowImage(tier=(tier-1), row=((row-1)/2))
+        elif row == rowsForTier-1:
+          self.processRowImage(tier=(tier-1), row=(row/2))
+
+  def ZoomifyProcess(self, imageNames):
+    """ the method the client calls to generate zoomify metadata """
+
+    pass
+    return
+
+  def preProcess(self):
+    """ plan for the arrangement of the tile groups """
+
+    tier = 0
+    tileGroupNumber = 0
+    numberOfTiles = 0
+    for width, height in self._v_scaleInfo:
+      #cycle through columns, then rows
+      row, column = (0,0)
+      ul_x, ul_y, lr_x, lr_y = (0,0,0,0)  #final crop coordinates
+      while not ((lr_x == width) and (lr_y == height)):
+        tileFileName = self.getTileFileName(tier, column, row)
+        tileContainerName = self.getNewTileContainerName(
+                                        tileGroupNumber=tileGroupNumber)
+        if numberOfTiles ==0:
+          self.createTileContainer(tileContainerName=tileContainerName)
+        elif (numberOfTiles % self.tileSize) == 0:
+          tileGroupNumber += 1
+          tileContainerName = self.getNewTileContainerName(
+                                       tileGroupNumber=tileGroupNumber)
+          self.createTileContainer(tileContainerName=tileContainerName)
+        self._v_tileGroupMappings[tileFileName] = tileContainerName
+        numberOfTiles += 1
+        # for the next tile, set lower right cropping point
+        if (ul_x + self.tileSize) < width:
+          lr_x = ul_x + self.tileSize
+        else:
+          lr_x = width
+        if (ul_y + self.tileSize) < height:
+          lr_y = ul_y + self.tileSize
+        else:
+          lr_y = height
+        # for the next tile, set upper left cropping point
+        if (lr_x == width):
+          ul_x=0
+          ul_y = lr_y
+          column = 0
+          row += 1
+        else:
+          ul_x = lr_x
+          column += 1
+      tier += 1
+
+
+class ZoomifyZopeProcessor(ZoomifyBase):
+  """ basic functionality to provide Zoomify functionality inside Zope """
+
+  _v_imageObject = None
+  _v_saveFolderObject = None
+  _v_transactionCount = 0
+  security = ClassSecurityInfo()
+  security.declareObjectProtected('Add Documents, Images, and Files')
+
+  def openImage(self):
+    """ load the image data """
+
+    return PIL_Image.open(self._v_imageObject.name)
+
+  def createDefaultViewer(self):
+    """ add the default Zoomify viewer to the Zoomify metadata """
+
+    # also, add the default zoomifyViewer here if a zoomify viewer is acquirable
+    # (could this be done a better way, like using the 'web methods' 
+    # approach that points to ZMI screens that are DTML or ZPT files
+    # in the product package)?
+    if not hasattr(self._v_saveFolderObject, 'default_ZoomifyViewer'):
+      defaultViewerPath = os.path.join(package_home(globals()), 'www',
+                                                  'zoomifyViewer.swf')
+      if os.path.isfile(defaultViewerPath):
+        fileContent = open(defaultViewerPath).read()
+        self._v_saveFolderObject._setObject('default_ZoomifyViewer', 
+                               File('default_ZoomifyViewer', '', fileContent, 
+                                    'application/x-shockwave-flash', ''))
+    transaction.savepoint()
+    return
+
+  def createDataContainer(self):
+    """ create a folder that contains all the tiles of the image """
+
+    self._v_saveToLocation = str(self._v_imageObject.getId()) + '_data'
+    parent = self._v_imageObject.aq_parent
+    if hasattr(parent, self._v_saveToLocation):
+      # allow for tiles to be updated from a changed image
+      parent._delObject(self._v_saveToLocation)
+    if not hasattr(parent, self._v_saveToLocation):
+      newFolder = Folder()
+      newFolder.id = self._v_saveToLocation
+      parent._setObject(self._v_saveToLocation, newFolder)
+    self._v_saveFolderObject = parent[self._v_saveToLocation]
+    transaction.savepoint()
+    return
+
+  def createTileContainer(self, tileContainerName=None):
+    """ create a container for the next group of tiles within the data container """ 
+
+    if hasattr(self._v_saveFolderObject, tileContainerName):
+      # allow for tiles to be updated from a changed image
+      self._v_saveFolderObject._delObject(tileContainerName)
+    if not hasattr(self._v_saveFolderObject, tileContainerName):
+      newFolder = Folder()
+      newFolder.id = tileContainerName
+      self._v_saveFolderObject._setObject(tileContainerName, newFolder)
+    transaction.savepoint()
+    return
+
+  def getNumberOfTiles(self):
+    """ get the number of tiles generated 
+        Should this be implemented as a safeguard, or just use the count of 
+        tiles gotten from processing? (This would make subclassing a little
+        easier.) """
+    return self.numberOfTiles
+
+  def saveXMLOutput(self):
+    """ save xml metadata about the tiles """
+
+    if hasattr(self._v_saveFolderObject, 'ImageProperties.xml'):
+      # allow file to be updated from a changed image, regenerated tiles
+      self._v_saveFolderObject._delObject('ImageProperties.xml')
+    self._v_saveFolderObject._setObject('ImageProperties.xml', 
+                        File('ImageProperties.xml', '', self.getXMLOutput(), 
+                             'text/xml', ''))
+    transaction.savepoint()
+    return
+
+  def saveTile(self, image, scaleNumber, column, row):
+    """ save the cropped region """
+
+    w,h = image.size
+    if w != 0 and h != 0:
+      tileFileName = self.getTileFileName(scaleNumber, column, row)
+      tileContainerName = self.getAssignedTileContainerName(
+                                          tileFileName=tileFileName)
+      tileImageData = StringIO()
+      image.save(tileImageData, 'JPEG', quality=self.qualitySetting)
+      tileImageData.seek(0)
+      if hasattr(self._v_saveFolderObject, tileContainerName):
+        tileFolder = getattr(self._v_saveFolderObject, tileContainerName)
+        # if an image of this name already exists, delete and replace it.
+        if hasattr(tileFolder, tileFileName):
+          tileFolder._delObject(tileFileName)
+        # finally, save the image data as a Zope Image object
+        tileFolder._setObject(tileFileName, Image(tileFileName, '', 
+                                              '', 'image/jpeg', ''))
+        tileFolder._getOb(tileFileName).manage_upload(tileImageData)
+      self._v_transactionCount += 1
+      if self._v_transactionCount % 10 == 0:
+        transaction.savepoint()
+    return
+
+  def encrypto(self):
+    if self.transformed:
+      # def encrypto(self,message='Attack at dawn'):
+      #   """encrypto each thing"""
+      #   key ='abcdefghijklmnop'
+      #   iv = Random.new().read(AES.block_size)
+      #   EncodeIV = lambda : base64.b64encode(iv)
+      #   EncodeAES = lambda c, s: base64.b64encode(c.encrypt(message))
+      #   IVcoded  = EncodeIV()
+      #   cipher = AES.new(key,AES.MODE_CFB,iv)
+      #   msg  = EncodeAES(cipher,key)
+      #   return msg    
+      pass
+    else:
+      pass
+    return
+
+  def _process(self):
+    """ the actual zoomify processing workflow """
+
+    self.createDataContainer()
+    self.createDefaultViewer()
+    self.openImage()
+    self.getImageMetadata()
+    self.processImage()
+    self.saveTransformedFile()
+    self.saveXMLOutput()
+    self.encrypto()
+    return
+
+  def saveTransformedFile(self):
+    pass
+    return
+
+  def _ZoomifyProcess(self):
+    """ factored out ZODB connection handling """
+
+    #import Zope
+    #app = Zope.app()
+    #get_transaction().begin()
+    self._process()
+    #app._p_jar.close()
+    #del app
+    return
+
+  security.declareProtected('Add Documents, Images, and Files', 'ZoomifyProcess')
+  def ZoomifyProcess(self, id, imageObject=None):
+    """ factored out threading of process (removed for now) """
+    if imageObject:
+      self._v_imageObject = imageObject
+      self._v_imageFilename = id
+      self._ZoomifyProcess()
+    return
+
+class ERP5ZoomifyZopeProcessor(ZoomifyZopeProcessor):
+
+  def __init__(self, document,transformed=None):
+     self.document = document
+     self.transformed = transformed
+     self.count = 0 
+
+  def createTileContainer(self, tileContainerName=None):
+    """ create each TileGroup """
+
+    self.document.newContent(portal_type="Image Tile Group", 
+                   title=tileContainerName, id=tileContainerName, 
+                   filename=tileContainerName)
+    return 
+
+  def createDefaultViewer(self):
+    """ add the default Zoomify viewer to the Zoomify metadata """
+    pass
+    return
+
+  def createDataContainer(self, imageName="None"):
+    """Creates nothing coz we are already in the container"""
+    pass
+    return
+
+  def _updateTransformedFile(self,tile_group_id,tile_title):
+    """create and save the transform file"""
+    num = random.choice([0,1])
+    while num >= 0: 
+      algorithm = random.choice(['sepia','brightness','noise','lighten',
+                                  'posterize','edge','none'])
+      if algorithm == 'lighten':
+        param1 = random.choice([-0.6,-0.5,-0.4,-0.3,-0.2,-0.1,0.1,0.2,
+                                 0.3,0.4,0.5,0.6])
+        param2 = 0
+      elif algorithm == 'posterize':
+        param1 = random.choice([4,5,6,7,8,9,10,11,12,13,14,15,16,17,
+                                18,19,20,21])
+        param2 = 0
+      elif algorithm == 'brightness':
+        param1 = random.choice([-80,-60,-40,-20,20,40,60,80])
+        param2 = random.choice([-0.3,-0.2,-0.1,0,0.1,0.5,0.9])
+      else:
+        param1 = 0
+        param2 = 0
+      my_text = '%s %s %s %s %s %s \n' %(tile_group_id, tile_title, 
+                                    algorithm, param1, param2, num)
+      self.my_file.write(my_text)
+      num = num - 1
+
+
+  def saveTile(self, image, scaleNumber, column,row):
+    """save the cropped region"""
+    tileFileName = self.getTileFileName(scaleNumber, column, row)
+    tileContainerName = self.getAssignedTileContainerName(
+                                       tileFileName=tileFileName)
+    namesplit = tileFileName.split('.')
+    w,h = image.size
+    if w != 0 and h !=0:
+      tile_group_id = self.getAssignedTileContainerName()
+      tile_group=self.document[tile_group_id]
+      tileImageData= StringIO()
+      image.save(tileImageData, 'JPEG', quality=self.qualitySetting)
+      tileImageData.seek(0)
+      if tile_group is None:
+        raise AttributeError('unable to fine tile group %r' % tile_group_id)
+      w = tile_group.newContent(portal_type='Image', title=namesplit[0],
+                 id=namesplit[0], file=tileImageData, filename=namesplit[0])
+      if self.transformed:
+        self._updateTransformedFile(tile_group_id, namesplit[0])
+    return
+
+  def saveXMLOutput(self):
+    """save the xml file"""
+    my_string = StringIO()
+    my_string.write(self.getXMLOutput())
+    my_string.seek(0)
+    self.document.newContent(portal_type='Embedded File',
+                             id='ImageProperties.xml', file=my_string,
+                             filename='ImageProperties.xml')
+    return
+
+  def saveTransformedFile(self):
+    """add in Zope the transform file """
+    if self.transformed:
+      self.my_file.seek(0)
+      self.document.newContent(portal_type='Embedded File',
+                             id='TransformFile.txt', file=self.my_file,
+                             filename='TransformFile.txt')
+    return
+
+
+def getERP5ZoomifyProcessor(document,transformed=False):
+  return ERP5ZoomifyZopeProcessor(document,transformed)
+
diff --git a/bt5/erp5_safeimage/bt/revision b/bt5/erp5_safeimage/bt/revision
index 9a037142aa3c1b4c490e1a38251620f113465330..9d607966b721abde8931ddd052181fae905db503 100644
--- a/bt5/erp5_safeimage/bt/revision
+++ b/bt5/erp5_safeimage/bt/revision
@@ -1 +1 @@
-10
\ No newline at end of file
+11
\ No newline at end of file
diff --git a/bt5/erp5_safeimage/bt/template_extension_id_list b/bt5/erp5_safeimage/bt/template_extension_id_list
new file mode 100644
index 0000000000000000000000000000000000000000..f68a94cffa22cba6151b27fd9046ab624d0f5fc8
--- /dev/null
+++ b/bt5/erp5_safeimage/bt/template_extension_id_list
@@ -0,0 +1,2 @@
+ERP5SafeImage_Selenium
+ERP5ZoomifyImage
\ No newline at end of file