<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>Objective-J/CommonJS/lib/objective-j/jake/environment.js</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -19,7 +19,6 @@ appKitTask = framework (&quot;AppKit&quot;, function(appKitTask)
     appKitTask.setLicense(BundleTask.License.LGPL_v2_1);
     appKitTask.setSources(AppKitFiles);
     appKitTask.setResources(new FileList(&quot;Resources/**/*&quot;));
-    appKitTask.setPlatforms([BundleTask.Platform.Browser, BundleTask.Platform.CommonJS]);
     appKitTask.setFlattensSources(true);
     appKitTask.setInfoPlistPath(&quot;Info.plist&quot;);
 </diff>
      <filename>AppKit/Jakefile</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,6 @@ blend (&quot;Aristo.blend&quot;, function(aristoTask)
     aristoTask.setBuildPath(FILE.join($BUILD_DIR, $CONFIGURATION));
 
     aristoTask.setThemeDescriptors(new FileList(&quot;ThemeDescriptors.j&quot;));
-    aristoTask.setPlatforms([BundleTask.Platform.Browser, BundleTask.Platform.CommonJS]);
     aristoTask.setIdentifier(&quot;com.280n.blend.Aristo&quot;);
     aristoTask.setResources(new FileList(&quot;Resources/*&quot;));
 });</diff>
      <filename>AppKit/Themes/Aristo/Jakefile</filename>
    </modified>
    <modified>
      <diff>@@ -14,7 +14,7 @@ var FILE = require(&quot;file&quot;),
 function BlendTask(aName)
 {
     BundleTask.apply(this, arguments);
-    
+
     this._themeDescriptors = [];
     this._keyedThemes = [];
 }
@@ -31,7 +31,7 @@ BlendTask.prototype.infoPlist = function()
 {
     var infoPlist = BundleTask.prototype.infoPlist.apply(this, arguments);
 
-    infoPlist.setValue(&quot;CPKeyedThemes&quot;, this._keyedThemes);
+    infoPlist.setValue(&quot;CPKeyedThemes&quot;, require(&quot;util&quot;).unique(this._keyedThemes));
 
     return infoPlist;
 }
@@ -54,52 +54,56 @@ BlendTask.prototype.defineTasks = function()
 }
 
 BlendTask.prototype.defineSourceTasks = function()
-{ 
+{
 }
 
 BlendTask.prototype.defineThemeDescriptorTasks = function()
 {
-    var themeDescriptors = this.themeDescriptors(),
-        resourcesPath = this.resourcesPath(),
-        intermediatesPath = FILE.join(this.buildIntermediatesProductPath(), &quot;Browser&quot; + &quot;.platform&quot;, &quot;Resources&quot;),
-        staticPath = this.buildProductStaticPathForPlatform(&quot;Browser&quot;),
-        keyedThemes = this._keyedThemes,
-        themesTaskName = this.name() + &quot;:themes&quot;;
+    this.flattenedEnvironments().forEach(function(anEnvironment)
+    {
+        var folder = anEnvironment.name() + &quot;.environment&quot;,
+            themeDescriptors = this.themeDescriptors(),
+            resourcesPath = this.resourcesPath(),
+            intermediatesPath = FILE.join(this.buildIntermediatesProductPath(), folder, &quot;Resources&quot;),
+            staticPath = this.buildProductStaticPathForEnvironment(anEnvironment),
+            keyedThemes = this._keyedThemes,
+            themesTaskName = this.name() + &quot;:themes&quot;;
 
-    this.enhance(themesTaskName);
+        this.enhance(themesTaskName);
 
-    objj_import(themeDescriptors.toArray(), YES, function()
-    {
-        [BKThemeDescriptor allThemeDescriptorClasses].forEach(function(aClass)
+        objj_import(themeDescriptors.toArray(), YES, function()
         {
-            var keyedThemePath = FILE.join(intermediatesPath, [aClass themeName] + &quot;.keyedtheme&quot;);
+            [BKThemeDescriptor allThemeDescriptorClasses].forEach(function(aClass)
+            {
+                var keyedThemePath = FILE.join(intermediatesPath, [aClass themeName] + &quot;.keyedtheme&quot;);
 
-            filedir (keyedThemePath, themesTaskName);
-            filedir (staticPath, [keyedThemePath]);
+                filedir (keyedThemePath, themesTaskName);
+                filedir (staticPath, [keyedThemePath]);
 
-            keyedThemes.push([aClass themeName] + &quot;.keyedtheme&quot;);
+                keyedThemes.push([aClass themeName] + &quot;.keyedtheme&quot;);
+            });
         });
-    });
 
-    require(&quot;browser/timeout&quot;).serviceTimeouts();
+        require(&quot;browser/timeout&quot;).serviceTimeouts();
 
-    task (themesTaskName, function()
-    {
-        [BKThemeDescriptor allThemeDescriptorClasses].forEach(function(aClass)
+        task (themesTaskName, function()
         {
-            var themeTemplate = [[BKThemeTemplate alloc] init];
+            [BKThemeDescriptor allThemeDescriptorClasses].forEach(function(aClass)
+            {
+                var themeTemplate = [[BKThemeTemplate alloc] init];
 
-            [themeTemplate setValue:[aClass themeName] forKey:@&quot;name&quot;];
+                [themeTemplate setValue:[aClass themeName] forKey:@&quot;name&quot;];
 
-            var objectTemplates = [aClass themedObjectTemplates],
-                data = cibDataFromTopLevelObjects(objectTemplates.concat([themeTemplate])),
-                fileContents = themeFromCibData(data);
+                var objectTemplates = [aClass themedObjectTemplates],
+                    data = cibDataFromTopLevelObjects(objectTemplates.concat([themeTemplate])),
+                    fileContents = themeFromCibData(data);
 
-            // No filedir in this case, so we have to make it ourselves.
-            FILE.mkdirs(intermediatesPath);
-            FILE.write(FILE.join(intermediatesPath, [aClass themeName] + &quot;.keyedtheme&quot;), MARKER_TEXT + &quot;;&quot; + fileContents.length + &quot;;&quot; + fileContents, { charset:&quot;UTF-8&quot; });
+                // No filedir in this case, so we have to make it ourselves.
+                FILE.mkdirs(intermediatesPath);
+                FILE.write(FILE.join(intermediatesPath, [aClass themeName] + &quot;.keyedtheme&quot;), MARKER_TEXT + &quot;;&quot; + fileContents.length + &quot;;&quot; + fileContents, { charset:&quot;UTF-8&quot; });
+            });
         });
-    }); 
+    }, this);
 }
 
 function cibDataFromTopLevelObjects(objects)
@@ -113,7 +117,7 @@ function cibDataFromTopLevelObjects(objects)
 
     var index = 0,
         count = objects.length;
-        
+
     for (; index &lt; count; ++index)
     {
         objectData._objectsValues[index] = objectData._fileOwner;
@@ -131,7 +135,7 @@ function themeFromCibData(data)
 {
     var cib = [[CPCib alloc] initWithData:data],
         topLevelObjects = [];
-    
+
     [cib _setAwakenCustomResources:NO];
     [cib instantiateCibWithExternalNameTable:[CPDictionary dictionaryWithObject:topLevelObjects forKey:CPCibTopLevelObjects]];
 
@@ -142,7 +146,7 @@ function themeFromCibData(data)
     while (count--)
     {
         var object = topLevelObjects[count];
-        
+
         templates = templates.concat([object blendThemeObjectTemplates]);
 
         if ([object isKindOfClass:[BKThemeTemplate class]])
@@ -175,22 +179,22 @@ function themeFromCibData(data)
 - (CPArray)blendThemeObjectTemplates
 {
     var theClass = [self class];
-    
+
     if ([theClass isKindOfClass:[BKThemedObjectTemplate class]])
         return [self];
-        
+
     if ([theClass isKindOfClass:[CPView class]])
     {
         var templates = [],
             subviews = [self subviews],
             count = [subviews count];
-        
+
         while (count--)
             templates = templates.concat([subviews[count] blendThemeObjectTemplates]);
-        
+
         return templates;
     }
-    
+
     return [];
 }
 
@@ -201,19 +205,19 @@ function themeFromCibData(data)
 - (void)blendAddThemedObjectAttributesToTheme:(CPTheme)aTheme
 {
     var themedObject = [self valueForKey:@&quot;themedObject&quot;];
-    
+
     if (!themedObject)
     {
         var subviews = [self subviews];
-        
+
         if ([subviews count] &gt; 0)
             themedObject = subviews[0];
     }
-    
+
     if (themedObject)
     {
         print(&quot; Recording themed properties for &quot; + [themedObject className] + &quot;.&quot;);
-        
+
         [aTheme takeThemeFromObject:themedObject];
     }
 }</diff>
      <filename>AppKit/Themes/CommonJS/blendtask.j</filename>
    </modified>
    <modified>
      <diff>@@ -98,9 +98,9 @@
     return className ? CPClassFromString(className) : Nil;
 }
 
-+ (CPString)firstCompatibleEngineFromArray:(CPArray)engines
++ (CPString)mostEligibleEnvironmentFromArray:(CPArray)environments
 {
-    return objj_firstCompatibleEngineFromArray(engines);
+    return objj_mostEligibleEnvironmentFromArray(environments);
 }
 
 - (CPString)pathForResource:(CPString)aFilename
@@ -132,11 +132,14 @@
     self._infoConnection = [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:[self bundlePath] + &quot;/Info.plist&quot;] delegate:self];
 }
 
-- (CPString)firstEligiblePlatform
+- (CPArray)supportedEnvironments
 {
-    var platforms = [self objectForInfoDictionaryKey:&quot;CPBundlePlatforms&quot;];
+    return [self objectForInfoDictionaryKey:&quot;CPBundleEnvironments&quot;] || [&quot;ObjJ&quot;];
+}
 
-    return [platforms firstObjectCommonWithArray:OBJJ_PLATFORMS] || nil;
+- (CPString)mostEligibleEnvironment
+{
+    return [[self class] mostEligibleEnvironmentFromArray:[self supportedEnvironments]];
 }
 
 - (void)connection:(CPURLConnection)aConnection didReceiveData:(CPString)data
@@ -145,12 +148,12 @@
     {
         info = CPPropertyListCreateFromData([CPData dataWithString:data]);
 
-        var platform = [self firstEligiblePlatform];
+        var environment = [self mostEligibleEnvironment];
 
-        if (!platform)
-            throw &quot;Engine not supported for &quot; + [self bundlePath] + &quot;. Supported engines: &quot; + [self objectForInfoDictionaryKey:&quot;CPBundlePlatforms&quot;] + &quot;.&quot;;
+        if (!environment)
+            throw &quot;Environment not supported for &quot; + [self bundlePath] + &quot;. Supported environments: &quot; + [self objectForInfoDictionaryKey:&quot;CPBundleEnvironments&quot;] + &quot;.&quot;;
 
-        [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:[self bundlePath] + '/' + platform + &quot;.platform/&quot; + [self objectForInfoDictionaryKey:&quot;CPBundleExecutable&quot;]] delegate:self];
+        [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:[self bundlePath] + '/' + environment + &quot;.environment/&quot; + [self objectForInfoDictionaryKey:&quot;CPBundleExecutable&quot;]] delegate:self];
     }
     else
     {
@@ -161,7 +164,7 @@
         if ([_delegate respondsToSelector:@selector(bundleDidFinishLoading:)])
             context.didCompleteCallback = function() { [_delegate bundleDidFinishLoading:self]; };
 
-        var files = [[self objectForInfoDictionaryKey:@&quot;CPBundleReplacedFiles&quot;] objectForKey:[self firstEligiblePlatform]],
+        var files = [[self objectForInfoDictionaryKey:@&quot;CPBundleReplacedFiles&quot;] objectForKey:[self mostEligibleEnvironment]],
             count = files ? files.length : 0, // Perhaps no files? Be liberal in what you accept...
             bundlePath = [self bundlePath];
 </diff>
      <filename>Foundation/CPBundle.j</filename>
    </modified>
    <modified>
      <diff>@@ -38,6 +38,7 @@ foundationTask = framework (&quot;Foundation&quot;, function(foundationTask)
     foundationTask.setResources(new FileList(&quot;Resources/**/*&quot;));
     foundationTask.setFlattensSources(true);
     foundationTask.setInfoPlistPath(&quot;Info.plist&quot;);
+    foundationTask.setEnvironments(require(&quot;objective-j/jake/environment&quot;).ObjJ);
 
     if ($CONFIGURATION === &quot;Release&quot;)
         foundationTask.setCompilerFlags(&quot;-O&quot;);</diff>
      <filename>Foundation/Jakefile</filename>
    </modified>
    <modified>
      <diff>@@ -13,7 +13,7 @@ if (system.engine === &quot;rhino&quot;)
 window.OBJJ_HOME = exports.OBJJ_HOME = FILE.resolve(module.path, &quot;..&quot;);
 
 var frameworksPath = FILE.resolve(window.OBJJ_HOME, &quot;Frameworks/&quot;),
-    objectivejPath = FILE.resolve(frameworksPath, &quot;Objective-J/&quot;, &quot;CommonJS.platform/&quot;, &quot;Objective-J.js&quot;);
+    objectivejPath = FILE.resolve(frameworksPath, &quot;Objective-J/&quot;, &quot;CommonJS.environment/&quot;, &quot;Objective-J.js&quot;);
 
 var OBJJ_INCLUDE_PATHS = window.OBJJ_INCLUDE_PATHS = exports.OBJJ_INCLUDE_PATHS = [];
 </diff>
      <filename>Objective-J/CommonJS/lib/objective-j.js</filename>
    </modified>
    <modified>
      <diff>@@ -42,7 +42,7 @@ ApplicationTask.prototype.indexFilePath = function()
 ApplicationTask.prototype.defineFrameworksTask = function()
 {
     // FIXME: platform requires...
-    if (this.platforms().indexOf(BundleTask.Platform.Browser) === -1)
+    if (this.flattenedEnvironments().indexOf(require(&quot;objective-j/jake/environment&quot;).Browsers) === -1)
         return;
 
     var frameworks = FILE.join(this.buildProductPath(), &quot;Frameworks&quot;),</diff>
      <filename>Objective-J/CommonJS/lib/objective-j/jake/applicationtask.js</filename>
    </modified>
    <modified>
      <diff>@@ -5,21 +5,41 @@ var FILE = require(&quot;file&quot;),
     Jake = require(&quot;jake&quot;),
     CLEAN = require(&quot;jake/clean&quot;).CLEAN,
     CLOBBER = require(&quot;jake/clean&quot;).CLOBBER,
-    base64 = require(&quot;base64&quot;);
+    base64 = require(&quot;base64&quot;),
+    environment = require(&quot;objective-j/jake/environment&quot;);
 
 var Task = Jake.Task,
     filedir = Jake.filedir;
 
+function isImage(/*String*/ aFilename)
+{
+    return  FILE.isFile(aFilename) &amp;&amp;
+            UTIL.has([&quot;.png&quot;, &quot;.jpg&quot;, &quot;.jpeg&quot;, &quot;.gif&quot;, &quot;.tif&quot;, &quot;.tiff&quot;], FILE.extension(aFilename).toLowerCase());
+}
+
+function mimeType(/*String*/ aFilename)
+{
+    return  {
+                &quot;.png&quot;  : &quot;image/png&quot;,
+                &quot;.jpg&quot;  : &quot;image/jpeg&quot;,
+                &quot;.jpeg&quot; : &quot;image/jpeg&quot;,
+                &quot;.gif&quot;  : &quot;image/gif&quot;,
+                &quot;.tif&quot;  : &quot;image/tiff&quot;,
+                &quot;.tiff&quot; : &quot;image/tiff&quot;
+            }[FILE.extension(aFilename).toLowerCase()];
+}
+
 function BundleTask(aName, anApplication)
 {
     Task.apply(this, arguments);
 
+    this.setEnvironments([environment.Browsers, environment.CommonJS]);
+
     this._author = null;
     this._email = null;
     this._summary = null;
 
     this._license = null;
-    this._platforms = [BundleTask.Platform.ObjJ];
     this._sources = null;
     this._resources = null;
     this._spritesResources = true;
@@ -57,17 +77,32 @@ BundleTask.defineTask = function(/*String*/ aName, /*Function*/ aFunction)
     return bundleTask;
 }
 
-BundleTask.Platform =   {
-                            &quot;ObjJ&quot;      : &quot;ObjJ&quot;,
-                            &quot;CommonJS&quot;  : &quot;CommonJS&quot;,
-                            &quot;Browser&quot;   : &quot;Browser&quot;
-                        };
+BundleTask.prototype.setEnvironments = function(environments)
+{
+    if (arguments.length &lt; 1)
+        this._environments = [];
 
-BundleTask.PLATFORM_DEFAULT_FLAGS = {
-                                        &quot;ObjJ&quot;      : [],
-                                        &quot;CommonJS&quot;  : ['-DPLATFORM_RHINO -DPLATFORM_COMMONJS'],
-                                        &quot;Browser&quot;   : ['-DPLATFORM_BROWSER', '-DPLATFORM_DOM']
-                                    };
+    else if (arguments.length &gt; 1)
+        this._environments = Array.prototype.slice.apply(environments);
+
+    else if (typeof environments.slice === &quot;function&quot;)
+        this._environments = environments.slice();
+
+    else
+        this._environments = [environments];
+
+    this._flattenedEnvironments = environment.Environment.flattenedEnvironments(this._environments);
+}
+
+BundleTask.prototype.environments = function()
+{
+    return this._environments;
+}
+
+BundleTask.prototype.flattenedEnvironments = function()
+{
+    return this._flattenedEnvironments;
+}
 
 BundleTask.prototype.setAuthor = function(anAuthor)
 {
@@ -119,16 +154,6 @@ BundleTask.prototype.version = function()
     return this._version;
 }
 
-BundleTask.prototype.setPlatforms = function(platforms)
-{
-    this._platforms = platforms;
-}
-
-BundleTask.prototype.platforms = function()
-{
-    return this._platforms;
-}
-
 BundleTask.prototype.setSources = function(sources)
 {
     this._sources = sources;
@@ -271,9 +296,14 @@ BundleTask.prototype.buildIntermediatesProductPath = function()
     return this.buildIntermediatesPath() || FILE.join(this.buildPath(), this.productName() + &quot;.build&quot;);
 }
 
-BundleTask.prototype.buildProductStaticPathForPlatform = function(aPlatform)
+BundleTask.prototype.buildProductStaticPathForEnvironment = function(anEnvironment)
 {
-    return FILE.join(this.buildProductPath(), aPlatform + &quot;.platform&quot;, this.productName() + &quot;.sj&quot;);
+    return FILE.join(this.buildProductPath(), anEnvironment.name() + &quot;.environment&quot;, this.productName() + &quot;.sj&quot;);
+}
+
+BundleTask.prototype.buildProductMHTMLPathForEnvironment = function(anEnvironment)
+{
+    return FILE.join(this.buildProductPath(), anEnvironment.name() + &quot;.environment&quot;, this.productName() + &quot;.mhtml&quot;);
 }
 
 BundleTask.prototype.defineTasks = function()
@@ -283,6 +313,7 @@ BundleTask.prototype.defineTasks = function()
     this.defineInfoPlistTask();
     this.defineLicenseTask();
     this.defineStaticTask();
+    this.defineMHTMLTask();
 
     CLEAN.include(this.buildIntermediatesProductPath());
     CLOBBER.include(this.buildProductPath());
@@ -309,7 +340,10 @@ BundleTask.prototype.infoPlist = function()
     infoPlist.setValue(&quot;CPBundleIdentifier&quot;, this.identifier());
     infoPlist.setValue(&quot;CPBundleVersion&quot;, this.version());
     infoPlist.setValue(&quot;CPBundlePackageType&quot;, this.packageType());
-    infoPlist.setValue(&quot;CPBundlePlatforms&quot;, this.platforms());
+    infoPlist.setValue(&quot;CPBundleEnvironments&quot;, this.flattenedEnvironments().map(function(anEnvironment)
+    {
+        return anEnvironment.name();
+    }));
     infoPlist.setValue(&quot;CPBundleExecutable&quot;, this.productName() + &quot;.sj&quot;);
 
     var principalClass = this.principalClass();
@@ -376,36 +410,34 @@ BundleTask.prototype.resourcesPath = function()
     return FILE.join(this.buildProductPath(), &quot;Resources&quot;, &quot;&quot;);
 }
 
-var IMAGE_EXTENSIONS =  [ &quot;.png&quot;, &quot;.jpg&quot;, &quot;.jpeg&quot;, &quot;.gif&quot;, &quot;.tif&quot;, &quot;.tiff&quot;];
-
-var MIME_TYPES =    {
-                        &quot;.png&quot;  : &quot;image/png&quot;,
-                        &quot;.jpg&quot;  : &quot;image/jpeg&quot;,
-                        &quot;.jpeg&quot; : &quot;image/jpeg&quot;,
-                        &quot;.gif&quot;  : &quot;image/gif&quot;,
-                        &quot;.tif&quot;  : &quot;image/tiff&quot;,
-                        &quot;.tiff&quot; : &quot;image/tiff&quot;
-                    };
-
 BundleTask.prototype.defineResourceTask = function(aResourcePath, aDestinationPath)
 {
-    var extension = FILE.extension(aResourcePath).toLowerCase(),
-        extensionless = aResourcePath.substr(0, aResourcePath.length - extension.length);
-
     // Don't sprite images larger than 32KB, IE 8 doesn't like it.
-    if (this.spritesResources() &amp;&amp; IMAGE_EXTENSIONS.indexOf(extension) !== -1 &amp;&amp; FILE.size(aResourcePath) &lt; 32768)
+    if (this.spritesResources() &amp;&amp; isImage(aResourcePath) &amp;&amp; FILE.size(aResourcePath) &lt; 32768)
     {
-        var spritedDestinationPath = FILE.join(this.buildIntermediatesProductPath(), &quot;Browser&quot; + &quot;.platform&quot;, &quot;Resources&quot;, FILE.relative(this.resourcesPath(), aDestinationPath));
-
-        filedir (spritedDestinationPath, function()
+        this.flattenedEnvironments().forEach(function(/*Environment*/ anEnvironment)
         {
-            var dataURI = &quot;data:&quot; + MIME_TYPES[extension] + &quot;;base64,&quot; + base64.encode(FILE.read(aResourcePath, { mode : 'b'}));
-            FILE.write(spritedDestinationPath, dataURI.length + &quot;;&quot; + dataURI, { charset:&quot;UTF-8&quot; });
-        });
+            if (!anEnvironment.spritesImages())
+                return;
+
+            var folder = anEnvironment.name() + &quot;.environment&quot;,
+                spritedDestinationPath = FILE.join(this.buildIntermediatesProductPath(), folder, &quot;Resources&quot;, FILE.relative(this.resourcesPath(), aDestinationPath));
+
+            filedir (spritedDestinationPath, function()
+            {
+                FILE.write(spritedDestinationPath, base64.encode(FILE.read(aResourcePath, { mode : 'b'})), { charset:&quot;UTF-8&quot; });
+            });
 
-        filedir (this.buildProductStaticPathForPlatform(&quot;Browser&quot;), [spritedDestinationPath]);
+            if (anEnvironment.spritesImagesToMHTMLFile())
+                filedir (this.buildProductMHTMLPathForEnvironment(anEnvironment), [spritedDestinationPath]);
+
+            // Add this as a dependency unconditionally because we need to set up the URL map either way.
+            filedir (this.buildProductStaticPathForEnvironment(anEnvironment), [spritedDestinationPath]);
+        }, this);
     }
 
+    var extension = FILE.extension(aResourcePath),
+        extensionless = aResourcePath.substr(0, aResourcePath.length - extension.length);
     // NOT:
     // (extname === &quot;.cib&quot; &amp;&amp; (FILE.exists(extensionless + '.xib') || FILE.exists(extensionless + '.nib')) ||
     // (extname === &quot;.xib&quot; || extname === &quot;.nib&quot;) &amp;&amp; !this.shouldIncludeNibsAndXibs())
@@ -457,18 +489,18 @@ function directoryInCommon(filenames)
 
         if (!aCommonDirectory)
             aCommonDirectory = directory;
-        
+
         else
         {
             var index = 0,
                 count = Math.min(directory.length, aFilename.length);
-    
+
             for (; index &lt; count &amp;&amp; aCommonDirectory.charAt(index) === directory.charAt(index); ++index) ;
-    
+
             aCommonDirectory = directory.substr(0, index);
         }
     });
