diff --git a/webtools/bouncer/.htaccess b/webtools/bouncer/.htaccess
new file mode 100644
index 000000000000..735c2f462a94
--- /dev/null
+++ b/webtools/bouncer/.htaccess
@@ -0,0 +1,5 @@
+
+ RewriteEngine on
+ RewriteRule ^$ webroot/ [L]
+ RewriteRule (.*) webroot/$1 [L]
+
diff --git a/webtools/bouncer/README b/webtools/bouncer/README
new file mode 100644
index 000000000000..1a336af97ad8
--- /dev/null
+++ b/webtools/bouncer/README
@@ -0,0 +1,48 @@
+Mozilla Firefox Uninstall Survey
+================================
+
+
+How To Install
+--------------
+
+Assumptions:
+ 1) You've got a working database with the appropriate schema
+ 2) You've got cake setup on your server already. The code you're looking at now
+ is just what is in the /app/ directory - everything else will have to be on your
+ server already.
+
+Steps:
+
+1) Copy config/database.php.default to config/database.php and fill in your database
+values (if you're only doing production, just fill in the production area).
+
+2) Edit /webroot/index.php.
+ Define ROOT:
+ If you're installing this in your home directory, ROOT should be:
+
+ DS.'home'.DS.'username'.DS.'public_html'
+
+ Define APP_DIR:
+ ROOT is the parent directory of the app, this is the actual app.
+ Continuing the example above, if people are going to go to:
+ http://server.com/~username/bouncer/ to get to the app, APP_DIR should be:
+
+ bouncer
+
+ Define CAKE_CORE_INCLUDE_PATH:
+ This is the path to the actual cake install on your server. For example:
+
+ DS.'usr'.DS.'local'.DS.'lib'.DS.'php'.DS.'cake'
+
+3) Edit /webroot/.htaccess. Add a RewriteBase line below the line that says 'RewriteEngine On'.
+For our example, we would add the line:
+
+ RewriteBase /~username/bouncer
+
+4) Edit /.htaccess. Add the same RewriteBase line from step 3 directly below the
+'RewriteEngine On' line.
+
+
+
+
+Questions? Email clouserw@mozilla.com
diff --git a/webtools/bouncer/config/acl.ini.php b/webtools/bouncer/config/acl.ini.php
new file mode 100644
index 000000000000..72ec291853dd
--- /dev/null
+++ b/webtools/bouncer/config/acl.ini.php
@@ -0,0 +1,76 @@
+;
+; SVN FILE: $Id: acl.ini.php,v 1.1 2006/06/09 18:14:09 mike.morgan%oregonstate.edu Exp $
+;/**
+; * Short description for file.
+; *
+; *
+; * PHP versions 4 and 5
+; *
+; * CakePHP : Rapid Development Framework
+; * Copyright (c) 2006, 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 (c) 2006, Cake Software Foundation, Inc.
+; * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
+; * @package cake
+; * @subpackage cake.app.config
+; * @since CakePHP v 0.10.0.1076
+; * @version $Revision: 1.1 $
+; * @modifiedby $LastChangedBy: phpnut $
+; * @lastmodified $Date: 2006/06/09 18:14:09 $
+; * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+; */
+
+; acl.ini.php - Cake ACL Configuration
+; ---------------------------------------------------------------------
+; Use this file to specify user permissions.
+; aco = access control object (something in your application)
+; aro = access request object (something requesting access)
+;
+; User records are added as follows:
+;
+; [uid]
+; groups = group1, group2, group3
+; allow = aco1, aco2, aco3
+; deny = aco4, aco5, aco6
+;
+; Group records are added in a similar manner:
+;
+; [gid]
+; allow = aco1, aco2, aco3
+; deny = aco4, aco5, aco6
+;
+; The allow, deny, and groups sections are all optional.
+; NOTE: groups names *cannot* ever be the same as usernames!
+;
+; ACL permissions are checked in the following order:
+; 1. Check for user denies (and DENY if specified)
+; 2. Check for user allows (and ALLOW if specified)
+; 3. Gather user's groups
+; 4. Check group denies (and DENY if specified)
+; 5. Check group allows (and ALLOW if specified)
+; 6. If no aro, aco, or group information is found, DENY
+;
+; ---------------------------------------------------------------------
+
+;-------------------------------------
+;Users
+;-------------------------------------
+
+[username-goes-here]
+groups = group1, group2
+deny = aco1, aco2
+allow = aco3, aco4
+
+;-------------------------------------
+;Groups
+;-------------------------------------
+
+[groupname-goes-here]
+deny = aco5, aco6
+allow = aco7, aco8
\ No newline at end of file
diff --git a/webtools/bouncer/config/bootstrap.php b/webtools/bouncer/config/bootstrap.php
new file mode 100644
index 000000000000..0ad96d0300d5
--- /dev/null
+++ b/webtools/bouncer/config/bootstrap.php
@@ -0,0 +1,46 @@
+
+ * Copyright (c) 2006, 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 (c) 2006, Cake Software Foundation, Inc.
+ * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
+ * @package cake
+ * @subpackage cake.app.config
+ * @since CakePHP v 0.10.8.2117
+ * @version $Revision: 1.1 $
+ * @modifiedby $LastChangedBy: phpnut $
+ * @lastmodified $Date: 2006/06/09 18:14:09 $
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+/**
+ *
+ * This file is loaded automatically by the app/webroot/index.php file after the core bootstrap.php is loaded
+ * This is an application wide file to load any function that is not used within a class define.
+ * You can also use this to include or require any files in your application.
+ *
+ */
+/**
+ * The settings below can be used to set additional paths to models, views and controllers.
+ * This is related to Ticket #470 (https://trac.cakephp.org/ticket/470)
+ *
+ * $modelPaths = array('full path to models', 'second full path to models', 'etc...');
+ * $viewPaths = array('this path to views', 'second full path to views', 'etc...');
+ * $controllerPaths = array('this path to controllers', 'second full path to controllers', 'etc...');
+ *
+ */
+//EOF
+?>
\ No newline at end of file
diff --git a/webtools/bouncer/config/core.php b/webtools/bouncer/config/core.php
new file mode 100644
index 000000000000..fcd599987eca
--- /dev/null
+++ b/webtools/bouncer/config/core.php
@@ -0,0 +1,147 @@
+
+ * Copyright (c) 2006, 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 (c) 2006, Cake Software Foundation, Inc.
+ * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
+ * @package cake
+ * @subpackage cake.app.config
+ * @since CakePHP v 0.2.9
+ * @version $Revision: 1.1 $
+ * @modifiedby $LastChangedBy: phpnut $
+ * @lastmodified $Date: 2006/06/09 18:14:09 $
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+/**
+ * If you do not have mod rewrite on your system
+ * or if you prefer to use CakePHP pretty urls.
+ * uncomment the line below.
+ * Note: If you do have mod rewrite but prefer the
+ * CakePHP pretty urls, you also have to remove the
+ * .htaccess files
+ * release/.htaccess
+ * release/app/.htaccess
+ * release/app/webroot/.htaccess
+ */
+// define ('BASE_URL', env('SCRIPT_NAME'));
+/**
+ * Set debug level here:
+ * - 0: production
+ * - 1: development
+ * - 2: full debug with sql
+ * - 3: full debug with sql and dump of the current object
+ *
+ * In production, the "flash messages" redirect after a time interval.
+ * With the other debug levels you get to click the "flash message" to continue.
+ *
+ */
+ define('DEBUG', 2);
+/**
+ * Turn of caching checking wide.
+ * You must still use the controller var cacheAction inside you controller class.
+ * You can either set it controller wide, or in each controller method.
+ * use var $cacheAction = true; or in the controller method $this->cacheAction = true;
+ */
+ define('CACHE_CHECK', false);
+/**
+ * Error constant. Used for differentiating error logging and debugging.
+ * Currently PHP supports LOG_DEBUG
+ */
+ define('LOG_ERROR', 2);
+/**
+ * CakePHP includes 3 types of session saves
+ * database or file. Set this to your preferred method.
+ * If you want to use your own save handler place it in
+ * app/config/name.php DO NOT USE file or database as the name.
+ * and use just the name portion below.
+ *
+ * Setting this to cake will save files to /cakedistro/tmp directory
+ * Setting it to php will use the php default save path
+ * Setting it to database will use the database
+ *
+ *
+ */
+ define('CAKE_SESSION_SAVE', 'php');
+/**
+ * If using you own table name for storing sessions
+ * set the table name here.
+ * DO NOT INCLUDE PREFIX IF YOU HAVE SET ONE IN database.php
+ *
+ */
+ define('CAKE_SESSION_TABLE', 'cake_sessions');
+/**
+ * Set a random string of used in session.
+ *
+ */
+ define('CAKE_SESSION_STRING', 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi');
+/**
+ * Set the name of session cookie
+ *
+ */
+ define('CAKE_SESSION_COOKIE', 'CAKEPHP');
+/**
+ * Set level of Cake security.
+ *
+ */
+ define('CAKE_SECURITY', 'high');
+/**
+ * Set Cake Session time out.
+ * If CAKE_SECURITY define is set
+ * high: multiplied by 10
+ * medium: is multiplied by 100
+ * low is: multiplied by 300
+ *
+ * Number below is seconds.
+ */
+ define('CAKE_SESSION_TIMEOUT', '120');
+/**
+ * Uncomment the define below to use cake built in admin routes.
+ * You can set this value to anything you want.
+ * All methods related to the admin route should be prefixed with the
+ * name you set CAKE_ADMIN to.
+ * For example: admin_index, admin_edit
+ */
+// define('CAKE_ADMIN', 'admin');
+/**
+ * The define below is used to turn cake built webservices
+ * on or off. Default setting is off.
+ */
+ define('WEBSERVICES', 'off');
+/**
+ * Compress output CSS (removing comments, whitespace, repeating tags etc.)
+ * This requires a/var/cache directory to be writable by the web server (caching).
+ * To use, prefix the CSS link URL with '/ccss/' instead of '/css/' or use Controller::cssTag().
+ */
+ define('COMPRESS_CSS', false);
+/**
+ * If set to true, helpers would output data instead of returning it.
+ */
+ define('AUTO_OUTPUT', false);
+/**
+ * If set to false, session would not automatically be started.
+ */
+ define('AUTO_SESSION', true);
+/**
+ * Set the max size of file to use md5() .
+ */
+ define('MAX_MD5SIZE', (5 * 1024) * 1024);
+/**
+ * To use Access Control Lists with Cake...
+ */
+ define('ACL_CLASSNAME', 'DB_ACL');
+ define('ACL_FILENAME', 'dbacl' . DS . 'db_acl');
+?>
diff --git a/webtools/bouncer/config/database.php.default b/webtools/bouncer/config/database.php.default
new file mode 100644
index 000000000000..0300c045271d
--- /dev/null
+++ b/webtools/bouncer/config/database.php.default
@@ -0,0 +1,74 @@
+
+ * Copyright (c) 2006, 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 (c) 2006, Cake Software Foundation, Inc.
+ * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
+ * @package cake
+ * @subpackage cake.app.config
+ * @since CakePHP v 0.2.9
+ * @version $Revision: 1.1 $
+ * @modifiedby $LastChangedBy: phpnut $
+ * @lastmodified $Date: 2006/06/09 18:14:09 $
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+/**
+ * In this file you set up your database connection details.
+ *
+ * @package cake
+ * @subpackage cake.config
+ */
+/**
+ * Database configuration class.
+ * You can specify multiple configurations for production, development and testing.
+ *
+ * driver =>
+ * mysql, postgres, sqlite, adodb-drivername, pear-drivername
+ *
+ * connect =>
+ * MySQL set the connect to either mysql_pconnect of mysql_connect
+ * PostgreSQL set the connect to either pg_pconnect of pg_connect
+ * SQLite set the connect to sqlite_popen sqlite_open
+ * ADOdb set the connect to one of these
+ * (http://phplens.com/adodb/supported.databases.html) and
+ * append it '|p' for persistent connection. (mssql|p for example, or just mssql for not persistent)
+ *
+ * host =>
+ * the host you connect to the database
+ * MySQL 'localhost' to add a port number use 'localhost:port#'
+ * PostgreSQL 'localhost' to add a port number use 'localhost port=5432'
+ *
+ */
+class DATABASE_CONFIG
+{
+ var $default = array('driver' => 'mysql',
+ 'connect' => 'mysql_connect',
+ 'host' => 'localhost',
+ 'login' => 'user',
+ 'password' => 'password',
+ 'database' => 'project_name',
+ 'prefix' => '');
+
+ var $test = array('driver' => 'mysql',
+ 'connect' => 'mysql_connect',
+ 'host' => 'localhost',
+ 'login' => 'user',
+ 'password' => 'password',
+ 'database' => 'project_name-test',
+ 'prefix' => '');
+}
+?>
\ No newline at end of file
diff --git a/webtools/bouncer/config/inflections.php b/webtools/bouncer/config/inflections.php
new file mode 100644
index 000000000000..aa7216f7a51a
--- /dev/null
+++ b/webtools/bouncer/config/inflections.php
@@ -0,0 +1,72 @@
+
+ * Copyright (c) 2006, 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 (c) 2006, Cake Software Foundation, Inc.
+ * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
+ * @package cake
+ * @subpackage cake.app.config
+ * @since CakePHP v 1.0.0.2312
+ * @version $Revision: 1.1 $
+ * @modifiedby $LastChangedBy: phpnut $
+ * @lastmodified $Date: 2006/06/09 18:14:09 $
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+/**
+ * This is a key => value array of regex used to match words.
+ * If key matches then the value is returned.
+ *
+ * $pluralRules = array('/(s)tatus$/i' => '\1\2tatuses', '/^(ox)$/i' => '\1\2en', '/([m|l])ouse$/i' => '\1ice');
+ */
+ $pluralRules = array();
+/**
+ * This is a key only array of plural words that should not be inflected.
+ * Notice the last comma
+ *
+ * $uninflectedPlural = array('.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox');
+ */
+ $uninflectedPlural = array();
+/**
+ * This is a key => value array of plural irregular words.
+ * If key matches then the value is returned.
+ *
+ * $irregularPlural = array('atlas' => 'atlases', 'beef' => 'beefs', 'brother' => 'brothers')
+ */
+ $irregularPlural = array();
+/**
+ * This is a key => value array of regex used to match words.
+ * If key matches then the value is returned.
+ *
+ * $singularRules = array('/(s)tatuses$/i' => '\1\2tatus', '/(matr)ices$/i' =>'\1ix','/(vert|ind)ices$/i')
+ */
+ $singularRules = array();
+/**
+ * This is a key only array of singular words that should not be inflected.
+ * You should not have to change this value below if you do change it use same format
+ * as the $uninflectedPlural above.
+ */
+ $uninflectedSingular = $uninflectedPlural;
+/**
+ * This is a key => value array of singular irregular words.
+ * Most of the time this will be a reverse of the above $irregularPlural array
+ * You should not have to change this value below if you do change it use same format
+ *
+ * $irregularSingular = array('atlases' => 'atlas', 'beefs' => 'beef', 'brothers' => 'brother')
+ */
+ $irregularSingular = array_flip($irregularPlural);
+?>
\ No newline at end of file
diff --git a/webtools/bouncer/config/routes.php b/webtools/bouncer/config/routes.php
new file mode 100644
index 000000000000..39c5adb6caa7
--- /dev/null
+++ b/webtools/bouncer/config/routes.php
@@ -0,0 +1,46 @@
+
+ * Copyright (c) 2006, 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 (c) 2006, Cake Software Foundation, Inc.
+ * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
+ * @package cake
+ * @subpackage cake.app.config
+ * @since CakePHP v 0.2.9
+ * @version $Revision: 1.1 $
+ * @modifiedby $LastChangedBy: phpnut $
+ * @lastmodified $Date: 2006/06/09 18:14:09 $
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+/**
+ * Here, we are connecting '/' (base path) to controller called 'Pages',
+ * its action called 'display', and we pass a param to select the view file
+ * to use (in this case, /app/views/pages/home.thtml)...
+ */
+ $Route->connect('/', array('controller' => 'pages', 'action' => 'display', 'dashboard'));
+/**
+ * ...and connect the rest of 'Pages' controller's urls.
+ */
+ $Route->connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
+/**
+ * Then we connect url '/test' to our test controller. This is helpfull in
+ * developement.
+ */
+ $Route->connect('/tests', array('controller' => 'tests', 'action' => 'index'));
+?>
diff --git a/webtools/bouncer/config/sql/db_acl.sql b/webtools/bouncer/config/sql/db_acl.sql
new file mode 100644
index 000000000000..8c7aae84fdf8
--- /dev/null
+++ b/webtools/bouncer/config/sql/db_acl.sql
@@ -0,0 +1,30 @@
+CREATE TABLE `acos` (
+ `id` int(11) NOT NULL auto_increment,
+ `model` varchar(255) NOT NULL default '',
+ `object_id` int(11) default NULL,
+ `alias` varchar(255) NOT NULL default '',
+ `lft` int(11) default NULL,
+ `rght` int(11) default NULL,
+ PRIMARY KEY (`id`)
+);
+
+CREATE TABLE `aros` (
+ `id` int(11) NOT NULL auto_increment,
+ `model` varchar(255) NOT NULL default '',
+ `user_id` int(11) default NULL,
+ `alias` varchar(255) NOT NULL default '',
+ `lft` int(11) default NULL,
+ `rght` int(11) default NULL,
+ PRIMARY KEY (`id`)
+);
+
+CREATE TABLE `aros_acos` (
+ `id` int(11) NOT NULL auto_increment,
+ `aro_id` int(11) default NULL,
+ `aco_id` int(11) default NULL,
+ `_create` int(1) NOT NULL default '0',
+ `_read` int(1) NOT NULL default '0',
+ `_update` int(1) NOT NULL default '0',
+ `_delete` int(11) NOT NULL default '0',
+ PRIMARY KEY (`id`)
+);
diff --git a/webtools/bouncer/config/sql/sessions.sql b/webtools/bouncer/config/sql/sessions.sql
new file mode 100644
index 000000000000..68a7dd268604
--- /dev/null
+++ b/webtools/bouncer/config/sql/sessions.sql
@@ -0,0 +1,11 @@
+-- @copyright Copyright (c) 2006, Cake Software Foundation, Inc.
+-- @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
+-- @since CakePHP v 0.10.8.1997
+-- @version $Revision: 1.1 $
+
+CREATE TABLE cake_sessions (
+ id varchar(255) NOT NULL default '',
+ data text,
+ expires int(11) default NULL,
+ PRIMARY KEY (id)
+);
\ No newline at end of file
diff --git a/webtools/bouncer/controllers/files_controller.php b/webtools/bouncer/controllers/files_controller.php
new file mode 100644
index 000000000000..cebacd1c2613
--- /dev/null
+++ b/webtools/bouncer/controllers/files_controller.php
@@ -0,0 +1,6 @@
+
diff --git a/webtools/bouncer/controllers/locales_controller.php b/webtools/bouncer/controllers/locales_controller.php
new file mode 100644
index 000000000000..ffadb21534d6
--- /dev/null
+++ b/webtools/bouncer/controllers/locales_controller.php
@@ -0,0 +1,6 @@
+
diff --git a/webtools/bouncer/controllers/mirrors_controller.php b/webtools/bouncer/controllers/mirrors_controller.php
new file mode 100644
index 000000000000..0d410b4269ed
--- /dev/null
+++ b/webtools/bouncer/controllers/mirrors_controller.php
@@ -0,0 +1,77 @@
+sanitize = &new Sanitize;
+ $this->show = empty($_GET['show'])? '10': $this->sanitize->sql($_GET['show']);
+ $this->sortBy = empty($_GET['sort'])? 'Mirror.mirror_id': $this->sanitize->sql($_GET['sort']);
+ $this->direction = empty($_GET['direction'])? 'desc': $this->sanitize->sql($_GET['direction']);
+ $this->page = empty($_GET['page'])? '1': $this->sanitize->sql($_GET['page']);
+ $this->order = $this->sortBy.' '.strtoupper($this->direction);
+ parent::__construct();
+ }
+
+ function index()
+ {
+ $data = $this->Mirror->findAll($criteria=null, $fields=null, $this->order, $this->show, $this->page);
+
+ $paging['style'] = 'html'; //set the style of the links: html or ajax
+
+ foreach ($this->Mirror->_tableInfo->value as $column) {
+
+ // If the sortBy is the same as the current link, we want to switch it.
+ // By default, we don't -- so that when a user changes columns, the order doesn't also reverse.
+ if ($this->sortBy == $column['name']) {
+ switch ($this->direction) {
+ case 'desc':
+ $link_direction = 'asc';
+ break;
+ case 'asc':
+ default:
+ $link_direction = 'desc';
+ break;
+ }
+ } else {
+ $link_direction =& $this->direction;
+ }
+ $paging['headers'][$column['name']] = $this->sanitize->html('/mirrors/?show='.$this->show.'&sort='.$column['name'].'&direction='.$link_direction.'&page='.$this->page);
+ }
+
+ $paging['link'] = $this->sanitize->html('./?show='.$this->show.'&sort='.$this->sortBy.'&direction='.$this->direction.'&page=');
+ $paging['count'] = $this->Mirror->findCount($criteria=null,'1000');
+ $paging['page'] = $this->page;
+ $paging['limit'] = $this->show;
+ $paging['show'] = array('10','25','50','100');
+
+ $this->set('paging',$paging);
+ $this->set('data',$data);
+ }
+
+ function view($id) {
+ $this->Mirror->setId($id);
+ $this->set('data', $this->Mirror->read());
+ }
+
+ function destroy($id) {
+ if (empty($this->params['data'])) {
+ $this->set('data', $this->Mirror->read());
+ $this->render();
+ } elseif ($this->Mirror->del($id)) {
+ $this->flash('Mirror '.$id.' has been deleted.', '/mirrors');
+ }
+ }
+}
+?>
diff --git a/webtools/bouncer/controllers/platforms_controller.php b/webtools/bouncer/controllers/platforms_controller.php
new file mode 100644
index 000000000000..1ee21ef40eee
--- /dev/null
+++ b/webtools/bouncer/controllers/platforms_controller.php
@@ -0,0 +1,6 @@
+
diff --git a/webtools/bouncer/controllers/regions_controller.php b/webtools/bouncer/controllers/regions_controller.php
new file mode 100644
index 000000000000..8d36c17d2a3e
--- /dev/null
+++ b/webtools/bouncer/controllers/regions_controller.php
@@ -0,0 +1,6 @@
+
diff --git a/webtools/bouncer/controllers/templates_controller.php b/webtools/bouncer/controllers/templates_controller.php
new file mode 100644
index 000000000000..abd14c7dbd20
--- /dev/null
+++ b/webtools/bouncer/controllers/templates_controller.php
@@ -0,0 +1,6 @@
+
diff --git a/webtools/bouncer/controllers/users_controller.php b/webtools/bouncer/controllers/users_controller.php
new file mode 100644
index 000000000000..3b5eccb2d93d
--- /dev/null
+++ b/webtools/bouncer/controllers/users_controller.php
@@ -0,0 +1,6 @@
+
diff --git a/webtools/bouncer/index.php b/webtools/bouncer/index.php
new file mode 100644
index 000000000000..bde636601a2e
--- /dev/null
+++ b/webtools/bouncer/index.php
@@ -0,0 +1,26 @@
+
+ * Copyright (c) 2006, 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 (c) 2006, Cake Software Foundation, Inc.
+ * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
+ * @package cake
+ * @subpackage cake.app
+ * @since CakePHP v 0.10.0.1076
+ * @version $Revision: 1.1 $
+ * @modifiedby $LastChangedBy: phpnut $
+ * @lastmodified $Date: 2006/06/09 18:14:09 $
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+require 'webroot' . DIRECTORY_SEPARATOR . 'index.php';
+?>
\ No newline at end of file
diff --git a/webtools/bouncer/models/file.php b/webtools/bouncer/models/file.php
new file mode 100644
index 000000000000..8666af07b785
--- /dev/null
+++ b/webtools/bouncer/models/file.php
@@ -0,0 +1,6 @@
+
diff --git a/webtools/bouncer/models/locale.php b/webtools/bouncer/models/locale.php
new file mode 100644
index 000000000000..0d6fe623805e
--- /dev/null
+++ b/webtools/bouncer/models/locale.php
@@ -0,0 +1,7 @@
+
diff --git a/webtools/bouncer/models/mirror.php b/webtools/bouncer/models/mirror.php
new file mode 100644
index 000000000000..a5598a2b8271
--- /dev/null
+++ b/webtools/bouncer/models/mirror.php
@@ -0,0 +1,15 @@
+
+ array( 'className' => 'Region',
+ 'joinTable' => 'mirror_region_map',
+ 'foreignKey' => 'mirror_id',
+ 'associationForeignKey' => 'region_id',
+ 'order' => 'region_name desc',
+ 'uniq' => true )
+ );
+}
+?>
diff --git a/webtools/bouncer/models/platform.php b/webtools/bouncer/models/platform.php
new file mode 100644
index 000000000000..8149efd7b7cb
--- /dev/null
+++ b/webtools/bouncer/models/platform.php
@@ -0,0 +1,7 @@
+
diff --git a/webtools/bouncer/models/region.php b/webtools/bouncer/models/region.php
new file mode 100644
index 000000000000..e53dde3c7abd
--- /dev/null
+++ b/webtools/bouncer/models/region.php
@@ -0,0 +1,7 @@
+
diff --git a/webtools/bouncer/models/template.php b/webtools/bouncer/models/template.php
new file mode 100644
index 000000000000..b3746885d82b
--- /dev/null
+++ b/webtools/bouncer/models/template.php
@@ -0,0 +1,7 @@
+
diff --git a/webtools/bouncer/models/user.php b/webtools/bouncer/models/user.php
new file mode 100644
index 000000000000..511f9b164e1e
--- /dev/null
+++ b/webtools/bouncer/models/user.php
@@ -0,0 +1,7 @@
+
diff --git a/webtools/bouncer/views/dashboard.thtml b/webtools/bouncer/views/dashboard.thtml
new file mode 100644
index 000000000000..0b00ef0da9bd
--- /dev/null
+++ b/webtools/bouncer/views/dashboard.thtml
@@ -0,0 +1,8 @@
+
Dashboard
+
+
Foo
+
Foo
+
Foo
+
Foo
+
Foo
+
Bar
diff --git a/webtools/bouncer/views/helpers/pagination.php b/webtools/bouncer/views/helpers/pagination.php
new file mode 100644
index 000000000000..2ba50583d77f
--- /dev/null
+++ b/webtools/bouncer/views/helpers/pagination.php
@@ -0,0 +1,211 @@
+link = $paging['link'];
+ $this->show = $paging['show'];
+ $this->page = $paging['page'];
+ $this->style = $paging['style'];
+
+ $pageCount = ceil($paging['count'] / $paging['limit'] );
+
+ $this->_pageDetails = array(
+ 'page'=>$paging['page'],
+ 'recordCount'=>$paging['count'],
+ 'pageCount' =>$pageCount,
+ 'nextPage'=> ($paging['page'] < $pageCount) ? $paging['page']+1 : '',
+ 'previousPage'=> ($paging['page']>1) ? $paging['page']-1 : '',
+ 'limit'=>$paging['limit']
+ );
+
+ return true;
+ }
+ return false;
+ }
+ /**
+ * Displays limits for the query
+ *
+ * @param string $text - text to display before limits
+ * @param string $separator - display a separate between limits
+ *
+ **/
+ function show($text=null, $separator=null)
+ {
+ if (empty($this->_pageDetails)) { return false; }
+ if ( !empty($this->_pageDetails['recordCount']) )
+ {
+ $t = '';
+ if(is_array($this->show))
+ {
+ $t = $text.$separator;
+ foreach($this->show as $value)
+ {
+ $link = preg_replace('/show=(.*?)&/','show='.$value.'&',$this->link);
+ if($this->_pageDetails['limit'] == $value)
+ {
+ $t .= ''.$value.''.$separator;
+ }
+ else
+ {
+ if($this->style == 'ajax')
+ {
+ $t .= $this->Ajax->linkToRemote($value, array("fallback"=>$this->action."#","url" => $link.$this->_pageDetails['page'],"update" => "ajax_update","method"=>"get")).$separator;
+ }
+ else
+ {
+ $t .= $this->Html->link($value,$link.$this->_pageDetails['page']).$separator;
+ }
+ }
+ }
+ }
+ return $t;
+ }
+ return false;
+
+ }
+ /**
+ * Displays current result information
+ *
+ * @param string $text - text to preceeding the number of results
+ *
+ **/
+ function result($text)
+ {
+ if (empty($this->_pageDetails)) { return false; }
+ if ( !empty($this->_pageDetails['recordCount']) )
+ {
+ if($this->_pageDetails['recordCount'] > $this->_pageDetails['limit'])
+ {
+ $start_row = $this->_pageDetails['page'] > 1 ? (($this->_pageDetails['page']-1)*$this->_pageDetails['limit'])+1:'1';
+ $end_row = ($this->_pageDetails['recordCount'] < ($start_row + $this->_pageDetails['limit']-1)) ? $this->_pageDetails['recordCount'] : ($start_row + $this->_pageDetails['limit']-1);
+ $t = $text.$start_row.'-'.$end_row.' of '.$this->_pageDetails['recordCount'];
+ }
+ else
+ {
+ $t = $text.$this->_pageDetails['recordCount'];
+ }
+ return $t;
+ }
+ return false;
+ }
+ /**
+ * Returns a "Google style" list of page numbers
+ *
+ * @param string $separator - defaults to null
+ * @param string $prefix - defaults to null. If set, displays prefix before page links.
+ * @param int $pageSetLength - defaults to 10. Maximum number of pages to show.
+ * @param string $prevLabel - defaults to null. If set, displays previous link.
+ * @param string $nextLabel - defaults to null. If set, displays next link.
+ *
+ **/
+ function pageNumbers($separator=null, $prefix=null, $pageSetLength=10, $prevLabel=null, $nextLabel=null)
+ {
+
+ if (empty($this->_pageDetails) || $this->_pageDetails['pageCount'] == 1) { return false; }
+
+ $t = array();
+
+ $modulo = $this->_pageDetails['page'] % $pageSetLength;
+ if ($modulo)
+ { // any number > 0
+ $prevSetLastPage = $this->_pageDetails['page'] - $modulo;
+ } else { // 0, last page of set
+ $prevSetLastPage = $this->_pageDetails['page'] - $pageSetLength;
+ }
+ //$nextSetFirstPage = $prevSetLastPage + $pageSetLength + 1;
+
+ if ($prevLabel) $t[] = $this->prevPage($prevLabel);
+
+ // loops through each page number
+ $pageSet = $prevSetLastPage + $pageSetLength;
+ if ($pageSet > $this->_pageDetails['pageCount']) $pageSet = $this->_pageDetails['pageCount'];
+ for ($pageIndex = $prevSetLastPage+1; $pageIndex <= $pageSet; $pageIndex++)
+ {
+ if ($pageIndex == $this->_pageDetails['page'])
+ {
+ $t[] = ''.$pageIndex.'';
+ }
+ else
+ {
+ if($this->style == 'ajax')
+ {
+ $t[] = $this->Ajax->linkToRemote($pageIndex, array("fallback"=>$this->action."#","url" =>$this->link.$pageIndex,"update" => "ajax_update","method"=>"get"));
+ } else {
+ $t[] = $this->Html->link($pageIndex,$this->link.$pageIndex);
+ }
+ }
+ }
+
+ if ($nextLabel) $t[] = $this->nextPage($nextLabel);
+
+ $t = implode($separator, $t);
+
+ return $prefix.$t;
+ }
+ /**
+ * Displays a link to the previous page, where the page doesn't exist then
+ * display the $text
+ *
+ * @param string $text - text display: defaults to next
+ *
+ **/
+ function prevPage($text='prev')
+ {
+ if (empty($this->_pageDetails)) { return false; }
+ if ( !empty($this->_pageDetails['previousPage']) )
+ {
+ if($this->style == 'ajax')
+ {
+ $t = $this->Ajax->linkToRemote($text, array("fallback"=>$this->action."#","url" => $this->link.$this->_pageDetails['previousPage'],"update" => "ajax_update","method"=>"get"));
+ }
+ else
+ {
+ $t = $this->Html->link($text,$this->link.$this->_pageDetails['previousPage']);
+ }
+ return $t;
+ }
+ return false;
+ }
+ /**
+ * Displays a link to the next page, where the page doesn't exist then
+ * display the $text
+ *
+ * @param string $text - text to display: defaults to next
+ *
+ **/
+ function nextPage($text='next')
+ {
+ if (empty($this->_pageDetails)) { return false; }
+ if (!empty($this->_pageDetails['nextPage']))
+ {
+ if($this->style == 'ajax')
+ {
+ $t = $this->Ajax->linkToRemote($text, array("fallback"=>$this->action."#","url" => $this->link.$this->_pageDetails['nextPage'],"update" => "ajax_update","method"=>"get"));
+ }
+ else
+ {
+ $t = $this->Html->link($text,$this->link.$this->_pageDetails['nextPage']);
+ }
+ return $t;
+ }
+ return false;
+ }
+
+}
+?>
diff --git a/webtools/bouncer/views/layouts/default.thtml b/webtools/bouncer/views/layouts/default.thtml
new file mode 100644
index 000000000000..9c52b5178800
--- /dev/null
+++ b/webtools/bouncer/views/layouts/default.thtml
@@ -0,0 +1,92 @@
+
+ * Copyright (c) 2005, 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 (c) 2005, Cake Software Foundation, Inc.
+ * @link http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
+ * @package cake
+ * @subpackage cake.cake.libs.view.templates.pages
+ * @since CakePHP v 0.10.0.1076
+ * @version $Revision: 1.1 $
+ * @modifiedby $LastChangedBy: phpnut $
+ * @lastmodified $Date: 2006/06/09 18:14:09 $
+ * @license http://www.opensource.org/licenses/mit-license.php The MIT License
+ */
+?>
+
+
+
+ :: Bouncer v2.0
+
+
+ charset('UTF-8')?>
+ css('bouncer.screen')?>
+ css('bouncer.print')?>
+
+
+
+ =$html->link('Edit',"/mirrors/edit/{$mirror['Mirror']['mirror_id']}",'class="action"')?>
+ =$html->link('Delete',"/mirrors/destroy/{$mirror['Mirror']['mirror_id']}",'class="action"','Are you sure you want to delete?')?>
+