[yelp-xsl] Update jquery.syntax to 3.0.0 (which is MIT licenced).



commit 80e58d62f9b33c4b57edd8ed486910407293cc77
Author: Frederic Crozat <fcrozat novell com>
Date:   Mon May 16 14:32:12 2011 +0200

    Update jquery.syntax to 3.0.0 (which is MIT licenced).

 js/Makefile.am                                     |   10 +-
 js/jquery.syntax.brush.apache.js                   |   18 +-
 js/jquery.syntax.brush.applescript.js              |    4 +-
 ...rush.asm.js => jquery.syntax.brush.assembly.js} |   19 +-
 js/jquery.syntax.brush.bash-script.js              |   62 ++-
 js/jquery.syntax.brush.bash.js                     |   14 +-
 js/jquery.syntax.brush.basic.js                    |    8 +-
 js/jquery.syntax.brush.clang.js                    |   33 +-
 js/jquery.syntax.brush.csharp.js                   |   17 +-
 js/jquery.syntax.brush.css.js                      |   21 +-
 js/jquery.syntax.brush.diff.js                     |   12 +-
 js/jquery.syntax.brush.haskell.js                  |    4 +-
 js/jquery.syntax.brush.html.js                     |   54 +--
 js/jquery.syntax.brush.io.js                       |   45 ++
 js/jquery.syntax.brush.java.js                     |    6 +-
 js/jquery.syntax.brush.javascript.js               |   13 +-
 js/jquery.syntax.brush.kai.js                      |   29 ++
 js/jquery.syntax.brush.lisp.js                     |   20 +-
 js/jquery.syntax.brush.lua.js                      |    4 +-
 js/jquery.syntax.brush.ooc.js                      |    4 +-
 js/jquery.syntax.brush.pascal.js                   |    4 +-
 js/jquery.syntax.brush.perl5.js                    |   15 +-
 js/jquery.syntax.brush.php-script.js               |    4 +-
 js/jquery.syntax.brush.php.js                      |    6 +-
 js/jquery.syntax.brush.plain.js                    |    4 +-
 js/jquery.syntax.brush.python.js                   |    4 +-
 js/jquery.syntax.brush.ruby.js                     |   27 +-
 js/jquery.syntax.brush.smalltalk.js                |    4 +-
 js/jquery.syntax.brush.sql.js                      |   15 +-
 js/jquery.syntax.brush.xml.js                      |   52 ++
 js/jquery.syntax.brush.yaml.js                     |   12 +-
 js/jquery.syntax.core.js                           |  496 +++++++++++++++++---
 js/jquery.syntax.js                                |  119 ++++--
 js/jquery.syntax.layout.fixed.js                   |   70 +++
 js/jquery.syntax.layout.inline.js                  |   11 +
 js/jquery.syntax.layout.list.js                    |   54 +++
 js/jquery.syntax.layout.plain.js                   |   15 +
 js/jquery.syntax.layout.table.js                   |   58 +++
 js/syntax.html                                     |    2 +-
 39 files changed, 1108 insertions(+), 261 deletions(-)
---
diff --git a/js/Makefile.am b/js/Makefile.am
index a3ca63a..495f0c2 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -4,7 +4,7 @@ js_DATA =					\
 	jquery.js				\
 	jquery.syntax.brush.apache.js		\
 	jquery.syntax.brush.applescript.js	\
-	jquery.syntax.brush.asm.js		\
+	jquery.syntax.brush.assembly.js		\
 	jquery.syntax.brush.bash.js		\
 	jquery.syntax.brush.bash-script.js	\
 	jquery.syntax.brush.basic.js		\
@@ -14,8 +14,10 @@ js_DATA =					\
 	jquery.syntax.brush.diff.js		\
 	jquery.syntax.brush.haskell.js		\
 	jquery.syntax.brush.html.js		\
+	jquery.syntax.brush.io.js		\
 	jquery.syntax.brush.java.js		\
 	jquery.syntax.brush.javascript.js	\
+	jquery.syntax.brush.kai.js		\
 	jquery.syntax.brush.lisp.js		\
 	jquery.syntax.brush.lua.js		\
 	jquery.syntax.brush.ooc.js		\
@@ -28,8 +30,14 @@ js_DATA =					\
 	jquery.syntax.brush.ruby.js		\
 	jquery.syntax.brush.smalltalk.js	\
 	jquery.syntax.brush.sql.js		\
+	jquery.syntax.brush.xml.js		\
 	jquery.syntax.brush.yaml.js		\
 	jquery.syntax.core.js			\
+	jquery.syntax.layout.fixed.js		\
+	jquery.syntax.layout.inline.js		\
+	jquery.syntax.layout.list.js		\
+	jquery.syntax.layout.plain.js		\
+	jquery.syntax.layout.table.js		\
 	jquery.syntax.js
 
 EXTRA_DIST = $(js_DATA)
diff --git a/js/jquery.syntax.brush.apache.js b/js/jquery.syntax.brush.apache.js
index 346e473..43bef26 100644
--- a/js/jquery.syntax.brush.apache.js
+++ b/js/jquery.syntax.brush.apache.js
@@ -1,22 +1,26 @@
 // brush: "apache" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('apache', function(brush) {
 	brush.push({
-		pattern: /<(\w+).*?>/gi,
-		matches: Syntax.extractMatches({
+		pattern: /(<(\w+).*?>)/gi,
+		matches: Syntax.extractMatches(
+		{
 			klass: 'tag',
-			allow: ['attribute'],
+			allow: ['attribute', 'tag-name', 'string']
+		},
+		{
+			klass: 'tag-name',
 			process: Syntax.lib.webLinkProcess("site:http://httpd.apache.org/docs/trunk/ directive", true)
 		})
 	});
 
 	brush.push({
-		pattern: /<\/(\w+).*?>/gi,
-		matches: Syntax.extractMatches({klass: 'tag', allow: ['attribute']})
+		pattern: /(<\/(\w+).*?>)/gi,
+		matches: Syntax.extractMatches({klass: 'tag', allow: ['tag-name']}, {klass: 'tag-name'})
 	});
 
 	brush.push({
diff --git a/js/jquery.syntax.brush.applescript.js b/js/jquery.syntax.brush.applescript.js
index 6f0a0f3..198d076 100644
--- a/js/jquery.syntax.brush.applescript.js
+++ b/js/jquery.syntax.brush.applescript.js
@@ -1,7 +1,7 @@
 // brush: "applescript" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('applescript', function(brush) {
diff --git a/js/jquery.syntax.brush.asm.js b/js/jquery.syntax.brush.assembly.js
similarity index 73%
rename from js/jquery.syntax.brush.asm.js
rename to js/jquery.syntax.brush.assembly.js
index 233f3af..91b4855 100644
--- a/js/jquery.syntax.brush.asm.js
+++ b/js/jquery.syntax.brush.assembly.js
@@ -1,25 +1,24 @@
-// brush: "asm" aliases: []
+// brush: "assembly" aliases: ["asm"]
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
-Syntax.register('asm', function(brush) {
+Syntax.register('assembly', function(brush) {
 	brush.push(Syntax.lib.cStyleComment);
 	brush.push(Syntax.lib.cppStyleComment);
 	
-	brush.push({
-		pattern: /^\s+([a-zA-Z]+)/gm,
-		matches: Syntax.extractMatches({klass: 'function'})
-	});
-	
 	brush.push({pattern: /\.[a-zA-Z_][a-zA-Z0-9_]*/gm, klass: 'directive'});
 	
 	brush.push({pattern: /^[a-zA-Z_][a-zA-Z0-9_]*:/gm, klass: 'label'});
 	
+	brush.push({
+		pattern: /^\s*([a-zA-Z]+)/gm,
+		matches: Syntax.extractMatches({klass: 'function'})
+	});
+	
 	brush.push({pattern: /(-[0-9]+)|(\b[0-9]+)|(\$[0-9]+)/g, klass: 'constant'});
 	brush.push({pattern: /(\-|\b|\$)(0x[0-9a-f]+|[0-9]+|[a-z0-9_]+)/gi, klass: 'constant'});
-	brush.push({pattern: /$[a-zA-Z_][a-zA-Z0-9_]*:/gm, klass: 'label'});
 	
 	brush.push({pattern: /%\w+/g, klass: 'register'});
 	
diff --git a/js/jquery.syntax.brush.bash-script.js b/js/jquery.syntax.brush.bash-script.js
index 94b30cb..1296edf 100644
--- a/js/jquery.syntax.brush.bash-script.js
+++ b/js/jquery.syntax.brush.bash-script.js
@@ -1,39 +1,67 @@
 // brush: "bash-script" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('bash-script', function(brush) {
-	var keywords = ["break", "case", "continue", "do", "done", "elif", "else", "eq", "fi", "for", "function", "ge", "gt", "if", "in", "le", "lt", "ne", "return", "then", "until", "while"];
+	var operators = ["&&", "|", ";", "{", "}"];
+	brush.push(operators, {klass: 'operator'});
 	
+	brush.push({
+		pattern: /(?:^|\||;|&&)\s*((?:"([^"]|\\")+"|'([^']|\\')+'|\\\n|.|[ \t])+?)(?=$|\||;|&&)/gmi,
+		matches: Syntax.extractMatches({brush: 'bash-statement'})
+	});
+});
+
+Syntax.register('bash-statement', function(brush) {
+	var keywords = ["break", "case", "continue", "do", "done", "elif", "else", "eq", "fi", "for", "function", "ge", "gt", "if", "in", "le", "lt", "ne", "return", "then", "until", "while"];
 	brush.push(keywords, {klass: 'keyword'});
 	
-	var operators = ["&", "|", ">", "<", "="];
-	
+	var operators = [">", "<", "=", "`", "--", "{", "}", "(", ")", "[", "]"];
 	brush.push(operators, {klass: 'operator'});
 	
-	var commands = ["wget", "alias", "apropos", "awk", "basename", "bash", "bc", "bg", "builtin", "bzip2", "cal", "cat", "cd", "cfdisk", "chgrp", "chmod", "chown", "chrootcksum", "clear", "cmp", "comm", "command", "cp", "cron", "crontab", "csplit", "cut", "date", "dc", "dd", "ddrescue", "declare", "df", "diff", "diff3", "dig", "dir", "dircolors", "dirname", "dirs", "du", "echo", "egrep", "eject", "enable", "env", "ethtool", "eval", "exec", "exit", "expand", "export", "expr", "false", "fdformat", "fdisk", "fg", "fgrep", "file", "find", "fmt", "fold", "format", "free", "fsck", "ftp", "gawk", "getopts", "grep", "groups", "gzip", "hash", "head", "history", "hostname", "id", "ifconfig", "import", "install", "join", "kill", "less", "let", "ln", "local", "locate", "logname", "logout", "look", "lpc", "lpr", "lprint", "lprintd", "lprintq", "lprm", "ls", "lsof", "make", "man", "mkdir", "mkfifo", "mkisofs", "mknod", "more", "mount", "mtools", "mv", "netstat", "nice", "nl", "nohup", "nsloo
 kup", "op", "open", "passwd", "paste", "pathchk", "ping", "popd", "pr", "printcap", "printenv", "printf", "ps", "pushd", "pwd", "quota", "quotacheck", "quotactl", "ram", "rcp", "read", "readonly", "remsync", "renice", "rm", "rmdir", "rsync", "scp", "screen", "sdiff", "sed", "select", "seq", "set", "sftp", "shift", "shopt", "shutdown", "sleep", "sort", "source", "split", "ssh", "strace", "su", "sudo", "sum", "symlink", "sync", "tail", "tar", "tee", "test", "time", "times", "top", "touch", "tr", "traceroute", "trap", "true", "tsort", "tty", "type", "ulimit", "umask", "umount", "unalias", "uname", "unexpand", "uniq", "units", "unset", "unshar", "useradd", "usermod", "users", "uudecode", "uuencode", "v", "vdir", "vi", "watch", "wc", "whereis", "which", "who", "whoami", "xargs", "yes", "git", "svn", "ruby", "gem", "rails"];
+	brush.push({
+		pattern: /\(\((.*?)\)\)/gmi,
+		klass: 'expression',
+		allow: ['variable', 'string', 'operator', 'constant']
+	});
 	
-	var b = "[^\\B\\-\\w\\.]";
-	var commandsPattern = "(" + b + ")(" + commands.join("|") + ")(?=" + b + ")";
+	brush.push({
+		pattern: /`([\s\S]+?)`/gmi,
+		matches: Syntax.extractMatches({brush: 'bash-script', debug: true})
+	});
+	
+	brush.push(Syntax.lib.perlStyleComment);
+	
+	// Probably need to write a real parser here rather than using regular expressions, it is too fragile
+	// and misses lots of edge cases (e.g. nested brackets, delimiters).
+	brush.push({
+		pattern: /^\s*((?:\S+?=\$?(?:\[[^\]]+\]|\(\(.*?\)\)|"(?:[^"]|\\")+"|'(?:[^']|\\')+'|\S+)\s*)*)((?:\S+)?)/gmi,
+		matches: Syntax.extractMatches(
+			{klass: 'env', allow: ['variable', 'string', 'operator', 'constant', 'expression']},
+			{klass: 'function', allow: ['variable', 'string']}
+		)
+	});
 	
 	brush.push({
-		pattern: new RegExp(commandsPattern, "g"),
-		matches: Syntax.extractMatches({klass: 'function', index: 2})
+		pattern: /(\S+?)=/gmi,
+		matches: Syntax.extractMatches({klass: 'variable'}),
+		only: ['env']
 	});
 	
 	brush.push({
 		pattern: /\$\w+/g,
 		klass: 'variable'
-	})
+	});
 	
 	brush.push({pattern: /\s\-+\w+/g, klass: 'option'})
-
-	brush.push(Syntax.lib.perlStyleComment);
-	brush.push(jQuery.extend(Syntax.lib.singleQuotedString, {allow: '*'}));
-	brush.push(jQuery.extend(Syntax.lib.doubleQuotedString, {allow: '*'}));
-
+	
+	brush.push(Syntax.lib.singleQuotedString);
+	brush.push(Syntax.lib.doubleQuotedString);
+	
+	brush.push(Syntax.lib.decimalNumber);
+	brush.push(Syntax.lib.hexNumber);
+	
 	brush.push(Syntax.lib.webLink);
 });
