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