Index: lib/repo/memory_repository.rb
===================================================================
--- lib/repo/memory_repository.rb	(revision 1064)
+++ lib/repo/memory_repository.rb	(working copy)
@@ -24,8 +24,8 @@
   # Constructor: Connects to an existing Memory
   # repository; Note: A repository has to be created using
   # MemoryRepository.create(), if it is not yet existent
-  # Generally: Do not(!) call it with 3 parameters, use MemoryRepository.create() instead!
-  def initialize(location, is_admin=true, is_create_call=false)
+  # Generally: Do not(!) call it with 2 parameters, use MemoryRepository.create() instead!
+  def initialize(location)
     
     # variables
     @users = {}                                 # hash of users (key) with corresponding permissions (value)
@@ -37,21 +37,10 @@
     @repository_location = location
     
     
-    # hack(ish) functionality
-    if !is_create_call
-      begin
-        super(location) # dummy super() call to be ruby conformant (in fact, does nothing but raising an exception) 
-      rescue NotImplementedError; end
-      if !self.class.repository_exists?(location)
-        raise "Could not open repository at location #{location}"
-      end
-      return @@repositories[location] # return reference in question
-    else
-      if MemoryRepository.repository_exists?(location)
-        raise RepositoryCollision.new("There is already a repository at #{location}")
-      end
-      @@repositories[location] = self             # push new MemoryRepository onto repository list
+    if MemoryRepository.repository_exists?(location)
+      raise RepositoryCollision.new("There is already a repository at #{location}")
     end
+    @@repositories[location] = self             # push new MemoryRepository onto repository list
     
   end
   
@@ -65,17 +54,20 @@
     return false
   end
   
-  # Open repository at specified location (dummy permission file to unify API)
-  def self.open(location, is_admin=true, perm_file=nil)
-    return @@repositories[location]
-    #return MemoryRepository.new(location, is_admin)
+  # Open repository at specified location
+  def self.open(location)
+    if !self.repository_exists?(location)
+        raise "Could not open repository at location #{location}"
+      end
+    return @@repositories[location] # return reference in question
   end
   
   # Creates memory repository at "virtual" location (they are identifiable by location)
-  # perm_file is a parameter, which exists to conform with the API
-  def self.create(location, is_admin=true, perm_file=nil)
-    MemoryRepository.new(location, is_admin, true) # want to create a repository
-    return MemoryRepository.open(location, is_admin)
+  def self.create(location)
+    if !MemoryRepository.repository_exists?(location)
+      MemoryRepository.new(location) # create a repository if it doesn't exist
+    end
+    return true
   end
   
   # Destroys all repositories
@@ -202,7 +194,12 @@
     end
     @users[user_id] = permissions
   end
-  
+
+  # Semi-private - used by the bulk permissions assignments
+  def has_user?(user_id)
+    return @users.key?(user_id)
+  end    
+   
   # Removes a user from from the repository
   def remove_user(user_id)
     if !@users.key?(user_id)
@@ -243,8 +240,36 @@
     return @users[user_id]
   end
   
+  # Set permissions for many repositories
+  def self.set_bulk_permissions(repo_names, user_id_permissions_map)
+    repo_names.each do |repo_name|
+      repo = self.open(repo_name)
+      user_id_permissions_map.each do |user_id, permissions|
+        if(!repo.has_user?(user_id)) 
+          repo.add_user(user_id, permissions)
+        else
+          repo.set_permissions(user_id, permissions)
+        end
+      end
+    end
+    return true
+  end
+  
+  # Delete permissions for many repositories
+  def self.delete_bulk_permissions(repo_names, user_ids)
+    repo_names.each do |repo_name|
+      repo = self.open(repo_name)
+      user_ids.each do |user_id|
+        if(repo.has_user?(user_id))
+          repo.remove_user(user_id)
+        end
+      end
+    end
+    return true
+  end
+
+  
   private
-  
   # Creates a directory as part of the provided revision
   def make_directory(rev, full_path)
     if rev.path_exists?(full_path)
@@ -494,6 +519,7 @@
   
   private
   
+  
   def files_at_path_helper(path="/", only_changed=false, type=RevisionFile)
     # Automatically append a root slash if not supplied
     result = Hash.new(nil)
Index: lib/repo/repository.rb
===================================================================
--- lib/repo/repository.rb	(revision 1064)
+++ lib/repo/repository.rb	(working copy)
@@ -1,272 +1,336 @@
 module Repository
 
-# Permission constants for repositories
-class Permission
-  if !defined? WRITE  # avoid constant already defined warnings
-    WRITE      = 2
+  # Configuration for the repository library,
+  # which is set via Repository.get_class
+  @CONF = {}
+  def Repository.conf
+    return @CONF
   end
-  if !defined? READ
-    READ       = 4
-  end
-  if !defined? READ_WRITE
-    READ_WRITE = READ + WRITE
-  end
-  if !defined? ANY
-    ANY        = READ # any permission means at least read permission
-  end
-end
 
-# Exceptions for repositories
-class ConnectionError < Exception; end
-
-class Conflict < Exception
-  attr_reader :path
-  def initialize(path)
-    super()
-    @path = path
+  # Permission constants for repositories
+  class Permission
+    if !defined? WRITE  # avoid constant already defined warnings
+      WRITE      = 2
+    end
+    if !defined? READ
+      READ       = 4
+    end
+    if !defined? READ_WRITE
+      READ_WRITE = READ + WRITE
+    end
+    if !defined? ANY
+      ANY        = READ # any permission means at least read permission
+    end
   end
-  def to_s
-    return 'There was an unspecified conflict with file ' + @path
-  end
-end
-
-class FileExistsConflict < Conflict
-  def to_s
-    return "#{@path} could not be added - it already exists in the folder.  If you'd like to overwrite, try replacing the file instead."
-  end
-end
-
-class FileDoesNotExistConflict < Conflict
-  def to_s
-    return "#{@path} could not be changed - it was deleted since you last saw it"
-  end
-end
-
-class FileOutOfSyncConflict < Conflict
-  def to_s
-    return "#{@path} has been updated since you last saw it, and could not be changed"
-  end
-end
-
-class RepositoryCollision < Exception; end
-
-class AbstractRepository
-
-  # Initializes Object, and verifies connection to the repository back end.
-  # This should throw a ConnectionError if we're unable to connect.
-  # The is_admin flag indicates if we have admin privileges. If set to false,
-  # the repository relies on a third party to create repositories and manage its
-  # permissions.
-  def initialize(connect_string, is_admin=true)
-    raise NotImplementedError, "Repository.initialize(connect_string): Not yet implemented"
-  end
   
-  # Static method: Should report if a repository exists at given location
-  def self.repository_exists?(path)
-    raise NotImplementedError, "Repository::repository_exists? Not yet implemented"
-  end
+  # Exceptions for repositories
+  class ConnectionError < Exception; end
   
-  # Static method: Opens a repository at given location; returns an
-  # AbstractRepository instance
-  # The is_admin flag indicates if we have admin privileges. If set to false,
-  # the repository relies on a third party to create repositories and manage its
-  # permissions.
-  def self.open(connect_string, is_admin=true, perm_file=nil)
-    raise NotImplementedError, "Repository::open Not yet implemented"
+  class Conflict < Exception
+    attr_reader :path
+    def initialize(path)
+      super()
+      @path = path
+    end
+    def to_s
+      return 'There was an unspecified conflict with file ' + @path
+    end
   end
   
-  # Static method: Creates a new repository at given location; returns
-  # an AbstractRepository instance, with the repository opened.
-  # The is_admin flag indicates if we have admin privileges. If set to false,
-  # the repository relies on a third party to create repositories and manage its
-  # permissions.  
-  def self.create(connect_string, is_admin=true, perm_file=nil)
-    raise NotImplementedError, "Repository::create Not yet implemented"
+  class FileExistsConflict < Conflict
+    def to_s
+      return "#{@path} could not be added - it already exists in the folder.  If you'd like to overwrite, try replacing the file instead."
+    end
   end
   
