Browse Source

Merge branch 'upstream' into pr-728

Herbert Vojčík 10 years ago
parent
commit
0c3d882fb6

+ 22 - 0
API-CHANGES.txt

@@ -1,3 +1,25 @@
+0.12.2:
+
+* Collection >> contains: is deprecated in favor of anySatisfy:
+
+
++ Announcer
+  + >>on:doOnce:
++ String
+  + >>uriEncoded
+  + >>uriDecoded
+  + >>uriComponentEncoded
+  + >>uriComponentDecoded
++ Collection
+  + >>removeAll
+  + >>ifEmpty:ifNotEmpty:
+  + >>ifNotEmpty:ifEmpty:
+  + >>anyOne
+  + >>noneSatisfy:
+  + >>anySatisfy:
+  + >>allSatisfy:
+
+
 0.12.0:
 
 * SmalltalkMethodContext.prototype.fillBlock() takes a third 'index' parameter

+ 28 - 2
CHANGELOG

@@ -1,5 +1,31 @@
- 2013 - Release 0.12.0
-===============================
+03rd December 2013 - Release 0.12.2
+===================================
+
+Highlights:
+
+* Loading Amber in nested pages now possible (via additional `data-libs` attribute of the `<script>` tag which loads `amber.js`)
+* IDE related fixes
+* Contributions Guide
+* Improved Collections
+* Amber Server responds with `not found` instead of `internal server error` if `index.html` could not be found
+
+Commits: https://github.com/amber-smalltalk/amber/compare/0.12.1...0.12.2
+Issues:  https://github.com/amber-smalltalk/amber/issues?milestone=10&state=closed
+
+For the most important API related changes see the file API-CHANGES.txt.
+
+
+14th November 2013 - Release 0.12.1
+===================================
+
+Fixes a bug in Helios preventing class definitions from being compiled
+
+Commits: https://github.com/amber-smalltalk/amber/compare/0.12.0...0.12.1
+Issues:  https://github.com/amber-smalltalk/amber/issues?milestone=9&state=closed
+
+
+11th November 2013 - Release 0.12.0
+===================================
 
 After 3 months of work we are pleased to announce the 0.12.0 release of Amber.
 

+ 103 - 0
CONTRIBUTING.md

@@ -0,0 +1,103 @@
+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 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.
+
+Afterwards, report the issue on one of the following trackers:
+
+* [Amber Issues](https://github.com/amber-smalltalk/amber/issues)
+* [Amber Examples Issues](https://github.com/amber-smalltalk/amber-examples/issues)
+* [Amber Website Issues](https://github.com/amber-smalltalk/amber-website/issues)
+
+
+Developing Amber
+================
+
+If you want to get started developing Amber itself there are a few links to get you started
+
+* [The Roadmap](https://github.com/amber-smalltalk/amber/wiki/Roadmap) gives a rough idea about where Amber is heading towards
+* [The Contributions Page](https://github.com/amber-smalltalk/amber/wiki/Contributions) contains some ideas which we would love to integrate into Amber
+* [The Amber FAQ](https://github.com/amber-smalltalk/amber/wiki/FAQ) contains Answers to commonly arising questions
+* [The Amber CookBook](https://github.com/amber-smalltalk/amber/wiki/Amber-cookbook) contains recipies about working with Amber and its IDE
+* [The Amber Porting Guide](https://github.com/amber-smalltalk/amber/wiki/Porting-code-from-other-Smalltalk-dialects) contains information about porting code from other Smalltalk dialects
+* [The Amber JavaScript Guide](https://github.com/amber-smalltalk/amber/wiki/From-smalltalk-to-javascript-and-back) contains information about how Amber and JavaScript are mapped to each other
+
+If you want to get serious with Amber development you should read the [Coding Conventions](https://github.com/amber-smalltalk/amber/wiki/Coding-conventions)
+and check if you have all development dependencies installed (as indicated in [Getting Started](https://github.com/amber-smalltalk/amber/wiki/Getting-started)):
+
+* Git (to get a clone of the repository)
+* Node.js (to run the Amber development server)
+* NPM (to install required Node.js packages)
+* Bower (to install required client side libraries)
+* Grunt-Cli (to compile Amber on the commandline)
+
+ 
+Setup your Amber clone
+----------------------
+
+1. Create a fork of the repository on GitHub
+2. Clone the repository
+3. Run ```npm install```
+4. Run ```bower install``` (requires bower to be installed via ```npm install -g bower```)
+5. Run ```${Amber_DIR}/bin/amber serve```
+
+Now you should be able to commit changes to your computer.
+
+
+Creating a Pull Request
+-----------------------
+
+The Amber development model currently revolves around Pull Requests which are created through GitHub
+
+1. Update to latest Amber 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 API, update API-CHANGES.txt 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 master branch)
+
+
+Compiling Amber 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 using the following command:
+
+    cd ${Amber_DIR}
+    grunt
+
+For Windows support check the [Grunt.js on Windows](http://gruntjs.com/frequently-asked-questions#does-grunt-work-on-windows) page.

+ 2 - 2
Gruntfile.js

@@ -34,7 +34,7 @@ module.exports = function(grunt) {
         output_dir : 'js',
         src: ['st/Kernel-Objects.st', 'st/Kernel-Classes.st', 'st/Kernel-Methods.st', 'st/Kernel-Collections.st',
               'st/Kernel-Infrastructure.st', 'st/Kernel-Exceptions.st', 'st/Kernel-Transcript.st', 'st/Kernel-Announcements.st',
-              'st/Importer-Exporter.st', 'st/Compiler-Exceptions.st', 'st/Compiler-Core.st', 'st/Compiler-AST.st',
+              'st/Kernel-ImportExport.st', 'st/Compiler-Exceptions.st', 'st/Compiler-Core.st', 'st/Compiler-AST.st',
               'st/Compiler-IR.st', 'st/Compiler-Inlining.st', 'st/Compiler-Semantic.st', 'st/Compiler-Interpreter.st',
               'st/Canvas.st', 'st/SUnit.st', 'st/IDE.st',
               'st/Kernel-Tests.st', 'st/Compiler-Tests.st', 'st/SUnit-Tests.st',
@@ -72,7 +72,7 @@ module.exports = function(grunt) {
         libraries: [
         'Compiler-Exceptions', 'Compiler-Core', 'Compiler-AST',
         'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic', 'Compiler-Interpreter', 'parser',
-        'SUnit', 'Importer-Exporter',
+        'SUnit', 'Kernel-ImportExport',
         'Kernel-Tests', 'Compiler-Tests', 'SUnit-Tests'],
         main_class: 'NodeTestRunner',
         output_name: 'test/amber_test_runner'

+ 3 - 28
README.md

@@ -27,34 +27,9 @@ Amber is released under the MIT license. All contributions made for inclusion ar
 Building Amber
 --------------
 
-Amber uses [Grunt.js](http://gruntjs.com/) as build system since version `0.10.0`.
-
-If you already have Grunt.js v0.3.x installed locally run the following (otherwise ignore these lines):
-
-    cd ${Amber_DIR}
-    npm uninstall grunt
-
-To install Grunt.js v0.4.x on the commandline execute the following commands:
-
-    npm install -g grunt-cli grunt-init
-
-Amber depends on some web libraries to work in browser, using bower to manage these dependencies.
-To install bower, run:
-
-    npm install -g bower
-
-To get all dependencies, run:
-
-    cd ${Amber_DIR}
-    bower install   # dependencies for the web
-    npm install     # dependencies for the cli development
-
-And finally, compile Amber using the following command:
-
-    cd ${Amber_DIR}
-    grunt
-
-For Windows support check the [Grunt.js on Windows](http://gruntjs.com/frequently-asked-questions#does-grunt-work-on-windows) page.
+This step is only used by people developing Amber itself.
+Please refer to [CONTRIBUTING.md](CONTRIBUTING.md) for further details.
+It explains the Amber development setup and how to contribute.
 
 
 More infos

+ 18 - 0
RELEASING.md

@@ -0,0 +1,18 @@
+Release Guide for Amber
+=======================
+
+The following steps are required to make a release of Amber:
+
+1. check that all tests are green
+2. check that the examples are up-to-date
+3. check that `API-CHANGES.txt` is up-to-date
+4. check the `CHANGELOG` file and update the release notes
+5. log in to npm with write access for the Amber package
+6. execute `cli/support/release.sh`
+7. answer the question about the version number used for the release
+8. answer the question about the version number for the upcoming release
+9. merge the created tag into the `stable` branch
+10. update the homepage to point to the latest tag on GitHub
+11. send announcement to mailinglists (Amber, Pharo, what else?)
+12. send announcement on Twitter
+13. send announcement on G+

+ 2 - 1
bower.json

@@ -10,7 +10,8 @@
     "tests"
   ],
   "dependencies": {
-    "jquery": "~1.8.3",
+    "jquery": "~1.10.2",
+    "jquery-ui": "~1.10.3",
     "bootstrap": "http://getbootstrap.com/2.3.2/assets/bootstrap.zip",
     "jquery-tabby": "git://github.com/alanhogan/Tabby",
     "es5-shim": "~2.1.0",

File diff suppressed because it is too large
+ 145 - 171
cli/js/AmberCli.js


+ 11 - 4
cli/st/AmberCli.st

@@ -169,7 +169,9 @@ username: aUsername
 
 checkDirectoryLayout
 	(fs existsSync: self basePath, 'index.html') ifFalse: [
-		console warn: 'Warning: project directory does not contain index.html'].
+		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 custom error page with --fallback-page.'.
 	(fs existsSync: self basePath, 'st') ifFalse: [
 		console warn: 'Warning: project directory is missing an "st" directory'].
 	(fs existsSync: self basePath, 'js') ifFalse: [
@@ -309,7 +311,7 @@ respondFileNamed: aFilename to: aResponse
 		ex notNil 
 			ifTrue: [
 				console log: filename, ' does not exist'.
-				self respondInternalErrorTo: aResponse]
+				self respondNotFoundTo: aResponse]
 			ifFalse: [
 				type := self class mimeTypeFor: filename.
 				type = 'application/javascript'
@@ -337,8 +339,13 @@ respondNotCreatedTo: aResponse
 respondNotFoundTo: aResponse
 	self fallbackPage isNil ifFalse: [^self respondFileNamed: self fallbackPage to: aResponse].
 	aResponse 
-		writeHead: 404 options: #{'Content-Type' -> 'text/plain'};
-		write: '404 Not found';
+		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 display instead of this error page 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
 !
 

File diff suppressed because it is too large
+ 158 - 178
cli/support/amber-cli.js


+ 7 - 5
cli/support/amberc-cli.js

@@ -86,8 +86,8 @@ function handle_options(optionsArray) {
 						// Will end up being the last non js/st argument
 						programName.push(currentItem);
 						break;
-				};
-		};
+				}
+		}
 		currentItem = optionsArray.shift();
 	}
 
@@ -97,7 +97,7 @@ function handle_options(optionsArray) {
 		defaults.program = programName[0];
 	}
 	return defaults;
-};
+}
 
 
 // print available flags
@@ -184,5 +184,7 @@ function print_usage() {
 		'',
 		'        amberc -M main.js myboot.js myKernel.js Cat1.st Cat2.st Program',
 	];
-	usage.forEach(function (line) { console.log(line); });
-};
+	usage.forEach(function (line) {
+        console.log(line);
+	});
+}

+ 13 - 13
cli/support/amberc.js

@@ -2,8 +2,10 @@
  * 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', ['/optional/path/to/compiler.jar]);
- *     compiler.main();
+ *     var compiler = new amberc.Compiler('path/to/amber');
+ *     var options = amberc.createDefaults();
+ *     // edit options entries
+ *     compiler.main(options);
  *
  * Execute 'node compiler.js' without arguments or with -h / --help for help.
  */
@@ -109,10 +111,10 @@ Combo.prototype = {
 			self.check(id, arguments);
 		};
 	},
-	check: function (id, arguments) {
-		this.results[id] = Array.prototype.slice.call(arguments);
+	check: function (id, theArguments) {
+		this.results[id] = Array.prototype.slice.call(theArguments);
 		this.items--;
-		if (this.items == 0) {
+		if (this.items === 0) {
 			this.callback.apply(this, this.results);
 		}
 	}
@@ -136,7 +138,7 @@ function AmberC(amber_dir) {
 	this.kernel_libraries = ['boot', 'smalltalk', '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', 'Importer-Exporter', 'Compiler-Exceptions',
+	this.compiler_libraries = this.kernel_libraries.concat(['parser', 'Kernel-ImportExport', 'Compiler-Exceptions',
 							'Compiler-Core', 'Compiler-AST', 'Compiler-Exceptions', 'Compiler-IR', 'Compiler-Inlining', 'Compiler-Semantic']);
 }
 
@@ -180,7 +182,7 @@ AmberC.prototype.main = function(configuration, finished_callback) {
 		configuration.finished_callback = finished_callback;
 	}
 
-	if (configuration.amd_namespace.length == 0) {
+	if (configuration.amd_namespace.length === 0) {
 		configuration.amd_namespace = 'amber_core';
 	}
 
@@ -210,7 +212,7 @@ AmberC.prototype.check_configuration_ok = function(configuration) {
 		throw new Error('AmberC.check_configuration_ok(): missing configuration object');
 	}
 
-	if (0 === configuration.jsFiles.length && 0 === configuration.stFiles.lenght) {
+	if (0 === configuration.jsFiles.length && 0 === configuration.stFiles.length) {
 		throw new Error('AmberC.check_configuration_ok(): no files to compile/link specified in configuration object');
 	}
 	return true;
@@ -387,7 +389,7 @@ AmberC.prototype.resolve_compiler = function(callback) {
 		});
 		callback(compilerFiles);
 	});
-	var self = this
+	var self = this;
 	compiler_files.forEach(function(file) {
 		self.resolve_js(file, compiler_resolved.add());
 	});
@@ -424,7 +426,7 @@ AmberC.prototype.create_compiler = function(compilerFilesArray) {
 		console.log('Compiler loaded');
 		self.defaults.smalltalk.ErrorHandler._setCurrent_(self.defaults.smalltalk.RethrowErrorHandler._new());
 
-		if(0 != self.defaults.jsGlobals.length) {
+		if(0 !== self.defaults.jsGlobals.length) {
 			var jsGlobalVariables = self.defaults.smalltalk.globalJsVariables;
 			jsGlobalVariables.push.apply(jsGlobalVariables, self.defaults.jsGlobals);
 		}
@@ -444,7 +446,7 @@ AmberC.prototype.create_compiler = function(compilerFilesArray) {
  * Followed by category_export().
  */
 AmberC.prototype.compile = function() {
-	console.log('Compiling collected .st files')
+	console.log('Compiling collected .st files');
 	// import .st files
 	var self = this;
 	var imports = new Combo(function() {
@@ -491,7 +493,6 @@ AmberC.prototype.category_export = function() {
 		jsFile = path.join(jsFilePath, jsFile);
 		defaults.compiled.push(jsFile);
 		var smalltalk = defaults.smalltalk;
-		var pluggableExporter = smalltalk.PluggableExporter;
 		var packageObject = smalltalk.Package._named_(category);
 		packageObject._transport()._namespace_(defaults.amd_namespace);
 		fs.writeFile(jsFile, smalltalk.String._streamContents_(function (stream) {
@@ -535,7 +536,6 @@ AmberC.prototype.verify = function() {
  */
 AmberC.prototype.compose_js_files = function() {
 	var defaults = this.defaults;
-	var self = this;
 	var programFile = defaults.program;
 	if (undefined === programFile) {
 		return;

+ 42 - 152
js/Canvas.js

@@ -93,7 +93,6 @@ referencedClasses: []
 smalltalk.BrowserInterface);
 
 
-smalltalk.BrowserInterface.klass.iVarNames = ['uiWorker','ajaxWorker'];
 
 smalltalk.addClass('HTMLCanvas', smalltalk.Object, ['root'], 'Canvas');
 smalltalk.HTMLCanvas.comment="I am a canvas for building HTML.\x0a\x0aI provide the `#tag:` method to create a `TagBrush` (wrapping a DOM element) and convenience methods in the `tags` protocol.\x0a\x0a## API\x0a\x0aMy instances are used as the argument of the `#renderOn:` method of `Widget` objects.\x0a\x0aThe `#with:` method is used to compose HTML, nesting tags. `#with:` can take a `TagBrush`, a `String`, a `BlockClosure` or a `Widget` as argument.\x0a\x0a## Usage example:\x0a\x0a    aCanvas a \x0a        with: [ aCanvas span with: 'click me' ];\x0a        onClick: [ window alert: 'clicked!' ]";
@@ -1823,16 +1822,15 @@ selector: "style",
 category: 'tags',
 fn: function (){
 var self=this;
-function $StyleTag(){return smalltalk.StyleTag||(typeof StyleTag=="undefined"?nil:StyleTag)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(self["@root"])._addBrush_(_st($StyleTag())._canvas_(self));
+$1=self._tag_("style");
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"style",{},smalltalk.HTMLCanvas)})},
 args: [],
-source: "style\x0a\x09^ root addBrush: (StyleTag canvas: self)",
-messageSends: ["addBrush:", "canvas:"],
-referencedClasses: ["StyleTag"]
+source: "style\x0a\x09^ self tag: 'style'",
+messageSends: ["tag:"],
+referencedClasses: []
 }),
 smalltalk.HTMLCanvas);
 
@@ -2182,104 +2180,6 @@ referencedClasses: []
 smalltalk.HTMLCanvas);
 
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "browserVersion",
-category: 'instance creation',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(_st(jQuery)._at_("browser"))._version();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"browserVersion",{},smalltalk.HTMLCanvas.klass)})},
-args: [],
-source: "browserVersion\x0a\x09^ (jQuery at: #browser) version",
-messageSends: ["version", "at:"],
-referencedClasses: []
-}),
-smalltalk.HTMLCanvas.klass);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "isMSIE",
-category: 'instance creation',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=_st(_st(jQuery)._at_("browser"))._at_("msie");
-$ctx1.sendIdx["at:"]=1;
-$1=_st($2)._notNil();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"isMSIE",{},smalltalk.HTMLCanvas.klass)})},
-args: [],
-source: "isMSIE\x0a\x09^ ((jQuery at: #browser) at: #msie) notNil",
-messageSends: ["notNil", "at:"],
-referencedClasses: []
-}),
-smalltalk.HTMLCanvas.klass);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "isMozilla",
-category: 'instance creation',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=_st(_st(jQuery)._at_("browser"))._at_("mozilla");
-$ctx1.sendIdx["at:"]=1;
-$1=_st($2)._notNil();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"isMozilla",{},smalltalk.HTMLCanvas.klass)})},
-args: [],
-source: "isMozilla\x0a\x09^ ((jQuery at: #browser) at: #mozilla) notNil",
-messageSends: ["notNil", "at:"],
-referencedClasses: []
-}),
-smalltalk.HTMLCanvas.klass);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "isOpera",
-category: 'instance creation',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=_st(_st(jQuery)._at_("browser"))._at_("opera");
-$ctx1.sendIdx["at:"]=1;
-$1=_st($2)._notNil();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"isOpera",{},smalltalk.HTMLCanvas.klass)})},
-args: [],
-source: "isOpera\x0a\x09^ ((jQuery at: #browser) at: #opera) notNil",
-messageSends: ["notNil", "at:"],
-referencedClasses: []
-}),
-smalltalk.HTMLCanvas.klass);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "isWebkit",
-category: 'instance creation',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=_st(_st(jQuery)._at_("browser"))._at_("webkit");
-$ctx1.sendIdx["at:"]=1;
-$1=_st($2)._notNil();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"isWebkit",{},smalltalk.HTMLCanvas.klass)})},
-args: [],
-source: "isWebkit\x0a\x09^ ((jQuery at: #browser) at: #webkit) notNil",
-messageSends: ["notNil", "at:"],
-referencedClasses: []
-}),
-smalltalk.HTMLCanvas.klass);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "onJQuery:",
@@ -2759,6 +2659,44 @@ referencedClasses: []
 }),
 smalltalk.TagBrush);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "at:",
