5485af4df88235e9de37dd43d62c36458886ab7b
Author: gwoo
Date: 2008-10-20 04:53:51 -0700
diff --git a/app_controller.php b/app_controller.php
index 5784c9c..bfc1865 100755
--- a/app_controller.php
+++ b/app_controller.php
@@ -37,17 +37,63 @@
* @subpackage cake.app
*/
class AppController extends Controller {
-
+
+ var $components = array('Auth');
+
var $helpers = array(
'Html', 'Form', 'Javascript'
- );
-
- function appError() {
- if ($this->params['controller'] == Inflector::camelize($this->params['controller'])) {
- $this->params['controller'] = 'Wiki';
- } else if ($this->params['action'] == Inflector::camelize($this->params['action'])) {
- $this->redirect(array('controller' => 'wiki', 'action' => $this->params['action'], $this->passedArgs));
+ );
+
+ var $uses = array('Project');
+
+ function beforeFilter() {
+
+ if ($this->Project->initialize($this->params) === false && $this->here !== $this->base . '/install' && empty($this->data['Project'])) {
+ $this->redirect(array('admin' => false, 'project' => null, 'controller' => 'install'));
}
+
+ if (!empty($this->params['project']) && $this->Project->id == 1) {
+ unset($this->params['project']);
+ }
+
+ if ($this->here === $this->base . '/install' || $this->here === $this->base . '/admin/projects/add') {
+ $this->Auth->allow($this->action);
+ }
+
+ if ($this->action == 'admin_login') {
+ $this->params['action'] = $this->action = 'login';
+ }
+
+ $this->Auth->loginAction = array('admin' => false, 'controller' => 'users', 'action' => 'login');
+ $this->Auth->allow('index', 'view');
+ }
+
+ function beforeRender() {
+ if (!empty($this->params['admin'])) {
+ $this->layout = 'admin';
+ }
+
+ $this->set('CurrentUser', Set::map($this->Auth->user()));
+ }
+
+ function appError($method, $messages) {
+ pr($this->params);
+ pr($method);
+ if (($method == 'missingAction' || $method == 'missingController') && $this->here !== $this->base . '/admin/install') {
+ pr($method);
+ pr($messages);
+ //$this->redirect(array('controller' => 'wiki', 'action' => $messages[0]['url'], $this->passedArgs));
+ }
+
+ //
+ // return new ErrorHandler($method, $messages);
+ }
+
+ function redirect($url = array(), $status = null, $exit = true) {
+ if (is_array($url) && !empty($this->params['project'])) {
+ $url = array_merge(array('project' => $this->params['project']), $url);
+ }
+ parent::redirect($url, $status, $exit);
}
}
?>
\ No newline at end of file
diff --git a/app_helper.php b/app_helper.php
index ef70de1..80c12e6 100755
--- a/app_helper.php
+++ b/app_helper.php
@@ -38,5 +38,12 @@
* @subpackage cake.cake
*/
class AppHelper extends Helper {
+
+ function url($url = null, $full = false) {
+ if (is_array($url) && !empty($this->params['project'])) {
+ $url = array_merge(array('project' => $this->params['project']), $url);
+ }
+ return Router::url($url, $full);
+ }
}
?>
\ No newline at end of file
diff --git a/config/bootstrap.php b/config/bootstrap.php
index 7713ee1..f6a6e2f 100755
--- a/config/bootstrap.php
+++ b/config/bootstrap.php
@@ -43,4 +43,9 @@
*
*/
//EOF
+
+Configure::write('Content', array(
+ 'git' => APP . 'content' . DS . 'git' . DS,
+ 'svn' => APP . 'content' . DS . 'svn' . DS ,
+));
?>
\ No newline at end of file
diff --git a/config/core.php b/config/core.php
index 99f6cb0..64a1fca 100755
--- a/config/core.php
+++ b/config/core.php
@@ -66,7 +66,7 @@
* 'admin' -> admin_index() and /admin/controller/index
* 'superuser' -> superuser_index() and /superuser/controller/index
*/
- //Configure::write('Routing.admin', 'admin');
+ Configure::write('Routing.admin', 'admin');
/**
* Turn off all caching application-wide.
diff --git a/config/database.php b/config/database.php
new file mode 100644
index 0000000..0afa423
--- /dev/null
+++ b/config/database.php
@@ -0,0 +1,30 @@
+<?php
+class DATABASE_CONFIG {
+
+ var $default = array(
+ 'driver' => 'mysql',
+ 'persistent' => false,
+ 'host' => 'localhost',
+ 'port' => '',
+ 'login' => 'root',
+ 'password' => '',
+ 'database' => 'chaw',
+ 'schema' => '',
+ 'prefix' => '',
+ 'encoding' => ''
+ );
+
+ var $test = array(
+ 'driver' => 'mysql',
+ 'persistent' => false,
+ 'host' => 'localhost',
+ 'port' => '',
+ 'login' => 'root',
+ 'password' => '',
+ 'database' => 'chaw_tests',
+ 'schema' => '',
+ 'prefix' => '',
+ 'encoding' => ''
+ );
+}
+?>
\ No newline at end of file
diff --git a/config/routes.php b/config/routes.php
index 4c81945..eed11f7 100755
--- a/config/routes.php
+++ b/config/routes.php
@@ -33,20 +33,51 @@
* its action called 'display', and we pass a param to select the view file
* to use (in this case, /app/views/pages/home.thtml)...
*/
- Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
-/**
- * ...and connect the rest of 'Pages' controller's urls.
- */
+ //Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
+
+ Router::connect('/', array('controller' => 'projects', 'action' => 'index'));
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
-/**
- * Then we connect url '/test' to our test controller. This is helpfull in
- * developement.
- */
- Router::connect('/wiki/add', array('controller' => 'wiki', 'action' => 'add'));
- Router::connect('/wiki/*', array('controller' => 'wiki', 'action' => 'index'));
- Router::connect('/browser/tree/*', array('controller' => 'browser', 'action' => 'tree'));
+ Router::connect('/install', array('admin'=> true, 'controller' => 'projects', 'action' => 'add'));
- Router::connect('/browser/*', array('controller' => 'browser', 'action' => 'index'));
+ Router::connect('/commits', array('controller' => 'commits', 'action' => 'index'));
+ Router::connect('/commits/:action/*', array('controller' => 'commits', 'action' => 'index'));
+ Router::connect('/browser', array('controller' => 'browser', 'action' => 'index'));
+ Router::connect('/browser/:action/*', array('controller' => 'browser', 'action' => 'index'));
+
+ Router::connect('/tickets', array('controller' => 'tickets', 'action' => 'index'));
+ Router::connect('/tickets/:action/*', array('controller' => 'tickets', 'action' => 'index'));
+
+ Router::connect('/timeline', array('controller' => 'timeline', 'action' => 'index'));
+ Router::connect('/timeline/:action/*', array('controller' => 'timeline', 'action' => 'index'));
+
+ Router::connect('/versions', array('controller' => 'versions', 'action' => 'index'));
+ Router::connect('/versions/:action/*', array('controller' => 'versions', 'action' => 'index'));
+
+ Router::connect('/users', array('controller' => 'users', 'action' => 'index'));
+ Router::connect('/users/:action/*', array('controller' => 'users', 'action' => 'index'));
+
+ Router::connect('/wiki/edit/:id', array('controller' => 'wiki', 'action' => 'add'), array('pass' => array('id')));
+ Router::connect('/wiki/add/*', array('controller' => 'wiki', 'action' => 'add'));
+ Router::connect('/wiki/*', array('controller' => 'wiki', 'action' => 'index'));
+
+ Router::connect('/projects/:project', array('controller' => 'projects', 'action' => 'view'));
+ Router::connect('/projects/:action/*', array('controller' => 'projects', 'action' => $Action));
+
+ Router::connect('/admin/:controller', array('admin'=> true, 'controller' => 'dashboard'));
+ Router::connect('/admin/:controller/:action/*', array('admin'=> true, 'controller' => 'dashboard'));
+
+ Router::connect('/:project/admin/:controller', array('admin'=> true, 'controller' => 'dashboard'));
+ Router::connect('/:project/admin/:controller/:action/*', array('admin'=> true, 'controller' => 'dashboard'));
+
+ Router::connect('/:project/wiki/edit/:id', array('controller' => 'wiki', 'action' => 'add'), array('pass' => array('id')));
+ Router::connect('/:project/wiki/add/*', array('controller' => 'wiki', 'action' => 'add'));
+ Router::connect('/:project/wiki/*', array('controller' => 'wiki', 'action' => 'index'));
+
+ Router::connect('/:project/:controller', array('action' => 'index'), array('action' => 'index'));
+ //Router::connect('/:project/:controller/:action/:id', array(), array('action' => 'view|edit|modify|delete', 'id' => $ID, 'pass' => array('id')));
+ Router::connect('/:project/:controller/:action/*', array(), array('action' => 'index|view|add|edit|modify|delete'));
+
+
?>
\ No newline at end of file
diff --git a/config/sql/schema.php b/config/sql/schema.php
index 6dc29f4..821f085 100644
--- a/config/sql/schema.php
+++ b/config/sql/schema.php
@@ -1,8 +1,8 @@
<?php
/* SVN FILE: $Id$ */
-/* Creampuff schema generated on: 2008-09-09 13:09:31 : 1220981071*/
-class CreampuffSchema extends CakeSchema {
- var $name = 'Creampuff';
+/* Chaw schema generated on: 2008-10-11 20:10:41 : 1223783441*/
+class ChawSchema extends CakeSchema {
+ var $name = 'Chaw';
function before($event = array()) {
return true;
@@ -11,61 +11,26 @@ class CreampuffSchema extends CakeSchema {
function after($event = array()) {
}
- var $tickets = array(
- 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
- 'type_id' => array('type' => 'integer', 'null' => false, 'default' => '0'),
- 'feature_id' => array('type' => 'integer', 'null' => false, 'default' => '0'),
- 'owner' => array('type' => 'integer', 'null' => false, 'default' => '0'),
- 'reporter' => array('type' => 'integer', 'null' => false, 'default' => '0'),
- 'summary' => array('type' => 'string', 'null' => false, 'length' => 200),
- 'body' => array('type' => 'text', 'null' => true, 'default' => NULL),
- 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'status' => array('type' => 'integer', 'null' => false, 'default' => '1', 'length' => 2),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
var $comments = array(
- 'id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'key' => 'primary'),
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
'ticket_id' => array('type' => 'integer', 'null' => false, 'default' => '0'),
'body' => array('type' => 'text', 'null' => true, 'default' => NULL),
'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
);
- var $configs = array(
- 'id' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'key' => 'primary'),
- 'key' => array('type' => 'string', 'null' => false, 'length' => 50),
- 'value' => array('type' => 'string', 'null' => false),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
- var $features = array(
- 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
- 'milestone_id' => array('type' => 'integer', 'null' => false, 'default' => '0'),
- 'title' => array('type' => 'string', 'null' => false, 'length' => 200),
- 'points' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 2),
- 'difficulty' => array('type' => 'integer', 'null' => true, 'default' => NULL, 'length' => 2),
- 'story' => array('type' => 'text', 'null' => true, 'default' => NULL),
- 'completed' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
- var $milestones = array(
- 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
- 'title' => array('type' => 'string', 'null' => false, 'length' => 200),
- 'due_date' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'completed' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
- );
- var $sprints = array(
+ var $projects = array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
- 'feature_id' => array('type' => 'integer', 'null' => false, 'default' => '0'),
- 'title' => array('type' => 'string', 'null' => false, 'length' => 200),
- 'completed' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
- 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'url' => array('type' => 'string', 'null' => false, 'length' => 200),
+ 'name' => array('type' => 'string', 'null' => false, 'length' => 200),
+ 'groups' => array('type' => 'string', 'null' => true, 'default' => NULL),
+ 'ticket_types' => array('type' => 'string', 'null' => true, 'default' => NULL),
+ 'ticket_statuses' => array('type' => 'string', 'null' => true, 'default' => NULL),
+ 'ticket_priorities' => array('type' => 'string', 'null' => true, 'default' => NULL),
+ 'description' => array('type' => 'text', 'null' => true, 'default' => NULL),
+ 'created' => array('type' => 'date', 'null' => true, 'default' => NULL),
+ 'modified' => array('type' => 'date', 'null' => true, 'default' => NULL),
+ 'active' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
);
var $tags = array(
@@ -81,21 +46,25 @@ class CreampuffSchema extends CakeSchema {
'ticket_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
'indexes' => array()
);
- var $tags_features = array(
- 'tag_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
- 'feature_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
- 'indexes' => array()
+ var $tickets = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'project_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
+ 'version_id' => array('type' => 'integer', 'null' => false, 'default' => '0'),
+ 'type' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 50),
+ 'status' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 50),
+ 'priority' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 50),
+ 'owner' => array('type' => 'integer', 'null' => false, 'default' => '0'),
+ 'reporter' => array('type' => 'integer', 'null' => false, 'default' => '0'),
+ 'title' => array('type' => 'string', 'null' => false, 'length' => 200),
+ 'description' => array('type' => 'text', 'null' => true, 'default' => NULL),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
);
- var $tags_tasks = array(
- 'tag_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
- 'task_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
- 'indexes' => array()
- );
- var $tasks = array(
+ var $timeline = array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
- 'sprint_id' => array('type' => 'integer', 'null' => false),
- 'title' => array('type' => 'string', 'null' => false),
- 'completed' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'project_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
+ 'summary' => array('type' => 'text', 'null' => true, 'default' => NULL),
'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
@@ -104,18 +73,28 @@ class CreampuffSchema extends CakeSchema {
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
'username' => array('type' => 'string', 'null' => false, 'length' => 40),
'password' => array('type' => 'string', 'null' => false, 'length' => 40),
- 'role' => array('type' => 'string', 'null' => false, 'default' => 'Chicken', 'length' => 100),
+ 'group_id' => array('type' => 'string', 'null' => true, 'default' => NULL, 'length' => 100),
'email' => array('type' => 'string', 'null' => false, 'length' => 200),
'last_login' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
);
+ var $versions = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'title' => array('type' => 'string', 'null' => false, 'length' => 100),
+ 'description' => array('type' => 'text', 'null' => true, 'default' => NULL),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'completed' => array('type' => 'boolean', 'null' => true, 'default' => NULL),
+ 'due' => array('type' => 'date', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
+ );
var $wiki = array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'project_id' => array('type' => 'integer', 'null' => false, 'default' => '0'),
'slug' => array('type' => 'string', 'null' => false, 'length' => 200),
- 'raw' => array('type' => 'text', 'null' => true, 'default' => NULL),
- 'transformed' => array('type' => 'text', 'null' => true, 'default' => NULL),
+ 'content' => array('type' => 'text', 'null' => true, 'default' => NULL),
'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
diff --git a/config/templates/commit_summary.ctp b/config/templates/commit_summary.ctp
new file mode 100644
index 0000000..250c7f1
--- /dev/null
+++ b/config/templates/commit_summary.ctp
@@ -0,0 +1,20 @@
+<?php if ($type == 'svn'):?>
+###Revision: [<?php echo $revision;?>]
+<?php else: ?>
+###Commit: [<?php echo $revision;?>]
+<?php endif; ?>
+
+__Author:__ <?php echo $author;?>
+
+
+__Date:__ <?php echo $commit_date;?>
+
+
+__Message:__
+```<?php echo $message;?>```
+
+<?php if (!empty($changed)):?>
+__Changes:__
+
+<?php echo $changed;?>
+<?php endif; ?>
diff --git a/config/templates/git/hooks/post-receive b/config/templates/git/hooks/post-receive
new file mode 100644
index 0000000..b6ed5c6
--- /dev/null
+++ b/config/templates/git/hooks/post-receive
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+export TERM="xterm"
+export PATH="<?php echo env('PATH'); ?>"
+
+cd <?php echo APP; ?>
+
+if [ -n "$1" ]; then
+ cake post_receive commit <?php echo $project; ?>
+
+else
+ while read oldrev newrev refname
+ do
+ cake post_receive commit <?php echo $project; ?> $refname $oldrev $newrev
+ done
+fi
diff --git a/config/templates/git/hooks/update b/config/templates/git/hooks/update
new file mode 100644
index 0000000..ad81b24
--- /dev/null
+++ b/config/templates/git/hooks/update
@@ -0,0 +1,13 @@
+#!/bin/sh
+refname="$1"
+oldrev="$2"
+newrev="$3"
+
+export TERM="xterm"
+export PATH="<?php echo env('PATH'); ?>"
+
+cd <?php echo APP; ?>
+
+cake update authorize <?php echo $project; ?> $refname $oldrev $newrev
+
+exit $?
\ No newline at end of file
diff --git a/config/templates/svn/hooks/post-commit b/config/templates/svn/hooks/post-commit
new file mode 100644
index 0000000..7cf031d
--- /dev/null
+++ b/config/templates/svn/hooks/post-commit
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+REPOS="$1"
+REV="$2"
+export TERM="xterm"
+export PATH="<?php echo env('PATH'); ?>"
+
+cd <?php echo APP; ?>
+
+cake post_commit commit <?php echo $project; ?> $REPOS $REV
\ No newline at end of file
diff --git a/config/templates/svn/hooks/pre-commit b/config/templates/svn/hooks/pre-commit
new file mode 100644
index 0000000..99fdb74
--- /dev/null
+++ b/config/templates/svn/hooks/pre-commit
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+REPOS="$1"
+TXN="$2"
+export TERM="xterm"
+export PATH="<?php echo env('PATH'); ?>"
+
+# Make sure that the log message contains some text.
+svnlook log -t "$TXN" "$REPOS" | \
+ grep "[a-zA-Z0-9]" > /dev/null || exit 1
+
+
+cd <?php echo APP; ?>
+cake pre_commit authorize <?php echo $project; ?> $REPOS $TXN
+
+# All checks passed, so allow the commit.
+exit 0
\ No newline at end of file
diff --git a/content/empty b/content/empty
new file mode 100755
index 0000000..e69de29
diff --git a/controllers/browser_controller.php b/controllers/browser_controller.php
index 301a149..048cc89 100644
--- a/controllers/browser_controller.php
+++ b/controllers/browser_controller.php
@@ -8,29 +8,30 @@ class BrowserController extends AppController {
$path = join(DS, $args);
$current = null;
-
+
if ($args > 0) {
$current = array_pop($args);
}
+ $this->Browser->config = $this->Project->config['repo'];
$data = $this->Browser->read($path);
$this->set(compact('data', 'args', 'current'));
}
-
+
function tree($branch = 'HEAD') {
$Git = ClassRegistry::init('Git');
- $Git->repo = '/htdocs/scm/creampuff.git';
+ $Git->repo = '/htdocs/scm/chaw.git';
$Git->workingCopy = TMP . 'git';
-
+
//pr($Git->tree($branch));
-
- //pr($Git->sub('cat-file', array('-t 0ed8662ea6402467a50a6e515042485227c2dd0c')));
-
+
+ pr($Git->sub('cat-file', array('-t 0ed8662ea6402467a50a6e515042485227c2dd0c')));
+
pr($Git->info($branch));
-
+
pr($Git->debug);
-
+
die();
}
}
diff --git a/controllers/commits_controller.php b/controllers/commits_controller.php
new file mode 100644
index 0000000..f15cef1
--- /dev/null
+++ b/controllers/commits_controller.php
@@ -0,0 +1,24 @@
+<?php
+class CommitsController extends AppController {
+
+ var $name = 'Commits';
+
+ var $paginate = array('order' => 'Commit.created DESC');
+
+ function index() {
+ $this->Commit->recursive = 0;
+ $conditions = null;
+
+ if (!empty($this->params['project'])) {
+ $conditions = array('Commit.project_id' => $this->Project->id);
+ }
+
+ $this->set('commits', $this->paginate('Commit', $conditions));
+ }
+
+ function view($revision = null) {
+ $commit = $this->Commit->findByRevision($revision);
+ $this->set('commit', $commit);
+ }
+}
+?>
\ No newline at end of file
diff --git a/controllers/components/empty b/controllers/components/empty
new file mode 100755
index 0000000..e69de29
diff --git a/controllers/dashboard_controller.php b/controllers/dashboard_controller.php
new file mode 100644
index 0000000..9cc060a
--- /dev/null
+++ b/controllers/dashboard_controller.php
@@ -0,0 +1,13 @@
+<?php
+class DashboardController extends AppController {
+
+ var $name = 'Dashboard';
+
+ var $uses = array();
+
+ function admin_index() {
+
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/controllers/permissions_controller.php b/controllers/permissions_controller.php
new file mode 100644
index 0000000..7980dbd
--- /dev/null
+++ b/controllers/permissions_controller.php
@@ -0,0 +1,29 @@
+<?php
+class PermissionsController extends AppController {
+
+ var $name = 'Permissions';
+
+ function admin_index() {
+ $this->admin_add();
+ $this->render('admin_add');
+ }
+
+ function admin_add() {
+ if (!empty($this->data)) {
+ $this->Permission->create(array('project_id' => $this->Project->id));
+ if ($this->Permission->save($this->data)) {
+ $this->Session->setFlash('Permissions updated');
+ } else {
+ $this->Session->setFlash('Permissions NOT updated');
+ }
+ }
+
+ $users = $this->Permission->User->find('list');
+ $groups = $this->Project->groups();
+
+ $this->data['Permission']['fine_grained'] = $this->Permission->file();
+
+ $this->set(compact('users', 'groups'));
+ }
+}
+?>
\ No newline at end of file
diff --git a/controllers/projects_controller.php b/controllers/projects_controller.php
new file mode 100644
index 0000000..8f69d3c
--- /dev/null
+++ b/controllers/projects_controller.php
@@ -0,0 +1,68 @@
+<?php
+class ProjectsController extends AppController {
+
+ var $name = 'Projects';
+
+ function index() {
+ $this->Project->recursive = 0;
+ $this->set('projects', $this->paginate());
+ }
+
+ function view($url = null) {
+ if (!empty($this->params['project'])) {
+ $url = $this->params['project'];
+ }
+ $this->set('project', $this->Project->findByUrl($url));
+ }
+
+ function admin_index() {
+ $this->Project->recursive = 0;
+ $this->set('projects', $this->paginate());
+ $this->render('index');
+ }
+
+ function admin_add() {
+
+ $this->pageTitle = 'Project Setup';
+
+ if (!empty($this->data)) {
+ $this->Project->create();
+ if ($data = $this->Project->save($this->data)) {
+ $this->Session->setFlash('Setup was stored');
+ return;
+ }
+ }
+
+ $this->data = array_merge((array)$this->data, array('Project' => $this->Project->config));
+ if (!empty($this->data['Project']['id'])) {
+ unset($this->data['Project']['id']);
+ }
+
+ $this->set('repoTypes', $this->Project->repoTypes());
+
+ $this->render('add');
+ }
+
+
+ function admin_edit($id = null) {
+
+ $this->pageTitle = 'Update Project';
+
+ if (!empty($this->data)) {
+ if ($data = $this->Project->save($this->data)) {
+ $this->Session->setFlash('Setup was stored');
+ }
+ }
+
+ if (!$id) {
+ $id = $this->Project->id;
+ }
+
+ $this->data = $this->Project->read(null, $id);
+
+ $this->set('repoTypes', $this->Project->repoTypes());
+
+ $this->render('edit');
+ }
+}
+?>
\ No newline at end of file
diff --git a/controllers/tickets_controller.php b/controllers/tickets_controller.php
new file mode 100644
index 0000000..9fc8a1a
--- /dev/null
+++ b/controllers/tickets_controller.php
@@ -0,0 +1,73 @@
+<?php
+class TicketsController extends AppController {
+
+ var $name = 'Tickets';
+
+ var $helpers = array('Time');
+
+ function index() {
+ $this->Ticket->recursive = 0;
+ $conditions = null;
+
+ if (!empty($this->params['project'])) {
+ $conditions = array('Ticket.project_id' => $this->Project->id);
+ }
+
+ $this->set('tickets', $this->paginate('Ticket', $conditions));
+ }
+
+ function view($id = null) {
+
+ $this->Ticket->contain(array('Tag', 'Comment', 'Comment.User'));
+ $ticket = $this->data = $this->Ticket->read(null, $id);
+ $this->data['Ticket']['tags'] = $this->Ticket->Tag->toString($this->data['Tag']);
+ $this->Session->write('Ticket.previous', $this->data['Ticket']);
+
+ $versions = $this->Ticket->Version->find('list');
+ $types = $this->Project->ticket('types');
+ $statuses = $this->Project->ticket('statuses');
+ $priorities = $this->Project->ticket('priorities');
+
+ $this->set(compact('ticket', 'versions', 'types', 'statuses', 'priorities'));
+ }
+
+ function add() {
+ if (!empty($this->data)) {
+ $this->Ticket->create(array(
+ 'reporter' => $this->Auth->user('id'),
+ 'project_id' => $this->Project->id,
+ 'status' => 'open'
+ ));
+
+ if ($this->Ticket->save($this->data)) {
+ $this->Session->setFlash('Ticket saved');
+ }
+ }
+
+ $versions = $this->Ticket->Version->find('list');
+ $types = $this->Project->ticket('types');
+ $priorities = $this->Project->ticket('priorities');
+
+ $this->set(compact('versions', 'types', 'priorities'));
+ }
+
+ function modify($id = null) {
+ $setPrevious = false;
+ if (!empty($this->data)) {
+ $this->Ticket->set(array(
+ 'user_id' => $this->Auth->user('id'),
+ 'project_id' => $this->Project->id,
+ 'previous' => $this->Session->read('Ticket.previous')
+ ));
+
+ if ($this->Ticket->save($this->data)) {
+ $this->Session->setFlash('Ticket saved');
+ $this->Session->delete('Ticket.previous');
+ }
+ }
+ $this->view($id);
+
+ $this->render('view');
+ }
+}
+?>
\ No newline at end of file
diff --git a/controllers/timeline_controller.php b/controllers/timeline_controller.php
new file mode 100644
index 0000000..e647841
--- /dev/null
+++ b/controllers/timeline_controller.php
@@ -0,0 +1,23 @@
+<?php
+class TimelineController extends AppController {
+
+ var $name = 'Timeline';
+
+ var $paginate = array('order' => 'Timeline.created DESC');
+
+ function index() {
+ $this->Timeline->recursive = 1;
+ $conditions = null;
+
+ if (!empty($this->params['project'])) {
+ $conditions = array('Timeline.project_id' => $this->Project->id);
+ }
+
+ $this->set('timeline', $this->paginate('Timeline', $conditions));
+ }
+
+ function sync() {
+
+ }
+}
+?>
\ No newline at end of file
diff --git a/controllers/users_controller.php b/controllers/users_controller.php
new file mode 100644
index 0000000..5204666
--- /dev/null
+++ b/controllers/users_controller.php
@@ -0,0 +1,50 @@
+<?php
+class UsersController extends AppController {
+
+ var $name = 'Users';
+
+ function beforeFilter() {
+ parent::beforeFilter();
+ $this->Auth->allow('add', 'logout');
+
+ if (!empty($this->data['User']['password'])) {
+ $this->data['User']['confirm_password'] = $this->data['User']['password'];
+ }
+ }
+
+ function login() {
+
+ }
+
+ function add() {
+ if (!empty($this->data)) {
+ $this->User->create();
+ if ($this->User->save($this->data)) {
+ $this->Session->setFlash('User added');
+ } else {
+ $this->Session->setFlash('User NOT added');
+ }
+
+ $this->data['User']['password'] = $this->data['User']['confirm_password'];
+ }
+ }
+
+ function edit() {
+ if (!empty($this->data) && $this->data['User']['id'] == $this->Auth->user('id')) {
+ if ($this->User->save($this->data)) {
+ $this->Session->setFlash('User updated');
+ } else {
+ $this->Session->setFlash('User NOT updated');
+ }
+ }
+
+ $this->data = $this->User->read(null, $this->Auth->user('id'));
+ }
+
+
+ function admin_index() {
+ $this->User->recursive = 0;
+ $this->set('users', $this->paginate());
+ }
+}
+?>
\ No newline at end of file
diff --git a/controllers/versions_controller.php b/controllers/versions_controller.php
new file mode 100644
index 0000000..cce4abd
--- /dev/null
+++ b/controllers/versions_controller.php
@@ -0,0 +1,84 @@
+<?php
+class VersionsController extends AppController {
+
+ var $name = 'Versions';
+ var $helpers = array('Html', 'Form');
+
+ function index() {
+ $this->Version->recursive = 0;
+ $this->set('versions', $this->paginate());
+ }
+
+ function view($id = null) {
+ if (!$id) {
+ $this->Session->setFlash(__('Invalid Version.', true));
+ $this->redirect(array('action'=>'index'));
+ }
+ $this->set('version', $this->Version->read(null, $id));
+
+ }
+
+ function admin_index() {
+ $this->Version->recursive = 0;
+ $this->set('versions', $this->paginate());
+
+ $this->render('index');
+ }
+
+ function admin_view($id = null) {
+ if (!$id) {
+ $this->Session->setFlash(__('Invalid Version.', true));
+ $this->redirect(array('action'=>'index'));
+ }
+ $this->set('version', $this->Version->read(null, $id));
+
+ $this->render('view');
+ }
+
+ function admin_add() {
+ $this->pageTitle = "New Version";
+
+ if (!empty($this->data)) {
+ $this->Version->create();
+ if ($this->Version->save($this->data)) {
+ $this->Session->setFlash(__('The Version has been saved', true));
+ $this->redirect(array('action'=>'index'));
+ } else {
+ $this->Session->setFlash(__('The Version could not be saved. Please, try again.', true));
+ }
+ }
+ }
+
+ function admin_edit($id = null) {
+ $this->pageTitle = "Update Version";
+
+ if (!$id && empty($this->data)) {
+ $this->Session->setFlash(__('Invalid Version', true));
+ $this->redirect(array('action'=>'index'));
+ }
+ if (!empty($this->data)) {
+ if ($this->Version->save($this->data)) {
+ $this->Session->setFlash(__('The Version has been saved', true));
+ $this->redirect(array('action'=>'index'));
+ } else {
+ $this->Session->setFlash(__('The Version could not be saved. Please, try again.', true));
+ }
+ }
+ if (empty($this->data)) {
+ $this->data = $this->Version->read(null, $id);
+ }
+ }
+
+ function admin_delete($id = null) {
+ if (!$id) {
+ $this->Session->setFlash(__('Invalid id for Version', true));
+ $this->redirect(array('action'=>'index'));
+ }
+ if ($this->Version->del($id)) {
+ $this->Session->setFlash(__('Version deleted', true));
+ $this->redirect(array('action'=>'index'));
+ }
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/controllers/wiki_controller.php b/controllers/wiki_controller.php
index de81810..c4da58d 100644
--- a/controllers/wiki_controller.php
+++ b/controllers/wiki_controller.php
@@ -3,15 +3,25 @@ class WikiController extends AppController {
var $name = 'Wiki';
- function index($slug = null) {
- if(count($this->passedArgs) > 1) {
- $slug = join('/', $this->passedArgs);
+ function index() {
+
+ $slug = $this->__slug();
+
+ if ($slug === null) {
+ $slug = 'home';
}
- $this->pageTitle = Inflector::humanize(Inflector::slug($slug));
+ $this->pageTitle = Inflector::humanize($slug);
- if ($wiki = $this->Wiki->findBySlug($slug)) {
+ $wiki = $this->Wiki->find(array(
+ 'Wiki.slug' => $slug,
+ 'Wiki.project_id' => $this->Project->id,
+ 'Wiki.active' => 1
+ ));
+
+ if (!empty($wiki)) {
$this->set('wiki', $wiki);
+ $this->render('view');
} else {
$this->data['Wiki']['slug'] = $slug;
$this->render('add');
@@ -19,16 +29,41 @@ class WikiController extends AppController {
}
function add() {
+
+ $slug = $this->__slug();
+
+ $this->pageTitle = Inflector::humanize($slug);
+
if (!empty($this->data)) {
- $this->Wiki->create();
+ $this->Wiki->create(array(
+ 'project_id' => $this->Project->id,
+ 'last_changed_by' => $this->Auth->user('id')
+ ));
if ($data = $this->Wiki->save($this->data)) {
- $this->Session->setFlash('Wiki Page created');
- $this->set('wiki', $data);
- $this->render('view');
+ $this->Session->setFlash($data['Wiki']['slug'] . ' saved');
+ $this->redirect(array('controller' => 'wiki', 'action' => 'index', $data['Wiki']['slug']));
} else {
- $this->Session->setFlash('Wiki Page broken');
+ $this->Session->setFlash($data['Wiki']['slug'] . ' NOT saved');
}
}
+
+ if (empty($this->data)) {
+
+ $this->data = $this->Wiki->find(array(
+ 'Wiki.slug' => $slug,
+ 'Wiki.project_id' => $this->Project->id,
+ 'Wiki.active' => 1
+ ));
+ }
+ }
+
+ function __slug() {
+ $slug = null;
+ if(count($this->passedArgs) >= 1) {
+ $slug = Inflector::slug(join('/', $this->passedArgs));
+ }
+
+ return $slug;
}
}
?>
\ No newline at end of file
diff --git a/docs/INSTALL.txt b/docs/INSTALL.txt
new file mode 100644
index 0000000..05a7579
--- /dev/null
+++ b/docs/INSTALL.txt
@@ -0,0 +1,29 @@
+FOR GIT
+make sure "git" is in $PATH
+http://blog.drewolson.org/2008/05/remote-git-repos-on-ubuntu-right-way.html
+http://osxdaily.com/2007/10/29/how-to-add-a-user-from-the-os-x-command-line-works-with-leopard/
+
+create the git user...
+chown -R git /path/to/content/git/repo
+mkdir .ssh
+touch .ssh/authorized_keys
+put git $PATH in ~/.bashrc
+
+
+FOR SVN
+port install subversion +mod_dav_svn
+
+<VirtualHost *:80>
+ ServerName chaw.svn
+ DocumentRoot "/Volumes/Home/htdocs/chaw/content/repo/"
+ <Directory "/Volumes/Home/htdocs/chaw/">
+ Options Indexes MultiViews
+ AllowOverride None
+ Order allow,deny
+ Allow from all
+ </Directory>
+ <Location /svn>
+ DAV svn
+ SVNParentPath /Volumes/Home/htdocs/chaw/content/repo/svn
+ </Location>
+</VirtualHost>
\ No newline at end of file
diff --git a/locale/eng/LC_MESSAGES/empty b/locale/eng/LC_MESSAGES/empty
new file mode 100755
index 0000000..e69de29
diff --git a/models/browser.php b/models/browser.php
index 39e0a17..4983440 100644
--- a/models/browser.php
+++ b/models/browser.php
@@ -1,61 +1,81 @@
<?php
-class Browser extends AppModel {
+class Browser extends Object {
- var $name = 'Browser';
-
- var $useTable = false;
-
- /* relative path to files */
- var $path = null;
+ /* path to files */
+ var $config = array('path' => null, 'type' => null, 'working' => null);
function read($path = null) {
$data = null;
- if (!class_exists('Folder')) {
- uses('Folder');
- }
-
- $Git = ClassRegistry::init('Git');
- $Git->repo = '/htdocs/scm/creampuff.git';
- $Git->workingCopy = TMP . 'git';
- if ($Git->pull('master')) {
- $this->path = $Git->workingCopy;
- }
-
- if ($this->path == null) {
+ if ($this->config['working'] == null) {
return false;
}
+ $this->config['working'] = Folder::slashTerm($this->config['working']);
+
$wwwPath = join('/', explode(DS, $path)) . '/';
- $Folder = new Folder($this->path . DS . $path);
- list($dirs, $files) = $Folder->read(true, array('.', '..', '.svn'));
+ $Folder = new Folder($this->config['working'] . $path);
+
+ list($dirs, $files) = $Folder->read(true, array('.svn'));
$dir = $file = array();
+ $path = $Folder->slashTerm($Folder->pwd());
+
+ $Repo = ClassRegistry::init($this->config['type']);
+
+ $Repo->config(array(
+ 'repo' => $this->config['path'],
+ 'working' => $this->config['working']
+ ));
+
+ if ($path === $this->config['working']) {
+ $Repo->update();
+ }
+
$count = count($dirs);
for ($i = 0; $i < $count; $i++) {
$dir[$i]['name'] = $dirs[$i];
$dir[$i]['path'] = $wwwPath . $dirs[$i];
$dir[$i]['md5'] = null;
- $dir[$i]['size'] = $this->__size($Folder->pwd() . DS . $dirs[$i]);
+ $dir[$i]['size'] = $this->__size($path . $dirs[$i]);
$dir[$i]['icon'] = '/icons/dir.gif';
-
+ $dir[$i]['info'] = $Repo->pathInfo($path . $dirs[$i]);
}
$count = count($files);
for ($i = 0; $i < $count; $i++) {
$file[$i]['name'] = $files[$i];
- $file[$i]['size'] = $this->__size($Folder->pwd() . DS . $files[$i]);
+ $file[$i]['size'] = $this->__size($path . $files[$i]);
$file[$i]['icon'] = $this->__icon($files[$i]);
$file[$i]['path'] = $wwwPath . $files[$i];
$file[$i]['md5'] = md5($Folder->pwd() . $files[$i]);
+ $file[$i]['info'] = $Repo->pathInfo($path . $files[$i]);
}
return array('Folder' => $dir, 'File' => $file);
}
- function __size($file = null, $ext = 'Byte', $size = '0') {
+ function __gitInfo($name) {
+ $Git = ClassRegistry::init('Git');
+
+ $Git->config(array(
+ 'repo' => $this->config['path'],
+ 'working' => $this->config['working']
+ ));
+
+ $path = str_replace($this->config['working'], '', $name);
+
+ return $Git->pathInfo($path);
+ }
+
+ function __svnInfo($name) {
+ $Svn = ClassRegistry::init('Svn');
+ return $Svn->pathInfo($name);
+ }
+
+ function __size($file = null, $ext = 'B', $size = '0') {
$size_ext = array('','K','M','G','T');
if (!file_exists($file)) {
diff --git a/models/comment.php b/models/comment.php
new file mode 100644
index 0000000..54f566e
--- /dev/null
+++ b/models/comment.php
@@ -0,0 +1,9 @@
+<?php
+class Comment extends AppModel {
+
+ var $name = 'Comment';
+
+ var $belongsTo = array('User');
+
+}
+?>
\ No newline at end of file
diff --git a/models/commit.php b/models/commit.php
new file mode 100644
index 0000000..2098de3
--- /dev/null
+++ b/models/commit.php
@@ -0,0 +1,56 @@
+<?php
+class Commit extends AppModel {
+
+ var $name = 'Commit';
+
+ var $belongsTo = array('User');
+
+ var $hasOne = array(
+ 'Timeline' => array(
+ 'foreignKey' => 'foreign_key',
+ 'conditions' => array('model' => 'Commit')
+ )
+ );
+
+ function beforeSave() {
+ if (!empty($this->data['Commit']['author'])) {
+ $this->data['Commit']['user_id'] = $this->User->field('id', array('username' => $this->data['Commit']['author']));
+ }
+ if (!empty($this->data['Commit']['changes'])) {
+ $this->data['Commit']['changes'] = serialize($this->data['Commit']['changes']);
+ }
+ return true;
+ }
+
+ function afterSave($created) {
+
+ if ($created) {
+
+ $timeline = array('Timeline' => array(
+ 'project_id' => $this->data['Commit']['project_id'],
+ 'model' => 'Wiki',
+ 'foreign_key' => $this->id,
+ ));
+
+ if (!empty($this->data['Commit']['revision'])) {
+
+ $changed = null;
+
+ foreach (unserialize($this->data['Commit']['changes']) as $change) {
+ $changed .= " * {$change}\n";
+ }
+ extract($this->data['Commit']);
+
+ ob_start();
+ include(CONFIGS . 'templates' . DS . 'commit_summary.ctp');
+ $timeline['Timeline']['summary'] = ob_get_clean();
+
+ }
+
+ $this->Timeline->create($timeline);
+
+ $this->Timeline->save();
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/models/git.php b/models/git.php
index 3aa7a48..6c5c0f5 100644
--- a/models/git.php
+++ b/models/git.php
@@ -1,46 +1,188 @@
<?php
-class Git extends AppModel {
+class Git extends Object {
- var $name = 'Git';
-
- var $useTable = false;
-
- var $__config = array('git' => '/opt/local/bin/git', 'tmp' => TMP, 'username' => '', 'password' => '');
+ var $__config = array('git' => 'git', 'tmp' => TMP, 'username' => '', 'password' => '');
var $debug = array();
- var $workingCopy = null;
+ var $response = array();
- var $repo = null;
+ var $working = null;
+ var $repo = null;
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function config($config = array()) {
+ $this->__config = array_merge($this->__config, $config);
- function create($project, $repo) {
+ if (!empty($this->__config['repo'])) {
+ $this->repo = $this->__config['repo'];
+ }
+ if (!empty($this->__config['working'])) {
+ $this->working = $this->__config['working'];
+ }
}
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function create($project, $options = array()) {
+ extract(array_merge($this->__config, $options));
- function pull($branch, $params = array()) {
- umask(0);
+ if ($repo === null) {
+ $repo = $this->repo;
+ }
+
+ if ($working === null) {
+ $working = $this->working;
+ }
- if (!is_dir($this->workingCopy)) {
- $this->run('clone', array_merge($params, array($this->repo, $this->workingCopy)));
+ $repo = Folder::slashTerm($repo);
+ $working = Folder::slashTerm($working);
+
+ if (!is_dir($repo)) {
+ $GitRepo = new Folder($repo, true, 0777);
+ }
+ if (!is_dir($working)) {
+ $GitWorking = new Folder($working, true, 0777);
+ }
+
+ if (!is_dir($repo . $project . '.git')) {
+ $Project = new Folder($repo . $project . '.git', true, 0777);
+ }
+
+ if (is_dir($repo . $project . '.git') && !file_exists($repo . $project . '.git' . DS . 'config')) {
+ $this->call($repo . $project . '.git', "--bare init");
}
- if (is_dir($this->workingCopy)) {
- $c = $this->debug[] = "cd {$this->workingCopy}";
- shell_exec($c);
- $this->run('checkout', array($branch));
- $this->run('pull', array_merge($params, array($this->repo, $branch)));
+ $this->config(array(
+ 'repo' => $repo . $project . '.git',
+ 'working' => $working . $project
+ ));
+
+ if (!is_dir($working . $project)) {
+ $this->pull();
+ }
+
+ if (!empty($options['remote'])) {
+ $remote = $options['remote'];
+ } else {
+ $remote = "git@git.chaw";
+ }
+
+ $this->sub("remote add origin {$remote}:{$project}.git");
+ $this->execute("cd {$this->working} && touch .gitignore");
+ $this->call($this->working, "add .");
+ $this->call($this->working, "commit", array("-m", '"Initial Project commit"'));
+ $this->sub("--bare update-server-info");
+ $this->push();
+ $this->update();
+
+ if (is_dir($this->repo) && is_dir($this->working)) {
return true;
}
+
return false;
}
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function push($branch1 = 'origin', $branch2 = 'master') {
+ return $this->call($this->working, "push", array($branch1, $branch2));
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function update($branch = 'master') {
+ return $this->call($this->working, 'pull', array($this->repo, $branch));
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function pull($branch = 'master', $params = array()) {
- function diff() {
+ if (!is_dir($this->repo)) {
+ return false;
+ }
+ if (!is_dir($this->working)) {
+ $this->run('clone', array_merge($params, array($this->repo, $this->working)));
+ chmod($this->working, 0777);
+ }
+
+ if (is_dir($this->working)) {
+ $this->call($this->working, 'checkout', array($branch));
+ $this->update($branch);
+ return $this->response;
+ }
+
+ return false;
}
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function commit($newrev) {
+ /*
+ $info = $this->info(array_pop(explode("/", $refname)), array("--pretty=format:'%H::%an::%ai::%s'", "--max-count=1"));
+
+ $revision = array_pop(explode(" ", $info[0]));
+ list($author, $commit_date, $message) = explode('::', $info[1]);
+
+ $diff = $this->sub('diff', array($oldrev, $newrev));
+
+
+ */
+ //$info = $this->sub('log', array("-p", "-1", "--pretty=format:%H::%an::%ai::%s", "--full-diff", "--unified", array_pop(explode("/", $refname))));
+
+ $info = $this->sub('show', array($newrev, "--pretty=format:%H::%an::%ai::%s"));
+
+ list($revision, $author, $commit_date, $message) = explode('::', $info[0]);
+ unset($info[0]);
+
+ $changes = array();
+
+ $diff = join("\n", $info);
+
+ $data['Git'] = compact('revision', 'author', 'commit_date', 'message', 'changes', 'diff');
+ return $data;
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function diff() {
+
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
function info($branch, $params = null) {
- $params = '%h %an %ar %s';
+ //$params = '%h %an %ar %s';
if ($params === null) {
$params = array('--header', '--max-count=1', $branch);
@@ -54,7 +196,12 @@ class Git extends AppModel {
return $out;
}
-
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
function tree($branch, $params = array()) {
if (empty($params)) {
$params = array($branch, "| sed -e 's/\t/ /g'");
@@ -84,20 +231,122 @@ class Git extends AppModel {
}
return $result;
}
+/**
+ * Creates an Git hook
+ *
+ * @param string $name values (applypatch-msg, commit-message, post-commit, post-receive, post-update, pre-applypatch, pre-commit, pre-rebase, update)
+ * @param string $data location of the repository
+ * @return void
+ *
+ **/
+ function hook($name, $data = null, $options = array()) {
+ extract(array_merge($this->__config, $options));
- function run($command, $params = array()) {
- extract($this->__config);
- $c = $this->debug[] = trim("{$git} {$command} " . join(' ', $params));
- umask(0);
- return shell_exec($c);
+ if ($repo === null) {
+ $repo = $this->repo;
+ }
+
+ $repo = Folder::slashTerm($repo);
+
+ $Hook = new File($repo . 'hooks' . DS . $name, true, 0777);
+
+ chmod($Hook->pwd(), 0777);
+
+ if (!is_string($data) || $data === null) {
+ extract($data);
+ if (file_exists(CONFIGS . 'templates' . DS . 'git' . DS . 'hooks' . DS . $name)) {
+ ob_start();
+ include(CONFIGS . 'templates' . DS . 'git' . DS . 'hooks' . DS . $name);
+ $data = ob_get_clean();
+ }
+ }
+
+ if (empty($data)) {
+ return false;
+ }
+
+ if ($Hook->append($data)) {
+ return true;
+ }
+
+ return false;
}
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function pathInfo($path = null) {
+ $info = $this->call($this->working, 'log', array("--pretty=medium", '-1', '--', $path));
+ $info = explode("\n", $info);
+
+ $result['revision'] = (!empty($info[0])) ? trim(array_shift($info), 'commit ') : null;
+
+ $result['author'] = (!empty($info[1])) ? trim(array_shift($info), "Author: ") : null;
+ $result['date'] = (!empty($info[2])) ? trim(array_shift($info), "Date: ") : null;
+ $result['message'] = (!empty($info)) ? trim(join("\n", $info)) : null;
- function sub($command, $params = array()) {
+ return $result;
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function call($path, $command, $options = array(), $return = false) {
extract($this->__config);
- $c = $this->debug[] = trim("GIT_DIR={$this->repo} {$git}-{$command} " . join(' ', $params));
+ $c = trim("cd {$path} && {$git} {$command} " . join(' ', (array)$options));
+ if ($return === true) {
+ return $c;
+ }
+ return $this->execute($c);
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function run($command, $options = array(), $return = false) {
+ extract($this->__config);
+ $c = trim("GIT_DIR={$this->repo} {$git} {$command} " . join(' ', (array)$options));
+ if ($return === true) {
+ return $c;
+ }
+ return $this->execute($c);
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function sub($command, $options = array(), $return = false) {
+ extract($this->__config);
+ $c = trim("GIT_DIR={$this->repo} {$git} {$command} " . join(' ', (array)$options));
+ if ($return === true) {
+ return $c;
+ }
umask(0);
- exec($c, $out);
- return $out;
+ exec($c, $response);
+ $this->debug[] = $c;
+ $this->response = array_merge($this->response, $response);
+ return $response;
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function execute($command) {
+ $this->debug[] = $command;
+ umask(0);
+ $response = shell_exec($command);
+ $this->response = array_merge($this->response, (array)$response);
+ return $response;
}
}
diff --git a/models/permission.php b/models/permission.php
new file mode 100644
index 0000000..faf5090
--- /dev/null
+++ b/models/permission.php
@@ -0,0 +1,143 @@
+<?php
+class Permission extends AppModel {
+
+ var $name = 'Permission';
+
+ var $belongsTo = array('User', 'Project');
+
+ var $__rules = array();
+
+ function afterSave($created) {
+ $File = $this->__getFile();
+ if (!$File->exists()) {
+ return false;
+ }
+ $File->write(trim($this->data['Permission']['fine_grained']));
+ }
+
+ function check($path, $options = array()) {
+ $defaults = array('access' => 'w', 'user' => null, 'group' => null, 'project' => null);
+ extract(array_merge($defaults, $options));
+
+ if (empty($project)) {
+ $config = Configure::read('Project');
+ $project = $config['url'];
+ }
+
+ if (!empty($this->__rules[$project])) {
+ $rules = $this->__rules[$project];
+ } else {
+ $rules = $this->toArray();
+ }
+
+ if (empty($rules)) {
+ return false;
+ }
+
+ $this->__rules[$project] = $rules;
+
+ foreach ((array)$rules as $rule => $perms) {
+ if ($rule === $path) {
+
+ $check = null;
+
+ if (isset($perms['*'])) {
+ $check = $perms['*'];
+ }
+
+ if(isset($perms['@' . $group])) {
+ $check .= $perms['@' . $group];
+ }
+
+ if (isset($perms[$user])) {
+ $check .= $perms[$user];
+ }
+
+ if ($check && strpos($check, $access) !== false) {
+ return true;
+ }
+
+ break;
+ }
+ }
+ return false;
+ }
+
+ function groups($project = null) {
+ if (empty($project)) {
+ $config = Configure::read('Project');
+ $project = $config['url'];
+ }
+
+ if (!empty($this->__rules[$project])) {
+ $rules = $this->__rules[$project];
+ } else {
+ $rules = $this->toArray();
+ }
+
+ if (empty($rules['groups'])) {
+ return false;
+ }
+
+ $result = array();
+ foreach ((array)$rules['groups'] as $group => $users) {
+ $result[]['Group'] = array(
+ 'name' => $group,
+ 'users' => array_map('trim', explode(',', $users))
+ );
+ }
+
+ return $result;
+ }
+
+ function toArray() {
+ $string = $this->file();
+ $lines = explode("\n", $string);
+
+ $result = array();
+
+ foreach ($lines as $line) {
+ $data = trim($line);
+ $first = substr($data, 0, 1);
+
+ if ($first != ';' && $data != '') {
+ if ($first == '[' && substr($data, -1, 1) == ']') {
+ $section = preg_replace('/[\[\]]/', '', $data);
+ } else {
+ $delimiter = strpos($data, '=');
+
+ if ($delimiter > 0) {
+ $key = strtolower(trim(substr($data, 0, $delimiter)));
+ $value = trim(substr($data, $delimiter + 1));
+
+ if (substr($value, 0, 1) == '"' && substr($value, -1) == '"') {
+ $value = substr($value, 1, -1);
+ }
+ $result[$section][$key] = stripcslashes($value);
+ } else {
+ if (!isset($section)) {
+ $section = '';
+ }
+ $resule[$section][strtolower($data)] = '';
+ }
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ function file() {
+ $File = $this->__getFile();
+ return $File->read();
+ }
+
+ function &__getFile() {
+ $config = Configure::read('Project');
+ $repoType = $config['repo']['type'];
+ $File = new File($config['repo']['path'] . DS . 'permissions.ini', true, 0777);
+ return $File;
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/models/project.php b/models/project.php
new file mode 100644
index 0000000..dbfe109
--- /dev/null
+++ b/models/project.php
@@ -0,0 +1,172 @@
+<?php
+class Project extends AppModel {
+
+ var $name = 'Project';
+
+ var $validate = array(
+ 'name' => array(
+ 'required' => array('rule' => 'notEmpty'),
+ 'unique' => array('rule' => 'isUnique')
+ )
+ );
+
+ var $repoTypes = array('Git', 'Svn');
+
+ var $hasMany = array('Permission');
+
+ function initialize($params) {
+
+ $duration = null;
+ if (Configure::read() > 1) {
+ $duration = '+15 seconds';
+ }
+
+ Cache::set(array('prefix' => 'config_', 'duration' => $duration));
+
+ if (!empty($params['project'])) {
+ $key = $params['project'];
+ $project = Cache::read($key);
+ if (empty($project)) {
+ $project = $this->findByUrl($params['project']);
+ if (!empty($project)) {
+ Cache::write($key, $project);
+ }
+ }
+ } else {
+ $key = Configure::read('App.dir');
+ $project = Cache::read($key);
+ if (empty($project)) {
+ $project = $this->find('first');
+ if (!empty($project)) {
+ Cache::write($key, $project);
+ }
+ }
+ }
+
+ if (empty($project)) {
+ $this->config = array(
+ 'id' => null,
+ 'name' => Inflector::humanize(Configure::read('App.dir')),
+ 'url' => null,
+ 'repo_type' => 'git',
+ 'private' => 0,
+ 'groups' => 'user, docs team, developer, admin',
+ 'ticket_types' => 'bug, enhancement',
+ 'ticket_statuses' => 'open, fixed, invalid, needmoreinfo, wontfix',
+ 'ticket_priorities' => 'low, normal, high',
+ 'active' => 1
+ );
+ Configure::write('Project', $this->config);
+ return false;
+ }
+
+ $this->config = $project['Project'];
+
+ $repoType = strtolower($this->config['repo_type']);
+ $path = Configure::read("Content.{$repoType}");
+
+ $this->config['repo'] = array(
+ 'path' => $path . 'repo' . DS . $key,
+ 'type' => $repoType,
+ 'working' => $path . 'working' . DS . $key,
+ );
+
+ if ($repoType == 'git') {
+ $this->config['repo']['path'] .= '.git';
+ }
+
+ $this->id = $this->config['id'];
+ Configure::write('Project', $this->config);
+ return true;
+ }
+
+ function beforeSave() {
+ if (!empty($this->data['Project']['name'])) {
+ $this->data['Project']['url'] = Inflector::slug(strtolower($this->data['Project']['name']));
+ }
+ return true;
+ }
+
+ function afterSave($created) {
+
+ $project = $this->data['Project']['url'];
+ $repoType = ucwords($this->data['Project']['repo_type']);
+
+ $Repo = ClassRegistry::init($repoType);
+
+ $key = strtolower($repoType);
+ $path = Configure::read("Content.{$key}");
+
+ $Repo->config(array('repo' => $path . 'repo', 'working' => $path . 'working'));
+
+ $Repo->create($project, array('remote' => 'git@thechaw.com'));
+
+ $hooks = array(
+ 'Git' => array('update', 'post-receive'),
+ 'Svn' => array('pre-commit', 'post-commit')
+ );
+
+ foreach ($hooks[$repoType] as $hook) {
+ if (!file_exists("{$Repo->repo}/hooks/{$hook}")) {
+ $Repo->hook($hook, array('project' => $this->id));
+ }
+
+ if ($hook === 'post-commit') {
+ $Repo->execute("env - {$Repo->repo}/hooks/{$hook} {$Repo->repo} 1");
+ }
+
+ if ($hook === 'post-receive') {
+ $Repo->execute("env - {$Repo->repo}/hooks/{$hook} refs/heads/master");
+ }
+ }
+
+ pr($Repo->response);
+ pr($Repo->debug);
+
+ return;
+ }
+
+ function isUnique($data, $options = array()) {
+ if (!empty($data['name'])) {
+ if ($this->findByName($data['name'])) {
+ return false;
+ }
+ return true;
+ }
+ if (!empty($data['url'])) {
+ if ($this->findByName($data['url'])) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ function ticket($key = null) {
+ switch ($key) {
+ case 'types':
+ $types = array_map('trim', explode(',', $this->config['ticket_types']));
+ return array_combine($types, $types);
+ break;
+ case 'priorities':
+ $priorities = array_map('trim', explode(',', $this->config['ticket_priorities']));
+ return array_combine($priorities, $priorities);
+ break;
+ case 'statuses':
+ $statuses = array_map('trim', explode(',', $this->config['ticket_statuses']));
+ return array_combine($statuses, $statuses);
+ break;
+ }
+ }
+
+ function groups($key = null) {
+ $Inflector = Inflector::getInstance();
+ $groups = explode(',', $this->config['groups']);
+ $groups = array_map(array($Inflector, 'slug'), $groups, array_fill(0, count($groups), '-'));
+ return array_combine($groups, $groups);
+ }
+
+ function repoTypes() {
+ return array_combine($this->repoTypes, $this->repoTypes);
+ }
+}
+?>
\ No newline at end of file
diff --git a/models/svn.php b/models/svn.php
index e5683e7..86ce907 100644
--- a/models/svn.php
+++ b/models/svn.php
@@ -1,62 +1,173 @@
<?php
class Svn extends Object {
- var $name = 'Svn';
-
- var $useTable = false;
-
- var $__config = array('svn' => '/usr/bin/svn', 'tmp' => TMP, 'username' => '', 'password' => '');
+ var $__config = array('svn' => 'svn', 'repo' => null, 'working' => null, 'username' => '', 'password' => '');
var $debug = array();
- var $workingCopy = null;
+ var $response = array();
var $repo = null;
+
+ var $working = null;
+
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function config($config = array()) {
+ $this->__config = array_merge($this->__config, $config);
+
+ if (!empty($this->__config['repo'])) {
+ $this->repo = $this->__config['repo'];
+ }
+
+ if (!empty($this->__config['working'])) {
+ $this->working = $this->__config['working'];
+ }
+ }
/**
* Create a new repo; initialize the branches, tags, trunk; checkout a working copy to TMP
*
* @param string $project name of the project
- * @param string $repo path to the new repository
- * @example $this->Svn->create('demo', TMP . 'svn/repo');
+ * @param array $options repo, working
+ * @example $this->Svn->create('demo', array('repo' => TMP . 'svn/repo', 'working' => APP . 'working'));
* @return void
*
**/
- function create($project, $repo = null) {
- extract($this->__config);
-
- if $repo === null) {
+ function create($project, $options = array()) {
+ extract(array_merge($this->__config, $options));
+
+ if ($repo === null) {
$repo = $this->repo;
}
- if (is_dir(dirname($repo))) {
- if (!is_dir($repo)) {
- $result = $this->admin('create', $repo);
- }
+ if ($working === null) {
+ $working = $this->working;
+ }
+
+ $repo = Folder::slashTerm($repo);
+ $working = Folder::slashTerm($working);
+
+ if (!is_dir($repo)) {
+ $SvnRepo = new Folder($repo, true, 0777);
+ }
+
+ if (!is_dir($repo . $project)) {
+ $this->admin('create', $repo . $project);
+ }
+
+ if (is_dir($repo . $project)) {
+
+ $this->config(array(
+ 'repo' => $repo . $project,
+ 'working' => $working . $project
+ ));
+ }
+
+ if (!is_dir($this->working . '/branches')) {
+ $file = 'file://' . $repo . $project;
+ $this->sub('import', array(CONFIGS . 'templates' . DS . 'svn' .DS . 'project', $file, '--message "Initial project import"'));
+ $this->sub('checkout', array($file, $this->working));
+ }
+
+ return !empty($this->response);
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function update($path = null) {
+ if ($path === null) {
+ $path = $this->working;
+ }
+ return $this->sub('update', array($path));
+ }
+
+/**
+ * Get the info about a directory or file
+ *
+ * @param string $path path inside of working with preceeding /
+ * @example $this->Svn->info('/branches');
+ * @return void
+ *
+ **/
+ function commit($revision) {
+ $author = $this->look('author', array('-r', $revision));
+ $commit_date = $this->look('date', array('-r', $revision));
+ $message = $this->look('log', array('-r', $revision));
+ $changed = $this->look('changed', array('-r', $revision));
+ $diff = $this->look('diff', array('-r', $revision));
- if (is_dir($repo)) {
+ /*
+ $previous = ($revision > 1) ? $revision - 1 : 1;
+ $diff = $this->sub('diff', array('-r', "{$previous}:{$revision}));
+ */
+ // Parse the date nicely
+ // FIXME: messy
+ // TODO: use a nice reg exp
+ $bits = explode(" ", $commit_date);
+ $commit_date = $bits[0] . ' ' . $bits[1];
- $this->repo = $repo;
+ // Put each file that has been changed into an array
+ $temp = array();
+ $temp = explode("\n", $changed);
+ // Make the codes more readable
+ // A => Item Added
+ // D => Item Deleted
+ // U => Item Contents Updated
+ // _U => Item Properties Updated
+ // UU => Item Contents and Properties Updated
- $this->workingCopy = $tmp . $project;
+ foreach ($temp as $tmp) {
+ if (empty($tmp)) {
+ continue;
+ }
+ $bits = explode(" ", $tmp);
+
+ $action = @$bits[0];
+ $file = $bits[sizeof($bits)-1];
- if (!is_dir($this->workingCopy . '/branches')) {
- $file = 'file://' . rtrim($repo, '/') . '/' . $project;
- $result = $this->sub('import', array($tmp . 'svn/project', $file, '--message "Initial project import"'));
- $result = $this->sub('checkout', array($file, $this->workingCopy));
- }
+ switch ($action) {
+ case 'A':
+ $action = 'Added';
+ break;
+ case 'D':
+ $action = 'Deleted';
+ break;
+ case 'U':
+ $action = 'Updated';
+ break;
+ case '_U':
+ $action = 'Updated';
+ break;
+ case 'UU':
+ $action = 'Updated';
+ break;
}
+
+ $changes[] = $action . ' ' . $file;
+
}
+
+ $data['Svn'] = compact('revision', 'author', 'commit_date', 'message', 'changes', 'diff');
+
+ return $data;
}
/**
* Get the info about a directory or file
*
- * @param string $path path inside of workingCopy with preceeding /
+ * @param string $path path inside of working with preceeding /
* @example $this->Svn->info('/branches');
* @return void
*
**/
function info($path = null) {
- return $this->sub('info', array($this->workingCopy . $path));
+ return $this->sub('info', array($this->working . $path));
}
/**
* Run svnadmin, Besides providing the ability to create Subversion repositories,
@@ -73,9 +184,8 @@ class Svn extends Object {
if (is_string($params)) {
$params = array($params);
}
- $c = $this->debug[] = trim("{$svn}admin {$command} " . join(' ', $params) . ' ' . $this->__creds());
- umask(0);
- return shell_exec($c);
+ $c = trim("{$svn}admin {$command} " . join(' ', $params) . ' ' . $this->__creds());
+ return $this->execute($c);
}
/**
* Run svnlook, is a command-line utility for examining different aspects of a Subversion repository.
@@ -92,9 +202,8 @@ class Svn extends Object {
if (is_string($params)) {
$params = array($params);
}
- $c = $this->debug[] = trim("{$svn}look {$command} " . join(' ', $params) . ' ' . $this->__creds());
- umask(0);
- return shell_exec($c);
+ $c = trim("{$svn}look {$command} {$this->repo} " . join(' ', $params) . ' ' . $this->__creds());
+ return $this->execute($c);
}
/**
* Run svn subcommands
@@ -110,9 +219,82 @@ class Svn extends Object {
if (is_string($params)) {
$params = array($params);
}
- $c = $this->debug[] = trim("{$svn} {$command} " . join(' ', $params) . ' ' . $this->__creds());
+ $c = trim("{$svn} {$command} " . join(' ', $params) . ' ' . $this->__creds());
+ return $this->execute($c);
+ }
+
+/**
+ * Creates an SVN hook
+ *
+ * @param string $name values (post-commit, post-lock, post-revprop-change, post-unlock, pre-commit, pre-lock, pre-revprop-change, pre-unlock, start-commit)
+ * @param string $data location of the repository
+ * @return void
+ *
+ **/
+ function hook($name, $data = null, $options = array()) {
+ extract(array_merge($this->__config, $options));
+
+ if ($repo === null) {
+ $repo = $this->repo;
+ }
+
+ $repo = Folder::slashTerm($repo);
+
+ $Hook = new File($repo . 'hooks' . DS . $name, true, 0777);
+
+ chmod($Hook->pwd(), 0777);
+
+ if (!is_string($data) || $data === null) {
+ extract($data);
+ if (file_exists(CONFIGS . 'templates' . DS . 'svn' . DS . 'hooks' . DS . $name)) {
+ ob_start();
+ include(CONFIGS . 'templates' . DS . 'svn' . DS . 'hooks' . DS . $name);
+ $data = ob_get_clean();
+ }
+ }
+
+ if (empty($data)) {
+ return false;
+ }
+
+ if ($Hook->append($data)) {
+ return true;
+ }
+
+ return false;
+ }
+/**
+ * undocumented function
+ *
+ * @return void
+ *
+ **/
+ function pathInfo($path) {
+ $data = $this->sub('log', array($path));
+
+ $lines = explode("\n", $data);
+ $info = (!empty($lines[3])) ? explode("|", $lines[1]) : array();
+
+ $result['revision'] = (!empty($info[0])) ? trim($info[0], 'r') : null;
+ $result['author'] = (!empty($info[1])) ? trim($info[1]) : null;
+ $result['date'] = (!empty($info[2])) ? trim($info[2]) : null;
+ $result['message'] = (!empty($lines[3])) ? trim($lines[3]) : null;
+
+ return $result;
+ }
+/**
+ * Execute any command
+ *
+ * @param string $command
+ * @return void
+ *
+ **/
+ function execute($command) {
+ $this->debug[] = $command;
umask(0);
- return shell_exec($c);
+ $response = shell_exec($command);
+ $this->response = array_merge($this->response, (array)$response);
+ return $response;
}
/**
* Get the config credentials
diff --git a/models/tag.php b/models/tag.php
new file mode 100644
index 0000000..798489b
--- /dev/null
+++ b/models/tag.php
@@ -0,0 +1,41 @@
+<?php
+class Tag extends AppModel {
+
+ var $name = 'Tag';
+
+ var $validate = array('name' => VALID_NOT_EMPTY);
+
+ var $hasAndBelongsToMany = array('Ticket');
+
+ function generate($string = null) {
+ $return = array();
+ if($string) {
+ $array = explode(',', $string);
+ foreach($array as $tag) {
+ if(!empty($tag)) {
+ $this->data[$this->alias]['name'] = trim($tag);
+ $this->data[$this->alias]['key'] = Inflector::slug($this->data[$this->alias]['name']);
+ $this->recursive = -1;
+ $existing = $this->findByKey($this->data[$this->alias]['key'], array($this->alias.'.'.$this->primaryKey));
+ if(!empty($existing)) {
+ $return[] = $existing[$this->alias][$this->primaryKey];
+ } else {
+ $this->id = null;
+ if($this->save($this->data)) {
+ $return[] = $this->id;
+ }
+ }
+ }
+ }
+ }
+
+ return $return;
+ }
+
+ function toString($data = array()) {
+ $cTag = Set::extract($data, '{n}.name');
+ return join(', ', array_reverse($cTag));
+ }
+
+}
+?>
\ No newline at end of file
diff --git a/models/ticket.php b/models/ticket.php
new file mode 100644
index 0000000..c21968c
--- /dev/null
+++ b/models/ticket.php
@@ -0,0 +1,90 @@
+<?php
+class Ticket extends AppModel {
+
+ var $name = 'Ticket';
+
+ var $actsAs = array('Containable');
+
+ var $belongsTo = array(
+ 'Version',
+ 'Owner' => array('className' => 'User', 'foreignKey' => 'Owner'),
+ 'Reporter' => array('className' => 'User', 'foreignKey' => 'reporter'),
+ );
+
+ var $hasOne = array(
+ 'Timeline' => array(
+ 'foreignKey' => 'foreign_key',
+ 'conditions' => array('model' => 'Ticket')
+ )
+ );
+
+ var $hasMany = array('Comment');
+
+ var $hasAndBelongsToMany = array('Tag');
+
+ function beforeSave() {
+ if (!empty($this->data['Ticket']['tags'])) {
+ if (empty($this->data['Ticket']['previous']) || !empty($this->data['Ticket']['previous']) && $this->data['Ticket']['tags'] != $this->data['Ticket']['previous']['tags']) {
+ $this->data['Tag']['Tag'] = $this->Ticket->Tag->generate($this->data['Ticket']['tags']);
+ }
+ }
+ return true;
+ }
+
+ function afterSave($created) {
+
+ if (!$created) {
+ $comment = $this->data['Ticket']['comment'];
+ unset($this->data['Ticket']['comment']);
+
+ $changes = array();
+ foreach((array)$this->data['Ticket']['previous'] as $field => $previous) {
+ if (in_array($field, array('id', 'created', 'modified'))) {
+ continue;
+ }
+ if (isset($this->data['Ticket'][$field]) && $previous !== $this->data['Ticket'][$field]) {
+ if ($field === 'description') {
+ $changes[] = "- __" . $field . "__ was changed\n";
+ } else {
+ $changes[] = "- __" . $field . "__ was changed to _" . $this->data['Ticket'][$field] . "_\n";
+ }
+ }
+ }
+
+ $data = array('Comment' => array(
+ 'ticket_id' => $this->id,
+ 'user_id' => $this->data['Ticket']['user_id'],
+ 'body' => join("\n", $changes) ."\n\n" . $comment
+ ));
+
+ if (!empty($data['Comment']['body'])) {
+ $this->Comment->create($data);
+ $this->Comment->save();
+ }
+ }
+
+ if (!empty($this->data['Ticket']['user_id'])) {
+ $this->Reporter->id = $this->data['Ticket']['user_id'];
+ } else {
+ $this->Reporter->id = $this->data['Ticket']['reporter'];
+ }
+
+ $username = $this->Reporter->field('username');
+
+ $summary = "###Ticket: #" . $this->id
+ . "\n\n__Author:__ " . $username
+ . "\n\n__Date:__ " . $this->data['Ticket']['modified'];
+
+ $timeline = array('Timeline' => array(
+ 'project_id' => $this->data['Ticket']['project_id'],
+ 'model' => 'Ticket',
+ 'foreign_key' => $this->id,
+ 'summary' => $summary,
+ ));
+
+ $this->Timeline->create($timeline);
+
+ $this->Timeline->save();
+ }
+}
+?>
\ No newline at end of file
diff --git a/models/timeline.php b/models/timeline.php
new file mode 100644
index 0000000..9d878e6
--- /dev/null
+++ b/models/timeline.php
@@ -0,0 +1,23 @@
+<?php
+class Timeline extends AppModel {
+
+ var $name = 'Timeline';
+
+ var $useTable = 'timeline';
+
+ var $belongsTo = array(
+ 'Commit' => array(
+ 'foreignKey' => 'foreign_key',
+ 'conditions' => array('Timeline.model' => 'Commit')
+ ),
+ 'Ticket' => array(
+ 'foreignKey' => 'foreign_key',
+ 'conditions' => array('Timeline.model' => 'Ticket')
+ ),
+ 'Wiki' => array(
+ 'foreignKey' => 'foreign_key',
+ 'conditions' => array('Timeline.model' => 'Wiki')
+ )
+ );
+}
+?>
\ No newline at end of file
diff --git a/models/user.php b/models/user.php
new file mode 100644
index 0000000..348e9b2
--- /dev/null
+++ b/models/user.php
@@ -0,0 +1,32 @@
+<?php
+class User extends AppModel {
+
+ var $name = 'User';
+
+ var $displayField = 'username';
+
+ var $validate = array();
+
+ var $hasMany = array('Permission');
+
+ function permit() {
+ if (!empty($this->data['User']['group'])) {
+ $data = array('Permission' => array(
+ 'user_id' => $this->id,
+ 'project_id' => $this->data['User']['project_id'],
+ 'group' => $this->data['User']['group']
+ ));
+ $this->Permission->save($data);
+ }
+ }
+
+ function afterSave($created) {
+ if (!empty($this->data['User']['ssh_key'])) {
+ $path = Configure::read('Content.git') . 'repo' . DS . '.ssh' . DS . 'authorized_keys';
+ $File = new File($path);
+ $data = trim($this->data['User']['ssh_key']) . "\n";
+ $File->append($data);
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/models/version.php b/models/version.php
new file mode 100644
index 0000000..e893d61
--- /dev/null
+++ b/models/version.php
@@ -0,0 +1,7 @@
+<?php
+class Version extends AppModel {
+
+ var $name = 'Version';
+
+}
+?>
\ No newline at end of file
diff --git a/models/wiki.php b/models/wiki.php
index 41ec9cc..e26defc 100644
--- a/models/wiki.php
+++ b/models/wiki.php
@@ -2,19 +2,59 @@
class Wiki extends AppModel {
var $name = 'Wiki';
-
+
var $useTable = 'wiki';
-
-
+
var $validate = array('content' => array('notEmpty'));
-
-
- function beforeSave() {
- ini_set('include_path', APP . 'vendors' . DS . 'Pear' . PATH_SEPARATOR . ini_get('include_path'));
- App::import('Vendor', 'Text_Wiki_Creole', array('file' => 'Text/Wiki/Creole.php'));
- $TextWiki = new Text_Wiki_Creole();
- $this->data['Wiki']['content'] = $TextWiki->transform($this->data['Wiki']['content'], 'Xhtml');
+
+ var $belongsTo = array(
+ 'User' => array(
+ 'foreignKey' => 'last_changed_by'
+ )
+ );
+
+ var $hasOne = array(
+ 'Timeline' => array(
+ 'foreignKey' => 'foreign_key',
+ 'conditions' => array('model' => 'Wiki')
+ )
+ );
+
+ function beforeSave(){
+ if (!empty($this->data['Wiki']['title'])) {
+ $this->data['Wiki']['slug'] = Inflector::slug($this->data['Wiki']['title']);
+ }
+ $this->recursive = -1;
+ $this->updateAll(array('Wiki.active' => 0), array(
+ 'Wiki.slug' => $this->data['Wiki']['slug'],
+ 'Wiki.project_id' => $this->data['Wiki']['project_id']
+ ));
+
+ $this->data['Wiki']['active'] = 1;
+
return true;
}
+
+ function afterSave($created) {
+
+ $this->User->id = $this->data['Wiki']['last_changed_by'];
+ $username = $this->User->field('username');
+
+ $summary = "###Wiki: [wiki:" . $this->data['Wiki']['slug'] . "]"
+ . "\n\n__Author:__ " . $username
+ . "\n\n__Date:__ " . $this->data['Wiki']['created'];
+
+ $timeline = array('Timeline' => array(
+ 'project_id' => $this->data['Wiki']['project_id'],
+ 'model' => 'Wiki',
+ 'foreign_key' => $this->id,
+ 'summary' => $summary,
+ ));
+
+ $this->Timeline->create($timeline);
+
+ $this->Timeline->save();
+ }
+
}
?>
\ No newline at end of file
diff --git a/plugins/empty b/plugins/empty
new file mode 100755
index 0000000..e69de29
diff --git a/tests/cases/controllers/dashboard_controller.test.php b/tests/cases/controllers/dashboard_controller.test.php
new file mode 100644
index 0000000..f579cfa
--- /dev/null
+++ b/tests/cases/controllers/dashboard_controller.test.php
@@ -0,0 +1,26 @@
+<?php
+/* SVN FILE: $Id$ */
+/* DashboardController Test cases generated on: 2008-10-16 12:10:35 : 1224184475*/
+App::import('Controller', 'Dashboard');
+
+class TestDashboard extends DashboardController {
+ var $autoRender = false;
+}
+
+class DashboardControllerTest extends CakeTestCase {
+ var $Dashboard = null;
+
+ function setUp() {
+ $this->Dashboard = new TestDashboard();
+ $this->Dashboard->constructClasses();
+ }
+
+ function testDashboardControllerInstance() {
+ $this->assertTrue(is_a($this->Dashboard, 'DashboardController'));
+ }
+
+ function tearDown() {
+ unset($this->Dashboard);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/controllers/permissions_controller.test.php b/tests/cases/controllers/permissions_controller.test.php
new file mode 100644
index 0000000..a5a0fb4
--- /dev/null
+++ b/tests/cases/controllers/permissions_controller.test.php
@@ -0,0 +1,26 @@
+<?php
+/* SVN FILE: $Id$ */
+/* PermissionsController Test cases generated on: 2008-10-16 15:10:08 : 1224196628*/
+App::import('Controller', 'Permissions');
+
+class TestPermissions extends PermissionsController {
+ var $autoRender = false;
+}
+
+class PermissionsControllerTest extends CakeTestCase {
+ var $Permissions = null;
+
+ function setUp() {
+ $this->Permissions = new TestPermissions();
+ $this->Permissions->constructClasses();
+ }
+
+ function testPermissionsControllerInstance() {
+ $this->assertTrue(is_a($this->Permissions, 'PermissionsController'));
+ }
+
+ function tearDown() {
+ unset($this->Permissions);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/controllers/projects_controller.test.php b/tests/cases/controllers/projects_controller.test.php
new file mode 100644
index 0000000..8fa231e
--- /dev/null
+++ b/tests/cases/controllers/projects_controller.test.php
@@ -0,0 +1,26 @@
+<?php
+/* SVN FILE: $Id$ */
+/* ProjectsController Test cases generated on: 2008-10-06 15:10:26 : 1223321246*/
+App::import('Controller', 'Projects');
+
+class TestProjects extends ProjectsController {
+ var $autoRender = false;
+}
+
+class ProjectsControllerTest extends CakeTestCase {
+ var $Projects = null;
+
+ function setUp() {
+ $this->Projects = new TestProjects();
+ $this->Projects->constructClasses();
+ }
+
+ function testProjectsControllerInstance() {
+ $this->assertTrue(is_a($this->Projects, 'ProjectsController'));
+ }
+
+ function tearDown() {
+ unset($this->Projects);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/controllers/tickets_controller.test.php b/tests/cases/controllers/tickets_controller.test.php
new file mode 100644
index 0000000..0c26ece
--- /dev/null
+++ b/tests/cases/controllers/tickets_controller.test.php
@@ -0,0 +1,26 @@
+<?php
+/* SVN FILE: $Id$ */
+/* TicketsController Test cases generated on: 2008-09-23 07:09:01 : 1222170901*/
+App::import('Controller', 'Tickets');
+
+class TestTickets extends TicketsController {
+ var $autoRender = false;
+}
+
+class TicketsControllerTest extends CakeTestCase {
+ var $Tickets = null;
+
+ function setUp() {
+ $this->Tickets = new TestTickets();
+ $this->Tickets->constructClasses();
+ }
+
+ function testTicketsControllerInstance() {
+ $this->assertTrue(is_a($this->Tickets, 'TicketsController'));
+ }
+
+ function tearDown() {
+ unset($this->Tickets);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/controllers/timeline_controller.test.php b/tests/cases/controllers/timeline_controller.test.php
new file mode 100644
index 0000000..b222027
--- /dev/null
+++ b/tests/cases/controllers/timeline_controller.test.php
@@ -0,0 +1,26 @@
+<?php
+/* SVN FILE: $Id$ */
+/* TimelineController Test cases generated on: 2008-10-06 15:10:08 : 1223321528*/
+App::import('Controller', 'Timeline');
+
+class TestTimeline extends TimelineController {
+ var $autoRender = false;
+}
+
+class TimelineControllerTest extends CakeTestCase {
+ var $Timeline = null;
+
+ function setUp() {
+ $this->Timeline = new TestTimeline();
+ $this->Timeline->constructClasses();
+ }
+
+ function testTimelineControllerInstance() {
+ $this->assertTrue(is_a($this->Timeline, 'TimelineController'));
+ }
+
+ function tearDown() {
+ unset($this->Timeline);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/controllers/users_controller.test.php b/tests/cases/controllers/users_controller.test.php
new file mode 100644
index 0000000..3a7f00a
--- /dev/null
+++ b/tests/cases/controllers/users_controller.test.php
@@ -0,0 +1,26 @@
+<?php
+/* SVN FILE: $Id$ */
+/* UsersController Test cases generated on: 2008-10-16 10:10:31 : 1224177031*/
+App::import('Controller', 'Users');
+
+class TestUsers extends UsersController {
+ var $autoRender = false;
+}
+
+class UsersControllerTest extends CakeTestCase {
+ var $Users = null;
+
+ function setUp() {
+ $this->Users = new TestUsers();
+ $this->Users->constructClasses();
+ }
+
+ function testUsersControllerInstance() {
+ $this->assertTrue(is_a($this->Users, 'UsersController'));
+ }
+
+ function tearDown() {
+ unset($this->Users);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/controllers/versions_controller.test.php b/tests/cases/controllers/versions_controller.test.php
new file mode 100644
index 0000000..b72aa37
--- /dev/null
+++ b/tests/cases/controllers/versions_controller.test.php
@@ -0,0 +1,26 @@
+<?php
+/* SVN FILE: $Id$ */
+/* VersionsController Test cases generated on: 2008-10-17 09:10:22 : 1224259342*/
+App::import('Controller', 'Versions');
+
+class TestVersions extends VersionsController {
+ var $autoRender = false;
+}
+
+class VersionsControllerTest extends CakeTestCase {
+ var $Versions = null;
+
+ function setUp() {
+ $this->Versions = new TestVersions();
+ $this->Versions->constructClasses();
+ }
+
+ function testVersionsControllerInstance() {
+ $this->assertTrue(is_a($this->Versions, 'VersionsController'));
+ }
+
+ function tearDown() {
+ unset($this->Versions);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/models/comment.test.php b/tests/cases/models/comment.test.php
new file mode 100644
index 0000000..639efef
--- /dev/null
+++ b/tests/cases/models/comment.test.php
@@ -0,0 +1,45 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Comment Test cases generated on: 2008-10-16 22:10:35 : 1224221135*/
+App::import('Model', 'Comment');
+
+class CommentTestCase extends CakeTestCase {
+ var $Comment = null;
+ var $fixtures = array('app.comment');
+
+ function start() {
+ parent::start();
+ $this->Comment =& ClassRegistry::init('Comment');
+ }
+
+ function testCommentInstance() {
+ $this->assertTrue(is_a($this->Comment, 'Comment'));
+ }
+
+ function testCommentFind() {
+ $this->Comment->recursive = -1;
+ $results = $this->Comment->find('first');
+ $this->assertTrue(!empty($results));
+
+ $expected = array('Comment' => array(
+ 'id' => 1,
+ 'ticket_id' => 1,
+ 'body' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida,
+ phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam,
+ vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit,
+ feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.
+ Orci aliquet, in lorem et velit maecenas luctus, wisi nulla at, mauris nam ut a, lorem et et elit eu.
+ Sed dui facilisi, adipiscing mollis lacus congue integer, faucibus consectetuer eros amet sit sit,
+ magna dolor posuere. Placeat et, ac occaecat rutrum ante ut fusce. Sit velit sit porttitor non enim purus,
+ id semper consectetuer justo enim, nulla etiam quis justo condimentum vel, malesuada ligula arcu. Nisl neque,
+ ligula cras suscipit nunc eget, et tellus in varius urna odio est. Fuga urna dis metus euismod laoreet orci,
+ litora luctus suspendisse sed id luctus ut. Pede volutpat quam vitae, ut ornare wisi. Velit dis tincidunt,
+ pede vel eleifend nec curabitur dui pellentesque, volutpat taciti aliquet vivamus viverra, eget tellus ut
+ feugiat lacinia mauris sed, lacinia et felis.',
+ 'created' => '2008-10-16 22:25:35',
+ 'modified' => '2008-10-16 22:25:35'
+ ));
+ $this->assertEqual($results, $expected);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/models/commit.test.php b/tests/cases/models/commit.test.php
new file mode 100644
index 0000000..e25288c
--- /dev/null
+++ b/tests/cases/models/commit.test.php
@@ -0,0 +1,92 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Commit Test cases generated on: 2008-10-13 09:10:08 : 1223915168*/
+App::import('Model', 'Commit');
+
+class TestCommit extends Commit {
+ //var $cacheSources = false;
+}
+
+class CommitTestCase extends CakeTestCase {
+ var $Commit = null;
+ var $fixtures = array('app.commit', 'app.timeline', 'app.project');
+
+ function start() {
+ parent::start();
+ $this->Commit = new Commit();
+ }
+
+ function testCommitInstance() {
+ $this->assertTrue(is_a($this->Commit, 'Commit'));
+ }
+/*
+ function testCommitFind() {
+ $this->Commit->recursive = -1;
+ $results = $this->Commit->find('first');
+ $this->assertTrue(!empty($results));
+
+ $expected = array('Commit' => array(
+ 'id' => 1,
+ 'revision' => 1,
+ 'message' => 'Lorem ipsum dolor sit amet',
+ 'diff' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida,
+ phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam,
+ vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit,
+ feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.
+ Orci aliquet, in lorem et velit maecenas luctus, wisi nulla at, mauris nam ut a, lorem et et elit eu.
+ Sed dui facilisi, adipiscing mollis lacus congue integer, faucibus consectetuer eros amet sit sit,
+ magna dolor posuere. Placeat et, ac occaecat rutrum ante ut fusce. Sit velit sit porttitor non enim purus,
+ id semper consectetuer justo enim, nulla etiam quis justo condimentum vel, malesuada ligula arcu. Nisl neque,
+ ligula cras suscipit nunc eget, et tellus in varius urna odio est. Fuga urna dis metus euismod laoreet orci,
+ litora luctus suspendisse sed id luctus ut. Pede volutpat quam vitae, ut ornare wisi. Velit dis tincidunt,
+ pede vel eleifend nec curabitur dui pellentesque, volutpat taciti aliquet vivamus viverra, eget tellus ut
+ feugiat lacinia mauris sed, lacinia et felis.',
+ 'created' => '2008-10-13 09:26:08',
+ 'modified' => '2008-10-13 09:26:08',
+ 'project_id' => 1
+ ));
+ $this->assertEqual($results, $expected);
+ }
+*/
+ function testCommitSave() {
+ $data = array('Commit' => array(
+ //'id' => 1,
+ 'revision' => 2,
+ 'author' => 'gwoo',
+ 'commit_date' => '2008-10-13 09:26:08',
+ 'message' => 'Lorem ipsum dolor sit amet',
+ 'diff' => 'Index: /htdocs/chaw/content/svn/working/one/branches/index.php
+ ===================================================================
+ --- /htdocs/chaw/content/svn/working/one/branches/index.php (revision 5)
+ +++ /htdocs/chaw/content/svn/working/one/branches/index.php (revision 6)
+ @@ -1,10 +1,10 @@
+ i am making a change to for file
+
+ -i am making a change to this file
+ -i am making a change to this file
+ +i am gonna make a change to this file
+ +i am a change to this file
+
+
+ -i am making a change to this file
+ +i making a to this file
+
+
+ i am making a change to this file
+ \ No newline at end of file
+ ',
+ 'created' => '2008-10-13 09:26:08',
+ 'modified' => '2008-10-13 09:26:08',
+ 'project_id' => 1
+ ));
+
+ $results = $this->Commit->save($data);
+
+ $this->assertEqual($results, $data);
+
+ $this->Commit->Timeline->recursive = -1;
+ $results = $this->Commit->Timeline->find('first');
+ pr($results);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/models/git.test.php b/tests/cases/models/git.test.php
index 5537d36..df75310 100644
--- a/tests/cases/models/git.test.php
+++ b/tests/cases/models/git.test.php
@@ -1,4 +1,4 @@
-<?php
+<?php
/* SVN FILE: $Id$ */
/* Git Test cases generated on: 2008-09-09 18:09:14 : 1220999054*/
App::import('Model', 'Git');
@@ -12,33 +12,73 @@ class GitTest extends CakeTestCase {
function start() {
parent::start();
$this->Git = new TestGit();
-
- $this->Git->repo = '/htdocs/scm/creampuff.git';
- $this->Git->workingCopy = TMP . 'git';
-
+
+ $this->Git->repo = '/Volumes/Home/htdocs/chaw/content/git/repo/chaw.git';
+ $this->Git->working = '/Volumes/Home/htdocs/chaw/content/git/working/chaw';
+
}
-
+
function end() {
parent::end();
- pr($Git->debug);
+ pr($this->Git->debug);
}
function testGitInstance() {
$this->assertTrue(is_a($this->Git, 'Git'));
}
+ function testCreate() {
+ /*
+ $path = TMP . 'tests' . DS . 'another' . DS;
+
+ $this->Git->repo = $path . 'repo' . DS;
+ $this->Git->working = $path . 'working' . DS;
+ $this->Git->create('another');
+
+ $this->assertTrue(file_exists($path . 'repo' . DS . 'another.git'));
+ $this->assertTrue(file_exists($path . 'working' . DS . 'another' . DS . '.git'));
+ */
+ }
+
+ function testPull() {
+ //$Git->pull('master');
+ }
+
+ function testUpdate() {
+ pr($this->Git->commit("6a4766a9766652f92c0dfe0f0b990408bda91cee"));
+ pr($this->Git->update());
+
+ }
+
+ function testCommit() {
+ //pr($this->Git->sub('diff', array("a0e50432c90e3818c6083c03b7f6d3f6fda4e2c0", "2da6ad74c3e23561cb2a528283b422199a21ab11", "-p", "--unified=3")));
+ //pr($this->Git->commit("refs/heads/master", "a0e50432c90e3818c6083c03b7f6d3f6fda4e2c0", "2da6ad74c3e23561cb2a528283b422199a21ab11"));
+
+ //pr($this->Git->commit("a659692e6506e7d44cf29c9f3a51cb885b33b0e5"));
+
+ //pr($this->Git->sub('log', array("-p", "-1", "--full-diff")));
+ //pr($this->Git->findByNewrev("4952d6d310f8f2a35cfbe570f84d0aa636c3555e"));
+
+ }
+
+ function testPathInfo() {
+
+ //pr($this->Git->pathInfo());
+
+ //pr($this->Git->sub('cat-file', array('-t 4952d6d310f8f2a35cfbe570f84d0aa636c3555e')));
+ }
+
function testInfo() {
- pr($Git->info($branch));
- pr($this->Git->sub('cat-file', array('-t 0ed8662ea6402467a50a6e515042485227c2dd0c')));
+ ///pr($this->Git->info('master'));
+
+ //pr($this->Git->sub('cat-file', array('-t 4952d6d310f8f2a35cfbe570f84d0aa636c3555e')));
}
function testTree() {
- pr($this->Git->tree($branch));
+ // pr($this->Git->tree('master'));
}
- function testPull() {
- //$Git->pull('master');
- }
+
}
?>
\ No newline at end of file
diff --git a/tests/cases/models/permission.test.php b/tests/cases/models/permission.test.php
new file mode 100644
index 0000000..999e24a
--- /dev/null
+++ b/tests/cases/models/permission.test.php
@@ -0,0 +1,42 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Permission Test cases generated on: 2008-10-17 12:10:29 : 1224273329*/
+App::import('Model', 'Permission');
+class TestPermission extends Permission {
+
+ var $cacheSources = false;
+}
+
+class PermissionTest extends CakeTestCase {
+
+ function start() {
+ parent::start();
+ $this->Permission = new TestPermission();
+ }
+
+ function testPermissionInstance() {
+ $this->assertTrue(is_a($this->Permission, 'Permission'));
+ }
+
+ function testFile() {
+ Configure::write('Project', array(
+ 'url' => 'chaw',
+ 'repo' => array(
+ 'type' => 'git',
+ 'path' => APP . 'content' . DS . 'git' . DS . 'repo' . DS . 'chaw.git',
+ 'working' => APP . 'content' . DS . 'git' .DS . 'chaw'
+ )
+ ));
+
+ $this->assertTrue($this->Permission->check("chaw:/refs/head/master", array('group' => 'amf-developers', 'access' => 'rw')));
+
+ $this->assertFalse($this->Permission->check("chaw:/refs/head/master", array('user' => 'gwoo', 'access' => 'w')));
+
+ $this->assertFalse($this->Permission->check("chaw:/refs/head/master", array('user' => 'gwoo', 'access' => 'w')));
+
+ $this->assertTrue($this->Permission->check("chaw:/refs/head/master", array('user' => 'gwoo', 'access' => 'r')));
+
+ pr($this->Permission->groups());
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/models/project.test.php b/tests/cases/models/project.test.php
new file mode 100644
index 0000000..96808ba
--- /dev/null
+++ b/tests/cases/models/project.test.php
@@ -0,0 +1,35 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Project Test cases generated on: 2008-10-06 15:10:20 : 1223321240*/
+App::import('Model', 'Project');
+
+class TestProject extends Project {
+ var $cacheSources = false;
+ var $useDbConfig = 'test_suite';
+}
+
+class ProjectTestCase extends CakeTestCase {
+ var $Project = null;
+ var $fixtures = array('app.project');
+
+ function start() {
+ parent::start();
+ $this->Project = new TestProject();
+ }
+
+ function testProjectInstance() {
+ $this->assertTrue(is_a($this->Project, 'Project'));
+ }
+
+ function testProjectSave() {
+ $data = array('Project' => array(
+ 'repo_type' => 'Git',
+ '',
+ ));
+ }
+
+ function testProjectFind() {
+
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/models/svn.test.php b/tests/cases/models/svn.test.php
index 5dad134..1950e42 100644
--- a/tests/cases/models/svn.test.php
+++ b/tests/cases/models/svn.test.php
@@ -17,7 +17,7 @@ class SvnTest extends CakeTestCase {
$this->Svn->repo = TMP . 'svn/repo';
- $this->Svn->workingCopy = TMP . 'demo';
+ $this->Svn->working = TMP . 'svn/working';
}
function end() {
@@ -26,7 +26,7 @@ class SvnTest extends CakeTestCase {
}
function getTests() {
- return array_merge(array('start', 'startCase'), array('testCreate', 'testCommit'), array('end', 'endCase'));
+ return array_merge(array('start', 'startCase'), array('testCreate', 'testRead', 'testFind'), array('end', 'endCase'));
}
function testSvnInstance() {
@@ -34,21 +34,28 @@ class SvnTest extends CakeTestCase {
}
function testCreate() {
- $this->Svn->create('demo', TMP . 'svn/repo');
+ $this->Svn->create('demo');
+
+ $this->assertTrue(file_exists($this->Svn->repo));
}
- function testRead() {
- $this->Svn->repo = TMP . 'svn/repo';
+ function testHook() {
+ $this->Svn->hook('post-commit');
- $this->Svn->workingCopy = TMP . 'demo';
-
- pr($this->Svn->info('/branches'));
+ $this->assertTrue(file_exists($this->Svn->repo . DS . 'hooks' . DS . 'post-commit'));
+ }
+
+ function testFind() {
+ pr($this->Svn->findByRevision(1));
+ }
+
+ function testRead() {
+ pr($this->Svn->info());
pr($this->Svn->look('author', $this->Svn->repo));
}
function testCommit() {
- $this->Svn->workingCopy = TMP . 'demo';
$File = new File($this->Svn->workingCopy . '/branches/demo_1.0.x.x/index.php', true);
$File->write("this is a new php file with plain text");
pr($this->Svn->sub('add', array(dirname($File->pwd()))));
@@ -57,10 +64,7 @@ class SvnTest extends CakeTestCase {
}
function testTree() {
- $this->Svn->repo = TMP . 'svn/repo';
- $this->Svn->repo = 'https://svn.cakephp.org/repo/branches';
- $this->Svn->workingCopy = TMP . 'demo';
-
+ //$this->Svn->repo = 'https://svn.cakephp.org/repo/branches';
pr($this->Svn->look('tree', $this->Svn->workingCopy));
}
diff --git a/tests/cases/models/ticket.test.php b/tests/cases/models/ticket.test.php
new file mode 100644
index 0000000..a5f5a42
--- /dev/null
+++ b/tests/cases/models/ticket.test.php
@@ -0,0 +1,55 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Ticket Test cases generated on: 2008-09-23 07:09:29 : 1222170869*/
+App::import('Model', 'Ticket');
+
+class TestTicket extends Ticket {
+ var $cacheSources = false;
+ var $useDbConfig = 'test_suite';
+}
+
+class TicketTestCase extends CakeTestCase {
+ var $Ticket = null;
+ var $fixtures = array('app.ticket');
+
+ function start() {
+ parent::start();
+ $this->Ticket = new TestTicket();
+ }
+
+ function testTicketInstance() {
+ $this->assertTrue(is_a($this->Ticket, 'Ticket'));
+ }
+
+ function testTicketFind() {
+ $this->Ticket->recursive = -1;
+ $results = $this->Ticket->find('first');
+ $this->assertTrue(!empty($results));
+
+ $expected = array('Ticket' => array(
+ 'id' => 1,
+ 'type_id' => 1,
+ 'feature_id' => 1,
+ 'owner' => 1,
+ 'reporter' => 1,
+ 'summary' => 'Lorem ipsum dolor sit amet',
+ 'body' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida,
+ phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam,
+ vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit,
+ feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.
+ Orci aliquet, in lorem et velit maecenas luctus, wisi nulla at, mauris nam ut a, lorem et et elit eu.
+ Sed dui facilisi, adipiscing mollis lacus congue integer, faucibus consectetuer eros amet sit sit,
+ magna dolor posuere. Placeat et, ac occaecat rutrum ante ut fusce. Sit velit sit porttitor non enim purus,
+ id semper consectetuer justo enim, nulla etiam quis justo condimentum vel, malesuada ligula arcu. Nisl neque,
+ ligula cras suscipit nunc eget, et tellus in varius urna odio est. Fuga urna dis metus euismod laoreet orci,
+ litora luctus suspendisse sed id luctus ut. Pede volutpat quam vitae, ut ornare wisi. Velit dis tincidunt,
+ pede vel eleifend nec curabitur dui pellentesque, volutpat taciti aliquet vivamus viverra, eget tellus ut
+ feugiat lacinia mauris sed, lacinia et felis.',
+ 'created' => '2008-09-23 07:54:29',
+ 'modified' => '2008-09-23 07:54:29',
+ 'status' => 1
+ ));
+ $this->assertEqual($results, $expected);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/models/user.test.php b/tests/cases/models/user.test.php
new file mode 100644
index 0000000..9eb872f
--- /dev/null
+++ b/tests/cases/models/user.test.php
@@ -0,0 +1,37 @@
+<?php
+/* SVN FILE: $Id$ */
+/* User Test cases generated on: 2008-10-16 10:10:23 : 1224177023*/
+App::import('Model', 'User');
+
+class UserTestCase extends CakeTestCase {
+ var $User = null;
+ var $fixtures = array('app.user');
+
+ function start() {
+ parent::start();
+ $this->User =& ClassRegistry::init('User');
+ }
+
+ function testUserInstance() {
+ $this->assertTrue(is_a($this->User, 'User'));
+ }
+
+ function testUserFind() {
+ $this->User->recursive = -1;
+ $results = $this->User->find('first');
+ $this->assertTrue(!empty($results));
+
+ $expected = array('User' => array(
+ 'id' => 1,
+ 'username' => 'Lorem ipsum dolor sit amet',
+ 'password' => 'Lorem ipsum dolor sit amet',
+ 'group_id' => 'Lorem ipsum dolor sit amet',
+ 'email' => 'Lorem ipsum dolor sit amet',
+ 'last_login' => '2008-10-16 10:10:23',
+ 'created' => '2008-10-16 10:10:23',
+ 'modified' => '2008-10-16 10:10:23'
+ ));
+ $this->assertEqual($results, $expected);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/cases/models/version.test.php b/tests/cases/models/version.test.php
new file mode 100644
index 0000000..3714692
--- /dev/null
+++ b/tests/cases/models/version.test.php
@@ -0,0 +1,52 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Version Test cases generated on: 2008-10-10 16:10:08 : 1223680508*/
+App::import('Model', 'Version');
+
+class TestVersion extends Version {
+ var $cacheSources = false;
+ var $useDbConfig = 'test_suite';
+}
+
+class VersionTestCase extends CakeTestCase {
+ var $Version = null;
+ var $fixtures = array('app.version');
+
+ function start() {
+ parent::start();
+ $this->Version = new TestVersion();
+ }
+
+ function testVersionInstance() {
+ $this->assertTrue(is_a($this->Version, 'Version'));
+ }
+
+ function testVersionFind() {
+ $this->Version->recursive = -1;
+ $results = $this->Version->find('first');
+ $this->assertTrue(!empty($results));
+
+ $expected = array('Version' => array(
+ 'id' => 1,
+ 'title' => 'Lorem ipsum dolor sit amet',
+ 'description' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida,
+ phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam,
+ vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit,
+ feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.
+ Orci aliquet, in lorem et velit maecenas luctus, wisi nulla at, mauris nam ut a, lorem et et elit eu.
+ Sed dui facilisi, adipiscing mollis lacus congue integer, faucibus consectetuer eros amet sit sit,
+ magna dolor posuere. Placeat et, ac occaecat rutrum ante ut fusce. Sit velit sit porttitor non enim purus,
+ id semper consectetuer justo enim, nulla etiam quis justo condimentum vel, malesuada ligula arcu. Nisl neque,
+ ligula cras suscipit nunc eget, et tellus in varius urna odio est. Fuga urna dis metus euismod laoreet orci,
+ litora luctus suspendisse sed id luctus ut. Pede volutpat quam vitae, ut ornare wisi. Velit dis tincidunt,
+ pede vel eleifend nec curabitur dui pellentesque, volutpat taciti aliquet vivamus viverra, eget tellus ut
+ feugiat lacinia mauris sed, lacinia et felis.',
+ 'created' => '2008-10-10 16:15:08',
+ 'modified' => '2008-10-10 16:15:08',
+ 'completed' => 1,
+ 'due' => '2008-10-10'
+ ));
+ $this->assertEqual($results, $expected);
+ }
+}
+?>
\ No newline at end of file
diff --git a/tests/fixtures/comment_fixture.php b/tests/fixtures/comment_fixture.php
new file mode 100644
index 0000000..d3ae333
--- /dev/null
+++ b/tests/fixtures/comment_fixture.php
@@ -0,0 +1,34 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Comment Fixture generated on: 2008-10-16 22:10:35 : 1224221135*/
+
+class CommentFixture extends CakeTestFixture {
+ var $name = 'Comment';
+ var $fields = array(
+ 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'ticket_id' => array('type'=>'integer', 'null' => false, 'default' => '0'),
+ 'body' => array('type'=>'text', 'null' => true, 'default' => NULL),
+ 'created' => array('type'=>'datetime', 'null' => true, 'default' => NULL),
+ 'modified' => array('type'=>'datetime', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
+ );
+ var $records = array(array(
+ 'id' => 1,
+ 'ticket_id' => 1,
+ 'body' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida,
+ phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam,
+ vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit,
+ feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.
+ Orci aliquet, in lorem et velit maecenas luctus, wisi nulla at, mauris nam ut a, lorem et et elit eu.
+ Sed dui facilisi, adipiscing mollis lacus congue integer, faucibus consectetuer eros amet sit sit,
+ magna dolor posuere. Placeat et, ac occaecat rutrum ante ut fusce. Sit velit sit porttitor non enim purus,
+ id semper consectetuer justo enim, nulla etiam quis justo condimentum vel, malesuada ligula arcu. Nisl neque,
+ ligula cras suscipit nunc eget, et tellus in varius urna odio est. Fuga urna dis metus euismod laoreet orci,
+ litora luctus suspendisse sed id luctus ut. Pede volutpat quam vitae, ut ornare wisi. Velit dis tincidunt,
+ pede vel eleifend nec curabitur dui pellentesque, volutpat taciti aliquet vivamus viverra, eget tellus ut
+ feugiat lacinia mauris sed, lacinia et felis.',
+ 'created' => '2008-10-16 22:25:35',
+ 'modified' => '2008-10-16 22:25:35'
+ ));
+}
+?>
\ No newline at end of file
diff --git a/tests/fixtures/project_fixture.php b/tests/fixtures/project_fixture.php
new file mode 100644
index 0000000..c680dd6
--- /dev/null
+++ b/tests/fixtures/project_fixture.php
@@ -0,0 +1,20 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Project Fixture generated on: 2008-10-06 23:10:38 : 1223348498*/
+
+class ProjectFixture extends CakeTestFixture {
+ var $name = 'Project';
+ var $fields = array(
+ 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'name' => array('type'=>'string', 'null' => false, 'length' => 200),
+ 'description' => array('type'=>'text', 'null' => true, 'default' => NULL),
+ 'created' => array('type'=>'date', 'null' => true, 'default' => NULL),
+ 'modified' => array('type'=>'date', 'null' => true, 'default' => NULL),
+ 'active' => array('type'=>'boolean', 'null' => true, 'default' => NULL),
+ 'ticket_types' => array('type'=>'string', 'null' => true, 'default' => NULL),
+ 'groups' => array('type'=>'string', 'null' => true, 'default' => NULL),
+ 'priorities' => array('type'=>'string', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
+ );
+}
+?>
\ No newline at end of file
diff --git a/tests/fixtures/ticket_fixture.php b/tests/fixtures/ticket_fixture.php
new file mode 100644
index 0000000..51a2441
--- /dev/null
+++ b/tests/fixtures/ticket_fixture.php
@@ -0,0 +1,44 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Ticket Fixture generated on: 2008-09-23 07:09:29 : 1222170869*/
+
+class TicketFixture extends CakeTestFixture {
+ var $name = 'Ticket';
+ var $fields = array(
+ 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'type_id' => array('type'=>'integer', 'null' => false, 'default' => '0'),
+ 'feature_id' => array('type'=>'integer', 'null' => false, 'default' => '0'),
+ 'owner' => array('type'=>'integer', 'null' => false, 'default' => '0'),
+ 'reporter' => array('type'=>'integer', 'null' => false, 'default' => '0'),
+ 'summary' => array('type'=>'string', 'null' => false, 'length' => 200),
+ 'body' => array('type'=>'text', 'null' => true, 'default' => NULL),
+ 'created' => array('type'=>'datetime', 'null' => true, 'default' => NULL),
+ 'modified' => array('type'=>'datetime', 'null' => true, 'default' => NULL),
+ 'status' => array('type'=>'integer', 'null' => false, 'default' => '1', 'length' => 2),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
+ );
+ var $records = array(array(
+ 'id' => 1,
+ 'type_id' => 1,
+ 'feature_id' => 1,
+ 'owner' => 1,
+ 'reporter' => 1,
+ 'summary' => 'Lorem ipsum dolor sit amet',
+ 'body' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida,
+ phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam,
+ vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit,
+ feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.
+ Orci aliquet, in lorem et velit maecenas luctus, wisi nulla at, mauris nam ut a, lorem et et elit eu.
+ Sed dui facilisi, adipiscing mollis lacus congue integer, faucibus consectetuer eros amet sit sit,
+ magna dolor posuere. Placeat et, ac occaecat rutrum ante ut fusce. Sit velit sit porttitor non enim purus,
+ id semper consectetuer justo enim, nulla etiam quis justo condimentum vel, malesuada ligula arcu. Nisl neque,
+ ligula cras suscipit nunc eget, et tellus in varius urna odio est. Fuga urna dis metus euismod laoreet orci,
+ litora luctus suspendisse sed id luctus ut. Pede volutpat quam vitae, ut ornare wisi. Velit dis tincidunt,
+ pede vel eleifend nec curabitur dui pellentesque, volutpat taciti aliquet vivamus viverra, eget tellus ut
+ feugiat lacinia mauris sed, lacinia et felis.',
+ 'created' => '2008-09-23 07:54:29',
+ 'modified' => '2008-09-23 07:54:29',
+ 'status' => 1
+ ));
+}
+?>
\ No newline at end of file
diff --git a/tests/fixtures/timeline_fixture.php b/tests/fixtures/timeline_fixture.php
new file mode 100644
index 0000000..f68ae97
--- /dev/null
+++ b/tests/fixtures/timeline_fixture.php
@@ -0,0 +1,19 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Timeline Fixture generated on: 2008-10-13 09:10:08 : 1223915168*/
+
+class TimelineFixture extends CakeTestFixture {
+ var $name = 'Timeline';
+
+ var $table = 'timeline';
+
+ var $fields = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'project_id' => array('type' => 'integer', 'null' => true, 'default' => NULL),
+ 'summary' => array('type' => 'text', 'null' => true, 'default' => NULL),
+ 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
+ );
+}
+?>
\ No newline at end of file
diff --git a/tests/fixtures/user_fixture.php b/tests/fixtures/user_fixture.php
new file mode 100644
index 0000000..585efd3
--- /dev/null
+++ b/tests/fixtures/user_fixture.php
@@ -0,0 +1,29 @@
+<?php
+/* SVN FILE: $Id$ */
+/* User Fixture generated on: 2008-10-16 10:10:23 : 1224177023*/
+
+class UserFixture extends CakeTestFixture {
+ var $name = 'User';
+ var $fields = array(
+ 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'username' => array('type'=>'string', 'null' => false, 'length' => 40),
+ 'password' => array('type'=>'string', 'null' => false, 'length' => 40),
+ 'group_id' => array('type'=>'string', 'null' => true, 'default' => NULL, 'length' => 100),
+ 'email' => array('type'=>'string', 'null' => false, 'length' => 200),
+ 'last_login' => array('type'=>'datetime', 'null' => true, 'default' => NULL),
+ 'created' => array('type'=>'datetime', 'null' => true, 'default' => NULL),
+ 'modified' => array('type'=>'datetime', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
+ );
+ var $records = array(array(
+ 'id' => 1,
+ 'username' => 'Lorem ipsum dolor sit amet',
+ 'password' => 'Lorem ipsum dolor sit amet',
+ 'group_id' => 'Lorem ipsum dolor sit amet',
+ 'email' => 'Lorem ipsum dolor sit amet',
+ 'last_login' => '2008-10-16 10:10:23',
+ 'created' => '2008-10-16 10:10:23',
+ 'modified' => '2008-10-16 10:10:23'
+ ));
+}
+?>
\ No newline at end of file
diff --git a/tests/fixtures/version_fixture.php b/tests/fixtures/version_fixture.php
new file mode 100644
index 0000000..037e40e
--- /dev/null
+++ b/tests/fixtures/version_fixture.php
@@ -0,0 +1,38 @@
+<?php
+/* SVN FILE: $Id$ */
+/* Version Fixture generated on: 2008-10-10 16:10:08 : 1223680508*/
+
+class VersionFixture extends CakeTestFixture {
+ var $name = 'Version';
+ var $fields = array(
+ 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
+ 'title' => array('type'=>'string', 'null' => false, 'length' => 100),
+ 'description' => array('type'=>'text', 'null' => true, 'default' => NULL),
+ 'created' => array('type'=>'datetime', 'null' => true, 'default' => NULL),
+ 'modified' => array('type'=>'datetime', 'null' => true, 'default' => NULL),
+ 'completed' => array('type'=>'boolean', 'null' => true, 'default' => NULL),
+ 'due' => array('type'=>'date', 'null' => true, 'default' => NULL),
+ 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
+ );
+ var $records = array(array(
+ 'id' => 1,
+ 'title' => 'Lorem ipsum dolor sit amet',
+ 'description' => 'Lorem ipsum dolor sit amet, aliquet feugiat. Convallis morbi fringilla gravida,
+ phasellus feugiat dapibus velit nunc, pulvinar eget sollicitudin venenatis cum nullam,
+ vivamus ut a sed, mollitia lectus. Nulla vestibulum massa neque ut et, id hendrerit sit,
+ feugiat in taciti enim proin nibh, tempor dignissim, rhoncus duis vestibulum nunc mattis convallis.
+ Orci aliquet, in lorem et velit maecenas luctus, wisi nulla at, mauris nam ut a, lorem et et elit eu.
+ Sed dui facilisi, adipiscing mollis lacus congue integer, faucibus consectetuer eros amet sit sit,
+ magna dolor posuere. Placeat et, ac occaecat rutrum ante ut fusce. Sit velit sit porttitor non enim purus,
+ id semper consectetuer justo enim, nulla etiam quis justo condimentum vel, malesuada ligula arcu. Nisl neque,
+ ligula cras suscipit nunc eget, et tellus in varius urna odio est. Fuga urna dis metus euismod laoreet orci,
+ litora luctus suspendisse sed id luctus ut. Pede volutpat quam vitae, ut ornare wisi. Velit dis tincidunt,
+ pede vel eleifend nec curabitur dui pellentesque, volutpat taciti aliquet vivamus viverra, eget tellus ut
+ feugiat lacinia mauris sed, lacinia et felis.',
+ 'created' => '2008-10-10 16:15:08',
+ 'modified' => '2008-10-10 16:15:08',
+ 'completed' => 1,
+ 'due' => '2008-10-10'
+ ));
+}
+?>
\ No newline at end of file
diff --git a/tests/groups/empty b/tests/groups/empty
new file mode 100755
index 0000000..e69de29
diff --git a/tmp/cache/models/empty b/tmp/cache/models/empty
new file mode 100755
index 0000000..e69de29
diff --git a/tmp/cache/persistent/empty b/tmp/cache/persistent/empty
new file mode 100755
index 0000000..e69de29
diff --git a/tmp/cache/views/empty b/tmp/cache/views/empty
new file mode 100755
index 0000000..e69de29
diff --git a/tmp/logs/empty b/tmp/logs/empty
new file mode 100755
index 0000000..e69de29
diff --git a/tmp/sessions/empty b/tmp/sessions/empty
new file mode 100755
index 0000000..e69de29
diff --git a/tmp/tests/empty b/tmp/tests/empty
new file mode 100755
index 0000000..e69de29
diff --git a/vendors/shells/post_commit.php b/vendors/shells/post_commit.php
new file mode 100644
index 0000000..4c4fef2
--- /dev/null
+++ b/vendors/shells/post_commit.php
@@ -0,0 +1,45 @@
+<?php
+
+class PostCommitShell extends Shell {
+
+ var $uses = array('Project', 'Commit', 'Svn');
+
+ function _welcome() {}
+
+ function main() {
+ //$this->_commit();
+ }
+
+ function commit() {
+
+ $this->Project->id = $this->args[0];
+ $project = $this->Project->field('url');
+
+ $path = Configure::read('Content.svn');
+
+ $this->Svn->config(array(
+ 'repo' => $path .'repo' . DS . $project,
+ 'working' => $path .'working' . DS . $project
+ ));
+
+ $revision = $this->args[2];
+
+ $data = $this->Svn->commit($revision);
+
+ $this->Svn->update();
+
+ if (!empty($data)) {
+
+ $data['Svn']['project_id'] = $this->Project->id;
+ $data['Svn']['type'] = 'svn';
+
+ $this->Commit->create($data['Svn']);
+
+ return $this->Commit->save();
+ }
+
+
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/vendors/shells/post_receive.php b/vendors/shells/post_receive.php
new file mode 100644
index 0000000..ec5c921
--- /dev/null
+++ b/vendors/shells/post_receive.php
@@ -0,0 +1,58 @@
+<?php
+
+class PostReceiveShell extends Shell {
+
+ var $uses = array( 'Project', 'Commit', 'Git');
+
+ function _welcome() {}
+
+ function main() {
+ //$this->_commit();
+ }
+
+ function commit() {
+ $this->Project->id = $this->args[0];
+ $project = $this->Project->field('url');
+
+ $refname = @$this->args[1];
+ $oldrev = @$this->args[2];
+ $newrev = @$this->args[3];
+
+ $path = Configure::read('Content.git');
+
+ $this->Git->config(array(
+ 'repo' => $path .'repo' . DS . $project . '.git',
+ 'working' => $path .'working' . DS . $project
+ ));
+
+ if (!isset($refname)) {
+ $refname = 'refs/heads/master';
+ }
+
+ $data = $this->Git->commit($newrev);
+
+ /*
+ pr($this->Git->update());
+ pr($this->Git->debug);
+
+ $this->log($this->Git);
+ $this->log($this->args);
+ $this->log($this->Git->response);
+ $this->log($this->Git->debug);
+ */
+ if (!empty($data)) {
+
+ $data['Git']['project_id'] = $this->Project->id;
+ $data['Git']['type'] = 'git';
+
+ $this->Commit->create($data['Git']);
+
+ if (!$this->Commit->save()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/vendors/shells/pre_commit.php b/vendors/shells/pre_commit.php
new file mode 100644
index 0000000..3c872d6
--- /dev/null
+++ b/vendors/shells/pre_commit.php
@@ -0,0 +1,44 @@
+<?php
+
+class PreCommitShell extends Shell {
+
+ var $uses = array('Project', 'Permission', 'Svn');
+
+ function _welcome() {}
+
+ function main() {
+ //$this->_commit();
+ }
+
+ function authorize() {
+ return true;
+ $this->error(print_r($this->args, true));
+ die();
+
+ $this->Project->id = $this->args[0];
+ $project = $this->Project->field('url');
+
+ $this->Project->initialize(compact('project'));
+
+ $path = Configure::read('Content.svn');
+
+ $this->Svn->config(array(
+ 'repo' => $path .'repo' . DS . $project,
+ 'working' => $path .'working' . DS . $project
+ ));
+
+ $txn = explode('-', $this->args[2]);
+ $transaction = $this->args[2];
+ $revision = $txn[0];
+
+ $this->log($this->Svn->look('author', array("-t {$transaction}")));
+ $this->log($this->Svn->look('changed', array("-t {$transaction}")));
+
+ //pr($this->Svn->debug);
+
+ //pr($this->Permission->file());
+
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/vendors/shells/tasks/empty b/vendors/shells/tasks/empty
new file mode 100755
index 0000000..e69de29
diff --git a/vendors/shells/templates/empty b/vendors/shells/templates/empty
new file mode 100755
index 0000000..e69de29
diff --git a/vendors/shells/update.php b/vendors/shells/update.php
new file mode 100644
index 0000000..f956505
--- /dev/null
+++ b/vendors/shells/update.php
@@ -0,0 +1,72 @@
+<?php
+
+class UpdateShell extends Shell {
+
+ var $uses = array('Project', 'Permission', 'Git');
+
+ function _welcome() {}
+
+ function main() {
+ //$this->_commit();
+ }
+/**
+ * undocumented function
+ *
+ * @return exit value 0 for true, 1-255 for status
+ *
+ **/
+ function authorize() {
+ $this->Project->id = $this->args[0];
+ $project = $this->Project->field('url');
+
+ $this->Project->initialize(compact('project'));
+
+ $path = Configure::read('Content.git');
+
+ $this->Git->config(array(
+ 'repo' => $path .'repo' . DS . $project . '.git',
+ 'working' => $path .'working' . DS . $project
+ ));
+
+
+ $refname = $this->args[1];
+ $oldrev = $this->args[2];
+ $newrev = $this->args[3];
+
+ $info = $this->Git->sub('show', array($newrev, "--pretty=format:'%an'"));
+
+ $username = $info[0];
+
+ $user_id = $this->Permission->User->field('id', array('User.username' => $username));
+
+
+ $this->Permission->recursive = -1;
+ $permissions = $this->Permission->find('all', array(
+ 'conditions' => array('Permission.user_id' => $user_id, 'Permission.project_id' => $this->Project->id)
+ ));
+
+ $path = $project .':/' . $refname;
+
+ $allowed = $this->Permission->check($project .':', array(
+ 'user' => $username,
+ 'group' => @$permissions['Permission']['group'],
+ ));
+
+ if ($allowed === true) {
+ return 0;
+ }
+
+ $allowed = $this->Permission->check($path, array(
+ 'user' => $username,
+ 'group' => @$permissions['Permission']['group'],
+ 'access' => 'w'
+ ));
+
+ if ($allowed === true) {
+ return 0;
+ }
+ $this->err('Authorization failed');
+ return 1;
+ }
+
+}
\ No newline at end of file
diff --git a/views/browser/diff.ctp b/views/browser/diff.ctp
new file mode 100644
index 0000000..e69de29
diff --git a/views/browser/index.ctp b/views/browser/index.ctp
index ab364ed..484552c 100644
--- a/views/browser/index.ctp
+++ b/views/browser/index.ctp
@@ -1,50 +1,57 @@
-<div class="page">
- <h2>
- <?php echo $html->link('..', array('action' => 'index'))?>
- <?php
- $path = '/';
- foreach ((array)$args as $part):
- echo '/' . $html->link($part, array($path . $part));
- endforeach;
+<div class="browser index">
- echo '/' . $current;
- ?>
- </h2>
+<h2>
+ <?php echo $html->link(Configure::read('Project.url'), array('action' => 'index'))?>
+ <?php
+ $path = '/';
+ foreach ((array)$args as $part):
+ $path .= $part . ' / ';
+ echo '/ ' . $html->link($part, array($path));
+ endforeach;
+ echo ' / ' . $current;
+ ?>
+</h2>
-<table class="downloads">
+<table cellpadding="0" cellspacing="0">
<tr>
<th><?php __('Name');?></th>
- <th><?php __('MD5');?></th>
<th><?php __('Size');?></th>
+ <th><?php __('Revision');?></th>
+ <th><?php __('Author');?></th>
+ <th><?php __('Message');?></th>
</tr>
<?php
$i = 0;
- foreach ($data['Folder'] as $download):
+ foreach ((array)$data['Folder'] as $item):
$class = null;
if ($i++ % 2 == 0) {
$class = ' class="zebra"';
}
?>
<tr<?php echo $class?>>
- <td><?php echo $html->link($download['name'], array($download['path']), array('class' => 'dir'));?></td>
- <td> </td>
- <td><?php echo $download['size']['num'];?> <?php echo $download['size']['ext'];?></td>
+ <td><?php echo $html->link($item['name'], array($item['path']));?></td>
+ <td><?php echo $item['size']['num'];?> <?php echo $item['size']['ext'];?></td>
+ <td><?php echo $item['info']['revision'];?></td>
+ <td><?php echo $item['info']['author'];?></td>
+ <td><?php echo $item['info']['message'];?></td>
</tr>
<?php
endforeach;
?>
<?php
- foreach ($data['File'] as $download):
+ foreach ((array)$data['File'] as $item):
$class = null;
if ($i++ % 2 == 0) {
$class = ' class="zebra"';
}
?>
<tr<?php echo $class?>>
- <td><?php echo $html->link($download['name'], $download['path']);?></td>
- <td><?php echo $download['md5'];?></td>
- <td><?php echo $download['size']['num'];?> <?php echo $download['size']['ext'];?></td>
+ <td><?php echo $html->link($item['name'], array($item['path']));?></td>
+ <td><?php echo $item['size']['num'];?> <?php echo $item['size']['ext'];?></td>
+ <td><?php echo $item['info']['revision'];?></td>
+ <td><?php echo $item['info']['author'];?></td>
+ <td><?php echo $item['info']['message'];?></td>
</tr>
<?php
endforeach;
diff --git a/views/commits/index.ctp b/views/commits/index.ctp
new file mode 100644
index 0000000..9b39979
--- /dev/null
+++ b/views/commits/index.ctp
@@ -0,0 +1,74 @@
+<?php
+$javascript->link('highlight', false);
+
+$script = '
+
+hljs.initHighlightingOnLoad("diff");
+
+
+$(document).ready(function(){
+ converter = new Showdown.converter("' . $this->webroot . '");
+ $(".message").each(function () {
+ $(this).html(converter.makeHtml(jQuery.trim($(this).text())))
+ });
+});
+';
+$javascript->codeBlock($script, array('inline' => false));
+?>
+
+<h2>Commits</h2>
+
+<div class="commit index">
+<?php foreach ((array)$commits as $commit):?>
+
+ <div class="commit">
+
+ <h3>
+ <?php echo $html->link($commit['Commit']['revision'], array('controller' => 'commits', 'action' => 'view', $commit['Commit']['revision']));?>
+ </h3>
+
+ <p>
+ <strong>Author:</strong> <?php echo $commit['Commit']['author'];?>
+ </p>
+
+ <p>
+ <strong>Date:</strong> <?php echo $commit['Commit']['commit_date'];?>
+ </p>
+
+ <p class="message">
+ <?php echo $commit['Commit']['message'];?>
+ </p>
+
+ <?php
+ $changes = unserialize($commit['Commit']['changes']);
+ if(!empty($changes)):
+ ?>
+ <p>
+ <strong>Changes:</strong>
+ <ul>
+ <?php
+ foreach ($changes as $changed) :
+ echo $html->tag('li', $changed);
+ endforeach;
+
+ ?>
+ </ul>
+ </p>
+ <?php endif?>
+
+ <?php
+
+ //echo (!empty($commit['Commit']['diff'])) ? $html->tag('pre', $html->tag('code', $commit['Commit']['diff'], array('class' => 'diff'))) : null;
+
+ ?>
+ </div>
+
+<?php endforeach;?>
+
+<?php
+ echo $paginator->prev();
+ echo $paginator->numbers(array('before' => ' | ', 'after' => ' | '));
+ echo $paginator->next();
+?>
+
+</div>
\ No newline at end of file
diff --git a/views/commits/view.ctp b/views/commits/view.ctp
new file mode 100644
index 0000000..35392a1
--- /dev/null
+++ b/views/commits/view.ctp
@@ -0,0 +1,50 @@
+<?php
+$html->css('highlight/idea', null, false);
+$javascript->link('highlight', false);
+
+$script = '
+hljs.initHighlightingOnLoad("diff");
+$(document).ready(function(){
+ converter = new Showdown.converter("' . $this->webroot . '");
+ $(".message").each(function () {
+ $(this).html(converter.makeHtml(jQuery.trim($(this).text())))
+ });
+});
+';
+$javascript->codeBlock($script, array('inline' => false));
+?>
+
+<h2>Commit <?php echo $commit['Commit']['revision'];?></h2>
+
+<div class="commit view">
+
+ <p>
+ <strong>Author:</strong> <?php echo $commit['Commit']['author'];?>
+ </p>
+
+ <p>
+ <strong>Date:</strong> <?php echo $commit['Commit']['commit_date'];?>
+ </p>
+
+ <p class="message">
+ <?php echo $commit['Commit']['message'];?>
+ </p>
+
+ <?php if(!empty($commit['Commit']['changes'])):?>
+ <p>
+ <strong>Changes:</strong>
+ <ul>
+ <?php
+ foreach (unserialize($commit['Commit']['changes']) as $changed) :
+ echo $html->tag('li', $changed);
+ endforeach;
+
+ ?>
+ </ul>
+ </p>
+ <?php endif?>
+
+ <?php
+ echo (!empty($commit['Commit']['diff'])) ? $html->tag('pre', $html->tag('code', $commit['Commit']['diff'], array('class' => 'diff'))) : null;
+ ?>
+</div>
\ No newline at end of file
diff --git a/views/dashboard/admin_index.ctp b/views/dashboard/admin_index.ctp
new file mode 100644
index 0000000..ac1fda3
--- /dev/null
+++ b/views/dashboard/admin_index.ctp
@@ -0,0 +1,4 @@
+<div class="dashboard index">
+<h2><?php __('Dashboard');?></h2>
+
+</div>
diff --git a/views/dashboard/index.ctp b/views/dashboard/index.ctp
new file mode 100644
index 0000000..ac1fda3
--- /dev/null
+++ b/views/dashboard/index.ctp
@@ -0,0 +1,4 @@
+<div class="dashboard index">
+<h2><?php __('Dashboard');?></h2>
+
+</div>
diff --git a/views/elements/current_user.ctp b/views/elements/current_user.ctp
new file mode 100644
index 0000000..c7ba174
--- /dev/null
+++ b/views/elements/current_user.ctp
@@ -0,0 +1,21 @@
+<div id="current-user">
+ <?php if (!empty($CurrentUser)):?>
+ <span class="gravatar">
+ <?php
+ $gravatar = "http://www.gravatar.com/avatar/" . md5($CurrentUser->email). "?"
+ . "size=22";
+ echo "<img src=\"{$gravatar}\" />";
+ ?>
+ </span>
+ <span class="username">
+ <?php echo $html->link($CurrentUser->username, array('controller' => 'users', 'action' => 'account', $CurrentUser->username)); ?>
+ </span>
+ <?php else:?>
+ <span class="login">
+ <?php echo $html->link('Login', array('controller' => 'users', 'action' => 'login')); ?>
+ </span>
+ <span class="register">
+ <?php echo $html->link('Register', array('controller' => 'users', 'action' => 'add')); ?>
+ </span>
+ <?php endif;?>
+</div>
diff --git a/views/elements/markdown_help.ctp b/views/elements/markdown_help.ctp
new file mode 100644
index 0000000..f0138f0
--- /dev/null
+++ b/views/elements/markdown_help.ctp
@@ -0,0 +1,31 @@
+<h4>
+ <?php echo $html->link('Markdown Help', '/markdown_syntax', array('target' => '_blank')); ?>
+</h4>
+<div class="markdown">
+ <br />
+ [link](http://url.com/)
+ <br />
+ <br />
+ <em>*italic*</em>
+ <em>or</em>
+ <em>_italic_</em>
+ <br />
+ <strong>**bold**</strong>
+ <em>or</em>
+ <strong>__bold__</strong>
+ <br />
+ <br />
+ # header 1
+ <br />
+ ## header 2
+ <br />
+ <br />
+ - unordered list 1
+ <br />
+ 1. ordered list 2
+ <br />
+ <br />
+ ```<code>inline code</code>```
+ <br/>
+ <pre>preformatted: <br/>4 spaces or tab</pre>
+</div>
\ No newline at end of file
diff --git a/views/layouts/admin.ctp b/views/layouts/admin.ctp
new file mode 100644
index 0000000..d046554
--- /dev/null
+++ b/views/layouts/admin.ctp
@@ -0,0 +1,124 @@
+<?php
+/* SVN FILE: $Id: default.ctp 6296 2008-01-01 22:18:17Z phpnut $ */
+/**
+ *
+ * PHP versions 4 and 5
+ *
+ * CakePHP(tm) : Rapid Development Framework <http://www.cakephp.org/>
+ * Copyright 2005-2008, Cake Software Foundation, Inc.
+ * 1785 E. Sahara Avenue, Suite 490-204
+ * Las Vegas, Nevada 89104
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @filesource
+ * @copyright Copyright 2005-2008, Cake Software Foundation, Inc.
+ * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
+ * @package cake
+ * @subpackage cake.cake.console.libs.templates.skel.views.layouts
+ * @since CakePHP(tm) v 0.10.0.1076
+ * @version $Revision: 6296 $
+ * @modifiedby $LastChangedBy: phpnut $
+ * @lastmodified $Date: 2008-01-01 14:18:17 -0800 (Tue, 01 Jan 2008) $
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>
+ <?php echo Configure::read('Project.name') .' : ' . $title_for_layout;?>
+ </title>
+ <?php
+ echo $html->charset();
+ echo $html->meta('icon');
+
+ echo $html->css(array('generic', 'chaw', 'chaw.admin'));
+
+ echo $javascript->link('jquery-1.2.6.min');
+
+ echo $javascript->link('gshowdown');
+
+ //echo $javascript->link('smartarea');
+
+ //echo $javascript->link('MeatballSocietyCreoleV0.4');
+
+ //echo $javascript->link(array('wiky', 'wiky.lang', 'wiky.math'));
+
+ echo $scripts_for_layout;
+
+ ?>
+</head>
+<body class="admin">
+ <div id="container">
+ <div id="header">
+
+ <h1><?php echo $html->link(Configure::read('Project.name'), '/');?></h1>
+
+ <div id="navigation">
+ <ul>
+ <li><?php echo $html->link('Wiki', array('admin' => false, 'controller' => 'wiki', 'action' => 'index'));?></li>
+ <li><?php echo $html->link('Timeline', array('admin' => false, 'controller' => 'timeline', 'action' => 'index'));?></li>
+ <li><?php echo $html->link('Tickets', array('admin' => false, 'controller' => 'tickets', 'action' => 'index'));?></li>
+ <li><?php echo $html->link('Source', array('admin' => false, 'controller' => 'browser', 'action' => 'index'));?></li>
+ <li><?php echo $html->link('Versions', array('admin' => false, 'controller' => 'versions', 'action' => 'index'));?></li>
+ </ul>
+ </div>
+
+ </div>
+ <div id="content">
+
+
+ <?php
+ echo $this->element('current_user');
+
+ $session->flash();
+ ?>
+
+ <div class="clear"><!----></div>
+
+ <div id="admin-navigation">
+ <h4>Admin</h4>
+ <ul>
+ <li><?php
+ $class = ($this->name == 'Projects') ? 'on' : null;
+ echo $html->link('Projects', array('admin' => true, 'controller' => 'projects', 'action' => 'index'), compact('class'));
+ ?></li>
+ <li><?php
+ $class = ($this->name == 'Users') ? 'on' : null;
+ echo $html->link('Users', array('admin' => true, 'controller' => 'users', 'action' => 'index'), compact('class'));
+ ?></li>
+ <li><?php
+ $class = ($this->name == 'Permissions') ? 'on' : null;
+ echo $html->link('Permissions', array('admin' => true, 'controller' => 'permissions', 'action' => 'index'), compact('class'));
+ ?></li>
+
+ </ul>
+ </div>
+
+ <div id="admin-content">
+
+ <?php
+ echo $content_for_layout;
+ ?>
+ </div>
+
+
+ <div class="clear"><!----></div>
+
+ </div>
+
+
+ <div id="footer">
+ <?php echo $html->link(
+ $html->image('cake.power.gif', array('alt'=> __("CakePHP: the rapid development php framework", true), 'border'=>"0")),
+ 'http://www.cakephp.org/',
+ array('target'=>'_new'), null, false
+ );
+ ?>
+ </div>
+ </div>
+ <?php echo $cakeDebug?>
+</body>
+</html>
\ No newline at end of file
diff --git a/views/layouts/default.ctp b/views/layouts/default.ctp
index ce58c4a..0958b83 100755
--- a/views/layouts/default.ctp
+++ b/views/layouts/default.ctp
@@ -28,39 +28,63 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
- <?php __('CakePHP: the rapid development php framework:'); ?>
- <?php echo $title_for_layout;?>
+ <?php echo Configure::read('Project.name') .' : ' . $title_for_layout;?>
</title>
<?php
echo $html->charset();
echo $html->meta('icon');
- echo $html->css('creampuff');
+ echo $html->css(array('generic', 'chaw'));
+ //echo $html->css('highlight/idea');
- echo $javascript->link('MeatballSocietyCreoleV0.4');
+
+ echo $javascript->link('jquery-1.2.6.min');
+
+ echo $javascript->link('gshowdown');
+
+ //echo $javascript->link('smartarea');
+
+ //echo $javascript->link('MeatballSocietyCreoleV0.4');
+
+ //echo $javascript->link(array('wiky', 'wiky.lang', 'wiky.math'));
echo $scripts_for_layout;
+
?>
- <script>
- var text = $("description").innerHtml;
- toXHTML('=== this is a an h3');
- </script>
</head>
<body>
<div id="container">
<div id="header">
- <h1><?php echo $html->link(__('CakePHP: the rapid development php framework', true), 'http://cakephp.org');?></h1>
+
+ <h1><?php echo $html->link(Configure::read('Project.name'), '/');?></h1>
+
+ <div id="navigation">
+ <ul>
+ <li><?php echo $html->link('Wiki', array('controller' => 'wiki', 'action' => 'index'));?></li>
+ <li><?php echo $html->link('Timeline', array('controller' => 'timeline', 'action' => 'index'));?></li>
+ <li><?php echo $html->link('Tickets', array('controller' => 'tickets', 'action' => 'index'));?></li>
+ <li><?php echo $html->link('Source', array('controller' => 'browser', 'action' => 'index'));?></li>
+ <li><?php echo $html->link('Versions', array('controller' => 'versions', 'action' => 'index'));?></li>
+ <li><?php echo $html->link('Admin', array('admin' => true, 'controller' => 'dashboard', 'action' => 'index'));?></li>
+ </ul>
+ </div>
+
</div>
+
<div id="content">
<?php
- if ($session->check('Message.flash')):
- $session->flash();
- endif;
- ?>
+ echo $this->element('current_user');
- <?php echo $content_for_layout;?>
+ $session->flash();
+ ?>
+ <div id="page-content">
+ <?php
+ echo $content_for_layout;
+ ?>
+ </div>
</div>
+
<div id="footer">
<?php echo $html->link(
$html->image('cake.power.gif', array('alt'=> __("CakePHP: the rapid development php framework", true), 'border'=>"0")),
diff --git a/views/permissions/admin_add.ctp b/views/permissions/admin_add.ctp
new file mode 100644
index 0000000..3b10487
--- /dev/null
+++ b/views/permissions/admin_add.ctp
@@ -0,0 +1,14 @@
+<div class="permissions form">
+<?php echo $form->create('Permission');?>
+ <fieldset>
+ <legend><?php __('Add Permission');?></legend>
+ <?php
+ echo $form->input('user_id', array('after' => ' <strong>is a friendly</strong>'));
+ echo $form->input('group');
+
+ echo $form->input('fine_grained', array('type' => 'textarea'));
+
+ ?>
+ </fieldset>
+<?php echo $form->end('Submit');?>
+</div>
diff --git a/views/permissions/admin_index.ctp b/views/permissions/admin_index.ctp
new file mode 100644
index 0000000..c6f475c
--- /dev/null
+++ b/views/permissions/admin_index.ctp
@@ -0,0 +1 @@
+<?php echo $html->link('Permissions', array('controller' => 'permissions', 'action'=>'add')); ?>
\ No newline at end of file
diff --git a/views/projects/add.ctp b/views/projects/add.ctp
new file mode 100644
index 0000000..85576ca
--- /dev/null
+++ b/views/projects/add.ctp
@@ -0,0 +1,19 @@
+<div class="projects form">
+<?php echo $form->create(array('action' => $this->action));?>
+ <fieldset>
+ <legend><?php echo $this->pageTitle; ?></legend>
+ <?php
+ echo $form->input('id');
+ echo $form->input('repo_type');
+ echo $form->input('name');
+ echo $form->input('groups');
+ echo $form->input('ticket_types');
+ echo $form->input('ticket_priorities');
+ echo $form->input('ticket_statuses');
+ echo $form->input('description');
+ echo $form->input('private');
+ echo $form->input('active');
+ ?>
+ </fieldset>
+<?php echo $form->end('Submit');?>
+</div>
\ No newline at end of file
diff --git a/views/projects/edit.ctp b/views/projects/edit.ctp
new file mode 100644
index 0000000..fad366d
--- /dev/null
+++ b/views/projects/edit.ctp
@@ -0,0 +1,20 @@
+<div class="projects form">
+<?php echo $form->create(array('action' => $this->action));?>
+ <fieldset>
+ <legend><?php echo $this->pageTitle; ?></legend>
+ <?php
+ echo $form->input('id');
+ echo $form->hidden('repo_type');
+ echo $form->input('name', array('disabled' => true));
+ echo $form->hidden('url');
+ echo $form->input('groups');
+ echo $form->input('ticket_types');
+ echo $form->input('ticket_priorities');
+ echo $form->input('ticket_statuses');
+ echo $form->input('description');
+ echo $form->input('private');
+ echo $form->input('active');
+ ?>
+ </fieldset>
+<?php echo $form->end('Submit');?>
+</div>
\ No newline at end of file
diff --git a/views/projects/index.ctp b/views/projects/index.ctp
new file mode 100644
index 0000000..a879808
--- /dev/null
+++ b/views/projects/index.ctp
@@ -0,0 +1,28 @@
+<div class="projects index">
+<?php foreach ((array)$projects as $project):?>
+
+ <div class="project">
+
+ <h3 class="name">
+ <?php
+ echo $html->link($project['Project']['name'], array(
+ 'admin' => false,
+ 'controller' => 'wiki', 'action' => 'index',
+ ));?>
+ </h3>
+
+ <p class="description">
+ <?php echo $project['Project']['description'];?>
+ </p>
+
+ </div>
+
+<?php endforeach;?>
+
+<?php
+ echo $paginator->prev();
+ echo $paginator->numbers(array('before' => ' | ', 'after' => ' | '));
+ echo $paginator->next();
+?>
+
+</div>
\ No newline at end of file
diff --git a/views/projects/view.ctp b/views/projects/view.ctp
new file mode 100644
index 0000000..5970d9c
--- /dev/null
+++ b/views/projects/view.ctp
@@ -0,0 +1,11 @@
+<div class="project">
+
+ <h3 class="name">
+ <?php echo $html->link($project['Project']['name'], array('controller' => 'projects', 'action' => 'view', 'project' => $project['Project']['url']));?>
+ </h3>
+
+ <p class="name">
+ <?php echo $project['Project']['description'];?>
+ </p>
+
+</div>
\ No newline at end of file
diff --git a/views/tickets/add.ctp b/views/tickets/add.ctp
new file mode 100644
index 0000000..5e69f85
--- /dev/null
+++ b/views/tickets/add.ctp
@@ -0,0 +1,55 @@
+<?php
+$script = '
+$(document).ready(function(){
+ converter = new Showdown.converter("' . $this->webroot . '");
+ $("#Preview").html(converter.makeHtml($("#TicketDescription").val()));
+ $("#TicketDescription").bind("keyup", function() {
+ $("#Preview").html("<h3>Preview</h3>" + converter.makeHtml($(this).val()));
+ });
+ //$("#WikiContent").smartArea();
+});
+';
+$javascript->codeBlock($script, array('inline' => false));
+?>
+<div class="tickets add form">
+<?php echo $form->create('Ticket');?>
+ <fieldset class="main">
+ <legend><?php __('Add Ticket');?></legend>
+ <?php
+ echo $form->input('title');
+ echo $form->input('description');
+ ?>
+
+ <div class="input">
+ <div id="Preview"></div>
+ </div>
+
+ </fieldset>
+
+
+ <fieldset class="options">
+ <legend>Tags</legend>
+ <?php
+ echo $form->textarea('tags');
+ ?>
+ comma separated
+ </fieldset>
+
+
+ <fieldset class="options">
+ <legend>Options</legend>
+ <?php
+ if (!empty($versions)) {
+ echo $form->input('version_id');
+ }
+ echo $form->input('type');
+ echo $form->input('priority');
+ ?>
+ </fieldset>
+
+ <div class="help">
+ <?php echo $this->element('markdown_help'); ?>
+ </div>
+
+<?php echo $form->end('Submit');?>
+</div>
\ No newline at end of file
diff --git a/views/tickets/index.ctp b/views/tickets/index.ctp
new file mode 100644
index 0000000..896d6af
--- /dev/null
+++ b/views/tickets/index.ctp
@@ -0,0 +1,63 @@
+<div class="tickets index">
+<h2>Tickets</h2>
+<p>
+<?php
+echo $paginator->counter(array(
+'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true)
+));
+?></p>
+<table cellpadding="0" cellspacing="0">
+<tr>
+ <th><?php echo $paginator->sort('id');?></th>
+ <th><?php echo $paginator->sort('title');?></th>
+ <?php if (!empty($ticket['Version']['title'])):?>
+ <th><?php echo $paginator->sort('version_id');?></th>
+ <?php endif;?>
+ <th><?php echo $paginator->sort('type');?></th>
+ <th><?php echo $paginator->sort('priority');?></th>
+ <th><?php echo $paginator->sort('status');?></th>
+ <th><?php echo $paginator->sort('created');?></th>
+</tr>
+<?php
+$i = 0;
+foreach ($tickets as $ticket):
+ $class = null;
+ if ($i++ % 2 == 0) {
+ $class = ' class="altrow"';
+ }
+?>
+ <tr<?php echo $class;?>>
+ <td>
+ <?php echo $ticket['Ticket']['id']; ?>
+ </td>
+ <td>
+ <?php echo $html->link($ticket['Ticket']['title'], array('controller'=> 'tickets', 'action'=>'view', 'id' => $ticket['Ticket']['id'])); ?>
+ </td>
+ <?php if (!empty($ticket['Version']['title'])):?>
+ <td>
+ <?php echo $html->link($ticket['Version']['title'], array('controller'=> 'versions', 'action'=>'view', $ticket['Version']['id'])); ?>
+ </td>
+ <?php endif;?>
+ <td>
+ <?php echo $ticket['Ticket']['type']; ?>
+ </td>
+ <td>
+ <?php echo $ticket['Ticket']['priority']; ?>
+ </td>
+ <td>
+ <?php echo $ticket['Ticket']['status']; ?>
+ </td>
+ <td>
+ <?php echo $ticket['Ticket']['created']; ?>
+ </td>
+ </tr>
+<?php endforeach; ?>
+</table>
+</div>
+<div class="paging">
+ <?php echo $paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled'));?>
+ | <?php echo $paginator->numbers();?>
+ <?php echo $paginator->next(__('next', true).' >>', array(), null, array('class'=>'disabled'));?>
+</div>
+
+<?php echo $html->link('New Ticket', array('controller' => 'tickets', 'action'=>'add')); ?>
\ No newline at end of file
diff --git a/views/tickets/view.ctp b/views/tickets/view.ctp
new file mode 100644
index 0000000..22e0312
--- /dev/null
+++ b/views/tickets/view.ctp
@@ -0,0 +1,121 @@
+<?php
+$script = '
+$(document).ready(function(){
+ converter = new Showdown.converter("' . $this->webroot . '");
+ $("#Preview").html(converter.makeHtml(jQuery.trim($("#Preview").text())));
+ $("#TicketDescription").bind("keyup", function() {
+ $("#Preview").html(converter.makeHtml($(this).val()));
+ });
+ $(".modify").click(function() {
+ $("#modify").show();
+ });
+ $(".close").click(function() {
+ $("#modify").hide();
+ });
+ $(".body").each(function () {
+ $(this).html(converter.makeHtml(jQuery.trim($(this).text())))
+ });
+});
+';
+$javascript->codeBlock($script, array('inline' => false));
+?>
+<h2>
+ <?php echo ucwords($ticket['Ticket']['type']);?> Ticket
+ (<em><?php echo $ticket['Ticket']['status'];?></em>)
+</h2>
+<div class="tickets view">
+ <h3 class="title">
+ <?php echo $ticket['Ticket']['title'];?>
+ <?php if (!empty($CurrentUser->id)): ?>
+ <em>(<a href="#modify" class="modify">edit</a>)</em>
+ <?php endif; ?>
+ </h3>
+
+ <div id="Preview" class="description">
+ <?php echo $ticket['Ticket']['description']; ?>
+ </div>
+
+ <div class="ticket edit">
+
+ <?php if (!empty($CurrentUser->id)): ?>
+
+ <?php echo $form->create(array('action' => 'modify'));?>
+
+ <div id="modify" style="display:none">
+ <fieldset class="main">
+ <legend>
+ <?php __('Modify Ticket');?>
+ <em>(<a href="#" class="close">close</a>)</em>
+ </legend>
+
+ <?php
+ echo $form->input('id');
+ echo $form->input('title');
+ echo $form->input('description');
+ ?>
+ </fieldset>
+
+ <fieldset class="options">
+ <legend>Tags</legend>
+ <?php
+ echo $form->textarea('tags');
+ ?>
+ comma separated
+ </fieldset>
+
+ <div class="help">
+ <?php echo $this->element('markdown_help'); ?>
+ </div>
+
+ </div>
+
+ <?php endif; ?>
+
+ <?php foreach ((array)$ticket['Comment'] as $comment): ?>
+
+ <div class="comment">
+ <span class="date">
+ <?php echo $time->timeAgoInWords($comment['created']);?>
+ </span>
+ <span class="user">
+ by <?php echo $comment['User']['username'];?>
+ </span>
+ <div class="body">
+ <?php echo $html->clean($comment['body']);?>
+ </div>
+ </div>
+
+ <?php endforeach; ?>
+
+ <?php if (!empty($CurrentUser->id)): ?>
+
+ <fieldset class="main">
+ <legend>
+ <?php __('Comment');?>
+ </legend>
+ <?php
+ echo $form->input('status');
+ echo $form->textarea('comment');
+ ?>
+ </fieldset>
+
+ <fieldset class="options">
+ <legend>Options</legend>
+ <?php
+ echo $form->input('version_id');
+ echo $form->input('type');
+ echo $form->input('priority');
+ ?>
+ </fieldset>
+
+ <div class="submit">
+ <?php echo $form->submit('Submit', array('div' => false));?>
+ </div>
+
+
+ <?php echo $form->end();?>
+
+ <?php endif; ?>
+ </div>
+
+</div>
\ No newline at end of file
diff --git a/views/timeline/index.ctp b/views/timeline/index.ctp
new file mode 100644
index 0000000..950c62c
--- /dev/null
+++ b/views/timeline/index.ctp
@@ -0,0 +1,34 @@
+<?php
+$script = '
+$(document).ready(function(){
+ converter = new Showdown.converter("' . $this->webroot . '");
+ $(".summary").each(function () {
+ $(this).html(converter.makeHtml(jQuery.trim($(this).text())))
+ });
+});
+';
+$javascript->codeBlock($script, array('inline' => false));
+?>
+
+<h2>Timeline</h2>
+
+<div class="timeline index">
+ <?php foreach ((array)$timeline as $event):?>
+
+ <div class="timeline">
+
+ <p class="summary">
+ <?php echo $event['Timeline']['summary'];?>
+ </p>
+
+ </div>
+
+ <?php endforeach;?>
+
+ <?php
+ echo $paginator->prev();
+ echo $paginator->numbers(array('before' => ' | ', 'after' => ' | '));
+ echo $paginator->next();
+ ?>
+
+</div>
\ No newline at end of file
diff --git a/views/users/add.ctp b/views/users/add.ctp
new file mode 100644
index 0000000..3ab617c
--- /dev/null
+++ b/views/users/add.ctp
@@ -0,0 +1,12 @@
+<div class="users form">
+<?php echo $form->create('User');?>
+ <fieldset>
+ <legend><?php __('Register');?></legend>
+ <?php
+ echo $form->input('username');
+ echo $form->input('password');
+ echo $form->input('email');
+ ?>
+ </fieldset>
+<?php echo $form->end('Submit');?>
+</div>
diff --git a/views/users/admin_index.ctp b/views/users/admin_index.ctp
new file mode 100644
index 0000000..2c77a28
--- /dev/null
+++ b/views/users/admin_index.ctp
@@ -0,0 +1,53 @@
+<div class="users index">
+<h2><?php __('Users');?></h2>
+<p>
+<?php
+echo $paginator->counter(array(
+'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true)
+));
+?></p>
+<table cellpadding="0" cellspacing="0">
+<tr>
+ <th><?php echo $paginator->sort('id');?></th>
+ <th><?php echo $paginator->sort('username');?></th>
+ <th><?php echo $paginator->sort('email');?></th>
+ <th class="actions"><?php __('Actions');?></th>
+</tr>
+<?php
+$i = 0;
+foreach ($users as $user):
+ $class = null;
+ if ($i++ % 2 == 0) {
+ $class = ' class="altrow"';
+ }
+?>
+ <tr<?php echo $class;?>>
+ <td>
+ <?php echo $user['User']['id']; ?>
+ </td>
+ <td>
+ <?php echo $user['User']['username']; ?>
+ </td>
+ <td>
+ <?php echo $user['User']['email']; ?>
+ </td>
+ <td class="actions">
+ <?php echo $html->link(__('View', true), array('action'=>'view', $user['User']['id'])); ?>
+ <?php echo $html->link(__('Edit', true), array('action'=>'edit', $user['User']['id'])); ?>
+ </td>
+ </tr>
+<?php endforeach; ?>
+</table>
+</div>
+<div class="paging">
+ <?php echo $paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled'));?>
+ | <?php echo $paginator->numbers();?>
+ <?php echo $paginator->next(__('next', true).' >>', array(), null, array('class'=>'disabled'));?>
+</div>
+<div class="actions">
+ <ul>
+ <li><?php echo $html->link(__('New User', true), array('action'=>'add')); ?></li>
+ <li><?php echo $html->link(__('List Permissions', true), array('controller'=> 'permissions', 'action'=>'index')); ?> </li>
+ <li><?php echo $html->link(__('New Permission', true), array('controller'=> 'permissions', 'action'=>'add')); ?> </li>
+ </ul>
+</div>
diff --git a/views/users/edit.ctp b/views/users/edit.ctp
new file mode 100644
index 0000000..bd2f312
--- /dev/null
+++ b/views/users/edit.ctp
@@ -0,0 +1,12 @@
+<div class="users form">
+<?php echo $form->create('User');?>
+ <fieldset>
+ <legend><?php __('Update Info');?></legend>
+ <?php
+ echo $form->input('id');
+ echo $form->input('email');
+ echo $form->input('ssh_key');
+ ?>
+ </fieldset>
+<?php echo $form->end('Submit');?>
+</div>
diff --git a/views/users/index.ctp b/views/users/index.ctp
new file mode 100644
index 0000000..97d4b25
--- /dev/null
+++ b/views/users/index.ctp
@@ -0,0 +1,70 @@
+<div class="users index">
+<h2><?php __('Users');?></h2>
+<p>
+<?php
+echo $paginator->counter(array(
+'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true)
+));
+?></p>
+<table cellpadding="0" cellspacing="0">
+<tr>
+ <th><?php echo $paginator->sort('id');?></th>
+ <th><?php echo $paginator->sort('username');?></th>
+ <th><?php echo $paginator->sort('password');?></th>
+ <th><?php echo $paginator->sort('email');?></th>
+ <th><?php echo $paginator->sort('last_login');?></th>
+ <th><?php echo $paginator->sort('created');?></th>
+ <th><?php echo $paginator->sort('modified');?></th>
+ <th class="actions"><?php __('Actions');?></th>
+</tr>
+<?php
+$i = 0;
+foreach ($users as $user):
+ $class = null;
+ if ($i++ % 2 == 0) {
+ $class = ' class="altrow"';
+ }
+?>
+ <tr<?php echo $class;?>>
+ <td>
+ <?php echo $user['User']['id']; ?>
+ </td>
+ <td>
+ <?php echo $user['User']['username']; ?>
+ </td>
+ <td>
+ <?php echo $user['User']['password']; ?>
+ </td>
+ <td>
+ <?php echo $user['User']['email']; ?>
+ </td>
+ <td>
+ <?php echo $user['User']['last_login']; ?>
+ </td>
+ <td>
+ <?php echo $user['User']['created']; ?>
+ </td>
+ <td>
+ <?php echo $user['User']['modified']; ?>
+ </td>
+ <td class="actions">
+ <?php echo $html->link(__('View', true), array('action'=>'view', $user['User']['id'])); ?>
+ <?php echo $html->link(__('Edit', true), array('action'=>'edit', $user['User']['id'])); ?>
+ <?php echo $html->link(__('Delete', true), array('action'=>'delete', $user['User']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $user['User']['id'])); ?>
+ </td>
+ </tr>
+<?php endforeach; ?>
+</table>
+</div>
+<div class="paging">
+ <?php echo $paginator->prev('<< '.__('previous', true), array(), null, array('class'=>'disabled'));?>
+ | <?php echo $paginator->numbers();?>
+ <?php echo $paginator->next(__('next', true).' >>', array(), null, array('class'=>'disabled'));?>
+</div>
+<div class="actions">
+ <ul>
+ <li><?php echo $html->link(__('New User', true), array('action'=>'add')); ?></li>
+ <li><?php echo $html->link(__('List Permissions', true), array('controller'=> 'permissions', 'action'=>'index')); ?> </li>
+ <li><?php echo $html->link(__('New Permission', true), array('controller'=> 'permissions', 'action'=>'add')); ?> </li>
+ </ul>
+</div>
diff --git a/views/users/login.ctp b/views/users/login.ctp
new file mode 100644
index 0000000..8188642
--- /dev/null
+++ b/views/users/login.ctp
@@ -0,0 +1,11 @@
+<div class="users login form">
+<?php echo $form->create(array('action' => 'login'));?>
+ <fieldset>
+ <legend><?php __('Login');?></legend>
+ <?php
+ echo $form->input('username');
+ echo $form->input('password');
+ ?>
+ </fieldset>
+<?php echo $form->end('Submit');?>
+</div>
\ No newline at end of file
diff --git a/views/versions/admin_add.ctp b/views/versions/admin_add.ctp
new file mode 100644
index 0000000..3219c3b
--- /dev/null
+++ b/views/versions/admin_add.ctp
@@ -0,0 +1,18 @@
+<div class="versions form">
+<?php echo $form->create(array('action' => $this->action));?>
+ <fieldset class="main">
+ <legend><?php echo $this->pageTitle;?></legend>
+ <?php
+ echo $form->input('title');
+ echo $form->input('description');
+ echo $form->input('due_date');
+ echo $form->input('completed');
+ ?>
+ </fieldset>
+
+ <div class="help">
+ <?php echo $this->element('markdown_help'); ?>
+ </div>
+
+<?php echo $form->end('Submit');?>
+</div>
\ No newline at end of file
diff --git a/views/versions/admin_edit.ctp b/views/versions/admin_edit.ctp
new file mode 100644
index 0000000..b4f2145
--- /dev/null
+++ b/views/versions/admin_edit.ctp
@@ -0,0 +1,14 @@
+<div class="versions form">
+<?php echo $form->create(array('action' => $this->action));?>
+ <fieldset class="main">
+ <legend><?php echo $this->pageTitle;?></legend>
+ <?php
+ echo $form->input('id');
+ echo $form->input('title');
+ echo $form->input('description');
+ echo $form->input('due_date');
+ echo $form->input('completed');
+ ?>
+ </fieldset>
+<?php echo $form->end('Submit');?>
+</div>
diff --git a/views/versions/index.ctp b/views/versions/index.ctp
new file mode 100644
index 0000000..afdd780
--- /dev/null
+++ b/views/versions/index.ctp
@@ -0,0 +1,43 @@
+<?php
+$script = '
+$(document).ready(function(){
+ converter = new Showdown.converter("' . $this->webroot . '");
+ $(".summary").each(function () {
+ $(this).html(converter.makeHtml(jQuery.trim($(this).text())))
+ });
+});
+';
+$javascript->codeBlock($script, array('inline' => false));
+?>
+
+<h2>Versions</h2>
+
+<div class="versions index">
+ <?php foreach ((array)$versions as $version):?>
+
+ <div class="version">
+ <h3>
+ <?php echo $version['Version']['title'];?>
+ </h3>
+ <span class="created">
+ <?php echo $version['Version']['created'];?>
+ </span>
+
+ <p class="summary">
+ <?php echo $version['Version']['description'];?>
+ </p>
+
+ </div>
+
+ <?php endforeach;?>
+
+ <?php
+ echo $paginator->prev();
+ echo $paginator->numbers(array('before' => ' | ', 'after' => ' | '));
+ echo $paginator->next();
+ ?>
+
+</div>
+<?php
+ echo $html->link('New Version', array('admin' => true, 'controller' => 'versions', 'action' => 'add'));
+?>
\ No newline at end of file
diff --git a/views/versions/view.ctp b/views/versions/view.ctp
new file mode 100644
index 0000000..c9cf133
--- /dev/null
+++ b/views/versions/view.ctp
@@ -0,0 +1,48 @@
+<div class="versions view">
+<h2><?php __('Version');?></h2>
+ <dl><?php $i = 0; $class = ' class="altrow"';?>
+ <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Id'); ?></dt>
+ <dd<?php if ($i++ % 2 == 0) echo $class;?>>
+ <?php echo $version['Version']['id']; ?>
+
+ </dd>
+ <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Title'); ?></dt>
+ <dd<?php if ($i++ % 2 == 0) echo $class;?>>
+ <?php echo $version['Version']['title']; ?>
+
+ </dd>
+ <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Description'); ?></dt>
+ <dd<?php if ($i++ % 2 == 0) echo $class;?>>
+ <?php echo $version['Version']['description']; ?>
+
+ </dd>
+ <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Created'); ?></dt>
+ <dd<?php if ($i++ % 2 == 0) echo $class;?>>
+ <?php echo $version['Version']['created']; ?>
+
+ </dd>
+ <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Modified'); ?></dt>
+ <dd<?php if ($i++ % 2 == 0) echo $class;?>>
+ <?php echo $version['Version']['modified']; ?>
+
+ </dd>
+ <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Completed'); ?></dt>
+ <dd<?php if ($i++ % 2 == 0) echo $class;?>>
+ <?php echo $version['Version']['completed']; ?>
+
+ </dd>
+ <dt<?php if ($i % 2 == 0) echo $class;?>><?php __('Due'); ?></dt>
+ <dd<?php if ($i++ % 2 == 0) echo $class;?>>
+ <?php echo $version['Version']['due']; ?>
+
+ </dd>
+ </dl>
+</div>
+<div class="actions">
+ <ul>
+ <li><?php echo $html->link(__('Edit Version', true), array('action'=>'edit', $version['Version']['id'])); ?> </li>
+ <li><?php echo $html->link(__('Delete Version', true), array('action'=>'delete', $version['Version']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $version['Version']['id'])); ?> </li>
+ <li><?php echo $html->link(__('List Versions', true), array('action'=>'index')); ?> </li>
+ <li><?php echo $html->link(__('New Version', true), array('action'=>'add')); ?> </li>
+ </ul>
+</div>
diff --git a/views/wiki/add.ctp b/views/wiki/add.ctp
index 48e5fcb..dd68c9f 100644
--- a/views/wiki/add.ctp
+++ b/views/wiki/add.ctp
@@ -1,11 +1,49 @@
+<?php
+/*
+$script = '
+$(document).ready(function(){
+ $("#Html").html(Wiky.toHtml($("#Text").val()));
+});
+';
+*/
+$script = '
+$(document).ready(function(){
+ converter = new Showdown.converter("' . $this->webroot . '");
+ $("#Preview").html(converter.makeHtml(jQuery.trim($("#WikiContent").val())));
+ $("#WikiContent").bind("keyup", function() {
+ $("#Preview").html("<h3>Preview</h3>" + converter.makeHtml($(this).val()));
+ });
+ //$("#WikiContent").smartArea();
+});
+';
+$javascript->codeBlock($script, array('inline' => false));
+?>
+
<div class="wiki form">
-<?php echo $form->create();?>
- <fieldset>
- <legend>Create <?php echo $this->pageTitle; ?></legend>
- <?php
- echo $form->hidden('slug');
- echo $form->input('content');
- ?>
- </fieldset>
-<?php echo $form->end('Submit');?>
+
+ <?php echo $form->create();?>
+ <fieldset>
+ <legend><?php echo $this->pageTitle; ?></legend>
+ <?php
+ if ($form->value('slug')) {
+ echo $form->hidden('slug');
+ } else {
+ echo $form->input('slug', array('label' => 'Title'));
+ }
+ echo $form->input('content', array('label' => 'Text'));
+ ?>
+
+ <div class="input">
+ <span id="Preview"></span>
+ </div>
+
+ </fieldset>
+
+
+ <?php echo $form->end('Submit');?>
+
+ <div class="help">
+ <?php echo $this->element('markdown_help'); ?>
+ </div>
+
</div>
\ No newline at end of file
diff --git a/views/wiki/edit.ctp b/views/wiki/edit.ctp
new file mode 100644
index 0000000..f43a873
--- /dev/null
+++ b/views/wiki/edit.ctp
@@ -0,0 +1,52 @@
+<?php
+/*
+For creole
+$script = '
+ function updateRender() {
+ $("Html").innerHTML = toXHTML($("Text").value);
+ }
+ function installRenderer() {
+ element = $("Text");
+ element.onkeyup = element.onkeypress = element.ondrop = element.onchange = updateRender;
+ updateRender();
+ }
+
+ window.onload = installRenderer;
+';
+*/
+$script = '
+$(document).ready(function(){
+ converter = new Showdown.converter("' . $this->webroot . '");
+ $("#Html").html(converter.makeHtml($("#WikiContent").val()));
+ $("#WikiContent").bind("keyup", function() {
+ $("#Html").html(converter.makeHtml($(this).val()));
+ });
+ //$("#WikiContent").smartArea();
+});
+';
+$javascript->codeBlock($script, array('inline' => false));
+
+?>
+
+<div class="wiki form">
+
+ <?php echo $form->create(array('action' => 'edit'));?>
+ <fieldset>
+ <legend>Edit: <?php echo $this->pageTitle; ?></legend>
+ <?php
+ echo $form->hidden('id');
+ echo $form->hidden('slug');
+ echo $form->input('content', array('label' => 'Text'));
+ ?>
+ </fieldset>
+
+ <h3>Live Preview</h3>
+ <div id="Html"></div>
+
+ <?php echo $form->end('Submit');?>
+
+ <div class="help">
+ <?php echo $this->element('markdown_help'); ?>
+ </div>
+
+</div>
\ No newline at end of file
diff --git a/views/wiki/view.ctp b/views/wiki/view.ctp
index f1c8285..e4aeb85 100644
--- a/views/wiki/view.ctp
+++ b/views/wiki/view.ctp
@@ -1,3 +1,17 @@
-<div class="wiki view">
+<?php
+$script = '
+$(document).ready(function(){
+ converter = new Showdown.converter("' . $this->webroot . '");
+ $("#WikiContent").html(converter.makeHtml(jQuery.trim($("#WikiContent").text())));
+});
+';
+$javascript->codeBlock($script, array('inline' => false));
+?>
+<div class="page-navigation">
+ <?php echo $html->link('New', array('controller' => 'wiki', 'action' => 'add'));?>
+ |
+ <?php echo $html->link('Edit', array('controller' => 'wiki', 'action' => 'edit', $wiki['Wiki']['slug']));?>
+</div>
+<div id="WikiContent" class="wiki view">
<?php echo $html->clean($wiki['Wiki']['content']); ?>
-</div>
\ No newline at end of file
+</div>
diff --git a/webroot/css/chaw.admin.css b/webroot/css/chaw.admin.css
new file mode 100644
index 0000000..b3b86a5
--- /dev/null
+++ b/webroot/css/chaw.admin.css
@@ -0,0 +1,43 @@
+#admin-content {
+ width:75%;
+ margin-left: 20px;
+ margin-right: 20px;
+}
+
+#admin-navigation {
+ clear: right;
+ float: right;
+ width: 20%;
+ margin-top: 30px;
+ margin-left: 20px;
+}
+
+#admin-navigation ul {
+ margin: 0;
+ padding: 0;
+ background: #f4f4f4;
+ border-top: 1px solid #e2e2e2;
+}
+
+#admin-navigation li {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+#admin-navigation li a {
+ display: block;
+ padding: 8px 10px;
+ text-decoration: none;
+ background: #f4f4f4;
+ border-bottom: 1px solid #e2e2e2;
+ border-left: 1px solid #e2e2e2;
+ border-right: 1px solid #e2e2e2;
+}
+
+#admin-navigation li a:hover, #admin-navigation li a.on {
+ display: block;
+ text-decoration: none;
+ background: #fff;
+ border-left: 1px solid #fff;
+}
diff --git a/webroot/css/chaw.css b/webroot/css/chaw.css
new file mode 100644
index 0000000..300a6e8
--- /dev/null
+++ b/webroot/css/chaw.css
@@ -0,0 +1,285 @@
+h2 {
+ color: #804000;
+}
+
+h3 {
+ color: #808000;
+}
+
+h4 {
+ color: #3b3b3b;
+}
+
+em a {
+ color: inherit;
+ font-size: 80%;
+}
+form {
+ clear: none;
+}
+fieldset legend {
+ color: #804000;
+}
+fieldset.main {
+ float: left;
+ margin-right: 40px;
+ width: 60%;
+}
+fieldset.options {
+ float: left;
+ width: 20%;
+}
+
+table {
+ clear: none;
+ float: left;
+ width: 100%;
+}
+
+#content {
+ clear: both;
+ padding-top: 0px;
+ padding-left: 0px;
+ padding-right: 0px;
+ overflow: auto;
+ border-bottom: 1px solid #ddd;
+}
+
+#page-content {
+ padding-left: 20px;
+ padding-right: 20px;
+}
+
+#flashMessage {
+ background: #f4f4f4;
+ margin-top: 0px;
+ padding: 9px 8px 8px 20px;
+ font-size: 110%;
+}
+
+#navigation {
+ margin-top: 1px;
+ margin-left: 20px;
+ white-space: nowrap;
+}
+
+#navigation ul, #navigation li {
+ display: inline;
+}
+
+#navigation li a {
+ padding: 10px;
+ color: #fff;
+ text-decoration: none;
+}
+
+#navigation li a:hover {
+ padding: 10px;
+ background-color: #fff;
+ color: #333;
+ text-decoration: none;
+}
+
+#current-user {
+ /*
+ border-top: 1px solid #3b3b3b;
+ position: fixed;
+ width: 100%;
+ top: auto;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ */
+ clear: both;
+ float: right;
+ margin-top: 0px;
+ margin-left: 20px;
+ background: #f4f4f4;
+ padding: 4px 0px;
+ width: 20%;
+}
+#current-user span {
+ padding-right: 6px;
+}
+#current-user .gravatar {
+ padding-left: 6px;
+}
+#current-user .gravatar img {
+ vertical-align: middle;
+ padding: 2px;
+ background: #fff;
+}
+#current-user span a {
+ padding: 2px 10px;
+ text-decoration: none;
+ color: #69C;
+}
+#current-user span a:hover {
+ text-decoration: underline;
+}
+
+.left {
+ float:left;
+ margin-right: 20px;
+}
+.right {
+ float:right;
+ margin-right: 20px;
+}
+.view .textarea textarea {
+ height: 200px;
+}
+
+fieldset.options select {
+ width: 100%;
+}
+fieldset.options textarea {
+ width: 100%;
+ height: 60px;
+}
+
+.wiki form {
+ float: left;
+ width: 76%;
+}
+.wiki .help {
+ float: right;
+ margin-top: 34px;
+ width: 20%;
+}
+.wiki textarea {
+ font-size: 12px;
+ height: 200px;
+}
+
+.timeline .summary {
+ padding-bottom: 20px;
+}
+.timeline .summary h3 {
+ font-size: 140%;
+}
+.timeline .summary p {
+ font-size: 120%;
+ margin-bottom: 4px;
+}
+.timeline .summary p strong {
+ font-size: 85%;
+}
+
+.tickets form {
+ min-width: 800px;
+ white-space: nowrap;
+}
+.tickets fieldset.main {
+ float: left;
+ margin-right: 40px;
+ width: 60%;
+}
+.tickets fieldset.options {
+ float: left;
+ width: 20%;
+}
+.tickets .textarea textarea {
+ font-size: 12px;
+ height: 400px;
+}
+.tickets .edit .textarea textarea {
+ font-size: 12px;
+ height: 200px;
+}
+.tickets div.help, .versions div.help {
+ float: left;
+ clear: none;
+ margin-top: 0;
+ width: 20%;
+}
+.tickets h3 em {
+ font-size: 80%;
+}
+.tickets .description {
+ width: 62%;
+ margin-bottom: 20px;
+}
+.tickets textarea#TicketComment {
+ height: 130px;
+}
+
+.comment {
+ width: 60%;
+ margin-bottom:1em;
+ padding:0.5em;
+}
+.comment .date {
+ font-weight: bold;
+}
+.comment .body {
+ border: 1px solid #ccc;
+ padding: 4px 8px;
+}
+.comment .body ul {
+ margin-bottom: 16px;
+}
+.comment .body li {
+ margin: 2px;
+}
+
+.browser h2 {
+ color: #333;
+}
+.browser table, .diff {
+ width: 100%;
+ border-collapse: collapse;
+ border: 1px solid #ccc;
+}
+.browser table th, .browser table td {
+ padding: 5px 10px;
+}
+.browser table th, .diff th {
+ border-left: 1px solid #ddd;
+ text-align: left;
+ background: #eee;
+ padding: 5px 10px;
+ border-bottom: 1px solid #ccc;
+ border-top: 1px solid #ccc;
+
+}
+.browser table td {
+ text-align: left;
+ background: #f7f7f7;
+ border-bottom: 1px solid #ccc;
+ border-left: 1px solid #ddd;
+}
+.browser table tr.zebra td {
+ background:#FAFAFA;
+}
+
+.versions div.help {
+ float: left;
+ clear: none;
+ margin-top: 2em;
+ width: 20%;
+}
+
+.projects form {
+ width: 60%;
+}
+
+.permissions form .select {
+ clear: none;
+ float: left;
+ margin-right: 0px;
+}
+.permissions form select {
+ margin-right: 10px;
+}
+.permissions form select option {
+ font-size: 20px;
+}
+.permissions textarea {
+ font-size: 12px;
+ height: 200px;
+}
+
+.users form {
+ width: 60%;
+}
\ No newline at end of file
diff --git a/webroot/css/generic.css b/webroot/css/generic.css
new file mode 100644
index 0000000..aba2c85
--- /dev/null
+++ b/webroot/css/generic.css
@@ -0,0 +1,428 @@
+/* SVN FILE: $Id: cake.generic.css 6314 2008-01-02 21:33:51Z phpnut $ */
+* {
+margin:0;
+padding:0;
+}
+.clear {
+clear:both;
+margin:0;
+padding:0;
+height:0;
+line-height:0;
+}
+.clear-left {
+clear:left;
+margin:0;
+padding:0;
+height:0;
+line-height:0;
+}
+.clear-right {
+clear:left;
+margin:0;
+padding:0;
+height:0;
+line-height:0;
+}
+
+/* General Style Info */
+body {
+ color: #333;
+ font-family: helvetica, arial, sans-serif;
+ font-size:90%;
+ margin: 0;
+ background-color: #f4f4f4;
+
+}
+a {
+ background-color: inherit;
+ color: #3b3b3b;
+ text-decoration: underline;
+ font-weight: bold;
+}
+a:hover {
+ background-color: inherit;
+ color: #3b3b3b;
+ text-decoration:none;
+}
+a img {
+ border:none;
+}
+h1, h2, h3, h4 {
+ background-color: inherit;
+ font-weight: normal;
+}
+h1 {
+ color: #3b3b3b;
+ font-size: 200%;
+ margin-top: 0.8em;
+ margin-bottom: 0.4em;
+}
+h2 {
+ color: #4C4C4C;
+ font-size: 180%;
+ font-weight: bold;
+ margin-top: 0.8em;
+ margin-bottom: 0.4em;
+}
+h3 {
+ color: #666;
+ font-size: 165%;
+ font-weight: bold;
+ margin-top: 0.8em;
+ margin-bottom: 0.4em;
+}
+h4 {
+ color: #656565;
+ font-weight: bold;
+ margin-top: 0.4em;
+ margin-bottom: 0.4em;
+}
+ul, li {
+ margin: 0 12px;
+}
+
+/* Layout */
+#container {
+ text-align: left;
+}
+
+#header{
+ background-color: #3b3b3b;
+ padding: 10px 20px;
+ overflow: hidden;
+ height: 16px;
+}
+#header h1 {
+ float:left;
+ color: #ffffff;
+ font-size: 16px;
+ padding: 0px 0px;
+ margin: 0;
+}
+#header h1 a {
+ color: #69C;
+ background: #3b3b3b;
+ font-weight: normal;
+ text-decoration: none;
+}
+#header h1 a:hover {
+ color: #ffffff;
+ background: #3b3b3b;
+ text-decoration: underline;
+}
+
+#content{
+ background-color: #fff;
+ clear: both;
+ color: #333;
+ padding: 0px 20px 40px 20px;
+}
+#footer {
+ clear: both;
+ padding: 6px 10px;
+ text-align: right;
+}
+
+/* Tables */
+table {
+ background-color: #fff;
+ border-top: 1px solid #ccc;
+ border-left: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ clear: both;
+ color: #333;
+ margin-bottom: 10px;
+ width: 100%;
+}
+th {
+ background-color: #f2f2f2;
+ border-top: 1px solid #fff;
+ border-left: 1px solid #fff;
+ border-right: 1px solid #bbb;
+ border-bottom: 1px solid #bbb;
+ text-align: center;
+}
+th a {
+ display: block;
+ padding: 2px 4px;
+ text-decoration: none;
+}
+th a:hover {
+ background-color: #ccc;
+ color: #333;
+ text-decoration: none;
+}
+table tr td {
+ background: #fff;
+ border-right: 1px solid #ccc;
+ padding: 4px;
+ text-align: center;
+ vertical-align: top;
+}
+table tr.altrow td {
+ background: #f4f4f4;
+}
+td.actions {
+ text-align: center;
+ white-space: nowrap;
+}
+td.actions a {
+ display: inline;
+ margin: 0px 6px;
+}
+.cake-sql-log table {
+ background: #f4f4f4;
+}
+.cake-sql-log td {
+ padding: 4px 8px;
+ text-align: left;
+}
+
+/* Paging */
+div.paging {
+ clear: both;
+ color: #ccc;
+ margin-bottom: 2em;
+}
+div.paging div.disabled {
+ color: #ddd;
+ display: inline;
+}
+div.paging span {
+}
+div.paging span.current {
+ color: #000;
+}
+div.paging span a {
+}
+
+/* Scaffold View */
+dl {
+ line-height: 2em;
+ margin: 0em 0em;
+ width: 60%;
+}
+dl.altrow {
+ background: #f4f4f4;
+}
+dt {
+ font-weight: bold;
+ padding-left: 4px;
+ vertical-align: top;
+}
+dd {
+ margin-left: 10em;
+ margin-top: -2em;
+ vertical-align: top;
+}
+
+/* Forms */
+form {
+ clear: both;
+ margin-right: 20px;
+ padding: 0;
+}
+fieldset {
+ border: 1px solid #ccc;
+ margin-top: 30px;
+ padding: 16px 20px;
+}
+fieldset legend {
+ color: #4c4c4c;
+ font-size: 160%;
+ font-weight: bold;
+}
+fieldset fieldset {
+ margin-top: 0px;
+ margin-bottom: 20px;
+ padding: 16px 0;
+}
+fieldset fieldset legend {
+ font-size: 120%;
+ font-weight: normal;
+ margin-left: 20px;
+}
+fieldset fieldset div {
+ clear: left;
+ margin: 0 20px;
+}
+form div {
+ clear: both;
+ margin-bottom: 1em;
+ padding: .5em;
+ vertical-align: text-top;
+}
+form div.input {
+ color: #444;
+}
+form div.required {
+ color: #333;
+ font-weight: bold;
+}
+form div.submit {
+ border: 0;
+ clear: both;
+ margin-top: 10px;
+ margin-left: 140px;
+}
+label {
+ display: block;
+ font-size: 110%;
+ padding-right: 20px;
+}
+input, textarea {
+ clear: both;
+ display: block;
+ font-size: 140%;
+ font-family: "frutiger linotype", "lucida grande", "verdana", sans-serif;
+ padding: 2px;
+ width: 100%;
+}
+select {
+ clear: both;
+ font-size: 120%;
+ vertical-align: text-bottom;
+}
+select[multiple=multiple] {
+ width: 100%;
+}
+option {
+ font-size: 120%;
+ padding: 0 3px;
+}
+input[type=radio] {
+ clear: left;
+ float: left;
+ margin: 0px 6px 7px 2px;
+ width: auto;
+}
+input[type=checkbox] {
+ clear: left;
+ float: left;
+ margin: 0px 6px 7px 2px;
+ width: auto;
+}
+input[type=submit] {
+ display: inline;
+ font-size: 110%;
+ padding: 2px 5px;
+ width: auto;
+ vertical-align: bottom;
+}
+
+/* Notices and Errors */
+div.message {
+ color: #69C;
+ font-size: 140%;
+ font-weight: bold;
+ margin: 0.5em 0;
+}
+div.error-message {
+ color: #69C;
+ font-weight: bold;
+}
+p.error {
+ background-color: #e32;
+ color: #fff;
+ font-family: Courier, monospace;
+ font-size: 120%;
+ line-height: 140%;
+ padding: 0.8em;
+ margin: 1em 0;
+}
+p.error em {
+ color: #000;
+ font-weight: normal;
+ line-height: 140%;
+}
+.notice {
+ background-color: #ffcc00;
+ color: #000;
+ display: block;
+ font-family: Courier, monospace;
+ font-size: 120%;
+ line-height: 140%;
+ padding: 0.8em;
+ margin: 1em 0;
+}
+.success {
+ background-color: green;
+ color: #FFF;
+}
+
+/* Actions */
+div.actions ul {
+ margin: 0px 0;
+ padding: 0;
+}
+div.actions li {
+ display: inline;
+ list-style-type: none;
+ line-height: 2em;
+ margin: 0 2em 0 0;
+ white-space: nowrap;
+}
+div.actions ul li a {
+ color: #3b3b3b;
+ text-decoration: none;
+}
+div.actions ul li a:hover {
+ color: #333;
+ text-decoration: underline;
+}
+
+/* Related */
+div.related {
+ clear: both;
+ display: block;
+}
+
+/* Debugging */
+pre {
+ color: #000;
+ background: #f0f0f0;
+ padding: 1em;
+}
+pre.cake-debug {
+ background: #ffcc00;
+ font-size: 120%;
+ line-height: 140%;
+ margin-top: 1em;
+ overflow: auto;
+ position: relative;
+}
+div.cake-stack-trace {
+ background: #fff;
+ border: 4px dotted #ffcc00;
+ color: #333;
+ margin: 0px;
+ padding: 6px;
+ font-size: 120%;
+ line-height: 140%;
+ overflow: auto;
+ position: relative;
+}
+div.cake-code-dump pre {
+ position: relative;
+ overflow: auto;
+}
+div.cake-stack-trace pre, div.cake-code-dump pre {
+ color: #000000;
+ background-color: #F0F0F0;
+ margin: 0px;
+ padding: 1em;
+ overflow: auto;
+}
+div.cake-code-dump pre, div.cake-code-dump pre code {
+ clear: both;
+ font-size: 12px;
+ line-height: 15px;
+ margin: 4px 2px;
+ padding: 4px;
+ overflow: auto;
+}
+div.cake-code-dump span.code-highlight {
+ background-color: #FFFF00;
+ padding: 4px;
+}
diff --git a/webroot/css/highlight/ascetic.css b/webroot/css/highlight/ascetic.css
new file mode 100644
index 0000000..aad13e6
--- /dev/null
+++ b/webroot/css/highlight/ascetic.css
@@ -0,0 +1,38 @@
+/*
+
+Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
+
+*/
+
+pre code {
+ display: block;
+ background: white; color: black;
+ border: solid #CCC 1px;
+}
+
+.string,
+.attribute .value,
+.filter .argument,
+.addition,
+.change {
+ color: #888;
+}
+
+.comment,
+.template_comment,
+.shebang,
+.doctype,
+.pi,
+.javadoc,
+.deletion {
+ color: #CCC;
+}
+
+.keyword,
+.tag .title,
+.ini .title,
+.winutils,
+.flow,
+.lisp .title {
+ font-weight: bold;
+}
\ No newline at end of file
diff --git a/webroot/css/highlight/dark.css b/webroot/css/highlight/dark.css
new file mode 100644
index 0000000..04d066f
--- /dev/null
+++ b/webroot/css/highlight/dark.css
@@ -0,0 +1,96 @@
+/*
+
+Dark style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
+
+*/
+
+pre code[class]:after {
+ content: 'highlight: ' attr(class);
+ display: block; text-align: right;
+ font-size: smaller;
+ color: #CCC; background: white;
+ border-top: solid 1px black;
+ padding-top: 0.5em;
+}
+
+pre code {
+ display: block;
+ background: #444;
+}
+
+.keyword,
+.literal,
+.change,
+.winutils,
+.flow,
+.lisp .title {
+ color: white;
+}
+
+pre code,
+.ruby .subst {
+ color: #DDD;
+}
+
+.string,
+.function .title,
+.class .title,
+.ini .title,
+.tag .attribute .value,
+.css .rules .value,
+.preprocessor,
+.ruby .symbol,
+.ruby .instancevar,
+.ruby .class .parent,
+.built_in,
+.sql .aggregate,
+.django .template_tag,
+.django .variable,
+.smalltalk .class,
+.javadoc,
+.ruby .string,
+.django .filter .argument,
+.smalltalk .localvars,
+.smalltalk .array,
+.css .attr_selector,
+.addition,
+.stream,
+.envvar {
+ color: #D88;
+}
+
+.comment,
+.java .annotation,
+.python .decorator,
+.template_comment,
+.pi,
+.doctype,
+.deletion,
+.shebang {
+ color: #777;
+}
+
+.keyword,
+.literal,
+.css .id,
+.phpdoc,
+.function .title,
+.class .title,
+.vbscript .built_in,
+.sql .aggregate,
+.rsl .built_in,
+.smalltalk .class,
+.xml .tag .title,
+.diff .header,
+.chunk,
+.winutils,
+.bash .variable,
+.lisp .title {
+ font-weight: bold;
+}
+
+.html .css,
+.html .javascript,
+.html .vbscript {
+ opacity: 0.5;
+}
\ No newline at end of file
diff --git a/webroot/css/highlight/default.css b/webroot/css/highlight/default.css
new file mode 100644
index 0000000..58d3a07
--- /dev/null
+++ b/webroot/css/highlight/default.css
@@ -0,0 +1,98 @@
+/*
+
+Original style from softwaremaniacs.org (c) Ivan Sagalaev <Maniac@SoftwareManiacs.Org>
+
+*/
+
+pre code[class]:after {
+ content: 'highlight: ' attr(class);
+ display: block; text-align: right;
+ font-size: smaller;
+ color: #CCC; background: white;
+ border-top: solid 1px;
+ padding-top: 0.5em;
+}
+
+pre code {
+ display: block;
+ background: #F0F0F0;
+}
+
+pre code,
+.ruby .subst,
+.xml .title,
+.lisp .title {
+ color: black;
+}
+
+.string,
+.title,
+.parent,
+.tag .attribute .value,
+.rules .value,
+.rules .value .number,
+.preprocessor,
+.ruby .symbol,
+.instancevar,
+.aggregate,
+.template_tag,
+.django .variable,
+.smalltalk .class,
+.addition,
+.flow,
+.stream,
+.bash .variable {
+ color: #800;
+}
+
+.comment,
+.annotation,
+.template_comment,
+.diff .header,
+.chunk {
+ color: #888;
+}
+
+.number,
+.regexp,
+.literal,
+.smalltalk .symbol,
+.smalltalk .char,
+.change {
+ color: #080;
+}
+
+.javadoc,
+.ruby .string,
+.decorator,
+.filter .argument,
+.localvars,
+.array,
+.attr_selector,
+.pi,
+.doctype,
+.deletion,
+.envvar,
+.shebang {
+ color: #88F;
+}
+
+.keyword,
+.id,
+.phpdoc,
+.title,
+.vbscript .built_in,
+.rsl .built_in,
+.cpp .built_in,
+.aggregate,
+.smalltalk .class,
+.winutils,
+.bash .variable {
+ font-weight: bold;
+}
+
+.html .css,
+.html .javascript,
+.html .vbscript {
+ opacity: 0.5;
+}
diff --git a/webroot/css/highlight/far.css b/webroot/css/highlight/far.css
new file mode 100644
index 0000000..d3d3ab5
--- /dev/null
+++ b/webroot/css/highlight/far.css
@@ -0,0 +1,95 @@
+/*
+
+FAR Style (c) MajestiC <majestic2k@gmail.com>
+
+*/
+
+pre code[class]:after {
+ content: 'highlight: ' attr(class);
+ display: block; text-align: right;
+ font-size: smaller;
+ color: #CCC; background: white;
+ border-top: solid 1px;
+ padding-top: 0.5em;
+}
+
+pre code {
+ display: block;
+ background: #000080;
+}
+
+pre code,
+.ruby .subst {
+ color: #0FF;
+}
+
+.string,
+.ruby .string,
+.function .title,
+.class .title,
+.ini .title,
+.tag .attribute .value,
+.css .rules .value,
+.css .rules .value .number,
+.preprocessor,
+.ruby .symbol,
+.built_in,
+.sql .aggregate,
+.django .template_tag,
+.django .variable,
+.smalltalk .class,
+.addition {
+ color: #FF0;
+}
+
+.change,
+.envvar,
+.bash .variable {
+ color: #FFF;
+}
+
+.comment,
+.phpdoc,
+.javadoc,
+.java .annotation,
+.template_comment,
+.deletion {
+ color: #888;
+}
+
+.number,
+.regexp,
+.literal,
+.smalltalk .symbol,
+.smalltalk .char {
+ color: #0F0;
+}
+
+.python .decorator,
+.django .filter .argument,
+.smalltalk .localvars,
+.smalltalk .array,
+.css .attr_selector,
+.xml .pi,
+.diff .header,
+.chunk,
+.shebang {
+ color: #008080;
+}
+
+.keyword,
+.css .id,
+.function .title,
+.class .title,
+.ini .title,
+.vbscript .built_in,
+.sql .aggregate,
+.rsl .built_in,
+.smalltalk .class,
+.xml .tag .title,
+.winutils,
+.flow,
+.lisp .title {
+ color: #FFF;
+ font-weight: bold;
+}
\ No newline at end of file
diff --git a/webroot/css/highlight/idea.css b/webroot/css/highlight/idea.css
new file mode 100644
index 0000000..995eb15
--- /dev/null
+++ b/webroot/css/highlight/idea.css
@@ -0,0 +1,75 @@
+/*
+
+Intellij Idea-like styling (c) Vasily Polovnyov <vast@whiteants.net>
+
+*/
+
+pre code {
+ font: 12px "Monospaced", monospace;
+ display: block;
+ color: #000;
+ background: #fff;
+}
+
+.subst, .title {
+ font-weight: normal;
+ color: #000;
+}
+
+.comment, .template_comment, .javadoc, .diff .header {
+ color: #808080;
+ font-style: italic;
+}
+
+.annotation, .decorator, .preprocessor, .doctype, .pi, .chunk, .shebang {
+ color: #808000;
+}
+
+.tag, .pi {
+ background: #efefef;
+}
+
+.tag .title, .id, .attr_selector, .literal, .keyword, .hexcolor, .css .function, .ini .title, .css .class, .list .title {
+ font-weight: bold;
+ color: #000080;
+}
+
+.attribute, .rules .keyword, .number, .regexp {
+ font-weight: bold;
+ color: #0000ff;
+}
+
+.number, .regexp {
+ font-weight: normal;
+}
+
+.string, .value, .filter .argument, .css .function .params {
+ color: #008000;
+ font-weight: bold;
+}
+
+.symbol, .char {
+ color: #000;
+ background: #d0eded;
+ font-style: italic;
+}
+
+.phpdoc, .javadoctag {
+ text-decoration: underline;
+}
+
+.variable, .envvar {
+ color: #660e7a;
+}
+
+.addition {
+ background: #baeeba;
+}
+
+.deletion {
+ background: #ffc8bd;
+}
+
+.diff .change {
+ background: #bccff9;
+}
\ No newline at end of file
diff --git a/webroot/css/highlight/sunburst.css b/webroot/css/highlight/sunburst.css
new file mode 100644
index 0000000..0b069e8
--- /dev/null
+++ b/webroot/css/highlight/sunburst.css
@@ -0,0 +1,112 @@
+/*
+
+Sunburst-like style (c) Vasily Polovnyov <vast@whiteants.net>
+
+*/
+
+pre code {
+ font: 12px / 1.3em 'Lucida Console', 'courier new', monospace;
+ color: #f8f8f8;
+}
+
+pre {
+ background: #000;
+}
+
+.comment, .template_comment, .javadoc {
+ color: #aeaeae;
+ font-style: italic;
+}
+
+.keyword, .ruby .function .keyword {
+ color: #E28964;
+}
+
+.function .keyword, .sub .keyword, .method, .list .title {
+ color: #99CF50;
+}
+
+.string, .attribute .value, .cdata, .filter .argument, .attr_selector {
+ color: #65B042;
+}
+
+.subst {
+ color: #DAEFA3;
+}
+
+.regexp {
+ color: #E9C062;
+}
+
+.function .title, .sub .identifier, .pi, .tag, .tag .keyword, .decorator, .ini .title, .shebang {
+ color: #89BDFF;
+}
+
+.class .title, .smalltalk .class, .javadoctag, .phpdoc {
+ text-decoration: underline;
+}
+
+.symbol, .number {
+ color: #3387CC;
+}
+
+.params, .variable {
+ color: #3E87E3;
+}
+
+.css .keyword {
+ color: #CDA869;
+}
+
+.css .class {
+ color: #9B703F;
+}
+
+.rules .keyword {
+ color: #C5AF75;
+}
+
+.rules .value {
+ color: #CF6A4C;
+}
+
+.css .id {
+ color: #8B98AB;
+}
+
+.annotation {
+ color: #9B859D;
+}
+
+.preprocessor {
+ color: #8996A8;
+}
+
+.hexcolor, .css .value .number {
+ color: #DD7B3B;
+}
+
+.css .function {
+ color: #DAD085;
+}
+
+.diff .header, .chunk {
+ background-color: #0E2231;
+ color: #F8F8F8;
+ font-style: italic;
+}
+
+.diff .change {
+ background-color: #4A410D;
+ color: #F8F8F8;
+}
+
+.addition {
+ background-color: #253B22;
+ color: #F8F8F8;
+}
+
+.deletion {
+ background-color: #420E09;
+ color: #F8F8F8;
+}
\ No newline at end of file
diff --git a/webroot/css/highlight/vs.css b/webroot/css/highlight/vs.css
new file mode 100644
index 0000000..98c1413
--- /dev/null
+++ b/webroot/css/highlight/vs.css
@@ -0,0 +1,65 @@
+/*
+
+Visual Studio-like style based on original C# coloring by Jason Diamond <jason@diamond.name>
+
+*/
+.comment,
+.annotation,
+.template_comment,
+.diff .header,
+.chunk {
+ color: rgb(0, 128, 0);
+}
+
+.keyword,
+.id,
+.title,
+.vbscript .built_in,
+.rsl .built_in,
+.cpp .built_in,
+.aggregate,
+.smalltalk .class,
+.winutils,
+.bash .variable {
+ color: rgb(0, 0, 255);
+}
+
+.string,
+.title,
+.parent,
+.tag .attribute .value,
+.rules .value,
+.rules .value .number,
+.ruby .symbol,
+.instancevar,
+.aggregate,
+.template_tag,
+.django .variable,
+.addition,
+.flow,
+.stream {
+ color: rgb(163, 21, 21);
+}
+
+.ruby .string,
+.decorator,
+.filter .argument,
+.localvars,
+.array,
+.attr_selector,
+.pi,
+.doctype,
+.deletion,
+.envvar,
+.shebang,
+.preprocessor,
+.userType {
+ color: rgb(43, 145, 175);
+}
+
+.phpdoc,
+.javadoc,
+.xmlDocTag {
+ color: rgb(128, 128, 128);
+}
+
diff --git a/webroot/css/highlight/zenburn.css b/webroot/css/highlight/zenburn.css
new file mode 100644
index 0000000..14e65e0
--- /dev/null
+++ b/webroot/css/highlight/zenburn.css
@@ -0,0 +1,108 @@
+/*
+
+Zenburn style from voldmar.ru (c) Vladimir Epifanov <voldmar@voldmar.ru>
+based on dark.css by Ivan Sagalaev
+
+*/
+
+pre code[class]:after {
+ content: 'highlight: ' attr(class);
+ display: block; text-align: right;
+ font-size: smaller;
+ color: #CCC; background: white;
+ border-top: solid 1px black;
+ padding-top: 0.5em;
+}
+
+pre code {
+ display: block;
+ background: #3F3F3F;
+ color: #DCDCDC;
+}
+
+.keyword,
+.tag,
+.django .tag,
+.django .keyword,
+.css .class,
+.css .id,
+.lisp .title {
+ color: #E3CEAB;
+}
+
+.django .template_tag,
+.django .variable,
+.django .filter .argument {
+ color: #DCDCDC;
+}
+
+.number {
+ color: #8CD0D3;
+}
+
+.dos .envvar,
+.dos .stream,
+.variable {
+ color: #EFDCBC;
+}
+
+.dos .flow,
+.diff .change,
+.python .exception,
+.python .built_in,
+.literal {
+ color: #EFEFAF;
+}
+
+.diff .chunk,
+.ruby .subst {
+ color: #8F8F8F;
+}
+
+.dos .keyword,
+.python .decorator,
+.class .title,
+.function .title,
+.ini .title,
+.diff .header,
+.ruby .class .parent {
+ color: #efef8f;
+}
+
+.dos .winutils,
+.ruby .symbol,
+.ruby .string,
+.ruby .instancevar {
+ color: #DCA3A3;
+}
+
+.diff .deletion,
+.string,
+.tag .attribute .value,
+.preprocessor,
+.built_in,
+.sql .aggregate,
+.javadoc,
+.smalltalk .class,
+.smalltalk .localvars,
+.smalltalk .array,
+.css .rules .value,
+.css .attr_selector {
+ color: #CC9393;
+}
+
+.shebang,
+.diff .addition,
+.comment,
+.java .annotation,
+.template_comment,
+.pi,
+.doctype {
+ color: #7F9F7F;
+}
+
+.html .css,
+.html .javascript {
+ opacity: 0.5;
+}
+
diff --git a/webroot/js/gshowdown.js b/webroot/js/gshowdown.js
new file mode 100644
index 0000000..32dabba
--- /dev/null
+++ b/webroot/js/gshowdown.js
@@ -0,0 +1,1331 @@
+//
+// showdown.js -- A javascript port of Markdown.
+//
+// Copyright (c) 2007 John Fraser.
+//
+// Original Markdown Copyright (c) 2004-2005 John Gruber
+// <http://daringfireball.net/projects/markdown/>
+//
+// Redistributable under a BSD-style open source license.
+// See license.txt for more information.
+//
+// The full source distribution is at:
+//
+// A A L
+// T C A
+// T K B
+//
+// <http://www.attacklab.net/>
+//
+
+//
+// modified by gwoo for #121212 and [commit] style syntax
+//
+
+//
+// Wherever possible, Showdown is a straight, line-by-line port
+// of the Perl version of Markdown.
+//
+// This is not a normal parser design; it's basically just a
+// series of string substitutions. It's hard to read and
+// maintain this way, but keeping Showdown close to the original
+// design makes it easier to port new features.
+//
+// More importantly, Showdown behaves like markdown.pl in most
+// edge cases. So web applications can do client-side preview
+// in Javascript, and then build identical HTML on the server.
+//
+// This port needs the new RegExp functionality of ECMA 262,
+// 3rd Edition (i.e. Javascript 1.5). Most modern web browsers
+// should do fine. Even with the new regular expression features,
+// We do a lot of work to emulate Perl's regex functionality.
+// The tricky changes in this file mostly have the "attacklab:"
+// label. Major or self-explanatory changes don't.
+//
+// Smart diff tools like Araxis Merge will be able to match up
+// this file with markdown.pl in a useful way. A little tweaking
+// helps: in a copy of markdown.pl, replace "#" with "//" and
+// replace "$text" with "text". Be sure to ignore whitespace
+// and line endings.
+//
+
+
+//
+// Showdown usage:
+//
+// var text = "Markdown *rocks*.";
+//
+// var converter = new Showdown.converter();
+// var html = converter.makeHtml(text);
+//
+// alert(html);
+//
+// Note: move the sample code to the bottom of this
+// file before uncommenting it.
+//
+
+
+//
+// Showdown namespace
+//
+var Showdown = {};
+
+//
+// converter
+//
+// Wraps all "globals" so that the only thing
+// exposed is makeHtml().
+//
+Showdown.converter = function(baseUrl) {
+
+//
+// Globals:
+//
+
+// Global hashes, used by various utility routines
+var g_urls;
+var g_titles;
+var g_html_blocks;
+
+// Used to track when we're inside an ordered or unordered list
+// (see _ProcessListItems() for details):
+var g_list_level = 0;
+
+var base = baseUrl;
+
+
+this.makeHtml = function(text) {
+//
+// Main function. The order in which other subs are called here is
+// essential. Link and image substitutions need to happen before
+// _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the <a>
+// and <img> tags get encoded.
+//
+
+ // Clear the global hashes. If we don't clear these, you get conflicts
+ // from other articles when generating a page which contains more than
+ // one article (e.g. an index page that shows the N most recent
+ // articles):
+ g_urls = new Array();
+ g_titles = new Array();
+ g_html_blocks = new Array();
+
+ // attacklab: Replace ~ with ~T
+ // This lets us use tilde as an escape char to avoid md5 hashes
+ // The choice of character is arbitray; anything that isn't
+ // magic in Markdown will work.
+ text = text.replace(/~/g,"~T");
+
+ // attacklab: Replace $ with ~D
+ // RegExp interprets $ as a special character
+ // when it's in a replacement string
+ text = text.replace(/\$/g,"~D");
+
+ // Standardize line endings
+ text = text.replace(/\r\n/g,"\n"); // DOS to Unix
+ text = text.replace(/\r/g,"\n"); // Mac to Unix
+
+ // Make sure text begins and ends with a couple of newlines:
+ text = "\n\n" + text + "\n\n";
+
+ // Convert all tabs to spaces.
+ text = _Detab(text);
+
+ // Strip any lines consisting only of spaces and tabs.
+ // This makes subsequent regexen easier to write, because we can
+ // match consecutive blank lines with /\n+/ instead of something
+ // contorted like /[ \t]*\n+/ .
+ text = text.replace(/^[ \t]+$/mg,"");
+
+ // Turn block-level HTML blocks into hash entries
+ text = _HashHTMLBlocks(text);
+
+ // Strip link definitions, store in hashes.
+ text = _StripLinkDefinitions(text);
+
+ text = _RunBlockGamut(text);
+
+ text = _UnescapeSpecialChars(text);
+
+ // attacklab: Restore dollar signs
+ text = text.replace(/~D/g,"$$");
+
+ // attacklab: Restore tildes
+ text = text.replace(/~T/g,"~");
+
+ return text;
+}
+
+
+var _StripLinkDefinitions = function(text) {
+//
+// Strips link definitions from text, stores the URLs and titles in
+// hash references.
+//
+
+ // Link defs are in the form: ^[id]: url "optional title"
+
+ /*
+ var text = text.replace(/
+ ^[ ]{0,3}\[(.+)\]: // id = $1 attacklab: g_tab_width - 1
+ [ \t]*
+ \n? // maybe *one* newline
+ [ \t]*
+ <?(\S+?)>? // url = $2
+ [ \t]*
+ \n? // maybe one newline
+ [ \t]*
+ (?:
+ (\n*) // any lines skipped = $3 attacklab: lookbehind removed
+ ["(]
+ (.+?) // title = $4
+ [")]
+ [ \t]*
+ )? // title is optional
+ (?:\n+|$)
+ /gm,
+ function(){...});
+ */
+ var text = text.replace(/^[ ]{0,3}\[(.+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|\Z)/gm,
+ function (wholeMatch,m1,m2,m3,m4) {
+ m1 = m1.toLowerCase();
+ g_urls[m1] = _EncodeAmpsAndAngles(m2); // Link IDs are case-insensitive
+ if (m3) {
+ // Oops, found blank lines, so it's not a title.
+ // Put back the parenthetical statement we stole.
+ return m3+m4;
+ } else if (m4) {
+ g_titles[m1] = m4.replace(/"/g,""");
+ }
+
+ // Completely remove the definition from the text
+ return "";
+ }
+ );
+
+ return text;
+}
+
+
+var _HashHTMLBlocks = function(text) {
+ // attacklab: Double up blank lines to reduce lookaround
+ text = text.replace(/\n/g,"\n\n");
+
+ // Hashify HTML blocks:
+ // We only want to do this for block-level HTML tags, such as headers,
+ // lists, and tables. That's because we still want to wrap <p>s around
+ // "paragraphs" that are wrapped in non-block-level tags, such as anchors,
+ // phrase emphasis, and spans. The list of tags we're looking for is
+ // hard-coded:
+ var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del"
+ var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math"
+
+ // First, look for nested blocks, e.g.:
+ // <div>
+ // <div>
+ // tags for inner block must be indented.
+ // </div>
+ // </div>
+ //
+ // The outermost tags must start at the left margin for this to match, and
+ // the inner nested divs must be indented.
+ // We need to do this before the next, more liberal match, because the next
+ // match will start at the first `<div>` and stop at the first `</div>`.
+
+ // attacklab: This regex can be expensive when it fails.
+ /*
+ var text = text.replace(/
+ ( // save in $1
+ ^ // start of line (with /m)
+ <($block_tags_a) // start tag = $2
+ \b // word break
+ // attacklab: hack around khtml/pcre bug...
+ [^\r]*?\n // any number of lines, minimally matching
+ </\2> // the matching end tag
+ [ \t]* // trailing spaces/tabs
+ (?=\n+) // followed by a newline
+ ) // attacklab: there are sentinel newlines at end of document
+ /gm,function(){...}};
+ */
+ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)\b[^\r]*?\n<\/\2>[ \t]*(?=\n+))/gm,hashElement);
+
+ //
+ // Now match more liberally, simply from `\n<tag>` to `</tag>\n`
+ //
+
+ /*
+ var text = text.replace(/
+ ( // save in $1
+ ^ // start of line (with /m)
+ <($block_tags_b) // start tag = $2
+ \b // word break
+ // attacklab: hack around khtml/pcre bug...
+ [^\r]*? // any number of lines, minimally matching
+ .*</\2> // the matching end tag
+ [ \t]* // trailing spaces/tabs
+ (?=\n+) // followed by a newline
+ ) // attacklab: there are sentinel newlines at end of document
+ /gm,function(){...}};
+ */
+ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)\b[^\r]*?.*<\/\2>[ \t]*(?=\n+)\n)/gm,hashElement);
+
+ // Special case just for <hr />. It was easier to make a special case than
+ // to make the other regex more complicated.
+
+ /*
+ text = text.replace(/
+ ( // save in $1
+ \n\n // Starting after a blank line
+ [ ]{0,3}
+ (<(hr) // start tag = $2
+ \b // word break
+ ([^<>])*? //
+ \/?>) // the matching end tag
+ [ \t]*
+ (?=\n{2,}) // followed by a blank line
+ )
+ /g,hashElement);
+ */
+ text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,hashElement);
+
+ // Special case for standalone HTML comments:
+
+ /*
+ text = text.replace(/
+ ( // save in $1
+ \n\n // Starting after a blank line
+ [ ]{0,3} // attacklab: g_tab_width - 1
+ <!
+ (--[^\r]*?--\s*)+
+ >
+ [ \t]*
+ (?=\n{2,}) // followed by a blank line
+ )
+ /g,hashElement);
+ */
+ text = text.replace(/(\n\n[ ]{0,3}<!(--[^\r]*?--\s*)+>[ \t]*(?=\n{2,}))/g,hashElement);
+
+ // PHP and ASP-style processor instructions (<?...?> and <%...%>)
+
+ /*
+ text = text.replace(/
+ (?:
+ \n\n // Starting after a blank line
+ )
+ ( // save in $1
+ [ ]{0,3} // attacklab: g_tab_width - 1
+ (?:
+ <([?%]) // $2
+ [^\r]*?
+ \2>
+ )
+ [ \t]*
+ (?=\n{2,}) // followed by a blank line
+ )
+ /g,hashElement);
+ */
+ text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,hashElement);
+
+ // attacklab: Undo double lines (see comment at top of this function)
+ text = text.replace(/\n\n/g,"\n");
+ return text;
+}
+
+var hashElement = function(wholeMatch,m1) {
+ var blockText = m1;
+
+ // Undo double lines
+ blockText = blockText.replace(/\n\n/g,"\n");
+ blockText = blockText.replace(/^\n/,"");
+
+ // strip trailing blank lines
+ blockText = blockText.replace(/\n+$/g,"");
+
+ // Replace the element text with a marker ("~KxK" where x is its key)
+ blockText = "\n\n~K" + (g_html_blocks.push(blockText)-1) + "K\n\n";
+
+ return blockText;
+};
+
+var _RunBlockGamut = function(text) {
+//
+// These are all the transformations that form block-level
+// tags like paragraphs, headers, and list items.
+//
+ text = _DoHeaders(text);
+
+ // Do Horizontal Rules:
+ var key = hashBlock("<hr />");
+ text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm,key);
+ text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm,key);
+ text = text.replace(/^[ ]{0,2}([ ]?\_[ ]?){3,}[ \t]*$/gm,key);
+
+ text = _DoLists(text);
+ text = _DoCodeBlocks(text);
+ text = _DoBlockQuotes(text);
+
+ // We already ran _HashHTMLBlocks() before, in Markdown(), but that
+ // was to escape raw HTML in the original Markdown source. This time,
+ // we're escaping the markup we've just created, so that we don't wrap
+ // <p> tags around block-level tags.
+ text = _HashHTMLBlocks(text);
+ text = _FormParagraphs(text);
+
+ return text;
+}
+
+
+var _RunSpanGamut = function(text) {
+//
+// These are all the transformations that occur *within* block-level
+// tags like paragraphs, headers, and list items.
+//
+
+ text = _DoCodeSpans(text);
+ text = _EscapeSpecialCharsWithinTagAttributes(text);
+ text = _EncodeBackslashEscapes(text);
+
+ // Process anchor and image tags. Images must come first,
+ // because ![foo][f] looks like an anchor.
+ text = _DoImages(text);
+ text = _DoSpecialRules(text);
+ text = _DoAnchors(text);
+
+ // Make links out of things like `<http://example.com/>`
+ // Must come after _DoAnchors(), because you can use < and >
+ // delimiters in inline links like [this](<url>).
+ text = _DoAutoLinks(text);
+ text = _EncodeAmpsAndAngles(text);
+ text = _DoItalicsAndBold(text);
+
+ // Do hard breaks:
+ text = text.replace(/ +\n/g," <br />\n");
+
+ return text;
+}
+
+var _EscapeSpecialCharsWithinTagAttributes = function(text) {
+//
+// Within tags -- meaning between < and > -- encode [\ ` * _] so they
+// don't conflict with their use in Markdown for code, italics and strong.
+//
+
+ // Build a regex to find HTML tags and comments. See Friedl's
+ // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
+ var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;
+
+ text = text.replace(regex, function(wholeMatch) {
+ var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g,"$1`");
+ tag = escapeCharacters(tag,"\\`*_");
+ return tag;
+ });
+
+ return text;
+}
+
+var _DoSpecialRules = function(text) {
+ // get ticket numbers
+ // # 11111
+ //
+ text = text.replace(/(^|[^\w])(\#{1})(\b[0-9]{1,10}\b)+/gm,
+ function(wholeMatch, m0, m1, m2) {
+ return (m0 + "<a href=\"" + base + "tickets/view/" + m2 + "\">" + m1 + m2 + "</a>");
+ });
+
+ // get commits
+ // [11111] | [40charactersForHash]
+ //
+ text = text.replace(/(^|[^\w])(\[([A-Za-z0-9+]{1,40})\])+/gm,
+ function(wholeMatch, m0, m1, m2) {
+ return (m0 + "<a href=\"" + base + "commits/view/" + m2 + "\">" + m1 + "</a>");
+ });
+
+ // get wiki pages
+ // [wiki:Slug]
+ //
+ text = text.replace(/(^|[^\w])(\[wiki:(.+?)\])+/gm,
+ function(wholeMatch, m0, m1, m2) {
+ return (m0 + "<a href=\"" + base + "wiki/" + m2 + "\">" + m2 + "</a>");
+ });
+
+ return text;
+}
+
+var _DoAnchors = function(text) {
+//
+// Turn Markdown link shortcuts into XHTML <a> tags.
+//
+ //
+ // First, handle reference-style links: [link text] [id]
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ \[
+ (
+ (?:
+ \[[^\]]*\] // allow brackets nested one level
+ |
+ [^\[] // or anything else
+ )*
+ )
+ \]
+
+ [ ]? // one optional space
+ (?:\n[ ]*)? // one optional newline followed by spaces
+
+ \[
+ (.*?) // id = $3
+ \]
+ )()()()() // pad remaining backreferences
+ /g,_DoAnchors_callback);
+ */
+ text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeAnchorTag);
+
+ //
+ // Next, inline-style links: [link text](url "optional title")
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ \[
+ (
+ (?:
+ \[[^\]]*\] // allow brackets nested one level
+ |
+ [^\[\]] // or anything else
+ )
+ )
+ \]
+ \( // literal paren
+ [ \t]*
+ () // no id, so leave $3 empty
+ <?(.*?)>? // href = $4
+ [ \t]*
+ ( // $5
+ (['"]) // quote char = $6
+ (.*?) // Title = $7
+ \6 // matching quote
+ [ \t]* // ignore any spaces/tabs between closing quote and )
+ )? // title is optional
+ \)
+ )
+ /g,writeAnchorTag);
+ */
+ text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()<?(.*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeAnchorTag);
+
+ //
+ // Last, handle reference-style shortcuts: [link text]
+ // These must come last in case you've also got [link test][1]
+ // or [link test](/foo)
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ \[
+ ([^\[\]]+) // link text = $2; can't contain '[' or ']'
+ \]
+ )()()()()() // pad rest of backreferences
+ /g, writeAnchorTag);
+ */
+ text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
+
+ return text;
+}
+
+var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
+ if (m7 == undefined) m7 = "";
+ var whole_match = m1;
+ var link_text = m2;
+ var link_id = m3.toLowerCase();
+ var url = m4;
+ var title = m7;
+
+ if (url == "") {
+ if (link_id == "") {
+ // lower-case and turn embedded newlines into spaces
+ link_id = link_text.toLowerCase().replace(/ ?\n/g," ");
+ }
+ url = "#"+link_id;
+
+ if (g_urls[link_id] != undefined) {
+ url = g_urls[link_id];
+ if (g_titles[link_id] != undefined) {
+ title = g_titles[link_id];
+ }
+ }
+ else {
+ if (whole_match.search(/\(\s*\)$/m)>-1) {
+ // Special case for explicit empty url
+ url = "";
+ } else {
+ return whole_match;
+ }
+ }
+ }
+
+ url = escapeCharacters(url,"*_");
+ var result = "<a href=\"" + url + "\"";
+
+ if (title != "") {
+ title = title.replace(/"/g,""");
+ title = escapeCharacters(title,"*_");
+ result += " title=\"" + title + "\"";
+ }
+
+ result += ">" + link_text + "</a>";
+
+ return result;
+}
+
+
+var _DoImages = function(text) {
+//
+// Turn Markdown image shortcuts into <img> tags.
+//
+
+ //
+ // First, handle reference-style labeled images: ![alt text][id]
+ //
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ !\[
+ (.*?) // alt text = $2
+ \]
+
+ [ ]? // one optional space
+ (?:\n[ ]*)? // one optional newline followed by spaces
+
+ \[
+ (.*?) // id = $3
+ \]
+ )()()()() // pad rest of backreferences
+ /g,writeImageTag);
+ */
+ text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g,writeImageTag);
+
+ //
+ // Next, handle inline images: 
+ // Don't forget: encode * and _
+
+ /*
+ text = text.replace(/
+ ( // wrap whole match in $1
+ !\[
+ (.*?) // alt text = $2
+ \]
+ \s? // One optional whitespace character
+ \( // literal paren
+ [ \t]*
+ () // no id, so leave $3 empty
+ <?(\S+?)>? // src url = $4
+ [ \t]*
+ ( // $5
+ (['"]) // quote char = $6
+ (.*?) // title = $7
+ \6 // matching quote
+ [ \t]*
+ )? // title is optional
+ \)
+ )
+ /g,writeImageTag);
+ */
+ text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()<?(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,writeImageTag);
+
+ return text;
+}
+
+var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) {
+ var whole_match = m1;
+ var alt_text = m2;
+ var link_id = m3.toLowerCase();
+ var url = m4;
+ var title = m7;
+
+ if (!title) title = "";
+
+ if (url == "") {
+ if (link_id == "") {
+ // lower-case and turn embedded newlines into spaces
+ link_id = alt_text.toLowerCase().replace(/ ?\n/g," ");
+ }
+ url = "#"+link_id;
+
+ if (g_urls[link_id] != undefined) {
+ url = g_urls[link_id];
+ if (g_titles[link_id] != undefined) {
+ title = g_titles[link_id];
+ }
+ }
+ else {
+ return whole_match;
+ }
+ }
+
+ alt_text = alt_text.replace(/"/g,""");
+ url = escapeCharacters(url,"*_");
+ var result = "<img src=\"" + url + "\" alt=\"" + alt_text + "\"";
+
+ // attacklab: Markdown.pl adds empty title attributes to images.
+ // Replicate this bug.
+
+ //if (title != "") {
+ title = title.replace(/"/g,""");
+ title = escapeCharacters(title,"*_");
+ result += " title=\"" + title + "\"";
+ //}
+
+ result += " />";
+
+ return result;
+}
+
+
+var _DoHeaders = function(text) {
+
+ // Setext-style headers:
+ // Header 1
+ // ========
+ //
+ // Header 2
+ // --------
+ //
+ text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,
+ function(wholeMatch,m1){return hashBlock("<h1>" + _RunSpanGamut(m1) + "</h1>");});
+
+ text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
+ function(matchFound,m1){return hashBlock("<h2>" + _RunSpanGamut(m1) + "</h2>");});
+
+ // atx-style headers:
+ // # Header 1
+ // ## Header 2
+ // ## Header 2 with closing hashes ##
+ // ...
+ // ###### Header 6
+ //
+
+ /*
+ text = text.replace(/
+ ^(\#{1,6}) // $1 = string of #'s
+ [ \t]*
+ (.+?) // $2 = Header text
+ [ \t]*
+ \#* // optional closing #'s (not counted)
+ \n+
+ /gm, function() {...});
+ */
+
+ text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
+ function(wholeMatch,m1,m2) {
+ var h_level = m1.length;
+ return hashBlock("<h" + h_level + ">" + _RunSpanGamut(m2) + "</h" + h_level + ">");
+ });
+
+ return text;
+}
+
+// This declaration keeps Dojo compressor from outputting garbage:
+var _ProcessListItems;
+
+var _DoLists = function(text) {
+//
+// Form HTML ordered (numbered) and unordered (bulleted) lists.
+//
+
+ // attacklab: add sentinel to hack around khtml/safari bug:
+ // http://bugs.webkit.org/show_bug.cgi?id=11231
+ text += "~0";
+
+ // Re-usable pattern to match any entirel ul or ol list:
+
+ /*
+ var whole_list = /
+ ( // $1 = whole list
+ ( // $2
+ [ ]{0,3} // attacklab: g_tab_width - 1
+ ([*+-]|\d+[.]) // $3 = first list item marker
+ [ \t]+
+ )
+ [^\r]+?
+ ( // $4
+ ~0 // sentinel for workaround; should be $
+ |
+ \n{2,}
+ (?=\S)
+ (?! // Negative lookahead for another list item marker
+ [ \t]*
+ (?:[*+-]|\d+[.])[ \t]+
+ )
+ )
+ )/g
+ */
+ var whole_list = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
+
+ if (g_list_level) {
+ text = text.replace(whole_list,function(wholeMatch,m1,m2) {
+ var list = m1;
+ var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol";
+
+ // Turn double returns into triple returns, so that we can make a
+ // paragraph for the last item in a list, if necessary:
+ list = list.replace(/\n{2,}/g,"\n\n\n");;
+ var result = _ProcessListItems(list);
+
+ // Trim any trailing whitespace, to put the closing `</$list_type>`
+ // up on the preceding line, to get it past the current stupid
+ // HTML block parser. This is a hack to work around the terrible
+ // hack that is the HTML block parser.
+ result = result.replace(/\s+$/,"");
+ result = "<"+list_type+">" + result + "</"+list_type+">\n";
+ return result;
+ });
+ } else {
+ whole_list = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/g;
+ text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) {
+ var runup = m1;
+ var list = m2;
+
+ var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol";
+ // Turn double returns into triple returns, so that we can make a
+ // paragraph for the last item in a list, if necessary:
+ var list = list.replace(/\n{2,}/g,"\n\n\n");;
+ var result = _ProcessListItems(list);
+ result = runup + "<"+list_type+">\n" + result + "</"+list_type+">\n";
+ return result;
+ });
+ }
+
+ // attacklab: strip sentinel
+ text = text.replace(/~0/,"");
+
+ return text;
+}
+
+_ProcessListItems = function(list_str) {
+//
+// Process the contents of a single ordered or unordered list, splitting it
+// into individual list items.
+//
+ // The $g_list_level global keeps track of when we're inside a list.
+ // Each time we enter a list, we increment it; when we leave a list,
+ // we decrement. If it's zero, we're not in a list anymore.
+ //
+ // We do this because when we're not inside a list, we want to treat
+ // something like this:
+ //
+ // I recommend upgrading to version
+ // 8. Oops, now this line is treated
+ // as a sub-list.
+ //
+ // As a single paragraph, despite the fact that the second line starts
+ // with a digit-period-space sequence.
+ //
+ // Whereas when we're inside a list (or sub-list), that line will be
+ // treated as the start of a sub-list. What a kludge, huh? This is
+ // an aspect of Markdown's syntax that's hard to parse perfectly
+ // without resorting to mind-reading. Perhaps the solution is to
+ // change the syntax rules such that sub-lists must start with a
+ // starting cardinal number; e.g. "1." or "a.".
+
+ g_list_level++;
+
+ // trim trailing blank lines:
+ list_str = list_str.replace(/\n{2,}$/,"\n");
+
+ // attacklab: add sentinel to emulate \z
+ list_str += "~0";
+
+ /*
+ list_str = list_str.replace(/
+ (\n)? // leading line = $1
+ (^[ \t]*) // leading whitespace = $2
+ ([*+-]|\d+[.]) [ \t]+ // list marker = $3
+ ([^\r]+? // list item text = $4
+ (\n{1,2}))
+ (?= \n* (~0 | \2 ([*+-]|\d+[.]) [ \t]+))
+ /gm, function(){...});
+ */
+ list_str = list_str.replace(/(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
+ function(wholeMatch,m1,m2,m3,m4){
+ var item = m4;
+ var leading_line = m1;
+ var leading_space = m2;
+
+ if (leading_line || (item.search(/\n{2,}/)>-1)) {
+ item = _RunBlockGamut(_Outdent(item));
+ }
+ else {
+ // Recursion for sub-lists:
+ item = _DoLists(_Outdent(item));
+ item = item.replace(/\n$/,""); // chomp(item)
+ item = _RunSpanGamut(item);
+ }
+
+ return "<li>" + item + "</li>\n";
+ }
+ );
+
+ // attacklab: strip sentinel
+ list_str = list_str.replace(/~0/g,"");
+
+ g_list_level--;
+ return list_str;
+}
+
+
+var _DoCodeBlocks = function(text) {
+//
+// Process Markdown `<pre><code>` blocks.
+//
+
+ /*
+ text = text.replace(text,
+ /(?:\n\n|^)
+ ( // $1 = the code block -- one or more lines, starting with a space/tab
+ (?:
+ (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
+ .*\n+
+ )+
+ )
+ (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
+ /g,function(){...});
+ */
+
+ // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
+ text += "~0";
+
+ text = text.replace(/(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
+ function(wholeMatch,m1,m2) {
+ var codeblock = m1;
+ var nextChar = m2;
+
+ codeblock = _EncodeCode( _Outdent(codeblock));
+ codeblock = _Detab(codeblock);
+ codeblock = codeblock.replace(/^\n+/g,""); // trim leading newlines
+ codeblock = codeblock.replace(/\n+$/g,""); // trim trailing whitespace
+
+ codeblock = "<pre><code>" + codeblock + "\n</code></pre>";
+
+ return hashBlock(codeblock) + nextChar;
+ }
+ );
+
+ // attacklab: strip sentinel
+ text = text.replace(/~0/,"");
+
+ return text;
+}
+
+var hashBlock = function(text) {
+ text = text.replace(/(^\n+|\n+$)/g,"");
+ return "\n\n~K" + (g_html_blocks.push(text)-1) + "K\n\n";
+}
+
+
+var _DoCodeSpans = function(text) {
+//
+// * Backtick quotes are used for <code></code> spans.
+//
+// * You can use multiple backticks as the delimiters if you want to
+// include literal backticks in the code span. So, this input:
+//
+// Just type ``foo `bar` baz`` at the prompt.
+//
+// Will translate to:
+//
+// <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
+//
+// There's no arbitrary limit to the number of backticks you
+// can use as delimters. If you need three consecutive backticks
+// in your code, use four for delimiters, etc.
+//
+// * You can use spaces to get literal backticks at the edges:
+//
+// ... type `` `bar` `` ...
+//
+// Turns to:
+//
+// ... type <code>`bar`</code> ...
+//
+
+ /*
+ text = text.replace(/
+ (^|[^\\]) // Character before opening ` can't be a backslash
+ (`+) // $2 = Opening run of `
+ ( // $3 = The code block
+ [^\r]*?
+ [^`] // attacklab: work around lack of lookbehind
+ )
+ \2 // Matching closer
+ (?!`)
+ /gm, function(){...});
+ */
+
+ text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
+ function(wholeMatch,m1,m2,m3,m4) {
+ var c = m3;
+ c = c.replace(/^([ \t]*)/g,""); // leading whitespace
+ c = c.replace(/[ \t]*$/g,""); // trailing whitespace
+ c = _EncodeCode(c);
+ return m1+"<code>"+c+"</code>";
+ });
+
+ return text;
+}
+
+
+var _EncodeCode = function(text) {
+//
+// Encode/escape certain characters inside Markdown code runs.
+// The point is that in code, these characters are literals,
+// and lose their special Markdown meanings.
+//
+ // Encode all ampersands; HTML entities are not
+ // entities within a Markdown code span.
+ text = text.replace(/&/g,"&");
+
+ // Do the angle bracket song and dance:
+ text = text.replace(/</g,"<");
+ text = text.replace(/>/g,">");
+
+ // Now, escape characters that are magic in Markdown:
+ text = escapeCharacters(text,"\*_{}[]\\",false);
+
+// jj the line above breaks this:
+//---
+
+//* Item
+
+// 1. Subitem
+
+// special char: *
+//---
+
+ return text;
+}
+
+
+var _DoItalicsAndBold = function(text) {
+
+ // <strong> must go first:
+ text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,
+ "<strong>$2</strong>");
+
+ text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,
+ "<em>$2</em>");
+
+ return text;
+}
+
+
+var _DoBlockQuotes = function(text) {
+
+ /*
+ text = text.replace(/
+ ( // Wrap whole match in $1
+ (
+ ^[ \t]*>[ \t]? // '>' at the start of a line
+ .+\n // rest of the first line
+ (.+\n)* // subsequent consecutive lines
+ \n* // blanks
+ )+
+ )
+ /gm, function(){...});
+ */
+
+ text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,
+ function(wholeMatch,m1) {
+ var bq = m1;
+
+ // attacklab: hack around Konqueror 3.5.4 bug:
+ // "----------bug".replace(/^-/g,"") == "bug"
+
+ bq = bq.replace(/^[ \t]*>[ \t]?/gm,"~0"); // trim one level of quoting
+
+ // attacklab: clean up hack
+ bq = bq.replace(/~0/g,"");
+
+ bq = bq.replace(/^[ \t]+$/gm,""); // trim whitespace-only lines
+ bq = _RunBlockGamut(bq); // recurse
+
+ bq = bq.replace(/(^|\n)/g,"$1 ");
+ // These leading spaces screw with <pre> content, so we need to fix that:
+ bq = bq.replace(
+ /(\s*<pre>[^\r]+?<\/pre>)/gm,
+ function(wholeMatch,m1) {
+ var pre = m1;
+ // attacklab: hack around Konqueror 3.5.4 bug:
+ pre = pre.replace(/^ /mg,"~0");
+ pre = pre.replace(/~0/g,"");
+ return pre;
+ });
+
+ return hashBlock("<blockquote>\n" + bq + "\n</blockquote>");
+ });
+ return text;
+}
+
+
+var _FormParagraphs = function(text) {
+//
+// Params:
+// $text - string to process with html <p> tags
+//
+
+ // Strip leading and trailing lines:
+ text = text.replace(/^\n+/g,"");
+ text = text.replace(/\n+$/g,"");
+
+ var grafs = text.split(/\n{2,}/g);
+ var grafsOut = new Array();
+
+ //
+ // Wrap <p> tags.
+ //
+ var end = grafs.length;
+ for (var i=0; i<end; i++) {
+ var str = grafs[i];
+
+ // if this is an HTML marker, copy it
+ if (str.search(/~K(\d+)K/g) >= 0) {
+ grafsOut.push(str);
+ }
+ else if (str.search(/\S/) >= 0) {
+ str = _RunSpanGamut(str);
+ str = str.replace(/^([ \t]*)/g,"<p>");
+ str += "</p>"
+ grafsOut.push(str);
+ }
+
+ }
+
+ //
+ // Unhashify HTML blocks
+ //
+ end = grafsOut.length;
+ for (var i=0; i<end; i++) {
+ // if this is a marker for an html block...
+ while (grafsOut[i].search(/~K(\d+)K/) >= 0) {
+ var blockText = g_html_blocks[RegExp.$1];
+ blockText = blockText.replace(/\$/g,"$$$$"); // Escape any dollar signs
+ grafsOut[i] = grafsOut[i].replace(/~K\d+K/,blockText);
+ }
+ }
+
+ return grafsOut.join("\n\n");
+}
+
+
+var _EncodeAmpsAndAngles = function(text) {
+// Smart processing for ampersands and angle brackets that need to be encoded.
+
+ // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
+ // http://bumppo.net/projects/amputator/
+ text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g,"&");
+
+ // Encode naked <'s
+ text = text.replace(/<(?![a-z\/?\$!])/gi,"<");
+
+ return text;
+}
+
+
+var _EncodeBackslashEscapes = function(text) {
+//
+// Parameter: String.
+// Returns: The string, with after processing the following backslash
+// escape sequences.
+//
+
+ // attacklab: The polite way to do this is with the new
+ // escapeCharacters() function:
+ //
+ // text = escapeCharacters(text,"\\",true);
+ // text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
+ //
+ // ...but we're sidestepping its use of the (slow) RegExp constructor
+ // as an optimization for Firefox. This function gets called a LOT.
+
+ text = text.replace(/\\(\\)/g,escapeCharacters_callback);
+ text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g,escapeCharacters_callback);
+ return text;
+}
+
+
+var _DoAutoLinks = function(text) {
+
+ text = text.replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,"<a href=\"$1\">$1</a>");
+
+ // Email addresses: <address@domain.foo>
+
+ /*
+ text = text.replace(/
+ <
+ (?:mailto:)?
+ (
+ [-.\w]+
+ \@
+ [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
+ )
+ >
+ /gi, _DoAutoLinks_callback());
+ */
+ text = text.replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
+ function(wholeMatch,m1) {
+ return _EncodeEmailAddress( _UnescapeSpecialChars(m1) );
+ }
+ );
+
+ return text;
+}
+
+
+var _EncodeEmailAddress = function(addr) {
+//
+// Input: an email address, e.g. "foo@example.com"
+//
+// Output: the email address as a mailto link, with each character
+// of the address encoded as either a decimal or hex entity, in
+// the hopes of foiling most address harvesting spam bots. E.g.:
+//
+// <a href="mailto:foo@e
+// xample.com">foo
+// @example.com</a>
+//
+// Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
+// mailing list: <http://tinyurl.com/yu7ue>
+//
+
+ // attacklab: why can't javascript speak hex?
+ function char2hex(ch) {
+ var hexDigits = '0123456789ABCDEF';
+ var dec = ch.charCodeAt(0);
+ return(hexDigits.charAt(dec>>4) + hexDigits.charAt(dec&15));
+ }
+
+ var encode = [
+ function(ch){return "&#"+ch.charCodeAt(0)+";";},
+ function(ch){return "&#x"+char2hex(ch)+";";},
+ function(ch){return ch;}
+ ];
+
+ addr = "mailto:" + addr;
+
+ addr = addr.replace(/./g, function(ch) {
+ if (ch == "@") {
+ // this *must* be encoded. I insist.
+ ch = encode[Math.floor(Math.random()*2)](ch);
+ } else if (ch !=":") {
+ // leave ':' alone (to spot mailto: later)
+ var r = Math.random();
+ // roughly 10% raw, 45% hex, 45% dec
+ ch = (
+ r > .9 ? encode[2](ch) :
+ r > .45 ? encode[1](ch) :
+ encode[0](ch)
+ );
+ }
+ return ch;
+ });
+
+ addr = "<a href=\"" + addr + "\">" + addr + "</a>";
+ addr = addr.replace(/">.+:/g,"\">"); // strip the mailto: from the visible part
+
+ return addr;
+}
+
+
+var _UnescapeSpecialChars = function(text) {
+//
+// Swap back in all the special characters we've hidden.
+//
+ text = text.replace(/~E(\d+)E/g,
+ function(wholeMatch,m1) {
+ var charCodeToReplace = parseInt(m1);
+ return String.fromCharCode(charCodeToReplace);
+ }
+ );
+ return text;
+}
+
+
+var _Outdent = function(text) {
+//
+// Remove one level of line-leading tabs or spaces
+//
+
+ // attacklab: hack around Konqueror 3.5.4 bug:
+ // "----------bug".replace(/^-/g,"") == "bug"
+
+ text = text.replace(/^(\t|[ ]{1,4})/gm,"~0"); // attacklab: g_tab_width
+
+ // attacklab: clean up hack
+ text = text.replace(/~0/g,"")
+
+ return text;
+}
+
+var _Detab = function(text) {
+// attacklab: Detab's completely rewritten for speed.
+// In perl we could fix it by anchoring the regexp with \G.
+// In javascript we're less fortunate.
+
+ // expand first n-1 tabs
+ text = text.replace(/\t(?=\t)/g," "); // attacklab: g_tab_width
+
+ // replace the nth with two sentinels
+ text = text.replace(/\t/g,"~A~B");
+
+ // use the sentinel to anchor our regex so it doesn't explode
+ text = text.replace(/~B(.+?)~A/g,
+ function(wholeMatch,m1,m2) {
+ var leadingText = m1;
+ var numSpaces = 4 - leadingText.length % 4; // attacklab: g_tab_width
+
+ // there *must* be a better way to do this:
+ for (var i=0; i<numSpaces; i++) leadingText+=" ";
+
+ return leadingText;
+ }
+ );
+
+ // clean up sentinels
+ text = text.replace(/~A/g," "); // attacklab: g_tab_width
+ text = text.replace(/~B/g,"");
+
+ return text;
+}
+
+
+//
+// attacklab: Utility functions
+//
+
+
+var escapeCharacters = function(text, charsToEscape, afterBackslash) {
+ // First we have to escape the escape characters so that
+ // we can build a character class out of them
+ var regexString = "([" + charsToEscape.replace(/([\[\]\\])/g,"\\$1") + "])";
+
+ if (afterBackslash) {
+ regexString = "\\\\" + regexString;
+ }
+
+ var regex = new RegExp(regexString,"g");
+ text = text.replace(regex,escapeCharacters_callback);
+
+ return text;
+}
+
+
+var escapeCharacters_callback = function(wholeMatch,m1) {
+ var charCodeToEscape = m1.charCodeAt(0);
+ return "~E"+charCodeToEscape+"E";
+}
+
+} // end of Showdown.converter
\ No newline at end of file
diff --git a/webroot/js/highlight.js b/webroot/js/highlight.js
new file mode 100644
index 0000000..aff4a5e
--- /dev/null
+++ b/webroot/js/highlight.js
@@ -0,0 +1,516 @@
+/*
+Syntax highlighting with language autodetection.
+http://softwaremaniacs.org/soft/highlight/
+*/
+
+var hljs = new function() {
+
+ var DEFAULT_LANGUAGES = ['python', 'ruby', 'perl', 'php', 'css', 'xml', 'html', 'django', 'javascript', 'java', 'cpp', 'cs', 'sql', 'ini', 'diff'];
+ var ALL_LANGUAGES = (DEFAULT_LANGUAGES.join(',') + ',' + ['1c', 'axapta', 'delphi', 'rib', 'rsl', 'vbscript', 'profile', 'dos', 'bash', 'lisp', 'smalltalk', 'mel'].join(',')).split(',');
+ var LANGUAGE_GROUPS = {
+ 'xml': 'www',
+ 'html': 'www',
+ 'css': 'www',
+ 'django': 'www',
+ 'python': 'dynamic',
+ 'perl': 'dynamic',
+ 'php': 'dynamic',
+ 'ruby': 'dynamic',
+ 'cpp': 'static',
+ 'java': 'static',
+ 'delphi': 'static',
+ 'cs': 'static',
+ 'rib': 'renderman',
+ 'rsl': 'renderman'
+ }
+
+ var LANGUAGES = {}
+ var selected_languages = {};
+
+ function escape(value) {
+ return value.replace(/&/gm, '&').replace(/</gm, '<').replace(/>/gm, '>');
+ }
+
+ function contains(array, item) {
+ if (!array)
+ return false;
+ for (var i = 0; i < array.length; i++)
+ if (array[i] == item)
+ return true;
+ return false;
+ }
+
+ function highlight(language_name, value) {
+ function compileSubModes(mode, language) {
+ mode.sub_modes = [];
+ for (var i = 0; i < mode.contains.length; i++) {
+ for (var j = 0; j < language.modes.length; j++) {
+ if (language.modes[j].className == mode.contains[i]) {
+ mode.sub_modes[mode.sub_modes.length] = language.modes[j];
+ }
+ }
+ }
+ }
+
+ function subMode(lexem, mode) {
+ if (!mode.contains) {
+ return null;
+ }
+ if (!mode.sub_modes) {
+ compileSubModes(mode, language);
+ }
+ for (var i = 0; i < mode.sub_modes.length; i++) {
+ if (mode.sub_modes[i].beginRe.test(lexem)) {
+ return mode.sub_modes[i];
+ }
+ }
+ return null;
+ }
+
+ function endOfMode(mode_index, lexem) {
+ if (modes[mode_index].end && modes[mode_index].endRe.test(lexem))
+ return 1;
+ if (modes[mode_index].endsWithParent) {
+ var level = endOfMode(mode_index - 1, lexem);
+ return level ? level + 1 : 0;
+ }
+ return 0;
+ }
+
+ function isIllegal(lexem, mode) {
+ return mode.illegalRe && mode.illegalRe.test(lexem);
+ }
+
+ function compileTerminators(mode, language) {
+ var terminators = [];
+
+ function addTerminator(re) {
+ if (!contains(terminators, re)) {
+ terminators[terminators.length] = re;
+ }
+ }
+
+ if (mode.contains)
+ for (var i = 0; i < language.modes.length; i++) {
+ if (contains(mode.contains, language.modes[i].className)) {
+ addTerminator(language.modes[i].begin);
+ }
+ }
+
+ var index = modes.length - 1;
+ do {
+ if (modes[index].end) {
+ addTerminator(modes[index].end);
+ }
+ index--;
+ } while (modes[index + 1].endsWithParent);
+
+ if (mode.illegal) {
+ addTerminator(mode.illegal);
+ }
+
+ var terminator_re = '(' + terminators[0];
+ for (var i = 0; i < terminators.length; i++)
+ terminator_re += '|' + terminators[i];
+ terminator_re += ')';
+ return langRe(language, terminator_re);
+ }
+
+ function eatModeChunk(value, index) {
+ var mode = modes[modes.length - 1];
+ if (!mode.terminators) {
+ mode.terminators = compileTerminators(mode, language);
+ }
+ value = value.substr(index);
+ var match = mode.terminators.exec(value);
+ if (!match)
+ return [value, '', true];
+ if (match.index == 0)
+ return ['', match[0], false];
+ else
+ return [value.substr(0, match.index), match[0], false];
+ }
+
+ function keywordMatch(mode, match) {
+ var match_str = language.case_insensitive ? match[0].toLowerCase() : match[0]
+ for (var className in mode.keywordGroups) {
+ if (!mode.keywordGroups.hasOwnProperty(className))
+ continue;
+ var value = mode.keywordGroups[className].hasOwnProperty(match_str);
+ if (value)
+ return [className, value];
+ }
+ return false;
+ }
+
+ function processKeywords(buffer, mode) {
+ if (!mode.keywords || !mode.lexems)
+ return escape(buffer);
+ if (!mode.lexemsRe) {
+ var lexems_re = '(' + mode.lexems[0];
+ for (var i = 1; i < mode.lexems.length; i++)
+ lexems_re += '|' + mode.lexems[i];
+ lexems_re += ')';
+ mode.lexemsRe = langRe(language, lexems_re, true);
+ }
+ var result = '';
+ var last_index = 0;
+ mode.lexemsRe.lastIndex = 0;
+ var match = mode.lexemsRe.exec(buffer);
+ while (match) {
+ result += escape(buffer.substr(last_index, match.index - last_index));
+ keyword_match = keywordMatch(mode, match);
+ if (keyword_match) {
+ keyword_count += keyword_match[1];
+ result += '<span class="'+ keyword_match[0] +'">' + escape(match[0]) + '</span>';
+ } else {
+ result += escape(match[0]);
+ }
+ last_index = mode.lexemsRe.lastIndex;
+ match = mode.lexemsRe.exec(buffer);
+ }
+ result += escape(buffer.substr(last_index, buffer.length - last_index));
+ return result;
+ }
+
+ function processBuffer(buffer, mode) {
+ if (mode.subLanguage && selected_languages[mode.subLanguage]) {
+ var result = highlight(mode.subLanguage, buffer);
+ keyword_count += result.keyword_count;
+ relevance += result.relevance;
+ return result.value;
+ } else {
+ return processKeywords(buffer, mode);
+ }
+ }
+
+ function startNewMode(mode, lexem) {
+ if (mode.returnBegin) {
+ result += '<span class="' + mode.className + '">';
+ mode.buffer = '';
+ } else if (mode.excludeBegin) {
+ result += escape(lexem) + '<span class="' + mode.className + '">';
+ mode.buffer = '';
+ } else {
+ result += '<span class="' + mode.className + '">';
+ mode.buffer = lexem;
+ }
+ modes[modes.length] = mode;
+ }
+
+ function processModeInfo(buffer, lexem, end) {
+ var current_mode = modes[modes.length - 1];
+ if (end) {
+ result += processBuffer(current_mode.buffer + buffer, current_mode);
+ return false;
+ }
+
+ var new_mode = subMode(lexem, current_mode);
+ if (new_mode) {
+ result += processBuffer(current_mode.buffer + buffer, current_mode);
+ startNewMode(new_mode, lexem);
+ relevance += new_mode.relevance;
+ return new_mode.returnBegin;
+ }
+
+ var end_level = endOfMode(modes.length - 1, lexem);
+ if (end_level) {
+ if (current_mode.returnEnd) {
+ result += processBuffer(current_mode.buffer + buffer, current_mode) + '</span>';
+ } else if (current_mode.excludeEnd) {
+ result += processBuffer(current_mode.buffer + buffer, current_mode) + '</span>' + escape(lexem);
+ } else {
+ result += processBuffer(current_mode.buffer + buffer + lexem, current_mode) + '</span>';
+ }
+ while (end_level > 1) {
+ result += '</span>';
+ end_level--;
+ modes.length--;
+ }
+ modes.length--;
+ modes[modes.length - 1].buffer = '';
+ if (current_mode.starts) {
+ for (var i = 0; i < language.modes.length; i++) {
+ if (language.modes[i].className == current_mode.starts) {
+ startNewMode(language.modes[i], '');
+ break;
+ }
+ }
+ }
+ return current_mode.returnEnd;
+ }
+
+ if (isIllegal(lexem, current_mode))
+ throw 'Illegal';
+ }
+
+ var language = LANGUAGES[language_name];
+ var modes = [language.defaultMode];
+ var relevance = 0;
+ var keyword_count = 0;
+ var result = '';
+ try {
+ var index = 0;
+ language.defaultMode.buffer = '';
+ do {
+ var mode_info = eatModeChunk(value, index);
+ var return_lexem = processModeInfo(mode_info[0], mode_info[1], mode_info[2]);
+ index += mode_info[0].length;
+ if (!return_lexem) {
+ index += mode_info[1].length;
+ }
+ } while (!mode_info[2]);
+ if(modes.length > 1)
+ throw 'Illegal';
+ return {
+ relevance: relevance,
+ keyword_count: keyword_count,
+ value: result
+ }
+ } catch (e) {
+ if (e == 'Illegal') {
+ return {
+ relevance: 0,
+ keyword_count: 0,
+ value: escape(value)
+ }
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ function blockText(block) {
+ var result = '';
+ for (var i = 0; i < block.childNodes.length; i++)
+ if (block.childNodes[i].nodeType == 3)
+ result += block.childNodes[i].nodeValue;
+ else if (block.childNodes[i].nodeName == 'BR')
+ result += '\n';
+ else
+ throw 'No highlight';
+ return result;
+ }
+
+ function blockLanguage(block) {
+ var classes = block.className.split(/\s+/);
+ for (var i = 0; i < classes.length; i++) {
+ if (classes[i] == 'no-highlight') {
+ throw 'No highlight'
+ }
+ if (LANGUAGES[classes[i]]) {
+ return classes[i];
+ }
+ }
+ }
+
+ function highlightBlock(block) {
+ try {
+ var text = blockText(block);
+ var language = blockLanguage(block);
+ } catch (e) {
+ if (e == 'No highlight')
+ return;
+ }
+
+ if (language) {
+ var result = highlight(language, text).value;
+ } else {
+ var max_relevance = 2;
+ var relevance = 0;
+ for (var key in selected_languages) {
+ if (!selected_languages.hasOwnProperty(key))
+ continue;
+ var r = highlight(key, text);
+ relevance = r.keyword_count + r.relevance;
+ if (relevance > max_relevance) {
+ max_relevance = relevance;
+ var result = r.value;
+ language = key;
+ }
+ }
+ }
+
+ if (result) {
+ var className = block.className;
+ if (!className.match(language)) {
+ className += ' ' + language;
+ }
+ // See these 4 lines? This is IE's notion of "block.innerHTML = result". Love this browser :-/
+ var container = document.createElement('div');
+ container.innerHTML = '<pre><code class="' + className + '">' + result + '</code></pre>';
+ var environment = block.parentNode.parentNode;
+ environment.replaceChild(container.firstChild, block.parentNode);
+ }
+ }
+
+ function langRe(language, value, global) {
+ var mode = 'm' + (language.case_insensitive ? 'i' : '') + (global ? 'g' : '');
+ return new RegExp(value, mode);
+ }
+
+ function compileModes() {
+ for (var i in LANGUAGES) {
+ if (!LANGUAGES.hasOwnProperty(i))
+ continue;
+ var language = LANGUAGES[i];
+ for (var j = 0; j < language.modes.length; j++) {
+ if (language.modes[j].begin)
+ language.modes[j].beginRe = langRe(language, '^' + language.modes[j].begin);
+ if (language.modes[j].end)
+ language.modes[j].endRe = langRe(language, '^' + language.modes[j].end);
+ if (language.modes[j].illegal)
+ language.modes[j].illegalRe = langRe(language, '^(?:' + language.modes[j].illegal + ')');
+ language.defaultMode.illegalRe = langRe(language, '^(?:' + language.defaultMode.illegal + ')');
+ if (language.modes[j].relevance == undefined) {
+ language.modes[j].relevance = 1;
+ }
+ }
+ }
+ }
+
+ function compileKeywords() {
+
+ function compileModeKeywords(mode) {
+ if (!mode.keywordGroups) {
+ for (var key in mode.keywords) {
+ if (!mode.keywords.hasOwnProperty(key))
+ continue;
+ if (mode.keywords[key] instanceof Object)
+ mode.keywordGroups = mode.keywords;
+ else
+ mode.keywordGroups = {'keyword': mode.keywords};
+ break;
+ }
+ }
+ }
+
+ for (var i in LANGUAGES) {
+ if (!LANGUAGES.hasOwnProperty(i))
+ continue;
+ var language = LANGUAGES[i];
+ compileModeKeywords(language.defaultMode);
+ for (var j = 0; j < language.modes.length; j++) {
+ compileModeKeywords(language.modes[j]);
+ }
+ }
+ }
+
+ function findCode(pre) {
+ for (var i = 0; i < pre.childNodes.length; i++) {
+ node = pre.childNodes[i];
+ if (node.nodeName == 'CODE')
+ return node;
+ if (!(node.nodeType == 3 && node.nodeValue.match(/\s+/)))
+ return null;
+ }
+ }
+
+ function initHighlighting() {
+ if (initHighlighting.called)
+ return;
+ initHighlighting.called = true;
+ compileModes();
+ compileKeywords();
+ if (arguments.length) {
+ for (var i = 0; i < arguments.length; i++) {
+ if (LANGUAGES[arguments[i]]) {
+ selected_languages[arguments[i]] = LANGUAGES[arguments[i]];
+ }
+ }
+ } else
+ selected_languages = LANGUAGES;
+ var pres = document.getElementsByTagName('pre');
+ for (var i = 0; i < pres.length; i++) {
+ var code = findCode(pres[i]);
+ if (code)
+ highlightBlock(code);
+ }
+ }
+
+ function injectScripts(languages) {
+ var scripts = document.getElementsByTagName('SCRIPT');
+ for (var i = 0; i < scripts.length; i++) {
+ if (scripts[i].src.match(/highlight\.js(\?.+)?$/)) {
+ var path = scripts[i].src.replace(/highlight\.js(\?.+)?$/, '');
+ break;
+ }
+ }
+ if (languages.length == 0) {
+ languages = DEFAULT_LANGUAGES;
+ }
+ var injected = {}
+ for (var i = 0; i < languages.length; i++) {
+ var filename = LANGUAGE_GROUPS[languages[i]] ? LANGUAGE_GROUPS[languages[i]] : languages[i];
+ if (!injected[filename]) {
+ document.write('<script type="text/javascript" src="' + path + 'languages/' + filename + '.js"></script>');
+ injected[filename] = true;
+ }
+ }
+ }
+
+ function initHighlightingOnLoad() {
+ var original_arguments = arguments;
+ injectScripts(arguments);
+ var handler = function(){initHighlighting.apply(null, original_arguments)};
+ if (window.addEventListener) {
+ window.addEventListener('DOMContentLoaded', handler, false);
+ window.addEventListener('load', handler, false);
+ } else if (window.attachEvent)
+ window.attachEvent('onload', handler);
+ else
+ window.onload = handler;
+ }
+
+ this.LANGUAGES = LANGUAGES;
+ this.ALL_LANGUAGES = ALL_LANGUAGES;
+ this.initHighlightingOnLoad = initHighlightingOnLoad;
+ this.highlightBlock = highlightBlock;
+
+ // Common regexps
+ this.IDENT_RE = '[a-zA-Z][a-zA-Z0-9_]*';
+ this.UNDERSCORE_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_]*';
+ this.NUMBER_RE = '\\b\\d+(\\.\\d+)?';
+ this.C_NUMBER_RE = '\\b(0x[A-Za-z0-9]+|\\d+(\\.\\d+)?)';
+
+ // Common modes
+ this.APOS_STRING_MODE = {
+ className: 'string',
+ begin: '\'', end: '\'',
+ illegal: '\\n',
+ contains: ['escape'],
+ relevance: 0
+ };
+ this.QUOTE_STRING_MODE = {
+ className: 'string',
+ begin: '"', end: '"',
+ illegal: '\\n',
+ contains: ['escape'],
+ relevance: 0
+ };
+ this.BACKSLASH_ESCAPE = {
+ className: 'escape',
+ begin: '\\\\.', end: '^',
+ relevance: 0
+ };
+ this.C_LINE_COMMENT_MODE = {
+ className: 'comment',
+ begin: '//', end: '$',
+ relevance: 0
+ };
+ this.C_BLOCK_COMMENT_MODE = {
+ className: 'comment',
+ begin: '/\\*', end: '\\*/'
+ };
+ this.HASH_COMMENT_MODE = {
+ className: 'comment',
+ begin: '#', end: '$'
+ };
+ this.C_NUMBER_MODE = {
+ className: 'number',
+ begin: this.C_NUMBER_RE, end: '^',
+ relevance: 0
+ };
+}();
+
+var initHighlightingOnLoad = hljs.initHighlightingOnLoad;
diff --git a/webroot/js/jquery-1.2.6.min.js b/webroot/js/jquery-1.2.6.min.js
new file mode 100644
index 0000000..82b98e1
--- /dev/null
+++ b/webroot/js/jquery-1.2.6.min.js
@@ -0,0 +1,32 @@
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-24 14:22:17 -0400 (Sat, 24 May 2008) $
+ * $Rev: 5685 $
+ */
+(function(){var _jQuery=window.jQuery,_$=window.$;var jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context);};var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,isSimple=/^.[^:#\[\.]*$/,undefined;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem){if(elem.id!=match[3])return jQuery().find(selector);return jQuery(elem);}selector=[];}}else
+return jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(jQuery.makeArray(selector));},jquery:"1.2.6",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this);},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value===undefined)return this[0]&&jQuery[type||"attr"](this[0],name);else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else
+return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else
+selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector=='string'?jQuery(selector):jQuery.makeArray(selector))));},is:function(selector){return!!selector&&jQuery.multiFilter(selector,this).length>0;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery.browser.msie&&!option.attributes.value.specified?option.text:option.value;if(one)return value;values.push(value);}}return values;}else
+return(this[0].value||"").replace(/\r/g,"");}return undefined;}if(value.constructor==Number)value+='';return this.each(function(){if(this.nodeType!=1)return;if(value.constructor==Array&&/radio|checkbox/.test(this.type))this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else
+this.value=value;});},html:function(value){return value==undefined?(this[0]?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length)data=jQuery.data(this[0],key);return data===undefined&&parts[1]?this.data(parts[0]):data;}else
+return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script"))scripts=scripts.add(elem);else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else
+jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}function now(){return+new Date;}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==i){target=this;--i;}for(;i<length;i++)if((options=arguments[i])!=null)for(var name in options){var src=target[name],copy=options[name];if(target===copy)continue;if(deep&©&&typeof copy=="object"&&!copy.nodeType)target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy);else if(copy!==undefined)target[name]=copy;}return target;};var expando="jQuery"+now(),uuid=0,windowData={},exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{};jQuery.extend({noConflict:function(deep){window.$=_$;if(deep)window.jQuery=_jQuery;return jQuery;},isFunction:function(fn){return!!fn&&typeof fn!="string"&&!fn.nodeName&&fn.constructor!=Array&&/^[\s[]?function/.test(fn+"");},isXMLDoc:function(elem){return elem.documentElement&&!elem.body||elem.tagName&&elem.ownerDocument&&!elem.ownerDocument.body;},globalEval:function(data){data=jQuery.trim(data);if(data){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.browser.msie)script.text=data;else
+script.appendChild(document.createTextNode(data));head.insertBefore(script,head.firstChild);head.removeChild(script);}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase();},cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id)id=elem[expando]=++uuid;if(name&&!jQuery.cache[id])jQuery.cache[id]={};if(data!==undefined)jQuery.cache[id][name]=data;return name?jQuery.cache[id][name]:id;},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id])break;if(!name)jQuery.removeData(elem);}}else{try{delete elem[expando];}catch(e){if(elem.removeAttribute)elem.removeAttribute(expando);}delete jQuery.cache[id];}},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length==undefined){for(name in object)if(callback.apply(object[name],args)===false)break;}else
+for(;i<length;)if(callback.apply(object[i++],args)===false)break;}else{if(length==undefined){for(name in object)if(callback.call(object[name],name,object[name])===false)break;}else
+for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}return object;},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value))value=value.call(elem,i);return value&&value.constructor==Number&&type=="curCSS"&&!exclude.test(name)?value+"px":value;},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className))elem.className+=(elem.className?" ":"")+className;});},remove:function(elem,classNames){if(elem.nodeType==1)elem.className=classNames!=undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return!jQuery.className.has(classNames,className);}).join(" "):"";},has:function(elem,className){return jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else
+jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret,style=elem.style;function color(elem){if(!jQuery.browser.safari)return false;var ret=defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=style.outline;style.outline="0 solid black";style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&style&&style[name])ret=style[name];else if(defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle&&!color(elem))ret=computedStyle.getPropertyValue(name);else{var swap=[],stack=[],a=elem,i=0;for(;a&&color(a);a=a.parentNode)stack.unshift(a);for(;i<stack.length;i++)if(color(stack[i])){swap[i]=stack[i].style.display;stack[i].style.display="block";}ret=name=="display"&&swap[stack.length-1]!=null?"none":(computedStyle&&computedStyle.getPropertyValue(name))||"";for(i=0;i<swap.length;i++)if(swap[i]!=null)stack[i].style.display=swap[i];}if(name=="opacity"&&ret=="")ret="1";}else if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase();});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft;}}return ret;},clean:function(elems,context){var ret=[];context=context||document;if(typeof context.createElement=='undefined')context=context.ownerDocument||context[0]&&context[0].ownerDocument||document;jQuery.each(elems,function(i,elem){if(!elem)return;if(elem.constructor==Number)elem+='';if(typeof elem=="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||jQuery.browser.msie&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf("<table")&&tags.indexOf("<tbody")<0?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&tags.indexOf("<tbody")<0?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else
+ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined,msie=jQuery.browser.msie;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(name in elem&¬xml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem[name]=value;}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name))return elem.getAttributeNode(name).nodeValue;return elem[name];}if(msie&¬xml&&name=="style")return jQuery.attr(elem.style,"cssText",value);if(set)elem.setAttribute(name,""+value);var attr=msie&¬xml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr;}if(msie&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+''=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+'':"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(set)elem[name]=value;return elem[name];},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||array.split||array.setInterval||array.call)ret[0]=array;else
+while(i)ret[--i]=array[i];}return ret;},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++)if(array[i]===elem)return i;return-1;},merge:function(first,second){var i=0,elem,pos=first.length;if(jQuery.browser.msie){while(elem=second[i++])if(elem.nodeType!=8)first[pos++]=elem;}else
+while(elem=second[i++])first[pos++]=elem;return first;},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i]);}}}catch(e){ret=array;}return ret;},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++)if(!inv!=!callback(elems[i],i))ret.push(elems[i]);return ret;},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null)ret[ret.length]=value;}return ret.concat.apply([],ret);}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};var styleFloat=jQuery.browser.msie?"styleFloat":"cssFloat";jQuery.extend({boxModel:!jQuery.browser.msie||document.compatMode=="CSS1Compat",props:{"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing"}});jQuery.each({parent:function(elem){return elem.parentNode;},parents:function(elem){return jQuery.dir(elem,"parentNode");},next:function(elem){return jQuery.nth(elem,2,"nextSibling");},prev:function(elem){return jQuery.nth(elem,2,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string")ret=jQuery.multiFilter(selector,ret);return this.pushStack(jQuery.unique(ret));};});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(){var args=arguments;return this.each(function(){for(var i=0,length=args.length;i<length;i++)jQuery(args[i])[original](this);});};});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1)this.removeAttribute(name);},addClass:function(classNames){jQuery.className.add(this,classNames);},removeClass:function(classNames){jQuery.className.remove(this,classNames);},toggleClass:function(classNames){jQuery.className[jQuery.className.has(this,classNames)?"remove":"add"](this,classNames);},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).r.length){jQuery("*",this).add(this).each(function(){jQuery.event.remove(this);jQuery.removeData(this);});if(this.parentNode)this.parentNode.removeChild(this);}},empty:function(){jQuery(">*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0;}var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return i<m[3]-0;},gt:function(a,i,m){return i>m[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false,re=quickChild,m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j<rl;j++){var n=m=="~"||m=="+"?ret[j].nextSibling:ret[j].firstChild;for(;n;n=n.nextSibling)if(n.nodeType==1){var id=jQuery.data(n);if(m=="~"&&merge[id])break;if(!nodeName||n.nodeName.toUpperCase()==nodeName){if(m=="~")merge[id]=true;r.push(n);}if(m=="+")break;}}ret=r;t=jQuery.trim(t.replace(re,""));foundToken=true;}}if(t&&!foundToken){if(!t.indexOf(",")){if(context==ret[0])ret.shift();done=jQuery.merge(done,ret);r=ret=[context];t=" "+t.substr(1,t.length);}else{var re2=quickID;var m=re2.exec(t);if(m){m=[0,m[2],m[3],m[1]];}else{re2=quickClass;m=re2.exec(t);}m[2]=m[2].replace(/\\/g,"");var elem=ret[ret.length-1];if(m[1]=="#"&&elem&&elem.getElementById&&!jQuery.isXMLDoc(elem)){var oid=elem.getElementById(m[2]);if((jQuery.browser.msie||jQuery.browser.opera)&&oid&&typeof oid.id=="string"&&oid.id!=m[2])oid=jQuery('[@id="'+m[2]+'"]',elem)[0];ret=r=oid&&(!m[3]||jQuery.nodeName(oid,m[3]))?[oid]:[];}else{for(var i=0;ret[i];i++){var tag=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];if(tag=="*"&&ret[i].nodeName.toLowerCase()=="object")tag="param";r=jQuery.merge(r,ret[i].getElementsByTagName(tag));}if(m[1]==".")r=jQuery.classFilter(r,m[2]);if(m[1]=="#"){var tmp=[];for(var i=0;r[i];i++)if(r[i].getAttribute("id")==m[2]){tmp=[r[i]];break;}r=tmp;}ret=r;}t=t.replace(re2,"");}}if(t){var val=jQuery.filter(t,r);ret=r=val.r;t=jQuery.trim(val.t);}}if(t)ret=[];if(ret&&context==ret[0])ret.shift();done=jQuery.merge(done,ret);return done;},classFilter:function(r,m,not){m=" "+m+" ";var tmp=[];for(var i=0;r[i];i++){var pass=(" "+r[i].className+" ").indexOf(m)>=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i<rl;i++){var a=r[i],z=a[jQuery.props[m[2]]||m[2]];if(z==null||/href|src|selected/.test(m[2]))z=jQuery.attr(a,m[2])||'';if((type==""&&!!z||type=="="&&z==m[5]||type=="!="&&z!=m[5]||type=="^="&&z&&!z.indexOf(m[5])||type=="$="&&z.substr(z.length-m[5].length)==m[5]||(type=="*="||type=="~=")&&z.indexOf(m[5])>=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i<rl;i++){var node=r[i],parentNode=node.parentNode,id=jQuery.data(parentNode);if(!merge[id]){var c=1;for(var n=parentNode.firstChild;n;n=n.nextSibling)if(n.nodeType==1)n.nodeIndex=c++;merge[id]=true;}var add=false;if(first==0){if(node.nodeIndex==last)add=true;}else if((node.nodeIndex-last)%first==0&&(node.nodeIndex-last)/first>=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem)r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=this.proxy(fn,function(){return fn.apply(this,arguments);});handler.data=data;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){if(typeof jQuery!="undefined"&&!jQuery.event.triggered)return jQuery.event.handle.apply(arguments.callee.elem,arguments);});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else
+for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event){data.unshift({type:type,target:elem,preventDefault:function(){},stopPropagation:function(){},timeStamp:now()});data[0][expando]=true;}data[0].type=type;if(exclusive)data[0].exclusive=true;var handle=jQuery.data(elem,"handle");if(handle)val=handle.apply(elem,data);if((!fn||(jQuery.nodeName(elem,'a')&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val,ret,namespace,all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);namespace=event.type.split(".");event.type=namespace[0];namespace=namespace[1];all=!namespace&&!event.exclusive;handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||handler.type==namespace){event.handler=handler;event.data=handler.data;ret=handler.apply(this,arguments);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}return val;},fix:function(event){if(event[expando]==true)return event;var originalEvent=event;event={originalEvent:originalEvent};var props="altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");for(var i=props.length;i;i--)event[props[i]]=originalEvent[props[i]];event[expando]=true;event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};event.timeStamp=event.timeStamp||now();if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=event.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},proxy:function(fn,proxy){proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;event.type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);});return this.each(function(){jQuery.event.add(this,type,one,fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){return this[0]&&jQuery.event.trigger(type,data,this[0],false,fn);},toggle:function(fn){var args=arguments,i=1;while(i<args.length)jQuery.event.proxy(fn,args[i++]);return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false;}));},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else
+jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){setTimeout(arguments.callee,0);return;}jQuery.ready();},false);if(jQuery.browser.safari){var numStyles;(function(){if(jQuery.isReady)return;if(document.readyState!="loaded"&&document.readyState!="complete"){setTimeout(arguments.callee,0);return;}if(numStyles===undefined)numStyles=jQuery("style, link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){setTimeout(arguments.callee,0);return;}jQuery.ready();})();}jQuery.event.add(window,"load",jQuery.ready);}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name);};});var withinElement=function(event,elem){var parent=event.relatedTarget;while(parent&&parent!=elem)try{parent=parent.parentNode;}catch(error){parent=elem;}return parent==elem;};jQuery(window).bind("unload",function(){jQuery("*").add(document).unbind();});jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!='string')return this._load(url);var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{url:location.href,global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");var remote=/^(?:\w+:)?\/\/([^\/?#]+)/;if(s.dataType=="script"&&type=="GET"&&remote.test(s.url)&&remote.exec(s.url)[1]!=location.host){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xhr=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();if(s.username)xhr.open(type,s.url,s.async,s.username,s.password);else
+xhr.open(type,s.url,s.async);try{if(s.data)xhr.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){s.global&&jQuery.active--;xhr.abort();return false;}if(s.global)jQuery.event.trigger("ajaxSend",[xhr,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xhr)&&"error"||s.ifModified&&jQuery.httpNotModified(xhr,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s.dataFilter);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else
+jQuery.handleError(s,xhr,status);complete();if(s.async)xhr=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xhr){xhr.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xhr.send(s.data);}catch(e){jQuery.handleError(s,xhr,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xhr,s]);}function complete(){if(s.complete)s.complete(xhr,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xhr,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xhr;},handleError:function(s,xhr,status,e){if(s.error)s.error(xhr,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xhr,s,e]);},active:0,httpSuccess:function(xhr){try{return!xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]||jQuery.browser.safari&&xhr.status==undefined;}catch(e){}return false;},httpData:function(xhr,type,filter){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(filter)data=filter(data,type);if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else
+for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else
+s.push(encodeURIComponent(j)+"="+encodeURIComponent(jQuery.isFunction(a[j])?a[j]():a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall),p,hidden=jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return opt.complete.call(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else
+e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.call(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(elem){type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",jQuery.makeArray(array));}return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].call(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:jQuery.fx.speeds[opt.duration])||jQuery.fx.speeds.def;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.call(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.call(this.elem,this.now,this);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++)if(!timers[i]())timers.splice(i--,1);if(!timers.length){clearInterval(jQuery.timerId);jQuery.timerId=null;}},13);}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(0,this.cur());if(this.prop=="width"||this.prop=="height")this.elem.style[this.prop]="1px";jQuery(this.elem).show();},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0);},step:function(gotoEnd){var t=now();if(gotoEnd||t>this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done)this.options.complete.call(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,def:400},step:{scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}}});jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),css=jQuery.curCSS,fixed=css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||css(offsetChild,"position")=="absolute"))||(mozilla&&css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l,10)||0;top+=parseInt(t,10)||0;}return results;};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,'marginTop');offset.left-=num(this,'marginLeft');parentOffset.top+=num(offsetParent,'borderTopWidth');parentOffset.left+=num(offsetParent,'borderLeftWidth');results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left};}return results;},offsetParent:function(){var offsetParent=this[0].offsetParent;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,'position')=='static'))offsetParent=offsetParent.offsetParent;return jQuery(offsetParent);}});jQuery.each(['Left','Top'],function(i,name){var method='scroll'+name;jQuery.fn[method]=function(val){if(!this[0])return;return val!=undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val;}):this[0]==window||this[0]==document?self[i?'pageYOffset':'pageXOffset']||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method];};});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom";jQuery.fn["inner"+name]=function(){return this[name.toLowerCase()]()+num(this,"padding"+tl)+num(this,"padding"+br);};jQuery.fn["outer"+name]=function(margin){return this["inner"+name]()+num(this,"border"+tl+"Width")+num(this,"border"+br+"Width")+(margin?num(this,"margin"+tl)+num(this,"margin"+br):0);};});})();
\ No newline at end of file
diff --git a/webroot/js/languages/1c.js b/webroot/js/languages/1c.js
new file mode 100644
index 0000000..963da04
--- /dev/null
+++ b/webroot/js/languages/1c.js
@@ -0,0 +1,82 @@
+hljs.IDENT_RE_RU = '[a-zA-Zа-яА-Я][a-zA-Z0-9_а-яА-Я]*';
+hljs.OneS_KEYWORDS = {'процедура':1,'функция':1,'экспорт':1,'перем':1,'конецфункции':1,'конецпроцедуры':1,'если':1,'тогда':1,'иначе':1,'иначеесли':1,'конецесли':1,'попытка':1,'исключение':1,'конецпопытки':1,'ложь':1,'истина':1,'неопределено':1,'и':1,'или':1,'не':1,'null':1,'для':1,'каждого':1,'из':1,'по':1,'цикл':1,'конеццикла':1};
+
+hljs.LANGUAGES['1c'] = {
+ defaultMode: {
+ lexems: [hljs.IDENT_RE_RU],
+ contains: ['comment', 'string', 'function', 'preprocessor', 'number'],
+ keywords: hljs.OneS_KEYWORDS
+ },
+ case_insensitive: true,
+ modes: [
+ hljs.C_LINE_COMMENT_MODE,
+ {
+ className: 'string',
+ begin: '"', end: '"',
+ contains: ['dquote'],
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: '"', end: '$',
+ contains: ['dquote']
+ },
+ {
+ className: 'string',
+ begin: '\\|', end: '$',
+ contains: ['dquote']
+ },
+ {
+ className: 'string',
+ begin: '\\|', end: '"',
+ contains: ['dquote']
+ },
+ {
+ className: 'dquote',
+ begin: '""', end: '^'
+ },
+ {
+ className: 'number',
+ begin: hljs.NUMBER_RE, end: '^',
+ relevance: 0
+ },
+ {
+ className: 'title',
+ lexems: [hljs.IDENT_RE_RU],
+ begin: hljs.IDENT_RE_RU, end: '^'
+ },
+ {
+ className: 'params',
+ begin: '\\(', end: '\\)',
+ lexems: [hljs.IDENT_RE_RU],
+ keywords: {'знач':1},
+ contains: ['string']
+ },
+ {
+ className: 'function',
+ begin: '(процедура|функция)', end: '$',
+ lexems: [hljs.IDENT_RE_RU],
+ keywords: {'процедура': 1, 'экспорт':1, 'функция': 1},
+ contains: ['title','tail','comment'],
+ relevance: 0
+ },
+ {
+ className: 'tail',
+ begin: '^', endsWithParent: true,
+ lexems: [hljs.IDENT_RE_RU],
+ contains: ['params', 'export']
+ },
+ {
+ className: 'export',
+ begin: 'экспорт', endsWithParent: true,
+ lexems: [hljs.IDENT_RE_RU],
+ keywords: {'экспорт': 1},
+ contains: ['comment']
+ },
+ {
+ className: 'preprocessor',
+ begin: '#', end: '$',
+ lexems: [hljs.IDENT_RE_RU]
+ }
+ ]
+};
diff --git a/webroot/js/languages/axapta.js b/webroot/js/languages/axapta.js
new file mode 100644
index 0000000..e9d77e5
--- /dev/null
+++ b/webroot/js/languages/axapta.js
@@ -0,0 +1,52 @@
+/*
+
+Axapta definition (с) Dmitri Roudakov <dmitri@roudakov.ru>
+
+*/
+hljs.LANGUAGES.axapta = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ contains: ['comment', 'string', 'class', 'number', 'preprocessor'],
+ keywords: {'false': 1, 'int': 1, 'abstract': 1, 'private': 1, 'char': 1, 'interface': 1, 'boolean': 1, 'static': 1, 'null': 1, 'if': 1, 'for': 1, 'true': 1, 'while': 1, 'long': 1, 'throw': 1, 'finally': 1, 'protected': 1, 'extends': 1, 'final': 1, 'implements': 1, 'return': 1, 'void': 1, 'enum': 1, 'else': 1, 'break': 1, 'new': 1, 'catch': 1, 'byte': 1, 'super': 1, 'class': 1, 'case': 1, 'short': 1, 'default': 1, 'double': 1, 'public': 1, 'try': 1, 'this': 1, 'switch': 1, 'continue': 1,
+ 'reverse':1, 'firstfast':1,'firstonly':1,'forupdate':1,'nofetch':1, 'sum':1, 'avg':1, 'minof':1, 'maxof':1, 'count':1, 'order':1, 'group':1, 'by':1, 'asc':1, 'desc':1, 'index':1, 'hint':1, 'like':1,
+ 'dispaly':1, 'edit':1, 'client':1, 'server':1, 'ttsbegin':1, 'ttscommit':1,
+ 'str':1, 'real':1, 'date':1, 'container':1, 'anytype':1, 'common':1, 'div':1,'mod':1
+ }
+ },
+ modes: [
+ {
+ className: 'class',
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ begin: '(class |interface )', end: '{',
+ illegal: ':',
+ keywords: {'class': 1, 'interface': 1},
+ contains: ['inheritance', 'title']
+ },
+ {
+ className: 'inheritance',
+ begin: '(implements|extends)', end: '^',
+ lexems: [hljs.IDENT_RE],
+ keywords: {'extends': 1, 'implements': 1},
+ relevance: 10
+ },
+ {
+ className: 'title',
+ begin: hljs.UNDERSCORE_IDENT_RE, end: '^'
+ },
+ {
+ className: 'params',
+ begin: '\\(', end: '\\)',
+ contains: ['string', 'annotation']
+ },
+ hljs.C_NUMBER_MODE,
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ {
+ className: 'preprocessor',
+ begin: '#', end: '$'
+ }
+ ]
+};
diff --git a/webroot/js/languages/bash.js b/webroot/js/languages/bash.js
new file mode 100644
index 0000000..ec8f252
--- /dev/null
+++ b/webroot/js/languages/bash.js
@@ -0,0 +1,80 @@
+/*
+
+Bash Scripts by vah <vahtenberg@gmail.com>
+
+*/
+hljs.BASH_LITERAL = {'true' : 1, 'false' : 1}
+hljs.LANGUAGES.bash = {
+ defaultMode: {
+ lexems: [hljs.IDENT_RE],
+ contains: ['string', 'shebang', 'comment', 'number', 'test_condition', 'string', 'variable'],
+ keywords: {
+ 'keyword': {'if' : 1, 'then' : 1, 'else' : 1, 'fi' : 1, 'for' : 1, 'break' : 1, 'continue' : 1, 'while' : 1, 'in' : 1, 'do' : 1, 'done' : 1, 'echo' : 1, 'exit' : 1, 'return' : 1, 'set' : 1, 'declare' : 1},
+ 'literal': hljs.BASH_LITERAL
+ }
+ },
+ case_insensitive: false,
+ modes: [
+ {
+ className: 'shebang',
+ begin: '(#!\\/bin\\/bash)|(#!\\/bin\\/sh)',
+ end: '^',
+ relevance: 10
+ },
+ hljs.HASH_COMMENT_MODE,
+ {
+ className: 'test_condition',
+ begin: '\\[ ',
+ end: ' \\]',
+ contains: ['string', 'variable', 'number'],
+ lexems: [hljs.IDENT_RE],
+ keywords: {
+ 'literal': hljs.BASH_LITERAL
+ },
+ relevance: 0
+ },
+ {
+ className: 'test_condition',
+ begin: '\\[\\[ ',
+ end: ' \\]\\]',
+ contains: ['string', 'variable', 'number'],
+ lexems: [hljs.IDENT_RE],
+ keywords: {
+ 'literal': hljs.BASH_LITERAL
+ }
+ },
+ {
+ className: 'variable',
+ begin: '\\$([a-zA-Z0-9_]+)\\b',
+ end: '^'
+ },
+ {
+ className: 'variable',
+ begin: '\\$\\{(([^}])|(\\\\}))+\\}',
+ end: '^',
+ contains: ['number']
+ },
+ {
+ className: 'string',
+ begin: '"', end: '"',
+ illegal: '\\n',
+ contains: ['escape', 'variable'],
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: '"', end: '"',
+ illegal: '\\n',
+ contains: ['escape', 'variable'],
+ relevance: 0
+ },
+ hljs.BACKSLASH_ESCAPE,
+ hljs.C_NUMBER_MODE,
+ {
+ className: 'comment',
+ begin: '\\/\\/', end: '$',
+ illegal: '.'
+ }
+ ]
+};
+
diff --git a/webroot/js/languages/diff.js b/webroot/js/languages/diff.js
new file mode 100644
index 0000000..9d27cab
--- /dev/null
+++ b/webroot/js/languages/diff.js
@@ -0,0 +1,64 @@
+/*
+
+Unified and context diff definition (c) Vasily Polovnyov <vast@whiteants.net>
+
+*/
+hljs.LANGUAGES.diff = {
+ case_insensitive: true,
+ defaultMode: {
+ contains: ['chunk', 'header', 'addition', 'deletion', 'change']
+ },
+ modes: [
+ {
+ className: 'chunk',
+ begin: '^\\@\\@ +\\-\\d+,\\d+ +\\+\\d+,\\d+ +\\@\\@$', end:'^',
+ relevance: 10
+ },
+ {
+ className: 'chunk',
+ begin: '^\\*\\*\\* +\\d+,\\d+ +\\*\\*\\*\\*$', end: '^',
+ relevance: 10
+ },
+ {
+ className: 'chunk',
+ begin: '^\\-\\-\\- +\\d+,\\d+ +\\-\\-\\-\\-$', end: '^',
+ relevance: 10
+ },
+ {
+ className: 'header',
+ begin: 'Index: ', end: '$'
+ },
+ {
+ className: 'header',
+ begin: '=====', end: '=====$'
+ },
+ {
+ className: 'header',
+ begin: '^\\-\\-\\-', end: '$'
+ },
+ {
+ className: 'header',
+ begin: '^\\*{3} ', end: '$'
+ },
+ {
+ className: 'header',
+ begin: '^\\+\\+\\+', end: '$'
+ },
+ {
+ className: 'header',
+ begin: '\\*{5}', end: '\\*{5}$'
+ },
+ {
+ className: 'addition',
+ begin: '^\\+', end: '$'
+ },
+ {
+ className: 'deletion',
+ begin: '^\\-', end: '$'
+ },
+ {
+ className: 'change',
+ begin: '^\\!', end: '$'
+ }
+ ]
+}
diff --git a/webroot/js/languages/dos.js b/webroot/js/languages/dos.js
new file mode 100644
index 0000000..9397936
--- /dev/null
+++ b/webroot/js/languages/dos.js
@@ -0,0 +1,33 @@
+/*
+DOS definition. Alexander Makarov (http://rmcreative.ru/)
+*/
+hljs.DOS_KEYWORDS = {
+ 'flow': {'if':1, 'else':1, 'goto':1, 'for':1, 'in':1, 'do':1, 'call':1, 'exit':1, 'not':1, 'exist':1, 'errorlevel':1, 'defined':1, 'equ':1, 'neq':1, 'lss':1, 'leq':1, 'gtr':1, 'geq':1},
+ 'keyword':{'shift':1, 'cd':1, 'dir':1, 'echo':1, 'setlocal':1, 'endlocal':1, 'set':1, 'pause':1, 'copy':1},
+ 'stream':{'prn':1, 'nul':1, 'lpt3':1, 'lpt2':1, 'lpt1':1, 'con':1, 'com4':1, 'com3':1, 'com2':1, 'com1':1, 'aux':1},
+ 'winutils':{'ping':1, 'net':1, 'ipconfig':1, 'taskkill':1, 'xcopy':1, 'ren':1, 'del':1}
+};
+
+hljs.LANGUAGES.dos = {
+ case_insensitive: true,
+ defaultMode: {
+ lexems: [hljs.IDENT_RE],
+ contains: ['envvar', 'number', 'comment'],
+ keywords: hljs.DOS_KEYWORDS
+ },
+ modes: [
+ {
+ className: 'number',
+ begin: '\\b\\d+', end: '^',
+ relevance: 0
+ },
+ {
+ className: 'comment',
+ begin: '@?rem', end: '$'
+ },
+ {
+ className: 'envvar',
+ begin: '%[^ ]+?%', end: '^'
+ }
+ ]
+};
diff --git a/webroot/js/languages/dynamic.js b/webroot/js/languages/dynamic.js
new file mode 100644
index 0000000..796317d
--- /dev/null
+++ b/webroot/js/languages/dynamic.js
@@ -0,0 +1,460 @@
+hljs.LANGUAGES.python = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ illegal: '(</|->)',
+ contains: ['comment', 'string', 'function', 'class', 'number', 'decorator'],
+ keywords: {
+ 'keyword': {'and': 1, 'elif': 1, 'is': 1, 'global': 1, 'as': 1, 'in': 1, 'if': 1, 'from': 1, 'raise': 1, 'for': 1, 'except': 1, 'finally': 1, 'print': 1, 'import': 1, 'pass': 1, 'return': 1, 'exec': 1, 'else': 1, 'break': 1, 'not': 1, 'with': 1, 'class': 1, 'assert': 1, 'yield': 1, 'try': 1, 'while': 1, 'continue': 1, 'del': 1, 'or': 1, 'def': 1, 'lambda': 1},
+ 'built_in': {'None': 1, 'True': 1, 'False': 1, 'Ellipsis': 1, 'NotImplemented': 1}
+ }
+ },
+ modes: [
+ {
+ className: 'function',
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ begin: '\\bdef ', end: ':',
+ illegal: '$',
+ keywords: {'def': 1},
+ contains: ['title', 'params'],
+ relevance: 10
+ },
+ {
+ className: 'class',
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ begin: '\\bclass ', end: ':',
+ illegal: '[${]',
+ keywords: {'class': 1},
+ contains: ['title', 'params',],
+ relevance: 10
+ },
+ {
+ className: 'title',
+ begin: hljs.UNDERSCORE_IDENT_RE, end: '^'
+ },
+ {
+ className: 'params',
+ begin: '\\(', end: '\\)',
+ contains: ['string']
+ },
+ hljs.HASH_COMMENT_MODE,
+ hljs.C_NUMBER_MODE,
+ {
+ className: 'string',
+ begin: '\'\'\'', end: '\'\'\'',
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: '"""', end: '"""',
+ relevance: 10
+ },
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'string',
+ begin: 'r\'', end: '\'',
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: 'r"', end: '"',
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: 'u\'', end: '(^|[^\\\\])\'',
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: 'u"', end: '(^|[^\\\\])"',
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: 'ur\'', end: '\'',
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: 'ur"', end: '"',
+ relevance: 10
+ },
+ {
+ className: 'decorator',
+ begin: '@', end: '$'
+ }
+ ]
+};
+
+
+/*
+
+Perl definition (с) Peter Leonov <gojpeg@yandex.ru>
+
+*/
+hljs.PERL_DEFAULT_CONTAINS = ['comment', 'string', 'number', 'regexp', 'sub', 'variable', 'operator', 'pod'];
+hljs.PERL_KEYWORDS = {'getpwent': 1, 'getservent': 1, 'quotemeta': 1, 'msgrcv': 1, 'scalar': 1, 'kill': 1, 'dbmclose': 1, 'undef': 1, 'lc': 1, 'ma': 1, 'syswrite': 1, 'tr': 1, 'send': 1, 'umask': 1, 'sysopen': 1, 'shmwrite': 1, 'vec': 1, 'qx': 1, 'utime': 1, 'local': 1, 'oct': 1, 'semctl': 1, 'localtime': 1, 'readpipe': 1, 'do': 1, 'return': 1, 'format': 1, 'read': 1, 'sprintf': 1, 'dbmopen': 1, 'pop': 1, 'getpgrp': 1, 'not': 1, 'getpwnam': 1, 'rewinddir': 1, 'qq': 1, 'fileno': 1, 'qw': 1, 'endprotoent': 1, 'wait': 1, 'sethostent': 1, 'bless': 1, 's': 1, 'opendir': 1, 'continue': 1, 'each': 1, 'sleep': 1, 'endgrent': 1, 'shutdown': 1, 'dump': 1, 'chomp': 1, 'connect': 1, 'getsockname': 1, 'die': 1, 'socketpair': 1, 'close': 1, 'flock': 1, 'exists': 1, 'index': 1, 'shmget': 1, 'sub': 1, 'for': 1, 'endpwent': 1, 'redo': 1, 'lstat': 1, 'msgctl': 1, 'setpgrp': 1, 'abs': 1, 'exit': 1, 'select': 1, 'print': 1, 'ref': 1, 'gethostbyaddr': 1, 'unshift': 1, 'fcntl': 1, 'syscall': 1, 'goto': 1, 'getnetbyaddr': 1, 'join': 1, 'gmtime': 1, 'symlink': 1, 'semget': 1, 'splice': 1, 'x': 1, 'getpeername': 1, 'recv': 1, 'log': 1, 'setsockopt': 1, 'cos': 1, 'last': 1, 'reverse': 1, 'gethostbyname': 1, 'getgrnam': 1, 'study': 1, 'formline': 1, 'endhostent': 1, 'times': 1, 'chop': 1, 'length': 1, 'gethostent': 1, 'getnetent': 1, 'pack': 1, 'getprotoent': 1, 'getservbyname': 1, 'rand': 1, 'mkdir': 1, 'pos': 1, 'chmod': 1, 'y': 1, 'substr': 1, 'endnetent': 1, 'printf': 1, 'next': 1, 'open': 1, 'msgsnd': 1, 'readdir': 1, 'use': 1, 'unlink': 1, 'getsockopt': 1, 'getpriority': 1, 'rindex': 1, 'wantarray': 1, 'hex': 1, 'system': 1, 'getservbyport': 1, 'endservent': 1, 'int': 1, 'chr': 1, 'untie': 1, 'rmdir': 1, 'prototype': 1, 'tell': 1, 'listen': 1, 'fork': 1, 'shmread': 1, 'ucfirst': 1, 'setprotoent': 1, 'else': 1, 'sysseek': 1, 'link': 1, 'getgrgid': 1, 'shmctl': 1, 'waitpid': 1, 'unpack': 1, 'getnetbyname': 1, 'reset': 1, 'chdir': 1, 'grep': 1, 'split': 1, 'require': 1, 'caller': 1, 'lcfirst': 1, 'until': 1, 'warn': 1, 'while': 1, 'values': 1, 'shift': 1, 'telldir': 1, 'getpwuid': 1, 'my': 1, 'getprotobynumber': 1, 'delete': 1, 'and': 1, 'sort': 1, 'uc': 1, 'defined': 1, 'srand': 1, 'accept': 1, 'package': 1, 'seekdir': 1, 'getprotobyname': 1, 'semop': 1, 'our': 1, 'rename': 1, 'seek': 1, 'if': 1, 'q': 1, 'chroot': 1, 'sysread': 1, 'setpwent': 1, 'no': 1, 'crypt': 1, 'getc': 1, 'chown': 1, 'sqrt': 1, 'write': 1, 'setnetent': 1, 'setpriority': 1, 'foreach': 1, 'tie': 1, 'sin': 1, 'msgget': 1, 'map': 1, 'stat': 1, 'getlogin': 1, 'unless': 1, 'elsif': 1, 'truncate': 1, 'exec': 1, 'keys': 1, 'glob': 1, 'tied': 1, 'closedir': 1, 'ioctl': 1, 'socket': 1, 'readlink': 1, 'eval': 1, 'xor': 1, 'readline': 1, 'binmode': 1, 'setservent': 1, 'eof': 1, 'ord': 1, 'bind': 1, 'alarm': 1, 'pipe': 1, 'atan2': 1, 'getgrent': 1, 'exp': 1, 'time': 1, 'push': 1, 'setgrent': 1, 'gt': 1, 'lt': 1, 'or': 1, 'ne': 1, 'm': 1};
+
+hljs.LANGUAGES.perl = {
+ defaultMode: {
+ lexems: [hljs.IDENT_RE],
+ contains: hljs.PERL_DEFAULT_CONTAINS,
+ keywords: hljs.PERL_KEYWORDS
+ },
+ modes: [
+
+ // variables
+ {
+ className: 'variable',
+ begin: '\\$\\d', end: '^'
+ },
+ {
+ className: 'variable',
+ begin: '[\\$\\%\\@\\*](\\^\\w\\b|#\\w+(\\:\\:\\w+)*|[^\\s\\w{]|{\\w+}|\\w+(\\:\\:\\w*)*)', end: '^'
+ },
+
+ // numbers and strings
+ {
+ className: 'subst',
+ begin: '[$@]\\{', end: '\}',
+ lexems: [hljs.IDENT_RE],
+ keywords: hljs.PERL_KEYWORDS,
+ contains: hljs.PERL_DEFAULT_CONTAINS,
+ relevance: 10
+ },
+ {
+ className: 'number',
+ begin: '(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b', end: '^',
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: 'q[qwxr]?\\s*\\(', end: '\\)',
+ contains: ['escape', 'subst', 'variable'],
+ relevance: 5
+ },
+ {
+ className: 'string',
+ begin: 'q[qwxr]?\\s*\\[', end: '\\]',
+ contains: ['escape', 'subst', 'variable'],
+ relevance: 5
+ },
+ {
+ className: 'string',
+ begin: 'q[qwxr]?\\s*\\{', end: '\\}',
+ contains: ['escape', 'subst', 'variable'],
+ relevance: 5
+ },
+ {
+ className: 'string',
+ begin: 'q[qwxr]?\\s*\\|', end: '\\|',
+ contains: ['escape', 'subst', 'variable'],
+ relevance: 5
+ },
+ {
+ className: 'string',
+ begin: 'q[qwxr]?\\s*\\<', end: '\\>',
+ contains: ['escape', 'subst', 'variable'],
+ relevance: 5
+ },
+ {
+ className: 'string',
+ begin: 'qw\\s+q', end: 'q',
+ contains: ['escape', 'subst', 'variable'],
+ relevance: 5
+ },
+ {
+ className: 'string',
+ begin: '\'', end: '\'',
+ contains: ['escape'],
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: '"', end: '"',
+ contains: ['escape','subst','variable'],
+ relevance: 0
+ },
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'string',
+ begin: '`', end: '`',
+ contains: ['escape']
+ },
+
+ // regexps
+ {
+ className: 'regexp',
+ begin: '(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*', end: '^',
+ relevance: 10
+ },
+ {
+ className: 'regexp',
+ begin: '(m|qr)?/', end: '/[a-z]*',
+ contains: ['escape'],
+ relevance: 0 // allows empty "//" which is a common comment delimiter in other languages
+ },
+
+ // bareword context
+ {
+ className: 'string',
+ begin: '{\\w+}', end: '^',
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: '\-?\\w+\\s*\\=\\>', end: '^',
+ relevance: 0
+ },
+
+ // subroutines
+ {
+ className: 'sub',
+ begin: '\\bsub\\b', end: '(\\s*\\(.*?\\))?[;{]',
+ lexems: [hljs.IDENT_RE],
+ keywords: {'sub':1},
+ relevance: 5
+ },
+
+ // operators
+ {
+ className: 'operator',
+ begin: '-\\w\\b', end: '^',
+ relevance: 0
+ },
+
+ // comments
+ hljs.HASH_COMMENT_MODE,
+ {
+ className: 'comment',
+ begin: '^(__END__|__DATA__)', end: '\\n$',
+ relevance: 5
+ },
+ // pod
+ {
+ className: 'pod',
+ begin: '\\=\\w', end: '\\=cut'
+ }
+
+ ]
+};
+
+/*
+
+PHP5 definition (с) Victor Karamzin <Victor.Karamzin@enterra-inc.com>
+
+*/
+hljs.PHP5_KEYWORDS = {'and': 1, 'include_once': 1, 'list': 1, 'abstract': 1, 'global': 1, 'private': 1, 'echo': 1, 'interface': 1, 'as': 1, 'static': 1, 'endswitch': 1, 'array': 1, 'null': 1, 'if': 1, 'endwhile': 1, 'or': 1, 'const': 1, 'for': 1, 'endforeach': 1, 'self': 1, 'var': 1, 'while': 1, 'isset': 1, 'public': 1, 'protected': 1, 'exit': 1, 'foreach': 1, 'throw': 1, 'elseif': 1, 'extends': 1, 'include': 1, '__FILE__': 1, 'empty': 1, 'require_once': 1, 'function': 1, 'do': 1, 'xor': 1, 'return': 1, 'implements': 1, 'parent': 1, 'clone': 1, 'use': 1, '__CLASS__': 1, '__LINE__': 1, 'else': 1, 'break': 1, 'print': 1, 'eval': 1, 'new': 1, 'catch': 1, '__METHOD__': 1, 'class': 1, 'case': 1, 'exception': 1, 'php_user_filter': 1, 'default': 1, 'die': 1, 'require': 1, '__FUNCTION__': 1, 'enddeclare': 1, 'final': 1, 'try': 1, 'this': 1, 'switch': 1, 'continue': 1, 'endfor': 1, 'endif': 1, 'declare': 1, 'unset': 1};
+
+hljs.PHP_IDENTIFIER_RE = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*';
+
+hljs.LANGUAGES.php = {
+ defaultMode: {
+ lexems: [hljs.IDENT_RE],
+ contains: ['comment', 'number', 'string', 'variable', 'preprocessor'],
+ keywords: hljs.PHP5_KEYWORDS
+ },
+ case_insensitive: true,
+ modes: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.HASH_COMMENT_MODE,
+ {
+ className: 'comment',
+ begin: '/\\*', end: '\\*/',
+ contains: ['phpdoc']
+ },
+ {
+ className: 'phpdoc',
+ begin: '\\s@[A-Za-z]+', end: '^',
+ relevance: 10
+ },
+ hljs.C_NUMBER_MODE,
+ {
+ className: 'string',
+ begin: '\'', end: '\'',
+ contains: ['escape'],
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: '"', end: '"',
+ contains: ['escape'],
+ relevance: 0
+ },
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'variable',
+ begin: '\\$' + hljs.PHP_IDENTIFIER_RE, end: '^'
+ },
+ {
+ className: 'preprocessor',
+ begin: '<\\?php', end: '^',
+ relevance: 10
+ },
+ {
+ className: 'preprocessor',
+ begin: '\\?>', end: '^'
+ }
+ ]
+};
+
+/*
+
+Ruby definition (с) Anton Kovalyov <anton@kovalyov.net>, Peter Leonov <gojpeg@yandex.ru>
+
+*/
+hljs.RUBY_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?';
+hljs.RUBY_DEFAULT_CONTAINS = ['comment', 'string', 'char', 'class', 'function', 'symbol', 'number', 'variable', 'regexp']
+hljs.RUBY_KEYWORDS = {
+ 'keyword': {'and': 1, 'false': 1, 'then': 1, 'defined': 1, 'module': 1, 'in': 1, 'return': 1, 'redo': 1, 'if': 1, 'BEGIN': 1, 'retry': 1, 'end': 1, 'for': 1, 'true': 1, 'self': 1, 'when': 1, 'next': 1, 'until': 1, 'do': 1, 'begin': 1, 'unless': 1, 'END': 1, 'rescue': 1, 'nil': 1, 'else': 1, 'break': 1, 'undef': 1, 'not': 1, 'super': 1, 'class': 1, 'case': 1, 'require': 1, 'yield': 1, 'alias': 1, 'while': 1, 'ensure': 1, 'elsif': 1, 'or': 1, 'def': 1},
+ 'keymethods': {'__id__': 1, '__send__': 1, 'abort': 1, 'abs': 1, 'all?': 1, 'allocate': 1, 'ancestors': 1, 'any?': 1, 'arity': 1, 'assoc': 1, 'at': 1, 'at_exit': 1, 'autoload': 1, 'autoload?': 1, 'between?': 1, 'binding': 1, 'binmode': 1, 'block_given?': 1, 'call': 1, 'callcc': 1, 'caller': 1, 'capitalize': 1, 'capitalize!': 1, 'casecmp': 1, 'catch': 1, 'ceil': 1, 'center': 1, 'chomp': 1, 'chomp!': 1, 'chop': 1, 'chop!': 1, 'chr': 1, 'class': 1, 'class_eval': 1, 'class_variable_defined?': 1, 'class_variables': 1, 'clear': 1, 'clone': 1, 'close': 1, 'close_read': 1, 'close_write': 1, 'closed?': 1, 'coerce': 1, 'collect': 1, 'collect!': 1, 'compact': 1, 'compact!': 1, 'concat': 1, 'const_defined?': 1, 'const_get': 1, 'const_missing': 1, 'const_set': 1, 'constants': 1, 'count': 1, 'crypt': 1, 'default': 1, 'default_proc': 1, 'delete': 1, 'delete!': 1, 'delete_at': 1, 'delete_if': 1, 'detect': 1, 'display': 1, 'div': 1, 'divmod': 1, 'downcase': 1, 'downcase!': 1, 'downto': 1, 'dump': 1, 'dup': 1, 'each': 1, 'each_byte': 1, 'each_index': 1, 'each_key': 1, 'each_line': 1, 'each_pair': 1, 'each_value': 1, 'each_with_index': 1, 'empty?': 1, 'entries': 1, 'eof': 1, 'eof?': 1, 'eql?': 1, 'equal?': 1, 'eval': 1, 'exec': 1, 'exit': 1, 'exit!': 1, 'extend': 1, 'fail': 1, 'fcntl': 1, 'fetch': 1, 'fileno': 1, 'fill': 1, 'find': 1, 'find_all': 1, 'first': 1, 'flatten': 1, 'flatten!': 1, 'floor': 1, 'flush': 1, 'for_fd': 1, 'foreach': 1, 'fork': 1, 'format': 1, 'freeze': 1, 'frozen?': 1, 'fsync': 1, 'getc': 1, 'gets': 1, 'global_variables': 1, 'grep': 1, 'gsub': 1, 'gsub!': 1, 'has_key?': 1, 'has_value?': 1, 'hash': 1, 'hex': 1, 'id': 1, 'include?': 1, 'included_modules': 1, 'index': 1, 'indexes': 1, 'indices': 1, 'induced_from': 1, 'inject': 1, 'insert': 1, 'inspect': 1, 'instance_eval': 1, 'instance_method': 1, 'instance_methods': 1, 'instance_of?': 1, 'instance_variable_defined?': 1, 'instance_variable_get': 1, 'instance_variable_set': 1, 'instance_variables': 1, 'integer?': 1, 'intern': 1, 'invert': 1, 'ioctl': 1, 'is_a?': 1, 'isatty': 1, 'iterator?': 1, 'join': 1, 'key?': 1, 'keys': 1, 'kind_of?': 1, 'lambda': 1, 'last': 1, 'length': 1, 'lineno': 1, 'ljust': 1, 'load': 1, 'local_variables': 1, 'loop': 1, 'lstrip': 1, 'lstrip!': 1, 'map': 1, 'map!': 1, 'match': 1, 'max': 1, 'member?': 1, 'merge': 1, 'merge!': 1, 'method': 1, 'method_defined?': 1, 'method_missing': 1, 'methods': 1, 'min': 1, 'module_eval': 1, 'modulo': 1, 'name': 1, 'nesting': 1, 'new': 1, 'next': 1, 'next!': 1, 'nil?': 1, 'nitems': 1, 'nonzero?': 1, 'object_id': 1, 'oct': 1, 'open': 1, 'pack': 1, 'partition': 1, 'pid': 1, 'pipe': 1, 'pop': 1, 'popen': 1, 'pos': 1, 'prec': 1, 'prec_f': 1, 'prec_i': 1, 'print': 1, 'printf': 1, 'private_class_method': 1, 'private_instance_methods': 1, 'private_method_defined?': 1, 'private_methods': 1, 'proc': 1, 'protected_instance_methods': 1, 'protected_method_defined?': 1, 'protected_methods': 1, 'public_class_method': 1, 'public_instance_methods': 1, 'public_method_defined?': 1, 'public_methods': 1, 'push': 1, 'putc': 1, 'puts': 1, 'quo': 1, 'raise': 1, 'rand': 1, 'rassoc': 1, 'read': 1, 'read_nonblock': 1, 'readchar': 1, 'readline': 1, 'readlines': 1, 'readpartial': 1, 'rehash': 1, 'reject': 1, 'reject!': 1, 'remainder': 1, 'reopen': 1, 'replace': 1, 'require': 1, 'respond_to?': 1, 'reverse': 1, 'reverse!': 1, 'reverse_each': 1, 'rewind': 1, 'rindex': 1, 'rjust': 1, 'round': 1, 'rstrip': 1, 'rstrip!': 1, 'scan': 1, 'seek': 1, 'select': 1, 'send': 1, 'set_trace_func': 1, 'shift': 1, 'singleton_method_added': 1, 'singleton_methods': 1, 'size': 1, 'sleep': 1, 'slice': 1, 'slice!': 1, 'sort': 1, 'sort!': 1, 'sort_by': 1, 'split': 1, 'sprintf': 1, 'squeeze': 1, 'squeeze!': 1, 'srand': 1, 'stat': 1, 'step': 1, 'store': 1, 'strip': 1, 'strip!': 1, 'sub': 1, 'sub!': 1, 'succ': 1, 'succ!': 1, 'sum': 1, 'superclass': 1, 'swapcase': 1, 'swapcase!': 1, 'sync': 1, 'syscall': 1, 'sysopen': 1, 'sysread': 1, 'sysseek': 1, 'system': 1, 'syswrite': 1, 'taint': 1, 'tainted?': 1, 'tell': 1, 'test': 1, 'throw': 1, 'times': 1, 'to_a': 1, 'to_ary': 1, 'to_f': 1, 'to_hash': 1, 'to_i': 1, 'to_int': 1, 'to_io': 1, 'to_proc': 1, 'to_s': 1, 'to_str': 1, 'to_sym': 1, 'tr': 1, 'tr!': 1, 'tr_s': 1, 'tr_s!': 1, 'trace_var': 1, 'transpose': 1, 'trap': 1, 'truncate': 1, 'tty?': 1, 'type': 1, 'ungetc': 1, 'uniq': 1, 'uniq!': 1, 'unpack': 1, 'unshift': 1, 'untaint': 1, 'untrace_var': 1, 'upcase': 1, 'upcase!': 1, 'update': 1, 'upto': 1, 'value?': 1, 'values': 1, 'values_at': 1, 'warn': 1, 'write': 1, 'write_nonblock': 1, 'zero?': 1, 'zip': 1}
+}
+
+hljs.LANGUAGES.ruby = {
+ defaultMode: {
+ lexems: [hljs.RUBY_IDENT_RE],
+ contains: hljs.RUBY_DEFAULT_CONTAINS,
+ keywords: hljs.RUBY_KEYWORDS
+ },
+ modes: [
+ hljs.HASH_COMMENT_MODE,
+ {
+ className: 'comment',
+ begin: '^\\=begin', end: '^\\=end',
+ relevance: 10
+ },
+ {
+ className: 'comment',
+ begin: '^__END__', end: '\\n$'
+ },
+ {
+ className: 'params',
+ begin: '\\(', end: '\\)',
+ lexems: [hljs.RUBY_IDENT_RE],
+ keywords: hljs.RUBY_KEYWORDS,
+ contains: hljs.RUBY_DEFAULT_CONTAINS
+ },
+ {
+ className: 'function',
+ begin: '\\bdef\\b', end: '$|;',
+ lexems: [hljs.RUBY_IDENT_RE],
+ keywords: hljs.RUBY_KEYWORDS,
+ contains: ['title', 'params', 'comment']
+ },
+ {
+ className: 'class',
+ begin: '\\b(class|module)\\b', end: '$',
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ keywords: hljs.RUBY_KEYWORDS,
+ contains: ['title', 'inheritance', 'comment'],
+ keywords: {'class': 1, 'module': 1}
+ },
+ {
+ className: 'title',
+ begin: '[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?', end: '^',
+ relevance: 0
+ },
+ {
+ className: 'inheritance',
+ begin: '<\\s*', end: '^',
+ contains: ['parent']
+ },
+ {
+ className: 'parent',
+ begin: '(' + hljs.IDENT_RE + '::)?' + hljs.IDENT_RE, end: '^'
+ },
+ {
+ className: 'number',
+ begin: '(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b', end: '^',
+ relevance: 0
+ },
+ {
+ className: 'number',
+ begin: '\\?\\w', end: '^'
+ },
+ {
+ className: 'string',
+ begin: '\'', end: '\'',
+ contains: ['escape', 'subst'],
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: '"', end: '"',
+ contains: ['escape', 'subst'],
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: '%[qw]?\\(', end: '\\)',
+ contains: ['escape', 'subst'],
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: '%[qw]?\\[', end: '\\]',
+ contains: ['escape', 'subst'],
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: '%[qw]?{', end: '}',
+ contains: ['escape', 'subst'],
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: '%[qw]?<', end: '>',
+ contains: ['escape', 'subst'],
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: '%[qw]?/', end: '/',
+ contains: ['escape', 'subst'],
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: '%[qw]?%', end: '%',
+ contains: ['escape', 'subst'],
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: '%[qw]?-', end: '-',
+ contains: ['escape', 'subst'],
+ relevance: 10
+ },
+ {
+ className: 'string',
+ begin: '%[qw]?\\|', end: '\\|',
+ contains: ['escape', 'subst'],
+ relevance: 10
+ },
+ {
+ className: 'symbol',
+ begin: ':' + hljs.RUBY_IDENT_RE, end: '^'
+ },
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'subst',
+ begin: '#\\{', end: '}',
+ lexems: [hljs.RUBY_IDENT_RE],
+ keywords: hljs.RUBY_KEYWORDS,
+ contains: hljs.RUBY_DEFAULT_CONTAINS
+ },
+ {
+ className: 'regexp',
+ begin: '/', end: '/[a-z]*',
+ contains: ['escape'],
+ relevance: 0
+ },
+ {
+ className: 'variable',
+ begin: '(\\$\\W)|((\\$|\\@\\@?)(\\w+))', end: '^'
+ }
+ ]
+};
diff --git a/webroot/js/languages/ini.js b/webroot/js/languages/ini.js
new file mode 100644
index 0000000..a186526
--- /dev/null
+++ b/webroot/js/languages/ini.js
@@ -0,0 +1,36 @@
+hljs.LANGUAGES.ini =
+{
+ case_insensitive: true,
+ defaultMode: {
+ contains: ['comment', 'title', 'setting'],
+ illegal: '[^\\s]'
+ },
+ modes: [
+ {
+ className: 'comment',
+ begin: ';', end: '$'
+ },
+ {
+ className: 'title',
+ begin: '\\[', end: '\\]'
+ },
+ {
+ className: 'setting',
+ begin: '^[a-z]+[ \\t]*=[ \\t]*', end: '$',
+ contains: ['value']
+ },
+ {
+ className: 'value',
+ begin: '^', endsWithParent: true,
+ contains: ['string', 'number'],
+ lexems: [hljs.IDENT_RE],
+ keywords: {'on': 1, 'off': 1, 'true': 1, 'false': 1, 'yes': 1, 'no': 1}
+ },
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'number',
+ begin: '\\d+', end: '^'
+ }
+ ]
+};
diff --git a/webroot/js/languages/javascript.js b/webroot/js/languages/javascript.js
new file mode 100644
index 0000000..93054b7
--- /dev/null
+++ b/webroot/js/languages/javascript.js
@@ -0,0 +1,38 @@
+hljs.LANGUAGES.javascript = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ contains: ['string', 'comment', 'number', 'regexp', 'function'],
+ keywords: {
+ 'keyword': {'in': 1, 'if': 1, 'for': 1, 'while': 1, 'finally': 1, 'var': 1, 'new': 1, 'function': 1, 'do': 1, 'return': 1, 'void': 1, 'else': 1, 'break': 1, 'catch': 1, 'instanceof': 1, 'with': 1, 'throw': 1, 'case': 1, 'default': 1, 'try': 1, 'this': 1, 'switch': 1, 'continue': 1, 'typeof': 1, 'delete': 1},
+ 'literal': {'true': 1, 'false': 1, 'null': 1}
+ }
+ },
+ modes: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ hljs.C_NUMBER_MODE,
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'regexp',
+ begin: '/.*?[^\\\\/]/[gim]*', end: '^'
+ },
+ {
+ className: 'function',
+ begin: 'function\\b', end: '{',
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ keywords: {'function': 1},
+ contains: ['title', 'params']
+ },
+ {
+ className: 'title',
+ begin: '[A-Za-z$_][0-9A-Za-z$_]*', end: '^'
+ },
+ {
+ className: 'params',
+ begin: '\\(', end: '\\)',
+ contains: ['string', 'comment']
+ }
+ ]
+};
diff --git a/webroot/js/languages/lisp.js b/webroot/js/languages/lisp.js
new file mode 100644
index 0000000..7930620
--- /dev/null
+++ b/webroot/js/languages/lisp.js
@@ -0,0 +1,86 @@
+/*
+
+Generic lisp definition (c) Vasily Polovnyov <vast@whiteants.net>
+
+*/
+hljs.LISP_IDENT_RE = '[a-zA-Z_\\-\\+\\*\\/\\<\\=\\>\\&\\#][a-zA-Z0-9_\\-\\+\\*\\/\\<\\=\\>\\&\\#]*'
+hljs.LISP_SIMPLE_NUMBER_RE = '(\\-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s)(\\+|\\-)?\\d+)?'
+hljs.LANGUAGES.lisp = {
+ case_insensitive: true,
+ defaultMode: {
+ lexems: [hljs.LISP_IDENT_RE],
+ contains: ['literal', 'number', 'string', 'comment', 'quoted', 'list'],
+ illegal: '[^\\s]'
+ },
+ modes: [
+ hljs.QUOTE_STRING_MODE,
+ {
+ className: 'number',
+ begin: hljs.LISP_SIMPLE_NUMBER_RE, end: '^'
+ },
+ {
+ className: 'number',
+ begin: '#b[0-1]+(/[0-1]+)?', end: '^'
+ },
+ {
+ className: 'number',
+ begin: '#o[0-7]+(/[0-7]+)?', end: '^'
+ },
+ {
+ className: 'number',
+ begin: '#x[0-9a-f]+(/[0-9a-f]+)?', end: '^'
+ },
+ {
+ className: 'number',
+ begin: '#c\\(' + hljs.LISP_SIMPLE_NUMBER_RE + ' +' + hljs.LISP_SIMPLE_NUMBER_RE, end: '\\)'
+ },
+ {
+ className: 'comment',
+ begin: ';', end: '$'
+ },
+ {
+ className: 'quoted',
+ begin: '\\\'\\(', end: '\\)',
+ contains: ['number', 'string', 'variable', 'keyword', 'quoted_list']
+ },
+ {
+ className: 'quoted',
+ begin: '\\(quote ', end: '\\)',
+ contains: ['number', 'string', 'variable', 'keyword', 'quoted_list'],
+ lexems: [hljs.LISP_IDENT_RE],
+ keywords: {'title': {'quote': 1}}
+ },
+ {
+ className: 'quoted_list',
+ begin: '\\(', end: '\\)',
+ contains: ['quoted_list', 'literal', 'number', 'string']
+ },
+ {
+ className: 'list',
+ begin: '\\(', end: '\\)',
+ contains: ['title','body']
+ },
+ {
+ className: 'title',
+ begin: hljs.LISP_IDENT_RE, end: '^',
+ endsWithParent: true
+ },
+ {
+ className: 'body',
+ begin: '^', endsWithParent: true, excludeEnd: true,
+ contains: ['quoted', 'list', 'literal', 'number', 'string', 'comment', 'variable', 'keyword']
+ },
+ {
+ className: 'keyword',
+ begin: '[:&]' + hljs.LISP_IDENT_RE, end: '^'
+ },
+ {
+ className: 'variable',
+ begin: '\\*', end: '\\*'
+ },
+ {
+ className: 'literal',
+ begin: '\\b(t{1}|nil)\\b', end: '^'
+ }
+ ]
+}
diff --git a/webroot/js/languages/mel.js b/webroot/js/languages/mel.js
new file mode 100644
index 0000000..54335f1
--- /dev/null
+++ b/webroot/js/languages/mel.js
@@ -0,0 +1,50 @@
+/*
+
+Maya Embedded Language (c) Shuen-Huei Guan <drake.guan@gmail.com>
+
+*/
+hljs.LANGUAGES.mel = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ illegal: '</',
+ contains: ['number', 'string', 'variable', 'comment'],
+ keywords: {'int': 1, 'float': 1, 'string': 1, 'float': 1, 'vector': 1, 'matrix': 1,
+ 'if': 1, 'else': 1, 'switch': 1, 'case': 1, 'default': 1, 'while': 1, 'do': 1, 'for': 1, 'in': 1, 'break': 1, 'continue': 1,
+ 'exists': 1, 'objExists': 1, 'attributeExists': 1,
+ 'global': 1, 'proc': 1, 'return': 1,
+ 'error': 1, 'warning': 1, 'trace': 1, 'catch': 1,
+ 'about': 1, 'abs': 1, 'addAttr': 1, 'addAttributeEditorNodeHelp': 1, 'addDynamic': 1, 'addNewShelfTab': 1, 'addPP': 1, 'addPanelCategory': 1, 'addPrefixToName': 1, 'advanceToNextDrivenKey': 1, 'affectedNet': 1, 'affects': 1, 'aimConstraint': 1, 'air': 1, 'alias': 1, 'aliasAttr': 1, 'align': 1, 'alignCtx': 1, 'alignCurve': 1, 'alignSurface': 1, 'allViewFit': 1, 'ambientLight': 1, 'angle': 1, 'angleBetween': 1, 'animCone': 1, 'animCurveEditor': 1, 'animDisplay': 1, 'animView': 1, 'annotate': 1, 'appendStringArray': 1, 'applicationName': 1, 'applyAttrPreset': 1, 'applyTake': 1, 'arcLenDimContext': 1, 'arcLengthDimension': 1, 'arclen': 1, 'arrayMapper': 1, 'art3dPaintCtx': 1, 'artAttrCtx': 1, 'artAttrPaintVertexCtx': 1, 'artAttrSkinPaintCtx': 1, 'artAttrTool': 1, 'artBuildPaintMenu': 1, 'artFluidAttrCtx': 1, 'artPuttyCtx': 1, 'artSelectCtx': 1, 'artSetPaintCtx': 1, 'artUserPaintCtx': 1, 'assignCommand': 1, 'assignInputDevice': 1, 'assignViewportFactories': 1, 'attachCurve': 1, 'attachDeviceAttr': 1, 'attachSurface': 1, 'attrColorSliderGrp': 1, 'attrCompatibility': 1, 'attrControlGrp': 1, 'attrEnumOptionMenu': 1, 'attrEnumOptionMenuGrp': 1, 'attrFieldGrp': 1, 'attrFieldSliderGrp': 1, 'attrNavigationControlGrp': 1, 'attrPresetEditWin': 1, 'attributeExists': 1, 'attributeInfo': 1, 'attributeMenu': 1, 'attributeQuery': 1, 'autoKeyframe': 1, 'autoPlace': 1, 'bakeClip': 1, 'bakeFluidShading': 1, 'bakePartialHistory': 1, 'bakeResults': 1, 'bakeSimulation': 1, 'basename': 1, 'basenameEx': 1, 'batchRender': 1, 'bessel': 1, 'bevel': 1, 'bevelPlus': 1, 'binMembership': 1, 'bindSkin': 1, 'blend2': 1, 'blendShape': 1, 'blendShapeEditor': 1, 'blendShapePanel': 1, 'blendTwoAttr': 1, 'blindDataType': 1, 'boneLattice': 1, 'boundary': 1, 'boxDollyCtx': 1, 'boxZoomCtx': 1, 'bufferCurve': 1, 'buildBookmarkMenu': 1, 'buildKeyframeMenu': 1, 'button': 1, 'buttonManip': 1, 'CBG': 1, 'cacheFile': 1, 'cacheFileCombine': 1, 'cacheFileMerge': 1, 'cacheFileTrack': 1, 'camera': 1, 'cameraView': 1, 'canCreateManip': 1, 'canvas': 1, 'capitalizeString': 1, 'catch': 1, 'catchQuiet': 1, 'ceil': 1, 'changeSubdivComponentDisplayLevel': 1, 'changeSubdivRegion': 1, 'channelBox': 1, 'character': 1, 'characterMap': 1, 'characterOutlineEditor': 1, 'characterize': 1, 'chdir': 1, 'checkBox': 1, 'checkBoxGrp': 1, 'checkDefaultRenderGlobals': 1, 'choice': 1, 'circle': 1, 'circularFillet': 1, 'clamp': 1, 'clear': 1, 'clearCache': 1, 'clip': 1, 'clipEditor': 1, 'clipEditorCurrentTimeCtx': 1, 'clipSchedule': 1, 'clipSchedulerOutliner': 1, 'clipTrimBefore': 1, 'closeCurve': 1, 'closeSurface': 1, 'cluster': 1, 'cmdFileOutput': 1, 'cmdScrollFieldExecuter': 1, 'cmdScrollFieldReporter': 1, 'cmdShell': 1, 'coarsenSubdivSelectionList': 1, 'collision': 1, 'color': 1, 'colorAtPoint': 1, 'colorEditor': 1, 'colorIndex': 1, 'colorIndexSliderGrp': 1, 'colorSliderButtonGrp': 1, 'colorSliderGrp': 1, 'columnLayout': 1, 'commandEcho': 1, 'commandLine': 1, 'commandPort': 1, 'compactHairSystem': 1, 'componentEditor': 1, 'compositingInterop': 1, 'computePolysetVolume': 1, 'condition': 1, 'cone': 1, 'confirmDialog': 1, 'connectAttr': 1, 'connectControl': 1, 'connectDynamic': 1, 'connectJoint': 1, 'connectionInfo': 1, 'constrain': 1, 'constrainValue': 1, 'constructionHistory': 1, 'container': 1, 'containsMultibyte': 1, 'contextInfo': 1, 'control': 1, 'convertFromOldLayers': 1, 'convertIffToPsd': 1, 'convertLightmap': 1, 'convertSolidTx': 1, 'convertTessellation': 1, 'convertUnit': 1, 'copyArray': 1, 'copyFlexor': 1, 'copyKey': 1, 'copySkinWeights': 1, 'cos': 1, 'cpButton': 1, 'cpCache': 1, 'cpClothSet': 1, 'cpCollision': 1, 'cpConstraint': 1, 'cpConvClothToMesh': 1, 'cpForces': 1, 'cpGetSolverAttr': 1, 'cpPanel': 1, 'cpProperty': 1, 'cpRigidCollisionFilter': 1, 'cpSeam': 1, 'cpSetEdit': 1, 'cpSetSolverAttr': 1, 'cpSolver': 1, 'cpSolverTypes': 1, 'cpTool': 1, 'cpUpdateClothUVs': 1, 'createDisplayLayer': 1, 'createDrawCtx': 1, 'createEditor': 1, 'createLayeredPsdFile': 1, 'createMotionField': 1, 'createNewShelf': 1, 'createNode': 1, 'createRenderLayer': 1, 'createSubdivRegion': 1, 'cross': 1, 'crossProduct': 1, 'ctxAbort': 1, 'ctxCompletion': 1, 'ctxEditMode': 1, 'ctxTraverse': 1, 'currentCtx': 1, 'currentTime': 1, 'currentTimeCtx': 1, 'currentUnit': 1, 'currentUnit': 1, 'curve': 1, 'curveAddPtCtx': 1, 'curveCVCtx': 1, 'curveEPCtx': 1, 'curveEditorCtx': 1, 'curveIntersect': 1, 'curveMoveEPCtx': 1, 'curveOnSurface': 1, 'curveSketchCtx': 1, 'cutKey': 1, 'cycleCheck': 1, 'cylinder': 1, 'dagPose': 1, 'date': 1, 'defaultLightListCheckBox': 1, 'defaultNavigation': 1, 'defineDataServer': 1, 'defineVirtualDevice': 1, 'deformer': 1, 'deg_to_rad': 1, 'delete': 1, 'deleteAttr': 1, 'deleteShadingGroupsAndMaterials': 1, 'deleteShelfTab': 1, 'deleteUI': 1, 'deleteUnusedBrushes': 1, 'delrandstr': 1, 'detachCurve': 1, 'detachDeviceAttr': 1, 'detachSurface': 1, 'deviceEditor': 1, 'devicePanel': 1, 'dgInfo': 1, 'dgdirty': 1, 'dgeval': 1, 'dgtimer': 1, 'dimWhen': 1, 'directKeyCtx': 1, 'directionalLight': 1, 'dirmap': 1, 'dirname': 1, 'disable': 1, 'disconnectAttr': 1, 'disconnectJoint': 1, 'diskCache': 1, 'displacementToPoly': 1, 'displayAffected': 1, 'displayColor': 1, 'displayCull': 1, 'displayLevelOfDetail': 1, 'displayPref': 1, 'displayRGBColor': 1, 'displaySmoothness': 1, 'displayStats': 1, 'displayString': 1, 'displaySurface': 1, 'distanceDimContext': 1, 'distanceDimension': 1, 'doBlur': 1, 'dolly': 1, 'dollyCtx': 1, 'dopeSheetEditor': 1, 'dot': 1, 'dotProduct': 1, 'doubleProfileBirailSurface': 1, 'drag': 1, 'dragAttrContext': 1, 'draggerContext': 1, 'dropoffLocator': 1, 'duplicate': 1, 'duplicateCurve': 1, 'duplicateSurface': 1, 'dynCache': 1, 'dynControl': 1, 'dynExport': 1, 'dynExpression': 1, 'dynGlobals': 1, 'dynPaintEditor': 1, 'dynParticleCtx': 1, 'dynPref': 1, 'dynRelEdPanel': 1, 'dynRelEditor': 1, 'dynamicLoad': 1, 'editAttrLimits': 1, 'editDisplayLayerGlobals': 1, 'editDisplayLayerMembers': 1, 'editRenderLayerAdjustment': 1, 'editRenderLayerGlobals': 1, 'editRenderLayerMembers': 1, 'editor': 1, 'editorTemplate': 1, 'effector': 1, 'emit': 1, 'emitter': 1, 'enableDevice': 1, 'encodeString': 1, 'endString': 1, 'endsWith': 1, 'env': 1, 'equivalent': 1, 'equivalentTol': 1, 'erf': 1, 'error': 1, 'eval': 1, 'eval': 1, 'evalDeferred': 1, 'evalEcho': 1, 'event': 1, 'exactWorldBoundingBox': 1, 'exclusiveLightCheckBox': 1, 'exec': 1, 'executeForEachObject': 1, 'exists': 1, 'exp': 1, 'expression': 1, 'expressionEditorListen': 1, 'extendCurve': 1, 'extendSurface': 1, 'extrude': 1, 'fcheck': 1, 'fclose': 1, 'feof': 1, 'fflush': 1, 'fgetline': 1, 'fgetword': 1, 'file': 1, 'fileBrowserDialog': 1, 'fileDialog': 1, 'fileExtension': 1, 'fileInfo': 1, 'filetest': 1, 'filletCurve': 1, 'filter': 1, 'filterCurve': 1, 'filterExpand': 1, 'filterStudioImport': 1, 'findAllIntersections': 1, 'findAnimCurves': 1, 'findKeyframe': 1, 'findMenuItem': 1, 'findRelatedSkinCluster': 1, 'finder': 1, 'firstParentOf': 1, 'fitBspline': 1, 'flexor': 1, 'floatEq': 1, 'floatField': 1, 'floatFieldGrp': 1, 'floatScrollBar': 1, 'floatSlider': 1, 'floatSlider2': 1, 'floatSliderButtonGrp': 1, 'floatSliderGrp': 1, 'floor': 1, 'flow': 1, 'fluidCacheInfo': 1, 'fluidEmitter': 1, 'fluidVoxelInfo': 1, 'flushUndo': 1, 'fmod': 1, 'fontDialog': 1, 'fopen': 1, 'formLayout': 1, 'format': 1, 'fprint': 1, 'frameLayout': 1, 'fread': 1, 'freeFormFillet': 1, 'frewind': 1, 'fromNativePath': 1, 'fwrite': 1, 'gamma': 1, 'gauss': 1, 'geometryConstraint': 1, 'getApplicationVersionAsFloat': 1, 'getAttr': 1, 'getClassification': 1, 'getDefaultBrush': 1, 'getFileList': 1, 'getFluidAttr': 1, 'getInputDeviceRange': 1, 'getMayaPanelTypes': 1, 'getModifiers': 1, 'getPanel': 1, 'getParticleAttr': 1, 'getPluginResource': 1, 'getenv': 1, 'getpid': 1, 'glRender': 1, 'glRenderEditor': 1, 'globalStitch': 1, 'gmatch': 1, 'goal': 1, 'gotoBindPose': 1, 'grabColor': 1, 'gradientControl': 1, 'gradientControlNoAttr': 1, 'graphDollyCtx': 1, 'graphSelectContext': 1, 'graphTrackCtx': 1, 'gravity': 1, 'grid': 1, 'gridLayout': 1, 'group': 1, 'groupObjectsByName': 1, 'HfAddAttractorToAS': 1, 'HfAssignAS': 1, 'HfBuildEqualMap': 1, 'HfBuildFurFiles': 1, 'HfBuildFurImages': 1, 'HfCancelAFR': 1, 'HfConnectASToHF': 1, 'HfCreateAttractor': 1, 'HfDeleteAS': 1, 'HfEditAS': 1, 'HfPerformCreateAS': 1, 'HfRemoveAttractorFromAS': 1, 'HfSelectAttached': 1, 'HfSelectAttractors': 1, 'HfUnAssignAS': 1, 'hardenPointCurve': 1, 'hardware': 1, 'hardwareRenderPanel': 1, 'headsUpDisplay': 1, 'headsUpMessage': 1, 'help': 1, 'helpLine': 1, 'hermite': 1, 'hide': 1, 'hilite': 1, 'hitTest': 1, 'hotBox': 1, 'hotkey': 1, 'hotkeyCheck': 1, 'hsv_to_rgb': 1, 'hudButton': 1, 'hudSlider': 1, 'hudSliderButton': 1, 'hwReflectionMap': 1, 'hwRender': 1, 'hwRenderLoad': 1, 'hyperGraph': 1, 'hyperPanel': 1, 'hyperShade': 1, 'hypot': 1, 'iconTextButton': 1, 'iconTextCheckBox': 1, 'iconTextRadioButton': 1, 'iconTextRadioCollection': 1, 'iconTextScrollList': 1, 'iconTextStaticLabel': 1, 'ikHandle': 1, 'ikHandleCtx': 1, 'ikHandleDisplayScale': 1, 'ikSolver': 1, 'ikSplineHandleCtx': 1, 'ikSystem': 1, 'ikSystemInfo': 1, 'ikfkDisplayMethod': 1, 'illustratorCurves': 1, 'image': 1, 'imfPlugins': 1, 'inheritTransform': 1, 'insertJoint': 1, 'insertJointCtx': 1, 'insertKeyCtx': 1, 'insertKnotCurve': 1, 'insertKnotSurface': 1, 'instance': 1, 'instanceable': 1, 'instancer': 1, 'intField': 1, 'intFieldGrp': 1, 'intScrollBar': 1, 'intSlider': 1, 'intSliderGrp': 1, 'interToUI': 1, 'internalVar': 1, 'intersect': 1, 'iprEngine': 1, 'isAnimCurve': 1, 'isConnected': 1, 'isDirty': 1, 'isParentOf': 1, 'isSameObject': 1, 'isTrue': 1, 'isValidObjectName': 1, 'isValidString': 1, 'isValidUiName': 1, 'isolateSelect': 1, 'itemFilter': 1, 'itemFilterAttr': 1, 'itemFilterRender': 1, 'itemFilterType': 1, 'joint': 1, 'jointCluster': 1, 'jointCtx': 1, 'jointDisplayScale': 1, 'jointLattice': 1, 'keyTangent': 1, 'keyframe': 1, 'keyframeOutliner': 1, 'keyframeRegionCurrentTimeCtx': 1, 'keyframeRegionDirectKeyCtx': 1, 'keyframeRegionDollyCtx': 1, 'keyframeRegionInsertKeyCtx': 1, 'keyframeRegionMoveKeyCtx': 1, 'keyframeRegionScaleKeyCtx': 1, 'keyframeRegionSelectKeyCtx': 1, 'keyframeRegionSetKeyCtx': 1, 'keyframeRegionTrackCtx': 1, 'keyframeStats': 1, 'lassoContext': 1, 'lattice': 1, 'latticeDeformKeyCtx': 1, 'launch': 1, 'launchImageEditor': 1, 'layerButton': 1, 'layeredShaderPort': 1, 'layeredTexturePort': 1, 'layout': 1, 'layoutDialog': 1, 'lightList': 1, 'lightListEditor': 1, 'lightListPanel': 1, 'lightlink': 1, 'lineIntersection': 1, 'linearPrecision': 1, 'linstep': 1, 'listAnimatable': 1, 'listAttr': 1, 'listCameras': 1, 'listConnections': 1, 'listDeviceAttachments': 1, 'listHistory': 1, 'listInputDeviceAxes': 1, 'listInputDeviceButtons': 1, 'listInputDevices': 1, 'listMenuAnnotation': 1, 'listNodeTypes': 1, 'listPanelCategories': 1, 'listRelatives': 1, 'listSets': 1, 'listTransforms': 1, 'listUnselected': 1, 'listerEditor': 1, 'loadFluid': 1, 'loadNewShelf': 1, 'loadPlugin': 1, 'loadPluginLanguageResources': 1, 'loadPrefObjects': 1, 'localizedPanelLabel': 1, 'lockNode': 1, 'loft': 1, 'log': 1, 'longNameOf': 1, 'lookThru': 1, 'ls': 1, 'lsThroughFilter': 1, 'lsType': 1, 'lsUI': 1, 'Mayatomr': 1, 'mag': 1, 'makeIdentity': 1, 'makeLive': 1, 'makePaintable': 1, 'makeRoll': 1, 'makeSingleSurface': 1, 'makeTubeOn': 1, 'makebot': 1, 'manipMoveContext': 1, 'manipMoveLimitsCtx': 1, 'manipOptions': 1, 'manipRotateContext': 1, 'manipRotateLimitsCtx': 1, 'manipScaleContext': 1, 'manipScaleLimitsCtx': 1, 'marker': 1, 'match': 1, 'max': 1, 'memory': 1, 'menu': 1, 'menuBarLayout': 1, 'menuEditor': 1, 'menuItem': 1, 'menuItemToShelf': 1, 'menuSet': 1, 'menuSetPref': 1, 'messageLine': 1, 'min': 1, 'minimizeApp': 1, 'mirrorJoint': 1, 'modelCurrentTimeCtx': 1, 'modelEditor': 1, 'modelPanel': 1, 'mouse': 1, 'movIn': 1, 'movOut': 1, 'move': 1, 'moveIKtoFK': 1, 'moveKeyCtx': 1, 'moveVertexAlongDirection': 1, 'multiProfileBirailSurface': 1, 'mute': 1, 'nParticle': 1, 'nameCommand': 1, 'nameField': 1, 'namespace': 1, 'namespaceInfo': 1, 'newPanelItems': 1, 'newton': 1, 'nodeCast': 1, 'nodeIconButton': 1, 'nodeOutliner': 1, 'nodePreset': 1, 'nodeType': 1, 'noise': 1, 'nonLinear': 1, 'normalConstraint': 1, 'normalize': 1, 'nurbsBoolean': 1, 'nurbsCopyUVSet': 1, 'nurbsCube': 1, 'nurbsEditUV': 1, 'nurbsPlane': 1, 'nurbsSelect': 1, 'nurbsSquare': 1, 'nurbsToPoly': 1, 'nurbsToPolygonsPref': 1, 'nurbsToSubdiv': 1, 'nurbsToSubdivPref': 1, 'nurbsUVSet': 1, 'nurbsViewDirectionVector': 1, 'objExists': 1, 'objectCenter': 1, 'objectLayer': 1, 'objectType': 1, 'objectTypeUI': 1, 'obsoleteProc': 1, 'oceanNurbsPreviewPlane': 1, 'offsetCurve': 1, 'offsetCurveOnSurface': 1, 'offsetSurface': 1, 'openGLExtension': 1, 'openMayaPref': 1, 'optionMenu': 1, 'optionMenuGrp': 1, 'optionVar': 1, 'orbit': 1, 'orbitCtx': 1, 'orientConstraint': 1, 'outlinerEditor': 1, 'outlinerPanel': 1, 'overrideModifier': 1, 'paintEffectsDisplay': 1, 'pairBlend': 1, 'palettePort': 1, 'paneLayout': 1, 'panel': 1, 'panelConfiguration': 1, 'panelHistory': 1, 'paramDimContext': 1, 'paramDimension': 1, 'paramLocator': 1, 'parent': 1, 'parentConstraint': 1, 'particle': 1, 'particleExists': 1, 'particleInstancer': 1, 'particleRenderInfo': 1, 'partition': 1, 'pasteKey': 1, 'pathAnimation': 1, 'pause': 1, 'pclose': 1, 'percent': 1, 'performanceOptions': 1, 'pfxstrokes': 1, 'pickWalk': 1, 'picture': 1, 'pixelMove': 1, 'planarSrf': 1, 'plane': 1, 'play': 1, 'playbackOptions': 1, 'playblast': 1, 'plugAttr': 1, 'plugNode': 1, 'pluginInfo': 1, 'pluginResourceUtil': 1, 'pointConstraint': 1, 'pointCurveConstraint': 1, 'pointLight': 1, 'pointMatrixMult': 1, 'pointOnCurve': 1, 'pointOnSurface': 1, 'pointPosition': 1, 'poleVectorConstraint': 1, 'polyAppend': 1, 'polyAppendFacetCtx': 1, 'polyAppendVertex': 1, 'polyAutoProjection': 1, 'polyAverageNormal': 1, 'polyAverageVertex': 1, 'polyBevel': 1, 'polyBlendColor': 1, 'polyBlindData': 1, 'polyBoolOp': 1, 'polyBridgeEdge': 1, 'polyCacheMonitor': 1, 'polyCheck': 1, 'polyChipOff': 1, 'polyClipboard': 1, 'polyCloseBorder': 1, 'polyCollapseEdge': 1, 'polyCollapseFacet': 1, 'polyColorBlindData': 1, 'polyColorDel': 1, 'polyColorPerVertex': 1, 'polyColorSet': 1, 'polyCompare': 1, 'polyCone': 1, 'polyCopyUV': 1, 'polyCrease': 1, 'polyCreaseCtx': 1, 'polyCreateFacet': 1, 'polyCreateFacetCtx': 1, 'polyCube': 1, 'polyCut': 1, 'polyCutCtx': 1, 'polyCylinder': 1, 'polyCylindricalProjection': 1, 'polyDelEdge': 1, 'polyDelFacet': 1, 'polyDelVertex': 1, 'polyDuplicateAndConnect': 1, 'polyDuplicateEdge': 1, 'polyEditUV': 1, 'polyEditUVShell': 1, 'polyEvaluate': 1, 'polyExtrudeEdge': 1, 'polyExtrudeFacet': 1, 'polyExtrudeVertex': 1, 'polyFlipEdge': 1, 'polyFlipUV': 1, 'polyForceUV': 1, 'polyGeoSampler': 1, 'polyHelix': 1, 'polyInfo': 1, 'polyInstallAction': 1, 'polyLayoutUV': 1, 'polyListComponentConversion': 1, 'polyMapCut': 1, 'polyMapDel': 1, 'polyMapSew': 1, 'polyMapSewMove': 1, 'polyMergeEdge': 1, 'polyMergeEdgeCtx': 1, 'polyMergeFacet': 1, 'polyMergeFacetCtx': 1, 'polyMergeUV': 1, 'polyMergeVertex': 1, 'polyMirrorFace': 1, 'polyMoveEdge': 1, 'polyMoveFacet': 1, 'polyMoveFacetUV': 1, 'polyMoveUV': 1, 'polyMoveVertex': 1, 'polyNormal': 1, 'polyNormalPerVertex': 1, 'polyNormalizeUV': 1, 'polyOptUvs': 1, 'polyOptions': 1, 'polyOutput': 1, 'polyPipe': 1, 'polyPlanarProjection': 1, 'polyPlane': 1, 'polyPlatonicSolid': 1, 'polyPoke': 1, 'polyPrimitive': 1, 'polyPrism': 1, 'polyProjection': 1, 'polyPyramid': 1, 'polyQuad': 1, 'polyQueryBlindData': 1, 'polyReduce': 1, 'polySelect': 1, 'polySelectConstraint': 1, 'polySelectConstraintMonitor': 1, 'polySelectCtx': 1, 'polySelectEditCtx': 1, 'polySeparate': 1, 'polySetToFaceNormal': 1, 'polySewEdge': 1, 'polyShortestPathCtx': 1, 'polySmooth': 1, 'polySoftEdge': 1, 'polySphere': 1, 'polySphericalProjection': 1, 'polySplit': 1, 'polySplitCtx': 1, 'polySplitEdge': 1, 'polySplitRing': 1, 'polySplitVertex': 1, 'polyStraightenUVBorder': 1, 'polySubdivideEdge': 1, 'polySubdivideFacet': 1, 'polyToSubdiv': 1, 'polyTorus': 1, 'polyTransfer': 1, 'polyTriangulate': 1, 'polyUVSet': 1, 'polyUnite': 1, 'polyWedgeFace': 1, 'popen': 1, 'popupMenu': 1, 'pose': 1, 'pow': 1, 'preloadRefEd': 1, 'print': 1, 'progressBar': 1, 'progressWindow': 1, 'projFileViewer': 1, 'projectCurve': 1, 'projectTangent': 1, 'projectionContext': 1, 'projectionManip': 1, 'promptDialog': 1, 'propModCtx': 1, 'propMove': 1, 'psdChannelOutliner': 1, 'psdEditTextureFile': 1, 'psdExport': 1, 'psdTextureFile': 1, 'putenv': 1, 'pwd': 1, 'python': 1, 'querySubdiv': 1, 'quit': 1, 'rad_to_deg': 1, 'radial': 1, 'radioButton': 1, 'radioButtonGrp': 1, 'radioCollection': 1, 'radioMenuItemCollection': 1, 'rampColorPort': 1, 'rand': 1, 'randomizeFollicles': 1, 'randstate': 1, 'rangeControl': 1, 'readTake': 1, 'rebuildCurve': 1, 'rebuildSurface': 1, 'recordAttr': 1, 'recordDevice': 1, 'redo': 1, 'reference': 1, 'referenceEdit': 1, 'referenceQuery': 1, 'refineSubdivSelectionList': 1, 'refresh': 1, 'refreshAE': 1, 'registerPluginResource': 1, 'rehash': 1, 'reloadImage': 1, 'removeJoint': 1, 'removeMultiInstance': 1, 'removePanelCategory': 1, 'rename': 1, 'renameAttr': 1, 'renameSelectionList': 1, 'renameUI': 1, 'render': 1, 'renderGlobalsNode': 1, 'renderInfo': 1, 'renderLayerButton': 1, 'renderLayerParent': 1, 'renderLayerPostProcess': 1, 'renderLayerUnparent': 1, 'renderManip': 1, 'renderPartition': 1, 'renderQualityNode': 1, 'renderSettings': 1, 'renderThumbnailUpdate': 1, 'renderWindowEditor': 1, 'renderWindowSelectContext': 1, 'renderer': 1, 'reorder': 1, 'reorderDeformers': 1, 'requires': 1, 'reroot': 1, 'resampleFluid': 1, 'resetAE': 1, 'resetPfxToPolyCamera': 1, 'resetTool': 1, 'resolutionNode': 1, 'retarget': 1, 'reverseCurve': 1, 'reverseSurface': 1, 'revolve': 1, 'rgb_to_hsv': 1, 'rigidBody': 1, 'rigidSolver': 1, 'roll': 1, 'rollCtx': 1, 'rootOf': 1, 'rot': 1, 'rotate': 1, 'rotationInterpolation': 1, 'roundConstantRadius': 1, 'rowColumnLayout': 1, 'rowLayout': 1, 'runTimeCommand': 1, 'runup': 1, 'sampleImage': 1, 'saveAllShelves': 1, 'saveAttrPreset': 1, 'saveFluid': 1, 'saveImage': 1, 'saveInitialState': 1, 'saveMenu': 1, 'savePrefObjects': 1, 'savePrefs': 1, 'saveShelf': 1, 'saveToolSettings': 1, 'scale': 1, 'scaleBrushBrightness': 1, 'scaleComponents': 1, 'scaleConstraint': 1, 'scaleKey': 1, 'scaleKeyCtx': 1, 'sceneEditor': 1, 'sceneUIReplacement': 1, 'scmh': 1, 'scriptCtx': 1, 'scriptEditorInfo': 1, 'scriptJob': 1, 'scriptNode': 1, 'scriptTable': 1, 'scriptToShelf': 1, 'scriptedPanel': 1, 'scriptedPanelType': 1, 'scrollField': 1, 'scrollLayout': 1, 'sculpt': 1, 'searchPathArray': 1, 'seed': 1, 'selLoadSettings': 1, 'select': 1, 'selectContext': 1, 'selectCurveCV': 1, 'selectKey': 1, 'selectKeyCtx': 1, 'selectKeyframeRegionCtx': 1, 'selectMode': 1, 'selectPref': 1, 'selectPriority': 1, 'selectType': 1, 'selectedNodes': 1, 'selectionConnection': 1, 'separator': 1, 'setAttr': 1, 'setAttrEnumResource': 1, 'setAttrMapping': 1, 'setAttrNiceNameResource': 1, 'setConstraintRestPosition': 1, 'setDefaultShadingGroup': 1, 'setDrivenKeyframe': 1, 'setDynamic': 1, 'setEditCtx': 1, 'setEditor': 1, 'setFluidAttr': 1, 'setFocus': 1, 'setInfinity': 1, 'setInputDeviceMapping': 1, 'setKeyCtx': 1, 'setKeyPath': 1, 'setKeyframe': 1, 'setKeyframeBlendshapeTargetWts': 1, 'setMenuMode': 1, 'setNodeNiceNameResource': 1, 'setNodeTypeFlag': 1, 'setParent': 1, 'setParticleAttr': 1, 'setPfxToPolyCamera': 1, 'setPluginResource': 1, 'setProject': 1, 'setStampDensity': 1, 'setStartupMessage': 1, 'setState': 1, 'setToolTo': 1, 'setUITemplate': 1, 'setXformManip': 1, 'sets': 1, 'shadingConnection': 1, 'shadingGeometryRelCtx': 1, 'shadingLightRelCtx': 1, 'shadingNetworkCompare': 1, 'shadingNode': 1, 'shapeCompare': 1, 'shelfButton': 1, 'shelfLayout': 1, 'shelfTabLayout': 1, 'shellField': 1, 'shortNameOf': 1, 'showHelp': 1, 'showHidden': 1, 'showManipCtx': 1, 'showSelectionInTitle': 1, 'showShadingGroupAttrEditor': 1, 'showWindow': 1, 'sign': 1, 'simplify': 1, 'sin': 1, 'singleProfileBirailSurface': 1, 'size': 1, 'sizeBytes': 1, 'skinCluster': 1, 'skinPercent': 1, 'smoothCurve': 1, 'smoothTangentSurface': 1, 'smoothstep': 1, 'snap2to2': 1, 'snapKey': 1, 'snapMode': 1, 'snapTogetherCtx': 1, 'snapshot': 1, 'soft': 1, 'softMod': 1, 'softModCtx': 1, 'sort': 1, 'sound': 1, 'soundControl': 1, 'source': 1, 'spaceLocator': 1, 'sphere': 1, 'sphrand': 1, 'spotLight': 1, 'spotLightPreviewPort': 1, 'spreadSheetEditor': 1, 'spring': 1, 'sqrt': 1, 'squareSurface': 1, 'srtContext': 1, 'stackTrace': 1, 'startString': 1, 'startsWith': 1, 'stitchAndExplodeShell': 1, 'stitchSurface': 1, 'stitchSurfacePoints': 1, 'strcmp': 1, 'stringArrayCatenate': 1, 'stringArrayContains': 1, 'stringArrayCount': 1, 'stringArrayInsertAtIndex': 1, 'stringArrayIntersector': 1, 'stringArrayRemove': 1, 'stringArrayRemoveAtIndex': 1, 'stringArrayRemoveDuplicates': 1, 'stringArrayRemoveExact': 1, 'stringArrayToString': 1, 'stringToStringArray': 1, 'strip': 1, 'stripPrefixFromName': 1, 'stroke': 1, 'subdAutoProjection': 1, 'subdCleanTopology': 1, 'subdCollapse': 1, 'subdDuplicateAndConnect': 1, 'subdEditUV': 1, 'subdListComponentConversion': 1, 'subdMapCut': 1, 'subdMapSewMove': 1, 'subdMatchTopology': 1, 'subdMirror': 1, 'subdToBlind': 1, 'subdToPoly': 1, 'subdTransferUVsToCache': 1, 'subdiv': 1, 'subdivCrease': 1, 'subdivDisplaySmoothness': 1, 'substitute': 1, 'substituteAllString': 1, 'substituteGeometry': 1, 'substring': 1, 'surface': 1, 'surfaceSampler': 1, 'surfaceShaderList': 1, 'swatchDisplayPort': 1, 'switchTable': 1, 'symbolButton': 1, 'symbolCheckBox': 1, 'sysFile': 1, 'system': 1, 'tabLayout': 1, 'tan': 1, 'tangentConstraint': 1, 'texLatticeDeformContext': 1, 'texManipContext': 1, 'texMoveContext': 1, 'texMoveUVShellContext': 1, 'texRotateContext': 1, 'texScaleContext': 1, 'texSelectContext': 1, 'texSelectShortestPathCtx': 1, 'texSmudgeUVContext': 1, 'texWinToolCtx': 1, 'text': 1, 'textCurves': 1, 'textField': 1, 'textFieldButtonGrp': 1, 'textFieldGrp': 1, 'textManip': 1, 'textScrollList': 1, 'textToShelf': 1, 'textureDisplacePlane': 1, 'textureHairColor': 1, 'texturePlacementContext': 1, 'textureWindow': 1, 'threadCount': 1, 'threePointArcCtx': 1, 'timeControl': 1, 'timePort': 1, 'timerX': 1, 'toNativePath': 1, 'toggle': 1, 'toggleAxis': 1, 'toggleWindowVisibility': 1, 'tokenize': 1, 'tokenizeList': 1, 'tolerance': 1, 'tolower': 1, 'toolButton': 1, 'toolCollection': 1, 'toolDropped': 1, 'toolHasOptions': 1, 'toolPropertyWindow': 1, 'torus': 1, 'toupper': 1, 'trace': 1, 'track': 1, 'trackCtx': 1, 'transferAttributes': 1, 'transformCompare': 1, 'transformLimits': 1, 'translator': 1, 'trim': 1, 'trunc': 1, 'truncateFluidCache': 1, 'truncateHairCache': 1, 'tumble': 1, 'tumbleCtx': 1, 'turbulence': 1, 'twoPointArcCtx': 1, 'uiRes': 1, 'uiTemplate': 1, 'unassignInputDevice': 1, 'undo': 1, 'undoInfo': 1, 'ungroup': 1, 'uniform': 1, 'unit': 1, 'unloadPlugin': 1, 'untangleUV': 1, 'untitledFileName': 1, 'untrim': 1, 'upAxis': 1, 'updateAE': 1, 'userCtx': 1, 'uvLink': 1, 'uvSnapshot': 1, 'validateShelfName': 1, 'vectorize': 1, 'view2dToolCtx': 1, 'viewCamera': 1, 'viewClipPlane': 1, 'viewFit': 1, 'viewHeadOn': 1, 'viewLookAt': 1, 'viewManip': 1, 'viewPlace': 1, 'viewSet': 1, 'visor': 1, 'volumeAxis': 1, 'vortex': 1, 'waitCursor': 1, 'warning': 1, 'webBrowser': 1, 'webBrowserPrefs': 1, 'whatIs': 1, 'window': 1, 'windowPref': 1, 'wire': 1, 'wireContext': 1, 'workspace': 1, 'wrinkle': 1, 'wrinkleContext': 1, 'writeTake': 1, 'xbmLangPathList': 1, 'xform': 1
+ }
+ },
+ modes: [
+ // number
+ hljs.C_NUMBER_MODE,
+ // string
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'string',
+ begin: '`', end: '`',
+ contains: ['escape']
+ },
+ // variable
+ {
+ className: 'variable',
+ begin: '\\$\\d', end: '^',
+ relevance: 5
+ },
+ {
+ className: 'variable',
+ begin: '[\\$\\%\\@\\*](\\^\\w\\b|#\\w+|[^\\s\\w{]|{\\w+}|\\w+)', end: '^'
+ },
+ // array, $a[3] = {"a","b","c"}, $b[3] = {1,2,3}
+ // vector, $test = <<3.0, 7.7, 9.1>>
+ // matrix, matrix $a3[3][4] = <<2.5, 4.5, 3.25, 8.05; ... >>
+ // param, -name ... -radius ...
+ // operator, () [] ! ++ -- * / % ^ + - < <= > >= == != && || ? : = += -= *= /=
+ // comment
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE
+ ]
+}
diff --git a/webroot/js/languages/profile.js b/webroot/js/languages/profile.js
new file mode 100644
index 0000000..e919f7a
--- /dev/null
+++ b/webroot/js/languages/profile.js
@@ -0,0 +1,50 @@
+/*
+
+Python profiler results (c) Brian Beck <exogen@gmail.com>
+
+*/
+hljs.LANGUAGES.profile = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ contains: ['number', 'builtin', 'filename', 'header', 'summary', 'string', 'function']
+ },
+ modes: [
+ hljs.C_NUMBER_MODE,
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ {
+ className: 'summary',
+ begin: 'function calls', end: '$',
+ contains: ['number'],
+ relevance: 10
+ },
+ {
+ className: 'header',
+ begin: '(ncalls|tottime|cumtime)', end: '$',
+ lexems: [hljs.IDENT_RE],
+ keywords: {'ncalls': 1, 'tottime': 10, 'cumtime': 10, 'filename': 1},
+ relevance: 10
+ },
+ {
+ className: 'function',
+ begin: '\\(', end: '\\)',
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ contains: ['title']
+ },
+ {
+ className: 'title',
+ begin: hljs.UNDERSCORE_IDENT_RE, end: '^'
+ },
+ {
+ className: 'builtin',
+ begin: '{', end: '}',
+ contains: ['string'],
+ excludeBegin: true, excludeEnd: true
+ },
+ {
+ className: 'filename',
+ begin: '(/\w|[a-zA-Z_][\da-zA-Z_]+\\.[\da-zA-Z_]{1,3})', end: ':',
+ excludeEnd: true
+ }
+ ]
+};
diff --git a/webroot/js/languages/renderman.js b/webroot/js/languages/renderman.js
new file mode 100644
index 0000000..decf13b
--- /dev/null
+++ b/webroot/js/languages/renderman.js
@@ -0,0 +1,71 @@
+/*
+
+RenderMan Languages (c) Konstantin Evdokimenko <qewerty@gmail.com>
+
+*/
+
+hljs.LANGUAGES.rib = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ illegal: '</',
+ contains: ['comment', 'string', 'number'],
+ keywords: {
+ 'keyword': {'ReadArchive': 1, 'FrameBegin': 1, 'FrameEnd': 1, 'WorldBegin': 1, 'WorldEnd': 1,
+ 'Attribute': 1, 'Display': 1, 'Option': 1, 'Format': 1, 'ShadingRate': 1,
+ 'PixelFilter': 1, 'PixelSamples': 1, 'Projection': 1, 'Scale': 1, 'ConcatTransform': 1,
+ 'Transform': 1, 'Translate': 1, 'Rotate': 1,
+ 'Surface': 1, 'Displacement': 1, 'Atmosphere': 1,
+ 'Interior': 1, 'Exterior': 1},
+ 'commands': {'WorldBegin': 1, 'WorldEnd': 1, 'FrameBegin': 1, 'FrameEnd': 1,
+ 'ReadArchive': 1, 'ShadingRate': 1}
+ }
+ },
+ modes: [
+ hljs.HASH_COMMENT_MODE,
+ hljs.C_NUMBER_MODE,
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE
+ ]
+};
+
+hljs.LANGUAGES.rsl = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ illegal: '</',
+ contains: ['comment', 'string', 'number', 'preprocessor',
+ 'shader', 'shading'],
+ keywords: {
+ 'keyword': {'float': 1, 'color': 1, 'point': 1, 'normal': 1, 'vector': 1,
+ 'matrix': 1, 'while': 1, 'for': 1, 'if': 1, 'do': 1,
+ 'return': 1, 'else': 1, 'break': 1, 'extern': 1, 'continue': 1},
+ 'built_in': {'smoothstep': 1, 'calculatenormal': 1, 'faceforward': 1,
+ 'normalize': 1, 'ambient': 1, 'diffuse': 1, 'specular': 1,
+ 'visibility': 1}
+ }
+ },
+ modes: [
+ {
+ className: 'shader',
+ begin: 'surface |displacement |light |volume |imager ', end: '\\(',
+ lexems: [hljs.IDENT_RE],
+ keywords: {'surface': 1, 'displacement': 1, 'light': 1, 'volume': 1, 'imager': 1}
+ },
+ {
+ className: 'shading',
+ begin: 'illuminate|illuminance|gather', end: '\\(',
+ lexems: [hljs.IDENT_RE],
+ keywords: {'illuminate': 1, 'illuminance': 1, 'gather': 1}
+ },
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ hljs.C_NUMBER_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.APOS_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'preprocessor',
+ begin: '#', end: '$'
+ }
+ ]
+};
diff --git a/webroot/js/languages/smalltalk.js b/webroot/js/languages/smalltalk.js
new file mode 100644
index 0000000..caa4b35
--- /dev/null
+++ b/webroot/js/languages/smalltalk.js
@@ -0,0 +1,53 @@
+/*
+
+Smalltalk definition (c) Vladimir Gubarkov <xonixx@gmail.com>
+
+*/
+
+hljs.SMALLTALK_KEYWORDS = {'self': 1, 'super': 1, 'nil': 1, 'true': 1, 'false': 1, 'thisContext': 1}; // only 6
+hljs.VAR_IDENT_RE = '[a-z][a-zA-Z0-9_]*';
+
+hljs.LANGUAGES.smalltalk = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ contains: ['comment', 'string', 'class', 'method',
+ 'number', 'symbol', 'char', 'localvars', 'array'],
+ keywords: hljs.SMALLTALK_KEYWORDS
+ },
+ modes: [
+ {
+ className: 'class',
+ begin: '\\b[A-Z][A-Za-z0-9_]*', end: '^',
+ relevance: 0
+ },
+ {
+ className: 'symbol',
+ begin: '#' + hljs.UNDERSCORE_IDENT_RE, end: '^'
+ },
+ hljs.C_NUMBER_MODE,
+ hljs.APOS_STRING_MODE,
+ {
+ className: 'comment',
+ begin: '"', end: '"',
+ relevance: 0
+ },
+ {
+ className: 'method',
+ begin: hljs.VAR_IDENT_RE+':', end:'^'
+ },
+ {
+ className: 'char',
+ begin: '\\$.{1}', end: '^'
+ },
+ {
+ className: 'localvars',
+ begin: '\\|\\s*(('+hljs.VAR_IDENT_RE+')\\s*)+\\|', end: '^',
+ relevance: 10
+ },
+ {
+ className: 'array',
+ begin: '\\#\\(', end: '\\)',
+ contains: ['string', 'char', 'number', 'symbol']
+ }
+ ]
+};
diff --git a/webroot/js/languages/sql.js b/webroot/js/languages/sql.js
new file mode 100644
index 0000000..98b402e
--- /dev/null
+++ b/webroot/js/languages/sql.js
@@ -0,0 +1,50 @@
+hljs.SQL_KEYWORDS = {'all': 1, 'partial': 1, 'global': 1, 'month': 1, 'current_timestamp': 1, 'using': 1, 'go': 1, 'revoke': 1, 'smallint': 1, 'indicator': 1, 'end-exec': 1, 'disconnect': 1, 'zone': 1, 'with': 1, 'character': 1, 'assertion': 1, 'to': 1, 'add': 1, 'current_user': 1, 'usage': 1, 'input': 1, 'local': 1, 'alter': 1, 'match': 1, 'collate': 1, 'real': 1, 'then': 1, 'rollback': 1, 'get': 1, 'read': 1, 'timestamp': 1, 'session_user': 1, 'not': 1, 'integer': 1, 'bit': 1, 'unique': 1, 'day': 1, 'minute': 1, 'desc': 1, 'insert': 1, 'execute': 1, 'like': 1, 'level': 1, 'decimal': 1, 'drop': 1, 'continue': 1, 'isolation': 1, 'found': 1, 'where': 1, 'constraints': 1, 'domain': 1, 'right': 1, 'national': 1, 'some': 1, 'module': 1, 'transaction': 1, 'relative': 1, 'second': 1, 'connect': 1, 'escape': 1, 'close': 1, 'system_user': 1, 'for': 1, 'deferred': 1, 'section': 1, 'cast': 1, 'current': 1, 'sqlstate': 1, 'allocate': 1, 'intersect': 1, 'deallocate': 1, 'numeric': 1, 'public': 1, 'preserve': 1, 'full': 1, 'goto': 1, 'initially': 1, 'asc': 1, 'no': 1, 'key': 1, 'output': 1, 'collation': 1, 'group': 1, 'by': 1, 'union': 1, 'session': 1, 'both': 1, 'last': 1, 'language': 1, 'constraint': 1, 'column': 1, 'of': 1, 'space': 1, 'foreign': 1, 'deferrable': 1, 'prior': 1, 'connection': 1, 'unknown': 1, 'action': 1, 'commit': 1, 'view': 1, 'or': 1, 'first': 1, 'into': 1, 'float': 1, 'year': 1, 'primary': 1, 'cascaded': 1, 'except': 1, 'restrict': 1, 'set': 1, 'references': 1, 'names': 1, 'table': 1, 'outer': 1, 'open': 1, 'select': 1, 'size': 1, 'are': 1, 'rows': 1, 'from': 1, 'prepare': 1, 'distinct': 1, 'leading': 1, 'create': 1, 'only': 1, 'next': 1, 'inner': 1, 'authorization': 1, 'schema': 1, 'corresponding': 1, 'option': 1, 'declare': 1, 'precision': 1, 'immediate': 1, 'else': 1, 'timezone_minute': 1, 'external': 1, 'varying': 1, 'translation': 1, 'true': 1, 'case': 1, 'exception': 1, 'join': 1, 'hour': 1, 'default': 1, 'double': 1, 'scroll': 1, 'value': 1, 'cursor': 1, 'descriptor': 1, 'values': 1, 'dec': 1, 'fetch': 1, 'procedure': 1, 'delete': 1, 'and': 1, 'false': 1, 'int': 1, 'is': 1, 'describe': 1, 'char': 1, 'as': 1, 'at': 1, 'in': 1, 'varchar': 1, 'null': 1, 'trailing': 1, 'any': 1, 'absolute': 1, 'current_time': 1, 'end': 1, 'grant': 1, 'privileges': 1, 'when': 1, 'cross': 1, 'check': 1, 'write': 1, 'current_date': 1, 'pad': 1, 'begin': 1, 'temporary': 1, 'exec': 1, 'time': 1, 'update': 1, 'catalog': 1, 'user': 1, 'sql': 1, 'date': 1, 'on': 1, 'identity': 1, 'timezone_hour': 1, 'natural': 1, 'whenever': 1, 'interval': 1, 'work': 1, 'order': 1, 'cascade': 1, 'diagnostics': 1, 'nchar': 1, 'having': 1, 'left': 1};
+
+hljs.LANGUAGES.sql =
+{
+ case_insensitive: true,
+ defaultMode:
+ {
+ lexems: [hljs.IDENT_RE],
+ contains: ['string', 'number', 'comment'],
+ keywords: {
+ 'keyword': hljs.SQL_KEYWORDS,
+ 'aggregate': {'count': 1, 'sum': 1, 'min': 1, 'max': 1, 'avg': 1}
+ }
+ },
+
+ modes: [
+ hljs.C_NUMBER_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ {
+ className: 'comment',
+ begin: '--', end: '$'
+ },
+ {
+ className: 'string',
+ begin: '\'', end: '\'',
+ contains: ['escape', 'squote'],
+ relevance: 0
+ },
+ {
+ className: 'squote',
+ begin: '\'\'', end: '^'
+ },
+ {
+ className: 'string',
+ begin: '"', end: '"',
+ contains: [ 'escape', 'dquote'],
+ relevance: 0
+ },
+ {
+ className: 'dquote',
+ begin: '""', end: '^'
+ },
+ {
+ className: 'string',
+ begin: '`', end: '`',
+ contains: ['escape']
+ },
+ hljs.BACKSLASH_ESCAPE
+ ]
+};
diff --git a/webroot/js/languages/static.js b/webroot/js/languages/static.js
new file mode 100644
index 0000000..d619a4d
--- /dev/null
+++ b/webroot/js/languages/static.js
@@ -0,0 +1,223 @@
+hljs.CPP_KEYWORDS = {
+ 'keyword': {'false': 1, 'int': 1, 'float': 1, 'while': 1, 'private': 1, 'char': 1, 'catch': 1, 'export': 1, 'virtual': 1, 'operator': 2, 'sizeof': 2, 'dynamic_cast': 2, 'typedef': 2, 'const_cast': 2, 'const': 1, 'struct': 1, 'for': 1, 'static_cast': 2, 'union': 1, 'namespace': 1, 'unsigned': 1, 'long': 1, 'throw': 1, 'volatile': 2, 'static': 1, 'protected': 1, 'bool': 1, 'template': 1, 'mutable': 1, 'if': 1, 'public': 1, 'friend': 2, 'do': 1, 'return': 1, 'goto': 1, 'auto': 1, 'void': 2, 'enum': 1, 'else': 1, 'break': 1, 'new': 1, 'extern': 1, 'using': 1, 'true': 1, 'class': 1, 'asm': 1, 'case': 1, 'typeid': 1, 'short': 1, 'reinterpret_cast': 2, 'default': 1, 'double': 1, 'register': 1, 'explicit': 1, 'signed': 1, 'typename': 1, 'try': 1, 'this': 1, 'switch': 1, 'continue': 1, 'wchar_t': 1, 'inline': 1, 'delete': 1},
+ 'built_in': {'std': 1, 'string': 1, 'cin': 1, 'cout': 1, 'cerr': 1, 'clog': 1, 'stringstream': 1, 'istringstream': 1, 'ostringstream': 1, 'auto_ptr': 1, 'deque': 1, 'list': 1, 'queue': 1, 'stack': 1, 'vector': 1, 'map': 1, 'set': 1, 'bitset': 1, 'multiset': 1, 'multimap': 1}
+}
+hljs.LANGUAGES.cpp = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ illegal: '</',
+ contains: ['comment', 'string', 'number', 'preprocessor', 'stl_container'],
+ keywords: hljs.CPP_KEYWORDS
+ },
+ modes: [
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ hljs.C_NUMBER_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'string',
+ begin: '\'', end: '[^\\\\]\'',
+ illegal: '[^\\\\][^\']'
+ },
+ {
+ className: 'preprocessor',
+ begin: '#', end: '$'
+ },
+ {
+ className: 'stl_container',
+ begin: '\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap)\\s*<', end: '>',
+ contains: ['stl_container'],
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ keywords: hljs.CPP_KEYWORDS,
+ relevance: 10
+ }
+ ]
+};
+
+
+/*
+
+Java definition (с) Vsevolod Solovyov <vsevolod.solovyov@gmail.com>
+
+*/
+hljs.LANGUAGES.java = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ contains: ['javadoc', 'comment', 'string', 'class', 'number', 'annotation'],
+ keywords: {'false': 1, 'synchronized': 1, 'int': 1, 'abstract': 1, 'float': 1, 'private': 1, 'char': 1, 'interface': 1, 'boolean': 1, 'static': 1, 'null': 1, 'if': 1, 'const': 1, 'for': 1, 'true': 1, 'while': 1, 'long': 1, 'throw': 1, 'strictfp': 1, 'finally': 1, 'protected': 1, 'extends': 1, 'import': 1, 'native': 1, 'final': 1, 'implements': 1, 'return': 1, 'void': 1, 'enum': 1, 'else': 1, 'break': 1, 'transient': 1, 'new': 1, 'catch': 1, 'instanceof': 1, 'byte': 1, 'super': 1, 'class': 1, 'volatile': 1, 'case': 1, 'assert': 1, 'short': 1, 'package': 1, 'default': 1, 'double': 1, 'public': 1, 'try': 1, 'this': 1, 'switch': 1, 'continue': 1, 'throws': 1}
+ },
+ modes: [
+ {
+ className: 'class',
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ begin: '(class |interface )', end: '{',
+ illegal: ':',
+ keywords: {'class': 1, 'interface': 1},
+ contains: ['inheritance', 'title']
+ },
+ {
+ className: 'inheritance',
+ begin: '(implements|extends)', end: '^',
+ lexems: [hljs.IDENT_RE],
+ keywords: {'extends': 1, 'implements': 1},
+ relevance: 10
+ },
+ {
+ className: 'title',
+ begin: hljs.UNDERSCORE_IDENT_RE, end: '^'
+ },
+ {
+ className: 'params',
+ begin: '\\(', end: '\\)',
+ contains: ['string', 'annotation']
+ },
+ hljs.C_NUMBER_MODE,
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ hljs.C_LINE_COMMENT_MODE,
+ {
+ className: 'javadoc',
+ begin: '/\\*\\*', end: '\\*/',
+ contains: ['javadoctag'],
+ relevance: 10
+ },
+ {
+ className: 'javadoctag',
+ begin: '@[A-Za-z]+', end: '^'
+ },
+ hljs.C_BLOCK_COMMENT_MODE,
+ {
+ className: 'annotation',
+ begin: '@[A-Za-z]+', end: '^'
+ }
+ ]
+};
+
+
+hljs.DELPHI_KEYWORDS = {'and': 1, 'safecall': 1, 'cdecl': 1, 'then': 1, 'string': 1, 'exports': 1, 'library': 1, 'not': 1, 'pascal': 1, 'set': 1, 'virtual': 1, 'file': 1, 'in': 1, 'array': 1, 'label': 1, 'packed': 1, 'end.': 1, 'index': 1, 'while': 1, 'const': 1, 'raise': 1, 'for': 1, 'to': 1, 'implementation': 1, 'with': 1, 'except': 1, 'overload': 1, 'destructor': 1, 'downto': 1, 'finally': 1, 'program': 1, 'exit': 1, 'unit': 1, 'inherited': 1, 'override': 1, 'if': 1, 'type': 1, 'until': 1, 'function': 1, 'do': 1, 'begin': 1, 'repeat': 1, 'goto': 1, 'nil': 1, 'far': 1, 'initialization': 1, 'object': 1, 'else': 1, 'var': 1, 'uses': 1, 'external': 1, 'resourcestring': 1, 'interface': 1, 'end': 1, 'finalization': 1, 'class': 1, 'asm': 1, 'mod': 1, 'case': 1, 'on': 1, 'shr': 1, 'shl': 1, 'of': 1, 'register': 1, 'xorwrite': 1, 'threadvar': 1, 'try': 1, 'record': 1, 'near': 1, 'stored': 1, 'constructor': 1, 'stdcall': 1, 'inline': 1, 'div': 1, 'out': 1, 'or': 1, 'procedure': 1};
+hljs.DELPHI_CLASS_KEYWORDS = {'safecall': 1, 'stdcall': 1, 'pascal': 1, 'stored': 1, 'const': 1, 'implementation': 1, 'finalization': 1, 'except': 1, 'to': 1, 'finally': 1, 'program': 1, 'inherited': 1, 'override': 1, 'then': 1, 'exports': 1, 'string': 1, 'read': 1, 'not': 1, 'mod': 1, 'shr': 1, 'try': 1, 'div': 1, 'shl': 1, 'set': 1, 'library': 1, 'message': 1, 'packed': 1, 'index': 1, 'for': 1, 'near': 1, 'overload': 1, 'label': 1, 'downto': 1, 'exit': 1, 'public': 1, 'goto': 1, 'interface': 1, 'asm': 1, 'on': 1, 'of': 1, 'constructor': 1, 'or': 1, 'private': 1, 'array': 1, 'unit': 1, 'raise': 1, 'destructor': 1, 'var': 1, 'type': 1, 'until': 1, 'function': 1, 'else': 1, 'external': 1, 'with': 1, 'case': 1, 'default': 1, 'record': 1, 'while': 1, 'protected': 1, 'property': 1, 'procedure': 1, 'published': 1, 'and': 1, 'cdecl': 1, 'do': 1, 'threadvar': 1, 'file': 1, 'in': 1, 'if': 1, 'end': 1, 'virtual': 1, 'write': 1, 'far': 1, 'out': 1, 'begin': 1, 'repeat': 1, 'nil': 1, 'initialization': 1, 'object': 1, 'uses': 1, 'resourcestring': 1, 'class': 1, 'register': 1, 'xorwrite': 1, 'inline': 1};
+
+hljs.LANGUAGES.delphi = {
+ defaultMode: {
+ lexems: [hljs.IDENT_RE],
+ illegal: '("|\\$[G-Zg-z]|\\/\\*|</)',
+ contains: ['comment', 'string', 'number', 'function', 'class'],
+ keywords: hljs.DELPHI_KEYWORDS
+ },
+ case_insensitive: true,
+ modes: [
+ {
+ className: 'comment',
+ begin: '{', end: '}'
+ },
+ {
+ className: 'comment',
+ begin: '\\(\\*', end: '\\*\\)',
+ relevance: 10
+ },
+ hljs.C_LINE_COMMENT_MODE,
+ {
+ className: 'number',
+ begin: hljs.NUMBER_RE, end: '^',
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: '\'', end: '\'',
+ contains: ['quote'],
+ relevance: 0
+ },
+ {
+ className: 'string',
+ begin: '(#\\d+)+', end: '^'
+ },
+ {
+ className: 'quote',
+ begin: '\'\'', end: '^'
+ },
+ {
+ className: 'function',
+ begin: 'function', end: '[:;]',
+ lexems: [hljs.IDENT_RE],
+ keywords: {'function': 1},
+ contains: ['title', 'params', 'comment'],
+ relevance: 0
+ },
+ {
+ className: 'function',
+ begin: '(procedure|constructor|destructor)', end: ';',
+ lexems: [hljs.IDENT_RE],
+ keywords: {'constructor': 1, 'destructor': 1, 'procedure': 1},
+ contains: ['title', 'params', 'comment'],
+ relevance: 10
+ },
+ {
+ className: 'title',
+ begin: hljs.IDENT_RE, end: '^'
+ },
+ {
+ className: 'params',
+ begin: '\\(', end: '\\)',
+ lexems: [hljs.IDENT_RE],
+ keywords: hljs.DELPHI_KEYWORDS,
+ contains: ['string']
+ },
+ {
+ className: 'class',
+ begin: '=\\s*class', end: 'end;',
+ lexems: [hljs.IDENT_RE],
+ keywords: hljs.DELPHI_CLASS_KEYWORDS,
+ contains: ['string', 'comment', 'function']
+ }
+ ]
+};
+
+/*
+
+C# definition (с) Jason Diamond <jason@diamond.name>
+
+*/
+hljs.LANGUAGES.cs = {
+ defaultMode: {
+ lexems: [hljs.UNDERSCORE_IDENT_RE],
+ contains: ['comment', 'string', 'number'],
+ keywords: {
+ // Normal keywords.
+ 'abstract': 1, 'as': 1, 'base': 1, 'bool': 1, 'break': 1, 'byte': 1, 'case': 1, 'catch': 1, 'char': 1, 'checked': 1, 'class': 1, 'const': 1, 'continue': 1, 'decimal': 1, 'default': 1, 'delegate': 1, 'do': 1, 'do': 1, 'double': 1, 'else': 1, 'enum': 1, 'event': 1, 'explicit': 1, 'extern': 1, 'false': 1, 'finally': 1, 'fixed': 1, 'float': 1, 'for': 1, 'foreach': 1, 'goto': 1, 'if': 1, 'implicit': 1, 'in': 1, 'int': 1, 'interface': 1, 'internal': 1, 'is': 1, 'lock': 1, 'long': 1, 'namespace': 1, 'new': 1, 'null': 1, 'object': 1, 'operator': 1, 'out': 1, 'override': 1, 'params': 1, 'private': 1, 'protected': 1, 'public': 1, 'readonly': 1, 'ref': 1, 'return': 1, 'sbyte': 1, 'sealed': 1, 'short': 1, 'sizeof': 1, 'stackalloc': 1, 'static': 1, 'string': 1, 'struct': 1, 'switch': 1, 'this': 1, 'throw': 1, 'true': 1, 'try': 1, 'typeof': 1, 'uint': 1, 'ulong': 1, 'unchecked': 1, 'unsafe': 1, 'ushort': 1, 'using': 1, 'virtual': 1, 'volatile': 1, 'void': 1, 'while': 1,
+ // Contextual keywords.
+ 'ascending': 1, 'descending': 1, 'from': 1, 'get': 1, 'group': 1, 'into': 1, 'join': 1, 'let': 1, 'orderby': 1, 'partial': 1, 'select': 1, 'set': 1, 'value': 1, 'var': 1, 'where': 1, 'yield': 1
+ }
+ },
+ modes: [
+ {
+ className: 'comment',
+ begin: '///', end: '$', returnBegin: true,
+ contains: ['xmlDocTag']
+ },
+ {
+ className: 'xmlDocTag',
+ begin: '///|<!--|-->', end: '^'
+ },
+ {
+ className: 'xmlDocTag',
+ begin: '</?', end: '>'
+ },
+ {
+ className: 'string',
+ begin: '@"', end: '"',
+ contains: ['quoteQuote']
+ },
+ {
+ className: 'quoteQuote',
+ begin: '""', end: '^'
+ },
+ hljs.C_LINE_COMMENT_MODE,
+ hljs.C_BLOCK_COMMENT_MODE,
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ hljs.C_NUMBER_MODE
+ ]
+};
\ No newline at end of file
diff --git a/webroot/js/languages/vbscript.js b/webroot/js/languages/vbscript.js
new file mode 100644
index 0000000..dbe0a4d
--- /dev/null
+++ b/webroot/js/languages/vbscript.js
@@ -0,0 +1,25 @@
+/*
+
+VBScript definition (c) Nikita Ledyaev <lenikita@yandex.ru>
+
+*/
+hljs.LANGUAGES.vbscript = {
+ defaultMode: {
+ lexems: [hljs.IDENT_RE],
+ contains: ['string', 'comment', 'number', 'built_in'],
+ keywords: {
+ 'keyword': {'call' : 1,'class' : 1,'const' : 1,'dim' : 1,'do' : 1,'loop' : 1,'erase' : 1,'execute' : 1,'executeglobal' : 1,'exit' : 1,'for' : 1,'each' : 1,'next' : 1,'function' : 1,'if' : 1,'then' : 1,'else' : 1,'on' : 1, 'error' : 1,'option' : 1, 'explicit' : 1,'private' : 1,'property' : 1,'let' : 1,'get' : 1,'public' : 1,'randomize' : 1,'redim' : 1,'rem' : 1,'select' : 1,'case' : 1,'set' : 1,'stop' : 1,'sub' : 1,'while' : 1,'wend' : 1,'with' : 1, 'end' : 1, 'to' : 1},
+ 'built_in': {'lcase': 1, 'month': 1, 'vartype': 1, 'instrrev': 1, 'ubound': 1, 'setlocale': 1, 'getobject': 1, 'rgb': 1, 'getref': 1, 'string': 1, 'weekdayname': 1, 'rnd': 1, 'dateadd': 1, 'monthname': 1, 'now': 1, 'day': 1, 'minute': 1, 'isarray': 1, 'cbool': 1, 'round': 1, 'formatcurrency': 1, 'conversions': 1, 'csng': 1, 'timevalue': 1, 'second': 1, 'year': 1, 'space': 1, 'abs': 1, 'clng': 1, 'timeserial': 1, 'fixs': 1, 'len': 1, 'asc': 1, 'isempty': 1, 'maths': 1, 'dateserial': 1, 'atn': 1, 'timer': 1, 'isobject': 1, 'filter': 1, 'weekday': 1, 'datevalue': 1, 'ccur': 1, 'isdate': 1, 'instr': 1, 'datediff': 1, 'formatdatetime': 1, 'replace': 1, 'isnull': 1, 'right': 1, 'sgn': 1, 'array': 1, 'snumeric': 1, 'log': 1, 'cdbl': 1, 'hex': 1, 'chr': 1, 'lbound': 1, 'msgbox': 1, 'ucase': 1, 'getlocale': 1, 'cos': 1, 'cdate': 1, 'cbyte': 1, 'rtrim': 1, 'join': 1, 'hour': 1, 'oct': 1, 'typename': 1, 'trim': 1, 'strcomp': 1, 'int': 1, 'createobject': 1, 'loadpicture': 1, 'tan': 1, 'formatnumber': 1, 'mid': 1, 'scriptenginebuildversion': 1, 'scriptengine': 1, 'split': 1, 'scriptengineminorversion': 1, 'cint': 1, 'sin': 1, 'datepart': 1, 'ltrim': 1, 'sqr': 1, 'scriptenginemajorversion': 1, 'time': 1, 'derived': 1, 'eval': 1, 'date': 1, 'formatpercent': 1, 'exp': 1, 'inputbox': 1, 'left': 1}
+ }
+ },
+ case_insensitive: true,
+ modes: [
+ hljs.QUOTE_STRING_MODE,
+ hljs.BACKSLASH_ESCAPE,
+ {
+ className: 'comment',
+ begin: '\'', end: '$'
+ },
+ hljs.C_NUMBER_MODE
+ ]
+};
diff --git a/webroot/js/languages/www.js b/webroot/js/languages/www.js
new file mode 100644
index 0000000..331ad9d
--- /dev/null
+++ b/webroot/js/languages/www.js
@@ -0,0 +1,257 @@
+hljs.XML_COMMENT = {
+ className: 'comment',
+ begin: '<!--', end: '-->'
+};
+hljs.XML_ATTR = {
+ className: 'attribute',
+ begin: '\\s[a-zA-Z\\:-]+=', end: '^',
+ contains: ['value']
+};
+hljs.XML_VALUE_QUOT = {
+ className: 'value',
+ begin: '"', end: '"'
+};
+hljs.XML_VALUE_APOS = {
+ className: 'value',
+ begin: '\'', end: '\''
+};
+
+
+hljs.LANGUAGES.xml = {
+ defaultMode: {
+ contains: ['pi', 'comment', 'cdata', 'tag']
+ },
+ case_insensitive: true,
+ modes: [
+ {
+ className: 'pi',
+ begin: '<\\?', end: '\\?>',
+ relevance: 10
+ },
+ hljs.XML_COMMENT,
+ {
+ className: 'cdata',
+ begin: '<\\!\\[CDATA\\[', end: '\\]\\]>'
+ },
+ {
+ className: 'tag',
+ begin: '</?', end: '>',
+ contains: ['title', 'tag_internal'],
+ relevance: 1.5
+ },
+ {
+ className: 'title',
+ begin: '[A-Za-z:_][A-Za-z0-9\\._:-]+', end: '^',
+ relevance: 0
+ },
+ {
+ className: 'tag_internal',
+ begin: '^', endsWithParent: true,
+ contains: ['attribute'],
+ relevance: 0,
+ illegal: '[\\+\\.]'
+ },
+ hljs.XML_ATTR,
+ hljs.XML_VALUE_QUOT,
+ hljs.XML_VALUE_APOS
+ ]
+};
+
+hljs.HTML_TAGS = {'code': 1, 'kbd': 1, 'font': 1, 'noscript': 1, 'style': 1, 'img': 1, 'title': 1, 'menu': 1, 'tt': 1, 'tr': 1, 'param': 1, 'li': 1, 'tfoot': 1, 'th': 1, 'input': 1, 'td': 1, 'dl': 1, 'blockquote': 1, 'fieldset': 1, 'big': 1, 'dd': 1, 'abbr': 1, 'optgroup': 1, 'dt': 1, 'button': 1, 'isindex': 1, 'p': 1, 'small': 1, 'div': 1, 'dir': 1, 'em': 1, 'frame': 1, 'meta': 1, 'sub': 1, 'bdo': 1, 'label': 1, 'acronym': 1, 'sup': 1, 'body': 1, 'xml': 1, 'basefont': 1, 'base': 1, 'br': 1, 'address': 1, 'strong': 1, 'legend': 1, 'ol': 1, 'script': 1, 'caption': 1, 's': 1, 'col': 1, 'h2': 1, 'h3': 1, 'h1': 1, 'h6': 1, 'h4': 1, 'h5': 1, 'table': 1, 'select': 1, 'noframes': 1, 'span': 1, 'area': 1, 'dfn': 1, 'strike': 1, 'cite': 1, 'thead': 1, 'head': 1, 'option': 1, 'form': 1, 'hr': 1, 'var': 1, 'link': 1, 'b': 1, 'colgroup': 1, 'ul': 1, 'applet': 1, 'del': 1, 'iframe': 1, 'pre': 1, 'frameset': 1, 'ins': 1, 'tbody': 1, 'html': 1, 'samp': 1, 'map': 1, 'object': 1, 'a': 1, 'xmlns': 1, 'center': 1, 'textarea': 1, 'i': 1, 'q': 1, 'u': 1};
+hljs.HTML_DOCTYPE = {
+ className: 'doctype',
+ begin: '<!DOCTYPE', end: '>',
+ relevance: 10
+};
+hljs.HTML_ATTR = {
+ className: 'attribute',
+ begin: '\\s[a-zA-Z\\:-]+=', end: '^',
+ contains: ['value']
+};
+hljs.HTML_SHORT_ATTR = {
+ className: 'attribute',
+ begin: ' [a-zA-Z]+', end: '^'
+};
+hljs.HTML_VALUE = {
+ className: 'value',
+ begin: '[a-zA-Z0-9]+', end: '^'
+};
+
+hljs.LANGUAGES.html = {
+ defaultMode: {
+ contains: ['tag', 'comment', 'doctype', 'vbscript']
+ },
+ case_insensitive: true,
+ modes: [
+ hljs.XML_COMMENT,
+ hljs.HTML_DOCTYPE,
+ {
+ className: 'tag',
+ lexems: [hljs.IDENT_RE],
+ keywords: hljs.HTML_TAGS,
+ begin: '<style', end: '>',
+ contains: ['attribute'],
+ illegal: '[\\+\\.]',
+ starts: 'css'
+ },
+ {
+ className: 'tag',
+ lexems: [hljs.IDENT_RE],
+ keywords: hljs.HTML_TAGS,
+ begin: '<script', end: '>',
+ contains: ['attribute'],
+ illegal: '[\\+\\.]',
+ starts: 'javascript'
+ },
+ {
+ className: 'tag',
+ lexems: [hljs.IDENT_RE],
+ keywords: hljs.HTML_TAGS,
+ begin: '<[A-Za-z/]', end: '>',
+ contains: ['attribute'],
+ illegal: '[\\+\\.]'
+ },
+ {
+ className: 'css',
+ end: '</style>', returnEnd: true,
+ subLanguage: 'css'
+ },
+ {
+ className: 'javascript',
+ end: '</script>', returnEnd: true,
+ subLanguage: 'javascript'
+ },
+ hljs.HTML_ATTR,
+ hljs.HTML_SHORT_ATTR,
+ hljs.XML_VALUE_QUOT,
+ hljs.XML_VALUE_APOS,
+ hljs.HTML_VALUE,
+ {
+ className: 'vbscript',
+ begin: '<%', end: '%>',
+ subLanguage: 'vbscript'
+ }
+ ]
+};
+
+hljs.LANGUAGES.css = {
+ defaultMode: {
+ contains: ['id', 'class', 'attr_selector', 'rules', 'comment'],
+ keywords: hljs.HTML_TAGS,
+ lexems: [hljs.IDENT_RE],
+ illegal: '='
+ },
+ case_insensitive: true,
+ modes: [
+ {
+ className: 'id',
+ begin: '\\#[A-Za-z0-9_-]+', end: '^'
+ },
+ {
+ className: 'class',
+ begin: '\\.[A-Za-z0-9_-]+', end: '^',
+ relevance: 0
+ },
+ {
+ className: 'attr_selector',
+ begin: '\\[', end: '\\]',
+ illegal: '$'
+ },
+ {
+ className: 'rules',
+ begin: '{', end: '}',
+ contains: ['rule', 'comment'],
+ illegal: '[^\\s]'
+ },
+ {
+ className: 'rule',
+ begin: '[A-Z\\_\\.\\-]+\\s*:', end: ';', endsWithParent: true,
+ lexems: ['[A-Za-z-]+'],
+ keywords: {'play-during': 1, 'counter-reset': 1, 'counter-increment': 1, 'min-height': 1, 'quotes': 1, 'border-top': 1, 'pitch': 1, 'font': 1, 'pause': 1, 'list-style-image': 1, 'border-width': 1, 'cue': 1, 'outline-width': 1, 'border-left': 1, 'elevation': 1, 'richness': 1, 'speech-rate': 1, 'border-bottom': 1, 'border-spacing': 1, 'background': 1, 'list-style-type': 1, 'text-align': 1, 'page-break-inside': 1, 'orphans': 1, 'page-break-before': 1, 'text-transform': 1, 'line-height': 1, 'padding-left': 1, 'font-size': 1, 'right': 1, 'word-spacing': 1, 'padding-top': 1, 'outline-style': 1, 'bottom': 1, 'content': 1, 'border-right-style': 1, 'padding-right': 1, 'border-left-style': 1, 'voice-family': 1, 'background-color': 1, 'border-bottom-color': 1, 'outline-color': 1, 'unicode-bidi': 1, 'max-width': 1, 'font-family': 1, 'caption-side': 1, 'border-right-width': 1, 'pause-before': 1, 'border-top-style': 1, 'color': 1, 'border-collapse': 1, 'border-bottom-width': 1, 'float': 1, 'height': 1, 'max-height': 1, 'margin-right': 1, 'border-top-width': 1, 'speak': 1, 'speak-header': 1, 'top': 1, 'cue-before': 1, 'min-width': 1, 'width': 1, 'font-variant': 1, 'border-top-color': 1, 'background-position': 1, 'empty-cells': 1, 'direction': 1, 'border-right': 1, 'visibility': 1, 'padding': 1, 'border-style': 1, 'background-attachment': 1, 'overflow': 1, 'border-bottom-style': 1, 'cursor': 1, 'margin': 1, 'display': 1, 'border-left-width': 1, 'letter-spacing': 1, 'vertical-align': 1, 'clip': 1, 'border-color': 1, 'list-style': 1, 'padding-bottom': 1, 'pause-after': 1, 'speak-numeral': 1, 'margin-left': 1, 'widows': 1, 'border': 1, 'font-style': 1, 'border-left-color': 1, 'pitch-range': 1, 'background-repeat': 1, 'table-layout': 1, 'margin-bottom': 1, 'speak-punctuation': 1, 'font-weight': 1, 'border-right-color': 1, 'page-break-after': 1, 'position': 1, 'white-space': 1, 'text-indent': 1, 'background-image': 1, 'volume': 1, 'stress': 1, 'outline': 1, 'clear': 1, 'z-index': 1, 'text-decoration': 1, 'margin-top': 1, 'azimuth': 1, 'cue-after': 1, 'left': 1, 'list-style-position': 1},
+ contains: ['value']
+ },
+ hljs.C_BLOCK_COMMENT_MODE,
+ {
+ className: 'value',
+ begin: '^', endsWithParent: true, excludeEnd: true,
+ contains: ['function', 'number', 'hexcolor', 'string']
+ },
+ {
+ className: 'number',
+ begin: hljs.NUMBER_RE, end: '^'
+ },
+ {
+ className: 'hexcolor',
+ begin: '\\#[0-9A-F]+', end: '^'
+ },
+ {
+ className: 'function',
+ begin: hljs.IDENT_RE + '\\(', end: '\\)',
+ contains: ['params']
+ },
+ {
+ className: 'params',
+ begin: '^', endsWithParent: true, excludeEnd: true,
+ contains: ['number', 'string']
+ },
+ hljs.APOS_STRING_MODE,
+ hljs.QUOTE_STRING_MODE
+ ]
+};
+
+hljs.LANGUAGES.django = {
+ defaultMode: {
+ contains: ['tag', 'comment', 'doctype', 'template_comment', 'template_tag', 'variable']
+ },
+ case_insensitive: true,
+ modes: [
+ hljs.XML_COMMENT,
+ hljs.HTML_DOCTYPE,
+ {
+ className: 'tag',
+ lexems: [hljs.IDENT_RE],
+ keywords: hljs.HTML_TAGS,
+ begin: '<[A-Za-z/]', end: '>',
+ contains: ['attribute', 'template_comment', 'template_tag', 'variable']
+ },
+ hljs.HTML_ATTR,
+ hljs.HTML_SHORT_ATTR,
+ {
+ className: 'value',
+ begin: '"', end: '"',
+ contains: ['template_comment', 'template_tag', 'variable']
+ },
+ hljs.HTML_VALUE,
+ {
+ className: 'template_comment',
+ begin: '\\{\\%\\s*comment\\s*\\%\\}', end: '\\{\\%\\s*endcomment\\s*\\%\\}'
+ },
+ {
+ className: 'template_comment',
+ begin: '\\{#', end: '#\\}'
+ },
+ {
+ className: 'template_tag',
+ begin: '\\{\\%', end: '\\%\\}',
+ lexems: [hljs.IDENT_RE],
+ keywords: {'comment': 1, 'endcomment': 1, 'load': 1, 'templatetag': 1, 'ifchanged': 1, 'endifchanged': 1, 'if': 1, 'endif': 1, 'firstof': 1, 'for': 1, 'endfor': 1, 'in': 1, 'ifnotequal': 1, 'endifnotequal': 1, 'widthratio': 1, 'extends': 1, 'include': 1, 'spaceless': 1, 'endspaceless': 1, 'regroup': 1, 'by': 1, 'as': 1, 'ifequal': 1, 'endifequal': 1, 'ssi': 1, 'now': 1, 'with': 1, 'cycle': 1, 'url': 1, 'filter': 1, 'endfilter': 1, 'debug': 1, 'block': 1, 'endblock': 1, 'else': 1},
+ contains: ['filter']
+ },
+ {
+ className: 'variable',
+ begin: '\\{\\{', end: '\\}\\}',
+ contains: ['filter']
+ },
+ {
+ className: 'filter',
+ begin: '\\|[A-Za-z]+\\:?', end: '^', excludeEnd: true,
+ lexems: [hljs.IDENT_RE],
+ keywords: {'truncatewords': 1, 'removetags': 1, 'linebreaksbr': 1, 'yesno': 1, 'get_digit': 1, 'timesince': 1, 'random': 1, 'striptags': 1, 'filesizeformat': 1, 'escape': 1, 'linebreaks': 1, 'length_is': 1, 'ljust': 1, 'rjust': 1, 'cut': 1, 'urlize': 1, 'fix_ampersands': 1, 'title': 1, 'floatformat': 1, 'capfirst': 1, 'pprint': 1, 'divisibleby': 1, 'add': 1, 'make_list': 1, 'unordered_list': 1, 'urlencode': 1, 'timeuntil': 1, 'urlizetrunc': 1, 'wordcount': 1, 'stringformat': 1, 'linenumbers': 1, 'slice': 1, 'date': 1, 'dictsort': 1, 'dictsortreversed': 1, 'default_if_none': 1, 'pluralize': 1, 'lower': 1, 'join': 1, 'center': 1, 'default': 1, 'truncatewords_html': 1, 'upper': 1, 'length': 1, 'phone2numeric': 1, 'wordwrap': 1, 'time': 1, 'addslashes': 1, 'slugify': 1, 'first': 1},
+ contains: ['argument']
+ },
+ {
+ className: 'argument',
+ begin: '"', end: '"'
+ }
+ ]
+};