-
diff --git a/js/jquery.syntax.brush.bash.js b/js/jquery.syntax.brush.bash.js
index 0a63cac..bf7cc5c 100644
--- a/js/jquery.syntax.brush.bash.js
+++ b/js/jquery.syntax.brush.bash.js
@@ -1,22 +1,28 @@
 // brush: "bash" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.brushes.dependency('bash', 'bash-script');
 
 Syntax.register('bash', function(brush) {
 	brush.push({
-		pattern: /^([\w@:~\s]*?[\$|\#])(.*?)$/gm,
+		pattern: /^([\w@:~ ]*?[\$|\#])\s+(.*?)$/gm,
 		matches: Syntax.extractMatches({klass: 'prompt'}, {brush: 'bash-script'})
 	});
 	
 	brush.push({
-		pattern: /\-\- .*$/gm,
+		pattern: /^\-\- .*$/gm,
 		klass: 'comment',
 		allow: ['href']
 	});
 	
+	// Strings
+	brush.push(Syntax.lib.singleQuotedString);
+	brush.push(Syntax.lib.doubleQuotedString);
+	brush.push(Syntax.lib.stringEscape);
+	
+	// Numbers
 	brush.push(Syntax.lib.webLink);
 });
diff --git a/js/jquery.syntax.brush.basic.js b/js/jquery.syntax.brush.basic.js
index 251e0b4..1cc1d74 100644
--- a/js/jquery.syntax.brush.basic.js
+++ b/js/jquery.syntax.brush.basic.js
@@ -1,17 +1,17 @@
 // brush: "basic" aliases: ['vb']
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.lib.vbStyleComment = {pattern: /' .*$/gm, klass: 'comment', allow: ['href']};
 
 Syntax.register('basic', function(brush) {
-	var keywords = ["AddHandler", "AddressOf", "Alias", "And", "AndAlso", "Ansi", "As", "Assembly", "Auto", "ByRef", "ByVal", "Call", "Case", "Catch", "Declare", "Default", "Delegate", "Dim", "DirectCast", "Do", "Each", "Else", "ElseIf", "End", "Enum", "Erase", "Error", "Event", "Exit", "Finally", "For", "Function", "Get", "GetType", "GoSub", "GoTo", "Handles", "If", "Implements", "Imports", "In", "Inherits", "Interface", "Is", "Let", "Lib", "Like", "Loop", "Mod", "Module", "MustOverride", "Namespace", "New", "Next", "Not", "On", "Option", "Optional", "Or", "OrElse", "Overloads", "Overridable", "Overrides", "ParamArray", "Preserve", "Property", "RaiseEvent", "ReadOnly", "ReDim", "REM", "RemoveHandler", "Resume", "Return", "Select", "Set", "Static", "Step", "Stop", "Structure", "Sub", "SyncLock", "Then", "Throw", "To", "Try", "TypeOf", "Unicode", "Until", "When", "While", "With", "WithEvents", "WriteOnly", "Xor", "ExternalSource", "Region", "Print"];
+	var keywords = ["AddHandler", "AddressOf", "Alias", "And", "AndAlso", "Ansi", "As", "Assembly", "Auto", "ByRef", "ByVal", "Call", "Case", "Catch", "Declare", "Default", "Delegate", "Dim", "DirectCast", "Do", "Each", "Else", "ElseIf", "End", "Enum", "Erase", "Error", "Event", "Exit", "Finally", "For", "Function", "Get", "GetType", "GoSub", "GoTo", "Handles", "If", "Implements", "Imports", "In", "Inherits", "Interface", "Is", "Let", "Lib", "Like", "Loop", "Mod", "Module", "MustOverride", "Namespace", "New", "Next", "Not", "On", "Option", "Optional", "Or", "OrElse", "Overloads", "Overridable", "Overrides", "ParamArray", "Preserve", "Property", "RaiseEvent", "ReadOnly", "ReDim", "REM", "RemoveHandler", "Resume", "Return", "Select", "Set", "Static", "Step", "Stop", "Structure", "Sub", "SyncLock", "Then", "Throw", "To", "Try", "TypeOf", "Unicode", "Until", "When", "While", "With", "WithEvents", "WriteOnly", "Xor", "ExternalSource", "Region", "Print", "Class"];
 
 	var operators = ["-", "&", "&=", "*", "*=", "/", "/=", "\\", "\=", "^", "^=", "+", "+=", "=", "-="];
 	
-	var types = ["CBool", "CByte", "CChar", "CDate", "CDec", "CDbl", "Char", "CInt", "Class", "CLng", "CObj", "Const", "CShort", "CSng", "CStr", "CType", "Date", "Decimal", "Variant", "String", "Short", "Long", "Single", "Double", "Object", "Integer", "Boolean", "Byte", "Char"];
+	var types = ["CBool", "CByte", "CChar", "CDate", "CDec", "CDbl", "Char", "CInt", "CLng", "CObj", "Const", "CShort", "CSng", "CStr", "CType", "Date", "Decimal", "Variant", "String", "Short", "Long", "Single", "Double", "Object", "Integer", "Boolean", "Byte", "Char"];
 	
 	var operators = ["+", "-", "*", "/", "+=", "-=", "*=", "/=", "=", ":=", "==", "!=", "!", "%", "?", ">", "<", ">=", "<=", "&&", "||", "&", "|", "^", ".", "~", "..", ">>", "<<", ">>>", "<<<", ">>=", "<<=", ">>>=", "<<<=", "%=", "^=", "@"];
 	
diff --git a/js/jquery.syntax.brush.clang.js b/js/jquery.syntax.brush.clang.js
index fc4e75b..db22bed 100644
--- a/js/jquery.syntax.brush.clang.js
+++ b/js/jquery.syntax.brush.clang.js
@@ -1,17 +1,17 @@
 // brush: "clang" aliases: ["cpp", "c++", "c", "objective-c"]
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('clang', function(brush) {
-	var keywords = ["@interface", "@implementation", "@protocol", "@end", "@try", "@throw", "@catch", "@finally", "@class", "@selector", "@encode", "@synchronized", "@property", "struct", "break", "continue", "else", "for", "switch", "case", "default", "enum", "goto", "register", "sizeof", "typedef", "volatile", "do", "extern", "if", "return", "static", "union", "while", "asm", "dynamic_cast", "namespace", "reinterpret_cast", "try", "explicit", "static_cast", "typeid", "catch", "operator", "template", "class", "const_cast", "inline", "throw", "virtual"];
+	var keywords = ["@interface", "@implementation", "@protocol", "@end", "@try", "@throw", "@catch", "@finally", "@class", "@selector", "@encode", "@synchronized", "@property", "@synthesize", "@dynamic", "struct", "break", "continue", "else", "for", "switch", "case", "default", "enum", "goto", "register", "sizeof", "typedef", "volatile", "do", "extern", "if", "return", "static", "union", "while", "asm", "dynamic_cast", "namespace", "reinterpret_cast", "try", "explicit", "static_cast", "typeid", "catch", "operator", "template", "class", "const_cast", "inline", "throw", "virtual", "IBOutlet"];
 	
-	var access = ["@private", "@protected", "@public", "private", "protected", "public", "friend", "using"];
+	var access = ["@private", "@protected", "@public", "@required", "@optional", "private", "protected", "public", "friend", "using"];
 	
 	var types = ["mutable", "auto", "const", "double", "float", "int", "short", "char", "long", "signed", "unsigned", "bool", "void", "typename", "id", "register", "wchar_t"];
 	
-	var operators = ["@", "+", "*", "/", "-", "&", "|", "~", "!", "%", "<", "=", ">", "[", "]", "new", "delete"];
+	var operators = ["+", "*", "/", "-", "&", "|", "~", "!", "%", "<", "=", ">", "[", "]", "new", "delete", "in"];
 	
 	var values = ["this", "true", "false", "NULL", "YES", "NO", "nil"];
 	
@@ -21,6 +21,27 @@ Syntax.register('clang', function(brush) {
 	brush.push(operators, {klass: 'operator'});
 	brush.push(access, {klass: 'access'});
 	
+	// Objective-C properties
+	brush.push({
+		pattern: /@property\((.*)\)[^;]+;/gmi,
+		klass: 'objective-c-property',
+		allow: '*'
+	});
+	
+	var propertyAttributes = ["getter", "setter", "readwrite", "readonly", "assign", "retain", "copy", "nonatomic"];
+	
+	brush.push(propertyAttributes, {
+		klass: 'keyword',
+		only: ['objective-c-property']
+	})
+	
+	// Objective-C strings
+	
+	brush.push({
+		pattern: /@(?=")/g,
+		klass: 'string'
+	});
+	
 	// Objective-C classes
 	brush.push(Syntax.lib.camelCaseType);
 	
@@ -43,7 +64,7 @@ Syntax.register('clang', function(brush) {
 	});
 	
 	brush.push({
-		pattern: /-\s*(\(.+?\))?\s*(\w+)\s*\{/g,
+		pattern: /-\s*(\([^\)]+?\))?\s*(\w+)\s*\{/g,
 		matches: Syntax.extractMatches({index: 2, klass: 'function'})
 	});
 	
diff --git a/js/jquery.syntax.brush.csharp.js b/js/jquery.syntax.brush.csharp.js
index e93318a..bb4d9aa 100644
--- a/js/jquery.syntax.brush.csharp.js
+++ b/js/jquery.syntax.brush.csharp.js
@@ -1,7 +1,7 @@
-// brush: "csharp" aliases: ["c#"]
+// brush: "csharp" aliases: ["c-sharp", "c#"]
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('csharp', function(brush) {
@@ -14,13 +14,20 @@ Syntax.register('csharp', function(brush) {
 	var operators = ["+", "-", "*", "/", "%", "&", "|", "^", "!", "~", "&&", "||", "++", "--", "<<", ">>", "==", "!=", "<", ">", "<=", ">=", "=", "?", "new", "as", "is", "sizeof", "typeof", "checked", "unchecked"];
 	
 	var values = ["this", "true", "false", "null"];
-	
+		
 	brush.push(values, {klass: 'constant'});
 	brush.push(types, {klass: 'type'});
 	brush.push(keywords, {klass: 'keyword'});
 	brush.push(operators, {klass: 'operator'});
 	brush.push(access, {klass: 'access'});
 	
+	// Functions
+	brush.push(Syntax.lib.cStyleFunction);
+	brush.push({
+		pattern: /(?:\.)([a-z_][a-z0-9_]+)/gi,
+		matches: Syntax.extractMatches({klass: 'function'})
+	});
+	
 	// Camel Case Types
 	brush.push(Syntax.lib.camelCaseType);
 	
@@ -36,7 +43,5 @@ Syntax.register('csharp', function(brush) {
 	
 	brush.push(Syntax.lib.decimalNumber);
 	brush.push(Syntax.lib.hexNumber);
-	
-	brush.push(Syntax.lib.cStyleFunction);
 });
 
diff --git a/js/jquery.syntax.brush.css.js b/js/jquery.syntax.brush.css.js
index 738c131..76df7fa 100644
--- a/js/jquery.syntax.brush.css.js
+++ b/js/jquery.syntax.brush.css.js
@@ -1,13 +1,22 @@
 // brush: "css" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('css', function(brush) {
-	var colorNames = ["AliceBlue", "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", "BlanchedAlmond", "Blue", "BlueViolet", "Brown", "BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral", "CornflowerBlue", "Cornsilk", "Crimson", "Cyan", "DarkBlue", "DarkCyan", "DarkGoldenRod", "DarkGray", "DarkGreen", "DarkKhaki", "DarkMagenta", "DarkOliveGreen", "Darkorange", "DarkOrchid", "DarkRed", "DarkSalmon", "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray", "DarkTurquoise", "DarkViolet", "DeepPink", "DeepSkyBlue", "DimGray", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen", "Fuchsia", "Gainsboro", "GhostWhite", "Gold", "GoldenRod", "Gray", "Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", "Indigo", "Ivory", "Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon", "LightBlue", "LightCoral", "LightCyan", "LightGoldenRodYellow", "LightGrey", "LightGreen", "LightPink", "LightSalmon", "LightSeaGreen", "LightSkyBlue", "LightSlateGray"
 , "LightSteelBlue", "LightYellow", "Lime", "LimeGreen", "Linen", "Magenta", "Maroon", "MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple", "MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", "MediumTurquoise", "MediumVioletRed", "MidnightBlue", "MintCream", "MistyRose", "Moccasin", "NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", "OrangeRed", "Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed", "PapayaWhip", "PeachPuff", "Peru", "Pink", "Plum", "PowderBlue", "Purple", "Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown", "SeaGreen", "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue", "SlateGray", "Snow", "SpringGreen", "SteelBlue", "Tan", "Teal", "Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke", "Yellow", "YellowGreen", "#[0-9a-f]{3,6}", "rgba?\\(.+?\\)", "hsla?\\(.+?\\)"];
+	var colorNames = ["AliceBlue", "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", "BlanchedAlmond", "Blue", "BlueViolet", "Brown", "BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral", "CornflowerBlue", "Cornsilk", "Crimson", "Cyan", "DarkBlue", "DarkCyan", "DarkGoldenRod", "DarkGray", "DarkGreen", "DarkKhaki", "DarkMagenta", "DarkOliveGreen", "Darkorange", "DarkOrchid", "DarkRed", "DarkSalmon", "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray", "DarkTurquoise", "DarkViolet", "DeepPink", "DeepSkyBlue", "DimGray", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen", "Fuchsia", "Gainsboro", "GhostWhite", "Gold", "GoldenRod", "Gray", "Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", "Indigo", "Ivory", "Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon", "LightBlue", "LightCoral", "LightCyan", "LightGoldenRodYellow", "LightGrey", "LightGreen", "LightPink", "LightSalmon", "LightSeaGreen", "LightSkyBlue", "LightSlateGray"
 , "LightSteelBlue", "LightYellow", "Lime", "LimeGreen", "Linen", "Magenta", "Maroon", "MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple", "MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", "MediumTurquoise", "MediumVioletRed", "MidnightBlue", "MintCream", "MistyRose", "Moccasin", "NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", "OrangeRed", "Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed", "PapayaWhip", "PeachPuff", "Peru", "Pink", "Plum", "PowderBlue", "Purple", "Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown", "SeaGreen", "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue", "SlateGray", "Snow", "SpringGreen", "SteelBlue", "Tan", "Teal", "Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke", "Yellow", "YellowGreen"];
 	
-	var colorMatcher = new RegExp("(" + (colorNames.join(")|(")) + ")", "gi")
+	var colorPatterns = ["#[0-9a-f]{3,6}", "rgba?\\(.+?\\)", "hsla?\\(.+?\\)"];
+	
+	var colorMatcher = [].concat(
+		jQuery.map(colorNames, function(pattern) {
+			return "(" + Syntax.Brush.convertStringToTokenPattern(pattern, true) + ")";
+		}), 
+		jQuery.map(colorPatterns, function(pattern) {
+			return "(" + Syntax.Brush.convertStringToTokenPattern(pattern, false) + ")";
+		})
+	);
 	
 	brush.push({
 		pattern: /\(.*?\)/g,
@@ -21,11 +30,11 @@ Syntax.register('css', function(brush) {
 	});
 	
 	brush.push({
-		pattern: colorMatcher,
+		pattern: new RegExp(colorMatcher.join("|"), "gi"),
 		klass: 'color',
 		process: function (element, match) {
 			var text = jQuery(element).text();
-			var colorBox = jQuery('<span style="font-size: 0.5em; margin: 4px; border: 1px solid black">&nbsp;&nbsp;</span>').css('background-color', text);
+			var colorBox = jQuery('<span class="color-box"><span class="sample" style="background-color: ' + text + '"></span>&nbsp;&nbsp;</span>');
 			return jQuery(element).append(colorBox);
 		}
 	});
diff --git a/js/jquery.syntax.brush.diff.js b/js/jquery.syntax.brush.diff.js
index 1d0038d..e55b83e 100644
--- a/js/jquery.syntax.brush.diff.js
+++ b/js/jquery.syntax.brush.diff.js
@@ -1,7 +1,7 @@
 // brush: "diff" aliases: ["patch"]
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('diff', function(brush) {
@@ -12,5 +12,13 @@ Syntax.register('diff', function(brush) {
 	
 	brush.push({pattern: /^\+[^\+]{1}.*$/gm, klass: 'insert'});
 	brush.push({pattern: /^\-[^\-]{1}.*$/gm, klass: 'remove'});
+	
+	brush.postprocess = function (options, html, container) {
+		$('.insert', html).closest('.source').addClass('insert-line');
+		$('.remove', html).closest('.source').addClass('remove-line');
+		$('.offset', html).closest('.source').addClass('offset-line');
+		
+		return html;
+	};
 });
 
diff --git a/js/jquery.syntax.brush.haskell.js b/js/jquery.syntax.brush.haskell.js
index 350896e..77deeba 100644
--- a/js/jquery.syntax.brush.haskell.js
+++ b/js/jquery.syntax.brush.haskell.js
@@ -1,7 +1,7 @@
 // brush: "haskell" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('haskell', function(brush) {
diff --git a/js/jquery.syntax.brush.html.js b/js/jquery.syntax.brush.html.js
index 247657a..4beb7fc 100644
--- a/js/jquery.syntax.brush.html.js
+++ b/js/jquery.syntax.brush.html.js
@@ -1,9 +1,10 @@
-// brush: "html" aliases: ["xml"]
+// brush: "html" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
+Syntax.brushes.dependency('html', 'xml');
 Syntax.brushes.dependency('html', 'javascript');
 Syntax.brushes.dependency('html', 'css');
 Syntax.brushes.dependency('html', 'php-script');
@@ -21,13 +22,23 @@ Syntax.register('html', function(brush) {
 	});
 	
 	brush.push({
-		pattern: /(<\?php)((.|\n)*?)(\?>)/gm,
-		matches: Syntax.extractMatches({klass: 'operator'}, {brush: 'php-script'}, null, {klass: 'operator'})
+		pattern: /((<\?php)([\s\S]*?)(\?>))/gm,
+		matches: Syntax.extractMatches(
+			{klass: 'php-tag', allow: ['keyword', 'php-script']},
+			{klass: 'keyword'},
+			{brush: 'php-script'},
+			{klass: 'keyword'}
+		)
 	});
 	
 	brush.push({
-		pattern: /(<\?rb?)((.|\n)*?)(\?>)/gm,
-		matches: Syntax.extractMatches({klass: 'operator'}, {brush: 'ruby'}, null, {klass: 'operator'})
+		pattern: /((<\?rb?)([\s\S]*?)(\?>))/gm,
+		matches: Syntax.extractMatches(
+			{klass: 'ruby-tag', allow: ['keyword', 'ruby']},
+			{klass: 'keyword'},
+			{brush: 'ruby'},
+			{klass: 'keyword'}
+		)
 	});
 	
 	brush.push({
@@ -37,36 +48,19 @@ Syntax.register('html', function(brush) {
 	});
 	
 	brush.push({
-		pattern: /<(\!DOCTYPE(.*?))>/g,
+		pattern: /<\!(DOCTYPE(.*?))>/g,
 		matches: Syntax.extractMatches({klass: 'doctype'})
 	});
 	
-	brush.push({
-		pattern: /<\/?((?:[\w]+:)?)([\w]+).*?>/g,
-		matches: Syntax.extractMatches({klass: 'namespace', allow: ['attribute']}, {klass: 'tag', allow: ['attribute']})
-	});
-	
-	brush.push({
-		pattern: /(\w+)=(".*?"|'.*?'|\S+)/g,
-		matches: Syntax.extractMatches({klass: 'attribute'}, {klass: 'string'})
-	});
-	
-	brush.push({
-		pattern: /&\w+;/g,
-		klass: 'entity'
-	});
-	
+	// Is this rule still relevant?
 	brush.push({
 		pattern: /(%[0-9a-f]{2})/gi,
 		klass: 'percent-escape',
-		only: ['html', 'string']
+		only: ['html']
 	});
-   
-	brush.push(Syntax.lib.xmlComment);
-   
-	brush.push(Syntax.lib.singleQuotedString);
-	brush.push(Syntax.lib.doubleQuotedString);
 	
-	brush.push(Syntax.lib.webLink);
+	// The position of this statement is important - it determines at what point the rules of the parent are processed.
+	// In this case, the rules for xml are processed after the rules for html.
+	brush.derives('xml');
 });
 
diff --git a/js/jquery.syntax.brush.io.js b/js/jquery.syntax.brush.io.js
new file mode 100644
index 0000000..312b750
--- /dev/null
+++ b/js/jquery.syntax.brush.io.js
@@ -0,0 +1,45 @@
+// brush: "io" aliases: []
+
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
+//	See <jquery.syntax.js> for licensing details.
+
+Syntax.register('io', function(brush) {
+	brush.push(Syntax.lib.cStyleFunction);
+	
+	var keywords = ["return"];
+	
+	var operators = ["::=", ":=", "or", "and", "@", "+", "*", "/", "-", "&", "|", "~", "!", "%", "<", "=", ">", "[", "]", "new", "delete"];
+	
+	brush.push(keywords, {klass: 'keywords'});
+	brush.push(operators, {klass: 'operator'});
+	
+	// Extract space delimited method invocations
+	brush.push({
+		pattern: /\b([ \t]+([a-z]+))/gi,
+		matches: Syntax.extractMatches({index: 2, klass: 'function'})
+	});
+	
+	brush.push({
+		pattern: /\)([ \t]+([a-z]+))/gi,
+		matches: Syntax.extractMatches({index: 2, klass: 'function'})
+	});
+	
+	// Objective-C classes
+	brush.push(Syntax.lib.camelCaseType);
+	
+	brush.push(Syntax.lib.perlStyleComment);
+	brush.push(Syntax.lib.cStyleComment);
+	brush.push(Syntax.lib.cppStyleComment);
+	brush.push(Syntax.lib.webLink);
+	
+	// Strings
+	brush.push(Syntax.lib.singleQuotedString);
+	brush.push(Syntax.lib.doubleQuotedString);
+	brush.push(Syntax.lib.stringEscape);
+	
+	// Numbers
+	brush.push(Syntax.lib.decimalNumber);
+	brush.push(Syntax.lib.hexNumber);
+});
+
diff --git a/js/jquery.syntax.brush.java.js b/js/jquery.syntax.brush.java.js
index 19613bd..ad0591e 100644
--- a/js/jquery.syntax.brush.java.js
+++ b/js/jquery.syntax.brush.java.js
@@ -1,7 +1,7 @@
 // brush: "java" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('java', function(brush) {
@@ -13,7 +13,7 @@ Syntax.register('java', function(brush) {
 	
 	var operators = ["++", "--", "++", "--", "+", "-", "~", "!", "*", "/", "%", "+", "-", "<<", ">>", ">>>", "<", ">", "<=", ">=", "==", "!=", "&", "^", "|", "&&", "||", "?", "=", "+=", "-=", "*=", "/=", "%=", "&=", "^=", "|=", "<<=", ">>=", ">>>=", "instanceof", "new", "delete"];
 	
-	var constants = ["this", "true", "false"];
+	var constants = ["this", "true", "false", "null"];
 	
 	brush.push(constants, {klass: 'constant'});
 	brush.push(types, {klass: 'type'});
diff --git a/js/jquery.syntax.brush.javascript.js b/js/jquery.syntax.brush.javascript.js
index cec566c..193c3ee 100644
--- a/js/jquery.syntax.brush.javascript.js
+++ b/js/jquery.syntax.brush.javascript.js
@@ -1,19 +1,22 @@
 // brush: "javascript" aliases: ["js", "actionscript"]
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('javascript', function(brush) {
-	var keywords = ["break", "case", "catch", "continue", "default", "delete", "do", "else", "for", "if", "in", "instanceof", "new", "return", "super", "switch", "throw", "true", "try", "typeof", "var", "while", "with", "prototype"];
+	var keywords = ["function", "break", "case", "catch", "continue", "default", "delete", "do", "else", "for", "if", "in", "instanceof", "new", "return", "super", "switch", "throw", "true", "try", "typeof", "var", "while", "with", "prototype"];
 	
 	var operators = ["+", "*", "/", "-", "&", "|", "~", "!", "%", "<", "=", ">"];
-	var values = ["function", "this", "true", "false", "null"];
-		
+	var values = ["this", "true", "false", "null"];
+	
 	brush.push(values, {klass: 'constant'});
 	brush.push(keywords, {klass: 'keyword'});
 	brush.push(operators, {klass: 'operator'});
 	
+	// Regular expressions
+	brush.push(Syntax.lib.perlStyleRegularExpressions);
+	
 	// Camel Case Types
 	brush.push(Syntax.lib.camelCaseType);
 	
diff --git a/js/jquery.syntax.brush.kai.js b/js/jquery.syntax.brush.kai.js
new file mode 100644
index 0000000..e3c7b00
--- /dev/null
+++ b/js/jquery.syntax.brush.kai.js
@@ -0,0 +1,29 @@
+// brush: "kai" aliases: []
+
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
+//	See <jquery.syntax.js> for licensing details.
+
+Syntax.register('kai', function(brush) {
+	brush.push(['(', ')', '[', ']', '{', '}'], {klass: 'operator'});
+	
+	brush.push(Syntax.lib.perlStyleComment);
+	
+	brush.push(Syntax.lib.decimalNumber);
+	brush.push(Syntax.lib.webLink);
+	
+	brush.push({
+		pattern: /\(([^\s\(\)]+)/gi,
+		matches: Syntax.extractMatches({klass: 'function'})
+	});
+	
+	brush.push({
+		pattern: /`[a-z]*/gi,
+		klass: 'constant'
+	})
+	
+	// Strings
+	brush.push(Syntax.lib.multiLineDoubleQuotedString);
+	brush.push(Syntax.lib.stringEscape);
+});
+
diff --git a/js/jquery.syntax.brush.lisp.js b/js/jquery.syntax.brush.lisp.js
index bbc1a84..d2cdc5f 100644
--- a/js/jquery.syntax.brush.lisp.js
+++ b/js/jquery.syntax.brush.lisp.js
@@ -1,7 +1,7 @@
 // brush: "lisp" aliases: ['scheme', 'clojure']
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.lib.lispStyleComment = {pattern: /(;+) .*$/gm, klass: 'comment', allow: ['href']};
@@ -13,22 +13,12 @@ Syntax.register('lisp', function(brush) {
 	
 	brush.push(Syntax.lib.lispStyleComment);
 	
-	// Hex, Octal and Binary numbers :)
-	brush.push({
-		pattern: /0x[0-9a-fA-F]+/g,
-		klass: 'constant'
-	});
-	
+	brush.push(Syntax.lib.hexNumber);
 	brush.push(Syntax.lib.decimalNumber);
 	brush.push(Syntax.lib.webLink);
 	
 	brush.push({
-		pattern: /\(([^\s\(\)]+)/gi,
-		matches: Syntax.extractMatches({klass: 'function'})
-	});
-	
-	brush.push({
-		pattern: /\(([^\s\(\)]+)/gi,
+		pattern: /\(\s*([^\s\(\)]+)/gmi,
 		matches: Syntax.extractMatches({klass: 'function'})
 	});
 	
@@ -38,7 +28,7 @@ Syntax.register('lisp', function(brush) {
 	})
 	
 	// Strings
-	brush.push(Syntax.lib.doubleQuotedString);
+	brush.push(Syntax.lib.multiLineDoubleQuotedString);
 	brush.push(Syntax.lib.stringEscape);
 });
 
diff --git a/js/jquery.syntax.brush.lua.js b/js/jquery.syntax.brush.lua.js
index 9592f47..f7821c3 100644
--- a/js/jquery.syntax.brush.lua.js
+++ b/js/jquery.syntax.brush.lua.js
@@ -1,7 +1,7 @@
 // brush: "lua" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('lua', function(brush) {
diff --git a/js/jquery.syntax.brush.ooc.js b/js/jquery.syntax.brush.ooc.js
index ee69bbc..000781b 100644
--- a/js/jquery.syntax.brush.ooc.js
+++ b/js/jquery.syntax.brush.ooc.js
@@ -1,7 +1,7 @@
 // brush: "ooc" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('ooc', function(brush) {
diff --git a/js/jquery.syntax.brush.pascal.js b/js/jquery.syntax.brush.pascal.js
index 6afac03..606d1f1 100644
--- a/js/jquery.syntax.brush.pascal.js
+++ b/js/jquery.syntax.brush.pascal.js
@@ -1,7 +1,7 @@
 // brush: "pascal" aliases: ["delphi"]
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 //
 // Constructed using information from http://pascal.comsci.us/etymology/
diff --git a/js/jquery.syntax.brush.perl5.js b/js/jquery.syntax.brush.perl5.js
index 4694cb2..6cce322 100644
--- a/js/jquery.syntax.brush.perl5.js
+++ b/js/jquery.syntax.brush.perl5.js
@@ -1,7 +1,7 @@
 // brush: "perl5" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('perl5', function(brush) {
@@ -18,6 +18,9 @@ Syntax.register('perl5', function(brush) {
 	brush.push(operators, {klass: 'operator'});
 	brush.push(builtins, {klass: 'function'});
 	
+	// Regular expressions
+	brush.push(Syntax.lib.perlStyleRegularExpressions);
+	
 	// Comments
 	brush.push(Syntax.lib.perlStyleComment);
 	brush.push(Syntax.lib.webLink);
@@ -27,7 +30,13 @@ Syntax.register('perl5', function(brush) {
 		pattern: /(\$|@|%)\w+/gi,
 		klass: 'variable'
 	});
-		
+	
+	// Enddoc
+	brush.push({
+		pattern: /__END__[\s\S]*/gm,
+		klass: 'comment'
+	});
+	
 	// Strings
 	brush.push(Syntax.lib.singleQuotedString);
 	brush.push(Syntax.lib.doubleQuotedString);
diff --git a/js/jquery.syntax.brush.php-script.js b/js/jquery.syntax.brush.php-script.js
index d9df9d2..fab2ff7 100644
--- a/js/jquery.syntax.brush.php-script.js
+++ b/js/jquery.syntax.brush.php-script.js
@@ -1,7 +1,7 @@
 // brush: "php-script" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('php-script', function(brush) {
diff --git a/js/jquery.syntax.brush.php.js b/js/jquery.syntax.brush.php.js
index 51e2891..cc813a4 100644
--- a/js/jquery.syntax.brush.php.js
+++ b/js/jquery.syntax.brush.php.js
@@ -1,7 +1,7 @@
 // brush: "php" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.brushes.dependency('php', 'php-script');
@@ -9,7 +9,7 @@ Syntax.brushes.dependency('php', 'php-script');
 Syntax.register('php', function(brush) {
 	brush.push({
 		pattern: /(<\?(php)?)((.|\n)*?)(\?>)/gm,
-		matches: Syntax.extractMatches({klass: 'operator'}, null, {brush: 'php-script'}, null, {klass: 'operator'})
+		matches: Syntax.extractMatches({klass: 'keyword'}, null, {brush: 'php-script'}, null, {klass: 'keyword'})
 	})
 });
 
diff --git a/js/jquery.syntax.brush.plain.js b/js/jquery.syntax.brush.plain.js
index a8be6ad..30f4bb8 100644
--- a/js/jquery.syntax.brush.plain.js
+++ b/js/jquery.syntax.brush.plain.js
@@ -1,7 +1,7 @@
 // brush: "plain" aliases: ["text"]
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('plain', function(brush) {
diff --git a/js/jquery.syntax.brush.python.js b/js/jquery.syntax.brush.python.js
index 7065817..40f6a90 100644
--- a/js/jquery.syntax.brush.python.js
+++ b/js/jquery.syntax.brush.python.js
@@ -1,7 +1,7 @@
 // brush: "python" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('python', function(brush) {
diff --git a/js/jquery.syntax.brush.ruby.js b/js/jquery.syntax.brush.ruby.js
index f362eda..9332890 100644
--- a/js/jquery.syntax.brush.ruby.js
+++ b/js/jquery.syntax.brush.ruby.js
@@ -1,22 +1,37 @@
 // brush: "ruby" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.lib.rubyStyleFunction = {pattern: /(?:def\s+|\.)([a-z_][a-z0-9_]+)/gi, matches: Syntax.extractMatches({klass: 'function'})};
-Syntax.lib.rubyStyleSymbol = {pattern: /:\w+/g, klass: 'constant'};
+
+// We need to emulate negative lookbehind
+Syntax.lib.rubyStyleSymbol = {pattern: /([:]?):\w+/g, klass: 'constant', matches: function (match, expr) {
+	if (match[1] != '') return [];
+	
+	return [new Syntax.Match(match.index, match[0].length, expr, match[0])];
+}};
 
 Syntax.register('ruby', function(brush) {
-	var keywords = ["alias", "and", "begin", "break", "case", "class", "def", "define_method", "defined", "do", "each", "else", "elsif", "end", "ensure", "false", "for", "if", "in", "module", "new", "next", "nil", "not", "or", "raise", "redo", "rescue", "retry", "return", "self", "super", "then", "throw", "true", "undef", "unless", "until", "when", "while", "yield"];
+	var keywords = ["alias", "and", "begin", "break", "case", "class", "def", "define_method", "defined?", "do", "else", "elsif", "end", "ensure", "false", "for", "if", "in", "module", "next", "not", "or", "raise", "redo", "rescue", "retry", "return", "then", "throw", "undef", "unless", "until", "when", "while", "yield", "block_given?"];
 	
 	var operators = ["+", "*", "/", "-", "&", "|", "~", "!", "%", "<", "=", ">"];
-	var values = ["this", "true", "false", "nil"];
+	var values = ["self", "super", "true", "false", "nil"];
 	
-	var access = ["private", "public"];
+	var access = ["private", "protected", "public"];
 	
 	brush.push(access, {klass: 'access'});
 	brush.push(values, {klass: 'constant'});
+
+	// Percent operator statements
+	brush.push({
+		pattern: /(\%[\S])(\{[\s\S]*?\})/g,
+		matches: Syntax.extractMatches({klass: 'function'}, {klass: 'constant'})
+	});
+	
+	// Regular expressions
+	brush.push(Syntax.lib.perlStyleRegularExpressions);
 	
 	brush.push({pattern: /(@+|\$)[\w]+/g, klass: 'variable'});
 	
diff --git a/js/jquery.syntax.brush.smalltalk.js b/js/jquery.syntax.brush.smalltalk.js
index 022cad3..a91200a 100644
--- a/js/jquery.syntax.brush.smalltalk.js
+++ b/js/jquery.syntax.brush.smalltalk.js
@@ -1,7 +1,7 @@
 // brush: "smalltalk" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('smalltalk', function(brush) {
diff --git a/js/jquery.syntax.brush.sql.js b/js/jquery.syntax.brush.sql.js
index 7e887c0..8f00aa0 100644
--- a/js/jquery.syntax.brush.sql.js
+++ b/js/jquery.syntax.brush.sql.js
@@ -1,13 +1,13 @@
 // brush: "sql" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.lib.sqlStyleComment = {pattern: /-- .*$/gm, klass: 'comment', allow: ['href']};
 
 Syntax.register('sql', function(brush) {
-	var keywords = ["A", "ABORT", "ABS", "ABSOLUTE", "ACCESS", "ACTION", "ADA", "ADD", "ADMIN", "AFTER", "AGGREGATE", "ALIAS", "ALL", "ALLOCATE", "ALSO", "ALTER", "ALWAYS", "ANALYSE", "ANALYZE", "AND", "ANY", "ARE", "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATOMIC", "ATTRIBUTE", "ATTRIBUTES", "AUDIT", "AUTHORIZATION", "AUTO_INCREMENT", "AVG", "AVG_ROW_LENGTH", "BACKUP", "BACKWARD", "BEFORE", "BEGIN", "BERNOULLI", "BETWEEN", "BIGINT", "BINARY", "BIT", "BIT_LENGTH", "BITVAR", "BLOB", "BOOL", "BOOLEAN", "BOTH", "BREADTH", "BREAK", "BROWSE", "BULK", "BY", "C", "CACHE", "CALL", "CALLED", "CARDINALITY", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG", "CATALOG_NAME", "CEIL", "CEILING", "CHAIN", "CHANGE", "CHAR", "CHAR_LENGTH", "CHARACTER", "CHARACTER_LENGTH", "CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME", "CHARACTER_SET_SCHEMA", "CHARACTERISTICS", "CHARACTERS", "CHECK", "CHECKED", "CHECKPOINT", "CHECKSUM", "CLASS", "CLASS_ORIGIN", "CLOB", "C
 LOSE", "CLUSTER", "CLUSTERED", "COALESCE", "COBOL", "COLLATE", "COLLATION", "COLLATION_CATALOG", "COLLATION_NAME", "COLLATION_SCHEMA", "COLLECT", "COLUMN", "COLUMN_NAME", "COLUMNS", "COMMAND_FUNCTION", "COMMAND_FUNCTION_CODE", "COMMENT", "COMMIT", "COMMITTED", "COMPLETION", "COMPRESS", "COMPUTE", "CONDITION", "CONDITION_NUMBER", "CONNECT", "CONNECTION", "CONNECTION_NAME", "CONSTRAINT", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONSTRAINTS", "CONSTRUCTOR", "CONTAINS", "CONTAINSTABLE", "CONTINUE", "CONVERSION", "CONVERT", "COPY", "CORR", "CORRESPONDING", "COUNT", "COVAR_POP", "COVAR_SAMP", "CREATE", "CREATEDB", "CREATEROLE", "CREATEUSER", "CROSS", "CSV", "CUBE", "CUME_DIST", "CURRENT", "CURRENT_DATE", "CURRENT_DEFAULT_TRANSFORM_GROUP", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_TRANSFORM_GROUP_FOR_TYPE", "CURRENT_USER", "CURSOR", "CURSOR_NAME", "CYCLE", "DATA", "DATABASE", "DATABASES", "DATE", "DATETIME", "DATETIME_INTERV
 AL_CODE", "DATETIME_INTERVAL_PRECISION", "DAY", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "DAYOFMONTH", "DAYOFWEEK", "DAYOFYEAR", "DBCC", "DEALLOCATE", "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFAULTS", "DEFERRABLE", "DEFERRED", "DEFINED", "DEFINER", "DEGREE", "DELAY_KEY_WRITE", "DELAYED", "DELETE", "DELIMITER", "DELIMITERS", "DENSE_RANK", "DENY", "DEPTH", "DEREF", "DERIVED", "DESC", "DESCRIBE", "DESCRIPTOR", "DESTROY", "DESTRUCTOR", "DETERMINISTIC", "DIAGNOSTICS", "DICTIONARY", "DISABLE", "DISCONNECT", "DISK", "DISPATCH", "DISTINCT", "DISTINCTROW", "DISTRIBUTED", "DIV", "DO", "DOMAIN", "DOUBLE", "DROP", "DUAL", "DUMMY", "DUMP", "DYNAMIC", "DYNAMIC_FUNCTION", "DYNAMIC_FUNCTION_CODE", "EACH", "ELEMENT", "ELSE", "ELSEIF", "ENABLE", "ENCLOSED", "ENCODING", "ENCRYPTED", "END", "END-EXEC", "ENUM", "EQUALS", "ERRLVL", "ESCAPE", "ESCAPED", "EVERY", "EXCEPT", "EXCEPTION", "EXCLUDE", "EXCLUDING", "EXCLUSIVE", "EXEC", "EXECUTE", "EXISTING", "EXISTS", "EXIT", "EXP", "
 EXPLAIN", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FIELDS", "FILE", "FILLFACTOR", "FILTER", "FINAL", "FIRST", "FLOAT", "FLOAT4", "FLOAT8", "FLOOR", "FLUSH", "FOLLOWING", "FOR", "FORCE", "FOREIGN", "FORTRAN", "FORWARD", "FOUND", "FREE", "FREETEXT", "FREETEXTTABLE", "FREEZE", "FROM", "FULL", "FULLTEXT", "FUNCTION", "FUSION", "G", "GENERAL", "GENERATED", "GET", "GLOBAL", "GO", "GOTO", "GRANT", "GRANTED", "GRANTS", "GREATEST", "GROUP", "GROUPING", "HANDLER", "HAVING", "HEADER", "HEAP", "HIERARCHY", "HIGH_PRIORITY", "HOLD", "HOLDLOCK", "HOST", "HOSTS", "HOUR", "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", "IDENTITY", "IDENTITY_INSERT", "IDENTITYCOL", "IF", "IGNORE", "ILIKE", "IMMEDIATE", "IMMUTABLE", "IMPLEMENTATION", "IMPLICIT", "IN", "INCLUDE", "INCLUDING", "INCREMENT", "INDEX", "INDICATOR", "INFILE", "INFIX", "INHERIT", "INHERITS", "INITIAL", "INITIALIZE", "INITIALLY", "INNER", "INOUT", "INPUT", "INSENSITIVE", "INSERT", "INSERT_ID", "INSTANCE", "INSTANTIABLE
 ", "INSTEAD", "INT", "INT1", "INT2", "INT3", "INT4", "INT8", "INTEGER", "INTERSECT", "INTERSECTION", "INTERVAL", "INTO", "INVOKER", "IS", "ISAM", "ISNULL", "ISOLATION", "ITERATE", "JOIN", "K", "KEY", "KEY_MEMBER", "KEY_TYPE", "KEYS", "KILL", "LANCOMPILER", "LANGUAGE", "LARGE", "LAST", "LAST_INSERT_ID", "LATERAL", "LEADING", "LEAST", "LEAVE", "LEFT", "LENGTH", "LESS", "LEVEL", "LIKE", "LIMIT", "LINENO", "LINES", "LISTEN", "LN", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATION", "LOCATOR", "LOCK", "LOGIN", "LOGS", "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", "LOWER", "M", "MAP", "MATCH", "MATCHED", "MAX", "MAX_ROWS", "MAXEXTENTS", "MAXVALUE", "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT", "MEMBER", "MERGE", "MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT", "METHOD", "MIDDLEINT", "MIN", "MIN_ROWS", "MINUS", "MINUTE", "MINUTE_MICROSECOND", "MINUTE_SECOND", "MINVALUE", "MLSLABEL", "MOD", "MODE", "MODIFIES", "MODIFY", "MODULE", "MONTH", "MONTHNAME", "MORE", "
 MOVE", "MULTISET", "MUMPS", "MYISAM", "NAME", "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NESTING", "NEW", "NEXT", "NO", "NO_WRITE_TO_BINLOG", "NOAUDIT", "NOCHECK", "NOCOMPRESS", "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NONCLUSTERED", "NONE", "NORMALIZE", "NORMALIZED", "NOSUPERUSER", "NOT", "NOTHING", "NOTIFY", "NOTNULL", "NOWAIT", "NULL", "NULLABLE", "NULLIF", "NULLS", "NUMBER", "NUMERIC", "OBJECT", "OCTET_LENGTH", "OCTETS", "OF", "OFF", "OFFLINE", "OFFSET", "OFFSETS", "OIDS", "OLD", "ON", "ONLINE", "ONLY", "OPEN", "OPENDATASOURCE", "OPENQUERY", "OPENROWSET", "OPENXML", "OPERATION", "OPERATOR", "OPTIMIZE", "OPTION", "OPTIONALLY", "OPTIONS", "OR", "ORDER", "ORDERING", "ORDINALITY", "OTHERS", "OUT", "OUTER", "OUTFILE", "OUTPUT", "OVER", "OVERLAPS", "OVERLAY", "OVERRIDING", "OWNER", "PACK_KEYS", "PAD", "PARAMETER", "PARAMETER_MODE", "PARAMETER_NAME", "PARAMETER_ORDINAL_POSITION", "PARAMETER_SPECIFIC_CATALOG", "PARAMETER_SPECIFIC_NAME", "PAR
 AMETER_SPECIFIC_SCHEMA", "PARAMETERS", "PARTIAL", "PARTITION", "PASCAL", "PASSWORD", "PATH", "PCTFREE", "PERCENT", "PERCENT_RANK", "PERCENTILE_CONT", "PERCENTILE_DISC", "PLACING", "PLAN", "PLI", "POSITION", "POSTFIX", "POWER", "PRECEDING", "PRECISION", "PREFIX", "PREORDER", "PREPARE", "PREPARED", "PRESERVE", "PRIMARY", "PRINT", "PRIOR", "PRIVILEGES", "PROC", "PROCEDURAL", "PROCEDURE", "PROCESS", "PROCESSLIST", "PUBLIC", "PURGE", "QUOTE", "RAID0", "RAISERROR", "RANGE", "RANK", "RAW", "READ", "READS", "READTEXT", "REAL", "RECHECK", "RECONFIGURE", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "REGEXP", "REGR_AVGX", "REGR_AVGY", "REGR_COUNT", "REGR_INTERCEPT", "REGR_R2", "REGR_SLOPE", "REGR_SXX", "REGR_SXY", "REGR_SYY", "REINDEX", "RELATIVE", "RELEASE", "RELOAD", "RENAME", "REPEAT", "REPEATABLE", "REPLACE", "REPLICATION", "REQUIRE", "RESET", "RESIGNAL", "RESOURCE", "RESTART", "RESTORE", "RESTRICT", "RESULT", "RETURN", "RETURNED_CARDINALITY", "RETURNED_LENGTH", "RETURNED_OCTET
 _LENGTH", "RETURNED_SQLSTATE", "RETURNS", "REVOKE", "RIGHT", "RLIKE", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROUTINE_CATALOG", "ROUTINE_NAME", "ROUTINE_SCHEMA", "ROW", "ROW_COUNT", "ROW_NUMBER", "ROWCOUNT", "ROWGUIDCOL", "ROWID", "ROWNUM", "ROWS", "RULE", "SAVE", "SAVEPOINT", "SCALE", "SCHEMA", "SCHEMA_NAME", "SCHEMAS", "SCOPE", "SCOPE_CATALOG", "SCOPE_NAME", "SCOPE_SCHEMA", "SCROLL", "SEARCH", "SECOND", "SECOND_MICROSECOND", "SECTION", "SECURITY", "SELECT", "SELF", "SENSITIVE", "SEPARATOR", "SEQUENCE", "SERIALIZABLE", "SERVER_NAME", "SESSION", "SESSION_USER", "SET", "SETOF", "SETS", "SETUSER", "SHARE", "SHOW", "SHUTDOWN", "SIGNAL", "SIMILAR", "SIMPLE", "SIZE", "SMALLINT", "SOME", "SONAME", "SOURCE", "SPACE", "SPATIAL", "SPECIFIC", "SPECIFIC_NAME", "SPECIFICTYPE", "SQL", "SQL_BIG_RESULT", "SQL_BIG_SELECTS", "SQL_BIG_TABLES", "SQL_CALC_FOUND_ROWS", "SQL_LOG_OFF", "SQL_LOG_UPDATE", "SQL_LOW_PRIORITY_UPDATES", "SQL_SELECT_LIMIT", "SQL_SMALL_RESULT", "SQL_WARNINGS", "SQLCA", 
 "SQLCODE", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "SQRT", "SSL", "STABLE", "START", "STARTING", "STATE", "STATEMENT", "STATIC", "STATISTICS", "STATUS", "STDDEV_POP", "STDDEV_SAMP", "STDIN", "STDOUT", "STORAGE", "STRAIGHT_JOIN", "STRICT", "STRING", "STRUCTURE", "STYLE", "SUBCLASS_ORIGIN", "SUBLIST", "SUBMULTISET", "SUBSTRING", "SUCCESSFUL", "SUM", "SUPERUSER", "SYMMETRIC", "SYNONYM", "SYSDATE", "SYSID", "SYSTEM", "SYSTEM_USER", "TABLE", "TABLE_NAME", "TABLES", "TABLESAMPLE", "TABLESPACE", "TEMP", "TEMPLATE", "TEMPORARY", "TERMINATE", "TERMINATED", "TEXT", "TEXTSIZE", "THAN", "THEN", "TIES", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TINYBLOB", "TINYINT", "TINYTEXT", "TO", "TOAST", "TOP", "TOP_LEVEL_COUNT", "TRAILING", "TRAN", "TRANSACTION", "TRANSACTION_ACTIVE", "TRANSACTIONS_COMMITTED", "TRANSACTIONS_ROLLED_BACK", "TRANSFORM", "TRANSFORMS", "TRANSLATE", "TRANSLATION", "TREAT", "TRIGGER", "TRIGGER_CATALOG", "TRIGGER_NAME", "TRIGGER_SCHEMA", "TRIM
 ", "TRUE", "TRUNCATE", "TRUSTED", "TSEQUAL", "TYPE", "UESCAPE", "UID", "UNBOUNDED", "UNCOMMITTED", "UNDER", "UNDO", "UNENCRYPTED", "UNION", "UNIQUE", "UNKNOWN", "UNLISTEN", "UNLOCK", "UNNAMED", "UNNEST", "UNSIGNED", "UNTIL", "UPDATE", "UPDATETEXT", "UPPER", "USAGE", "USE", "USER", "USER_DEFINED_TYPE_CATALOG", "USER_DEFINED_TYPE_CODE", "USER_DEFINED_TYPE_NAME", "USER_DEFINED_TYPE_SCHEMA", "USING", "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", "VACUUM", "VALID", "VALIDATE", "VALIDATOR", "VALUE", "VALUES", "VAR_POP", "VAR_SAMP", "VARBINARY", "VARCHAR", "VARCHAR2", "VARCHARACTER", "VARIABLE", "VARIABLES", "VARYING", "VERBOSE", "VIEW", "VOLATILE", "WAITFOR", "WHEN", "WHENEVER", "WHERE", "WHILE", "WIDTH_BUCKET", "WINDOW", "WITH", "WITHIN", "WITHOUT", "WORK", "WRITE", "WRITETEXT", "X509", "XOR", "YEAR", "YEAR_MONTH", "ZEROFILL", "ZONE"];
+	var keywords = ["A", "ABORT", "ABS", "ABSOLUTE", "ACCESS", "ACTION", "ADA", "ADD", "ADMIN", "AFTER", "AGGREGATE", "ALIAS", "ALL", "ALLOCATE", "ALSO", "ALTER", "ALWAYS", "ANALYSE", "ANALYZE", "AND", "ANY", "ARE", "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATOMIC", "ATTRIBUTE", "ATTRIBUTES", "AUDIT", "AUTHORIZATION", "AUTO_INCREMENT", "AVG", "AVG_ROW_LENGTH", "BACKUP", "BACKWARD", "BEFORE", "BEGIN", "BERNOULLI", "BETWEEN", "BIGINT", "BINARY", "BIT", "BIT_LENGTH", "BITVAR", "BLOB", "BOOL", "BOOLEAN", "BOTH", "BREADTH", "BREAK", "BROWSE", "BULK", "BY", "C", "CACHE", "CALL", "CALLED", "CARDINALITY", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG", "CATALOG_NAME", "CEIL", "CEILING", "CHAIN", "CHANGE", "CHAR", "CHAR_LENGTH", "CHARACTER", "CHARACTER_LENGTH", "CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME", "CHARACTER_SET_SCHEMA", "CHARACTERISTICS", "CHARACTERS", "CHECK", "CHECKED", "CHECKPOINT", "CHECKSUM", "CLASS", "CLASS_ORIGIN", "CLOB", "C
 LOSE", "CLUSTER", "CLUSTERED", "COALESCE", "COBOL", "COLLATE", "COLLATION", "COLLATION_CATALOG", "COLLATION_NAME", "COLLATION_SCHEMA", "COLLECT", "COLUMN", "COLUMN_NAME", "COLUMNS", "COMMAND_FUNCTION", "COMMAND_FUNCTION_CODE", "COMMENT", "COMMIT", "COMMITTED", "COMPLETION", "COMPRESS", "COMPUTE", "CONDITION", "CONDITION_NUMBER", "CONNECT", "CONNECTION", "CONNECTION_NAME", "CONSTRAINT", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONSTRAINTS", "CONSTRUCTOR", "CONTAINS", "CONTAINSTABLE", "CONTINUE", "CONVERSION", "CONVERT", "COPY", "CORR", "CORRESPONDING", "COUNT", "COVAR_POP", "COVAR_SAMP", "CREATE", "CREATEDB", "CREATEROLE", "CREATEUSER", "CROSS", "CSV", "CUBE", "CUME_DIST", "CURRENT", "CURRENT_DATE", "CURRENT_DEFAULT_TRANSFORM_GROUP", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_TRANSFORM_GROUP_FOR_TYPE", "CURRENT_USER", "CURSOR", "CURSOR_NAME", "CYCLE", "DATA", "DATABASE", "DATABASES", "DATE", "DATETIME", "DATETIME_INTERV
 AL_CODE", "DATETIME_INTERVAL_PRECISION", "DAY", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "DAYOFMONTH", "DAYOFWEEK", "DAYOFYEAR", "DBCC", "DEALLOCATE", "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFAULTS", "DEFERRABLE", "DEFERRED", "DEFINED", "DEFINER", "DEGREE", "DELAY_KEY_WRITE", "DELAYED", "DELETE", "DELIMITER", "DELIMITERS", "DENSE_RANK", "DENY", "DEPTH", "DEREF", "DERIVED", "DESC", "DESCRIBE", "DESCRIPTOR", "DESTROY", "DESTRUCTOR", "DETERMINISTIC", "DIAGNOSTICS", "DICTIONARY", "DISABLE", "DISCONNECT", "DISK", "DISPATCH", "DISTINCT", "DISTINCTROW", "DISTRIBUTED", "DIV", "DO", "DOMAIN", "DOUBLE", "DROP", "DUAL", "DUMMY", "DUMP", "DYNAMIC", "DYNAMIC_FUNCTION", "DYNAMIC_FUNCTION_CODE", "EACH", "ELEMENT", "ELSE", "ELSEIF", "ENABLE", "ENCLOSED", "ENCODING", "ENCRYPTED", "END", "END-EXEC", "ENUM", "EQUALS", "ERRLVL", "ESCAPE", "ESCAPED", "EVERY", "EXCEPT", "EXCEPTION", "EXCLUDE", "EXCLUDING", "EXCLUSIVE", "EXEC", "EXECUTE", "EXISTING", "EXISTS", "EXIT", "EXP", "
 EXPLAIN", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FIELDS", "FILE", "FILLFACTOR", "FILTER", "FINAL", "FIRST", "FLOAT", "FLOAT4", "FLOAT8", "FLOOR", "FLUSH", "FOLLOWING", "FOR", "FORCE", "FOREIGN", "FORTRAN", "FORWARD", "FOUND", "FREE", "FREETEXT", "FREETEXTTABLE", "FREEZE", "FROM", "FULL", "FULLTEXT", "FUNCTION", "FUSION", "G", "GENERAL", "GENERATED", "GET", "GLOBAL", "GO", "GOTO", "GRANT", "GRANTED", "GRANTS", "GREATEST", "GROUP", "GROUPING", "HANDLER", "HAVING", "HEADER", "HEAP", "HIERARCHY", "HIGH_PRIORITY", "HOLD", "HOLDLOCK", "HOST", "HOSTS", "HOUR", "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", "IDENTITY", "IDENTITY_INSERT", "IDENTITYCOL", "IF", "IGNORE", "ILIKE", "IMMEDIATE", "IMMUTABLE", "IMPLEMENTATION", "IMPLICIT", "IN", "INCLUDE", "INCLUDING", "INCREMENT", "INDEX", "INDICATOR", "INFILE", "INFIX", "INHERIT", "INHERITS", "INITIAL", "INITIALIZE", "INITIALLY", "INNER", "INOUT", "INPUT", "INSENSITIVE", "INSERT", "INSERT_ID", "INSTANCE", "INSTANTIABLE
 ", "INSTEAD", "INT", "INT1", "INT2", "INT3", "INT4", "INT8", "INTEGER", "INTERSECT", "INTERSECTION", "INTERVAL", "INTO", "INVOKER", "IS", "ISAM", "ISNULL", "ISOLATION", "ITERATE", "JOIN", "K", "KEY", "KEY_MEMBER", "KEY_TYPE", "KEYS", "KILL", "LANCOMPILER", "LANGUAGE", "LARGE", "LAST", "LAST_INSERT_ID", "LATERAL", "LEADING", "LEAST", "LEAVE", "LEFT", "LENGTH", "LESS", "LEVEL", "LIKE", "LIMIT", "LINENO", "LINES", "LISTEN", "LN", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATION", "LOCATOR", "LOCK", "LOGIN", "LOGS", "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", "LOWER", "M", "MAP", "MATCH", "MATCHED", "MAX", "MAX_ROWS", "MAXEXTENTS", "MAXVALUE", "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT", "MEMBER", "MERGE", "MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT", "METHOD", "MIDDLEINT", "MIN", "MIN_ROWS", "MINUS", "MINUTE", "MINUTE_MICROSECOND", "MINUTE_SECOND", "MINVALUE", "MLSLABEL", "MOD", "MODE", "MODIFIES", "MODIFY", "MODULE", "MONTH", "MONTHNAME", "MORE", "
 MOVE", "MULTISET", "MUMPS", "MYISAM", "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NESTING", "NEW", "NEXT", "NO", "NO_WRITE_TO_BINLOG", "NOAUDIT", "NOCHECK", "NOCOMPRESS", "NOCREATEDB", "NOCREATEROLE", "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NONCLUSTERED", "NONE", "NORMALIZE", "NORMALIZED", "NOSUPERUSER", "NOT", "NOTHING", "NOTIFY", "NOTNULL", "NOWAIT", "NULL", "NULLABLE", "NULLIF", "NULLS", "NUMBER", "NUMERIC", "OBJECT", "OCTET_LENGTH", "OCTETS", "OF", "OFF", "OFFLINE", "OFFSET", "OFFSETS", "OIDS", "OLD", "ON", "ONLINE", "ONLY", "OPEN", "OPENDATASOURCE", "OPENQUERY", "OPENROWSET", "OPENXML", "OPERATION", "OPERATOR", "OPTIMIZE", "OPTION", "OPTIONALLY", "OPTIONS", "OR", "ORDER", "ORDERING", "ORDINALITY", "OTHERS", "OUT", "OUTER", "OUTFILE", "OUTPUT", "OVER", "OVERLAPS", "OVERLAY", "OVERRIDING", "OWNER", "PACK_KEYS", "PAD", "PARAMETER", "PARAMETER_MODE", "PARAMETER_NAME", "PARAMETER_ORDINAL_POSITION", "PARAMETER_SPECIFIC_CATALOG", "PARAMETER_SPECIFIC_NAME", "PARAMETER_S
 PECIFIC_SCHEMA", "PARAMETERS", "PARTIAL", "PARTITION", "PASCAL", "PASSWORD", "PATH", "PCTFREE", "PERCENT", "PERCENT_RANK", "PERCENTILE_CONT", "PERCENTILE_DISC", "PLACING", "PLAN", "PLI", "POSITION", "POSTFIX", "POWER", "PRECEDING", "PRECISION", "PREFIX", "PREORDER", "PREPARE", "PREPARED", "PRESERVE", "PRIMARY", "PRINT", "PRIOR", "PRIVILEGES", "PROC", "PROCEDURAL", "PROCEDURE", "PROCESS", "PROCESSLIST", "PUBLIC", "PURGE", "QUOTE", "RAID0", "RAISERROR", "RANGE", "RANK", "RAW", "READ", "READS", "READTEXT", "REAL", "RECHECK", "RECONFIGURE", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "REGEXP", "REGR_AVGX", "REGR_AVGY", "REGR_COUNT", "REGR_INTERCEPT", "REGR_R2", "REGR_SLOPE", "REGR_SXX", "REGR_SXY", "REGR_SYY", "REINDEX", "RELATIVE", "RELEASE", "RELOAD", "RENAME", "REPEAT", "REPEATABLE", "REPLACE", "REPLICATION", "REQUIRE", "RESET", "RESIGNAL", "RESOURCE", "RESTART", "RESTORE", "RESTRICT", "RESULT", "RETURN", "RETURNED_CARDINALITY", "RETURNED_LENGTH", "RETURNED_OCTET_LENGTH"
 , "RETURNED_SQLSTATE", "RETURNS", "REVOKE", "RIGHT", "RLIKE", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROUTINE_CATALOG", "ROUTINE_NAME", "ROUTINE_SCHEMA", "ROW", "ROW_COUNT", "ROW_NUMBER", "ROWCOUNT", "ROWGUIDCOL", "ROWID", "ROWNUM", "ROWS", "RULE", "SAVE", "SAVEPOINT", "SCALE", "SCHEMA", "SCHEMA_NAME", "SCHEMAS", "SCOPE", "SCOPE_CATALOG", "SCOPE_NAME", "SCOPE_SCHEMA", "SCROLL", "SEARCH", "SECOND", "SECOND_MICROSECOND", "SECTION", "SECURITY", "SELECT", "SELF", "SENSITIVE", "SEPARATOR", "SEQUENCE", "SERIALIZABLE", "SERVER_NAME", "SESSION", "SESSION_USER", "SET", "SETOF", "SETS", "SETUSER", "SHARE", "SHOW", "SHUTDOWN", "SIGNAL", "SIMILAR", "SIMPLE", "SIZE", "SMALLINT", "SOME", "SONAME", "SOURCE", "SPACE", "SPATIAL", "SPECIFIC", "SPECIFIC_NAME", "SPECIFICTYPE", "SQL", "SQL_BIG_RESULT", "SQL_BIG_SELECTS", "SQL_BIG_TABLES", "SQL_CALC_FOUND_ROWS", "SQL_LOG_OFF", "SQL_LOG_UPDATE", "SQL_LOW_PRIORITY_UPDATES", "SQL_SELECT_LIMIT", "SQL_SMALL_RESULT", "SQL_WARNINGS", "SQLCA", "SQLCODE
 ", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "SQRT", "SSL", "STABLE", "START", "STARTING", "STATE", "STATEMENT", "STATIC", "STATISTICS", "STATUS", "STDDEV_POP", "STDDEV_SAMP", "STDIN", "STDOUT", "STORAGE", "STRAIGHT_JOIN", "STRICT", "STRING", "STRUCTURE", "STYLE", "SUBCLASS_ORIGIN", "SUBLIST", "SUBMULTISET", "SUBSTRING", "SUCCESSFUL", "SUM", "SUPERUSER", "SYMMETRIC", "SYNONYM", "SYSDATE", "SYSID", "SYSTEM", "SYSTEM_USER", "TABLE", "TABLE_NAME", "TABLES", "TABLESAMPLE", "TABLESPACE", "TEMP", "TEMPLATE", "TEMPORARY", "TERMINATE", "TERMINATED", "TEXT", "TEXTSIZE", "THAN", "THEN", "TIES", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TINYBLOB", "TINYINT", "TINYTEXT", "TO", "TOAST", "TOP", "TOP_LEVEL_COUNT", "TRAILING", "TRAN", "TRANSACTION", "TRANSACTION_ACTIVE", "TRANSACTIONS_COMMITTED", "TRANSACTIONS_ROLLED_BACK", "TRANSFORM", "TRANSFORMS", "TRANSLATE", "TRANSLATION", "TREAT", "TRIGGER", "TRIGGER_CATALOG", "TRIGGER_NAME", "TRIGGER_SCHEMA", "TRIM", "TRUE
 ", "TRUNCATE", "TRUSTED", "TSEQUAL", "TYPE", "UESCAPE", "UID", "UNBOUNDED", "UNCOMMITTED", "UNDER", "UNDO", "UNENCRYPTED", "UNION", "UNIQUE", "UNKNOWN", "UNLISTEN", "UNLOCK", "UNNAMED", "UNNEST", "UNSIGNED", "UNTIL", "UPDATE", "UPDATETEXT", "UPPER", "USAGE", "USE", "USER", "USER_DEFINED_TYPE_CATALOG", "USER_DEFINED_TYPE_CODE", "USER_DEFINED_TYPE_NAME", "USER_DEFINED_TYPE_SCHEMA", "USING", "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", "VACUUM", "VALID", "VALIDATE", "VALIDATOR", "VALUE", "VALUES", "VAR_POP", "VAR_SAMP", "VARBINARY", "VARCHAR", "VARCHAR2", "VARCHARACTER", "VARIABLE", "VARIABLES", "VARYING", "VERBOSE", "VIEW", "VOLATILE", "WAITFOR", "WHEN", "WHENEVER", "WHERE", "WHILE", "WIDTH_BUCKET", "WINDOW", "WITH", "WITHIN", "WITHOUT", "WORK", "WRITE", "WRITETEXT", "X509", "XOR", "YEAR", "YEAR_MONTH", "ZEROFILL", "ZONE"];
 	
 	var operators = ["=", "!=", "<", ">", "<=", ">=", "+", "-", "*", "/", "%"];
 	
@@ -17,6 +17,15 @@ Syntax.register('sql', function(brush) {
 	
 	brush.push(keywords, {klass: 'keyword', options: 'gi'});
 	
+	// Strings
+	brush.push(Syntax.lib.singleQuotedString);
+	brush.push(Syntax.lib.doubleQuotedString);
+	brush.push(Syntax.lib.stringEscape);
+	
+	// Numbers
+	brush.push(Syntax.lib.decimalNumber);
+	brush.push(Syntax.lib.hexNumber);
+	
 	brush.push(Syntax.lib.webLink);
 });
 
diff --git a/js/jquery.syntax.brush.xml.js b/js/jquery.syntax.brush.xml.js
new file mode 100644
index 0000000..69a4b47
--- /dev/null
+++ b/js/jquery.syntax.brush.xml.js
@@ -0,0 +1,52 @@
+// brush: "xml" aliases: []
+
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
+//	See <jquery.syntax.js> for licensing details.
+
+Syntax.register('xml', function(brush) {
+	brush.push({
+		pattern: /(<!(\[CDATA\[)([\s\S]*?)(\]\])>)/gm,
+		matches: Syntax.extractMatches(
+			{klass: 'cdata', allow: ['cdata-content', 'cdata-tag']},
+			{klass: 'cdata-tag'},
+			{klass: 'cdata-content'},
+			{klass: 'cdata-tag'}
+		)
+	});
+	
+	brush.push(Syntax.lib.xmlComment);
+	
+	// /[\s\S]/ means match anything... /./ doesn't match newlines
+	brush.push({
+		pattern: /<[^>]+>/g,
+		klass: 'tag',
+		allow: '*'
+	});
+	
+	brush.push({
+		pattern: /<\/?((?:[^:\s>]+:)?)([^\s>]+)(\s[^>]*)?\/?>/g,
+		matches: Syntax.extractMatches({klass: 'namespace'}, {klass: 'tag-name'})
+	});
+	
+	brush.push({
+		pattern: /([^=\s]+)=(".*?"|'.*?'|[^\s>]+)/g,
+		matches: Syntax.extractMatches({klass: 'attribute', only: ['tag']}, {klass: 'string', only: ['tag']})
+	});
+	
+	brush.push({
+		pattern: /&\w+;/g,
+		klass: 'entity'
+	});
+	
+	brush.push({
+		pattern: /(%[0-9a-f]{2})/gi,
+		klass: 'percent-escape',
+		only: ['string']
+	});
+	
+	brush.push(Syntax.lib.singleQuotedString);
+	brush.push(Syntax.lib.doubleQuotedString);
+	
+	brush.push(Syntax.lib.webLink);
+});
diff --git a/js/jquery.syntax.brush.yaml.js b/js/jquery.syntax.brush.yaml.js
index fbc439d..9920770 100644
--- a/js/jquery.syntax.brush.yaml.js
+++ b/js/jquery.syntax.brush.yaml.js
@@ -1,16 +1,14 @@
 // brush: "yaml" aliases: []
 
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 Syntax.register('yaml', function(brush) {
 	brush.push({
-		pattern: /^\s*(#.*)$/gm,
-		matches: Syntax.extractMatches({
-			klass: 'comment',
-			allow: ['href']
-		})
+		pattern: /^\s*#.*$/gm,
+		klass: 'comment',
+		allow: ['href']
 	});
 	
 	brush.push(Syntax.lib.singleQuotedString);
diff --git a/js/jquery.syntax.core.js b/js/jquery.syntax.core.js
index 25415c9..4cbd9c9 100644
--- a/js/jquery.syntax.core.js
+++ b/js/jquery.syntax.core.js
@@ -1,5 +1,5 @@
-//	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-//	Copyright 2010 Samuel Williams. All rights reserved.
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 //	See <jquery.syntax.js> for licensing details.
 
 if (!RegExp.prototype.indexOf) {
@@ -53,7 +53,41 @@ Syntax.getCDATA = function (elems) {
 	return cdata.replace(/\r\n?/g, "\n");
 }
 
-Syntax.layouts.plain = function (options, html, container) {
+// Convert to stack based implementation
+Syntax.extractElementMatches = function (elems, offset, tabWidth) {
+	var matches = [], current = [elems];
+	offset = offset || 0;
+	tabWidth = tabWidth || 4;
+	
+	(function (elems) {
+		for (var i = 0; elems[i]; i++) {
+			var text = null, elem = elems[i];
+			
+			if (elem.nodeType === 3 || elem.nodeType === 4) {
+				offset += elem.nodeValue.length;
+			
+			} else if (elem.nodeType === 1) {
+				var text = Syntax.getCDATA(elem.childNodes);
+				var expr = {klass: elem.className, force: true, element: elem};
+				
+				matches.push(new Syntax.Match(offset, text.length, expr, text));
+			}
+			
+			// Traverse everything, except comment nodes
+			if (elem.nodeType !== 8) {
+				arguments.callee(elem.childNodes, offset);
+			}
+		}
+	})(elems);
+	
+	// Remove the top level element, since this will be recreated based on the supplied configuration.
+	// Maybe there is a better way to achieve this?
+	matches.shift();
+	
+	return matches;
+}
+
+Syntax.layouts.preformatted = function (options, html, container) {
 	return html;
 };
 
@@ -62,7 +96,8 @@ Syntax.modeLineOptions = {
 };
 
 Syntax.convertTabsToSpaces = function (text, tabSize) {
-	var space = [], pattern = /\r|\n|\t/g, tabOffset = 0;
+	var space = [], pattern = /\r|\n|\t/g, tabOffset = 0, offsets = [], totalOffset = 0;
+	tabSize = tabSize || 4
 	
 	for (var i = ""; i.length <= tabSize; i = i + " ") {
 		space.push(i);
@@ -76,11 +111,58 @@ Syntax.convertTabsToSpaces = function (text, tabSize) {
 		} else {
 			var width = tabSize - ((tabOffset + offset) % tabSize);
 			tabOffset += width - 1;
+			
+			// Any match after this offset has been shifted right by totalOffset
+			totalOffset += width - 1
+			offsets.push([offset, width, totalOffset]);
+			
 			return space[width];
 		}
 	});
 	
-	return text;
+	return {text: text, offsets: offsets};
+};
+
+Syntax.convertToLinearOffsets = function (offsets, length) {
+	var current = 0, changes = [];
+	
+	// Anything with offset after offset[current][0] but smaller than offset[current+1][0]
+	// has been shifted right by offset[current][2]
+	for (var i = 0; i < length; i++) {
+		if (offsets[current] && i > offsets[current][0]) {
+			if (offsets[current+1] && i <= offsets[current+1][0]) {
+				changes.push(offsets[current][2]);
+			} else {
+				current += 1;
+				i -= 1;
+			}
+		} else {
+			changes.push(changes[changes.length-1] || 0);
+		}
+	}
+	
+	return changes;
+}
+
+Syntax.updateMatchesWithOffsets = function (matches, linearOffsets, text) {
+	(function (matches) {
+		for (var i = 0; i < matches.length; i++) {
+			var match = matches[i];
+			
+			// Calculate the new start and end points
+			var offset = match.offset + linearOffsets[match.offset];
+			var end = match.offset + match.length;
+			end += linearOffsets[end];
+			
+			// Start, Length, Text
+			match.adjust(linearOffsets[match.offset], end - offset, text);
+			
+			if (match.children.length > 0)
+				arguments.callee(match.children);
+		}
+	})(matches);
+	
+	return matches;
 };
 
 Syntax.extractMatches = function() {
@@ -90,17 +172,19 @@ Syntax.extractMatches = function() {
 		var matches = [];
 		
 		for (var i = 0; i < rules.length; i += 1) {
-			var rule = rules[i];
+			var rule = rules[i], index = i+1;
 			
 			if (rule == null) {
 				continue;
 			}
 			
-			if (rule.debug) {
-				alert("'" + match[1] + "' : " + match[1].charCodeAt(0));
+			if (typeof(rule.index) != 'undefined') {
+				index = rule.index;
 			}
 			
-			var index = rule.index || (i+1);
+			if (rule.debug) {
+				Syntax.log("extractMatches", rule, index, match[index], match);
+			}
 			
 			if (match[index].length > 0) {
 				if (rule.brush) {
@@ -123,7 +207,10 @@ Syntax.lib.webLinkProcess = function (queryURI, lucky) {
 	}
 	
 	return function (element, match) {
-		return jQuery('<a>').attr('href', queryURI + encodeURIComponent(element.text())).append(element);
+		return jQuery('<a>').
+			attr('href', queryURI + encodeURIComponent(element.text())).
+			attr('class', element.attr('class')).
+			append(element.contents());
 	};
 };
 
@@ -138,14 +225,16 @@ Syntax.lib.cStyleComment = {pattern: /\/\*[\s\S]*?\*\//gm, klass: 'comment', all
 Syntax.lib.cppStyleComment = {pattern: /\/\/.*$/gm, klass: 'comment', allow: ['href']};
 Syntax.lib.perlStyleComment = {pattern: /#.*$/gm, klass: 'comment', allow: ['href']};
 
+Syntax.lib.perlStyleRegularExpressions = {pattern: /\B\/([^\/]|\\\/)*?\/[a-z]*(?=\s*[^\w\s'";\/])/g, klass: 'constant'};
+
 Syntax.lib.cStyleFunction = {pattern: /([a-z_][a-z0-9_]*)\s*\(/gi, matches: Syntax.extractMatches({klass: 'function'})};
-Syntax.lib.camelCaseType = {pattern: /\b_*[A-Z_][\w]*\b/g, klass: 'type'};
+Syntax.lib.camelCaseType = {pattern: /\b_*[A-Z][\w]*\b/g, klass: 'type'};
 
 Syntax.lib.xmlComment = {pattern: /(&lt;|<)!--[\s\S]*?--(&gt;|>)/gm, klass: 'comment'};
 Syntax.lib.webLink = {pattern: /\w+:\/\/[\w\-.\/?%&=@:;#]*/g, klass: 'href'};
 
-Syntax.lib.hexNumber = {pattern: /0x[0-9a-fA-F]+/g, klass: 'constant'};
-Syntax.lib.decimalNumber = {pattern: /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/g, klass: 'constant'};
+Syntax.lib.hexNumber = {pattern: /\b0x[0-9a-fA-F]+/g, klass: 'constant'};
+Syntax.lib.decimalNumber = {pattern: /\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/g, klass: 'constant'};
 
 Syntax.lib.doubleQuotedString = {pattern: /"([^\\"\n]|\\.)*"/g, klass: 'string'};
 Syntax.lib.singleQuotedString = {pattern: /'([^\\'\n]|\\.)*'/g, klass: 'string'};
@@ -153,11 +242,11 @@ Syntax.lib.multiLineDoubleQuotedString = {pattern: /"([^\\"]|\\.)*"/g, klass: 's
 Syntax.lib.multiLineSingleQuotedString = {pattern: /'([^\\']|\\.)*'/g, klass: 'string'};
 Syntax.lib.stringEscape = {pattern: /\\./g, klass: 'escape', only: ['string']};
 
-Syntax.Match = function (offset, length, expr, value) {
+Syntax.Match = function (offset, length, expression, value) {
 	this.offset = offset;
 	this.endOffset = offset + length;
 	this.length = length;
-	this.expression = expr;
+	this.expression = expression;
 	this.value = value;
 	this.children = [];
 	this.parent = null;
@@ -166,9 +255,28 @@ Syntax.Match = function (offset, length, expr, value) {
 	this.next = null;
 };
 
-Syntax.Match.prototype.shift = function (x) {
-	this.offset += x;
-	this.endOffset += x;
+// Shifts an entire tree forward or backwards.
+Syntax.Match.prototype.shift = function (offset, text) {
+	this.adjust(offset, null, text);
+	
+	for (var i = 0; i < this.children.length; i++) {
+		this.children[i].shift(offset, text)
+	}
+};
+
+// C the current match to have different offset and length.
+Syntax.Match.prototype.adjust = function (offset, length, text) {
+	this.offset += offset;
+	this.endOffset += offset;
+	
+	if (length) {
+		this.length = length;
+		this.endOffset = this.offset + length;
+	}
+	
+	if (text) {
+		this.value = text.substr(this.offset, this.length);
+	}
 };
 
 Syntax.Match.sort = function (a,b) {
@@ -203,6 +311,11 @@ Syntax.Match.prototype.reduce = function (append, process) {
 	
 	for (var i = 0; i < this.children.length; i += 1) {
 		var child = this.children[i], end = child.offset;
+		
+		if (child.offset < this.offset) {
+			Syntax.log("Syntax Warning: Offset of child", child, "is before offset of parent", this);
+		}
+		
 		var text = this.value.substr(start - this.offset, end - start);
 		
 		append(text, container);
@@ -216,7 +329,7 @@ Syntax.Match.prototype.reduce = function (append, process) {
 	} else if (start < this.endOffset) {
 		append(this.value.substr(start - this.offset, this.endOffset - start), container);
 	} else if (start > this.endOffset) {
-		alert("Syntax Warning: Start position " + start + " exceeds end of value " + this.endOffset);
+		Syntax.log("Syntax Warning: Start position " + start + " exceeds end of value " + this.endOffset);
 	}
 	
 	if (process) {
@@ -227,6 +340,12 @@ Syntax.Match.prototype.reduce = function (append, process) {
 };
 
 Syntax.Match.prototype.canContain = function (match) {
+	// This is a special conditional for explicitly added ranges by the user.
+	// Since user added it, we honour it no matter what.
+	if (match.expression.force) {
+		return true;
+	}
+	
 	// Can't add anything into complete trees.
 	if (this.complete) {
 		return false;
@@ -257,19 +376,18 @@ Syntax.Match.prototype.canContain = function (match) {
 		return true;
 	}
 	
-	// else, false.
 	return false;
 };
 
-Syntax.Match.prototype.canHaveChild = function (match) {
+Syntax.Match.prototype.canHaveChild = function(match) {
 	var only = match.expression.only;
 	
 	// This condition is fairly slow
-	if (match.expression.only) {
+	if (only) {
 		var cur = this;
 		
 		while (cur !== null) {
-			if (jQuery.inArray(cur.expression.klass, match.expression.only) !== -1) {
+			if (jQuery.inArray(cur.expression.klass, only) !== -1) {
 				return true;
 			}
 			
@@ -291,17 +409,36 @@ Syntax.Match.prototype._splice = function(i, match) {
 	if (this.canHaveChild(match)) {
 		this.children.splice(i, 0, match);
 		match.parent = this;
+		
+		// For matches added using tags.
+		if (!match.expression.owner) {
+			match.expression.owner = this.expression.owner;
+		}
+		
 		return this;
 	} else {
 		return null;
 	}
 };
 
+// This function implements a full insertion procedure, and will break up the match to fit.
+// This operation is potentially very expensive, but is used to insert custom ranges into
+// the tree, if they are specified by the user. A custom <span> may cover multiple leafs in
+// the tree, thus naturally it needs to be broken up.
+// You should avoid using this function except in very specific cases.
+Syntax.Match.prototype.insert = function(match) {
+	if (!this.contains(match))
+		return null;
+	
+	return this._insert(match);
+}
+
 // This is not a general tree insertion function. It is optimised to run in almost constant
 // time, but data must be inserted in sorted order, otherwise you will have problems.
+// This function also ensures that matches won't be broken up unless absolutely necessary.
 Syntax.Match.prototype.insertAtEnd = function (match) {
 	if (!this.contains(match)) {
-		alert("Syntax Error: Child is not contained in parent node!");
+		Syntax.log("Syntax Error: Child is not contained in parent node!");
 		return null;
 	}
 	
@@ -314,43 +451,150 @@ Syntax.Match.prototype.insertAtEnd = function (match) {
 		var child = this.children[i];
 		
 		if (match.offset < child.offset) {
-			if (match.endOffset <= child.offset) {
-				// displacement = 'before'
-				return this._splice(i, match);
+			// Displacement: Before or LHS Overlap
+			// This means that the match has actually occurred before the last child.
+			// This is a bit of an unusual situation because the matches SHOULD be in
+			// sorted order.
+			// However, we are sure that the match is contained in this node. This situation
+			// sometimes occurs when sorting existing branches with matches that are supposed
+			// to be within that branch. When we insert the match into the branch, there are
+			// matches that technically should have been inserted afterwards.
+			// Normal usage should avoid this case, and this is best for performance.
+			if (match.force) {
+				return this._insert(match);
 			} else {
-				// displacement = 'left-overlap'
 				return null;
 			}
 		} else if (match.offset < child.endOffset) {
-			if (match.endOffset <= child.endOffset) {
-				// displacement = 'contains'
+			if (match.endOffset <= child.endOffset) { 
+				// Displacement: Contains
+				//console.log("displacement => contains");
 				var result = child.insertAtEnd(match);
 				return result;
 			} else {
-				// displacement = 'right-overlap'
-				// If a match overlaps a previous one, we ignore it.
-				return null;
+				// Displacement: RHS Overlap
+				if (match.force) {
+					return this._insert(match);
+				} else {
+					return null;
+				}
 			}
 		} else {
-			// displacement = 'after'
+			// Displacement: After
 			return this._splice(i+1, match);
 		}
 		
-		// Could not find a suitable placement
+		// Could not find a suitable placement: this is probably an error.
 		return null;
 	} else {
+		// Displacement: Contains [but currently no children]
 		return this._splice(0, match);
 	}
 };
 
-Syntax.Match.prototype.halfBisect = function(offset) {
-	if (offset > this.offset && offset < this.endOffset) {
-		return this.bisectAtOffsets([offset, this.endOffset]);
-	} else {
-		return null;
+// This insertion function is relatively complex because it is required to split the match over
+// several children.
+Syntax.Match.prototype._insert = function(match) {
+	if (this.children.length == 0)
+		return this._splice(0, match);
+	
+	for (var i = 0; i < this.children.length; i += 1) {
+		var child = this.children[i];
+		
+		// If the match ends before this child, it must be before it.
+		if (match.endOffset <= child.offset)
+			return this._splice(i, match);
+		
+		// If the match starts after this child, we continue.
+		if (match.offset >= child.endOffset)
+			continue;
+		
+		// There are four possibilities... 
+		// ... with the possibility of overlapping children on the RHS.
+		//           {------child------}   {---possibly some other child---}
+		//   |----------complete overlap---------|
+		//   |--lhs overlap--|
+		//             |--contains--|
+		//                       |--rhs overlap--|
+		
+		// First, the easiest case:
+		if (child.contains(match)) {
+			return child._insert(match);
+		}
+		
+		console.log("Bisect at offsets", match, child.offset, child.endOffset);
+		var parts = match.bisectAtOffsets([child.offset, child.endOffset]);
+		console.log("parts =", parts);
+		// We now have at most three parts
+		//           {------child------}   {---possibly some other child---}
+		//   |--[0]--|-------[1]-------|--[2]--|
+		
+		// console.log("parts", parts);
+		
+		if (parts[0]) {
+			this._splice(i, parts[0])
+		}
+		
+		if (parts[1]) {
+			child.insert(parts[1])
+		}
+		
+		// Continue insertion at this level with remainder.
+		if (parts[2]) {
+			match = parts[2]
+		} else {
+			return this;
+		}
 	}
-};
+	
+	// If we got this far, the match wasn't [completely] inserted into the list of existing children, so it must be on the end.
+	this._splice(this.children.length, match);
+}
 
+// This algorithm recursively bisects the tree at a given offset, but it does this efficiently by folding multiple bisections
+// at a time.
+// Splits:            /                /                   /
+// Tree:       |-------------------------Top-------------------------|
+//             |------------A--------------------|  |------C-------|
+//                         |-------B----------|
+// Step (1):
+// Split Top into 4 parts:
+//             |------/----------------/-------------------/---------|
+// For each part, check if there are any children that cover this part.
+// If there is a child, recursively call bisect with all splits.
+// Step (1-1):
+// Split A into parts:
+//             |------/-----A----------/---------|
+// For each part, check if there are any children that cover this part.
+// If there is a child, recursively call bisect with all splits.
+// Step (1-1-1):
+// Split B into parts:
+//                         |-------B---/------|
+// No children covered by split. Return array of two parts, B1, B2.
+// Step (1-2):
+// Enumerate the results of splitting the child and merge piece-wise into own parts
+//             |------/-----A----------/---------|
+//                         |------B1---|--B2--|
+// Finished merging children, return array of three parts, A1, A2, A3
+// Step (2):
+// Enumerate the results of splitting the child and merge piece-wise into own parts.
+//             |------/----------------/-------------------/---------|
+//             |--A1--|-------A2-------|----A3---|
+//                         |------B1---|--B2--|
+// Continue by splitting next child, C.
+// Once all children have been split and merged, return all parts, T1, T2, T3, T4.
+// The new tree:
+//             |--T1--|-------T2-------|--------T3---------|---T4---|
+//             |--A1--|-------A2-------|----A3---|  |--C1--|---C2--|
+//                         |------B1---|--B2--|
+//
+// The new structure is as follows:
+//		T1 <-	A1
+//		T2 <-	A2	<- B1
+//		T3 <-	A3	<-	B2
+//		   \-	C1
+//		T4 <- C2
+//
 Syntax.Match.prototype.bisectAtOffsets = function(splits) {
 	var parts = [], start = this.offset, prev = null, children = jQuery.merge([], this.children);
 	
@@ -364,13 +608,33 @@ Syntax.Match.prototype.bisectAtOffsets = function(splits) {
 		return a-b;
 	});
 	
+	// We build a set of top level matches by looking at each split point and
+	// creating a new match from the end of the previous match to the split point.
 	for (var i = 0; i < splits.length; i += 1) {
 		var offset = splits[i];
 		
-		if (offset < this.offset || offset > this.endOffset || (offset - start) == 0) {
+		// The split offset is past the end of the match, so there are no more possible
+		// splits.
+		if (offset > this.endOffset) {
 			break;
 		}
 		
+		// We keep track of null parts if the offset is less than the start
+		// so that things align up as expected with the requested splits.
+		if (
+			offset < this.offset // If the split point is less than the start of the match.
+			|| (offset - start) == 0 // If the match would have effectively zero length.
+		) {
+			parts.push(null); // Preserve alignment with splits.
+			start = offset;
+			continue;
+		}
+		
+		// Even if the previous split was out to the left, we align up the start
+		// to be at the start of the match we are bisecting.
+		if (start < this.offset)
+			start = this.offset;
+		
 		var match = new Syntax.Match(start, offset - start, this.expression);
 		match.value = this.value.substr(start - this.offset, match.length);
 		
@@ -388,6 +652,9 @@ Syntax.Match.prototype.bisectAtOffsets = function(splits) {
 	splits.length = parts.length;
 	
 	for (var i = 0; i < parts.length; i += 1) {
+		if (parts[i] == null)
+			continue;
+		
 		var offset = splits[0];
 		
 		while (children.length > 0) {
@@ -406,6 +673,8 @@ Syntax.Match.prototype.bisectAtOffsets = function(splits) {
 				// children_parts are the bisected children which need to be merged with parts
 				// in a linear fashion
 				for (; j < children_parts.length; j += 1) {
+					if (children_parts[j] == null) continue; // Preserve alignment with splits.
+					
 					parts[i+j].children.push(children_parts[j]);
 				}
 				
@@ -420,7 +689,7 @@ Syntax.Match.prototype.bisectAtOffsets = function(splits) {
 	}
 	
 	if (children.length) {
-		alert("Syntax Error: Children nodes not consumed, " + children.length + " remaining!");
+		Syntax.log("Syntax Error: Children nodes not consumed", children.length, " remaining!");
 	}
 	
 	return parts;
@@ -433,15 +702,71 @@ Syntax.Match.prototype.split = function(pattern) {
 		splits.push(pattern.lastIndex);
 	}
 	
-	return this.bisectAtOffsets(splits);
+	var matches = this.bisectAtOffsets(splits);
+	
+	// Remove any null placeholders.
+	return jQuery.grep(matches, function(n,i){
+		return n;
+	});
 };
 
 Syntax.Brush = function () {
+	// The primary class of this brush. Must be unique.
 	this.klass = null;
+	
+	// A sequential list of rules for extracting matches.
 	this.rules = [];
+	
+	// A list of all parents that this brush derives from.
+	this.parents = [];
+	
+	// A list of processes that may be run after extracting matches.
 	this.processes = {};
 };
 
+Syntax.Brush.convertStringToTokenPattern = function (pattern, escape) {
+	var prefix = "\\b", postfix = "\\b";
+	
+	if (!pattern.match(/^\w/)) {
+		if (!pattern.match(/\w$/)) {
+			prefix = postfix = "";
+		} else {
+			prefix = "\\B";
+		}
+	} else {
+		if (!pattern.match(/\w$/)) {
+			postfix = "\\B";
+		}
+	}
+	
+	if (escape)
+		pattern = RegExp.escape(pattern)
+	
+	return prefix + pattern + postfix;
+}
+
+// Add a parent to the brush. This brush should be loaded as a dependency.
+Syntax.Brush.prototype.derives = function (name) {
+	this.parents.push(name);
+	this.rules.push({
+		apply: function(text, expr, offset) {
+			return Syntax.brushes[name].getMatches(text, offset);
+		}
+	});
+}
+
+// Return an array of all classes that the brush consists of.
+// A derivied brush is its own klass + the klass of any and all parents.
+Syntax.Brush.prototype.allKlasses = function () {
+	var klasses = [this.klass];
+	
+	for (var i = 0; i < this.parents.length; i += 1) {
+		klasses = klasses.concat(Syntax.brushes[this.parents[i]].allKlasses());
+	}
+	
+	return klasses;
+}
+
 Syntax.Brush.prototype.push = function () {
 	if (jQuery.isArray(arguments[0])) {
 		var patterns = arguments[0], rule = arguments[1];
@@ -454,21 +779,7 @@ Syntax.Brush.prototype.push = function () {
 		
 		if (typeof(rule.pattern) === 'string') {
 			rule.string = rule.pattern;
-			var prefix = "\\b", postfix = "\\b";
-			
-			if (!rule.pattern.match(/^\w/)) {
-				if (!rule.pattern.match(/\w$/)) {
-					prefix = postfix = "";
-				} else {
-					prefix = "\\B";
-				}
-			} else {
-				if (!rule.pattern.match(/\w$/)) {
-					postfix = "\\B";
-				}
-			}
-			
-			rule.pattern = new RegExp(prefix + RegExp.escape(rule.pattern) + postfix, rule.options || 'g');
+			rule.pattern = new RegExp(Syntax.Brush.convertStringToTokenPattern(rule.string, true), rule.options || 'g')
 		}
 
 		if (typeof(XRegExp) !== 'undefined') {
@@ -478,19 +789,30 @@ Syntax.Brush.prototype.push = function () {
 		if (rule.pattern && rule.pattern.global) {
 			this.rules.push(jQuery.extend({owner: this}, rule));
 		} else if (typeof(console) != "undefined") {
-			console.log("Syntax Error: Malformed rule: ", rule);
+			Syntax.log("Syntax Error: Malformed rule: ", rule);
 		}
 	}
 };
 
-Syntax.Brush.prototype.getMatchesForRule = function (text, expr, offset) {
+Syntax.Brush.prototype.getMatchesForRule = function (text, rule, offset) {
 	var matches = [], match = null;
 	
-	while((match = expr.pattern.exec(text)) !== null) {
-		if (expr.matches) {
-			matches = matches.concat(expr.matches(match, expr));
+	// Short circuit (user defined) function:
+	if (typeof rule.apply != "undefined") {
+		return rule.apply(text, rule, offset);
+	}
+	
+	// Duplicate the pattern so that the function is reentrant.
+	var pattern = new RegExp;
+	pattern.compile(rule.pattern);
+	
+	while((match = pattern.exec(text)) !== null) {
+		if (rule.matches) {
+			matches = matches.concat(rule.matches(match, rule));
+		} else if (rule.brush) {
+			matches.push(Syntax.brushes[rule.brush].buildTree(match[0], match.index));
 		} else {
-			matches.push(new Syntax.Match(match.index, match[0].length, expr, match[0]));
+			matches.push(new Syntax.Match(match.index, match[0].length, rule, match[0]));
 		}
 	}
 	
@@ -500,6 +822,10 @@ Syntax.Brush.prototype.getMatchesForRule = function (text, expr, offset) {
 		}
 	}
 	
+	if (rule.debug) {
+		Syntax.log("matches", matches);
+	}
+	
 	return matches;
 };
 
@@ -513,14 +839,15 @@ Syntax.Brush.prototype.getMatches = function(text, offset) {
 	return matches;
 };
 
-Syntax.Brush.prototype.buildTree = function(text, offset) {
+Syntax.Brush.prototype.buildTree = function(text, offset, additionalMatches) {
 	offset = offset || 0;
 	
 	// Fixes code that uses \r\n for line endings. /$/ matches both \r\n, which is a problem..
 	text = text.replace(/\r/g, "");
 	
 	var matches = this.getMatches(text, offset);
-	var top = new Syntax.Match(offset, text.length, {klass: this.klass, allow: '*', owner: this}, text);
+	
+	var top = new Syntax.Match(offset, text.length, {klass: this.allKlasses().join(" "), allow: '*', owner: this}, text);
 
 	// This sort is absolutely key to the functioning of the tree insertion algorithm.
 	matches.sort(Syntax.Match.sort);
@@ -529,13 +856,20 @@ Syntax.Brush.prototype.buildTree = function(text, offset) {
 		top.insertAtEnd(matches[i]);
 	}
 	
+	if (additionalMatches) {
+		for (var i = 0; i < additionalMatches.length; i += 1) {
+			top.insert(additionalMatches[i], true);
+		}
+	}
+	
 	top.complete = true;
 	
 	return top;
 };
 
-Syntax.Brush.prototype.process = function(text) {
-	var top = this.buildTree(text);
+// Matches is optional, and provides a set of pre-existing matches.
+Syntax.Brush.prototype.process = function(text, matches) {
+	var top = this.buildTree(text, 0, matches);
 	
 	var lines = top.split(/\n/g);
 	
@@ -568,7 +902,7 @@ Syntax.highlight = function (elements, options, callback) {
 		options = {};
 	}
 	
-	options.layout = options.layout || 'plain';
+	options.layout = options.layout || 'preformatted';
 	
 	if (typeof(options.tabWidth) === 'undefined') {
 		options.tabWidth = 4;
@@ -577,13 +911,15 @@ Syntax.highlight = function (elements, options, callback) {
 	elements.each(function () {
 		var container = jQuery(this);
 		
+		// We can augment the plain text to extract existing annotations.
+		var matches = Syntax.extractElementMatches(container);
 		var text = Syntax.getCDATA(container);
-
+		
 		var match = text.match(/-\*- mode: (.+?);(.*?)-\*-/i);
 		var endOfSecondLine = text.indexOf("\n", text.indexOf("\n") + 1);
 		
 		if (match && match.index < endOfSecondLine) {
-			options.brush = match[1];
+			options.brush = options.brush || match[1];
 			var modeline = match[2];
 			
 			var mode = /([a-z\-]+)\:(.*?)\;/gi;
@@ -598,16 +934,24 @@ Syntax.highlight = function (elements, options, callback) {
 		}
 		
 		var brushName = (options.brush || 'plain').toLowerCase();
+		
 		brushName = Syntax.aliases[brushName] || brushName;
 		
 		Syntax.brushes.get(brushName, function(brush) {
-			container.addClass('syntax');
-			
 			if (options.tabWidth) {
-				text = Syntax.convertTabsToSpaces(text, options.tabWidth);
+				// Calculate the tab expansion and offsets
+				replacement = Syntax.convertTabsToSpaces(text, options.tabWidth);
+				
+				// Update any existing matches
+				if (matches && matches.length) {
+					var linearOffsets = Syntax.convertToLinearOffsets(replacement.offsets, text.length);
+					matches = Syntax.updateMatchesWithOffsets(matches, linearOffsets, replacement.text);
+				}
+				
+				text = replacement.text;
 			}
 			
-			var html = brush.process(text);
+			var html = brush.process(text, matches);
 			
 			if (options.linkify !== false) {
 				jQuery('span.href', html).each(function(){
diff --git a/js/jquery.syntax.js b/js/jquery.syntax.js
index e5a8bf4..86d54e0 100644
--- a/js/jquery.syntax.js
+++ b/js/jquery.syntax.js
@@ -1,20 +1,26 @@
 /* 
-	This file is part of the "jQuery.Syntax" project, and is licensed under the GNU AGPLv3.
-
-	Copyright 2010 Samuel Williams. All rights reserved.
-
+	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
 	For more information, please see http://www.oriontransfer.co.nz/software/jquery-syntax
+	
+	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
 
-	This program is free software: you can redistribute it and/or modify it under the terms
-	of the GNU Affero General Public License as published by the Free Software Foundation,
-	either version 3 of the License, or (at your option) any later version.
+	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:
 
-	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-	See the GNU Affero General Public License for more details.
+	The above copyright notice and this permission notice shall be included in
+	all copies or substantial portions of the Software.
 
-	You should have received a copy of the GNU Affero General Public License along with this
-	program. If not, see <http://www.gnu.org/licenses/>.
+	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.
 */
 
 /*global Function: true, ResourceLoader: true, Syntax: true, alert: false, jQuery: true */
@@ -70,9 +76,12 @@ ResourceLoader.prototype._loaded = function (name) {
 	}
 };
 
+// This function must ensure that current cannot be completely loaded until next
+// is completely loaded.
 ResourceLoader.prototype.dependency = function (current, next) {
-	 // if it is already loaded, it isn't a dependency
-	if (this[next]) {
+	// If the resource has completely loaded, then we don't need to queue it
+	// as a dependency
+	if (this[next] && !this.loading[name]) {
 		return;
 	}
 	
@@ -83,11 +92,12 @@ ResourceLoader.prototype.dependency = function (current, next) {
 	}
 };
 
+// This function must be reentrant for the same name and different callbacks.
 ResourceLoader.prototype.get = function (name, callback) {
-	if (this[name]) {
+	if (this.loading[name]) {
+		this.loading[name].push(callback)
+	} else if (this[name]) {
 		callback(this[name]);
-	} else if (this.loading[name]) { 
-		this.loading[name].push(callback);
 	} else {
 		this.loading[name] = [callback];
 		this.loader(name, this._finish.bind(this, name));
@@ -95,12 +105,13 @@ ResourceLoader.prototype.get = function (name, callback) {
 };
 
 var Syntax = {
-	root: './', 
+	root: null, 
 	aliases: {},
 	styles: {},
 	lib: {},
 	defaultOptions: {
-		cacheScripts: true
+		cacheScripts: true,
+		cacheStyleSheets: true
 	},
 	
 	brushes: new ResourceLoader(function (name, callback) {
@@ -121,6 +132,10 @@ var Syntax = {
 		var link = jQuery('<link>');
 		jQuery("head").append(link);
 
+		if (!Syntax.defaultOptions.cacheStyleSheets) {
+			path = path + "?" + Math.random()
+		}
+		
 		link.attr({
 			rel: "stylesheet",
 			type: "text/css",
@@ -129,14 +144,28 @@ var Syntax = {
 	},
 	
 	getScript: function (path, callback) {
-		jQuery.ajax({
-			async: false,
-			type: "GET",
-			url: path,
-			success: callback,
-			dataType: "script",
-			cache: Syntax.defaultOptions.cacheScripts
-		});
+		var script = document.createElement('script');
+		
+		// Internet Exploder
+		script.onreadystatechange = function() {
+			if (this.onload && (this.readyState == 'loaded' || this.readyState == 'complete')) {
+				this.onload();
+				
+				// Ensure the function is only called once.
+				this.onload = null;
+			}
+		};
+		
+		// Every other modern browser
+		script.onload = callback;
+		script.type = "text/javascript";
+		
+		if (!Syntax.defaultOptions.cacheScripts)
+			path = path + '?' + Math.random()
+		
+		script.src = path;
+		
+		document.getElementsByTagName('head')[0].appendChild(script);
 	},
 	
 	getResource: function (prefix, name, callback) {
@@ -204,10 +233,40 @@ var Syntax = {
 		}
 		
 		return null;
+	},
+	
+	detectRoot: function () {
+		if (Syntax.root == null) {
+			// Initialize root based on current script path.
+			var scripts = jQuery('script').filter(function(){
+				return this.src.match(/jquery\.syntax/);
+			});
+
+			var first = scripts.get(0);
+
+			if (first) {
+				// Calculate the basename for the given script src.
+				var root = first.src.match(/.*\//);
+
+				if (root) {
+					Syntax.root = root[0];
+				}
+			}
+		}
+	},
+	
+	log: function() {
+		if (console && console.log) {
+			console.log.apply(console, arguments);
+		} else {
+			alert(arguments.join(" "));
+		}
 	}
 };
 
 jQuery.fn.syntax = function (options, callback) {
+	Syntax.detectRoot();
+	
 	var elements = this;
 	
 	Syntax.loader.get('core', function () {
@@ -221,6 +280,8 @@ jQuery.syntax = function (options, callback) {
 	
 	if (options.root) {
 		Syntax.root = options.root;
+	} else {
+		Syntax.detectRoot();
 	}
 	
 	options = jQuery.extend(Syntax.defaultOptions, options)
@@ -231,7 +292,9 @@ jQuery.syntax = function (options, callback) {
 	options.blockLayout = options.blockLayout || 'list';
 	options.inlineLayout = options.inlineLayout || 'inline';
 	
-	options.replace = true;
+	// Allow the user to specify callbacks without replacement.
+	if (typeof options.replace == "undefined")
+		options.replace = true;
 	
 	jQuery(options.blockSelector, context).each(function () {
 		jQuery(this).syntax(jQuery.extend({}, options, {
diff --git a/js/jquery.syntax.layout.fixed.js b/js/jquery.syntax.layout.fixed.js
new file mode 100644
index 0000000..f51c0bc
--- /dev/null
+++ b/js/jquery.syntax.layout.fixed.js
@@ -0,0 +1,70 @@
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
+//	See <jquery.syntax.js> for licensing details.
+
+// This layout doesn't work correctly in IE6, but is fine in all other tested browsers.
+Syntax.layouts.fixed = function(options, code, container) {
+	var fixed = jQuery('<div class="fixed syntax highlighted">'), line = 1, space = /^\s*$/;
+	var toolbar = jQuery('<div class="toolbar">');
+
+	var rawCode = container.clone();
+	rawCode.addClass("raw syntax highlighted");
+
+	var codeTable = document.createElement('table');
+	
+	var codeTableBody = document.createElement('tbody');
+	codeTable.appendChild(codeTableBody);
+	
+	var numbersColumn = jQuery('<div class="numbers-column">');
+	var codeColumn = jQuery('<div class="code-column">');
+	
+	// Source code
+	code.children().each(function() {
+		var lineNumber = document.createElement('div');
+		lineNumber.className = "line ln" + line
+		lineNumber.innerHTML = line;
+		numbersColumn.append(lineNumber);
+		
+		var lineCode = document.createElement('td');
+		lineCode.className = "source "  + this.className;
+		
+		if (line % 2) {
+			lineCode.className += " alt";
+		}
+		
+		if (lineCode == 1) {
+			lineNumber.className += " first"
+		}
+		
+		// Thanks to Michael for suggesting the obvious :)
+		lineCode.appendChild(this);
+		
+		var tr = document.createElement('tr');
+		tr.appendChild(lineCode);
+		codeTableBody.appendChild(tr);
+		
+		line = line + 1;
+	});
+	
+	codeColumn.append(codeTable);
+	
+	fixed.append(numbersColumn);
+	fixed.append(codeColumn);
+	
+	a = jQuery('<a href="#">View Raw Code</a>');
+	a.click(function (event) {
+		event.preventDefault();
+		
+		if (jQuery(fixed).is(':visible')) {
+			rawCode.height(jQuery(fixed).height());
+			jQuery(fixed).replaceWith(rawCode);
+		} else {
+			jQuery(rawCode).replaceWith(fixed);
+		}
+	});
+	
+	toolbar.append(a);
+	toolbar.append('<a href="http://www.oriontransfer.co.nz/software/jquery-syntax"; target="oriontransfer">?</a>');
+	
+	return jQuery('<div class="syntax-container">').append(toolbar).append(fixed);
+};
diff --git a/js/jquery.syntax.layout.inline.js b/js/jquery.syntax.layout.inline.js
new file mode 100644
index 0000000..f44c70b
--- /dev/null
+++ b/js/jquery.syntax.layout.inline.js
@@ -0,0 +1,11 @@
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
+//	See <jquery.syntax.js> for licensing details.
+
+Syntax.layouts.inline = function(options, code, container) {
+	var inline = jQuery('<code class="syntax highlighted"></code>');
+	
+	inline.append(code.children());
+	
+	return inline;
+};
diff --git a/js/jquery.syntax.layout.list.js b/js/jquery.syntax.layout.list.js
new file mode 100644
index 0000000..0dcf6d8
--- /dev/null
+++ b/js/jquery.syntax.layout.list.js
@@ -0,0 +1,54 @@
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
+//	See <jquery.syntax.js> for licensing details.
+
+Syntax.layouts.list = function(options, code, container) {
+	var listTag = options.listTag || 'ol';
+
+	var list = jQuery('<' + listTag + ' class="syntax highlighted">'), line = 1, space = /^\s*$/;
+	var toolbar = jQuery('<div class="toolbar">');
+	
+	var rawCode = container.clone();
+	rawCode.addClass("raw syntax highlighted");
+	
+	// Source code
+	code.children().each(function() {
+		var li = document.createElement('li');
+		li.className = "line ln" + line
+		
+		if (line % 2) {
+			li.className += " alt";
+		}
+		
+		if (line == 1) {
+			li.className += " first"
+		}
+		
+		var div = document.createElement('div');
+		div.className = "source "  + this.className;
+		
+		div.appendChild(this);
+		
+		li.appendChild(div);
+		list[0].appendChild(li);
+		
+		line = line + 1;
+	});
+	
+	a = jQuery('<a href="#">View Raw Code</a>');
+	a.click(function (event) {
+		event.preventDefault();
+		
+		if (jQuery(list).is(':visible')) {
+			rawCode.height(jQuery(list).height());
+			jQuery(list).replaceWith(rawCode);
+		} else {
+			jQuery(rawCode).replaceWith(list);
+		}
+	});
+	
+	toolbar.append(a);
+	toolbar.append('<a href="http://www.oriontransfer.co.nz/software/jquery-syntax"; target="oriontransfer">?</a>');
+	
+	return jQuery('<div class="syntax-container">').append(toolbar).append(list);
+};
diff --git a/js/jquery.syntax.layout.plain.js b/js/jquery.syntax.layout.plain.js
new file mode 100644
index 0000000..877590d
--- /dev/null
+++ b/js/jquery.syntax.layout.plain.js
@@ -0,0 +1,15 @@
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
+//	See <jquery.syntax.js> for licensing details.
+
+// This layout doesn't work correctly in IE6, but is fine in all other tested browsers.
+Syntax.layouts.plain = function(options, code, container) {
+	var toolbar = jQuery('<div class="toolbar">');
+	
+	var scrollContainer = jQuery('<div class="syntax plain highlighted">');
+	code.removeClass('syntax');
+	
+	scrollContainer.append(code);
+	
+	return jQuery('<div class="syntax-container">').append(toolbar).append(scrollContainer);
+};
diff --git a/js/jquery.syntax.layout.table.js b/js/jquery.syntax.layout.table.js
new file mode 100644
index 0000000..fbd656f
--- /dev/null
+++ b/js/jquery.syntax.layout.table.js
@@ -0,0 +1,58 @@
+//	This file is part of the "jQuery.Syntax" project, and is distributed under the MIT License.
+//	Copyright (c) 2011 Samuel G. D. Williams. <http://www.oriontransfer.co.nz>
+//	See <jquery.syntax.js> for licensing details.
+
+Syntax.layouts.table = function(options, code, container) {
+	var table = jQuery('<table class="syntax highlighted"></table>'), tr = null, td = null, a = null, line = 1;
+	var tbody = document.createElement('tbody');
+	var toolbar = jQuery('<div class="toolbar"></div>');
+	
+	var rawCode = container.clone();
+	rawCode.addClass("raw syntax highlighted");
+	
+	// Source code
+	code.children().each(function() {
+		tr = document.createElement('tr');
+		tr.className = "line ln" + line;
+		
+		if (line % 2) {
+			tr.className += " alt";
+		}
+		
+		td = document.createElement('td');
+		td.className = "number";
+		
+		number = document.createElement('span');
+		number.innerHTML = line;
+		td.appendChild(number);
+		tr.appendChild(td);
+		
+		td = document.createElement('td');
+		td.className = "source";
+		
+		td.appendChild(this);
+		tr.appendChild(td);
+		
+		tbody.appendChild(tr);
+		line = line + 1;
+	});
+	
+	table.append(tbody);
+	
+	a = jQuery('<a href="#">View Raw Code</a>');
+	a.click(function (event) {
+		event.preventDefault();
+		
+		if (jQuery(table).is(':visible')) {
+			rawCode.height(jQuery(table).height());
+			jQuery(table).replaceWith(rawCode);
+		} else {
+			jQuery(rawCode).replaceWith(table);
+		}
+	});
+	
+	toolbar.append(a);
+	toolbar.append('<a href="http://www.oriontransfer.co.nz/software/jquery-syntax"; target="oriontransfer">?</a>');
+	
+	return jQuery('<div class="syntax-container">').append(toolbar).append(table);
+};
diff --git a/js/syntax.html b/js/syntax.html
index a9d4384..32b3a74 100644
--- a/js/syntax.html
+++ b/js/syntax.html
@@ -13,7 +13,7 @@ p { max-width: 48em; }
 <body>
 
 <p>Yelp uses <a href="http://www.oriontransfer.co.nz/software/jquery-syntax/index.en";>jQuery.Syntax</a>
-(currently version 2.3) for syntax highlighting. jquery.Syntax has its own naming
+(currently version 3.0) for syntax highlighting. jquery.Syntax has its own naming
 conventions for syntaxes. Mallard uses MIME types. DocBook has a free-form language
 attribute. This page shows the mapping. We try to use MIME types found in the XDG
 mime types package. For DocBook, we try to be compatible with language names used



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]