+category: 'attributes',
+fn: function (aString){
+var self=this;
+function $Collection(){return smalltalk.Collection||(typeof Collection=="undefined"?nil:Collection)}
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self._at_ifAbsent_(aString,(function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st($Collection())._new())._errorNotFound();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"at:",{aString:aString},smalltalk.TagBrush)})},
+args: ["aString"],
+source: "at: aString\x0a\x09^ self at: aString ifAbsent: [ Collection new errorNotFound ]",
+messageSends: ["at:ifAbsent:", "errorNotFound", "new"],
+referencedClasses: ["Collection"]
+}),
+smalltalk.TagBrush);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "at:ifAbsent:",
+category: 'attributes',
+fn: function (aString,aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return self['@element'].hasAttribute(aString) ? self['@element'].getAttribute(aString) : aBlock._value();
+return self}, function($ctx1) {$ctx1.fill(self,"at:ifAbsent:",{aString:aString,aBlock:aBlock},smalltalk.TagBrush)})},
+args: ["aString", "aBlock"],
+source: "at: aString ifAbsent: aBlock\x0a\x09<return self['@element'].hasAttribute(aString) ? self['@element'].getAttribute(aString) : aBlock._value()>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.TagBrush);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "at:put:",
@@ -3705,54 +3643,6 @@ referencedClasses: []
 smalltalk.TagBrush.klass);
 
 
-smalltalk.addClass('StyleTag', smalltalk.TagBrush, [], 'Canvas');
-smalltalk.StyleTag.comment="I'm a `<style>` tag use to inline CSS or load a stylesheet.\x0a\x0a## Motivation\x0a\x0aThe need for a specific class comes from Internet Explorer compatibility issues.";
-smalltalk.addMethod(
-smalltalk.method({
-selector: "with:",
-category: 'adding',
-fn: function (aString){
-var self=this;
-function $HTMLCanvas(){return smalltalk.HTMLCanvas||(typeof HTMLCanvas=="undefined"?nil:HTMLCanvas)}
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st($HTMLCanvas())._isMSIE();
-if(smalltalk.assert($1)){
-_st(_st(self._element())._styleSheet())._cssText_(aString);
-} else {
-smalltalk.StyleTag.superclass.fn.prototype._with_.apply(_st(self), [aString]);
-};
-return self}, function($ctx1) {$ctx1.fill(self,"with:",{aString:aString},smalltalk.StyleTag)})},
-args: ["aString"],
-source: "with: aString\x0a\x09HTMLCanvas isMSIE\x0a\x09\x09ifTrue: [ self element styleSheet cssText: aString ]\x0a\x09\x09ifFalse: [ super with: aString ].",
-messageSends: ["ifTrue:ifFalse:", "isMSIE", "cssText:", "styleSheet", "element", "with:"],
-referencedClasses: ["HTMLCanvas"]
-}),
-smalltalk.StyleTag);
-
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "canvas:",
-category: 'instance creation',
-fn: function (aCanvas){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1;
-$2=self._new();
-_st($2)._initializeFromString_canvas_("style",aCanvas);
-$3=_st($2)._yourself();
-$1=$3;
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"canvas:",{aCanvas:aCanvas},smalltalk.StyleTag.klass)})},
-args: ["aCanvas"],
-source: "canvas: aCanvas\x0a\x09^ self new\x0a\x09\x09initializeFromString: 'style' canvas: aCanvas;\x0a\x09\x09yourself",
-messageSends: ["initializeFromString:canvas:", "new", "yourself"],
-referencedClasses: []
-}),
-smalltalk.StyleTag.klass);
-
-
 smalltalk.addClass('Widget', smalltalk.InterfacingObject, [], 'Canvas');
 smalltalk.Widget.comment="I am a presenter building HTML. Subclasses are typically reusable components.\x0a\x0a## API\x0a\x0aUse `#renderContentOn:` to build HTML. (See `HTMLCanvas` and `TagBrush` classes for more about building HTML).\x0a\x0aTo add a widget to the page, the convenience method `#appendToJQuery:` is very useful.\x0a\x0aExemple: \x0a\x0a    Counter new appendToJQuery: 'body' asJQuery";
 smalltalk.addMethod(

+ 4 - 7
js/Compiler-AST.js

@@ -630,20 +630,17 @@ return smalltalk.withContext(function($ctx2) {
 return self._shouldBeInlined();
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})})))._or_((function(){
 return smalltalk.withContext(function($ctx2) {
-return _st(_st(self._nodes())._detect_ifNone_((function(each){
+return _st(self._nodes())._anySatisfy_((function(each){
 return smalltalk.withContext(function($ctx3) {
 return _st(each)._subtreeNeedsAliasing();
-}, function($ctx3) {$ctx3.fillBlock({each:each},$ctx2,3)})}),(function(){
-return smalltalk.withContext(function($ctx3) {
-return false;
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,4)})}))).__tild_eq(false);
+}, function($ctx3) {$ctx3.fillBlock({each:each},$ctx2,3)})}));
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
 $ctx1.sendIdx["or:"]=1;
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"subtreeNeedsAliasing",{},smalltalk.Node)})},
 args: [],
-source: "subtreeNeedsAliasing\x0a\x09^ (self shouldBeAliased or: [ self shouldBeInlined ]) or: [\x0a\x09\x09(self nodes detect: [ :each | each subtreeNeedsAliasing ] ifNone: [ false ]) ~= false ]",
-messageSends: ["or:", "shouldBeAliased", "shouldBeInlined", "~=", "detect:ifNone:", "nodes", "subtreeNeedsAliasing"],
+source: "subtreeNeedsAliasing\x0a\x09^ (self shouldBeAliased or: [ self shouldBeInlined ]) or: [\x0a\x09\x09self nodes anySatisfy: [ :each | each subtreeNeedsAliasing ] ]",
+messageSends: ["or:", "shouldBeAliased", "shouldBeInlined", "anySatisfy:", "nodes", "subtreeNeedsAliasing"],
 referencedClasses: []
 }),
 smalltalk.Node);

+ 40 - 33
js/IDE.js

@@ -492,13 +492,20 @@ selector: "initialize",
 category: 'initialization',
 fn: function (){
 var self=this;
+function $ErrorHandler(){return smalltalk.ErrorHandler||(typeof ErrorHandler=="undefined"?nil:ErrorHandler)}
 return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st($ErrorHandler())._current();
+if(($receiver = $1) == nil || $receiver == null){
 self._register();
+} else {
+$1;
+};
 return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},smalltalk.DebugErrorHandler.klass)})},
 args: [],
-source: "initialize\x0a\x09self register",
-messageSends: ["register"],
-referencedClasses: []
+source: "initialize\x0a\x09ErrorHandler current ifNil: [ self register ]",
+messageSends: ["ifNil:", "current", "register"],
+referencedClasses: ["ErrorHandler"]
 }),
 smalltalk.DebugErrorHandler.klass);
 
@@ -7398,27 +7405,21 @@ var $1;
 variables=_st($Dictionary())._new();
 _st(variables)._at_put_("#self",self);
 $ctx1.sendIdx["at:put:"]=1;
-_st(variables)._at_put_("#home",self._home());
+_st(variables)._at_put_("#keys",self._keys());
 $ctx1.sendIdx["at:put:"]=2;
-_st(variables)._at_put_("#receiver",self._receiver());
-$ctx1.sendIdx["at:put:"]=3;
-_st(variables)._at_put_("#selector",self._selector());
-$ctx1.sendIdx["at:put:"]=4;
-_st(variables)._at_put_("#temps",self._temps());
-$ctx1.sendIdx["at:put:"]=5;
-_st(_st(self._class())._instanceVariableNames())._do_((function(each){
+self._keysAndValuesDo_((function(key,value){
 return smalltalk.withContext(function($ctx2) {
-return _st(variables)._at_put_(each,self._instVarAt_(each));
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return _st(variables)._at_put_(key,value);
+}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1,1)})}));
 _st(anInspector)._setLabel_(self._printString());
 $1=_st(anInspector)._setVariables_(variables);
-return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},smalltalk.MethodContext)})},
+return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},smalltalk.HashedCollection)})},
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#home' put: self home.\x0a\x09variables at: '#receiver' put: self receiver.\x0a\x09variables at: '#selector' put: self selector.\x0a\x09variables at: '#temps' put: self temps.\x0a\x09self class instanceVariableNames do: [ :each |\x0a\x09\x09variables at: each put: (self instVarAt: each) ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-messageSends: ["new", "at:put:", "home", "receiver", "selector", "temps", "do:", "instanceVariableNames", "class", "instVarAt:", "setLabel:", "printString", "setVariables:"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#keys' put: self keys.\x0a\x09self keysAndValuesDo: [ :key :value |\x0a\x09\x09variables at: key put: value ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
+messageSends: ["new", "at:put:", "keys", "keysAndValuesDo:", "setLabel:", "printString", "setVariables:"],
 referencedClasses: ["Dictionary"]
 }),
-smalltalk.MethodContext);
+smalltalk.HashedCollection);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -7433,21 +7434,19 @@ var $1;
 variables=_st($Dictionary())._new();
 _st(variables)._at_put_("#self",self);
 $ctx1.sendIdx["at:put:"]=1;
-_st(variables)._at_put_("#keys",self._keys());
-$ctx1.sendIdx["at:put:"]=2;
-self._keysAndValuesDo_((function(key,value){
+_st(self["@elements"])._withIndexDo_((function(each,i){
 return smalltalk.withContext(function($ctx2) {
-return _st(variables)._at_put_(key,value);
-}, function($ctx2) {$ctx2.fillBlock({key:key,value:value},$ctx1,1)})}));
+return _st(variables)._at_put_(i,each);
+}, function($ctx2) {$ctx2.fillBlock({each:each,i:i},$ctx1,1)})}));
 _st(anInspector)._setLabel_(self._printString());
 $1=_st(anInspector)._setVariables_(variables);
-return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},smalltalk.HashedCollection)})},
+return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},smalltalk.Set)})},
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#keys' put: self keys.\x0a\x09self keysAndValuesDo: [ :key :value |\x0a\x09\x09variables at: key put: value ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-messageSends: ["new", "at:put:", "keys", "keysAndValuesDo:", "setLabel:", "printString", "setVariables:"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09elements withIndexDo: [ :each :i |\x0a\x09\x09variables at: i put: each ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
+messageSends: ["new", "at:put:", "withIndexDo:", "setLabel:", "printString", "setVariables:"],
 referencedClasses: ["Dictionary"]
 }),
-smalltalk.HashedCollection);
+smalltalk.Set);
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -7462,18 +7461,26 @@ var $1;
 variables=_st($Dictionary())._new();
 _st(variables)._at_put_("#self",self);
 $ctx1.sendIdx["at:put:"]=1;
-_st(self["@elements"])._withIndexDo_((function(each,i){
+_st(variables)._at_put_("#home",self._home());
+$ctx1.sendIdx["at:put:"]=2;
+_st(variables)._at_put_("#receiver",self._receiver());
+$ctx1.sendIdx["at:put:"]=3;
+_st(variables)._at_put_("#selector",self._selector());
+$ctx1.sendIdx["at:put:"]=4;
+_st(variables)._at_put_("#temps",self._temps());
+$ctx1.sendIdx["at:put:"]=5;
+_st(_st(self._class())._instanceVariableNames())._do_((function(each){
 return smalltalk.withContext(function($ctx2) {
-return _st(variables)._at_put_(i,each);
-}, function($ctx2) {$ctx2.fillBlock({each:each,i:i},$ctx1,1)})}));
+return _st(variables)._at_put_(each,self._instVarAt_(each));
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 _st(anInspector)._setLabel_(self._printString());
 $1=_st(anInspector)._setVariables_(variables);
-return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},smalltalk.Set)})},
+return self}, function($ctx1) {$ctx1.fill(self,"inspectOn:",{anInspector:anInspector,variables:variables},smalltalk.MethodContext)})},
 args: ["anInspector"],
-source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09elements withIndexDo: [ :each :i |\x0a\x09\x09variables at: i put: each ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
-messageSends: ["new", "at:put:", "withIndexDo:", "setLabel:", "printString", "setVariables:"],
+source: "inspectOn: anInspector\x0a\x09| variables |\x0a\x09variables := Dictionary new.\x0a\x09variables at: '#self' put: self.\x0a\x09variables at: '#home' put: self home.\x0a\x09variables at: '#receiver' put: self receiver.\x0a\x09variables at: '#selector' put: self selector.\x0a\x09variables at: '#temps' put: self temps.\x0a\x09self class instanceVariableNames do: [ :each |\x0a\x09\x09variables at: each put: (self instVarAt: each) ].\x0a\x09anInspector\x0a\x09\x09setLabel: self printString;\x0a\x09\x09setVariables: variables",
+messageSends: ["new", "at:put:", "home", "receiver", "selector", "temps", "do:", "instanceVariableNames", "class", "instVarAt:", "setLabel:", "printString", "setVariables:"],
 referencedClasses: ["Dictionary"]
 }),
-smalltalk.Set);
+smalltalk.MethodContext);
 
 });

+ 29 - 35
js/Kernel-Announcements.js

@@ -240,6 +240,34 @@ referencedClasses: ["AnnouncementSubscription"]
 }),
 smalltalk.Announcer);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "on:doOnce:",
+category: 'subscribing',
+fn: function (aClass,aBlock){
+var self=this;
+var subscription;
+function $AnnouncementSubscription(){return smalltalk.AnnouncementSubscription||(typeof AnnouncementSubscription=="undefined"?nil:AnnouncementSubscription)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st($AnnouncementSubscription())._new();
+_st($1)._announcementClass_(aClass);
+$2=_st($1)._yourself();
+subscription=$2;
+_st(subscription)._valuable_((function(ann){
+return smalltalk.withContext(function($ctx2) {
+_st(self["@subscriptions"])._remove_(subscription);
+return _st(aBlock)._value_(ann);
+}, function($ctx2) {$ctx2.fillBlock({ann:ann},$ctx1,1)})}));
+_st(self["@subscriptions"])._add_(subscription);
+return self}, function($ctx1) {$ctx1.fill(self,"on:doOnce:",{aClass:aClass,aBlock:aBlock,subscription:subscription},smalltalk.Announcer)})},
+args: ["aClass", "aBlock"],
+source: "on: aClass doOnce: aBlock\x0a\x09| subscription |\x0a\x09\x0a\x09subscription := AnnouncementSubscription new\x0a\x09\x09announcementClass: aClass;\x0a\x09\x09yourself.\x0a\x09subscription valuable: [ :ann |\x0a\x09\x09subscriptions remove: subscription.\x0a\x09\x09aBlock value: ann ].\x0a\x0a\x09subscriptions add: subscription",
+messageSends: ["announcementClass:", "new", "yourself", "valuable:", "remove:", "value:", "add:"],
+referencedClasses: ["AnnouncementSubscription"]
+}),
+smalltalk.Announcer);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "on:send:to:",
@@ -339,42 +367,8 @@ referencedClasses: []
 smalltalk.SystemAnnouncer.klass);
 
 