-print(&quot;DIRECTORY IN COMMON IS &quot; + aCommonDirectory);
+
     return aCommonDirectory;
 }
 
@@ -508,12 +540,14 @@ BundleTask.prototype.defineResourceTasks = function()
 
 BundleTask.prototype.defineStaticTask = function()
 {
-    this.platforms().forEach(function(/*String*/ aPlatform)
+    this.flattenedEnvironments().forEach(function(/*Environment*/ anEnvironment)
     {
-        var sourcesPath = FILE.join(this.buildIntermediatesProductPath(), aPlatform + &quot;.platform&quot;, &quot;Sources&quot;, &quot;&quot;),
-            resourcesPath = FILE.join(this.buildIntermediatesProductPath(), aPlatform + &quot;.platform&quot;, &quot;Resources&quot;, &quot;&quot;),
-            staticPath = this.buildProductStaticPathForPlatform(aPlatform),
-            flattensSources = this.flattensSources();
+        var folder = anEnvironment.name() + &quot;.environment&quot;,
+            sourcesPath = FILE.join(this.buildIntermediatesProductPath(), folder, &quot;Sources&quot;, &quot;&quot;),
+            resourcesPath = FILE.join(this.buildIntermediatesProductPath(), folder, &quot;Resources&quot;, &quot;&quot;),
+            staticPath = this.buildProductStaticPathForEnvironment(anEnvironment),
+            flattensSources = this.flattensSources(),
+            productName = this.productName();
 
         filedir (staticPath, function(aTask)
         {
@@ -536,23 +570,36 @@ BundleTask.prototype.defineStaticTask = function()
                     var relativePath = flattensSources ? FILE.basename(aFilename) : FILE.relative(sourcesPath, aFilename);
 
                     fileStream.write(&quot;p;&quot; + relativePath.length + &quot;;&quot; + relativePath);
+
+                    // FIXME: We need to do this for now due to file.read adding newlines. Revert when fixed.
+                    //fileStream.write(FILE.read(aFilename, { charset:&quot;UTF-8&quot; }));
+                    fileStream.write(FILE.read(aFilename, { mode:&quot;b&quot; }).decodeToString(&quot;UTF-8&quot;));
                 }
 
                 else if (aFilename.indexOf(resourcesPath) === 0)
                 {
-                    var resourcePath = &quot;Resources/&quot; + FILE.relative(resourcesPath, aFilename);
+                    var contents = &quot;&quot;,
+                        resourcePath = &quot;Resources/&quot; + FILE.relative(resourcesPath, aFilename);
 
-                    if (IMAGE_EXTENSIONS.indexOf(FILE.extension(aFilename)) !== -1)
+                    if (isImage(aFilename))
+                    {
                         fileStream.write(&quot;u;&quot;);
+
+                        if (anEnvironment.spritesImagesToStaticFile())
+                            contents += &quot;data:&quot; + mimeType(aFilename) + &quot;;base64,&quot; + FILE.read(aFilename, { charset:&quot;UTF-8&quot; });
+                        else if (anEnvironment.spritesImagesToMHTMLFile())
+                            contents = &quot;mhtml:&quot; + FILE.join(folder, productName + &quot;.mhtml!&quot;) + resourcePath;
+
+                        contents = contents.length + &quot;;&quot; + contents;
+                    }
                     else
+                    {
                         fileStream.write(&quot;p;&quot;);
+                        contents = FILE.read(aFilename, { charset:&quot;UTF-8&quot; });
+                    }
 
-                    fileStream.write(resourcePath.length + &quot;;&quot; + resourcePath);
+                    fileStream.write(resourcePath.length + &quot;;&quot; + resourcePath + contents);
                 }
-
-                // FIXME: We need to do this for now due to file.read adding newlines. Revert when fixed.
-                //fileStream.write(FILE.read(aFilename, { charset:&quot;UTF-8&quot; }));
-                fileStream.write(FILE.read(aFilename, { mode:&quot;b&quot; }).decodeToString(&quot;UTF-8&quot;));
             }, this);
 
             fileStream.close();
@@ -562,6 +609,59 @@ BundleTask.prototype.defineStaticTask = function()
     }, this);
 }
 
