diff --git a/doc-src/content/posts/2011-05-09-compass-django.markdown b/doc-src/content/posts/2011-05-09-compass-django.markdown
index 29c4bc29..61bc91fd 100644
--- a/doc-src/content/posts/2011-05-09-compass-django.markdown
+++ b/doc-src/content/posts/2011-05-09-compass-django.markdown
@@ -7,7 +7,7 @@ author: eric
 It's easy! Follow these two simple steps:
 
 1. Use Compass/Sass.
-2. Use Django.
+2. Use Django. 
 
 That's it. Compass works great as a stand-alone tool. Run "compass --watch" on the command line or use [compass.app](http://compass.handlino.com/) to compile your stylesheets, and then commit the CSS to your Django project, just like you always have. Done.
 
@@ -27,10 +27,8 @@ The disadvantage to our approach is that you are committing generated code to th
 
 And I, as the designer/front-end developer, keep full control of the css-generation process without needing to touch the server. If I want to update the gems and make some changes, I can do that. I make the change, I commit the change, and it just works. For everyone. That's important to me. It removes all the pretense of dark magic that can come with Sass/Compass. I'm writing CSS. I'm committing CSS. Compass, Sass and all their plugins are just tools towards that end.
 
-Of course, you'll want to commit the Sass as well, especially if you have multiple front-end developers on the team. That way the source is available for anyone who needs to update it, even though it's not needed by the server. You might also want a way of documenting the latest gems that should be used to compile it. That's easy enough to add in a comment or doc of it's own.
+Of course, you'll want to commit the Sass as well, especially if you have multiple front-end developers on the team. That way the source is available for anyone who needs to update it, even though it's not needed by the server. You might also want a way of documenting the latest gems that should be used to compile it. That's easy enough to add in a comment or doc of it's own. 
 
 ## Just Tools.
 