-smalltalk.addClass('SystemAnnouncement', smalltalk.Object, ['theClass'], 'Kernel-Announcements');
+smalltalk.addClass('SystemAnnouncement', smalltalk.Object, [], 'Kernel-Announcements');
 smalltalk.SystemAnnouncement.comment="I am the superclass of all system announcements";
-smalltalk.addMethod(
-smalltalk.method({
-selector: "theClass",
-category: 'accessing',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=self["@theClass"];
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"theClass",{},smalltalk.SystemAnnouncement)})},
-args: [],
-source: "theClass\x0a\x09^ theClass",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.SystemAnnouncement);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "theClass:",
-category: 'accessing',
-fn: function (aClass){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-self["@theClass"]=aClass;
-return self}, function($ctx1) {$ctx1.fill(self,"theClass:",{aClass:aClass},smalltalk.SystemAnnouncement)})},
-args: ["aClass"],
-source: "theClass: aClass\x0a\x09theClass := aClass",
-messageSends: [],
-referencedClasses: []
-}),
-smalltalk.SystemAnnouncement);
-
 
 smalltalk.addMethod(
 smalltalk.method({

+ 35 - 15
js/Kernel-Classes.js

@@ -33,7 +33,7 @@ function $MethodAdded(){return smalltalk.MethodAdded||(typeof MethodAdded=="unde
 function $MethodModified(){return smalltalk.MethodModified||(typeof MethodModified=="undefined"?nil:MethodModified)}
 function $SystemAnnouncer(){return smalltalk.SystemAnnouncer||(typeof SystemAnnouncer=="undefined"?nil:SystemAnnouncer)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$3,$1,$4,$5,$6,$7,$8;
+var $2,$3,$1,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13;
 oldMethod=_st(self._methodDictionary())._at_ifAbsent_(_st(aMethod)._selector(),(function(){
 return smalltalk.withContext(function($ctx2) {
 return nil;
@@ -43,30 +43,50 @@ $3=_st(aMethod)._protocol();
 $ctx1.sendIdx["protocol"]=1;
 $1=_st($2)._includes_($3);
 if(! smalltalk.assert($1)){
-_st(self._organization())._addElement_(_st(aMethod)._protocol());
+$4=self._organization();
+$ctx1.sendIdx["organization"]=1;
+$5=_st(aMethod)._protocol();
+$ctx1.sendIdx["protocol"]=2;
+_st($4)._addElement_($5);
 };
 self._basicAddCompiledMethod_(aMethod);
-$4=oldMethod;
-if(($receiver = $4) == nil || $receiver == null){
-$5=_st($MethodAdded())._new();
+$6=oldMethod;
+if(($receiver = $6) == nil || $receiver == null){
+$6;
+} else {
+_st(_st(self._methods())._select_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$7=_st(each)._protocol();
+$ctx2.sendIdx["protocol"]=3;
+$8=_st(oldMethod)._protocol();
+$ctx2.sendIdx["protocol"]=4;
+return _st($7).__eq($8);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,4)})})))._ifEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._organization())._removeElement_(_st(oldMethod)._protocol());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}));
+};
+$9=oldMethod;
+if(($receiver = $9) == nil || $receiver == null){
+$10=_st($MethodAdded())._new();
 $ctx1.sendIdx["new"]=1;
-_st($5)._method_(aMethod);
+_st($10)._method_(aMethod);
 $ctx1.sendIdx["method:"]=1;
-$6=_st($5)._yourself();
+$11=_st($10)._yourself();
 $ctx1.sendIdx["yourself"]=1;
-announcement=$6;
+announcement=$11;
 } else {
-$7=_st($MethodModified())._new();
-_st($7)._oldMethod_(oldMethod);
-_st($7)._method_(aMethod);
-$8=_st($7)._yourself();
-announcement=$8;
+$12=_st($MethodModified())._new();
+_st($12)._oldMethod_(oldMethod);
+_st($12)._method_(aMethod);
+$13=_st($12)._yourself();
+announcement=$13;
 };
 _st(_st($SystemAnnouncer())._current())._announce_(announcement);
 return self}, function($ctx1) {$ctx1.fill(self,"addCompiledMethod:",{aMethod:aMethod,oldMethod:oldMethod,announcement:announcement},smalltalk.Behavior)})},
 args: ["aMethod"],
-source: "addCompiledMethod: aMethod\x0a\x09| oldMethod announcement |\x0a\x09\x0a\x09oldMethod := self methodDictionary\x0a\x09\x09at: aMethod selector\x0a\x09\x09ifAbsent: [ nil ].\x0a\x09\x0a\x09(self protocols includes: aMethod protocol)\x0a\x09\x09ifFalse: [ self organization addElement: aMethod protocol ].\x0a\x0a\x09self basicAddCompiledMethod: aMethod.\x0a\x09\x0a\x09announcement := oldMethod\x0a\x09\x09ifNil: [\x0a\x09\x09\x09MethodAdded new\x0a\x09\x09\x09\x09\x09method: aMethod;\x0a\x09\x09\x09\x09\x09yourself ]\x0a\x09\x09ifNotNil: [\x0a\x09\x09\x09MethodModified new\x0a\x09\x09\x09\x09\x09oldMethod: oldMethod;\x0a\x09\x09\x09\x09\x09method: aMethod;\x0a\x09\x09\x09\x09\x09yourself ].\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x0a\x09SystemAnnouncer current\x0a\x09\x09\x09\x09announce: announcement",
-messageSends: ["at:ifAbsent:", "methodDictionary", "selector", "ifFalse:", "includes:", "protocols", "protocol", "addElement:", "organization", "basicAddCompiledMethod:", "ifNil:ifNotNil:", "method:", "new", "yourself", "oldMethod:", "announce:", "current"],
+source: "addCompiledMethod: aMethod\x0a\x09| oldMethod announcement |\x0a\x09\x0a\x09oldMethod := self methodDictionary\x0a\x09\x09at: aMethod selector\x0a\x09\x09ifAbsent: [ nil ].\x0a\x09\x0a\x09(self protocols includes: aMethod protocol)\x0a\x09\x09ifFalse: [ self organization addElement: aMethod protocol ].\x0a\x0a\x09self basicAddCompiledMethod: aMethod.\x0a\x09\x0a\x09oldMethod ifNotNil: [\x0a\x09\x09(self methods\x0a\x09\x09\x09select: [ :each | each protocol = oldMethod protocol ])\x0a\x09\x09\x09ifEmpty: [ self organization removeElement: oldMethod protocol ] ].\x0a\x09\x0a\x09announcement := oldMethod\x0a\x09\x09ifNil: [\x0a\x09\x09\x09MethodAdded new\x0a\x09\x09\x09\x09\x09method: aMethod;\x0a\x09\x09\x09\x09\x09yourself ]\x0a\x09\x09ifNotNil: [\x0a\x09\x09\x09MethodModified new\x0a\x09\x09\x09\x09\x09oldMethod: oldMethod;\x0a\x09\x09\x09\x09\x09method: aMethod;\x0a\x09\x09\x09\x09\x09yourself ].\x0a\x09\x09\x09\x09\x09\x0a\x09\x09\x09\x09\x09\x0a\x09SystemAnnouncer current\x0a\x09\x09\x09\x09announce: announcement",
+messageSends: ["at:ifAbsent:", "methodDictionary", "selector", "ifFalse:", "includes:", "protocols", "protocol", "addElement:", "organization", "basicAddCompiledMethod:", "ifNotNil:", "ifEmpty:", "select:", "methods", "=", "removeElement:", "ifNil:ifNotNil:", "method:", "new", "yourself", "oldMethod:", "announce:", "current"],
 referencedClasses: ["MethodAdded", "MethodModified", "SystemAnnouncer"]
 }),
 smalltalk.Behavior);

+ 319 - 56
js/Kernel-Collections.js

@@ -209,6 +209,89 @@ referencedClasses: []
 }),
 smalltalk.Collection);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "allSatisfy:",
+category: 'enumerating',
+fn: function (aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+var $early={};
+try {
+self._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(aBlock)._value_(each);
+if(! smalltalk.assert($1)){
+throw $early=[false];
+};
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return true;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"allSatisfy:",{aBlock:aBlock},smalltalk.Collection)})},
+args: ["aBlock"],
+source: "allSatisfy: aBlock\x0a\x09\x22Evaluate aBlock with the elements of the receiver.\x0a\x09If aBlock returns false for any element return false.\x0a\x09Otherwise return true.\x22\x0a\x0a\x09self do: [ :each | (aBlock value: each) ifFalse: [ ^ false ] ].\x0a\x09^ true",
+messageSends: ["do:", "ifFalse:", "value:"],
+referencedClasses: []
+}),
+smalltalk.Collection);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "anyOne",
+category: 'adding/removing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $early={};
+try {
+self._ifEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._error_("Collection is empty");
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+self._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+throw $early=[each];
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})}));
+return self}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"anyOne",{},smalltalk.Collection)})},
+args: [],
+source: "anyOne\x0a\x09\x22Answer a representative sample of the receiver. This method can\x0a\x09be helpful when needing to preinfer the nature of the contents of \x0a\x09semi-homogeneous collections.\x22\x0a\x0a\x09self ifEmpty: [ self error: 'Collection is empty' ].\x0a\x09self do: [ :each | ^ each ]",
+messageSends: ["ifEmpty:", "error:", "do:"],
+referencedClasses: []
+}),
+smalltalk.Collection);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "anySatisfy:",
+category: 'enumerating',
+fn: function (aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+var $early={};
+try {
+self._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(aBlock)._value_(each);
+if(smalltalk.assert($1)){
+throw $early=[true];
+};
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return false;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"anySatisfy:",{aBlock:aBlock},smalltalk.Collection)})},
+args: ["aBlock"],
+source: "anySatisfy: aBlock\x0a\x09\x22Evaluate aBlock with the elements of the receiver.\x0a\x09If aBlock returns true for any element return true.\x0a\x09Otherwise return false.\x22\x0a\x0a\x09self do: [ :each | (aBlock value: each) ifTrue: [ ^ true ] ].\x0a\x09^ false",
+messageSends: ["do:", "ifTrue:", "value:"],
+referencedClasses: []
+}),
+smalltalk.Collection);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "asArray",
@@ -318,22 +401,13 @@ fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-var $early={};
-try {
-self._do_((function(each){
-return smalltalk.withContext(function($ctx2) {
-$1=_st(aBlock)._value_(each);
-if(smalltalk.assert($1)){
-throw $early=[true];
-};
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
-return false;
-}
-catch(e) {if(e===$early)return e[0]; throw e}
+self._deprecatedAPI();
+$1=self._anySatisfy_(aBlock);
+return $1;
 }, function($ctx1) {$ctx1.fill(self,"contains:",{aBlock:aBlock},smalltalk.Collection)})},
 args: ["aBlock"],
-source: "contains: aBlock\x0a\x09\x22Evaluate aBlock with the elements of the receiver.\x0a\x09If aBlock returns true for any element return true.\x0a\x09Otherwise return false.\x22\x0a\x0a\x09self do: [ :each | (aBlock value: each) ifTrue: [ ^ true ] ].\x0a\x09^ false",
-messageSends: ["do:", "ifTrue:", "value:"],
+source: "contains: aBlock\x0a\x09self deprecatedAPI.\x0a\x0a\x09^ self anySatisfy: aBlock",
+messageSends: ["deprecatedAPI", "anySatisfy:"],
 referencedClasses: []
 }),
 smalltalk.Collection);
@@ -505,16 +579,34 @@ var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
 $2=self._isEmpty();
-if(smalltalk.assert($2)){
-$1=_st(aBlock)._value();
-} else {
-$1=self;
-};
+$1=_st($2)._ifTrue_ifFalse_(aBlock,(function(){
+return smalltalk.withContext(function($ctx2) {
+return self;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"ifEmpty:",{aBlock:aBlock},smalltalk.Collection)})},
 args: ["aBlock"],
-source: "ifEmpty: aBlock\x0a\x09\x22Evaluate the given block with the receiver as argument, answering its value if the receiver is empty, otherwise answer the receiver. Note that the fact that this method returns its argument in case the receiver is not empty allows one to write expressions like the following ones: self classifyMethodAs:\x0a\x09\x09(myProtocol ifEmpty: ['As yet unclassified'])\x22\x0a\x09^ self isEmpty\x0a\x09\x09ifTrue: [ aBlock value ]\x0a\x09\x09ifFalse: [ self ]",
-messageSends: ["ifTrue:ifFalse:", "isEmpty", "value"],
+source: "ifEmpty: aBlock\x0a\x09\x22Evaluate the given block with the receiver as argument, answering its value if the receiver is empty, otherwise answer the receiver. \x0a\x09Note that the fact that this method returns its argument in case the receiver is not empty allows one to write expressions like the following ones: \x0a\x09\x09self classifyMethodAs:\x0a\x09\x09\x09(myProtocol ifEmpty: ['As yet unclassified'])\x22\x0a\x09^ self isEmpty\x0a\x09\x09ifTrue: aBlock\x0a\x09\x09ifFalse: [ self ]",
+messageSends: ["ifTrue:ifFalse:", "isEmpty"],
+referencedClasses: []
+}),
+smalltalk.Collection);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "ifEmpty:ifNotEmpty:",
+category: 'testing',
+fn: function (aBlock,anotherBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self._isEmpty();
+$1=_st($2)._ifTrue_ifFalse_(aBlock,anotherBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"ifEmpty:ifNotEmpty:",{aBlock:aBlock,anotherBlock:anotherBlock},smalltalk.Collection)})},
+args: ["aBlock", "anotherBlock"],
+source: "ifEmpty: aBlock ifNotEmpty: anotherBlock\x0a\x09^ self isEmpty\x0a\x09\x09ifTrue: aBlock\x0a\x09\x09ifFalse: anotherBlock",
+messageSends: ["ifTrue:ifFalse:", "isEmpty"],
 referencedClasses: []
 }),
 smalltalk.Collection);
@@ -526,13 +618,36 @@ category: 'testing',
 fn: function (aBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=self._notEmpty();
-_st($1)._ifTrue_(aBlock);
-return self}, function($ctx1) {$ctx1.fill(self,"ifNotEmpty:",{aBlock:aBlock},smalltalk.Collection)})},
+var $2,$1;
+$2=self._notEmpty();
+$1=_st($2)._ifTrue_ifFalse_(aBlock,(function(){
+return smalltalk.withContext(function($ctx2) {
+return self;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"ifNotEmpty:",{aBlock:aBlock},smalltalk.Collection)})},
 args: ["aBlock"],
-source: "ifNotEmpty: aBlock\x0a\x09self notEmpty ifTrue: aBlock.",
-messageSends: ["ifTrue:", "notEmpty"],
+source: "ifNotEmpty: aBlock\x0a\x09^ self notEmpty\x0a\x09\x09ifTrue: aBlock\x0a\x09\x09ifFalse: [ self ]",
+messageSends: ["ifTrue:ifFalse:", "notEmpty"],
+referencedClasses: []
+}),
+smalltalk.Collection);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "ifNotEmpty:ifEmpty:",
+category: 'testing',
+fn: function (aBlock,anotherBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self._notEmpty();
+$1=_st($2)._ifTrue_ifFalse_(aBlock,anotherBlock);
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"ifNotEmpty:ifEmpty:",{aBlock:aBlock,anotherBlock:anotherBlock},smalltalk.Collection)})},
+args: ["aBlock", "anotherBlock"],
+source: "ifNotEmpty: aBlock ifEmpty: anotherBlock\x0a\x09^ self notEmpty\x0a\x09\x09ifTrue: aBlock\x0a\x09\x09ifFalse: anotherBlock",
+messageSends: ["ifTrue:ifFalse:", "notEmpty"],
 referencedClasses: []
 }),
 smalltalk.Collection);
@@ -543,24 +658,18 @@ selector: "includes:",
 category: 'testing',
 fn: function (anObject){
 var self=this;
-var sentinel;
-function $Object(){return smalltalk.Object||(typeof Object=="undefined"?nil:Object)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-sentinel=_st($Object())._new();
-$1=_st(self._detect_ifNone_((function(each){
+$1=self._anySatisfy_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return _st(each).__eq(anObject);
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
-return sentinel;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}))).__tild_eq(sentinel);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 return $1;
-}, function($ctx1) {$ctx1.fill(self,"includes:",{anObject:anObject,sentinel:sentinel},smalltalk.Collection)})},
+}, function($ctx1) {$ctx1.fill(self,"includes:",{anObject:anObject},smalltalk.Collection)})},
 args: ["anObject"],
-source: "includes: anObject\x0a\x09| sentinel |\x0a\x09sentinel := Object new.\x0a\x09^ (self detect: [ :each | each = anObject ] ifNone: [ sentinel ]) ~= sentinel",
-messageSends: ["new", "~=", "detect:ifNone:", "="],
-referencedClasses: ["Object"]
+source: "includes: anObject\x0a\x09^ self anySatisfy: [ :each | each = anObject ]",
+messageSends: ["anySatisfy:", "="],
+referencedClasses: []
 }),
 smalltalk.Collection);
 
@@ -641,6 +750,34 @@ referencedClasses: []
 }),
 smalltalk.Collection);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "noneSatisfy:",