+BundleTask.prototype.defineMHTMLTask = function()
+{
+    var environments = this.flattenedEnvironments();
+
+    if (!environments.some(function(anEnvironment)
+    {
+        return anEnvironment.spritesImagesToMHTMLFile();
+    }))
+        return;
+
+    environments.filter(function(/*Environment*/ anEnvironment)
+    {
+        return anEnvironment.spritesImagesToMHTMLFile();
+    }).forEach(function(/*Environment*/ anEnvironment)
+    {
+        var folder = anEnvironment.name() + &quot;.environment&quot;,
+            resourcesPath = FILE.join(this.buildIntermediatesProductPath(), folder, &quot;Resources&quot;, &quot;&quot;),
+            MHTMLPath = this.buildProductMHTMLPathForEnvironment(anEnvironment);
+
+        filedir (MHTMLPath, function(aTask)
+        {
+            print(&quot;Creating MHTML file... &quot; + MHTMLPath);
+
+            var fileStream = FILE.open(MHTMLPath, &quot;w+&quot;, { charset:&quot;UTF-8&quot; });
+
+            fileStream.write(&quot;/*\r\nContent-Type: multipart/related; boundary=\&quot;_ANY_STRING_WILL_DO_AS_A_SEPARATOR\&quot;\r\n\r\n&quot;);
+
+            aTask.prerequisites().forEach(function(aFilename)
+            {
+                // Our prerequisites will contain directories due to filedir.
+                if (!isImage(aFilename))
+                    return;
+
+                var resourcePath = &quot;Resources/&quot; + FILE.relative(resourcesPath, aFilename);
+
+                fileStream.write(&quot;--_ANY_STRING_WILL_DO_AS_A_SEPARATOR\r\n&quot;);
+                fileStream.write(&quot;Content-Location:&quot; + resourcePath + &quot;\r\nContent-Transfer-Encoding:base64\r\n\r\n&quot;);
+
+                var contents = FILE.read(aFilename, { charset:&quot;UTF-8&quot; });
+
+                fileStream.write(contents);
+                fileStream.write(&quot;\r\n&quot;);
+
+            }, this);
+
+            fileStream.write(&quot;*/&quot;);
+            fileStream.close();
+        });
+
+        this.enhance([MHTMLPath]);
+    }, this);
+}
+
 BundleTask.prototype.defineSourceTasks = function()
 {
     var sources = this.sources();
@@ -578,40 +678,43 @@ BundleTask.prototype.defineSourceTasks = function()
     else if (compilerFlags.join)
         compilerFlags = compilerFlags.join(&quot; &quot;);
 
-    this.platforms().forEach(function(/*String*/ aPlatform)
+    var environments = this.flattenedEnvironments();
+
+    environments.forEach(function(/*Environment*/ anEnvironment)
     {
-        var platformSources = sources,
-            sourcesPath = FILE.join(this.buildIntermediatesProductPath(), aPlatform + &quot;.platform&quot;, &quot;Sources&quot;, &quot;&quot;),
-            staticPath = this.buildProductStaticPathForPlatform(aPlatform),
-            flags = BundleTask.PLATFORM_DEFAULT_FLAGS[aPlatform].join(&quot; &quot;);
+        var environmentSources = sources,
+            folder = anEnvironment.name() + &quot;.environment&quot;,
+            sourcesPath = FILE.join(this.buildIntermediatesProductPath(), folder, &quot;Sources&quot;, &quot;&quot;),
+            staticPath = this.buildProductStaticPathForEnvironment(anEnvironment);
 
-        if (!Array.isArray(platformSources) &amp;&amp; platformSources.constructor !== Jake.FileList)
-            platformSources = platformSources[aPlatform];
+        if (!Array.isArray(environmentSources) &amp;&amp; environmentSources.constructor !== Jake.FileList)
+            environmentSources = environmentSources[anEnvironment];
 
-        var replacedFiles = [];
+        var replacedFiles = [],
+            environmentCompilerFlags = anEnvironment.compilerFlags().join(&quot; &quot;) + &quot; &quot; + compilerFlags;
 
-        platformSources.forEach(function(/*String*/ aFilename)
+        environmentSources.forEach(function(/*String*/ aFilename)
         {
             // if this file doesn't exist or isn't a .j file, don't preprocess it.
             if (!FILE.exists(aFilename) || FILE.extension(aFilename) !== '.j')
                 return;
 
-            var compiledPlatformSource = FILE.join(sourcesPath, FILE.basename(aFilename));
+            var compiledEnvironmentSource = FILE.join(sourcesPath, FILE.basename(aFilename));
 
-            filedir (compiledPlatformSource, [aFilename], function()
+            filedir (compiledEnvironmentSource, [aFilename], function()
             {
-                print(&quot;Compiling &quot; + aFilename + &quot;...&quot;);
-                FILE.write(compiledPlatformSource, require(&quot;objective-j/compiler&quot;).compile(aFilename, flags + &quot; &quot; + compilerFlags), { charset:&quot;UTF-8&quot; });
+                print(&quot;Compiling [&quot; + anEnvironment + &quot;] &quot; + aFilename + &quot;...&quot;);
+                FILE.write(compiledEnvironmentSource, require(&quot;objective-j/compiler&quot;).compile(aFilename, environmentCompilerFlags), { charset:&quot;UTF-8&quot; });
             });
 
-            filedir (staticPath, [compiledPlatformSource]);
+            filedir (staticPath, [compiledEnvironmentSource]);
 
             // FIXME: how do we non flatten?
             // dir in common
             replacedFiles.push(flattensSources ? FILE.basename(aFilename) : FILE.relative(sourcesPath, aFilename));
         }, this);
 
-        this._replacedFiles[aPlatform] = replacedFiles;
+        this._replacedFiles[anEnvironment] = replacedFiles;
     }, this);
 }
 </diff>
      <filename>Objective-J/CommonJS/lib/objective-j/jake/bundletask.js</filename>
    </modified>
    <modified>
      <diff>@@ -34,16 +34,16 @@ if ($CONFIGURATION === &quot;Debug&quot;)
     Files.include(&quot;Runtime/debug.js&quot;);
 
 $BUILD_BROWSER_FILE = FILE.join($BUILD_OBJECTIVE_J, &quot;Objective-J.js&quot;);
-$BUILD_CJS_FILE     = FILE.join($BUILD_OBJECTIVE_J, &quot;CommonJS.platform&quot;, &quot;Objective-J.js&quot;);
+$BUILD_CJS_FILE     = FILE.join($BUILD_OBJECTIVE_J, &quot;CommonJS.environment&quot;, &quot;Objective-J.js&quot;);
 
 filedir ($BUILD_BROWSER_FILE, Files, function(aTask)
 {
-    build_product(aTask.name(), platform_flags('Browser', 'ObjJ'));
+    build_product(aTask.name(), environmentFlags(&quot;ObjJ&quot;) + &quot; -DPLATFORM_USERAGENT&quot;);
 });
 
 filedir ($BUILD_CJS_FILE, Files, function(aTask)
 {
-    flags = platform_flags('CommonJS', 'ObjJ');
+    flags = environmentFlags(&quot;CommonJS&quot;, &quot;ObjJ&quot;);
     flags += ' -DRHINO'
 
     build_product(aTask.name(), flags)
@@ -90,11 +90,11 @@ filedir ($BUILD_CJS_OBJECTIVE_J_FRAMEWORK, function()
 
 CLOBBER.include($BUILD_OBJECTIVE_J);
 
-function platform_flags()
+function environmentFlags()
 {
-    return &quot;-DPLATFORMS=\&quot;[&quot; + Array.prototype.map.apply(arguments, [function(aPlatform)
+    return &quot;-DENVIRONMENTS=\&quot;[&quot; + Array.prototype.map.apply(arguments, [function(anEnvironment)
     {
-        return &quot;\\\&quot;&quot; + aPlatform + &quot;\\\&quot;&quot;;
+        return &quot;\\\&quot;&quot; + anEnvironment + &quot;\\\&quot;&quot;;
     }]).join(&quot;, &quot;) + &quot;]\&quot;&quot;;
 }
 </diff>
      <filename>Objective-J/Jakefile</filename>
    </modified>
    <modified>
      <diff>@@ -27,31 +27,39 @@
 // Look inside bundleResponseCallback.
 
 
-var OBJJ_PLATFORMS = PLATFORMS;
+var OBJJ_ENVIRONMENTS = ENVIRONMENTS;
+
+#ifdef PLATFORM_USERAGENT
+var userAgent = window.navigator.userAgent;
+
+if (userAgent.indexOf(&quot;MSIE 7&quot;) !== -1)
+    OBJJ_ENVIRONMENTS.unshift(&quot;IE7&quot;);
+if (userAgent.indexOf(&quot;MSIE 8&quot;) !== -1)
+    OBJJ_ENVIRONMENTS.unshift(&quot;IE8&quot;);
+else
+    OBJJ_ENVIRONMENTS.unshift(&quot;W3C&quot;);
+#endif
+
 #define DIRECTORY(aPath) (aPath).substr(0, (aPath).lastIndexOf('/') + 1)
 
-function objj_firstCompatibleEngineFromArray(engines)
+function objj_mostEligibleEnvironmentFromArray(environments)
 {
-    var engine = NULL,
-        index = 0,
-        count = OBJJ_PLATFORMS.length,
-        innerCount = engines.length;
+    var index = 0,
+        count = OBJJ_ENVIRONMENTS.length,
+        innerCount = environments.length;
 
     // Ugh, no indexOf, no objects-in-common.
     for(; index &lt; count; ++index)
     {
         var innerIndex = 0,
-            currentEngine = OBJJ_PLATFORMS[index];
+            environment = OBJJ_ENVIRONMENTS[index];
         
         for (; innerIndex &lt; innerCount; ++innerIndex)
-            if(currentEngine=== engines[innerIndex])
-            {
-                engine = currentEngine;
-                break;
-            }
+            if(environment === environments[innerIndex])
+                return environment;
     }
 
-    return engine;
+    return NULL;
 }
 
 var OBJJFileNotFoundException       = &quot;OBJJFileNotFoundException&quot;,
@@ -393,16 +401,16 @@ objj_search.prototype.didReceiveBundleResponse = function(aResponse)
     
     if (executablePath)
     {
-        var platform = objj_firstCompatibleEngineFromArray(dictionary_getValue(bundle.info, &quot;CPBundlePlatforms&quot;));
+        var environment = objj_mostEligibleEnvironmentFromArray(dictionary_getValue(bundle.info, &quot;CPBundleEnvironments&quot;));
         
-        executablePath = platform + &quot;.platform/&quot; + executablePath;
+        executablePath = environment + &quot;.environment/&quot; + executablePath;
 
         this.request(DIRECTORY(aResponse.filePath) + executablePath, this.didReceiveExecutableResponse);
         
         // FIXME: Is this the right approach?
         // Request the compiled file regardless of whether our current inquiry 
         var directory = DIRECTORY(aResponse.filePath),
-            replacedFiles = dictionary_getValue(dictionary_getValue(bundle.info, &quot;CPBundleReplacedFiles&quot;), platform),
+            replacedFiles = dictionary_getValue(dictionary_getValue(bundle.info, &quot;CPBundleReplacedFiles&quot;), environment),
             index = 0,
             count = replacedFiles.length;
         
@@ -628,7 +636,11 @@ function objj_decompile(aString, bundle)
                                         
                                         break;
 
-            case MARKER_URI:            bundle._URIMap[text] = stream.getString();
+            case MARKER_URI:            var URI = stream.getString();
+                                        if (URI.toLowerCase().indexOf(&quot;mhtml:&quot;) === 0)
+                                            URI = &quot;mhtml:&quot; + DIRECTORY(window.location.href) + '/' + DIRECTORY(bundle.path) + '/' + URI.substr(&quot;mhtml:&quot;.length);
+                                        bundle._URIMap[text] = URI;
+
                                         break;
 
             case MARKER_BUNDLE:         var bundlePath = DIRECTORY(bundle.path) + '/' + text;</diff>
      <filename>Objective-J/Runtime/file.js</filename>
    </modified>
    <modified>
      <diff>@@ -17,7 +17,7 @@ app (&quot;capp&quot;, function(cappTask)
     cappTask.setSources(new FileList(&quot;*.j&quot;));
     cappTask.setResources(new FileList(&quot;Resources/*&quot;));
     cappTask.setIncludesNibsAndXibs(true);
-    cappTask.setPlatforms([BundleTask.Platform.CommonJS]);
+    cappTask.setEnvironments(require(&quot;objective-j/jake/environment&quot;).CommonJS);
     cappTask.setFlattensSources(true);
     cappTask.setSpritesResources(false);
 </diff>
      <filename>Tools/capp/Jakefile</filename>
    </modified>
    <modified>
      <diff>@@ -16,9 +16,9 @@ app (&quot;nib2cib&quot;, function(nib2cibTask)
     nib2cibTask.setAuthor(&quot;280 North, Inc.&quot;);
     nib2cibTask.setEmail(&quot;feedback @nospam@ 280north.com&quot;);
     nib2cibTask.setSummary(&quot;nib2cib converts Cocoa nib and xibs to Cappuccino cibs&quot;);
-    nib2cibTask.setSources(FILE.glob(&quot;*.j&quot;));//    t.sources       = FileList['**/*.j']
+    nib2cibTask.setSources(FILE.glob(&quot;**/*.j&quot;));
     nib2cibTask.setResources(FILE.glob(&quot;Resources/*&quot;));
-    nib2cibTask.setPlatforms([BundleTask.Platform.CommonJS]);
+    nib2cibTask.setEnvironments(require(&quot;objective-j/jake/environment&quot;).CommonJS);
     nib2cibTask.setFlattensSources(true);
 
     if ($CONFIGURATION === &quot;Release&quot;)</diff>
      <filename>Tools/nib2cib/Jakefile</filename>
    </modified>
    <modified>
      <diff>@@ -16,7 +16,8 @@ app (&quot;press&quot;, function(pressTask)
     pressTask.setVersion(&quot;0.7.9&quot;);
     pressTask.setSources(FILE.glob(&quot;*.j&quot;));
     pressTask.setResources(FILE.glob(&quot;Resources/*&quot;));
-    pressTask.setPlatforms([BundleTask.Platform.CommonJS]);
+    pressTask.setEnvironments(require(&quot;objective-j/jake/environment&quot;).CommonJS);
+    pressTask.setFlattensSources(true);
 
     if ($CONFIGURATION === &quot;Release&quot;)
         pressTask.setCompilerFlags(&quot;-O&quot;);</diff>
      <filename>Tools/press/Jakefile</filename>
    </modified>
    <modified>
      <diff>@@ -115,7 +115,7 @@ function partial_require(path, exports)
 global.setupEnvironment = function()
 {
     if (partial_require(FILE.join($BUILD_CONFIGURATION_DIR, &quot;CommonJS&quot;, &quot;objective-j&quot;)) ||
-        partial_require(FILE.join($HOME_DIR, &quot;Objective-J&quot;, &quot;CommonJS&quot;, &quot;objective-j&quot;)))
+        partial_require(FILE.join($HOME_DIR, &quot;Objective-J&quot;, &quot;CommonJS&quot;)))
     {
         var OBJECTIVE_J_JAKE = require(&quot;objective-j/jake&quot;);
 
@@ -174,8 +174,6 @@ global.mv = function(/*String*/ from, /*String*/ to)
     FILE.move(from, to);
 }
 
-//require 'objective-j'
-
 function serializedENV()
 {
     var serialized = &quot;&quot;;</diff>
      <filename>common.jake</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>848828222b67f2efda968d24c9139542b3ff8734</id>
    </parent>
  </parents>
  <author>
    <name>Francisco Ryan Tolmasky I</name>
    <email>francisco@280north.com</email>
  </author>
  <url>http://github.com/280north/cappuccino/commit/cb1889613767df9df4c67028bd835966af08584f</url>
  <id>cb1889613767df9df4c67028bd835966af08584f</id>
  <committed-date>2009-11-04T21:38:24-08:00</committed-date>
  <authored-date>2009-11-04T21:38:24-08:00</authored-date>
  <message>First pass at spriting in IE.

Reviewed by me.</message>
  <tree>46073450f60f485cb3ad9e2abea674c953fb3b0b</tree>
  <committer>
    <name>Francisco Ryan Tolmasky I</name>
    <email>francisco@280north.com</email>
  </committer>
</commit>
