Browse Source

Merge branch 'master' into helios-sunit

Nicolas Petton 10 years ago
parent
commit
bd60a9d801
100 changed files with 56187 additions and 108 deletions
  1. 2 7
      .gitignore
  2. 17 0
      .npmignore
  3. 11 0
      API-CHANGES.txt
  4. 7 1
      CHANGELOG
  5. 28 7
      Gruntfile.js
  6. 4 7
      README.md
  7. 2 0
      bower.json
  8. 44 0
      external/amber-cli/CHANGELOG
  9. 63 0
      external/amber-cli/CONTRIBUTING.md
  10. 45 0
      external/amber-cli/Gruntfile.js
  11. 22 0
      external/amber-cli/LICENSE
  12. 47 0
      external/amber-cli/README.md
  13. 15 0
      external/amber-cli/RELEASING.md
  14. 18 0
      external/amber-cli/bower.json
  15. 32 0
      external/amber-cli/index.html
  16. 49 0
      external/amber-cli/package.json
  17. 1234 0
      external/amber-cli/src/AmberCli.js
  18. 1232 0
      external/amber-cli/src/AmberCli.st
  19. 51977 0
      external/amber-cli/support/amber-cli.js
  20. 197 0
      external/amber-cli/support/amberc-cli.js
  21. 143 0
      external/amber-dev/lib/Test.js
  22. 37 0
      external/amber-dev/lib/Test.st
  23. 595 0
      external/amber-dev/lib/amberc.js
  24. 21 0
      external/amber-dev/package.json
  25. 137 0
      external/amber-dev/tasks/grunt-amberc.js
  26. 1 1
      grunt/tasks/grunt-peg.js
  27. 4 2
      package.json
  28. 2 1
      src/Benchfib.js
  29. 2 1
      src/Compiler-AST.js
  30. 4 3
      src/Compiler-Core.js
  31. 1 1
      src/Compiler-Core.st
  32. 2 1
      src/Compiler-Exceptions.js
  33. 2 1
      src/Compiler-IR.js
  34. 2 1
      src/Compiler-Inlining.js
  35. 2 1
      src/Compiler-Interpreter.js
  36. 2 1
      src/Compiler-Semantic.js
  37. 2 1
      src/Compiler-Tests.js
  38. 2 1
      src/Examples.js
  39. 2 1
      src/IDE.js
  40. 30 1
      src/Kernel-Announcements.js
  41. 10 0
      src/Kernel-Announcements.st
  42. 2 1
      src/Kernel-Classes.js
  43. 2 1
      src/Kernel-Collections.js
  44. 2 1
      src/Kernel-Exceptions.js
  45. 9 4
      src/Kernel-ImportExport.js
  46. 4 2
      src/Kernel-ImportExport.st
  47. 14 5
      src/Kernel-Infrastructure.js
  48. 2 3
      src/Kernel-Infrastructure.st
  49. 9 12
      src/Kernel-Methods.js
  50. 1 1
      src/Kernel-Methods.st
  51. 2 1
      src/Kernel-Objects.js
  52. 28 1
      src/Kernel-Tests.js
  53. 7 0
      src/Kernel-Tests.st
  54. 2 1
      src/Kernel-Transcript.js
  55. 2 1
      src/SUnit-Tests.js
  56. 2 1
      src/SUnit.js
  57. 2 1
      src/Spaces.js
  58. 2 1
      src/Web.js
  59. 0 18
      support/_st.js
  60. 4 3
      support/amber.js
  61. 25 2
      support/boot.js
  62. 1 1
      support/browser-compatibility.js
  63. 3 0
      support/deprecated-vm-files/_st.js
  64. 3 0
      support/deprecated-vm-files/as-receiver.js
  65. 3 0
      support/deprecated-vm-files/boot.js
  66. 0 0
      support/deprecated-vm-files/globals.js
  67. 0 0
      support/deprecated-vm-files/nil.js
  68. 0 0
      support/deprecated-vm-files/smalltalk.js
  69. 1 1
      support/helios/all.js
  70. 0 0
      support/helios/resources/all-inner.js
  71. 0 0
      support/helios/resources/announcement.png
  72. 0 0
      support/helios/resources/arrowLeft.png
  73. 0 0
      support/helios/resources/arrowRight.png
  74. 0 0
      support/helios/resources/browser.png
  75. 0 0
      support/helios/resources/class.png
  76. 0 0
      support/helios/resources/close-dark.png
  77. 0 0
      support/helios/resources/close.gif
  78. 0 0
      support/helios/resources/collection.png
  79. 0 0
      support/helios/resources/debugger.png
  80. 0 0
      support/helios/resources/exception.png
  81. 0 0
      support/helios/resources/extension.png
  82. 2 2
      support/helios/resources/helios-niflheim.css
  83. 2 2
      support/helios/resources/helios-niflheim.less
  84. 1 1
      support/helios/resources/helios.css
  85. 1 1
      support/helios/resources/helios.less
  86. 0 0
      support/helios/resources/helios_frame.css
  87. 0 0
      support/helios/resources/initialization.png
  88. 0 0
      support/helios/resources/inspector.png
  89. 0 0
      support/helios/resources/magnitude.png
  90. 0 0
      support/helios/resources/modified.png
  91. 0 0
      support/helios/resources/niflheim.css
  92. 0 0
      support/helios/resources/off.png
  93. 0 0
      support/helios/resources/offHover.png
  94. 0 0
      support/helios/resources/overridden.png
  95. 0 0
      support/helios/resources/override-overridden.png
  96. 0 0
      support/helios/resources/override.png
  97. 0 0
      support/helios/resources/package-dirty.png
  98. 0 0
      support/helios/resources/package.png
  99. 0 0
      support/helios/resources/pause.png
  100. 0 0
      support/helios/resources/private.png

+ 2 - 7
.gitignore

@@ -1,19 +1,14 @@
-# Ignoring compiled files in examples etc
-server/FileServer*.js
-
 # Ignoring Mac Finder files
 .DS_Store
 
 # Ignoring test runner
-test/amber_test_runner.js
-test/run.js
 test_runner.js
 
 # In case amber is also saved in a local Subversion
 .svn
 
 # Ignoring local NPM modules
-/node_modules/*
+node_modules/
 
 # Ignoring local bower modules
-/bower_components/*
+bower_components/

+ 17 - 0
.npmignore

@@ -0,0 +1,17 @@
+# Ignoring Mac Finder files
+.DS_Store
+
+# Ignoring test runner
+test_runner.js
+
+# In case amber is also saved in a local Subversion
+.svn
+
+# Ignoring local NPM modules
+node_modules/
+
+# Ignoring local bower modules
+bower_components/
+
+# Exclude the externals
+/external/

+ 11 - 0
API-CHANGES.txt

@@ -1,3 +1,14 @@
+0.12.5:
+
++ String >>
+  + value:
++ ProtocolAnnouncement >>
+  + package
++ amber/{devel,deploy,lang} exports
+  + nil
++ amber/helpers exports
+  + nil
+
 0.12.4:
 
 * Package Canvas renamed to Web

+ 7 - 1
CHANGELOG

@@ -3,7 +3,13 @@ XXnd XXX 2014 - Release 0.12.5
 
 Highlights:
 
-* `amber` and `amberc` cli moved to dedicated repository.
+* `amber` and `amberc` cli moved to `external` directory
+  and to dedicated npm package.
+* Amber now parses `$c` character literal.
+* `amber` is not to be installed globally any more.
+  Instead, `npm install -g amber-cli` installs cli tooling.
+* After installing the cli tooling, `amber init` initializes
+  new project if run in empty directory.
 
 Commits: https://github.com/amber-smalltalk/amber/compare/0.12.4...0.12.5
 Issues:  https://github.com/amber-smalltalk/amber/issues?milestone=13&state=closed

+ 28 - 7
Gruntfile.js

@@ -4,8 +4,12 @@ module.exports = function(grunt) {
   grunt.loadNpmTasks('amber-dev');
 
   grunt.loadNpmTasks('grunt-contrib-jshint');
+  grunt.loadNpmTasks('grunt-contrib-clean');
+  grunt.loadNpmTasks('grunt-execute');
 
   grunt.registerTask('default', ['peg', 'amberc:all']);
+  grunt.registerTask('amberc:all', ['amberc:core', 'amberc:helios']);
+  grunt.registerTask('test', ['amberc:test_runner', 'execute:test_runner', 'clean:test_runner']);
 
   grunt.initConfig({
     pkg: grunt.file.readJSON('package.json'),
@@ -30,7 +34,7 @@ module.exports = function(grunt) {
         amber_dir: process.cwd(),
         closure_jar: ''
       },
-      all: {
+      core: {
         output_dir : 'src',
         src: ['src/Kernel-Objects.st', 'src/Kernel-Classes.st', 'src/Kernel-Methods.st', 'src/Kernel-Collections.st',
               'src/Kernel-Infrastructure.st', 'src/Kernel-Exceptions.st', 'src/Kernel-Transcript.st', 'src/Kernel-Announcements.st',
@@ -38,16 +42,23 @@ module.exports = function(grunt) {
               'src/Compiler-IR.st', 'src/Compiler-Inlining.st', 'src/Compiler-Semantic.st', 'src/Compiler-Interpreter.st',
               'src/Web.st', 'src/SUnit.st', 'src/IDE.st',
               'src/Kernel-Tests.st', 'src/Compiler-Tests.st', 'src/SUnit-Tests.st',
-              'src/Helios-Core.st', 'src/Helios-Exceptions.st', 'src/Helios-Announcements.st',
-              'src/Helios-KeyBindings.st', 'src/Helios-Layout.st',
-              'src/Helios-Commands-Core.st', 'src/Helios-Commands-Tools.st', 'src/Helios-Commands-Browser.st',
-              'src/Helios-References.st', 'src/Helios-Inspector.st', 'src/Helios-Browser.st',
-              'src/Helios-Transcript.st', 'src/Helios-Workspace.st', 'src/Helios-Debugger.st',
-              'src/Helios-Workspace-Tests.st',
               'src/Benchfib.st', 'src/Examples.st', 'src/Spaces.st'
               ],
         jsGlobals: ['navigator']
       },
+      helios: {
+        output_dir : 'support/helios/src',
+        src: ['support/helios/src/Helios-Core.st', 'support/helios/src/Helios-Exceptions.st', 'support/helios/src/Helios-Announcements.st',
+              'support/helios/src/Helios-KeyBindings.st', 'support/helios/src/Helios-Layout.st',
+              'support/helios/src/Helios-Commands-Core.st', 'support/helios/src/Helios-Commands-Tools.st', 'support/helios/src/Helios-Commands-Browser.st',
+              'support/helios/src/Helios-References.st', 'support/helios/src/Helios-Inspector.st', 'support/helios/src/Helios-Browser.st',
+              'support/helios/src/Helios-Transcript.st', 'support/helios/src/Helios-Workspace.st', 'support/helios/src/Helios-Debugger.st',
+              'support/helios/src/Helios-Workspace-Tests.st'
+              ],
+        libraries: ['Web', 'SUnit'],
+        amd_namespace: 'helios',
+        jsGlobals: ['navigator']
+      },
       amber_kernel: {
         output_dir : 'src',
         src: ['src/Kernel-Objects.st', 'src/Kernel-Classes.st', 'src/Kernel-Methods.st', 'src/Kernel-Collections.st',
@@ -79,6 +90,16 @@ module.exports = function(grunt) {
       }
     },
 
+    execute: {
+      test_runner: {
+        src: ['test_runner.js']
+      }
+    },
+
+    clean: {
+      test_runner: ['test_runner.js']
+    },
+
     jshint: {
       amber: ['src/*.js'],
       server: ['server/*.js'],

+ 4 - 7
README.md

@@ -23,16 +23,13 @@ Getting Amber
 
 Amber is shipped as a [npm](http://npmjs.org) package for its CLI tools and as a [bower](https://github.com/bower/bower) package for the client-side.
 
-    # Install the CLI tool `amber`
-    npm install -g amber
+    # Install the CLI tool `amber-cli`
+    npm install -g amber-cli
     
-    # Initialize your project as bower package
+    # Initialize your project (directory must be empty)
     cd /path/to/myproject
-    bower init
+    amber init
 
-    # Load amber via bower in your project
-    bower install amber --save
-    
     # Serve amber on localhost:4000
     amber serve
 

+ 2 - 0
bower.json

@@ -6,6 +6,8 @@
     "**/.*",
     "node_modules",
     "bower_components",
+    "/external",
+    "/test_runner.js",
     "test",
     "tests"
   ],

+ 44 - 0
external/amber-cli/CHANGELOG

@@ -0,0 +1,44 @@
+XXth XXX 2014 - Release 0.1.0
+===================================
+
+Highlights:
+
+* Package is polished.
+* `amber-cli` is now official package to install globally.
+
+Commits: https://github.com/amber-smalltalk/amber-cli/compare/0.0.6...0.1.0
+Issues:  https://github.com/amber-smalltalk/amber-cli/issues?milestone=2&state=closed
+
+
+15th April 2014 - Release 0.0.6
+===================================
+
+Highlights:
+
+* `amberc -d dir` allows specify alternate Amber dir.
+
+Commits: https://github.com/amber-smalltalk/amber-cli/compare/0.0.5...0.0.6
+Issues:  https://github.com/amber-smalltalk/amber-cli/issues?milestone=4&state=closed
+
+
+15th April 2014 - Release 0.0.5
+===================================
+
+Highlights:
+
+* Bugfix: `amberc -l` now working.
+
+Commits: https://github.com/amber-smalltalk/amber-cli/compare/0.0.4...0.0.5
+Issues:  https://github.com/amber-smalltalk/amber-cli/issues?milestone=3&state=closed
+
+
+14th April 2014 - Release 0.0.4
+===================================
+
+Highlights:
+
+* Amber tooling is now in its own package.
+
+Commits: https://github.com/amber-smalltalk/amber-cli/compare/cc2a163...0.0.4
+Issues:  https://github.com/amber-smalltalk/amber-cli/issues?milestone=1&state=closed
+

+ 63 - 0
external/amber-cli/CONTRIBUTING.md