+category: 'enumerating',
+fn: function (aBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+var $early={};
+try {
+self._do_((function(item){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(aBlock)._value_(item);
+if(smalltalk.assert($1)){
+throw $early=[false];
+};
+}, function($ctx2) {$ctx2.fillBlock({item:item},$ctx1,1)})}));
+return true;
+}
+catch(e) {if(e===$early)return e[0]; throw e}
+}, function($ctx1) {$ctx1.fill(self,"noneSatisfy:",{aBlock:aBlock},smalltalk.Collection)})},
+args: ["aBlock"],
+source: "noneSatisfy: aBlock\x0a\x09\x22Evaluate aBlock with the elements of the receiver.\x0a\x09If aBlock returns false for all elements return true.\x0a\x09Otherwise return false\x22\x0a\x0a\x09self do: [ :item | (aBlock value: item) ifTrue: [ ^ false ] ].\x0a\x09^ true",
+messageSends: ["do:", "ifTrue:", "value:"],
+referencedClasses: []
+}),
+smalltalk.Collection);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "notEmpty",
@@ -764,6 +901,22 @@ referencedClasses: []
 }),
 smalltalk.Collection);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "removeAll",
+category: 'adding/removing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._subclassResponsibility();
+return self}, function($ctx1) {$ctx1.fill(self,"removeAll",{},smalltalk.Collection)})},
+args: [],
+source: "removeAll\x0a\x09self subclassResponsibility",
+messageSends: ["subclassResponsibility"],
+referencedClasses: []
+}),
+smalltalk.Collection);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "select:",
@@ -785,7 +938,7 @@ $2=_st(stream)._contents();
 return $2;
 }, function($ctx1) {$ctx1.fill(self,"select:",{aBlock:aBlock,stream:stream},smalltalk.Collection)})},
 args: ["aBlock"],
-source: "select: aBlock\x0a\x09| stream |\x0a\x09stream := self class new writeStream.\x0a\x09self do: [ :each |\x0a\x09\x09(aBlock value: each) ifTrue: [\x0a\x09\x09stream nextPut: each ]].\x0a\x09^ stream contents",
+source: "select: aBlock\x0a\x09| stream |\x0a\x09stream := self class new writeStream.\x0a\x09self do: [ :each |\x0a\x09\x09(aBlock value: each) ifTrue: [\x0a\x09\x09stream nextPut: each ] ].\x0a\x09^ stream contents",
 messageSends: ["writeStream", "new", "class", "do:", "ifTrue:", "value:", "nextPut:", "contents"],
 referencedClasses: []
 }),
@@ -813,7 +966,7 @@ $2=_st(stream)._contents();
 return $2;
 }, function($ctx1) {$ctx1.fill(self,"select:thenCollect:",{selectBlock:selectBlock,collectBlock:collectBlock,stream:stream},smalltalk.Collection)})},
 args: ["selectBlock", "collectBlock"],
-source: "select: selectBlock thenCollect: collectBlock\x0a\x09| stream |\x0a\x09stream := self class new writeStream.\x0a\x09self do: [ :each |\x0a\x09\x09(selectBlock value: each) ifTrue: [\x0a\x09\x09stream nextPut: (collectBlock value: each) ]].\x0a\x09^ stream contents",
+source: "select: selectBlock thenCollect: collectBlock\x0a\x09| stream |\x0a\x09stream := self class new writeStream.\x0a\x09self do: [ :each |\x0a\x09\x09(selectBlock value: each) ifTrue: [\x0a\x09\x09stream nextPut: (collectBlock value: each) ] ].\x0a\x09^ stream contents",
 messageSends: ["writeStream", "new", "class", "do:", "ifTrue:", "value:", "nextPut:", "contents"],
 referencedClasses: []
 }),
@@ -1565,19 +1718,10 @@ category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-
-		if ('function'===typeof Object.keys) return Object.keys(self);
-		var keys = [];
-		for(var i in self) {
-			if(self.hasOwnProperty(i)) {
-				keys.push(i);
-			}
-		};
-		return keys;
-	;
+return Object.keys(self);
 return self}, function($ctx1) {$ctx1.fill(self,"keys",{},smalltalk.HashedCollection)})},
 args: [],
-source: "keys\x0a\x09<\x0a\x09\x09if ('function'===typeof Object.keys) return Object.keys(self);\x0a\x09\x09var keys = [];\x0a\x09\x09for(var i in self) {\x0a\x09\x09\x09if(self.hasOwnProperty(i)) {\x0a\x09\x09\x09\x09keys.push(i);\x0a\x09\x09\x09}\x0a\x09\x09};\x0a\x09\x09return keys;\x0a\x09>",
+source: "keys\x0a\x09<return Object.keys(self)>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1664,6 +1808,27 @@ referencedClasses: []
 }),
 smalltalk.HashedCollection);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "removeAll",
+category: 'adding/removing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._keys())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return self._removeKey_(each);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"removeAll",{},smalltalk.HashedCollection)})},
+args: [],
+source: "removeAll\x0a\x09^ self keys do: [ :each | self removeKey: each ]",
+messageSends: ["do:", "keys", "removeKey:"],
+referencedClasses: []
+}),
+smalltalk.HashedCollection);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "removeKey:",
@@ -2130,6 +2295,24 @@ referencedClasses: []
 }),
 smalltalk.Dictionary);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "removeAll",
+category: 'adding/removing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self["@keys"])._removeAll();
+$ctx1.sendIdx["removeAll"]=1;
+_st(self["@values"])._removeAll();
+return self}, function($ctx1) {$ctx1.fill(self,"removeAll",{},smalltalk.Dictionary)})},
+args: [],
+source: "removeAll\x0a\x09keys removeAll.\x0a\x09values removeAll",
+messageSends: ["removeAll"],
+referencedClasses: []
+}),
+smalltalk.Dictionary);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "removeKey:ifAbsent:",
@@ -3000,6 +3183,22 @@ referencedClasses: []
 }),
 smalltalk.Array);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "removeAll",
+category: 'adding/removing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self.length = 0;
+return self}, function($ctx1) {$ctx1.fill(self,"removeAll",{},smalltalk.Array)})},
+args: [],
+source: "removeAll\x0a\x09<self.length = 0>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Array);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "removeFrom:to:",
@@ -3527,10 +3726,10 @@ category: 'copying',
 fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-return self + aString;
+return String(self) + aString;
 return self}, function($ctx1) {$ctx1.fill(self,",",{aString:aString},smalltalk.String)})},
 args: ["aString"],
-source: ", aString\x0a\x09<return self + aString>",
+source: ", aString\x0a\x09<return String(self) + aString>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -3976,7 +4175,7 @@ smalltalk.String);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "escaped",
-category: 'accessing',
+category: 'converting',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -4609,7 +4808,7 @@ smalltalk.String);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "unescaped",
-category: 'accessing',
+category: 'converting',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
@@ -4622,6 +4821,70 @@ referencedClasses: []
 }),
 smalltalk.String);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "uriComponentDecoded",
+category: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return decodeURIComponent(self);
+return self}, function($ctx1) {$ctx1.fill(self,"uriComponentDecoded",{},smalltalk.String)})},
+args: [],
+source: "uriComponentDecoded\x0a\x09<return decodeURIComponent(self)>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.String);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "uriComponentEncoded",
+category: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return encodeURIComponent(self);
+return self}, function($ctx1) {$ctx1.fill(self,"uriComponentEncoded",{},smalltalk.String)})},
+args: [],
+source: "uriComponentEncoded\x0a\x09<return encodeURIComponent(self)>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.String);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "uriDecoded",
+category: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return decodeURI(self);
+return self}, function($ctx1) {$ctx1.fill(self,"uriDecoded",{},smalltalk.String)})},
+args: [],
+source: "uriDecoded\x0a\x09<return decodeURI(self)>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.String);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "uriEncoded",
+category: 'converting',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+return encodeURI(self);
+return self}, function($ctx1) {$ctx1.fill(self,"uriEncoded",{},smalltalk.String)})},
+args: [],
+source: "uriEncoded\x0a\x09<return encodeURI(self)>",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.String);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "withIndexDo:",

+ 3 - 25
js/Kernel-Exceptions.js

@@ -565,35 +565,13 @@ category: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self["@current"];
-if(($receiver = $2) == nil || $receiver == null){
-self["@current"]=self._new();
+var $1;
 $1=self["@current"];
-} else {
-$1=$2;
-};
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"current",{},smalltalk.ErrorHandler.klass)})},
 args: [],
-source: "current\x0a\x09^ current ifNil: [ current := self new ]",
-messageSends: ["ifNil:", "new"],
-referencedClasses: []
-}),
-smalltalk.ErrorHandler.klass);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "initialize",
-category: 'initialization',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-self._register();
-return self}, function($ctx1) {$ctx1.fill(self,"initialize",{},smalltalk.ErrorHandler.klass)})},
-args: [],
-source: "initialize\x0a\x09self register",
-messageSends: ["register"],
+source: "current\x0a\x09^ current",
+messageSends: [],
 referencedClasses: []
 }),
 smalltalk.ErrorHandler.klass);

+ 15 - 15
js/Importer-Exporter.js → js/Kernel-ImportExport.js

@@ -1,8 +1,8 @@
-define("amber_core/Importer-Exporter", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure"], function(smalltalk,nil,_st){
-smalltalk.addPackage('Importer-Exporter');
-smalltalk.packages["Importer-Exporter"].transport = {"type":"amd","amdNamespace":"amber_core"};
+define("amber_core/Kernel-ImportExport", ["amber_vm/smalltalk", "amber_vm/nil", "amber_vm/_st", "amber_core/Kernel-Objects", "amber_core/Kernel-Infrastructure"], function(smalltalk,nil,_st){
+smalltalk.addPackage('Kernel-ImportExport');
+smalltalk.packages["Kernel-ImportExport"].transport = {"type":"amd","amdNamespace":"amber_core"};
 
-smalltalk.addClass('AbstractExporter', smalltalk.Object, [], 'Importer-Exporter');
+smalltalk.addClass('AbstractExporter', smalltalk.Object, [], 'Kernel-ImportExport');
 smalltalk.AbstractExporter.comment="I am an abstract exporter for Amber source code.\x0a\x0a## API\x0a\x0aUse `#exportPackage:on:` to export a given package on a Stream.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -130,7 +130,7 @@ smalltalk.AbstractExporter);
 
 
 
-smalltalk.addClass('ChunkExporter', smalltalk.AbstractExporter, [], 'Importer-Exporter');
+smalltalk.addClass('ChunkExporter', smalltalk.AbstractExporter, [], 'Kernel-ImportExport');
 smalltalk.ChunkExporter.comment="I am an exporter dedicated to outputting Amber source code in the classic Smalltalk chunk format.\x0a\x0aI do not output any compiled code.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -575,7 +575,7 @@ smalltalk.ChunkExporter);
 
 
 
-smalltalk.addClass('Exporter', smalltalk.AbstractExporter, [], 'Importer-Exporter');
+smalltalk.addClass('Exporter', smalltalk.AbstractExporter, [], 'Kernel-ImportExport');
 smalltalk.Exporter.comment="I am responsible for outputting Amber code into a JavaScript string.\x0a\x0aThe generated output is enough to reconstruct the exported data, including Smalltalk source code and other metadata.\x0a\x0a## Use case\x0a\x0aI am typically used to save code outside of the Amber runtime (committing to disk, etc.).";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1000,7 +1000,7 @@ smalltalk.Exporter);
 
 
 
-smalltalk.addClass('AmdExporter', smalltalk.Exporter, ['namespace'], 'Importer-Exporter');
+smalltalk.addClass('AmdExporter', smalltalk.Exporter, ['namespace'], 'Kernel-ImportExport');
 smalltalk.AmdExporter.comment="I am used to export Packages in an AMD (Asynchronous Module Definition) JavaScript format.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1105,7 +1105,7 @@ smalltalk.AmdExporter);
 
 
 
-smalltalk.addClass('ChunkParser', smalltalk.Object, ['stream'], 'Importer-Exporter');
+smalltalk.addClass('ChunkParser', smalltalk.Object, ['stream'], 'Kernel-ImportExport');
 smalltalk.ChunkParser.comment="I am responsible for parsing aStream contents in the chunk format.\x0a\x0a## API\x0a\x0a    ChunkParser new\x0a        stream: aStream;\x0a        nextChunk";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1187,7 +1187,7 @@ referencedClasses: []
 smalltalk.ChunkParser.klass);
 
 
-smalltalk.addClass('ExportMethodProtocol', smalltalk.Object, ['name', 'theClass'], 'Importer-Exporter');
+smalltalk.addClass('ExportMethodProtocol', smalltalk.Object, ['name', 'theClass'], 'Kernel-ImportExport');
 smalltalk.ExportMethodProtocol.comment="I am an abstraction for a method protocol in a class / metaclass.\x0a\x0aI know of my class, name and methods.\x0aI am used when exporting a package.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1304,7 +1304,7 @@ referencedClasses: []
 smalltalk.ExportMethodProtocol.klass);
 
 
-smalltalk.addClass('Importer', smalltalk.Object, [], 'Importer-Exporter');
+smalltalk.addClass('Importer', smalltalk.Object, [], 'Kernel-ImportExport');
 smalltalk.Importer.comment="I can import Amber code from a string in the chunk format.\x0a\x0a## API\x0a\x0a    Importer new import: aString";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1351,7 +1351,7 @@ smalltalk.Importer);
 
 
 
-smalltalk.addClass('PackageHandler', smalltalk.InterfacingObject, [], 'Importer-Exporter');
+smalltalk.addClass('PackageHandler', smalltalk.InterfacingObject, [], 'Kernel-ImportExport');
 smalltalk.PackageHandler.comment="I am responsible for handling package loading and committing.\x0a\x0aI should not be used directly. Instead, use the corresponding `Package` methods.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1619,7 +1619,7 @@ smalltalk.PackageHandler);
 
 
 
-smalltalk.addClass('AmdPackageHandler', smalltalk.PackageHandler, [], 'Importer-Exporter');
+smalltalk.addClass('AmdPackageHandler', smalltalk.PackageHandler, [], 'Kernel-ImportExport');
 smalltalk.AmdPackageHandler.comment="I am responsible for handling package loading and committing.\x0a\x0aI should not be used directly. Instead, use the corresponding `Package` methods.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1785,7 +1785,7 @@ referencedClasses: ["Smalltalk"]
 smalltalk.AmdPackageHandler.klass);
 
 
-smalltalk.addClass('PackageTransport', smalltalk.Object, ['package'], 'Importer-Exporter');
+smalltalk.addClass('PackageTransport', smalltalk.Object, ['package'], 'Kernel-ImportExport');
 smalltalk.PackageTransport.comment="I represent the transport mechanism used to commit a package.\x0a\x0aMy concrete subclasses have a `#handler` to which committing is delegated.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -2114,7 +2114,7 @@ referencedClasses: []
 smalltalk.PackageTransport.klass);
 
 
-smalltalk.addClass('AmdPackageTransport', smalltalk.PackageTransport, ['namespace'], 'Importer-Exporter');
+smalltalk.addClass('AmdPackageTransport', smalltalk.PackageTransport, ['namespace'], 'Kernel-ImportExport');
 smalltalk.AmdPackageTransport.comment="I am the default transport for committing packages.\x0a\x0aSee `AmdExporter` and `AmdPackageHandler`.";
 smalltalk.addMethod(
 smalltalk.method({
@@ -2320,7 +2320,7 @@ smalltalk.AmdPackageTransport.klass);
 smalltalk.addMethod(
 smalltalk.method({
 selector: "commit",
-category: '*Importer-Exporter',
+category: '*Kernel-ImportExport',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 

File diff suppressed because it is too large
+ 1002 - 730
js/Kernel-Infrastructure.js


+ 6 - 24
js/Kernel-Objects.js

@@ -373,15 +373,15 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 
-	var hash=self.identityHash;
-	if (hash) return hash;
-	hash=smalltalk.nextId();
-	Object.defineProperty(self, 'identityHash', {value:hash});
-	return hash;
+		var hash=self.identityHash;
+		if (hash) return hash;
+		hash=smalltalk.nextId();
+		Object.defineProperty(self, 'identityHash', {value:hash});
+		return hash;
 	;
 return self}, function($ctx1) {$ctx1.fill(self,"identityHash",{},smalltalk.Object)})},
 args: [],
-source: "identityHash\x0a\x09<\x0a\x09var hash=self.identityHash;\x0a\x09if (hash) return hash;\x0a\x09hash=smalltalk.nextId();\x0a\x09Object.defineProperty(self, 'identityHash', {value:hash});\x0a\x09return hash;\x0a\x09>",
+source: "identityHash\x0a\x09<\x0a\x09\x09var hash=self.identityHash;\x0a\x09\x09if (hash) return hash;\x0a\x09\x09hash=smalltalk.nextId();\x0a\x09\x09Object.defineProperty(self, 'identityHash', {value:hash});\x0a\x09\x09return hash;\x0a\x09>",
 messageSends: [],
 referencedClasses: []
 }),
@@ -1006,24 +1006,6 @@ referencedClasses: []
 }),
 smalltalk.Object);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "test",
-category: 'converting',
-fn: function (){
-var self=this;
-var a;
-return smalltalk.withContext(function($ctx1) { 
-a=(1);
-self._halt();
-return self}, function($ctx1) {$ctx1.fill(self,"test",{a:a},smalltalk.Object)})},
-args: [],
-source: "test\x0a\x09| a |\x0a\x09a := 1.\x0a\x09self halt",
-messageSends: ["halt"],
-referencedClasses: []
-}),
-smalltalk.Object);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "throw:",

+ 342 - 81
js/Kernel-Tests.js

@@ -40,6 +40,81 @@ smalltalk.AnnouncementSubscriptionTest);
 
 
 
