<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,5 +1,8 @@
 == master
 
+* Replace dynamic :salt option with :embed_salt option and utilizing the #encrypts block 
+* Allow a block to be used for dynamically defining encryption options
+* Add :before / :after callbacks for hooking into the encryption process
 * Allow the callback when encryption occurs to be customized [Sergio Salvatore]
 * Define source attribute accessor if different than target and not defined [Sergio Salvatore]
 * Update tests to work with Rails 2.3</diff>
      <filename>CHANGELOG.rdoc</filename>
    </modified>
    <modified>
      <diff>@@ -25,7 +25,7 @@ Source
 
 Encrypting attributes can be repetitive especially when doing so throughout
 various models and various projects.  encrypted_attributes, in association
-with the encrypted_strings plugin, helps make encrypting ActiveRecord
+with the encrypted_strings library, helps make encrypting ActiveRecord
 attributes easier by automating the process.
 
 The options that +encrypts+ takes includes all of the encryption options for
@@ -35,46 +35,46 @@ into the +encrypts+ method.  Examples of this are show in the Usage section.
 
 == Usage
 
-=== SHA Encryption
+=== Encryption Modes
 
-For SHA encryption, you can either use the default salt, a custom salt, or
-generate one based on the attributes of the model.
+SHA, symmetric, and asymmetric encryption modes are supported (default is SHA):
 
-With the default salt:
   class User &lt; ActiveRecord::Base
-    encrypts :password
+    encrypts :password, :salt =&gt; 'secret'
+    # encrypts :password, :mode =&gt; :symmetric, :password =&gt; 'secret'
+    # encrypts :password, :mode =&gt; :asymmetric, :public_key_file =&gt; '/keys/public', :private_key_file =&gt; '/keys/private'
   end
 
-With a custom salt based on the record's values:
-  class User &lt; ActiveRecord::Base
-    encrypts :password, :salt =&gt; :create_salt
-    
-    private
-      def create_salt
-        &quot;#{login}_salt&quot;
-      end
-  end
+=== Dynamic Configuration
 
-The salt and password values are combined and stored in the attribute being
-encrypted.  Therefore, there's no need to add a second column for storing the
-salt value.
-
-=== Symmetric Encryption
+The encryption configuration can be dynamically set like so:
 
   class User &lt; ActiveRecord::Base