@@ -0,0 +1,63 @@
+Start Contributing by talking about Amber
+=========================================
+
+* Join our [Mailinglist/Google Group](http://groups.google.com/group/amber-lang)
+* Talk to us on [the #amber-lang IRC channel](irc://irc.freenode.net/amber-lang)
+* Follow [@AmberSmalltalk](https://twitter.com/AmberSmalltalk) on Twitter
+* Circle Amber Smalltalk on [Google+](https://plus.google.com/u/0/107038882958653788078) 
+
+
+Filing Issues
+=============
+
+If you think Amber CLI is not working as expected, You can start by asking on IRC or the Mailinglist.
+Please make sure that you have first checked the following guides:
+
+* [Getting Started](https://github.com/amber-smalltalk/amber/wiki/Getting-started)
+* [Writing My First App](https://github.com/amber-smalltalk/amber/wiki/Writing-my-first-app)
+* [How To Load Amber](https://github.com/amber-smalltalk/amber/wiki/How-to-load-amber)
+* [Amber FAQ](https://github.com/amber-smalltalk/amber/wiki/FAQ)
+
+If the issue can not be resolved you should file an issue on the respective tracker.
+
+Before reporting an issue, try to reduce the issue to the bare minimum required to reproduce it.
+This allows us to track down and fix the issue in an easier and faster way.
+
+Additionally, you should give us enough information to reproduce the issue.
+Therefore, include versions of your OS, Amber, Node.js, Grunt, and possibly used libraries as well as sample code.
+If you don't list the exact steps required to reproduce the issue we won't be able to fix it.
+
+
+Creating a Pull Request
+-----------------------
+
+The Amber development model currently revolves around Pull Requests which are created through GitHub
+
+1. Update to latest Amber CLI master (```git pull```)
+2. Develop your feature or bugfix in a local branch (not in ```master```)
+3. Create unittest for your feature or bugfix (your feature/fix will be integrated a lot faster if unittests are present)
+4. Enhance/fix Amber
+5. Run the unittests
+6. Commit your changes to disk if all tests are green
+7. Try to split your fix into small Git commits if multiple changes are involved (this makes it easier for us to review the changes)
+8. If you created / deleted / moved something significant, update CHANGELOG appropriately and commit.
+8. Push the changes to your fork on GitHub ```git push <your repo> <your branchname>```
+9. Submit Pull Request (usually for the Amber CLI master branch)
+
+
+Compiling Amber CLI with Grunt
+--------------------------
+
+Amber uses [Grunt.js](http://gruntjs.com/) as build system since version `0.10.0`.
+
+To install Grunt.js v0.4.x on the commandline execute the following commands:
+
+    npm install -g grunt-cli
+
+Make sure that you have installed all required dependencies via `npm` and `bower`.
+Then you can finally compile Amber CLI using the following command:
+
+    cd ${Amber_DIR}
+    grunt amberc:amber_cli
+
+For Windows support check the [Grunt.js on Windows](http://gruntjs.com/frequently-asked-questions#does-grunt-work-on-windows) page.

+ 45 - 0
external/amber-cli/Gruntfile.js

@@ -0,0 +1,45 @@
+module.exports = function(grunt) {
+  var path = require('path');
+
+  grunt.loadNpmTasks('amber-dev');
+
+  grunt.loadNpmTasks('grunt-contrib-jshint');
+
+  grunt.registerTask('default', ['amberc:cli']);
+
+  grunt.initConfig({
+    pkg: grunt.file.readJSON('package.json'),
+
+    meta: {
+      banner: '/*!\n <%= pkg.title || pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> \n License: <%= pkg.license.type %> \n*/\n'
+    },
+
+    amberc: {
+      options: {
+        amber_dir: path.normalize(path.join(__dirname, "node_modules", "amber"))
+      },
+      amber_tests: {
+        output_dir : 'src',
+        src: ['src/Kernel-Tests.st', 'src/Compiler-Tests.st', 'src/SUnit-Tests.st'],
+        libraries: ['SUnit']
+      },
+      cli: {
+        output_dir: 'src',
+        src: ['src/AmberCli.st'],
+        libraries: [
+            'Compiler-Exceptions', 'Compiler-Core', 'Compiler-AST',
+            'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic', 'Compiler-Interpreter', 'parser',
+            'SUnit', 'Kernel-ImportExport',
+            'Kernel-Tests', 'Compiler-Tests', 'SUnit-Tests'
+        ],
+        main_class: 'AmberCli',
+        output_name: '../support/amber-cli',
+        amd_namespace: 'amber_cli'
+      }
+    },
+
+    jshint: {
+      cli: ['src/*.js', 'support/*.js']
+    }
+  });
+};

+ 22 - 0
external/amber-cli/LICENSE

@@ -0,0 +1,22 @@
+Copyright (C) 2011-2014 Nicolas Petton <petton.nicolas@gmail.com>
+Copyright (C) 2011-2014 Amber contributors https://github.com/NicolasPetton/amber/contributors
+
+Parts of Amber take ideas from Clamato (http://clamato.net), written by Avi Bryant.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 47 - 0
external/amber-cli/README.md

@@ -0,0 +1,47 @@
+Amber [![Travis CI Status](https://secure.travis-ci.org/amber-smalltalk/amber.png)](https://travis-ci.org/#!/amber-smalltalk/amber-cli)
+=====
+
+By Nicolas Petton <petton.nicolas@gmail.com> and [Amber contributors](https://github.com/amber-smalltalk/amber/contributors)
+
+Amber is an implementation of the Smalltalk language that runs on top of the JavaScript runtime. It is designed to make client-side development faster and easier.
+
+Overview
+--------
+
+Amber is written in itself, including the parser and compiler. Amber compiles into efficient JavaScript, mapping one-to-one with the equivalent JavaScript. There is no interpretation at runtime.
+
+Some highlights:
+
+-    Amber features an IDE with a Class browser, Workspace, Transcript, a ReferencesBrowser supporting senders/implementors and class references, basic Inspector and even a beginning of a Debugger and a unit TestRunner.
+-    [Pharo Smalltalk](http://www.pharo-project.org) is considered as the reference implementation.
+-    Amber includes a canvas to generate HTML, like [Seaside](http://www.seaside.st)
+-    Amber can use Javascript libraries and the current IDE is built on [jQuery](http://www.jquery.com)
+-    You can inline Javascript code and there are many ways to interact between Amber and Javascript
+
+Getting Amber
+-------------
+
+Amber is shipped as a [npm](http://npmjs.org) package for its CLI tools and as a [bower](https://github.com/bower/bower) package for the client-side.
+
+    # Install the CLI tool `amber`
+    npm install -g amber-cli
+    
+    # Initialize your project
+    cd /path/to/myproject
+    amber init
+
+    # Serve amber on localhost:4000
+    amber serve
+
+The [Getting started](http://docs.amber-lang.net/getting-started.html) page shows more details on ways to obtain Amber and start a project.
+
+License
+-------
+
+Amber is released under the MIT license. All contributions made for inclusion are considered to be under MIT.
+
+
+More infos
+----------
+
+More on the [project page](http://amber-lang.net)

+ 15 - 0
external/amber-cli/RELEASING.md

@@ -0,0 +1,15 @@
+Release Guide for Amber
+=======================
+
+The following steps are required to make a release of Amber:
+
+1. (not yet) check that all tests are green
+1. check the `CHANGELOG` file and update the release notes, check the milestone index in issues link
+1. bump version and git repo tag in `package.json`
+1. Create a tag for bumped version:`git tag -a 1.2.3 -m "Version 1.2.3`
+1. `git commit -a -m "Release 1.2.3" && git push && git push --tags`
+1. log in to npm with write access for the Amber package
+1. update the homepage to point to the latest tag on GitHub
+1. send announcement to mailinglists (Amber, Pharo, what else?)
+1. send announcement on Twitter
+1. send announcement on G+

+ 18 - 0
external/amber-cli/bower.json

@@ -0,0 +1,18 @@
+{
+  "name": "amber-cli",
+  "version": "0.0.1",
+  "homepage": "https://github.com/amber-smalltalk/amber-cli",
+  "description": "CLI for Amber Smalltalk",
+  "license": "MIT",
+  "private": true,
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+    "amber": "~0.12.4"
+  }
+}

+ 32 - 0
external/amber-cli/index.html

@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+
+  <head>
+    <title>Amber Smalltalk</title>
+    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+    <meta name="author" content="Nicolas Petton" />
+    <script type='text/javascript' src='bower_components/amber/support/requirejs/require.min.js'></script>
+    <script src='bower_components/amber/support/amber.js'></script>
+
+  </head>
+
+  <body>
+    <script type='text/javascript'>
+    require.config({
+        paths: {
+            'amber_cli': 'src'
+        }
+    });
+    require(
+        ["amber/devel",
+            "amber_cli/AmberCli" ],
+        function (smalltalk) {
+            smalltalk.initialize({'transport.defaultAmdNamespace': 'amber_cli'});
+//            smalltalk.globals.Browser._openOn_(smalltalk.AmberCli);
+            smalltalk.popupHelios();
+        }
+    );
+    </script>
+  </body>
+</html> 
+

+ 49 - 0
external/amber-cli/package.json

@@ -0,0 +1,49 @@
+{
+  "name": "amber-cli",
+  "version": "0.0.10",
+  "description": "An implementation of the Smalltalk language that runs on top of the JS runtime.",
+  "homepage": "http://amber-lang.net",
+  "keywords": [
+    "javascript",
+    "smalltalk",
+    "language",
+    "compiler",
+    "web"
+  ],
+  "author": {
+    "name": "Nicolas Petton",
+    "email": "petton.nicolas@gmail.com",
+    "url": "http://www.nicolas-petton.fr"
+  },
+  "license": {
+    "type": "MIT"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/amber-smalltalk/amber.git"
+  },
+  "engines": {
+    "node": ">=0.8.0"
+  },
+  "bugs": {
+    "url": "https://github.com/amber-smalltalk/amber/issues?labels=cli"
+  },
+  "bin": {
+    "amber": "./support/amber-cli.js",
+    "amberc": "./support/amberc-cli.js"
+  },
+  "scripts": {
+    "test": "grunt amberc:cli && node ./support/amber-cli.js tests"
+  },
+  "dependencies": {
+    "amber": "~0.12.4",
+    "grunt-init-amber": "0.0.1",
+    "grunt-init": "~0.3.1",
+    "bower": "~1.3.2",
+    "amber-dev": "~0.1.1"
+  },
+  "devDependencies": {
+    "grunt": "~0.4.0",
+    "grunt-contrib-jshint": "~0.3.0"
+  }
+}

File diff suppressed because it is too large
+ 1234 - 0
external/amber-cli/src/AmberCli.js


+ 1232 - 0
external/amber-cli/src/AmberCli.st

@@ -0,0 +1,1232 @@
+Smalltalk createPackage: 'AmberCli'!
+Object subclass: #AmberCli
+	instanceVariableNames: ''
+	package: 'AmberCli'!
+!AmberCli commentStamp!
+I am the Amber CLI (CommandLine Interface) tool which runs on Node.js.
+
+My responsibility is to start different Amber programs like the FileServer or the Repl.
+Which program to start is determined by the first commandline parameters passed to the AmberCli executable.
+Use `help` to get a list of all available options.
+Any further commandline parameters are passed to the specific program.
+
+## Commands
+
+New commands can be added by creating a class side method in the `commands` protocol which takes one parameter.
+This parameter is an array of all commandline options + values passed on to the program.
+Any `camelCaseCommand` is transformed into a commandline parameter of the form `camel-case-command` and vice versa.!
+
+!AmberCli class methodsFor: 'commandline'!
+
+commandLineSwitches
+	"Collect all methodnames from the 'commands' protocol of the class
+	 and select the ones with only one parameter.
+	 Then remove the ':' at the end of the name.
+	 Additionally all uppercase letters are made lowercase and preceded by a '-'.
+	 Example: fallbackPage: becomes --fallback-page.
+	 Return the Array containing the commandline switches."
+	| switches |
+	switches := ((self class methodsInProtocol: 'commands') collect: [ :each | each selector]).
+	switches := switches select: [ :each | each match: '^[^:]*:$'].
+	switches :=switches collect: [ :each |
+		(each allButLast replace: '([A-Z])' with: '-$1') asLowercase].
+	^ switches
+!
+
+handleArguments: args
+	| selector |
+
+	selector := self selectorForCommandLineSwitch: (args first).
+	args remove: args first.
+	self perform: selector  withArguments: (Array with: args)
+!
+
+selectorForCommandLineSwitch: aSwitch
+	"Add ':' at the end and replace all occurences of a lowercase letter preceded by a '-' with the Uppercase letter.
+	 Example: fallback-page becomes fallbackPage:.
+	 If no correct selector is found return 'help:'"
+	 | command selector |
+
+	 (self commandLineSwitches includes: aSwitch)
+	 ifTrue: [ selector := (aSwitch replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':']
+	 ifFalse: [ selector := 'help:' ].
+	^ selector
+! !
+
+!AmberCli class methodsFor: 'commands'!
+
+help: args
+	Transcript show: 'Available commands'.
+	self commandLineSwitches do: [ :each | console log: each ]
+!
+
+init: args
+	Initer new start
+!
+
+repl: args
+	^ Repl new createInterface
+!
+
+serve: args
+	^ (FileServer createServerWithArguments: args) start
+!
+
+tests: arguments
+	^ NodeTestRunner runTestSuite
+!
+
+version: arguments
+! !
+
+!AmberCli class methodsFor: 'startup'!
+
+main
+	"Main entry point for Amber applications.
+	Parses commandline arguments and starts the according subprogram."
+	| args nodeMinorVersion |
+	
+	Transcript show: 'Welcome to Amber version ', Smalltalk version, ' (NodeJS ', process versions node, ').'.
+
+	nodeMinorVersion := ((process version) tokenize: '.') second asNumber.
+	nodeMinorVersion < 8 ifTrue: [
+		Transcript show: 'You are currently using Node.js ', (process version).
+		Transcript show: 'Required is at least Node.js v0.8.x or greater.'.
+		^ -1.
+	].
+
+	args := process argv.
+	"Remove the first args which contain the path to the node executable and the script file."
+	args removeFrom: 1 to: 2.
+	
+	(args isEmpty)
+		ifTrue: [self help: nil]
+		ifFalse: [^self handleArguments: args]
+! !
+
+Object subclass: #FileServer
+	instanceVariableNames: 'path http fs url host port basePath util username password fallbackPage'
+	package: 'AmberCli'!
+!FileServer commentStamp!
+I am the Amber Smalltalk FileServer.
+My runtime requirement is a functional Node.js executable.
+
+To start a FileServer instance on port `4000` use the following code:
+
+    FileServer new start
+
+A parameterized instance can be created with the following code:
+
+    FileServer createServerWithArguments: options
+
+Here, `options` is an array of commandline style strings each followed by a value e.g. `#('--port', '6000', '--host', '0.0.0.0')`.
+A list of all available parameters can be printed to the commandline by passing `--help` as parameter.
+See the `Options` section for further details on how options are mapped to instance methods.
+
+After startup FileServer checks if the directory layout required by Amber is present and logs a warning on absence.
+
+
+## Options
+
+Each option is of the form `--some-option-string` which is transformed into a selector of the format `someOptionString:`.
+The trailing `--` gets removed, each `-[a-z]` gets transformed into the according uppercase letter, and a `:` is appended to create a selector which takes a single argument.
+Afterwards, the selector gets executed on the `FileServer` instance with the value following in the options array as parameter.
+
+## Adding new commandline parameters
+
+Adding new commandline parameters to `FileServer` is as easy as adding a new single parameter method to the `accessing` protocol.!
+
+!FileServer methodsFor: 'accessing'!
+
+basePath
+	^ basePath ifNil: [self class defaultBasePath]
+!
+
+basePath: aString
+	basePath := aString.
+	self validateBasePath.
+!
+
+fallbackPage
+	^ fallbackPage
+!
+
+fallbackPage: aString
+	fallbackPage := aString
+!
+
+host
+	^ host
+!
+
+host: hostname
+	host := hostname
+!
+
+password: aPassword
+	password := aPassword.
+!
+
+port
+	^ port
+!
+
+port: aNumber
+	port := aNumber
+!
+
+username: aUsername
+	username := aUsername.
+! !
+
+!FileServer methodsFor: 'initialization'!
+
+checkDirectoryLayout
+	(fs existsSync:	(self withBasePath: 'index.html')) ifFalse: [
+		console warn: 'Warning: project directory does not contain index.html.'.
+		console warn: '    You can specify the directory containing index.html with --base-path.'.
+		console warn: '    You can also specify a page to be served by default,'.
+		console warn: '    for all paths that do not map to a file, with --fallback-page.'].
+!
+
+initialize
+	super initialize.
+	path := self require: 'path'.
+	http := self require: 'http'.
+	fs := self require: 'fs'.
+	util := self require: 'util'.
+	url := self require: 'url'.
+	host := self class defaultHost.
+	port := self class defaultPort.
+	username := nil.
+	password := nil.
+	fallbackPage := nil.
+! !
+
+!FileServer methodsFor: 'private'!
+
+base64Decode: aString
+	<return (new Buffer(aString, 'base64').toString())>
+!
+
+isAuthenticated: aRequest
+	"Basic HTTP Auth: http://stackoverflow.com/a/5957629/293175
+	 and https://gist.github.com/1686663"
+	| header token auth parts|
+
+	(username isNil and: [password isNil]) ifTrue: [^ true].
+
+	"get authentication header"
+	header := (aRequest headers at: 'authorization') ifNil:[''].
+	(header isEmpty)
+	ifTrue: [^ false]
+	ifFalse: [
+		"get authentication token"
+		token := (header tokenize: ' ') ifNil:[''].
+		"convert back from base64"
+		auth := self base64Decode: (token at: 2).
+		"split token at colon"
+		parts := auth tokenize: ':'.
+
+		((username = (parts at: 1)) and: [password = (parts at: 2)])
+			ifTrue: [^ true]
+			ifFalse: [^ false]
+	].
+!
+
+require: aModuleString
+	"call to the require function"
+	^require value: aModuleString
+!
+
+validateBasePath
+	"The basePath must be an existing directory. "
+	fs stat: self basePath then: [ :err :stat | err
+		ifNil: [ stat isDirectory ifFalse: [ console warn: 'Warning: --base-path parameter ' , self basePath , ' is not a directory.' ]]
+		ifNotNil: [ console warn: 'Warning: path at --base-path parameter ' , self basePath , ' does not exist.'  ]].
+!
+
+withBasePath: aBaseRelativePath
+	"return a file path which is relative to the basePath."
+	^ path join: self basePath with: aBaseRelativePath
+!
+
+writeData: data toFileNamed: aFilename
+	console log: aFilename
+! !
+
+!FileServer methodsFor: 'request handling'!
+
+handleGETRequest: aRequest respondTo: aResponse
+	| uri filename |
+	uri := url parse: aRequest url.
+	filename := path join: self basePath with: uri pathname.
+	fs exists: filename do: [:aBoolean |
+		aBoolean
+			ifFalse: [self respondNotFoundTo: aResponse]
+			ifTrue: [(fs statSync: filename) isDirectory
+				ifTrue: [self respondDirectoryNamed: filename from: uri to: aResponse]
+				ifFalse: [self respondFileNamed: filename to: aResponse]]]
+!
+
+handleOPTIONSRequest: aRequest respondTo: aResponse
+	aResponse writeHead: 200 options: #{'Access-Control-Allow-Origin' -> '*'.
+					'Access-Control-Allow-Methods' -> 'GET, PUT, POST, DELETE, OPTIONS'.
+					'Access-Control-Allow-Headers' -> 'Content-Type, Accept'.
+					'Content-Length' -> 0.
+					'Access-Control-Max-Age' -> 10}.
+	aResponse end
+!
+
+handlePUTRequest: aRequest respondTo: aResponse
+	| file stream |
+	(self isAuthenticated: aRequest)
+		ifFalse: [self respondAuthenticationRequiredTo: aResponse. ^ nil].
+
+	file := '.', aRequest url.
+	stream := fs createWriteStream: file.
+
+	stream on: 'error' do: [:error |
+		console warn: 'Error creating WriteStream for file ', file.
+		console warn: '    Did you forget to create the necessary directory in your project (often /src)?'.
+		console warn: '    The exact error is: ', error.
+		self respondNotCreatedTo: aResponse].
+
+	stream on: 'close' do: [
+		self respondCreatedTo: aResponse].
+
+	aRequest setEncoding: 'utf8'.
+	aRequest on: 'data' do: [:data |
+		stream write: data].
+
+	aRequest on: 'end' do: [
+		stream writable ifTrue: [stream end]]
+!
+
+handleRequest: aRequest respondTo: aResponse
+	aRequest method = 'PUT'
+		ifTrue: [self handlePUTRequest: aRequest respondTo: aResponse].
+	aRequest method = 'GET'
+		ifTrue:[self handleGETRequest: aRequest respondTo: aResponse].
+	aRequest method = 'OPTIONS'
+		ifTrue:[self handleOPTIONSRequest: aRequest respondTo: aResponse]
+!
+
+respondAuthenticationRequiredTo: aResponse
+	aResponse
+		writeHead: 401 options: #{'WWW-Authenticate' -> 'Basic realm="Secured Developer Area"'};
+		write: '<html><body>Authentication needed</body></html>';
+		end.
+!
+
+respondCreatedTo: aResponse
+	aResponse
+		writeHead: 201 options: #{'Content-Type' -> 'text/plain'. 'Access-Control-Allow-Origin' -> '*'};
+		end.
+!
+
+respondDirectoryNamed: aDirname from: aUrl to: aResponse
+	(aUrl pathname endsWith: '/')
+		ifTrue: [self respondFileNamed: aDirname, 'index.html' to: aResponse]
+		ifFalse: [self respondRedirect: aUrl pathname, '/', (aUrl search ifNil: ['']) to: aResponse]
+!
+
+respondFileNamed: aFilename to: aResponse
+	| type filename |
+
+	filename := aFilename.
+
+	fs readFile: filename do: [:ex :file |
+		ex notNil 
+			ifTrue: [
+				console log: filename, ' does not exist'.
+				self respondNotFoundTo: aResponse]
+			ifFalse: [
+				type := self class mimeTypeFor: filename.
+				type = 'application/javascript'
+					ifTrue: [ type:=type,';charset=utf-8' ].
+				aResponse 
+					writeHead: 200 options:  #{'Content-Type' -> type};
+					write: file encoding: 'binary';
+					end]]
+!
+
+respondInternalErrorTo: aResponse
+	aResponse 
+		writeHead: 500 options: #{'Content-Type' -> 'text/plain'};
+		write: '500 Internal server error';
+		end
+!
+
+respondNotCreatedTo: aResponse
+	aResponse
+		writeHead: 400 options: #{'Content-Type' -> 'text/plain'};
+		write: 'File could not be created. Did you forget to create the src directory on the server?';
+		end.
+!
+
+respondNotFoundTo: aResponse
+	self fallbackPage isNil ifFalse: [^self respondFileNamed: self fallbackPage to: aResponse].
+	aResponse 
+		writeHead: 404 options: #{'Content-Type' -> 'text/html'};
+		write: '<html><body><p>404 Not found</p>';
+		write: '<p>Did you forget to put an index.html file into the directory which is served by "bin/amber serve"? To solve this you can:<ul>';
+		write: '<li>create an index.html in the served directory.</li>';
+		write: '<li>can also specify the location of a page to be served whenever path does not resolve to a file with the "--fallback-page" option.</li>';
+		write: '<li>change the directory to be served with the "--base-path" option.</li>';
+		write: '</ul></p></body></html>';
+		end
+!
+
+respondOKTo: aResponse
+	aResponse
+		writeHead: 200 options: #{'Content-Type' -> 'text/plain'. 'Access-Control-Allow-Origin' -> '*'};
+		end.
+!
+
+respondRedirect: aString to: aResponse
+	aResponse
+		writeHead: 303 options: #{'Location' -> aString};
+		end.
+! !
+
+!FileServer methodsFor: 'starting'!
+
+start
+	"Checks if required directory layout is present (issue warning if not).
+	 Afterwards start the server."
+	self checkDirectoryLayout.
+	(http createServer: [:request :response |
+	      self handleRequest: request respondTo: response])
+	      on: 'error' do: [:error | console log: 'Error starting server: ', error];
+	      on: 'listening' do: [console log: 'Starting file server on http://', self host, ':', self port asString];
+	      listen: self port host: self host.
+!
+
+startOn: aPort
+	self port: aPort.
+	self start
+! !
+
+FileServer class instanceVariableNames: 'mimeTypes'!
+
+!FileServer class methodsFor: 'accessing'!
+
+commandLineSwitches
+	"Collect all methodnames from the 'accessing' protocol
+	 and select the ones with only one parameter.
+	 Then remove the ':' at the end of the name
+	 and add a '--' at the beginning.
+	 Additionally all uppercase letters are made lowercase and preceded by a '-'.
+	 Example: fallbackPage: becomes --fallback-page.
+	 Return the Array containing the commandline switches."
+	| switches |
+	switches := ((self methodsInProtocol: 'accessing') collect: [ :each | each selector]).
+	switches := switches select: [ :each | each match: '^[^:]*:$'].
+	switches :=switches collect: [ :each |
+		(each allButLast replace: '([A-Z])' with: '-$1') asLowercase replace: '^([a-z])' with: '--$1' ].
+	^ switches
+!
+
+defaultBasePath
+	^ './'
+!
+
+defaultHost
+	^ '127.0.0.1'
+!
+
+defaultMimeTypes
+	^ #{
+		'%' -> 'application/x-trash'.
+		'323' -> 'text/h323'.
+		'abw' -> 'application/x-abiword'.
+		'ai' -> 'application/postscript'.
+		'aif' -> 'audio/x-aiff'.
+		'aifc' -> 'audio/x-aiff'.
+		'aiff' -> 'audio/x-aiff'.
+		'alc' -> 'chemical/x-alchemy'.
+		'art' -> 'image/x-jg'.
+		'asc' -> 'text/plain'.
+		'asf' -> 'video/x-ms-asf'.
+		'asn' -> 'chemical/x-ncbi-asn1-spec'.
+		'aso' -> 'chemical/x-ncbi-asn1-binary'.
+		'asx' -> 'video/x-ms-asf'.
+		'au' -> 'audio/basic'.
+		'avi' -> 'video/x-msvideo'.
+		'b' -> 'chemical/x-molconn-Z'.
+		'bak' -> 'application/x-trash'.
+		'bat' -> 'application/x-msdos-program'.
+		'bcpio' -> 'application/x-bcpio'.
+		'bib' -> 'text/x-bibtex'.
+		'bin' -> 'application/octet-stream'.
+		'bmp' -> 'image/x-ms-bmp'.
+		'book' -> 'application/x-maker'.
+		'bsd' -> 'chemical/x-crossfire'.
+		'c' -> 'text/x-csrc'.
+		'c++' -> 'text/x-c++src'.
+		'c3d' -> 'chemical/x-chem3d'.
+		'cac' -> 'chemical/x-cache'.
+		'cache' -> 'chemical/x-cache'.
+		'cascii' -> 'chemical/x-cactvs-binary'.
+		'cat' -> 'application/vnd.ms-pki.seccat'.
+		'cbin' -> 'chemical/x-cactvs-binary'.
+		'cc' -> 'text/x-c++src'.
+		'cdf' -> 'application/x-cdf'.
+		'cdr' -> 'image/x-coreldraw'.
+		'cdt' -> 'image/x-coreldrawtemplate'.
+		'cdx' -> 'chemical/x-cdx'.
+		'cdy' -> 'application/vnd.cinderella'.
+		'cef' -> 'chemical/x-cxf'.
+		'cer' -> 'chemical/x-cerius'.
+		'chm' -> 'chemical/x-chemdraw'.
+		'chrt' -> 'application/x-kchart'.
+		'cif' -> 'chemical/x-cif'.
+		'class' -> 'application/java-vm'.
+		'cls' -> 'text/x-tex'.
+		'cmdf' -> 'chemical/x-cmdf'.
+		'cml' -> 'chemical/x-cml'.
+		'cod' -> 'application/vnd.rim.cod'.
+		'com' -> 'application/x-msdos-program'.
+		'cpa' -> 'chemical/x-compass'.
+		'cpio' -> 'application/x-cpio'.
+		'cpp' -> 'text/x-c++src'.
+		'cpt' -> 'image/x-corelphotopaint'.
+		'crl' -> 'application/x-pkcs7-crl'.
+		'crt' -> 'application/x-x509-ca-cert'.
+		'csf' -> 'chemical/x-cache-csf'.
+		'csh' -> 'text/x-csh'.
+		'csm' -> 'chemical/x-csml'.
+		'csml' -> 'chemical/x-csml'.
+		'css' -> 'text/css'.
+		'csv' -> 'text/comma-separated-values'.
+		'ctab' -> 'chemical/x-cactvs-binary'.
+		'ctx' -> 'chemical/x-ctx'.
+		'cu' -> 'application/cu-seeme'.
+		'cub' -> 'chemical/x-gaussian-cube'.
+		'cxf' -> 'chemical/x-cxf'.
+		'cxx' -> 'text/x-c++src'.
+		'dat' -> 'chemical/x-mopac-input'.
+		'dcr' -> 'application/x-director'.
+		'deb' -> 'application/x-debian-package'.
+		'dif' -> 'video/dv'.
+		'diff' -> 'text/plain'.
+		'dir' -> 'application/x-director'.
+		'djv' -> 'image/vnd.djvu'.
+		'djvu' -> 'image/vnd.djvu'.
+		'dl' -> 'video/dl'.
+		'dll' -> 'application/x-msdos-program'.
+		'dmg' -> 'application/x-apple-diskimage'.
+		'dms' -> 'application/x-dms'.
+		'doc' -> 'application/msword'.
+		'dot' -> 'application/msword'.
+		'dv' -> 'video/dv'.
+		'dvi' -> 'application/x-dvi'.
+		'dx' -> 'chemical/x-jcamp-dx'.
+		'dxr' -> 'application/x-director'.
+		'emb' -> 'chemical/x-embl-dl-nucleotide'.
+		'embl' -> 'chemical/x-embl-dl-nucleotide'.
+		'ent' -> 'chemical/x-pdb'.
+		'eps' -> 'application/postscript'.
+		'etx' -> 'text/x-setext'.
+		'exe' -> 'application/x-msdos-program'.
+		'ez' -> 'application/andrew-inset'.
+		'fb' -> 'application/x-maker'.
+		'fbdoc' -> 'application/x-maker'.
+		'fch' -> 'chemical/x-gaussian-checkpoint'.
+		'fchk' -> 'chemical/x-gaussian-checkpoint'.
+		'fig' -> 'application/x-xfig'.
+		'flac' -> 'application/x-flac'.
+		'fli' -> 'video/fli'.
+		'fm' -> 'application/x-maker'.
+		'frame' -> 'application/x-maker'.
+		'frm' -> 'application/x-maker'.
+		'gal' -> 'chemical/x-gaussian-log'.
+		'gam' -> 'chemical/x-gamess-input'.
+		'gamin' -> 'chemical/x-gamess-input'.
+		'gau' -> 'chemical/x-gaussian-input'.
+		'gcd' -> 'text/x-pcs-gcd'.
+		'gcf' -> 'application/x-graphing-calculator'.
+		'gcg' -> 'chemical/x-gcg8-sequence'.
+		'gen' -> 'chemical/x-genbank'.
+		'gf' -> 'application/x-tex-gf'.
+		'gif' -> 'image/gif'.
+		'gjc' -> 'chemical/x-gaussian-input'.
+		'gjf' -> 'chemical/x-gaussian-input'.
+		'gl' -> 'video/gl'.
+		'gnumeric' -> 'application/x-gnumeric'.
+		'gpt' -> 'chemical/x-mopac-graph'.
+		'gsf' -> 'application/x-font'.
+		'gsm' -> 'audio/x-gsm'.
+		'gtar' -> 'application/x-gtar'.
+		'h' -> 'text/x-chdr'.
+		'h++' -> 'text/x-c++hdr'.
+		'hdf' -> 'application/x-hdf'.
+		'hh' -> 'text/x-c++hdr'.
+		'hin' -> 'chemical/x-hin'.
+		'hpp' -> 'text/x-c++hdr'.
+		'hqx' -> 'application/mac-binhex40'.
+		'hs' -> 'text/x-haskell'.
+		'hta' -> 'application/hta'.
+		'htc' -> 'text/x-component'.
+		'htm' -> 'text/html'.
+		'html' -> 'text/html'.
+		'hxx' -> 'text/x-c++hdr'.
+		'ica' -> 'application/x-ica'.
+		'ice' -> 'x-conference/x-cooltalk'.
+		'ico' -> 'image/x-icon'.
+		'ics' -> 'text/calendar'.
+		'icz' -> 'text/calendar'.
+		'ief' -> 'image/ief'.
+		'iges' -> 'model/iges'.
+		'igs' -> 'model/iges'.
+		'iii' -> 'application/x-iphone'.
+		'inp' -> 'chemical/x-gamess-input'.
+		'ins' -> 'application/x-internet-signup'.
+		'iso' -> 'application/x-iso9660-image'.
+		'isp' -> 'application/x-internet-signup'.
+		'ist' -> 'chemical/x-isostar'.
+		'istr' -> 'chemical/x-isostar'.
+		'jad' -> 'text/vnd.sun.j2me.app-descriptor'.
+		'jar' -> 'application/java-archive'.
+		'java' -> 'text/x-java'.
+		'jdx' -> 'chemical/x-jcamp-dx'.
+		'jmz' -> 'application/x-jmol'.
+		'jng' -> 'image/x-jng'.
+		'jnlp' -> 'application/x-java-jnlp-file'.
+		'jpe' -> 'image/jpeg'.
+		'jpeg' -> 'image/jpeg'.
+		'jpg' -> 'image/jpeg'.
+		'js' -> 'application/javascript'.
+		'kar' -> 'audio/midi'.
+		'key' -> 'application/pgp-keys'.
+		'kil' -> 'application/x-killustrator'.
+		'kin' -> 'chemical/x-kinemage'.
+		'kpr' -> 'application/x-kpresenter'.
+		'kpt' -> 'application/x-kpresenter'.
+		'ksp' -> 'application/x-kspread'.
+		'kwd' -> 'application/x-kword'.
+		'kwt' -> 'application/x-kword'.
+		'latex' -> 'application/x-latex'.
+		'lha' -> 'application/x-lha'.
+		'lhs' -> 'text/x-literate-haskell'.
+		'lsf' -> 'video/x-la-asf'.
+		'lsx' -> 'video/x-la-asf'.
+		'ltx' -> 'text/x-tex'.
+		'lzh' -> 'application/x-lzh'.
+		'lzx' -> 'application/x-lzx'.
+		'm3u' -> 'audio/x-mpegurl'.
+		'm4a' -> 'audio/mpeg'.
+		'maker' -> 'application/x-maker'.
+		'man' -> 'application/x-troff-man'.
+		'mcif' -> 'chemical/x-mmcif'.
+		'mcm' -> 'chemical/x-macmolecule'.
+		'mdb' -> 'application/msaccess'.
+		'me' -> 'application/x-troff-me'.
+		'mesh' -> 'model/mesh'.
+		'mid' -> 'audio/midi'.
+		'midi' -> 'audio/midi'.
+		'mif' -> 'application/x-mif'.
+		'mm' -> 'application/x-freemind'.
+		'mmd' -> 'chemical/x-macromodel-input'.
+		'mmf' -> 'application/vnd.smaf'.
+		'mml' -> 'text/mathml'.
+		'mmod' -> 'chemical/x-macromodel-input'.
+		'mng' -> 'video/x-mng'.
+		'moc' -> 'text/x-moc'.
+		'mol' -> 'chemical/x-mdl-molfile'.
+		'mol2' -> 'chemical/x-mol2'.
+		'moo' -> 'chemical/x-mopac-out'.
+		'mop' -> 'chemical/x-mopac-input'.
+		'mopcrt' -> 'chemical/x-mopac-input'.
+		'mov' -> 'video/quicktime'.
+		'movie' -> 'video/x-sgi-movie'.
+		'mp2' -> 'audio/mpeg'.
+		'mp3' -> 'audio/mpeg'.
+		'mp4' -> 'video/mp4'.
+		'mpc' -> 'chemical/x-mopac-input'.
+		'mpe' -> 'video/mpeg'.
+		'mpeg' -> 'video/mpeg'.
+		'mpega' -> 'audio/mpeg'.
+		'mpg' -> 'video/mpeg'.
+		'mpga' -> 'audio/mpeg'.
+		'ms' -> 'application/x-troff-ms'.
+		'msh' -> 'model/mesh'.
+		'msi' -> 'application/x-msi'.
+		'mvb' -> 'chemical/x-mopac-vib'.
+		'mxu' -> 'video/vnd.mpegurl'.
+		'nb' -> 'application/mathematica'.
+		'nc' -> 'application/x-netcdf'.
+		'nwc' -> 'application/x-nwc'.
+		'o' -> 'application/x-object'.
+		'oda' -> 'application/oda'.
+		'odb' -> 'application/vnd.oasis.opendocument.database'.
+		'odc' -> 'application/vnd.oasis.opendocument.chart'.
+		'odf' -> 'application/vnd.oasis.opendocument.formula'.
+		'odg' -> 'application/vnd.oasis.opendocument.graphics'.
+		'odi' -> 'application/vnd.oasis.opendocument.image'.
+		'odm' -> 'application/vnd.oasis.opendocument.text-master'.
+		'odp' -> 'application/vnd.oasis.opendocument.presentation'.
+		'ods' -> 'application/vnd.oasis.opendocument.spreadsheet'.
+		'odt' -> 'application/vnd.oasis.opendocument.text'.
+		'ogg' -> 'application/ogg'.
+		'old' -> 'application/x-trash'.
+		'oth' -> 'application/vnd.oasis.opendocument.text-web'.
+		'oza' -> 'application/x-oz-application'.
+		'p' -> 'text/x-pascal'.
+		'p7r' -> 'application/x-pkcs7-certreqresp'.
+		'pac' -> 'application/x-ns-proxy-autoconfig'.
+		'pas' -> 'text/x-pascal'.
+		'pat' -> 'image/x-coreldrawpattern'.
+		'pbm' -> 'image/x-portable-bitmap'.
+		'pcf' -> 'application/x-font'.
+		'pcf.Z' -> 'application/x-font'.
+		'pcx' -> 'image/pcx'.
+		'pdb' -> 'chemical/x-pdb'.
+		'pdf' -> 'application/pdf'.
+		'pfa' -> 'application/x-font'.
+		'pfb' -> 'application/x-font'.
+		'pgm' -> 'image/x-portable-graymap'.
+		'pgn' -> 'application/x-chess-pgn'.
+		'pgp' -> 'application/pgp-signature'.
+		'pk' -> 'application/x-tex-pk'.
+		'pl' -> 'text/x-perl'.
+		'pls' -> 'audio/x-scpls'.
+		'pm' -> 'text/x-perl'.
+		'png' -> 'image/png'.
+		'pnm' -> 'image/x-portable-anymap'.
+		'pot' -> 'text/plain'.
+		'ppm' -> 'image/x-portable-pixmap'.
+		'pps' -> 'application/vnd.ms-powerpoint'.
+		'ppt' -> 'application/vnd.ms-powerpoint'.
+		'prf' -> 'application/pics-rules'.
+		'prt' -> 'chemical/x-ncbi-asn1-ascii'.
+		'ps' -> 'application/postscript'.
+		'psd' -> 'image/x-photoshop'.
+		'psp' -> 'text/x-psp'.
+		'py' -> 'text/x-python'.
+		'pyc' -> 'application/x-python-code'.
+		'pyo' -> 'application/x-python-code'.
+		'qt' -> 'video/quicktime'.
+		'qtl' -> 'application/x-quicktimeplayer'.
+		'ra' -> 'audio/x-realaudio'.
+		'ram' -> 'audio/x-pn-realaudio'.
+		'rar' -> 'application/rar'.
+		'ras' -> 'image/x-cmu-raster'.
+		'rd' -> 'chemical/x-mdl-rdfile'.
+		'rdf' -> 'application/rdf+xml'.
+		'rgb' -> 'image/x-rgb'.
+		'rm' -> 'audio/x-pn-realaudio'.
+		'roff' -> 'application/x-troff'.
+		'ros' -> 'chemical/x-rosdal'.
+		'rpm' -> 'application/x-redhat-package-manager'.
+		'rss' -> 'application/rss+xml'.
+		'rtf' -> 'text/rtf'.
+		'rtx' -> 'text/richtext'.
+		'rxn' -> 'chemical/x-mdl-rxnfile'.
+		'sct' -> 'text/scriptlet'.
+		'sd' -> 'chemical/x-mdl-sdfile'.
+		'sd2' -> 'audio/x-sd2'.
+		'sda' -> 'application/vnd.stardivision.draw'.
+		'sdc' -> 'application/vnd.stardivision.calc'.
+		'sdd' -> 'application/vnd.stardivision.impress'.
+		'sdf' -> 'chemical/x-mdl-sdfile'.
+		'sdp' -> 'application/vnd.stardivision.impress'.
+		'sdw' -> 'application/vnd.stardivision.writer'.
+		'ser' -> 'application/java-serialized-object'.
+		'sgf' -> 'application/x-go-sgf'.
+		'sgl' -> 'application/vnd.stardivision.writer-global'.
+		'sh' -> 'text/x-sh'.
+		'shar' -> 'application/x-shar'.
+		'shtml' -> 'text/html'.
+		'sid' -> 'audio/prs.sid'.
+		'sik' -> 'application/x-trash'.
+		'silo' -> 'model/mesh'.
+		'sis' -> 'application/vnd.symbian.install'.
+		'sit' -> 'application/x-stuffit'.
+		'skd' -> 'application/x-koan'.
+		'skm' -> 'application/x-koan'.
+		'skp' -> 'application/x-koan'.
+		'skt' -> 'application/x-koan'.
+		'smf' -> 'application/vnd.stardivision.math'.
+		'smi' -> 'application/smil'.
+		'smil' -> 'application/smil'.
+		'snd' -> 'audio/basic'.
+		'spc' -> 'chemical/x-galactic-spc'.
+		'spl' -> 'application/x-futuresplash'.
+		'src' -> 'application/x-wais-source'.
+		'stc' -> 'application/vnd.sun.xml.calc.template'.
+		'std' -> 'application/vnd.sun.xml.draw.template'.
+		'sti' -> 'application/vnd.sun.xml.impress.template'.
+		'stl' -> 'application/vnd.ms-pki.stl'.
+		'stw' -> 'application/vnd.sun.xml.writer.template'.
+		'sty' -> 'text/x-tex'.
+		'sv4cpio' -> 'application/x-sv4cpio'.
+		'sv4crc' -> 'application/x-sv4crc'.
+		'svg' -> 'image/svg+xml'.
+		'svgz' -> 'image/svg+xml'.
+		'sw' -> 'chemical/x-swissprot'.
+		'swf' -> 'application/x-shockwave-flash'.
+		'swfl' -> 'application/x-shockwave-flash'.
+		'sxc' -> 'application/vnd.sun.xml.calc'.
+		'sxd' -> 'application/vnd.sun.xml.draw'.
+		'sxg' -> 'application/vnd.sun.xml.writer.global'.
+		'sxi' -> 'application/vnd.sun.xml.impress'.
+		'sxm' -> 'application/vnd.sun.xml.math'.
+		'sxw' -> 'application/vnd.sun.xml.writer'.
+		't' -> 'application/x-troff'.
+		'tar' -> 'application/x-tar'.
+		'taz' -> 'application/x-gtar'.
+		'tcl' -> 'text/x-tcl'.
+		'tex' -> 'text/x-tex'.
+		'texi' -> 'application/x-texinfo'.
+		'texinfo' -> 'application/x-texinfo'.
+		'text' -> 'text/plain'.
+		'tgf' -> 'chemical/x-mdl-tgf'.
+		'tgz' -> 'application/x-gtar'.
+		'tif' -> 'image/tiff'.
+		'tiff' -> 'image/tiff'.
+		'tk' -> 'text/x-tcl'.
+		'tm' -> 'text/texmacs'.
+		'torrent' -> 'application/x-bittorrent'.
+		'tr' -> 'application/x-troff'.
+		'ts' -> 'text/texmacs'.
+		'tsp' -> 'application/dsptype'.
+		'tsv' -> 'text/tab-separated-values'.
+		'txt' -> 'text/plain'.
+		'udeb' -> 'application/x-debian-package'.
+		'uls' -> 'text/iuls'.
+		'ustar' -> 'application/x-ustar'.
+		'val' -> 'chemical/x-ncbi-asn1-binary'.
+		'vcd' -> 'application/x-cdlink'.
+		'vcf' -> 'text/x-vcard'.
+		'vcs' -> 'text/x-vcalendar'.
+		'vmd' -> 'chemical/x-vmd'.
+		'vms' -> 'chemical/x-vamas-iso14976'.
+		'vor' -> 'application/vnd.stardivision.writer'.
+		'vrm' -> 'x-world/x-vrml'.
+		'vrml' -> 'x-world/x-vrml'.
+		'vsd' -> 'application/vnd.visio'.
+		'wad' -> 'application/x-doom'.
+		'wav' -> 'audio/x-wav'.
+		'wax' -> 'audio/x-ms-wax'.
+		'wbmp' -> 'image/vnd.wap.wbmp'.
+		'wbxml' -> 'application/vnd.wap.wbxml'.
+		'wk' -> 'application/x-123'.
+		'wm' -> 'video/x-ms-wm'.
+		'wma' -> 'audio/x-ms-wma'.
+		'wmd' -> 'application/x-ms-wmd'.
+		'wml' -> 'text/vnd.wap.wml'.
+		'wmlc' -> 'application/vnd.wap.wmlc'.
+		'wmls' -> 'text/vnd.wap.wmlscript'.
+		'wmlsc' -> 'application/vnd.wap.wmlscriptc'.
+		'wmv' -> 'video/x-ms-wmv'.
+		'wmx' -> 'video/x-ms-wmx'.
+		'wmz' -> 'application/x-ms-wmz'.
+		'wp5' -> 'application/wordperfect5.1'.
+		'wpd' -> 'application/wordperfect'.
+		'wrl' -> 'x-world/x-vrml'.
+		'wsc' -> 'text/scriptlet'.
+		'wvx' -> 'video/x-ms-wvx'.
+		'wz' -> 'application/x-wingz'.
+		'xbm' -> 'image/x-xbitmap'.
+		'xcf' -> 'application/x-xcf'.
+		'xht' -> 'application/xhtml+xml'.
+		'xhtml' -> 'application/xhtml+xml'.
+		'xlb' -> 'application/vnd.ms-excel'.
+		'xls' -> 'application/vnd.ms-excel'.
+		'xlt' -> 'application/vnd.ms-excel'.
+		'xml' -> 'application/xml'.
+		'xpi' -> 'application/x-xpinstall'.
+		'xpm' -> 'image/x-xpixmap'.
+		'xsl' -> 'application/xml'.
+		'xtel' -> 'chemical/x-xtel'.
+		'xul' -> 'application/vnd.mozilla.xul+xml'.
+		'xwd' -> 'image/x-xwindowdump'.
+		'xyz' -> 'chemical/x-xyz'.
+		'zip' -> 'application/zip'.
+		'zmt' -> 'chemical/x-mopac-input'.
+		'~' -> 'application/x-trash'
+	}
+!
+
+defaultPort
+	^ 4000
+!
+
+mimeTypeFor: aString
+	^ self mimeTypes at: (aString replace: '.*[\.]' with: '') ifAbsent: ['text/plain']
+!
+
+mimeTypes
+	^ mimeTypes ifNil: [mimeTypes := self defaultMimeTypes]
+!
+
+printHelp
+	console log: 'Available commandline options are:'.
+	console log: '--help'.
+	self commandLineSwitches do: [ :each |
+		console log: each, ' <parameter>']
+!
+
+selectorForCommandLineSwitch: aSwitch
+	"Remove the trailing '--', add ':' at the end
+	 and replace all occurences of a lowercase letter preceded by a '-' with
+	 the Uppercase letter.
+	 Example: --fallback-page becomes fallbackPage:"
+	^ ((aSwitch replace: '^--' with: '')
+		replace: '-[a-z]' with: [ :each | each second asUppercase ]), ':'
+! !
+
+!FileServer class methodsFor: 'initialization'!
+
+createServerWithArguments: options
+	"If options are empty return a default FileServer instance.
+	 If options are given loop through them and set the passed in values
+	 on the FileServer instance.
+	 
+	 Commanline options map directly to methods in the 'accessing' protocol
+	 taking one parameter.
+	 Adding a method to this protocol makes it directly settable through
+	 command line options.
+	 "
+	| server popFront front optionName optionValue switches |
+
+	switches := self commandLineSwitches.
+
+	server := self new.
+
+	options ifEmpty: [^server].
+
+	(options size even) ifFalse: [
+		console log: 'Using default parameters.'.
+		console log: 'Wrong commandline options or not enough arguments for: ' , options.
+		console log: 'Use any of the following ones: ', switches.
+		^server].
+
+	popFront := [:args |
+		front := args first.
+		args remove: front.
+		front].
+
+	[options notEmpty] whileTrue: [
+		optionName  := popFront value: options.
+		optionValue := popFront value: options.
+
+		(switches includes: optionName) ifTrue: [
+			optionName := self selectorForCommandLineSwitch: optionName.
+			server perform: optionName withArguments: (Array with: optionValue)]
+			ifFalse: [
+				console log: optionName, ' is not a valid commandline option'.
+				console log: 'Use any of the following ones: ', switches ]].
+	^ server.
+!
+
+main
+	"Main entry point for Amber applications.
+	 Creates and starts a FileServer instance."
+	| fileServer args |
+	args := process argv.
+	"Remove the first args which contain the path to the node executable and the script file."
+	args removeFrom: 1 to: 3.
+
+	args detect: [ :each |
+		(each = '--help') ifTrue: [FileServer printHelp]]
+	ifNone: [
+		fileServer := FileServer createServerWithArguments: args.
+		^ fileServer start]
+! !
+
+Object subclass: #Initer
+	instanceVariableNames: 'path childProcess nmPath'
+	package: 'AmberCli'!
+
+!Initer methodsFor: 'action'!
+
+bowerInstallThenDo: aBlock
+	| child |
+	child := childProcess
+		exec: (path join: nmPath with: '.bin' with: 'bower'), ' install'
+		thenDo: aBlock.
+	child stdout pipe: process stdout options: #{ 'end' -> false }
+!
+
+gruntInitThenDo: aBlock
+	| child |
+	child := childProcess
+		exec: (path join: nmPath with: '.bin' with: 'grunt-init'), ' ', (((path join: nmPath with: 'grunt-init-amber') replace: '\\' with: '\\') replace: ':' with: '\:')
+		thenDo: aBlock.
+	child stdout pipe: process stdout options: #{ 'end' -> false }.
+	process stdin resume.
+	process stdin pipe: child stdin options: #{ 'end' -> false }
+!
+
+start
+	self gruntInitThenDo: [ :error |
+		error ifNotNil: [ console log: 'grunt-init exec error:'; log: error. process exit ]
+		ifNil: [
+			self bowerInstallThenDo: [ :error2 |
+				error2 ifNotNil: [ console log: 'bower install exec error:'; log: error2 ].
+				process exit ]]]
+! !
+
+!Initer methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	path := require value: 'path'.
+	childProcess := require value: 'child_process'.
+	nmPath := path join: self rootDirname with: 'node_modules'
+! !
+
+!Initer methodsFor: 'private'!
+
+dirname
+	<return __dirname>
+!
+
+rootDirname
+	^ path join: self dirname with: '..'
+! !
+
+Object subclass: #NodeTestRunner
+	instanceVariableNames: ''
+	package: 'AmberCli'!
+
+!NodeTestRunner class methodsFor: 'not yet classified'!
+
+runTestSuite
+	| suite worker |
+
+	suite := OrderedCollection new.
+	(TestCase allSubclasses select: [ :each | each isAbstract not ])
+		do: [ :each | suite addAll: each buildSuite ].
+
+	worker := TestSuiteRunner on: suite.
+	worker announcer on: ResultAnnouncement do:
+		[ :ann | | result |
+			result := ann result.
+			result runs = result total ifTrue: [
+				console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.
+
+				result failures isEmpty ifFalse: [
+					result failures first runCase.
+					"the line above should throw, normally, but just in case I leave the line below"
+					self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!!!' ].
+				result errors isEmpty ifFalse: [
+					result errors first runCase.
+					"the line above should throw, normally, but just in case I leave the line below"
+					self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!!!!' ].
+	]].
+	worker run
+! !
+
+Object subclass: #Repl
+	instanceVariableNames: 'readline interface util session resultCount commands'
+	package: 'AmberCli'!
+!Repl commentStamp!
+I am a class representing a REPL (Read Evaluate Print Loop) and provide a command line interface to Amber Smalltalk.
+On the prompt you can type Amber statements which will be evaluated after pressing <Enter>.
+The evaluation is comparable with executing a 'DoIt' in a workspace.
+
+My runtime requirement is a functional Node.js executable with working Readline support.!
+
+!Repl methodsFor: 'accessing'!
+
+commands
+	^ commands
+!
+
+prompt
+	^ 'amber >> '
+! !
+
+!Repl methodsFor: 'actions'!
+
+clearScreen
+	| esc cls |
+	esc := String fromCharCode: 27.
+	cls := esc, '[2J', esc, '[0;0f'.
+	process stdout write: cls.
+	interface prompt
+!
+
+close
+	process stdin destroy
+!
+
+createInterface
+	interface := readline createInterface: process stdin stdout: process stdout.
+	interface on: 'line' do: [:buffer | self processLine: buffer].
+	interface on: 'close' do: [self close].
+	self printWelcome; setupHotkeys; setPrompt.
+	interface prompt
+!
+
+eval: buffer
+	^ self eval: buffer on: DoIt new.
+!
+
+eval: buffer on: anObject
+	| result |
+	buffer isEmpty ifFalse: [
+		[result := Compiler new evaluateExpression: buffer on: anObject]
+			tryCatch: [:e |
+				e isSmalltalkError
+				    ifTrue: [ e resignal ]
+			 	   ifFalse: [ process stdout write: e jsStack ]]].
+	^ result
+!
+
+printWelcome
+	Transcript show: 'Type :q to exit.'; cr.
+!
+
+setPrompt
+	interface setPrompt: self prompt
+! !
+
+!Repl methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	session := DoIt new.
+	readline := require value: 'readline'.
+	util := require value: 'util'.
+	self setupCommands
+!
+
+setupCommands
+	commands := Dictionary from: {
+		{':q'} -> [process exit].
+		{''} -> [interface prompt]}
+!
+
+setupHotkeys
+	process stdin on: 'keypress' do: [:s :key | key ifNotNil: [self onKeyPress: key]].
+! !
+
+!Repl methodsFor: 'private'!
+
+addVariableNamed: aString to: anObject
+	| newClass newObject |
+	newClass := self subclass: anObject class withVariable: aString.
+	self encapsulateVariable: aString withValue: anObject in: newClass.
+	newObject := newClass new.
+	self setPreviousVariablesFor: newObject from: anObject.
+	^ newObject
+!
+
+assignNewVariable: buffer do: aBlock
+	"Assigns a new variable and calls the given block with the variable's name and value
+	 if buffer contains an assignment expression. If it doesn't the block is called with nil for
+	 both arguments."
+	^ self parseAssignment: buffer do: [ :name :expr || varName value |
+		varName := name ifNil: [self nextResultName].
+		session := self addVariableNamed: varName to: session.
+		[ value := self eval: varName, ' := ', (expr ifNil: [buffer]) on: session ]
+			on: Error
+			do: [ :e | ConsoleErrorHandler new logError: e. value := nil].
+		aBlock value: varName value: value]
+!
+
+encapsulateVariable: aString withValue: anObject in: aClass
+	"Add getter and setter for given variable to session."
+	| compiler |
+	compiler := Compiler new.
+	compiler install: aString, ': anObject ^ ', aString, ' := anObject' forClass: aClass protocol: 'session'.
+	compiler install: aString, ' ^ ', aString forClass: aClass protocol: 'session'.
+!
+
+executeCommand: aString
+	"Tries to process the given string as a command. Returns true if it was a command, false if not."
+	self commands keysAndValuesDo: [:names :cmd |
+		(names includes: aString) ifTrue: [
+			cmd value.
+			^ true]].
+	^ false
+!
+
+instanceVariableNamesFor: aClass
+	"Yields all instance variable names for the given class, including inherited ones."
+	^ aClass superclass
+		ifNotNil: [
+			aClass instanceVariableNames copyWithAll: (self instanceVariableNamesFor: aClass superclass)]
+		ifNil: [
+			aClass instanceVariableNames]
+!
+
+isIdentifier: aString
+	^ aString match: '^[a-z_]\w*$' asRegexp
+!
+
+isVariableDefined: aString
+	^ (self instanceVariableNamesFor: session class) includes: aString
+!
+
+nextResultName
+	resultCount := resultCount
+    	ifNotNil: [resultCount + 1]
+    	ifNil: [1].
+    ^ 'res', resultCount asString
+!
+
+onKeyPress: key
+	(key ctrl and: [key name = 'l'])
+		ifTrue: [self clearScreen]
+!
+
+parseAssignment: aString do: aBlock
+	"Assigns a new variable if the given string is an assignment expression. Calls the given block with name and value.
+	 If the string is not one no variable will be assigned and the block will be called with nil for both arguments."
+	| assignment |
+	assignment := (aString tokenize: ':=') collect: [:s | s trimBoth].
+	^ (assignment size = 2 and: [self isIdentifier: assignment first])
+		ifTrue: [ aBlock value: assignment first value: assignment last ]
+		ifFalse: [ aBlock value: nil value: nil ]
+!
+
+presentResultNamed: varName withValue: value
+	Transcript show: varName, ': ', value class name, ' = ', value asString; cr.
+	interface prompt
+!
+
+processLine: buffer
+	"Processes lines entered through the readline interface."
+	| show |
+	show := [:varName :value | self presentResultNamed: varName withValue: value].
+	(self executeCommand: buffer) ifFalse: [
+		(self isVariableDefined: buffer)
+			ifTrue: [show value: buffer value: (session perform: buffer)]
+			ifFalse: [self assignNewVariable: buffer do: show]]
+!
+
+setPreviousVariablesFor: newObject from: oldObject
+	(self instanceVariableNamesFor: oldObject class) do: [:each |
+		newObject perform: each, ':' withArguments: {oldObject perform: each}].
+!
+
+subclass: aClass withVariable: varName
+	"Create subclass with new variable."
+	^ ClassBuilder new
+		addSubclassOf: aClass
+		named: (self subclassNameFor: aClass) asSymbol
+		instanceVariableNames: {varName}
+		package: 'Compiler-Core'
+!
+
+subclassNameFor: aClass
+	^ (aClass name matchesOf: '\d+$')
+		ifNotNil: [ | counter |
+			counter := (aClass name matchesOf: '\d+$') first asNumber + 1.
+			aClass name replaceRegexp: '\d+$' asRegexp with: counter asString]
+		ifNil: [
+			aClass name, '2'].
+! !
+
+!Repl class methodsFor: 'initialization'!
+
+main
+	self new createInterface
+! !
+

File diff suppressed because it is too large
+ 51977 - 0
external/amber-cli/support/amber-cli.js


+ 197 - 0
external/amber-cli/support/amberc-cli.js

@@ -0,0 +1,197 @@
+#!/usr/bin/env node
+
+var path = require('path');
+var amberc = require('amber-dev/lib/amberc');
+
+// get parameters passed to the command line script
+// discard the first two parameters which are the node binary and the script name
+var parameters = process.argv.slice(2);
+
+// check if at least one parameter was passed to the script
+if (1 > parameters.length) {
+	print_usage_and_exit();
+}
+
+
+// Get Amber root directory from the location of this script so that
+// we can find the st and js directories etc.
+var amber_dir = path.normalize(path.join(__dirname, '..', '..', 'node_modules', 'amber'));
+
+var configuration = handle_options(parameters);
+
+var compiler = new amberc.Compiler(amber_dir);
+
+compiler.main(configuration);
+
+
+/**
+ * Process given program options and update defaults values.
+ * Followed by check_for_closure_compiler() and then collect_files().
+ */
+function handle_options(optionsArray) {
+	var programName = [];
+	var currentItem = optionsArray.shift();
+	var defaults = amberc.createDefaultConfiguration();
+
+	while(undefined !== currentItem) {
+		switch(currentItem) {
+			case '-l':
+				defaults.load.push.apply(defaults.load, optionsArray.shift().split(','));
+				break;
+			case '-L':
+				defaults.jsLibraryDirs.push.apply(defaults.jsLibraryDirs, optionsArray.shift().split(','));
+				break;
+			case '-g':
+				defaults.jsGlobals.push.apply(defaults.jsGlobals, optionsArray.shift().split(','));
+				break;
+			case '-m':
+				defaults.main = optionsArray.shift();
+				break;
+			case '-M':
+				defaults.mainfile = optionsArray.shift();
+				break;
+			case '-n':
+				defaults.amd_namespace = optionsArray.shift();
+				break;
+			case '-D':
+				defaults.output_dir = optionsArray.shift();
+				break;
+			case '-d':
+				amber_dir = path.normalize(optionsArray.shift());
+				break;
+			case '-s':
+				defaults.suffix = optionsArray.shift();
+				defaults.suffix_used = defaults.suffix;
+				break;
+			case '-S':
+				defaults.loadsuffix = optionsArray.shift();
+				defaults.suffix_used = defaults.suffix;
+				break;
+			case '-v':
+				defaults.verbose = true;
+				break;
+			case '-h':
+			case '--help':
+			case '?':
+				print_usage_and_exit();
+				break;
+			default:
+				var fileSuffix = path.extname(currentItem);
+				switch (fileSuffix) {
+					case '.st':
+						defaults.stFiles.push(currentItem);
+						break;
+					case '.js':
+						defaults.jsFiles.push(currentItem);
+						break;
+					default:
+						// Will end up being the last non js/st argument
+						programName.push(currentItem);
+						break;
+				}
+		}
+		currentItem = optionsArray.shift();
+	}
+
+	if(1 < programName.length) {
+		throw new Error('More than one name for ProgramName given: ' + programName);
+	} else {
+		defaults.program = programName[0];
+	}
+	return defaults;
+}
+
+
+// print available flags
+function print_usage_and_exit() {
+	var usage = [
+		'Usage: amberc [-l lib1,lib2...] [-g jsGlobal1,jsGlobla2] [-m main_class] [-M main_file]',
+		'          [-n namespace] [-D output_dir] [-v] [-s suffix] [-S suffix] [file1 [file2 ...]] [Program]',
+		'',
+		'   amberc compiles Amber files - either separately or into a complete runnable',
+		'   program. If no .st files are listed only a linking stage is performed.',
+		'   Files listed will be handled using the following rules:',
+		'',
+		'   *.js',
+		'     Files are linked (concatenated) in listed order.',
+		'     If not found we look in $AMBER/src/',
+		'',
+		'   *.st',
+		'     Files are compiled into .js files before concatenation.',
+		'     If not found we look in $AMBER/src/',
+		'',
+		'     NOTE: Each .st file is currently considered to be a fileout of a single class',
+		'     category of the same name as the file!',
+		'',
+		'   If no <Program> is specified each given .st file will be compiled into',
+		'   a matching .js file. Otherwise a <Program>.js file is linked together based on',
+		'   the given options:',
+		'',
+		'  -l library1,library2',
+		'     Add listed JavaScript libraries in listed order.',
+		'     Libraries are not separated by spaces or end with .js.',
+		'',
+		'  -L directory1,directory2',
+		'     Add listed directories to the library search path.',
+		'     The order of processing is:',
+		'     1. current directory',
+		'     2. directories specified by -L',
+		'     3. $AMBER',
+		'',
+		'  -g jsGlobal1,jsGlobal2',
+		'     Comma separated list of JS global variable names.',
+		'     The names are added to a list containing "window", "document" and others.',
+		'',
+		'  -m main_class',
+		'     Add a call to the class method main_class>>main at the end of <Program>.',
+		'',
+		'  -M main_file',
+		'     Add <main_file> at the end of <Program.js> acting as #main.',
+		'',
+		'  -n amd_namespace',
+		'     Export packages with <amd_namespace> as the require.js namespace.',
+		'     Default value is "amber_core".',
+		'',
+		'  -v',
+		'     Produce a more verbose output.',
+		'',
+		'  -D',
+		'     Specifies the output directory for all generated .js files.',
+		'     The hierarchy of the input files is not maintaned.',
+		'     If this option is omitted all generated .js files are placed next to their input files',
+		'',
+		'  -d',
+		'     Specifies the alternate directory to look for Amber files.',
+		'     If not specified, the version embedded in CLI is used..',
+		'',
+		'  -s suffix',
+		'     Add <suffix> to compiled .js files. File.st is then compiled into',
+		'     File.<suffix>.js.',
+		'',
+		'  -S suffix',
+		'     Use <suffix> for all libraries accessed using -l. This makes it possible',
+		'     to have multiple flavors of Amber and libraries in the same place.',
+		'',
+		'',
+		'     Example invocations:',
+		'',
+		'     Just compile Kernel-Objects.st to Kernel-Objects.js:',
+		'',
+		'        amberc Kernel-Objects.st',
+		'',
+		'     Compile Hello.st to Hello.js and create complete program called Program.js.',
+		'     Additionally add a call to the class method Hello>>main:',
+		'',
+		'        amberc -m Hello Hello.st Program',
+		'',
+		'     Compile Cat1.st and Cat2.st files into corresponding .js files.',
+		'     Link them with myboot.js and myKernel.js',
+		'     and merge everything into a complete program named Program.js:',
+		'',
+		'        amberc -M main.js myboot.js myKernel.js Cat1.st Cat2.st Program',
+	];
+	usage.forEach(function (line) {
+		console.log(line);
+	});
+	process.exit();
+}

+ 143 - 0
external/amber-dev/lib/Test.js

@@ -0,0 +1,143 @@
+define("amber_core/Test", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+smalltalk.addPackage('Test');
+smalltalk.packages["Test"].transport = {"type":"amd","amdNamespace":"amber_core"};
+
+smalltalk.addClass('NodeTestRunner', globals.Object, [], 'Test');
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "main",
+protocol: 'not yet classified',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._runTestSuite();
+return self}, function($ctx1) {$ctx1.fill(self,"main",{},globals.NodeTestRunner.klass)})},
+args: [],
+source: "main\x0a\x09self runTestSuite",
+messageSends: ["runTestSuite"],
+referencedClasses: []
+}),
+globals.NodeTestRunner.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "runTestSuite",
+protocol: 'not yet classified',
+fn: function (){
+var self=this;
+var suite,worker;
+function $OrderedCollection(){return globals.OrderedCollection||(typeof OrderedCollection=="undefined"?nil:OrderedCollection)}
+function $TestCase(){return globals.TestCase||(typeof TestCase=="undefined"?nil:TestCase)}
+function $TestSuiteRunner(){return globals.TestSuiteRunner||(typeof TestSuiteRunner=="undefined"?nil:TestSuiteRunner)}
+function $ResultAnnouncement(){return globals.ResultAnnouncement||(typeof ResultAnnouncement=="undefined"?nil:ResultAnnouncement)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$3,$9,$8,$12,$11,$10,$7,$6,$15,$14,$13,$5,$4,$17,$16,$19,$18,$26,$25,$24,$23,$22,$28,$27,$21,$20,$30,$29,$32,$31,$39,$38,$37,$36,$35,$34,$33;
+suite=_st($OrderedCollection())._new();
+_st(_st(_st($TestCase())._allSubclasses())._select_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(each)._isAbstract())._not();
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})})))._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(suite)._addAll_(_st(each)._buildSuite());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
+worker=_st($TestSuiteRunner())._on_(suite);
+_st(_st(worker)._announcer())._on_do_($ResultAnnouncement(),(function(ann){
+var result;
+return smalltalk.withContext(function($ctx2) {
+result=_st(ann)._result();
+result;
+$2=_st(result)._runs();
+$ctx2.sendIdx["runs"]=1;
+$1=_st($2).__eq(_st(result)._total());
+if(smalltalk.assert($1)){
+$3=console;
+$9=_st(_st(result)._runs())._asString();
+$ctx2.sendIdx["asString"]=1;
+$8=_st($9).__comma(" tests run, ");
+$ctx2.sendIdx[","]=5;
+$12=_st(result)._failures();
+$ctx2.sendIdx["failures"]=1;
+$11=_st($12)._size();
+$ctx2.sendIdx["size"]=1;
+$10=_st($11)._asString();
+$ctx2.sendIdx["asString"]=2;
+$7=_st($8).__comma($10);
+$ctx2.sendIdx[","]=4;
+$6=_st($7).__comma(" failures, ");
+$ctx2.sendIdx[","]=3;
+$15=_st(result)._errors();
+$ctx2.sendIdx["errors"]=1;
+$14=_st($15)._size();
+$13=_st($14)._asString();
+$5=_st($6).__comma($13);
+$ctx2.sendIdx[","]=2;
+$4=_st($5).__comma(" errors.");
+$ctx2.sendIdx[","]=1;
+_st($3)._log_($4);
+$17=_st(result)._failures();
+$ctx2.sendIdx["failures"]=2;
+$16=_st($17)._isEmpty();
+$ctx2.sendIdx["isEmpty"]=1;
+if(! smalltalk.assert($16)){
+$19=_st(result)._failures();
+$ctx2.sendIdx["failures"]=3;
+$18=_st($19)._first();
+$ctx2.sendIdx["first"]=1;
+_st($18)._runCase();
+$ctx2.sendIdx["runCase"]=1;
+$26=_st(result)._failures();
+$ctx2.sendIdx["failures"]=4;
+$25=_st($26)._first();
+$ctx2.sendIdx["first"]=2;
+$24=_st($25)._class();
+$ctx2.sendIdx["class"]=1;
+$23=_st($24)._name();
+$ctx2.sendIdx["name"]=1;
+$22=_st($23).__comma(" >> ");
+$ctx2.sendIdx[","]=8;
+$28=_st(_st(result)._failures())._first();
+$ctx2.sendIdx["first"]=3;
+$27=_st($28)._selector();
+$ctx2.sendIdx["selector"]=1;
+$21=_st($22).__comma($27);
+$ctx2.sendIdx[","]=7;
+$20=_st($21).__comma(" is failing!");
+$ctx2.sendIdx[","]=6;
+self._throw_($20);
+$ctx2.sendIdx["throw:"]=1;
+};
+$30=_st(result)._errors();
+$ctx2.sendIdx["errors"]=2;
+$29=_st($30)._isEmpty();
+if(! smalltalk.assert($29)){
+$32=_st(result)._errors();
+$ctx2.sendIdx["errors"]=3;
+$31=_st($32)._first();
+$ctx2.sendIdx["first"]=4;
+_st($31)._runCase();
+$39=_st(result)._errors();
+$ctx2.sendIdx["errors"]=4;
+$38=_st($39)._first();
+$ctx2.sendIdx["first"]=5;
+$37=_st($38)._class();
+$36=_st($37)._name();
+$35=_st($36).__comma(" >> ");
+$34=_st($35).__comma(_st(_st(_st(result)._errors())._first())._selector());
+$ctx2.sendIdx[","]=10;
+$33=_st($34).__comma(" has errors!");
+$ctx2.sendIdx[","]=9;
+return self._throw_($33);
+};
+};
+}, function($ctx2) {$ctx2.fillBlock({ann:ann,result:result},$ctx1,3)})}));
+_st(worker)._run();
+return self}, function($ctx1) {$ctx1.fill(self,"runTestSuite",{suite:suite,worker:worker},globals.NodeTestRunner.klass)})},
+args: [],
+source: "runTestSuite\x0a\x09| suite worker |\x0a\x0a\x09suite := OrderedCollection new.\x0a    (TestCase allSubclasses select: [ :each | each isAbstract not ])\x0a\x09do: [ :each | suite addAll: each buildSuite ].\x0a\x0a\x09worker := TestSuiteRunner on: suite.\x0a\x09worker announcer on: ResultAnnouncement do:\x0a\x09[ :ann | | result |\x0a    \x09result := ann result.\x0a        result runs = result total ifTrue: [\x0a\x09        console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.\x0a\x0a            result failures isEmpty ifFalse: [\x0a                result failures first runCase.\x0a                \x22the line above should throw, normally, but just in case I leave the line below\x22\x0a                self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!' ].\x0a            result errors isEmpty ifFalse: [\x0a                result errors first runCase.\x0a                \x22the line above should throw, normally, but just in case I leave the line below\x22\x0a                self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!' ].\x0a    ]].\x0a    worker run",
+messageSends: ["new", "do:", "select:", "allSubclasses", "not", "isAbstract", "addAll:", "buildSuite", "on:", "on:do:", "announcer", "result", "ifTrue:", "=", "runs", "total", "log:", ",", "asString", "size", "failures", "errors", "ifFalse:", "isEmpty", "runCase", "first", "throw:", "name", "class", "selector", "run"],
+referencedClasses: ["OrderedCollection", "TestCase", "TestSuiteRunner", "ResultAnnouncement"]
+}),
+globals.NodeTestRunner.klass);
+
+});

+ 37 - 0
external/amber-dev/lib/Test.st

@@ -0,0 +1,37 @@
+Smalltalk createPackage: 'Test'!
+Object subclass: #NodeTestRunner
+	instanceVariableNames: ''
+	package: 'Test'!
+
+!NodeTestRunner class methodsFor: 'not yet classified'!
+
+main
+	self runTestSuite
+!
+
+runTestSuite
+	| suite worker |
+
+	suite := OrderedCollection new.
+    (TestCase allSubclasses select: [ :each | each isAbstract not ])
+	do: [ :each | suite addAll: each buildSuite ].
+
+	worker := TestSuiteRunner on: suite.
+	worker announcer on: ResultAnnouncement do:
+	[ :ann | | result |
+    	result := ann result.
+        result runs = result total ifTrue: [
+	        console log: result runs asString, ' tests run, ', result failures size asString, ' failures, ', result errors size asString, ' errors.'.
+
+            result failures isEmpty ifFalse: [
+                result failures first runCase.
+                "the line above should throw, normally, but just in case I leave the line below"
+                self throw: result failures first class name, ' >> ', result failures first selector, ' is failing!!' ].
+            result errors isEmpty ifFalse: [
+                result errors first runCase.
+                "the line above should throw, normally, but just in case I leave the line below"
+                self throw: result errors first class name, ' >> ', result errors first selector, ' has errors!!' ].
+    ]].
+    worker run
+! !
+

+ 595 - 0
external/amber-dev/lib/amberc.js

@@ -0,0 +1,595 @@
+/**
+ * This is a "compiler" for Amber code.
+ * Put the following code into compiler.js:
+ *     var amberc = require('amberc');
+ *     var compiler = new amberc.Compiler('path/to/amber');
+ *     var options = amberc.createDefaults();
+ *     // edit options entries
+ *     compiler.main(options);
+ */
+
+/**
+ * Helper for concatenating Amber generated AMD modules.
+ * The produced output can be exported and run as an independent program.
+ *
+ * var concatenator = createConcatenator();
+ * concatenator.start(); // write the required AMD define header
+ * concatenator.add(module1);
+ * concatenator.addId(module1_ID);
+ * //...
+ * concatenator.finish("//some last code");
+ * var concatenation = concatenator.toString();
+ * // The variable concatenation contains the concatenated result
+ * // which can either be stored in a file or interpreted with eval().
+ */
+function createConcatenator () {
+	return {
+		elements: [],
+		ids: [],
+		add: function () {
+			this.elements.push.apply(this.elements, arguments);
+		},
+		addId: function () {
+			this.ids.push.apply(this.ids, arguments);
+		},
+		forEach: function () {
+			this.elements.forEach.apply(this.elements, arguments);
+		},
+		start: function () {
+			this.add(
+				'var define = (' + require('amdefine') + ')(null, function (id) { throw new Error("Dependency not found: " +  id); }), requirejs = define.require;',
+				'define("amber_vm/browser-compatibility", [], {});',
+				'define("amber/browser-compatibility", [], {});'
+			);
+		},
+		finish: function (realWork) {
+			this.add(
+				'define("amber/_init", ["' + this.ids.join('","') + '"], function (boot) {',
+				'boot.vm.initialize();',
+				realWork,
+				'});',
+				'requirejs("amber/_init");'
+			);
+		},
+		toString: function () {
+			return this.elements.join('\n');
+		}
+	};
+}
+
+
+var path = require('path'),
+	fs = require('fs'),
+	Promise = require('es6-promise').Promise;
+
+/**
+ * AmberCompiler constructor function.
+ * amber_dir: points to the location of an amber installation
+ */
+function AmberCompiler(amber_dir) {
+	if (undefined === amber_dir || !fs.existsSync(amber_dir)) {
+		throw new Error('amber_dir needs to be a valid directory');
+	}
+
+	this.amber_dir = amber_dir;
+	// Important: in next list, boot MUST be first
+	this.kernel_libraries = ['boot', 'smalltalk', 'globals', 'nil', '_st', 'Kernel-Objects', 'Kernel-Classes', 'Kernel-Methods',
+							'Kernel-Collections', 'Kernel-Infrastructure', 'Kernel-Exceptions', 'Kernel-Transcript',
+							'Kernel-Announcements'];
+	this.compiler_libraries = this.kernel_libraries.concat(['parser', 'Kernel-ImportExport', 'Compiler-Exceptions',
+							'Compiler-Core', 'Compiler-AST', 'Compiler-Exceptions', 'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic']);
+}
+
+
+/**
+ * Default values.
+ */
+var createDefaultConfiguration = function() {
+	return {
+		'load': [],
+		'main': undefined,
+		'mainfile': undefined,
+		'stFiles': [],
+		'jsFiles': [],
+		'jsGlobals': [],
+		'amd_namespace': 'amber_core',
+		'suffix': '',
+		'loadsuffix': '',
+		'suffix_used': '',
+		'libraries': [],
+		'jsLibraryDirs': [],
+		'compile': [],
+		'compiled': [],
+		'program': undefined,
+		'output_dir': undefined,
+		'verbose': false
+	};
+};
+
+
+/**
+ * Main function for executing the compiler.
+ * If check_configuration_ok() returns successfully
+ * the configuration is used to trigger the following compilation steps.
+ */
+AmberCompiler.prototype.main = function(configuration, finished_callback) {
+	console.time('Compile Time');
+
+	if (configuration.amd_namespace.length === 0) {
+		configuration.amd_namespace = 'amber_core';
+	}
+
+	if (undefined !== configuration.jsLibraryDirs) {
+		configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'src'));
+		configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'support'));
+		configuration.jsLibraryDirs.push(path.join(this.amber_dir, 'support', 'deprecated-vm-files'));
+	}
+
+	console.ambercLog = console.log;
+	if (false === configuration.verbose) {
+		console.log = function() {};
+	}
+
+	// the evaluated compiler will be stored in this variable (see create_compiler)
+	configuration.vm = {};
+	configuration.globals = {};
+	configuration.kernel_libraries = this.kernel_libraries;
+	configuration.compiler_libraries = this.compiler_libraries;
+	configuration.amber_dir = this.amber_dir;
+
+	check_configuration(configuration)
+	.then(collect_st_files)
+	.then(collect_js_files)
+	.then(resolve_kernel)
+	.then(create_compiler)
+	.then(compile)
+	.then(category_export)
+	.then(verify)
+	.then(compose_js_files)
+	.then(function () {
+		console.timeEnd('Compile Time');
+	}, function(error) {
+		console.error(error);
+	})
+	.then(function () {
+		console.log = console.ambercLog;
+		finished_callback && finished_callback();
+	});
+};
+
+
+/**
+ * Check if the passed in configuration object has sufficient/nonconflicting values.
+ * Returns a Promise which resolves into the configuration object.
+ */
+function check_configuration(configuration) {
+	return new Promise(function(resolve, reject) {
+		if (undefined === configuration) {
+			reject(Error('AmberCompiler.check_configuration_ok(): missing configuration object'));
+		}
+
+		if (0 === configuration.jsFiles.length && 0 === configuration.stFiles.length) {
+			reject(Error('AmberCompiler.check_configuration_ok(): no files to compile/link specified in configuration object'));
+		}
+
+		resolve(configuration);
+	});
+};
+
+
+/**
+ * Check if the file given as parameter exists in any of the following directories:
+ *  1. current local directory
+ *  2. configuration.jsLibraryDirs
+ *  3. $AMBER/src/
+ *  3. $AMBER/support/
+ *
+ * @param filename name of a file without '.js' prefix
+ * @param configuration the main amberc configuration object
+ */
+function resolve_js(filename, configuration) {
+	var baseName = path.basename(filename, '.js');
+	var jsFile = baseName + configuration.loadsuffix + '.js';
+	return resolve_file(jsFile, configuration.jsLibraryDirs);
+};
+
+
+/**
+ * Check if the file given as parameter exists in any of the following directories:
+ *  1. current local directory
+ *  2. $AMBER/
+ *
+ * @param filename name of a .st file
+ * @param configuration the main amberc configuration object
+ */
+function resolve_st(filename, configuration) {
+	return resolve_file(filename, [configuration.amber_dir]);
+};
+
+
+/**
+ * Resolve the location of a file given as parameter filename.
+ * First check if the file exists at given location,
+ * then check in each of the directories specified in parameter searchDirectories.
+ */
+function resolve_file(filename, searchDirectories) {
+	return new Promise(function(resolve, reject) {
+		console.log('Resolving: ' + filename);
+		fs.exists(filename, function(exists) {
+			if (exists) {
+				resolve(filename);
+			} else {
+				var alternativeFile = '';
+				// check for filename in any of the given searchDirectories
+				var found = searchDirectories.some(function(directory) {
+					alternativeFile = path.join(directory, filename);
+					return fs.existsSync(alternativeFile);
+				});
+				if (found) {
+					resolve(alternativeFile);
+				} else {
+					reject(Error('File not found: ' + alternativeFile));
+				}
+			}
+		});
+	});
+};
+
+
+/**
+ * Resolve st files given by stFiles and add them to configuration.compile.
+ * Returns a Promise which resolves into the configuration object.
+ */
+function collect_st_files(configuration) {
+	return Promise.all(
+		configuration.stFiles.map(function(stFile) {
+			return resolve_st(stFile, configuration);
+		})
+	)
+	.then(function(data) {
+		configuration.compile = configuration.compile.concat(data);
+		return configuration;
+	});
+}
+
+
+/**
+ * Resolve js files given by jsFiles and add them to configuration.libraries.
+ * Returns a Promise which resolves into the configuration object.
+ */
+function collect_js_files(configuration) {
+	return Promise.all(
+		configuration.jsFiles.map(function(file) {
+			return resolve_js(file, configuration);
+		})
+	)
+	.then(function(data) {
+		configuration.libraries = configuration.libraries.concat(data);
+		return configuration;
+	});
+}
+
+
+/**
+ * Resolve .js files needed by kernel.
+ * Returns a Promise which resolves into the configuration object.
+ */
+function resolve_kernel(configuration) {
+	var kernel_files = configuration.kernel_libraries.concat(configuration.load);
+	return Promise.all(
+		kernel_files.map(function(file) {
+			return resolve_js(file, configuration);
+		})
+	)
+	.then(function(data) {
+		// boot.js and Kernel files need to be used first
+		// otherwise the global objects 'vm' and 'globals' are undefined
+		configuration.libraries = data.concat(configuration.libraries);
+		return configuration;
+	});
+}
+
+
+/**
+ * Resolve .js files needed by compiler, read and eval() them.
+ * The finished Compiler gets stored in configuration.{vm,globals}.
+ * Returns a Promise object which resolves into the configuration object.
+ */
+function create_compiler(configuration) {
+	var compiler_files = configuration.compiler_libraries;
+	var include_files = configuration.load;
+	var builder;
+	return Promise.all(
+		compiler_files.map(function(file) {
+			return resolve_js(file, configuration);
+		})
+	)
+	.then(function(compilerFilesArray) {
+		return Promise.all(
+			compilerFilesArray.map(function(file) {
+				return new Promise(function(resolve, reject) {
+					console.log('Loading file: ' + file);
+					fs.readFile(file, function(err, data) {
+						if (err)
+							reject(err);
+						else
+							resolve(data);
+					});
+				});
+			})
+		)
+	})
+	.then(function(files) {
+		builder = createConcatenator();
+		builder.add('(function() {');
+		builder.start();
+
+		files.forEach(function(data) {
+			// data is an array where index 0 is the error code and index 1 contains the data
+			builder.add(data);
+			// matches and returns the "module_id" string in the AMD definition: define("module_id", ...)
+			var match = ('' + data).match(/(^|\n)define\("([^"]*)"/);
+			if (match) {
+				builder.addId(match[2]);
+			}
+		});
+	})
+	.then(function () { return Promise.all(
+		include_files.map(function(file) {
+			return resolve_js(file, configuration);
+		})
+	); })
+	.then(function(includeFilesArray) {
+		return Promise.all(
+			includeFilesArray.map(function(file) {
+				return new Promise(function(resolve, reject) {
+					console.log('Loading library file: ' + file);
+					fs.readFile(file, function(err, data) {
+						if (err)
+							reject(err);
+						else
+							resolve(data);
+					});
+				});
+			})
+		)
+	})
+	.then(function(files) {
+		var loadIds = [];
+		files.forEach(function(data) {
+			// data is an array where index 0 is the error code and index 1 contains the data
+			builder.add(data);
+			// matches and returns the "module_id" string in the AMD definition: define("module_id", ...)
+			var match = ('' + data).match(/^define\("([^"]*)"/);
+			if (match) {
+				loadIds.push(match[1]);
+			}
+		});
+		//backward compatibility
+		if (builder.ids.indexOf("amber_vm/boot") === -1) { console.log(builder.ids); console.log("defining amber_vm/boot"); builder.add('define("amber_vm/boot", ["amber/boot"], function (boot) { return boot; });'); }
+
+		// store the generated smalltalk env in configuration.{vm,globals}
+		builder.finish('configuration.vm = boot.vm; configuration.globals = boot.globals;');
+		loadIds.forEach(function (id) {
+			builder.add('requirejs("' + id + '");');
+		});
+		builder.add('})();');
+
+		eval(builder.toString());
+
+		console.log('Compiler loaded');
+
+		configuration.globals.ErrorHandler._register_(configuration.globals.RethrowErrorHandler._new());
+
+		if(0 !== configuration.jsGlobals.length) {
+			var jsGlobalVariables = configuration.vm.globalJsVariables;
+			jsGlobalVariables.push.apply(jsGlobalVariables, configuration.jsGlobals);
+		}
+
+		return configuration;
+	});
+}
+
+
+/**
+ * Compile all given .st files by importing them.
+ * Returns a Promise object that resolves into the configuration object.
+ */
+function compile(configuration) {
+	// return function which does the actual work
+	// and use the compile function to reference the configuration object
+	return Promise.all(
+		configuration.compile.map(function(stFile) {
+			return new Promise(function(resolve, reject) {
+				if (/\.st/.test(stFile)) {
+					console.ambercLog('Reading: ' + stFile);
+					fs.readFile(stFile, 'utf8', function(err, data) {
+						if (!err)
+							resolve(data);
+						else
+							reject(Error('Could not read: ' + stFile));
+					});
+				}
+			});
+		})
+	)
+	.then(function(fileContents) {
+		console.log('Compiling collected .st files');
+		// import/compile content of .st files
+		return Promise.all(
+			fileContents.map(function(code) {
+				return new Promise(function(resolve, reject) {
+					var importer = configuration.globals.Importer._new();
+					try {
+						importer._import_(code._stream());
+						resolve(true);
+					} catch (ex) {
+						reject(Error("Compiler error in section:\n" +
+							importer._lastSection() + "\n\n" +
+							"while processing chunk:\n" +
+							importer._lastChunk() + "\n\n" +
+							(ex._messageText && ex._messageText() || ex.message || ex))
+						);
+					}
+				});
+			})
+		);
+	})
+	.then(function () {
+		return configuration;
+	});
+}
+
+
+/**
+ * Export compiled categories to JavaScript files.
+ * Returns a Promise() that resolves into the configuration object.
+ */
+function category_export(configuration) {
+	return Promise.all(
+		configuration.compile.map(function(stFile) {
+			return new Promise(function(resolve, reject) {
+				var category = path.basename(stFile, '.st');
+				var jsFilePath = configuration.output_dir;
+				if (undefined === jsFilePath) {
+					jsFilePath = path.dirname(stFile);
+				}
+				var jsFile = category + configuration.suffix_used + '.js';
+				jsFile = path.join(jsFilePath, jsFile);
+				configuration.compiled.push(jsFile);
+				var smalltalkGlobals = configuration.globals;
+				var packageObject = smalltalkGlobals.Package._named_(category);
+				packageObject._transport()._namespace_(configuration.amd_namespace);
+				fs.writeFile(jsFile, smalltalkGlobals.String._streamContents_(function (stream) {
+					smalltalkGlobals.AmdExporter._new()._exportPackage_on_(packageObject, stream);
+				}), function(err) {
+					if (err)
+						reject(err);
+					else
+						resolve(true);
+				});
+			});
+		})
+	)
+	.then(function() {
+		return configuration;
+	});
+}
+
+
+/**
+ * Verify if all .st files have been compiled.
+ * Returns a Promise() that resolves into the configuration object.
+ */
+function verify(configuration) {
+	console.log('Verifying if all .st files were compiled');
+	return Promise.all(
+		configuration.compiled.map(function(file) {
+			return new Promise(function(resolve, reject) {
+				fs.exists(file, function(exists) {
+					if (exists)
+						resolve(true);
+					else
+						reject(Error('Compilation failed of: ' + file));
+				});
+			});
+		})
+	)
+	.then(function() {
+		return configuration;
+	});
+}
+
+
+/**
+ * Synchronous function.
+ * Concatenates compiled JavaScript files into one file in the correct order.
+ * The name of the produced file is given by configuration.program.
+ * Returns a Promise which resolves into the configuration object.
+ */
+function compose_js_files(configuration) {
+	return new Promise(function(resolve, reject) {
+		var programFile = configuration.program;
+		if (undefined === programFile) {
+			resolve(configuration);
+			return;
+		}
+		if (undefined !== configuration.output_dir) {
+			programFile = path.join(configuration.output_dir, programFile);
+		}
+
+		var program_files = [];
+		if (0 !== configuration.libraries.length) {
+			console.log('Collecting libraries: ' + configuration.libraries);
+			program_files.push.apply(program_files, configuration.libraries);
+		}
+
+		if (0 !== configuration.compiled.length) {
+			var compiledFiles = configuration.compiled.slice(0);
+
+			console.log('Collecting compiled files: ' + compiledFiles);
+			program_files.push.apply(program_files, compiledFiles);
+		}
+
+		console.ambercLog('Writing program file: %s.js', programFile);
+
+		var fileStream = fs.createWriteStream(programFile + configuration.suffix_used + '.js');
+		fileStream.on('error', function(error) {
+			fileStream.end();
+			console.ambercLog(error);
+			reject(error);
+		});
+
+		fileStream.on('close', function(){
+			resolve(configuration);
+		});
+
+		var builder = createConcatenator();
+		builder.add('#!/usr/bin/env node');
+		builder.start();
+
+		program_files.forEach(function(file) {
+			if(fs.existsSync(file)) {
+				console.log('Adding : ' + file);
+				var buffer = fs.readFileSync(file);
+				// matches and returns the "module_id" string in the AMD define: define("module_id", ...)
+				var match = buffer.toString().match(/(^|\n)define\("([^"]*)"/);
+				if (match /*&& match[1].slice(0,9) !== "amber_vm/"*/) {
+					builder.addId(match[2]);
+				}
+				builder.add(buffer);
+			} else {
+				fileStream.end();
+				reject(Error('Can not find file ' + file));
+			}
+		});
+		//backward compatibility
+		if (builder.ids.indexOf("amber_vm/boot") === -1) { builder.add('define("amber_vm/boot", ["amber/boot"], function (boot) { return boot; });'); }
+
+		var mainFunctionOrFile = 'var vm = boot.vm, globals = boot.globals;\n';
+
+		if (undefined !== configuration.main) {
+			console.log('Adding call to: %s>>main', configuration.main);
+			mainFunctionOrFile += 'globals.' + configuration.main + '._main();';
+		}
+
+		if (undefined !== configuration.mainfile && fs.existsSync(configuration.mainfile)) {
+			console.log('Adding main file: ' + configuration.mainfile);
+			mainFunctionOrFile += '\nvar smalltalk = vm; // backward compatibility\n' + fs.readFileSync(configuration.mainfile);
+		}
+
+		builder.finish(mainFunctionOrFile);
+
+		console.log('Writing...');
+		builder.forEach(function (element) {
+			fileStream.write(element);
+			fileStream.write('\n');
+		});
+		console.log('Done.');
+		fileStream.end();
+	});
+}
+
+
+module.exports.Compiler = AmberCompiler;
+module.exports.createDefaultConfiguration = createDefaultConfiguration;

