<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -12,7 +12,7 @@
           =link 'JS.Class', '/'
           %span Ruby-style JavaScript
         #download
-          %a{:href =&gt; '/assets/JS.Class.2-1-2.zip', :onclick =&gt; &quot;trackDownload('2.1.2')&quot;}
+          %a{:href =&gt; '/assets/JS.Class.2-1-3.zip', :onclick =&gt; &quot;trackDownload('2.1.3')&quot;}
             Download v2.1
     .sub
       #content</diff>
      <filename>site/src/layouts/application.haml</filename>
    </modified>
    <modified>
      <diff>@@ -52,7 +52,7 @@
   * Classes can be named to generate @displayName@ on methods for
     &quot;use with the WebKit debugger&quot;:/debugging.html.
   
-  &lt;a href=&quot;/assets/JS.Class.2-1-2.zip&quot; onclick=&quot;trackDownload('2.1.2')&quot;&gt;Download JS.Class 2.1.2&lt;/a&gt;
+  &lt;a href=&quot;/assets/JS.Class.2-1-3.zip&quot; onclick=&quot;trackDownload('2.1.3')&quot;&gt;Download JS.Class 2.1.3&lt;/a&gt;
   
   Most code based on version 1.x will be compatible with this release, but there a few &quot;issues
   to be aware of&quot;:/upgrade.html. If you have code you cannot update to 2.x at present, 1.6 is</diff>
      <filename>site/src/pages/index.haml</filename>
    </modified>
    <modified>
      <diff>@@ -9,9 +9,13 @@ JS.Class.klass = JS.Class.constructor = JS.Class;
 
 JS.extend(JS.Module, {
   _observers: [],
+  
+  __chainq__: [],
+  
   methodAdded: function(block, context) {
     this._observers.push([block, context]);
   },
+  
   _notify: function(name, object) {
     var obs = this._observers, i = obs.length;
     while (i--) obs[i][0].call(obs[i][1] || null, name, object);</diff>
      <filename>source/core/bootstrap.js</filename>
    </modified>
    <modified>
      <diff>@@ -111,6 +111,8 @@ JS.extend(JS.Module.prototype, {
     this.__res__ = options._resolve || null;
     
     if (methods) this.include(methods, false);
+    
+    if (JS.Module.__chainq__) JS.Module.__chainq__.push(this);
   },
   
   /**</diff>
      <filename>source/core/module.js</filename>
    </modified>
    <modified>
      <diff>@@ -82,8 +82,8 @@ JS.MethodChain.addMethods = function(object) {
   i = methods.length;
   while (i--) this.addMethod(methods[i]);
   
-  object.prototype &amp;&amp;
-    this.addMethods(object.prototype);
+  object.__fns__ &amp;&amp; this.addMethods(object.__fns__);
+  object.prototype &amp;&amp; this.addMethods(object.prototype);
 };
 
 it = its = function() { return new JS.MethodChain; };
@@ -119,6 +119,14 @@ JS.Kernel.include({
   }
 }, true);
 
+(function() {
+  var queue = JS.Module.__chainq__,
+      n     = queue.length;
+  
+  while (n--) JS.MethodChain.addMethods(queue[n]);
+  JS.Module.__chainq__ = null;
+})();
+
 JS.MethodChain.addMethods([
   &quot;abbr&quot;, &quot;abs&quot;, &quot;accept&quot;, &quot;acceptCharset&quot;, &quot;accesskey&quot;, &quot;acos&quot;, &quot;action&quot;, &quot;addEventListener&quot;, 
   &quot;adjacentNode&quot;, &quot;align&quot;, &quot;alignWithTop&quot;, &quot;alink&quot;, &quot;alt&quot;, &quot;anchor&quot;, &quot;appendChild&quot;, &quot;appendedNode&quot;, </diff>
      <filename>source/method_chain.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,6 +3,8 @@ JS.Packages(function() { with(this) {
     var PATH = JS.Package._env.JSCLASS_PATH ||
                __FILE__().replace(/[^\/]*$/g, '');
     
+    PATH = PATH.replace(/\/?$/g, '/');
+    
     var module = function(name) { return file(PATH + name + '.js') };
     
     module('core')          .provides('JS.Module',</diff>
      <filename>source/package/config.js</filename>
    </modified>
    <modified>
      <diff>@@ -18,7 +18,7 @@ JS.Package.extend({
     },
     
     load: function(path, fireCallbacks) {
-      JS.Package.loadFile(path, fireCallbacks);
+      JS.Package.Loader.loadFile(path, fireCallbacks);
     }
   },
   </diff>
      <filename>source/package/dsl.js</filename>
    </modified>
    <modified>
      <diff>@@ -24,7 +24,7 @@ JS.Package.extend({
           tag = null;
         }
       };
-      ;;; window.console &amp;&amp; console.info('Loading ' + path);
+      window.console &amp;&amp; console.info('Loading ' + path);
       document.getElementsByTagName('head')[0].appendChild(tag);
     },
     </diff>
      <filename>source/package/loader.js</filename>
    </modified>
    <modified>
      <diff>@@ -23,11 +23,9 @@ JS.Package = new JS.Class('Package', {
   },
   
   addName: function(name) {
-    if (!this.contains(name)) this._names.push(name);
-  },
-  
-  contains: function(name) {
-    return JS.indexOf(this._names, name) !== -1;
+    if (JS.indexOf(this._names, name) !== -1) return;
+    this._names.push(name);
+    this.klass.getFromCache(name).pkg = this;
   },
   
   depsComplete: function(deps) {
@@ -69,11 +67,15 @@ JS.Package = new JS.Class('Package', {
   
   expand: function(list) {
     var deps = list || [], dep, n;
+    
     n = this._deps.length;
     while (n--) this._getPackage(this._deps, n).expand(deps);
+    
     if (JS.indexOf(deps, this) === -1) deps.push(this);
+    
     n = this._uses.length;
     while (n--) this._getPackage(this._uses, n).expand(deps);
+    
     return deps;
   },
   
@@ -82,6 +84,9 @@ JS.Package = new JS.Class('Package', {
   },
   
   load: function(callback, context) {
+    if (this._loader === undefined)
+      throw new Error('No load path specified for ' + this._names.join(', '));
+    
     var self = this, handler, fireCallbacks;
     
     handler = function() {
@@ -114,6 +119,7 @@ JS.Package = new JS.Class('Package', {
   
   extend: {
     _store:   {},
+    _cache:   {},
     _env:     this,
     
     getByPath: function(loader) {
@@ -121,20 +127,29 @@ JS.Package = new JS.Class('Package', {
       return this._store[path] || (this._store[path] = new this(loader));
     },
     
+    getFromCache: function(name) {
+      return this._cache[name] = this._cache[name] || {};
+    },
+    
     getByName: function(name) {
-      for (var path in this._store) {
-        if (this._store[path].contains(name))
-          return this._store[path];
-      }
-      throw new Error('Could not find package containing ' + name);
+      var cached = this.getFromCache(name);
+      if (cached.pkg) return cached.pkg;
+      
+      var placeholder = new this();
+      placeholder.addName(name);
+      return placeholder;
     },
     
     getObject: function(name) {
+      var cached = this.getFromCache(name);
+      if (cached.obj !== undefined) return cached.obj;
+      
       var object = this._env,
           parts  = name.split('.'), part;
       
-      while (part = parts.shift()) object = (object||{})[part];
-      return object;
+      while (part = parts.shift()) object = object &amp;&amp; object[part];
+      
+      return this.getFromCache(name).obj = object;
     },
     
     expand: function(list) {</diff>
      <filename>source/package/package.js</filename>
    </modified>
    <modified>
      <diff>@@ -28,21 +28,36 @@ JS.State = new JS.Module('State', {
         for (method in states[state]) stubs[method] = this.stub;
     } },
     
+    findStates: function(collections, name) {
+      var i = collections.length, results = [];
+      while (i--) {
+        if (collections[i].hasOwnProperty(name))
+          results.push(collections[i][name]);
+      }
+      return results;
+    },
+    
     buildCollection: function(module, states) {
       var stubs       = {},
           collection  = {},
-          superstates = module.lookup('states').pop() || {},
-          state, klass, methods, name;
+          superstates = module.lookup('states'),
+          state, klass, methods, name, mixins, i, n;
       
       this.buildStubs(stubs, collection, states);
-      this.buildStubs(stubs, collection, superstates);
+      
+      for (i = 0, n = superstates.length; i &lt; n;  i++)
+        this.buildStubs(stubs, collection, superstates[i]);
       
       for (state in collection) {
-        klass = (superstates[state]||{}).klass;
-        klass = klass ? new JS.Class(klass, states[state]) : new JS.Class(states[state]);
+        klass  = new JS.Class(states[state]);
+        mixins = this.findStates(superstates, state);
+        
+        i = mixins.length;
+        while (i--) klass.include(mixins[i].klass);
+        
         methods = {};
         for (name in stubs) { if (!klass.prototype[name]) methods[name] = stubs[name]; }
-        klass.include(methods, false);
+        klass.include(methods);
         collection[state] = new klass;
       }
       if (module.__res__) this.addMethods(stubs, module.__res__.klass);</diff>
      <filename>source/state.js</filename>
    </modified>
    <modified>
      <diff>@@ -572,6 +572,51 @@ var AnotherChildStateMachine = new JS.Class(ChildStateMachine, {
     }
 });
 
+
+var TopState = new JS.Class({
+    include: JS.State,
+
+    initialize: function() {
+        this.setState('CREATED');
+    },
+
+    states: {
+        CREATED: {
+            setup: function() {
+                this.setState('READY');
+                return 'Ready!';
+        }   },
+        
+        READY: {
+            say: function() {
+                return 'Hello';
+    }   }   }
+});
+
+var StateMixin = new JS.Module({
+    states: {
+        CREATED: {
+            setup: function() {
+                return 'Running setup from StateMixin. ' + this.callSuper();
+            },
+            
+            say: function() {
+                return 'Hunh?';
+    }   }   }
+});
+
+console.log('now');
+
+var LowerState = new JS.Class(TopState, {
+    include: StateMixin,
+
+    initialize: function() {
+        this.callSuper();
+    },
+    
+    states: {}
+});
+
 //================================================================
 //================================================================
 </diff>
      <filename>test/fixtures/fixtures.js</filename>
    </modified>
    <modified>
      <diff>@@ -35,6 +35,7 @@
                 .requires('YAHOO.util.Connect');
             
             file(yui + 'yahoo-dom-event/yahoo-dom-event.js')
+            .requires('document.getElementById')
             .provides('YAHOO',
                       'YAHOO.lang',
                       'YAHOO.util.Dom',</diff>
      <filename>test/loader.html</filename>
    </modified>
    <modified>
      <diff>@@ -1199,6 +1199,11 @@
             assertEqual(&quot;Jenny likes ponies! aren't they cute?&quot;, child.speak());
             child.setState('poundingTechnoMusic');
             assertEqual('Do you know where your children are?', child.speak());
+            
+            var lower = new LowerState();
+            assertEqual('Hunh?', lower.say());
+            assertEqual('Running setup from StateMixin. Ready!', lower.setup());
+            assertEqual('Hello', lower.say());
         }},
         
         testDecoratedStateClass: function() { with(this) {</diff>
      <filename>test/test.html</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>524a637b0b1388544d7f7361585dadee3efe2051</id>
    </parent>
    <parent>
      <id>c2b364002a2ee3e7504a3452dbc85120fe6d825c</id>
    </parent>
  </parents>
  <author>
    <name>James Coglan</name>
    <email>jcoglan@googlemail.com</email>
  </author>
  <url>http://github.com/jcoglan/js.class/commit/ed1c0e1c635e713c564b08474ccb54bd7188714a</url>
  <id>ed1c0e1c635e713c564b08474ccb54bd7188714a</id>
  <committed-date>2009-10-17T12:54:39-07:00</committed-date>
  <authored-date>2009-10-17T12:54:39-07:00</authored-date>
  <message>Merge branch '2.1.x'</message>
  <tree>4cbfc751ed64bc6600ae7b043ef93279c2b0c1b8</tree>
  <committer>
    <name>James Coglan</name>
    <email>jcoglan@googlemail.com</email>
  </committer>
</commit>