-  # Given either an array of, or a single object of class RevisionFile, 
-  # return a stream of data for the user to download as the file(s).
-  def stringify_files(files)
-    raise NotImplementedError,  "Repository.download: Not yet implemented"
+  class FileDoesNotExistConflict < Conflict
+    def to_s
+      return "#{@path} could not be changed - it was deleted since you last saw it"
+    end
   end
-  alias download_as_string stringify_files
-
-  # Returns a transaction for the provided user and uses comment as the commit message
-  def get_transaction(user_id, comment)
-    raise NotImplementedError,  "Repository.get_transaction: Not yet implemented"
-  end  
   
-  # Commits a transaction associated with a repository
-  def commit(transaction)
-    raise NotImplementedError,  "Repository.commit: Not yet implemented"
+  class FileOutOfSyncConflict < Conflict
+    def to_s
+      return "#{@path} has been updated since you last saw it, and could not be changed"
+    end
   end
   
-  # Returns the latest Repository::AbstractRevision
-  def get_latest_revision
-    raise NotImplementedError, "Repository.get_latest_revision: Not yet implemented"
-  end
-    
-  # Return a Repository::AbstractRevision for a given revision_number
-  # if it exists
-  def get_revision(revision_number)
-    raise NotImplementedError,  "Repository.get_revision: Not yet implemented"
-  end
+  class RepositoryCollision < Exception; end
   
-  # Return a RepositoryRevision for a given timestamp
-  def get_revision_by_timestamp(timestamp)
-    raise NotImplementedError,  "Repository.get_revision_by_timestamp: Not yet implemented"
-  end
-   
-  # Adds a user with a given permission-set to the repository
-  def add_user(user_id, permissions)
-    raise NotImplementedError,  "Repository.add_user: Not yet implemented"
-  end
+  class AbstractRepository
   
-  # Removes user permissions for read & write access to the repository
-  def remove_user(user_id)
-    raise NotImplementedError,  "Repository.remove_user: Not yet implemented"
-  end
+    # Initializes Object, and verifies connection to the repository back end.
+    # This should throw a ConnectionError if we're unable to connect.
+    def initialize(connect_string)
+      raise NotImplementedError, "Repository.initialize(connect_string): Not yet implemented"
+    end
+    
+    # Static method: Should report if a repository exists at given location
+    def self.repository_exists?(path)
+      raise NotImplementedError, "Repository::repository_exists? Not yet implemented"
+    end
+    
+    # Static method: Opens a repository at given location; returns an
+    # AbstractRepository instance
+    def self.open(connect_string)
+      raise NotImplementedError, "Repository::open Not yet implemented"
+    end
+    
+    # Static method: Creates a new repository at given location; returns
+    # an AbstractRepository instance, with the repository opened.
+    def self.create(connect_string)
+      raise NotImplementedError, "Repository::create Not yet implemented"
+    end
+    
+    # Given either an array of, or a single object of class RevisionFile, 
+    # return a stream of data for the user to download as the file(s).
+    def stringify_files(files)
+      raise NotImplementedError,  "Repository.download: Not yet implemented"
+    end
+    alias download_as_string stringify_files
   
-  # Gets a list of users with permissions in question on the repository
-  #   use "Repository::Permission::ANY" to get a list of all users with any permissions
-  #   i.e. all users with at least read permissions
-  def get_users(permissions)
-    raise NotImplementedError, "Repository.get_users: Not yet implemented"
+    # Returns a transaction for the provided user and uses comment as the commit message
+    def get_transaction(user_id, comment)
+      raise NotImplementedError,  "Repository.get_transaction: Not yet implemented"
+    end  
+    
+    # Commits a transaction associated with a repository
+    def commit(transaction)
+      raise NotImplementedError,  "Repository.commit: Not yet implemented"
+    end
+    
+    # Returns the latest Repository::AbstractRevision
+    def get_latest_revision
+      raise NotImplementedError, "Repository.get_latest_revision: Not yet implemented"
+    end
+      
+    # Return a Repository::AbstractRevision for a given revision_number
+    # if it exists
+    def get_revision(revision_number)
+      raise NotImplementedError,  "Repository.get_revision: Not yet implemented"
+    end
+    
+    # Return a RepositoryRevision for a given timestamp
+    def get_revision_by_timestamp(timestamp)
+      raise NotImplementedError,  "Repository.get_revision_by_timestamp: Not yet implemented"
+    end
+     
+    # Adds a user with a given permission-set to the repository
+    def add_user(user_id, permissions)
+      raise NotImplementedError,  "Repository.add_user: Not yet implemented"
+    end
+    
+    # Removes user permissions for read & write access to the repository
+    def remove_user(user_id)
+      raise NotImplementedError,  "Repository.remove_user: Not yet implemented"
+    end
+    
+    # Gets a list of users with permissions in question on the repository
+    #   use "Repository::Permission::ANY" to get a list of all users with any permissions
+    #   i.e. all users with at least read permissions
+    def get_users(permissions)
+      raise NotImplementedError, "Repository.get_users: Not yet implemented"
+    end
+    
+    # Gets permissions for a particular user
+    def get_permissions(user_id)
+      raise NotImplementedError, "Repository.get_permissions: Not yet implemented"
+    end
+    
+    # Sets permissions for a particular user
+    def set_permissions(user_id, permissions)
+      raise NotImplementedError, "Repository.set_permissions: Not yet implemented"
+    end
+    
+    # Static method on Repository to set permissions on a set of users across a series
+    # of group repositories.  
+    # user_id_permissions_map is a hash in the form of:
+    # {user_id => Repository::Permissions::READ, user_id =>....}
+    #
+    # set_bulk_permissions will clobber pre-existing permissions, and automatically
+    # add_user to a repository permission set.
+    #
+    # set_bulk_permissions is commonly used when setting permissions for _many_
+    # repositories
+    #
+    def self.set_bulk_permissions(groups, user_id_permissions_map)
+      raise NotImplementedError, "Repository.set_bulk_permissions: Not yet implemented"
+    end
+    
+    # Static method on Repository to remove permissions on an Array of users across
+    # a series of group repositories
+    # user_ids is an Array of user_ids
+    #
+    def self.delete_bulk_permissions(groups, user_ids)
+      raise NotImplementedError, "Repository.delete_bulk_permissions: Not yet implemented"  
+    end
+    
   end
   
-  # Gets permissions for a particular user
-  def get_permissions(user_id)
-    raise NotImplementedError, "Repository.get_permissions: Not yet implemented"
-  end
   
-  # Sets permissions for a particular user
-  def set_permissions(user_id, permissions)
-    raise NotImplementedError, "Repository.set_permissions: Not yet implemented"
-  end
+  # Exceptions for Revisions
+  class RevisionDoesNotExist < Exception; end
+  class RevisionOutOfSyncConflict < Conflict; end
   
-end
-
-
-# Exceptions for Revisions
-class RevisionDoesNotExist < Exception; end
-class RevisionOutOfSyncConflict < Conflict; end
-
-class AbstractRevision
-  attr_reader :revision_number, :timestamp, :user_id, :comment
-
-  def initialize(revision_number)
-    @revision_number = revision_number
-  end
+  class AbstractRevision
+    attr_reader :revision_number, :timestamp, :user_id, :comment
   
-  def path_exists?(path)
-    raise NotImplementedError, "Revision.path_exists? not yet implemented"
+    def initialize(revision_number)
+      @revision_number = revision_number
+    end
+    
+    def path_exists?(path)
+      raise NotImplementedError, "Revision.path_exists? not yet implemented"
+    end
+    
+    # Return all of the files in this repository at the root directory
+    def files_at_path(path)
+      raise NotImplementedError, "Revision.files_at_path not yet implemented"
+    end
+    
+    def directories_at_path(path)
+      raise NotImplementedError, "Revision.directories_at_path not yet implemented"
+    end
+    
+    def changed_files_at_path(path)
+      raise NotImplementedError, "Revision.changed_files_at_path not yet implemented"
+    end    
   end
   