+ 21 - 0
external/amber-dev/package.json

@@ -0,0 +1,21 @@
+{
+  "name": "amber-dev",
+  "version": "0.1.1",
+  "description": "Development goodies for Amber Smalltalk",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/amber-smalltalk/amber.git"
+  },
+  "author": "",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/amber-smalltalk/amber/issues?labels=devkit"
+  },
+  "dependencies": {
+    "amdefine": "0.0.8",
+    "es6-promise": "~0.1.1"
+  }
+}

+ 137 - 0
external/amber-dev/tasks/grunt-amberc.js

@@ -0,0 +1,137 @@
+module.exports = function(grunt) {
+
+  var path = require('path');
+  var fs = require('fs');
+  var amberc = require('../lib/amberc.js');
+
+  /**
+     A full example entry for a Gruntfile.js is available below.
+     Please note that the verbose level is either specified globally
+     or on a target specific level.
+     However, it can additionally be triggered on the commandline by
+     adding the '-v' or '--verbose' flag.
+
+     Example Gruntfile.js entry:
+
+     amberc: {
+       options: {
+         amber_dir: process.cwd(),                // REQUIRED
+         library_dirs: ['dir1', '/usr/local/js'], // optional
+         verbose: true                            // optional
+       },
+       helloWorld: {
+         // this 'options' object is optional as well as all parameters inside it
+         // they can be used to override the global 'options'
+         options: {
+           library_dirs: ['dir1', '/usr/local/js'], // optional
+           verbose: true
+         },
+         src: ['projects/HelloWorld/src/HelloWorld.st'], // REQUIRED
+         output_dir: 'projects/HelloWorld/src',  // optional
+         libraries: 'Web',                       // optional
+         jsGlobals: ['global1', 'global2'],     // optional
+         main_class: 'HelloWorld',              // optional
+         output_name: 'helloWorld',             // optional
+         amd_namespace: 'MyNamespace',          // optional (default: 'amber')
+         main_file: 'myMain.js',                // optional
+         output_suffix: 'mySuffix',             // optional
+         library_suffix: '-0.9'                 // optional
+       },
+     },
+
+   */
+  grunt.registerMultiTask('amberc', 'Compile Smalltalk files with the amberc compiler', function() {
+    // mark task as async task
+    var done = this.async();
+
+    var options = this.options({
+      amber_dir: undefined,
+      library_dirs: [],
+      verbose: grunt.option('verbose') || false
+    });
+    this.data.verbose = options.verbose;
+    this.data.library_dirs = options.library_dirs;
+
+    // mark required properties
+    this.requiresConfig('amberc.options.amber_dir');
+    // raise error on missing source files
+    if (this.filesSrc.length === 0) {
+        grunt.fail.fatal('No source files to compile or link.');
+    }
+
+    // create and initialize amberc
+    var compiler = new amberc.Compiler(grunt.config('amberc.options.amber_dir'));
+
+    // generate the amberc configuration out of the given target properties
+    var configuration = generateCompilerConfiguration(this.data, this.filesSrc);
+
+    // run the compiler and call the async callback once finished
+    var self = this;
+    compiler.main(configuration, function(){
+      // signal that task has finished
+      done();
+    });
+  });
+
+
+  function generateCompilerConfiguration(data, sourceFiles) {
+    var configuration = amberc.createDefaultConfiguration();
+    var parameters = [];
+
+    var libraries = data.libraries;
+    if (undefined !== libraries) {
+      configuration.load = libraries;
+    }
+    var library_dirs = data.library_dirs;
+    if (undefined !== library_dirs) {
+      configuration.jsLibraryDirs = library_dirs;
+    }
+    var mainClass = data.main_class;
+    if (undefined !== mainClass) {
+      configuration.main = mainClass;
+    }
+    var mainFile = data.main_file;
+    if (undefined !== mainFile) {
+      configuration.mainfile = mainFile;
+    }
+    var outputSuffix = data.output_suffix;
+    if (undefined !== outputSuffix) {
+      configuration.suffix = outputSuffix;
+      configuration.suffix_used = outputSuffix;
+    }
+    var librarySuffix = data.library_suffix;
+    if (undefined !== librarySuffix) {
+      configuration.loadsuffix = librarySuffix;
+      configuration.suffix_used = librarySuffix;
+    }
+    if (undefined !== sourceFiles) {
+      sourceFiles.forEach(function(currentItem){
+        var fileSuffix = path.extname(currentItem);
+        switch (fileSuffix) {
+          case '.st':
+            configuration.stFiles.push(currentItem);
+          break;
+          case '.js':
+            configuration.jsFiles.push(currentItem);
+          break;
+        }
+      });
+    }
+    var outputName = data.output_name;
+    if (undefined !== outputName) {
+      configuration.program = outputName;
+    }
+    var amdNamespace = data.amd_namespace;
+    if (undefined !== amdNamespace) {
+      configuration.amd_namespace = amdNamespace;
+    }
+    if (undefined !== data.output_dir) {
+      configuration.output_dir = data.output_dir;
+    }
+    if (undefined !== data.jsGlobals) {
+      configuration.jsGlobals.push.apply(configuration.jsGlobals, data.jsGlobals);
+    }
+    configuration.verbose = data.verbose;
+    return configuration;
+  }
+};