+smalltalk.addClass('AnnouncerTest', smalltalk.TestCase, [], 'Kernel-Tests');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testOnDo",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var counter,announcer;
+function $Announcer(){return smalltalk.Announcer||(typeof Announcer=="undefined"?nil:Announcer)}
+function $SystemAnnouncement(){return smalltalk.SystemAnnouncement||(typeof SystemAnnouncement=="undefined"?nil:SystemAnnouncement)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+counter=(0);
+announcer=_st($Announcer())._new();
+$ctx1.sendIdx["new"]=1;
+_st(announcer)._on_do_($SystemAnnouncement(),(function(){
+return smalltalk.withContext(function($ctx2) {
+counter=_st(counter).__plus((1));
+return counter;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+$1=announcer;
+$2=_st($SystemAnnouncement())._new();
+$ctx1.sendIdx["new"]=2;
+_st($1)._announce_($2);
+$ctx1.sendIdx["announce:"]=1;
+self._assert_equals_(counter,(1));
+$ctx1.sendIdx["assert:equals:"]=1;
+_st(announcer)._announce_(_st($SystemAnnouncement())._new());
+self._assert_equals_(counter,(2));
+return self}, function($ctx1) {$ctx1.fill(self,"testOnDo",{counter:counter,announcer:announcer},smalltalk.AnnouncerTest)})},
+args: [],
+source: "testOnDo\x0a\x09| counter announcer |\x0a\x09\x0a\x09counter := 0.\x0a\x09announcer := Announcer new.\x0a\x09announcer on: SystemAnnouncement do: [ counter := counter + 1 ].\x0a\x0a\x09announcer announce: (SystemAnnouncement new).\x0a\x09self assert: counter equals: 1.\x0a\x0a\x09announcer announce: (SystemAnnouncement new).\x0a\x09self assert: counter equals: 2.",
+messageSends: ["new", "on:do:", "+", "announce:", "assert:equals:"],
+referencedClasses: ["Announcer", "SystemAnnouncement"]
+}),
+smalltalk.AnnouncerTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testOnDoOnce",
+category: 'not yet classified',
+fn: function (){
+var self=this;
+var counter,announcer;
+function $Announcer(){return smalltalk.Announcer||(typeof Announcer=="undefined"?nil:Announcer)}
+function $SystemAnnouncement(){return smalltalk.SystemAnnouncement||(typeof SystemAnnouncement=="undefined"?nil:SystemAnnouncement)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+counter=(0);
+announcer=_st($Announcer())._new();
+$ctx1.sendIdx["new"]=1;
+_st(announcer)._on_doOnce_($SystemAnnouncement(),(function(){
+return smalltalk.withContext(function($ctx2) {
+counter=_st(counter).__plus((1));
+return counter;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+$1=announcer;
+$2=_st($SystemAnnouncement())._new();
+$ctx1.sendIdx["new"]=2;
+_st($1)._announce_($2);
+$ctx1.sendIdx["announce:"]=1;
+self._assert_equals_(counter,(1));
+$ctx1.sendIdx["assert:equals:"]=1;
+_st(announcer)._announce_(_st($SystemAnnouncement())._new());
+self._assert_equals_(counter,(1));
+return self}, function($ctx1) {$ctx1.fill(self,"testOnDoOnce",{counter:counter,announcer:announcer},smalltalk.AnnouncerTest)})},
+args: [],
+source: "testOnDoOnce\x0a\x09| counter announcer |\x0a\x09\x0a\x09counter := 0.\x0a\x09announcer := Announcer new.\x0a\x09announcer on: SystemAnnouncement doOnce: [ counter := counter + 1 ].\x0a\x0a\x09announcer announce: (SystemAnnouncement new).\x0a\x09self assert: counter equals: 1.\x0a\x0a\x09announcer announce: (SystemAnnouncement new).\x0a\x09self assert: counter equals: 1.",
+messageSends: ["new", "on:doOnce:", "+", "announce:", "assert:equals:"],
+referencedClasses: ["Announcer", "SystemAnnouncement"]
+}),
+smalltalk.AnnouncerTest);
+
+
+
 smalltalk.addClass('BlockClosureTest', smalltalk.TestCase, [], 'Kernel-Tests');
 smalltalk.addMethod(
 smalltalk.method({
@@ -1281,6 +1356,95 @@ referencedClasses: []
 }),
 smalltalk.CollectionTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testAllSatisfy",
+category: 'tests',
+fn: function (){
+var self=this;
+var collection,anyOne;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+collection=self._collection();
+anyOne=_st(collection)._anyOne();
+$1=_st(collection)._allSatisfy_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(collection)._includes_(each);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+$ctx1.sendIdx["allSatisfy:"]=1;
+self._assert_($1);
+self._deny_(_st(collection)._allSatisfy_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(each).__tild_eq(anyOne);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})})));
+return self}, function($ctx1) {$ctx1.fill(self,"testAllSatisfy",{collection:collection,anyOne:anyOne},smalltalk.CollectionTest)})},
+args: [],
+source: "testAllSatisfy\x0a\x09| collection anyOne |\x0a\x09collection := self collection.\x0a\x09anyOne := collection anyOne.\x0a\x09self assert: (collection allSatisfy: [ :each | collection includes: each ]).\x0a\x09self deny: (collection allSatisfy: [ :each | each ~= anyOne ])",
+messageSends: ["collection", "anyOne", "assert:", "allSatisfy:", "includes:", "deny:", "~="],
+referencedClasses: []
+}),
+smalltalk.CollectionTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testAnyOne",
+category: 'tests',
+fn: function (){
+var self=this;
+function $Error(){return smalltalk.Error||(typeof Error=="undefined"?nil:Error)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+self._should_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self._collectionClass())._new())._anyOne();
+$ctx2.sendIdx["anyOne"]=1;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),$Error());
+$2=self._collection();
+$ctx1.sendIdx["collection"]=1;
+$1=_st($2)._includes_(_st(self._collection())._anyOne());
+self._assert_($1);
+return self}, function($ctx1) {$ctx1.fill(self,"testAnyOne",{},smalltalk.CollectionTest)})},
+args: [],
+source: "testAnyOne\x0a\x09self should: [ self collectionClass new anyOne ] raise: Error.\x0a\x09self assert: (self collection includes: self collection anyOne)",
+messageSends: ["should:raise:", "anyOne", "new", "collectionClass", "assert:", "includes:", "collection"],
+referencedClasses: ["Error"]
+}),
+smalltalk.CollectionTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testAnySatisfy",
+category: 'tests',
+fn: function (){
+var self=this;
+var anyOne;
+function $Object(){return smalltalk.Object||(typeof Object=="undefined"?nil:Object)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$3,$2;
+$1=self._collection();
+$ctx1.sendIdx["collection"]=1;
+anyOne=_st($1)._anyOne();
+$3=self._collection();
+$ctx1.sendIdx["collection"]=2;
+$2=_st($3)._anySatisfy_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(each).__eq(anyOne);
+$ctx2.sendIdx["="]=1;
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+$ctx1.sendIdx["anySatisfy:"]=1;
+self._assert_($2);
+self._deny_(_st(self._collection())._anySatisfy_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(each).__eq(_st($Object())._new());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})})));
+return self}, function($ctx1) {$ctx1.fill(self,"testAnySatisfy",{anyOne:anyOne},smalltalk.CollectionTest)})},
+args: [],
+source: "testAnySatisfy\x0a\x09| anyOne |\x0a\x09anyOne := self collection anyOne.\x0a\x09self assert: (self collection anySatisfy: [ :each | each = anyOne ]).\x0a\x09self deny: (self collection anySatisfy: [ :each | each = Object new ])",
+messageSends: ["anyOne", "collection", "assert:", "anySatisfy:", "=", "deny:", "new"],
+referencedClasses: ["Object"]
+}),
+smalltalk.CollectionTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testAsArray",
@@ -1421,6 +1585,108 @@ referencedClasses: ["OrderedCollection"]
 }),
 smalltalk.CollectionTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testIfEmptyFamily",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $3,$2,$1,$5,$4,$6,$9,$8,$7,$11,$10,$13,$12,$16,$15,$14,$18,$17,$19;
+$3=self._collectionClass();
+$ctx1.sendIdx["collectionClass"]=1;
+$2=_st($3)._new();
+$ctx1.sendIdx["new"]=1;
+$1=_st($2)._ifEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return (42);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+$ctx1.sendIdx["ifEmpty:"]=1;
+self._assert_equals_($1,(42));
+$ctx1.sendIdx["assert:equals:"]=1;
+$5=self._collection();
+$ctx1.sendIdx["collection"]=1;
+$4=_st($5)._ifEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return (42);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+$6=self._collection();
+$ctx1.sendIdx["collection"]=2;
+self._assert_equals_($4,$6);
+$ctx1.sendIdx["assert:equals:"]=2;
+$9=self._collectionClass();
+$ctx1.sendIdx["collectionClass"]=2;
+$8=_st($9)._new();
+$ctx1.sendIdx["new"]=2;
+$7=_st($8)._ifNotEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return (42);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,3)})}));
+$ctx1.sendIdx["ifNotEmpty:"]=1;
+$11=self._collectionClass();
+$ctx1.sendIdx["collectionClass"]=3;
+$10=_st($11)._new();
+$ctx1.sendIdx["new"]=3;
+self._assert_equals_($7,$10);
+$ctx1.sendIdx["assert:equals:"]=3;
+$13=self._collection();
+$ctx1.sendIdx["collection"]=3;
+$12=_st($13)._ifNotEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return (42);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,4)})}));
+self._assert_equals_($12,(42));
+$ctx1.sendIdx["assert:equals:"]=4;
+$16=self._collectionClass();
+$ctx1.sendIdx["collectionClass"]=4;
+$15=_st($16)._new();
+$ctx1.sendIdx["new"]=4;
+$14=_st($15)._ifEmpty_ifNotEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return (42);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,5)})}),(function(){
+return smalltalk.withContext(function($ctx2) {
+return (999);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,6)})}));
+$ctx1.sendIdx["ifEmpty:ifNotEmpty:"]=1;
+self._assert_equals_($14,(42));
+$ctx1.sendIdx["assert:equals:"]=5;
+$18=self._collection();
+$ctx1.sendIdx["collection"]=4;
+$17=_st($18)._ifEmpty_ifNotEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return (42);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,7)})}),(function(){
+return smalltalk.withContext(function($ctx2) {
+return (999);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,8)})}));
+self._assert_equals_($17,(999));
+$ctx1.sendIdx["assert:equals:"]=6;
+$19=_st(_st(self._collectionClass())._new())._ifNotEmpty_ifEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return (42);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,9)})}),(function(){
+return smalltalk.withContext(function($ctx2) {
+return (999);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,10)})}));
+$ctx1.sendIdx["ifNotEmpty:ifEmpty:"]=1;
+self._assert_equals_($19,(999));
+$ctx1.sendIdx["assert:equals:"]=7;
+self._assert_equals_(_st(self._collection())._ifNotEmpty_ifEmpty_((function(){
+return smalltalk.withContext(function($ctx2) {
+return (42);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,11)})}),(function(){
+return smalltalk.withContext(function($ctx2) {
+return (999);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,12)})})),(42));
+return self}, function($ctx1) {$ctx1.fill(self,"testIfEmptyFamily",{},smalltalk.CollectionTest)})},
+args: [],
+source: "testIfEmptyFamily\x0a\x09self assert: (self collectionClass new ifEmpty: [ 42 ]) equals: 42.\x0a\x09self assert: (self collection ifEmpty: [ 42 ]) equals: self collection.\x0a\x0a\x09self assert: (self collectionClass new ifNotEmpty: [ 42 ]) equals: self collectionClass new.\x0a\x09self assert: (self collection ifNotEmpty: [ 42 ]) equals: 42.\x0a\x09\x0a\x09self assert: (self collectionClass new ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 42.\x0a\x09self assert: (self collection ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 999.\x0a\x0a\x09self assert: (self collectionClass new ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 999.\x0a\x09self assert: (self collection ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 42",
+messageSends: ["assert:equals:", "ifEmpty:", "new", "collectionClass", "collection", "ifNotEmpty:", "ifEmpty:ifNotEmpty:", "ifNotEmpty:ifEmpty:"],
+referencedClasses: []
+}),
+smalltalk.CollectionTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testIsEmpty",
@@ -1441,6 +1707,60 @@ referencedClasses: []
 }),
 smalltalk.CollectionTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testNoneSatisfy",
+category: 'tests',
+fn: function (){
+var self=this;
+var anyOne;
+function $Object(){return smalltalk.Object||(typeof Object=="undefined"?nil:Object)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$3,$2;
+$1=self._collection();
+$ctx1.sendIdx["collection"]=1;
+anyOne=_st($1)._anyOne();
+$3=self._collection();
+$ctx1.sendIdx["collection"]=2;
+$2=_st($3)._noneSatisfy_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(each).__eq(anyOne);
+$ctx2.sendIdx["="]=1;
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+$ctx1.sendIdx["noneSatisfy:"]=1;
+self._deny_($2);
+self._assert_(_st(self._collection())._noneSatisfy_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return _st(each).__eq(_st($Object())._new());
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})})));
+return self}, function($ctx1) {$ctx1.fill(self,"testNoneSatisfy",{anyOne:anyOne},smalltalk.CollectionTest)})},
+args: [],
+source: "testNoneSatisfy\x0a\x09| anyOne |\x0a\x09anyOne := self collection anyOne.\x0a\x09self deny: (self collection noneSatisfy: [ :each | each = anyOne ]).\x0a\x09self assert: (self collection noneSatisfy: [ :each | each = Object new ])",
+messageSends: ["anyOne", "collection", "deny:", "noneSatisfy:", "=", "assert:", "new"],
+referencedClasses: ["Object"]
+}),
+smalltalk.CollectionTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testRemoveAll",
+category: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=self._collection();
+_st($1)._removeAll();
+$2=_st($1)._yourself();
+self._assert_equals_($2,_st(self._collectionClass())._new());
+return self}, function($ctx1) {$ctx1.fill(self,"testRemoveAll",{},smalltalk.CollectionTest)})},
+args: [],
+source: "testRemoveAll\x0a\x09self assert: (self collection removeAll; yourself) equals: self collectionClass new",
+messageSends: ["assert:equals:", "removeAll", "collection", "yourself", "new", "collectionClass"],
+referencedClasses: []
+}),
+smalltalk.CollectionTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testSelect",
@@ -1569,42 +1889,6 @@ referencedClasses: []
 }),
 smalltalk.IndexableCollectionTest);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "testContains",
-category: 'tests',
-fn: function (){
-var self=this;
-var collection;
-function $Object(){return smalltalk.Object||(typeof Object=="undefined"?nil:Object)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$4,$3,$1;
-collection=self._collection();
-$ctx1.sendIdx["collection"]=1;
-$2=self._collection();
-$ctx1.sendIdx["collection"]=2;
-$1=_st($2)._contains_((function(each){
-return smalltalk.withContext(function($ctx2) {
-$4=self._collection();
-$ctx2.sendIdx["collection"]=3;
-$3=_st($4)._first();
-return _st(each).__eq($3);
-$ctx2.sendIdx["="]=1;
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
-$ctx1.sendIdx["contains:"]=1;
-self._assert_($1);
-self._deny_(_st(self._collection())._contains_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(each).__eq(_st($Object())._new());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})})));
-return self}, function($ctx1) {$ctx1.fill(self,"testContains",{collection:collection},smalltalk.IndexableCollectionTest)})},
-args: [],
-source: "testContains\x0a\x09| collection |\x0a\x09collection := self collection.\x0a\x09\x0a\x09self assert: (self collection contains: [ :each | each = self collection first ]).\x0a\x09self deny: (self collection contains: [ :each | each = Object new ])",
-messageSends: ["collection", "assert:", "contains:", "=", "first", "deny:", "new"],
-referencedClasses: ["Object"]
-}),
-smalltalk.IndexableCollectionTest);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testIndexOf",
@@ -1760,43 +2044,6 @@ referencedClasses: ["Error"]
 }),
 smalltalk.HashedCollectionTest);
 