-    encrypts :password, :mode =&gt; :symmetric, :password =&gt; 'secret'
+    encrypts :password, :mode =&gt; :sha do |user|
+      {:salt =&gt; &quot;#{user.login}-#{Time.now}&quot;, :embed_salt =&gt; true}
+    end
   end
 
-=== Asymmetric Encryption
+In this case, the salt and password values are combined and stored in the
+attribute being encrypted.  Therefore, there's no need to add a second column
+for storing the salt value.
+
+To store the dynamic salt in a separate column:
 
   class User &lt; ActiveRecord::Base
-    encrypts :password, :mode =&gt; :asymmetric, :public_key_file =&gt; '/keys/public', :private_key_file =&gt; '/keys/private'
+    encrypts :password, :mode =&gt; :sha, :before =&gt; :create_salt do |user|
+      {:salt =&gt; user.salt}
+    end
+    
+    def create_salt
+      self.salt = &quot;#{login}-#{Time.now}&quot;
+    end
   end
 
 === Targeted Encryption
 
 If you want to store the encrypted value in a different attribute than the
-attribute being encrypted, you can do so like so:
+attribute being encrypted:
 
   class User &lt; ActiveRecord::Base
     encrypts :password, :to =&gt; :crypted_password</diff>
      <filename>README.rdoc</filename>
    </modified>
    <modified>
      <diff>@@ -3,13 +3,17 @@ require 'encrypted_attributes/sha_cipher'
 
 module EncryptedAttributes
   module MacroMethods
-    # Encrypts the specified attribute.
+    # Encrypts the given attribute.
     # 
     # Configuration options:
-    # * &lt;tt&gt;:mode&lt;/tt&gt; - The mode of encryption to use.  Default is sha. See
-    #   EncryptedStrings for other possible modes.
-    # * &lt;tt&gt;:to&lt;/tt&gt; - The attribute to write the encrypted value to. Default is
-    #   the same attribute being encrypted.
+    # * &lt;tt&gt;:mode&lt;/tt&gt; - The mode of encryption to use.  Default is &lt;tt&gt;:sha&lt;/tt&gt;.
+    #   See EncryptedStrings for other possible modes.
+    # * &lt;tt&gt;:to&lt;/tt&gt; - The attribute to write the encrypted value to. Default
+    #   is the same attribute being encrypted.
+    # * &lt;tt&gt;:before&lt;/tt&gt; - The callback to invoke every time *before* the
+    #   attribute is encrypted
+    # * &lt;tt&gt;:after&lt;/tt&gt; - The callback to invoke every time *after* the
+    #   attribute is encrypted
     # * &lt;tt&gt;:on&lt;/tt&gt; - The ActiveRecord callback to use when triggering the
     #   encryption.  By default, this will encrypt on &lt;tt&gt;before_validation&lt;/tt&gt;.
     #   See ActiveRecord::Callbacks for a list of possible callbacks.
@@ -25,11 +29,11 @@ module EncryptedAttributes
     # 
     # == Encryption timeline
     # 
-    # Attributes are encrypted immediately before a record is validated.
-    # This means that you can still validate the presence of the encrypted
-    # attribute, but other things like password length cannot be validated
-    # without either (a) decrypting the value first or (b) using a different
-    # encryption target.  For example,
+    # By default, attributes are encrypted immediately before a record is
+    # validated.  This means that you can still validate the presence of the
+    # encrypted attribute, but other things like password length cannot be
+    # validated without either (a) decrypting the value first or (b) using a
+    # different encryption target.  For example,
     # 
     #   class User &lt; ActiveRecord::Base
     #     encrypts :password, :to =&gt; :crypted_password
@@ -59,7 +63,7 @@ module EncryptedAttributes
     # 
     #   class User &lt; ActiveRecord::Base
     #     encrypts :password
-    #     # encrypts :password, :salt =&gt; :create_salt
+    #     # encrypts :password, :salt =&gt; 'secret'
     #   end
     # 
     # Symmetric encryption:
@@ -75,7 +79,32 @@ module EncryptedAttributes
     #     encrypts :password, :mode =&gt; :asymmetric
     #     # encrypts :password, :mode =&gt; :asymmetric, :public_key_file =&gt; '/keys/public', :private_key_file =&gt; '/keys/private'
     #   end
-    def encrypts(attr_name, options = {})
+    # 
+    # == Dynamic configuration
+    # 
+    # For better security, the encryption options (such as the salt value)
+    # can be based on values in each individual record.  In order to
+    # dynamically configure the encryption options so that individual records
+    # can be referenced, an optional block can be specified.
+    # 
+    # For example,
+    # 
+    #   class User &lt; ActiveRecord::Base
+    #     encrypts :password, :mode =&gt; :sha, :before =&gt; :create_salt do |user|
+    #       {:salt =&gt; user.salt}
+    #     end
+    #     
+    #     private
+    #       def create_salt
+    #         self.salt = &quot;#{login}-#{Time.now}&quot;
+    #       end
+    #   end
+    # 
+    # In the above example, the SHA encryption's &lt;tt&gt;salt&lt;/tt&gt; is configured
+    # dynamically based on the user's login and the time at which it was
+    # encrypted.  This helps improve the security of the user's password.
+    def encrypts(attr_name, options = {}, &amp;config)
+      config ||= options
       attr_name = attr_name.to_s
       to_attr_name = (options.delete(:to) || attr_name).to_s
       
@@ -88,10 +117,15 @@ module EncryptedAttributes
         cipher_class = EncryptedStrings.const_get(class_name)
       end
       
+      # Define encryption hooks
+      define_callbacks(&quot;before_encrypt_#{attr_name}&quot;, &quot;after_encrypt_#{attr_name}&quot;)
+      send(&quot;before_encrypt_#{attr_name}&quot;, options.delete(:before)) if options.include?(:before)
+      send(&quot;after_encrypt_#{attr_name}&quot;, options.delete(:after)) if options.include?(:after)
+      
       # Set the encrypted value on the configured callback
       callback = options.delete(:on) || :before_validation
       send(callback, :if =&gt; options.delete(:if), :unless =&gt; options.delete(:unless)) do |record|
-        record.send(:write_encrypted_attribute, attr_name, to_attr_name, cipher_class, options)
+        record.send(:write_encrypted_attribute, attr_name, to_attr_name, cipher_class, config)
         true
       end
       
@@ -103,7 +137,7 @@ module EncryptedAttributes
       
       # Define the reader when reading the encrypted attribute from the database
       define_method(to_attr_name) do
-        read_encrypted_attribute(to_attr_name, cipher_class, options)
+        read_encrypted_attribute(to_attr_name, cipher_class, config)
       end
       
       unless included_modules.include?(EncryptedAttributes::InstanceMethods)
@@ -122,8 +156,10 @@ module EncryptedAttributes
         # Only encrypt values that actually have content and have not already
         # been encrypted
         unless value.blank? || value.encrypted?
+          callback(&quot;before_encrypt_#{attr_name}&quot;)
+          
           # Create the cipher configured for this attribute
-          cipher = create_cipher(cipher_class, options, :write, value)
+          cipher = create_cipher(cipher_class, options, value)
           
           # Encrypt the value
           value = cipher.encrypt(value)
@@ -131,6 +167,8 @@ module EncryptedAttributes
           
           # Update the value based on the target attribute
           send(&quot;#{to_attr_name}=&quot;, value)
+          
+          callback(&quot;after_encrypt_#{attr_name}&quot;)
         end
       end
       
@@ -148,21 +186,18 @@ module EncryptedAttributes
         # don't want to encrypt when a new value has been set)
         unless value.blank? || value.encrypted? || attribute_changed?(to_attr_name)
           # Create the cipher configured for this attribute
-          value.cipher = create_cipher(cipher_class, options, :read, value)
+          value.cipher = create_cipher(cipher_class, options, value)
         end
         
         value
       end
       
-      # Creates a new cipher with the given configuration options. The
-      # operator defines the context in which the cipher will be used.
-      def create_cipher(klass, options, operator, value)
-        if klass.parent == EncryptedAttributes
-          # Only use the contextual information for ciphers defined in this plugin
-          klass.new(self, value, operator, options.dup)
-        else
-          klass.new(options.dup)
-        end
+      # Creates a new cipher with the given configuration options
+      def create_cipher(klass, options, value)
+        options = options.is_a?(Proc) ? options.call(self) : options.dup
+        
+        # Only use the contextual information for this plugin's ciphers
+        klass.parent == EncryptedAttributes ? klass.new(value, options) : klass.new(options)
       end
   end
 end</diff>
      <filename>lib/encrypted_attributes.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,48 +1,29 @@
 module EncryptedAttributes
-  # Adds support for dynamically generated salts
+  # Adds support for embedding salts in the encrypted value
   class ShaCipher &lt; EncryptedStrings::ShaCipher
     # Encrypts a string using a Secure Hash Algorithm (SHA), specifically SHA-1.
     # 
-    # The &lt;tt&gt;:salt&lt;/tt&gt; configuration option can be any one of the following types:
-    # * +symbol+ - Calls the method on the object whose value is being encrypted
-    # * +proc+ - A block that will be invoked, providing it with the object
-    #   whose value is being encrypted
-    # * +string+ - The actual salt value to use
-    def initialize(object, value, operation, options = {}) #:nodoc:
-      if operation == :write
-        # Figure out the actual salt value
-        if salt = options[:salt]
-          options[:salt] =
-            case salt
-            when Symbol
-              object.send(salt)
-            when Proc
-              salt.call(object)
-            else
-              salt
-            end
-        end
-        
-        # Track whether or not the salt was generated dynamically
-        @dynamic_salt = salt != options[:salt]
-        
-        super(options)
-      else
-        # The salt is at the end of the value if it's dynamic
+    # Configuration options:
+    # * &lt;tt&gt;:salt&lt;/tt&gt; - Random bytes used as one of the inputs for generating
+    #   the encrypted string
+    # * &lt;tt&gt;:embed_salt&lt;/tt&gt; - Whether to embed the salt directly within the
+    #   encrypted value.  Default is false.  This is useful for storing both
+    #   the salt and the encrypted value in the same attribute.
+    def initialize(value, options = {}) #:nodoc:
+      if @embed_salt = options.delete(:embed_salt)
+        # The salt is at the end of the value
         salt = value[40..-1]
-        if @dynamic_salt = !salt.blank?
-          options[:salt] = salt 
-        end
-        
-        super(options)
+        options[:salt] = salt unless salt.blank?
       end
+      
+      super(options)
     end
     
-    # Encrypts the data, appending the salt to the end of the string if it
-    # was created dynamically
+    # Encrypts the data, embedding the salt at the end of the string if
+    # configured to do so
     def encrypt(data)
       encrypted_data = super
-      encrypted_data &lt;&lt; salt if @dynamic_salt
+      encrypted_data &lt;&lt; salt if @embed_salt
       encrypted_data
     end
   end</diff>
      <filename>lib/encrypted_attributes/sha_cipher.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 class CreateUsers &lt; ActiveRecord::Migration
   def self.up
     create_table :users do |t|
-      t.string :login, :password, :crypted_password
+      t.string :login, :password, :crypted_password, :salt
     end
   end
   </diff>
      <filename>test/app_root/db/migrate/001_create_users.rb</filename>
    </modified>
    <modified>
      <diff>@@ -177,9 +177,9 @@ class EncryptedAttributesWithConflictingVirtualAttributeSourceTest &lt; ActiveSuppo
   end
 end
 
-class EncryptedAttributesWithConditionalsTest &lt; ActiveSupport::TestCase
+class EncryptedAttributesWithCustomCallbackTest &lt; ActiveSupport::TestCase
   def setup
-    User.encrypts :password, :on =&gt; :before_create
+    User.encrypts :password, :on =&gt; :before_save
   end
   
   def test_should_not_encrypt_on_validation
@@ -201,12 +201,117 @@ class EncryptedAttributesWithConditionalsTest &lt; ActiveSupport::TestCase
   end
 end
 
-class EncryptedAttributesWithCustomCallbackTest &lt; ActiveSupport::TestCase
+class EncryptedAttributesWithConditionalsTest &lt; ActiveSupport::TestCase
   def test_should_not_encrypt_if_if_conditional_is_false
     User.encrypts :password, :if =&gt; lambda {|user| false}
     user = create_user(:login =&gt; 'admin', :password =&gt; 'secret')
     assert_equal 'secret', user.password
   end
+  
+  def test_should_encrypt_if_if_conditional_is_true
+    User.encrypts :password, :if =&gt; lambda {|user| true}
+    user = create_user(:login =&gt; 'admin', :password =&gt; 'secret')
+    assert_equal '8152bc582f58c854f580cb101d3182813dec4afe', &quot;#{user.password}&quot;
+  end
+  
+  def test_should_not_encrypt_if_unless_conditional_is_true
+    User.encrypts :password, :unless =&gt; lambda {|user| true}
+    user = create_user(:login =&gt; 'admin', :password =&gt; 'secret')
+    assert_equal 'secret', user.password
+  end
+  
+  def test_should_encrypt_if_unless_conditional_is_false
+    User.encrypts :password, :unless =&gt; lambda {|user| false}
+    user = create_user(:login =&gt; 'admin', :password =&gt; 'secret')
+    assert_equal '8152bc582f58c854f580cb101d3182813dec4afe', &quot;#{user.password}&quot;
+  end
+  
+  def teardown
+    User.class_eval do
+      @before_validation_callbacks = nil
+    end
+  end
+end
+
+class EncryptedAttributesWithBeforeCallbacksTest &lt; ActiveSupport::TestCase
+  def setup
+    @password = nil
+    @ran_callback = false
+    User.encrypts :password, :before =&gt; lambda {|user| @ran_callback = true; @password = user.password.to_s}
+    
+    create_user(:login =&gt; 'admin', :password =&gt; 'secret')
+  end
+  
+  def test_should_run_callback
+    assert @ran_callback
+  end
+  
+  def test_should_not_have_encrypted_yet
+    assert_equal 'secret', @password
+  end
+  
+  def teardown
+    User.class_eval do
+      @before_validation_callbacks = nil
+      @before_encrypt_password_callbacks = nil
+    end
+  end
+end
+
+class EncryptedAttributesWithAfterCallbacksTest &lt; ActiveSupport::TestCase
+  def setup
+    @password = nil
+    @ran_callback = false
+    User.encrypts :password, :after =&gt; lambda {|user| @ran_callback = true; @password = user.password.to_s}
+    
+    create_user(:login =&gt; 'admin', :password =&gt; 'secret')
+  end
+  
+  def test_should_run_callback
+    assert @ran_callback
+  end
+  
+  def test_should_have_encrypted_already
+    assert_equal '8152bc582f58c854f580cb101d3182813dec4afe', @password
+  end
+  
+  def teardown
+    User.class_eval do
+      @before_validation_callbacks = nil
+      @after_encrypt_password_callbacks = nil
+    end
+  end
+end
+
+class EncryptedAttributesWithDynamicConfigurationTest &lt; ActiveSupport::TestCase
+  def setup
+    @salt = nil
+    User.encrypts :password, :before =&gt; lambda {|user| user.salt = user.login} do |user|
+      {:salt =&gt; @salt = user.salt}
+    end
+    
+    @user = create_user(:login =&gt; 'admin', :password =&gt; 'secret')
+  end
+  
+  def test_should_use_dynamic_configuration_during_write
+    assert_equal 'a55d037f385cad22efe7862e07b805938d150154', &quot;#{@user[:password]}&quot;
+  end
+  
+  def test_should_use_dynamic_configuration_during_read
+    user = User.find(@user.id)
+    assert_equal 'a55d037f385cad22efe7862e07b805938d150154', &quot;#{user.password}&quot;
+  end
+  
+  def test_should_build_configuration_after_before_callbacks_invoked
+    assert_equal 'admin', @salt
+  end
+  
+  def teardown
+    User.class_eval do
+      @before_validation_callbacks = nil
+      @before_encrypt_password_callbacks = nil
+    end
+  end
 end
 
 class ShaEncryptionTest &lt; ActiveSupport::TestCase
@@ -232,7 +337,7 @@ class ShaEncryptionTest &lt; ActiveSupport::TestCase
   end
   
   def test_should_be_able_to_check_password
-    assert_equal 'secret', @user.password
+    assert_equal 'secret', @user. password
   end
   
   def teardown
@@ -242,9 +347,9 @@ class ShaEncryptionTest &lt; ActiveSupport::TestCase
   end
 end
 
-class ShaWithCustomSaltEncryptionTest &lt; ActiveSupport::TestCase
+class ShaWithEmbeddedSaltEncryptionTest &lt; ActiveSupport::TestCase
   def setup
-    User.encrypts :password, :mode =&gt; :sha, :salt =&gt; :login
+    User.encrypts :password, :mode =&gt; :sha, :salt =&gt; 'admin', :embed_salt =&gt; true
     @user = create_user(:login =&gt; 'admin', :password =&gt; 'secret')
   end
   </diff>
      <filename>test/unit/encrypted_attributes_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,56 +1,43 @@
 require File.dirname(__FILE__) + '/../test_helper'
 
-class ShaCipherOnWriteTest &lt; Test::Unit::TestCase
+class ShaCipherWithoutEmbeddingTest &lt; Test::Unit::TestCase
   def setup
-    @user = create_user(:login =&gt; 'admin')
+    @cipher = EncryptedAttributes::ShaCipher.new('dc0fc7c07bba982a8d8f18fe138dbea912df5e0e', :salt =&gt; 'custom_salt')
   end
   
-  def test_should_allow_symbolic_salt
-    cipher = EncryptedAttributes::ShaCipher.new(@user, 'password', :write, :salt =&gt; :login)
-    assert_equal 'admin', cipher.salt
-  end
-  
-  def test_should_allow_stringified_salt
-    cipher = EncryptedAttributes::ShaCipher.new(@user, 'password', :write, :salt =&gt; 'custom_salt')
-    assert_equal 'custom_salt', cipher.salt
+  def test_should_use_configured_salt
+    assert_equal 'custom_salt', @cipher.salt
   end
   
-  def test_should_allow_block_salt
-    dynamic_salt = lambda {|user| user.login}
-    cipher = EncryptedAttributes::ShaCipher.new(@user, 'password', :write, :salt =&gt; dynamic_salt)
-    assert_equal 'admin', cipher.salt
+  def test_should_not_embed_salt_in_encrypted_string
+    assert_equal 'dc0fc7c07bba982a8d8f18fe138dbea912df5e0e', @cipher.encrypt('secret')
   end
-  
-  def test_should_allow_dynamic_nil_salt
-    dynamic_salt = lambda {|user| nil}
-    cipher = EncryptedAttributes::ShaCipher.new(@user, 'password', :write, :salt =&gt; dynamic_salt)
-    assert_equal '', cipher.salt
+end
+
+class ShaCipherWithNoSaltEmbeddedTest &lt; Test::Unit::TestCase
+  def setup
+    @cipher = EncryptedAttributes::ShaCipher.new('dc0fc7c07bba982a8d8f18fe138dbea912df5e0e', :embed_salt =&gt; true, :salt =&gt; 'custom_salt')
   end
   
-  def test_should_append_salt_to_encrypted_value_if_dynamic
-    cipher = EncryptedAttributes::ShaCipher.new(@user, 'password', :write, :salt =&gt; :login)
-    assert_equal 'a55d037f385cad22efe7862e07b805938d150154admin', cipher.encrypt('secret')
+  def test_should_use_configured_salt
+    assert_equal 'custom_salt', @cipher.salt
   end
   
-  def test_should_not_append_salt_to_encrypted_value_if_static
-    cipher = EncryptedAttributes::ShaCipher.new(@user, 'password', :write, :salt =&gt; 'custom_salt')
-    assert_equal 'dc0fc7c07bba982a8d8f18fe138dbea912df5e0e', cipher.encrypt('secret')
+  def test_should_embed_salt_in_encrypted_string
+    assert_equal 'dc0fc7c07bba982a8d8f18fe138dbea912df5e0ecustom_salt', @cipher.encrypt('secret')
   end
 end
 
-class ShaCipherOnReadTest &lt; Test::Unit::TestCase
+class ShaCipherWithSaltEmbeddedTest &lt; Test::Unit::TestCase
   def setup
-    @user = create_user(:login =&gt; 'admin')
-    @cipher = EncryptedAttributes::ShaCipher.new(@user, 'dc0fc7c07bba982a8d8f18fe138dbea912df5e0ecustom_salt', :read)
+    @cipher = EncryptedAttributes::ShaCipher.new('dc0fc7c07bba982a8d8f18fe138dbea912df5e0ecustom_salt', :embed_salt =&gt; true, :salt =&gt; 'ignored_salt')
   end
   
-  def test_should_should_use_remaining_characters_after_password_for_salt
+  def test_should_use_remaining_characters_after_password_for_salt
     assert_equal 'custom_salt', @cipher.salt
   end
   
-  def test_should_be_able_to_perform_equality_on_encrypted_strings
-    password = 'dc0fc7c07bba982a8d8f18fe138dbea912df5e0ecustom_salt'
-    password.cipher = @cipher
-    assert_equal 'secret', password
+  def test_should_embed_salt_in_encrypted_string
+    assert_equal 'dc0fc7c07bba982a8d8f18fe138dbea912df5e0ecustom_salt', @cipher.encrypt('secret')
   end
 end</diff>
      <filename>test/unit/sha_cipher_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>52e093f7ff6aa3d9b1ce514d0817c936bc1c71e7</id>
    </parent>
  </parents>
  <author>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </author>
  <url>http://github.com/pluginaweek/encrypted_attributes/commit/86423ed1b8090604270a243910f1c11264afd3da</url>
  <id>86423ed1b8090604270a243910f1c11264afd3da</id>
  <committed-date>2009-05-02T10:49:51-07:00</committed-date>
  <authored-date>2009-05-02T10:49:51-07:00</authored-date>
  <message>Allow a block to be used for dynamically defining encryption options
Replace dynamic :salt option with :embed_salt option and utilizing the #encrypts block
Add :before / :after callbacks for hooking into the encryption process</message>
  <tree>9eb47f4e664af833063d39e99ac357bf5b315eab</tree>
  <committer>
    <name>Aaron Pfeifer</name>
    <email>aaron.pfeifer@gmail.com</email>
  </committer>
</commit>