-  # Return all of the files in this repository at the root directory
-  def files_at_path(path)
-    raise NotImplementedError, "Revision.files_at_path not yet implemented"
-  end
+  # Exceptions for Files
+  class FileOutOfDate < Exception; end
+  class FileDoesNotExist < Exception; end
+    
+  # Exceptions for repo user management
+  class UserNotFound < Exception; end
+  class UserAlreadyExistent < Exception; end
+  # raised when trying to modify permissions and repo is not in authoritative mode
+  class NotAuthorityError < Exception; end
+  # raised when configuration is wrong
+  class ConfigurationError < Exception; end 
   
-  def directories_at_path(path)
-    raise NotImplementedError, "Revision.directories_at_path not yet implemented"
-  end
   
-  def changed_files_at_path(path)
-    raise NotImplementedError, "Revision.changed_files_at_path not yet implemented"
-  end    
-end
-
-# Exceptions for Files
-class FileOutOfDate < Exception; end
-class FileDoesNotExist < Exception; end
-  
-# Exceptions for repo user management
-class UserNotFound < Exception; end
-class UserAlreadyExistent < Exception; end
-# raised, when trying to modify permissions and repo is not in authoritative mode
-class NotAuthorityError < Exception; end
-
-
-#################################################
-#  Class File:
-#        Files stored in a Revision
-#################################################
-class RevisionFile
-   
-  def initialize(from_revision, args)
-    @name = args[:name]
-    @path = args[:path]
-    @last_modified_revision = args[:last_modified_revision]
-    @last_modified_date = args[:last_modified_date]
-    @changed = args[:changed]
-    @user_id = args[:user_id]
-    @mime_type = args[:mime_type]
-    @from_revision = from_revision   
-  end
-  
-  attr_accessor :name, :path, :last_modified_revision, :changed
-  attr_accessor :from_revision, :user_id, :mime_type, :last_modified_date
+  #################################################
+  #  Class File:
+  #        Files stored in a Revision
+  #################################################
+  class RevisionFile
+     
+    def initialize(from_revision, args)
+      @name = args[:name]
+      @path = args[:path]
+      @last_modified_revision = args[:last_modified_revision]
+      @last_modified_date = args[:last_modified_date]
+      @changed = args[:changed]
+      @user_id = args[:user_id]
+      @mime_type = args[:mime_type]
+      @from_revision = from_revision   
+    end
     
-end # end class File
-
-class RevisionDirectory
-   
-  def initialize(from_revision, args)
-    @name = args[:name]
-    @path = args[:path]
-    @last_modified_revision = args[:last_modified_revision]
-    @last_modified_date = args[:last_modified_date]
-    @changed = args[:changed]
-    @user_id = args[:user_id]
-    @from_revision = from_revision   
-  end
+    attr_accessor :name, :path, :last_modified_revision, :changed
+    attr_accessor :from_revision, :user_id, :mime_type, :last_modified_date
+      
+  end # end class File
   
-  attr_accessor :name, :path, :last_modified_revision, :changed
-  attr_accessor :from_revision, :user_id, :last_modified_date
+  class RevisionDirectory
+     
+    def initialize(from_revision, args)
+      @name = args[:name]
+      @path = args[:path]
+      @last_modified_revision = args[:last_modified_revision]
+      @last_modified_date = args[:last_modified_date]
+      @changed = args[:changed]
+      @user_id = args[:user_id]
+      @from_revision = from_revision   
+    end
     
-end # end class File
-
-
-class Transaction
-
-  attr_reader :user_id, :comment, :jobs, :conflicts
-
-  def initialize(user_id, comment)
-    @user_id = user_id
-    @comment = comment
-    @jobs = []
-    @conflicts = []
-  end
+    attr_accessor :name, :path, :last_modified_revision, :changed
+    attr_accessor :from_revision, :user_id, :last_modified_date
+      
+  end # end class File
   
-  def add_path(path)
-    @jobs.push(:action => :add_path, :path => path)
-  end
   
-  def add(path, file_data=nil, mime_type=nil)
-    @jobs.push(:action => :add, :path => path, :file_data => file_data, :mime_type => mime_type)
-  end
+  class Transaction
   
-  def remove(path, expected_revision_number)
-    @jobs.push(:action => :remove, :path => path, :expected_revision_number => expected_revision_number)
-  end
+    attr_reader :user_id, :comment, :jobs, :conflicts
   
-  def replace(path, file_data, mime_type, expected_revision_number)
-    @jobs.push(:action => :replace, :path => path, :file_data => file_data, :mime_type => mime_type, :expected_revision_number => expected_revision_number)
+    def initialize(user_id, comment)
+      @user_id = user_id
+      @comment = comment
+      @jobs = []
+      @conflicts = []
+    end
+    
+    def add_path(path)
+      @jobs.push(:action => :add_path, :path => path)
+    end
+    
+    def add(path, file_data=nil, mime_type=nil)
+      @jobs.push(:action => :add, :path => path, :file_data => file_data, :mime_type => mime_type)
+    end
+    
+    def remove(path, expected_revision_number)
+      @jobs.push(:action => :remove, :path => path, :expected_revision_number => expected_revision_number)
+    end
+    
+    def replace(path, file_data, mime_type, expected_revision_number)
+      @jobs.push(:action => :replace, :path => path, :file_data => file_data, :mime_type => mime_type, :expected_revision_number => expected_revision_number)
+    end
+    
+    def add_conflict(conflict)
+      @conflicts.push(conflict)
+    end
+    
+    def conflicts?
+      @conflicts.size > 0
+    end
+    
+    def has_jobs?
+      @jobs.size > 0
+    end
+   
   end
   
-  def add_conflict(conflict)
-    @conflicts.push(conflict)
-  end
+  # A repository factory
+  require File.join(File.dirname(__FILE__),'/memory_repository')
+  require File.join(File.dirname(__FILE__),'/subversion_repository')
+  # Returns a repository class of the requested type,
+  # which implements AbstractRepository
   
-  def conflicts?
-    @conflicts.size > 0
+  # get_class takes a hash as a second argument. This hash must contain the following
+  # keys with corresponding values (other configuration is ignored):
+  #  REPOSITORY_IS_ADMIN:  This flag indicates if we have admin privileges.
+  #                        If set to false, the repository relies on a third party
+  #                        to create repositories and manage its permissions.
+  #  REPOSITORY_PERMISSION_FILE: This is the absolute path to the permission file
+  #                              of repositories.
+  def Repository.get_class(repo_type, conf_hash)
+    if conf_hash.nil?
+      raise ConfigurationError.new("Configuration must not be nil")
+    end
+    # configure Repository module first; as of now, we require the following constants
+    # to be defined
+    config_keys = ['REPOSITORY_PERMISSION_FILE', 'IS_REPOSITORY_ADMIN']
+    @CONF = Hash.new # important(!) reset config
+    conf_hash.each do |k,v|
+      if config_keys.include?(k)
+        @CONF[k.to_sym] = v
+      end
+    end
+    # Check if configuration is in order
+    config_keys.each do |c|
+      if Repository.conf[c.to_sym].nil?
+        raise ConfigurationError.new("Required config '#{c}' not set")
+      end
+    end
+    case repo_type
+      when "svn"
+        return SubversionRepository
+      when "memory"
+        return MemoryRepository
+      else
+        raise "Repository implementation not found: #{repo_type}"
+    end
   end
-  
-  def has_jobs?
-    @jobs.size > 0
-  end
- 
-end
 
-
 end # end module Repository