-smalltalk.addMethod(
-smalltalk.method({
-selector: "testContains",
-category: 'tests',
-fn: function (){
-var self=this;
-var collection;
-function $Object(){return smalltalk.Object||(typeof Object=="undefined"?nil:Object)}
-return smalltalk.withContext(function($ctx1) { 
-var $2,$5,$4,$3,$1;
-collection=self._collection();
-$ctx1.sendIdx["collection"]=1;
-$2=self._collection();
-$ctx1.sendIdx["collection"]=2;
-$1=_st($2)._contains_((function(each){
-return smalltalk.withContext(function($ctx2) {
-$5=self._collection();
-$ctx2.sendIdx["collection"]=3;
-$4=_st($5)._values();
-$3=_st($4)._first();
-return _st(each).__eq($3);
-$ctx2.sendIdx["="]=1;
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
-$ctx1.sendIdx["contains:"]=1;
-self._assert_($1);
-self._deny_(_st(self._collection())._contains_((function(each){
-return smalltalk.withContext(function($ctx2) {
-return _st(each).__eq(_st($Object())._new());
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,2)})})));
-return self}, function($ctx1) {$ctx1.fill(self,"testContains",{collection:collection},smalltalk.HashedCollectionTest)})},
-args: [],
-source: "testContains\x0a\x09| collection |\x0a\x09collection := self collection.\x0a\x09\x0a\x09self assert: (self collection contains: [ :each | each = self collection values first ]).\x0a\x09self deny: (self collection contains: [ :each | each = Object new ])",
-messageSends: ["collection", "assert:", "contains:", "=", "first", "values", "deny:", "new"],
-referencedClasses: ["Object"]
-}),
-smalltalk.HashedCollectionTest);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testFrom",
@@ -3468,6 +3715,26 @@ referencedClasses: []
 }),
 smalltalk.StringTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testRemoveAll",
+category: 'tests',
+fn: function (){
+var self=this;
+function $Error(){return smalltalk.Error||(typeof Error=="undefined"?nil:Error)}
+return smalltalk.withContext(function($ctx1) { 
+self._should_raise_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(self._collection())._removeAll();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),$Error());
+return self}, function($ctx1) {$ctx1.fill(self,"testRemoveAll",{},smalltalk.StringTest)})},
+args: [],
+source: "testRemoveAll\x0a\x09self should: [ self collection removeAll ] raise: Error",
+messageSends: ["should:raise:", "removeAll", "collection"],
+referencedClasses: ["Error"]
+}),
+smalltalk.StringTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testReversed",
@@ -3951,19 +4218,13 @@ fn: function (){
 var self=this;
 var testObject;
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
 testObject=self._jsObject();
-$2=_st(testObject)._value();
-$ctx1.sendIdx["value"]=1;
-$1=_st($2)._printString();
-self._assert_equals_($1,"[object Object]");
-$ctx1.sendIdx["assert:equals:"]=1;
 _st(testObject)._at_put_("value","aValue");
 self._assert_equals_(_st(testObject)._value(),"aValue");
 return self}, function($ctx1) {$ctx1.fill(self,"testValue",{testObject:testObject},smalltalk.JSObjectProxyTest)})},
 args: [],
-source: "testValue\x0a\x09| testObject |\x0a\x09testObject := self jsObject.\x0a\x09self assert: testObject value printString equals: '[object Object]'.\x0a\x09testObject at: 'value' put: 'aValue'.\x0a\x09self assert: testObject value equals: 'aValue'",
-messageSends: ["jsObject", "assert:equals:", "printString", "value", "at:put:"],
+source: "testValue\x0a\x09| testObject |\x0a\x09testObject := self jsObject.\x0a\x09testObject at: 'value' put: 'aValue'.\x0a\x09self assert: testObject value equals: 'aValue'",
+messageSends: ["jsObject", "at:put:", "assert:equals:", "value"],
 referencedClasses: []
 }),
 smalltalk.JSObjectProxyTest);

+ 9 - 49
st/Canvas.st

@@ -41,8 +41,6 @@ isAvailable
 <return typeof window !!== "undefined" && typeof jQuery !!== "undefined">
 ! !
 
-BrowserInterface class instanceVariableNames: 'uiWorker ajaxWorker'!
-
 Object subclass: #HTMLCanvas
 	instanceVariableNames: 'root'
 	package: 'Canvas'!
@@ -472,7 +470,7 @@ strong: anObject
 !
 
 style
-	^ root addBrush: (StyleTag canvas: self)
+	^ self tag: 'style'
 !
 
 style: aString
@@ -549,26 +547,6 @@ video
 
 !HTMLCanvas class methodsFor: 'instance creation'!
 