+ 1 - 1
grunt/tasks/grunt-peg.js

@@ -18,7 +18,7 @@ module.exports = function(grunt) {
       export_var: 'module.exports'
     });
     var parser = PEG.buildParser(grunt.file.read(this.data.src), options);
-    var content = 'define("amber_vm/parser", ["./globals", "./nil"], function(globals, nil) {\n'+options.export_var + ' = ' + parser + ';\n});';
+    var content = 'define("amber/parser", ["./boot"], function(boot) {\nvar globals = boot.globals, nil = boot.nil;\n'+options.export_var + ' = ' + parser + ';\n});';
     grunt.file.write(this.data.dest, content);
   });
 };

+ 4 - 2
package.json

@@ -26,12 +26,14 @@
     "node": ">=0.8.0"
   },
   "scripts": {
-    "test": "grunt amberc:test_runner && node test_runner.js && ( rm test_runner.js || del test_runner.js )"
+    "test": "grunt test"
   },
   "devDependencies": {
     "pegjs": "~0.8.0",
     "grunt": "~0.4.0",
     "grunt-contrib-jshint": "~0.3.0",
-    "amber-dev": "0.0.2"
+    "grunt-execute": "~0.2.1",
+    "amber-dev": "~0.1.1",
+    "grunt-contrib-clean": "~0.5.0"
   }
 }

