From 1a5e3c2d64be1c05a422fd78b23a31de155eca64 Mon Sep 17 00:00:00 2001 From: "alexanders@b2ef00c0-3703-41da-baef-cfe82387ac0c" Date: Wed, 3 Feb 2010 00:48:31 +0000 Subject: removed duplicate trunk directory --HG-- extra : convert_revision : svn%3Ab2ef00c0-3703-41da-baef-cfe82387ac0c/trunk%404 --- trunk/infrastructure/ace/bin/backup.sh | 17 ++ trunk/infrastructure/ace/bin/jsmin.py | 218 +++++++++++++++++++++ trunk/infrastructure/ace/bin/make | 336 ++++++++++++++++++++++++++++++++ trunk/infrastructure/ace/bin/publish.sh | 19 ++ trunk/infrastructure/ace/bin/serve | 45 +++++ 5 files changed, 635 insertions(+) create mode 100755 trunk/infrastructure/ace/bin/backup.sh create mode 100755 trunk/infrastructure/ace/bin/jsmin.py create mode 100755 trunk/infrastructure/ace/bin/make create mode 100755 trunk/infrastructure/ace/bin/publish.sh create mode 100755 trunk/infrastructure/ace/bin/serve (limited to 'trunk/infrastructure/ace/bin') diff --git a/trunk/infrastructure/ace/bin/backup.sh b/trunk/infrastructure/ace/bin/backup.sh new file mode 100755 index 0000000..82b75cb --- /dev/null +++ b/trunk/infrastructure/ace/bin/backup.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Copyright 2009 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS-IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cp -r .. ~/Dropbox/backups/ace2-`date '+%s'` #&& dropbox-backup.sh diff --git a/trunk/infrastructure/ace/bin/jsmin.py b/trunk/infrastructure/ace/bin/jsmin.py new file mode 100755 index 0000000..a1b81f9 --- /dev/null +++ b/trunk/infrastructure/ace/bin/jsmin.py @@ -0,0 +1,218 @@ +#!/usr/bin/python + +# This code is original from jsmin by Douglas Crockford, it was translated to +# Python by Baruch Even. The original code had the following copyright and +# license. +# +# /* jsmin.c +# 2007-05-22 +# +# Copyright (c) 2002 Douglas Crockford (www.crockford.com) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# The Software shall be used for Good, not Evil. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# */ + +from StringIO import StringIO + +def jsmin(js): + ins = StringIO(js) + outs = StringIO() + JavascriptMinify().minify(ins, outs) + str = outs.getvalue() + if len(str) > 0 and str[0] == '\n': + str = str[1:] + return str + +def isAlphanum(c): + """return true if the character is a letter, digit, underscore, + dollar sign, or non-ASCII character. + """ + return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or + (c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126)); + +class UnterminatedComment(Exception): + pass + +class UnterminatedStringLiteral(Exception): + pass + +class UnterminatedRegularExpression(Exception): + pass + +class JavascriptMinify(object): + + def _outA(self): + self.outstream.write(self.theA) + def _outB(self): + self.outstream.write(self.theB) + + def _get(self): + """return the next character from stdin. Watch out for lookahead. If + the character is a control character, translate it to a space or + linefeed. + """ + c = self.theLookahead + self.theLookahead = None + if c == None: + c = self.instream.read(1) + if c >= ' ' or c == '\n': + return c + if c == '': # EOF + return '\000' + if c == '\r': + return '\n' + return ' ' + + def _peek(self): + self.theLookahead = self._get() + return self.theLookahead + + def _next(self): + """get the next character, excluding comments. peek() is used to see + if a '/' is followed by a '/' or '*'. + """ + c = self._get() + if c == '/': + p = self._peek() + if p == '/': + c = self._get() + while c > '\n': + c = self._get() + return c + if p == '*': + c = self._get() + while 1: + c = self._get() + if c == '*': + if self._peek() == '/': + self._get() + return ' ' + if c == '\000': + raise UnterminatedComment() + + return c + + def _action(self, action): + """do something! What you do is determined by the argument: + 1 Output A. Copy B to A. Get the next B. + 2 Copy B to A. Get the next B. (Delete A). + 3 Get the next B. (Delete B). + action treats a string as a single character. Wow! + action recognizes a regular expression if it is preceded by ( or , or =. + """ + if action <= 1: + self._outA() + + if action <= 2: + self.theA = self.theB + if self.theA == "'" or self.theA == '"': + while 1: + self._outA() + self.theA = self._get() + if self.theA == self.theB: + break + if self.theA <= '\n': + raise UnterminatedStringLiteral() + if self.theA == '\\': + self._outA() + self.theA = self._get() + + + if action <= 3: + self.theB = self._next() + if self.theB == '/' and (self.theA == '(' or self.theA == ',' or + self.theA == '=' or self.theA == ':' or + self.theA == '[' or self.theA == '?' or + self.theA == '!' or self.theA == '&' or + self.theA == '|' or self.theA == ';' or + self.theA == '{' or self.theA == '}' or + self.theA == '\n'): + self._outA() + self._outB() + while 1: + self.theA = self._get() + if self.theA == '/': + break + elif self.theA == '\\': + self._outA() + self.theA = self._get() + elif self.theA <= '\n': + raise UnterminatedRegularExpression() + self._outA() + self.theB = self._next() + + + def _jsmin(self): + """Copy the input to the output, deleting the characters which are + insignificant to JavaScript. Comments will be removed. Tabs will be + replaced with spaces. Carriage returns will be replaced with linefeeds. + Most spaces and linefeeds will be removed. + """ + self.theA = '\n' + self._action(3) + + while self.theA != '\000': + if self.theA == ' ': + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + elif self.theA == '\n': + if self.theB in ['{', '[', '(', '+', '-']: + self._action(1) + elif self.theB == ' ': + self._action(3) + else: + if isAlphanum(self.theB): + self._action(1) + else: + self._action(2) + else: + if self.theB == ' ': + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + elif self.theB == '\n': + if self.theA in ['}', ']', ')', '+', '-', '"', '\'']: + self._action(1) + else: + if isAlphanum(self.theA): + self._action(1) + else: + self._action(3) + else: + self._action(1) + + def minify(self, instream, outstream): + self.instream = instream + self.outstream = outstream + self.theA = '\n' + self.theB = None + self.theLookahead = None + + self._jsmin() + self.instream.close() + +if __name__ == '__main__': + import sys + jsm = JavascriptMinify() + jsm.minify(sys.stdin, sys.stdout) diff --git a/trunk/infrastructure/ace/bin/make b/trunk/infrastructure/ace/bin/make new file mode 100755 index 0000000..2237df0 --- /dev/null +++ b/trunk/infrastructure/ace/bin/make @@ -0,0 +1,336 @@ +#!/bin/sh +exec scala -classpath lib/yuicompressor-2.4-appjet.jar:lib/rhino-js-1.7r1.jar $0 $@ +!# + +import java.io._; + +def superpack(input: String): String = { + // this function is self-contained; takes a string, returns an expression + // that evaluates to that string + + // constraints on special chars: + // - this string must be able to go in a character class + // - each char must be able to go in single quotes + val specialChars = "-~@%$#*^_`()|abcdefghijklmnopqrstuvwxyz=!+,.;:?{}"; + val specialCharsSet:Set[Char] = Set(specialChars:_*); + def containsSpecialChar(str: String) = str.exists(specialCharsSet.contains(_)); + + val toks:Array[String] = ( + "@|[a-zA-Z0-9]+|[^@a-zA-Z0-9]{1,3}").r.findAllIn(input).collect.toArray; + + val stringCounts = { + val m = new scala.collection.mutable.HashMap[String,Int]; + def incrementCount(s: String) = { m(s) = m.getOrElse(s, 0) + 1; } + for(s <- toks) incrementCount(s); + m; + } + + val estimatedSavings = scala.util.Sorting.stableSort( + for((s,n) <- stringCounts.toArray; savings = s.length*n + if (savings > 8 || containsSpecialChar(s))) + yield (s,n,savings), + (x:(String,Int,Int))=> -x._3); + + def strLast(str: String, n: Int) = str.substring(str.length - n, str.length); + // order of encodeNames is very important! + val encodeNames = for(n <- 0 until (36*36); c <- specialChars) yield c.toString+strLast("0"+Integer.toString(n, 36).toUpperCase, 2); + + val thingsToReplace:Seq[String] = estimatedSavings.map(_._1); + assert(encodeNames.length >= thingsToReplace.length); + + val replacements = Map(thingsToReplace.elements.zipWithIndex.map({ + case (str, i) => (str, encodeNames(i)); + }).collect:_*); + def encode(tk: String) = if (replacements.contains(tk)) replacements(tk) else tk; + + val afterReplace = toks.map(encode(_)).mkString.replaceAll( + "(["+specialChars+"])(?=..[^0-9A-Z])(00|0)", "$1"); + + def makeSingleQuotedContents(str: String): String = { + str.replace("\\", "\\\\").replace("'", "\\'").replace("<", "\\x3c").replace("\n", "\\n"). + replace("\r", "\\n").replace("\t", "\\t"); + } + + val expansionMap = new scala.collection.mutable.HashMap[Char,scala.collection.mutable.ArrayBuffer[String]]; + for(i <- 0 until thingsToReplace.length; sc = encodeNames(i).charAt(0); + e = thingsToReplace(i)) { + expansionMap.getOrElseUpdate(sc, new scala.collection.mutable.ArrayBuffer[String]) += + (if (e == "@") "" else e); + } + val expansionMapLiteral = "{"+(for((sc,strs) <- expansionMap) yield { + "'"+sc+"':'"+makeSingleQuotedContents(strs.mkString("@"))+"'"; + }).mkString(",")+"}"; + + val expr = ("(function(m){m="+expansionMapLiteral+ + ";for(var k in m){if(m.hasOwnProperty(k))m[k]=m[k].split('@')};return '"+ + makeSingleQuotedContents(afterReplace)+ + "'.replace(/(["+specialChars+ + "])([0-9A-Z]{0,2})/g,function(a,b,c){return m[b][parseInt(c||'0',36)]||'@'})}())"); + /*val expr = ("(function(m){m="+expansionMapLiteral+ + ";for(var k in m){if(m.hasOwnProperty(k))m[k]=m[k].split('@')};"+ + "var result=[];var i=0;var s='"+makeSingleQuotedContents(afterReplace)+ + "';var len=s.length;while (i= 'A' && a <= 'Z' || a >= '0' && a <= '9')) {c=L[0];i++} else if (!(b >= 'A' && b <= 'Z' || b >= '0' && b <= '9')) {c = L[parseInt(a,36)]; i+=2} else {c = L[parseInt(a+b,36)]; i+=3}; result.push(c||'@'); } else {result.push(x); i++} }; return result.join(''); }())");*/ + + def evaluateString(js: String): String = { + import org.mozilla.javascript._; + ContextFactory.getGlobal.call(new ContextAction { + def run(cx: Context) = { + val scope = cx.initStandardObjects; + cx.evaluateString(scope, js, "", 1, null) } }).asInstanceOf[String]; + } + + def putFile(str: String, path: String): Unit = { + import java.io._; + val writer = new FileWriter(path); + writer.write(str); + writer.close; + } + + val exprOut = evaluateString(expr); + if (exprOut != input) { + putFile(input, "/tmp/superpack.input"); + putFile(expr, "/tmp/superpack.expr"); + putFile(exprOut, "/tmp/superpack.output"); + error("Superpacked string does not evaluate to original string; check /tmp/superpack.*"); + } + + val singleLiteral = "'"+makeSingleQuotedContents(input)+"'"; + if (singleLiteral.length < expr.length) { + singleLiteral; + } + else { + expr; + } +} + +def doMake { + + lazy val isEtherPad = (args.length >= 2 && args(1) == "etherpad"); + lazy val isNoHelma = (args.length >= 2 && args(1) == "nohelma"); + + def getFile(path:String): String = { + val builder = new StringBuilder(1000); + val reader = new BufferedReader(new FileReader(path)); + val buf = new Array[Char](1024); + var numRead = 0; + while({ numRead = reader.read(buf); numRead } != -1) { + builder.append(buf, 0, numRead); + } + reader.close; + return builder.toString; + } + + def putFile(str: String, path: String): Unit = { + val writer = new FileWriter(path); + writer.write(str); + writer.close; + } + + def writeToString(func:(Writer=>Unit)): String = { + val writer = new StringWriter; + func(writer); + return writer.toString; + } + + def compressJS(code: String, wrap: Boolean): String = { + import yuicompressor.org.mozilla.javascript.{ErrorReporter, EvaluatorException}; + object MyErrorReporter extends ErrorReporter { + def warning(message:String, sourceName:String, line:Int, lineSource:String, lineOffset:Int) { + if (message startsWith "Try to use a single 'var' statement per scope.") return; + if (line < 0) System.err.println("\n[WARNING] " + message); + else System.err.println("\n[WARNING] " + line + ':' + lineOffset + ':' + message); + } + def error(message:String, sourceName:String, line:Int, lineSource:String, lineOffset:Int) { + if (line < 0) System.err.println("\n[ERROR] " + message); + else System.err.println("\n[ERROR] " + line + ':' + lineOffset + ':' + message); + } + def runtimeError(message:String, sourceName:String, line:Int, lineSource:String, lineOffset:Int): EvaluatorException = { + error(message, sourceName, line, lineSource, lineOffset); + return new EvaluatorException(message); + } + } + + val munge = true; + val verbose = false; + val optimize = true; + val compressor = new com.yahoo.platform.yui.compressor.JavaScriptCompressor(new StringReader(code), MyErrorReporter); + return writeToString(compressor.compress(_, if (wrap) 100 else -1, munge, verbose, true, !optimize)); + } + + def compressCSS(code: String, wrap: Boolean): String = { + val compressor = new com.yahoo.platform.yui.compressor.CssCompressor(new StringReader(code)); + return writeToString(compressor.compress(_, if (wrap) 100 else -1)); + } + + import java.util.regex.{Pattern, Matcher, MatchResult}; + + def stringReplace(orig: String, regex: String, groupReferences:Boolean, func:(MatchResult=>String)): String = { + val buf = new StringBuffer; + val m = Pattern.compile(regex).matcher(orig); + while (m.find) { + var str = func(m); + if (! groupReferences) { + str = str.replace("\\", "\\\\").replace("$", "\\$"); + } + m.appendReplacement(buf, str); + } + m.appendTail(buf); + return buf.toString; + } + + def stringToExpression(str: String): String = { + var contents = str.replace("\\", "\\\\").replace("'", "\\'").replace("<", "\\x3c").replace("\n", "\\n"). + replace("\r", "\\n").replace("\t", "\\t"); + contents = contents.replace("\\/", "\\\\x2f"); // for Norton Internet Security + val result = "'"+contents+"'"; + result; + } + + val srcDir = "www"; + val destDir = "build"; + var code = getFile(srcDir+"/ace2_outer.js"); + + val useCompression = true; //if (isEtherPad) false else true; + + code = stringReplace(code, "\\$\\$INCLUDE_([A-Z_]+)\\([\"']([^\"']+)[\"']\\)", false, (m:MatchResult) => { + val includeType = m.group(1); + val paths = m.group(2); + val pathsArray = paths.replaceAll("""/\*.*?\*/""", "").split(" +").filter(_.length > 0); + def getSubcode = pathsArray.map(p => getFile(srcDir+"/"+p)).mkString("\n"); + val doPack = (stringToExpression _); + includeType match { + case "JS" => { + var subcode = getSubcode; + subcode = subcode.replaceAll("var DEBUG=true;//\\$\\$[^\n\r]*", "var DEBUG=false;"); + if (useCompression) subcode = compressJS(subcode, true); + "('\\x3cscript type=\"text/javascript\">//\\n')"; + } + case "CSS" => { + var subcode = getSubcode; + if (useCompression) subcode = compressCSS(subcode, false); + "('')"; + } + case "JS_Q" => { + var subcode = getSubcode + subcode = subcode.replaceAll("var DEBUG=true;//\\$\\$[^\n\r]*", "var DEBUG=false;"); + if (useCompression) subcode = compressJS(subcode, true); + "('(\\'\\\\x3cscript type=\"text/javascript\">//\\\\n\\\\x3c/script>\\')')"; + } + case "CSS_Q" => { + var subcode = getSubcode; + if (useCompression) subcode = compressCSS(subcode, false); + "('(\\'