Index: lib/repo/repository_factory.rb
===================================================================
--- lib/repo/repository_factory.rb	(revision 1064)
+++ lib/repo/repository_factory.rb	(working copy)
@@ -1,20 +0,0 @@
-require File.join(File.dirname(__FILE__),'/memory_repository')
-require File.join(File.dirname(__FILE__),'/subversion_repository')
-
-# module functions
-module Repository
-  
-  # Returns a repository class of the requested type,
-  # which implements AbstractRepository
-  def Repository.get_class(repo_type)
-    case repo_type
-      when "svn"
-        return SubversionRepository
-      when "memory"
-        return MemoryRepository
-      else
-        raise "Repository implementation not found: #{repo_type}"
-    end
-  end
-  
-end # end module
Index: lib/repo/subversion_repository.rb
===================================================================
--- lib/repo/subversion_repository.rb	(revision 1064)
+++ lib/repo/subversion_repository.rb	(working copy)
@@ -1,4 +1,4 @@
-require "svn/repos" # load SVN Ruby bindings stuff
+require "svn/repos" # load SVN Ruby bindings
 require "md5"
 require "rubygems"    # debugging
 require "ruby-debug"  # debugging
@@ -6,6 +6,7 @@
 
 module Repository
 
+# subversion specific module constants
 if !defined? SVN_CONSTANTS # avoid constants already defined warnings
   SVN_CONSTANTS = {
     :author => Svn::Core::PROP_REVISION_AUTHOR, 
@@ -30,16 +31,20 @@
   # Constructor: Connects to an existing Subversion
   # repository, using Ruby bindings; Note: A repository has to be
   # created using SubversionRepository.create(), it it is not yet existent
-  # The is_admin flag indicates if we have admin privileges. If set to false,
-  # the repository relies on a third party to create repositories and manage its
-  # permissions.
-  def initialize(connect_string, is_admin=true, svn_authz=nil)
+  def initialize(connect_string)
+    # Check if configuration is in order
+    if Repository.conf[:IS_REPOSITORY_ADMIN].nil?
+      raise ConfigurationError.new("Required config 'IS_REPOSITORY_ADMIN' not set")
+    end
+    if Repository.conf[:REPOSITORY_PERMISSION_FILE].nil?
+      raise ConfigurationError.new("Required config 'REPOSITORY_PERMISSION_FILE' not set")
+    end
     begin
       super(connect_string) # dummy call to super
     rescue NotImplementedError; end
     @repos_path = connect_string
-    @repos_auth_file = svn_authz || File.dirname(connect_string)+"/svn_authz"
-    @repos_admin = is_admin
+    @repos_auth_file = Repository.conf[:REPOSITORY_PERMISSION_FILE] || File.dirname(connect_string) + "/svn_authz"
+    @repos_admin = Repository.conf[:IS_REPOSITORY_ADMIN]
     if (SubversionRepository.repository_exists?(@repos_path))
       @repos = Svn::Repos.open(@repos_path)
     else
@@ -49,12 +54,7 @@
 
   # Static method: Creates a new Subversion repository at
   # location 'connect_string'
-  # The is_admin flag indicates if we have admin privileges. If set to false,
-  # the repository relies on a third party to create repositories and manage its
-  # permissions.
-  # svn_authz is the path to the svn_authz file which should be used, for repo
-  # management.
-  def self.create(connect_string, is_admin=true, svn_authz=nil)
+  def self.create(connect_string)
     if SubversionRepository.repository_exists?(connect_string)
       raise RepositoryCollision.new("There is already a repository at #{connect_string}")
     end
@@ -63,18 +63,15 @@
     end
     
     # create the repository using the ruby bindings
-    fs_config = {Svn::Fs::CONFIG_FS_TYPE => Repository::SVN_FS_TYPES[:fsfs]} 
-    Svn::Repos.create(connect_string, {}, fs_config)
-    return SubversionRepository.open(connect_string, is_admin, svn_authz)
+    fs_config = {Svn::Fs::CONFIG_FS_TYPE => Repository::SVN_FS_TYPES[:fsfs]}
+    Svn::Repos.create(connect_string, {}, fs_config) #raises exception if not successful
+    return true
   end
   
   # Static method: Opens an existing Subversion repository
   # at location 'connect_string'
-  # The is_admin flag indicates if we have admin privileges. If set to false,
-  # the repository relies on a third party to create repositories and manage its
-  # permissions.
-  def self.open(connect_string, is_admin=true, svn_authz=nil)
-    return SubversionRepository.new(connect_string, is_admin, svn_authz)
+  def self.open(connect_string)
+    return SubversionRepository.new(connect_string)
   end
   
   # Static method: Reports if a Subversion repository exists
@@ -214,7 +211,7 @@
         if repo_permissions.key?(user_id)
           raise UserAlreadyExistent.new(user_id + " already existent")
         end
-        svn_permissions = translate_to_svn_perms(permissions)
+        svn_permissions = self.class.__translate_to_svn_perms(permissions)
         repo_permissions[user_id] = svn_permissions
         # inject new permissions into file string
         write_string = inject_permissions(repo_permissions, defined?(file_content)? file_content: "")
@@ -245,7 +242,7 @@
       end
       result_list = []
       repo_permissions.each do |user, perm|
-        if translate_perms_from_file(perm) >= permissions
+        if self.class.__translate_perms_from_file(perm) >= permissions
           result_list.push(user)
         end
       end
@@ -262,6 +259,7 @@
     if svn_auth_file_checks() # do basic file checks
       repo_permissions = {}
       File.open(@repos_auth_file) do |auth_file|
+
         auth_file.flock(File::LOCK_EX)
         file_content = auth_file.read()
         if (file_content.length != 0)
@@ -272,7 +270,7 @@
     if !repo_permissions.key?(user_id)
       raise UserNotFound.new(user_id + " not found")
     end
-        return translate_perms_from_file(repo_permissions[user_id])
+        return self.class.__translate_perms_from_file(repo_permissions[user_id])
     end
   end
   
@@ -295,7 +293,7 @@
         if !repo_permissions.key?(user_id)
           raise UserNotFound.new(user_id + " not found")
         end
-        svn_permissions = translate_to_svn_perms(permissions)
+        svn_permissions = self.class.__translate_to_svn_perms(permissions)
         repo_permissions[user_id] = svn_permissions
         # inject new permissions into file string
         write_string = inject_permissions(repo_permissions, defined?(file_content)? file_content: "")
@@ -344,7 +342,158 @@
     end
   end
   
+  # Sets permissions over several repositories. Use set_permissions to set
+  # permissions on a single repository.
+  def self.set_bulk_permissions(repo_names, user_id_permissions_map) 
+    # Check if configuration is in order
+    if Repository.conf[:IS_REPOSITORY_ADMIN].nil?
+      raise ConfigurationError.new("Required config 'IS_REPOSITORY_ADMIN' not set")
+    end
+    # If we're not in authoritative mode, bail out
+    if !Repository.conf[:IS_REPOSITORY_ADMIN] # Are we admin?
+      raise NotAuthorityError.new("Unable to set bulk permissions:  Not in authoritative mode!");
+    end
+
+    # Read in the authz file
+    authz_file_contents = self.__read_in_authz_file()
+       
+    # Parse the file contents into to something we can work with
+    repo_permissions = self.__parse_authz_file(authz_file_contents)
+    # Set / clobber permissions on each group for this user
+    repo_names.each do |repo_name|
+      repo_name = File.basename(repo_name)
+      user_id_permissions_map.each do |user_id, permissions|
+        if repo_permissions[repo_name].nil?
+          repo_permissions[repo_name] = {}
+        end
+        repo_permissions[repo_name][user_id] = permissions
+      end
+    end
+
+    # Translate the hash into the svn authz file format
+    authz_file_contents = self.__prepare_authz_string(repo_permissions)
+    
+    # Write out the authz file
+    return self.__write_out_authz_file(authz_file_contents)
+  end
+
+  # Deletes permissions over several repositories. Use remove_user to remove
+  # permissions of a single repository.
+  def self.delete_bulk_permissions(repo_names, user_ids) 
+    # Check if configuration is in order
+    if Repository.conf[:IS_REPOSITORY_ADMIN].nil?
+      raise ConfigurationError.new("Required config 'IS_REPOSITORY_ADMIN' not set")
+    end
+    # If we're not in authoritative mode, bail out
+    if !Repository.conf[:IS_REPOSITORY_ADMIN] # Are we admin?
+      raise NotAuthorityError.new("Unable to delete bulk permissions:  Not in authoritative mode!");
+    end
+
+    # Read in the authz file
+    authz_file_contents = self.__read_in_authz_file()
+       
+    # Parse the file contents into to something we can work with
+    repo_permissions = self.__parse_authz_file(authz_file_contents)
+    
+    # Delete the user_id for each repository
+    repo_names.each do |repo_name|
+      repo_name = File.basename(repo_name)
+      user_ids.each do |user_id|
+        repo_permissions[repo_name].delete(user_id)
+      end
+    end
+    
+    # Translate the hash into the svn authz file format
+    authz_file_contents = self.__prepare_authz_string(repo_permissions)
+    
+    # Write out the authz file
+    return self.__write_out_authz_file(authz_file_contents)
+  end
+  
   ####################################################################
+  ##  Semi-private class methods (one should not use them from outside
+  ##  this class). 
+  ####################################################################
+  
+  # Semi-private class method: Reads in Repository.conf[:REPOSITORY_PERMISSION_FILE]
+  def self.__read_in_authz_file()
+    # Check if configuration is in order
+    if Repository.conf[:REPOSITORY_PERMISSION_FILE].nil?
+      raise ConfigurationError.new("Required config 'REPOSITORY_PERMISSION_FILE' not set")
+    end
+    if !File.exist?(Repository.conf[:REPOSITORY_PERMISSION_FILE])
+        File.open(Repository.conf[:REPOSITORY_PERMISSION_FILE], "w").close() # create file if not existent
+    end
+    # Load up the Permissions:
+    file_content = ""
+    File.open(Repository.conf[:REPOSITORY_PERMISSION_FILE], "r+") do |auth_file|
+      auth_file.flock(File::LOCK_EX)
+      file_content = auth_file.read()
+      auth_file.flock(File::LOCK_UN) # release lock
+    end
+    return file_content
+  end
+  
+  # Semi-private class method: Writes out Repository.conf[:REPOSITORY_PERMISSION_FILE]
+  def self.__write_out_authz_file(authz_file_contents)
+    # Check if configuration is in order
+    if Repository.conf[:IS_REPOSITORY_ADMIN].nil?
+      raise ConfigurationError.new("Required config 'IS_REPOSITORY_ADMIN' not set")
+    end
+    if Repository.conf[:REPOSITORY_PERMISSION_FILE].nil?
+      raise ConfigurationError.new("Required config 'REPOSITORY_PERMISSION_FILE' not set")
+    end
+    # If we're not in authoritative mode, bail out
+    if !Repository.conf[:IS_REPOSITORY_ADMIN] # Are we admin?
+      raise NotAuthorityError.new("Unable to write out repo permissions:  Not in authoritative mode!");
+    end
+
+    if !File.exist?(Repository.conf[:REPOSITORY_PERMISSION_FILE])
+        File.open(Repository.conf[:REPOSITORY_PERMISSION_FILE], "w").close() # create file if not existent
+    end
+    result = false
+    File.open(Repository.conf[:REPOSITORY_PERMISSION_FILE], "w+") do |auth_file|
+      auth_file.flock(File::LOCK_EX)
+      # Blast out the string to the file
+      result = (auth_file.write(authz_file_contents) == authz_file_contents.length)
+      auth_file.flock(File::LOCK_UN) # release lock
+    end
+    return result
+  end
+  
+  # Semi-private class method: Parses a subversion authz file passed in as a string
+  def self.__parse_authz_file(authz_string)
+    permissions_mapping = {}
+
+    permissions_array = authz_string.scan(/\[(.+):\/\]\n([\w\s=]+)/)
+    permissions_array.each do |permissions_group|
+      # The first match is the group repository name
+      user_permissions = {}
+      raw_users_permissions = permissions_group[1].scan(/\s*(\w+)\s*=\s*(\w+)\s*/)
+      raw_users_permissions.each do |raw_user_permissions|
+        user_permissions[raw_user_permissions[0]] = self.__translate_perms_from_file(raw_user_permissions[1])
+      end
+      permissions_mapping[permissions_group[0]] = user_permissions
+    end
+    return permissions_mapping
+  end
+  
+  # Semi-private class method: Transforms passed in permissions into 
+  # subversion authz file syntax
+  def self.__prepare_authz_string(permissions)
+    result = ""
+    permissions.each do |repository_name, users_permissions|
+      result += "[#{repository_name}:/]\n"
+      users_permissions.each do |user_id, user_permissions|
+        user_permissions_string = self.__translate_to_svn_perms(user_permissions)
+        result += "#{user_id} = #{user_permissions_string}\n"
+      end
+      result += "\n"
+    end
+    return result
+  end
+  
+  ####################################################################
   ##  The following stuff is semi-private. As a general rule don't use
   ##  it directly. The only reason it's public, is that
   ##  SubversionRevision needs to have access.
@@ -364,7 +513,7 @@
   def __get_files(path="/", revision_number=nil)
     begin
       entries = @repos.fs.root(revision_number).dir_entries(path)
-    rescue Exception => e
+    rescue Exception
       raise FileDoesNotExist.new("#{path} does not exist in the repository for revision #{revision_number}")
     end
     entries.each do |key, value|
@@ -429,6 +578,30 @@
     return revision_numbers.sort.uniq
   end
   
+  # Helper method to translate internal permissions to Subversion
+  # permissions
+  def self.__translate_to_svn_perms(permissions)
+    case (permissions)
+      when Repository::Permission::READ
+        return "r"
+      when Repository::Permission::READ_WRITE
+        return "rw"
+      else raise "Unknown permissions"
+    end # end case
+  end
+  
+  # Helper method to translate Subversion permissions to internal
+  # permissions 
+  def self.__translate_perms_from_file(perm_string)
+    case (perm_string)
+      when "r"
+        return Repository::Permission::READ
+      when "rw"
+        return Repository::Permission::READ_WRITE
+      else raise "Unknown permissions"
+    end # end case
+  end
+  
   ####################################################################
   ##  Private method definitions
   ####################################################################
@@ -546,30 +719,6 @@
     end
   end
   
-  # Helper method to translate internal permissions to Subversion
-  # permissions
-  def translate_to_svn_perms(permissions)
-    case (permissions)
-      when Repository::Permission::READ
-        return "r"
-      when Repository::Permission::READ_WRITE
-        return "rw"
-      else raise "Unknown permissions"
-    end # end case
-  end
-  
-  # Helper method to translate Subversion permissions to internal
-  # permissions 
-  def translate_perms_from_file(perm_string)
-    case (perm_string)
-      when "r"
-        return Repository::Permission::READ
-      when "rw"
-        return Repository::Permission::READ_WRITE
-      else raise "Unknown permissions"
-    end # end case
-  end
-  
   # Helper method to check file permissions of svn auth file 
   def svn_auth_file_checks()
     if !@repos_admin # if we are not admin, check if files exist
Index: lib/repo/test/memory_repository_test.rb
===================================================================
--- lib/repo/test/memory_repository_test.rb	(revision 1064)
+++ lib/repo/test/memory_repository_test.rb	(working copy)
@@ -22,11 +22,13 @@
     end
     
     should "be able to create a new Memory repository" do
-      repo = MemoryRepository.create(REPO_LOCATION)
+      MemoryRepository.create(REPO_LOCATION)
+      repo = MemoryRepository.open(REPO_LOCATION)
       assert_not_nil(repo, "Could not create Repository")
       assert_instance_of(Repository::MemoryRepository, repo, "Repository is of wrong type")
       # and create another one :-)
-      repo2 = MemoryRepository.create(ANOTHER_REPO_LOCATION)
+      MemoryRepository.create(ANOTHER_REPO_LOCATION)
+      repo2 = MemoryRepository.open(ANOTHER_REPO_LOCATION)
       assert_not_nil(repo2, "Could not create Repository")
       assert_instance_of(Repository::MemoryRepository, repo2, "Repository is of wrong type")
     end
@@ -55,7 +57,7 @@
     # specified in TEST_REPO_CONTENT
     setup do
       MemoryRepository.create(REPO_LOCATION) # create repository first
-      @repo = MemoryRepository.new(REPO_LOCATION)
+      @repo = MemoryRepository.open(REPO_LOCATION)
     end
     
     # destroy all repositories created
@@ -134,7 +136,7 @@
       # filename should not be available in repo now
       rev = @repo.get_latest_revision()
       files = rev.files_at_path("/")
-      assert_equal({}, files, "File '"+filename+"' should have been removed!")
+      assert_equal(0, files.size, "File '"+filename+"' should have been removed!")
     end
     
     should "be able to add multiple files using a single transaction" do
@@ -367,10 +369,10 @@
       
       @repo.remove_user(another_user)
       users_with_any_perm = @repo.get_users(Repository::Permission::ANY)
-      assert_nil(users_with_any_perm, "There are NO users with any permissions")
+      assert_nil(users_with_any_perm, "There are NO users with any permissions")  
+      
     end
-    
-    
+  
     should "have repositories persist" do
       files_to_add = ["MyClass.java", "MyInterface.java", "test.xml"]
       add_some_files_helper(@repo, files_to_add) # add some initial files
@@ -382,6 +384,64 @@
     
   end # end context
   
+  context "MemoryRepository" do
+    
+    # setup and teardown for the current context
+    
+    # creates repositories
+    setup do
+      @repo_names = ["test_repo", "test_repo2", "test_repo3", "test_repo4"]
+      # Create the repos
+      @repo_names.each do |repo_name|
+        MemoryRepository.create(repo_name)
+      end
+    end
+    
+    # destroy all repositories created
+    teardown do
+      MemoryRepository.purge_all()
+    end
+    
+    should "raise an exception if not properly configured" do
+      conf = Hash.new
+      conf["IS_REPOSITORY_ADMIN"] = true
+      assert_raise(ConfigurationError) do
+        Repository.get_class("memory", conf) # missing required REPOSITORY_PERMISSION_FILE
+      end
+    end
+    
+    should "be able to bulk add and delete user permissions" do
+      
+      # Now lets try to bulk add some users
+      MemoryRepository.set_bulk_permissions(@repo_names, {"test_user" => Repository::Permission::READ})
+      MemoryRepository.set_bulk_permissions(@repo_names, {"test_user2" => Repository::Permission::READ_WRITE})
+      MemoryRepository.set_bulk_permissions(@repo_names, {"test_user3" => Repository::Permission::READ})
+      
+      # Check to see if permissions were added
+      @repo_names.each do |repo_name|
+        repo = MemoryRepository.open(repo_name)
+        assert_equal(Repository::Permission::READ, repo.get_permissions('test_user'))
+        assert_equal(Repository::Permission::READ_WRITE, repo.get_permissions('test_user2'))
+        assert_equal(Repository::Permission::READ, repo.get_permissions('test_user3'))
+      end
+      
+      # Check to see if we can bulk delete
+      MemoryRepository.delete_bulk_permissions(@repo_names, ['test_user', 'test_user2'])
+      @repo_names.each do |repo_name|
+        repo = MemoryRepository.open(repo_name)
+        assert_raises Repository::UserNotFound do
+          repo.get_permissions('test_user')
+        end
+        assert_raises Repository::UserNotFound do
+          repo.get_permissions('test_user2')
+        end
+        assert_equal(Repository::Permission::READ, repo.get_permissions('test_user3'))
+      end
+      
+    end
+       
+  end # end context
+  
   private # private helper methods for this class
   def add_file_helper(repo, file)
     txn = repo.get_transaction(TEST_USER)
Index: lib/repo/test/repository_abstract_tests.rb
===================================================================
--- lib/repo/test/repository_abstract_tests.rb	(revision 1064)
+++ lib/repo/test/repository_abstract_tests.rb	(working copy)
@@ -1,305 +0,0 @@
-require 'test/unit'
-require 'time'
-
-class RepositoryAbstractTests < Test::Unit::TestCase
-  def basic_fixture
-    transaction = @repo.get_transaction("someuser")
-    transaction.add("SomeFile.java", "File contents", "text/java")
-    @repo.commit(transaction)
-    
-    transaction = @repo.get_transaction("someuser")
-    transaction.add("SomeNewFile.java",  "File Contents", "text/java")
-    @repo.commit(transaction)
-    
-    transaction = @repo.get_transaction("someuser")
-    transaction.add("new_folder/SomeFolderFile.java",  "File Contents", "text/java")
-    @repo.commit(transaction)
-  end
-
-  def test_create
-    assert_not_nil @repo, "Could not create Repository"
-  end
-  
-  def test_number_of_revisions
-    assert_equal 0, @repo.latest_revision_number, "Number of revisions is wrong"
-    transaction = @repo.get_transaction("someuser")
-    transaction.add("SomeFile.java", "File Contents", "text/java")
-    @repo.commit(transaction)
-    assert_equal 1, @repo.latest_revision_number, "Number of revisions is wrong"
-  end
-  
-  def test_get_revision
-    basic_fixture
-    assert_equal 3, @repo.latest_revision_number, "Number of revisions is wrong"
-    revision = @repo.get_revision(1)
-    files = revision.files_at_path('/')
-    assert_equal 1, files.count, "Number of files in this revision is wrong"
-    file = files["SomeFile.java"]
-    assert_not_nil file, "Could not find an expected file"
-    assert_equal "SomeFile.java", file.name, "Name of file is wrong"
-    
-    revision = @repo.get_revision(2)
-    files = revision.files_at_path('/')
-    assert_equal 2, files.count, "Number of files in this revision is wrong"
-    file = files["SomeNewFile.java"]
-    assert_not_nil file, "Could not find an expected file"
-    assert_equal "SomeNewFile.java", file.name, "Name of file is wrong"
-  end
-  
-  def test_get_invalid_revision
-    basic_fixture
-    assert_raises Repository::RevisionDoesNotExist do
-      revision = @repo.get_revision(4)
-    end
-    transaction = @repo.get_transaction("someuser")
-    transaction.add("NewFile.java", "Some new file contents", "text/java")
-    @repo.commit(transaction)
-    revision = @repo.get_revision(4)
-    assert_not_nil revision, "Could not find revision"
-  end
-  
-  def test_get_missing_file
-    basic_fixture
-    revision = @repo.get_latest_revision
-    files = revision.files_at_path('/')
-    assert_nil files["MissingFile.java"], "Found a file that shouldn't be there"
-  end
-  
-  def test_download_missing_file
-    basic_fixture
-    file = nil
-    assert_raises TypeError do
-      @repo.download_as_string(file)
-    end
-    
-    file = Repository::RevisionFile.new(1, {
-      :name => 'InvalidFile.java',
-      :path => '/',
-      :last_modified_revision => 1,
-      :changed => true,
-      :user_id => 'someuser'
-    })
-    assert_raises Repository::FileDoesNotExistConflict do
-      @repo.download_as_string(file)
-    end
-    
-    begin
-      @repo.download_as_string(file)
-    rescue Repository::FileDoesNotExistConflict => e
-#      assert e.attempted_job.kind_of?(Repository::RevisionFile), "Did not get the right kind of conflict - expected the attempted_job to be a file"
-      assert_equal '/InvalidFile.java', e.path, "Did not get the right conflict contents - expected the missing file"
-    end
-    
-    file = Repository::RevisionFile.new(1, {
-      :name => '??>@$>Z>$@<D',
-      :path => '/s35523/a4yasda/asdr43rasdf/??!....%*@#!(@)',
-      :last_modified_revision => 1,
-      :changed => true,
-      :user_id => 'someuser'
-    })
-    assert_raises Repository::FileDoesNotExistConflict do
-      @repo.download_as_string(file)
-    end
-    
-    begin
-      @repo.download_as_string(file)
-    rescue Repository::FileDoesNotExistConflict => e
-      assert_equal '/s35523/a4yasda/asdr43rasdf/??!....%*@#!(@)/??>@$>Z>$@<D', e.path, "Did not get the right conflict contents - expected the missing file"
-    end
-
-  end
-  
-  def test_get_missing_directory
-    basic_fixture
-  end
-end
-  
-#    revision = @repo.get_revision(3)
-#    assert_not_nil revision, "Could not retrieve Revision with get_revision"
-#    assert_equal 3, revision.number, "Revision number did not match"
-#    assert_equal "Needed to update TestShapes.java!", revision.comment, "Comments did not match"
-#    assert_equal "Fri May 22 13:35:02 -0400 2009", revision.timestamp, "Timestamps did not match"
-#    assert_equal "c6conley", revision.user_id, "User ID did not match"
-#    
-#    assert_raises Repository::RevisionDoesNotExist do
-#      revision = @repo.get_revision(50)
-#    end
-
-
-#  end
-
-#  def test_get_revision_by_timestamp
-#    revision = @repo.get_revision_by_timestamp(Time.parse("Wed May 20 13:35:02 -0400 2009"))
-#    assert_not_nil revision, "Could not retrieve Revision with get_revision_by_timestamp"
-#    assert_equal 1, revision.number, "Revision number did not match"
-#    assert_equal "This was my first commit!", revision.comment, "Comments did not match"
-#    assert_equal "Wed May 20 13:35:02 -0400 2009", revision.timestamp, "Timestamps did not match"
-#    assert_equal "c6conley", revision.user_id, "User ID did not match"
-
-
-#    assert_raises Repository::RevisionDoesNotExist do
-#      revision = @repo.get_revision_by_timestamp(Time.parse("Mon May 18 14:35:02 -0400 2009"))    
-#    end
-
-#    
-#    revision = @repo.get_revision_by_timestamp(Time.parse("Thu May 21 13:35:02 -0400 2009"))
-#    assert_not_nil revision, "Could not retrieve Revision with get_revision_by_timestamp"
-#    assert_equal 2, revision.number, "Revision number did not match"
-#    assert_equal "Whoops - needed to add TestShapes.java", revision.comment, "Comments did not match"
-#    assert_equal "Thu May 21 13:35:02 -0400 2009", revision.timestamp, "Timestamps did not match"
-#    assert_equal "c6conley", revision.user_id, "User ID did not match"
-
-
-#    
-#    revision = @repo.get_revision_by_timestamp(Time.parse("Sun May 24 14:35:02 -0400 2009"))
-#    assert_not_nil revision, "Could not retrieve Revision with get_revision_by_timestamp"
-#    assert_equal 3, revision.number, "Revision number did not match"
-#    assert_equal "Needed to update TestShapes.java!", revision.comment, "Comments did not match"
-#    assert_equal "Fri May 22 13:35:02 -0400 2009", revision.timestamp, "Timestamps did not match"
-#    assert_equal "c6conley", revision.user_id, "User ID did not match"
-
-#  end  
-#  
-#  def test_get_files_in_revision
-#    revision = @repo.get_revision(0)
-#    files = revision.all_files
-#    assert_equal true, files.empty?, "Returned a revision with files when not expected"
-#    
-#    revision = @repo.get_revision(1)
-
-#    file = revision.all_files["Test.java"]
-#    assert_equal "Test.java", file.name, "Did not receive the right file"
-#    assert_equal 1, file.last_modified_revision, "Did not receive the right file"
-#    
-#    revision = @repo.get_revision(2)
-#    
-#    file = revision.all_files["Test.java"]
-#    assert_equal "Test.java", file.name, "Did not receive the right file"
-#    assert_equal 1, file.last_modified_revision, "Did not receive the right file"
-#    
-#    file = revision.all_files["TestShapes.java"]
-#    assert_equal "TestShapes.java", file.name, "Did not receive the right file"
-#    assert_equal 2, file.last_modified_revision, "Did not receive the right file"
-#        
-#  end
-#  
-#  def test_get_changed_files
-#    revision = @repo.get_revision(2)
-#    
-#    assert_equal 1, revision.changed_files.count, "Did not get the right number of changed files"
-#    
-#    file = revision.changed_files["TestShapes.java"]
-#    
-#    assert_equal "TestShapes.java", file.name, "Did not receive the right file"
-#    assert_equal 2, file.last_modified_revision, "Did not receive the right file"
-
-#  end
-#  
-#  def test_download
-#    revision = @repo.get_revision(2)
-#    target_file = revision.all_files["TestShapes.java"]
-#    result_string = @repo.download(target_file)
-#    
-#    assert_equal "This is some NEW TestShapes.java file!", result_string, "Did not receive the correct file contents"
-#    
-#    target_file = revision.all_files["Test.java"]
-#    result_string = @repo.download(target_file)
-#    assert_equal "This is some Test.java file!", result_string, "Did not receive the correct file contents"
-
-#  end
-#  
-#  def test_add_file_commit
-#   
-#    @repo.add_file("NewFile.java", "This is some new content!")
-#    @repo.commit
-#    
-#    assert_equal 4, @repo.number_of_revisions, "Number of revisions is wrong"
-#    
-#    revision = @repo.get_latest_revision
-#    target_file = revision.all_files["NewFile.java"]
-#    result_string = @repo.download(target_file)
-#    assert_equal "This is some new content!", result_string, "Did not receive the correct file contents"
-#    
-#  end
-#  
-#  def test_add_file_conflict
-#    @repo.add_file("Test.java", "This shouldn't get added")
-#    assert_raises Repository::CommitConflicts do
-#      @repo.commit
-#    end
-#    
-#    @repo.add_file("Test.java", "This shouldn't get added")
-#    begin
-#      @repo.commit
-#    rescue Repository::CommitConflicts => commit_conflicts
-#      conflicts = commit_conflicts.get_conflicts
-#      assert_equal 1, conflicts.length, "Expected only 1 conflict"
-#      assert_instance_of Repository::FileExistsConflict, conflicts[0], "Got the wrong type of conflict"
-#    end
-#  end
-#  
-#  def test_remove_file_commit
-#    @repo.remove_file("Test.java")
-#    @repo.commit
-#    assert_equal 4, @repo.number_of_revisions, "Number of revisions is wrong"    
-#    revision = @repo.get_latest_revision
-#    assert_nil revision.all_files["Test.java"], "File still existed"
-#    assert_equal "TestShapes.java", revision.all_files["TestShapes.java"].name, "A file that we expected to exist, doesn't exist anymore."
-#  end
-#  
-#  def test_replace_file_commit
-#    @repo.replace_file("Test.java", "Here is some brand new content!", 1)
-#    @repo.commit
-#    assert_equal 4, @repo.number_of_revisions, "Number of revisions is wrong"
-#    revision = @repo.get_latest_revision
-#    target_file = revision.all_files["Test.java"]
-#    result_string = @repo.download(target_file)
-#    assert_equal "Here is some brand new content!", result_string, "Did not receive the correct file contents"
-#       
-#  end
-#  
-#  def test_replace_file_commit_with_conflict
-
-#    @repo.replace_file("TestShapes.java", "This should not get written", 2)
-#    begin
-#      @repo.commit
-#    rescue Repository::CommitConflicts => commit_conflicts
-#      conflicts = commit_conflicts.get_conflicts
-#      assert_equal 1, conflicts.length, "Expected only 1 conflict"
-#      assert_instance_of Repository::RevisionOutOfSyncConflict, conflicts[0], "Got the wrong type of conflict"
-#    end
-#    
-#    # Make sure it wasn't written    
-#    assert_equal 3, @repo.number_of_revisions, "Number of revisions is wrong"
-#    revision = @repo.get_latest_revision
-#    target_file = revision.all_files["TestShapes.java"]
-#    result_string = @repo.download(target_file)
-#    assert_equal "This is some ALTERED Test.java file!", result_string, "Did not receive the correct file contents"
-#  
-#  end
-#  
-#  def add_file_get_changes
-#    @repo.add_file("NewFile.java", "A brand new file!")
-#    @repo.commit   
-#    revision = @repo.get_latest_revision
-#    assert_equal 1, revision.changed_files.length, "Did not get the right number of changed files"   
-#    file = revision.changed_files["NewFile.java"]
-#    assert_equal "NewFile.java", file.name, "Did not receive the right file"
-#    assert_equal 4, file.last_modified_revision, "Did not receive the right file"
-#  end
-#  
-#  def test_get_users
-#    users = @repo.get_users
-#    assert_equal ["c6conley"], users, "Users do not match"
-#  end
-#  
-#  def test_add_user
-#    @repo.add_user("c6smith")
-#    assert_equal ["c6conley", "c6smith"], @repo.get_users, "Users do not match"
-#  end
-#  
-#  def test_remove_user
-#    @repo.add_user("c6smith")
-#    @repo.remove_user("c6conley")
-#    assert_equal ["c6smith"], @repo.get_users, "Users do not match"
-#  end
Index: lib/repo/test/subversion_repository_test.rb
===================================================================
--- lib/repo/test/subversion_repository_test.rb	(revision 1064)
+++ lib/repo/test/subversion_repository_test.rb	(working copy)
@@ -47,10 +47,14 @@
     
     # creates a new SVN repository at TEST_REPO
     setup do
+      # configure and create repositories
+      conf_admin = Hash.new
+      conf_admin["IS_REPOSITORY_ADMIN"] = true
+      conf_admin["REPOSITORY_PERMISSION_FILE"] = SVN_AUTHZ_FILE
       # create repository first
-      SubversionRepository.create(TEST_REPO)
+      Repository.get_class("svn", conf_admin).create(TEST_REPO)
       # open the repository
-      @repo = SubversionRepository.new(TEST_REPO)      
+      @repo = Repository.get_class("svn", conf_admin).open(TEST_REPO)      
     end
     
     # removes the SVN repository at TEST_REPO
@@ -266,14 +270,21 @@
       # create repository first
       repo1 = SVN_TEST_REPOS_DIR+"/Testrepo1"
       repo2 = SVN_TEST_REPOS_DIR+"/Repository2"
+      conf_admin = Hash.new
+      conf_admin["IS_REPOSITORY_ADMIN"] = true
+      conf_admin["REPOSITORY_PERMISSION_FILE"] = SVN_AUTHZ_FILE
+      Repository.get_class("svn", conf_admin).create(repo1)
+      Repository.get_class("svn", conf_admin).create(repo2)
+      Repository.get_class("svn", conf_admin).create(TEST_REPO)
+      # open the repository
+      conf_non_admin = Hash.new
+      conf_non_admin["IS_REPOSITORY_ADMIN"] = false
+      conf_non_admin["REPOSITORY_PERMISSION_FILE"] = SVN_AUTHZ_FILE
       
-      SubversionRepository.create(repo1, true, SVN_AUTHZ_FILE)
-      SubversionRepository.create(repo2, true, SVN_AUTHZ_FILE)
-      SubversionRepository.create(TEST_REPO, true, SVN_AUTHZ_FILE)
-      # open the repository
-      @repo1 = SubversionRepository.new(repo1, false, SVN_AUTHZ_FILE) # non-admin repository
-      @repo2 = SubversionRepository.new(repo2, false, SVN_AUTHZ_FILE) # again, a non-admin repo
-      @repo = SubversionRepository.new(TEST_REPO, true, SVN_AUTHZ_FILE)     # repo with admin-privs
+      @repo1 = Repository.get_class("svn", conf_non_admin).open(repo1) # non-admin repository
+      @repo2 = Repository.get_class("svn", conf_non_admin).open(repo2) # again, a non-admin repo
+      @repo = Repository.get_class("svn", conf_admin).open(TEST_REPO)     # repo with admin-privs
+      
       # add some files
       files_to_add = ["MyClass.java", "MyInterface.java", "test.xml"]
       add_some_files_helper(@repo1, files_to_add)
@@ -462,9 +473,12 @@
       end
       
       repositories = []
+      conf_admin = Hash.new
+      conf_admin["IS_REPOSITORY_ADMIN"] = true
+      conf_admin["REPOSITORY_PERMISSION_FILE"] = SVN_AUTHZ_FILE
       repository_names.each do |repo_name|
-        SubversionRepository.create(repo_name, true, new_svn_authz)
-        repo = SubversionRepository.open(repo_name)
+        Repository.get_class("svn", conf_admin).create(repo_name)
+        repo = Repository.get_class("svn", conf_admin).open(repo_name)
         repo.add_user("some_user", Repository::Permission::READ_WRITE)
         repo.add_user("another_user", Repository::Permission::READ_WRITE)
         repositories.push(repo)
@@ -488,6 +502,82 @@
     end
   end # end context
   
+  context "SubversionRepository" do
+    should "raise an exception if not properly configured" do
+      conf = Hash.new
+      conf["REPOSITORY_PERMISSION_FILE"] = 'something'
+      assert_raise(ConfigurationError) do
+        Repository.get_class("svn", conf) # missing a required constant
+      end
+    end
+  end # end context
+  
+  context "Setting and deleting bulk permissions" do
+    setup do
+      # use a different svn_authz file for this test
+      new_svn_authz = SVN_TEST_REPOS_DIR + "/svn_authz_bulk_stuff2"
+      @conf_admin = Hash.new
+      @conf_admin["IS_REPOSITORY_ADMIN"] = true
+      @conf_admin["REPOSITORY_PERMISSION_FILE"] = new_svn_authz
+      
+      # create some repositories, add some users
+      repo_base_name = "Group_"
+      @repository_names = []
+      (1..5).each do |counter|
+        @repository_names.push(repo_base_name + counter.to_s.rjust(3, "0"))
+      end
+      
+      repositories = []
+      @repository_names.each do |repo_name|
+        Repository.get_class("svn", @conf_admin).create(SVN_TEST_REPOS_DIR + "/" + repo_name)
+        repo = Repository.get_class("svn", @conf_admin).open(SVN_TEST_REPOS_DIR + "/" + repo_name)
+        repositories.push(repo)
+      end
+    end
+    
+    teardown do
+      new_svn_authz = SVN_TEST_REPOS_DIR + "/svn_authz_bulk_stuff2"
+      # remove authz file if it exists
+      if File.exist?(new_svn_authz)
+        FileUtils.rm(new_svn_authz)
+      end
+      
+      # remove repositories, if they exist
+      @repository_names.each do |repo_name|
+        if SubversionRepository.repository_exists?(SVN_TEST_REPOS_DIR + "/" + repo_name)
+          FileUtils.remove_dir(SVN_TEST_REPOS_DIR + "/" + repo_name, true)
+        end
+      end
+    end
+    
+    should "Add a user and set permissions to every Group repository" do
+
+      # Ok, now lets try to add a few bulk users
+      assert SubversionRepository.set_bulk_permissions(@repository_names, {"test_user" => Repository::Permission::READ})
+      assert SubversionRepository.set_bulk_permissions(@repository_names, {"test_user2" => Repository::Permission::READ_WRITE})
+
+      # Test to make sure they got attached to each repository
+      @repository_names.each do |repo_name|
+        repo = Repository.get_class("svn", @conf_admin).open(SVN_TEST_REPOS_DIR + "/" + repo_name)
+        assert_equal(Repository::Permission::READ, repo.get_permissions("test_user"))
+        assert_equal(Repository::Permission::READ_WRITE, repo.get_permissions("test_user2"))      
+      end
+      
+      # Ok, now let's try to remove them
+      assert SubversionRepository.delete_bulk_permissions(@repository_names, ['test_user'])
+
+      # Test to make sure they got attached to each repository
+      @repository_names.each do |repo_name|
+        repo = repo = Repository.get_class("svn", @conf_admin).open(SVN_TEST_REPOS_DIR + "/" + repo_name)
+        assert_raises Repository::UserNotFound do
+          repo.get_permissions("test_user")
+        end 
+        assert_equal(Repository::Permission::READ_WRITE, repo.get_permissions("test_user2"))      
+      end
+            
+    end
+  end
+  
   private # private helper methods for this class
     
   def add_file_helper(repo, file)