-I want to say that again because I think it is the most important and most often forgotten rule of using a css pre-processor. Compass and Sass are simply tools for writing CSS. They are not a new styling language. They are not magic. They make writing css easier - and that is all. The css output is the only thing that matters.
-
-_This was written in collaboration with [Carl Meyer](http://stackoverflow.com/users/3207/carl-meyer), in response to a [question on stack overflow](http://stackoverflow.com/questions/5900208/best-method-for-adding-compass-to-a-django-project)_
+I want to say that again because I think it is the most important and most often forgotten rule of using a css pre-processor. **Compass and Sass are simply tools for writing CSS. They are not a new styling language. They are not magic. They make writing css easier - and that is all. The css output is the only thing that matters.**
\ No newline at end of file
diff --git a/lib/compass/actions.rb b/lib/compass/actions.rb
index fe4df6e1..bc4a2b82 100644
--- a/lib/compass/actions.rb
+++ b/lib/compass/actions.rb
@@ -4,7 +4,7 @@ module Compass
     attr_writer :logger
 
     def logger
-      @logger ||= Logger.new
+      @logger ||= ::Compass::Logger.new
     end
 
     # copy/process a template in the compass template directory to the project directory.
@@ -17,13 +17,14 @@ module Compass
     # create a directory and all the directories necessary to reach it.
     def directory(dir, options = nil)
       options ||= self.options if self.respond_to?(:options)
+      options ||= {}
       if File.exists?(dir) && File.directory?(dir)
-          # logger.record :exists, basename(dir) unless options[:quiet]
+          # do nothing
       elsif File.exists?(dir)
         msg = "#{basename(dir)} already exists and is not a directory."
         raise Compass::FilesystemConflict.new(msg)
       else
-        logger.record :directory, separate("#{basename(dir)}/")
+        log_action :directory, separate("#{basename(dir)}/"), options
         FileUtils.mkdir_p(dir) unless options[:dry_run]
       end
     end
@@ -33,20 +34,19 @@ module Compass
       options ||= self.options if self.respond_to?(:options)
       skip_write = options[:dry_run]
       contents = process_erb(contents, options[:erb]) if options[:erb]
-      extra = options[:extra] || ""
       if File.exists?(file_name)
         existing_contents = IO.read(file_name)
         if existing_contents == contents
-          logger.record :identical, basename(file_name), extra
+          log_action :identical, basename(file_name), options
           skip_write = true
         elsif options[:force]
-          logger.record :overwrite, basename(file_name), extra
+          log_action :overwrite, basename(file_name), options
         else
           msg = "File #{basename(file_name)} already exists. Run with --force to force overwrite."
           raise Compass::FilesystemConflict.new(msg)
         end
       else
-        logger.record :create, basename(file_name), extra
+        log_action :create, basename(file_name), options
       end
       if skip_write
         FileUtils.touch file_name unless options[:dry_run]
@@ -67,7 +67,7 @@ module Compass
     def remove(file_name)
       if File.exists?(file_name)
         File.unlink file_name
-        logger.record :remove, basename(file_name)
+        log_action :remove, basename(file_name), options
       end
     end
 
@@ -95,5 +95,14 @@ module Compass
       (path[-1..-1] == File::SEPARATOR) ? path[0..-2] : path
     end
 
+    def log_action(action, file, options)
+      quiet = !!options[:quiet]
+      quiet = false if options[:loud] && options[:loud] == true
+      quiet = false if options[:loud] && options[:loud].is_a?(Array) && options[:loud].include?(action)
+      unless quiet
+        logger.record(action, file, options[:extra].to_s)
+      end
+    end
+
   end
 end
diff --git a/lib/compass/commands/sprite.rb b/lib/compass/commands/sprite.rb
index 2b33f9fc..b1c8bee9 100644
--- a/lib/compass/commands/sprite.rb
+++ b/lib/compass/commands/sprite.rb
@@ -39,7 +39,7 @@ module Compass
 
       def perform
         relative_uri = options[:uri].gsub(/^#{Compass.configuration.images_dir}\//, '')
-        sprites = Compass::SpriteMap.new(relative_uri, Compass.sass_engine_options)
+        sprites = Compass::SpriteImporter.new(relative_uri, Compass.sass_engine_options)
         options[:output_file] ||= File.join(Compass.configuration.sass_path, "sprites", "_#{sprites.name}.#{Compass.configuration.preferred_syntax}")
         options[:skip_overrides] ||= false
         contents = sprites.content_for_images(options[:skip_overrides])
diff --git a/lib/compass/commands/update_project.rb b/lib/compass/commands/update_project.rb
index b98fa93a..1eb0a595 100644
--- a/lib/compass/commands/update_project.rb
+++ b/lib/compass/commands/update_project.rb
@@ -33,6 +33,7 @@ module Compass
       def perform
         compiler = new_compiler_instance
         check_for_sass_files!(compiler)
+        compiler.clean! if compiler.new_config?
         compiler.run
       end
 
diff --git a/lib/compass/commands/watch_project.rb b/lib/compass/commands/watch_project.rb
index cdc2bf2f..0246aca9 100644
--- a/lib/compass/commands/watch_project.rb
+++ b/lib/compass/commands/watch_project.rb
@@ -135,7 +135,7 @@ module Compass
 
       def recompile(base = nil, relative = nil)
         @memory_cache.reset! if @memory_cache
-        compiler = new_compiler_instance(:quiet => true)
+        compiler = new_compiler_instance(:quiet => true, :loud => [:identical, :overwrite, :create])
         if file = compiler.out_of_date?
           begin
             puts ">>> Change detected to: #{relative || compiler.relative_stylesheet_name(file)}"
diff --git a/lib/compass/compiler.rb b/lib/compass/compiler.rb
index 0f4f70f9..e7f6feef 100644
--- a/lib/compass/compiler.rb
+++ b/lib/compass/compiler.rb
@@ -153,7 +153,7 @@ module Compass
       formatted_error = "(Line #{e.sass_line}: #{e.message})"
       file = basename(sass_filename)
       logger.record :error, file, formatted_error
-      Compass.configuration.run_callback(:styesheet_error, sass_filename, formatted_error)
+      Compass.configuration.run_callback(:stylesheet_error, sass_filename, formatted_error)
       write_file css_filename, error_contents(e, sass_filename), options.merge(:force => true)
     end
 
diff --git a/lib/compass/configuration/adapters.rb b/lib/compass/configuration/adapters.rb
index 6a35c91a..352eb3c4 100644
--- a/lib/compass/configuration/adapters.rb
+++ b/lib/compass/configuration/adapters.rb
@@ -23,7 +23,7 @@ module Compass
         plugin_opts[:cache_location] = cache_path unless cache_path.nil?
         plugin_opts.merge!(sass_options || {})
         plugin_opts[:load_paths] ||= []
-        plugin_opts[:load_paths] << Compass::SpriteMap.new
+        plugin_opts[:load_paths] << Compass::SpriteImporter.new
         plugin_opts
       end
 
@@ -63,7 +63,7 @@ module Compass
           next p if p.respond_to?(:find_relative)
           Sass::Importers::Filesystem.new(p.to_s)
         end
-        load_paths << Compass::SpriteMap.new
+        load_paths << Compass::SpriteImporter.new
         load_paths
       end
     end
diff --git a/lib/compass/sass_extensions/functions/sprites.rb b/lib/compass/sass_extensions/functions/sprites.rb
index 69b7599e..0bd54ff5 100644
--- a/lib/compass/sass_extensions/functions/sprites.rb
+++ b/lib/compass/sass_extensions/functions/sprites.rb
@@ -10,7 +10,7 @@ module Compass::SassExtensions::Functions::Sprites
     end
   end
 
-  # Creates a Compass::SassExtensions::Sprites::Base object. A sprite map, when used in a property is the same
+  # Creates a Compass::SassExtensions::Sprites::SpriteMap object. A sprite map, when used in a property is the same
   # as calling sprite-url. So the following background properties are equivalent:
   #
   #     $icons: sprite-map("icons/*.png");
@@ -21,7 +21,7 @@ module Compass::SassExtensions::Functions::Sprites
   # the first time it is converted to a url. Simply constructing it has no side-effects.
   def sprite_map(glob, kwargs = {})
     kwargs.extend VariableReader
-    Compass::SassExtensions::Sprites::Base.from_uri(glob, self, kwargs)
+    Compass::SassExtensions::Sprites::SpriteMap.from_uri(glob, self, kwargs)
   end 
   Sass::Script::Functions.declare :sprite_map, [:glob], :var_kwargs => true
 
@@ -160,7 +160,7 @@ protected
   end
 
   def verify_map(map, error = "sprite")
-    unless map.is_a?(Compass::SassExtensions::Sprites::Base)
+    unless map.is_a?(Compass::SassExtensions::Sprites::SpriteMap)
       missing_sprite!(error)
     end
   end
diff --git a/lib/compass/sass_extensions/sprites.rb b/lib/compass/sass_extensions/sprites.rb
index faf6afec..919de7fd 100644
--- a/lib/compass/sass_extensions/sprites.rb
+++ b/lib/compass/sass_extensions/sprites.rb
@@ -1,4 +1,14 @@
 require 'digest/md5'
+require 'compass/sprite_importer'
+
+
+module Compass
+  module SassExtensions
+    module Sprites
+    end
+  end
+end
+
 #modules
 require 'compass/sass_extensions/sprites/sprite'
 require 'compass/sass_extensions/sprites/processing'
@@ -8,12 +18,4 @@ require 'compass/sass_extensions/sprites/sprite_map'
 require 'compass/sass_extensions/sprites/image'
 require 'compass/sass_extensions/sprites/row_fitter'
 require 'compass/sass_extensions/sprites/image_row'
-require 'compass/sass_extensions/sprites/base'
-require 'compass/sass_extensions/sprites/engines'
-
-module Compass
-  module SassExtensions
-    module Sprites
-    end
-  end
-end
\ No newline at end of file
+require 'compass/sass_extensions/sprites/engines'
\ No newline at end of file
diff --git a/lib/compass/sass_extensions/sprites/sprite_map.rb b/lib/compass/sass_extensions/sprites/sprite_map.rb
index 69e3edf9..2bdf905c 100644
--- a/lib/compass/sass_extensions/sprites/sprite_map.rb
+++ b/lib/compass/sass_extensions/sprites/sprite_map.rb
@@ -1,185 +1,213 @@
 module Compass
-  class SpriteMap < Sass::Importers::Base
-    attr_accessor :uri, :options
-    VAILD_FILE_NAME = /\A#{Sass::SCSS::RX::IDENT}\Z/
-    SPRITE_IMPORTER_REGEX = %r{((.+/)?([^\*.]+))/(.+?)\.png}
-    
-    def self.load(uri, options)
-      Compass.quick_cache "Sprite_map:#{uri}#{options.inspect}", 5 do
-        klass = Compass::SpriteMap.new
-        klass.uri, klass.options = uri, options
-        klass
-      end
-    end
-    
-    def initialize(options ={})
-      @uri, @options = '', {}
-      options.each do |key, value|
-        send("#{key}=", value)
-      end
-    end
-    
-    def find(uri, options)
-      @uri, @options = uri, options
-      if uri =~ SPRITE_IMPORTER_REGEX
-        return sass_engine
-      end
-    end
-    
-    def find_relative(uri, base, options)
-      @uri, @options = uri, options
-      find(File.join(base, uri), options)
-    end
-    
-    def to_s
-      content_for_images
-    end
-    
-    def hash
-      self.class.name.hash
-    end
-	
-    def eql?(other)
-      other.class == self.class
-    end
-    
-
-    
-    def key(uri, options={})
-      @uri, @options = uri, options
-      [self.class.name + ":" + File.dirname(File.expand_path(uri)), File.basename(uri)]
-    end
-    
-    def self.path_and_name(uri)
-      Compass.quick_cache "Sprite_map_name:#{uri}", 5 do
-        if uri =~ SPRITE_IMPORTER_REGEX
-          [$1, $3]
-        else
-          [nil, nil]
+  module SassExtensions
+    module Sprites
+      class SpriteMap < Sass::Script::Literal
+        
+        
+        # Initialize a new sprite object from a relative file path
+        # the path is relative to the <tt>images_path</tt> confguration option
+        def self.from_uri(uri, context, kwargs)
+          importer = ::Compass::SpriteImporter.new(:uri => uri.value, :options => {})
+          sprites = importer.files.map do |sprite|
+            sprite.gsub(Compass.configuration.images_path+"/", "")
+          end
+          new(sprites, importer.path, importer.name, context, kwargs)
         end
-      end
-    end
-
-    # Name of this spite
-    def name
-      ensure_path_and_name!
-      @name
-    end
-
-    # The on-disk location of this sprite
-    def path
-      ensure_path_and_name!
-      @path
-    end
-    
-    # Returns the Glob of image files for this sprite
-    def files
-      @files ||= Dir[File.join(Compass.configuration.images_path, uri)].sort
-    end
-
-    # Returns an Array of image names without the file extension
-    def sprite_names
-      @sprite_names ||= files.collect do |file|
-        filename = File.basename(file, '.png')
-        unless VAILD_FILE_NAME =~ filename
-          raise Compass::Error, "Sprite file names must be legal css identifiers. Please rename #{File.basename(file)}"
+        
+        # Loads the sprite engine
+        def require_engine!
+          self.class.send(:include, eval("::Compass::SassExtensions::Sprites::#{modulize}Engine"))
         end
-        filename
+      
+        # Changing this string will invalidate all previously generated sprite images.
+        # We should do so only when the packing algorithm changes
+        SPRITE_VERSION = "1"
+
+        attr_accessor :image_names, :path, :name, :kwargs
+        attr_accessor :images, :width, :height
+
+
+        def initialize(sprites, path, name, context, kwargs)
+          require_engine!
+          @image_names = sprites
+          @path = path
+          @name = name
+          @kwargs = kwargs
+          @kwargs['cleanup'] ||= Sass::Script::Bool.new(true)
+          @images = nil
+          @width = nil
+          @height = nil
+          @evaluation_context = context
+          validate!
+          compute_image_metadata!
+        end
+
+        # Calculate the size of the sprite
+        def size
+          [width, height]
+        end
+      
+        # Calculates the overal image dimensions
+        # collects image sizes and input parameters for each sprite
+        # Calculates the height
+        def compute_image_metadata!
+          @width = 0
+          init_images
+          compute_image_positions!
+          @height = @images.last.top + @images.last.height
+        end
+        
+        # Creates the Sprite::Image objects for each image and calculates the width
+        def init_images
+          @images = image_names.collect do |relative_file|
+            image = Compass::SassExtensions::Sprites::Image.new(self, relative_file, kwargs)
+            @width = [ @width, image.width + image.offset ].max
+            image
+          end
+        end
+        
+        # Calculates the overal image dimensions
+        # collects image sizes and input parameters for each sprite
+        def compute_image_positions!
+          @images.each_with_index do |image, index|
+            image.left = image.position.unit_str == "%" ? (@width - image.width) * (image.position.value / 100) : image.position.value
+            next if index == 0
+            last_image = @images[index-1]
+            image.top = last_image.top + last_image.height + [image.spacing,  last_image.spacing].max
+          end
+        end
+        
+        # Fetches the Sprite::Image object for the supplied name
+        def image_for(name)
+          @images.detect { |img| img.name == name}
+        end
+        
+        # Returns true if the image name has a hover selector image
+        def has_hover?(name)
+          !image_for("#{name}_hover").nil?
+        end
+        
+        # Returns true if the image name has a target selector image
+        def has_target?(name)
+          !image_for("#{name}_target").nil?
+        end
+        
+        # Returns true if the image name has an active selector image
+        def has_active?(name)
+          !image_for("#{name}_active").nil?
+        end
+        
+        # Return and array of image names that make up this sprite
+        def sprite_names
+          image_names.map { |f| File.basename(f, '.png') }
+        end
+
+
+        # Validates that the sprite_names are valid sass
+        def validate!
+          for sprite_name in sprite_names
+            unless sprite_name =~ /\A#{Sass::SCSS::RX::IDENT}\Z/
+              raise Sass::SyntaxError, "#{sprite_name} must be a legal css identifier"
+            end
+          end
+        end
+
+        # The on-the-disk filename of the sprite
+        def filename
+          File.join(Compass.configuration.images_path, "#{path}-#{uniqueness_hash}.png")
+        end
+
+        # Generate a sprite image if necessary
+        def generate
+          if generation_required?
+            if kwargs.get_var('cleanup').value
+              cleanup_old_sprites
+            end
+            sprite_data = construct_sprite
+            save!(sprite_data)
+            Compass.configuration.run_callback(:sprite_generated, sprite_data)
+          end
+        end
+        
+        def cleanup_old_sprites
+          Dir[File.join(Compass.configuration.images_path, "#{path}-*.png")].each do |file|
+            FileUtils.rm file
+          end
+        end
+        
+        # Does this sprite need to be generated
+        def generation_required?
+          !File.exists?(filename) || outdated?
+        end
+
+        # Returns the uniqueness hash for this sprite object
+        def uniqueness_hash
+          @uniqueness_hash ||= begin
+            sum = Digest::MD5.new
+            sum << SPRITE_VERSION
+            sum << path
+            images.each do |image|
+              [:relative_file, :height, :width, :repeat, :spacing, :position, :digest].each do |attr|
+                sum << image.send(attr).to_s
+              end
+            end
+            sum.hexdigest[0...10]
+          end
+          @uniqueness_hash
+        end
+
+        # Saves the sprite engine
+        def save!(output_png)
+          saved = output_png.save filename
+          Compass.configuration.run_callback(:sprite_saved, filename)
+          saved
+        end
+
+        # All the full-path filenames involved in this sprite
+        def image_filenames
+          @images.map(&:file)
+        end
+
+        # Checks whether this sprite is outdated
+        def outdated?
+          if File.exists?(filename)
+            return @images.map(&:mtime).any? { |imtime| imtime.to_i > self.mtime.to_i }
+          end
+          true
+        end
+
+        # Mtime of the sprite file
+        def mtime
+          @mtime ||= File.mtime(filename)
+        end
+
+        def inspect
+          to_s
+        end
+
+        def to_s(kwargs = self.kwargs)
+          sprite_url(self).value
+        end
+
+        def respond_to?(meth)
+          super || @evaluation_context.respond_to?(meth)
+        end
+
+        def method_missing(meth, *args, &block)
+          if @evaluation_context.respond_to?(meth)
+            @evaluation_context.send(meth, *args, &block)
+          else
+            super
+          end
+        end
+        
+        private 
+        
+        def modulize
+          @modulize ||= Compass::configuration.sprite_engine.to_s.scan(/([^_.]+)/).flatten.map {|chunk| "#{chunk[0].chr.upcase}#{chunk[1..-1]}" }.join
+        end
+        
       end
     end
-    
-    # Returns the sass options for this sprite
-    def sass_options
-      @sass_options ||= options.merge(:filename => name, :syntax => :scss, :importer => self)
-    end
-    
-    # Returns a Sass::Engine for this sprite object
-    def sass_engine
-      Sass::Engine.new(content_for_images, sass_options)
-    end
-    
-    def ensure_path_and_name!
-      @path, @name = self.class.path_and_name(uri)
-    end 
-
-    # Generates the Sass for this sprite file
-    def content_for_images(skip_overrides = false)
-      <<-SCSS
-@import "compass/utilities/sprites/base";
-
-// General Sprite Defaults
-// You can override them before you import this file.
-$#{name}-sprite-base-class: ".#{name}-sprite" !default;
-$#{name}-sprite-dimensions: false !default;
-$#{name}-position: 0% !default;
-$#{name}-spacing: 0 !default;
-$#{name}-repeat: no-repeat !default;
-$#{name}-prefix: '' !default;
-$#{name}-clean-up: true !default;
-$#{name}-smart-pack: false !default;
-
-#{skip_overrides ? "$#{name}-sprites: sprite-map(\"#{uri}\", $smart-pack: $#{name}-smart-pack, $cleanup: $#{name}-clean-up);" : generate_overrides }
-
-// All sprites should extend this class
-// The #{name}-sprite mixin will do so for you.
-\#{$#{name}-sprite-base-class} {
-  background: $#{name}-sprites no-repeat;
-}
-
-// Use this to set the dimensions of an element
-// based on the size of the original image.
-@mixin #{name}-sprite-dimensions($name) {
-  @include sprite-dimensions($#{name}-sprites, $name)
-}
-
-// Move the background position to display the sprite.
-@mixin #{name}-sprite-position($name, $offset-x: 0, $offset-y: 0) {
-  @include sprite-background-position($#{name}-sprites, $name, $offset-x, $offset-y)
-}
-
-// Extends the sprite base class and set the background position for the desired sprite.
-// It will also apply the image dimensions if $dimensions is true.
-@mixin #{name}-sprite($name, $dimensions: $#{name}-sprite-dimensions, $offset-x: 0, $offset-y: 0) {
-  @extend \#{$#{name}-sprite-base-class};
-  @include sprite($#{name}-sprites, $name, $dimensions, $offset-x, $offset-y)
-}
-
-@mixin #{name}-sprites($sprite-names, $dimensions: $#{name}-sprite-dimensions, $prefix: sprite-map-name($#{name}-sprites)) {
-  @include sprites($#{name}-sprites, $sprite-names, $#{name}-sprite-base-class, $dimensions, $prefix)
-}
-
-// Generates a class for each sprited image.
-@mixin all-#{name}-sprites($dimensions: $#{name}-sprite-dimensions, $prefix: sprite-map-name($#{name}-sprites)) {
-  @include #{name}-sprites(#{sprite_names.join(" ")}, $dimensions, $prefix);
-}
-SCSS
-    end
-    
-    # Generates the override defaults for this Sprite
-    # <tt>$#{name}-#{sprite_name}-position </tt>
-    # <tt> $#{name}-#{sprite_name}-spacing </tt>
-    # <tt> #{name}-#{sprite_name}-repeat: </tt>
-    def generate_overrides
-      content = <<-TXT
-// These variables control the generated sprite output
-// You can override them selectively before you import this file.
-      TXT
-      sprite_names.map do |sprite_name| 
-        content += <<-SCSS
-$#{name}-#{sprite_name}-position: $#{name}-position !default;
-$#{name}-#{sprite_name}-spacing: $#{name}-spacing !default;
-$#{name}-#{sprite_name}-repeat: $#{name}-repeat !default;
-        SCSS
-      end.join
-
-      content += "\n$#{name}-sprites: sprite-map(\"#{uri}\", \n $smart-pack: $#{name}-smart-pack, $cleanup: $#{name}-clean-up,\n"
-      content += sprite_names.map do |sprite_name| 
-%Q{  $#{sprite_name}-position: $#{name}-#{sprite_name}-position,
-  $#{sprite_name}-spacing: $#{name}-#{sprite_name}-spacing,
-  $#{sprite_name}-repeat: $#{name}-#{sprite_name}-repeat}
-      end.join(",\n")
-      content += ");"
-    end
   end
 end
-
diff --git a/lib/compass/sprite_importer.rb b/lib/compass/sprite_importer.rb
new file mode 100644
index 00000000..1b02ccba
--- /dev/null
+++ b/lib/compass/sprite_importer.rb
@@ -0,0 +1,184 @@
+module Compass
+  class SpriteImporter < Sass::Importers::Base
+    attr_accessor :uri, :options
+    VAILD_FILE_NAME = /\A#{Sass::SCSS::RX::IDENT}\Z/
+    SPRITE_IMPORTER_REGEX = %r{((.+/)?([^\*.]+))/(.+?)\.png}
+    
+    def self.load(uri, options)
+      Compass.quick_cache "Sprite_map:#{uri}#{options.inspect}", 5 do
+        klass = Compass::SpriteImporter.new
+        klass.uri, klass.options = uri, options
+        klass
+      end
+    end
+    
+    def initialize(options ={})
+      @uri, @options = '', {}
+      options.each do |key, value|
+        send("#{key}=", value)
+      end
+    end
+    
+    def find(uri, options)
+      @uri, @options = uri, options
+      if uri =~ SPRITE_IMPORTER_REGEX
+        return sass_engine
+      end
+    end
+    
+    def find_relative(uri, base, options)
+      @uri, @options = uri, options
+      find(File.join(base, uri), options)
+    end
+    
+    def to_s
+      content_for_images
+    end
+    
+    def hash
+      self.class.name.hash
+    end
+	
+    def eql?(other)
+      other.class == self.class
+    end
+    
+
+    
+    def key(uri, options={})
+      @uri, @options = uri, options
+      [self.class.name + ":" + File.dirname(File.expand_path(uri)), File.basename(uri)]
+    end
+    
+    def self.path_and_name(uri)
+      Compass.quick_cache "Sprite_map_name:#{uri}", 5 do
+        if uri =~ SPRITE_IMPORTER_REGEX
+          [$1, $3]
+        else
+          [nil, nil]
+        end
+      end
+    end
+
+    # Name of this spite
+    def name
+      ensure_path_and_name!
+      @name
+    end
+
+    # The on-disk location of this sprite
+    def path
+      ensure_path_and_name!
+      @path
+    end
+    
+    # Returns the Glob of image files for this sprite
+    def files
+      @files ||= Dir[File.join(Compass.configuration.images_path, uri)].sort
+    end
+
+    # Returns an Array of image names without the file extension
+    def sprite_names
+      @sprite_names ||= files.collect do |file|
+        filename = File.basename(file, '.png')
+        unless VAILD_FILE_NAME =~ filename
+          raise Compass::Error, "Sprite file names must be legal css identifiers. Please rename #{File.basename(file)}"
+        end
+        filename
+      end
+    end
+    
+    # Returns the sass options for this sprite
+    def sass_options
+      @sass_options ||= options.merge(:filename => name, :syntax => :scss, :importer => self)
+    end
+    
+    # Returns a Sass::Engine for this sprite object
+    def sass_engine
+      Sass::Engine.new(content_for_images, sass_options)
+    end
+    
+    def ensure_path_and_name!
+      @path, @name = self.class.path_and_name(uri)
+    end 
+
+    # Generates the Sass for this sprite file
+    def content_for_images(skip_overrides = false)
+      <<-SCSS
+@import "compass/utilities/sprites/base";
+
+// General Sprite Defaults
+// You can override them before you import this file.
+$#{name}-sprite-base-class: ".#{name}-sprite" !default;
+$#{name}-sprite-dimensions: false !default;
+$#{name}-position: 0% !default;
+$#{name}-spacing: 0 !default;
+$#{name}-repeat: no-repeat !default;
+$#{name}-prefix: '' !default;
+$#{name}-clean-up: true !default;
+
+#{skip_overrides ? "$#{name}-sprites: sprite-map(\"#{uri}\", $cleanup: $#{name}-clean-up);" : generate_overrides }
+
+// All sprites should extend this class
+// The #{name}-sprite mixin will do so for you.
+\#{$#{name}-sprite-base-class} {
+  background: $#{name}-sprites no-repeat;
+}
+
+// Use this to set the dimensions of an element
+// based on the size of the original image.
+@mixin #{name}-sprite-dimensions($name) {
+  @include sprite-dimensions($#{name}-sprites, $name)
+}
+
+// Move the background position to display the sprite.
+@mixin #{name}-sprite-position($name, $offset-x: 0, $offset-y: 0) {
+  @include sprite-background-position($#{name}-sprites, $name, $offset-x, $offset-y)
+}
+
+// Extends the sprite base class and set the background position for the desired sprite.
+// It will also apply the image dimensions if $dimensions is true.
+@mixin #{name}-sprite($name, $dimensions: $#{name}-sprite-dimensions, $offset-x: 0, $offset-y: 0) {
+  @extend \#{$#{name}-sprite-base-class};
+  @include sprite($#{name}-sprites, $name, $dimensions, $offset-x, $offset-y)
+}
+
+@mixin #{name}-sprites($sprite-names, $dimensions: $#{name}-sprite-dimensions, $prefix: sprite-map-name($#{name}-sprites)) {
+  @include sprites($#{name}-sprites, $sprite-names, $#{name}-sprite-base-class, $dimensions, $prefix)
+}
+
+// Generates a class for each sprited image.
+@mixin all-#{name}-sprites($dimensions: $#{name}-sprite-dimensions, $prefix: sprite-map-name($#{name}-sprites)) {
+  @include #{name}-sprites(#{sprite_names.join(" ")}, $dimensions, $prefix);
+}
+SCSS
+    end
+    
+    # Generates the override defaults for this Sprite
+    # <tt>$#{name}-#{sprite_name}-position </tt>
+    # <tt> $#{name}-#{sprite_name}-spacing </tt>
+    # <tt> #{name}-#{sprite_name}-repeat: </tt>
+    def generate_overrides
+      content = <<-TXT
+// These variables control the generated sprite output
+// You can override them selectively before you import this file.
+      TXT
+      sprite_names.map do |sprite_name| 
+        content += <<-SCSS
+$#{name}-#{sprite_name}-position: $#{name}-position !default;
+$#{name}-#{sprite_name}-spacing: $#{name}-spacing !default;
+$#{name}-#{sprite_name}-repeat: $#{name}-repeat !default;
+        SCSS
+      end.join
+
+      content += "\n$#{name}-sprites: sprite-map(\"#{uri}\", \n$cleanup: $#{name}-clean-up,\n"
+      content += sprite_names.map do |sprite_name| 
+%Q{  $#{sprite_name}-position: $#{name}-#{sprite_name}-position,
+  $#{sprite_name}-spacing: $#{name}-#{sprite_name}-spacing,
+  $#{sprite_name}-repeat: $#{name}-#{sprite_name}-repeat}
+      end.join(",\n")
+      content += ");"
+    end
+  end
+end
+
diff --git a/spec/compass/sass_extensions/sprites/base_spec.rb b/spec/compass/sass_extensions/sprites/base_spec.rb
index 6a086737..1d8cfedc 100644
--- a/spec/compass/sass_extensions/sprites/base_spec.rb
+++ b/spec/compass/sass_extensions/sprites/base_spec.rb
@@ -11,7 +11,7 @@ describe Compass::SassExtensions::Sprites::Base do
     Compass.configure_sass_plugin!
     #fix this eww
     options = Compass.sass_engine_options.extend Compass::SassExtensions::Functions::Sprites::VariableReader
-    @map = Compass::SpriteMap.new("selectors/*.png", options)
+    @map = Compass::SpriteImporter.new("selectors/*.png", options)
     @base = Compass::SassExtensions::Sprites::Base.new(@map.sprite_names.map{|n| "selectors/#{n}.png"}, @map.path, 'selectors', @map.sass_engine, @map.options)
   end
 
diff --git a/spec/compass/sass_extensions/sprites/sprite_map_spec.rb b/spec/compass/sass_extensions/sprites/sprite_map_spec.rb
index a6eee9ea..30a3895d 100644
--- a/spec/compass/sass_extensions/sprites/sprite_map_spec.rb
+++ b/spec/compass/sass_extensions/sprites/sprite_map_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
 require 'fakefs/spec_helpers'
 require 'timecop'
 
-describe Compass::SpriteMap do
+describe Compass::SpriteImporter do
   include FakeFS::SpecHelpers
 
   let(:sprite_map) { self.class.describes.new(uri, options) }
diff --git a/test/fixtures/stylesheets/error/config.rb b/test/fixtures/stylesheets/error/config.rb
new file mode 100644
index 00000000..f4a6649f
--- /dev/null
+++ b/test/fixtures/stylesheets/error/config.rb
@@ -0,0 +1,10 @@
+# Require any additional compass plugins here.
+css_dir = "tmp"
+sass_dir = "sass"
+images_dir = "assets/images"
+javascripts_dir = "assets/javascripts"
+# Set this to the root of your project when deployed:
+http_path = "/"
+# To enable relative paths to assets via compass helper functions. Uncomment:
+output_style = :compact
+relative_assets = true
diff --git a/test/fixtures/stylesheets/error/sass/screen.sass b/test/fixtures/stylesheets/error/sass/screen.sass
new file mode 100644
index 00000000..6b797912
--- /dev/null
+++ b/test/fixtures/stylesheets/error/sass/screen.sass
@@ -0,0 +1,2 @@
+test
+  background: image_url("testing.png)
diff --git a/test/integrations/compass_test.rb b/test/integrations/compass_test.rb
index 26491328..ebe2bc54 100644
--- a/test/integrations/compass_test.rb
+++ b/test/integrations/compass_test.rb
@@ -30,14 +30,16 @@ class CompassTest < Test::Unit::TestCase
 
   # no project with errors exists to test aginst - leep of FAITH!
   # *chriseppstein flogs himself*
-  # def test_on_stylesheet_error_callback
-  #     error = false
-  #     file = nil
-  #     Compass.configuration.on_stylesheet_error {|filename, message| file = filename; error = true }
-  #     within_project(:error) { } #requires a block but we don't need to pass anything - sdavis
-  #     assert error, "Project did not throw a compile error"
-  #     assert file.is_a?(String), "Filename was not a string"
-  #   end
+  def test_on_stylesheet_error_callback
+      error = false
+      file = nil
+      before_compile = Proc.new do |config|
+        config.on_stylesheet_error {|filename, message| file = filename; error = true }
+      end
+      within_project(:error, before_compile) rescue nil;
+      assert error, "Project did not throw a compile error"
+      assert file.is_a?(String), "Filename was not a string"
+    end
 
   def test_empty_project
     # With no sass files, we should have no css files.
diff --git a/test/units/actions_test.rb b/test/units/actions_test.rb
new file mode 100644
index 00000000..21b26414
--- /dev/null
+++ b/test/units/actions_test.rb
@@ -0,0 +1,24 @@
+require 'test_helper'
+require 'compass'
+
+class ActionsTest < Test::Unit::TestCase
+  class BaseActionExtender
+    include Compass::Actions
+    def options
+      @@options ||= {}
+    end
+    def working_path
+      "/tmp"
+    end
+  end
+  
+  # When log4r is included, it sometimes breaks the Actions
+  def test_quiet_option
+    b = BaseActionExtender.new
+    b.logger = ""
+    b.options[:quiet] = true
+
+    # logger shouldn't be called... if it is, this will error
+    b.directory("/tmp/#{(rand * 1000000).to_i}")
+  end
+end
\ No newline at end of file
diff --git a/test/units/sprites/image_test.rb b/test/units/sprites/image_test.rb
index 36dcc93b..592cedbd 100644
--- a/test/units/sprites/image_test.rb
+++ b/test/units/sprites/image_test.rb
@@ -3,7 +3,6 @@ require 'mocha'
 require 'ostruct'
 class SpritesImageTest < Test::Unit::TestCase
 
-
   def setup
     @images_src_path = File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'sprites', 'public', 'images')
     file = StringIO.new("images_path = #{@images_src_path.inspect}\n")
@@ -19,8 +18,8 @@ class SpritesImageTest < Test::Unit::TestCase
   let(:sprite_name) { File.basename(sprite_filename, '.png') }
   
   def parent
-    map = Compass::SpriteMap.new(:uri => "selectors/*.png", :options => {'cleanup' => Sass::Script::Bool.new(true), 'smart_pack' => Sass::Script::Bool.new(false)})
-    @parent ||= Compass::SassExtensions::Sprites::Base.new(map.sprite_names.map{|n| "selectors/#{n}.png"}, map, map.sass_engine, map.options)
+    importer = Compass::SpriteImporter.new(:uri => "selectors/*.png", :options => options)
+    @parent ||= Compass::SassExtensions::Sprites::SpriteMap.new(importer.sprite_names.map{|n| "selectors/#{n}.png"}, importer.path, importer.name, importer.sass_engine, importer.options)
   end
   
   let(:options) do
diff --git a/test/units/sprites/base_test.rb b/test/units/sprites/sprite_map_test.rb
similarity index 87%
rename from test/units/sprites/base_test.rb
rename to test/units/sprites/sprite_map_test.rb
index 511a5501..69c375ef 100644
--- a/test/units/sprites/base_test.rb
+++ b/test/units/sprites/sprite_map_test.rb
@@ -1,7 +1,7 @@
 require 'test_helper'
 
-class SpritesBaseTest < Test::Unit::TestCase
-  attr_accessor :options
+class SpriteMapTest < Test::Unit::TestCase
+  
   def setup
     Hash.send(:include, Compass::SassExtensions::Functions::Sprites::VariableReader)
     @images_src_path = File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'sprites', 'public', 'images')
@@ -16,8 +16,8 @@ class SpritesBaseTest < Test::Unit::TestCase
   end
   
   def setup_map
-    @map = Compass::SpriteMap.new(:uri => "selectors/*.png", :options => options)
-    @base = Compass::SassExtensions::Sprites::Base.new(@map.sprite_names.map{|n| "selectors/#{n}.png"}, @map, @map.sass_engine, @map.options)
+    @importer = Compass::SpriteImporter.new(:uri => "selectors/*.png", :options => @options)
+    @base = Compass::SassExtensions::Sprites::SpriteMap.new(@importer.sprite_names.map{|n| "selectors/#{n}.png"}, @importer.path, @importer.name, @importer.sass_engine, @importer.options)
   end
 
   def teardown
@@ -29,7 +29,7 @@ class SpritesBaseTest < Test::Unit::TestCase
   end
   
   it "should have the sprite names" do
-    assert_equal @map.sprite_names, @base.sprite_names
+    assert_equal @importer.sprite_names, @base.sprite_names
   end
   
   it 'should have image filenames' do