Index: /CKReleaser/trunk/_source/ckreleaser.js
===================================================================
--- /CKReleaser/trunk/_source/ckreleaser.js	(revision 3152)
+++ /CKReleaser/trunk/_source/ckreleaser.js	(revision 3152)
@@ -0,0 +1,64 @@
+/*
+Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+importPackage( org.mozilla.javascript );
+importClass( java.io.File );
+
+var jarPath = JavaAdapter(org.mozilla.javascript.Parser)["class"].getResource("/org/mozilla/javascript").toString();
+var releaserPath = jarPath.replaceFirst( "^jar:", '' ).replaceFirst( "\/js\.jar\!\/org\/mozilla\/javascript$", '');
+
+load( releaserPath + "/includes/ckreleaser.js" );
+CKRELEASER.path = releaserPath;
+CKRELEASER.loadCode( "includes/releaser.js" );
+	
+function error( msg )
+{
+	print( msg );
+	print( '' );
+	quit();
+}
+
+if (arguments.length > 1 && arguments[arguments.length-1] == '-v')
+	CKRELEASER.verbose = 1; 
+
+if ( arguments[0] == '-test' )
+{
+	CKRELEASER.loadCode( 'test/test.js' );
+	quit();
+}
+
+CKRELEASER.releaseFile = arguments[0];
+CKRELEASER.sourceDir = arguments[1];
+CKRELEASER.targetDir = arguments[2];
+CKRELEASER.version = arguments[3];
+CKRELEASER.zipName = arguments[4];
+CKRELEASER.targzName = arguments[5];
+
+if ( !CKRELEASER.releaseFile || !CKRELEASER.sourceDir || !CKRELEASER.targetDir 
+		|| !CKRELEASER.version || !CKRELEASER.zipName || !CKRELEASER.targzName)
+{
+	error( 'Usage:java -jar js.jar ckreleaser.js [release_file] [source_dir] [target_dir] [version] [zip_name] [targz_name]' );
+}
+
+CKRELEASER.releaseDir = CKRELEASER.targetDir + "/" + "release";
+CKRELEASER.loadCode( 'tools/CKPackager/includes/ckpackager.js' );
+CKPACKAGER.packDir = CKRELEASER.releaseDir;
+CKPACKAGER.dir = 'tools/CKPackager/';
+CKPACKAGER.outputDir = CKRELEASER.releaseDir;
+CKPACKAGER.loadCode( 'includes/packager.js' );
+
+(function()
+{
+	try {
+		var releaser = new CKRELEASER.releaser();
+		releaser.loadDefinitionFile( CKRELEASER.releaseFile );
+		releaser.run();
+	}
+	catch(e)
+	{
+		print("");
+		error(e);
+	}
+})();
Index: /CKReleaser/trunk/_source/includes/ckreleaser.js
===================================================================
--- /CKReleaser/trunk/_source/includes/ckreleaser.js	(revision 3152)
+++ /CKReleaser/trunk/_source/includes/ckreleaser.js	(revision 3152)
@@ -0,0 +1,27 @@
+/*
+Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+importClass( java.lang.Integer );
+importClass( java.lang.System );
+
+var CKRELEASER = {
+	verbose : 0,
+	os : System.getProperty( "os.name" ).substring(0,3).toLowerCase(),
+
+	timestamp :( function()
+	{
+		var time = new Date();
+		
+		var timestamp = Integer.toString( time.getUTCFullYear() % 1000, 36 ) + Integer.toString( time.getUTCMonth(), 36 )
+				+ Integer.toString( time.getUTCDate(), 36 ) + Integer.toString( time.getUTCHours(), 36 );
+
+		return timestamp.toUpperCase();
+	})(),
+
+	loadCode : function( path )
+	{
+		load( CKRELEASER.path + "/" + path );
+	}
+};
Index: /CKReleaser/trunk/_source/includes/docsprocessor.js
===================================================================
--- /CKReleaser/trunk/_source/includes/docsprocessor.js	(revision 3152)
+++ /CKReleaser/trunk/_source/includes/docsprocessor.js	(revision 3152)
@@ -0,0 +1,59 @@
+/*
+Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+CKRELEASER.loadCode( 'tools/json/json2.js' );
+
+CKRELEASER.docsProcessor = function()
+{
+};
+
+( function()
+{
+	CKRELEASER.docsProcessor.prototype = {
+		createDocumentation : function( sourceDir, targetDir )
+		{
+			var confLocation = new File( sourceDir, CKRELEASER.release.documentation.config );
+			var targetLocation = new File( targetDir, CKRELEASER.release.documentation.target );
+
+			if ( !confLocation.exists() )
+				throw "Missing configuration file (" + confLocation.getAbsolutePath() + ")";
+
+			var jsdocLocation = new File( 'tools/jsdoc' );
+			var jsdocPath = jsdocLocation.getAbsolutePath();
+
+			var o = {
+				output :""
+			};
+
+			var configurationCode = 'var configuration = ' + CKRELEASER.io.readFile( confLocation.getAbsolutePath() ) + '\n;';
+			var cx = Context.enter(), scope = cx.initStandardObjects();
+			cx.evaluateString( scope, configurationCode, confLocation.getName(), 1, null );
+
+			var confDir = confLocation.getParent();
+
+			var f;
+
+			f = new File( confDir.replace( "\\", "/" ), scope.configuration.t );
+			scope.configuration.t = new String( f.getAbsolutePath() );
+			f = new File( confDir.replace( "\\", "/" ), scope.configuration.d );
+			scope.configuration.d = new String( f.getAbsolutePath() );
+
+			for ( var i = 0 ; i < scope.configuration._.length ; i++ )
+			{
+				f = new File( confDir.replace( "\\", "/" ), scope.configuration._[i] );
+				scope.configuration._[i] = new String( f.getAbsolutePath() );
+			}
+
+			var tempFile = File.createTempFile( "ckreleaser_jsdoc", ".conf" );
+			CKRELEASER.io.saveFile( tempFile, JSON.stringify( scope.configuration ) );
+
+			runCommand( "java", "-jar", jsdocPath + "/jsrun.jar", jsdocPath + "/app/run.js", "-c=" + tempFile.getAbsolutePath(), "-d="
+					+ targetLocation.getAbsolutePath(), o );
+
+			if ( CKRELEASER.verbose )
+				print( o.output );
+		}
+	};
+})();
Index: /CKReleaser/trunk/_source/includes/io.js
===================================================================
--- /CKReleaser/trunk/_source/includes/io.js	(revision 3152)
+++ /CKReleaser/trunk/_source/includes/io.js	(revision 3152)
@@ -0,0 +1,377 @@
+/*
+Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+importPackage( javax.activation );
+importPackage( com.ice.tar );
+
+importClass( java.io.BufferedReader );
+importClass( java.io.BufferedWriter );
+importClass( java.io.FileWriter );
+importClass( java.io.FileOutputStream );
+importClass( java.io.FileInputStream );
+importClass( java.io.InputStreamReader );
+importClass( java.io.FileOutputStream );
+importClass( java.io.OutputStreamWriter );
+importClass( java.util.zip.ZipOutputStream );
+importClass( java.util.zip.ZipEntry );
+importClass( java.util.zip.GZIPInputStream );
+
+( function()
+{
+	var txtExtensions = {
+		"" :0,
+		"afp" :1,
+		"afpa" :1,
+		"ascx" :1,
+		"asp" :1,
+		"aspx" :1,
+		"bat" :1,
+		"cfc" :1,
+		"cfm" :1,
+		"cgi" :1,
+		"code" :1,
+		"command" :1,
+		"conf" :1,
+		"css" :1,
+		"dtd" :1,
+		"htaccess" :1,
+		"htc" :1,
+		"htm" :1,
+		"html" :1,
+		"js" :1,
+		"jsp" :1,
+		"lasso" :1,
+		"php" :1,
+		"pl" :1,
+		"py" :1,
+		"readme" :1,
+		"sample" :1,
+		"sh" :1,
+		"txt" :1,
+		"xml" :1
+	};
+
+	function compressDirectory( sourcePath, outStream, compressMethod, rootDir )
+	{
+		if ( CKRELEASER.verbose )
+			print( "    " + compressMethod + ": " + sourcePath );
+
+		if ( !rootDir )
+			rootDir = "";
+
+		var r = new File( CKRELEASER.releaseDir );
+
+		try
+		{
+			var compressedDir = new File( sourcePath );
+
+			var dirList = compressedDir.list();
+			var readBuffer = new Packages.java.lang.reflect.Array.newInstance( java.lang.Byte.TYPE, 2056 );
+			var bytesIn = 0;
+			var anEntry, fis;
+
+			for ( var i = 0 ; i < dirList.length ; i++ )
+			{
+				var f = new File( compressedDir, dirList[i] );
+
+				if ( f.isDirectory() )
+				{
+					compressDirectory( f.getPath(), outStream, compressMethod, rootDir );
+					continue;
+				}
+
+				fis = new FileInputStream( f );
+
+				switch ( compressMethod )
+				{
+					case 'tar.gz':
+						anEntry = new TarEntry( f.getCanonicalPath().replace( r.getCanonicalPath(), rootDir ).replace("\\", "/") );
+						break;
+					case 'zip':
+						anEntry = new ZipEntry( f.getCanonicalPath().replace( r.getCanonicalPath(), rootDir ).replace("\\", "/") );
+						break;
+					default:
+						throw "Unknown compression method: " + compressMethod;
+						break;
+				}
+
+				outStream.putNextEntry( anEntry );
+
+				while ( (bytesIn = fis.read( readBuffer )) != -1 )
+				{
+					outStream.write( readBuffer, 0, bytesIn );
+				}
+				outStream.closeEntry();
+
+				fis.close();
+			}
+		}
+		catch ( e )
+		{
+			throw "An error occured during (" + compressMethod + ") compression of " + sourcePath + ": " + e;
+		}
+	}
+
+	function copyFile( sourceLocation, targetLocation )
+	{
+		try
+		{
+			var inStream = new FileInputStream( sourceLocation );
+			var outStream = new FileOutputStream( targetLocation );
+
+			var len, buf = new Packages.java.lang.reflect.Array.newInstance( java.lang.Byte.TYPE, 1024 );
+
+			while ( (len = inStream.read( buf )) != -1 )
+			{
+				outStream.write( buf, 0, len );
+			}
+			inStream.close();
+			outStream.close();
+		}
+		catch ( e )
+		{
+			throw "Cannot copy file:\n Source: " + sourceLocation.getCanonicalPath() + "\n Destination : "
+					+ targetLocation.getCanonicalPath() + "\n" + e.message;
+		}
+	}
+
+	CKRELEASER.io = {
+		copyFile :copyFile,
+
+		deleteDirectory : function( path )
+		{
+			var dir = new File( path );
+
+			if ( dir.isDirectory() )
+			{
+				var children = dir.list();
+				for ( var i = 0 ; i < children.length ; i++ )
+				{
+					if ( !this.deleteDirectory( new File( dir, children[i] ) ) )
+					{
+						return false;
+					}
+				}
+			}
+
+			return dir["delete"]();
+		},
+
+		deleteFile : function( path )
+		{
+			var f = new File( path );
+
+			if ( !f.exists() )
+				return true;
+
+			if ( !f.canWrite() )
+				throw "Cannot delete file: " + f.getAbsolutePath();
+
+			return f["delete"]();
+		},
+
+		saveFile : function( file, text, includeBom )
+		{
+			try
+			{
+				var stream = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( file ), "UTF-8" ) );
+				if ( includeBom )
+					stream.write( 65279 );
+				stream.write( text );
+				stream.flush();
+				stream.close();
+			}
+			catch ( e )
+			{
+				throw "Cannot save file:\n Path: " + file.getCanonicalPath() + "\n Eception details: " + e.message;
+			}
+		},
+
+		copy : function( sourceLocation, targetLocation )
+		{
+			if ( CKRELEASER.release.isIgnoredPath( sourceLocation.getAbsolutePath() ) )
+				return;
+
+			if ( CKRELEASER.verbose )
+				print( "    Copy -> " + targetLocation.toString().replaceFirst( ".*?release(/|\\\\)?", '' ) );
+
+			if ( sourceLocation.isDirectory() )
+			{
+				if ( !targetLocation.exists() )
+				{
+					targetLocation.mkdir();
+				}
+
+				var children = sourceLocation.list();
+				for ( var i = 0 ; i < children.length ; i++ )
+				{
+					this.copy( new File( sourceLocation, children[i] ), new File( targetLocation, children[i] ) );
+				}
+			}
+			else
+			{
+				copyFile( sourceLocation, targetLocation );
+			}
+		},
+
+		zipDirectory : function( sourcePath, targetFile, rootDir )
+		{
+			var outStream = new ZipOutputStream( new FileOutputStream( targetFile ) );
+			compressDirectory( sourcePath, outStream, "zip", rootDir );
+			outStream.close();
+		},
+
+		targzDirectory : function( sourcePath, targetFile, rootDir )
+		{
+			var outStream = new TarGzOutputStream( new FileOutputStream( targetFile ) );
+			compressDirectory( sourcePath, outStream, "tar.gz", rootDir );
+			outStream.close();
+		},
+
+		setByteOrderMark : function( file, includeUtf8Bom )
+		{
+			var buffer = new StringBuffer();
+			var chars = new Packages.java.lang.reflect.Array.newInstance( java.lang.Character.TYPE, 32 );
+			var count;
+
+			try
+			{
+				var inStream = new InputStreamReader( new FileInputStream( file ), "UTF-8" );
+
+				count = inStream.read( chars, 0, 32 );
+
+				if ( count <= 0 )
+					return;
+
+				buffer.append( chars, 0, count );
+
+				/* BOM is at the beginning of file */
+				if ( buffer.length() && buffer.charAt( 0 ) == 65279 )
+				{
+					if ( !includeUtf8Bom )
+					{
+						if ( CKRELEASER.verbose )
+							print( "Removing BOM from " + file.getCanonicalPath() );
+						this.saveFile( file, this.readFile( file ) );
+					}
+				}
+				else
+				{
+					if ( includeUtf8Bom )
+					{
+						if ( CKRELEASER.verbose )
+							print( "Adding BOM to " + file.getCanonicalPath() );
+						this.saveFile( file, this.readFile( file ), true );
+					}
+				}
+			}
+			catch ( e )
+			{
+				throw 'An I/O error occurred while reading the ' + file.getCanonicalPath() + ' file.';
+			}
+			finally
+			{
+				inStream.close();
+			}
+		},
+
+		/**
+		 * Reads file and returns file contents without initial UTF-8 Byte Order
+		 * Mark
+		 */
+		readFile : function( file )
+		{
+			var buffer = new StringBuffer();
+			var chars = new Packages.java.lang.reflect.Array.newInstance( java.lang.Character.TYPE, 8192 );
+			var count;
+
+			try
+			{
+				var inStream = new InputStreamReader( new FileInputStream( file ), "UTF-8" );
+
+				while ( (count = inStream.read( chars, 0, 8192 )) != -1 )
+				{
+					if ( count > 0 )
+					{
+						buffer.append( chars, 0, count );
+					}
+				}
+			}
+			catch ( e )
+			{
+				throw 'An I/O error occurred while reading the ' + file.getCanonicalPath() + ' file.';
+			}
+			finally
+			{
+				inStream.close();
+			}
+
+			/* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 */
+			if ( buffer.length() && buffer.charAt( 0 ) == 65279 )
+				buffer.deleteCharAt( 0 );
+
+			return String( buffer.toString() );
+		},
+
+		getDirectoryInfo : function( file )
+		{
+			var path_iterator, current_file, files, result = {
+				files :0,
+				size :0
+			};
+
+			if ( !file.exists() )
+				return result;
+
+			files = file.listFiles();
+
+			if ( !files )
+				return result;
+
+			path_iterator = (java.util.Arrays.asList( files )).iterator();
+
+			while ( path_iterator.hasNext() )
+			{
+				current_file = path_iterator.next();
+				if ( current_file.isFile() )
+				{
+					result.size += current_file.length();
+					result.files++;
+				}
+				else
+				{
+					var info = this.getDirectoryInfo( current_file );
+					result.size += info.size;
+					result.files += info.files;
+				}
+			}
+
+			return result;
+		},
+
+		getFileName : function( filePath )
+		{
+			var file = new File( filePath );
+			return file.getName();
+		},
+
+		getExtension : function( fileName )
+		{
+			var pos = fileName.lastIndexOf( "." );
+			if ( pos == -1 )
+				return "";
+			else
+				return String( fileName.substring( pos + 1 ).toLowerCase() );
+		},
+
+		isTextFile : function( fileName )
+		{
+			var ext = this.getExtension( fileName );
+
+			return txtExtensions[ext] === 1;
+		}
+
+	};
+})();
Index: /CKReleaser/trunk/_source/includes/releaser.js
===================================================================
--- /CKReleaser/trunk/_source/includes/releaser.js	(revision 3152)
+++ /CKReleaser/trunk/_source/includes/releaser.js	(revision 3152)
@@ -0,0 +1,449 @@
+/*
+Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+importClass( java.io.BufferedWriter );
+importClass( java.io.FileWriter );
+importPackage( java.util.regex );
+
+CKRELEASER.loadCode( 'includes/io.js' );
+CKRELEASER.loadCode( 'includes/skinprocessor.js' );
+CKRELEASER.loadCode( 'includes/samplesprocessor.js' );
+CKRELEASER.loadCode( 'includes/docsprocessor.js' );
+CKRELEASER.loadCode( 'includes/tools.js' );
+
+( function()
+{
+	CKRELEASER.releaser = function()
+	{
+		CKRELEASER.release = new release();
+	};
+
+	function release()
+	{
+		this.fixLineEnds = false;
+		this.ignore = [];
+		this.copy = [];
+		this.rename = [];
+		this.packages = [];
+		this.documentation = {};
+		this.samples = {};
+		this.skins = {};
+		this.header = "";
+	}
+
+	release.prototype.isIgnoredPath = function( path )
+	{
+		if ( !this.ignore )
+			return false;
+
+		for ( var i = 0 ; i < this.ignore.length ; i++ )
+		{
+			if ( path.replace( "\\", "/" ).endsWith( this.ignore[i] ) )
+				return true;
+		}
+
+		return false;
+	};
+
+	release.prototype.addIgnoredPath = function( path )
+	{
+		this.ignore.push( path );
+	};
+
+	release.prototype.removeIgnoredPath = function( path )
+	{
+		if ( !this.ignore )
+			return;
+
+		for ( var i = 0 ; i < this.ignore.length ; i++ )
+		{
+			if ( path == this.ignore[i] )
+			{
+				this.ignore.splice( i, 1 );
+				return;
+			}
+		}
+	};
+
+	function renameFiles()
+	{
+		for ( var i = 0 ; i < CKRELEASER.release.rename.length ; i++ )
+		{
+			try
+			{
+				var sourceLocation = new File( CKRELEASER.releaseDir, CKRELEASER.release.rename[i].source );
+				var targetLocation = new File( CKRELEASER.releaseDir, CKRELEASER.release.rename[i].target );
+				sourceLocation.renameTo(targetLocation);
+			}
+			catch ( e )
+			{
+				print( "WARNING: Cannot rename " + CKRELEASER.release.rename[i].source + " into " + CKRELEASER.release.rename[i].target + " "
+						+ e.toString() );
+			}
+		}
+	}
+	
+	function copyFiles()
+	{
+		for ( var i = 0 ; i < CKRELEASER.release.copy.length ; i++ )
+		{
+			try
+			{
+				var sourceLocation = new File( CKRELEASER.releaseDir, CKRELEASER.release.copy[i].source );
+				var targetLocation = new File( CKRELEASER.releaseDir, CKRELEASER.release.copy[i].target );
+				CKRELEASER.io.copy( sourceLocation, targetLocation );
+			}
+			catch ( e )
+			{
+				print( "WARNING: Cannot copy " + CKRELEASER.release.copy[i].source + " into " + CKRELEASER.release.copy[i].target + " "
+						+ e.toString() );
+			}
+		}
+	}
+
+	function minifyFile( file )
+	{
+		var o = {
+			output :""
+		};
+		var ext = CKRELEASER.io.getExtension( file.getName() );
+
+		if ( ext == "css" )
+		{
+			runCommand( "java", "-jar", "tools/yui/yuicompressor.jar", file.getAbsolutePath(), "--line-break", "4096", "-v", "--charset",
+					"UTF-8", "-o", file.getAbsolutePath(), o );
+
+			print( o.output );
+		}
+		else if ( ext == "js" )
+		{
+			var source = CKRELEASER.io.readFile( file );
+			var compressed = CKPACKAGER.scriptCompressor.compress( source, false, null, false, false );
+			CKRELEASER.io.saveFile( file, compressed );
+		}
+	}
+
+	function fixByteOrderMark( file )
+	{
+		if ( file.isDirectory() )
+		{
+			var children = file.list();
+			for ( var i = 0 ; i < children.length ; i++ )
+				fixByteOrderMark( new File( file, children[i] ) );
+		}
+		else
+		{
+			extension = CKRELEASER.io.getExtension( file.getName() );
+			switch ( extension )
+			{
+				case "gif":
+				case "jpg":
+				case "jpeg":
+				case "png":
+				case "gz":
+				case "zip":
+					break;
+
+				case "asp":
+				case "js":
+					CKRELEASER.io.setByteOrderMark( file, true );
+					break;
+
+				default:
+					CKRELEASER.io.setByteOrderMark( file, false );
+					break;
+			}
+		}
+	}
+
+	function prependHeader( file )
+	{
+		CKRELEASER.io.saveFile( file, CKRELEASER.release.header + CKRELEASER.io.readFile( file ) );
+	}
+
+	function minifyFiles( file )
+	{
+		if ( file.isDirectory() )
+		{
+			var children = file.list();
+			for ( var i = 0 ; i < children.length ; i++ )
+				minifyFiles( new File( file, children[i] ) );
+		}
+		else
+		{
+			var ext = CKRELEASER.io.getExtension( file.getName() );
+
+			switch ( ext )
+			{
+				case "css":
+				case "js":
+					minifyFile( file );
+					prependHeader( file );
+					break;
+			}
+		}
+	}
+
+	/**
+	 * FIXME: this function shouldn't exist at all
+	 */
+	function cleanUp()
+	{
+		var file, text;
+
+		file = new File( CKRELEASER.releaseDir, 'ckeditor.js' );
+		if ( !file.exists() )
+			throw "ckeditor.js not found";
+
+		text = CKRELEASER.io.readFile( file );
+		CKRELEASER.io.saveFile( file, text.replace( /_source\//g, '' ) );
+	}
+
+	var regexLib = {
+		packagerRemove :Pattern.compile( '(?m-s:^.*?%REMOVE_START%).*?(?m-s:%REMOVE_END%.*?$)', Pattern.DOTALL ),
+		packagerRemoveLine :Pattern.compile( '.*%REMOVE_LINE%.*(?:\\r\\n|\\r|\\n)?' )
+	};
+
+	/*
+	 * %VERSION%: 
+	 *     the "version" string passed to the CKReleaser execution command.
+	 * %TIMESTAMP%: 
+	 *     a four characters string containing the
+	 *     concatenation of the "Base 36" value of each of the following components
+	 *     of the program execution date and time: year + month + day + hour.
+	 * %REMOVE_LINE%: 
+	 *     removes the line. 
+	 * %REMOVE_START% and %REMOVE_END%: 
+	 *     removes all lines starting from %REMOVE_START% to %REMOVE_END%, 
+	 *     declaration line inclusive.
+	 */
+	function replaceDirectives( file )
+	{
+		var text = CKRELEASER.io.readFile( file );
+		var replaced = false;
+
+		if ( text.indexOf( "%VERSION%" ) != -1 )
+		{
+			text = text.replace( /%VERSION%/g, CKRELEASER.version );
+			replaced = true;
+		}
+		if ( text.indexOf( "%TIMESTAMP%" ) != -1 )
+		{
+			text = text.replace( /%TIMESTAMP%/g, CKRELEASER.timestamp );
+			replaced = true;
+		}
+		if ( text.indexOf( "%REMOVE_START%" ) != -1 && text.indexOf( "%REMOVE_END%" ) != -1 )
+		{
+			text = String( regexLib.packagerRemove.matcher( text ).replaceAll( '%REMOVE_LINE%' ) );
+			text = String( regexLib.packagerRemoveLine.matcher( text ).replaceAll( '' ) );
+			replaced = true;
+		}
+		else if ( text.indexOf( "%REMOVE_LINE%" ) != -1 )
+		{
+			text = String( regexLib.packagerRemoveLine.matcher( text ).replaceAll( '' ) );
+			replaced = true;
+		}
+
+		if ( replaced )
+		{
+			if ( CKRELEASER.verbose )
+				print( "\r    Replacing directives in " + file );
+
+			CKRELEASER.io.saveFile( file, text );
+		}
+	}
+
+	function fixLineEndings( file )
+	{
+		if ( file.isDirectory() )
+		{
+			var children = file.list();
+			for ( var i = 0 ; i < children.length ; i++ )
+				fixLineEndings( new File( file, children[i] ) );
+		}
+		else
+		{
+			CKRELEASER.tools.fixLineEndings( file, true );
+		}
+	}
+
+	CKRELEASER.releaser.prototype = {
+		loadDefinitionFile : function( filePath )
+		{
+			var file = new File( filePath );
+
+			var releaseCode = 'var release = { ' + CKRELEASER.io.readFile( filePath ) + '\n};';
+
+			var cx = Context.enter(), scope = cx.initStandardObjects();
+
+			cx.evaluateString( scope, releaseCode, file.getName(), 1, null );
+
+			this.loadDefinition( scope.release );
+		},
+
+		loadDefinition : function( definitionObject )
+		{
+			CKRELEASER.release = new release();
+
+			if ( definitionObject.header )
+				CKRELEASER.release.header = definitionObject.header;
+
+			if ( definitionObject.fixLineEnds )
+				CKRELEASER.release.fixLineEnds = definitionObject.fixLineEnds;
+
+			if ( definitionObject.ignore )
+				CKRELEASER.release.ignore = definitionObject.ignore;
+
+			for ( var i = 0 ; i < CKRELEASER.release.ignore.length ; i++ )
+				CKRELEASER.release.ignore[i] = CKRELEASER.release.ignore[i].replace( "\\", "/" );
+
+			if ( definitionObject.copy )
+				CKRELEASER.release.copy = definitionObject.copy;
+
+			if ( definitionObject.rename )
+				CKRELEASER.release.rename = definitionObject.rename;
+			
+			if ( definitionObject.packages )
+				CKRELEASER.release.packages = definitionObject.packages;
+
+			if ( definitionObject.documentation )
+				CKRELEASER.release.documentation = definitionObject.documentation;
+
+			if ( definitionObject.samples )
+				CKRELEASER.release.samples = definitionObject.samples;
+
+			if ( definitionObject.skins )
+				CKRELEASER.release.skins = definitionObject.skins;
+
+			if ( !CKRELEASER.release.packages.length )
+				throw "Nothing to release: no packages found in the release file (" + CKRELEASER.releaseFile + ")";
+		},
+
+		processDirectives : function( file )
+		{
+			System.out.print( "." );
+			if ( file.isDirectory() )
+			{
+				var children = file.list();
+				for ( var i = 0 ; i < children.length ; i++ )
+					this.processDirectives( new File( file, children[i] ) );
+			}
+			else if ( CKRELEASER.io.isTextFile( file.getName() ) )
+				replaceDirectives( file );
+		},
+
+		run : function()
+		{
+			var error, i, info, time = new Date();
+
+			var targetDir = new File( CKRELEASER.targetDir );
+			var releaseDir = new File( CKRELEASER.releaseDir );
+			var sourceDir = new File( CKRELEASER.sourceDir );
+
+			if ( !sourceDir.exists() )
+				throw 'Source directory does not exist (' + CKRELEASER.sourceDir + ')';
+			if ( targetDir.exists() )
+				throw 'Target directory already exists (' + CKRELEASER.targetDir + ')';
+			else if ( !releaseDir.mkdirs() )
+				throw "Cannot create release directory (" + releaseDir + ")";
+
+			print( "\nCopying files...\n" );
+			CKRELEASER.io.copy( sourceDir, releaseDir );
+
+			print( "\nCopying files to special destination...\n" );
+			copyFiles();
+
+			print( "\nRenaming files...\n" );
+			renameFiles();
+
+			print( "\nProcessing directives in files used by CKPackager...\n" );
+			this.processDirectives( new File( CKPACKAGER.packDir ) );
+			
+			print( "\nPackaging CKEditor...\n" );
+			for ( i = 0 ; i < CKRELEASER.release.packages.length ; i++ )
+			{
+				var packager = new CKPACKAGER.packager();
+				packager.loadDefinitionFile( CKRELEASER.release.packages[i] );
+				packager.run();
+			}
+
+			print( "\nCreating skins...\n" );
+			var skinProcessor = new CKRELEASER.skinProcessor();
+			skinProcessor.createSkins( CKRELEASER.sourceDir, CKRELEASER.releaseDir );
+
+			if ( CKRELEASER.release.skins.minify )
+				minifyFiles( new File( CKRELEASER.releaseDir, CKRELEASER.release.skins.target ) );
+
+			print( "\nCreating documentation...\n" );
+			var docsProcessor = new CKRELEASER.docsProcessor();
+			docsProcessor.createDocumentation( CKRELEASER.sourceDir, CKRELEASER.releaseDir );
+
+			var docsDir = new File( CKRELEASER.releaseDir, CKRELEASER.release.documentation.target );
+			info = CKRELEASER.io.getDirectoryInfo( docsDir );
+			print( "    Number of created files: " + info.files );
+			print( "    Total size.............: " + info.size + " bytes" );
+
+			print( "\nCreating samples...\n" );
+			var samplesProcessor = new CKRELEASER.samplesProcessor();
+			samplesProcessor.createSamples( CKRELEASER.sourceDir, CKRELEASER.releaseDir );
+
+			print( "\nMinifying files...\n" );
+			for ( i = 0 ; i < CKRELEASER.release.copy.length ; i++ )
+			{
+				if ( CKRELEASER.release.copy[i].minify )
+				{
+					var targetLocation = new File( CKRELEASER.releaseDir, CKRELEASER.release.copy[i].target );
+					minifyFiles( targetLocation );
+				}
+			}
+
+			/* FIXME: directives are processed twice in some directories */
+			print( "\nProcessing directives in files...\n" );
+			this.processDirectives( releaseDir );
+
+			print( "\n\nCleaning up...\n" );
+			cleanUp();
+
+			print( "\nFixing line endings...\n" );
+			fixLineEndings( releaseDir );
+
+			print( "\nFixing byte-order mark in files...\n" );
+			fixByteOrderMark( new File( CKRELEASER.releaseDir ) );
+
+			// get information about release directory
+			info = CKRELEASER.io.getDirectoryInfo( releaseDir );
+
+			print( "\nCreating compressed files...\n" );
+
+			var zipFile = new File( CKRELEASER.targetDir, CKRELEASER.zipName );
+			CKRELEASER.io.zipDirectory( CKRELEASER.releaseDir, zipFile, "ckeditor" );
+			print( "    Created " + zipFile.getName() + "...: " + zipFile.length() + " bytes ("
+					+ Math.round( zipFile.length() / info.size * 100 ) + "% of original)" );
+
+			var tarFile = new File( CKRELEASER.targetDir, CKRELEASER.targzName );
+			CKRELEASER.io.targzDirectory( CKRELEASER.releaseDir, tarFile, "ckeditor" );
+			print( "    Created " + tarFile.getName() + ": " + tarFile.length() + " bytes ("
+					+ Math.round( tarFile.length() / info.size * 100 ) + "% of original)" );
+
+			print( "\n==========================" );
+
+			time = (new Date()) - time;
+			time = time / 1000;
+
+			print( "Release process completed:\n" );
+			print( "    Number of files: " + info.files );
+			print( "    Total size.....: " + info.size + " bytes" );
+			print( "    Time taken.....: " + time + " seconds" );
+			print( "" );
+
+			if ( error )
+			{
+				print( "Error details:" );
+				print( error );
+				print( "" );
+			}
+		}
+	};
+})();
Index: /CKReleaser/trunk/_source/includes/samplesprocessor.js
===================================================================
--- /CKReleaser/trunk/_source/includes/samplesprocessor.js	(revision 3152)
+++ /CKReleaser/trunk/_source/includes/samplesprocessor.js	(revision 3152)
@@ -0,0 +1,181 @@
+/*
+Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+CKRELEASER.loadCode( 'includes/xml.js' );
+
+CKRELEASER.samplesProcessor = function( release )
+{
+};
+
+( function()
+{
+	var template, templateLocation, templateDocument, processedFiles = {}, copiedFiles = {};
+
+	var regexLib = {
+		head :Pattern.compile( '<head.*?<\\/head>', Pattern.DOTALL ),
+		body :Pattern.compile( '<body.*?<\\/body>', Pattern.DOTALL ),
+		script :Pattern.compile( '<script ([^>]+)/>' )
+	};
+
+	/**
+	 * Remove node and initial text node (with white space characters only)
+	 */
+	function removeNode( node )
+	{
+		var sibling = node.getPreviousSibling();
+
+		if ( sibling && sibling.getNodeType() == org.w3c.dom.Node.TEXT_NODE && sibling.getNodeValue().match( /^\s*$/ ) !== null )
+			node.parentNode.removeChild( sibling );
+
+		node.parentNode.removeChild( node );
+	}
+
+	function processXmlFile( sourceLocation, targetLocation )
+	{
+		var newDocument = templateDocument.cloneNode( true );
+		var document = CKRELEASER.xml.loadDocument( sourceLocation );
+		var result = template;
+		var node = {
+			code :null,
+			html :null,
+			headscript :null,
+			styles :null
+		};
+		var replacement = {
+			code :"",
+			html :"",
+			headscript :"",
+			styles :"",
+			head :"",
+			body :""
+		};
+
+		node.html = document.getElementById( 'html' );
+		node.code = document.getElementById( 'code' );
+
+		if ( !node.html || !node.code )
+		{
+			//Not a xml template, probably index.html or documentation.
+			if ( CKRELEASER.verbose )
+				print( "    WARNING: File with .html extension does not contain all necessary elements (html, code): "
+						+ sourceLocation.getName() );
+
+			if ( sourceLocation.getAbsolutePath() != templateLocation.getAbsolutePath() )
+				CKRELEASER.io.copyFile( sourceLocation, targetLocation );
+			return;
+		}
+
+		node.html = newDocument.importNode( node.html, true );
+		node.code = newDocument.importNode( node.code, true );
+
+		CKRELEASER.xml.replaceNodeWithNodes( newDocument, newDocument.getElementById( 'html' ), node.html.getChildNodes() );
+		CKRELEASER.xml.replaceNodeWithNodes( newDocument, newDocument.getElementById( 'code' ), node.code.getChildNodes() );
+
+		node.styles = document.getElementById( 'styles' );
+		node.headscript = document.getElementById( 'headscript' );
+
+		if ( node.styles )
+		{
+			node.styles = newDocument.importNode( node.styles, true );
+			CKRELEASER.xml.replaceNode( newDocument, newDocument.getElementById( 'styles' ), node.styles );
+		}
+		else
+		{
+			removeNode( newDocument.getElementById( 'styles' ) );
+			if ( CKRELEASER.verbose )
+				print( "    XML file does not contain element with id 'styles': " + sourceLocation.getName() );
+		}
+
+		if ( node.headscript )
+		{
+			node.headscript = newDocument.importNode( node.headscript, true );
+			CKRELEASER.xml.replaceNode( newDocument, newDocument.getElementById( 'headscript' ), node.headscript );
+		}
+		else
+		{
+			removeNode( newDocument.getElementById( 'headscript' ) );
+			if ( CKRELEASER.verbose )
+				print( "    XML file does not contain element with id 'headscript': " + sourceLocation.getName() );
+		}
+
+		/**
+		 * FIXME: No matter how do we set the OutputKeys.METHOD in
+		 * CKRELEASER.xml.saveXml there is always something wrong. Setting
+		 * "text" removes all tags. Setting "html" adds uppercased Meta tag,
+		 * even if meta tag already exists. Setting "xml" moves first comment
+		 * above doctype declaration. So instead of simply saving the xml file,
+		 * we have to take the template file and replace only head and body tags
+		 * in it.
+		 */
+		replacement.head = CKRELEASER.xml.asXml( newDocument, newDocument.getElementsByTagName( 'head' ).item( 0 ) );
+		replacement.body = CKRELEASER.xml.asXml( newDocument, newDocument.getElementsByTagName( 'body' ).item( 0 ) );
+
+		result = String( regexLib.head.matcher( result ).replaceAll( replacement.head ) );
+		result = String( regexLib.body.matcher( result ).replaceAll( replacement.body ) );
+		result = String( regexLib.script.matcher( result ).replaceAll( "<script $1></script>" ) );
+
+		print( "    Created sample " + targetLocation.getName() );
+		CKRELEASER.io.saveFile( targetLocation, result );
+	}
+
+	function processDirectory( sourceLocation, targetLocation )
+	{
+		if ( CKRELEASER.release.isIgnoredPath( sourceLocation.getAbsolutePath() ) )
+			return;
+
+		if ( sourceLocation.isDirectory() )
+		{
+			if ( !targetLocation.exists() )
+			{
+				targetLocation.mkdir();
+			}
+
+			var children = sourceLocation.list();
+			for ( var i = 0 ; i < children.length ; i++ )
+			{
+				processDirectory( new File( sourceLocation, children[i] ), new File( targetLocation, children[i] ) );
+			}
+		}
+		else
+		{
+			if ( sourceLocation.equals( templateLocation ) )
+				return;
+
+			if ( sourceLocation.getAbsolutePath().toLowerCase().endsWith( ".html" ) )
+				processXmlFile( sourceLocation, targetLocation );
+			else
+				CKRELEASER.io.copy( sourceLocation, targetLocation );
+
+			copiedFiles[sourceLocation] = targetLocation;
+		}
+	}
+
+	CKRELEASER.samplesProcessor.prototype = {
+		createSamples : function( sourceDir, targetDir )
+		{
+			var sourceLocation = new File( sourceDir, CKRELEASER.release.samples.source );
+			if ( !sourceLocation.exists() )
+				throw "Invalid source (" + sourceLocation.getAbsolutePath() + ")";
+
+			var targetLocation = new File( targetDir, CKRELEASER.release.samples.target );
+			if ( !targetLocation.exists() )
+			{
+				if ( !targetLocation.mkdir() )
+					throw "Creating samples failed. Can't create target directory (" + targetLocation.getCanonicalPath() + ")";
+			}
+
+			templateLocation = new File( sourceDir, CKRELEASER.release.samples.template );
+			if ( !templateLocation.exists() )
+				throw "Missing template file (" + templateLocation.getAbsolutePath() + ")";
+
+			templateDocument = CKRELEASER.xml.loadDocument( templateLocation );
+			template = CKRELEASER.io.readFile( templateLocation );
+
+			CKRELEASER.release.removeIgnoredPath( CKRELEASER.release.samples.source );
+			processDirectory( sourceLocation, targetLocation );
+			CKRELEASER.release.addIgnoredPath( CKRELEASER.release.samples.source );
+		}
+	};
+})();
Index: /CKReleaser/trunk/_source/includes/skinprocessor.js
===================================================================
--- /CKReleaser/trunk/_source/includes/skinprocessor.js	(revision 3152)
+++ /CKReleaser/trunk/_source/includes/skinprocessor.js	(revision 3152)
@@ -0,0 +1,155 @@
+/*
+Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+importClass( java.io.BufferedWriter );
+importClass( java.io.FileWriter );
+importClass( java.io.FileOutputStream );
+importClass( java.io.FileInputStream );
+
+CKRELEASER.skinProcessor = function()
+{
+};
+
+( function()
+{
+	var importedFiles = {}, copiedFiles = {};
+
+	function processCssFile( sourceLocation, parentLocation )
+	{
+		var parentPath, path = sourceLocation.getCanonicalPath();
+		var lines = CKRELEASER.io.readFile( path ).split( /\r\n|\n|\r/ );
+		var out = [];
+		var isImported = false;
+
+		if ( !parentLocation )
+		{
+			parentLocation = sourceLocation;
+			parentPath = sourceLocation.getCanonicalPath();
+		}
+		else
+		{
+			isImported = true;
+			parentPath = parentLocation.getCanonicalPath();
+			if ( path == parentPath )
+				throw "Invalid @import statements, file including itself: " + path;
+
+			if ( importedFiles[parentPath][path] )
+				throw "Invalid @import statement in " + parentPath + ", file " + path + " was already imported.";
+
+			importedFiles[parentPath][path] = true;
+		}
+
+		for ( var i = 0 ; i < lines.length ; i++ )
+		{
+			if ( lines[i].indexOf( "@import" ) == -1 )
+				out.push( lines[i] );
+			else
+			{
+				var matches = lines[i].match( /^\s*@import\s+url\("(.*?)"\)/ );
+
+				if ( matches[1] )
+				{
+					var file = new File( sourceLocation.getParent(), matches[1] );
+					if ( !file.exists() )
+						throw "Importing of CSS file failed, file does not exist (" + file.getPath() + ")";
+					else
+					{
+						if ( !importedFiles[parentPath] )
+							importedFiles[parentPath] = {};
+
+						out.push( processCssFile( file, parentLocation ) );
+					}
+				}
+				else
+					out.push( lines[i] );
+			}
+		}
+
+		if ( isImported )
+			return CKRELEASER.tools.removeComments( out.join( "\r\n" ) );
+		else
+			return out.join( "\r\n" );
+	}
+
+	function processSkins( sourceLocation, targetLocation )
+	{
+		if ( !sourceLocation.isDirectory() )
+			throw "Skins source is not a directory (" + sourceLocation.getAbsolutePath() + ");";
+
+		if ( !targetLocation.exists() )
+			targetLocation.mkdir();
+
+		var children = sourceLocation.list();
+		for ( var i = 0 ; i < children.length ; i++ )
+		{
+			if (children[i] == ".svn" || children[i] == "CVS")
+				continue;
+			
+			importedFiles = {};
+			copiedFiles = {};
+
+			if ( false !== processDirectory( new File( sourceLocation, children[i] ), new File( targetLocation, children[i] ) ) )
+				print( "    Created skin " + children[i] + "." );
+
+			for ( var parentPath in importedFiles )
+			{
+				for ( var path in importedFiles[parentPath] )
+				{
+					if ( !importedFiles[path] )
+					{
+						if ( CKRELEASER.verbose )
+							print( "    CSS file was imported, removing: " + path );
+						CKRELEASER.io.deleteFile( copiedFiles[path] );
+					}
+					else
+					{
+						if ( CKRELEASER.verbose )
+							print( "    CSS file was imported, but is also a root CSS file for another file: " + path );
+					}
+				}
+			}
+		}
+	}
+
+	function processDirectory( sourceLocation, targetLocation )
+	{
+		if ( CKRELEASER.release.isIgnoredPath( sourceLocation.getAbsolutePath() ) )
+			return;
+
+		if ( sourceLocation.isDirectory() )
+		{
+			if ( !targetLocation.exists() )
+				targetLocation.mkdir();
+
+			var children = sourceLocation.list();
+			for ( var i = 0 ; i < children.length ; i++ )
+			{
+				processDirectory( new File( sourceLocation, children[i] ), new File( targetLocation, children[i] ) );
+			}
+		}
+		else
+		{
+			if ( sourceLocation.getAbsolutePath().toLowerCase().endsWith( ".css" ) )
+			{
+				CKRELEASER.io.saveFile( targetLocation, processCssFile( sourceLocation, false ) );
+				if ( CKRELEASER.verbose )
+					print( "    Created CSS file: " + sourceLocation );
+			}
+			else
+				CKRELEASER.io.copy( sourceLocation, targetLocation );
+
+			copiedFiles[sourceLocation.getCanonicalPath()] = targetLocation;
+		}
+	}
+
+	CKRELEASER.skinProcessor.prototype.createSkins = function( sourceDir, targetDir )
+	{
+		var sourceLocation = new File( sourceDir, CKRELEASER.release.skins.source );
+		var targetLocation = new File( targetDir, CKRELEASER.release.skins.target );
+
+		processSkins( sourceLocation, targetLocation );
+	};
+
+})();
Index: /CKReleaser/trunk/_source/includes/tools.js
===================================================================
--- /CKReleaser/trunk/_source/includes/tools.js	(revision 3152)
+++ /CKReleaser/trunk/_source/includes/tools.js	(revision 3152)
@@ -0,0 +1,130 @@
+/*
+Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+importClass( java.lang.StringBuffer );
+
+( function()
+{
+	var regexLib = {
+		eol :Pattern.compile( '(?:\\x09|\\x20)+$' ),
+		eof :Pattern.compile( '(?:\\x09|\\x20|\\r|\\n)+$' )
+	};
+
+	var lineEnding = {
+		"cgi" :"\n",
+		"pl" :"\n",
+		"sh" :"\n",
+		"readme" :"\r\n",
+		"afp" :"\r\n",
+		"afpa" :"\r\n",
+		"ascx" :"\r\n",
+		"asp" :"\r\n",
+		"aspx" :"\r\n",
+		"bat" :"\r\n",
+		"cfc" :"\r\n",
+		"cfm" :"\r\n",
+		"code" :"\r\n",
+		"command" :"\r\n",
+		"conf" :"\r\n",
+		"css" :"\r\n",
+		"dtd" :"\r\n",
+		"htaccess" :"\r\n",
+		"htc" :"\r\n",
+		"htm" :"\r\n",
+		"html" :"\r\n",
+		"js" :"\r\n",
+		"jsp" :"\r\n",
+		"lasso" :"\r\n",
+		"php" :"\r\n",
+		"py" :"\r\n",
+		"sample" :"\r\n",
+		"txt" :"\r\n",
+		"xml" :"\r\n"
+	};
+
+	CKRELEASER.tools = {
+		fixLineEndings : function( file, stripWhiteSpace )
+		{
+			var buffer = new StringBuffer();
+			var inStream = new BufferedReader( new InputStreamReader( new FileInputStream( file ), "UTF-8" ) );
+			var line;
+
+			extension = CKRELEASER.io.getExtension( file.getName() );
+
+			if ( !lineEnding[extension] )
+				return;
+
+			while ( (line = inStream.readLine()) != null )
+			{
+				if ( stripWhiteSpace )
+				{
+					line = regexLib.eol.matcher( line ).replaceAll( "" );
+				}
+				buffer.append( line );
+				buffer.append( lineEnding[extension] );
+			}
+			CKRELEASER.io.saveFile( file, regexLib.eof.matcher( buffer.toString() ).replaceAll( lineEnding[extension] ) );
+		},
+
+		removeComments : function( text )
+		{
+			var endIndex, startIndex = 0;
+			var iemac = false;
+			var preserve = false;
+
+			var sb = new StringBuffer( text );
+			while ( (startIndex = sb.indexOf( "/*", startIndex )) >= 0 )
+			{
+				preserve = sb.length() > startIndex + 2 && sb.charAt( startIndex + 2 ) == '!';
+				endIndex = sb.indexOf( "*/", startIndex + 2 );
+				if ( endIndex < 0 )
+				{
+					if ( !preserve )
+					{
+						sb["delete"]( startIndex, sb.length() );
+					}
+				}
+				else if ( endIndex >= startIndex + 2 )
+				{
+					if ( sb.charAt( endIndex - 1 ) == '\\' )
+					{
+						/* 
+						 * Looks like a comment to hide rules from IE Mac.
+						 * Leave this comment, and the following one, alone...
+						 */
+						startIndex = endIndex + 2;
+						iemac = true;
+					}
+					else if ( iemac )
+					{
+						startIndex = endIndex + 2;
+						iemac = false;
+					}
+					else if ( !preserve )
+					{
+						/* Remove new line character if there is nothing else after a comment */
+						if ( sb.charAt( endIndex + 2 ) == 13 && sb.charAt( endIndex + 3 ) == 10 )
+							endIndex += 2;
+						else if ( sb.charAt( endIndex + 2 ) == 10 && sb.charAt( endIndex + 3 ) == 13 )
+							endIndex += 2;
+						else if ( sb.charAt( endIndex + 2 ) == 13 && sb.charAt( endIndex + 3 ) == 13 )
+							endIndex += 1;
+						else if ( sb.charAt( endIndex + 2 ) == 10 && sb.charAt( endIndex + 3 ) == 10 )
+							endIndex += 1;
+
+						sb["delete"]( startIndex, endIndex + 2 );
+					}
+					else
+					{
+						startIndex = endIndex + 2;
+					}
+				}
+			}
+
+			return sb.toString();
+		}
+	};
+
+})();
Index: /CKReleaser/trunk/_source/includes/xml.js
===================================================================
--- /CKReleaser/trunk/_source/includes/xml.js	(revision 3152)
+++ /CKReleaser/trunk/_source/includes/xml.js	(revision 3152)
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+ */
+
+importClass( java.io.StringWriter );
+importClass( java.io.FileInputStream );
+
+importClass( javax.xml.parsers.DocumentBuilderFactory );
+importClass( javax.xml.transform.dom.DOMSource );
+importClass( javax.xml.transform.OutputKeys );
+importClass( javax.xml.transform.stream.StreamResult );
+importClass( javax.xml.transform.TransformerFactory );
+
+( function()
+{
+	var docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+
+	CKRELEASER.xml = {
+
+		replaceNodeWithNodes : function( document, oldNode, nodeList )
+		{
+			var length = nodeList.getLength();
+			for ( var i = 0 ; i < length ; i++ )
+			{
+				/**
+				 * Skip empty text nodes (containing white space characters) at the beginning and at the end.
+				 */
+				if ( (i == 0 || i == length - 1) && nodeList.item( i ).getNodeType() == org.w3c.dom.Node.TEXT_NODE
+						&& nodeList.item( i ).getNodeValue().match( /^\s*$/ ) !== null )
+					continue;
+
+				oldNode.getParentNode().insertBefore( document.importNode( nodeList.item( i ), true ), oldNode );
+			}
+
+			oldNode.getParentNode().removeChild( oldNode );
+		},
+
+		replaceNode : function( document, oldNode, newNode )
+		{
+			oldNode.getParentNode().insertBefore( document.importNode( newNode, true ), oldNode );
+			oldNode.getParentNode().removeChild( oldNode );
+		},
+
+		loadDocument : function( location )
+		{
+			return docBuilder.parse( location );
+		},
+
+		asXml : function( document, node )
+		{
+			var transformer = TransformerFactory.newInstance().newTransformer();
+			transformer.setOutputProperty( OutputKeys.INDENT, "no" );
+			transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );
+
+			var result = new StreamResult( new StringWriter() );
+			var source = new DOMSource( document );
+			if ( node )
+				source.setNode( node );
+			transformer.transform( source, result );
+
+			return result.getWriter().toString();
+		},
+
+		/**
+		 * FIXME: New line characters in comments are changed. x0Dx0A is changed
+		 * into x0A.
+		 */
+		saveXml : function( document, file )
+		{
+			var docType = document.getDoctype();
+			var transformer = TransformerFactory.newInstance().newTransformer();
+			transformer.setOutputProperty( OutputKeys.DOCTYPE_PUBLIC, docType.getPublicId() );
+			transformer.setOutputProperty( OutputKeys.DOCTYPE_SYSTEM, docType.getSystemId() );
+			transformer.setOutputProperty( OutputKeys.INDENT, "no" );
+			transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "yes" );
+
+			var result = new StreamResult( file );
+			var source = new DOMSource( document );
+			transformer.transform( source, result );
+		}
+	};
+})();
Index: Releaser/trunk/ckreleaser.js
===================================================================
--- /CKReleaser/trunk/ckreleaser.js	(revision 3151)
+++ 	(revision )
@@ -1,64 +1,0 @@
-/*
-Copyright (c) 2003-2008, Frederico Caldeira Knabben. All rights reserved.
-For licensing, see LICENSE.html or http://ckeditor.com/license
-*/
-
-importPackage( org.mozilla.javascript );
-importClass( java.io.File );
-
-var jarPath = JavaAdapter(org.mozilla.javascript.Parser)["class"].getResource("/org/mozilla/javascript").toString();
-var releaserPath = jarPath.replaceFirst( "^jar:", '' ).replaceFirst( "\/js\.jar\!\/org\/mozilla\/javascript$", '');
-
-load( releaserPath + "/includes/ckreleaser.js" );
-CKRELEASER.path = releaserPath;
-CKRELEASER.loadCode( "includes/releaser.js" );
-	
-function error( msg )
-{
-	print( msg );
-	print( '' );
-	quit();
-}
-
-if (arguments.length > 1 && arguments[arguments.length-1] == '-v')
-	CKRELEASER.verbose = 1; 
-
-if ( arguments[0] == '-test' )
-{
-	CKRELEASER.loadCode( 'test/test.js' );
-	quit();
-}
-
-CKRELEASER.releaseFile = arguments[0];
-CKRELEASER.sourceDir = arguments[1];
-CKRELEASER.targetDir = arguments[2];
-CKRELEASER.version = arguments[3];
-CKRELEASER.zipName = arguments[4];
-CKRELEASER.targzName = arguments[5];
-
-if ( !CKRELEASER.releaseFile || !CKRELEASER.sourceDir || !CKRELEASER.targetDir 
-		|| !CKRELEASER.version || !CKRELEASER.zipName || !CKRELEASER.targzName)
-{
-	error( 'Usage:java -jar js.jar ckreleaser.js [release_file] [source_dir] [target_dir] [version] [zip_name] [targz_name]' );
-}
-
-CKRELEASER.releaseDir = CKRELEASER.targetDir + "/" + "release";
-CKRELEASER.loadCode( 'tools/CKPackager/includes/ckpackager.js' );
-CKPACKAGER.packDir = CKRELEASER.releaseDir;
-CKPACKAGER.dir = 'tools/CKPackager/';
-CKPACKAGER.outputDir = CKRELEASER.releaseDir;
-CKPACKAGER.loadCode( 'includes/packager.js' );
-
-(function()
-{
-	try {
-		var releaser = new CKRELEASER.releaser();
-		releaser.loadDefinitionFile( CKRELEASER.releaseFile );
-		releaser.run();
-	}
-	catch(e)
-	{
-		print("");
-		error(e);
-	}
-})();
