|  | @@ -857,6 +857,77 @@ referencedClasses: []
 | 
	
		
			
				|  |  |  smalltalk.ChunkParser.klass);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +smalltalk.addClass('ExportRecipeInterpreter', smalltalk.Object, [], 'Importer-Exporter');
 | 
	
		
			
				|  |  | +smalltalk.ExportRecipeInterpreter.comment="I am an interpreter for export recipes.\x0a\x0a## Recipe format\x0a\x0aRecipe is an array, which can contain two kinds of elements:\x0a\x0a - an assocation where the key is the receiver and the value is a two-arguments selector\x0a    In this case, `receiver perform: selector withArguments: { data. stream }` is called.\x0a\x09This essentially defines one step of export process.\x0a\x09The key (eg. receiver) is presumed to be some kind of 'repository' of the exporting methods\x0a\x09that just format appropriate aspect of data into a stream; like a class or a singleton,\x0a\x09so that the recipe itself can be decoupled from data.\x0a\x0a - a subarray, where first element is special and the rest is recursive recipe.\x0a\x0a    `subarray first` must be an association similar to one above,\x0a\x09with key being the 'repository' receiver, but value is one-arg selector.\x0a\x09In this case, `receiver perform: selector withArguments: { data }` should create a collection.\x0a\x09Then, the sub-recipe (`subarray allButFirst`) is applied to every element of a collection, eg.\x0a\x09  collection do: [ :each | self export: each using: sa allButFirst on: stream ]";
 | 
	
		
			
				|  |  | +smalltalk.addMethod(
 | 
	
		
			
				|  |  | +smalltalk.method({
 | 
	
		
			
				|  |  | +selector: "interpret:for:on:",
 | 
	
		
			
				|  |  | +category: 'interpreting',
 | 
	
		
			
				|  |  | +fn: function (aRecipe,anObject,aStream){
 | 
	
		
			
				|  |  | +var self=this;
 | 
	
		
			
				|  |  | +var recipeStream;
 | 
	
		
			
				|  |  | +return smalltalk.withContext(function($ctx1) { 
 | 
	
		
			
				|  |  | +recipeStream=_st(aRecipe)._readStream();
 | 
	
		
			
				|  |  | +_st((function(){
 | 
	
		
			
				|  |  | +return smalltalk.withContext(function($ctx2) {
 | 
	
		
			
				|  |  | +return _st(recipeStream)._atEnd();
 | 
	
		
			
				|  |  | +}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._whileFalse_((function(){
 | 
	
		
			
				|  |  | +return smalltalk.withContext(function($ctx2) {
 | 
	
		
			
				|  |  | +return self._interpretStep_for_on_(_st(recipeStream)._next(),anObject,aStream);
 | 
	
		
			
				|  |  | +}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
 | 
	
		
			
				|  |  | +return self}, function($ctx1) {$ctx1.fill(self,"interpret:for:on:",{aRecipe:aRecipe,anObject:anObject,aStream:aStream,recipeStream:recipeStream},smalltalk.ExportRecipeInterpreter)})},
 | 
	
		
			
				|  |  | +args: ["aRecipe", "anObject", "aStream"],
 | 
	
		
			
				|  |  | +source: "interpret: aRecipe for: anObject on: aStream\x0a\x09| recipeStream |\x0a\x09\x0a\x09recipeStream := aRecipe readStream.\x0a\x09\x0a\x09[ recipeStream atEnd ] whileFalse: [\x0a\x09\x09self \x0a\x09\x09\x09interpretStep: recipeStream next\x0a\x09\x09\x09for: anObject\x0a\x09\x09\x09on: aStream ]",
 | 
	
		
			
				|  |  | +messageSends: ["readStream", "whileFalse:", "atEnd", "interpretStep:for:on:", "next"],
 | 
	
		
			
				|  |  | +referencedClasses: []
 | 
	
		
			
				|  |  | +}),
 | 
	
		
			
				|  |  | +smalltalk.ExportRecipeInterpreter);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +smalltalk.addMethod(
 | 
	
		
			
				|  |  | +smalltalk.method({
 | 
	
		
			
				|  |  | +selector: "interpretStep:for:on:",
 | 
	
		
			
				|  |  | +category: 'interpreting',
 | 
	
		
			
				|  |  | +fn: function (aRecipeStep,anObject,aStream){
 | 
	
		
			
				|  |  | +var self=this;
 | 
	
		
			
				|  |  | +return smalltalk.withContext(function($ctx1) { 
 | 
	
		
			
				|  |  | +var $1,$2;
 | 
	
		
			
				|  |  | +$1=_st(_st(aRecipeStep)._value()).__eq_eq(aRecipeStep);
 | 
	
		
			
				|  |  | +if(smalltalk.assert($1)){
 | 
	
		
			
				|  |  | +$2=self._interpretSubRecipe_for_on_(aRecipeStep,anObject,aStream);
 | 
	
		
			
				|  |  | +return $2;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +_st(_st(aRecipeStep)._key())._perform_withArguments_(_st(aRecipeStep)._value(),[anObject,aStream]);
 | 
	
		
			
				|  |  | +return self}, function($ctx1) {$ctx1.fill(self,"interpretStep:for:on:",{aRecipeStep:aRecipeStep,anObject:anObject,aStream:aStream},smalltalk.ExportRecipeInterpreter)})},
 | 
	
		
			
				|  |  | +args: ["aRecipeStep", "anObject", "aStream"],
 | 
	
		
			
				|  |  | +source: "interpretStep: aRecipeStep for: anObject on: aStream\x0a\x09aRecipeStep value == aRecipeStep ifTrue: [ \x0a\x09\x09^ self interpretSubRecipe: aRecipeStep for: anObject on: aStream ].\x0a\x09\x09\x09\x0a\x09aRecipeStep key perform: aRecipeStep value withArguments: { anObject. aStream }",
 | 
	
		
			
				|  |  | +messageSends: ["ifTrue:", "==", "value", "interpretSubRecipe:for:on:", "perform:withArguments:", "key"],
 | 
	
		
			
				|  |  | +referencedClasses: []
 | 
	
		
			
				|  |  | +}),
 | 
	
		
			
				|  |  | +smalltalk.ExportRecipeInterpreter);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +smalltalk.addMethod(
 | 
	
		
			
				|  |  | +smalltalk.method({
 | 
	
		
			
				|  |  | +selector: "interpretSubRecipe:for:on:",
 | 
	
		
			
				|  |  | +category: 'interpreting',
 | 
	
		
			
				|  |  | +fn: function (aRecipe,anObject,aStream){
 | 
	
		
			
				|  |  | +var self=this;
 | 
	
		
			
				|  |  | +var selection;
 | 
	
		
			
				|  |  | +return smalltalk.withContext(function($ctx1) { 
 | 
	
		
			
				|  |  | +selection=_st(_st(_st(aRecipe)._first())._key())._perform_withArguments_(_st(_st(aRecipe)._first())._value(),[anObject]);
 | 
	
		
			
				|  |  | +_st(selection)._do_((function(each){
 | 
	
		
			
				|  |  | +return smalltalk.withContext(function($ctx2) {
 | 
	
		
			
				|  |  | +return self._interpret_for_on_(_st(aRecipe)._allButFirst(),each,aStream);
 | 
	
		
			
				|  |  | +}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 | 
	
		
			
				|  |  | +return self}, function($ctx1) {$ctx1.fill(self,"interpretSubRecipe:for:on:",{aRecipe:aRecipe,anObject:anObject,aStream:aStream,selection:selection},smalltalk.ExportRecipeInterpreter)})},
 | 
	
		
			
				|  |  | +args: ["aRecipe", "anObject", "aStream"],
 | 
	
		
			
				|  |  | +source: "interpretSubRecipe: aRecipe for: anObject on: aStream\x0a\x09| selection |\x0a\x09selection := aRecipe first key \x0a\x09\x09perform: aRecipe first value \x0a\x09\x09withArguments: { anObject }.\x0a\x09selection do: [ :each |\x09\x0a\x09\x09self interpret: aRecipe allButFirst for: each on: aStream ]",
 | 
	
		
			
				|  |  | +messageSends: ["perform:withArguments:", "key", "first", "value", "do:", "interpret:for:on:", "allButFirst"],
 | 
	
		
			
				|  |  | +referencedClasses: []
 | 
	
		
			
				|  |  | +}),
 | 
	
		
			
				|  |  | +smalltalk.ExportRecipeInterpreter);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  smalltalk.addClass('Importer', smalltalk.Object, [], 'Importer-Exporter');
 | 
	
		
			
				|  |  |  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(
 | 
	
	
		
			
				|  | @@ -1531,16 +1602,16 @@ selector: "interpreter",
 | 
	
		
			
				|  |  |  category: 'accessing',
 | 
	
		
			
				|  |  |  fn: function (){
 | 
	
		
			
				|  |  |  var self=this;
 | 
	
		
			
				|  |  | -function $RecipeInterpreter(){return smalltalk.RecipeInterpreter||(typeof RecipeInterpreter=="undefined"?nil:RecipeInterpreter)}
 | 
	
		
			
				|  |  | +function $ExportRecipeInterpreter(){return smalltalk.ExportRecipeInterpreter||(typeof ExportRecipeInterpreter=="undefined"?nil:ExportRecipeInterpreter)}
 | 
	
		
			
				|  |  |  return smalltalk.withContext(function($ctx1) { 
 | 
	
		
			
				|  |  |  var $1;
 | 
	
		
			
				|  |  | -$1=_st($RecipeInterpreter())._new();
 | 
	
		
			
				|  |  | +$1=_st($ExportRecipeInterpreter())._new();
 | 
	
		
			
				|  |  |  return $1;
 | 
	
		
			
				|  |  |  }, function($ctx1) {$ctx1.fill(self,"interpreter",{},smalltalk.PluggableExporter)})},
 | 
	
		
			
				|  |  |  args: [],
 | 
	
		
			
				|  |  | -source: "interpreter\x0a\x09^ RecipeInterpreter new",
 | 
	
		
			
				|  |  | +source: "interpreter\x0a\x09^ ExportRecipeInterpreter new",
 | 
	
		
			
				|  |  |  messageSends: ["new"],
 | 
	
		
			
				|  |  | -referencedClasses: ["RecipeInterpreter"]
 | 
	
		
			
				|  |  | +referencedClasses: ["ExportRecipeInterpreter"]
 | 
	
		
			
				|  |  |  }),
 | 
	
		
			
				|  |  |  smalltalk.PluggableExporter);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1618,77 +1689,6 @@ referencedClasses: []
 | 
	
		
			
				|  |  |  }),
 | 
	
		
			
				|  |  |  smalltalk.PluggableExporter.klass);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -smalltalk.addClass('RecipeInterpreter', smalltalk.Object, [], 'Importer-Exporter');
 | 
	
		
			
				|  |  | -smalltalk.RecipeInterpreter.comment="I am an interpreter for export recipes.\x0a\x0a## Recipe format\x0a\x0aRecipe is an array, which can contain two kinds of elements:\x0a\x0a - an assocation where the key is the receiver and the value is a two-arguments selector\x0a    In this case, `receiver perform: selector withArguments: { data. stream }` is called.\x0a\x09This essentially defines one step of export process.\x0a\x09The key (eg. receiver) is presumed to be some kind of 'repository' of the exporting methods\x0a\x09that just format appropriate aspect of data into a stream; like a class or a singleton,\x0a\x09so that the recipe itself can be decoupled from data.\x0a\x0a - a subarray, where first element is special and the rest is recursive recipe.\x0a\x0a    `subarray first` must be an association similar to one above,\x0a\x09with key being the 'repository' receiver, but value is one-arg selector.\x0a\x09In this case, `receiver perform: selector withArguments: { data }` should create a collection.\x0a\x09Then, the sub-recipe (`subarray allButFirst`) is applied to every element of a collection, eg.\x0a\x09  collection do: [ :each | self export: each using: sa allButFirst on: stream ]";
 | 
	
		
			
				|  |  | -smalltalk.addMethod(
 | 
	
		
			
				|  |  | -smalltalk.method({
 | 
	
		
			
				|  |  | -selector: "interpret:for:on:",
 | 
	
		
			
				|  |  | -category: 'interpreting',
 | 
	
		
			
				|  |  | -fn: function (aRecipe,anObject,aStream){
 | 
	
		
			
				|  |  | -var self=this;
 | 
	
		
			
				|  |  | -var recipeStream;
 | 
	
		
			
				|  |  | -return smalltalk.withContext(function($ctx1) { 
 | 
	
		
			
				|  |  | -recipeStream=_st(aRecipe)._readStream();
 | 
	
		
			
				|  |  | -_st((function(){
 | 
	
		
			
				|  |  | -return smalltalk.withContext(function($ctx2) {
 | 
	
		
			
				|  |  | -return _st(recipeStream)._atEnd();
 | 
	
		
			
				|  |  | -}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._whileFalse_((function(){
 | 
	
		
			
				|  |  | -return smalltalk.withContext(function($ctx2) {
 | 
	
		
			
				|  |  | -return self._interpretStep_for_on_(_st(recipeStream)._next(),anObject,aStream);
 | 
	
		
			
				|  |  | -}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
 | 
	
		
			
				|  |  | -return self}, function($ctx1) {$ctx1.fill(self,"interpret:for:on:",{aRecipe:aRecipe,anObject:anObject,aStream:aStream,recipeStream:recipeStream},smalltalk.RecipeInterpreter)})},
 | 
	
		
			
				|  |  | -args: ["aRecipe", "anObject", "aStream"],
 | 
	
		
			
				|  |  | -source: "interpret: aRecipe for: anObject on: aStream\x0a\x09| recipeStream |\x0a\x09\x0a\x09recipeStream := aRecipe readStream.\x0a\x09\x0a\x09[ recipeStream atEnd ] whileFalse: [\x0a\x09\x09self \x0a\x09\x09\x09interpretStep: recipeStream next\x0a\x09\x09\x09for: anObject\x0a\x09\x09\x09on: aStream ]",
 | 
	
		
			
				|  |  | -messageSends: ["readStream", "whileFalse:", "atEnd", "interpretStep:for:on:", "next"],
 | 
	
		
			
				|  |  | -referencedClasses: []
 | 
	
		
			
				|  |  | -}),
 | 
	
		
			
				|  |  | -smalltalk.RecipeInterpreter);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -smalltalk.addMethod(
 | 
	
		
			
				|  |  | -smalltalk.method({
 | 
	
		
			
				|  |  | -selector: "interpretStep:for:on:",
 | 
	
		
			
				|  |  | -category: 'interpreting',
 | 
	
		
			
				|  |  | -fn: function (aRecipeStep,anObject,aStream){
 | 
	
		
			
				|  |  | -var self=this;
 | 
	
		
			
				|  |  | -return smalltalk.withContext(function($ctx1) { 
 | 
	
		
			
				|  |  | -var $1,$2;
 | 
	
		
			
				|  |  | -$1=_st(_st(aRecipeStep)._value()).__eq_eq(aRecipeStep);
 | 
	
		
			
				|  |  | -if(smalltalk.assert($1)){
 | 
	
		
			
				|  |  | -$2=self._interpretSubRecipe_for_on_(aRecipeStep,anObject,aStream);
 | 
	
		
			
				|  |  | -return $2;
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -_st(_st(aRecipeStep)._key())._perform_withArguments_(_st(aRecipeStep)._value(),[anObject,aStream]);
 | 
	
		
			
				|  |  | -return self}, function($ctx1) {$ctx1.fill(self,"interpretStep:for:on:",{aRecipeStep:aRecipeStep,anObject:anObject,aStream:aStream},smalltalk.RecipeInterpreter)})},
 | 
	
		
			
				|  |  | -args: ["aRecipeStep", "anObject", "aStream"],
 | 
	
		
			
				|  |  | -source: "interpretStep: aRecipeStep for: anObject on: aStream\x0a\x09aRecipeStep value == aRecipeStep ifTrue: [ \x0a\x09\x09^ self interpretSubRecipe: aRecipeStep for: anObject on: aStream ].\x0a\x09\x09\x09\x0a\x09aRecipeStep key perform: aRecipeStep value withArguments: { anObject. aStream }",
 | 
	
		
			
				|  |  | -messageSends: ["ifTrue:", "==", "value", "interpretSubRecipe:for:on:", "perform:withArguments:", "key"],
 | 
	
		
			
				|  |  | -referencedClasses: []
 | 
	
		
			
				|  |  | -}),
 | 
	
		
			
				|  |  | -smalltalk.RecipeInterpreter);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -smalltalk.addMethod(
 | 
	
		
			
				|  |  | -smalltalk.method({
 | 
	
		
			
				|  |  | -selector: "interpretSubRecipe:for:on:",
 | 
	
		
			
				|  |  | -category: 'interpreting',
 | 
	
		
			
				|  |  | -fn: function (aRecipe,anObject,aStream){
 | 
	
		
			
				|  |  | -var self=this;
 | 
	
		
			
				|  |  | -var selection;
 | 
	
		
			
				|  |  | -return smalltalk.withContext(function($ctx1) { 
 | 
	
		
			
				|  |  | -selection=_st(_st(_st(aRecipe)._first())._key())._perform_withArguments_(_st(_st(aRecipe)._first())._value(),[anObject]);
 | 
	
		
			
				|  |  | -_st(selection)._do_((function(each){
 | 
	
		
			
				|  |  | -return smalltalk.withContext(function($ctx2) {
 | 
	
		
			
				|  |  | -return self._interpret_for_on_(_st(aRecipe)._allButFirst(),each,aStream);
 | 
	
		
			
				|  |  | -}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 | 
	
		
			
				|  |  | -return self}, function($ctx1) {$ctx1.fill(self,"interpretSubRecipe:for:on:",{aRecipe:aRecipe,anObject:anObject,aStream:aStream,selection:selection},smalltalk.RecipeInterpreter)})},
 | 
	
		
			
				|  |  | -args: ["aRecipe", "anObject", "aStream"],
 | 
	
		
			
				|  |  | -source: "interpretSubRecipe: aRecipe for: anObject on: aStream\x0a\x09| selection |\x0a\x09selection := aRecipe first key \x0a\x09\x09perform: aRecipe first value \x0a\x09\x09withArguments: { anObject }.\x0a\x09selection do: [ :each |\x09\x0a\x09\x09self interpret: aRecipe allButFirst for: each on: aStream ]",
 | 
	
		
			
				|  |  | -messageSends: ["perform:withArguments:", "key", "first", "value", "do:", "interpret:for:on:", "allButFirst"],
 | 
	
		
			
				|  |  | -referencedClasses: []
 | 
	
		
			
				|  |  | -}),
 | 
	
		
			
				|  |  | -smalltalk.RecipeInterpreter);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  smalltalk.addMethod(
 | 
	
		
			
				|  |  |  smalltalk.method({
 | 
	
		
			
				|  |  |  selector: "commit",
 |