-browserVersion
-	^ (jQuery at: #browser) version
-!
-
-isMSIE
-	^ ((jQuery at: #browser) at: #msie) notNil
-!
-
-isMozilla
-	^ ((jQuery at: #browser) at: #mozilla) notNil
-!
-
-isOpera
-	^ ((jQuery at: #browser) at: #opera) notNil
-!
-
-isWebkit
-	^ ((jQuery at: #browser) at: #webkit) notNil
-!
-
 onJQuery: aJQuery
 	^ self basicNew
 		initializeFromJQuery: aJQuery;
@@ -820,6 +798,14 @@ alt: aString
 	self at: 'alt' put: aString
 !
 
+at: aString
+	^ self at: aString ifAbsent: [ Collection new errorNotFound ]
+!
+
+at: aString ifAbsent: aBlock
+	<return self['@element'].hasAttribute(aString) ? self['@element'].getAttribute(aString) : aBlock._value()>
+!
+
 at: aString put: aValue
 	<self['@element'].setAttribute(aString, aValue)>
 !
@@ -1060,32 +1046,6 @@ fromString: aString canvas: aCanvas
 	yourself
 ! !
 
-TagBrush subclass: #StyleTag
-	instanceVariableNames: ''
-	package: 'Canvas'!
-!StyleTag commentStamp!
-I'm a `<style>` tag use to inline CSS or load a stylesheet.
-
-## Motivation
-
-The need for a specific class comes from Internet Explorer compatibility issues.!
-
-!StyleTag methodsFor: 'adding'!
-
-with: aString
-	HTMLCanvas isMSIE
-		ifTrue: [ self element styleSheet cssText: aString ]
-		ifFalse: [ super with: aString ].
-! !
-
-!StyleTag class methodsFor: 'instance creation'!
-
-canvas: aCanvas
-	^ self new
-		initializeFromString: 'style' canvas: aCanvas;
-		yourself
-! !
-
 InterfacingObject subclass: #Widget
 	instanceVariableNames: ''
 	package: 'Canvas'!

+ 6 - 6
st/Compiler-AST.st

@@ -48,7 +48,7 @@ nextNode: aNode
 !
 
 nodes
-	^ nodes ifNil: [ nodes := Array new ] 
+	^ nodes ifNil: [ nodes := Array new ]
 !
 
 parent
@@ -168,7 +168,7 @@ stopOnStepping
 
 subtreeNeedsAliasing
 	^ (self shouldBeAliased or: [ self shouldBeInlined ]) or: [
-		(self nodes detect: [ :each | each subtreeNeedsAliasing ] ifNone: [ false ]) ~= false ]
+		self nodes anySatisfy: [ :each | each subtreeNeedsAliasing ] ]
 ! !
 
 !Node methodsFor: 'visiting'!
@@ -244,7 +244,7 @@ nextNode: aNode
 !
 
 parameters
-	^ parameters ifNil: [ parameters := Array new ] 
+	^ parameters ifNil: [ parameters := Array new ]
 !
 
 parameters: aCollection
@@ -336,7 +336,7 @@ I represent an JavaScript statement node.!
 !JSStatementNode methodsFor: 'accessing'!
 
 source
-	^ source ifNil: [ '' ] 
+	^ source ifNil: [ '' ]
 !
 
 source: aString
@@ -366,7 +366,7 @@ A method node must be the root and only method node of a valid AST.!
 !MethodNode methodsFor: 'accessing'!
 
 arguments
-	^ arguments ifNil: [ #() ] 
+	^ arguments ifNil: [ #() ]
 !
 
 arguments: aCollection
@@ -480,7 +480,7 @@ I represent an message send node.!
 !SendNode methodsFor: 'accessing'!
 
 arguments
-	^ arguments ifNil: [ arguments := #() ] 
+	^ arguments ifNil: [ arguments := #() ]
 !
 
 arguments: aCollection

+ 1 - 1
st/IDE.st

@@ -165,7 +165,7 @@ handleError: anError
 !DebugErrorHandler class methodsFor: 'initialization'!
 
 initialize
-	self register
+	ErrorHandler current ifNil: [ self register ]
 ! !
 
 Widget subclass: #SourceArea

+ 14 - 11
st/Kernel-Announcements.st

@@ -104,6 +104,19 @@ on: aClass do: aBlock
 		yourself)
 !
 
+on: aClass doOnce: aBlock
+	| subscription |
+	
+	subscription := AnnouncementSubscription new
+		announcementClass: aClass;
+		yourself.
+	subscription valuable: [ :ann |
+		subscriptions remove: subscription.
+		aBlock value: ann ].
+
+	subscriptions add: subscription
+!
+
 on: aClass send: aSelector to: anObject
 	subscriptions add: (AnnouncementSubscription new
 		valuable: (MessageSend new
@@ -144,21 +157,11 @@ new
 ! !
 
 Object subclass: #SystemAnnouncement
-	instanceVariableNames: 'theClass'
+	instanceVariableNames: ''
 	package: 'Kernel-Announcements'!
 !SystemAnnouncement commentStamp!
 I am the superclass of all system announcements!
 
-!SystemAnnouncement methodsFor: 'accessing'!
-
-theClass
-	^ theClass
-!
-
-theClass: aClass
-	theClass := aClass
-! !
-
 !SystemAnnouncement class methodsFor: 'helios'!
 
 heliosClass

+ 5 - 0
st/Kernel-Classes.st

@@ -218,6 +218,11 @@ addCompiledMethod: aMethod
 
 	self basicAddCompiledMethod: aMethod.
 	
+	oldMethod ifNotNil: [
+		(self methods
+			select: [ :each | each protocol = oldMethod protocol ])
+			ifEmpty: [ self organization removeElement: oldMethod protocol ] ].
+
 	announcement := oldMethod
 		ifNil: [
 			MethodAdded new

+ 104 - 33
st/Kernel-Collections.st

@@ -85,12 +85,25 @@ addAll: aCollection
 	^ aCollection
 !
 
+anyOne
+	"Answer a representative sample of the receiver. This method can
+	be helpful when needing to preinfer the nature of the contents of 
+	semi-homogeneous collections."
+
+	self ifEmpty: [ self error: 'Collection is empty' ].
+	self do: [ :each | ^ each ]
+!
+
 remove: anObject
 	^ self remove: anObject ifAbsent: [ self errorNotFound ]
 !
 
 remove: anObject ifAbsent: aBlock
 	self subclassResponsibility
+!
+
+removeAll
+	self subclassResponsibility
 ! !
 
 !Collection methodsFor: 'converting'!
@@ -136,6 +149,24 @@ copyWithoutAll: aCollection
 
 !Collection methodsFor: 'enumerating'!
 
+allSatisfy: aBlock
+	"Evaluate aBlock with the elements of the receiver.
+	If aBlock returns false for any element return false.
+	Otherwise return true."
+
+	self do: [ :each | (aBlock value: each) ifFalse: [ ^ false ] ].
+	^ true
+!
+
+anySatisfy: aBlock
+	"Evaluate aBlock with the elements of the receiver.
+	If aBlock returns true for any element return true.
+	Otherwise return false."
+
+	self do: [ :each | (aBlock value: each) ifTrue: [ ^ true ] ].
+	^ false
+!
+
 collect: aBlock
 	| stream |
 	stream := self class new writeStream.
@@ -188,6 +219,15 @@ intersection: aCollection
 	^ self class withAll: outputSet asArray
 !
 
+noneSatisfy: aBlock
+	"Evaluate aBlock with the elements of the receiver.
+	If aBlock returns false for all elements return true.
+	Otherwise return false"
+
+	self do: [ :item | (aBlock value: item) ifTrue: [ ^ false ] ].
+	^ true
+!
+
 reject: aBlock
 	^ self select: [ :each | (aBlock value: each) = false ]
 !
@@ -197,7 +237,7 @@ select: aBlock
 	stream := self class new writeStream.
 	self do: [ :each |
 		(aBlock value: each) ifTrue: [
-		stream nextPut: each ]].
+		stream nextPut: each ] ].
 	^ stream contents
 !
 
@@ -206,7 +246,7 @@ select: selectBlock thenCollect: collectBlock
 	stream := self class new writeStream.
 	self do: [ :each |
 		(selectBlock value: each) ifTrue: [
-		stream nextPut: (collectBlock value: each) ]].
+		stream nextPut: (collectBlock value: each) ] ].
 	^ stream contents
 ! !
 
@@ -225,30 +265,41 @@ putOn: aStream
 !Collection methodsFor: 'testing'!
 
 contains: aBlock
-	"Evaluate aBlock with the elements of the receiver.
-	If aBlock returns true for any element return true.
-	Otherwise return false."
+	self deprecatedAPI.
 
-	self do: [ :each | (aBlock value: each) ifTrue: [ ^ true ] ].
-	^ false
+	^ self anySatisfy: aBlock
 !
 
 ifEmpty: aBlock
-	"Evaluate the given block with the receiver as argument, answering its value if the receiver is empty, otherwise answer the receiver. Note that the fact that this method returns its argument in case the receiver is not empty allows one to write expressions like the following ones: self classifyMethodAs:
-		(myProtocol ifEmpty: ['As yet unclassified'])"
+	"Evaluate the given block with the receiver as argument, answering its value if the receiver is empty, otherwise answer the receiver. 
+	Note that the fact that this method returns its argument in case the receiver is not empty allows one to write expressions like the following ones: 
+		self classifyMethodAs:
+			(myProtocol ifEmpty: ['As yet unclassified'])"
 	^ self isEmpty
-		ifTrue: [ aBlock value ]
+		ifTrue: aBlock
 		ifFalse: [ self ]
 !
 
+ifEmpty: aBlock ifNotEmpty: anotherBlock
+	^ self isEmpty
+		ifTrue: aBlock
+		ifFalse: anotherBlock
+!
+
 ifNotEmpty: aBlock
-	self notEmpty ifTrue: aBlock.
+	^ self notEmpty
+		ifTrue: aBlock
+		ifFalse: [ self ]
+!
+
+ifNotEmpty: aBlock ifEmpty: anotherBlock
+	^ self notEmpty
+		ifTrue: aBlock
+		ifFalse: anotherBlock
 !
 
 includes: anObject
-	| sentinel |
-	sentinel := Object new.
-	^ (self detect: [ :each | each = anObject ] ifNone: [ sentinel ]) ~= sentinel
+	^ self anySatisfy: [ :each | each = anObject ]
 !
 
 isEmpty
@@ -434,16 +485,7 @@ keyAtValue: anObject ifAbsent: aBlock
 !
 
 keys
-	<
-		if ('function'===typeof Object.keys) return Object.keys(self);
-		var keys = [];
-		for(var i in self) {
-			if(self.hasOwnProperty(i)) {
-				keys.push(i);
-			}
-		};
-		return keys;
-	>
+	<return Object.keys(self)>
 !
 
 size
@@ -473,6 +515,10 @@ remove: aKey ifAbsent: aBlock
 	^ self removeKey: aKey ifAbsent: aBlock
 !
 
+removeAll
+	^ self keys do: [ :each | self removeKey: each ]
+!
+
 removeKey: aKey
 	^ self remove: aKey
 !
@@ -678,6 +724,11 @@ values
 
 !Dictionary methodsFor: 'adding/removing'!
 
+removeAll
+	keys removeAll.
+	values removeAll
+!
+
 removeKey: aKey ifAbsent: aBlock
 	<
 		var index = self._positionOfKey_(aKey);
@@ -994,6 +1045,10 @@ remove: anObject ifAbsent: aBlock
 	>
 !
 
+removeAll
+	<self.length = 0>
+!
+
 removeFrom: aNumber to: anotherNumber
 	<self.splice(aNumber -1, anotherNumber - aNumber + 1)>
 !
@@ -1214,20 +1269,12 @@ charCodeAt: anInteger
 	< return self.charCodeAt(anInteger - 1) >
 !
 
-escaped
-	<return escape(self)>
-!
-
 identityHash
 	^ self, 's'
 !
 
 size
 	<return self.length>
-!
-
-unescaped
-	<return unescape(self)>
 ! !
 
 !String methodsFor: 'comparing'!
@@ -1323,14 +1370,38 @@ crlfSanitized
 	^ self lines join: String lf
 !
 
+escaped
+	<return escape(self)>
+!
+
 reversed
 	<return self.split("").reverse().join("")>
+!
+
+unescaped
+	<return unescape(self)>
+!
+
+uriComponentDecoded
+	<return decodeURIComponent(self)>
+!
+
+uriComponentEncoded
+	<return encodeURIComponent(self)>
+!
+
+uriDecoded
+	<return decodeURI(self)>
+!
+
+uriEncoded
+	<return encodeURI(self)>
 ! !
 
 !String methodsFor: 'copying'!
 
 , aString
-	<return self + aString>
+	<return String(self) + aString>
 !
 
 copyFrom: anIndex to: anotherIndex

+ 1 - 5
st/Kernel-Exceptions.st

@@ -208,7 +208,7 @@ ErrorHandler class instanceVariableNames: 'current'!
 !ErrorHandler class methodsFor: 'accessing'!
 
 current
-	^ current ifNil: [ current := self new ]
+	^ current
 !
 
 setCurrent: anHandler
@@ -217,10 +217,6 @@ setCurrent: anHandler
 
 !ErrorHandler class methodsFor: 'initialization'!
 
-initialize
-	self register
-!
-
 register
 	ErrorHandler setCurrent: self new
 ! !

+ 13 - 13
st/Importer-Exporter.st → st/Kernel-ImportExport.st

@@ -1,7 +1,7 @@
-Smalltalk current createPackage: 'Importer-Exporter'!
+Smalltalk current createPackage: 'Kernel-ImportExport'!
 Object subclass: #AbstractExporter
 	instanceVariableNames: ''
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !AbstractExporter commentStamp!
 I am an abstract exporter for Amber source code.
 
@@ -65,7 +65,7 @@ exportPackage: aPackage on: aStream
 
 AbstractExporter subclass: #ChunkExporter
 	instanceVariableNames: ''
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !ChunkExporter commentStamp!
 I am an exporter dedicated to outputting Amber source code in the classic Smalltalk chunk format.
 
@@ -218,7 +218,7 @@ exportProtocols: aCollection on: aStream
 
 AbstractExporter subclass: #Exporter
 	instanceVariableNames: ''
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !Exporter commentStamp!
 I am responsible for outputting Amber code into a JavaScript string.
 
@@ -365,7 +365,7 @@ exportPackageTransportOf: aPackage on: aStream
 
 Exporter subclass: #AmdExporter
 	instanceVariableNames: 'namespace'
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !AmdExporter commentStamp!
 I am used to export Packages in an AMD (Asynchronous Module Definition) JavaScript format.!
 
@@ -405,7 +405,7 @@ amdNamespaceOfPackage: aPackage
 
 Object subclass: #ChunkParser
 	instanceVariableNames: 'stream'
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !ChunkParser commentStamp!
 I am responsible for parsing aStream contents in the chunk format.
 
@@ -454,7 +454,7 @@ on: aStream
 
 Object subclass: #ExportMethodProtocol
 	instanceVariableNames: 'name theClass'
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !ExportMethodProtocol commentStamp!
 I am an abstraction for a method protocol in a class / metaclass.
 
@@ -495,7 +495,7 @@ name: aString theClass: aClass
 
 Object subclass: #Importer
 	instanceVariableNames: ''
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !Importer commentStamp!
 I can import Amber code from a string in the chunk format.
 
@@ -523,7 +523,7 @@ import: aStream
 
 InterfacingObject subclass: #PackageHandler
 	instanceVariableNames: ''
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !PackageHandler commentStamp!
 I am responsible for handling package loading and committing.
 
@@ -610,7 +610,7 @@ ajaxPutAt: aURL data: aString
 
 PackageHandler subclass: #AmdPackageHandler
 	instanceVariableNames: ''
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !AmdPackageHandler commentStamp!
 I am responsible for handling package loading and committing.
 
@@ -666,7 +666,7 @@ defaultNamespace: aString
 
 Object subclass: #PackageTransport
 	instanceVariableNames: 'package'
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !PackageTransport commentStamp!
 I represent the transport mechanism used to commit a package.
 
@@ -776,7 +776,7 @@ register: aClass
 
 PackageTransport subclass: #AmdPackageTransport
 	instanceVariableNames: 'namespace'
-	package: 'Importer-Exporter'!
+	package: 'Kernel-ImportExport'!
 !AmdPackageTransport commentStamp!
 I am the default transport for committing packages.
 
@@ -848,7 +848,7 @@ namespace: aString
 		yourself
 ! !
 
-!Package methodsFor: '*Importer-Exporter'!
+!Package methodsFor: '*Kernel-ImportExport'!
 
 commit
 	^ self transport commit

+ 251 - 162
st/Kernel-Infrastructure.st

@@ -1,4 +1,254 @@
 Smalltalk current createPackage: 'Kernel-Infrastructure'!
+nil subclass: #AbstractProxy
+	instanceVariableNames: ''
+	package: 'Kernel-Infrastructure'!
+!AbstractProxy commentStamp!
+I provide a basic set of methods for proxies handling `#doesNotUnderstand:` so that inspectors, debuggers, etc. won't fail.!
+
+!AbstractProxy methodsFor: 'accessing'!
+
+class
+	<return self.klass>
+!
+
+identityHash
+	<
+		var hash=self.identityHash;
+		if (hash) return hash;
+		hash=smalltalk.nextId();
+		Object.defineProperty(self, 'identityHash', {value:hash});
+		return hash;
+	>
+!
+
+instVarAt: aString
+	< return self['@'+aString] >
+!
+
+instVarAt: aString put: anObject
+	< self['@' + aString] = anObject >
+!
+
+yourself
+	^ self
+! !
+
+!AbstractProxy methodsFor: 'converting'!
+
+asString
+	^ self printString
+! !
+
+!AbstractProxy methodsFor: 'error handling'!
+
+doesNotUnderstand: aMessage
+	MessageNotUnderstood new
+		receiver: self;
+		message: aMessage;
+		signal
+! !
+
+!AbstractProxy methodsFor: 'initialization'!
+
+initialize
+! !
+
+!AbstractProxy methodsFor: 'inspecting'!
+
+inspect
+	InspectorHandler inspect: self
+!
+
+inspectOn: anInspector
+! !
+
+!AbstractProxy methodsFor: 'message handling'!
+
+perform: aString
+	^ self perform: aString withArguments: #()
+!
+
+perform: aString withArguments: aCollection
+	<return smalltalk.send(self, aString._asSelector(), aCollection)>
+! !
+
+!AbstractProxy methodsFor: 'printing'!
+
+printOn: aStream
+	aStream nextPutAll: (self class name first isVowel
+		ifTrue: [ 'an ' ]
+		ifFalse: [ 'a ' ]).
+	aStream nextPutAll: self class name
+!
+
+printString
+	^ String streamContents: [ :str | 
+		self printOn: str ]
+! !
+
+!AbstractProxy class methodsFor: 'helios'!
+
+heliosClass
+	^ 'class'
+! !
+
+!AbstractProxy class methodsFor: 'initialization'!
+
+initialize
+! !
+
+AbstractProxy subclass: #JSObjectProxy
+	instanceVariableNames: 'jsObject'
+	package: 'Kernel-Infrastructure'!
+!JSObjectProxy commentStamp!
+I handle sending messages to JavaScript objects, making  JavaScript object accessing from Amber fully transparent.
+My instances make intensive use of `#doesNotUnderstand:`.
+
+My instances are automatically created by Amber whenever a message is sent to a JavaScript object.
+
+## Usage examples
+
+JSObjectProxy objects are instanciated by Amber when a Smalltalk message is sent to a JavaScript object.
+
+	window alert: 'hello world'.
+	window inspect.
+	(window jQuery: 'body') append: 'hello world'
+
+Amber messages sends are converted to JavaScript function calls or object property access _(in this order)_. If n one of them match, a `MessageNotUnderstood` error will be thrown.
+
+## Message conversion rules
+
+- `someUser name` becomes `someUser.name`
+- `someUser name: 'John'` becomes `someUser name = "John"`
+- `console log: 'hello world'` becomes `console.log('hello world')`
+- `(window jQuery: 'foo') css: 'background' color: 'red'` becomes `window.jQuery('foo').css('background', 'red')`
+
+__Note:__ For keyword-based messages, only the first keyword is kept: `window foo: 1 bar: 2` is equivalent to `window foo: 1 baz: 2`.!
+
+!JSObjectProxy methodsFor: 'accessing'!
+
+at: aString
+	<return self['@jsObject'][aString]>
+!
+
+at: aString ifAbsent: aBlock
+	"return the aString property or evaluate aBlock if the property is not defined on the object"
+	<
+		var obj = self['@jsObject'];
+		return aString in obj ? obj[aString] : aBlock._value();
+	>
+!
+
+at: aString ifPresent: aBlock
+	"return the evaluation of aBlock with the value if the property is defined or return nil"
+	<
+		var obj = self['@jsObject'];
+		return aString in obj ? aBlock._value_(obj[aString]) : nil;
+	>
+!
+
+at: aString ifPresent: aBlock ifAbsent: anotherBlock
+	"return the evaluation of aBlock with the value if the property is defined
+	or return value of anotherBlock"
+	<
+		var obj = self['@jsObject'];
+		return aString in obj ? aBlock._value_(obj[aString]) : anotherBlock._value();
+	>
+!
+
+at: aString put: anObject
+	<self['@jsObject'][aString] = anObject>
+!
+
+jsObject
+	^ jsObject
+!
+
+jsObject: aJSObject
+	jsObject := aJSObject
+!
+
+lookupProperty: aString
+	"Looks up a property in JS object.
+	Answer the property if it is present, or nil if it is not present."
+	
+	<return aString in self._jsObject() ? aString : nil>
+! !
+
+!JSObjectProxy methodsFor: 'enumerating'!
+
+asJSON
+	"Answers the receiver in a stringyfy-friendly fashion"
+
+	^ jsObject
+!
+
+keysAndValuesDo: aBlock
+	<
+		var o = self['@jsObject'];
+		for(var i in o) {
+			aBlock._value_value_(i, o[i]);
+		}
+	>
+! !
+
+!JSObjectProxy methodsFor: 'printing'!
+
+printOn: aStream
+	aStream nextPutAll: self printString
+!
+
+printString
+	<
+		var js = self['@jsObject'];
+		return js.toString
+			? js.toString()
+			: Object.prototype.toString.call(js)
+	>
+! !
+
+!JSObjectProxy methodsFor: 'proxy'!
+
+addObjectVariablesTo: aDictionary
+	<
+		for(var i in self['@jsObject']) {
+			aDictionary._at_put_(i, self['@jsObject'][i]);
+		}
+	>
+!
+
+doesNotUnderstand: aMessage
+	^ (self lookupProperty: aMessage selector asJavaScriptSelector)
+		ifNil: [ super doesNotUnderstand: aMessage ]
+		ifNotNil: [ :jsSelector | 
+			self 
+				forwardMessage: jsSelector 
+				withArguments: aMessage arguments ]
+!
+
+forwardMessage: aString withArguments: anArray
+	<
+		return smalltalk.send(self._jsObject(), aString, anArray);
+	>
+!
+
+inspectOn: anInspector
+	| variables |
+	variables := Dictionary new.
+	variables at: '#self' put: self jsObject.
+	anInspector setLabel: self printString.
+	self addObjectVariablesTo: variables.
+	anInspector setVariables: variables
+! !
+
+!JSObjectProxy class methodsFor: 'instance creation'!
+
+on: aJSObject
+	^ self new
+		jsObject: aJSObject;
+		yourself
+! !
+
 Object subclass: #InspectorHandler
 	instanceVariableNames: ''
 	package: 'Kernel-Infrastructure'!
@@ -249,167 +499,6 @@ evaluate: aBlock on: anErrorClass do: exceptionBlock
  			ifFalse: [ exception signal ] ]
 ! !
 
-Object subclass: #JSObjectProxy
-	instanceVariableNames: 'jsObject'
-	package: 'Kernel-Infrastructure'!
-!JSObjectProxy commentStamp!
-I handle sending messages to JavaScript objects, making  JavaScript object accessing from Amber fully transparent.
-My instances make intensive use of `#doesNotUnderstand:`.
-
-My instances are automatically created by Amber whenever a message is sent to a JavaScript object.
-
-## Usage examples
-
-JSObjectProxy objects are instanciated by Amber when a Smalltalk message is sent to a JavaScript object.
-
-	window alert: 'hello world'.
-	window inspect.
-	(window jQuery: 'body') append: 'hello world'
-
-Amber messages sends are converted to JavaScript function calls or object property access _(in this order)_. If n one of them match, a `MessageNotUnderstood` error will be thrown.
-
-## Message conversion rules
-
-- `someUser name` becomes `someUser.name`
-- `someUser name: 'John'` becomes `someUser name = "John"`
-- `console log: 'hello world'` becomes `console.log('hello world')`
-- `(window jQuery: 'foo') css: 'background' color: 'red'` becomes `window.jQuery('foo').css('background', 'red')`
-
-__Note:__ For keyword-based messages, only the first keyword is kept: `window foo: 1 bar: 2` is equivalent to `window foo: 1 baz: 2`.!
-
-!JSObjectProxy methodsFor: 'accessing'!
-
-at: aString
-	<return self['@jsObject'][aString]>
-!
-
-at: aString ifAbsent: aBlock
-	"return the aString property or evaluate aBlock if the property is not defined on the object"
-	<
-		var obj = self['@jsObject'];
-		return aString in obj ? obj[aString] : aBlock._value();
-	>
-!
-
-at: aString ifPresent: aBlock
-	"return the evaluation of aBlock with the value if the property is defined or return nil"
-	<
-		var obj = self['@jsObject'];
-		return aString in obj ? aBlock._value_(obj[aString]) : nil;
-	>
-!
-
-at: aString ifPresent: aBlock ifAbsent: anotherBlock
-	"return the evaluation of aBlock with the value if the property is defined
-	or return value of anotherBlock"
-	<
-		var obj = self['@jsObject'];
-		return aString in obj ? aBlock._value_(obj[aString]) : anotherBlock._value();
-	>
-!
-
-at: aString put: anObject
-	<self['@jsObject'][aString] = anObject>
-!
-
-jsObject
-	^ jsObject
-!
-
-jsObject: aJSObject
-	jsObject := aJSObject
-!
-
-lookupProperty: aString
-	"Looks up a property in JS object.
-	Answer the property if it is present, or nil if it is not present."
-	
-	<return aString in self._jsObject() ? aString : nil>
-!
-
-value
-	"if attribute 'value' exists on the JS object return it,
-	otherwise return the result of Object>>value."
-	
-	^ self 
-		at: 'value' 
-		ifAbsent: [ super value ]
-! !
-
-!JSObjectProxy methodsFor: 'enumerating'!
-
-asJSON
-	"Answers the receiver in a stringyfy-friendly fashion"
-
-	^ jsObject
-!
-
-keysAndValuesDo: aBlock
-	<
-		var o = self['@jsObject'];
-		for(var i in o) {
-			aBlock._value_value_(i, o[i]);
-		}
-	>
-! !
-
-!JSObjectProxy methodsFor: 'printing'!
-
-printOn: aStream
-	aStream nextPutAll: self printString
-!
-
-printString
-	<
-		var js = self['@jsObject'];
-		return js.toString
-			? js.toString()
-			: Object.prototype.toString.call(js)
-	>
-! !
-
-!JSObjectProxy methodsFor: 'proxy'!
-
-addObjectVariablesTo: aDictionary
-	<
-		for(var i in self['@jsObject']) {
-			aDictionary._at_put_(i, self['@jsObject'][i]);
-		}
-	>
-!
-
-doesNotUnderstand: aMessage
-	^ (self lookupProperty: aMessage selector asJavaScriptSelector)
-		ifNil: [ super doesNotUnderstand: aMessage ]
-		ifNotNil: [ :jsSelector | 
-			self 
-				forwardMessage: jsSelector 
-				withArguments: aMessage arguments ]
-!
-
-forwardMessage: aString withArguments: anArray
-	<
-		return smalltalk.send(self._jsObject(), aString, anArray);
-	>
-!
-
-inspectOn: anInspector
-	| variables |
-	variables := Dictionary new.
-	variables at: '#self' put: self jsObject.
-	anInspector setLabel: self printString.
-	self addObjectVariablesTo: variables.
-	anInspector setVariables: variables
-! !
-
-!JSObjectProxy class methodsFor: 'instance creation'!
-
-on: aJSObject
-	^ self new
-		jsObject: aJSObject;
-		yourself
-! !
-
 Object subclass: #Organizer
 	instanceVariableNames: ''
 	package: 'Kernel-Infrastructure'!
@@ -575,7 +664,7 @@ loadDependencyClasses
 	starCategoryName := '*', self name.
 	^ (self classes collect: [ :each | each superclass ]) asSet
 		remove: nil ifAbsent: [];
-		addAll: (Smalltalk current classes select: [ :each | each protocols includes: starCategoryName ]);
+		addAll: (Smalltalk current classes select: [ :each | each protocols, each class protocols includes: starCategoryName ]);
 		yourself
 ! !
 

+ 5 - 11
st/Kernel-Objects.st

@@ -59,11 +59,11 @@ class
 
 identityHash
 	<
-	var hash=self.identityHash;
-	if (hash) return hash;
-	hash=smalltalk.nextId();
-	Object.defineProperty(self, 'identityHash', {value:hash});
-	return hash;
+		var hash=self.identityHash;
+		if (hash) return hash;
+		hash=smalltalk.nextId();
+		Object.defineProperty(self, 'identityHash', {value:hash});
+		return hash;
 	>
 !
 
@@ -129,12 +129,6 @@ asJavascript
 
 asString
 	^ self printString
-!
-
-test
-	| a |
-	a := 1.
-	self halt
 ! !
 
 !Object methodsFor: 'copying'!

+ 83 - 17
st/Kernel-Tests.st

@@ -22,6 +22,40 @@ testHandlesAnnouncement
 	classBuilder basicRemoveClass: announcementClass1.
 ! !
 
+TestCase subclass: #AnnouncerTest
+	instanceVariableNames: ''
+	package: 'Kernel-Tests'!
+
+!AnnouncerTest methodsFor: 'not yet classified'!
+
+testOnDo
+	| counter announcer |
+	
+	counter := 0.
+	announcer := Announcer new.
+	announcer on: SystemAnnouncement do: [ counter := counter + 1 ].
+
+	announcer announce: (SystemAnnouncement new).
+	self assert: counter equals: 1.
+
+	announcer announce: (SystemAnnouncement new).
+	self assert: counter equals: 2.
+!
+
+testOnDoOnce
+	| counter announcer |
+	
+	counter := 0.
+	announcer := Announcer new.
+	announcer on: SystemAnnouncement doOnce: [ counter := counter + 1 ].
+
+	announcer announce: (SystemAnnouncement new).
+	self assert: counter equals: 1.
+
+	announcer announce: (SystemAnnouncement new).
+	self assert: counter equals: 1.
+! !
+
 TestCase subclass: #BlockClosureTest
 	instanceVariableNames: ''
 	package: 'Kernel-Tests'!
@@ -382,6 +416,26 @@ isCollectionReadOnly
 
 !CollectionTest methodsFor: 'tests'!
 
+testAllSatisfy
+	| collection anyOne |
+	collection := self collection.
+	anyOne := collection anyOne.
+	self assert: (collection allSatisfy: [ :each | collection includes: each ]).
+	self deny: (collection allSatisfy: [ :each | each ~= anyOne ])
+!
+
+testAnyOne
+	self should: [ self collectionClass new anyOne ] raise: Error.
+	self assert: (self collection includes: self collection anyOne)
+!
+
+testAnySatisfy
+	| anyOne |
+	anyOne := self collection anyOne.
+	self assert: (self collection anySatisfy: [ :each | each = anyOne ]).
+	self deny: (self collection anySatisfy: [ :each | each = Object new ])
+!
+
 testAsArray
 	self
 		assertSameContents: self collection
@@ -429,11 +483,36 @@ testDo
 		as: newCollection
 !
 
+testIfEmptyFamily
+	self assert: (self collectionClass new ifEmpty: [ 42 ]) equals: 42.
+	self assert: (self collection ifEmpty: [ 42 ]) equals: self collection.
+
+	self assert: (self collectionClass new ifNotEmpty: [ 42 ]) equals: self collectionClass new.
+	self assert: (self collection ifNotEmpty: [ 42 ]) equals: 42.
+	
+	self assert: (self collectionClass new ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 42.
+	self assert: (self collection ifEmpty: [ 42 ] ifNotEmpty: [ 999 ]) equals: 999.
+
+	self assert: (self collectionClass new ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 999.
+	self assert: (self collection ifNotEmpty: [ 42 ] ifEmpty: [ 999 ]) equals: 42
+!
+
 testIsEmpty
 	self assert: self collectionClass new isEmpty.
 	self deny: self collection isEmpty
 !
 
+testNoneSatisfy
+	| anyOne |
+	anyOne := self collection anyOne.
+	self deny: (self collection noneSatisfy: [ :each | each = anyOne ]).
+	self assert: (self collection noneSatisfy: [ :each | each = Object new ])
+!
+
+testRemoveAll
+	self assert: (self collection removeAll; yourself) equals: self collectionClass new
+!
+
 testSelect
 	| newCollection |
 	newCollection := #(2 -4).
@@ -475,14 +554,6 @@ testAtIfAbsent
 	self assert: (self collection at: (self collection size + 1) ifAbsent: [ 'none' ]) equals: 'none'
 !
 
-testContains
-	| collection |
-	collection := self collection.
-	
-	self assert: (self collection contains: [ :each | each = self collection first ]).
-	self deny: (self collection contains: [ :each | each = Object new ])
-!
-
 testIndexOf
 	self assert: (self collection indexOf: 2) equals: 2.
 	self should: [ self collection indexOf: 999 ] raise: Error.
@@ -522,14 +593,6 @@ testAt
 	self should: [ self collection at: 5 ] raise: Error
 !
 
-testContains
-	| collection |
-	collection := self collection.
-	
-	self assert: (self collection contains: [ :each | each = self collection values first ]).
-	self deny: (self collection contains: [ :each | each = Object new ])
-!
-
 testFrom
 "Accept a collection of associations."
 | associations |
@@ -1057,6 +1120,10 @@ testJoin
 	self assert: (',' join: #('hello' 'world')) equals: 'hello,world'
 !
 
+testRemoveAll
+	self should: [ self collection removeAll ] raise: Error
+!
+
 testReversed
 	self assert: 'jackiechan' reversed equals: 'nahceikcaj'.
 !
@@ -1197,7 +1264,6 @@ testPropertyThatReturnsUndefined
 testValue
 	| testObject |
 	testObject := self jsObject.
-	self assert: testObject value printString equals: '[object Object]'.
 	testObject at: 'value' put: 'aValue'.
 	self assert: testObject value equals: 'aValue'
 !

+ 23 - 20
support/amber.js

@@ -16,23 +16,26 @@ var require;
 
 require = function (require) {
     var scripts = document.getElementsByTagName("script");
-    var src = scripts[ scripts.length - 1 ].src;
+    var me = scripts[scripts.length - 1];
+    var src = me.src;
     // strip the last two elements from the URL
-    // e.g. http://app.com/lib/script.js -> http://app.com/
+    // e.g. http://app.com/amber/support/amber.js -> http://app.com/amber
     var amber_home = resolveViaDOM(src).replace(/\/[^\/]+\/[^\/]+$/, "");
-    // strip the last element from the URL
-    // e.g. http://app.com/index.html -> http://app.com/
-    var document_home = window.location.href.replace(/\/[^\/]+$/, "");
+    // In case of nonstandard deployment, you can specify libraries placement directly ...
+    var library_home = me.hasAttribute('data-libs') && me.getAttribute('data-libs');
 
-    // at the present moment, bower tries to have flat hierarchy,
-    // which leads to two possible scenarios:
-    // 1. amber itself was deployed via bower,
-    //    its libraries are next to it; document_home from above covers this
-    // 2. amber was deployed in different fashion,
-    //    its libraries are included by bower locally; document_home is fixed below
-    // The detection is done by looking for '/bower_components/' in amber path.
-    if (!amber_home.match(/\/bower_components\//)) {
-        document_home = amber_home;
+    // ... otherwise, this heuristics is used:
+    if (!library_home) {
+        // At the present moment, bower tries to have flat hierarchy,
+        // which leads to two possible scenarios:
+        // 1. amber itself was deployed via bower,
+        //    its libraries are at the same bower dir
+        //    where amber itself is placed
+        // 2. amber was deployed in different fashion,
+        //    its libraries are included by bower locally, inside amber
+        // The detection is done by looking for '/bower_components/' in amber path.
+        var match = amber_home.match(/^(.*\/bower_components)\//);
+        library_home = match ? match[1] : amber_home + '/bower_components';
     }
 
     function resolveViaDOM(url) {
@@ -46,13 +49,13 @@ require = function (require) {
             'amber': amber_home + '/support',
             'amber_vm': amber_home + '/support',
             'amber_css': amber_home + '/css',
-            'amber_lib': document_home + '/bower_components',
+            'amber_lib': library_home,
             'amber_inc': amber_home + '/support',
             'amber_core': amber_home + '/js',
             'amber_core/_source': amber_home + '/st',
-            'amber_html': amber_home,
-            'jquery': document_home + '/bower_components/jquery/jquery.min',
-            'jquery-ui': amber_home + '/support/jQuery/jquery-ui-1.8.24.custom.min'
+            'amber_helios/html': amber_home,
+            'jquery': library_home + '/jquery/jquery.min',
+            'jquery-ui': library_home + '/jquery-ui/ui/minified/jquery-ui.min'
         },
         map: {
             '*': {
@@ -66,11 +69,11 @@ require = function (require) {
             'amber_lib/bootstrap/js/bootstrap': {
                 deps: [ 'jquery', 'css!amber_lib/bootstrap/css/bootstrap' ]
             },
-            'amber_lib/CodeMirror/codemirror': {
+            'amber_lib/codemirror/lib/codemirror': {
                 deps: [ 'css!amber_lib/codemirror/lib/codemirror' ]
             },
             'amber_lib/jquery-tabby/jquery.textarea': {
-                deps: [ 'jquery', 'jquery-ui' ]
+                deps: [ 'jquery' ]
             },
             'amber_inc/CodeMirror/smalltalk': {
                 deps: [ 'amber_lib/codemirror/lib/codemirror' ]

+ 29 - 10
support/boot.js

@@ -57,6 +57,7 @@ function Brikz(api, apiKey, initKey) {
 
 	var d={value: null, enumerable: false, configurable: true, writable: true};
 	Object.defineProperties(this, { ensure: d, rebuild: d });
+	var exclude = mixin(this, {});
 
 	this.rebuild = function () {
 		Object.keys(backup).forEach(function (key) {
@@ -64,6 +65,7 @@ function Brikz(api, apiKey, initKey) {
 		});
 		var oapi = mixin(api, {}), order = [], chk = {};
 		brikz.ensure = function(key) {
+			if (key in exclude) { return null; }
 			var b = brikz[key], bak = backup[key];
 			mixin({}, api, api);
 			while (typeof b === "function") { b = new b(brikz, api, bak); }
@@ -92,7 +94,11 @@ function inherits(child, parent) {
 
 /* Smalltalk foundational objects */
 
+/* SmalltalkRoot is the hidden root of the Amber hierarchy.
+ All objects including `Object` inherit from SmalltalkRoot */
+function SmalltalkRoot() {}
 function SmalltalkObject() {}
+inherits(SmalltalkObject, SmalltalkRoot);
 
 function Smalltalk() {}
 inherits(Smalltalk, SmalltalkObject);
@@ -107,6 +113,9 @@ function RootBrik(brikz, st) {
 
 	this.nil = new SmalltalkNil();
 
+	// Hidden root class of the system.
+	this.rootAsClass = {fn: SmalltalkRoot};
+
 	this.__init__ = function () {
 		st.addPackage("Kernel-Objects");
 		st.addPackage("Kernel-Infrastructure");
@@ -162,6 +171,7 @@ function DNUBrik(brikz, st) {
 	brikz.ensure("selectorConversion");
 	brikz.ensure("messageSend");
 	var manip = brikz.ensure("manipulation");
+	var rootAsClass = brikz.ensure("root").rootAsClass;
 
 	/* Method not implemented handlers */
 
@@ -178,6 +188,7 @@ function DNUBrik(brikz, st) {
 		checker[selector] = true;
 		var method = {jsSelector: selector, fn: createHandler(selector)};
 		methods.push(method);
+		manip.installMethod(method, rootAsClass);
 		return method;
 	};
 
@@ -222,7 +233,7 @@ function ClassInitBrik(brikz, st) {
 			copySuperclass(klass);
 		}
 
-		if(klass === st.Object || klass.wrapped) {
+		if(klass.wrapped) {
 			dnu.installHandlers(klass);
 		}
 	};
@@ -291,7 +302,10 @@ function ManipulationBrik(brikz, st) {
 function ClassesBrik(brikz, st) {
 
 	var org = brikz.ensure("organize");
-	var nil = brikz.ensure("root").nil;
+	var root = brikz.ensure("root");
+	var nil = root.nil;
+	var rootAsClass = root.rootAsClass;
+	rootAsClass.klass = {fn: SmalltalkClass};
 
 	function SmalltalkPackage() {}
 	function SmalltalkBehavior() {}
@@ -311,7 +325,8 @@ function ClassesBrik(brikz, st) {
 		st.wrapClassName("Metaclass", "Kernel-Classes", SmalltalkMetaclass, st.Behavior, false);
 		st.wrapClassName("Class", "Kernel-Classes", SmalltalkClass, st.Behavior, false);
 
-		st.Object.klass.superclass = st.Class;
+		// Manually bootstrap the metaclass hierarchy
+		st.Object.klass.superclass = rootAsClass.klass = st.Class;
 		addSubclass(st.Object.klass);
 
 		st.wrapClassName("Package", "Kernel-Infrastructure", SmalltalkPackage, st.Object, false);
@@ -343,9 +358,16 @@ function ClassesBrik(brikz, st) {
 
 	function klass(spec) {
 		spec = spec || {};
+		var setSuperClass = spec.superclass;
+		if(!spec.superclass) {
+			spec.superclass = rootAsClass;
+		}
+
 		var meta = metaclass(spec);
 		var that = meta.instanceClass;
 
+		that.superclass = setSuperClass;
+
 		that.fn = spec.fn || inherits(function () {}, spec.superclass.fn);
 		that.subclasses = [];
 
@@ -354,17 +376,14 @@ function ClassesBrik(brikz, st) {
 		that.className = spec.className;
 		that.wrapped   = spec.wrapped || false;
 		meta.className = spec.className + ' class';
-		if(spec.superclass) {
-			that.superclass = spec.superclass;
-			meta.superclass = spec.superclass.klass;
-		}
+		meta.superclass = spec.superclass.klass;
 		return that;
 	}
 
 	function metaclass(spec) {
 		spec = spec || {};
 		var that = new SmalltalkMetaclass();
-		that.fn = inherits(function () {}, spec.superclass ? spec.superclass.klass.fn : SmalltalkClass);
+		that.fn = inherits(function () {}, spec.superclass.klass.fn);
 		that.instanceClass = new that.fn();
 		setupClass(that);
 		return that;
@@ -431,8 +450,8 @@ function ClassesBrik(brikz, st) {
 	function rawAddClass(pkgName, className, superclass, iVarNames, wrapped, fn) {
 		var pkg = st.packages[pkgName];
 
-		if (!pkg) { 
-			throw new Error("Missing package "+pkgName); 
+		if (!pkg) {
+			throw new Error("Missing package "+pkgName);
 		}
 
 		if(st[className] && st[className].superclass == superclass) {

+ 4 - 26
support/devel.js

@@ -1,7 +1,7 @@
 define([
-	'amber_vm/smalltalk',
-	'./helpers',
-	'jquery',
+	'amber_vm/smalltalk', // pre-fetch, dep of ./deploy
+	'./deploy', // pre-fetch, dep of ./lang
+	'./lang',
 	'jquery-ui',
 	'amber_lib/jquery-tabby/jquery.textarea',
 	'amber_lib/codemirror/lib/codemirror',
@@ -12,29 +12,7 @@ define([
 	'css!amber_lib/codemirror/addon/hint/show-hint',
 	'css!amber_inc/CodeMirror/amber',
 	'css!amber_css/amber',
-	'amber_core/Kernel-Objects',
-	'amber_core/Kernel-Classes',
-	'amber_core/Kernel-Methods',
-	'amber_core/Kernel-Collections',
-	'amber_core/Kernel-Infrastructure',
-	'amber_core/Kernel-Exceptions',
-	'amber_core/Kernel-Transcript',
-	'amber_core/Kernel-Announcements',
-	'amber_core/Canvas',
-	'amber_core/SUnit',
-	'amber_core/Importer-Exporter',
-	'amber_core/Compiler-Exceptions',
-	'amber_core/Compiler-Core',
-	'amber_core/Compiler-AST',
-	'amber_core/Compiler-Semantic',
-	'amber_core/Compiler-IR',
-	'amber_core/Compiler-Inlining',
-	'amber_core/Compiler-Interpreter',
-	'amber_core/Compiler-Tests',
-	'amber_vm/parser',
 	'amber_core/IDE',
 	'amber_core/Examples',
-	'amber_core/Benchfib',
-	'amber_core/Kernel-Tests',
-	'amber_core/SUnit-Tests'
+	'amber_core/Benchfib'
 ], function (smalltalk) { return smalltalk; });

+ 3 - 25
support/helios.js

@@ -1,7 +1,7 @@
 define([
-	'amber_vm/smalltalk',
-	'./helpers',
-	'jquery',
+	'amber_vm/smalltalk', // pre-fetch, dep of ./deploy
+	'./deploy', // pre-fetch, dep of ./lang
+	'./lang',
 	'jquery-ui',
 	'amber_lib/jquery-tabby/jquery.textarea',
 	'amber_lib/bootstrap/js/bootstrap',
@@ -14,31 +14,9 @@ define([
 	'css!amber_lib/codemirror/addon/hint/show-hint',
 	'css!amber_inc/CodeMirror/amber',
 	'css!amber_css/helios',
-	'amber_core/Kernel-Objects',
-	'amber_core/Kernel-Classes',
-	'amber_core/Kernel-Methods',
-	'amber_core/Kernel-Collections',
-	'amber_core/Kernel-Infrastructure',
-	'amber_core/Kernel-Exceptions',
-	'amber_core/Kernel-Transcript',
-	'amber_core/Kernel-Announcements',
-	'amber_core/Canvas',
-	'amber_core/SUnit',
-	'amber_core/Importer-Exporter',
-	'amber_core/Compiler-Exceptions',
-	'amber_core/Compiler-Core',
-	'amber_core/Compiler-AST',
-	'amber_core/Compiler-Semantic',
-	'amber_core/Compiler-IR',
-	'amber_core/Compiler-Inlining',
-	'amber_core/Compiler-Interpreter',
-	'amber_core/Compiler-Tests',
-	'amber_vm/parser',
 	'amber_core/IDE',
 	'amber_core/Examples',
 	'amber_core/Benchfib',
-	'amber_core/Kernel-Tests',
-	'amber_core/SUnit-Tests',
 	'amber_core/Spaces',
 	'amber_core/Helios-Core',
 	'amber_core/Helios-Exceptions',

+ 8 - 4
support/helpers.js

@@ -1,8 +1,12 @@
 define("amber/helpers", ["amber_vm/smalltalk", "require"], function (smalltalk, require) {
-    return {
+    var exports = {
         popupHelios: function () {
-            window.open(require.toUrl('amber_html/helios.html'), "Helios", "menubar=no, status=no, scrollbars=no, menubar=no, width=1000, height=600");
-        },
-        get smalltalk() { return smalltalk; }
+            window.open(require.toUrl('amber_helios/html/helios.html'), "Helios", "menubar=no, status=no, scrollbars=no, menubar=no, width=1000, height=600");
+        }
     };
+    Object.defineProperty(exports, "smalltalk", {
+        value: smalltalk,
+        enumerable: true, configurable: true, writable: false
+    });
+    return  exports;
 });

File diff suppressed because it is too large
+ 0 - 4
support/jQuery/jquery-ui-1.8.24.custom.min.js


+ 17 - 0
support/lang.js

@@ -0,0 +1,17 @@
+define([
+	'amber_vm/smalltalk', // pre-fetch, dep of ./deploy
+	'./deploy',
+	'amber_vm/parser',
+	'amber_core/Kernel-ImportExport',
+	'amber_core/Compiler-Exceptions',
+	'amber_core/Compiler-Core',
+	'amber_core/Compiler-AST',
+	'amber_core/Compiler-Semantic',
+	'amber_core/Compiler-IR',
+	'amber_core/Compiler-Inlining',
+	'amber_core/Compiler-Interpreter',
+	'amber_core/SUnit',
+	'amber_core/Compiler-Tests',
+	'amber_core/Kernel-Tests',
+	'amber_core/SUnit-Tests'
+], function (smalltalk) { return smalltalk; });

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