+ 2 - 1
src/Benchfib.js

@@ -1,4 +1,5 @@
-define("amber_core/Benchfib", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Benchfib", ["amber/boot", "amber_core/Kernel-Objects"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Benchfib');
 smalltalk.packages["Benchfib"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Compiler-AST.js

@@ -1,4 +1,5 @@
-define("amber_core/Compiler-AST", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Kernel-Methods"], function(smalltalk,nil,_st, globals){
+define("amber_core/Compiler-AST", ["amber/boot", "amber_core/Kernel-Objects", "amber_core/Kernel-Methods"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Compiler-AST');
 smalltalk.packages["Compiler-AST"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 4 - 3
src/Compiler-Core.js

@@ -1,4 +1,5 @@
-define("amber_core/Compiler-Core", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure", "amber_core/Kernel-Collections"], function(smalltalk,nil,_st, globals){
+define("amber_core/Compiler-Core", ["amber/boot", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure", "amber_core/Kernel-Collections"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Compiler-Core');
 smalltalk.packages["Compiler-Core"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
@@ -459,7 +460,7 @@ var result,method;
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 method=self._eval_(self._compileExpression_on_(aString,anObject));
-_st(method)._protocol_("xxxDoIt");
+_st(method)._protocol_("**xxxDoIt");
 $1=_st(anObject)._class();
 $ctx1.sendIdx["class"]=1;
 _st($1)._addCompiledMethod_(method);
@@ -469,7 +470,7 @@ $2=result;
 return $2;
 }, function($ctx1) {$ctx1.fill(self,"evaluateExpression:on:",{aString:aString,anObject:anObject,result:result,method:method},globals.Compiler)})},
 args: ["aString", "anObject"],
-source: "evaluateExpression: aString on: anObject\x0a\x09\x22Unlike #eval: evaluate a Smalltalk expression with anObject as the receiver and answer the returned object\x22\x0a\x09| result method |\x0a\x09method := self eval: (self compileExpression: aString on: anObject).\x0a\x09method protocol: 'xxxDoIt'.\x0a\x09anObject class addCompiledMethod: method.\x0a\x09result := anObject xxxDoIt.\x0a\x09anObject class removeCompiledMethod: method.\x0a\x09^ result",
+source: "evaluateExpression: aString on: anObject\x0a\x09\x22Unlike #eval: evaluate a Smalltalk expression with anObject as the receiver and answer the returned object\x22\x0a\x09| result method |\x0a\x09method := self eval: (self compileExpression: aString on: anObject).\x0a\x09method protocol: '**xxxDoIt'.\x0a\x09anObject class addCompiledMethod: method.\x0a\x09result := anObject xxxDoIt.\x0a\x09anObject class removeCompiledMethod: method.\x0a\x09^ result",
 messageSends: ["eval:", "compileExpression:on:", "protocol:", "addCompiledMethod:", "class", "xxxDoIt", "removeCompiledMethod:"],
 referencedClasses: []
 }),

+ 1 - 1
src/Compiler-Core.st

@@ -167,7 +167,7 @@ evaluateExpression: aString on: anObject
 	"Unlike #eval: evaluate a Smalltalk expression with anObject as the receiver and answer the returned object"
 	| result method |
 	method := self eval: (self compileExpression: aString on: anObject).
-	method protocol: 'xxxDoIt'.
+	method protocol: '**xxxDoIt'.
 	anObject class addCompiledMethod: method.
 	result := anObject xxxDoIt.
 	anObject class removeCompiledMethod: method.

+ 2 - 1
src/Compiler-Exceptions.js

@@ -1,4 +1,5 @@
-define("amber_core/Compiler-Exceptions", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Exceptions", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Compiler-Exceptions", ["amber/boot", "amber_core/Kernel-Exceptions", "amber_core/Kernel-Objects"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Compiler-Exceptions');
 smalltalk.packages["Compiler-Exceptions"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Compiler-IR.js

@@ -1,4 +1,5 @@
-define("amber_core/Compiler-IR", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Compiler-Core", "amber_core/Kernel-Objects", "amber_core/Kernel-Methods"], function(smalltalk,nil,_st, globals){
+define("amber_core/Compiler-IR", ["amber/boot", "amber_core/Compiler-Core", "amber_core/Kernel-Objects", "amber_core/Kernel-Methods"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Compiler-IR');
 smalltalk.packages["Compiler-IR"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Compiler-Inlining.js

@@ -1,4 +1,5 @@
-define("amber_core/Compiler-Inlining", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Compiler-IR", "amber_core/Kernel-Objects", "amber_core/Compiler-Core"], function(smalltalk,nil,_st, globals){
+define("amber_core/Compiler-Inlining", ["amber/boot", "amber_core/Compiler-IR", "amber_core/Kernel-Objects", "amber_core/Compiler-Core"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Compiler-Inlining');
 smalltalk.packages["Compiler-Inlining"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Compiler-Interpreter.js

@@ -1,4 +1,5 @@
-define("amber_core/Compiler-Interpreter", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Methods", "amber_core/Compiler-Semantic", "amber_core/Kernel-Objects", "amber_core/Compiler-Core", "amber_core/Kernel-Exceptions", "amber_core/Compiler-AST"], function(smalltalk,nil,_st, globals){
+define("amber_core/Compiler-Interpreter", ["amber/boot", "amber_core/Kernel-Methods", "amber_core/Compiler-Semantic", "amber_core/Kernel-Objects", "amber_core/Compiler-Core", "amber_core/Kernel-Exceptions", "amber_core/Compiler-AST"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Compiler-Interpreter');
 smalltalk.packages["Compiler-Interpreter"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Compiler-Semantic.js

@@ -1,4 +1,5 @@
-define("amber_core/Compiler-Semantic", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Compiler-Core"], function(smalltalk,nil,_st, globals){
+define("amber_core/Compiler-Semantic", ["amber/boot", "amber_core/Kernel-Objects", "amber_core/Compiler-Core"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Compiler-Semantic');
 smalltalk.packages["Compiler-Semantic"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Compiler-Tests.js

@@ -1,4 +1,5 @@
-define("amber_core/Compiler-Tests", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/SUnit"], function(smalltalk,nil,_st, globals){
+define("amber_core/Compiler-Tests", ["amber/boot", "amber_core/SUnit"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Compiler-Tests');
 smalltalk.packages["Compiler-Tests"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Examples.js

@@ -1,4 +1,5 @@
-define("amber_core/Examples", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Web"], function(smalltalk,nil,_st, globals){
+define("amber_core/Examples", ["amber/boot", "amber_core/Web"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Examples');
 smalltalk.packages["Examples"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/IDE.js

@@ -1,4 +1,5 @@
-define("amber_core/IDE", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Web", "amber_core/Kernel-Objects", "amber_core/Kernel-Collections", "amber_core/Kernel-Methods"], function(smalltalk,nil,_st, globals){
+define("amber_core/IDE", ["amber/boot", "amber_core/Web", "amber_core/Kernel-Objects", "amber_core/Kernel-Collections", "amber_core/Kernel-Methods"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('IDE');
 smalltalk.packages["IDE"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 30 - 1
src/Kernel-Announcements.js

@@ -1,4 +1,5 @@
-define("amber_core/Kernel-Announcements", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-Announcements", ["amber/boot", "amber_core/Kernel-Objects"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-Announcements');
 smalltalk.packages["Kernel-Announcements"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
@@ -814,6 +815,34 @@ globals.PackageRemoved.comment="I am emitted when a `Package` is removed from th
 
 smalltalk.addClass('ProtocolAnnouncement', globals.SystemAnnouncement, ['theClass', 'protocol'], 'Kernel-Announcements');
 globals.ProtocolAnnouncement.comment="I am the abstract superclass of protocol-related announcements.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "package",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+function $Package(){return globals.Package||(typeof Package=="undefined"?nil:Package)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$3,$4;
+$2=self._protocol();
+$ctx1.sendIdx["protocol"]=1;
+$1=_st($2)._beginsWith_("*");
+if(! smalltalk.assert($1)){
+$3=_st(self._theClass())._package();
+return $3;
+};
+$4=_st($Package())._named_ifAbsent_(_st(self._protocol())._allButFirst(),(function(){
+return nil;
+}));
+return $4;
+}, function($ctx1) {$ctx1.fill(self,"package",{},globals.ProtocolAnnouncement)})},
+args: [],
+source: "package\x0a\x0a\x09(self protocol beginsWith: '*') ifFalse: [\x0a\x09\x09^ self theClass package ].\x0a\x09\x09\x0a\x09^ Package \x0a\x09\x09named: self protocol allButFirst\x0a\x09\x09ifAbsent: [ nil ]",
+messageSends: ["ifFalse:", "beginsWith:", "protocol", "package", "theClass", "named:ifAbsent:", "allButFirst"],
+referencedClasses: ["Package"]
+}),
+globals.ProtocolAnnouncement);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "protocol",

+ 10 - 0
src/Kernel-Announcements.st

@@ -399,6 +399,16 @@ I am the abstract superclass of protocol-related announcements.!
 
 !ProtocolAnnouncement methodsFor: 'accessing'!
 
+package
+
+	(self protocol beginsWith: '*') ifFalse: [
+		^ self theClass package ].
+		
+	^ Package 
+		named: self protocol allButFirst
+		ifAbsent: [ nil ]
+!
+
 protocol
 	^ protocol
 !

+ 2 - 1
src/Kernel-Classes.js

@@ -1,4 +1,5 @@
-define("amber_core/Kernel-Classes", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-Classes", ["amber/boot", "amber_core/Kernel-Objects"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-Classes');
 smalltalk.packages["Kernel-Classes"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Kernel-Collections.js

@@ -1,4 +1,5 @@
-define("amber_core/Kernel-Collections", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-Collections", ["amber/boot", "amber_core/Kernel-Objects"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-Collections');
 smalltalk.packages["Kernel-Collections"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Kernel-Exceptions.js

@@ -1,4 +1,5 @@
-define("amber_core/Kernel-Exceptions", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-Exceptions", ["amber/boot", "amber_core/Kernel-Objects"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-Exceptions');
 smalltalk.packages["Kernel-Exceptions"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 9 - 4
src/Kernel-ImportExport.js

@@ -1,4 +1,5 @@
-define("amber_core/Kernel-ImportExport", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-ImportExport", ["amber/boot", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-ImportExport');
 smalltalk.packages["Kernel-ImportExport"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
@@ -1098,13 +1099,17 @@ _st(aStream)._nextPutAll_(_st(aPackage)._name());
 $ctx1.sendIdx["nextPutAll:"]=4;
 _st(aStream)._nextPutAll_("\x22, ");
 $ctx1.sendIdx["nextPutAll:"]=5;
-_st(aStream)._nextPutAll_(_st(["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals"].__comma(self._amdNamesOfPackages_(_st(aPackage)._loadDependencies())))._asJavascript());
+_st(aStream)._nextPutAll_(_st(["amber/boot"].__comma(self._amdNamesOfPackages_(_st(aPackage)._loadDependencies())))._asJavascript());
 $ctx1.sendIdx["nextPutAll:"]=6;
-_st(aStream)._nextPutAll_(", function(smalltalk,nil,_st, globals){");
+_st(aStream)._nextPutAll_(", function($boot){");
+$ctx1.sendIdx["nextPutAll:"]=7;
+_st(aStream)._lf();
+$ctx1.sendIdx["lf"]=1;
+_st(aStream)._nextPutAll_("var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;");
 $1=_st(aStream)._lf();
 return self}, function($ctx1) {$ctx1.fill(self,"exportPackagePrologueOf:on:",{aPackage:aPackage,aStream:aStream},globals.AmdExporter)})},
 args: ["aPackage", "aStream"],
-source: "exportPackagePrologueOf: aPackage on: aStream\x0a\x09aStream\x0a\x09\x09nextPutAll: 'define(\x22';\x0a\x09\x09nextPutAll: (self amdNamespaceOfPackage: aPackage);\x0a\x09\x09nextPutAll: '/';\x0a\x09\x09nextPutAll: aPackage name;\x0a\x09\x09nextPutAll: '\x22, ';\x0a\x09\x09nextPutAll: (#('amber_vm/smalltalk' 'amber_vm/nil' 'amber_vm/_st' 'amber_vm/globals'), (self amdNamesOfPackages: aPackage loadDependencies)) asJavascript;\x0a\x09\x09nextPutAll: ', function(smalltalk,nil,_st, globals){';\x0a\x09\x09lf",
+source: "exportPackagePrologueOf: aPackage on: aStream\x0a\x09aStream\x0a\x09\x09nextPutAll: 'define(\x22';\x0a\x09\x09nextPutAll: (self amdNamespaceOfPackage: aPackage);\x0a\x09\x09nextPutAll: '/';\x0a\x09\x09nextPutAll: aPackage name;\x0a\x09\x09nextPutAll: '\x22, ';\x0a\x09\x09nextPutAll: (#('amber/boot'), (self amdNamesOfPackages: aPackage loadDependencies)) asJavascript;\x0a\x09\x09nextPutAll: ', function($boot){';\x0a\x09\x09lf;\x0a\x09\x09nextPutAll: 'var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;';\x0a\x09\x09lf",
 messageSends: ["nextPutAll:", "amdNamespaceOfPackage:", "name", "asJavascript", ",", "amdNamesOfPackages:", "loadDependencies", "lf"],
 referencedClasses: []
 }),

+ 4 - 2
src/Kernel-ImportExport.st

@@ -386,8 +386,10 @@ exportPackagePrologueOf: aPackage on: aStream
 		nextPutAll: '/';
 		nextPutAll: aPackage name;
 		nextPutAll: '", ';
-		nextPutAll: (#('amber_vm/smalltalk' 'amber_vm/nil' 'amber_vm/_st' 'amber_vm/globals'), (self amdNamesOfPackages: aPackage loadDependencies)) asJavascript;
-		nextPutAll: ', function(smalltalk,nil,_st, globals){';
+		nextPutAll: (#('amber/boot'), (self amdNamesOfPackages: aPackage loadDependencies)) asJavascript;
+		nextPutAll: ', function($boot){';
+		lf;
+		nextPutAll: 'var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;';
 		lf
 ! !
 

+ 14 - 5
src/Kernel-Infrastructure.js

@@ -1,4 +1,5 @@
-define("amber_core/Kernel-Infrastructure", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Kernel-Collections"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-Infrastructure", ["amber/boot", "amber_core/Kernel-Objects", "amber_core/Kernel-Collections"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-Infrastructure');
 smalltalk.packages["Kernel-Infrastructure"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
@@ -2106,7 +2107,7 @@ _st(_st(theClass)._package())._beDirty();
 };
 return self}, function($ctx1) {$ctx1.fill(self,"onClassModification:",{anAnnouncement:anAnnouncement},globals.PackageStateObserver)})},
 args: ["anAnnouncement"],
-source: "onClassModification: anAnnouncement\x0a\x09anAnnouncement theClass ifNotNil: [ :theClass |\x0a\x09\x09theClass package beDirty ]",
+source: "onClassModification: anAnnouncement\x0a\x09anAnnouncement theClass ifNotNil: [ :theClass | theClass package beDirty ]",
 messageSends: ["ifNotNil:", "theClass", "beDirty", "package"],
 referencedClasses: []
 }),
@@ -2159,11 +2160,19 @@ protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(_st(anAnnouncement)._theClass())._package())._beDirty();
+var $1,$receiver;
+$1=_st(anAnnouncement)._package();
+if(($receiver = $1) == null || $receiver.isNil){
+$1;
+} else {
+var package_;
+package_=$receiver;
+_st(package_)._beDirty();
+};
 return self}, function($ctx1) {$ctx1.fill(self,"onProtocolModification:",{anAnnouncement:anAnnouncement},globals.PackageStateObserver)})},
 args: ["anAnnouncement"],
-source: "onProtocolModification: anAnnouncement\x0a\x09anAnnouncement theClass package beDirty",
-messageSends: ["beDirty", "package", "theClass"],
+source: "onProtocolModification: anAnnouncement\x0a\x09anAnnouncement package ifNotNil: [ :package | package beDirty ]",
+messageSends: ["ifNotNil:", "package", "beDirty"],
 referencedClasses: []
 }),
 globals.PackageStateObserver);

+ 2 - 3
src/Kernel-Infrastructure.st

@@ -778,8 +778,7 @@ observeSystem
 !PackageStateObserver methodsFor: 'reactions'!
 
 onClassModification: anAnnouncement
-	anAnnouncement theClass ifNotNil: [ :theClass |
-		theClass package beDirty ]
+	anAnnouncement theClass ifNotNil: [ :theClass | theClass package beDirty ]
 !
 
 onMethodModification: anAnnouncement
@@ -791,7 +790,7 @@ onPackageAdded: anAnnouncement
 !
 
 onProtocolModification: anAnnouncement
-	anAnnouncement theClass package beDirty
+	anAnnouncement package ifNotNil: [ :package | package beDirty ]
 ! !
 
 PackageStateObserver class instanceVariableNames: 'current'!

+ 9 - 12
src/Kernel-Methods.js

@@ -1,4 +1,5 @@
-define("amber_core/Kernel-Methods", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-Methods", ["amber/boot", "amber_core/Kernel-Objects"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-Methods');
 smalltalk.packages["Kernel-Methods"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
@@ -705,7 +706,7 @@ fn: function (){
 var self=this;
 function $Package(){return globals.Package||(typeof Package=="undefined"?nil:Package)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$2,$5,$4,$6,$receiver;
+var $1,$3,$2,$4,$5,$receiver;
 $1=self._methodClass();
 $ctx1.sendIdx["methodClass"]=1;
 if(($receiver = $1) == null || $receiver.isNil){
@@ -717,20 +718,16 @@ $3=self._protocol();
 $ctx1.sendIdx["protocol"]=1;
 $2=_st($3)._beginsWith_("*");
 if(! smalltalk.assert($2)){
-$5=self._methodClass();
-$ctx1.sendIdx["methodClass"]=2;
-$4=_st($5)._package();
-$ctx1.sendIdx["package"]=1;
+$4=_st(self._methodClass())._package();
 return $4;
 };
-$6=_st($Package())._named_ifAbsent_(_st(self._protocol())._allButFirst(),(function(){
-return smalltalk.withContext(function($ctx2) {
-return _st(self._methodClass())._package();
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
-return $6;
+$5=_st($Package())._named_ifAbsent_(_st(self._protocol())._allButFirst(),(function(){
+return nil;
+}));
+return $5;
 }, function($ctx1) {$ctx1.fill(self,"package",{},globals.CompiledMethod)})},
 args: [],
-source: "package\x0a\x09\x22Answer the package the receiver belongs to:\x0a\x09- if it is an extension method, answer the corresponding package\x0a\x09- else answer the `methodClass` package\x22\x0a\x09\x0a\x09self methodClass ifNil: [ ^ nil ].\x0a\x09\x0a\x09(self protocol beginsWith: '*') ifFalse: [\x0a\x09\x09^ self methodClass package ].\x0a\x09\x09\x0a\x09^ Package \x0a\x09\x09named: self protocol allButFirst\x0a\x09\x09ifAbsent: [ self methodClass package ]",
+source: "package\x0a\x09\x22Answer the package the receiver belongs to:\x0a\x09- if it is an extension method, answer the corresponding package\x0a\x09- else answer the `methodClass` package\x22\x0a\x09\x0a\x09self methodClass ifNil: [ ^ nil ].\x0a\x09\x0a\x09(self protocol beginsWith: '*') ifFalse: [\x0a\x09\x09^ self methodClass package ].\x0a\x09\x09\x0a\x09^ Package \x0a\x09\x09named: self protocol allButFirst\x0a\x09\x09ifAbsent: [ nil ]",
 messageSends: ["ifNil:", "methodClass", "ifFalse:", "beginsWith:", "protocol", "package", "named:ifAbsent:", "allButFirst"],
 referencedClasses: ["Package"]
 }),

+ 1 - 1
src/Kernel-Methods.st

@@ -246,7 +246,7 @@ package
 		
 	^ Package 
 		named: self protocol allButFirst
-		ifAbsent: [ self methodClass package ]
+		ifAbsent: [ nil ]
 !
 
 protocol

+ 2 - 1
src/Kernel-Objects.js

@@ -1,4 +1,5 @@
-define("amber_core/Kernel-Objects", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-Objects", ["amber/boot"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-Objects');
 smalltalk.packages["Kernel-Objects"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 28 - 1
src/Kernel-Tests.js

@@ -1,8 +1,35 @@
-define("amber_core/Kernel-Tests", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/SUnit", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-Tests", ["amber/boot", "amber_core/SUnit", "amber_core/Kernel-Objects"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-Tests');
 smalltalk.packages["Kernel-Tests"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
 smalltalk.addClass('AnnouncementSubscriptionTest', globals.TestCase, [], 'Kernel-Tests');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testAddExtensionMethod",
+protocol: 'tests',
+fn: function (){
+var self=this;
+var method;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$4,$3,$2;
+$1=self._class();
+$ctx1.sendIdx["class"]=1;
+method=_st($1)._compile_protocol_("doNothing","**not-a-package");
+$4=self._class();
+$ctx1.sendIdx["class"]=2;
+$3=_st($4)._package();
+$2=_st($3)._isDirty();
+self._deny_($2);
+_st(self._class())._removeCompiledMethod_(method);
+return self}, function($ctx1) {$ctx1.fill(self,"testAddExtensionMethod",{method:method},globals.AnnouncementSubscriptionTest)})},
+args: [],
+source: "testAddExtensionMethod\x0a\x09| method |\x0a\x09method := self class compile: 'doNothing' protocol: '**not-a-package'.\x0a\x09self deny: self class package isDirty.\x0a\x09self class removeCompiledMethod: method.",
+messageSends: ["compile:protocol:", "class", "deny:", "isDirty", "package", "removeCompiledMethod:"],
+referencedClasses: []
+}),
+globals.AnnouncementSubscriptionTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testHandlesAnnouncement",

+ 7 - 0
src/Kernel-Tests.st

@@ -5,6 +5,13 @@ TestCase subclass: #AnnouncementSubscriptionTest
 
 !AnnouncementSubscriptionTest methodsFor: 'tests'!
 
+testAddExtensionMethod
+	| method |
+	method := self class compile: 'doNothing' protocol: '**not-a-package'.
+	self deny: self class package isDirty.
+	self class removeCompiledMethod: method.
+!
+
 testHandlesAnnouncement
 	| subscription announcementClass1 announcementClass2 classBuilder |
 	

+ 2 - 1
src/Kernel-Transcript.js

@@ -1,4 +1,5 @@
-define("amber_core/Kernel-Transcript", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects"], function(smalltalk,nil,_st, globals){
+define("amber_core/Kernel-Transcript", ["amber/boot", "amber_core/Kernel-Objects"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Kernel-Transcript');
 smalltalk.packages["Kernel-Transcript"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/SUnit-Tests.js

@@ -1,4 +1,5 @@
-define("amber_core/SUnit-Tests", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/SUnit"], function(smalltalk,nil,_st, globals){
+define("amber_core/SUnit-Tests", ["amber/boot", "amber_core/SUnit"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('SUnit-Tests');
 smalltalk.packages["SUnit-Tests"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/SUnit.js

@@ -1,4 +1,5 @@
-define("amber_core/SUnit", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Kernel-Exceptions"], function(smalltalk,nil,_st, globals){
+define("amber_core/SUnit", ["amber/boot", "amber_core/Kernel-Objects", "amber_core/Kernel-Exceptions"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('SUnit');
 smalltalk.packages["SUnit"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Spaces.js

@@ -1,4 +1,5 @@
-define("amber_core/Spaces", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Kernel-Exceptions", "amber_core/SUnit"], function(smalltalk,nil,_st, globals){
+define("amber_core/Spaces", ["amber/boot", "amber_core/Kernel-Objects", "amber_core/Kernel-Exceptions", "amber_core/SUnit"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Spaces');
 smalltalk.packages["Spaces"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 2 - 1
src/Web.js

@@ -1,4 +1,5 @@
-define("amber_core/Web", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_vm/globals", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure", "amber_core/Kernel-Methods", "amber_core/Kernel-Collections"], function(smalltalk,nil,_st, globals){
+define("amber_core/Web", ["amber/boot", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure", "amber_core/Kernel-Methods", "amber_core/Kernel-Collections"], function($boot){
+var smalltalk=$boot.vm,nil=$boot.nil,_st=$boot.asReceiver,globals=$boot.globals;
 smalltalk.addPackage('Web');
 smalltalk.packages["Web"].transport = {"type":"amd","amdNamespace":"amber_core"};
 

+ 0 - 18
support/_st.js

@@ -1,18 +0,0 @@
-
-/**
- * _st is a function used all over the compiled amber code that
- * takes any value (JavaScript or Smalltalk)
- * and returns a proper Amber Smalltalk receiver.
- *
- * null or undefined -> nil,
- * plain JS object -> wrapped JS object,
- * otherwise unchanged
- */
-
-define("amber_vm/_st", ["./globals", "./nil"], function (globals, nil) {
-    return function (o) {
-        if (o == null) { return nil; }
-        if (o.klass) { return o; }
-        return globals.JSObjectProxy._on_(o);
-    };
-});

+ 4 - 3
support/amber.js

@@ -77,13 +77,14 @@ require = function (require) {
     var config = {
         paths: {
             'amber': amber_home + '/support',
-            'amber_vm': amber_home + '/support',
+            'amber_vm': amber_home + '/support/deprecated-vm-files',
+            'amber_vm/_st': amber_home + '/support/deprecated-vm-files/as-receiver',
             'amber_css': amber_home + '/css',
             'amber_lib': library_home,
             'amber_core': amber_home + '/src',
-            'helios': amber_home + '/src',
+            'helios': amber_home + '/support/helios/src',
             'helios/all': amber_home + '/support/helios/all',
-            'helios/resources': amber_home + '/support/helios',
+            'helios/resources': amber_home + '/support/helios/resources',
             'helios/index': amber_home + '/support/helios/index',
             'jquery': library_home + '/jquery/jquery.min'
         },

+ 25 - 2
support/boot.js

@@ -38,7 +38,7 @@
  ==================================================================== */
 
 
-define("amber_vm/boot", [ 'require', './browser-compatibility' ], function (require) {
+define("amber/boot", [ 'require', './browser-compatibility' ], function (require) {
 
 	/* Reconfigurable micro composition system, https://github.com/amber-smalltalk/brikz */
 
@@ -1122,6 +1122,28 @@ define("amber_vm/boot", [ 'require', './browser-compatibility' ], function (requ
 		};
 	}
 
+    /* Defines asReceiver to be present at load time */
+    /* (logically it belongs more to PrimitiveBrik) */
+    function AsReceiverBrik(brikz, st) {
+
+        var nil = brikz.ensure("root").nil;
+
+        /**
+         * This function is used all over the compiled amber code.
+         * It takes any value (JavaScript or Smalltalk)
+         * and returns a proper Amber Smalltalk receiver.
+         *
+         * null or undefined -> nil,
+         * plain JS object -> wrapped JS object,
+         * otherwise unchanged
+         */
+        this.asReceiver = function (o) {
+            if (o == null) { return nil; }
+            if (o.klass) { return o; }
+            return globals.JSObjectProxy._on_(o);
+        };
+    }
+
 
 	/* Making smalltalk that can load */
 
@@ -1136,6 +1158,7 @@ define("amber_vm/boot", [ 'require', './browser-compatibility' ], function (requ
 	brikz.stInit = SmalltalkInitBrik;
 	brikz.augments = AugmentsBrik;
 	brikz.amdBrik = AMDBrik;
+	brikz.asReceiverBrik = AsReceiverBrik;
 
 	brikz.rebuild();
 
@@ -1149,5 +1172,5 @@ define("amber_vm/boot", [ 'require', './browser-compatibility' ], function (requ
 		brikz.rebuild();
 	};
 
-	return { vm: api, nil: brikz.root.nil, globals: globals };
+	return { vm: api, nil: brikz.root.nil, globals: globals, asReceiver: brikz.asReceiverBrik.asReceiver };
 });

+ 1 - 1
support/browser-compatibility.js

@@ -1,4 +1,4 @@
-define("amber_vm/browser-compatibility", [
+define([
     './ensure-console',
     'amber_lib/es5-shim/es5-shim.min',
     'amber_lib/es5-shim/es5-sham.min'

+ 3 - 0
support/deprecated-vm-files/_st.js

@@ -0,0 +1,3 @@
+define("amber_vm/_st", ["./boot"], function (boot) {
+    return boot.asReceiver;
+});

+ 3 - 0
support/deprecated-vm-files/as-receiver.js

@@ -0,0 +1,3 @@
+define("amber_vm/_st", ["./boot"], function (boot) {
+    return boot.asReceiver;
+});

+ 3 - 0
support/deprecated-vm-files/boot.js

@@ -0,0 +1,3 @@
+define("amber_vm/boot", ["amber/boot"], function (boot) {
+    return boot;
+});

+ 0 - 0
support/globals.js → support/deprecated-vm-files/globals.js


+ 0 - 0
support/nil.js → support/deprecated-vm-files/nil.js


+ 0 - 0
support/smalltalk.js → support/deprecated-vm-files/smalltalk.js


+ 1 - 1
support/helios/all.js

@@ -24,5 +24,5 @@ define([
 	'./resources/all-inner',
     'css!./resources/helios',
 	'css!./resources/helios-niflheim',
-    'css!amber_css/niflheim'
+    'css!./resources/niflheim'
 ], function (smalltalk) { return smalltalk; });

+ 0 - 0
support/helios/all-inner.js → support/helios/resources/all-inner.js


+ 0 - 0
support/helios/announcement.png → support/helios/resources/announcement.png


+ 0 - 0
support/helios/arrowLeft.png → support/helios/resources/arrowLeft.png


+ 0 - 0
support/helios/arrowRight.png → support/helios/resources/arrowRight.png


+ 0 - 0
support/helios/browser.png → support/helios/resources/browser.png


+ 0 - 0
support/helios/class.png → support/helios/resources/class.png


+ 0 - 0
support/helios/close-dark.png → support/helios/resources/close-dark.png


+ 0 - 0
support/helios/close.gif → support/helios/resources/close.gif


+ 0 - 0
support/helios/collection.png → support/helios/resources/collection.png


+ 0 - 0
support/helios/debugger.png → support/helios/resources/debugger.png


+ 0 - 0
support/helios/exception.png → support/helios/resources/exception.png


+ 0 - 0
support/helios/extension.png → support/helios/resources/extension.png


+ 2 - 2
support/helios/helios-niflheim.css → support/helios/resources/helios-niflheim.css

@@ -4,7 +4,7 @@ body[id="helios"].niflheim {
 		  width: 100%;
 		}*/
   /*.tool_container .pane .nav-pills i.package {
-			background-image: url('package.png');
+			background-image: url('resources/package.png');
 		}*/
 }
 body[id="helios"].niflheim .btn-group > .dropdown-menu {
@@ -125,7 +125,7 @@ body[id="helios"].niflheim .welcome {
 body[id="helios"].niflheim [class^="icon-"],
 body[id="helios"].niflheim body[id="helios"][class*=" icon-"] {
   opacity: 0.68;
-  background-image: url("../../bower_components/bootstrap/img/glyphicons-halflings-white.png");
+  background-image: url("../../../bower_components/bootstrap/img/glyphicons-halflings-white.png");
 }
 body[id="helios"].niflheim .welcome h2 {
   text-align: center;

+ 2 - 2
support/helios/helios-niflheim.less → support/helios/resources/helios-niflheim.less

@@ -152,7 +152,7 @@ body[id="helios"] {
 
 		[class^="icon-"], body[id="helios"][class*=" icon-"]{
 			opacity: 0.68;
-			background-image: url("../../bower_components/bootstrap/img/glyphicons-halflings-white.png");
+			background-image: url("../../../bower_components/bootstrap/img/glyphicons-halflings-white.png");
 		}
 
 		.welcome h2 {
@@ -186,7 +186,7 @@ body[id="helios"] {
 	
 		//todo: remove
 		/*.tool_container .pane .nav-pills i.package {
-			background-image: url('package.png');
+			background-image: url('resources/package.png');
 		}*/
 
 		.tool_container .list-label {

+ 1 - 1
support/helios/helios.css → support/helios/resources/helios.css

@@ -455,7 +455,7 @@ body[id="helios"] .tool_container .pane .nav-pills i.package {
   background-image: url('package.png');
 }
 body[id="helios"] .tool_container .pane .nav-pills i.override {
-  background-image: url('override.png ');
+  background-image: url('resources/override.png ');
 }
 body[id="helios"] .tool_container .pane .nav-pills i.overridden {
   background-image: url('overridden.png');

+ 1 - 1
support/helios/helios.less → support/helios/resources/helios.less

@@ -535,7 +535,7 @@ body[id="helios"] {
 		background-image: url('package.png');
 	}
 	.tool_container .pane .nav-pills i.override {
-		background-image: url('override.png ');
+		background-image: url('resources/override.png ');
 	}
 	.tool_container .pane .nav-pills i.overridden {
 		background-image: url('overridden.png');

+ 0 - 0
support/helios/helios_frame.css → support/helios/resources/helios_frame.css


+ 0 - 0
support/helios/initialization.png → support/helios/resources/initialization.png


+ 0 - 0
support/helios/inspector.png → support/helios/resources/inspector.png


+ 0 - 0
support/helios/magnitude.png → support/helios/resources/magnitude.png


+ 0 - 0
support/helios/modified.png → support/helios/resources/modified.png


+ 0 - 0
css/niflheim.css → support/helios/resources/niflheim.css


+ 0 - 0
support/helios/off.png → support/helios/resources/off.png


+ 0 - 0
support/helios/offHover.png → support/helios/resources/offHover.png


+ 0 - 0
support/helios/overridden.png → support/helios/resources/overridden.png


+ 0 - 0
support/helios/override-overridden.png → support/helios/resources/override-overridden.png


+ 0 - 0
support/helios/override.png → support/helios/resources/override.png


+ 0 - 0
support/helios/package-dirty.png → support/helios/resources/package-dirty.png


+ 0 - 0
support/helios/package.png → support/helios/resources/package.png


+ 0 - 0
support/helios/pause.png → support/helios/resources/pause.png


+ 0 - 0
support/helios/private.png → support/helios/resources/private.png


Some files were not shown because too many files changed in this diff