diff --git a/app/console/shells/empty b/app/Console/Command/Task/empty similarity index 100% rename from app/console/shells/empty rename to app/Console/Command/Task/empty diff --git a/app/console/shells/tasks/empty b/app/Console/Command/empty similarity index 100% rename from app/console/shells/tasks/empty rename to app/Console/Command/empty diff --git a/app/console/cake b/app/Console/cake similarity index 100% rename from app/console/cake rename to app/Console/cake diff --git a/app/console/cake.bat b/app/Console/cake.bat similarity index 93% rename from app/console/cake.bat rename to app/Console/cake.bat index ed04546c9..7d0c1247d 100644 --- a/app/console/cake.bat +++ b/app/Console/cake.bat @@ -25,7 +25,7 @@ SET app=%0 SET lib=%~dp0 -php -q "%lib%cake.php" -working "%CD%" %* +php -q "%lib%cake.php" -working "%CD% " %* echo. diff --git a/app/console/cake.php b/app/Console/cake.php old mode 100755 new mode 100644 similarity index 86% rename from app/console/cake.php rename to app/Console/cake.php index 9200fd36b..ef5e26816 --- a/app/console/cake.php +++ b/app/Console/cake.php @@ -19,6 +19,6 @@ * @since CakePHP(tm) v 1.2.0.5012 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once(dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'cake' . DIRECTORY_SEPARATOR . 'console' . DIRECTORY_SEPARATOR . 'shell_dispatcher.php'); +require_once(dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'lib'. DIRECTORY_SEPARATOR . 'Cake' . DIRECTORY_SEPARATOR . 'Console' . DIRECTORY_SEPARATOR . 'ShellDispatcher.php'); return ShellDispatcher::run($argv); diff --git a/app/console/shells/templates/empty b/app/Console/templates/empty similarity index 100% rename from app/console/shells/templates/empty rename to app/Console/templates/empty diff --git a/app/controllers/components/empty b/app/Controller/Component/empty similarity index 100% rename from app/controllers/components/empty rename to app/Controller/Component/empty diff --git a/app/libs/empty b/app/Lib/empty similarity index 100% rename from app/libs/empty rename to app/Lib/empty diff --git a/app/models/behaviors/empty b/app/Model/Behavior/empty similarity index 100% rename from app/models/behaviors/empty rename to app/Model/Behavior/empty diff --git a/app/models/datasources/empty b/app/Model/Datasource/empty similarity index 100% rename from app/models/datasources/empty rename to app/Model/Datasource/empty diff --git a/app/tests/cases/behaviors/empty b/app/View/Helper/empty similarity index 100% rename from app/tests/cases/behaviors/empty rename to app/View/Helper/empty diff --git a/app/tests/cases/components/empty b/app/View/elements/email/html/empty similarity index 100% rename from app/tests/cases/components/empty rename to app/View/elements/email/html/empty diff --git a/app/tests/cases/controllers/empty b/app/View/elements/email/text/empty similarity index 100% rename from app/tests/cases/controllers/empty rename to app/View/elements/email/text/empty diff --git a/app/tests/cases/helpers/empty b/app/View/elements/empty similarity index 100% rename from app/tests/cases/helpers/empty rename to app/View/elements/empty diff --git a/app/tests/cases/models/empty b/app/View/errors/empty similarity index 100% rename from app/tests/cases/models/empty rename to app/View/errors/empty diff --git a/app/tests/fixtures/empty b/app/View/layouts/email/html/empty similarity index 100% rename from app/tests/fixtures/empty rename to app/View/layouts/email/html/empty diff --git a/app/tests/groups/empty b/app/View/layouts/email/text/empty similarity index 100% rename from app/tests/groups/empty rename to app/View/layouts/email/text/empty diff --git a/app/views/elements/email/html/empty b/app/View/layouts/js/empty similarity index 100% rename from app/views/elements/email/html/empty rename to app/View/layouts/js/empty diff --git a/app/views/elements/email/text/empty b/app/View/layouts/rss/empty similarity index 100% rename from app/views/elements/email/text/empty rename to app/View/layouts/rss/empty diff --git a/app/views/elements/empty b/app/View/layouts/xml/empty similarity index 100% rename from app/views/elements/empty rename to app/View/layouts/xml/empty diff --git a/app/views/errors/empty b/app/View/pages/empty similarity index 100% rename from app/views/errors/empty rename to app/View/pages/empty diff --git a/app/views/helpers/empty b/app/View/scaffolds/empty similarity index 100% rename from app/views/helpers/empty rename to app/View/scaffolds/empty diff --git a/app/config/bootstrap.php b/app/config/bootstrap.php index ceeb85670..0865ac4fc 100644 --- a/app/config/bootstrap.php +++ b/app/config/bootstrap.php @@ -1,9 +1,12 @@ 'File')); + /** * 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) * * App::build(array( * 'plugins' => array('/full/path/to/plugins/', '/next/full/path/to/plugins/'), diff --git a/app/config/core.php b/app/config/core.php index 9744da06c..3a7613b85 100644 --- a/app/config/core.php +++ b/app/config/core.php @@ -283,4 +283,40 @@ * )); * */ - Cache::config('default', array('engine' => 'File')); + +// Pick the caching engine to use. If APC is enabled use it. +$engine = 'File'; +if (extension_loaded('apc')) { + $engine = 'Apc'; +} + +// In development mode, caches should expire quickly. +$duration = '+999 days'; +if (Configure::read('debug') >= 1) { + $duration = '+10 seconds'; +} + +/** + * Configure the cache used for general framework caching. Path information, + * object listings, and translation cache files are stored with this configuration. + */ +Cache::config('_cake_core_', array( + 'engine' => $engine, + 'prefix' => 'cake_core_', + 'path' => CACHE . 'persistent' . DS, + 'serialize' => ($engine === 'File'), + 'duration' => $duration +)); + +/** + * Configure the cache for model, and datasource caches. This cache configuration + * is used to store schema descriptions, and table listings in connections. + */ +Cache::config('_cake_model_', array( + 'engine' => $engine, + 'prefix' => 'cake_model_', + 'path' => CACHE . 'models' . DS, + 'serialize' => ($engine === 'File'), + 'duration' => $duration +)); + diff --git a/app/config/database.php.default b/app/config/database.php.default index 2078240ea..b7eb4bba2 100644 --- a/app/config/database.php.default +++ b/app/config/database.php.default @@ -28,40 +28,38 @@ * You can specify multiple configurations for production, development and testing. * * driver => The name of a supported driver; valid options are as follows: - * mysql - MySQL 4 & 5, - * mysqli - MySQL 4 & 5 Improved Interface (PHP5 only), - * sqlite - SQLite (PHP5 only), - * postgres - PostgreSQL 7 and higher, - * mssql - Microsoft SQL Server 2000 and higher, - * oracle - Oracle 8 and higher + * Datasabe/Mysql - MySQL 4 & 5, + * Datasabe/Sqlite - SQLite (PHP5 only), + * Datasabe/Postgres - PostgreSQL 7 and higher, + * Datasabe/Mssql - Microsoft SQL Server 2000 and higher, + * Datasabe/Oracle - Oracle 8 and higher * * You can add custom database drivers (or override existing drivers) by adding the - * appropriate file to app/models/datasources/dbo. Drivers should be named 'dbo_x.php', - * where 'x' is the name of the database. + * appropriate file to app/models/datasources/database. Drivers should be named 'MyDriver.php', + * * * persistent => true / false * Determines whether or not the database should use a persistent connection * * host => - * the host you connect to the database. To add a socket or port number, use 'port' => # + * the host you connect to the database. To add a socket or port number, use 'port' => # * * prefix => * Uses the given prefix for all the tables in this database. This setting can be overridden * on a per-table basis with the Model::$tablePrefix property. * * schema => - * For Postgresspecifies which schema you would like to use the tables in. Postgres defaults to - * 'public', DB2 defaults to empty. + * For Postgres specifies which schema you would like to use the tables in. Postgres defaults to 'public'. * * encoding => - * For MySQL, MySQLi, Postgres specifies the character encoding to use when connecting to the - * database. Uses database default. + * For MySQL, Postgres specifies the character encoding to use when connecting to the + * database. Uses database default not specified. * */ class DATABASE_CONFIG { public $default = array( - 'driver' => 'mysql', + 'datasource' => 'Database/Mysql', 'persistent' => false, 'host' => 'localhost', 'login' => 'user', @@ -71,7 +69,7 @@ class DATABASE_CONFIG { ); public $test = array( - 'driver' => 'mysql', + 'datasource' => 'Database/Mysql', 'persistent' => false, 'host' => 'localhost', 'login' => 'user', diff --git a/app/config/schema/db_acl.php b/app/config/schema/db_acl.php index 25b6ee6df..25ed49204 100644 --- a/app/config/schema/db_acl.php +++ b/app/config/schema/db_acl.php @@ -27,15 +27,6 @@ */ class DbAclSchema extends CakeSchema { - public $name = 'DbAcl'; - - function before($event = array()) { - return true; - } - - function after($event = array()) { - } - public $acos = array( 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'), 'parent_id' => array('type'=>'integer', 'null' => true, 'default' => NULL, 'length' => 10), diff --git a/app/config/schema/i18n.php b/app/config/schema/i18n.php index f57bbce7f..7776dbcd0 100644 --- a/app/config/schema/i18n.php +++ b/app/config/schema/i18n.php @@ -27,15 +27,6 @@ */ class i18nSchema extends CakeSchema { - public $name = 'i18n'; - - function before($event = array()) { - return true; - } - - function after($event = array()) { - } - public $i18n = array( 'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'length' => 10, 'key' => 'primary'), 'locale' => array('type'=>'string', 'null' => false, 'length' => 6, 'key' => 'index'), diff --git a/app/config/schema/sessions.php b/app/config/schema/sessions.php index e5ae37dc1..6304317f9 100644 --- a/app/config/schema/sessions.php +++ b/app/config/schema/sessions.php @@ -27,15 +27,6 @@ */ class SessionsSchema extends CakeSchema { - public $name = 'Sessions'; - - function before($event = array()) { - return true; - } - - function after($event = array()) { - } - public $cake_sessions = array( 'id' => array('type'=>'string', 'null' => false, 'key' => 'primary'), 'data' => array('type'=>'text', 'null' => true, 'default' => NULL), diff --git a/app/views/layouts/email/html/empty b/app/tests/Case/Controller/Component/empty similarity index 100% rename from app/views/layouts/email/html/empty rename to app/tests/Case/Controller/Component/empty diff --git a/app/views/layouts/email/text/empty b/app/tests/Case/Controller/empty similarity index 100% rename from app/views/layouts/email/text/empty rename to app/tests/Case/Controller/empty diff --git a/app/views/layouts/js/empty b/app/tests/Case/Model/Behavior/empty similarity index 100% rename from app/views/layouts/js/empty rename to app/tests/Case/Model/Behavior/empty diff --git a/app/views/layouts/rss/empty b/app/tests/Case/Model/empty similarity index 100% rename from app/views/layouts/rss/empty rename to app/tests/Case/Model/empty diff --git a/app/views/layouts/xml/empty b/app/tests/Case/View/Helper/empty similarity index 100% rename from app/views/layouts/xml/empty rename to app/tests/Case/View/Helper/empty diff --git a/app/views/pages/empty b/app/tests/Fixture/empty similarity index 100% rename from app/views/pages/empty rename to app/tests/Fixture/empty diff --git a/app/tmp/cache/models/empty b/app/tmp/cache/models/empty old mode 100755 new mode 100644 diff --git a/app/tmp/cache/views/empty b/app/tmp/cache/views/empty old mode 100755 new mode 100644 diff --git a/app/tmp/logs/empty b/app/tmp/logs/empty old mode 100755 new mode 100644 diff --git a/app/tmp/sessions/empty b/app/tmp/sessions/empty old mode 100755 new mode 100644 diff --git a/app/tmp/tests/empty b/app/tmp/tests/empty old mode 100755 new mode 100644 diff --git a/app/webroot/.htaccess b/app/webroot/.htaccess index f9d8b938b..8e7f16397 100644 --- a/app/webroot/.htaccess +++ b/app/webroot/.htaccess @@ -2,5 +2,5 @@ RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^(.*)$ index.php?url=$1 [QSA,L] + RewriteRule ^(.*)$ index.php/$1 [QSA,L] \ No newline at end of file diff --git a/app/webroot/index.php b/app/webroot/index.php index 5955688f6..3c5e71589 100644 --- a/app/webroot/index.php +++ b/app/webroot/index.php @@ -49,7 +49,7 @@ * */ if (!defined('CAKE_CORE_INCLUDE_PATH')) { - define('CAKE_CORE_INCLUDE_PATH', ROOT); + define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); } /** @@ -67,13 +67,14 @@ define('APP_PATH', ROOT . DS . APP_DIR . DS); define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); } - if (!include(CORE_PATH . 'cake' . DS . 'bootstrap.php')) { + if (!include(CORE_PATH . 'Cake' . DS . 'bootstrap.php')) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } - if (isset($_GET['url']) && $_GET['url'] === 'favicon.ico') { + + if (isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] == '/favicon.ico') { return; - } else { - require LIBS . 'dispatcher.php'; - $Dispatcher = new Dispatcher(); - $Dispatcher->dispatch(new CakeRequest(isset($_GET['url']) ? $_GET['url'] : null)); } + + App::uses('Dispatcher', 'Routing'); + $Dispatcher = new Dispatcher(); + $Dispatcher->dispatch(new CakeRequest()); diff --git a/app/webroot/test.php b/app/webroot/test.php index eddcc437f..ffcedfe39 100644 --- a/app/webroot/test.php +++ b/app/webroot/test.php @@ -45,11 +45,11 @@ ini_set('display_errors', 1); define('APP_DIR', basename(dirname(dirname(__FILE__)))); } /** - * The absolute path to the "cake" directory, WITHOUT a trailing DS. + * The absolute path to the "Cake" directory, WITHOUT a trailing DS. * */ if (!defined('CAKE_CORE_INCLUDE_PATH')) { - define('CAKE_CORE_INCLUDE_PATH', ROOT); + define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); } /** @@ -67,21 +67,14 @@ if (!defined('CORE_PATH')) { define('APP_PATH', ROOT . DS . APP_DIR . DS); define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); } -if (!include(CORE_PATH . 'cake' . DS . 'bootstrap.php')) { +if (!include(CORE_PATH . 'Cake' . DS . 'bootstrap.php')) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } -$corePath = App::core('cake'); -if (isset($corePath[0])) { - define('TEST_CAKE_CORE_INCLUDE_PATH', rtrim($corePath[0], DS) . DS); -} else { - define('TEST_CAKE_CORE_INCLUDE_PATH', CAKE_CORE_INCLUDE_PATH); -} - if (Configure::read('debug') < 1) { - die(__('Debug setting does not allow access to this url.', true)); + die(__d('cake', 'Debug setting does not allow access to this url.')); } -require_once CAKE_TESTS_LIB . 'cake_test_suite_dispatcher.php'; +require_once CAKE_TESTS_LIB . 'CakeTestSuiteDispatcher.php'; CakeTestSuiteDispatcher::run(); diff --git a/cake/bootstrap.php b/cake/bootstrap.php deleted file mode 100644 index 65931eb39..000000000 --- a/cake/bootstrap.php +++ /dev/null @@ -1,38 +0,0 @@ - array('suffix' => '.php', 'extends' => null, 'core' => true), - 'file' => array('suffix' => '.php', 'extends' => null, 'core' => true), - 'model' => array('suffix' => '.php', 'extends' => 'AppModel', 'core' => false), - 'behavior' => array('suffix' => '.php', 'extends' => 'ModelBehavior', 'core' => true), - 'controller' => array('suffix' => '_controller.php', 'extends' => 'AppController', 'core' => true), - 'component' => array('suffix' => '.php', 'extends' => null, 'core' => true), - 'lib' => array('suffix' => '.php', 'extends' => null, 'core' => true), - 'view' => array('suffix' => '.php', 'extends' => null, 'core' => true), - 'helper' => array('suffix' => '.php', 'extends' => 'AppHelper', 'core' => true), - 'vendor' => array('suffix' => '', 'extends' => null, 'core' => true), - 'shell' => array('suffix' => '.php', 'extends' => 'Shell', 'core' => true), - 'plugin' => array('suffix' => '', 'extends' => null, 'core' => true) - ); - -/** - * List of additional path(s) where model files reside. - * - * @var array - */ - public static $models = array(); - -/** - * List of additional path(s) where behavior files reside. - * - * @var array - */ - public static $behaviors = array(); - -/** - * List of additional path(s) where controller files reside. - * - * @var array - */ - public static $controllers = array(); - -/** - * List of additional path(s) where component files reside. - * - * @var array - */ - public static $components = array(); - -/** - * List of additional path(s) where datasource files reside. - * - * @var array - */ - public static $datasources = array(); - -/** - * List of additional path(s) where libs files reside. - * - * @var array - */ - public static $libs = array(); - -/** - * List of additional path(s) where view files reside. - * - * @var array - */ - public static $views = array(); - -/** - * List of additional path(s) where helper files reside. - * - * @var array - */ - public static $helpers = array(); - -/** - * List of additional path(s) where plugins reside. - * - * @var array - */ - public static $plugins = array(); - -/** - * List of additional path(s) where vendor packages reside. - * - * @var array - */ - public static $vendors = array(); - -/** - * List of additional path(s) where locale files reside. - * - * @var array - */ - public static $locales = array(); - -/** - * List of additional path(s) where console shell files reside. - * - * @var array - */ - public static $shells = array(); - -/** - * Paths to search for files. - * - * @var array - */ - public static $search = array(); - -/** - * Whether or not to return the file that is loaded. - * - * @var boolean - */ - public static $return = false; - -/** - * Determines if $__maps and $__paths cache should be written. - * - * @var boolean - */ - private static $__cache = false; - -/** - * Holds key/value pairs of $type => file path. - * - * @var array - */ - private static $__map = array(); - -/** - * Holds paths for deep searching of files. - * - * @var array - */ - private static $__paths = array(); - -/** - * Holds loaded files. - * - * @var array - */ - private static $__loaded = array(); - -/** - * Holds and key => value array of object types. - * - * @var array - */ - private static $__objects = array(); - -/** - * Used to read information stored path - * - * Usage: - * - * `App::path('models'); will return all paths for models` - * - * @param string $type type of path - * @return string array - */ - public static function path($type) { - if (!isset(self::${$type})) { - return array(); - } - return self::${$type}; - } - -/** - * Build path references. Merges the supplied $paths - * with the base paths and the default core paths. - * - * @param array $paths paths defines in config/bootstrap.php - * @param boolean $reset true will set paths, false merges paths [default] false - * @return void - */ - public static function build($paths = array(), $reset = false) { - $defaults = array( - 'models' => array(MODELS), - 'behaviors' => array(BEHAVIORS), - 'datasources' => array(MODELS . 'datasources'), - 'controllers' => array(CONTROLLERS), - 'components' => array(COMPONENTS), - 'libs' => array(APPLIBS), - 'views' => array(VIEWS), - 'helpers' => array(HELPERS), - 'locales' => array(APP . 'locale' . DS), - 'shells' => array( - APP . 'console' . DS . 'shells' . DS, - APP . 'vendors' . DS . 'shells' . DS, - VENDORS . 'shells' . DS - ), - 'vendors' => array(APP . 'vendors' . DS, VENDORS), - 'plugins' => array(APP . 'plugins' . DS) - ); - - if ($reset == true) { - foreach ($paths as $type => $new) { - self::${$type} = (array)$new; - } - return $paths; - } - - $core = self::core(); - $app = array('models' => true, 'controllers' => true, 'helpers' => true); - - foreach ($defaults as $type => $default) { - $merge = array(); - - if (isset($app[$type])) { - $merge = array(APP); - } - if (isset($core[$type])) { - $merge = array_merge($merge, (array)$core[$type]); - } - - if (empty(self::${$type}) || empty($paths)) { - self::${$type} = $default; - } - - if (!empty($paths[$type])) { - $path = array_flip(array_flip(array_merge( - (array)$paths[$type], self::${$type}, $merge - ))); - self::${$type} = array_values($path); - } else { - $path = array_flip(array_flip(array_merge(self::${$type}, $merge))); - self::${$type} = array_values($path); - } - } - } - -/** - * Get the path that a plugin is on. Searches through the defined plugin paths. - * - * @param string $plugin CamelCased/lower_cased plugin name to find the path of. - * @return string full path to the plugin. - */ - public static function pluginPath($plugin) { - $pluginDir = Inflector::underscore($plugin); - for ($i = 0, $length = count(self::$plugins); $i < $length; $i++) { - if (is_dir(self::$plugins[$i] . $pluginDir)) { - return self::$plugins[$i] . $pluginDir . DS ; - } - } - return self::$plugins[0] . $pluginDir . DS; - } - -/** - * Find the path that a theme is on. Search through the defined theme paths. - * - * @param string $theme lower_cased theme name to find the path of. - * @return string full path to the theme. - */ - public static function themePath($theme) { - $themeDir = 'themed' . DS . Inflector::underscore($theme); - for ($i = 0, $length = count(self::$views); $i < $length; $i++) { - if (is_dir(self::$views[$i] . $themeDir)) { - return self::$views[$i] . $themeDir . DS ; - } - } - return self::$views[0] . $themeDir . DS; - } - -/** - * Returns a key/value list of all paths where core libs are found. - * Passing $type only returns the values for a given value of $key. - * - * @param string $type valid values are: 'model', 'behavior', 'controller', 'component', - * 'view', 'helper', 'datasource', 'libs', and 'cake' - * @return array numeric keyed array of core lib paths - */ - public static function core($type = null) { - static $paths = false; - if (!$paths) { - $paths = array(); - $libs = dirname(__FILE__) . DS; - $cake = dirname($libs) . DS; - $path = dirname($cake) . DS; - - $paths['cake'][] = $cake; - $paths['libs'][] = $libs; - $paths['models'][] = $libs . 'model' . DS; - $paths['datasources'][] = $libs . 'model' . DS . 'datasources' . DS; - $paths['behaviors'][] = $libs . 'model' . DS . 'behaviors' . DS; - $paths['controllers'][] = $libs . 'controller' . DS; - $paths['components'][] = $libs . 'controller' . DS . 'components' . DS; - $paths['views'][] = $libs . 'view' . DS; - $paths['helpers'][] = $libs . 'view' . DS . 'helpers' . DS; - $paths['plugins'][] = $path . 'plugins' . DS; - $paths['vendors'][] = $path . 'vendors' . DS; - $paths['shells'][] = $cake . 'console' . DS . 'shells' . DS; - // Provide BC path to vendors/shells - $paths['shells'][] = $path . 'vendors' . DS . 'shells' . DS; - } - if ($type && isset($paths[$type])) { - return $paths[$type]; - } - return $paths; - } - -/** - * Returns an array of objects of the given type. - * - * Example usage: - * - * `App::objects('plugin');` returns `array('DebugKit', 'Blog', 'User');` - * - * @param string $type Type of object, i.e. 'model', 'controller', 'helper', or 'plugin' - * @param mixed $path Optional Scan only the path given. If null, paths for the chosen - * type will be used. - * @param boolean $cache Set to false to rescan objects of the chosen type. Defaults to true. - * @return mixed Either false on incorrect / miss. Or an array of found objects. - */ - public static function objects($type, $path = null, $cache = true) { - $objects = array(); - $extension = false; - $name = $type; - - if ($type === 'file' && !$path) { - return false; - } elseif ($type === 'file') { - $extension = true; - $name = $type . str_replace(DS, '', $path); - } - - if (empty(self::$__objects) && $cache === true) { - self::$__objects = Cache::read('object_map', '_cake_core_'); - } - - if (!isset(self::$__objects[$name]) || $cache !== true) { - $types = self::$types; - - if (!isset($types[$type])) { - return false; - } - $objects = array(); - - if (empty($path)) { - $path = self::${"{$type}s"}; - if (isset($types[$type]['core']) && $types[$type]['core'] === false) { - array_pop($path); - } - } - $items = array(); - - foreach ((array)$path as $dir) { - if ($dir != APP) { - $items = self::__list($dir, $types[$type]['suffix'], $extension); - $objects = array_merge($items, array_diff($objects, $items)); - } - } - - if ($type !== 'file') { - foreach ($objects as $key => $value) { - $objects[$key] = Inflector::camelize($value); - } - } - - if ($cache === true) { - self::$__cache = true; - } - self::$__objects[$name] = $objects; - } - - return self::$__objects[$name]; - } - -/** - * Allows you to modify the object listings that App maintains inside of it - * Useful for testing - * - * @param string $type Type of object listing you are changing - * @param array $values The values $type should be set to. - * @return void - */ - public static function setObjects($type, $values) { - self::$__objects[$type] = $values; - } - -/** - * Finds classes based on $name or specific file(s) to search. Calling App::import() will - * not construct any classes contained in the files. It will only find and require() the file. - * - * @link http://book.cakephp.org/view/934/Using-App-import - * @param mixed $type The type of Class if passed as a string, or all params can be passed as - * an single array to $type, - * @param string $name Name of the Class or a unique name for the file - * @param mixed $parent boolean true if Class Parent should be searched, accepts key => value - * array('parent' => $parent ,'file' => $file, 'search' => $search, 'ext' => '$ext'); - * $ext allows setting the extension of the file name - * based on Inflector::underscore($name) . ".$ext"; - * @param array $search paths to search for files, array('path 1', 'path 2', 'path 3'); - * @param string $file full name of the file to search for including extension - * @param boolean $return, return the loaded file, the file must have a return - * statement in it to work: return $variable; - * @return boolean true if Class is already in memory or if file is found and loaded, false if not - */ - public static function import($type = null, $name = null, $parent = true, $search = array(), $file = null, $return = false) { - $plugin = $directory = null; - - if (is_array($type)) { - extract($type, EXTR_OVERWRITE); - } - - if (is_array($parent)) { - extract($parent, EXTR_OVERWRITE); - } - - if ($name === null && $file === null) { - $name = $type; - $type = 'Core'; - } elseif ($name === null) { - $type = 'File'; - } - - if (is_array($name)) { - foreach ($name as $class) { - $tempType = $type; - $plugin = null; - - if (strpos($class, '.') !== false) { - $value = explode('.', $class); - $count = count($value); - - if ($count > 2) { - $tempType = $value[0]; - $plugin = $value[1] . '.'; - $class = $value[2]; - } elseif ($count === 2 && ($type === 'Core' || $type === 'File')) { - $tempType = $value[0]; - $class = $value[1]; - } else { - $plugin = $value[0] . '.'; - $class = $value[1]; - } - } - - if (!App::import($tempType, $plugin . $class, $parent)) { - return false; - } - } - return true; - } - - if ($name != null && strpos($name, '.') !== false) { - list($plugin, $name) = explode('.', $name); - $plugin = Inflector::camelize($plugin); - } - self::$return = $return; - - if (isset($ext)) { - $file = Inflector::underscore($name) . ".{$ext}"; - } - $ext = self::__settings($type, $plugin, $parent); - $className = $name; - if (strpos($className, '/') !== false) { - $className = substr($className, strrpos($className, '/') + 1); - } - if ($name != null && !class_exists($className . $ext['class'])) { - if ($load = self::__mapped($name . $ext['class'], $type, $plugin)) { - if (self::__load($load)) { - if (self::$return) { - return include($load); - } - return true; - } else { - self::__remove($name . $ext['class'], $type, $plugin); - self::$__cache = true; - } - } - if (!empty($search)) { - self::$search = $search; - } elseif ($plugin) { - self::$search = self::__paths('plugin'); - } else { - self::$search = self::__paths($type); - } - $find = $file; - - if ($find === null) { - $find = Inflector::underscore($name . $ext['suffix']).'.php'; - - if ($plugin) { - $paths = self::$search; - foreach ($paths as $key => $value) { - self::$search[$key] = $value . $ext['path']; - } - } - } - - if (strtolower($type) !== 'vendor' && empty($search) && self::__load($file)) { - $directory = false; - } else { - $file = $find; - $directory = self::__find($find, true); - } - - if ($directory !== null) { - self::$__cache = true; - self::__map($directory . $file, $name . $ext['class'], $type, $plugin); - - if (self::$return) { - return include($directory . $file); - } - return true; - } - return false; - } - return true; - } - -/** - * Initializes the cache for App, registers a shutdown function. - * - * @return void - */ - public static function init() { - self::$__map = (array)Cache::read('file_map', '_cake_core_'); - register_shutdown_function(array('App', 'shutdown')); - } - -/** - * Locates the $file in $__paths, searches recursively. - * - * @param string $file full file name - * @param boolean $recursive search $__paths recursively - * @return mixed boolean on fail, $file directory path on success - */ - private static function __find($file, $recursive = true) { - static $appPath = false; - - if (empty(self::$search)) { - return null; - } elseif (is_string(self::$search)) { - $this->search = array(self::$search); - } - - if (empty(self::$__paths)) { - self::$__paths = Cache::read('dir_map', '_cake_core_'); - } - - foreach (self::$search as $path) { - if ($appPath === false) { - $appPath = rtrim(APP, DS); - } - $path = rtrim($path, DS); - - if ($path === $appPath) { - $recursive = false; - } - if ($recursive === false) { - if (self::__load($path . DS . $file)) { - return $path . DS; - } - continue; - } - - if (!isset(self::$__paths[$path])) { - if (!class_exists('Folder')) { - require LIBS . 'folder.php'; - } - $Folder = new Folder(); - $directories = $Folder->tree($path, array('.svn', '.git', 'CVS', 'tests', 'templates'), 'dir'); - sort($directories); - self::$__paths[$path] = $directories; - } - - foreach (self::$__paths[$path] as $directory) { - if (self::__load($directory . DS . $file)) { - return $directory . DS; - } - } - } - return null; - } - -/** - * Attempts to load $file. - * - * @param string $file full path to file including file name - * @return boolean - * @access private - */ - private static function __load($file) { - if (empty($file)) { - return false; - } - if (!self::$return && isset(self::$__loaded[$file])) { - return true; - } - if (file_exists($file)) { - if (!self::$return) { - require($file); - self::$__loaded[$file] = true; - } - return true; - } - return false; - } - -/** - * Maps the $name to the $file. - * - * @param string $file full path to file - * @param string $name unique name for this map - * @param string $type type object being mapped - * @param string $plugin camelized if object is from a plugin, the name of the plugin - * @return void - * @access private - */ - private static function __map($file, $name, $type, $plugin) { - if ($plugin) { - self::$__map['Plugin'][$plugin][$type][$name] = $file; - } else { - self::$__map[$type][$name] = $file; - } - } - -/** - * Returns a file's complete path. - * - * @param string $name unique name - * @param string $type type object - * @param string $plugin camelized if object is from a plugin, the name of the plugin - * @return mixed, file path if found, false otherwise - * @access private - */ - private static function __mapped($name, $type, $plugin) { - if ($plugin) { - if (isset(self::$__map['Plugin'][$plugin][$type]) && isset(self::$__map['Plugin'][$plugin][$type][$name])) { - return self::$__map['Plugin'][$plugin][$type][$name]; - } - return false; - } - - if (isset(self::$__map[$type]) && isset(self::$__map[$type][$name])) { - return self::$__map[$type][$name]; - } - return false; - } - -/** - * Loads parent classes based on $type. - * Returns a prefix or suffix needed for loading files. - * - * @param string $type type of object - * @param string $plugin camelized name of plugin - * @param boolean $parent false will not attempt to load parent - * @return array - * @access private - */ - private static function __settings($type, $plugin, $parent) { - if (!$parent) { - return array('class' => null, 'suffix' => null, 'path' => null); - } - - if ($plugin) { - $pluginPath = Inflector::underscore($plugin); - } - $path = null; - $load = strtolower($type); - - switch ($load) { - case 'model': - if (!class_exists('Model')) { - require LIBS . 'model' . DS . 'model.php'; - } - if (!class_exists('AppModel')) { - App::import($type, 'AppModel', false); - } - if ($plugin) { - if (!class_exists($plugin . 'AppModel')) { - App::import($type, $plugin . '.' . $plugin . 'AppModel', false, array(), $pluginPath . DS . $pluginPath . '_app_model.php'); - } - $path = $pluginPath . DS . 'models' . DS; - } - return array('class' => null, 'suffix' => null, 'path' => $path); - break; - case 'behavior': - if ($plugin) { - $path = $pluginPath . DS . 'models' . DS . 'behaviors' . DS; - } - return array('class' => $type, 'suffix' => null, 'path' => $path); - break; - case 'datasource': - if ($plugin) { - $path = $pluginPath . DS . 'models' . DS . 'datasources' . DS; - } - return array('class' => $type, 'suffix' => null, 'path' => $path); - case 'controller': - App::import($type, 'AppController', false); - if ($plugin) { - App::import($type, $plugin . '.' . $plugin . 'AppController', false, array(), $pluginPath . DS . $pluginPath . '_app_controller.php'); - $path = $pluginPath . DS . 'controllers' . DS; - } - return array('class' => $type, 'suffix' => $type, 'path' => $path); - break; - case 'component': - App::import('Core', 'Component', false); - if ($plugin) { - $path = $pluginPath . DS . 'controllers' . DS . 'components' . DS; - } - return array('class' => $type, 'suffix' => null, 'path' => $path); - break; - case 'lib': - if ($plugin) { - $path = $pluginPath . DS . 'libs' . DS; - } - return array('class' => null, 'suffix' => null, 'path' => $path); - break; - case 'view': - App::import('View', 'View', false); - if ($plugin) { - $path = $pluginPath . DS . 'views' . DS; - } - return array('class' => $type, 'suffix' => null, 'path' => $path); - break; - case 'helper': - if (!class_exists('AppHelper')) { - App::import($type, 'AppHelper', false); - } - if ($plugin) { - $path = $pluginPath . DS . 'views' . DS . 'helpers' . DS; - } - return array('class' => $type, 'suffix' => null, 'path' => $path); - break; - case 'shell': - if (!class_exists('Shell')) { - App::import($type, 'Shell', false); - } - if (!class_exists('AppShell')) { - App::import($type, 'AppShell', false); - } - if ($plugin) { - $path = $pluginPath . DS . 'console' . DS . 'shells' . DS; - } - return array('class' => $type, 'suffix' => null, 'path' => $path); - break; - case 'vendor': - if ($plugin) { - $path = $pluginPath . DS . 'vendors' . DS; - } - return array('class' => null, 'suffix' => null, 'path' => $path); - break; - default: - $type = $suffix = $path = null; - break; - } - return array('class' => null, 'suffix' => null, 'path' => null); - } - -/** - * Returns default search paths. - * - * @param string $type type of object to be searched - * @return array list of paths - */ - private static function __paths($type) { - $type = strtolower($type); - $paths = array(); - - if ($type === 'core') { - return App::core('libs'); - } - if (isset(self::${$type . 's'})) { - return self::${$type . 's'}; - } - return $paths; - } - -/** - * Removes file location from map if the file has been deleted. - * - * @param string $name name of object - * @param string $type type of object - * @param string $plugin camelized name of plugin - * @return void - */ - private static function __remove($name, $type, $plugin) { - if ($plugin) { - unset(self::$__map['Plugin'][$plugin][$type][$name]); - } else { - unset(self::$__map[$type][$name]); - } - } - -/** - * Returns an array of filenames of PHP files in the given directory. - * - * @param string $path Path to scan for files - * @param string $suffix if false, return only directories. if string, match and return files - * @return array List of directories or files in directory - */ - private static function __list($path, $suffix = false, $extension = false) { - if (!class_exists('Folder')) { - require LIBS . 'folder.php'; - } - $items = array(); - $Folder = new Folder($path); - $contents = $Folder->read(false, true); - - if (is_array($contents)) { - if (!$suffix) { - return $contents[0]; - } else { - foreach ($contents[1] as $item) { - if (substr($item, - strlen($suffix)) === $suffix) { - if ($extension) { - $items[] = $item; - } else { - $items[] = substr($item, 0, strlen($item) - strlen($suffix)); - } - } - } - } - } - return $items; - } - -/** - * Object destructor. - * - * Writes cache file if changes have been made to the $__map or $__paths - * - * @return void - */ - public static function shutdown() { - if (self::$__cache) { - $core = App::core('cake'); - unset(self::$__paths[rtrim($core[0], DS)]); - Cache::write('dir_map', array_filter(self::$__paths), '_cake_core_'); - Cache::write('file_map', array_filter(self::$__map), '_cake_core_'); - Cache::write('object_map', self::$__objects, '_cake_core_'); - } - } -} diff --git a/cake/libs/controller/components/auth.php b/cake/libs/controller/components/auth.php deleted file mode 100644 index 063960f91..000000000 --- a/cake/libs/controller/components/auth.php +++ /dev/null @@ -1,946 +0,0 @@ - 'name'); will validate mapActions against model $name::isAuthorized(user, controller, mapAction) - * 'object' will validate Controller::action against object::isAuthorized(user, controller, action) - * - * @var mixed - * @link http://book.cakephp.org/view/1275/authorize - */ - public $authorize = false; - -/** - * The name of an optional view element to render when an Ajax request is made - * with an invalid or expired session - * - * @var string - * @link http://book.cakephp.org/view/1277/ajaxLogin - */ - public $ajaxLogin = null; - -/** - * The name of the element used for SessionComponent::setFlash - * - * @var string - */ - public $flashElement = 'default'; - -/** - * The name of the model that represents users which will be authenticated. Defaults to 'User'. - * - * @var string - * @link http://book.cakephp.org/view/1266/userModel - */ - public $userModel = 'User'; - -/** - * Additional query conditions to use when looking up and authenticating users, - * i.e. array('User.is_active' => 1). - * - * @var array - * @link http://book.cakephp.org/view/1268/userScope - */ - public $userScope = array(); - -/** - * Allows you to specify non-default login name and password fields used in - * $userModel, i.e. array('username' => 'login_name', 'password' => 'passwd'). - * - * @var array - * @link http://book.cakephp.org/view/1267/fields - */ - public $fields = array('username' => 'username', 'password' => 'password'); - -/** - * The session key name where the record of the current user is stored. If - * unspecified, it will be "Auth.{$userModel name}". - * - * @var string - * @link http://book.cakephp.org/view/1276/sessionKey - */ - public $sessionKey = null; - -/** - * If using action-based access control, this defines how the paths to action - * ACO nodes is computed. If, for example, all controller nodes are nested - * under an ACO node named 'Controllers', $actionPath should be set to - * "Controllers/". - * - * @var string - * @link http://book.cakephp.org/view/1279/actionPath - */ - public $actionPath = null; - -/** - * A URL (defined as a string or array) to the controller action that handles - * logins. - * - * @var mixed - * @link http://book.cakephp.org/view/1269/loginAction - */ - public $loginAction = null; - -/** - * Normally, if a user is redirected to the $loginAction page, the location they - * were redirected from will be stored in the session so that they can be - * redirected back after a successful login. If this session value is not - * set, the user will be redirected to the page specified in $loginRedirect. - * - * @var mixed - * @link http://book.cakephp.org/view/1270/loginRedirect - */ - public $loginRedirect = null; - -/** - * The default action to redirect to after the user is logged out. While AuthComponent does - * not handle post-logout redirection, a redirect URL will be returned from AuthComponent::logout(). - * Defaults to AuthComponent::$loginAction. - * - * @var mixed - * @see AuthComponent::$loginAction - * @see AuthComponent::logout() - * @link http://book.cakephp.org/view/1271/logoutRedirect - */ - public $logoutRedirect = null; - -/** - * The name of model or model object, or any other object has an isAuthorized method. - * - * @var string - */ - public $object = null; - -/** - * Error to display when user login fails. For security purposes, only one error is used for all - * login failures, so as not to expose information on why the login failed. - * - * @var string - * @link http://book.cakephp.org/view/1272/loginError - */ - public $loginError = null; - -/** - * Error to display when user attempts to access an object or action to which they do not have - * acccess. - * - * @var string - * @link http://book.cakephp.org/view/1273/authError - */ - public $authError = null; - -/** - * Determines whether AuthComponent will automatically redirect and exit if login is successful. - * - * @var boolean - * @link http://book.cakephp.org/view/1274/autoRedirect - */ - public $autoRedirect = true; - -/** - * Controller actions for which user validation is not required. - * - * @var array - * @see AuthComponent::allow() - * @link http://book.cakephp.org/view/1251/Setting-Auth-Component-Variables - */ - public $allowedActions = array(); - -/** - * Maps actions to CRUD operations. Used for controller-based validation ($validate = 'controller'). - * - * @var array - * @see AuthComponent::mapActions() - */ - public $actionMap = array( - 'index' => 'read', - 'add' => 'create', - 'edit' => 'update', - 'view' => 'read', - 'remove' => 'delete' - ); - -/** - * Request object - * - * @var CakeRequest - */ - public $request; - -/** - * Form data from Controller::$data - * - * @deprecated Use $this->request->data instead - * @var array - */ - public $data = array(); - -/** - * Parameter data from Controller::$params - * - * @deprecated Use $this->request instead - * @var array - */ - public $params = array(); - -/** - * AclComponent instance if using Acl + Auth - * - * @var AclComponent - */ - public $Acl; - -/** - * Method list for bound controller - * - * @var array - */ - protected $_methods = array(); - -/** - * Initializes AuthComponent for use in the controller - * - * @param object $controller A reference to the instantiating controller object - * @return void - */ - public function initialize($controller) { - $this->request = $controller->request; - $this->params = $this->request; - - $crud = array('create', 'read', 'update', 'delete'); - $this->actionMap = array_merge($this->actionMap, array_combine($crud, $crud)); - $this->_methods = $controller->methods; - - $prefixes = Router::prefixes(); - if (!empty($prefixes)) { - foreach ($prefixes as $prefix) { - $this->actionMap = array_merge($this->actionMap, array( - $prefix . '_index' => 'read', - $prefix . '_add' => 'create', - $prefix . '_edit' => 'update', - $prefix . '_view' => 'read', - $prefix . '_remove' => 'delete', - $prefix . '_create' => 'create', - $prefix . '_read' => 'read', - $prefix . '_update' => 'update', - $prefix . '_delete' => 'delete' - )); - } - } - if (Configure::read('debug') > 0) { - App::import('Debugger'); - Debugger::checkSecurityKeys(); - } - } - -/** - * Main execution method. Handles redirecting of invalid users, and processing - * of login form data. - * - * @param object $controller A reference to the instantiating controller object - * @return boolean - */ - public function startup($controller) { - $isErrorOrTests = ( - strtolower($controller->name) == 'cakeerror' || - (strtolower($controller->name) == 'tests' && Configure::read('debug') > 0) - ); - if ($isErrorOrTests) { - return true; - } - - $methods = array_flip($controller->methods); - $action = $controller->request->params['action']; - - $isMissingAction = ( - $controller->scaffold === false && - !isset($methods[$action]) - ); - - if ($isMissingAction) { - return true; - } - - if (!$this->__setDefaults()) { - return false; - } - $request = $controller->request; - - $this->request->data = $controller->request->data = $this->hashPasswords($request->data); - $url = ''; - - if (isset($request->query['url'])) { - $url = $request->query['url']; - } - $url = Router::normalize($url); - $loginAction = Router::normalize($this->loginAction); - - $allowedActions = $this->allowedActions; - $isAllowed = ( - $this->allowedActions == array('*') || - in_array($action, $allowedActions) - ); - - if ($loginAction != $url && $isAllowed) { - return true; - } - - if ($loginAction == $url) { - $model = $this->getModel(); - if (empty($request->data) || !isset($request->data[$model->alias])) { - if (!$this->Session->check('Auth.redirect') && !$this->loginRedirect && env('HTTP_REFERER')) { - $this->Session->write('Auth.redirect', $controller->referer(null, true)); - } - return false; - } - - $isValid = !empty($request->data[$model->alias][$this->fields['username']]) && - !empty($request->data[$model->alias][$this->fields['password']]); - - if ($isValid) { - $username = $request->data[$model->alias][$this->fields['username']]; - $password = $request->data[$model->alias][$this->fields['password']]; - - $data = array( - $model->alias . '.' . $this->fields['username'] => $username, - $model->alias . '.' . $this->fields['password'] => $password - ); - - if ($this->login($data)) { - if ($this->autoRedirect) { - $controller->redirect($this->redirect(), null, true); - } - return true; - } - } - - $this->Session->setFlash($this->loginError, $this->flashElement, array(), 'auth'); - $request->data[$model->alias][$this->fields['password']] = null; - return false; - } else { - if (!$this->user()) { - if (!$request->is('ajax')) { - $this->Session->setFlash($this->authError, $this->flashElement, array(), 'auth'); - if (!empty($request->query) && count($request->query) >= 2) { - $query = $request->query; - unset($query['url'], $query['ext']); - $url .= Router::queryString($query, array()); - } - $this->Session->write('Auth.redirect', $url); - $controller->redirect($loginAction); - return false; - } elseif (!empty($this->ajaxLogin)) { - $controller->viewPath = 'elements'; - echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout); - $this->_stop(); - return false; - } else { - $controller->redirect(null, 403); - } - } - } - - if (!$this->authorize) { - return true; - } - - extract($this->__authType()); - switch ($type) { - case 'controller': - $this->object = $controller; - break; - case 'crud': - case 'actions': - if (isset($controller->Acl)) { - $this->Acl = $controller->Acl; - } else { - trigger_error(__('Could not find AclComponent. Please include Acl in Controller::$components.'), E_USER_WARNING); - } - break; - case 'model': - if (!isset($object)) { - $hasModel = ( - isset($controller->{$controller->modelClass}) && - is_object($controller->{$controller->modelClass}) - ); - $isUses = ( - !empty($controller->uses) && isset($controller->{$controller->uses[0]}) && - is_object($controller->{$controller->uses[0]}) - ); - - if ($hasModel) { - $object = $controller->modelClass; - } elseif ($isUses) { - $object = $controller->uses[0]; - } - } - $type = array('model' => $object); - break; - } - - if ($this->isAuthorized($type)) { - return true; - } - - $this->Session->setFlash($this->authError, $this->flashElement, array(), 'auth'); - $controller->redirect($controller->referer(), null, true); - return false; - } - -/** - * Attempts to introspect the correct values for object properties including - * $userModel and $sessionKey. - * - * @param object $controller A reference to the instantiating controller object - * @return boolean - * @access private - */ - function __setDefaults() { - if (empty($this->userModel)) { - trigger_error(__("Could not find \$userModel. Please set AuthComponent::\$userModel in beforeFilter()."), E_USER_WARNING); - return false; - } - list($plugin, $model) = pluginSplit($this->userModel); - $defaults = array( - 'loginAction' => array( - 'controller' => Inflector::underscore(Inflector::pluralize($model)), - 'action' => 'login', - 'plugin' => Inflector::underscore($plugin), - ), - 'sessionKey' => 'Auth.' . $model, - 'logoutRedirect' => $this->loginAction, - 'loginError' => __('Login failed. Invalid username or password.'), - 'authError' => __('You are not authorized to access that location.') - ); - foreach ($defaults as $key => $value) { - if (empty($this->{$key})) { - $this->{$key} = $value; - } - } - return true; - } - -/** - * Determines whether the given user is authorized to perform an action. The type of - * authorization used is based on the value of AuthComponent::$authorize or the - * passed $type param. - * - * Types: - * 'controller' will validate against Controller::isAuthorized() if controller instance is - * passed in $object - * 'actions' will validate Controller::action against an AclComponent::check() - * 'crud' will validate mapActions against an AclComponent::check() - * array('model'=> 'name'); will validate mapActions against model - * $name::isAuthorized(user, controller, mapAction) - * 'object' will validate Controller::action against - * object::isAuthorized(user, controller, action) - * - * @param string $type Type of authorization - * @param mixed $object object, model object, or model name - * @param mixed $user The user to check the authorization of - * @return boolean True if $user is authorized, otherwise false - */ - public function isAuthorized($type = null, $object = null, $user = null) { - if (empty($user) && !$this->user()) { - return false; - } elseif (empty($user)) { - $user = $this->user(); - } - - extract($this->__authType($type)); - - if (!$object) { - $object = $this->object; - } - - $valid = false; - switch ($type) { - case 'controller': - $valid = $object->isAuthorized(); - break; - case 'actions': - $valid = $this->Acl->check($user, $this->action()); - break; - case 'crud': - if (!isset($this->actionMap[$this->request['action']])) { - trigger_error( - __('Auth::startup() - Attempted access of un-mapped action "%1$s" in controller "%2$s"', $this->request['action'], $this->request['controller']), - E_USER_WARNING - ); - } else { - $valid = $this->Acl->check( - $user, - $this->action(':controller'), - $this->actionMap[$this->request['action']] - ); - } - break; - case 'model': - $action = $this->request['action']; - if (isset($this->actionMap[$action])) { - $action = $this->actionMap[$action]; - } - if (is_string($object)) { - $object = $this->getModel($object); - } - case 'object': - if (!isset($action)) { - $action = $this->action(':action'); - } - if (empty($object)) { - trigger_error(__('Could not find %s. Set AuthComponent::$object in beforeFilter() or pass a valid object', get_class($object)), E_USER_WARNING); - return; - } - if (method_exists($object, 'isAuthorized')) { - $valid = $object->isAuthorized($user, $this->action(':controller'), $action); - } elseif ($object) { - trigger_error(__('%s::isAuthorized() is not defined.', get_class($object)), E_USER_WARNING); - } - break; - case null: - case false: - return true; - break; - default: - trigger_error(__('Auth::isAuthorized() - $authorize is set to an incorrect value. Allowed settings are: "actions", "crud", "model" or null.'), E_USER_WARNING); - break; - } - return $valid; - } - -/** - * Get authorization type - * - * @param string $auth Type of authorization - * @return array Associative array with: type, object - * @access private - */ - function __authType($auth = null) { - if ($auth == null) { - $auth = $this->authorize; - } - $object = null; - if (is_array($auth)) { - $type = key($auth); - $object = $auth[$type]; - } else { - $type = $auth; - return compact('type'); - } - return compact('type', 'object'); - } - -/** - * Takes a list of actions in the current controller for which authentication is not required, or - * no parameters to allow all actions. - * - * @param mixed $action Controller action name or array of actions - * @param string $action Controller action name - * @param string ... etc. - * @return void - * @link http://book.cakephp.org/view/1257/allow - */ - public function allow() { - $args = func_get_args(); - if (empty($args) || $args == array('*')) { - $this->allowedActions = $this->_methods; - } else { - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - $this->allowedActions = array_merge($this->allowedActions, $args); - } - } - -/** - * Removes items from the list of allowed actions. - * - * @param mixed $action Controller action name or array of actions - * @param string $action Controller action name - * @param string ... etc. - * @return void - * @see AuthComponent::allow() - * @link http://book.cakephp.org/view/1258/deny - */ - public function deny() { - $args = func_get_args(); - if (isset($args[0]) && is_array($args[0])) { - $args = $args[0]; - } - foreach ($args as $arg) { - $i = array_search($arg, $this->allowedActions); - if (is_int($i)) { - unset($this->allowedActions[$i]); - } - } - $this->allowedActions = array_values($this->allowedActions); - } - -/** - * Maps action names to CRUD operations. Used for controller-based authentication. - * - * @param array $map Actions to map - * @return void - * @link http://book.cakephp.org/view/1260/mapActions - */ - public function mapActions($map = array()) { - $crud = array('create', 'read', 'update', 'delete'); - foreach ($map as $action => $type) { - if (in_array($action, $crud) && is_array($type)) { - foreach ($type as $typedAction) { - $this->actionMap[$typedAction] = $action; - } - } else { - $this->actionMap[$action] = $type; - } - } - } - -/** - * Manually log-in a user with the given parameter data. The $data provided can be any data - * structure used to identify a user in AuthComponent::identify(). If $data is empty or not - * specified, POST data from Controller::$data will be used automatically. - * - * After (if) login is successful, the user record is written to the session key specified in - * AuthComponent::$sessionKey. - * - * @param mixed $data User object - * @return boolean True on login success, false on failure - * @link http://book.cakephp.org/view/1261/login - */ - public function login($data = null) { - $this->__setDefaults(); - $this->_loggedIn = false; - - if (empty($data)) { - $data = $this->data; - } - - if ($user = $this->identify($data)) { - $this->Session->write($this->sessionKey, $user); - $this->_loggedIn = true; - } - return $this->_loggedIn; - } - -/** - * Logs a user out, and returns the login action to redirect to. - * - * @param mixed $url Optional URL to redirect the user to after logout - * @return string AuthComponent::$loginAction - * @see AuthComponent::$loginAction - * @link http://book.cakephp.org/view/1262/logout - */ - public function logout() { - $this->__setDefaults(); - $this->Session->delete($this->sessionKey); - $this->Session->delete('Auth.redirect'); - $this->_loggedIn = false; - return Router::normalize($this->logoutRedirect); - } - -/** - * Get the current user from the session. - * - * @param string $key field to retrive. Leave null to get entire User record - * @return mixed User record. or null if no user is logged in. - * @link http://book.cakephp.org/view/1264/user - */ - public function user($key = null) { - $this->__setDefaults(); - if (!$this->Session->check($this->sessionKey)) { - return null; - } - - if ($key == null) { - $model = $this->getModel(); - return array($model->alias => $this->Session->read($this->sessionKey)); - } else { - $user = $this->Session->read($this->sessionKey); - if (isset($user[$key])) { - return $user[$key]; - } - return null; - } - } - -/** - * If no parameter is passed, gets the authentication redirect URL. - * - * @param mixed $url Optional URL to write as the login redirect URL. - * @return string Redirect URL - */ - public function redirect($url = null) { - if (!is_null($url)) { - $redir = $url; - $this->Session->write('Auth.redirect', $redir); - } elseif ($this->Session->check('Auth.redirect')) { - $redir = $this->Session->read('Auth.redirect'); - $this->Session->delete('Auth.redirect'); - - if (Router::normalize($redir) == Router::normalize($this->loginAction)) { - $redir = $this->loginRedirect; - } - } else { - $redir = $this->loginRedirect; - } - return Router::normalize($redir); - } - -/** - * Validates a user against an abstract object. - * - * @param mixed $object The object to validate the user against. - * @param mixed $user Optional. The identity of the user to be validated. - * Uses the current user session if none specified. For - * valid forms of identifying users, see - * AuthComponent::identify(). - * @param string $action Optional. The action to validate against. - * @see AuthComponent::identify() - * @return boolean True if the user validates, false otherwise. - */ - public function validate($object, $user = null, $action = null) { - if (empty($user)) { - $user = $this->user(); - } - if (empty($user)) { - return false; - } - return $this->Acl->check($user, $object, $action); - } - -/** - * Returns the path to the ACO node bound to a controller/action. - * - * @param string $action Optional. The controller/action path to validate the - * user against. The current request action is used if - * none is specified. - * @return boolean ACO node path - * @link http://book.cakephp.org/view/1256/action - */ - public function action($action = ':plugin/:controller/:action') { - $plugin = empty($this->request['plugin']) ? null : Inflector::camelize($this->request['plugin']) . '/'; - return str_replace( - array(':controller', ':action', ':plugin/'), - array(Inflector::camelize($this->request['controller']), $this->request['action'], $plugin), - $this->actionPath . $action - ); - } - -/** - * Returns a reference to the model object specified, and attempts - * to load it if it is not found. - * - * @param string $name Model name (defaults to AuthComponent::$userModel) - * @return object A reference to a model object - */ - public function &getModel($name = null) { - $model = null; - if (!$name) { - $name = $this->userModel; - } - - $model = ClassRegistry::init($name); - - if (empty($model)) { - trigger_error(__('Auth::getModel() - Model is not set or could not be found'), E_USER_WARNING); - return null; - } - - return $model; - } - -/** - * Identifies a user based on specific criteria. - * - * @param mixed $user Optional. The identity of the user to be validated. - * Uses the current user session if none specified. - * @param array $conditions Optional. Additional conditions to a find. - * @return array User record data, or null, if the user could not be identified. - */ - public function identify($user = null, $conditions = null) { - if ($conditions === false) { - $conditions = null; - } elseif (is_array($conditions)) { - $conditions = array_merge((array)$this->userScope, $conditions); - } else { - $conditions = $this->userScope; - } - $model = $this->getModel(); - if (empty($user)) { - $user = $this->user(); - if (empty($user)) { - return null; - } - } elseif (is_object($user) && is_a($user, 'Model')) { - if (!$user->exists()) { - return null; - } - $user = $user->read(); - $user = $user[$model->alias]; - } elseif (is_array($user) && isset($user[$model->alias])) { - $user = $user[$model->alias]; - } - - if (is_array($user) && (isset($user[$this->fields['username']]) || isset($user[$model->alias . '.' . $this->fields['username']]))) { - if (isset($user[$this->fields['username']]) && !empty($user[$this->fields['username']]) && !empty($user[$this->fields['password']])) { - if (trim($user[$this->fields['username']]) == '=' || trim($user[$this->fields['password']]) == '=') { - return false; - } - $find = array( - $model->alias.'.'.$this->fields['username'] => $user[$this->fields['username']], - $model->alias.'.'.$this->fields['password'] => $user[$this->fields['password']] - ); - } elseif (isset($user[$model->alias . '.' . $this->fields['username']]) && !empty($user[$model->alias . '.' . $this->fields['username']])) { - if (trim($user[$model->alias . '.' . $this->fields['username']]) == '=' || trim($user[$model->alias . '.' . $this->fields['password']]) == '=') { - return false; - } - $find = array( - $model->alias.'.'.$this->fields['username'] => $user[$model->alias . '.' . $this->fields['username']], - $model->alias.'.'.$this->fields['password'] => $user[$model->alias . '.' . $this->fields['password']] - ); - } else { - return false; - } - $data = $model->find('first', array( - 'conditions' => array_merge($find, $conditions), - 'recursive' => 0 - )); - if (empty($data) || empty($data[$model->alias])) { - return null; - } - } elseif (!empty($user) && is_string($user)) { - $data = $model->find('first', array( - 'conditions' => array_merge(array($model->escapeField() => $user), $conditions), - )); - if (empty($data) || empty($data[$model->alias])) { - return null; - } - } - - if (!empty($data)) { - if (!empty($data[$model->alias][$this->fields['password']])) { - unset($data[$model->alias][$this->fields['password']]); - } - return $data[$model->alias]; - } - return null; - } - -/** - * Hash any passwords found in $data using $userModel and $fields['password'] - * - * @param array $data Set of data to look for passwords - * @return array Data with passwords hashed - * @link http://book.cakephp.org/view/1259/hashPasswords - */ - public function hashPasswords($data) { - if (is_object($this->authenticate) && method_exists($this->authenticate, 'hashPasswords')) { - return $this->authenticate->hashPasswords($data); - } - - if (is_array($data)) { - $model = $this->getModel(); - - if(isset($data[$model->alias])) { - if (isset($data[$model->alias][$this->fields['username']]) && isset($data[$model->alias][$this->fields['password']])) { - $data[$model->alias][$this->fields['password']] = $this->password($data[$model->alias][$this->fields['password']]); - } - } - } - return $data; - } - -/** - * Hash a password with the application's salt value (as defined with Configure::write('Security.salt'); - * - * @param string $password Password to hash - * @return string Hashed password - * @link http://book.cakephp.org/view/1263/password - */ - public function password($password) { - return Security::hash($password, null, true); - } - -/** - * Component shutdown. If user is logged in, wipe out redirect. - * - * @param object $controller Instantiating controller - */ - public function shutdown($controller) { - if ($this->_loggedIn) { - $this->Session->delete('Auth.redirect'); - } - } - -/** - * Sets or gets whether the user is logged in - * - * @param boolean $logged sets the status of the user, true to logged in, false to logged out - * @return boolean true if the user is logged in, false otherwise - * @access public - */ - public function loggedIn($logged = null) { - if (!is_null($logged)) { - $this->_loggedIn = $logged; - } - return $this->_loggedIn; - } -} diff --git a/cake/libs/magic_db.php b/cake/libs/magic_db.php deleted file mode 100644 index 86a91d82d..000000000 --- a/cake/libs/magic_db.php +++ /dev/null @@ -1,291 +0,0 @@ -exists()) { - return false; - } - if ($File->ext() == 'php') { - include($File->pwd()); - $data = $magicDb; - } else { - // @TODO: Needs test coverage - $data = $File->read(); - } - } - - $magicDb = $this->toArray($data); - if (!$this->validates($magicDb)) { - return false; - } - return !!($this->db = $magicDb); - } - -/** - * Parses a MagicDb $data string into an array or returns the current MagicDb instance as an array - * - * @param string $data A MagicDb string to turn into an array - * @return array A parsed MagicDb array or an empty array if the $data param was invalid. Returns the db property if $data is not set. - */ - public function toArray($data = null) { - if (is_array($data)) { - return $data; - } - if ($data === null) { - return $this->db; - } - - if (strpos($data, '# FILE_ID DB') !== 0) { - return array(); - } - - $lines = explode("\r\n", $data); - $db = array(); - - $validHeader = count($lines) > 3 - && preg_match('/^# Date:([0-9]{4}-[0-9]{2}-[0-9]{2})$/', $lines[1], $date) - && preg_match('/^# Source:(.+)$/', $lines[2], $source) - && strlen($lines[3]) == 0; - if (!$validHeader) { - return $db; - } - - $db = array('header' => array('Date' => $date[1], 'Source' => $source[1]), 'database' => array()); - $lines = array_splice($lines, 3); - - $format = array(); - while (!empty($lines)) { - $line = array_shift($lines); - if (isset($line[0]) && $line[0] == '#' || empty($line)) { - continue; - } - - $columns = explode("\t", $line); - if (in_array($columns[0]{0}, array('>', '&'))) { - $format[] = $columns; - } elseif (!empty($format)) { - $db['database'][] = $format; - $format = array($columns); - } else { - $format = array($columns); - } - } - - return $db; - } - -/** - * Returns true if the MagicDb instance or the passed $magicDb is valid - * - * @param mixed $magicDb A $magicDb string / array to validate (optional) - * @return boolean True if the $magicDb / instance db validates, false if not - */ - public function validates($magicDb = null) { - if (is_null($magicDb)) { - $magicDb = $this->db; - } elseif (!is_array($magicDb)) { - $magicDb = $this->toArray($magicDb); - } - - return isset($magicDb['header'], $magicDb['database']) && is_array($magicDb['header']) && is_array($magicDb['database']); - } - -/** - * Analyzes a given $file using the currently loaded MagicDb information based on the desired $options - * - * @param string $file Absolute path to the file to analyze - * @param array $options TBT - * @return mixed - */ - public function analyze($file, $options = array()) { - if (!is_string($file)) { - return false; - } - - $matches = array(); - $MagicFileResource = new MagicFileResource($file); - foreach ($this->db['database'] as $format) { - $magic = $format[0]; - $match = $MagicFileResource->test($magic); - if ($match === false) { - continue; - } - $matches[] = $magic; - } - - return $matches; - } -} - -/** - * undocumented class - * - * @package cake.libs - */ -class MagicFileResource extends Object{ - -/** - * undocumented variable - * - * @var unknown - * @access public - */ - public $resource = null; - -/** - * undocumented variable - * - * @var unknown - * @access public - */ - public $offset = 0; - -/** - * undocumented function - * - * @param unknown $file - * @return void - */ - public function __construct($file) { - if (file_exists($file)) { - $this->resource = new File($file); - } else { - $this->resource = $file; - } - } - -/** - * undocumented function - * - * @param unknown $magic - * @return void - */ - public function test($magic) { - $offset = null; - $type = null; - $expected = null; - $comment = null; - if (isset($magic[0])) { - $offset = $magic[0]; - } - if (isset($magic[1])) { - $type = $magic[1]; - } - if (isset($magic[2])) { - $expected = $magic[2]; - } - if (isset($magic[3])) { - $comment = $magic[3]; - } - $val = $this->extract($offset, $type, $expected); - return $val == $expected; - } - -/** - * undocumented function - * - * @param unknown $type - * @param unknown $length - * @return void - */ - public function read($length = null) { - if (!is_object($this->resource)) { - return substr($this->resource, $this->offset, $length); - } - return $this->resource->read($length); - } - -/** - * undocumented function - * - * @param unknown $type - * @param unknown $expected - * @return void - */ - public function extract($offset, $type, $expected) { - switch ($type) { - case 'string': - $this->offset($offset); - $val = $this->read(strlen($expected)); - if ($val === $expected) { - return true; - } - break; - } - } - -/** - * undocumented function - * - * @param unknown $offset - * @param unknown $whence - * @return void - */ - public function offset($offset = null) { - if (is_null($offset)) { - if (!is_object($this->resource)) { - return $this->offset; - } - return $this->offset; - } - - if (!ctype_digit($offset)) { - return false; - } - if (is_object($this->resource)) { - $this->resource->offset($offset); - } else { - $this->offset = $offset; - } - } -} diff --git a/cake/libs/model/connection_manager.php b/cake/libs/model/connection_manager.php deleted file mode 100644 index f8916877e..000000000 --- a/cake/libs/model/connection_manager.php +++ /dev/null @@ -1,274 +0,0 @@ -config = new DATABASE_CONFIG(); - $this->_getConnectionObjects(); - } - } - -/** - * Gets a reference to the ConnectionManger object instance - * - * @return object Instance - */ - public static function &getInstance() { - static $instance = array(); - - if (!$instance) { - $instance[0] = new ConnectionManager(); - } - - return $instance[0]; - } - -/** - * Gets a reference to a DataSource object - * - * @param string $name The name of the DataSource, as defined in app/config/database.php - * @return object Instance - */ - public static function &getDataSource($name) { - $_this = ConnectionManager::getInstance(); - - if (!empty($_this->_dataSources[$name])) { - $return = $_this->_dataSources[$name]; - return $return; - } - - if (empty($_this->_connectionsEnum[$name])) { - trigger_error(__("ConnectionManager::getDataSource - Non-existent data source %s", $name), E_USER_ERROR); - $null = null; - return $null; - } - $conn = $_this->_connectionsEnum[$name]; - $class = $conn['classname']; - - if ($_this->loadDataSource($name) === null) { - trigger_error(__("ConnectionManager::getDataSource - Could not load class %s", $class), E_USER_ERROR); - $null = null; - return $null; - } - $_this->_dataSources[$name] = new $class($_this->config->{$name}); - $_this->_dataSources[$name]->configKeyName = $name; - - $return = $_this->_dataSources[$name]; - return $return; - } - -/** - * Gets the list of available DataSource connections - * - * @return array List of available connections - */ - public static function sourceList() { - $_this = ConnectionManager::getInstance(); - return array_keys($_this->_dataSources); - } - -/** - * Gets a DataSource name from an object reference. - * - * **Warning** this method may cause fatal errors in PHP4. - * - * @param object $source DataSource object - * @return string Datasource name, or null if source is not present - * in the ConnectionManager. - */ - public static function getSourceName(&$source) { - $_this = ConnectionManager::getInstance(); - foreach ($_this->_dataSources as $name => $ds) { - if ($ds == $source) { - return $name; - } - } - return ''; - } - -/** - * Loads the DataSource class for the given connection name - * - * @param mixed $connName A string name of the connection, as defined in app/config/database.php, - * or an array containing the filename (without extension) and class name of the object, - * to be found in app/models/datasources/ or cake/libs/model/datasources/. - * @return boolean True on success, null on failure or false if the class is already loaded - */ - public static function loadDataSource($connName) { - $_this = ConnectionManager::getInstance(); - - if (is_array($connName)) { - $conn = $connName; - } else { - $conn = $_this->_connectionsEnum[$connName]; - } - - if (class_exists($conn['classname'])) { - return false; - } - - if (!empty($conn['parent'])) { - $_this->loadDataSource($conn['parent']); - } - - $conn = array_merge(array('plugin' => null, 'classname' => null, 'parent' => null), $conn); - $class = "{$conn['plugin']}.{$conn['classname']}"; - - if (!App::import('Datasource', $class, !is_null($conn['plugin']))) { - trigger_error(__('ConnectionManager::loadDataSource - Unable to import DataSource class %s', $class), E_USER_ERROR); - return null; - } - return true; - } - -/** - * Return a list of connections - * - * @return array An associative array of elements where the key is the connection name - * (as defined in Connections), and the value is an array with keys 'filename' and 'classname'. - */ - public static function enumConnectionObjects() { - $_this = ConnectionManager::getInstance(); - return $_this->_connectionsEnum; - } - -/** - * Dynamically creates a DataSource object at runtime, with the given name and settings - * - * @param string $name The DataSource name - * @param array $config The DataSource configuration settings - * @return object A reference to the DataSource object, or null if creation failed - */ - public static function &create($name = '', $config = array()) { - $_this = ConnectionManager::getInstance(); - - if (empty($name) || empty($config) || array_key_exists($name, $_this->_connectionsEnum)) { - $null = null; - return $null; - } - $_this->config->{$name} = $config; - $_this->_connectionsEnum[$name] = $_this->__connectionData($config); - $return = $_this->getDataSource($name); - return $return; - } - -/** - * Gets a list of class and file names associated with the user-defined DataSource connections - * - * @return void - */ - protected function _getConnectionObjects() { - $connections = get_object_vars($this->config); - - if ($connections != null) { - foreach ($connections as $name => $config) { - $this->_connectionsEnum[$name] = $this->__connectionData($config); - } - } else { - throw new MissingConnectionException(array('class' => 'ConnectionManager')); - } - } - -/** - * Returns the file, class name, and parent for the given driver. - * - * @return array An indexed array with: filename, classname, plugin and parent - */ - private function __connectionData($config) { - if (!isset($config['datasource'])) { - $config['datasource'] = 'dbo'; - } - $filename = $classname = $parent = $plugin = null; - - if (!empty($config['driver'])) { - $parent = $this->__connectionData(array('datasource' => $config['datasource'])); - $parentSource = preg_replace('/_source$/', '', $parent['filename']); - - list($plugin, $classname) = pluginSplit($config['driver']); - if ($plugin) { - $source = Inflector::underscore($classname); - } else { - $source = $parentSource . '_' . $config['driver']; - $classname = Inflector::camelize(strtolower($source)); - } - $filename = $parentSource . DS . $source; - } else { - list($plugin, $classname) = pluginSplit($config['datasource']); - if ($plugin) { - $filename = Inflector::underscore($classname); - } else { - $filename = Inflector::underscore($config['datasource']); - } - if (substr($filename, -7) != '_source') { - $filename .= '_source'; - } - $classname = Inflector::camelize(strtolower($filename)); - } - return compact('filename', 'classname', 'parent', 'plugin'); - } - -/** - * Destructor. - * - */ - function __destruct() { - if (Configure::read('Session.defaults') == 'database' && function_exists('session_write_close')) { - session_write_close(); - } - } -} \ No newline at end of file diff --git a/cake/libs/view/errors/missing_action.ctp b/cake/libs/view/errors/missing_action.ctp deleted file mode 100644 index 5b6fdb970..000000000 --- a/cake/libs/view/errors/missing_action.ctp +++ /dev/null @@ -1,44 +0,0 @@ - -

-

- : - ' . $action . '', '' . $controller . ''); ?> -

-

- : - ' . $controller . '::', '' . $action . '()', APP_DIR . DS . 'controllers' . DS . Inflector::underscore($controller) . '.php'); ?> -

-
-<?php
-class  extends AppController {
-
-
-	function  {
-
-	}
-
-}
-?>
-
-

- : - -

-element('exception_stack_trace'); ?> diff --git a/cake/libs/view/errors/missing_view.ctp b/cake/libs/view/errors/missing_view.ctp deleted file mode 100644 index 9d8c7cb91..000000000 --- a/cake/libs/view/errors/missing_view.ctp +++ /dev/null @@ -1,33 +0,0 @@ - -

-

- : - ' . Inflector::camelize($this->request->controller) . 'Controller::', '' . $this->request->action . '()'); ?> -

-

- : - -

-

- : - -

- -element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/pages/home.ctp b/cake/libs/view/pages/home.ctp deleted file mode 100644 index 9951a08c0..000000000 --- a/cake/libs/view/pages/home.ctp +++ /dev/null @@ -1,170 +0,0 @@ - -

- - 0): - Debugger::checkSecurityKeys(); -endif; -?> -

- '; - echo __('Your tmp directory is writable.'); - echo ''; - else: - echo ''; - echo __('Your tmp directory is NOT writable.'); - echo ''; - endif; - ?> -

-

- '; - echo __('The %s is being used for caching. To change the config edit APP/config/core.php ', ''. $settings['engine'] . 'Engine'); - echo ''; - else: - echo ''; - echo __('Your cache is NOT working. Please check the settings in APP/config/core.php'); - echo ''; - endif; - ?> -

-

- '; - echo __('Your database configuration file is present.'); - $filePresent = true; - echo ''; - else: - echo ''; - echo __('Your database configuration file is NOT present.'); - echo '
'; - echo __('Rename config/database.php.default to config/database.php'); - echo '
'; - endif; - ?> -

-'; - __('PCRE has not been compiled with Unicode support.'); - echo '
'; - __('Recompile PCRE with Unicode support by adding --enable-unicode-properties when configuring'); - echo '

'; - } -?> -getDataSource('default'); -?> -

- isConnected()): - echo ''; - echo __('Cake is able to connect to the database.'); - echo ''; - else: - echo ''; - echo __('Cake is NOT able to connect to the database.'); - echo ''; - endif; - ?> -

- -

-

- -To change its layout, create: APP/views/layouts/default.ctp.
-You can also add some CSS styles for your pages at: APP/webroot/css.'); -?> -

- -

-

- Html->link( - sprintf('%s %s', __('New', true), __('CakePHP 1.3 Docs', true)), - 'http://book.cakephp.org/view/875/x1-3-Collection', - array('target' => '_blank', 'escape' => false) - ); - ?> -

-

- Html->link( - __('The 15 min Blog Tutorial', true), - 'http://book.cakephp.org/view/1528/Blog', - array('target' => '_blank', 'escape' => false) - ); - ?> -

- -

-

- -

-

- -

- - diff --git a/cake/tests/cases/libs/all_libs.test.php b/cake/tests/cases/libs/all_libs.test.php deleted file mode 100644 index ba0388850..000000000 --- a/cake/tests/cases/libs/all_libs.test.php +++ /dev/null @@ -1,53 +0,0 @@ -addTestFile(CORE_TEST_CASES . DS . 'basics.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'cake_session.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'debugger.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'file.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'folder.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'inflector.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'log' . DS . 'file_log.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'cake_log.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'class_registry.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'sanitize.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'set.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'string.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'validation.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'object_collection.test.php'); - return $suite; - } -} \ No newline at end of file diff --git a/cake/tests/cases/libs/all_test_suite.test.php b/cake/tests/cases/libs/all_test_suite.test.php deleted file mode 100644 index b85ea0a19..000000000 --- a/cake/tests/cases/libs/all_test_suite.test.php +++ /dev/null @@ -1,44 +0,0 @@ -addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'test_manager.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'cake_test_case.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'cake_test_fixture.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'html_coverage_report.test.php'); - $suite->addTestFile(CORE_TEST_CASES . DS . 'libs' . DS . 'controller_test_case.test.php'); - return $suite; - } -} \ No newline at end of file diff --git a/cake/tests/cases/libs/all_tests.test.php b/cake/tests/cases/libs/all_tests.test.php deleted file mode 100644 index f7bdc72d3..000000000 --- a/cake/tests/cases/libs/all_tests.test.php +++ /dev/null @@ -1,61 +0,0 @@ -addTestFile($console . 'all_console_libs.test.php'); - $suite->addTestFile($console . 'all_shells.test.php'); - $suite->addTestFile($console . 'all_tasks.test.php'); - - $suite->addTestFile($path . 'all_behaviors.test.php'); - $suite->addTestFile($path . 'all_cache_engines.test.php'); - $suite->addTestFile($path . 'all_components.test.php'); - $suite->addTestFile($path . 'all_configure.test.php'); - $suite->addTestFile($path . 'all_controllers.test.php'); - $suite->addTestFile($path . 'all_database.test.php'); - $suite->addTestFile($path . 'all_error.test.php'); - $suite->addTestFile($path . 'all_helpers.test.php'); - $suite->addTestFile($path . 'all_libs.test.php'); - $suite->addTestFile($path . 'all_localization.test.php'); - $suite->addTestFile($path . 'all_model.test.php'); - $suite->addTestFile($path . 'all_routing.test.php'); - $suite->addTestFile($path . 'all_socket.test.php'); - $suite->addTestFile($path . 'all_test_suite.test.php');; - $suite->addTestFile($path . 'all_views.test.php'); - $suite->addTestFile($path . 'all_xml.test.php'); - return $suite; - } -} diff --git a/cake/tests/cases/libs/app.test.php b/cake/tests/cases/libs/app.test.php deleted file mode 100644 index 6e7793072..000000000 --- a/cake/tests/cases/libs/app.test.php +++ /dev/null @@ -1,532 +0,0 @@ -assertEqual($expected, $old); - - App::build(array('models' => array('/path/to/models/'))); - - $new = App::path('models'); - - $expected = array( - '/path/to/models/', - APP . 'models' . DS, - APP, - LIBS . 'model' . DS - ); - $this->assertEqual($expected, $new); - - App::build(); //reset defaults - $defaults = App::path('models'); - $this->assertEqual($old, $defaults); - } - -/** - * testBuildWithReset method - * - * @access public - * @return void - */ - function testBuildWithReset() { - $old = App::path('models'); - $expected = array( - APP . 'models' . DS, - APP, - LIBS . 'model' . DS - ); - $this->assertEqual($expected, $old); - - App::build(array('models' => array('/path/to/models/')), true); - - $new = App::path('models'); - - $expected = array( - '/path/to/models/' - ); - $this->assertEqual($expected, $new); - - App::build(); //reset defaults - $defaults = App::path('models'); - $this->assertEqual($old, $defaults); - } - -/** - * testCore method - * - * @access public - * @return void - */ - function testCore() { - $model = App::core('models'); - $this->assertEqual(array(LIBS . 'model' . DS), $model); - - $view = App::core('views'); - $this->assertEqual(array(LIBS . 'view' . DS), $view); - - $controller = App::core('controllers'); - $this->assertEqual(array(LIBS . 'controller' . DS), $controller); - - } - -/** - * testListObjects method - * - * @access public - * @return void - */ - function testListObjects() { - $result = App::objects('class', TEST_CAKE_CORE_INCLUDE_PATH . 'libs', false); - $this->assertTrue(in_array('Xml', $result)); - $this->assertTrue(in_array('Cache', $result)); - $this->assertTrue(in_array('HttpSocket', $result)); - - $result = App::objects('behavior', null, false); - $this->assertTrue(in_array('Tree', $result)); - - $result = App::objects('controller', null, false); - $this->assertTrue(in_array('Pages', $result)); - - $result = App::objects('component', null, false); - $this->assertTrue(in_array('Auth', $result)); - - $result = App::objects('view', null, false); - $this->assertTrue(in_array('Media', $result)); - - $result = App::objects('helper', null, false); - $this->assertTrue(in_array('Html', $result)); - - $result = App::objects('model', null, false); - $notExpected = array('AppModel', 'ModelBehavior', 'ConnectionManager', 'DbAcl', 'Model', 'CakeSchema'); - foreach ($notExpected as $class) { - $this->assertFalse(in_array($class, $result)); - } - - $result = App::objects('file'); - $this->assertFalse($result); - - $result = App::objects('file', 'non_existing_configure'); - $expected = array(); - $this->assertEqual($result, $expected); - - $result = App::objects('NonExistingType'); - $this->assertFalse($result); - - App::build(array( - 'plugins' => array( - TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'libs' . DS - ) - )); - $result = App::objects('plugin', null, false); - $this->assertTrue(in_array('Cache', $result)); - $this->assertTrue(in_array('Log', $result)); - - App::build(); - } - -/** - * test that pluginPath can find paths for plugins. - * - * @return void - */ - function testPluginPath() { - App::build(array( - 'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS) - )); - $path = App::pluginPath('test_plugin'); - $expected = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS . 'test_plugin' . DS; - $this->assertEqual($path, $expected); - - $path = App::pluginPath('TestPlugin'); - $expected = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS . 'test_plugin' . DS; - $this->assertEqual($path, $expected); - - $path = App::pluginPath('TestPluginTwo'); - $expected = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS . 'test_plugin_two' . DS; - $this->assertEqual($path, $expected); - App::build(); - } - -/** - * test that pluginPath can find paths for plugins. - * - * @return void - */ - function testThemePath() { - App::build(array( - 'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS) - )); - $path = App::themePath('test_theme'); - $expected = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS . 'themed' . DS . 'test_theme' . DS; - $this->assertEqual($path, $expected); - - $path = App::themePath('TestTheme'); - $expected = TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS . 'themed' . DS . 'test_theme' . DS; - $this->assertEqual($path, $expected); - - App::build(); - } - -/** - * testClassLoading method - * - * @access public - * @return void - */ - function testClassLoading() { - $file = App::import(); - $this->assertTrue($file); - - $file = App::import('Model', 'Model', false); - $this->assertTrue($file); - $this->assertTrue(class_exists('Model')); - - $file = App::import('Controller', 'Controller', false); - $this->assertTrue($file); - $this->assertTrue(class_exists('Controller')); - - $file = App::import('Component', 'Component', false); - $this->assertTrue($file); - $this->assertTrue(class_exists('Component')); - - $file = App::import('Shell', 'Shell', false); - $this->assertTrue($file); - $this->assertTrue(class_exists('Shell')); - - $file = App::import('Lib', 'config/PhpReader'); - $this->assertTrue($file); - $this->assertTrue(class_exists('PhpReader')); - - $file = App::import('Model', 'SomeRandomModelThatDoesNotExist', false); - $this->assertFalse($file); - - $file = App::import('Model', 'AppModel', false); - $this->assertTrue($file); - $this->assertTrue(class_exists('AppModel')); - - $file = App::import('WrongType', null, true, array(), ''); - $this->assertTrue($file); - - $file = App::import('Model', 'NonExistingPlugin.NonExistingModel', false); - $this->assertFalse($file); - - $file = App::import('Core', 'NonExistingPlugin.NonExistingModel', false); - $this->assertFalse($file); - - $file = App::import('Model', array('NonExistingPlugin.NonExistingModel'), false); - $this->assertFalse($file); - - $file = App::import('Core', array('NonExistingPlugin.NonExistingModel'), false); - $this->assertFalse($file); - - $file = App::import('Core', array('NonExistingPlugin.NonExistingModel.AnotherChild'), false); - $this->assertFalse($file); - - if (!class_exists('AppController')) { - $classes = array_flip(get_declared_classes()); - - $this->assertFalse(isset($classes['PagesController'])); - $this->assertFalse(isset($classes['AppController'])); - - $file = App::import('Controller', 'Pages'); - $this->assertTrue($file); - $this->assertTrue(class_exists('PagesController')); - - $classes = array_flip(get_declared_classes()); - - $this->assertTrue(isset($classes['PagesController'])); - $this->assertTrue(isset($classes['AppController'])); - - $file = App::import('Behavior', 'Containable'); - $this->assertTrue($file); - $this->assertTrue(class_exists('ContainableBehavior')); - - $file = App::import('Component', 'RequestHandler'); - $this->assertTrue($file); - $this->assertTrue(class_exists('RequestHandlerComponent')); - - $file = App::import('Helper', 'Form'); - $this->assertTrue($file); - $this->assertTrue(class_exists('FormHelper')); - - $file = App::import('Model', 'NonExistingModel'); - $this->assertFalse($file); - - $file = App::import('Datasource', 'DboSource'); - $this->assertTrue($file); - $this->assertTrue(class_exists('DboSource')); - } - App::build(); - } - -/** - * test import() with plugins - * - * @return void - */ - function testPluginImporting() { - App::build(array( - 'libs' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'libs' . DS), - 'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS) - )); - - $result = App::import('Controller', 'TestPlugin.Tests'); - $this->assertTrue($result); - $this->assertTrue(class_exists('TestPluginAppController')); - $this->assertTrue(class_exists('TestsController')); - - $result = App::import('Lib', 'TestPlugin.TestPluginLibrary'); - $this->assertTrue($result); - $this->assertTrue(class_exists('TestPluginLibrary')); - - $result = App::import('Lib', 'Library'); - $this->assertTrue($result); - $this->assertTrue(class_exists('Library')); - - $result = App::import('Helper', 'TestPlugin.OtherHelper'); - $this->assertTrue($result); - $this->assertTrue(class_exists('OtherHelperHelper')); - - $result = App::import('Helper', 'TestPlugin.TestPluginApp'); - $this->assertTrue($result); - $this->assertTrue(class_exists('TestPluginAppHelper')); - - $result = App::import('Datasource', 'TestPlugin.TestSource'); - $this->assertTrue($result); - $this->assertTrue(class_exists('TestSource')); - - App::build(); - } - -/** - * test that building helper paths actually works. - * - * @return void - * @link http://cakephp.lighthouseapp.com/projects/42648/tickets/410 - */ - function testImportingHelpersFromAlternatePaths() { - App::build(); - $this->assertFalse(class_exists('BananaHelper'), 'BananaHelper exists, cannot test importing it.'); - App::import('Helper', 'Banana'); - $this->assertFalse(class_exists('BananaHelper'), 'BananaHelper was not found because the path does not exist.'); - - App::build(array( - 'helpers' => array( - TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS . 'helpers' . DS - ) - )); - App::build(array('vendors' => array(TEST_CAKE_CORE_INCLUDE_PATH))); - $this->assertFalse(class_exists('BananaHelper'), 'BananaHelper exists, cannot test importing it.'); - App::import('Helper', 'Banana'); - $this->assertTrue(class_exists('BananaHelper'), 'BananaHelper was not loaded.'); - - App::build(); - } - -/** - * testFileLoading method - * - * @access public - * @return void - */ - function testFileLoading () { - $file = App::import('File', 'RealFile', false, array(), TEST_CAKE_CORE_INCLUDE_PATH . 'config' . DS . 'config.php'); - $this->assertTrue($file); - - $file = App::import('File', 'NoFile', false, array(), TEST_CAKE_CORE_INCLUDE_PATH . 'config' . DS . 'cake' . DS . 'config.php'); - $this->assertFalse($file); - } - -/** - * testFileLoadingWithArray method - * - * @access public - * @return void - */ - function testFileLoadingWithArray() { - $type = array('type' => 'File', 'name' => 'SomeName', 'parent' => false, - 'file' => TEST_CAKE_CORE_INCLUDE_PATH . DS . 'config' . DS . 'config.php'); - $file = App::import($type); - $this->assertTrue($file); - - $type = array('type' => 'File', 'name' => 'NoFile', 'parent' => false, - 'file' => TEST_CAKE_CORE_INCLUDE_PATH . 'config' . DS . 'cake' . DS . 'config.php'); - $file = App::import($type); - $this->assertFalse($file); - } - -/** - * testFileLoadingReturnValue method - * - * @access public - * @return void - */ - function testFileLoadingReturnValue () { - $file = App::import('File', 'Name', false, array(), TEST_CAKE_CORE_INCLUDE_PATH . 'config' . DS . 'config.php', true); - $this->assertTrue(!empty($file)); - - $this->assertTrue(isset($file['Cake.version'])); - - $type = array('type' => 'File', 'name' => 'OtherName', 'parent' => false, - 'file' => TEST_CAKE_CORE_INCLUDE_PATH . 'config' . DS . 'config.php', 'return' => true); - $file = App::import($type); - $this->assertTrue(!empty($file)); - - $this->assertTrue(isset($file['Cake.version'])); - } - -/** - * testLoadingWithSearch method - * - * @access public - * @return void - */ - function testLoadingWithSearch () { - $file = App::import('File', 'NewName', false, array(TEST_CAKE_CORE_INCLUDE_PATH ), 'config.php'); - $this->assertTrue($file); - - $file = App::import('File', 'AnotherNewName', false, array(LIBS), 'config.php'); - $this->assertFalse($file); - } - -/** - * testLoadingWithSearchArray method - * - * @access public - * @return void - */ - function testLoadingWithSearchArray () { - $type = array('type' => 'File', 'name' => 'RandomName', 'parent' => false, 'file' => 'config.php', 'search' => array(TEST_CAKE_CORE_INCLUDE_PATH )); - $file = App::import($type); - $this->assertTrue($file); - - $type = array('type' => 'File', 'name' => 'AnotherRandomName', 'parent' => false, 'file' => 'config.php', 'search' => array(LIBS)); - $file = App::import($type); - $this->assertFalse($file); - } - -/** - * testMultipleLoading method - * - * @access public - * @return void - */ - function testMultipleLoading() { - if (class_exists('I18n', false) || class_exists('CakeSocket', false)) { - $this->markTestSkipped('Cannot test loading of classes that exist.'); - } - $toLoad = array('I18n', 'CakeSocket'); - - $classes = array_flip(get_declared_classes()); - $this->assertFalse(isset($classes['i18n'])); - $this->assertFalse(isset($classes['CakeSocket'])); - - $load = App::import($toLoad); - $this->assertTrue($load); - - $classes = array_flip(get_declared_classes()); - - - $this->assertTrue(isset($classes['I18n'])); - - $load = App::import(array('I18n', 'SomeNotFoundClass', 'CakeSocket')); - $this->assertFalse($load); - - $load = App::import($toLoad); - $this->assertTrue($load); - } - -/** - * This test only works if you have plugins/my_plugin set up. - * plugins/my_plugin/models/my_plugin.php and other_model.php - */ - -/* - function testMultipleLoadingByType() { - $classes = array_flip(get_declared_classes()); - $this->assertFalse(isset($classes['OtherPlugin'])); - $this->assertFalse(isset($classes['MyPlugin'])); - - - $load = App::import('Model', array('MyPlugin.OtherPlugin', 'MyPlugin.MyPlugin')); - $this->assertTrue($load); - - $classes = array_flip(get_declared_classes()); - $this->assertTrue(isset($classes['OtherPlugin'])); - $this->assertTrue(isset($classes['MyPlugin'])); - } -*/ - function testLoadingVendor() { - App::build(array( - 'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS), - 'vendors' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'vendors'. DS), - ), true); - - ob_start(); - $result = App::import('Vendor', 'TestPlugin.TestPluginAsset', array('ext' => 'css')); - $text = ob_get_clean(); - $this->assertTrue($result); - $this->assertEqual($text, 'this is the test plugin asset css file'); - - ob_start(); - $result = App::import('Vendor', 'TestAsset', array('ext' => 'css')); - $text = ob_get_clean(); - $this->assertTrue($result); - $this->assertEqual($text, 'this is the test asset css file'); - - $result = App::import('Vendor', 'TestPlugin.SamplePlugin'); - $this->assertTrue($result); - $this->assertTrue(class_exists('SamplePluginClassTestName')); - - $result = App::import('Vendor', 'ConfigureTestVendorSample'); - $this->assertTrue($result); - $this->assertTrue(class_exists('ConfigureTestVendorSample')); - - ob_start(); - $result = App::import('Vendor', 'SomeName', array('file' => 'some.name.php')); - $text = ob_get_clean(); - $this->assertTrue($result); - $this->assertEqual($text, 'This is a file with dot in file name'); - - ob_start(); - $result = App::import('Vendor', 'TestHello', array('file' => 'Test'.DS.'hello.php')); - $text = ob_get_clean(); - $this->assertTrue($result); - $this->assertEqual($text, 'This is the hello.php file in Test directory'); - - ob_start(); - $result = App::import('Vendor', 'MyTest', array('file' => 'Test'.DS.'MyTest.php')); - $text = ob_get_clean(); - $this->assertTrue($result); - $this->assertEqual($text, 'This is the MyTest.php file'); - - ob_start(); - $result = App::import('Vendor', 'Welcome'); - $text = ob_get_clean(); - $this->assertTrue($result); - $this->assertEqual($text, 'This is the welcome.php file in vendors directory'); - - ob_start(); - $result = App::import('Vendor', 'TestPlugin.Welcome'); - $text = ob_get_clean(); - $this->assertTrue($result); - $this->assertEqual($text, 'This is the welcome.php file in test_plugin/vendors directory'); - } -} diff --git a/cake/tests/cases/libs/controller/components/auth.test.php b/cake/tests/cases/libs/controller/components/auth.test.php deleted file mode 100644 index 371edd2ed..000000000 --- a/cake/tests/cases/libs/controller/components/auth.test.php +++ /dev/null @@ -1,1613 +0,0 @@ - - * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) - * - * Licensed under The MIT License - * Redistributions of files must retain the above copyright notice - * - * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests - * @package cake.tests.cases.libs.controller.components - * @since CakePHP(tm) v 1.2.0.5347 - * @license MIT License (http://www.opensource.org/licenses/mit-license.php) - */ -App::import('Core', 'Controller'); -App::import('Component', array('Auth', 'Acl')); -App::import('Model', 'DbAcl'); -App::import('Core', 'Xml'); - -/** -* TestAuthComponent class -* -* @package cake -* @package cake.tests.cases.libs.controller.components -*/ -class TestAuthComponent extends AuthComponent { - -/** - * testStop property - * - * @var bool false - * @access public - */ - public $testStop = false; - -/** - * Sets default login state - * - * @var bool true - * @access protected - */ - protected $_loggedIn = true; - -/** - * stop method - * - * @access public - * @return void - */ - function _stop($status = 0) { - $this->testStop = true; - } -} - -/** -* AuthUser class -* -* @package cake -* @package cake.tests.cases.libs.controller.components -*/ -class AuthUser extends CakeTestModel { - -/** - * name property - * - * @var string 'AuthUser' - * @access public - */ - public $name = 'AuthUser'; - -/** - * useDbConfig property - * - * @var string 'test' - * @access public - */ - public $useDbConfig = 'test'; - -/** - * parentNode method - * - * @access public - * @return void - */ - function parentNode() { - return true; - } - -/** - * bindNode method - * - * @param mixed $object - * @access public - * @return void - */ - function bindNode($object) { - return 'Roles/Admin'; - } - -/** - * isAuthorized method - * - * @param mixed $user - * @param mixed $controller - * @param mixed $action - * @access public - * @return void - */ - function isAuthorized($user, $controller = null, $action = null) { - if (!empty($user)) { - return true; - } - return false; - } -} - -/** - * AuthUserCustomField class - * - * @package cake.tests.cases.libs.controller.components - */ -class AuthUserCustomField extends AuthUser { - -/** - * name property - * - * @var string 'AuthUser' - * @access public - */ - public $name = 'AuthUserCustomField'; -} - -/** -* UuidUser class -* -* @package cake -* @package cake.tests.cases.libs.controller.components -*/ -class UuidUser extends CakeTestModel { - -/** - * name property - * - * @var string 'AuthUser' - * @access public - */ - public $name = 'UuidUser'; - -/** - * useDbConfig property - * - * @var string 'test' - * @access public - */ - public $useDbConfig = 'test'; - -/** - * useTable property - * - * @var string 'uuid' - * @access public - */ - public $useTable = 'uuids'; - -/** - * parentNode method - * - * @access public - * @return void - */ - function parentNode() { - return true; - } - -/** - * bindNode method - * - * @param mixed $object - * @access public - * @return void - */ - function bindNode($object) { - return 'Roles/Admin'; - } - -/** - * isAuthorized method - * - * @param mixed $user - * @param mixed $controller - * @param mixed $action - * @access public - * @return void - */ - function isAuthorized($user, $controller = null, $action = null) { - if (!empty($user)) { - return true; - } - return false; - } -} - -/** -* AuthTestController class -* -* @package cake -* @package cake.tests.cases.libs.controller.components -*/ -class AuthTestController extends Controller { - -/** - * name property - * - * @var string 'AuthTest' - * @access public - */ - public $name = 'AuthTest'; - -/** - * uses property - * - * @var array - * @access public - */ - public $uses = array('AuthUser'); - -/** - * components property - * - * @var array - * @access public - */ - public $components = array('Session', 'Auth', 'Acl'); - -/** - * testUrl property - * - * @var mixed null - * @access public - */ - public $testUrl = null; - -/** - * construct method - * - * @access private - * @return void - */ - function __construct($request) { - $request->addParams(Router::parse('/auth_test')); - $request->here = '/auth_test'; - $request->webroot = '/'; - Router::setRequestInfo($request); - parent::__construct($request); - } - -/** - * beforeFilter method - * - * @access public - * @return void - */ - function beforeFilter() { - $this->Auth->userModel = 'AuthUser'; - } - -/** - * login method - * - * @access public - * @return void - */ - function login() { - } - -/** - * admin_login method - * - * @access public - * @return void - */ - function admin_login() { - } - -/** - * logout method - * - * @access public - * @return void - */ - function logout() { - // $this->redirect($this->Auth->logout()); - } - -/** - * add method - * - * @access public - * @return void - */ - function add() { - echo "add"; - } - -/** - * add method - * - * @access public - * @return void - */ - function camelCase() { - echo "camelCase"; - } - -/** - * redirect method - * - * @param mixed $url - * @param mixed $status - * @param mixed $exit - * @access public - * @return void - */ - function redirect($url, $status = null, $exit = true) { - $this->testUrl = Router::url($url); - return false; - } - -/** - * isAuthorized method - * - * @access public - * @return void - */ - function isAuthorized() { - if (isset($this->request['testControllerAuth'])) { - return false; - } - return true; - } - -/** - * Mock delete method - * - * @param mixed $url - * @param mixed $status - * @param mixed $exit - * @access public - * @return void - */ - function delete($id = null) { - if ($this->TestAuth->testStop !== true && $id !== null) { - echo 'Deleted Record: ' . var_export($id, true); - } - } -} - -/** - * AjaxAuthController class - * - * @package cake.tests.cases.libs.controller.components - */ -class AjaxAuthController extends Controller { - -/** - * name property - * - * @var string 'AjaxAuth' - * @access public - */ - public $name = 'AjaxAuth'; - -/** - * components property - * - * @var array - * @access public - */ - public $components = array('Session', 'TestAuth'); - -/** - * uses property - * - * @var array - * @access public - */ - public $uses = array(); - -/** - * testUrl property - * - * @var mixed null - * @access public - */ - public $testUrl = null; - -/** - * beforeFilter method - * - * @access public - * @return void - */ - function beforeFilter() { - $this->TestAuth->ajaxLogin = 'test_element'; - $this->TestAuth->userModel = 'AuthUser'; - $this->TestAuth->RequestHandler->ajaxLayout = 'ajax2'; - } - -/** - * add method - * - * @access public - * @return void - */ - function add() { - if ($this->TestAuth->testStop !== true) { - echo 'Added Record'; - } - } - -/** - * redirect method - * - * @param mixed $url - * @param mixed $status - * @param mixed $exit - * @access public - * @return void - */ - function redirect($url, $status = null, $exit = true) { - $this->testUrl = Router::url($url); - return false; - } -} - -/** -* AuthTest class -* -* @package cake -* @package cake.tests.cases.libs.controller.components -*/ -class AuthTest extends CakeTestCase { - -/** - * name property - * - * @var string 'Auth' - * @access public - */ - public $name = 'Auth'; - -/** - * fixtures property - * - * @var array - * @access public - */ - public $fixtures = array('core.uuid', 'core.auth_user', 'core.auth_user_custom_field', 'core.aro', 'core.aco', 'core.aros_aco', 'core.aco_action'); - -/** - * initialized property - * - * @var bool false - * @access public - */ - public $initialized = false; - -/** - * setUp method - * - * @access public - * @return void - */ - function setUp() { - parent::setUp(); - $this->_server = $_SERVER; - $this->_env = $_ENV; - - Configure::write('Security.salt', 'YJfIxfs2guVoUubWDYhG93b0qyJfIxfs2guwvniR2G0FgaC9mi'); - Configure::write('Security.cipherSeed', 770011223369876); - - Configure::write('Acl.database', 'test'); - Configure::write('Acl.classname', 'DbAcl'); - - $request = new CakeRequest(null, false); - - $this->Controller = new AuthTestController($request); - $this->Controller->Components->init($this->Controller); - $this->Controller->Components->trigger( - 'initialize', array(&$this->Controller), array('triggerDisabled' => true) - ); - $this->Controller->beforeFilter(); - - $view = new View($this->Controller); - ClassRegistry::addObject('view', $view); - - $this->Controller->Session->delete('Auth'); - $this->Controller->Session->delete('Message.auth'); - - $this->initialized = true; - Router::reload(); - } - -/** - * tearDown method - * - * @return void - */ - function tearDown() { - parent::tearDown(); - $_SERVER = $this->_server; - $_ENV = $this->_env; - - $this->Controller->Session->delete('Auth'); - $this->Controller->Session->delete('Message.auth'); - unset($this->Controller, $this->AuthUser); - } - -/** - * testNoAuth method - * - * @access public - * @return void - */ - function testNoAuth() { - $this->assertFalse($this->Controller->Auth->isAuthorized()); - } - -/** - * testIsErrorOrTests - * - * @access public - * @return void - */ - function testIsErrorOrTests() { - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->name = 'CakeError'; - $this->assertTrue($this->Controller->Auth->startup($this->Controller)); - - $this->Controller->name = 'Post'; - $this->Controller->request['action'] = 'thisdoesnotexist'; - $this->assertTrue($this->Controller->Auth->startup($this->Controller)); - - $this->Controller->scaffold = null; - $this->Controller->request['action'] = 'index'; - $this->assertFalse($this->Controller->Auth->startup($this->Controller)); - } - -/** - * testLogin method - * - * @access public - * @return void - */ - function testLogin() { - $this->AuthUser = new AuthUser(); - $user['id'] = 1; - $user['username'] = 'mariano'; - $user['password'] = Security::hash(Configure::read('Security.salt') . 'cake'); - $this->AuthUser->save($user, false); - - $authUser = $this->AuthUser->find(); - - $this->Controller->request->data['AuthUser'] = array( - 'username' => $authUser['AuthUser']['username'], 'password' => 'cake' - ); - - $this->Controller->request->addParams(Router::parse('auth_test/login')); - $this->Controller->request->query['url'] = 'auth_test/login'; - - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->loginAction = 'auth_test/login'; - $this->Controller->Auth->userModel = 'AuthUser'; - - $this->Controller->Auth->startup($this->Controller); - $user = $this->Controller->Auth->user(); - $expected = array('AuthUser' => array( - 'id' => 1, 'username' => 'mariano', 'created' => '2007-03-17 01:16:23', 'updated' => date('Y-m-d H:i:s') - )); - $this->assertEqual($user, $expected); - $this->Controller->Session->delete('Auth'); - - $this->Controller->request->data['AuthUser'] = array( - 'username' => 'blah', 'password' => '' - ); - - $this->Controller->Auth->startup($this->Controller); - - $user = $this->Controller->Auth->user(); - $this->assertNull($user); - $this->Controller->Session->delete('Auth'); - - $this->Controller->request->data['AuthUser'] = array( - 'username' => 'now() or 1=1 --', 'password' => '' - ); - - $this->Controller->Auth->startup($this->Controller); - - $user = $this->Controller->Auth->user(); - $this->assertNull($user); - $this->Controller->Session->delete('Auth'); - - $this->Controller->request->data['AuthUser'] = array( - 'username' => 'now() or 1=1 #something', 'password' => '' - ); - - $this->Controller->Auth->startup($this->Controller); - - $user = $this->Controller->Auth->user(); - $this->assertNull($user); - $this->Controller->Session->delete('Auth'); - - $this->Controller->Auth->userModel = 'UuidUser'; - $this->Controller->Auth->login('47c36f9c-bc00-4d17-9626-4e183ca6822b'); - - $user = $this->Controller->Auth->user(); - $expected = array('UuidUser' => array( - 'id' => '47c36f9c-bc00-4d17-9626-4e183ca6822b', 'title' => 'Unique record 1', 'count' => 2, 'created' => '2008-03-13 01:16:23', 'updated' => '2008-03-13 01:18:31' - )); - $this->assertEqual($user, $expected); - $this->Controller->Session->delete('Auth'); - } - -/** - * test that being redirected to the login page, with no post data does - * not set the session value. Saving the session value in this circumstance - * can cause the user to be redirected to an already public page. - * - * @return void - */ - function testLoginActionNotSettingAuthRedirect() { - $_SERVER['HTTP_REFERER'] = '/pages/display/about'; - - $this->Controller->data = array(); - $this->Controller->request->addParams(Router::parse('auth_test/login')); - $this->Controller->request->query['url'] = 'auth_test/login'; - $this->Controller->Session->delete('Auth'); - - $this->Controller->Auth->loginRedirect = '/users/dashboard'; - $this->Controller->Auth->loginAction = 'auth_test/login'; - $this->Controller->Auth->userModel = 'AuthUser'; - - $this->Controller->Auth->startup($this->Controller); - $redirect = $this->Controller->Session->read('Auth.redirect'); - $this->assertNull($redirect); - } - -/** - * testAuthorizeFalse method - * - * @access public - * @return void - */ - function testAuthorizeFalse() { - $this->AuthUser = new AuthUser(); - $user = $this->AuthUser->find(); - $this->Controller->Session->write('Auth', $user); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->authorize = false; - $this->Controller->request->addParams(Router::parse('auth_test/add')); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($result); - - $this->Controller->Session->delete('Auth'); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertFalse($result); - $this->assertTrue($this->Controller->Session->check('Message.auth')); - - $this->Controller->request->addParams(Router::parse('auth_test/camelCase')); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertFalse($result); - } - -/** - * testAuthorizeController method - * - * @access public - * @return void - */ - function testAuthorizeController() { - $this->AuthUser = new AuthUser(); - $user = $this->AuthUser->find(); - $this->Controller->Session->write('Auth', $user); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->authorize = 'controller'; - $this->Controller->request->addParams(Router::parse('auth_test/add')); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($result); - - $this->Controller->request['testControllerAuth'] = 1; - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($this->Controller->Session->check('Message.auth')); - $this->assertFalse($result); - - $this->Controller->Session->delete('Auth'); - } - -/** - * testAuthorizeModel method - * - * @access public - * @return void - */ - function testAuthorizeModel() { - $this->AuthUser = new AuthUser(); - $user = $this->AuthUser->find(); - $this->Controller->Session->write('Auth', $user); - - $this->Controller->request['controller'] = 'auth_test'; - $this->Controller->request['action'] = 'add'; - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->authorize = array('model'=>'AuthUser'); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($result); - - $this->Controller->Session->delete('Auth'); - $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($this->Controller->Session->check('Message.auth')); - $result = $this->Controller->Auth->isAuthorized(); - $this->assertFalse($result); - } - -/** - * testAuthorizeCrud method - * - * @access public - * @return void - */ - function testAuthorizeCrud() { - $this->AuthUser = new AuthUser(); - $user = $this->AuthUser->find(); - $this->Controller->Session->write('Auth', $user); - - $this->Controller->request['controller'] = 'auth_test'; - $this->Controller->request['action'] = 'add'; - - $this->Controller->Acl->name = 'DbAclTest'; - - $this->Controller->Acl->Aro->id = null; - $this->Controller->Acl->Aro->create(array('alias' => 'Roles')); - $result = $this->Controller->Acl->Aro->save(); - $this->assertFalse(empty($result)); - - $parent = $this->Controller->Acl->Aro->id; - - $this->Controller->Acl->Aro->create(array('parent_id' => $parent, 'alias' => 'Admin')); - $result = $this->Controller->Acl->Aro->save(); - $this->assertFalse(empty($result)); - - $parent = $this->Controller->Acl->Aro->id; - - $this->Controller->Acl->Aro->create(array( - 'model' => 'AuthUser', 'parent_id' => $parent, 'foreign_key' => 1, 'alias'=> 'mariano' - )); - $result = $this->Controller->Acl->Aro->save(); - $this->assertFalse(empty($result)); - - $this->Controller->Acl->Aco->create(array('alias' => 'Root')); - $result = $this->Controller->Acl->Aco->save(); - $this->assertFalse(empty($result)); - - $parent = $this->Controller->Acl->Aco->id; - - $this->Controller->Acl->Aco->create(array('parent_id' => $parent, 'alias' => 'AuthTest')); - $result = $this->Controller->Acl->Aco->save(); - $this->assertFalse(empty($result)); - - $this->Controller->Acl->allow('Roles/Admin', 'Root'); - $this->Controller->Acl->allow('Roles/Admin', 'Root/AuthTest'); - - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->authorize = 'crud'; - $this->Controller->Auth->actionPath = 'Root/'; - - $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($this->Controller->Auth->isAuthorized()); - - $this->Controller->Session->delete('Auth'); - $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($this->Controller->Session->check('Message.auth')); - } - -/** - * test authorize = 'actions' setting. - * - * @return void - */ - function testAuthorizeActions() { - $this->AuthUser = new AuthUser(); - $user = $this->AuthUser->find(); - $this->Controller->Session->write('Auth', $user); - $this->Controller->request['controller'] = 'auth_test'; - $this->Controller->request['action'] = 'add'; - - $this->Controller->Acl = $this->getMock('AclComponent', array(), array(), '', false); - $this->Controller->Acl->expects($this->atLeastOnce())->method('check')->will($this->returnValue(true)); - - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->authorize = 'actions'; - $this->Controller->Auth->actionPath = 'Root/'; - - $this->Controller->Acl->expects($this->at(0))->method('check')->with($user, 'Root/AuthTest/add'); - - $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($this->Controller->Auth->isAuthorized()); - } - -/** - * Tests that deny always takes precedence over allow - * - * @access public - * @return void - */ - function testAllowDenyAll() { - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->allow('*'); - $this->Controller->Auth->deny('add', 'camelCase'); - - $this->Controller->request['action'] = 'delete'; - $this->assertTrue($this->Controller->Auth->startup($this->Controller)); - - $this->Controller->request['action'] = 'add'; - $this->assertFalse($this->Controller->Auth->startup($this->Controller)); - - $this->Controller->request['action'] = 'camelCase'; - $this->assertFalse($this->Controller->Auth->startup($this->Controller)); - - $this->Controller->Auth->allow('*'); - $this->Controller->Auth->deny(array('add', 'camelCase')); - - $this->Controller->request['action'] = 'camelCase'; - $this->assertFalse($this->Controller->Auth->startup($this->Controller)); - } - -/** - * test the action() method - * - * @return void - */ - function testActionMethod() { - $this->Controller->request['controller'] = 'auth_test'; - $this->Controller->request['action'] = 'add'; - - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->actionPath = 'ROOT/'; - - $result = $this->Controller->Auth->action(); - $this->assertEqual($result, 'ROOT/AuthTest/add'); - - $result = $this->Controller->Auth->action(':controller'); - $this->assertEqual($result, 'ROOT/AuthTest'); - - $result = $this->Controller->Auth->action(':controller'); - $this->assertEqual($result, 'ROOT/AuthTest'); - - $this->Controller->request['plugin'] = 'test_plugin'; - $this->Controller->request['controller'] = 'auth_test'; - $this->Controller->request['action'] = 'add'; - $this->Controller->Auth->initialize($this->Controller); - $result = $this->Controller->Auth->action(); - $this->assertEqual($result, 'ROOT/TestPlugin/AuthTest/add'); - } - -/** - * test that deny() converts camel case inputs to lowercase. - * - * @return void - */ - function testDenyWithCamelCaseMethods() { - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->allow('*'); - $this->Controller->Auth->deny('add', 'camelCase'); - - $url = '/auth_test/camelCase'; - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = Router::normalize($url); - - $this->assertFalse($this->Controller->Auth->startup($this->Controller)); - } - -/** - * test that allow() and allowedActions work with camelCase method names. - * - * @return void - */ - function testAllowedActionsWithCamelCaseMethods() { - $url = '/auth_test/camelCase'; - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = Router::normalize($url); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->allow('*'); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($result, 'startup() should return true, as action is allowed. %s'); - - $url = '/auth_test/camelCase'; - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = Router::normalize($url); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->allowedActions = array('delete', 'camelCase', 'add'); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($result, 'startup() should return true, as action is allowed. %s'); - - $this->Controller->Auth->allowedActions = array('delete', 'add'); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertFalse($result, 'startup() should return false, as action is not allowed. %s'); - - $url = '/auth_test/delete'; - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = Router::normalize($url); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - - $this->Controller->Auth->allow(array('delete', 'add')); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($result, 'startup() should return true, as action is allowed. %s'); - } - - function testAllowedActionsSetWithAllowMethod() { - $url = '/auth_test/action_name'; - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = Router::normalize($url); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->allow('action_name', 'anotherAction'); - $this->assertEqual($this->Controller->Auth->allowedActions, array('action_name', 'anotherAction')); - } - -/** - * testLoginRedirect method - * - * @access public - * @return void - */ - function testLoginRedirect() { - $_SERVER['HTTP_REFERER'] = false; - $_ENV['HTTP_REFERER'] = false; - putenv('HTTP_REFERER='); - - $this->Controller->Session->write('Auth', array( - 'AuthUser' => array('id' => '1', 'username' => 'nate') - )); - - $this->Controller->request->addParams(Router::parse('users/login')); - $this->Controller->request->query['url'] = 'users/login'; - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->loginRedirect = array( - 'controller' => 'pages', 'action' => 'display', 'welcome' - ); - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize($this->Controller->Auth->loginRedirect); - $this->assertEqual($expected, $this->Controller->Auth->redirect()); - - $this->Controller->Session->delete('Auth'); - - $this->Controller->request->query['url'] = 'admin/'; - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->loginRedirect = null; - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize('admin/'); - $this->assertTrue($this->Controller->Session->check('Message.auth')); - $this->assertEqual($expected, $this->Controller->Auth->redirect()); - - $this->Controller->Session->delete('Auth'); - - //empty referer no session - $_SERVER['HTTP_REFERER'] = false; - $_ENV['HTTP_REFERER'] = false; - putenv('HTTP_REFERER='); - $url = '/posts/view/1'; - - $this->Controller->Session->write('Auth', array( - 'AuthUser' => array('id' => '1', 'username' => 'nate')) - ); - $this->Controller->testUrl = null; - $this->Controller->request->addParams(Router::parse($url)); - array_push($this->Controller->methods, 'view', 'edit', 'index'); - - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->authorize = 'controller'; - $this->Controller->request['testControllerAuth'] = true; - - $this->Controller->Auth->loginAction = array( - 'controller' => 'AuthTest', 'action' => 'login' - ); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize('/'); - $this->assertEqual($expected, $this->Controller->testUrl); - - $this->Controller->Session->delete('Auth'); - $_SERVER['HTTP_REFERER'] = $_ENV['HTTP_REFERER'] = Router::url('/admin', true); - $this->Controller->Session->write('Auth', array( - 'AuthUser' => array('id'=>'1', 'username' => 'nate') - )); - $this->Controller->request->params['action'] = 'login'; - $this->Controller->request->query['url'] = 'auth_test/login'; - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = 'auth_test/login'; - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->loginRedirect = false; - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize('/admin'); - $this->assertEqual($expected, $this->Controller->Auth->redirect()); - - //Ticket #4750 - //named params - $this->Controller->Session->delete('Auth'); - $url = '/posts/index/year:2008/month:feb'; - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = Router::normalize($url); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize('posts/index/year:2008/month:feb'); - $this->assertEqual($expected, $this->Controller->Session->read('Auth.redirect')); - - //passed args - $this->Controller->Session->delete('Auth'); - $url = '/posts/view/1'; - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = Router::normalize($url); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize('posts/view/1'); - $this->assertEqual($expected, $this->Controller->Session->read('Auth.redirect')); - - // QueryString parameters - $_back = $_GET; - $_GET = array( - 'url' => '/posts/index/29', - 'print' => 'true', - 'refer' => 'menu' - ); - $this->Controller->Session->delete('Auth'); - $url = '/posts/index/29'; - $this->Controller->request = new CakeRequest($url); - $this->Controller->request->addParams(Router::parse($url)); - - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize('posts/index/29?print=true&refer=menu'); - $this->assertEqual($expected, $this->Controller->Session->read('Auth.redirect')); - - $_GET = array( - 'url' => '/posts/index/29', - 'print' => 'true', - 'refer' => 'menu', - 'ext' => 'html' - ); - $this->Controller->Session->delete('Auth'); - $url = '/posts/index/29'; - $this->Controller->request = new CakeRequest($url); - $this->Controller->request->addParams(Router::parse($url)); - - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize('posts/index/29?print=true&refer=menu'); - $this->assertEqual($expected, $this->Controller->Session->read('Auth.redirect')); - $_GET = $_back; - - //external authed action - $_SERVER['HTTP_REFERER'] = 'http://webmail.example.com/view/message'; - $this->Controller->Session->delete('Auth'); - $url = '/posts/edit/1'; - $this->Controller->request = new CakeRequest($url); - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query = array('url' => Router::normalize($url)); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize('/posts/edit/1'); - $this->assertEqual($expected, $this->Controller->Session->read('Auth.redirect')); - - //external direct login link - $_SERVER['HTTP_REFERER'] = 'http://webmail.example.com/view/message'; - $this->Controller->Session->delete('Auth'); - $url = '/AuthTest/login'; - $this->Controller->request = new CakeRequest($url); - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = Router::normalize($url); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'AuthTest', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->startup($this->Controller); - $expected = Router::normalize('/'); - $this->assertEqual($expected, $this->Controller->Session->read('Auth.redirect')); - - $this->Controller->Session->delete('Auth'); - } - -/** - * Ensure that no redirect is performed when a 404 is reached - * And the user doesn't have a session. - * - * @return void - */ - function testNoRedirectOn404() { - $this->Controller->Session->delete('Auth'); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->request->addParams(Router::parse('auth_test/something_totally_wrong')); - $result = $this->Controller->Auth->startup($this->Controller); - $this->assertTrue($result, 'Auth redirected a missing action %s'); - } - -/** - * testEmptyUsernameOrPassword method - * - * @access public - * @return void - */ - function testEmptyUsernameOrPassword() { - $this->AuthUser = new AuthUser(); - $user['id'] = 1; - $user['username'] = 'mariano'; - $user['password'] = Security::hash(Configure::read('Security.salt') . 'cake'); - $this->AuthUser->save($user, false); - - $authUser = $this->AuthUser->find(); - - $this->Controller->request->data['AuthUser'] = array( - 'username' => '', 'password' => '' - ); - - $this->Controller->request->addParams(Router::parse('auth_test/login')); - $this->Controller->request->query['url'] = 'auth_test/login'; - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = 'auth_test/login'; - $this->Controller->Auth->userModel = 'AuthUser'; - - $this->Controller->Auth->startup($this->Controller); - $user = $this->Controller->Auth->user(); - $this->assertTrue($this->Controller->Session->check('Message.auth')); - $this->assertEqual($user, false); - $this->Controller->Session->delete('Auth'); - } - -/** - * testInjection method - * - * @access public - * @return void - */ - function testInjection() { - $this->AuthUser = new AuthUser(); - $this->AuthUser->id = 2; - $this->AuthUser->saveField('password', Security::hash(Configure::read('Security.salt') . 'cake')); - - $this->Controller->request->data['AuthUser'] = array( - 'username' => 'nate', 'password' => 'cake' - ); - - $this->Controller->request->addParams(Router::parse('auth_test/login')); - $this->Controller->request->query['url'] = 'auth_test/login'; - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->loginAction = 'auth_test/login'; - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->startup($this->Controller); - $this->assertTrue(is_array($this->Controller->Auth->user())); - - $this->Controller->Session->delete($this->Controller->Auth->sessionKey); - - $this->Controller->request->data = array( - 'AuthUser' => array( - 'username' => 'nate', - 'password' => 'cake1' - ) - ); - $this->Controller->request->query['url'] = 'auth_test/login'; - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->loginAction = 'auth_test/login'; - $this->Controller->Auth->userModel = 'AuthUser'; - $this->Controller->Auth->startup($this->Controller); - $this->assertTrue(is_null($this->Controller->Auth->user())); - - $this->Controller->Session->delete($this->Controller->Auth->sessionKey); - - $this->Controller->request->data = array( - 'AuthUser' => array( - 'username' => '> n', - 'password' => 'cake' - ) - ); - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->startup($this->Controller); - $this->assertTrue(is_null($this->Controller->Auth->user())); - - unset($this->Controller->request->data['AuthUser']['password']); - $this->Controller->request->data['AuthUser']['username'] = "1'1"; - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->startup($this->Controller); - $this->assertTrue(is_null($this->Controller->Auth->user())); - - unset($this->Controller->request->data['AuthUser']['username']); - $this->Controller->request->data['AuthUser']['password'] = "1'1"; - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->startup($this->Controller); - $this->assertTrue(is_null($this->Controller->Auth->user())); - } - -/** - * test Hashing of passwords - * - * @return void - */ - function testHashPasswords() { - $this->Controller->Auth->userModel = 'AuthUser'; - - $data['AuthUser']['password'] = 'superSecret'; - $data['AuthUser']['username'] = 'superman@dailyplanet.com'; - $return = $this->Controller->Auth->hashPasswords($data); - $expected = $data; - $expected['AuthUser']['password'] = Security::hash($expected['AuthUser']['password'], null, true); - $this->assertEqual($return, $expected); - - $data['Wrong']['password'] = 'superSecret'; - $data['Wrong']['username'] = 'superman@dailyplanet.com'; - $data['AuthUser']['password'] = 'IcantTellYou'; - $return = $this->Controller->Auth->hashPasswords($data); - $expected = $data; - $expected['AuthUser']['password'] = Security::hash($expected['AuthUser']['password'], null, true); - $this->assertEqual($return, $expected); - - $xml = array( - 'User' => array( - 'username' => 'batman@batcave.com', - 'password' => 'bruceWayne', - ) - ); - $data = new Xml($xml); - $return = $this->Controller->Auth->hashPasswords($data); - $expected = $data; - $this->assertEqual($return, $expected); - } - -/** - * testCustomRoute method - * - * @access public - * @return void - */ - function testCustomRoute() { - Router::reload(); - Router::connect( - '/:lang/:controller/:action/*', - array('lang' => null), - array('lang' => '[a-z]{2,3}') - ); - - $url = '/en/users/login'; - $this->Controller->request->addParams(Router::parse($url)); - Router::setRequestInfo($this->Controller->request); - - $this->AuthUser = new AuthUser(); - $user = array( - 'id' => 1, 'username' => 'felix', - 'password' => Security::hash(Configure::read('Security.salt') . 'cake' - )); - $user = $this->AuthUser->save($user, false); - - $this->Controller->request->data['AuthUser'] = array('username' => 'felix', 'password' => 'cake'); - $this->Controller->request->query['url'] = substr($url, 1); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('lang' => 'en', 'controller' => 'users', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - - $this->Controller->Auth->startup($this->Controller); - $user = $this->Controller->Auth->user(); - $this->assertTrue(!!$user); - - $this->Controller->Session->delete('Auth'); - Router::reload(); - Router::connect('/', array('controller' => 'people', 'action' => 'login')); - $url = '/'; - $this->Controller->request->addParams(Router::parse($url)); - Router::setRequestInfo(array($this->Controller->passedArgs, array( - 'base' => null, 'here' => $url, 'webroot' => '/', 'passedArgs' => array(), - 'argSeparator' => ':', 'namedArgs' => array() - ))); - $this->Controller->request->data['AuthUser'] = array('username' => 'felix', 'password' => 'cake'); - $this->Controller->request->query['url'] = substr($url, 1); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->loginAction = array('controller' => 'people', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - - $this->Controller->Auth->startup($this->Controller); - $user = $this->Controller->Auth->user(); - $this->assertTrue(!!$user); - } - -/** - * testCustomField method - * - * @access public - * @return void - */ - function testCustomField() { - Router::reload(); - - $this->AuthUserCustomField = new AuthUserCustomField(); - $user = array( - 'id' => 1, 'email' => 'harking@example.com', - 'password' => Security::hash(Configure::read('Security.salt') . 'cake' - )); - $user = $this->AuthUserCustomField->save($user, false); - - Router::connect('/', array('controller' => 'people', 'action' => 'login')); - $url = '/'; - $this->Controller->request->addParams(Router::parse($url)); - Router::setRequestInfo($this->Controller->request); - $this->Controller->request->data['AuthUserCustomField'] = array( - 'email' => 'harking@example.com', 'password' => 'cake' - ); - $this->Controller->request->query['url'] = substr($url, 1); - $this->Controller->Auth->initialize($this->Controller); - $this->Controller->Auth->fields = array('username' => 'email', 'password' => 'password'); - $this->Controller->Auth->loginAction = array('controller' => 'people', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUserCustomField'; - - $this->Controller->Auth->startup($this->Controller); - $user = $this->Controller->Auth->user(); - $this->assertTrue(!!$user); - } - -/** - * testAdminRoute method - * - * @access public - * @return void - */ - function testAdminRoute() { - $prefixes = Configure::read('Routing.prefixes'); - Configure::write('Routing.prefixes', array('admin')); - Router::reload(); - - $url = '/admin/auth_test/add'; - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = ltrim($url, '/'); - $this->Controller->request->base = ''; - Router::setRequestInfo($this->Controller->request); - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->loginAction = array( - 'admin' => true, 'controller' => 'auth_test', 'action' => 'login' - ); - $this->Controller->Auth->userModel = 'AuthUser'; - - $this->Controller->Auth->startup($this->Controller); - $this->assertEqual($this->Controller->testUrl, '/admin/auth_test/login'); - - Configure::write('Routing.prefixes', $prefixes); - } - -/** - * testPluginModel method - * - * @access public - * @return void - */ - function testPluginModel() { - // Adding plugins - Cache::delete('object_map', '_cake_core_'); - App::build(array( - 'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS), - 'models' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'models' . DS) - ), true); - App::objects('plugin', null, false); - - $PluginModel = ClassRegistry::init('TestPlugin.TestPluginAuthUser'); - $user['id'] = 1; - $user['username'] = 'gwoo'; - $user['password'] = Security::hash(Configure::read('Security.salt') . 'cake'); - $PluginModel->save($user, false); - - $authUser = $PluginModel->find(); - - $this->Controller->request->data['TestPluginAuthUser'] = array( - 'username' => $authUser['TestPluginAuthUser']['username'], 'password' => 'cake' - ); - - $this->Controller->request->addParams(Router::parse('auth_test/login')); - $this->Controller->request->query['url'] = 'auth_test/login'; - - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->loginAction = 'auth_test/login'; - $this->Controller->Auth->userModel = 'TestPlugin.TestPluginAuthUser'; - - $this->Controller->Auth->startup($this->Controller); - $user = $this->Controller->Auth->user(); - $expected = array('TestPluginAuthUser' => array( - 'id' => 1, 'username' => 'gwoo', 'created' => '2007-03-17 01:16:23', 'updated' => date('Y-m-d H:i:s') - )); - $this->assertEqual($user, $expected); - $sessionKey = $this->Controller->Auth->sessionKey; - $this->assertEqual('Auth.TestPluginAuthUser', $sessionKey); - - $this->Controller->Auth->loginAction = null; - $this->Controller->Auth->__setDefaults(); - $loginAction = $this->Controller->Auth->loginAction; - $expected = array( - 'controller' => 'test_plugin_auth_users', - 'action' => 'login', - 'plugin' => 'test_plugin' - ); - $this->assertEqual($loginAction, $expected); - - // Reverting changes - Cache::delete('object_map', '_cake_core_'); - App::build(); - App::objects('plugin', null, false); - } - -/** - * testAjaxLogin method - * - * @access public - * @return void - */ - function testAjaxLogin() { - App::build(array( - 'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS) - )); - $_SERVER['HTTP_X_REQUESTED_WITH'] = "XMLHttpRequest"; - - App::import('Core', 'Dispatcher'); - - ob_start(); - $Dispatcher = new Dispatcher(); - $Dispatcher->dispatch(new CakeRequest('/ajax_auth/add'), array('return' => 1)); - $result = ob_get_clean(); - - $this->assertEqual("Ajax!\nthis is the test element", str_replace("\r\n", "\n", $result)); - unset($_SERVER['HTTP_X_REQUESTED_WITH']); - } - -/** - * testLoginActionRedirect method - * - * @access public - * @return void - */ - function testLoginActionRedirect() { - $admin = Configure::read('Routing.prefixes'); - Configure::write('Routing.prefixes', array('admin')); - Router::reload(); - - $url = '/admin/auth_test/login'; - $this->Controller->request->addParams(Router::parse($url)); - $this->Controller->request->query['url'] = ltrim($url, '/'); - Router::setRequestInfo(array( - array( - 'pass' => array(), 'action' => 'admin_login', 'plugin' => null, 'controller' => 'auth_test', - 'admin' => true, 'url' => array('url' => $this->Controller->request->query['url']), - ), - array( - 'base' => null, 'here' => $url, - 'webroot' => '/', 'passedArgs' => array(), - ) - )); - - $this->Controller->Auth->initialize($this->Controller); - - $this->Controller->Auth->loginAction = array('admin' => true, 'controller' => 'auth_test', 'action' => 'login'); - $this->Controller->Auth->userModel = 'AuthUser'; - - $this->Controller->Auth->startup($this->Controller); - - $this->assertNull($this->Controller->testUrl); - - Configure::write('Routing.prefixes', $admin); - } - -/** - * Tests that shutdown destroys the redirect session var - * - * @access public - * @return void - */ - function testShutDown() { - $this->Controller->Auth->initialize($this->Controller, array('_loggedIn' => true)); - $this->Controller->Session->write('Auth.redirect', 'foo'); - $this->Controller->Auth->loggedIn(true); - - $this->Controller->Auth->shutdown($this->Controller); - $this->assertNull($this->Controller->Session->read('Auth.redirect')); - } - -/** - * test the initialize callback and its interactions with Router::prefixes() - * - * @return void - */ - function testInitializeAndRoutingPrefixes() { - $restore = Configure::read('Routing'); - Configure::write('Routing.prefixes', array('admin', 'super_user')); - Router::reload(); - $this->Controller->Auth->initialize($this->Controller); - - $this->assertTrue(isset($this->Controller->Auth->actionMap['delete'])); - $this->assertTrue(isset($this->Controller->Auth->actionMap['view'])); - $this->assertTrue(isset($this->Controller->Auth->actionMap['add'])); - $this->assertTrue(isset($this->Controller->Auth->actionMap['admin_view'])); - $this->assertTrue(isset($this->Controller->Auth->actionMap['super_user_delete'])); - - Configure::write('Routing', $restore); - } - -/** - * test $settings in Controller::$components - * - * @access public - * @return void - */ - function testComponentSettings() { - - $request = new CakeRequest(null, false); - $this->Controller = new AuthTestController($request); - - $this->Controller->components = array( - 'Auth' => array( - 'fields' => array('username' => 'email', 'password' => 'password'), - 'loginAction' => array('controller' => 'people', 'action' => 'login'), - 'userModel' => 'AuthUserCustomField', - 'sessionKey' => 'AltAuth.AuthUserCustomField' - ), - 'Session' - ); - $this->Controller->Components->init($this->Controller); - $this->Controller->Components->trigger('initialize', array(&$this->Controller)); - Router::reload(); - - $this->AuthUserCustomField = new AuthUserCustomField(); - $user = array( - 'id' => 1, 'email' => 'harking@example.com', - 'password' => Security::hash(Configure::read('Security.salt') . 'cake' - )); - $user = $this->AuthUserCustomField->save($user, false); - - Router::connect('/', array('controller' => 'people', 'action' => 'login')); - $url = '/'; - $this->Controller->request->addParams(Router::parse($url)); - Router::setRequestInfo($this->Controller->request); - $this->Controller->request->data['AuthUserCustomField'] = array( - 'email' => 'harking@example.com', 'password' => 'cake' - ); - $this->Controller->request->query['url'] = substr($url, 1); - $this->Controller->Auth->startup($this->Controller); - - $user = $this->Controller->Auth->user(); - $this->assertTrue(!!$user); - - $expected = array( - 'fields' => array('username' => 'email', 'password' => 'password'), - 'loginAction' => array('controller' => 'people', 'action' => 'login'), - 'logoutRedirect' => array('controller' => 'people', 'action' => 'login'), - 'userModel' => 'AuthUserCustomField', - 'sessionKey' => 'AltAuth.AuthUserCustomField' - ); - $this->assertEqual($expected['fields'], $this->Controller->Auth->fields); - $this->assertEqual($expected['loginAction'], $this->Controller->Auth->loginAction); - $this->assertEqual($expected['logoutRedirect'], $this->Controller->Auth->logoutRedirect); - $this->assertEqual($expected['userModel'], $this->Controller->Auth->userModel); - $this->assertEqual($expected['sessionKey'], $this->Controller->Auth->sessionKey); - } - -/** - * test that logout deletes the session variables. and returns the correct url - * - * @return void - */ - function testLogout() { - $this->Controller->Session->write('Auth.User.id', '1'); - $this->Controller->Session->write('Auth.redirect', '/users/login'); - $this->Controller->Auth->logoutRedirect = '/'; - $result = $this->Controller->Auth->logout(); - - $this->assertEqual($result, '/'); - $this->assertNull($this->Controller->Session->read('Auth.AuthUser')); - $this->assertNull($this->Controller->Session->read('Auth.redirect')); - } -} diff --git a/cake/tests/cases/libs/magic_db.test.php b/cake/tests/cases/libs/magic_db.test.php deleted file mode 100644 index 80586925b..000000000 --- a/cake/tests/cases/libs/magic_db.test.php +++ /dev/null @@ -1,193 +0,0 @@ -Db = new MagicDb(); - } -/** - * MagicDb::analyze should properly detect the file type and output additional info as requested. - * - */ - public function testAnalyze() { - $r = $this->Db->read(MagicDbTestData::get('magic.db')); - $this->assertTrue($r === true); - - $r = $this->Db->analyze(array()); - $this->assertTrue($r === false); - - $r = $this->Db->analyze(WWW_ROOT.'img'.DS.'cake.icon.gif'); - // TODO: Check several serialized file samples for accurate detection - } -/** - * MagicDb::read should properly read MagicDb databases from .php-/.db-files and plain data arguments passed in and return false if the file wasn't found or - * if the readed data did not validate. - * - */ - public function testRead() { - $this->Db->db = array(); - - $r = $this->Db->read(true); - $this->assertTrue($r === false); - $r = $this->Db->read(5); - $this->assertTrue($r === false); - - $this->Db->db = array('a'); - $r = $this->Db->read(array('foo' => 'bar')); - $this->assertTrue($r === false); - $this->assertTrue($this->Db->db === array('a')); - - $magicDb = array('header' => array(), 'database' => array()); - $r = $this->Db->read($magicDb); - $this->assertTrue($r === true); - $this->assertTrue($this->Db->db === $magicDb); - - // @TODO: Test parsing an actual magic.db file - - $r = $this->Db->read('does-not-exist.db'); - $this->assertTrue($r === false); - $this->assertTrue($this->Db->db === $magicDb); - - if (file_exists(VENDORS.'magic.php')) { - $r = $this->Db->read(VENDORS.'magic.php'); - $this->assertTrue($r === true); - $this->assertTrue($this->Db->db === array('header' => array(), 'database' => array())); - } - - $r = $this->Db->read(MagicDbTestData::get('magic.snippet.db')); - $this->assertTrue($r === true); - } -/** - * MagicDb::toArray should either return the MagicDb::db property, or the parsed array data if a magic.db dump is passed in as the first argument - * - */ - public function testToArray() { - $this->Db->db = array(); - - $r = $this->Db->toArray(); - $this->assertTrue($r === array()); - $this->Db->db = array('foo' => 'bar'); - $r = $this->Db->toArray(); - $this->assertTrue($r === array('foo' => 'bar')); - - $r = $this->Db->toArray(array('yeah')); - $this->assertTrue($r === array('yeah')); - - $r = $this->Db->toArray("# FILE_ID DB\r\n# Date:2009-10-10\r\n# Source:xxx.php"); - $this->assertTrue($r === array()); - - $r = $this->Db->toArray('foo'); - $this->assertTrue($r === array()); - - $r = $this->Db->toArray(MagicDbTestData::get('magic.snippet.db')); - $this->assertTrue($r === MagicDbTestData::get('magic.snippet.db.result')); - } -/** - * The MagicDb::validates function should return if the array passed to it or the local db property contains a valid MagicDb record set - * - */ - public function testValidates() { - $r = $this->Db->validates(array()); - $this->assertTrue($r === false); - - $r = $this->Db->validates(array('header' => true, 'database' => true)); - $this->assertTrue($r === false); - $magicDb = array('header' => array(), 'database' => array()); - $r = $this->Db->validates($magicDb); - $this->assertTrue($r === true); - - $this->Db->db = array(); - $r = $this->Db->validates(); - $this->assertTrue($r === false); - - $this->Db->db = $magicDb; - $r = $this->Db->validates(); - $this->assertTrue($r === true); - } -} -/** - * Test data holding object for MagicDb tests - * - * @package cake.tests.cases.libs - */ -/** - * MagicDbTestData class - * - * @package cake.tests.cases.libs - */ -class MagicDbTestData extends Object { -/** - * Base64 encoded data - * - * @var array - * @access public - */ - public $data = array( - 'magic.snippet.db' => 'IyBGSUxFX0lEIERCDQojIERhdGU6MjAwNS0wMy0yOQ0KIyBTb3VyY2U6aHR0cDovL3d3dy5tYWdpY2RiLm9yZw0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBoZWxwIGZpbGUNCiY5CWJ5dGUJMHgwMgkNCj4xMCBieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTEJYnl0ZQl4CS4lZA0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBhcHBsaWNhdGlvbiByZXNvdXJjZSBsaWJyYXJ5DQomOQlieXRlCTUxCQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwMDAxO2V4dD07bWltZT07XVdvcmRwZXJmZWN0IGJsb2NrIGZpbGUNCiY5CWJ5dGUJMTMJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQ=', - 'magic.snippet.db.result' => 'YToyOntzOjY6ImhlYWRlciI7YToyOntzOjQ6IkRhdGUiO3M6MTA6IjIwMDUtMDMtMjkiO3M6NjoiU291cmNlIjtzOjIyOiJodHRwOi8vd3d3Lm1hZ2ljZGIub3JnIjt9czo4OiJkYXRhYmFzZSI7YToyOntpOjA7YTo0OntpOjA7YTo0OntpOjA7czoxOiIwIjtpOjE7czo2OiJzdHJpbmciO2k6MjtzOjg6IlxceEZGV1BDIjtpOjM7czo1OToiW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBoZWxwIGZpbGUiO31pOjE7YTo0OntpOjA7czoyOiImOSI7aToxO3M6NDoiYnl0ZSI7aToyO3M6NDoiMHgwMiI7aTozO3M6MDoiIjt9aToyO2E6Mzp7aTowO3M6ODoiPjEwIGJ5dGUiO2k6MTtzOjE6IngiO2k6MjtzOjEyOiIsIHZlcnNpb24gJWQiO31pOjM7YTo0OntpOjA7czozOiI+MTEiO2k6MTtzOjQ6ImJ5dGUiO2k6MjtzOjE6IngiO2k6MztzOjM6Ii4lZCI7fX1pOjE7YTo0OntpOjA7YTo0OntpOjA7czoxOiIwIjtpOjE7czo2OiJzdHJpbmciO2k6MjtzOjg6IlxceEZGV1BDIjtpOjM7czo3ODoiW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBhcHBsaWNhdGlvbiByZXNvdXJjZSBsaWJyYXJ5Ijt9aToxO2E6NDp7aTowO3M6MjoiJjkiO2k6MTtzOjQ6ImJ5dGUiO2k6MjtzOjI6IjUxIjtpOjM7czowOiIiO31pOjI7YTo0OntpOjA7czozOiI+MTAiO2k6MTtzOjQ6ImJ5dGUiO2k6MjtzOjE6IngiO2k6MztzOjEyOiIsIHZlcnNpb24gJWQiO31pOjM7YTo0OntpOjA7czozOiI+MTEiO2k6MTtzOjQ6ImJ5dGUiO2k6MjtzOjE6IngiO2k6MztzOjM6Ii4lZCI7fX19fQ==', - 'magic.db' => 'IyBGSUxFX0lEIERCDQojIERhdGU6MjAwNS0wMy0yOQ0KIyBTb3VyY2U6aHR0cDovL3d3dy5tYWdpY2RiLm9yZw0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBoZWxwIGZpbGUNCiY5CWJ5dGUJMHgwMgkNCj4xMCBieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTEJYnl0ZQl4CS4lZA0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBhcHBsaWNhdGlvbiByZXNvdXJjZSBsaWJyYXJ5DQomOQlieXRlCTUxCQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwMDAxO2V4dD07bWltZT07XVdvcmRwZXJmZWN0IGJsb2NrIGZpbGUNCiY5CWJ5dGUJMTMJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDAwMDE7ZXh0PTttaW1lPTtdV29yZHBlcmZlY3QgY29sdW1uIGJsb2NrDQomOQlieXRlCTE1CQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwMDAxO2V4dD07bWltZT07XVdvcmRwZXJmZWN0IGRpY3Rpb25hcnkgZmlsZQ0KJjkJYnl0ZQkweDBCCQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwMDAxO2V4dD07bWltZT07XVdvcmRwZXJmZWN0IGRpY3Rpb25hcnkgcnVsZXMgZmlsZQ0KJjkJYnl0ZQkzNAkNCj4xMAlieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTEJYnl0ZQl4CS4lZA0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBleHRlcm5hbCBzcGVsbCBjb2RlIG1vZHVsZSBmaWxlDQomOQlieXRlCTQ2CQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwMDAxO2V4dD07bWltZT07XVdvcmRwZXJmZWN0IGV4dGVybmFsIHNwZWxsIGRpY3Rpb25hcnkgZmlsZQ0KJjkJYnl0ZQk0NwkNCj4xMAlieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTEJYnl0ZQl4CS4lZA0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBHcmFwaGljcyBzY3JlZW4gZHJpdmVyIGZpbGUNCiY5CWJ5dGUJMjYJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDAwMDE7ZXh0PTttaW1lPTtdV29yZHBlcmZlY3QgaHlwaGVuYXRpb24gY29kZSBtb2R1bGUgZmlsZQ0KJjkJYnl0ZQkyMwkNCj4xMAlieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTEJYnl0ZQl4CS4lZA0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBoeXBoZW5hdGlvbiBkYXRhIG1vZHVsZSBmaWxlDQomOQlieXRlCTI0CQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwMDAxO2V4dD07bWltZT07XVdvcmRwZXJmZWN0IGh5cGhlbmF0aW9uIGxleCBtb2R1bGUNCiY5CWJ5dGUJMjcJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDAwMDE7ZXh0PTttaW1lPTtdV29yZHBlcmZlY3QgaW5zdGFsbGF0aW9uIGluZm9ybWF0aW9uIGZpbGUNCiY5CWJ5dGUJNDEJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDAwMDE7ZXh0PTttaW1lPTtdV29yZHBlcmZlY3Qga2V5Ym9hcmQgZGVmaW5pdGlvbiBmaWxlDQomOQlieXRlCTB4MDMJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDAwMDE7ZXh0PTttaW1lPTtdV29yZHBlcmZlY3QgbWFjcm8gZGF0YSBmaWxlDQomOQlieXRlCTB4MDEJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDAwMDE7ZXh0PTttaW1lPTtdV29yZHBlcmZlY3QgbWFjcm8gcmVzb3VyY2UgZmlsZQ0KJjkJYnl0ZQkyNQkNCj4xMAlieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTEJYnl0ZQl4CS4lZA0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCBwcmludGVyIFEgY29kZXMgKHVzZWQgYnkgVkFYL0RHKQ0KJjkJYnl0ZQkyOAkNCj4xMAlieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTEJYnl0ZQl4CS4lZA0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMDAwMTtleHQ9O21pbWU9O11Xb3JkcGVyZmVjdCByZWN0YW5ndWxhciBibG9jayBmaWxlDQomOQlieXRlCTE0CQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwMDAxO2V4dD07bWltZT07XVdvcmRwZXJmZWN0IHNwZWxsIGNvZGUgbW9kdWxlIHJ1bGVzIGZpbGUNCiY5CWJ5dGUJMzMJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDAwMDE7ZXh0PTttaW1lPTtdV29yZHBlcmZlY3Qgc3BlbGwgY29kZSBtb2R1bGUgd29yZCBsaXN0DQomOQlieXRlCTI5CQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwMDAxO2V4dD07bWltZT07XVdvcmRwZXJmZWN0IHRoZXNhcnVzIGZpbGUNCiY5CWJ5dGUJMTIJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDAwMDE7ZXh0PTttaW1lPTtdV29yZHBlcmZlY3QgVkFYIGtleWJvYXJkIGRlZmluaXRpb24gZmlsZQ0KJjkJYnl0ZQkweDA0CQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwQUxMO2V4dD1hbGw7bWltZT07XVdvcmRwZXJmZWN0IHByaW50ZXIgcmVzb3VyY2UgZmlsZQ0KJjkJYnl0ZQkxOQkNCj4xMAlieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTEJYnl0ZQl4CS4lZA0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCVJJRkYJW2ZpZD0wMDAwMDEwMDEtMDAtMDAwMENPTjtleHQ9Y29uO21pbWU9O11NaWNyb3NvZnQgQW5pbWF0ZWQgY3Vyc29yLCBsaXR0bGUtZW5kaWFuDQomOAlzdHJpbmcJQUNPTgkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlSSUZYCVtmaWQ9MDAwMDAxMDAxLTAwLTAwMDBDT047ZXh0PWNvbjttaW1lPTtdTWljcm9zb2Z0IEFuaW1hdGVkIGN1cnNvciwgYmlnLWVuZGlhbg0KJjgJc3RyaW5nCUFDT04JDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwRE9DO2V4dD1kb2M7bWltZT07XU1hY2ludG9zaCBXb3JkcGVyZmVjdCBkb2N1bWVudCBmaWxlDQomOQlieXRlCTQ0CQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwRE9DO2V4dD1kb2M7bWltZT07XVZBWCBXb3JkcGVyZmVjdCBkb2N1bWVudCBmaWxlDQomOQlieXRlCTQ1CQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwRFJTO2V4dD1kcnM7bWltZT07XVdvcmRwZXJmZWN0IGRpc3BsYXkgcmVzb3VyY2UgZmlsZQ0KJjkJYnl0ZQkyMAkNCj4xMAlieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTEJYnl0ZQl4CS4lZA0KDQojIE1hZ2ljIElEIGZvciBXb3JkcGVyZmVjdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZXUEMJW2ZpZD0wMDAwMDEwMDgtMDAtMDAwMEZJTDtleHQ9ZmlsO21pbWU9O11Xb3JkcGVyZmVjdCBvdmVybGF5IGZpbGUNCiY5CWJ5dGUJMjEJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlQTUNDCVtmaWQ9MDAwMDAxMDAxLTAwLTAwMDBHUlA7ZXh0PWdycDttaW1lPTtdTWljcm9zb2Z0IHdpbmRvd3MgZ3JvdXAgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJYmVzaG9ydAkweEUzMTAJW2ZpZD0wMDAwMDEwMDctMDAtMDAwSU5GTztleHQ9aW5mbzttaW1lPTtdQW1pZ2Egc2hvcnRjdXQgLyBpY29uIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDBJTlM7ZXh0PWluczttaW1lPTtdV29yZHBlcmZlY3QgaW5zdGFsbGF0aW9uIGluZm9ybWF0aW9uIGZpbGUNCiY5CWJ5dGUJNDMJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCWxlbG9uZwkweDAwMDAwMDRDCVtmaWQ9MDAwMDAxMDAxLTAwLTAwMDBMTks7ZXh0PWxuazttaW1lPTtdTWljcm9zb2Z0IFdpbmRvd3Mgc2hvcnRjdXQgZmlsZQ0KJjQJc3RyaW5nCVxceDAxXFx4MTRcXHgwMgkNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTAwLTAwMDBQUlM7ZXh0PXByczttaW1lPTtdV29yZHBlcmZlY3QgcHJpbnRlciByZXNvdXJjZSBmaWxlDQomOQlieXRlCTE2CQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwUVJTO2V4dD1xcnM7bWltZT07XVdvcmRwZXJmZWN0IDUuMSBlcXVhdGlvbiByZXNvdXJjZSBmaWxlDQomOQlieXRlCTMwCQ0KPjEwCWJ5dGUJeAksIHZlcnNpb24gJWQNCj4xMQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlcXHhGRldQQwlbZmlkPTAwMDAwMTAwOC0wMC0wMDAwU0VUO2V4dD1zZXQ7bWltZT07XVdvcmRwZXJmZWN0IHNldHVwIGRhdGENCiY5CWJ5dGUJMTcJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlSSUZGCVtmaWQ9MDAwMDAxMDAxLTBFLTAwMDBQQUw7ZXh0PXBhbCxyaWZmO21pbWU9O11NaWNyb3NvZnQgUGFsZXR0ZSwgbGl0dGxlLWVuZGlhbg0KJjgJc3RyaW5nCVBBTAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlSSUZYCVtmaWQ9MDAwMDAxMDAxLTBFLTAwMDBQQUw7ZXh0PXBhbCxyaWZ4O21pbWU9O11NaWNyb3NvZnQgUGFsZXR0ZSwgYmlnLWVuZGlhbg0KJjgJc3RyaW5nCVBBTAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNCBieSBDYXJsDQowCXN0cmluZwlET1MJW2ZpZD0wMDAwMDEwMDctMEYtMDAwMEFERjtleHQ9YWRmO21pbWU9O11BbWlnYU9TIEZpbGUgc3lzdGVtDQomMwlieXRlJjB4ZjgJMAkNCj4zCWJ5dGUmMQkwCSwgT0ZTDQo+MwlieXRlJjEJMQksIEZGUw0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTExIGJ5IENhcmwNCjAJYmVsb25nCTB4MDNGMwlbZmlkPTAwMDAwMTAwNy0xMC1MSUJSQVJZO2V4dD0sbGlicmFyeTttaW1lPTtdQW1pZ2EgQ2xhc3NpYyBleGVjdXRhYmxlIGZpbGUgKDY4MHgwIGZhbWlseSkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlcXHg3ZkVMRglbZmlkPTAwMDAwMDAwMy0xMC0wMDAwMDBPO2V4dD0sbyxzbyxvdXQ7bWltZT07XUV4ZWN1dGFibGUgbGlua2FibGUgZmlsZSAoRUxGKQ0KJjQJYnl0ZQk9MQksIDMyLWJpdA0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCVxceDdmRUxGCVtmaWQ9MDAwMDAwMDAzLTEwLTAwMDAwME87ZXh0PSxvLHNvLG91dDttaW1lPTtdRXhlY3V0YWJsZSBsaW5rYWJsZSBmaWxlIChFTEYpDQomNAlieXRlCT0yCSwgNjQtYml0DQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTQgYnkgQ2FybA0KMAlzdHJpbmcJTVoJW2ZpZD0wMDAwMDEwMDEtMTAtMDAwMEVYRTtleHQ9ZXhlLGRsbDttaW1lPTtdTmV3IGV4ZWN1dGFibGUgZmlsZQ0KJjB4MTgJbGVzaG9ydAk+MHgzRgkNCiYoNjAubCkJc3RyaW5nCU5FCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTE0IGJ5IENhcmwNCjAJc3RyaW5nCVpNCVtmaWQ9MDAwMDAxMDAxLTEwLTAwMDBFWEU7ZXh0PWV4ZSxkbGw7bWltZT07XU5ldyBleGVjdXRhYmxlIGZpbGUNCiYweDE4CWxlc2hvcnQJPjB4M0YJDQomKDYwLmwpCXN0cmluZwlORQkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xNCBieSBDYXJsDQowCXN0cmluZwlNWglbZmlkPTAwMDAwMTAwMS0xMC0wMDAwRVhFO2V4dD1leGUsZGxsO21pbWU9O11NaWNyb3NvZnQgV2luZG93cyAzLnggTmV3IEV4ZWN1dGFibGUgZmlsZQ0KJjB4MTgJbGVzaG9ydAk+MHgzRgkNCiYoNjAubCkJc3RyaW5nCU5FCQ0KJig2MC5sKzU0KQlieXRlCTB4MDIJDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTQgYnkgQ2FybA0KMAlzdHJpbmcJWk0JW2ZpZD0wMDAwMDEwMDEtMTAtMDAwMEVYRTtleHQ9ZXhlLGRsbDttaW1lPTtdTWljcm9zb2Z0IFdpbmRvd3MgMy54IE5ldyBFeGVjdXRhYmxlIGZpbGUNCiYweDE4CWxlc2hvcnQJPjB4M0YJDQomKDYwLmwpCXN0cmluZwlORQkNCiYoNjAubCs1NCkJYnl0ZQkweDAyCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTE0IGJ5IENhcmwNCjAJc3RyaW5nCU1aCVtmaWQ9MDAwMDAxMDA5LTEwLTAwMDBFWEU7ZXh0PWV4ZSxkbGw7bWltZT07XUlCTSBPUy8yIE5ldyBFeGVjdXRhYmxlIGZpbGUNCiYweDE4CWxlc2hvcnQJPjB4M0YJDQomKDYwLmwpCXN0cmluZwlORQkNCiYoNjAubCs1NCkJYnl0ZQkweDAxCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTE0IGJ5IENhcmwNCjAJc3RyaW5nCVpNCVtmaWQ9MDAwMDAxMDA5LTEwLTAwMDBFWEU7ZXh0PWV4ZSxkbGw7bWltZT07XUlCTSBPUy8yIE5ldyBFeGVjdXRhYmxlIGZpbGUNCiYweDE4CWxlc2hvcnQJPjB4M0YJDQomKDYwLmwpCXN0cmluZwlORQkNCiYoNjAubCs1NCkJYnl0ZQkweDAxCQ0KDQojIE1hZ2ljIElEIGZvciBNaWNyb3NvZnQgV2luZG93cyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTMgYnkgQ2FybA0KMAlzdHJpbmcJTVoJW2ZpZD0wMDAwMDEwMDEtMTAtMDAwMEVYRTtleHQ9ZXhlLGRsbDttaW1lPTtdTWljcm9zb2Z0IFdpbmRvd3MgTlQgUG9ydGFibGUgRXhlY3V0YWJsZSBmaWxlDQomMHgxOAlsZXNob3J0CTB4NDAJDQomKDYwLmwpCXN0cmluZwlQRVxceDAwXFx4MDAJDQoNCiMgTWFnaWMgSUQgZm9yIE1pY3Jvc29mdCBXaW5kb3dzIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMyBieSBDYXJsDQowCXN0cmluZwlaTQlbZmlkPTAwMDAwMTAwMS0xMC0wMDAwRVhFO2V4dD1leGUsZGxsO21pbWU9O11NaWNyb3NvZnQgV2luZG93cyBOVCBQb3J0YWJsZSBFeGVjdXRhYmxlIGZpbGUNCiYweDE4CWxlc2hvcnQJMHg0MAkNCiYoNjAubCkJc3RyaW5nCVBFXFx4MDBcXHgwMAkNCg0KIyBNYWdpYyBJRCBmb3IgTWljcm9zb2Z0IFdpbmRvd3MsRE9TNEdXIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xNCBieSBDYXJsDQowCXN0cmluZwlNWglbZmlkPTAwMDAwMTAwMS0xMC0wMDAwRVhFO2V4dD1leGUsZGxsLGRydjttaW1lPTtdTWljcm9zb2Z0IFdpbmRvd3MgTGluZWFyIGV4ZWN1dGFibGUNCiYweDE4CWxlc2hvcnQJPjB4M0YJDQomKDYwLmwpCXN0cmluZwlMRQkNCg0KIyBNYWdpYyBJRCBmb3IgTWljcm9zb2Z0IFdpbmRvd3MsRE9TNEdXIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xNCBieSBDYXJsDQowCXN0cmluZwlaTQlbZmlkPTAwMDAwMTAwMS0xMC0wMDAwRVhFO2V4dD1leGUsZGxsLGRydjttaW1lPTtdTWljcm9zb2Z0IFdpbmRvd3MgTGluZWFyIGV4ZWN1dGFibGUNCiYweDE4CWxlc2hvcnQJPjB4M0YJDQomKDYwLmwpCXN0cmluZwlMRQkNCg0KIyBNYWdpYyBJRCBmb3IgT1MvMixET1M0R1cgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTE0IGJ5IENhcmwNCjAJc3RyaW5nCU1aCVtmaWQ9MDAwMDAxMDA5LTEwLTAwMDBFWEU7ZXh0PWV4ZSxkbGwsZHJ2O21pbWU9O11PUy8yIExpbmVhciBleGVjdXRhYmxlDQomMHgxOAlsZXNob3J0CT4weDNGCQ0KJig2MC5sKQlzdHJpbmcJTFgJDQoNCiMgTWFnaWMgSUQgZm9yIE9TLzIsRE9TNEdXIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xNCBieSBDYXJsDQowCXN0cmluZwlaTQlbZmlkPTAwMDAwMTAwOS0xMC0wMDAwRVhFO2V4dD1leGUsZGxsLGRydjttaW1lPTtdT1MvMiBMaW5lYXIgZXhlY3V0YWJsZQ0KJjB4MTgJbGVzaG9ydAk+MHgzRgkNCiYoNjAubCkJc3RyaW5nCUxYCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA3LTMwIGJ5IENhcmwNCjAJc3RyaW5nCU1TRlQJW2ZpZD0wMDAwMDEwMDEtMTAtMDAwMFRMQjtleHQ9dGxiO21pbWU9O11NaWNyb3NvZnQgY29tcG9uZW50IHR5cGUgbGlicmFyeQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTExIGJ5IENhcmwNCjAJYmVzaG9ydAkweDYwMUEJW2ZpZD0wMDAwMDEwMDYtMTAtMDAwMFRUUDtleHQ9dHRwLGdlbSxwcmc7bWltZT07XUF0YXJpIE1pTlQgZXhlY3V0YWJsZS9vYmplY3QgZmlsZQ0KJjB4MTIJc3RyaW5nCU1pTlQJDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMTEgYnkgQ2FybA0KMAliZXNob3J0CTB4NjAxQQlbZmlkPTAwMDAwMTAwNi0xMC0wMDAwVFRQO2V4dD10dHAsZ2VtLHByZzttaW1lPTtdQXRhcmkgVE9TIGV4ZWN1dGFibGUvb2JqZWN0IGZpbGUNCiYweDEyCWJlbG9uZwkweDAwMDAJDQoNCiMgTWFnaWMgSUQgZm9yIFZpcnR1YWwgUGFzY2FsIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNy0zMCBieSBDYXJsDQowCXN0cmluZwlWUEkJW2ZpZD0wMDAwMDAwMDAtMTAtMDAwMFZQSTtleHQ9dnBpO21pbWU9O11WaXJ0dWFsIHBhc2NhbCB1bml0IGZpbGUNCiYweDAzCWJ5dGUJPjQ3CQ0KJjB4MDMJYnl0ZQk8NTgJDQoNCiMgTWFnaWMgSUQgZm9yIEphdmEgY29tcGlsZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTExIGJ5IENhcmwNCjAJYmVsb25nCTB4Q0FGRUJBQkUJW2ZpZD0wMDAwMDEwMTEtMTEtMDBDTEFTUztleHQ9Y2xhc3M7bWltZT07XUphdmFsIHZpcnR1YWwgbWFjaGluZSBjbGFzcyBmaWxlDQo+NgliZXNob3J0CXgJLCB2ZXJzaW9uICVkDQo+NAliZXNob3J0CXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIEJvcmxhbmQgRGVscGhpIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNy0zMCBieSBDYXJsDQowCXN0cmluZwlQS0cJW2ZpZD0wMDAwMDEwMDUtMTEtMDAwMERDUDtleHQ9ZGNwO21pbWU9O11Cb3JsYW5kIERlbHBoaSBjb21waWxlZCBwYWNrYWdlIGNvZGUgZmlsZQ0KJjB4MDMJYnl0ZQk+NDcJDQomMHgwMwlieXRlCTw1OAkNCg0KIyBNYWdpYyBJRCBmb3IgQm9ybGFuZCBEZWxwaGkgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA3LTMwIGJ5IENhcmwNCjAJc3RyaW5nCVxceERGXFx4MDBcXHgwMFxceDBGCVtmaWQ9MDAwMDAxMDA1LTExLTAwMDBEQ1U7ZXh0PWRjdTttaW1lPTtdQm9ybGFuZCBEZWxwaGkgY29kZSB1bml0IGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgVHVyYm8gUGFzY2FsIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNy0yOSBieSBDYXJsDQowCXN0cmluZwlUUFU5CVtmaWQ9MDAwMDAxMDA1LTExLTAwMDBUUFU7ZXh0PXRwdTttaW1lPTtdVHVyYm8gUGFzY2FsIDYuMCBjb2RlIHVuaXQgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBUdXJibyBQYXNjYWwsIEJvcmxhbmQgUGFzY2FsIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNy0yOSBieSBDYXJsDQowCXN0cmluZwlUUFVRCVtmaWQ9MDAwMDAxMDA1LTExLTAwMDBUUFU7ZXh0PXRwdSx0cHAsdHB3O21pbWU9O11Cb3JsYW5kIFBhc2NhbCA3LjAgY29kZSB1bml0IGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQoyCXN0cmluZwlBRExJQi0JW2ZpZD0wMDAwMDEwMTYtMjAtMDAwMEJOSztleHQ9Ym5rO21pbWU9O11BZGxpYiBGTSBpbnN0cnVtZW50IGJhbmsgZmlsZQ0KPjAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjEJYnl0ZQl4CS4lZA0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE2IGJ5IENhcmwNCjAJc3RyaW5nCUlCS1xceDFBCVtmaWQ9MDAwMDAxMDEzLTIwLTAwMDBJQks7ZXh0PWliazttaW1lPTtdQ3JlYXRpdmUgTGFicyBGTSBpbnN0cnVtZW50IGJhbmsgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBNaWNyb3NvZnQgSW5zdHJ1bWVudCBEZWZpbml0aW9uIGZpbGUgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA0IGJ5IENhcmwNCjAJc3RyaW5nCVJJRkYJW2ZpZD0wMDAwMDEwMDEtMjAtMDAwMElERjtleHQ9aWRmO21pbWU9O11NaWNyb3NvZnQgaW5zdHJ1bWVudCBkZWZpbml0aW9uIGZpbGUsIGxpdHRsZS1lbmRpYW4NCiY4CXN0cmluZwlJREZcXCAJDQoNCiMgTWFnaWMgSUQgZm9yIE1pY3Jvc29mdCBJbnN0cnVtZW50IERlZmluaXRpb24gZmlsZSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJUklGWAlbZmlkPTAwMDAwMTAwMS0yMC0wMDAwSURGO2V4dD1pZGY7bWltZT07XU1pY3Jvc29mdCBpbnN0cnVtZW50IGRlZmluaXRpb24gZmlsZSwgYmlnLWVuZGlhbg0KJjgJc3RyaW5nCUlERlxcIAkNCg0KIyBNYWdpYyBJRCBmb3IgRGlnaXRyYWtrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA0IGJ5IENhcmwNCjAJc3RyaW5nCURJU1QJW2ZpZD0wMDAxMDAwODgtMjAtMDAwMElTVDtleHQ9aXN0O21pbWU9O11EaWdpdHJha2tlciBJbnN0cnVtZW50IGZpbGUNCiY0CWJ5dGUJPDIJDQoNCiMgTWFnaWMgSUQgZm9yIEltcHVsc2UgdHJhY2tlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJSU1QSQlbZmlkPTAwMDEwMDAzMi0yMC0wMDAwSVRJO2V4dD1pdGk7bWltZT07XUltcHVsc2UgdHJhY2tlciBpbnN0cnVtZW50IGZpbGUNCj4weDIwCXN0cmluZwl4CVt0aXRsZT0lLjI2c10NCg0KIyBNYWdpYyBJRCBmb3IgTWFkdHJhY2tlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDUgYnkgQ2FybA0KMAlzdHJpbmcJTUkyMQlbZmlkPTAwMDEwMDA5MS0yMC0wMDAwTVRJO2V4dD1tdGk7bWltZT07XU1hZHRyYWNrZXIgaW5zdHJ1bWVudCBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEdyYXZpcyBVbHRyYXNvdW5kIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlHRjFQQVRDSDEwMFxcMElEIzAwMDAwMlxcMAlbZmlkPTAwMDAwMTAxOC0yMC0wMDAwUEFUO2V4dD1wYXQ7bWltZT07XUdyYXZpcyBVbHRyYXNvdW5kIFBhdGNoIChvbGQgaW5zdHJ1bWVudCBkYXRhKQ0KDQojIE1hZ2ljIElEIGZvciBHcmF2aXMgVWx0cmFzb3VuZCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMAlzdHJpbmcJR0YxUEFUQ0gxMTBcXDBJRCMwMDAwMDJcXDAJW2ZpZD0wMDAwMDEwMTgtMjAtMDAwMFBBVDtleHQ9cGF0O21pbWU9O11HcmF2aXMgVWx0cmFzb3VuZCBQYXRjaCAoaW5zdHJ1bWVudCBkYXRhKQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjAJc3RyaW5nCVNCSVxceDFBCVtmaWQ9MDAwMDAxMDEzLTIwLTAwMDBTQkk7ZXh0PXNiaTttaW1lPTtdQ3JlYXRpdmUgTGFicyBGTSBpbnN0cnVtZW50IGRhdGEgZmlsZQ0KPjQJc3RyaW5nCT4wCVt0aXRsZT0lLjMyc10NCg0KIyBNYWdpYyBJRCBmb3IgU2lkcGxheSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDUgYnkgQ2FybA0KMAlzdHJpbmcJU0lEUExBWVxcIElORk9GSUxFCVtmaWQ9MDAwMDAwMDAwLTIwLTAwMDBTSUQ7ZXh0PXNpZDttaW1lPTtdU0lEUGxheWVyIG11c2ljIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgRmFzdHRyYWNrZXIgMi4wIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlFeHRlbmRlZFxcIEluc3RydW1lbnQ6XFwgCVtmaWQ9MDAwMTAwMDI2LTIwLTAwMDAwWEk7ZXh0PXhpO21pbWU9O11GYXN0VHJhY2tlciBJSSBpbnN0cnVtZW50IGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlSSUZGCVtmaWQ9MDAwMDAxMDAxLTIxLTAwMDAwMDA7ZXh0PTttaW1lPTtdTUlESSBtdXNpYyBmaWxlLCBsaXR0bGUtZW5kaWFuDQomOAlzdHJpbmcJUk1JRAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlSSUZYCVtmaWQ9MDAwMDAxMDAxLTIxLTAwMDAwMDA7ZXh0PTttaW1lPTtdTUlESSBtdXNpYyBmaWxlLCBiaWctZW5kaWFuDQomOAlzdHJpbmcJUk1JRAkNCg0KIyBNYWdpYyBJRCBmb3IgQWJ5c3NcJ3MgaGlnaGVzdCBleHBlcmllbmNlIChBSFgpIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlUSFgJW2ZpZD0wMDAxMDAwMjktMjEtMDAwMEFIWDtleHQ9YWh4O21pbWU9O11BSFggbW9kdWxlIG11c2ljIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQW11c2ljIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQoxMDYyCXN0cmluZwlcXHgzY1xceDZmXFx4ZWZcXHg1MVxceDU1XFx4RUVcXHg1MlxceDZGXFx4NTIJW2ZpZD0wMDAxMDAwMzQtMjEtMDAwMEFNRDtleHQ9YW1kO21pbWU9O11BbXVzaWMgQWRsaWIgdHJhY2tlciBtdXNpYyBmaWxlDQo+MAlzdHJpbmcJPlxceDAwCVt0aXRsZT0lLjIzc10NCj4yNAlzdHJpbmcJPlxcMAlbY3JlYXRvcj0lLjI0c10NCg0KIyBNYWdpYyBJRCBmb3IgVmVsdmV0IFN0dWRpbyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMAlzdHJpbmcJQU1TaGRyXFx4MWEJW2ZpZD0wMDAwMDEyNzYtMjEtMDAwMEFNUztleHQ9YW1zO21pbWU9O11WZWx2ZXQgU3R1ZGlvIG1vZHVsZSBtdXNpYyBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEF1ZGlvIHZpc3VhbCByZXNlYXJjaCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJMkJJVAlbZmlkPTAwMDAwMTMwMS0yMS0wMDAwQVZSO2V4dD1hdnI7bWltZT07XUF1ZGlvIHZpc3VhbCByZXNlYXJjaCBhdWRpbyBmaWxlDQo+NAlzdHJpbmcJeAlbdGl0bGU9JS44c10NCg0KIyBNYWdpYyBJRCBmb3IgU291bmRtb24gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjI2CXN0cmluZwlWLjIJW2ZpZD0wMDAxMDAwMjgtMjEtMDAwMDBCUDtleHQ9YnA7bWltZT07XVNvdW5kbW9uIG1vZHVsZSBtdXNpYyBmaWxlLCB2ZXJzaW9uIDIueA0KPjAJc3RyaW5nCT5cXDAJW3RpdGxlPSUuMjZzXQ0KDQojIE1hZ2ljIElEIGZvciBTb3VuZG1vbiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMjYJc3RyaW5nCVYuMwlbZmlkPTAwMDEwMDAyOC0yMS0wMDAwQlAzO2V4dD1icDM7bWltZT07XVNvdW5kbW9uIG1vZHVsZSBtdXNpYyBmaWxlLCB2ZXJzaW9uIDMueA0KPjAJc3RyaW5nCT5cXDAJW3RpdGxlPSUuMjZzXQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjAJc3RyaW5nCUNUTUYJW2ZpZD0wMDAwMDEwMTMtMjEtMDAwMENNRjtleHQ9Y21mO21pbWU9O11DcmVhdGl2ZSBMYWJzIG11c2ljIGZpbGUNCj40CWJ5dGUJeAksIHZlcnNpb24gJWQNCj41CWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgRGlnaWJvb3N0ZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA0IGJ5IENhcmwNCjAJc3RyaW5nCURJR0kgQm9vc3RlciBtb2R1bGVcXDAJW2ZpZD0wMDAwMDEzMDItMjEtMDAwRElHSTtleHQ9ZGlnaTttaW1lPTtdRGlnaWJvb3N0ZXIgbXVzaWMgZmlsZQ0KPjYxMAlzdHJpbmcJeAlbdGl0bGU9JS4zMnNdDQoNCiMgTWFnaWMgSUQgZm9yIERlbHVzaW9uIFh0cmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlERE1GCVtmaWQ9MDAwMDAwMDAwLTIxLTAwMDBETUY7ZXh0PWRtZjttaW1lPTtdRGVsdXNpb24gdHJhY2tlciBtb2R1bGUgbXVzaWMgZmlsZQ0KPjQJYnl0ZQl4CSwgdmVyc2lvbiAlZC4wDQo+MTMJc3RyaW5nCT5cXDAJW3RpdGxlPSUuMzBzXQ0KPjQzCXN0cmluZwk+XFwwCVtjcmVhdG9yPSUuMjBzXQ0KDQojIE1hZ2ljIElEIGZvciBET1MgU291bmQgaW50ZXJmYWNlIGtpdCAoRFNJSykgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjAJc3RyaW5nCVJJRkYJW2ZpZD0wMDAwMDAwMDAtMjEtMDAwMERTTTtleHQ9ZHNtO21pbWU9O11ET1MgU291bmQgaW50ZXJmYWNlIGtpdCBtb2R1bGUgbXVzaWMgZmlsZQ0KJjgJc3RyaW5nCURTTUYJDQoNCiMgTWFnaWMgSUQgZm9yIEVkbGliIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNyBieSBDYXJsDQowCXN0cmluZwlcXHgwMFxceDA2XFx4RkVcXHhGRAlbZmlkPTAwMDEwMDAyNy0yMS0wMDAwRURMO2V4dD1lZGw7bWltZT07XUVkbGliIEZNIHRyYWNrZXIgbXVzaWMgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBRdWFkcmEgQ29tcG9zZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA0IGJ5IENhcmwNCjAJc3RyaW5nCUZPUk0JW2ZpZD0wMDAxMDAwODUtMjEtMDAwMEVNRDtleHQ9ZW1kO21pbWU9O11FbmhhbmNlZCBtb2R1bGUgbXVzaWMgZmlsZSAoSUZGKQ0KJjgJc3RyaW5nCUVNT0QJDQoNCiMgTWFnaWMgSUQgZm9yIEZhcmFuZG9sZSBjb21wb3NlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMAlzdHJpbmcJRkFSXFx4RkUJW2ZpZD0wMDAxMDAwODctMjEtMDAwMEZBUjtleHQ9ZmFyO21pbWU9O11GYXJhbmRvbGUgY29tcG9zZXIgbW9kdWxlIG11c2ljIGZpbGUNCj40CXN0cmluZwk+XFwwCVt0aXRsZT0lLjQwc10NCg0KIyBNYWdpYyBJRCBmb3IgRnVua3RyYWNrZXIgR29sZCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJRnVuawlbZmlkPTAwMDEwMDA4Ni0yMS0wMDAwRk5LO2V4dD1mbms7bWltZT07XUZ1bmt0cmFja2VyIEdvbGQgbXVzaWMgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBCZWxscywgV2hpc3RsZXMsIGFuZCBTb3VuZCBCb2FyZHMgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE2IGJ5IENhcmwNCjAJc3RyaW5nCUdETVxceEZFCVtmaWQ9MDAwMDAxMjgwLTIxLTAwMDBHRE07ZXh0PWdkbTttaW1lPTtdR2VuZXJhbCBEaWdpTXVzaWMgbW9kdWxlIG11c2ljIGZpbGUNCj40CXN0cmluZwk+XFx4MDAJW3RpdGxlPSUuMzJzXQ0KDQojIE1hZ2ljIElEIGZvciBHcmFvdW1mIFRyYWNrZXIgMiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMAlzdHJpbmcJR1QyCVtmaWQ9MDAwMTAwMDMxLTIxLTAwMDBHVDI7ZXh0PWd0MjttaW1lPTtdR3Jhb3VtZiBUcmFja2VyIG1vZHVsZSBtdXNpYyBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEltYWdvIE1vcnBoZXVzIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNCBieSBDYXJsDQoweDNDCXN0cmluZwlJTTEwCVtmaWQ9MDAwMDAxMjc5LTIxLTAwMDBJTUY7ZXh0PWltZjttaW1lPTtdSW1hZ28gbW9ycGhldXMgbXVzaWMgZmlsZSwgMzIgY2hhbm5lbHMNCj4wCXN0cmluZwl4CVt0aXRsZT0lLjMxc10NCg0KIyBNYWdpYyBJRCBmb3IgSW1wdWxzZSB0cmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlJTVBNCVtmaWQ9MDAwMTAwMDMyLTIxLTAwMDAwSVQ7ZXh0PWl0O21pbWU9O11JbXB1bHNlIFRyYWNrZXIgbW9kdWxlIG11c2ljIGZpbGUNCj40CXN0cmluZwk+XFx4MDAJW3RpdGxlPSUuMjZzXQ0KDQojIE1hZ2ljIElEIGZvciBKYW1jcmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNCBieSBDYXJsDQowCXN0cmluZwlCZUVwCVtmaWQ9MDAwMDAwMDAwLTIxLTAwMDBKQU07ZXh0PWphbTttaW1lPTtdSmFtY3JhY2tlciB0cmFja2VyIG1vZHVsZSBtdXNpYyBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIExpcXVpZCB0cmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNCBieSBDYXJsDQowCXN0cmluZwlMaXF1aWQgTW9kdWxlOglbZmlkPTAwMDEwMDA5MC0yMS0wMDAwTElRO2V4dD1saXE7bWltZT07XUxpcXVpZCB0cmFja2VyIG1vZHVsZSBtdXNpYyBmaWxlDQomMHg0MAlieXRlCTB4MUEJDQo+MHgwRQlzdHJpbmcJPlxcMAlbdGl0bGU9JS4zMHNdDQo+MHgyYwlzdHJpbmcJPlxcMAlbY3JlYXRvcj0lLjIwc10NCg0KIyBNYWdpYyBJRCBmb3IgRGlnaXRyYWtrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA0IGJ5IENhcmwNCjAJc3RyaW5nCURNREwJW2ZpZD0wMDAxMDAwODgtMjEtMDAwME1ETDtleHQ9bWRsO21pbWU9O11EaWdpdHJha2tlciBtb2R1bGUgbXVzaWMgZmlsZQ0KJjQJYnl0ZQk8MHgxMgkNCg0KIyBNYWdpYyBJRCBmb3IgTUVEIFNvdW5kc3R1ZGlvIC8gT2N0YU1FRCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMAlzdHJpbmcJTU1EMAlbZmlkPTAwMDAwMTI3OC0yMS0wMDAwTUVEO2V4dD1tZWQ7bWltZT07XU9jdGFtZWQgdHJhY2tlciBtb2R1bGUgbXVzaWMgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBNRUQgU291bmRzdHVkaW8gLyBPY3RhTUVEIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlNTUQxCVtmaWQ9MDAwMDAxMjc4LTIxLTAwMDBNRUQ7ZXh0PW1lZDttaW1lPTtdT2N0YW1lZCBQcm8gVHJhY2tlciBtb2R1bGUgbXVzaWMgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBNRUQgU291bmRzdHVkaW8gLyBPY3RhTUVEIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlNTUQyCVtmaWQ9MDAwMDAxMjc4LTIxLTAwMDBNRUQ7ZXh0PW1lZDttaW1lPTtdT2N0YW1lZCBQcm8gVHJhY2tlciBtb2R1bGUgbXVzaWMgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBNRUQgU291bmRzdHVkaW8gLyBPY3RhTUVEIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlNTUQzCVtmaWQ9MDAwMDAxMjc4LTIxLTAwMDBNRUQ7ZXh0PW1lZDttaW1lPTtdT2N0YW1lZCBTb3VuZCBTdHVkaW8gbW9kdWxlIG11c2ljIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgTXVzaWNsaW5lIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNSBieSBDYXJsDQowCXN0cmluZwlNTEVETU9ETAlbZmlkPTAwMDAwMTMwNC0yMS0wMDAwME1MO2V4dD1tbDttaW1lPTtdTXVzaWNsaW5lIG1vZHVsZSBtdXNpYyBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFByb3RyYWNrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjEwODAJc3RyaW5nCU0hSyEJW2ZpZD0wMDAxMDAwMjItMjEtMDAwME1PRDtleHQ9bW9kO21pbWU9O11Qcm90cmFja2VyIDIuMyBtb2R1bGUgbXVzaWMgZmlsZQ0KPjAJc3RyaW5nCT5cXDAJW3RpdGxlPSUuMjBzXQ0KDQojIE1hZ2ljIElEIGZvciBQcm90cmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQoxMDgwCXN0cmluZwlNLksuCVtmaWQ9MDAwMTAwMDIyLTIxLTAwMDBNT0Q7ZXh0PW1vZDttaW1lPTtdUHJvdHJhY2tlciBtb2R1bGUgbXVzaWMgZmlsZQ0KPjAJc3RyaW5nCT5cXDAJW3RpdGxlPSUuMjBzXQ0KDQojIE1hZ2ljIElEIGZvciBQcm90cmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNSBieSBDYXJsDQowCXN0cmluZwlGT1JNCVtmaWQ9MDAwMTAwMDIyLTIxLTAwMDBNT0Q7ZXh0PW1vZDttaW1lPTtdUHJvdHJhY2tlciBtb2R1bGUgbXVzaWMgZmlsZSwgdmVyc2lvbiAzLngNCiY4CXN0cmluZwlNT0RMCQ0KDQojIE1hZ2ljIElEIGZvciBTdGFydHJla2tlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMTA4MAlzdHJpbmcJRkxUNAlbZmlkPTAwMDEwMDAyNC0yMS0wMDAwTU9EO2V4dD1tb2Q7bWltZT07XVN0YXJ0cmVra2VyIG1vZHVsZSBtdXNpYyBmaWxlLCA0IGNoYW5uZWxzDQo+MAlzdHJpbmcJPlxcMAlbdGl0bGU9JS4yMHNdDQoNCiMgTWFnaWMgSUQgZm9yIFN0YXJ0cmVra2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQoxMDgwCXN0cmluZwlGTFQ4CVtmaWQ9MDAwMTAwMDI0LTIxLTAwMDBNT0Q7ZXh0PW1vZDttaW1lPTtdU3RhcnRyZWtrZXIgbW9kdWxlIG11c2ljIGZpbGUsIDggY2hhbm5lbHMNCj4wCXN0cmluZwk+XFwwCVt0aXRsZT0lLjIwc10NCg0KIyBNYWdpYyBJRCBmb3IgRmFzdHRyYWNrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjEwODAJc3RyaW5nCTZDSE4JW2ZpZD0wMDAwMDEyNzUtMjEtMDAwME1PRDtleHQ9bW9kO21pbWU9O11GYXN0dHJhY2tlciBtb2R1bGUgbXVzaWMgZmlsZSwgNiBjaGFubmVscw0KPjAJc3RyaW5nCT5cXDAJW3RpdGxlPSUuMjBzXQ0KDQojIE1hZ2ljIElEIGZvciBGYXN0dHJhY2tlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMTA4MAlzdHJpbmcJOENITglbZmlkPTAwMDAwMTI3NS0yMS0wMDAwTU9EO2V4dD1tb2Q7bWltZT07XUZhc3R0cmFja2VyIG1vZHVsZSBtdXNpYyBmaWxlLCA2IGNoYW5uZWxzDQo+MAlzdHJpbmcJPlxcMAlbdGl0bGU9JS4yMHNdDQoNCiMgTWFnaWMgSUQgZm9yIE1hZHRyYWNrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA1IGJ5IENhcmwNCjAJc3RyaW5nCU1UMjAJW2ZpZD0wMDAxMDAwOTEtMjEtMDAwME1UMjtleHQ9bXQyO21pbWU9O11NYWR0cmFja2VyIG1vZHVsZSBtdXNpYyBmaWxlDQo+NDIJc3RyaW5nCXgJW3RpdGxlPSUuNjRzXQ0KPjExMglsZXNob3J0CXgJW2Nobj0lZF0NCg0KIyBNYWdpYyBJRCBmb3IgTXVsdGl0cmFja2VyIE1vZHVsZSBlZGl0b3IgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjAJc3RyaW5nCU1UTQlbZmlkPTAwMDEwMDA4OS0yMS0wMDAwTVRNO2V4dD1tdG07bWltZT07XU11bHRpVHJhY2tlciBtb2R1bGUgbXVzaWMgZmlsZQ0KPjQJc3RyaW5nCT5cXHgwMAlbdGl0bGU9JS4yMHNdDQoNCiMgTWFnaWMgSUQgZm9yIE1hZHRyYWNrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA1IGJ5IENhcmwNCjAJc3RyaW5nCU1UUDIJW2ZpZD0wMDAxMDAwOTEtMjEtMDAwME1UUDtleHQ9bXRwO21pbWU9O11NYWR0cmFja2VyIHBhdHRlcm4gZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBBL05FUyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDcgYnkgQ2FybA0KMAlzdHJpbmcJTkVTQQlbZmlkPTAwMDEwMDA5NC0yMS0wMDAwTlNBO2V4dD1uc2E7bWltZT07XUEvTkVTIHJpcHBlZCBhdWRpbyBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDcgYnkgQ2FybA0KMAlzdHJpbmcJTkVTTVxceDFBCVtmaWQ9MDAwMTAwMDkzLTIxLTAwMDBOU0Y7ZXh0PW5zZjttaW1lPTtdTkVTIHJpcHBlZCBhdWRpbyBmaWxlDQo+NQlieXRlCXgJLCB2ZXJzaW9uICVkLjANCj4weDBFCXN0cmluZwl4CVt0aXRsZT0lLjMyc10NCj4weDJFCXN0cmluZwl4CVtjcmVhdG9yPSUuMzJzXQ0KDQojIE1hZ2ljIElEIGZvciBOb2lzZXRyYWNrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjEwODAJc3RyaW5nCU0mSyEJW2ZpZD0wMDAxMDAwMjMtMjEtMDAwME5TVDtleHQ9bnN0O21pbWU9O11Ob2lzZXRyYWNrZXIgbW9kdWxlIG11c2ljIGZpbGUNCj4wCXN0cmluZwk+XFwwCVt0aXRsZT0lLjIwc10NCg0KIyBNYWdpYyBJRCBmb3IgT2t0YWx5emVyIHRyYWNrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjAJc3RyaW5nCU9LVEFTT05HCVtmaWQ9MDAwMTAwMDMwLTIxLTAwMDBPS1Q7ZXh0PW9rdDttaW1lPTtdT2t0YWx5emVyIG1vZHVsZSBtdXNpYyBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFNCU3R1ZGlvIHNvdW5kIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNSBieSBDYXJsDQowCXN0cmluZwlQQUNHCVtmaWQ9MDAwMTAwMDIwLTIxLTAwMDBQQUM7ZXh0PXBhYzttaW1lPTtdU0JTdHVkaW8gbW9kdWxlIG11c2ljIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgUG9seXRyYWNrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjQ0CXN0cmluZwlQVE1GCVtmaWQ9MDAwMDAwMDAwLTIxLTAwMDBQVE07ZXh0PXB0bTttaW1lPTtdUG9seSBUcmFja2VyIG1vZHVsZSBtdXNpYyBmaWxlDQo+MzgJbGVzaG9ydAk+MAlbY2huPSVkXQ0KPjAJc3RyaW5nCT5cXDAJW3RpdGxlPSUuMjhzXQ0KDQojIE1hZ2ljIElEIGZvciBSZWFsaXR5IEFkbGliIHRyYWNrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjAJc3RyaW5nCVJBRFxcIGJ5CVtmaWQ9MDAwMDAwMDAwLTIxLTAwMDBSQUQ7ZXh0PXJhZDttaW1lPTtdUmVhbGl0eSBBZGxpYiB0cmFja2VyIG11c2ljIGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlSSUZGCVtmaWQ9MDAwMDAwMDAwLTIxLTAwMDBSTUk7ZXh0PXJtaTttaW1lPWFwcGxpY2F0aW9uL3ZuZC5tdXNpYy1uaWZmO11Tb25nIG5vdGF0aW9uIGRhdGEgZmlsZSwgbGl0dGxlLWVuZGlhbg0KJjgJc3RyaW5nCU5JRkYJDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMAlzdHJpbmcJUklGWAlbZmlkPTAwMDAwMDAwMC0yMS0wMDAwUk1JO2V4dD1ybWk7bWltZT1hcHBsaWNhdGlvbi92bmQubXVzaWMtbmlmZjtdU29uZyBub3RhdGlvbiBkYXRhIGZpbGUsIGJpZy1lbmRpYW4NCiY4CXN0cmluZwlOSUZGCQ0KDQojIE1hZ2ljIElEIGZvciBBZGxpYiBWaXN1YWwgQ29tcG9zZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjAJbGVzaG9ydAkweDAwMDAJW2ZpZD0wMDAwMDEwMTYtMjEtMDAwMFJPTDtleHQ9cm9sO21pbWU9O11BZGxpYiBtdXNpYyBmaWxlDQomMglsZXNob3J0CTB4MDAwNAkNCg0KIyBNYWdpYyBJRCBmb3IgU2NyZWFtdHJhY2tlciAzIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQoweDJDCXN0cmluZwlTQ1JNCVtmaWQ9MDAwMTAwMDI1LTIxLTAwMDBTM007ZXh0PXMzbTttaW1lPTtdU2NyZWFtIHRyYWNrZXIgbW9kdWxlIG11c2ljIGZpbGUNCj4weDJBCWxlc2hvcnQJPjAJLCB2ZXJzaW9uICVkLjANCj4wCXN0cmluZwk+XFwwCVt0aXRsZT0lLjI4c10NCg0KIyBNYWdpYyBJRCBmb3IgU3VycHJpc2UhIEFkbGliIFRyYWNrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjAJc3RyaW5nCVNBZFQJW2ZpZD0wMDAxMDAwMjEtMjEtMDAwMFNBMjtleHQ9c2EyO21pbWU9O11TdXJwcmlzZSBQcm9kdWN0aW9ucyBBZGxpYiB0cmFja2VyIG11c2ljIGZpbGUNCj40CWJ5dGUJeAksIHZlcnNpb24gMC4lZA0KDQojIE1hZ2ljIElEIGZvciBTb3VuZEZYIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQo2MAlzdHJpbmcJU09ORwlbZmlkPTAwMDAwMTI3Ny0yMS0wMDAwU0ZYO2V4dD1zZng7bWltZT07XVNvdW5kRlggVHJhY2tlciBtb2R1bGUgbXVzaWMgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBQbGF5U0lELCBTaWRwbGF5IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNSBieSBDYXJsDQowCXN0cmluZwlQU0lECVtmaWQ9MDAwMDAwMDAwLTIxLTAwMDBTSUQ7ZXh0PXNpZDttaW1lPTtdUGxheVNJRCBtdXNpYyBmaWxlDQo+MTYJc3RyaW5nCXgJW3RpdGxlPSUuMjBzXQ0KPjM2CXN0cmluZwl4CVtjcmVhdG9yPSUuMjBzXQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE1IGJ5IENhcmwNCjAJc3RyaW5nCU1UaGQJW2ZpZD0wMDAwMDEwMTctMjEtMDAwMFNNRjtleHQ9c21mLG1pZGk7bWltZT07XVN0YW5kYXJkIE1JREkgbXVzaWMgZmlsZQ0KPjEwCWJlc2hvcnQJPjAJW2Nobj0lZF0NCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNSBieSBDYXJsDQowCXN0cmluZwlGT1JNCVtmaWQ9MDAwMDAxMDEwLTIxLTAwMFNNVVM7ZXh0PXNtdXMsbXVzO21pbWU9O11JRkYgU2ltcGxlIE11c2ljYWwgU2NvcmUgZmlsZQ0KJjgJc3RyaW5nCVNNVVMJDQoNCiMgTWFnaWMgSUQgZm9yIFNuZHRvb2wyLG5lenBsYXkgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA1IGJ5IENhcmwNCjAJc3RyaW5nCVNORFxceDFBCVtmaWQ9MDAwMDAwMDAwLTIxLTAwMDBTTkQ7ZXh0PXNuZDttaW1lPTtdTmludGVuZG8gRW50ZXJ0YWlubWVudCBTeXN0ZW0gYXVkaW8gZmlsZSAoTkVTKQ0KJjQJYnl0ZQkzCSwgdmVyc2lvbiAlMy4wDQo+NQlieXRlCXgJW2Nobj0lZF0NCg0KIyBNYWdpYyBJRCBmb3IgaU5FUyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDUgYnkgQ2FybA0KMAlzdHJpbmcJU05EXFx4MUEJW2ZpZD0wMDAxMDAwOTItMjEtMDAwMFNORDtleHQ9c25kO21pbWU9O11pTkVTIGVtdWxhdG9yIGF1ZGlvIGZpbGUNCiY0CWJ5dGUJMQksIHZlcnNpb24gJTEuMA0KPjUJYnl0ZQl4CVtjaG49JWRdDQoNCiMgTWFnaWMgSUQgZm9yIFNUTUlLIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQoweDE1CXN0cmluZwlTY3JlYW0hCVtmaWQ9MDAwMTAwMDI1LTIxLTAwMDBTVFg7ZXh0PXN0eDttaW1lPTtdU1RNSUsgbW9kdWxlIG11c2ljIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgVGhlIEZpbmFsIE11c2ljc3lzdGVtIGVYdGVuZGVkIChURk1YKSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDcgYnkgQ2FybA0KMAlzdHJpbmcJVEZNWC1TT05HXFwgCVtmaWQ9MDAwMTAwMDk2LTIxLTAwMDBURlg7ZXh0PXRmeCx0Zm14O21pbWU9O11URk1YIHRyYWNrZXIgbW9kdWxlIG11c2ljIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgVWx0cmEgVHJhY2tlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDcgYnkgQ2FybA0KMAlzdHJpbmcJTUFTX1VUcmFja19WMDAJW2ZpZD0wMDAxMDAwOTctMjEtMDAwMFVMVDtleHQ9dWx0O21pbWU9O11VbHRyYSBUcmFja2VyIG1vZHVsZSBtdXNpYyBmaWxlDQo+MTUJc3RyaW5nCXgJW3RpdGxlPSUuMzJzXQ0KDQojIE1hZ2ljIElEIGZvciBBUGxheWVyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlBUFVOXFx4MDEJW2ZpZD0wMDAwMDAwMDAtMjEtMDAwMFVOSTtleHQ9dW5pO21pbWU9O11BUGxheWVyIG1vZHVsZSBtdXNpYyBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIE1pa21vZCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTUgYnkgQ2FybA0KMAlzdHJpbmcJVU4wCVtmaWQ9MDAwMDAwMDAwLTIxLTAwMDBVTkk7ZXh0PXVuaTttaW1lPTtdTWlrbW9kIG1vZHVsZSBtdXNpYyBmaWxlDQo+NAlieXRlCXgJW2Nobj0lZF0NCg0KIyBNYWdpYyBJRCBmb3IgRmFzdHRyYWNrZXIgMi4wIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNSBieSBDYXJsDQowCXN0cmluZwlFeHRlbmRlZFxcIE1vZHVsZTpcXCAJW2ZpZD0wMDAxMDAwMjYtMjEtMDAwMDBYTTtleHQ9eG07bWltZT07XUZhc3RUcmFja2VyIElJIG1vZHVsZSBtdXNpYyBmaWxlDQo+NTkJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjU4CWJ5dGUJeAkuMCVkDQo+MTcJc3RyaW5nCXgJW3RpdGxlPSUuMjBzXQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCUZPUk0JW2ZpZD0wMDAwMDEwMTAtMjItMDAwOFNWWDtleHQ9OHN2eDttaW1lPTtdQW1pZ2EgU2FtcGxlZCBhdWRpbyBmaWxlDQomOAlzdHJpbmcJOFNWWAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlGT1JNCVtmaWQ9MDAwMDAxMDAyLTIyLTAwMEFJRkM7ZXh0PWFpZmMsYWlmO21pbWU9O11BdWRpbyBDb21wcmVzc2VkIEludGVyY2hhbmdlIEZpbGUgRm9ybWF0DQomOAlzdHJpbmcJQUlGQwkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlGT1JNCVtmaWQ9MDAwMDAxMDAyLTIyLTAwMEFJRkY7ZXh0PWFpZmYsYWlmO21pbWU9O11BdWRpbyBJbnRlcmNoYW5nZSBGaWxlIEZvcm1hdA0KJjgJc3RyaW5nCUFJRkYJDQoNCiMgTWFnaWMgSUQgZm9yIE1vbmtleUF1ZGlvIHNvZnR3YXJlIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNS0yMCBieSBDYXJsDQowCXN0cmluZwlNQUNcXCAJW2ZpZD0wMDAxMDAxMjAtMjItMDAwMEFQRTtleHQ9YXBlO21pbWU9O11Nb25rZXlBdWRpbyBjb21wcmVzc2VkIGF1ZGlvIGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwkuc25kCVtmaWQ9MDAwMDAxMDExLTIyLTAwMDAwQVU7ZXh0PWF1LHNuZDttaW1lPTtdU3VuIC8gTmVYdCBzYW1wbGVkIGF1ZGlvIGZpbGUNCj4xNgliZWxvbmcJPjAJW2ZyZXE9JWRdDQoNCiMgTWFnaWMgSUQgZm9yIFNwcGFjayBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMjUyCWJlc2hvcnQJMHg0MEMzCVtmaWQ9MDAwMDAxMDE5LTIyLTAwMDAwMEQ7ZXh0PWQ7bWltZT07XVNwcGFjayBhdWRpbyBzYW1wbGUgZmlsZQ0KJjI1NAliZXNob3J0CTB4RkMwRQkNCg0KIyBNYWdpYyBJRCBmb3IgRmxhYyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDggYnkgQ2FybA0KMAlzdHJpbmcJZkxhQwlbZmlkPTAwMDEwMDA5OC0yMi0wMDBGTEFDO2V4dD1mbGFjO21pbWU9O11GcmVlIExvc3NsZXNzIEF1ZGlvIENvZGVjIHJhdyBhdWRpbyBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEZhcmFuZG9sZSBDb21wb3NlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJRlNNXFx4RkUJW2ZpZD0wMDAxMDAwODctMjItMDAwMEZTTTtleHQ9ZnNtO21pbWU9O11GYXJhbmRvbGUgY29tcG9zZXIgYXVkaW8gc2FtcGxlIGZpbGUNCj40CXN0cmluZwl4CVt0aXRsZT0lLjMyc10NCg0KIyBNYWdpYyBJRCBmb3IgTUFVRCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJRk9STQlbZmlkPTAwMDAwMDAwMC0yMi0wMDBNQVVEO2V4dD1tYXVkO21pbWU9O11NQVVEIGF1ZGlvIHNhbXBsZSBmaWxlDQomNAlzdHJpbmcJTUFVRAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNS0wNCBieSBDYXJsDQowCWJlc2hvcnQmMHhGRkUwCTB4ZmZlMAlbZmlkPTAwMDAwMDAwMS0yMi0wMDExMTcyO2V4dD1tcDEsbXAyLG1wMzttaW1lPWF1ZGlvL21wZWc7XU1QMyBBdWRpbyBzdHJlYW0gZmlsZQ0KJloxMjgJc3RyaW5nCVRBRwkNCj5aMTI1CXN0cmluZwl4CVt0aXRsZT0lLjMwc10NCj5aOTUJc3RyaW5nCXgJW2NyZWF0b3I9JS4zMHNdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMDQgYnkgQ2FybA0KMAlzdHJpbmcJSUQzCVtmaWQ9MDAwMDAwMDAxLTIyLTAwMTExNzI7ZXh0PW1wMSxtcDIsbXAzO21pbWU9YXVkaW8vbXBlZztdTVAzIEF1ZGlvIHN0cmVhbSBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJXFwwXFwwMDFcXDI0M1xcMTQ0CVtmaWQ9MDAwMDAxMDE0LTIyLTAwMDAwU0Y7ZXh0PXNmO21pbWU9O11JUkNBTSBhdWRpbyBzYW1wbGUgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCVxcMFxcMDAyXFwyNDNcXDE0NAlbZmlkPTAwMDAwMTAxNC0yMi0wMDAwMFNGO2V4dD1zZjttaW1lPTtdSVJDQU0gYXVkaW8gc2FtcGxlIGZpbGUsIGxpdHRsZS1lbmRpYW4NCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlcXDBcXDAwM1xcMjQzXFwxNDQJW2ZpZD0wMDAwMDEwMTQtMjItMDAwMDBTRjtleHQ9c2Y7bWltZT07XUlSQ0FNIGF1ZGlvIHNhbXBsZSBmaWxlLCBiaWctZW5kaWFuDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJXFwxNDRcXDI0M1xcMDAxXFwwCVtmaWQ9MDAwMDAxMDE0LTIyLTAwMDAwU0Y7ZXh0PXNmO21pbWU9O11JUkNBTSBhdWRpbyBzYW1wbGUgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCVxcMTQ0XFwyNDNcXDAwMlxcMAlbZmlkPTAwMDAwMTAxNC0yMi0wMDAwMFNGO2V4dD1zZjttaW1lPTtdSVJDQU0gYXVkaW8gc2FtcGxlIGZpbGUsIGJpZy1lbmRpYW4NCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlcXDE0NFxcMjQzXFwwMDNcXDAJW2ZpZD0wMDAwMDEwMTQtMjItMDAwMDBTRjtleHQ9c2Y7bWltZT07XUlSQ0FNIGF1ZGlvIHNhbXBsZSBmaWxlLCBsaXR0bGUtZW5kaWFuDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJXFwxNDRcXDI0M1xcMDA0XFwwCVtmaWQ9MDAwMDAxMDE0LTIyLTAwMDAwU0Y7ZXh0PXNmO21pbWU9O11JUkNBTSBhdWRpbyBzYW1wbGUgZmlsZSwgYmlnLWVuZGlhbg0KDQojIE1hZ2ljIElEIGZvciBTY3JlYW10cmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNSBieSBDYXJsDQoweDRDCXN0cmluZwlTQ1JTCVtmaWQ9MDAwMTAwMDI1LTIyLTAwMDBTTVA7ZXh0PXNtcDttaW1lPTtdU2NyZWFtdHJhY2tlciBhdWRpbyBzYW1wbGUNCj4weDMwCXN0cmluZwl4CVt0aXRsZT0lLjMwc10NCg0KIyBNYWdpYyBJRCBmb3IgU291bmRUb29sIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNyBieSBDYXJsDQowCXN0cmluZwlTT1VORFxceDFBCVtmaWQ9MDAwMTAwMDk1LTIyLTAwMDBTTkQ7ZXh0PXNuZDttaW1lPTtdU291bmQgdG9vbCBhdWRpbyBkYXRhIGZpbGUNCj4xNAlsZXNob3J0CXgJW2ZyZXE9JWRdDQoNCiMgTWFnaWMgSUQgZm9yIFNCU3R1ZGlvIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlTTkRcXCAJW2ZpZD0wMDAxMDAwMjAtMjItMDAwMFNPVTtleHQ9c291O21pbWU9O11TQlN0dWRpbyBzYW1wbGVkIGF1ZGlvIGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNS0xOCBieSBDYXJsDQowCXN0cmluZwlTcGVleAlbZmlkPTAwMDAwMDAwMC0yMi0wMFNQRUVYO2V4dD1zcGVleDttaW1lPTtdU3BlZXggTG9zc3kgQXVkaW8gQ29kZWMgcmF3IGF1ZGlvIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgU291bmQgQmxhc3RlciBTREsgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCUNyZWF0aXZlXFwgVm9pY2VcXCBGaWxlXFx4MUEJW2ZpZD0wMDAwMDEwMTMtMjItMDAwMFZPQztleHQ9dm9jO21pbWU9O11DcmVhdGl2ZSBWb2ljZSBhdWRpbyBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMTggYnkgQ2FybA0KMAlzdHJpbmcJdm9yYmlzCVtmaWQ9MDAwMDAwMDAwLTIyLTBWT1JCSVM7ZXh0PXZvcmJpczttaW1lPTtdVm9yYmlzIExvc3N5IEF1ZGlvIENvZGVjIHJhdyBhdWRpbyBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJUklGRglbZmlkPTAwMDAwMTAwMS0yMi0wMDAwV0FWO2V4dD13YXY7bWltZT07XU1pY3Jvc29mdCBXYXZlZm9ybSBBdWRpbyBmaWxlLCBsaXR0bGUtZW5kaWFuDQomOAlzdHJpbmcJV0FWRQkNCj4yNAlsZWxvbmcJPjAJW2ZyZXE9JWRdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJUklGWAlbZmlkPTAwMDAwMTAwMS0yMi0wMDAwV0FWO2V4dD13YXY7bWltZT07XU1pY3Jvc29mdCBXYXZlZm9ybSBBdWRpbyBmaWxlLCBiaWctZW5kaWFuDQomOAlzdHJpbmcJV0FWRQkNCj4yNAliZWxvbmcJPjAJW2ZyZXE9JWRdDQoNCiMgTWFnaWMgSUQgZm9yIE1heWEgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCUZPUjQJW2ZpZD0wMDAwMDEzMTItMzEtMDAwMDAwMDtleHQ9O21pbWU9O11NYXlhIGltYWdlIGZpbGUNCiY4CXN0cmluZwlDSU1HCQ0KDQojIE1hZ2ljIElEIGZvciBNYXlhIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwlGT1I4CVtmaWQ9MDAwMDAxMzEyLTMxLTAwMDAwMDA7ZXh0PTttaW1lPTtdTWF5YSBpbWFnZSBmaWxlDQomOAlzdHJpbmcJQ0lNRwkNCg0KIyBNYWdpYyBJRCBmb3IgQU9MIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMiBieSBDYXJsDQowCXN0cmluZwlKR1xceDA0XFx4MEUJW2ZpZD0wMDAwMDEwMjMtMzEtMDAwMEFSVDtleHQ9YXJ0O21pbWU9O11BT0wvSm9obnNvbi1HcmFjZSBpbWFnZSBmaWxlLCB2ZXJzaW9uIDIuMA0KPjB4MEQJbGVzaG9ydAl4CVtyZXM9JWR4DQo+MHgwRglsZXNob3J0CXgJJWRdDQoNCiMgTWFnaWMgSUQgZm9yIEJNRiBpbWFnZSBjb21wcmVzc29yIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yNyBieSBDYXJsDQowCXN0cmluZwlcXHg4MVxceDhBMAlbZmlkPTAwMDEwMDA0OC0zMS0wMDAwQk1GO2V4dD1ibWY7bWltZT07XUJNRiBpbWFnZSBmaWxlDQo+MglzdHJpbmcJeAksIHZlcnNpb24gJS4xcw0KPjMJc3RyaW5nCXgJLiUuMXMNCg0KIyBNYWdpYyBJRCBmb3IgQk1GIGltYWdlIGNvbXByZXNzb3IgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTI3IGJ5IENhcmwNCjAJc3RyaW5nCVxceDgxXFx4OEEyCVtmaWQ9MDAwMTAwMDQ4LTMxLTAwMDBCTUY7ZXh0PWJtZjttaW1lPTtdQk1GIGltYWdlIGZpbGUNCj4yCXN0cmluZwl4CSwgdmVyc2lvbiAlLjFzDQo+MwlzdHJpbmcJeAkuJS4xcw0KDQojIE1hZ2ljIElEIGZvciBCTUYgaW1hZ2UgY29tcHJlc3NvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjcgYnkgQ2FybA0KMAlzdHJpbmcJXFx4ODFcXHg4QTEJW2ZpZD0wMDAxMDAwNDgtMzEtMDAwMEJNRjtleHQ9Ym1mO21pbWU9O11CTUYgaW1hZ2UgZmlsZQ0KPjIJc3RyaW5nCXgJLCB2ZXJzaW9uICUuMXMNCj4zCXN0cmluZwl4CS4lLjFzDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJQk0JW2ZpZD0wMDAwMDEwMDEtMzEtMDAwMEJNUDtleHQ9Ym1wO21pbWU9O11XaW5kb3dzIG9yIE9TLzIgQml0bWFwIGltYWdlIGZpbGUNCiY2CWxlbG9uZwkwCQ0KDQojIE1hZ2ljIElEIGZvciBBdXRvZGVzayBBbmltYXRvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDggYnkgQ2FybA0KMAlsZXNob3J0CTB4OTExOQlbZmlkPTAwMDAwMTI1NC0zMS0wMDAwQ0VMO2V4dD1jZWwscGljO21pbWU9O11BdXRvZGVzayBhbmltYXRvciBpbWFnZSBmaWxlDQomMTAJYnl0ZQk4CQ0KJjExCWJ5dGUJMAkNCj4yCWxlc2hvcnQJeAlbcmVzPSVkDQo+NAlsZXNob3J0CXgJeCVkeDhicHBdDQoNCiMgTWFnaWMgSUQgZm9yIEFuZHJldyBVc2VyIEludGVyZmFjZSBTeXN0ZW0gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAyIGJ5IENhcmwNCjEJc3RyaW5nCWJlZ2luZGF0YXtyYXN0ZXIJW2ZpZD0wMDAwMDEzMTUtMzEtMDAwMENNVTtleHQ9Y211O21pbWU9O11BbmRyZXcgdG9vbGtpdCByYXN0ZXIgaW1hZ2UgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBBbml2Z2EgdG9vbGtpdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDIgYnkgQ2FybA0KMzgJc3RyaW5nCUtSXFx4MDFcXHgwMAlbZmlkPTAwMDEwMDEwNC0zMS0wMDAwQ09EO2V4dD1jb2Q7bWltZT07XUFuaXZnYSBzcHJpdGUgaW1hZ2UgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBXaW5kb3dzIEN1cnNvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDBcXHgwMFxceDAyXFx4MDAJW2ZpZD0wMDAwMDEwMDEtMzEtMDAwMENVUjtleHQ9Y3VyO21pbWU9O11NaWNyb3NvZnQgd2luZG93cyBjdXJzb3IgaW1hZ2UgZmlsZQ0KJjB4MDgJYnl0ZQkwCQ0KPjQJbGVzaG9ydAl4CSwgJWQgY3Vyc29yKHMpDQo+NglieXRlCXgJW3Jlcz0lZHgNCj43CWJ5dGUJeAklZHg4YnBwXQ0KDQojIE1hZ2ljIElEIGZvciBXaW5kb3dzIEN1cnNvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDBcXHgwMFxceDAyXFx4MDAJW2ZpZD0wMDAwMDEwMDEtMzEtMDAwMENVUjtleHQ9Y3VyO21pbWU9O11NaWNyb3NvZnQgd2luZG93cyBjdXJzb3IgaW1hZ2UgZmlsZQ0KJjB4MDgJYnl0ZQkxNgkNCj40CWxlc2hvcnQJeAksICVkIGN1cnNvcihzKQ0KPjYJYnl0ZQl4CVtyZXM9JWR4DQo+NwlieXRlCXgJJWR4NGJwcF0NCg0KIyBNYWdpYyBJRCBmb3IgV2luZG93cyBDdXJzb3IgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAxIGJ5IENhcmwNCjAJc3RyaW5nCVxceDAwXFx4MDBcXHgwMlxceDAwCVtmaWQ9MDAwMDAxMDAxLTMxLTAwMDBDVVI7ZXh0PWN1cjttaW1lPTtdTWljcm9zb2Z0IHdpbmRvd3MgY3Vyc29yIGltYWdlIGZpbGUNCiYweDA4CWJ5dGUJMgkNCj40CWxlc2hvcnQJeAksICVkIGN1cnNvcihzKQ0KPjYJYnl0ZQl4CVtyZXM9JWR4DQo+NwlieXRlCXgJJWR4MWJwcF0NCg0KIyBNYWdpYyBJRCBmb3IgV2luZG93cyBDdXJzb3IgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAxIGJ5IENhcmwNCjAJc3RyaW5nCVxceDAwXFx4MDBcXHgwMlxceDAwCVtmaWQ9MDAwMDAxMDAxLTMxLTAwMDBDVVI7ZXh0PWN1cjttaW1lPTtdTWljcm9zb2Z0IHdpbmRvd3MgY3Vyc29yIGltYWdlIGZpbGUNCiYweDA4CWJ5dGUJMzIJDQo+NAlsZXNob3J0CXgJLCAlZCBjdXJzb3IocykNCj42CWJ5dGUJeAlbcmVzPSVkeA0KPjcJYnl0ZQl4CSVkeDVicHBdDQoNCiMgTWFnaWMgSUQgZm9yIFdpbmRvd3MgQ3Vyc29yIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMSBieSBDYXJsDQowCXN0cmluZwlcXHgwMFxceDAwXFx4MDJcXHgwMAlbZmlkPTAwMDAwMTAwMS0zMS0wMDAwQ1VSO2V4dD1jdXI7bWltZT07XU1pY3Jvc29mdCB3aW5kb3dzIGN1cnNvciBpbWFnZSBmaWxlDQomMHgwOAlieXRlCTY0CQ0KPjQJbGVzaG9ydAl4CSwgJWQgY3Vyc29yKHMpDQo+NglieXRlCXgJW3Jlcz0lZHgNCj43CWJ5dGUJeAklZHg2YnBwXQ0KDQojIE1hZ2ljIElEIGZvciBXaW5kb3dzIEN1cnNvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDBcXHgwMFxceDAyXFx4MDAJW2ZpZD0wMDAwMDEwMDEtMzEtMDAwMENVUjtleHQ9Y3VyO21pbWU9O11NaWNyb3NvZnQgd2luZG93cyBjdXJzb3IgaW1hZ2UgZmlsZQ0KJjB4MDgJYnl0ZQk4CQ0KPjQJbGVzaG9ydAl4CSwgJWQgY3Vyc29yKHMpDQo+NglieXRlCXgJW3Jlcz0lZHgNCj43CWJ5dGUJeAklZHgzYnBwXQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEzIGJ5IENhcmwNCjEyOAlzdHJpbmcJRElDTQlbZmlkPTAwMDAwMDAwNC0zMS0wMDBESUNNO2V4dD1kaWNtLGRjbTttaW1lPTtdRGlnaXRhbCBpbWFnaW5nIGFuZCBjb21tdW5pY2F0aW9uIGluIG1lZGVjaW5lIGltZy4NCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMSBieSBDYXJsDQowCXN0cmluZwlTRFBYCVtmaWQ9MDAwMDAxMzA5LTMxLTAwMDBEUFg7ZXh0PWRweDttaW1lPTtdRGlnaXRhbCBNb3ZpbmctUGljdHVyZSBFeGNoYW5nZSBpbWFnZSBmaWxlDQo+MTYwCXN0cmluZwk+XFx4MDAJW2NyZWF0b3I9JS4xMDBzXQ0KPjI2MAlzdHJpbmcJPlxceDAwCVt0aXRsZT0lLjIwMHNdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDEgYnkgQ2FybA0KMAlzdHJpbmcJWFBEUwlbZmlkPTAwMDAwMTMwOS0zMS0wMDAwRFBYO2V4dD1kcHg7bWltZT07XURpZ2l0YWwgTW92aW5nLVBpY3R1cmUgRXhjaGFuZ2UgaW1hZ2UgZmlsZQ0KPjE2MAlzdHJpbmcJPlxceDAwCVtjcmVhdG9yPSUuMTAwc10NCj4yNjAJc3RyaW5nCT5cXHgwMAlbdGl0bGU9JS4yMDBzXQ0KDQojIE1hZ2ljIElEIGZvciBMaWdodHdhdmUgM0QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCUZPUk0JW2ZpZD0wMDAwMDEyNTEtMzEtMDAwRlBCTTtleHQ9ZnBibTttaW1lPTtdRmxleGlibGUgUHJlY2lzaW9uIEJ1ZmZlciBNYXAgaW1hZ2UgZmlsZQ0KJjgJc3RyaW5nCUZQQk0JDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJR0lGOAlbZmlkPTAwMDAwMTI3NC0zMS0wMDAwR0lGO2V4dD1naWY7bWltZT1pbWFnZS9naWY7XUdJRiBpbWFnZSBmaWxlDQomMTAJYnl0ZSYweDcwCSEweDcwCQ0KPjQJc3RyaW5nCXgJLCB2ZXJzaW9uIDglLjJzDQo+NglsZXNob3J0CT4wCVtyZXM9JWR4DQo+OAlsZXNob3J0CT4wCSVkXQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCUdJRjgJW2ZpZD0wMDAwMDEyNzQtMzEtMDAwMEdJRjtleHQ9Z2lmO21pbWU9aW1hZ2UvZ2lmO11HSUYgaW1hZ2UgZmlsZQ0KJjEwCWJ5dGUmMHg3MAkweDcwCQ0KPjQJc3RyaW5nCXgJLCB2ZXJzaW9uIDglLjJzDQo+NglsZXNob3J0CT4wCVtyZXM9JWR4DQo+OAlsZXNob3J0CT4wCSVkeDhicHBdDQoNCiMgTWFnaWMgSUQgZm9yIFdpbmRvd3MgSWNvbiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDBcXHgwMFxceDAxXFx4MDAJW2ZpZD0wMDAwMDEwMDEtMzEtMDAwMElDTztleHQ9aWNvO21pbWU9aW1hZ2Uvdm5kLm1pY3Jvc29mdC5pY29uO11NaWNyb3NvZnQgd2luZG93cyBJY29uIGltYWdlIGZpbGUNCiYweDA4CWJ5dGUJMAkNCj40CWxlc2hvcnQJeAksICVkIGljb24ocykNCj42CWJ5dGUJeAlbcmVzPSVkeA0KPjcJYnl0ZQl4CSVkeDhicHBdDQoNCiMgTWFnaWMgSUQgZm9yIFdpbmRvd3MgSWNvbiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDBcXHgwMFxceDAxXFx4MDAJW2ZpZD0wMDAwMDEwMDEtMzEtMDAwMElDTztleHQ9aWNvO21pbWU9aW1hZ2Uvdm5kLm1pY3Jvc29mdC5pY29uO11NaWNyb3NvZnQgd2luZG93cyBJY29uIGltYWdlIGZpbGUNCiYweDA4CWJ5dGUJMTYJDQo+NAlsZXNob3J0CXgJLCAlZCBpY29uKHMpDQo+NglieXRlCXgJW3Jlcz0lZHgNCj43CWJ5dGUJeAklZHg0YnBwXQ0KDQojIE1hZ2ljIElEIGZvciBXaW5kb3dzIEljb24gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAxIGJ5IENhcmwNCjAJc3RyaW5nCVxceDAwXFx4MDBcXHgwMVxceDAwCVtmaWQ9MDAwMDAxMDAxLTMxLTAwMDBJQ087ZXh0PWljbzttaW1lPWltYWdlL3ZuZC5taWNyb3NvZnQuaWNvbjtdTWljcm9zb2Z0IHdpbmRvd3MgSWNvbiBpbWFnZSBmaWxlDQomMHgwOAlieXRlCTIJDQo+NAlsZXNob3J0CXgJLCAlZCBpY29uKHMpDQo+NglieXRlCXgJW3Jlcz0lZHgNCj43CWJ5dGUJeAklZHgxYnBwXQ0KDQojIE1hZ2ljIElEIGZvciBXaW5kb3dzIEljb24gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAxIGJ5IENhcmwNCjAJc3RyaW5nCVxceDAwXFx4MDBcXHgwMVxceDAwCVtmaWQ9MDAwMDAxMDAxLTMxLTAwMDBJQ087ZXh0PWljbzttaW1lPWltYWdlL3ZuZC5taWNyb3NvZnQuaWNvbjtdTWljcm9zb2Z0IHdpbmRvd3MgSWNvbiBpbWFnZSBmaWxlDQomMHgwOAlieXRlCTMyCQ0KPjQJbGVzaG9ydAl4CSwgJWQgaWNvbihzKQ0KPjYJYnl0ZQl4CVtyZXM9JWR4DQo+NwlieXRlCXgJJWR4NWJwcF0NCg0KIyBNYWdpYyBJRCBmb3IgV2luZG93cyBJY29uIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMSBieSBDYXJsDQowCXN0cmluZwlcXHgwMFxceDAwXFx4MDFcXHgwMAlbZmlkPTAwMDAwMTAwMS0zMS0wMDAwSUNPO2V4dD1pY287bWltZT1pbWFnZS92bmQubWljcm9zb2Z0Lmljb247XU1pY3Jvc29mdCB3aW5kb3dzIEljb24gaW1hZ2UgZmlsZQ0KJjB4MDgJYnl0ZQk2NAkNCj40CWxlc2hvcnQJeAksICVkIGljb24ocykNCj42CWJ5dGUJeAlbcmVzPSVkeA0KPjcJYnl0ZQl4CSVkeDZicHBdDQoNCiMgTWFnaWMgSUQgZm9yIFdpbmRvd3MgSWNvbiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDBcXHgwMFxceDAxXFx4MDAJW2ZpZD0wMDAwMDEwMDEtMzEtMDAwMElDTztleHQ9aWNvO21pbWU9aW1hZ2Uvdm5kLm1pY3Jvc29mdC5pY29uO11NaWNyb3NvZnQgd2luZG93cyBJY29uIGltYWdlIGZpbGUNCiYweDA4CWJ5dGUJOAkNCj40CWxlc2hvcnQJeAksICVkIGljb24ocykNCj42CWJ5dGUJeAlbcmVzPSVkeA0KPjcJYnl0ZQl4CSVkeDNicHBdDQoNCiMgTWFnaWMgSUQgZm9yIFN1bk9TIEljb24gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAyIGJ5IENhcmwNCjAJc3RyaW5nCS8qXFwgRm9ybWF0X3ZlcnNpb249MSxcXCAJW2ZpZD0wMDAwMDEwMTEtMzEtMDAwSUNPTjtleHQ9aWNvbjttaW1lPTtdU3VuT1MgaWNvbiBpbWFnZSBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAliZXNob3J0CTB4MDEJW2ZpZD0wMDAwMDEyNzMtMzEtMDAwMElNRztleHQ9aW1nO21pbWU9O11HRU0gQml0IEltYWdlDQomMgliZXNob3J0CTB4MDgJDQo+MTIJYmVzaG9ydAk+MAlbcmVzPSVkeA0KPjE0CWJlc2hvcnQJPjAJJWQNCj40CWJlc2hvcnQJPjAJeCVkYnBwXQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAyIGJ5IENhcmwNCjAJc3RyaW5nCVxceDhiSk5HXFx4MGRcXHgwYVxceDFhXFx4MGEJW2ZpZD0wMDAwMDAwMDAtMzEtMDAwMEpORztleHQ9am5nO21pbWU9O11KUEVHIE5ldHdvcmsgZ3JhcGhpY3MgaW1hZ2UgZmlsZQ0KJjEyCXN0cmluZwlKSERSCQ0KPjE2CWJlbG9uZwl4CVtyZXM9JWQNCj4yMAliZWxvbmcJeAl4JWRdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTMgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDBcXHgwMFxceDAwXFx4MGNqUFxceDIwXFx4MjAJW2ZpZD0wMDAwMDAwMDEtMzEtMDAxNTQ0NDtleHQ9anAyO21pbWU9aW1hZ2UvanAyO11KUEVHIDIwMDAgaW1hZ2UgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEzIGJ5IENhcmwNCjAJc3RyaW5nCVxceGZmXFx4NGZcXHhmZlxceDUxCVtmaWQ9MDAwMDAwMDAxLTMxLTAwMTU0NDQ7ZXh0PWpwYzttaW1lPTtdSlBFRyAyMDAwIGNvZGUgc3RyZWFtIGltYWdlIGZpbGUNCiZaMgliZXNob3J0CTB4RkZEOQkNCj44CWJlbG9uZwl4CVtyZXM9JWR4DQo+MTIJYmVsb25nCXgJJWRdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAliZWxvbmcJMHhmZmQ4ZmZlMAlbZmlkPTAwMDAwMTMwNS0zMS0wMDBKUEVHO2V4dD1qcGVnLGpwZzttaW1lPWltYWdlL2pwZWc7XUpvaW50IFBob3RvZ3JhcGhpYyBFeHBlcnRzIEdyb3VwIEpGSUYgaW1hZ2UgZmlsZQ0KJjYJc3RyaW5nCUpGSUZcXHgwMAkNCj4xMQlieXRlCXgJLCB2ZXJzaW9uICVkDQo+MTIJYnl0ZQl4CS4wJWQNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMyBieSBDYXJsDQowCXN0cmluZwlcXHhmZlxceGQ4XFx4ZmZcXHhlMQlbZmlkPTAwMDAwMDAwNS0zMS0wMDBKUEVHO2V4dD1qcGcsanBlZzttaW1lPWltYWdlL2pwZWc7XURpZ2l0YWwgc3RpbGwgY2FtZXJhIGltYWdlIGZpbGUNCiY2CXN0cmluZwlFeGlmCQ0KDQojIE1hZ2ljIElEIGZvciBEZWx1eGUgUGFpbnQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTMxIGJ5IENhcmwNCjAJc3RyaW5nCUZPUk0JW2ZpZD0wMDAwMDEwMTAtMzEtMDAwMExCTTtleHQ9bGJtO21pbWU9O11JbnRlcmxlYXZlZCBiaXRtYXAgaW1hZ2UgZmlsZQ0KJjgJc3RyaW5nCUlMQk0JDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTMgYnkgQ2FybA0KMAlzdHJpbmcJVGhpc1xcIGlzXFwgYVxcIEJpdE1hcFxcIGZpbGUJW2ZpZD0wMDAwMDAwMDAtMzEtMDAwTElTUDtleHQ9bGlzcDttaW1lPTtdTGlzcCBtYWNoaW5lIGZvcm1hdCBpbWFnZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIE1pY3JvZGVzaWduMiwgTWljcm9kZXNpZ24zIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMiBieSBDYXJsDQowCXN0cmluZwkuTURBCVtmaWQ9MDAwMDAxMzE2LTMxLTAwMDBNREE7ZXh0PW1kYTttaW1lPTtdTWljcm9kZXNpZ24gQXJlYSBpbWFnZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIE1pY3JvZGVzaWduMiwgTWljcm9kZXNpZ24zIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMiBieSBDYXJsDQowCXN0cmluZwkuTURQCVtmaWQ9MDAwMDAxMzE2LTMxLTAwMDBNRFA7ZXh0PW1kcDttaW1lPTtdTWljcm9kZXNpZ24gcGFnZSBpbWFnZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEltYWdlbWFnaWNrIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMSBieSBDYXJsDQowCXN0cmluZwlpZD1JbWFnZU1hZ2ljawlbZmlkPTAwMDEwMDEwMS0zMS0wMDBNSUZGO2V4dD1taWZmLG1pZjttaW1lPTtdSW1hZ2VtYWdpY2sgaW1hZ2UgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBOZXRwYm0gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAyIGJ5IENhcmwNCjAJc3RyaW5nCU1SRjEJW2ZpZD0wMDAxMDAxMDUtMzEtMDAwME1SRjtleHQ9bXJmO21pbWU9O11Nb25vY2hyb21lIHJlY3Vyc2l2ZSBmb3JtYXQgaW1hZ2UgZmlsZQ0KPjQJYmVsb25nCXgJW3Jlcz0lZHgNCj44CWJlbG9uZwl4CSVkeDFicHBdDQoNCiMgTWFnaWMgSUQgZm9yIE1pY3Jvc29mdCBQYWludCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDIgYnkgQ2FybA0KMAlsZXNob3J0CTB4NjE0NAlbZmlkPTAwMDAwMTAwMS0zMS0wMDAwTVNQO2V4dD1tc3A7bWltZT07XU1pY3Jvc29mdCBwYWludCBpbWFnZSBmaWxlLCB2ZXJzaW9uIDEuMA0KJjIJbGVzaG9ydAkweDRkNmUJDQo+NAlsZXNob3J0CXgJW3Jlcz0lZHgNCj42CWxlc2hvcnQJeAklZHgxYnBwXQ0KDQojIE1hZ2ljIElEIGZvciBNaWNyb3NvZnQgUGFpbnQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAyIGJ5IENhcmwNCjAJbGVzaG9ydAkweDY5NGMJW2ZpZD0wMDAwMDEwMDEtMzEtMDAwME1TUDtleHQ9bXNwO21pbWU9O11NaWNyb3NvZnQgcGFpbnQgaW1hZ2UgZmlsZSwgdmVyc2lvbiAyLjANCiYyCWxlc2hvcnQJMHg1MzZlCQ0KPjQJbGVzaG9ydAl4CVtyZXM9JWR4DQo+NglsZXNob3J0CXgJJWR4MWJwcF0NCg0KIyBNYWdpYyBJRCBmb3IgTmV0cGJtIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0zMSBieSBDYXJsDQowCXN0cmluZwlQN1xceDBBCVtmaWQ9MDAwMTAwMTAwLTMxLTAwMDBQQU07ZXh0PXBhbTttaW1lPTtdUG9ydGFibGUgYXJiaXRyYXJ5IG1hcCBpbWFnZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIE5ldHBibSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAlzdHJpbmcJUDEJW2ZpZD0wMDAxMDAxMDAtMzEtMDAwMFBCTTtleHQ9cGJtO21pbWU9O11Qb3J0YWJsZSBiaXRtYXAgaW1hZ2UgZmlsZSwgYXNjaWkNCg0KIyBNYWdpYyBJRCBmb3IgTmV0cGJtIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0zMSBieSBDYXJsDQowCXN0cmluZwlQNAlbZmlkPTAwMDEwMDEwMC0zMS0wMDAwUEJNO2V4dD1wYm07bWltZT07XVBvcnRhYmxlIGJpdG1hcCBpbWFnZSBmaWxlLCBiaW5hcnkNCg0KIyBNYWdpYyBJRCBmb3IgUEMtUGFpbnRicnVzaCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAliZXNob3J0CTB4MEEwMAlbZmlkPTAwMDAwMTI1Ny0zMS0wMDAwUENYO2V4dD1wY3g7bWltZT07XVBDLVBhaW50YnJ1c2ggaW1hZ2UgZmlsZSwgdmVyc2lvbiAyLjUNCiYyCWJ5dGUJMQkNCg0KIyBNYWdpYyBJRCBmb3IgUEMtUGFpbnRicnVzaCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAliZXNob3J0CTB4MEEwMglbZmlkPTAwMDAwMTI1Ny0zMS0wMDAwUENYO2V4dD1wY3g7bWltZT07XVBDLVBhaW50YnJ1c2ggaW1hZ2UgZmlsZSwgdmVyc2lvbiAyLjgNCiYyCWJ5dGUJMQkNCg0KIyBNYWdpYyBJRCBmb3IgUEMtUGFpbnRicnVzaCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAliZXNob3J0CTB4MEEwMwlbZmlkPTAwMDAwMTI1Ny0zMS0wMDAwUENYO2V4dD1wY3g7bWltZT07XVBDLVBhaW50YnJ1c2ggaW1hZ2UgZmlsZSwgdmVyc2lvbiAyLjgNCiYyCWJ5dGUJMQkNCg0KIyBNYWdpYyBJRCBmb3IgUEMtUGFpbnRicnVzaCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAliZXNob3J0CTB4MEEwNAlbZmlkPTAwMDAwMTI1Ny0zMS0wMDAwUENYO2V4dD1wY3g7bWltZT07XVBDLVBhaW50YnJ1c2ggZm9yIHdpbmRvd3MgaW1hZ2UgZmlsZQ0KJjIJYnl0ZQkxCQ0KDQojIE1hZ2ljIElEIGZvciBQQy1QYWludGJydXNoIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0zMSBieSBDYXJsDQowCWJlc2hvcnQJMHgwQTA1CVtmaWQ9MDAwMDAxMjU3LTMxLTAwMDBQQ1g7ZXh0PXBjeDttaW1lPTtdUEMtUGFpbnRicnVzaCBpbWFnZSBmaWxlLCB2ZXJzaW9uIDMuMA0KJjIJYnl0ZQkxCQ0KDQojIE1hZ2ljIElEIGZvciBOZXRwYm0gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTMxIGJ5IENhcmwNCjAJc3RyaW5nCVAyCVtmaWQ9MDAwMTAwMTAwLTMxLTAwMDBQR007ZXh0PXBnbTttaW1lPTtdUG9ydGFibGUgZ3JheSBtYXAgaW1hZ2UgZmlsZSwgYXNjaWkNCg0KIyBNYWdpYyBJRCBmb3IgTmV0cGJtIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0zMSBieSBDYXJsDQowCXN0cmluZwlQNQlbZmlkPTAwMDEwMDEwMC0zMS0wMDAwUEdNO2V4dD1wZ207bWltZT07XVBvcnRhYmxlIGdyYXkgbWFwIGltYWdlIGZpbGUsIGJpbmFyeQ0KDQojIE1hZ2ljIElEIGZvciBQQyBQYWludCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDggYnkgQ2FybA0KMAlsZXNob3J0CTB4MTIzNAlbZmlkPTAwMDAwMTMxOC0zMS0wMDAwUElDO2V4dD1waWM7bWltZT07XVBpY3RvciBQQyBQYWludCBpbWFnZSBmaWxlDQomMTEJYnl0ZQkweEZGCQ0KJjEwCWJ5dGUJMHgwMgkNCj4yCWxlc2hvcnQJeAlbcmVzPSVkDQo+NAlsZXNob3J0CXgJeCVkXQ0KDQojIE1hZ2ljIElEIGZvciBQQyBQYWludCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDggYnkgQ2FybA0KMAlsZXNob3J0CTB4MTIzNAlbZmlkPTAwMDAwMTMxOC0zMS0wMDAwUElDO2V4dD1waWM7bWltZT07XVBpY3RvciBQQyBQYWludCBpbWFnZSBmaWxlDQomMTEJYnl0ZQkweEZGCQ0KJjEwCWJ5dGUJMHgwOAkNCj4yCWxlc2hvcnQJeAlbcmVzPSVkDQo+NAlsZXNob3J0CXgJeCVkXQ0KDQojIE1hZ2ljIElEIGZvciBQQyBQYWludCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDggYnkgQ2FybA0KMAlsZXNob3J0CTB4MTIzNAlbZmlkPTAwMDAwMTMxOC0zMS0wMDAwUElDO2V4dD1waWM7bWltZT07XVBpY3RvciBQQyBQYWludCBpbWFnZSBmaWxlDQomMTEJYnl0ZQkweEZGCQ0KJjEwCWJ5dGUJMHgzMQkNCj4yCWxlc2hvcnQJeAlbcmVzPSVkDQo+NAlsZXNob3J0CXgJeCVkXQ0KDQojIE1hZ2ljIElEIGZvciBTb2Z0aW1hZ2UgM0QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTA4IGJ5IENhcmwNCjAJYmVsb25nCTB4NTM4MGY2MzQJW2ZpZD0wMDAwMDEzMjEtMzEtMDAwMFBJQztleHQ9cGljO21pbWU9O11Tb2Z0aW1hZ2UgM0QgaW1hZ2UgZmlsZQ0KJjg4CXN0cmluZwlQSUNUCQ0KPjgJc3RyaW5nCT5cXHgwMAlbdGl0bGU9JS44MHNdDQo+OTIJYmVzaG9ydAl4CVtyZXM9JWQNCj45NAliZXNob3J0CXgJeCVkXQ0KDQojIE1hZ2ljIElEIGZvciBCaW8tcmFkIG1pY3Jvc2NvcGUgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTA4IGJ5IENhcmwNCjU0CWxlc2hvcnQJMTIzNDUJW2ZpZD0wMDAwMDEzMjItMzEtMDAwMFBJQztleHQ9cGljO21pbWU9O11CaW8tcmFkIGNvbmZvY2FsIG1pY3Jvc2NvcGUgaW1hZ2UgZmlsZQ0KJjE2CWxlc2hvcnQJMAkNCj4wCWxlc2hvcnQJPjAJW3Jlcz0lZA0KPjIJbGVzaG9ydAk+MAl4JWRdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDYgYnkgQ2FybA0KMAlzdHJpbmcJXFx4ODlQTkdcXHgwZFxceDBhXFx4MWFcXHgwYQlbZmlkPTAwMDAwMDAwMS0zMS0wMDE1OTQ4O2V4dD1wbmc7bWltZT1pbWFnZS9wbmc7XVBvcnRhYmxlIE5ldHdvcmsgR3JhcGhpYyBmaWxlDQomMTIJc3RyaW5nCUlIRFIJDQo+MTYJYmVsb25nCT4wCVtyZXM9JWQNCj4yMAliZWxvbmcJPjAJeCVkDQo+MjQJYnl0ZQl4CXglZGJwcF0NCg0KIyBNYWdpYyBJRCBmb3IgTmV0cGJtIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0zMSBieSBDYXJsDQowCXN0cmluZwlQMwlbZmlkPTAwMDEwMDEwMC0zMS0wMDAwUFBNO2V4dD1wcG07bWltZT07XVBvcnRhYmxlIHBpeGVsIG1hcCBpbWFnZSBmaWxlLCBhc2NpaQ0KDQojIE1hZ2ljIElEIGZvciBOZXRwYm0gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTMxIGJ5IENhcmwNCjAJc3RyaW5nCVA2CVtmaWQ9MDAwMTAwMTAwLTMxLTAwMDBQUE07ZXh0PXBwbTttaW1lPTtdUG9ydGFibGUgcGl4ZWwgbWFwIGltYWdlIGZpbGUsIGJpbmFyeQ0KDQojIE1hZ2ljIElEIGZvciBQaG90b3Nob3AgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAxIGJ5IENhcmwNCjAJc3RyaW5nCThCUFNcXHgwMFxceDAxCVtmaWQ9MDAwMDAxMDAzLTMxLTAwMDBQU0Q7ZXh0PXBzZDttaW1lPTtdQWRvYmUgUGhvdG9zaG9wIGltYWdlIGZpbGUNCj4xOAliZWxvbmcJPjAJW3Jlcz0lZHgNCj4xNAliZWxvbmcJPjAJJWRdDQoNCiMgTWFnaWMgSUQgZm9yIFBhaW50IHNob3AgcHJvIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMSBieSBDYXJsDQowCXN0cmluZwlQYWludCBTaG9wIFBybyBJbWFnZSBGaWxlXFx4MGFcXHgxYQlbZmlkPTAwMDAwMTMxMC0zMS0wMDAwUFNQO2V4dD1wc3A7bWltZT07XVBhaW50c2hvcCBwcm8gaW1hZ2UgZmlsZQ0KPjUwCWxlbG9uZwk+MAlbcmVzPSVkeA0KPjU0CWxlbG9uZwk+MAklZA0KPjY5CWxlc2hvcnQJPjAJeCVkYnBwXQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJYmVsb25nCTB4NTlhNjZhOTUJW2ZpZD0wMDAwMDEwMTEtMzEtMDAwMFJBUztleHQ9cmFzO21pbWU9O11TdW4gcmFzdGVyIGltYWdlDQo+NAliZWxvbmcJPjAJW3Jlcz0lZHgNCj44CWJlbG9uZwk+MAklZA0KPjEyCWJlbG9uZwk+MAl4JWRicHBdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAlzdHJpbmcJXFwweDAxXFx4REEJW2ZpZD0wMDAwMDEwMDQtMzEtMDAwMFJHQjtleHQ9cmdiO21pbWU9O11TR0kgSW1hZ2UgZmlsZQ0KPjI0CXN0cmluZwk+XFx4MDAJW3RpdGxlPSUuODBzXQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTMxIGJ5IENhcmwNCjAJc3RyaW5nCVxceDAxXFx4REFcXHgwMFxceDAxCVtmaWQ9MDAwMDAxMDA0LTMxLTAwMDBSR0I7ZXh0PXJnYjttaW1lPTtdU0dJIEltYWdlIGZpbGUNCiYxMAliZXNob3J0CTEJDQo+NgliZXNob3J0CXgJW3Jlcz0lZHgNCj44CWJlc2hvcnQJeAklZHg4YnBwXQ0KPjI0CXN0cmluZwk+XFx4MAlbdGl0bGU9JS44MHNdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDFcXHhEQVxceDAwXFx4MDEJW2ZpZD0wMDAwMDEwMDQtMzEtMDAwMFJHQjtleHQ9cmdiO21pbWU9O11TR0kgSW1hZ2UgZmlsZQ0KJjEwCWJlc2hvcnQJMwkNCj42CWJlc2hvcnQJeAlbcmVzPSVkeA0KPjgJYmVzaG9ydAl4CSVkeDI0YnBwXQ0KPjI0CXN0cmluZwk+XFx4MAlbdGl0bGU9JS44MHNdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDFcXHhEQVxceDAwXFx4MDEJW2ZpZD0wMDAwMDEwMDQtMzEtMDAwMFJHQjtleHQ9cmdiO21pbWU9O11TR0kgSW1hZ2UgZmlsZQ0KJjEwCWJlc2hvcnQJNAkNCj42CWJlc2hvcnQJeAlbcmVzPSVkeA0KPjgJYmVzaG9ydAl4CSVkeDI0YnBwXQ0KPjI0CXN0cmluZwk+XFx4MAlbdGl0bGU9JS44MHNdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMzEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDFcXHhEQVxceDAxXFx4MDEJW2ZpZD0wMDAwMDEwMDQtMzEtMDAwMFJHQjtleHQ9cmdiO21pbWU9O11TR0kgSW1hZ2UgZmlsZSwgY29tcHJlc3NlZA0KJjEwCWJlc2hvcnQJMQkNCj42CWJlc2hvcnQJeAlbcmVzPSVkeA0KPjgJYmVzaG9ydAl4CSVkeDhicHBdDQo+MjQJc3RyaW5nCT5cXHgwCVt0aXRsZT0lLjgwc10NCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0zMSBieSBDYXJsDQowCXN0cmluZwlcXHgwMVxceERBXFx4MDFcXHgwMQlbZmlkPTAwMDAwMTAwNC0zMS0wMDAwUkdCO2V4dD1yZ2I7bWltZT07XVNHSSBJbWFnZSBmaWxlLCBjb21wcmVzc2VkDQomMTAJYmVzaG9ydAkzCQ0KPjYJYmVzaG9ydAl4CVtyZXM9JWR4DQo+OAliZXNob3J0CXgJJWR4MjRicHBdDQo+MjQJc3RyaW5nCT5cXHgwCVt0aXRsZT0lLjgwc10NCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0zMSBieSBDYXJsDQowCXN0cmluZwlcXHgwMVxceERBXFx4MDFcXHgwMQlbZmlkPTAwMDAwMTAwNC0zMS0wMDAwUkdCO2V4dD1yZ2I7bWltZT07XVNHSSBJbWFnZSBmaWxlLCBjb21wcmVzc2VkDQomMTAJYmVzaG9ydAk0CQ0KPjYJYmVzaG9ydAl4CVtyZXM9JWR4DQo+OAliZXNob3J0CXgJJWR4MjRicHBdDQo+MjQJc3RyaW5nCT5cXHgwCVt0aXRsZT0lLjgwc10NCg0KIyBNYWdpYyBJRCBmb3IgVHVyYm8gU2lsdmVyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMyBieSBDYXJsDQowCXN0cmluZwlGT1JNCVtmaWQ9MDAwMDAxMjUyLTMxLTAwMFJHQjg7ZXh0PXJnYjgscmdiO21pbWU9O11UdXJibyBTaWx2ZXIgMjQtYml0IFJHQiBpbWFnZSBmaWxlDQomOAlzdHJpbmcJUkdCOAkNCg0KIyBNYWdpYyBJRCBmb3IgVHVyYm8gU2lsdmVyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMyBieSBDYXJsDQowCXN0cmluZwlGT1JNCVtmaWQ9MDAwMDAxMjUyLTMxLTAwMFJHQk47ZXh0PXJnYm4scmdiO21pbWU9O11UdXJibyBTaWx2ZXIgMTItYml0IFJHQiBpbWFnZSBmaWxlDQomOAlzdHJpbmcJUkdCTgkNCg0KIyBNYWdpYyBJRCBmb3IgQ29sb1JJWCBWR0EgUGFpbnQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTA4IGJ5IENhcmwNCjAJc3RyaW5nCVJJWDMJW2ZpZD0wMDAwMDEzMjAtMzEtMDAwMFNDWjtleHQ9c2N6O21pbWU9O11Db2xvclJJWCBWR0EgUGFpbnQgaW1hZ2UgZmlsZQ0KPjQJbGVzaG9ydAl4CVtyZXM9JWQNCj42CWxlc2hvcnQJeAl4JWRdDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTMgYnkgQnJ5YW4gSGVuZGVyc29uDQowCXN0cmluZwlcXDExN1xcMDcyCVtmaWQ9MDAwMDAwMDAwLTMxLTAwMDBTSVI7ZXh0PXNpcjttaW1lPTtdU29saXRhaXJlIGltYWdlIHJlY29yZGVyIGltYWdlIGZpbGUsIE1HSSB0eXBlIDExDQomNAlzdHJpbmcJXFwwMTMJDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTMgYnkgQnJ5YW4gSGVuZGVyc29uDQowCXN0cmluZwlcXDExN1xcMDcyCVtmaWQ9MDAwMDAwMDAwLTMxLTAwMDBTSVI7ZXh0PXNpcjttaW1lPTtdU29saXRhaXJlIGltYWdlIHJlY29yZGVyIGltYWdlIGZpbGUsIE1HSSB0eXBlIDE3DQomNAlzdHJpbmcJXFwwMjEJDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDEgYnkgQ2FybA0KWjE4CXN0cmluZwlUUlVFVklTSU9OLVhGSUxFCVtmaWQ9MDAwMDAxMzA2LTMxLTAwMDBUR0E7ZXh0PXRnYTttaW1lPTtdVHJ1ZXZpc2lvbiBUYXJnYSBpbWFnZSBmaWxlDQo+MTIJbGVzaG9ydAl4CVtyZXM9JWR4DQo+MTQJbGVzaG9ydAl4CSVkDQo+MTYJYnl0ZQl4CXglZGJwcF0NCg0KIyBNYWdpYyBJRCBmb3IgR3JhcGhpY3MgV29ya3Nob3AgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAxIGJ5IENhcmwNCjAJc3RyaW5nCVRITkwJW2ZpZD0wMDAwMDEyNTgtMzEtMDAwMFRITjtleHQ9dGhuO21pbWU9O11HcmFwaGljcyB3b3Jrc2hvcCB0aHVtYm5haWwgaW1hZ2UgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTMxIGJ5IENhcmwNCjAJc3RyaW5nCUlJCVtmaWQ9MDAwMDAxMDAzLTMxLTAwMDBUSUY7ZXh0PXRpZix0aWZmLGRuZzttaW1lPWltYWdlL3RpZmY7XVRhZ2dlZCBpbWFnZSBmaWxlIGZvcm1hdCBpbWFnZSBmaWxlLCBsaXR0bGUtZW5kaWFuDQomMglsZXNob3J0CTQyCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTMxIGJ5IENhcmwNCjAJc3RyaW5nCU1NCVtmaWQ9MDAwMDAxMDAzLTMxLTAwMDBUSUY7ZXh0PXRpZix0aWZmLGRuZzttaW1lPWltYWdlL3RpZmY7XVRhZ2dlZCBpbWFnZSBmaWxlIGZvcm1hdCBpbWFnZSBmaWxlLCBiaWctZW5kaWFuDQomMglsZXNob3J0CQkNCg0KIyBNYWdpYyBJRCBmb3IgVklDQVIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAxIGJ5IENhcmwNCjAJc3RyaW5nCUxCTFNJWkU9CVtmaWQ9MDAwMDAxMDIyLTMxLTAwMDBWSUM7ZXh0PXZpYyx2aWNhcjttaW1lPTtdVmljYXIgaW1hZ2UgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBLaG9yb3MgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAxIGJ5IENhcmwNCjAJc3RyaW5nCVxceEFCXFx4MDFcXHgwMVxceDAzCVtmaWQ9MDAwMDAxMzA4LTMxLTAwMDBWSUY7ZXh0PXZpZix2aWZmO21pbWU9O11LaG9yb3MgVmlzdWFsaXphdGlvbi9JbWFnZSBGaWxlIEZvcm1hdCwgdmVyc2lvbiAxLjMNCiY0CWJ5dGUJMgkNCj41MjAJYmVsb25nCT4wCVtyZXM9JWR4DQo+NTI0CWJlbG9uZwk+MAklZF0NCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMiBieSBDYXJsDQowCXN0cmluZwlGSUFTQ08JW2ZpZD0wMDAxMDAxMDctMzEtMDAwMFdGQTtleHQ9d2ZhO21pbWU9O11GcmFjdGFsIEltYWdlIEFuZCBTZXF1ZW5jZSBDb2RlYyBpbWFnZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFgtV2luZG93cyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDEgYnkgQ2FybA0KMAlzdHJpbmcJLyogWFBNICovCVtmaWQ9MDAwMDAxMDIwLTMxLTAwMDBYUE07ZXh0PXhwbTttaW1lPTtdWC1XaW5kb3dzIHBpeGVsIG1hcCBpbWFnZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFhWIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wMSBieSBDYXJsDQowCXN0cmluZwlQN1xcIDMzMglbZmlkPTAwMDEwMDEwMy0zMS0wMDAwMFhWO2V4dD14djttaW1lPTtdWFYgVGh1bWJuYWlsIGltYWdlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgWFdpbmRvd3MgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAyIGJ5IENhcmwNCjAJYmVsb25nCTB4NDAJW2ZpZD0wMDAwMDEwMjAtMzEtMDAwMFhXRDtleHQ9eHdkO21pbWU9O11YMTAgWFdpbmRvd3MgZHVtcCBpbWFnZSBmaWxlDQomNAliZWxvbmcJMHgwNgkNCj4yNAliZWxvbmcJeAlbcmVzPSVkDQo+MjgJYmVsb25nCXgJeCVkXQ0KDQojIE1hZ2ljIElEIGZvciBYV2luZG93cyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDIgYnkgQ2FybA0KMAlsZWxvbmcJMHg0MAlbZmlkPTAwMDAwMTAyMC0zMS0wMDAwWFdEO2V4dD14d2Q7bWltZT07XVgxMCBYV2luZG93cyBkdW1wIGltYWdlIGZpbGUNCiY0CWxlbG9uZwkweDA2CQ0KPjI0CWxlbG9uZwl4CVtyZXM9JWQNCj4yOAlsZWxvbmcJeAl4JWRdDQoNCiMgTWFnaWMgSUQgZm9yIFByb3ZlY3RvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDggYnkgQ2FybA0KMAlzdHJpbmcJRk9STQlbZmlkPTAwMDAwMTMxOS0zMi0wMDBEUjJEO2V4dD1kcjJkO21pbWU9O11Qcm92ZWN0b3IgMkQgaW1hZ2UgZmlsZQ0KJjgJc3RyaW5nCURSMkQJDQoNCiMgTWFnaWMgSUQgZm9yIFhGaWcsIFdpbkZpZywgakZpZyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJI0ZJRwlbZmlkPTAwMDEwMDAxMS0zMi0wMDAwRklHO2V4dD1maWc7bWltZT07XUZhY2lsaXR5IGZvciBJbnRlcmFjdGl2ZSBHZW5lcmF0aW9uIGZpbGUNCj41CXN0cmluZwl4CSwgdmVyc2lvbiAlLjFzLg0KPjcJc3RyaW5nCXgJJS4xcw0KDQojIE1hZ2ljIElEIGZvciBMb3R1cyAxLTItMyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMDIgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDFcXHgwMFxceDAwXFx4MDBcXHgwMVxceDAwXFx4MDhcXHgwMFxceDQ0CVtmaWQ9MDAwMDAxMDA5LTMyLTAwMDBQSUM7ZXh0PXBpYzttaW1lPTtdTG90dXMgMS0yLTMgaW1hZ2UgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBBdXRvY2FkIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwlBdXRvQ0FEIFNsaWRlCVtmaWQ9MDAwMDAxMjU0LTMyLTAwMDBTTEQ7ZXh0PXNsZDttaW1lPTtdQXV0b2NhZCBzbGlkZSBpbWFnZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFdvcmRwZXJmZWN0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlcXHhmZldQQwlbZmlkPTAwMDAwMTAwOC0zMi0wMDAwV1BHO2V4dD13cGc7bWltZT07XVdvcmRwZXJmZWN0IEdyYXBoaWNzIHZlY3RvcnMNCiY4CWJ5dGUJMQkNCiY5CWJ5dGUJMHgxNgkNCj4xMAlieXRlCXgJLCB2ZXJzaW9uICVkLg0KPjExCWJ5dGUJeAklZA0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCUZPUk0JW2ZpZD0wMDAxMDAwMTktMzMtMDAwQU1GRjtleHQ9YW1mZjttaW1lPTtdQW1pZ2EgbWV0YWZpbGUNCiY4CXN0cmluZwlBTUZGCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJbGVsb25nCTB4OUFDNkNERDcJW2ZpZD0wMDAwMDEwMDMtMzMtMDAwMEFQTTtleHQ9YXBtO21pbWU9O11BbGR1cyBwbGFjZWFibGUgV2luZG93cyBtZXRhZmlsZQ0KJjQJbGVzaG9ydAkwCQ0KDQojIE1hZ2ljIElEIGZvciBDb3JlbERSQVcgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCVJJRkYJW2ZpZD0wMDAwMDEwMDgtMzMtMDAwMENEUjtleHQ9Y2RyO21pbWU9O11Db3JlbGRyYXcgIGxpdHRsZS1lbmRpYW4gbWV0YWZpbGUNCiY4CXN0cmluZwlDRFIJDQoNCiMgTWFnaWMgSUQgZm9yIENvcmVsRFJBVyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJUklGWAlbZmlkPTAwMDAwMTAwOC0zMy0wMDAwQ0RSO2V4dD1jZHI7bWltZT07XUNvcmVsZHJhdyAgYmlnLWVuZGlhbiBtZXRhZmlsZQ0KJjgJc3RyaW5nCUNEUgkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wOCBieSBDYXJsDQowCWJlc2hvcnQmMHhGRjIwCTB4MDAyMAlbZmlkPTAwMDAwMDAwMS0zMy0wMDA4NjMyO2V4dD1jZ207bWltZT1pbWFnZS9jZ207XUNvbXB1dGVyIGdyYXBoaWNzIG1ldGFmaWxlLCBiaW5hcnkgZW5jb2RlZA0KJloweDAyCWJlc2hvcnQmMHhGRjQwCTB4MDA0MAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0wOCBieSBDYXJsDQowCXN0cmluZwlCRUdNRglbZmlkPTAwMDAwMDAwMS0zMy0wMDA4NjMyO2V4dD1jZ207bWltZT1pbWFnZS9jZ207XUNvbXB1dGVyIGdyYXBoaWNzIG1ldGFmaWxlLCBhc2NpaSBlbmNvZGVkDQoNCiMgTWFnaWMgSUQgZm9yIENvcmVsRFJBVyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJUklGRglbZmlkPTAwMDAwMTAwOC0zMy0wMDAwQ01YO2V4dD1jbXg7bWltZT07XUNvcmVsIGxpdHRsZS1lbmRpYW4gbWV0YWZpbGUNCiY4CXN0cmluZwlDTVgxCQ0KDQojIE1hZ2ljIElEIGZvciBDb3JlbERSQVcgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCVJJRlgJW2ZpZD0wMDAwMDEwMDgtMzMtMDAwMENNWDtleHQ9Y214O21pbWU9O11Db3JlbCBiaWctZW5kaWFuIG1ldGFmaWxlDQomOAlzdHJpbmcJQ01YMQkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCWxlbG9uZwkweDAwMDAwMDAxCVtmaWQ9MDAwMDAxMDAxLTMzLTAwMDBFTUY7ZXh0PWVtZjttaW1lPTtdTWljcm9zb2Z0IFdpbmRvd3MgRW5oYW5jZWQgbWV0YWZpbGUNCiY0MAlsZWxvbmcJMHg0NjRENDUyMAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwklIVBTLUFkb2JlLTIuMFxcIEVQU0YtMS4yCVtmaWQ9MDAwMDAxMDAzLTMzLTAwMEVQU0Y7ZXh0PWVwc2Y7bWltZT1hcHBsaWNhdGlvbi9wb3N0c2NyaXB0O11BZG9iZSBFbmNhcHN1bGF0ZWQgUG9zdHNjcmlwdCBMZXZlbCAyLCB2ZXJzaW9uIDEuMg0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCSUhUFMtQWRvYmUtMi4wXFwgRVBTRi0yLjAJW2ZpZD0wMDAwMDEwMDMtMzMtMDAwRVBTRjtleHQ9ZXBzZjttaW1lPWFwcGxpY2F0aW9uL3Bvc3RzY3JpcHQ7XUFkb2JlIEVuY2Fwc3VsYXRlZCBQb3N0c2NyaXB0IExldmVsIDIsIHZlcnNpb24gMi4wDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJJSFQUy1BZG9iZS0zLjBcXCBFUFNGLTMuMAlbZmlkPTAwMDAwMTAwMy0zMy0wMDBFUFNGO2V4dD1lcHNmO21pbWU9YXBwbGljYXRpb24vcG9zdHNjcmlwdDtdQWRvYmUgRW5jYXBzdWxhdGVkIFBvc3RzY3JpcHQgTGV2ZWwgMywgdmVyc2lvbiAzLjANCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlcXHhDNVxceEQwXFx4RDNcXHhDNglbZmlkPTAwMDAwMTAwMy0zMy0wMDBFUFNGO2V4dD1lcHNmLGFpO21pbWU9YXBwbGljYXRpb24vcG9zdHNjcmlwdDtdQWRvYmUgRW5jYXBzdWxhdGVkIFBvc3RzY3JpcHQsIHZlcnNpb24gMy4wLCBiaW5hcnkNCg0KIyBNYWdpYyBJRCBmb3IgR0VNIFBhaW50IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0zMSBieSBDYXJsDQowCWJlc2hvcnQJMHhGRkZGCVtmaWQ9MDAwMDAxMjczLTMzLTAwMDBHRU07ZXh0PWdlbTttaW1lPTtdR2VtRE9TIE1vdG9yb2xhIE1ldGFmaWxlLCB2ZXJzaW9uIDEuMDENCiY0CWJlc2hvcnQJMTAxCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IGh0dHA6Ly93d3cuc2Vhc2lwLmluZm8vR2VtL2ZmX2dlbS5odG1sDQowCWxlc2hvcnQJMHhGRkZGCVtmaWQ9MDAwMDAxMjczLTMzLTAwMDBHRU07ZXh0PWdlbTttaW1lPTtdR2VtRE9TIE1ldGFmaWxlDQomNAlsZXNob3J0CTAJDQoNCiMgTWFnaWMgSUQgZm9yIEFydGxpbmUgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IGh0dHA6Ly93d3cuc2Vhc2lwLmluZm8vR2VtL2ZmX2dlbS5odG1sDQowCWxlc2hvcnQJMHhGRkZGCVtmaWQ9MDAwMDAxMjczLTMzLTAwMDBHRU07ZXh0PWdlbTttaW1lPTtdR2VtRE9TIEludGVsIE1ldGFmaWxlLCB2ZXJzaW9uIDQuMDANCiY0CWxlc2hvcnQJNDAwCQ0KDQojIE1hZ2ljIElEIGZvciBEZXNrcHJlc3MgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IGh0dHA6Ly93d3cuc2Vhc2lwLmluZm8vR2VtL2ZmX2dlbS5odG1sDQowCWxlc2hvcnQJMHhGRkZGCVtmaWQ9MDAwMDAxMjczLTMzLTAwMDBHRU07ZXh0PWdlbTttaW1lPTtdR2VtRE9TIEludGVsIE1ldGFmaWxlLCB2ZXJzaW9uIDMuMTANCiY0CWxlc2hvcnQJMzEwCQ0KDQojIE1hZ2ljIElEIGZvciBHRU0gUGFpbnQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IGh0dHA6Ly93d3cuc2Vhc2lwLmluZm8vR2VtL2ZmX2dlbS5odG1sDQowCWxlc2hvcnQJMHhGRkZGCVtmaWQ9MDAwMDAxMjczLTMzLTAwMDBHRU07ZXh0PWdlbTttaW1lPTtdR2VtRE9TIEludGVsIE1ldGFmaWxlLCB2ZXJzaW9uIDEuMDENCiY0CWxlc2hvcnQJMTAxCQ0KDQojIE1hZ2ljIElEIGZvciBRdWlja2RyYXcgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTAxIGJ5IENhcmwNCjB4MjBBCWJlbG9uZwkweDAwMTEwMkZGCVtmaWQ9MDAwMDAxMDAyLTMzLTAwMDBQQ1Q7ZXh0PXBjdDttaW1lPTtdTWFjaW50b3NoIFF1aWNrZHJhdyBtZXRhZmlsZSBcJ1BJQ1RcJywgdmVyc2lvbiAyLjANCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCWxlc2hvcnQJMHgwMDAxCVtmaWQ9MDAwMDAxMDAxLTMzLTAwMDBXTUY7ZXh0PXdtZjttaW1lPTtdTWljcm9zb2Z0IFdpbmRvd3MgbWV0YWZpbGUNCiYyCWxlc2hvcnQJOQkNCg0KIyBNYWdpYyBJRCBmb3IgQ2luZW1hIDREIFZlcnNpb24gNS54IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wNiBieSBDYXJsDQowCXN0cmluZwlNQzUwCVtmaWQ9MDAwMDAxMjU1LTQwLTAwMDAwMDA7ZXh0PTttaW1lPTtdTWF4b24gQ2luZW1hIDREIHZlcnNpb24gNSAzRCBkYXRhDQoNCiMgTWFnaWMgSUQgZm9yIFF1aWNrZHJhdyAzRCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDYgYnkgQ2FybA0KMAlzdHJpbmcJM0RNRglbZmlkPTAwMDAwMTAwMi00MC0wMDAzRE1GO2V4dD0zZG1mO21pbWU9O11BcHBsZSBRdWlja2RyYXcgM0QgbWV0YWZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgUmhpbm8gM2QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCTNEIEdlb21ldHJ5IEZpbGUgRm9ybWF0CVtmaWQ9MDAwMDAxMzMwLTQwLTAwMDNETUY7ZXh0PTNkbWY7bWltZT07XVJoaW5vM2QgLyBPcGVuTnVyYnMgM2QgbW9kZWwNCg0KIyBNYWdpYyBJRCBmb3IgUXVpY2tkcmF3IDNEIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMSBieSBDYXJsDQowCXN0cmluZwkzRE1ldGFmaWxlCVtmaWQ9MDAwMDAxMDAyLTQwLTAwMDNETUY7ZXh0PTNkbWYsYTNkO21pbWU9O11BcHBsZSBRdWlja2RyYXcgM0QgbWV0YWZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQUMzZCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTIgYnkgQ2FybA0KMAlzdHJpbmcJQUMzRAlbZmlkPTAwMDAwMDAwMC00MC0wMDAwMEFDO2V4dD1hYzttaW1lPTtdQWMzZCAzZCBtb2RlbA0KDQojIE1hZ2ljIElEIGZvciAzZFN0dWRpbyBNYXggZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCSozRFNNQVhfQVNDSUlFWFBPUlQJW2ZpZD0wMDAwMDEzMjYtNDAtMDAwMEFTRTtleHQ9YXNlO21pbWU9O10zZCBzdHVkaW8gbWF4IGFzY2lpIGV4cG9ydCAzRCBtb2RlbA0KDQojIE1hZ2ljIElEIGZvciBDYWxpZ2FyaSBUcnVlc3BhY2UgTW9kZWxlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDYgYnkgQ2FybA0KMAlzdHJpbmcJQ2FsaWdhcmlcXCBWCVtmaWQ9MDAwMDAxMjU2LTQwLTAwMDBDT0I7ZXh0PWNvYixzY247bWltZT07XUNhbGlnYXJpIFRydWVzcGFjZTIgM0QgbW9kZWwNCg0KIyBNYWdpYyBJRCBmb3IgVGFjaHlvbiBwYXJhbGxlbCByYXl0cmFjZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCUJFR0lOX1NDRU5FCVtmaWQ9MDAwMTAwMTE2LTQwLTAwMDBEQVQ7ZXh0PWRhdDttaW1lPTtdVGFjaHlvbiByYXktdHJhY2VyIDNkIG1vZGVsDQoNCiMgTWFnaWMgSUQgZm9yIEF1dG9jYWQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCUFDMTAJW2ZpZD0wMDAwMDEyNTQtNDAtMDAwMERXRztleHQ9ZHdnO21pbWU9aW1hZ2Uvdm5kLmR3ZztdQXV0b2NhZCBkcmF3aW5nIGZvcm1hdCAzZCBtb2RlbA0KDQojIE1hZ2ljIElEIGZvciBBdXRvY2FkIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwlBdXRvQ0FEIEJpbmFyeSBEWEYJW2ZpZD0wMDAwMDEyNTQtNDAtMDAwMERYRjtleHQ9ZHhmO21pbWU9aW1hZ2Uvdm5kLmR4ZjtdQXV0b2NhZCBkcmF3aW5nIGludGVyY2hhbmdlIDNkIG1vZGVsLCBiaW5hcnkNCg0KIyBNYWdpYyBJRCBmb3IgTXVsdGlnZW4gY3JlYXRvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTIgYnkgQ2FybA0KMAliZXNob3J0CTEJW2ZpZD0wMDAwMDEzMzItNDAtMDAwMEZMVDtleHQ9Zmx0O21pbWU9O11PcGVuZmxpZ2h0IHNjZW5lIGRlc2NyaXB0aW9uIDNkIG1vZGVsDQomNAlzdHJpbmcJZGIJDQoNCiMgTWFnaWMgSUQgZm9yIFZpZGVvc2NhcGUgM0QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCUdPVVIJW2ZpZD0wMDAwMDEzMjgtNDAtMDAwMEdFTztleHQ9Z2VvO21pbWU9O11WaWRlb3NjYXBlIDNkIG1vZGVsIHdpdGggY29sb3JlZCB2ZXJ0aWNlcw0KDQojIE1hZ2ljIElEIGZvciBWaWRlb3NjYXBlIDNELCBCbGVuZGVyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwkzREcxCVtmaWQ9MDAwMDAxMzI4LTQwLTAwMDBHRU87ZXh0PWdlbzttaW1lPTtdVmlkZW9zY2FwZSAzZCBtb2RlbCB3aXRoIGNvbG9yZWQgZmFjZXMNCg0KIyBNYWdpYyBJRCBmb3IgVmlkZW9zY2FwZSAzRCwgQmxlbmRlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTIgYnkgQ2FybA0KMAlzdHJpbmcJM0RHMglbZmlkPTAwMDAwMTMyOC00MC0wMDAwR0VPO2V4dD1nZW87bWltZT07XVZpZGVvc2NhcGUgM2QgbW9kZWwgbGlnaHQgc291cmNlDQoNCiMgTWFnaWMgSUQgZm9yIFZpZGVvc2NhcGUgM0QsIEJsZW5kZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCTNERzMJW2ZpZD0wMDAwMDEzMjgtNDAtMDAwMEdFTztleHQ9Z2VvO21pbWU9O11WaWRlb3NjYXBlIDNkIG1vZGVsIHdpdGggZ291cmF1ZCBjdXJ2ZXMNCg0KIyBNYWdpYyBJRCBmb3IgU29mdGltYWdlIDREIENyZWF0aXZlIGVudmlyb25tZW50IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwlIUkNIOglbZmlkPTAwMDAwMTMyMS00MC0wMDAwSFJDO2V4dD1ocmM7bWltZT07XVNvZnRpbWFnZSA0ZCBtb2RlbCwgYXNjaWkgZW5jb2RlZA0KDQojIE1hZ2ljIElEIGZvciBPcGVuIEludmVudG9yIFRvb2xraXQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA2IGJ5IENhcmwNCjAJc3RyaW5nCSNJbnZlbnRvcglbZmlkPTAwMDAwMTAwNC00MC0wMDAwMElWO2V4dD1pdjttaW1lPTtdT3BlbiBJbnZlbnRvciAzZCBtb2RlbA0KPjExCXN0cmluZwl4CSwgdmVyc2lvbiAlLjFzLg0KPjEzCXN0cmluZwl4CSUuMXMNCj4xNQlzdHJpbmcJYmluYXJ5CSwgYmluYXJ5IGVuY29kZWQNCj4xNQlzdHJpbmcJYXNjaWkJLCBhc2NpaSBlbmNvZGVkDQoNCiMgTWFnaWMgSUQgZm9yIEdlb212aWV3IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwlMSVNUCVtmaWQ9MDAwMTAwMTE4LTQwLTAwMExJU1Q7ZXh0PWxpc3Q7bWltZT07XUdlb212aWV3IGxpc3Qgb2YgM0QgbW9kZWxzIGFuZCBvYmplY3RzDQoNCiMgTWFnaWMgSUQgZm9yIExpZ2h0d2F2ZSAzRCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTIgYnkgQ2FybA0KMAlzdHJpbmcJRk9STQlbZmlkPTAwMDAwMTI1MS00MC0wMDAwTFdPO2V4dD1sd28sbHdvYjttaW1lPTtdTGlnaHR3YXZlIDNEIG9iamVjdA0KJjgJc3RyaW5nCUxXTzIJDQoNCiMgTWFnaWMgSUQgZm9yIExpZ2h0d2F2ZSAzRCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDYgYnkgQ2FybA0KMAlzdHJpbmcJRk9STQlbZmlkPTAwMDAwMTI1MS00MC0wMDAwTFdPO2V4dD1sd29iLGx3bzttaW1lPTtdTGlnaHR3YXZlIDNEIG9iamVjdA0KJjgJc3RyaW5nCUxXT0IJDQoNCiMgTWFnaWMgSUQgZm9yIExpZ2h0d2F2ZSAzRCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDYgYnkgQ2FybA0KMAlzdHJpbmcJTFdTQwlbZmlkPTAwMDAwMTI1MS00MC0wMDAwTFdTO2V4dD1sd3NjLGx3czttaW1lPTtdTGlnaHR3YXZlIDNEIHNjZW5lDQoNCiMgTWFnaWMgSUQgZm9yIE1heWEgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCS8vTWF5YQlbZmlkPTAwMDAwMTMxMi00MC0wMDAwME1BO2V4dD1tYTttaW1lPTtdTWF5YSAzZCBtb2RlbCwgYXNjaWkgZW5jb2RlZA0KDQojIE1hZ2ljIElEIGZvciBDaW5lbWEgNEQgVmVyc2lvbiA0LnggYW5kIGVhcmxpZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA2IGJ5IENhcmwNCjAJc3RyaW5nCUZPUk0JW2ZpZD0wMDAwMDEyNTUtNDAtMDAwTUM0RDtleHQ9bWM0ZDttaW1lPTtdTWF4b24gQ2luZW1hIDREIHY0LnggM0QgZGF0YQ0KJjgJc3RyaW5nCU1DNEQJDQoNCiMgTWFnaWMgSUQgZm9yIEdlb212aWV3IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwlDTUVTSAlbZmlkPTAwMDEwMDExOC00MC0wMDBNRVNIO2V4dD1tZXNoO21pbWU9O11HZW9tdmlldyBwb2x5Z29uDQoNCiMgTWFnaWMgSUQgZm9yIEdlb212aWV3IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwlNRVNICVtmaWQ9MDAwMTAwMTE4LTQwLTAwME1FU0g7ZXh0PW1lc2g7bWltZT07XUdlb212aWV3IHBvbHlnb24NCg0KIyBNYWdpYyBJRCBmb3IgTWlsc2hhcGUgM2QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCU1TM0QwMDAwMDAJW2ZpZD0wMDAxMDAxMTctNDAtMDAwTVMzRDtleHQ9bXMzZDttaW1lPTtdTWlsa3NoYXBlIDNkIG1vZGVsLCBiaW5hcnkgZW5jb2RlZA0KDQojIE1hZ2ljIElEIGZvciBXb3JsZHRvb2xraXQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA2IGJ5IENhcmwNCjAJc3RyaW5nCW5mZglbZmlkPTAwMDAwMTI1My00MC0wMDAwTkZGO2V4dD1uZmY7bWltZT07XVNlbnNlOCBXb3JsZHRvb2xraXQgM0Qgb2JqZWN0DQoNCiMgTWFnaWMgSUQgZm9yIEF1dG9kZXNrIEFuaW1hdG9yIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQoyCWxlbG9uZwkweDAwMDAJW2ZpZD0wMDAwMDEyNTQtNDAtMDAwMFBMWTtleHQ9cGx5O21pbWU9O11BdXRvZGVzayBhbmltYXRvciBwb2x5Z29uIGZpbGUNCiY2CWJ5dGUJMAkNCiY3CWJ5dGUJMHg5OQkNCg0KIyBNYWdpYyBJRCBmb3IgQXV0b2Rlc2sgQW5pbWF0b3IgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjIJbGVsb25nCTB4MDAwMAlbZmlkPTAwMDAwMTI1NC00MC0wMDAwUExZO2V4dD1wbHk7bWltZT07XUF1dG9kZXNrIGFuaW1hdG9yIHBvbHlnb24gZmlsZQ0KJjYJYnl0ZQkxCQ0KJjcJYnl0ZQkweDk5CQ0KDQojIE1hZ2ljIElEIGZvciBRdWljazNkIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwlxdWljazNEbwlbZmlkPTAwMDAwMTMzNC00MC0wMDAwUTNPO2V4dD1xM287bWltZT07XVF1aWNrM2QgM0Qgb2JqZWN0DQoNCiMgTWFnaWMgSUQgZm9yIFF1aWNrM2QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCXF1aWNrM0RzCVtmaWQ9MDAwMDAxMzM0LTQwLTAwMDBRM1M7ZXh0PXEzczttaW1lPTtdUXVpY2szZCAzRCBzY2VuZQ0KDQojIE1hZ2ljIElEIGZvciBSZW5kZXJtYW4gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCSMjUmVuZGVyTWFuXFwgUklCLVN0cnVjdHVyZQlbZmlkPTAwMDAwMTMyMy00MC0wMDAwUklCO2V4dD1yaWI7bWltZT07XVJlbmRlcm1hbiBieXRlc3RyZWFtIDNEIG1vZGVsDQoNCiMgTWFnaWMgSUQgZm9yIFNjdWxwdCAzZCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMTIgYnkgQ2FybA0KMAlzdHJpbmcJRk9STQlbZmlkPTAwMDAwMDAwMC00MC0wMFNDRU5FO2V4dD1zY2VuZTttaW1lPTtdU2N1bHB0IDNkIHNjZW5lIG1vZGVsDQomOAlzdHJpbmcJU0MzRAkNCg0KIyBNYWdpYyBJRCBmb3IgSW1hZ2luZSAzRCBTdHVkaW8sIFR1cmJvIFNpbHZlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDYgYnkgQ2FybA0KMAlzdHJpbmcJRk9STQlbZmlkPTAwMDAwMTI1Mi00MC0wMDBUREREO2V4dD10ZGRkLG9iajttaW1lPTtdSW1hZ2luZSAzRCBvYmplY3QNCiY4CXN0cmluZwlURERECQ0KDQojIE1hZ2ljIElEIGZvciBNYWNyb21lZGlhIERpcmVjdG9yIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwlJRlgJW2ZpZD0wMDAwMDEyNTktNDAtMDAwMFczRDtleHQ9dzNkO21pbWU9O11TaG9ja3dhdmUgM0QgbW9kZWwNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wNiBieSBDYXJsDQowCXN0cmluZwkjVlJNTAlbZmlkPTAwMDAwMDAwMS00MC0wMDE0NzcyO2V4dD13cmw7bWltZT1tb2RlbC92cm1sO11WaXJ0dWFsIFJlYWxpdHkgbW9kZWxpbmcgbGFuZ3VhZ2UNCj43CXN0cmluZwl4CSwgdmVyc2lvbiAlLjFzLg0KPjkJc3RyaW5nCXgJJS4xcw0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTEyIGJ5IENhcmwNCjAJc3RyaW5nCTxXT1JMRD4JW2ZpZD0wMDAwMDAwMDAtNDAtMDAwMFhHTDtleHQ9eGdsO21pbWU9O11YR0wgM2QgbW9kZWwNCg0KIyBNYWdpYyBJRCBmb3IgRGlyZWN0M0QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA0LTExIGJ5IENhcmwNCjAJc3RyaW5nCXhvZlxcIAlbZmlkPTAwMDAwMTAwMS00MC0wMDAwWElFO2V4dD14aWU7bWltZT07XU1pY3Jvc29mdCBkaXJlY3QzZCAzRCBtb2RlbA0KDQojIE1hZ2ljIElEIGZvciBTb2Z0aW1hZ2UgWFNJIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMiBieSBDYXJsDQowCXN0cmluZwl4c2lcXCAJW2ZpZD0wMDAwMDEzMjEtNDAtMDAwMFhTSTtleHQ9eHNpO21pbWU9O11Tb2Z0aW1hZ2UgM2QgbW9kZWwNCg0KIyBNYWdpYyBJRCBmb3IgS2Fib29tIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlcXHhBOE1QXFx4QTgJW2ZpZD0wMDAwMDAwMDAtNTAtMDAwMDAwMDtleHQ9O21pbWU9O11LYm9vbSBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQ1RXIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNCBieSBDYXJsDQowCWxlc2hvcnQJMTIJW2ZpZD0wMDAxMDAwNzctNTAtMDAwMDAwMDtleHQ9O21pbWU9O11Db250ZXh0IHRyZWUgd2VpZ2hpbmcgKENUVykgYXJjaGl2ZSBmaWxlDQomMglsZXNob3J0CTAJDQoNCiMgTWFnaWMgSUQgZm9yIE1pY3Jvc29mdCBDb21wcmVzcyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJU1pERFxceDg4XFx4RjBcXHgyN1xceDMzCVtmaWQ9MDAwMDAxMDAxLTUwLTAwMDAwMDA7ZXh0PTttaW1lPTtdTWljcm9zb2Z0IExaU1MgY29tcHJlc3NlZCBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEFBWCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTggYnkgQ2FybA0KMAlzdHJpbmcJXFx4NDBcXHhGRVxceDAwXFx4MDAJW2ZpZD0wMDAwMDEyODEtNTAtMDAwMEFBWDtleHQ9YWF4O21pbWU9O11BQVggYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEFCQ29tcCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTggYnkgQ2FybA0KMAlzdHJpbmcJXFx4MDNBQjIJW2ZpZD0wMDAwMDEyODItNTAtMDAwMEFCUDtleHQ9YWJwO21pbWU9O11BQkNvbXAgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEFjZSAvIFdpbkFjZSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KNwlzdHJpbmcJKipBQ0UqKglbZmlkPTAwMDAwMTI2NS01MC0wMDAwQUNFO2V4dD1hY2U7bWltZT07XUFjZSAvIFdpbkFDRSBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQWkgQXJjaGl2ZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE4IGJ5IENhcmwNCjAJc3RyaW5nCUFpCVtmaWQ9MDAwMDAwMDAwLTUwLTAwMDAwQUk7ZXh0PWFpO21pbWU9O11BaSBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQWt0IGFyY2hpdmVyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xOCBieSBDYXJsDQowCXN0cmluZwlBS1RcXHgwQQlbZmlkPTAwMDAwMDAwMC01MC0wMDAwQUtUO2V4dD1ha3Q7bWltZT07XUFLVCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQU1HIEFyY2hpdmVyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xOCBieSBDYXJsDQowCXN0cmluZwlcXHhBRFxceDM2CVtmaWQ9MDAwMDAxMjg0LTUwLTAwMDBBTUc7ZXh0PWFtZzttaW1lPTtdQU1HIGFyY2hpdmUgZmlsZQ0KPjIJYnl0ZQl4CSwgdmVyc2lvbiAlYmguDQo+MglieXRlCXgJJWJsDQomMwlieXRlCTAJDQoNCiMgTWFnaWMgSUQgZm9yIGFyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNCBieSBDYXJsDQowCXN0cmluZwlcXHgyMTxhcmNoPlxceDBBCVtmaWQ9MDAwMDAwMDAzLTUwLTAwMDAwQVI7ZXh0PWFyO21pbWU9O11VTklYIGFyY2hpdmUgZmlsZSAoYXIpDQoNCiMgTWFnaWMgSUQgZm9yIEFSNyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTggYnkgQ2FybA0KMAlzdHJpbmcJLEFSNyBlLW1haWxhYmxlIGFyY2hpdmU6CVtmaWQ9MDAwMTAwMDM2LTUwLTAwMDBBUjc7ZXh0PWFyNzttaW1lPTtdQVI3IGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBTcXVhc2ggZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE4IGJ5IENhcmwNCjMJc3RyaW5nCU9jdFNxdQlbZmlkPTAwMDEwMDAzOC01MC0wMDAwQVJIO2V4dD1hcmg7bWltZT07XVNxdWFzaCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQXJqIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xOCBieSBDYXJsDQowCXN0cmluZwlcXHg2MFxceEVBCVtmaWQ9MDAwMDAxMjg1LTUwLTAwMDBBUko7ZXh0PWFyajttaW1lPTtdQVJKIGFyY2hpdmUgZmlsZQ0KJjEwCWJ5dGUJMgkNCg0KIyBNYWdpYyBJRCBmb3IgQVNEIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xOCBieSBDYXJsDQowCXN0cmluZwlBU0QwMVxceDFBCVtmaWQ9MDAwMDAxMjg3LTUwLTAwMDBBU0Q7ZXh0PWFzZDttaW1lPTtdQVNEIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBCb2EgY29uc3RyaWN0b3IgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE4IGJ5IENhcmwNCjAJc3RyaW5nCUJPQVxceDAwCVtmaWQ9MDAwMTAwMDQwLTUwLTAwMDBCNTg7ZXh0PWI1ODttaW1lPTtdQk9BIGNvbnN0cmljdG9yIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBCV0MgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE4IGJ5IENhcmwNCjAJc3RyaW5nCUJXQwlbZmlkPTAwMDEwMDA0Mi01MC0wMDAwMEJDO2V4dD1iYzttaW1lPTtdQldDIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBCaXggZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE4IGJ5IENhcmwNCjAJc3RyaW5nCUJJWDAJW2ZpZD0wMDAxMDAwMzctNTAtMDAwMEJJWDtleHQ9Yml4O21pbWU9O11CSVggYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEJ0b2EgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE4IGJ5IENhcmwNCjAJc3RyaW5nCXhidG9hNQlbZmlkPTAwMDEwMDA0My01MC0wMDAwQk9PO2V4dD1ib287bWltZT07XUJ0b2EgZW5jb2RlZCBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEJzYSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTggYnkgQ2FybA0KMAlzdHJpbmcJXFx4RkZCU0dcXHgwMFxceDAwXFx4RkZCU0EJW2ZpZD0wMDAwMDEyODktNTAtMDAwMEJTTjtleHQ9YnNuO21pbWU9O11Cc2EgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEJUUEMgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTAzIGJ5IENhcmwNCjAJc3RyaW5nCWJ0cGNcXCAJW2ZpZD0wMDAxMDAwNzQtNTAtMDAwQlRQQztleHQ9YnRwYzttaW1lPTtdQlRQQyBjb21wcmVzc2VkIGltYWdlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQlRTIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xOCBieSBDYXJsDQowCXN0cmluZwlcXHgxQVxceDAzRGVzY3JpcHQJW2ZpZD0wMDAxMDAwNDQtNTAtMDAwMEJUUztleHQ9YnRzO21pbWU9O11CVFNwayBhcmNoaXZlIGZpbGUNCiYweDUyMQlzdHJpbmcJQlRTUEshCQ0KDQojIE1hZ2ljIElEIGZvciBCemlwIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xOCBieSBDYXJsDQowCXN0cmluZwlCWjAJW2ZpZD0wMDAxMDAwMDgtNTAtMDAwMDBCWjtleHQ9Yno7bWltZT07XUJ6aXAgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEJ6aXAyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlCWmgJW2ZpZD0wMDAxMDAwMDgtNTAtMDAwMEJaMjtleHQ9YnoyO21pbWU9O11CemlwMiBhcmNoaXZlIGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlNU0NGCVtmaWQ9MDAwMDAxMDAxLTUwLTAwMDBDQUI7ZXh0PWNhYjttaW1lPTtdTWljcm9zb2Z0IENhYmluZXQgZmlsZQ0KPjI1CWJ5dGUJeAksIHZlcnNpb24gJWQuDQo+MjQJYnl0ZQl4CSVkDQoNCiMgTWFnaWMgSUQgZm9yIENydXNoIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yMyBieSBDYXJsDQowCXN0cmluZwlDUlVTSFxcIHYxLjgJW2ZpZD0wMDAwMDEyOTAtNTAtMDAwMENSVTtleHQ9Y3J1O21pbWU9O11DcnVzaCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQ3R4ZiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjMgYnkgQ2FybA0KMAlzdHJpbmcJQ1hGXFx4MUEJW2ZpZD0wMDAxMDAwNDUtNTAtMDAwMENYRjtleHQ9Y3hmO21pbWU9O11DdHggYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIERBWFdhdiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJRk9STQlbZmlkPTAwMDAwMDAwMC01MC0wMDAwREFYO2V4dD1kYXg7bWltZT07XURBWCBhdWRpbyBhcmNoaXZlIGZpbGUNCiY4CXN0cmluZwlkYXhBCQ0KDQojIE1hZ2ljIElEIGZvciBEaXNrbWFzaGVyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yMyBieSBDYXJsDQowCXN0cmluZwlETVMhCVtmaWQ9MDAwMDAwMDAwLTUwLTAwMDBETVM7ZXh0PWRtczttaW1lPTtdRGlza21hc2hlciBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgRHBhZSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjMgYnkgQ2FybA0KMAlzdHJpbmcJRGlya1xcIFBhZWhsKGMpCVtmaWQ9MDAwMTAwMDQ2LTUwLTAwMDBEUEE7ZXh0PWRwYTttaW1lPTtdRHBhZSBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgRGlzaW50ZWdyYXRvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjMgYnkgQ2FybA0KMAlzdHJpbmcJRFNUYglbZmlkPTAwMDEwMDA0Ny01MC0wMDAwRFNUO2V4dD1kc3Q7bWltZT07XURpc2ludGVncmF0b3IgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEVuaGFuY2VkIGNvbXByZXNzb3IgKEVOQykgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTIzIGJ5IENhcmwNCjAJc3RyaW5nCUVuY2gJW2ZpZD0wMDAxMDAwNTEtNTAtMDAwMEVOQztleHQ9ZW5jO21pbWU9O11FbmhhbmNlZCBjb21wcmVzc29yIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBFU1AgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCUVTUD4JW2ZpZD0wMDAxMDAwMDItNTAtMDAwMEVTUDtleHQ9ZXNwO21pbWU9O11FU1AgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEVTUCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMHg1M2YJc3RyaW5nCUVTUAlbZmlkPTAwMDEwMDAwMi01MC0wMDAwRVhFO2V4dD1leGU7bWltZT07XUVTUCBTZWxmLWV4dHJhY3RpbmcgYXJjaGl2ZXcgKE1TLURPUykNCg0KIyBNYWdpYyBJRCBmb3IgRnJlZXplIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlcXHgxRlxceDlFCVtmaWQ9MDAwMDAwMDAwLTUwLTAwMDAwMEY7ZXh0PWY7bWltZT07XUZyZWV6ZSBhcmNoaXZlIGZpbGUsIHZlcnNpb24gMS4wDQoNCiMgTWFnaWMgSUQgZm9yIEZyZWV6ZSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MUZcXHg5RglbZmlkPTAwMDAwMDAwMC01MC0wMDAwMDBGO2V4dD1mO21pbWU9O11GcmVlemUgYXJjaGl2ZSBmaWxlLCB2ZXJzaW9uIDIuMA0KDQojIE1hZ2ljIElEIGZvciBRbGZjIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yMyBieSBDYXJsDQowCXN0cmluZwlcXHg0N1xceDY4XFx4NjlcXHg2NFxceDZmCVtmaWQ9MDAwMTAwMDU1LTUwLTAwMDAwR1E7ZXh0PWdxO21pbWU9O11RbGZjIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBHemlwIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlcXHgxRlxceDhCCVtmaWQ9MDAwMDAwMDAyLTUwLTAwMDE5NTI7ZXh0PWd6O21pbWU9O11HemlwIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBIYSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTAgYnkgQ2FybA0KMAlzdHJpbmcJSEEJW2ZpZD0wMDAxMDAwMTMtNTAtMDAwMDBIQTtleHQ9aGE7bWltZT07XUhBIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBIQVAgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTIzIGJ5IENhcmwNCjAJc3RyaW5nCVxceDkxM0hGCVtmaWQ9MDAwMDAxMjkxLTUwLTAwMDBIQVA7ZXh0PWhhcDttaW1lPTtdSEFQIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBIcGFjayBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJSFBBSwlbZmlkPTAwMDEwMDAxNi01MC0wMDAwSFBLO2V4dD1ocGs7bWltZT07XUhwYWNrIGFyY2hpdmUgZmlsZQ0KJlo0CXN0cmluZwlIUEFLCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTEwIGJ5IENhcmwNCjExCXN0cmluZwltdXN0XFwgYmVcXCBjb252ZXJ0ZWRcXCB3aXRoXFwgQmluSGV4CVtmaWQ9MDAwMDAxMDAyLTUwLTAwMDBIUVg7ZXh0PWhxeDttaW1lPTtdQmluSGV4IGFyY2hpdmUNCg0KIyBNYWdpYyBJRCBmb3IgSFlQIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yMyBieSBDYXJsDQowCXN0cmluZwlcXHgxQUhQXFx4MjUJW2ZpZD0wMDAxMDAwNTYtNTAtMDAwMEhZUDtleHQ9aHlwO21pbWU9O11IWVAgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEhZUCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjMgYnkgQ2FybA0KMAlzdHJpbmcJXFx4MUFTVFxceDI1CVtmaWQ9MDAwMTAwMDU2LTUwLTAwMDBIWVA7ZXh0PWh5cDttaW1lPTtdSFlQIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBXaW5pbXAgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJbGVsb25nCTB4QTUwNEQ0OQlbZmlkPTAwMDAwMTI3MC01MC0wMDAwSU1QO2V4dD1pbXA7bWltZT07XVdpbmltcCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgSlJjaGl2ZSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJSlJjaGl2ZQlbZmlkPTAwMDAwMTI2My01MC0wMDAwSlJDO2V4dD1qcmM7bWltZT07XUpSY2hpdmUgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIEFyY2hpdmUgSGFuZGxlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJTEcJW2ZpZD0wMDAxMDAwMDEtNTAtMDAwMDBMRztleHQ9bGc7bWltZT07XUFyaGFuZ2VsIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBMaW1pdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJTE1cXHgxQQlbZmlkPTAwMDEwMDAwMy01MC0wMDAwTElNO2V4dD1saW07bWltZT07XUxpbWl0IGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBMYXJjIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQoyCXN0cmluZwktbHo0LQlbZmlkPTAwMDEwMDAxNy01MC0wMDAwTFpIO2V4dD1semg7bWltZT07XUxhcmMgYXJjaGl2ZQ0KDQojIE1hZ2ljIElEIGZvciBMYXJjIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQoyCXN0cmluZwktbHo1LQlbZmlkPTAwMDEwMDAxNy01MC0wMDAwTFpIO2V4dD1semg7bWltZT07XUxhcmMgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIExhcmMgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjIJc3RyaW5nCS1senMtCVtmaWQ9MDAwMTAwMDE3LTUwLTAwMDBMWkg7ZXh0PWx6aDttaW1lPTtdTGFyYyBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgbGhhIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQoyCXN0cmluZwktbGhcXCAtCVtmaWQ9MDAwMTAwMDE3LTUwLTAwMDBMWkg7ZXh0PWx6aCxsaGE7bWltZT07XUxIYXJjIGFyY2hpdmUgZmlsZSwgdmVyc2lvbiAyLngNCg0KIyBNYWdpYyBJRCBmb3IgbGhhIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQoyCXN0cmluZwktbGgwLQlbZmlkPTAwMDEwMDAxNy01MC0wMDAwTFpIO2V4dD1semgsbGhhO21pbWU9O11MSGFyYyBhcmNoaXZlIGZpbGUsIHZlcnNpb24gMS54DQoNCiMgTWFnaWMgSUQgZm9yIGxoYSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMglzdHJpbmcJLWxoMS0JW2ZpZD0wMDAxMDAwMTctNTAtMDAwMExaSDtleHQ9bHpoLGxoYTttaW1lPTtdTEhhcmMgYXJjaGl2ZSBmaWxlLCB2ZXJzaW9uIDEueA0KDQojIE1hZ2ljIElEIGZvciBsaGEgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjIJc3RyaW5nCS1saDItCVtmaWQ9MDAwMTAwMDE3LTUwLTAwMDBMWkg7ZXh0PWx6aCxsaGE7bWltZT07XUxIYXJjIGFyY2hpdmUgZmlsZSwgdmVyc2lvbiAyLngNCg0KIyBNYWdpYyBJRCBmb3IgbGhhIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQoyCXN0cmluZwktbGgzLQlbZmlkPTAwMDEwMDAxNy01MC0wMDAwTFpIO2V4dD1semgsbGhhO21pbWU9O11MSGFyYyBhcmNoaXZlIGZpbGUsIHZlcnNpb24gMi54DQoNCiMgTWFnaWMgSUQgZm9yIGxoYSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMglzdHJpbmcJLWxoNC0JW2ZpZD0wMDAxMDAwMTctNTAtMDAwMExaSDtleHQ9bHpoLGxoYTttaW1lPTtdTEhhcmMgYXJjaGl2ZSBmaWxlLCB2ZXJzaW9uIDIueA0KDQojIE1hZ2ljIElEIGZvciBsaGEgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjIJc3RyaW5nCS1saDUtCVtmaWQ9MDAwMTAwMDE3LTUwLTAwMDBMWkg7ZXh0PWx6aCxsaGE7bWltZT07XUxIYXJjIGFyY2hpdmUgZmlsZSwgdmVyc2lvbiAyLngNCg0KIyBNYWdpYyBJRCBmb3IgbGhhIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQoyCXN0cmluZwktbGg2LQlbZmlkPTAwMDEwMDAxNy01MC0wMDAwTFpIO2V4dD1semgsbGhhO21pbWU9O11MSGFyYyBhcmNoaXZlIGZpbGUsIHZlcnNpb24gMi54DQoNCiMgTWFnaWMgSUQgZm9yIGxoYSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMglzdHJpbmcJLWxoNy0JW2ZpZD0wMDAxMDAwMTctNTAtMDAwMExaSDtleHQ9bHpoLGxoYTttaW1lPTtdTEhhcmMgYXJjaGl2ZSBmaWxlLCB2ZXJzaW9uIDIueA0KDQojIE1hZ2ljIElEIGZvciBsaGEgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjIJc3RyaW5nCS1saGQtCVtmaWQ9MDAwMTAwMDE3LTUwLTAwMDBMWkg7ZXh0PWx6aCxsaGE7bWltZT07XUxIYXJjIGFyY2hpdmUgZmlsZSwgdmVyc2lvbiAyLngNCg0KIyBNYWdpYyBJRCBmb3IgbHpvIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlcXHg4OVxceDRjXFx4NWFcXHg0ZlxceDAwXFx4MGRcXHgwYVxceDFhXFx4MGEJW2ZpZD0wMDAxMDAwMTgtNTAtMDAwMExaTztleHQ9bHpvO21pbWU9O11MWk9QIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBMenggZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTIzIGJ5IENhcmwNCjAJc3RyaW5nCUxaWAlbZmlkPTAwMDEwMDA1OC01MC0wMDAwTFpYO2V4dD1seng7bWltZT07XUxaWCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgTWRjZCAoTWlrZSBEYXZlbnBvcnQgY29tcHJlc3NvcikgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCU1EbWQJW2ZpZD0wMDAxMDAwMDQtNTAtMDAwMDBNRDtleHQ9bWQ7bWltZT07XU1pa2UgRGF2ZW5wb3J0IGFyY2hpdmUgZmlsZQ0KPjQJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KJjUJYnl0ZQkxCQ0KDQojIE1hZ2ljIElEIGZvciBOYXNocmluayBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjMgYnkgQ2FybA0KMAlzdHJpbmcJTlNLCVtmaWQ9MDAwMDAxMjkyLTUwLTAwMDBOU0s7ZXh0PW5zazttaW1lPTtdTmFTaHJpbmsgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFNlbW9uZSBhcmNoaXZlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjcgYnkgQ2FybA0KMAlzdHJpbmcJU0VNaAlbZmlkPTAwMDEwMDA2OC01MC0wMDAwT05FO2V4dD1vbmU7bWltZT07XVNlbW9uZSBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgTHBhYyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJTFBBQwlbZmlkPTAwMDEwMDA4NC01MC0wMDAwUEFDO2V4dD1wYWM7bWltZT07XUxQQUMgYXVkaW8gYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIENyb3NzZVBBQyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJRFNJR0RDQwlbZmlkPTAwMDAwMTI2Mi01MC0wMDAwUEFDO2V4dD1wYWM7bWltZT07XUNyb3NzZVBBQyBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgSGlnaCBDb21wcmVzc2lvbiBNYXJrb3YgUHJlZGljdGl2ZSBDb2RlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjMgYnkgQ2FybA0KMAlzdHJpbmcJUFBaMglbZmlkPTAwMDEwMDA2MS01MC0wMDAwUE1aO2V4dD1wbXo7bWltZT07XVBQTVoyIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBQb3dlcnBhY2tlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjcgYnkgQ2FybA0KMAlzdHJpbmcJUFAyMAlbZmlkPTAwMDEwMDA2Mi01MC0wMDAwMFBQO2V4dD1wcDttaW1lPTtdUG93ZXJwYWNrZXIgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFBBUTEgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTI3IGJ5IENhcmwNCjAJc3RyaW5nCVBBUTFcXHgwRFxceDBBCVtmaWQ9MDAwMTAwMDY0LTUwLTAwMDBQUTE7ZXh0PXBxMTttaW1lPTtdUEFRMSBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgUEFRMyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjcgYnkgQ2FybA0KMAlzdHJpbmcJUEFRM1xceDBEXFx4MEEJW2ZpZD0wMDAxMDAwNjQtNTAtMDAwMFBRMztleHQ9cHEzO21pbWU9O11QQVEzIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBQQVE2IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yNyBieSBDYXJsDQowCXN0cmluZwlQQVE2CVtmaWQ9MDAwMTAwMDY0LTUwLTAwMDBQUTY7ZXh0PXBxNjttaW1lPTtdUEFRNiBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgUHJldHR5IHNpbXBsZSBhcmNoaXZlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjcgYnkgQ2FybA0KMAlzdHJpbmcJUFNBXFx4MDFcXHgwMwlbZmlkPTAwMDEwMDA2NS01MC0wMDAwUFNBO2V4dD1wc2E7bWltZT07XVByZXR0eSBzaW1wbGUgYXJjaGl2ZXIgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFF1YW50dW0gY29tcHJlc3NvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjcgYnkgQ2FybA0KMAlzdHJpbmcJRFMJW2ZpZD0wMDAwMDEyOTQtNTAtMDAwMDAwUTtleHQ9cTttaW1lPTtdUXVhbnR1bSBhcmNoaXZlIGZpbGUNCiYyCWJ5dGUJPDIJDQo+MglieXRlCXgJLCB2ZXJzaW9uICVkDQo+MwlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFJhciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJXFx4NTJcXHg2MVxceDcyXFx4MjFcXHgxYVxceDA3XFx4MDAJW2ZpZD0wMDAwMDEyNjctNTAtMDAwMFJBUjtleHQ9cmFyO21pbWU9O11SQVIgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFJvbWFuaWFuIGFyY2hpdmVyIGVYcGVydCAoUkFYKSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjcgYnkgQ2FybA0KMAlzdHJpbmcJVUxFQglbZmlkPTAwMDAwMTI5NS01MC0wMDAwUkFYO2V4dD1yYXg7bWltZT07XVJBWCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgUmVkdXEgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTI3IGJ5IENhcmwNCjAJc3RyaW5nCXJkcXgJW2ZpZD0wMDAxMDAwNjYtNTAtMDAwMFJEUTtleHQ9cmRxO21pbWU9O11SZWR1cSBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgUlBNIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNCBieSBDYXJsDQowCXN0cmluZwlcXHhlZFxceGFiXFx4ZWVcXHhkYglbZmlkPTAwMDAwMDAwMC01MC0wMDAwUlBNO2V4dD1ycG07bWltZT07XVJQTSBhcmNoaXZlDQo+NAlieXRlCXgJLCB2ZXJzaW9uICVkDQo+NQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIHJ6aXAgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA0IGJ5IENhcmwNCjAJc3RyaW5nCVJaSVAJW2ZpZD0wMDAxMDAwNzYtNTAtMDAwMDBSWjtleHQ9cno7bWltZT07XVJ6aXAgYXJjaGl2ZSBmaWxlDQo+NAlieXRlCXgJLCB2ZXJzaW9uICVkDQo+NQlieXRlCXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIFN0cmVhbWxpbmUgQXJjaGl2YWwgVXRpbGl0eSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMwlzdHJpbmcJTEgwCVtmaWQ9MDAwMDAxMjY0LTUwLTAwMDBTQVI7ZXh0PXNhcjttaW1lPTtdU3RyZWFtaW5nIEFyY2hpdmVyIFV0aWxpdHkgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFN0cmVhbWxpbmUgQXJjaGl2YWwgVXRpbGl0eSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMwlzdHJpbmcJTEg0CVtmaWQ9MDAwMDAxMjY0LTUwLTAwMDBTQVI7ZXh0PXNhcjttaW1lPTtdU3RyZWFtaW5nIEFyY2hpdmVyIFV0aWxpdHkgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFN0cmVhbWxpbmUgQXJjaGl2YWwgVXRpbGl0eSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMwlzdHJpbmcJTEg1CVtmaWQ9MDAwMDAxMjY0LTUwLTAwMDBTQVI7ZXh0PXNhcjttaW1lPTtdU3RyZWFtaW5nIEFyY2hpdmVyIFV0aWxpdHkgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFNCWCBBcmNoaXZlciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMjcgYnkgQ2FybA0KMAlzdHJpbmcJU0IxXFx4MDAJW2ZpZD0wMDAwMDEyOTctNTAtMDAwMDBTQjtleHQ9c2I7bWltZT07XVNCWCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgU0JDIEFyY2hpdmVyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yNyBieSBDYXJsDQowCXN0cmluZwlTQkNcXHgxRQlbZmlkPTAwMDEwMDA2Ny01MC0wMDAwU0JDO2V4dD1zYmM7bWltZT07XVNCQyBhcmNoaXZlIGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMCBieSBDYXJsDQoxMAlzdHJpbmcJI1xcIFRoaXNcXCBpc1xcIGFcXCBzaGVsbFxcIGFyY2hpdmUJW2ZpZD0wMDAwMDAwMDAtNTAtMDAwU0hBUjtleHQ9c2hhcjttaW1lPTtdVU5JWCBzaGVsbCBhcmNoaXZlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTAgYnkgQ2FybA0KMTEJc3RyaW5nCSNcXCBUaGlzXFwgaXNcXCBhXFwgc2hlbGxcXCBhcmNoaXZlCVtmaWQ9MDAwMDAwMDAwLTUwLTAwMFNIQVI7ZXh0PXNoYXI7bWltZT07XVVOSVggc2hlbGwgYXJjaGl2ZQ0KDQojIE1hZ2ljIElEIGZvciBOdWxpYiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJXFx4NGVcXHhmNVxceDQ2XFx4ZDgJW2ZpZD0wMDAxMDAwMDUtNTAtMDAwMFNISztleHQ9c2hrO21pbWU9O11TaHJpbmtpdC9OdWxpYiBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgTnVsaWIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCVxceDRlXFx4ZjVcXHg0NlxceGU5XFx4NmNcXHhlNQlbZmlkPTAwMDEwMDAwNS01MC0wMDAwU0hLO2V4dD1zaGs7bWltZT07XVNocmlua2l0L051bGliIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBTdHVmZml0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNCBieSBDYXJsDQowCXN0cmluZwlTdHVmZkl0XFwgCVtmaWQ9MDAwMDAxMjcyLTUwLTAwMDBTSVQ7ZXh0PXNpdDttaW1lPTtdU3R1ZmZpdCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgU3R1ZmZpdCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTEgYnkgQ2FybA0KMAlzdHJpbmcJU0lUIQlbZmlkPTAwMDAwMTI3Mi01MC0wMDAwU0lUO2V4dD1zaXQ7bWltZT07XVN0dWZmaXQgYXJjaGl2ZSBmaWxlDQomMTAJc3RyaW5nCXJMYXUJDQo+MTQJYnl0ZQl4CSwgdmVyc2lvbiAlZC4wDQoNCiMgTWFnaWMgSUQgZm9yIFN0dWZmaXQgRXh0ZW5kZWQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAzLTA0IGJ5IENhcmwNCjAJc3RyaW5nCVN0dWZmSXQhCVtmaWQ9MDAwMDAxMjcyLTUwLTAwMFNJVFg7ZXh0PXNpdHg7bWltZT07XVN0dWZmaXQgZXh0ZW5kZWQgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFNvZiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDMtMDQgYnkgQ2FybA0KMAlzdHJpbmcJUEtcXHgwM1xceDA2CVtmaWQ9MDAwMDAwMDAwLTUwLTAwMDBTT0Y7ZXh0PXNvZjttaW1lPTtdU09GIGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBTcGxpbnQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCVxceDkzXFx4QjlcXHgwNglbZmlkPTAwMDEwMDAwNi01MC0wMDAwU1BMO2V4dD1zcGw7bWltZT07XVNwbGludCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgU3F3ZWV6IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMCBieSBDYXJsDQowCXN0cmluZwlTUVdFWlxcIAlbZmlkPTAwMDEwMDAxNC01MC0wMDAwU1FaO2V4dD1zcXo7bWltZT07XVNxd2V6IGFyY2hpdmUgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBTcXogZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTEwIGJ5IENhcmwNCjAJc3RyaW5nCUhMU1FaCVtmaWQ9MDAwMTAwMDE1LTUwLTAwMDBTUVo7ZXh0PXNxejttaW1lPTtdU3F1ZWV6ZSBhcmNoaXZlIGZpbGUNCj41CXN0cmluZwl4CSwgdmVyc2lvbiAlLjFzLjANCg0KIyBNYWdpYyBJRCBmb3IgU3RvbmVjcmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yNyBieSBDYXJsDQowCXN0cmluZwlTNDAxCVtmaWQ9MDAwMTAwMDYzLTUwLTAwMDBTVEM7ZXh0PXN0YzttaW1lPTtdU3RvbmVjcmFja2VyIGFyY2hpdmUgZmlsZQ0KPjAJc3RyaW5nCVM0MDEJLCB2ZXJzaW9uIDQuMDENCg0KIyBNYWdpYyBJRCBmb3IgU3RvbmVjcmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yNyBieSBDYXJsDQowCXN0cmluZwlTNDAzCVtmaWQ9MDAwMTAwMDYzLTUwLTAwMDBTVEM7ZXh0PXN0YzttaW1lPTtdU3RvbmVjcmFja2VyIGFyY2hpdmUgZmlsZQ0KPjAJc3RyaW5nCVM0MDMJLCB2ZXJzaW9uIDQuMDMNCg0KIyBNYWdpYyBJRCBmb3IgU3RvbmVjcmFja2VyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yNyBieSBDYXJsDQowCXN0cmluZwlTNDA0CVtmaWQ9MDAwMTAwMDYzLTUwLTAwMDBTVEM7ZXh0PXN0YzttaW1lPTtdU3RvbmVjcmFja2VyIGFyY2hpdmUgZmlsZQ0KPjAJc3RyaW5nCVM0MDQJLCB2ZXJzaW9uIDQuMDQNCg0KIyBNYWdpYyBJRCBmb3IgU3ppcCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJU1pcXHgwQVxceDA0CVtmaWQ9MDAwMTAwMDA5LTUwLTAwMDAwU1o7ZXh0PXN6O21pbWU9O11TWklQIGFyY2hpdmUgZmlsZQ0KPjQJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjUJYnl0ZQl4CS4lZA0KDQojIE1hZ2ljIElEIGZvciBUYXIscGF4IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMCBieSBDYXJsDQoyNTcJc3RyaW5nCXVzdGFyXFwwNDBcXDA0MFxcMAlbZmlkPTAwMDAwMDAwMC01MC0wMDAwVEFSO2V4dD10YXI7bWltZT07XUdOVSB0YXIgYXJjaGl2ZQ0KDQojIE1hZ2ljIElEIGZvciBUYXIscGF4IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMCBieSBDYXJsDQoyNTcJc3RyaW5nCXVzdGFyXFwwXFx4MDYJW2ZpZD0wMDAwMDAwMDMtNTAtMDAwMTAwMztleHQ9dGFyO21pbWU9O11PcGVuZ3JvdXAvUE9TSVggdGFyIGFyY2hpdmUNCg0KIyBNYWdpYyBJRCBmb3IgdWMyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMCBieSBDYXJsDQowCXN0cmluZwlVQzJcXHgxYQlbZmlkPTAwMDAwMTI3MS01MC0wMDAwVUMyO2V4dD11YzI7bWltZT07XVVsdHJhIENvbXByZXNzb3IgYXJjaGl2ZSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFVoYXJjIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wNCBieSBDYXJsDQowCXN0cmluZwlVSEEJW2ZpZD0wMDAxMDAwODMtNTAtMDAwMFVIQTtleHQ9dWhhO21pbWU9O11VSEFyYyBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgWUJTIGFyY2hpdmVyIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0yNyBieSBDYXJsDQowCXN0cmluZwlZQlMzCVtmaWQ9MDAwMTAwMDcxLTUwLTAwMDBZQlM7ZXh0PXliczttaW1lPTtdWUJTIGFyY2hpdmUgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCVxcMDM3XFwyMzUJW2ZpZD0wMDAwMDAwMDAtNTAtMDAwMDAwWjtleHQ9ejttaW1lPTtdVU5JWCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgUGt1bnppcCwgSW5mby16aXAgVW56aXAgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJbGVsb25nCTB4MDQwMzRiNTAJW2ZpZD0wMDAwMDEyNjYtNTAtMDAwMFpJUDtleHQ9emlwO21pbWU9YXBwbGljYXRpb24vemlwO11Qa3ppcCBhcmNoaXZlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3Igem9vIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMCBieSBDYXJsDQowCXN0cmluZwlaT08JW2ZpZD0wMDAxMDAwMTItNTAtMDAwMFpPTztleHQ9em9vO21pbWU9O11ab28gYXJjaGl2ZSBmaWxlDQomMHgxNAlsZWxvbmcJMHgwRkRDNEE3REMJDQo+MzIJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjMzCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgWnppcCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJWloJW2ZpZD0wMDAxMDAwMDctNTAtMDAwMDBaWjtleHQ9eno7bWltZT07XVpaaXAgYXJjaGl2ZSBmaWxlDQo+MglieXRlCXgJLCB2ZXJzaW9uICVkLjANCg0KIyBNYWdpYyBJRCBmb3IgNjI0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wMyBieSBDYXJsDQowCXN0cmluZwlbRVNQXVxceEI1XFx4NzgJW2ZpZD0wMDAxMDAwMDItNTEtMDAwMENPTTtleHQ9Y29tO21pbWU9O102MjQgZXhlY3V0YWJsZSBjb21wcmVzc2VkIGZpbGUgKE1TLURPUykNCg0KIyBNYWdpYyBJRCBmb3IgNjI0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMy0wMyBieSBDYXJsDQowCXN0cmluZwlQVUxQXFx4ODMJW2ZpZD0wMDAxMDAwMDItNTEtMDAwMENPTTtleHQ9Y29tO21pbWU9O102MjQgZXhlY3V0YWJsZSBjb21wcmVzc2VkIGZpbGUgKE1TLURPUykNCg0KIyBNYWdpYyBJRCBmb3IgTHpleGUgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTIzIGJ5IENhcmwNCjB4MUMJc3RyaW5nCUxaOTEJW2ZpZD0wMDAxMDAwNTMtNTEtMDAwMEVYRTtleHQ9ZXhlO21pbWU9O11MemV4ZSBjb21wcmVzc2VkIGV4ZWN1dGFibGUgZmlsZSAoTVMtRE9TKQ0KDQojIE1hZ2ljIElEIGZvciBIVE1MIEhlbHAgV29ya3Nob3AgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCUlUU0YJW2ZpZD0wMDAwMDEwMDEtNjAtMDAwMENITTtleHQ9Y2htO21pbWU9O11NaWNyb3NvZnQgY29tcGlsZWQgaHlwZXJ0ZXh0IGRvY3VtZW50DQoNCiMgTWFnaWMgSUQgZm9yIEJvcmxhbmQgRGVscGhpIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNy0zMCBieSBDYXJsDQoyCXN0cmluZwlERUxQSEkuRElBR1JBTS5QT1JURk9MSU8JW2ZpZD0wMDAwMDEwMDUtNjAtMDAwMEREUDtleHQ9ZGRwO21pbWU9O11EZWxwaGkgRGlhZ3JhbSBQb3J0Zm9saW8gZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBQYWdlc3RyZWFtIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlGT1JNCVtmaWQ9MDAwMDAxMjY4LTYwLTAwMDBET0M7ZXh0PWRvYzttaW1lPTtdUGFnZXN0cmVhbSBkb2N1bWVudA0KJjgJc3RyaW5nCURPQ1xcIAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlDQVRcXCAJW2ZpZD0wMDAwMDEwMTAtNjAtMDAwRlRYVDtleHQ9ZnR4dDttaW1lPTtdRm9ybWF0dGVkIHRleHQgaW50ZXJjaGFuZ2UgZmlsZQ0KJjgJc3RyaW5nCUZUWFQJDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJRk9STQlbZmlkPTAwMDAwMTAxMC02MC0wMDBGVFhUO2V4dD1mdHh0O21pbWU9O11Gb3JtYXR0ZWQgdGV4dCBpbnRlcmNoYW5nZSBmaWxlDQomOAlzdHJpbmcJRlRYVAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlMSVNUCVtmaWQ9MDAwMDAxMDEwLTYwLTAwMEZUWFQ7ZXh0PWZ0eHQ7bWltZT07XUZvcm1hdHRlZCB0ZXh0IGludGVyY2hhbmdlIGZpbGUNCiY4CXN0cmluZwlGVFhUCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCUBkYXRhYmFzZQlbZmlkPTAwMDAwMTAwNy02MC0wMEdVSURFO2V4dD1ndWlkZTttaW1lPTtdQW1pZ2FHdWlkZSBoeXBlcnRleHQgZG9jdW1lbnQNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCWxlbG9uZwkweDAwMDM1RjNGCVtmaWQ9MDAwMDAxMDAxLTYwLTAwMDBITFA7ZXh0PWhscDttaW1lPTtdTWljcm9zb2Z0IFdpbmRvd3MgSGVscCBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMTAtMDggYnkgQ2FybA0KMAlzdHJpbmcJPCFET0NUWVBFXFwgCVtmaWQ9MDAwMDAwMDAxLTYwLTAwMTU0NDU7ZXh0PWh0bWwsaHRtO21pbWU9dGV4dC9odG1sO11IeXBlclRleHQgTWFya3VwIExhbmd1YWdlIGRvY3VtZW50IChIVE1MKQ0KJjEwCXN0cmluZy9jCWh0bWwJDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJSERPQwlbZmlkPTAwMDAwMTAwNi02MC0wMDAwSFlQO2V4dD1oeXA7bWltZT07XUF0YXJpIFNULUd1aWRlIGh5cGVydGV4dCBkb2N1bWVudA0KDQojIE1hZ2ljIElEIGZvciBPUy8yIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCXN0cmluZwlIU1AJW2ZpZD0wMDAwMDEwMDktNjAtMDAwMElORjtleHQ9aW5mO21pbWU9O11PUy8yIEd1aWRlIGh5cGVydGV4dCBkb2N1bWVudA0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCVRoaXNcXCBpc1xcIEluZm9cXCBmaWxlCVtmaWQ9MDAwMTAwMDEwLTYwLTAwMElORk87ZXh0PWluZm87bWltZT07XUdOVSBJbmZvIGh5cGVydGV4dCBkb2N1bWVudA0KDQojIE1hZ2ljIElEIGZvciBBZG9iZSBBY3JvYmF0IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0xMC0wOCBieSBDYXJsDQowCXN0cmluZwklUERGLQlbZmlkPTAwMDAwMDAwMS02MC0wMDE1OTMwO2V4dD1wZGY7bWltZT1hcHBsaWNhdGlvbi9wZGY7XVBvcnRhYmxlIGRvY3VtZW50IGZvcm1hdCBkb2N1bWVudCBmaWxlIChQREYpDQo+NQlzdHJpbmcJeAksIHZlcnNpb24gJS4xcw0KPjcJc3RyaW5nCXgJLiUuMXMNCg0KIyBNYWdpYyBJRCBmb3IgTWljcm9zb2Z0IFdvcmRwYWQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCXtcXFxccnRmCVtmaWQ9MDAwMDAxMDAxLTYwLTAwMDBSVEY7ZXh0PXJ0ZjttaW1lPXRleHQvcnRmO11SaWNoIFRleHQgRm9ybWF0IGRvY3VtZW50DQo+NQlzdHJpbmcJeAksIHZlcnNpb24gJS4xcy54DQoNCiMgTWFnaWMgSUQgZm9yIERvY0Jvb2sgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTEwLTA4IGJ5IENhcmwNCjAJc3RyaW5nCTwhRE9DVFlQRVxcIAlbZmlkPTAwMDAwMDAwMS02MC0wMDA4ODc5O2V4dD1zZ21sLHNnbTttaW1lPXRleHQvc2dtbDtdU3RhbmRhcmQgZ2VuZXJhbCBtYXJrdXAgbGFuZ3VhZ2UgZG9jdW1lbnQgKFNHTUwpDQoNCiMgTWFnaWMgSUQgZm9yIFR1cmJvIEMgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVRVUkJPXFwgQ1xcIEhFTFBcXCBGSUxFXFx4MDAJW2ZpZD0wMDAwMDEwMDUtNjAtMDAwMFRDSDtleHQ9dGNoO21pbWU9O11UdXJibyBDIGhlbHAgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBUdXJibyBQYXNjYWwgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCVRVUkJPXFwgUEFTQ0FMXFwgSEVMUFxcIEZJTEVcXHgwMAlbZmlkPTAwMDAwMTAwNS02MC0wMDAwVFBIO2V4dD10cGg7bWltZT07XUJvcmxhbmQgUGFzY2FsIGhlbHAgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBUdXJibyBWaXNpb24gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJbGVsb25nCTB4NDY0ODQyNDYJW2ZpZD0wMDAwMDEwMDUtNjAtMDAwMFRWSDtleHQ9dHZoO21pbWU9O11Cb3JsYW5kIFR1cmJvIFZpc2lvbiBoZWxwIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgV29yZHBlcmZlY3QgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCVxceEZGV1BDCVtmaWQ9MDAwMDAxMDA4LTYwLTAwMDBXUEQ7ZXh0PXdwZCxkb2M7bWltZT1hcHBsaWNhdGlvbi92bmQud29yZHBlcmZlY3Q7XVdvcmRwZXJmZWN0IGRvY3VtZW50DQomOQlieXRlCTB4MEEJDQo+MTAJYnl0ZQl4CSwgdmVyc2lvbiAlZA0KPjExCWJ5dGUJeAkuJWQNCg0KIyBNYWdpYyBJRCBmb3IgTWljcm9zb2Z0IFdyaXRlIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCWxlc2hvcnQJMDEzNzA2MQlbZmlkPTAwMDAwMTAwMS02MC0wMDAwV1JJO2V4dD13cmk7bWltZT07XU1pY3Jvc29mdCBXcml0ZSBkb2N1bWVudA0KJjIJbGVzaG9ydAkweDAwMDAJDQoNCiMgTWFnaWMgSUQgZm9yIE1pY3Jvc29mdCBXcml0ZSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlsZXNob3J0CTAxMzcwNjIJW2ZpZD0wMDAwMDEwMDEtNjAtMDAwMFdSSTtleHQ9d3JpO21pbWU9O11NaWNyb3NvZnQgV3JpdGUgZG9jdW1lbnQNCiYyCWxlc2hvcnQJMHgwMDAwCQ0KDQojIE1hZ2ljIElEIGZvciBYLVdpbmRvd3MgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA5LTAxIGJ5IENhcmwNCjAJc3RyaW5nCVNUQVJURk9OVFxcIAlbZmlkPTAwMDAwMTAwMy03MC0wMDAwQkRGO2V4dD1iZGY7bWltZT07XUFkb2JlIGdseXBoIGJpdG1hcCBkaXN0cmlidXRpb24gZm9ybWF0IGZvbnQgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBEZWx1eGUgUGFpbnQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA5LTAxIGJ5IENhcmwNCjAJc3RyaW5nCUNGXFx4MDFcXHgwMAlbZmlkPTAwMDAwMTAxMC03MC0wMDAwMDBDO2V4dD1jO21pbWU9O11EZWx1eGUgcGFpbnQgbXVsdGktY29sb3VyIGZvbnQgZmlsZQ0KDQojIE1hZ2ljIElEIGZvciBGaWdsZXQgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA5LTAxIGJ5IENhcmwNCjAJc3RyaW5nCWZsZjIJW2ZpZD0wMDAxMDAxMjItNzAtMDAwMEZMRjtleHQ9ZmxmO21pbWU9O11GaWdsZXQgZm9udCBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFBDTCA1IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wOS0wMSBieSBDYXJsDQowCXN0cmluZwlcXHgwMFxceDQ0XFx4MDBcXHgwMVxceDAwXFx4MDBcXHgwMFxceDFBCVtmaWQ9MDAwMDAxMzM2LTcwLTAwMDBMSUI7ZXh0PWxpYix0eXBlO21pbWU9O11JbnRlbGxpZm9udCBTY2FsYWJsZSBUeXBlZmFjZSBGb3JtYXQgIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgRGVsdXhlIFBhaW50IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wOS0wMSBieSBDYXJsDQowCXN0cmluZwlcXHgxQlxceDI5XFx4NzNcXHgzNlxceDM0XFx4NTdcXHgwMFxceDQwCVtmaWQ9MDAwMDAxMDEwLTcwLTAwMDAwME07ZXh0PW07bWltZT07XURlbHV4ZSBwYWludCBtb25vIGNvbG91ciBmb250IGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNS0yMCBieSBDYXJsDQowCWJlbG9uZwkweDAwMDEwMDAwCVtmaWQ9MDAwMDAxMDAxLTcwLTAwMDBUVEY7ZXh0PW90Zix0dGY7bWltZT07XU9wZW50eXBlIGZvbnQgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTIwIGJ5IENhcmwNCjAJc3RyaW5nCU9UVE8JW2ZpZD0wMDAwMDEwMDEtNzAtMDAwMFRURjtleHQ9b3RmLHR0ZjttaW1lPTtdT3BlbnR5cGUgZm9udCBmaWxlLCBDRkYgdHlwZQ0KDQojIE1hZ2ljIElEIGZvciBYLVdpbmRvd3MgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA5LTAxIGJ5IENhcmwNCjAJYmVsb25nCTB4MDE2NjYzNzAJW2ZpZD0wMDAwMDAwMDAtNzAtMDAwMFBDRjtleHQ9cGNmO21pbWU9O11Qb3J0YWJsZSBjb21waWxlZCBmb3JtYXQgKFBDRikgZm9udCBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMjAgYnkgQ2FybA0KMAlzdHJpbmcJJSFGb250VHlwZTEJW2ZpZD0wMDAwMDAwMDEtNzAtMDAwOTU0MTtleHQ9cGZhO21pbWU9O11UeXBlIDEgZm9udCBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMjAgYnkgQ2FybA0KMAlzdHJpbmcJJSFQUy1BZG9iZUZvbnQtMS4wCVtmaWQ9MDAwMDAwMDAxLTcwLTAwMDk1NDE7ZXh0PXBmYTttaW1lPTtdVHlwZSAxIGZvbnQgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTIwIGJ5IENhcmwNCjYJc3RyaW5nCSUhRm9udFR5cGUxCVtmaWQ9MDAwMDAxMDAzLTcwLTAwMDBQRkI7ZXh0PXBmYjttaW1lPTtdVHlwZSAxIHByaW50ZXIgZm9udCBiaW5hcnkgZmlsZQ0KJjAJYnl0ZQkweDgwCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTIwIGJ5IENhcmwNCjYJc3RyaW5nCSUhUFMtQWRvYmVGb250LTEuMAlbZmlkPTAwMDAwMTAwMy03MC0wMDAwUEZCO2V4dD1wZmI7bWltZT07XVR5cGUgMSBwcmludGVyIGZvbnQgYmluYXJ5IGZpbGUNCiYwCWJ5dGUJMHg4MAkNCg0KIyBNYWdpYyBJRCBmb3IgWC1XaW5kb3dzLCBHZW1ET1MgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA5LTAxIGJ5IENhcmwNCjIJc3RyaW5nCVxceDJFXFx4MzBcXHgwRFxceDBBXFx4MDBcXHgwMAlbZmlkPTAwMDAwMTMzNy03MC0wMDAwU1BEO2V4dD1zcGQ7bWltZT07XUJpdHN0cmVhbSBTcGVlZG8gZm9udCBmaWxlDQomMAlzdHJpbmcJRAkNCj4yNAlzdHJpbmcJeAlbdGl0bGU9JS43MHNdDQo+MQlzdHJpbmcJeAksdmVyc2lvbiAlLjFzLjANCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNS0yMCBieSBDYXJsDQowCXN0cmluZwl0cnVlCVtmaWQ9MDAwMDAxMDAyLTcwLTAwMDBUVEY7ZXh0PXR0ZjttaW1lPTtdVHJ1ZXR5cGUgZm9udCBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMjAgYnkgQ2FybA0KMAlzdHJpbmcJdHlwMQlbZmlkPTAwMDAwMTAwMi03MC0wMDAwVFRGO2V4dD10dGY7bWltZT07XVRydWV0eXBlIGZvbnQgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTIwIGJ5IENhcmwNCjAJc3RyaW5nCVN0YXJ0Q29tcEZvbnRNZXRyaWNzCVtmaWQ9MDAwMDAxMDAzLTcwLTAwMDBBRk07ZXh0PWFmbTttaW1lPTtdQWRvYmUgY29tcG9zaXRlIGZvbnQgbWV0cmljcyBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMjAgYnkgQ2FybA0KMAlzdHJpbmcJU3RhcnRGb250TWV0cmljcwlbZmlkPTAwMDAwMTAwMy03MC0wMDAwQUZNO2V4dD1hZm07bWltZT07XUFkb2JlIGZvbnQgbWV0cmljcyBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMjAgYnkgQ2FybA0KMAlzdHJpbmcJU3RhcnRNYXN0ZXJGb250TWV0cmljcwlbZmlkPTAwMDAwMTAwMy03MC0wMDAwQUZNO2V4dD1hZm07bWltZT07XUFkb2JlIG1hc3RlciBmb250IG1ldHJpY3MgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTIwIGJ5IENhcmwNCjAJbGVzaG9ydAkweDAxMDAJW2ZpZD0wMDAwMDEwMDEtNzAtMDAwMFBGTTtleHQ9cGZtO21pbWU9O11QcmludGVyIEZvbnQgTWV0cmljcyBmaWxlIGZvciBUeXBlIDEgZm9udHMNCiY2NglsZXNob3J0CTB4MDA4MQkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCWxlbG9uZwkweDc1QjIyNjMwCVtmaWQ9MDAwMDAxMDAxLTgxLTAwMDBBU0Y7ZXh0PWFzZix3bWEsd212O21pbWU9O11NaWNyb3NvZnQgQWR2YW5jZWQgU3RyZWFtaW5nIGZvcm1hdCBtdWx0aW1lZGlhIGZpbGUNCiY2CWxlc2hvcnQJMHgxMUNGCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCVJJRkYJW2ZpZD0wMDAwMDEwMDEtODEtMDAwMEFWSTtleHQ9YXZpO21pbWU9O11BdWRpby12aWRlbyBpbnRlcmxlYXZlZCBtb3ZpZSwgbGl0dGxlLWVuZGlhbg0KJjgJc3RyaW5nCUFWSVxcIAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMyBieSBDYXJsDQowCXN0cmluZwlSSUZYCVtmaWQ9MDAwMDAxMDAxLTgxLTAwMDBBVkk7ZXh0PWF2aTttaW1lPTtdQXVkaW8tdmlkZW8gaW50ZXJsZWF2ZWQgbW92aWUsIGJpZy1lbmRpYW4NCiY4CXN0cmluZwlBVklcXCAJDQoNCiMgTWFnaWMgSUQgZm9yIFF1aWNrdGltZSBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KNAlzdHJpbmcJbWRhdAlbZmlkPTAwMDAwMTAwMi04MS0wMDAwTU9WO2V4dD1tb3YscXQ7bWltZT12aWRlby9xdWlja3RpbWU7XUFwcGxlIFF1aWNrVGltZSBtb3ZpZSBkYXRhIChtZGF0KQ0KDQojIE1hZ2ljIElEIGZvciBRdWlja3RpbWUgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjQJc3RyaW5nCW1vb3YJW2ZpZD0wMDAwMDEwMDItODEtMDAwME1PVjtleHQ9bW92LHF0O21pbWU9dmlkZW8vcXVpY2t0aW1lO11BcHBsZSBRdWlja1RpbWUgbW92aWUgcmVzb3VyY2UgKG1vb3YpDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMjAgYnkgQ2FybA0KMAliZWxvbmcJMHgxQjMJW2ZpZD0wMDAwMDAwMDEtODEtMDAwTVBFRztleHQ9bXBlLG1wZWcsbXBnO21pbWU9dmlkZW8vbXBlZztdTVBFRyBtdWx0aW1lZGlhIChhdWRpby92aWRlbykgc3RyZWFtIGZpbGUNCiZaNAliZWxvbmcJMHgwMUI5CQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTIwIGJ5IENhcmwNCjAJYmVsb25nCTB4MUJBCVtmaWQ9MDAwMDAwMDAxLTgxLTAwME1QRUc7ZXh0PW1wZSxtcGVnLG1wZzttaW1lPXZpZGVvL21wZWc7XU1QRUcgbXVsdGltZWRpYSAoYXVkaW8vdmlkZW8pIHN0cmVhbSBmaWxlDQomWjQJYmVsb25nCTB4MDFCOQkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNS0yMCBieSBDYXJsDQowCWJlbG9uZwkweDFFMAlbZmlkPTAwMDAwMDAwMS04MS0wMDBNUEVHO2V4dD1tcGUsbXBlZyxtcGc7bWltZT12aWRlby9tcGVnO11NUEVHIG11bHRpbWVkaWEgKGF1ZGlvL3ZpZGVvKSBzdHJlYW0gZmlsZQ0KJlo0CWJlbG9uZwkweDAxQjkJDQoNCiMgTWFnaWMgSUQgZm9yIEFsaWFzL1dhdmVmcm9udCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJTU9WSQlbZmlkPTAwMDAwMTAwNC04MS0wMDAwME1WO2V4dD1tdjttaW1lPTtdQWxpYXMvV2F2ZWZyb250IG1vdmllIGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNS0xOCBieSBDYXJsDQowCXN0cmluZwlPZ2dTCVtmaWQ9MDAwMDAwMDAwLTgxLTAwMDBPR0c7ZXh0PW9nZzttaW1lPWFwcGxpY2F0aW9uL29nZztdT0dHIE11bHRpbWVkaWEgY29udGFpbmVyIHN0cmVhbSBmaWxlDQoNCiMgTWFnaWMgSUQgZm9yIFJlYWxwbGF5ZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTE5IGJ5IENhcmwNCjAJc3RyaW5nCS5STUYJW2ZpZD0wMDAwMDEwMjctODEtMDAwMDBSTTtleHQ9cm0scmEscnQscnAscnBhO21pbWU9O11SZWFsTWVkaWEgbXVsdGltZWRpYSBjb250YWluZXIgc3RyZWFtIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgTWFjcm9tZWRpYSBGbGFzaCBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KMAlzdHJpbmcJRldTCVtmaWQ9MDAwMDAxMjU5LTgxLTAwMDBTV0Y7ZXh0PXN3ZjttaW1lPTtdU2hvY2t3YXZlIE1hY3JvbWVkaWEgYW5pbWF0aW9uDQo+MwlieXRlCXgJLCB2ZXJzaW9uICVkLjANCg0KIyBNYWdpYyBJRCBmb3IgVml2byBwbGF5ZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTIwIGJ5IENhcmwNCjUJc3RyaW5nCVZlcnNpb246Vml2bwlbZmlkPTAwMDAwMDAwMC04MS0wMDBWSVZPO2V4dD12aXYsdml2bzttaW1lPXZpZGVvL3ZuZC52aXZvO11WaXZvIG11bHRpbWVkaWEgc3RyZWFtIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgQWVnaXMgQW5pbWF0b3IgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCUZPUk0JW2ZpZD0wMDAwMDEyNjEtODItMDAwQU5JTTtleHQ9YW5pbTttaW1lPTtdQW1pZ2EgLyBTcGFydGEgc29mdHdhcmUgYW5pbWF0aW9uDQomOAlzdHJpbmcJQU5JTQkNCg0KIyBNYWdpYyBJRCBmb3IgRmFudGF2aXNpb24gbW92aWUgbWFrZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjAJc3RyaW5nCUZPUk0JW2ZpZD0wMDAwMDEyNjAtODItMDAwRkFOVDtleHQ9ZmFudDttaW1lPTtdRmFudGF2aXNpb24gbW92aWUNCiY4CXN0cmluZwlGQU5UCQ0KDQojIE1hZ2ljIElEIGZvciBBdXRvZGVzayBBbmltYXRvciBQcm8gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTA4IGJ5IENhcmwNCjQJbGVzaG9ydAkweEFGMTIJW2ZpZD0wMDAwMDEyNTQtODItMDAwMEZMQztleHQ9ZmxjO21pbWU9O11BdXRvZGVzayBBbmltYXRvciBQcm8gYW5pbWF0aW9uDQomMTIJbGVzaG9ydAkweDA4CQ0KPjgJbGVzaG9ydAl4CVtyZXM9JWR4DQo+MTAJbGVzaG9ydAl4CSVkDQo+MTIJbGVzaG9ydAl4CXg4YnBwXQ0KDQojIE1hZ2ljIElEIGZvciBBdXRvZGVzayBBbmltYXRvciBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMDggYnkgQ2FybA0KNAlsZXNob3J0CTB4QUYxMQlbZmlkPTAwMDAwMTI1NC04Mi0wMDAwRkxJO2V4dD1mbGk7bWltZT07XUF1dG9kZXNrIEFuaW1hdG9yIGFuaW1hdGlvbg0KJjEyCWxlc2hvcnQJMHgwOAkNCj44CWxlc2hvcnQJeAlbcmVzPSVkeA0KPjEwCWxlc2hvcnQJeAklZA0KPjEyCWxlc2hvcnQJeAl4OGJwcF0NCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0xMyBieSBDYXJsDQowCXN0cmluZwlcXHg4QU1OR1xceDBkXFx4MEFcXHgxQVxceDBBCVtmaWQ9MDAwMDAwMDAwLTgyLTAwMDBNTkc7ZXh0PW1uZzttaW1lPTtdTXVsdGktaW1hZ2UgbmV0d29yayBncmFwaGljcyBhbmltYXRpb24gZmlsZQ0KPjB4MTAJYmVsb25nCXgJW3Jlcz0lZHgNCj4weDE0CWJlbG9uZwl4CSVkXQ0KDQojIE1hZ2ljIElEIGZvciBDeWJlcnBhaW50IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0wOCBieSBDYXJsDQowCWJlc2hvcnQJMHhGRURCCVtmaWQ9MDAwMDAwMDAwLTgyLTAwMDBTRVE7ZXh0PXNlcTttaW1lPTtdQ3liZXJwYWludCBBbmltYXRpb24gU2VxdWVuY2UNCiYyCWJlc2hvcnQJMHgwMDAwCQ0KDQojIE1hZ2ljIElEIGZvciBRdWlja2VuLE1vbmV5IGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wOC0wMSBieSBDYXJsDQowCXN0cmluZwlPRlhIRUFERVI6CVtmaWQ9MDAwMDAwMDA4LTkxLTAwMDBRRlg7ZXh0PXFmeDttaW1lPTtdT3BlbiBmaW5hbmNpYWwgZXhjaGFuZ2UgZmlsZSAoU0dNTCkNCg0KIyBNYWdpYyBJRCBmb3IgUXVpY2tlbiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDgtMDEgYnkgQ2FybA0KMQlzdHJpbmcJQWNjb3VudAlbZmlkPTAwMDAwMTMzNS05MS0wMDAwUUlGO2V4dD1xaWY7bWltZT07XVF1aWNrZW4gaW50ZXJjaGFuZ2UgZmlsZQ0KJjAJYnl0ZQkzMwkNCg0KIyBNYWdpYyBJRCBmb3IgUXVpY2tlbiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDgtMDEgYnkgQ2FybA0KMQlzdHJpbmcJVHlwZTpCYW5rCVtmaWQ9MDAwMDAxMzM1LTkxLTAwMDBRSUY7ZXh0PXFpZjttaW1lPTtdUXVpY2tlbiBpbnRlcmNoYW5nZSBmaWxlDQomMAlieXRlCTMzCQ0KDQojIE1hZ2ljIElEIGZvciBRdWlja2VuIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wOC0wMSBieSBDYXJsDQoxCXN0cmluZwlUeXBlOkNhc2gJW2ZpZD0wMDAwMDEzMzUtOTEtMDAwMFFJRjtleHQ9cWlmO21pbWU9O11RdWlja2VuIGludGVyY2hhbmdlIGZpbGUNCiYwCWJ5dGUJMzMJDQoNCiMgTWFnaWMgSUQgZm9yIFF1aWNrZW4gZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA4LTAxIGJ5IENhcmwNCjEJc3RyaW5nCVR5cGU6Q2F0CVtmaWQ9MDAwMDAxMzM1LTkxLTAwMDBRSUY7ZXh0PXFpZjttaW1lPTtdUXVpY2tlbiBpbnRlcmNoYW5nZSBmaWxlDQomMAlieXRlCTMzCQ0KDQojIE1hZ2ljIElEIGZvciBRdWlja2VuIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wOC0wMSBieSBDYXJsDQoxCXN0cmluZwlUeXBlOkNDYXJkCVtmaWQ9MDAwMDAxMzM1LTkxLTAwMDBRSUY7ZXh0PXFpZjttaW1lPTtdUXVpY2tlbiBpbnRlcmNoYW5nZSBmaWxlDQomMAlieXRlCTMzCQ0KDQojIE1hZ2ljIElEIGZvciBRdWlja2VuIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wOC0wMSBieSBDYXJsDQoxCXN0cmluZwlUeXBlOkNsYXNzCVtmaWQ9MDAwMDAxMzM1LTkxLTAwMDBRSUY7ZXh0PXFpZjttaW1lPTtdUXVpY2tlbiBpbnRlcmNoYW5nZSBmaWxlDQomMAlieXRlCTMzCQ0KDQojIE1hZ2ljIElEIGZvciBRdWlja2VuIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wOC0wMSBieSBDYXJsDQoxCXN0cmluZwlUeXBlOkludnN0CVtmaWQ9MDAwMDAxMzM1LTkxLTAwMDBRSUY7ZXh0PXFpZjttaW1lPTtdUXVpY2tlbiBpbnRlcmNoYW5nZSBmaWxlDQomMAlieXRlCTMzCQ0KDQojIE1hZ2ljIElEIGZvciBRdWlja2VuIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wOC0wMSBieSBDYXJsDQoxCXN0cmluZwlUeXBlOk1lbW9yaXplZAlbZmlkPTAwMDAwMTMzNS05MS0wMDAwUUlGO2V4dD1xaWY7bWltZT07XVF1aWNrZW4gaW50ZXJjaGFuZ2UgZmlsZQ0KJjAJYnl0ZQkzMwkNCg0KIyBNYWdpYyBJRCBmb3IgUXVpY2tlbiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDgtMDEgYnkgQ2FybA0KMQlzdHJpbmcJVHlwZTpPdGggQQlbZmlkPTAwMDAwMTMzNS05MS0wMDAwUUlGO2V4dD1xaWY7bWltZT07XVF1aWNrZW4gaW50ZXJjaGFuZ2UgZmlsZQ0KJjAJYnl0ZQkzMwkNCg0KIyBNYWdpYyBJRCBmb3IgUXVpY2tlbiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMDgtMDEgYnkgQ2FybA0KMQlzdHJpbmcJVHlwZTpPdGggTAlbZmlkPTAwMDAwMTMzNS05MS0wMDAwUUlGO2V4dD1xaWY7bWltZT07XVF1aWNrZW4gaW50ZXJjaGFuZ2UgZmlsZQ0KJjAJYnl0ZQkzMwkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xMSBieSBDYXJsDQowCXN0cmluZwlSUkcJW2ZpZD0wMDAwMDEwMDEtQjAtMDAwMENSRDtleHQ9Y3JkO21pbWU9O11XaW5kb3dzIDMueCBjYXJkZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTExIGJ5IENhcmwNCjAJc3RyaW5nCU1HQwlbZmlkPTAwMDAwMTAwMS1CMC0wMDAwQ1JEO2V4dD1jcmQ7bWltZT07XVdpbmRvd3MgTlQgMy41MSBjYXJkIGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wMi0xNCBieSBDYXJsDQowCXN0cmluZwlCRUdJTjpWQ0FSRAlbZmlkPTAwMDAwMTAxNS1CMC0wMDAwVkNGO2V4dD12Y2Y7bWltZT07XXZDYXJkIEJ1c2luZXNzIENhcmQgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTAyLTE0IGJ5IENhcmwNCjAJc3RyaW5nCVxceGI1XFx4YTJcXHhiMFxceGIzXFx4YjNcXHhiMFxceGEyXFx4YjUJW2ZpZD0wMDAwMDEwMDEtQjEtMDAwMENBTDtleHQ9Y2FsO21pbWU9O11NaWNyb3NvZnQgd2luZG93cyBjYWxlbmRhciBmaWxlDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDItMTQgYnkgQ2FybA0KMAlzdHJpbmcJQkVHSU46VkNBTEVOREFSCVtmaWQ9MDAwMDAxMDE2LUIxLTAwMDBWQ1M7ZXh0PXZjczttaW1lPTtddkNhbGVuZGFyL2lDYWxlbmRhciBBZ2VuZGEgZmlsZQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTE3IGJ5IENhcmwNCjAJc3RyaW5nCVxceDAwXFx4MDBcXHgwMFxceDNDXFx4MDBcXHgwMFxceDAwXFx4M0YJW2ZpZD0wMDAwMDAwMDctRjMtMDAwMFhNTDtleHQ9eG1sO21pbWU9dGV4dC94bWw7XUV4dGVuc2libGUgTWFya3VwIGxhbmd1YWdlIChYTUwpIGZpbGUsIFVURi0zMkJFIGVuY29kZWQNCiY4CWJlbG9uZwkweDAwMDAwMDc4CQ0KJjEyCWJlbG9uZwkweDAwMDAwMDZkCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTE3IGJ5IENhcmwNCjAJc3RyaW5nCVxceDAwXFx4MDBcXHhmZVxceGZmXFx4MDBcXHgwMFxceDAwXFx4M0MJW2ZpZD0wMDAwMDAwMDctRjMtMDAwMFhNTDtleHQ9eG1sO21pbWU9dGV4dC94bWw7XUV4dGVuc2libGUgTWFya3VwIGxhbmd1YWdlIChYTUwpIGZpbGUsIFVURi0zMkJFIGVuY29kZWQNCiY4CWJlbG9uZwkweDAwMDAwMDNGCQ0KJjEyCWJlbG9uZwkweDAwMDAwMDc4CQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTE3IGJ5IENhcmwNCjAJc3RyaW5nCVxceDAwXFx4M0NcXHgwMFxceDNGXFx4MDBcXHg3OFxceDAwXFx4NkRcXHgwMFxceDZjCVtmaWQ9MDAwMDAwMDA3LUYzLTAwMDBYTUw7ZXh0PXhtbDttaW1lPXRleHQveG1sO11FeHRlbnNpYmxlIE1hcmt1cCBsYW5ndWFnZSAoWE1MKSBmaWxlLCBVVEYtMTZCRSBlbmNvZGVkDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMTcgYnkgQ2FybA0KMAlzdHJpbmcJXFx4M0NcXHgwMFxceDAwXFx4MDBcXHgzRlxceDAwXFx4MDBcXHgwMAlbZmlkPTAwMDAwMDAwNy1GMy0wMDAwWE1MO2V4dD14bWw7bWltZT10ZXh0L3htbDtdRXh0ZW5zaWJsZSBNYXJrdXAgbGFuZ3VhZ2UgKFhNTCkgZmlsZSwgVVRGLTMyTEUgZW5jb2RlZA0KJjgJYmVzaG9ydAkweDAwMDAwMDc4CQ0KJjEyCWJlc2hvcnQJMHgwMDAwMDA2ZAkNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNS0xNyBieSBDYXJsDQowCXN0cmluZwlcXHgzQ1xceDAwXFx4M0ZcXHgwMFxceDc4XFx4MDBcXHg2RFxceDAwXFx4NmNcXHgwMAlbZmlkPTAwMDAwMDAwNy1GMy0wMDAwWE1MO2V4dD14bWw7bWltZT10ZXh0L3htbDtdRXh0ZW5zaWJsZSBNYXJrdXAgbGFuZ3VhZ2UgKFhNTCkgZmlsZSwgVVRGLTE2TEUgZW5jb2RlZA0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTE3IGJ5IENhcmwNCjAJc3RyaW5nCVxceGVmXFx4YmJcXHhiZjw/eG1sCVtmaWQ9MDAwMDAwMDA3LUYzLTAwMDBYTUw7ZXh0PXhtbDttaW1lPXRleHQveG1sO11FeHRlbnNpYmxlIE1hcmt1cCBsYW5ndWFnZSAoWE1MKSBmaWxlLCBVVEYtOCBlbmNvZGVkDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMTcgYnkgQ2FybA0KMAlzdHJpbmcJXFx4ZmVcXHhmZlxceDAwXFx4M0NcXHgwMFxceDNGXFx4MDBcXHg3OFxceDAwXFx4NkQJW2ZpZD0wMDAwMDAwMDctRjMtMDAwMFhNTDtleHQ9eG1sO21pbWU9dGV4dC94bWw7XUV4dGVuc2libGUgTWFya3VwIGxhbmd1YWdlIChYTUwpIGZpbGUsIFVURi0xNkJFIGVuY29kZWQNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNS0xNyBieSBDYXJsDQowCXN0cmluZwlcXHhmZlxceGZlXFx4MDBcXHgwMFxceDNDXFx4MDBcXHgwMFxceDAwCVtmaWQ9MDAwMDAwMDA3LUYzLTAwMDBYTUw7ZXh0PXhtbDttaW1lPXRleHQveG1sO11FeHRlbnNpYmxlIE1hcmt1cCBsYW5ndWFnZSAoWE1MKSBmaWxlLCBVVEYtMzJMRSBlbmNvZGVkDQomOAliZXNob3J0CTB4M0YwMDAwMDAJDQomMTIJYmVzaG9ydAkweDc4MDAwMDAwCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTA1LTE3IGJ5IENhcmwNCjAJc3RyaW5nCVxceGZmXFx4ZmVcXHgzQ1xceDAwXFx4M0ZcXHgwMFxceDc4XFx4MDBcXHg2RFxceDAwCVtmaWQ9MDAwMDAwMDA3LUYzLTAwMDBYTUw7ZXh0PXhtbDttaW1lPXRleHQveG1sO11FeHRlbnNpYmxlIE1hcmt1cCBsYW5ndWFnZSAoWE1MKSBmaWxlLCBVVEYtMTZMRSBlbmNvZGVkDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDUtMTcgYnkgQ2FybA0KMAlzdHJpbmcJPD94bWwJW2ZpZD0wMDAwMDAwMDctRjMtMDAwMFhNTDtleHQ9eG1sO21pbWU9dGV4dC94bWw7XUV4dGVuc2libGUgTWFya3VwIGxhbmd1YWdlIChYTUwpIGZpbGUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0wNC0yMCBieSBDYXJsDQowCXN0cmluZwlcXHhkMFxceGNmXFx4MTFcXHhlMFxceGExXFx4YjFcXHgxYVxceGUxCVtmaWQ9MDAwMDAxMDAxLUY0LTAwMDBPTEU7ZXh0PW9sZTttaW1lPTtdTWljcm9zb2Z0IE9MRSBDb21wb3VuZCBmaWxlLCBiaWctZW5kaWFuDQomMHgxQwlsZXNob3J0CSEweEZGRkUJDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMDQtMjAgYnkgQ2FybA0KMAlzdHJpbmcJXFx4ZDBcXHhjZlxceDExXFx4ZTBcXHhhMVxceGIxXFx4MWFcXHhlMQlbZmlkPTAwMDAwMTAwMS1GNC0wMDAwT0xFO2V4dD1vbGU7bWltZT07XU1pY3Jvc29mdCBPTEUgQ29tcG91bmQgZmlsZSwgbGl0dGxlLWVuZGlhbg0KJjB4MUMJbGVzaG9ydAkweEZGRkUJDQo+MHgxQQlsZXNob3J0CXgJLCB2ZXJzaW9uICVkDQo+MHgxOAlsZXNob3J0CXgJLiVkDQoNCiMgTWFnaWMgSUQgZm9yIEZyZWVwYXNjYWwgY29tcGlsZXIgZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTEwLTI0IGJ5IENhcmwNCjAJc3RyaW5nCVBQVTAJW2ZpZD0wMDAxMDAxMjAtMTEtMDAwMFBQVTtleHQ9cHB1LHBwbCxwcG8scHB3LHBwYSxwcHQ7bWltZT07XUZyZWVwYXNjYWwgdW5pdCBmaWxlDQo+MHgwNAlzdHJpbmcJeAksIHZlcnNpb24gJS4ycw0KDQojIE1hZ2ljIElEIGZvciBTbWFydGNhcmRzIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0xMC0yOSBieSBDYXJsDQowCWJlbG9uZwkweDAwRkFDQURFCVtmaWQ9MDAwMDAxMDExLTEwLTAwMDBFWFA7ZXh0PWV4cDttaW1lPTtdSmF2YWNhcmQgQVBJIGV4cG9ydCBmaWxlDQo+MHgwNQlieXRlCXgJLCB2ZXJzaW9uICVkDQo+NAlieXRlCXgJLiVkDQoNCiMgU3VibWl0dGVkIG9uIDIwMDQtMTAtMjkgYnkgQ2FybA0KMAlzdHJpbmcJLXJvbTFmcy0JW2ZpZD0wMDAxMDAxMjEtMEYtMDAwMElNRztleHQ9aW1nO21pbWU9O11TaW1wbGUgUk9NIGZpbGVzeXN0ZW0gKFJPTUZTKQ0KPjE2CXN0cmluZwl4CVt0aXRsZT0lc10NCg0KIyBNYWdpYyBJRCBmb3IgVmlydHVhbCBQQyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMTAtMjkgYnkgQ2FybA0KMAlzdHJpbmcJY29uZWN0aXgJW2ZpZD0wMDAwMDEwMDEtMEYtMDAwMFZIRDtleHQ9dmhkO21pbWU9O11WaXJ0dWFsIFBDIEhhcmQgZHJpdmUNCg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0xMS0xMiBieSBDYXJsIEVyaWMgQ29kZXJlDQowCXN0cmluZwklIVBTLUFkb2JlLQlbZmlkPTAwMDAwMTAwMy0zMy0wMDAwMFBTO2V4dD1wcyxlcHM7bWltZT1hcHBsaWNhdGlvbi9wb3N0c2NyaXB0O11Qb3N0c2NyaXB0IGZpbGUNCj4xMQlzdHJpbmcJeAksIGxldmVsICUuMXMNCj4xMwlzdHJpbmcJeAkuJS4xcw0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTExLTEyIGJ5IENhcmwgRXJpYyBDb2RlcmUNCjAJbGVsb25nCTB4NTI2ZjZkMmUJW2ZpZD0wMDAwMDEzMzgtMEYtMDAwMFJPTTtleHQ9cm9tLGZzO21pbWU9O11lQ29zIFJPTSBGaWxlc3lzdGVtIGltYWdlIChST01GUykNCj4xNglzdHJpbmcJeAlbdGl0bGU9JS4xNnNdDQoNCiMgTWFnaWMgSUQgZm9yIFBBREdlbiBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDQtMTEtMjYgYnkgQ2FybCBFcmljIENvZGVyZQ0KMHgyOQlzdHJpbmcJPFhNTF9ESVpfSU5GTz4JW2ZpZD0wMDAwMDEzMzktQTAtMDAwMFhNTDtleHQ9eG1sO21pbWU9dGV4dC94bWw7XVBvcnRhYmxlIGFwcGxpY2F0aW9uIGRlc2NyaXB0aW9uIGZpbGUgKFhNTCkNCiYwCXN0cmluZwk8P3htbAkNCg0KIyBNYWdpYyBJRCBmb3IgUEFER2VuIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0xMS0yNiBieSBDYXJsIEVyaWMgQ29kZXJlDQoweDI4CXN0cmluZwk8WE1MX0RJWl9JTkZPPglbZmlkPTAwMDAwMTMzOS1BMC0wMDAwWE1MO2V4dD14bWw7bWltZT10ZXh0L3htbDtdUG9ydGFibGUgYXBwbGljYXRpb24gZGVzY3JpcHRpb24gZmlsZSAoWE1MKQ0KJjAJc3RyaW5nCTw/eG1sCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTExLTI2IGJ5IENhcmwgRXJpYyBDb2RlcmUNCjB4MjkJc3RyaW5nCTx4OnhtcG1ldGFcXCAJW2ZpZD0wMDAwMDEwMDMtQTAtMDAwMFhNUDtleHQ9eG1sLHhtcDttaW1lPXRleHQveG1sO11FeHRlbnNpYmxlIG1ldGFkYXRhIHBsYXRmb3JtIHNpZGVjYXIgZmlsZSAoWE1MKQ0KJjAJc3RyaW5nCTw/eG1sCQ0KDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTExLTI2IGJ5IENhcmwgRXJpYyBDb2RlcmUNCjB4MjgJc3RyaW5nCTx4OnhtcG1ldGFcXCAJW2ZpZD0wMDAwMDEwMDMtQTAtMDAwMFhNUDtleHQ9eG1sLHhtcDttaW1lPXRleHQveG1sO11FeHRlbnNpYmxlIG1ldGFkYXRhIHBsYXRmb3JtIHNpZGVjYXIgZmlsZSAoWE1MKQ0KJjAJc3RyaW5nCTw/eG1sCQ0KDQojIE1hZ2ljIElEIGZvciBUZXhpbmZvIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0xMS0yNiBieSBDYXJsIEVyaWMgQ29kZXJlDQoxCXN0cmluZwlpbnB1dCB0ZXhpbmZvCVtmaWQ9MDAwMDAxMzQwLTAwLTAwMFRFWEk7ZXh0PXRleGk7bWltZT07XVRleGluZm8gc291cmNlIGZpbGUNCg0KIyBNYWdpYyBJRCBmb3IgTVMtRE9TIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNC0xMS0yNiBieSBDYXJsIEVyaWMgQ29kZXJlDQowCXN0cmluZwlcXHhGRkZPTlQJW2ZpZD0wMDAwMDEwMDEtNzAtMDAwMENQSTtleHQ9Y3BpO21pbWU9O11NUy1ET1MgY29kZSBwYWdlIHJhc3RlciBmb250DQoNCiMgTWFnaWMgSUQgZm9yIFVOSVggZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA0LTExLTI2IGJ5IENhcmwgRXJpYyBDb2RlcmUNCjAJc3RyaW5nCVRaaWYJW2ZpZD0wMDAwMDAwMDAtOTAtMDAwMDAwMDtleHQ9O21pbWU9O11UaW1lem9uZSBpbmZvcm1hdGlvbiBkYXRhYmFzZSBmaWxlIChjb21waWxlZCkNCg0KIyBNYWdpYyBJRCBmb3IgVGVsaXggZmlsZXMuDQojIFN1Ym1pdHRlZCBvbiAyMDA1LTAzLTA0IGJ5IENhcmwgRXJpYyBDb2RlcmUNCjAJbGVsb25nCTB4MmUyYjI5MWEJW2ZpZD0wMDAxMDAxMjYtQjAtMDAwMEZPTjtleHQ9Zm9uO21pbWU9O11UZWxpeCBwaG9uZSBib29rDQomNAlsZXNob3J0CTEJDQoNCiMgTWFnaWMgSUQgZm9yIE1pY3Jvc29mdCBWaXN1YWwgQysrIGZpbGVzLg0KIyBTdWJtaXR0ZWQgb24gMjAwNS0wMy0wNCBieSBDYXJsIEVyaWMgQ29kZXJlDQowCXN0cmluZwlWQ1BDSDBcXHgwMFxceDAwCVtmaWQ9MDAwMDAxMDAxLTkwLTAwMDBQQ0g7ZXh0PXBjaDttaW1lPTtdTWljcm9zb2Z0IFZpc3VhbCBDKysgcHJlLWNvbXBpbGVkIGhlYWRlcihzKQ0KDQojIE1hZ2ljIElEIGZvciBNaWNyb3NvZnQgVmlzdWFsIEMrKyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDUtMDMtMDQgYnkgQ2FybCBFcmljIENvZGVyZQ0KMAlzdHJpbmcJTWljcm9zb2Z0XFwgQy9DKytcXCBwcm9ncmFtXFwgZGF0YWJhc2UJW2ZpZD0wMDAwMDEwMDEtOTAtMDAwMFBEQjtleHQ9cGRiO21pbWU9O11NaWNyb3NvZnQgVmlzdWFsIEMrKyBkZWJ1ZyBpbmZvcm1hdGlvbiBkYXRhYmFzZQ0KJjB4MjUJc3RyaW5nCVxceDBEXFx4MEFcXHgxQQkNCiYweDI4CXN0cmluZwlKR1xceDAwCQ0KDQojIE1hZ2ljIElEIGZvciBNaWNyb3NvZnQgVmlzdWFsIEMrKyBmaWxlcy4NCiMgU3VibWl0dGVkIG9uIDIwMDUtMDMtMDQgYnkgQ2FybCBFcmljIENvZGVyZQ0KMAlzdHJpbmcJTWljcm9zb2Z0XFwgTGlua2VyXFwgRGF0YWJhc2VcXHgwQVxceDA3XFx4MUEJW2ZpZD0wMDAwMDEwMDEtOTAtMDAwMElMSztleHQ9aWxrO21pbWU9O11NaWNyb3NvZnQgVmlzdWFsIEMrKyBsaW5rZXIgZGF0YWJhc2UNCg0KDQojIENSQzMyOjhCQzNCQTQ2DQo=' - ); -/** - * Returns the test data for a given key - * - * @param string $key - */ - public function get($key) { -/** - * data property - * - * @var array - * @access public - */ - static $data = array(); - - if (empty($data)) { - $vars = get_class_vars(__CLASS__); - foreach ($vars['data'] as $k => $v) { - $data[$k] = base64_decode($v); - if (preg_match('/^[ais]:[0-9]+/', $data[$k])) { - $data[$k] = unserialize($data[$k]); - } - } - } - - if (!isset($data[$key])) { - return false; - } - return $data[$key]; - } -} diff --git a/cake/tests/cases/libs/test_manager.test.php b/cake/tests/cases/libs/test_manager.test.php deleted file mode 100644 index 524e77fc3..000000000 --- a/cake/tests/cases/libs/test_manager.test.php +++ /dev/null @@ -1,110 +0,0 @@ - - * Copyright 2005-2010, 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 - * - * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests - * @package cake.tests.cases.libs - * @since CakePHP(tm) v 1.2.0.4206 - * @license MIT License (http://www.opensource.org/licenses/mit-license.php) - */ - -class TestTestManager extends TestManager { - - public function setTestSuite($testSuite) { - $this->_testSuite = $testSuite; - } -} - -/** - * TestManagerTest class - * - * @package cake.tests.cases.libs - */ -class TestManagerTest extends CakeTestCase { - -/** - * Number of times the funcion PHPUnit_Framework_TestSuite::addTestFile() has been called - * - * @var integer - */ - protected $_countFiles = 0; - -/** - * setUp method - * - * @return void - */ - public function setUp() { - parent::setUp(); - $this->_countFiles = 0; - $this->TestManager = new TestTestManager(); - $this->testSuiteStub = $this->getMock('CakeTestSuite'); - - $this->testSuiteStub - ->expects($this->any()) - ->method('addTestFile') - ->will($this->returnCallback(array(&$this, '_countIncludedTestFiles'))); - - $this->testSuiteStub - ->expects($this->any()) - ->method('addTestSuite') - ->will($this->returnCallback(array(&$this, '_countIncludedTestFiles'))); - - $this->TestManager->setTestSuite($this->testSuiteStub); - $this->Reporter = $this->getMock('CakeHtmlReporter'); - } - -/** - * Helper method to count the number of times the - * function PHPUnit_Framework_TestSuite::addTestFile() has been called - * @return void - */ - public function _countIncludedTestFiles() { - $this->_countFiles++; - } - - protected function _getAllTestFiles($directory = CORE_TEST_CASES, $type = 'test') { - $folder = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)); - $extension = str_replace('.', '\.', $this->TestManager->getExtension($type)); - $out = new RegexIterator($folder, '#^.+'.$extension.'$#i', RecursiveRegexIterator::GET_MATCH); - - $files = array(); - foreach ($out as $testFile) { - $files[] = $testFile[0]; - } - return $files; - } - -/** -* Tests that trying to run an unexistent file throws an exception -* @expectedException InvalidArgumentException -*/ - public function testRunUnexistentCase() { - $file = md5(time()); - $result = $this->TestManager->runTestCase($file, $this->Reporter); - } - -/** - * testRunTestCase method - * - * @return void - */ - public function testRunTestCase() { - $file = 'libs/test_manager.test.php'; - $result = $this->TestManager->runTestCase($file, $this->Reporter, true); - $this->assertEquals(1, $this->_countFiles); - $this->assertInstanceOf('PHPUnit_Framework_TestResult', $result); - } - -} diff --git a/cake/tests/lib/test_manager.php b/cake/tests/lib/test_manager.php deleted file mode 100644 index 7cb6a3fdd..000000000 --- a/cake/tests/lib/test_manager.php +++ /dev/null @@ -1,299 +0,0 @@ - - * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) - * - * Licensed under The MIT License - * Redistributions of files must retain the above copyright notice - * - * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org) - * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests - * @package cake.tests.lib - * @since CakePHP(tm) v 1.2.0.4433 - * @license MIT License (http://www.opensource.org/licenses/mit-license.php) - */ -define('CORE_TEST_CASES', TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'cases'); -define('CORE_TEST_GROUPS', TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'groups'); -define('APP_TEST_CASES', TESTS . 'cases'); -define('APP_TEST_GROUPS', TESTS . 'groups'); - -PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); -require_once CAKE_TESTS_LIB . 'cake_test_suite.php'; - -/** - * TestManager is the base class that handles loading and initiating the running - * of TestCase and TestSuite classes that the user has selected. - * - * @package cake.tests.lib - */ -class TestManager { -/** - * Extension suffix for test case files. - * - * @var string - */ - protected static $_testExtension = '.test.php'; - -/** - * Is this test an AppTest? - * - * @var boolean - */ - public $appTest = false; - -/** - * Is this test a plugin test? - * - * @var mixed boolean false or string name of the plugin being used. - */ - public $pluginTest = false; - -/** - * String to filter test case method names by. - * - * @var string - */ - public $filter = false; - -/** - * TestSuite container for single or grouped test files - * - * @var PHPUnit_Framework_TestSuite - */ - protected $_testSuite = null; - -/** - * Object instance responsible for managing the test fixtures - * - * @var CakeFixtureManager - */ - protected $_fixtureManager = null; - -/** - * Params to configure test runner - * - * @var CakeFixtureManager - */ - public $params = array(); - -/** - * Constructor for the TestManager class - * - * @return void - */ - public function __construct($params = array()) { - require_once(CAKE_TESTS_LIB . 'cake_test_case.php'); - require_once(CAKE_TESTS_LIB . 'controller_test_case.php'); - - $this->params = $params; - if (isset($params['app'])) { - $this->appTest = true; - } - if (isset($params['plugin'])) { - $this->pluginTest = htmlentities($params['plugin']); - } - if ( - isset($params['filter']) && - $params['filter'] !== false && - preg_match('/^[a-zA-Z0-9_]/', $params['filter']) - ) { - $this->filter = '/' . $params['filter'] . '/'; - } - } - -/** - * Runs a specific test case file - * - * @param string $testCaseFile Filename of the test to be run. - * @param PHPUnit_Framework_TestListener $reporter Reporter instance to attach to the test case. - * @throws InvalidArgumentException if the supplied $testCaseFile does not exists - * @return mixed Result of test case being run. - */ - public function runTestCase($testCaseFile, PHPUnit_Framework_TestListener $reporter, $codeCoverage = false) { - $this->loadCase($testCaseFile); - return $this->run($reporter, $codeCoverage); - } - -/** - * Runs the main testSuite and attaches to it a reporter - * - * @param PHPUnit_Framework_TestListener $reporter Reporter instance to use with the group test being run. - * @return PHPUnit_Framework_TestResult Result object of the test run. - */ - protected function run($reporter, $codeCoverage = false) { - restore_error_handler(); - restore_error_handler(); - - $result = new PHPUnit_Framework_TestResult; - $result->collectCodeCoverageInformation($codeCoverage); - $result->addListener($reporter); - $reporter->paintHeader(); - $testSuite = $this->getTestSuite(); - $testSuite->setFixtureManager($this->getFixtureManager()); - $testSuite->run($result, $this->filter); - $reporter->paintResult($result); - return $result; - } - -/** - * Loads a test case in a test suite, if the test suite is null it will create it - * - * @param string Test file path - * @param PHPUnit_Framework_TestSuite $suite the test suite to load the case in - * @throws InvalidArgumentException if test case file is not found - * @return PHPUnit_Framework_TestSuite the suite with the test case loaded - */ - public function loadCase($testCaseFile, PHPUnit_Framework_TestSuite $suite = null) { - $testCaseFileWithPath = $this->_getTestsPath($this->params) . DS . $testCaseFile; - - if (!file_exists($testCaseFileWithPath) || strpos($testCaseFileWithPath, '..')) { - throw new InvalidArgumentException(__('Unable to load test file %s', htmlentities($testCaseFile))); - } - if (!$suite) { - $suite = $this->getTestSuite(__('Individual test case: %s', $testCaseFile)); - } - $suite->addTestFile($testCaseFileWithPath); - - return $suite; - } - -/** - * Returns a list of test cases found in the current valid test case path - * - * @access public - * @static - */ - public static function getTestCaseList($params) { - $directory = self::_getTestsPath($params); - $fileList = self::_getTestFileList($directory); - - $testCases = array(); - foreach ($fileList as $testCaseFile) { - $testCases[$testCaseFile] = str_replace($directory . DS, '', $testCaseFile); - } - return $testCases; - } - -/** - * Returns a list of test files from a given directory - * - * @param string $directory Directory to get test case files from. - * @static - */ - protected static function &_getTestFileList($directory = '.') { - $return = self::_getRecursiveFileList($directory, array('self', '_isTestCaseFile')); - return $return; - } - -/** - * Gets a recursive list of files from a given directory and matches then against - * a given fileTestFunction, like isTestCaseFile() - * - * @param string $directory The directory to scan for files. - * @param mixed $fileTestFunction - * @static - */ - protected static function &_getRecursiveFileList($directory = '.', $fileTestFunction) { - $fileList = array(); - if (!is_dir($directory)) { - return $fileList; - } - - $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)); - - foreach ($files as $file) { - if (!$file->isFile()) { - continue; - } - $file = $file->getRealPath(); - - if (call_user_func_array($fileTestFunction, array($file))) { - $fileList[] = $file; - } - } - return $fileList; - } - -/** - * Tests if a file has the correct test case extension - * - * @param string $file - * @return boolean Whether $file is a test case. - * @static - */ - protected static function _isTestCaseFile($file) { - return self::_hasExpectedExtension($file, self::$_testExtension); - } - -/** - * Check if a file has a specific extension - * - * @param string $file - * @param string $extension - * @return void - * @static - */ - protected static function _hasExpectedExtension($file, $extension) { - return $extension == strtolower(substr($file, (0 - strlen($extension)))); - } - -/** - * Returns the given path to the test files depending on a given type of tests (core, app, plugin) - * - * @param array $params Array of parameters for getting test paths. - * Can contain app, type, and plugin params. - * @return string The path tests are located on - * @static - */ - protected static function _getTestsPath($params) { - $result = null; - if (!empty($params['app'])) { - $result = APP_TEST_CASES; - } else if (!empty($params['plugin'])) { - $pluginPath = App::pluginPath($params['plugin']); - $result = $pluginPath . 'tests' . DS . 'cases'; - } else { - $result = CORE_TEST_CASES; - } - return $result; - } - -/** - * Get the extension for either 'group' or 'test' types. - * - * @param string $type Type of test to get, either 'test' or 'group' - * @return string Extension suffix for test. - */ - public static function getExtension($type = 'test') { - return self::$_testExtension; - } - -/** - * Get the container testSuite instance for this runner or creates a new one - * - * @param string $name The name for the container test suite - * @return PHPUnit_Framework_TestSuite container test suite - */ - public function getTestSuite($name = '') { - if (!empty($this->_testSuite)) { - return $this->_testSuite; - } - return $this->_testSuite = new CakeTestSuite($name); - } - -/** - * Get an instance of a Fixture manager to be used by the test cases - * - * @return CakeFixtureManager fixture manager - */ - public function getFixtureManager() { - if (!empty($this->_fixtureManager)) { - return $this->_fixtureManager; - } - return $this->_fixtureManager = new CakeFixtureManager; - } -} diff --git a/cake/tests/lib/test_runner.php b/cake/tests/lib/test_runner.php deleted file mode 100644 index 22def2a23..000000000 --- a/cake/tests/lib/test_runner.php +++ /dev/null @@ -1,57 +0,0 @@ -addFileToBlacklist(__FILE__, 'DEFAULT'); - -/** - * Class to customize loading of test suites from CLI - * - * @package cake.tests.lib - */ -class TestRunner extends PHPUnit_TextUI_Command { - -/** - * Construct method - * - * @param array $params list of options to be used for this run - */ - public function __construct($params = array()) { - $this->_params = $params; - } - -/** - * Sets the proper test suite to use and loads the test file in it. - * this method gets called as a callback from the parent class - * - * @return void - */ - protected function handleCustomTestSuite() { - $manager = new TestManager($this->_params); - - if (!empty($this->_params['case'])) { - $this->arguments['test'] = $manager->getTestSuite(); - $this->arguments['test']->setFixtureManager($manager->getFixtureManager()); - $manager->loadCase($this->_params['case'] . '.test.php', $this->arguments['test']); - } - } -} \ No newline at end of file diff --git a/cake/tests/test_app/models/datasources/test/test_local_driver.php b/cake/tests/test_app/models/datasources/test/test_local_driver.php deleted file mode 100644 index e483cb303..000000000 --- a/cake/tests/test_app/models/datasources/test/test_local_driver.php +++ /dev/null @@ -1,5 +0,0 @@ -Sweet, "Test App" got Baked by CakePHP! -

-'; - echo __('Your tmp directory is writable.'); - echo ''; - else: - echo ''; - echo __('Your tmp directory is NOT writable.'); - echo ''; - endif; -?> -

-

-'; - echo __('The %s is being used for caching. To change the config edit APP/config/core.php ', ''. $settings['engine'] . 'Engine'); - echo ''; - else: - echo ''; - echo __('Your cache is NOT working. Please check the settings in APP/config/core.php'); - echo ''; - endif; -?> -

-

-'; - echo __('Your database configuration file is present.'); - $filePresent = true; - echo ''; - else: - echo ''; - echo __('Your database configuration file is NOT present.'); - echo '
'; - echo __('Rename config/database.php.default to config/database.php'); - echo '
'; - endif; -?> -

- -

-'; - echo __('Cake is able to connect to the database.'); - echo ''; - else: - echo ''; - echo __('Cake is NOT able to connect to the database.'); - echo ''; - endif; -?> -

- -

-

-', APP . 'views' . DS . 'layouts' . DS . 'default.ctp.
', APP . 'webroot' . DS . 'css'); -?> -

\ No newline at end of file diff --git a/cake/tests/test_app/views/posts/test_nocache_tags.ctp b/cake/tests/test_app/views/posts/test_nocache_tags.ctp deleted file mode 100644 index 745ef4ad9..000000000 --- a/cake/tests/test_app/views/posts/test_nocache_tags.ctp +++ /dev/null @@ -1,143 +0,0 @@ - -

- - - - - -

-

- - ' . $settings['engine']; - echo __(' is being used to cache, to change this edit config/core.php '); - echo '

'; - - echo 'Settings: '; - - else: - echo __('NOT working.'); - echo '
'; - if (is_writable(TMP)): - echo __('Edit: config/core.php to insure you have the newset version of this file and the variable $cakeCache set properly'); - endif; - endif; - ?> - -

-

- - '; - echo __('Rename config/database.php.default to config/database.php'); - endif; - ?> - -

-getDataSource('default'); -?> -

- - isConnected()): - __(' is able to '); - else: - __(' is NOT able to '); - endif; - __('connect to the database.'); - ?> - -

- -

- -

-

-
-
-
- -

-

-

-
-
- -

-

-

- -

-

- -

- \ No newline at end of file diff --git a/cake/tests/test_app/views/scaffolds/empty b/cake/tests/test_app/views/scaffolds/empty deleted file mode 100644 index e69de29bb..000000000 diff --git a/cake/libs/cache.php b/lib/Cake/Cache/Cache.php similarity index 86% rename from cake/libs/cache.php rename to lib/Cake/Cache/Cache.php index 66f255b34..2ffdeb007 100644 --- a/cake/libs/cache.php +++ b/lib/Cake/Cache/Cache.php @@ -18,14 +18,16 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Inflector', 'Utility'); + /** * Cache provides a consistent interface to Caching in your application. It allows you - * to use several different Cache engines, without coupling your application to a specific - * implementation. It also allows you to change out cache storage or configuration without effecting + * to use several different Cache engines, without coupling your application to a specific + * implementation. It also allows you to change out cache storage or configuration without effecting * the rest of your application. * - * You can configure Cache engines in your application's `bootstrap.php` file. A sample configuration would - * be + * You can configure Cache engines in your application's `bootstrap.php` file. A sample configuration would + * be * * {{{ * Cache::config('shared', array( @@ -35,7 +37,7 @@ * }}} * * This would configure an APC cache engine to the 'shared' alias. You could then read and write - * to that cache alias by using it for the `$config` parameter in the various Cache methods. In + * to that cache alias by using it for the `$config` parameter in the various Cache methods. In * general all Cache operations are supported by all cache engines. However, Cache::increment() and * Cache::decrement() are not supported by File caching. * @@ -71,14 +73,39 @@ class Cache { * both create new configurations, return the settings for already configured * configurations. * - * To create a new configuration: + * To create a new configuration, or to modify an existing configuration permanently: * * `Cache::config('my_config', array('engine' => 'File', 'path' => TMP));` * - * To get the settings for a configuration, and set it as the currently selected configuration + * If you need to modify a configuration temporarily, use Cache::set(). + * To get the settings for a configuration: * * `Cache::config('default');` * + * There are 4 built-in caching engines: + * + * - `FileEngine` - Uses simple files to store content. Poor performance, but good for + * storing large objects, or things that are not IO sensitive. + * - `ApcEngine` - Uses the APC object cache, one of the fastest caching engines. + * - `MemcacheEngine` - Uses the PECL::Memcache extension and Memcached for storage. + * Fast reads/writes, and benefits from memcache being distributed. + * - `XcacheEngine` - Uses the Xcache extension, an alternative to APC. + * + * The following keys are used in core cache engines: + * + * - `duration` Specify how long items in this cache configuration last. + * - `prefix` Prefix appended to all entries. Good for when you need to share a keyspace + * with either another cache config or annother application. + * - `probability` Probability of hitting a cache gc cleanup. Setting to 0 will disable + * cache::gc from ever being called automatically. + * - `servers' Used by memcache. Give the address of the memcached servers to use. + * - `compress` Used by memcache. Enables memcache's compressed format. + * - `serialize` Used by FileCache. Should cache objects be serialized first. + * - `path` Used by FileCache. Path to where cachefiles should be saved. + * - `lock` Used by FileCache. Should files be locked before writing to them? + * - `user` Used by Xcache. Username for XCache + * - `password` Used by Xcache. Password for XCache + * * @see app/config/core.php for configuration settings * @param string $name Name of the configuration * @param array $settings Optional associative array of settings passed to the engine @@ -123,18 +150,19 @@ class Cache { protected static function _buildEngine($name) { $config = self::$_config[$name]; - list($plugin, $class) = pluginSplit($config['engine']); + list($plugin, $class) = pluginSplit($config['engine'], true); $cacheClass = $class . 'Engine'; - if (!class_exists($cacheClass) && self::_loadEngine($class, $plugin) === false) { + App::uses($cacheClass, $plugin . 'Cache/Engine'); + if (!class_exists($cacheClass)) { return false; } $cacheClass = $class . 'Engine'; if (!is_subclass_of($cacheClass, 'CacheEngine')) { - throw new CacheException(__('Cache engines must use CacheEngine as a base class.')); + throw new CacheException(__d('cake_dev', 'Cache engines must use CacheEngine as a base class.')); } self::$_engines[$name] = new $cacheClass(); if (self::$_engines[$name]->init($config)) { - if (time() % self::$_engines[$name]->settings['probability'] === 0) { + if (self::$_engines[$name]->settings['probability'] && time() % self::$_engines[$name]->settings['probability'] === 0) { self::$_engines[$name]->gc(); } return true; @@ -167,35 +195,15 @@ class Cache { return true; } -/** - * Tries to find and include a file for a cache engine and returns object instance - * - * @param $name Name of the engine (without 'Engine') - * @return mixed $engine object or null - */ - protected static function _loadEngine($name, $plugin = null) { - if ($plugin) { - return App::import('Lib', $plugin . '.cache' . DS . $name, false); - } else { - $core = App::core(); - $path = $core['libs'][0] . 'cache' . DS . strtolower($name) . '.php'; - if (file_exists($path)) { - require $path; - return true; - } - return App::import('Lib', 'cache' . DS . $name, false); - } - } - /** * Temporarily change the settings on a cache config. The settings will persist for the next write - * operation (write, decrement, increment, clear). Any reads that are done before the write, will - * use the modified settings. If `$settings` is empty, the settings will be reset to the + * operation (write, decrement, increment, clear). Any reads that are done before the write, will + * use the modified settings. If `$settings` is empty, the settings will be reset to the * original configuration. * * Can be called with 2 or 3 parameters. To set multiple values at once. * - * `Cache::set(array('duration' => '+30 minutes'), 'my_config');` + * `Cache::set(array('duration' => '+30 minutes'), 'my_config');` * * Or to set one value. * @@ -290,7 +298,7 @@ class Cache { self::set(null, $config); if ($success === false && $value !== '') { trigger_error( - __("%s cache was unable to write '%s' to cache", $config, $key), + __d('cake_dev', "%s cache was unable to write '%s' to cache", $config, $key), E_USER_WARNING ); } @@ -364,7 +372,7 @@ class Cache { * * @param string $key Identifier for the data * @param integer $offset How much to substract - * @param string $config Optional string configuration name. Defaults to 'default' + * @param string $config Optional string configuration name. Defaults to 'default' * @return mixed new value, or false if the data doesn't exist, is not integer, * or if there was an error fetching it */ diff --git a/cake/libs/cache/apc.php b/lib/Cake/Cache/Engine/ApcEngine.php similarity index 100% rename from cake/libs/cache/apc.php rename to lib/Cake/Cache/Engine/ApcEngine.php diff --git a/cake/libs/cache/file.php b/lib/Cake/Cache/Engine/FileEngine.php similarity index 92% rename from cake/libs/cache/file.php rename to lib/Cake/Cache/Engine/FileEngine.php index 46ff892a3..fd6286b9a 100644 --- a/cake/libs/cache/file.php +++ b/lib/Cake/Cache/Engine/FileEngine.php @@ -1,7 +1,10 @@ CACHE * - prefix = string prefix for filename, default => cake_ * - lock = enable file locking on write, default => false @@ -161,7 +162,7 @@ class FileEngine extends CacheEngine { if ($cachetime !== false && ($cachetime < $time || ($time + $this->settings['duration']) < $cachetime)) { return false; } - + $data = ''; $this->_File->next(); while ($this->_File->valid()) { @@ -250,7 +251,7 @@ class FileEngine extends CacheEngine { * @throws CacheException */ public function decrement($key, $offset = 1) { - throw new CacheException(__('Files cannot be atomically decremented.')); + throw new CacheException(__d('cake_dev', 'Files cannot be atomically decremented.')); } /** @@ -260,7 +261,7 @@ class FileEngine extends CacheEngine { * @throws CacheException */ public function increment($key, $offset = 1) { - throw new CacheException(__('Files cannot be atomically incremented.')); + throw new CacheException(__d('cake_dev', 'Files cannot be atomically incremented.')); } /** @@ -296,9 +297,9 @@ class FileEngine extends CacheEngine { $dir = new SplFileInfo($this->settings['path']); if ($this->_init && !($dir->isDir() && $dir->isWritable())) { $this->_init = false; - trigger_error(__('%s is not writable', $this->settings['path']), E_USER_WARNING); + trigger_error(__d('cake_dev', '%s is not writable', $this->settings['path']), E_USER_WARNING); return false; } return true; } -} +} \ No newline at end of file diff --git a/cake/libs/cache/memcache.php b/lib/Cake/Cache/Engine/MemcacheEngine.php similarity index 83% rename from cake/libs/cache/memcache.php rename to lib/Cake/Cache/Engine/MemcacheEngine.php index 79d98376e..7b9aa5523 100644 --- a/cake/libs/cache/memcache.php +++ b/lib/Cake/Cache/Engine/MemcacheEngine.php @@ -19,7 +19,7 @@ */ /** - * Memcache storage engine for cache. Memcache has some limitations in the amount of + * Memcache storage engine for cache. Memcache has some limitations in the amount of * control you have over expire times far in the future. See MemcacheEngine::write() for * more information. * @@ -33,7 +33,7 @@ class MemcacheEngine extends CacheEngine { * @var Memcache * @access private */ - private $__Memcache = null; + protected $_Memcache = null; /** * Settings @@ -61,8 +61,8 @@ class MemcacheEngine extends CacheEngine { return false; } parent::init(array_merge(array( - 'engine'=> 'Memcache', - 'prefix' => Inflector::slug(APP_DIR) . '_', + 'engine'=> 'Memcache', + 'prefix' => Inflector::slug(APP_DIR) . '_', 'servers' => array('127.0.0.1'), 'compress'=> false ), $settings) @@ -74,12 +74,12 @@ class MemcacheEngine extends CacheEngine { if (!is_array($this->settings['servers'])) { $this->settings['servers'] = array($this->settings['servers']); } - if (!isset($this->__Memcache)) { + if (!isset($this->_Memcache)) { $return = false; - $this->__Memcache = new Memcache(); + $this->_Memcache = new Memcache(); foreach ($this->settings['servers'] as $server) { list($host, $port) = $this->_parseServerString($server); - if ($this->__Memcache->addServer($host, $port)) { + if ($this->_Memcache->addServer($host, $port)) { $return = true; } } @@ -115,9 +115,8 @@ class MemcacheEngine extends CacheEngine { /** * Write data for key into cache. When using memcache as your cache engine - * remember that the Memcache pecl extension does not support cache expiry times greater - * than 30 days in the future. If you wish to create cache entries that do not expire, set the duration - * to `0` in your cache configuration. + * remember that the Memcache pecl extension does not support cache expiry times greater + * than 30 days in the future. Any duration greater than 30 days will be treated as never expiring. * * @param string $key Identifier for the data * @param mixed $value Data to be cached @@ -126,7 +125,10 @@ class MemcacheEngine extends CacheEngine { * @see http://php.net/manual/en/memcache.set.php */ public function write($key, $value, $duration) { - return $this->__Memcache->set($key, $value, $this->settings['compress'], $duration); + if ($duration > 30 * DAY) { + $duration = 0; + } + return $this->_Memcache->set($key, $value, $this->settings['compress'], $duration); } /** @@ -136,7 +138,7 @@ class MemcacheEngine extends CacheEngine { * @return mixed The cached data, or false if the data doesn't exist, has expired, or if there was an error fetching it */ public function read($key) { - return $this->__Memcache->get($key); + return $this->_Memcache->get($key); } /** @@ -151,10 +153,10 @@ class MemcacheEngine extends CacheEngine { public function increment($key, $offset = 1) { if ($this->settings['compress']) { throw new CacheException( - __('Method increment() not implemented for compressed cache in %s', __CLASS__) + __d('cake_dev', 'Method increment() not implemented for compressed cache in %s', __CLASS__) ); } - return $this->__Memcache->increment($key, $offset); + return $this->_Memcache->increment($key, $offset); } /** @@ -169,10 +171,10 @@ class MemcacheEngine extends CacheEngine { public function decrement($key, $offset = 1) { if ($this->settings['compress']) { throw new CacheException( - __('Method decrement() not implemented for compressed cache in %s', __CLASS__) + __d('cake_dev', 'Method decrement() not implemented for compressed cache in %s', __CLASS__) ); } - return $this->__Memcache->decrement($key, $offset); + return $this->_Memcache->decrement($key, $offset); } /** @@ -182,7 +184,7 @@ class MemcacheEngine extends CacheEngine { * @return boolean True if the value was succesfully deleted, false if it didn't exist or couldn't be removed */ public function delete($key) { - return $this->__Memcache->delete($key); + return $this->_Memcache->delete($key); } /** @@ -191,7 +193,7 @@ class MemcacheEngine extends CacheEngine { * @return boolean True if the cache was succesfully cleared, false otherwise */ public function clear($check) { - return $this->__Memcache->flush(); + return $this->_Memcache->flush(); } /** @@ -202,12 +204,12 @@ class MemcacheEngine extends CacheEngine { * @return boolean True if memcache server was connected */ public function connect($host, $port = 11211) { - if ($this->__Memcache->getServerStatus($host, $port) === 0) { - if ($this->__Memcache->connect($host, $port)) { + if ($this->_Memcache->getServerStatus($host, $port) === 0) { + if ($this->_Memcache->connect($host, $port)) { return true; } return false; } return true; } -} +} \ No newline at end of file diff --git a/cake/libs/cache/xcache.php b/lib/Cake/Cache/Engine/XcacheEngine.php similarity index 100% rename from cake/libs/cache/xcache.php rename to lib/Cake/Cache/Engine/XcacheEngine.php diff --git a/cake/libs/config/ini_reader.php b/lib/Cake/Configure/IniReader.php similarity index 86% rename from cake/libs/config/ini_reader.php rename to lib/Cake/Configure/IniReader.php index 915bf9498..d4eb8172d 100644 --- a/cake/libs/config/ini_reader.php +++ b/lib/Cake/Configure/IniReader.php @@ -27,7 +27,7 @@ * you to create nested arrays structures in an ini config file. For example: * * `db.password = secret` would turn into `array('db' => array('password' => 'secret'))` - * + * * You can nest properties as deeply as needed using .'s. IniReader also manipulates * how the special ini values of 'yes', 'no', 'on', 'off', 'null' are handled. * These values will be converted to their boolean equivalents. @@ -71,13 +71,24 @@ class IniReader implements ConfigReaderInterface { */ public function read($file) { $filename = $this->_path . $file; + if (!file_exists($filename)) { + $filename .= '.ini'; + if (!file_exists($filename)) { + throw new ConfigureException(__d('cake_dev', 'Could not load configuration files: %s or %s', substr($filename, 0, -4), $filename)); + } + } $contents = parse_ini_file($filename, true); if (!empty($this->_section) && isset($contents[$this->_section])) { $values = $this->_parseNestedValues($contents[$this->_section]); } else { $values = array(); foreach ($contents as $section => $attribs) { - $values[$section] = $this->_parseNestedValues($attribs); + if (is_array($attribs)) { + $values[$section] = $this->_parseNestedValues($attribs); + } else { + $parse = $this->_parseNestedValues(array($attribs)); + $values[$section] = array_shift($parse); + } } } return $values; diff --git a/cake/libs/config/php_reader.php b/lib/Cake/Configure/PhpReader.php similarity index 78% rename from cake/libs/config/php_reader.php rename to lib/Cake/Configure/PhpReader.php index c122f0808..54f99dae1 100644 --- a/cake/libs/config/php_reader.php +++ b/lib/Cake/Configure/PhpReader.php @@ -18,7 +18,7 @@ */ /** - * PHP Reader allows Configure to load configuration values from + * PHP Reader allows Configure to load configuration values from * files containing simple PHP arrays. * * @package cake.libs.config @@ -55,22 +55,28 @@ class PhpReader implements ConfigReaderInterface { */ public function read($key) { if (strpos($key, '..') !== false) { - throw new ConfigureException(__('Cannot load configuration files with ../ in them.')); + throw new ConfigureException(__d('cake_dev', 'Cannot load configuration files with ../ in them.')); + } + if (substr($key, -4) === '.php') { + $key = substr($key, 0, -4); } list($plugin, $key) = pluginSplit($key); - + if ($plugin) { - $file = App::pluginPath($plugin) . 'config' . DS . $key . '.php'; + $file = App::pluginPath($plugin) . 'config' . DS . $key; } else { - $file = $this->_path . $key . '.php'; + $file = $this->_path . $key; } if (!file_exists($file)) { - throw new ConfigureException(__('Could not load configuration file: ') . $file); + $file .= '.php'; + if (!file_exists($file)) { + throw new ConfigureException(__d('cake_dev', 'Could not load configuration files: %s or %s', substr($file, 0, -4), $file)); + } } include $file; if (!isset($config)) { throw new ConfigureException( - sprintf(__('No variable $config found in %s.php'), $file) + sprintf(__d('cake_dev', 'No variable $config found in %s.php'), $file) ); } return $config; diff --git a/cake/console/shells/app_shell.php b/lib/Cake/Console/AppShell.php similarity index 93% rename from cake/console/shells/app_shell.php rename to lib/Cake/Console/AppShell.php index a624a31ad..ca3abc8ed 100644 --- a/cake/console/shells/app_shell.php +++ b/lib/Cake/Console/AppShell.php @@ -19,7 +19,7 @@ /** * This is a placeholder class. - * Create the same file in app/console/shells/app_shell.php + * Create the same file in app/console/shells/AppShell.php * * Add your application-wide methods in the class below, your shells * will inherit them. diff --git a/cake/console/shells/acl.php b/lib/Cake/Console/Command/AclShell.php similarity index 63% rename from cake/console/shells/acl.php rename to lib/Cake/Console/Command/AclShell.php index b4d458ba7..29312eaef 100644 --- a/cake/console/shells/acl.php +++ b/lib/Cake/Console/Command/AclShell.php @@ -16,8 +16,8 @@ * @since CakePHP(tm) v 1.2.0.5012 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Component', 'Acl'); -App::import('Model', 'DbAcl'); +App::uses('AclComponent', 'Controller/Component'); +App::uses('DbAcl', 'Model'); /** * Shell for ACL management. This console is known to have issues with zend.ze1_compatibility_mode @@ -71,12 +71,12 @@ class AclShell extends Shell { if (!in_array(Configure::read('Acl.classname'), array('DbAcl', 'DB_ACL'))) { $out = "--------------------------------------------------\n"; - $out .= __('Error: Your current Cake configuration is set to') . "\n"; - $out .= __('an ACL implementation other than DB. Please change') . "\n"; - $out .= __('your core config to reflect your decision to use') . "\n"; - $out .= __('DbAcl before attempting to use this script') . ".\n"; + $out .= __d('cake_console', 'Error: Your current Cake configuration is set to') . "\n"; + $out .= __d('cake_console', 'an ACL implementation other than DB. Please change') . "\n"; + $out .= __d('cake_console', 'your core config to reflect your decision to use') . "\n"; + $out .= __d('cake_console', 'DbAcl before attempting to use this script') . ".\n"; $out .= "--------------------------------------------------\n"; - $out .= __('Current ACL Classname: %s', Configure::read('Acl.classname')) . "\n"; + $out .= __d('cake_console', 'Current ACL Classname: %s', Configure::read('Acl.classname')) . "\n"; $out .= "--------------------------------------------------\n"; $this->err($out); $this->_stop(); @@ -84,7 +84,7 @@ class AclShell extends Shell { if ($this->command) { if (!config('database')) { - $this->out(__('Your database configuration was not found. Take a moment to create one.'), true); + $this->out(__d('cake_console', 'Your database configuration was not found. Take a moment to create one.'), true); $this->args = null; return $this->DbConfig->execute(); } @@ -127,15 +127,15 @@ class AclShell extends Shell { if (is_string($data) && $data != '/') { $data = array('alias' => $data); } elseif (is_string($data)) { - $this->error(__('/ can not be used as an alias!') . __(" / is the root, please supply a sub alias")); + $this->error(__d('cake_console', '/ can not be used as an alias!') . __d('cake_console', " / is the root, please supply a sub alias")); } $data['parent_id'] = $parent; $this->Acl->{$class}->create(); if ($this->Acl->{$class}->save($data)) { - $this->out(__("New %s '%s' created.", $class, $this->args[2]), 2); + $this->out(__d('cake_console', "New %s '%s' created.", $class, $this->args[2]), 2); } else { - $this->err(__("There was a problem creating a new %s '%s'.", $class, $this->args[2])); + $this->err(__d('cake_console', "There was a problem creating a new %s '%s'.", $class, $this->args[2])); } } @@ -150,9 +150,9 @@ class AclShell extends Shell { $nodeId = $this->_getNodeId($class, $identifier); if (!$this->Acl->{$class}->delete($nodeId)) { - $this->error(__('Node Not Deleted') . __('There was an error deleting the %s. Check that the node exists', $class) . ".\n"); + $this->error(__d('cake_console', 'Node Not Deleted') . __d('cake_console', 'There was an error deleting the %s. Check that the node exists', $class) . ".\n"); } - $this->out(__('%s deleted.', $class), 2); + $this->out(__d('cake_console', '%s deleted.', $class), 2); } /** @@ -172,9 +172,9 @@ class AclShell extends Shell { ); $this->Acl->{$class}->create(); if (!$this->Acl->{$class}->save($data)) { - $this->out(__('Error in setting new parent. Please make sure the parent node exists, and is not a descendant of the node specified.'), true); + $this->out(__d('cake_console', 'Error in setting new parent. Please make sure the parent node exists, and is not a descendant of the node specified.'), true); } else { - $this->out(__('Node parent set to %s', $this->args[2]) . "\n", true); + $this->out(__d('cake_console', 'Node parent set to %s', $this->args[2]) . "\n", true); } } @@ -191,11 +191,11 @@ class AclShell extends Shell { if (empty($nodes)) { $this->error( - __("Supplied Node '%s' not found", $this->args[1]), - __('No tree returned.') + __d('cake_console', "Supplied Node '%s' not found", $this->args[1]), + __d('cake_console', 'No tree returned.') ); } - $this->out(__('Path:')); + $this->out(__d('cake_console', 'Path:')); $this->hr(); for ($i = 0; $i < count($nodes); $i++) { $this->_outputNode($class, $nodes[$i], $i); @@ -228,9 +228,9 @@ class AclShell extends Shell { extract($this->__getParams()); if ($this->Acl->check($aro, $aco, $action)) { - $this->out(__('%s is allowed.', $aroName), true); + $this->out(__d('cake_console', '%s is allowed.', $aroName), true); } else { - $this->out(__('%s is not allowed.', $aroName), true); + $this->out(__d('cake_console', '%s is not allowed.', $aroName), true); } } @@ -242,9 +242,9 @@ class AclShell extends Shell { extract($this->__getParams()); if ($this->Acl->allow($aro, $aco, $action)) { - $this->out(__('Permission granted.'), true); + $this->out(__d('cake_console', 'Permission granted.'), true); } else { - $this->out(__('Permission was not granted.'), true); + $this->out(__d('cake_console', 'Permission was not granted.'), true); } } @@ -256,9 +256,9 @@ class AclShell extends Shell { extract($this->__getParams()); if ($this->Acl->deny($aro, $aco, $action)) { - $this->out(__('Permission denied.'), true); + $this->out(__d('cake_console', 'Permission denied.'), true); } else { - $this->out(__('Permission was not denied.'), true); + $this->out(__d('cake_console', 'Permission was not denied.'), true); } } @@ -270,9 +270,9 @@ class AclShell extends Shell { extract($this->__getParams()); if ($this->Acl->inherit($aro, $aco, $action)) { - $this->out(__('Permission inherited.'), true); + $this->out(__d('cake_console', 'Permission inherited.'), true); } else { - $this->out(__('Permission was not inherited.'), true); + $this->out(__d('cake_console', 'Permission was not inherited.'), true); } } @@ -303,9 +303,9 @@ class AclShell extends Shell { if (empty($nodes)) { if (isset($this->args[1])) { - $this->error(__('%s not found', $this->args[1]), __('No tree returned.')); + $this->error(__d('cake_console', '%s not found', $this->args[1]), __d('cake_console', 'No tree returned.')); } elseif (isset($this->args[0])) { - $this->error(__('%s not found', $this->args[0]), __('No tree returned.')); + $this->error(__d('cake_console', '%s not found', $this->args[0]), __d('cake_console', 'No tree returned.')); } } $this->out($class . " tree:"); @@ -354,140 +354,140 @@ class AclShell extends Shell { $type = array( 'choices' => array('aro', 'aco'), 'required' => true, - 'help' => __('Type of node to create.') + 'help' => __d('cake_console', 'Type of node to create.') ); $parser->description('A console tool for managing the DbAcl') ->addSubcommand('create', array( - 'help' => __('Create a new ACL node'), + 'help' => __d('cake_console', 'Create a new ACL node'), 'parser' => array( - 'description' => __('Creates a new ACL object under the parent'), + 'description' => __d('cake_console', 'Creates a new ACL object under the parent'), 'arguments' => array( 'type' => $type, 'parent' => array( - 'help' => __('The node selector for the parent.'), + 'help' => __d('cake_console', 'The node selector for the parent.'), 'required' => true ), 'alias' => array( - 'help' => __('The alias to use for the newly created node.'), + 'help' => __d('cake_console', 'The alias to use for the newly created node.'), 'required' => true ) ) ) ))->addSubcommand('delete', array( - 'help' => __('Deletes the ACL object with the given reference'), + 'help' => __d('cake_console', 'Deletes the ACL object with the given reference'), 'parser' => array( - 'description' => __('Delete an ACL node.'), + 'description' => __d('cake_console', 'Delete an ACL node.'), 'arguments' => array( 'type' => $type, 'node' => array( - 'help' => __('The node identifier to delete.'), + 'help' => __d('cake_console', 'The node identifier to delete.'), 'required' => true, ) ) ) ))->addSubcommand('setparent', array( - 'help' => __('Moves the ACL node under a new parent.'), + 'help' => __d('cake_console', 'Moves the ACL node under a new parent.'), 'parser' => array( - 'description' => __('Moves the ACL object specified by beneath '), + 'description' => __d('cake_console', 'Moves the ACL object specified by beneath '), 'arguments' => array( 'type' => $type, 'node' => array( - 'help' => __('The node to move'), + 'help' => __d('cake_console', 'The node to move'), 'required' => true, ), 'parent' => array( - 'help' => __('The new parent for .'), + 'help' => __d('cake_console', 'The new parent for .'), 'required' => true ) ) ) ))->addSubcommand('getpath', array( - 'help' => __('Print out the path to an ACL node.'), + 'help' => __d('cake_console', 'Print out the path to an ACL node.'), 'parser' => array( 'description' => array( - __("Returns the path to the ACL object specified by ."), - __("This command is useful in determining the inhertiance of permissions"), - __("for a certain object in the tree.") + __d('cake_console', "Returns the path to the ACL object specified by ."), + __d('cake_console', "This command is useful in determining the inhertiance of permissions"), + __d('cake_console', "for a certain object in the tree.") ), 'arguments' => array( 'type' => $type, 'node' => array( - 'help' => __('The node to get the path of'), + 'help' => __d('cake_console', 'The node to get the path of'), 'required' => true, ) ) ) ))->addSubcommand('check', array( - 'help' => __('Check the permissions between an ACO and ARO.'), + 'help' => __d('cake_console', 'Check the permissions between an ACO and ARO.'), 'parser' => array( 'description' => array( - __("Use this command to grant ACL permissions. Once executed, the ARO "), - __("specified (and its children, if any) will have ALLOW access to the"), - __("specified ACO action (and the ACO's children, if any).") + __d('cake_console', "Use this command to grant ACL permissions. Once executed, the ARO "), + __d('cake_console', "specified (and its children, if any) will have ALLOW access to the"), + __d('cake_console', "specified ACO action (and the ACO's children, if any).") ), 'arguments' => array( - 'aro' => array('help' => __('ARO to check.'), 'required' => true), - 'aco' => array('help' => __('ACO to check.'), 'required' => true), - 'action' => array('help' => __('Action to check'), 'default' => 'all') + 'aro' => array('help' => __d('cake_console', 'ARO to check.'), 'required' => true), + 'aco' => array('help' => __d('cake_console', 'ACO to check.'), 'required' => true), + 'action' => array('help' => __d('cake_console', 'Action to check'), 'default' => 'all') ) ) ))->addSubcommand('grant', array( - 'help' => __('Grant an ARO permissions to an ACO.'), + 'help' => __d('cake_console', 'Grant an ARO permissions to an ACO.'), 'parser' => array( 'description' => array( - __("Use this command to grant ACL permissions. Once executed, the ARO"), - __("specified (and its children, if any) will have ALLOW access to the"), - __("specified ACO action (and the ACO's children, if any).") + __d('cake_console', "Use this command to grant ACL permissions. Once executed, the ARO"), + __d('cake_console', "specified (and its children, if any) will have ALLOW access to the"), + __d('cake_console', "specified ACO action (and the ACO's children, if any).") ), 'arguments' => array( - 'aro' => array('help' => __('ARO to grant permission to.'), 'required' => true), - 'aco' => array('help' => __('ACO to grant access to.'), 'required' => true), - 'action' => array('help' => __('Action to grant'), 'default' => 'all') + 'aro' => array('help' => __d('cake_console', 'ARO to grant permission to.'), 'required' => true), + 'aco' => array('help' => __d('cake_console', 'ACO to grant access to.'), 'required' => true), + 'action' => array('help' => __d('cake_console', 'Action to grant'), 'default' => 'all') ) ) ))->addSubcommand('deny', array( - 'help' => __('Deny an ARO permissions to an ACO.'), + 'help' => __d('cake_console', 'Deny an ARO permissions to an ACO.'), 'parser' => array( 'description' => array( - __("Use this command to deny ACL permissions. Once executed, the ARO"), - __("specified (and its children, if any) will have DENY access to the"), - __("specified ACO action (and the ACO's children, if any).") + __d('cake_console', "Use this command to deny ACL permissions. Once executed, the ARO"), + __d('cake_console', "specified (and its children, if any) will have DENY access to the"), + __d('cake_console', "specified ACO action (and the ACO's children, if any).") ), 'arguments' => array( - 'aro' => array('help' => __('ARO to deny.'), 'required' => true), - 'aco' => array('help' => __('ACO to deny.'), 'required' => true), - 'action' => array('help' => __('Action to deny'), 'default' => 'all') + 'aro' => array('help' => __d('cake_console', 'ARO to deny.'), 'required' => true), + 'aco' => array('help' => __d('cake_console', 'ACO to deny.'), 'required' => true), + 'action' => array('help' => __d('cake_console', 'Action to deny'), 'default' => 'all') ) ) ))->addSubcommand('inherit', array( - 'help' => __('Inherit an ARO\'s parent permissions.'), + 'help' => __d('cake_console', 'Inherit an ARO\'s parent permissions.'), 'parser' => array( 'description' => array( - __("Use this command to force a child ARO object to inherit its"), - __("permissions settings from its parent.") + __d('cake_console', "Use this command to force a child ARO object to inherit its"), + __d('cake_console', "permissions settings from its parent.") ), 'arguments' => array( - 'aro' => array('help' => __('ARO to have permisssions inherit.'), 'required' => true), - 'aco' => array('help' => __('ACO to inherit permissions on.'), 'required' => true), - 'action' => array('help' => __('Action to inherit'), 'default' => 'all') + 'aro' => array('help' => __d('cake_console', 'ARO to have permisssions inherit.'), 'required' => true), + 'aco' => array('help' => __d('cake_console', 'ACO to inherit permissions on.'), 'required' => true), + 'action' => array('help' => __d('cake_console', 'Action to inherit'), 'default' => 'all') ) ) ))->addSubcommand('view', array( - 'help' => __('View a tree or a single node\'s subtree.'), + 'help' => __d('cake_console', 'View a tree or a single node\'s subtree.'), 'parser' => array( 'description' => array( - __("The view command will return the ARO or ACO tree."), - __("The optional node parameter allows you to return"), - __("only a portion of the requested tree.") + __d('cake_console', "The view command will return the ARO or ACO tree."), + __d('cake_console', "The optional node parameter allows you to return"), + __d('cake_console', "only a portion of the requested tree.") ), 'arguments' => array( 'type' => $type, - 'node' => array('help' => __('The optional node to view the subtree of.')) + 'node' => array('help' => __d('cake_console', 'The optional node to view the subtree of.')) ) ) ))->addSubcommand('initdb', array( - 'help' => __('Initialize the DbAcl tables. Uses this command : cake schema run create DbAcl') + 'help' => __d('cake_console', 'Initialize the DbAcl tables. Uses this command : cake schema run create DbAcl') ))->epilog( array( 'Node and parent arguments can be in one of the following formats:', @@ -520,7 +520,7 @@ class AclShell extends Shell { $conditions = array($class . '.' . $key => $this->args[1]); $possibility = $this->Acl->{$class}->find('all', compact('conditions')); if (empty($possibility)) { - $this->error(__('%s not found', $this->args[1]), __('No tree returned.')); + $this->error(__d('cake_console', '%s not found', $this->args[1]), __d('cake_console', 'No tree returned.')); } return $possibility; } @@ -556,7 +556,7 @@ class AclShell extends Shell { if (is_array($identifier)) { $identifier = var_export($identifier, true); } - $this->error(__('Could not find node using reference "%s"', $identifier)); + $this->error(__d('cake_console', 'Could not find node using reference "%s"', $identifier)); } return Set::extract($node, "0.{$class}.id"); } diff --git a/cake/console/shells/api.php b/lib/Cake/Console/Command/ApiShell.php similarity index 83% rename from cake/console/shells/api.php rename to lib/Cake/Console/Command/ApiShell.php index 05cf326b8..d37b6acd0 100644 --- a/cake/console/shells/api.php +++ b/lib/Cake/Console/Command/ApiShell.php @@ -18,7 +18,7 @@ * @since CakePHP(tm) v 1.2.0.5012 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'File'); +App::uses('File', 'Utility'); /** * API shell to show method signatures of CakePHP core classes. @@ -41,13 +41,13 @@ class ApiShell extends Shell { */ public function initialize() { $this->paths = array_merge($this->paths, array( - 'behavior' => LIBS . 'model' . DS . 'behaviors' . DS, - 'cache' => LIBS . 'cache' . DS, - 'controller' => LIBS . 'controller' . DS, - 'component' => LIBS . 'controller' . DS . 'components' . DS, - 'helper' => LIBS . 'view' . DS . 'helpers' . DS, - 'model' => LIBS . 'model' . DS, - 'view' => LIBS . 'view' . DS, + 'behavior' => LIBS . 'Model' . DS . 'Behavior' . DS, + 'cache' => LIBS . 'Cache' . DS, + 'controller' => LIBS . 'Controller' . DS, + 'component' => LIBS . 'Controller' . DS . 'Component' . DS, + 'helper' => LIBS . 'View' . DS . 'Helper' . DS, + 'model' => LIBS . 'Model' . DS, + 'view' => LIBS . 'View' . DS, 'core' => LIBS )); } @@ -74,7 +74,7 @@ class ApiShell extends Shell { $class = Inflector::camelize($type); } elseif (count($this->args) > 1) { $file = Inflector::underscore($this->args[1]); - $class = Inflector::camelize($file); + $class = Inflector::camelize($this->args[1]); } $objects = App::objects('class', $path); if (in_array($class, $objects)) { @@ -85,15 +85,15 @@ class ApiShell extends Shell { } } else { - $this->error(__('%s not found', $class)); + $this->error(__d('cake_console', '%s not found', $class)); } - $parsed = $this->__parseClass($path . $file .'.php', $class); + $parsed = $this->__parseClass($path . $class .'.php', $class); if (!empty($parsed)) { if (isset($this->params['method'])) { if (!isset($parsed[$this->params['method']])) { - $this->err(__('%s::%s() could not be found', $class, $this->params['method'])); + $this->err(__d('cake_console', '%s::%s() could not be found', $class, $this->params['method'])); $this->_stop(); } $method = $parsed[$this->params['method']]; @@ -110,9 +110,9 @@ class ApiShell extends Shell { $this->out($list); $methods = array_keys($parsed); - while ($number = strtolower($this->in(__('Select a number to see the more information about a specific method. q to quit. l to list.'), null, 'q'))) { + while ($number = strtolower($this->in(__d('cake_console', 'Select a number to see the more information about a specific method. q to quit. l to list.'), null, 'q'))) { if ($number === 'q') { - $this->out(__('Done')); + $this->out(__d('cake_console', 'Done')); return $this->_stop(); } @@ -145,8 +145,8 @@ class ApiShell extends Shell { 'help' => 'A CakePHP core class name (e.g: Component, HtmlHelper).' ))->addOption('method', array( 'short' => 'm', - 'help' => __('The specific method you want help on.') - ))->description(__('Lookup doc block comments for classes in CakePHP.')); + 'help' => __d('cake_console', 'The specific method you want help on.') + ))->description(__d('cake_console', 'Lookup doc block comments for classes in CakePHP.')); return $parser; } /** @@ -197,9 +197,12 @@ class ApiShell extends Shell { function __parseClass($path, $class) { $parsed = array(); - if (!include_once($path)) { - $this->err(__('%s could not be found', $path)); + if (!class_exists($class)) { + if (!include_once($path)) { + $this->err(__d('cake_console', '%s could not be found', $path)); + } } + $reflection = new ReflectionClass($class); foreach ($reflection->getMethods() as $method) { diff --git a/cake/console/shells/bake.php b/lib/Cake/Console/Command/BakeShell.php similarity index 78% rename from cake/console/shells/bake.php rename to lib/Cake/Console/Command/BakeShell.php index ec741ed3a..94b06f379 100644 --- a/cake/console/shells/bake.php +++ b/lib/Cake/Console/Command/BakeShell.php @@ -21,6 +21,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Model', 'Model'); + /** * Bake is a command-line code generation utility for automating programmer chores. * @@ -73,7 +75,7 @@ class BakeShell extends Shell { } if (!config('database')) { - $this->out(__('Your database configuration was not found. Take a moment to create one.')); + $this->out(__d('cake_console', 'Your database configuration was not found. Take a moment to create one.')); $this->args = null; return $this->DbConfig->execute(); } @@ -88,7 +90,7 @@ class BakeShell extends Shell { $this->out('[T]est case'); $this->out('[Q]uit'); - $classToBake = strtoupper($this->in(__('What would you like to Bake?'), array('D', 'M', 'V', 'C', 'P', 'F', 'T', 'Q'))); + $classToBake = strtoupper($this->in(__d('cake_console', 'What would you like to Bake?'), array('D', 'M', 'V', 'C', 'P', 'F', 'T', 'Q'))); switch ($classToBake) { case 'D': $this->DbConfig->execute(); @@ -115,7 +117,7 @@ class BakeShell extends Shell { exit(0); break; default: - $this->out(__('You have made an invalid selection. Please choose a type of class to Bake by entering D, M, V, F, T, or C.')); + $this->out(__d('cake_console', 'You have made an invalid selection. Please choose a type of class to Bake by entering D, M, V, F, T, or C.')); } $this->hr(); $this->main(); @@ -149,11 +151,13 @@ class BakeShell extends Shell { $modelExists = false; $model = $this->_modelName($name); - if (App::import('Model', $model)) { + + App::uses('AppModel', 'Model'); + App::uses($model, 'Model'); + if (class_exists($model)) { $object = new $model(); $modelExists = true; } else { - App::import('Model', 'Model', false); $object = new Model(array('name' => $name, 'ds' => $this->connection)); } @@ -174,15 +178,16 @@ class BakeShell extends Shell { $this->Controller->bakeTest($controller); } } - if (App::import('Controller', $controller)) { + App::uses($controller . 'Controller', 'Controller'); + if (class_exists($controller . 'Controller')) { $this->View->args = array($controller); $this->View->execute(); } $this->out('', 1, Shell::QUIET); - $this->out(__('Bake All complete'), 1, Shell::QUIET); + $this->out(__d('cake_console', 'Bake All complete'), 1, Shell::QUIET); array_shift($this->args); } else { - $this->error(__('Bake All could not continue without a valid model')); + $this->error(__d('cake_console', 'Bake All could not continue without a valid model')); } return $this->_stop(); } @@ -200,33 +205,33 @@ class BakeShell extends Shell { 'creation process. You can customize the generation process by telling Bake' . 'where different parts of your application are using command line arguments.' )->addSubcommand('all', array( - 'help' => __('Bake a complete MVC. optional of a Model'), + 'help' => __d('cake_console', 'Bake a complete MVC. optional of a Model'), ))->addSubcommand('project', array( - 'help' => __('Bake a new app folder in the path supplied or in current directory if no path is specified'), + 'help' => __d('cake_console', 'Bake a new app folder in the path supplied or in current directory if no path is specified'), 'parser' => $this->Project->getOptionParser() ))->addSubcommand('plugin', array( - 'help' => __('Bake a new plugin folder in the path supplied or in current directory if no path is specified.'), + 'help' => __d('cake_console', 'Bake a new plugin folder in the path supplied or in current directory if no path is specified.'), 'parser' => $this->Plugin->getOptionParser() ))->addSubcommand('db_config', array( - 'help' => __('Bake a database.php file in config directory.'), + 'help' => __d('cake_console', 'Bake a database.php file in config directory.'), 'parser' => $this->DbConfig->getOptionParser() ))->addSubcommand('model', array( - 'help' => __('Bake a model.'), + 'help' => __d('cake_console', 'Bake a model.'), 'parser' => $this->Model->getOptionParser() ))->addSubcommand('view', array( - 'help' => __('Bake views for controllers.'), + 'help' => __d('cake_console', 'Bake views for controllers.'), 'parser' => $this->View->getOptionParser() ))->addSubcommand('controller', array( - 'help' => __('Bake a controller.'), + 'help' => __d('cake_console', 'Bake a controller.'), 'parser' => $this->Controller->getOptionParser() ))->addSubcommand('fixture', array( - 'help' => __('Bake a fixture.'), + 'help' => __d('cake_console', 'Bake a fixture.'), 'parser' => $this->Fixture->getOptionParser() ))->addSubcommand('test', array( - 'help' => __('Bake a unit test.'), + 'help' => __d('cake_console', 'Bake a unit test.'), 'parser' => $this->Test->getOptionParser() ))->addOption('connection', array( - 'help' => __('Database connection to use in conjunction with `bake all`.'), + 'help' => __d('cake_console', 'Database connection to use in conjunction with `bake all`.'), 'short' => 'c', 'default' => 'default' )); diff --git a/cake/console/shells/command_list.php b/lib/Cake/Console/Command/CommandListShell.php similarity index 84% rename from cake/console/shells/command_list.php rename to lib/Cake/Console/Command/CommandListShell.php index e9323c6f7..aa3d0d4ed 100644 --- a/cake/console/shells/command_list.php +++ b/lib/Cake/Console/Command/CommandListShell.php @@ -16,6 +16,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Inflector', 'Utility'); + /** * Shows a list of commands available from the console. * @@ -79,17 +81,18 @@ class CommandListShell extends Shell { protected function _getShellList() { $shellList = array(); - $corePaths = App::core('shells'); - $shellList = $this->_appendShells('CORE', $corePaths, $shellList); + $shells = App::objects('file', App::core('Console/Command')); + $shellList = $this->_appendShells('CORE', $shells, $shellList); - $appPaths = array_diff(App::path('shells'), $corePaths); - $shellList = $this->_appendShells('app', $appPaths, $shellList); + $appShells = App::objects('Console/Command', null, false); + $shellList = $this->_appendShells('app', $appShells, $shellList); $plugins = App::objects('plugin'); foreach ($plugins as $plugin) { - $pluginPath = App::pluginPath($plugin) . 'console' . DS . 'shells' . DS; - $shellList = $this->_appendShells($plugin, array($pluginPath), $shellList); + $pluginShells = App::objects($plugin . '.Console/Command'); + $shellList = $this->_appendShells($plugin, $pluginShells, $shellList); } + return $shellList; } @@ -98,22 +101,10 @@ class CommandListShell extends Shell { * * @return array */ - protected function _appendShells($type, $paths, $shellList) { - foreach ($paths as $path) { - if (!is_dir($path)) { - continue; - } - $shells = App::objects('file', $path); - - if (empty($shells)) { - continue; - } - foreach ($shells as $shell) { - if ($shell !== 'shell.php' && $shell !== 'app_shell.php') { - $shell = str_replace('.php', '', $shell); - $shellList[$shell][$type] = $type; - } - } + protected function _appendShells($type, $shells, $shellList) { + foreach ($shells as $shell) { + $shell = Inflector::underscore(str_replace('Shell', '', $shell)); + $shellList[$shell][$type] = $type; } return $shellList; } @@ -223,10 +214,10 @@ class CommandListShell extends Shell { $parser = parent::getOptionParser(); return $parser->description('Get the list of available shells for this CakePHP application.') ->addOption('xml', array( - 'help' => __('Get the listing as XML.'), + 'help' => __d('cake_console', 'Get the listing as XML.'), 'boolean' => true ))->addOption('sort', array( - 'help' => __('Sorts the commands by where they are located.'), + 'help' => __d('cake_console', 'Sorts the commands by where they are located.'), 'boolean' => true )); } diff --git a/cake/console/shells/console.php b/lib/Cake/Console/Command/ConsoleShell.php similarity index 96% rename from cake/console/shells/console.php rename to lib/Cake/Console/Command/ConsoleShell.php index 44cc13d45..1e00d7dd7 100644 --- a/cake/console/shells/console.php +++ b/lib/Cake/Console/Command/ConsoleShell.php @@ -51,14 +51,14 @@ class ConsoleShell extends Shell { * */ public function initialize() { - require_once CAKE . 'dispatcher.php'; + App::uses('Dispatcher', 'Routing'); $this->Dispatcher = new Dispatcher(); $this->models = App::objects('model'); - App::import('Model', $this->models); foreach ($this->models as $model) { $class = Inflector::camelize(str_replace('.php', '', $model)); $this->models[$model] = $class; + App::uses($class, 'Model'); $this->{$class} = new $class(); } $this->out('Model classes:'); @@ -333,21 +333,20 @@ class ConsoleShell extends Shell { * @return boolean True if config reload was a success, otherwise false */ protected function _loadRoutes() { - $router = Router::getInstance(); - - $router->reload(); - extract($router->getNamedExpressions()); + Router::reload(); + extract(Router::getNamedExpressions()); if (!@include(CONFIGS . 'routes.php')) { return false; } - $router->parse('/'); + Router::parse('/'); - foreach (array_keys($router->getNamedExpressions()) as $var) { + foreach (array_keys(Router::getNamedExpressions()) as $var) { unset(${$var}); } - for ($i = 0, $len = count($router->routes); $i < $len; $i++) { - $router->routes[$i]->compile(); + + foreach (Router::$routes as $route) { + $route->compile(); } return true; } diff --git a/cake/console/shells/i18n.php b/lib/Cake/Console/Command/I18nShell.php similarity index 69% rename from cake/console/shells/i18n.php rename to lib/Cake/Console/Command/I18nShell.php index 0a2bdeef6..3a3c5691e 100644 --- a/cake/console/shells/i18n.php +++ b/lib/Cake/Console/Command/I18nShell.php @@ -52,7 +52,7 @@ class I18nShell extends Shell { if ($this->command && !in_array($this->command, array('help'))) { if (!config('database')) { - $this->out(__('Your database configuration was not found. Take a moment to create one.'), true); + $this->out(__d('cake_console', 'Your database configuration was not found. Take a moment to create one.'), true); return $this->DbConfig->execute(); } } @@ -63,14 +63,14 @@ class I18nShell extends Shell { * */ public function main() { - $this->out(__('I18n Shell')); + $this->out(__d('cake_console', 'I18n Shell')); $this->hr(); - $this->out(__('[E]xtract POT file from sources')); - $this->out(__('[I]nitialize i18n database table')); - $this->out(__('[H]elp')); - $this->out(__('[Q]uit')); + $this->out(__d('cake_console', '[E]xtract POT file from sources')); + $this->out(__d('cake_console', '[I]nitialize i18n database table')); + $this->out(__d('cake_console', '[H]elp')); + $this->out(__d('cake_console', '[Q]uit')); - $choice = strtolower($this->in(__('What would you like to do?'), array('E', 'I', 'H', 'Q'))); + $choice = strtolower($this->in(__d('cake_console', 'What would you like to do?'), array('E', 'I', 'H', 'Q'))); switch ($choice) { case 'e': $this->Extract->execute(); @@ -85,7 +85,7 @@ class I18nShell extends Shell { exit(0); break; default: - $this->out(__('You have made an invalid selection. Please choose a command to execute by entering E, I, H, or Q.')); + $this->out(__d('cake_console', 'You have made an invalid selection. Please choose a command to execute by entering E, I, H, or Q.')); } $this->hr(); $this->main(); @@ -107,11 +107,11 @@ class I18nShell extends Shell { public function getOptionParser() { $parser = parent::getOptionParser(); return $parser->description( - __('I18n Shell initializes i18n database table for your application and generates .pot files(s) with translations.') + __d('cake_console', 'I18n Shell initializes i18n database table for your application and generates .pot files(s) with translations.') )->addSubcommand('initdb', array( - 'help' => __('Initialize the i18n table.') + 'help' => __d('cake_console', 'Initialize the i18n table.') ))->addSubcommand('extract', array( - 'help' => __('Extract the po translations from your application'), + 'help' => __d('cake_console', 'Extract the po translations from your application'), 'parser' => $this->Extract->getOptionParser() )); } diff --git a/cake/console/shells/schema.php b/lib/Cake/Console/Command/SchemaShell.php similarity index 76% rename from cake/console/shells/schema.php rename to lib/Cake/Console/Command/SchemaShell.php index c0fe44751..f3faa5890 100644 --- a/cake/console/shells/schema.php +++ b/lib/Cake/Console/Command/SchemaShell.php @@ -19,8 +19,8 @@ * @since CakePHP(tm) v 1.2.0.5550 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'File', false); -App::import('Model', 'CakeSchema', false); +App::uses('File', 'Utility'); +App::uses('CakeSchema', 'Model'); /** * Schema is a command-line database management utility for automating programmer chores. @@ -112,7 +112,7 @@ class SchemaShell extends Shell { $this->_stop(); } else { $file = $this->Schema->path . DS . $this->params['file']; - $this->err(__('Schema file (%s) could not be found.', $file)); + $this->err(__d('cake_console', 'Schema file (%s) could not be found.', $file)); $this->_stop(); } } @@ -123,7 +123,7 @@ class SchemaShell extends Shell { * */ public function generate() { - $this->out(__('Generating Schema...')); + $this->out(__d('cake_console', 'Generating Schema...')); $options = array(); if (isset($this->params['force'])) { $options = array('models' => false); @@ -145,8 +145,13 @@ class SchemaShell extends Shell { } } + $cacheDisable = Configure::read('Cache.disable'); + Configure::write('Cache.disable', true); + $content = $this->Schema->read($options); $content['file'] = $this->params['file']; + + Configure::write('Cache.disable', $cacheDisable); if ($snapshot === true) { $Folder = new Folder($this->Schema->path); @@ -177,10 +182,10 @@ class SchemaShell extends Shell { } if ($this->Schema->write($content)) { - $this->out(__('Schema file: %s generated', $content['file'])); + $this->out(__d('cake_console', 'Schema file: %s generated', $content['file'])); $this->_stop(); } else { - $this->err(__('Schema file: %s generated')); + $this->err(__d('cake_console', 'Schema file: %s generated')); $this->_stop(); } } @@ -197,7 +202,7 @@ class SchemaShell extends Shell { $write = false; $Schema = $this->Schema->load(); if (!$Schema) { - $this->err(__('Schema could not be loaded')); + $this->err(__d('cake_console', 'Schema could not be loaded')); $this->_stop(); } if (!empty($this->params['write'])) { @@ -222,10 +227,10 @@ class SchemaShell extends Shell { } if ($File->write($contents)) { - $this->out(__('SQL dump file created in %s', $File->pwd())); + $this->out(__d('cake_console', 'SQL dump file created in %s', $File->pwd())); $this->_stop(); } else { - $this->err(__('SQL dump could not be created')); + $this->err(__d('cake_console', 'SQL dump could not be created')); $this->_stop(); } } @@ -269,7 +274,7 @@ class SchemaShell extends Shell { if (!empty($this->params['dry'])) { $this->__dry = true; - $this->out(__('Performing a dry run.')); + $this->out(__d('cake_console', 'Performing a dry run.')); } $options = array('name' => $name, 'plugin' => $plugin); @@ -281,7 +286,7 @@ class SchemaShell extends Shell { $Schema = $this->Schema->load($options); if (!$Schema) { - $this->err(__('%s could not be loaded', $this->Schema->path . DS . $this->Schema->file)); + $this->err(__d('cake_console', '%s could not be loaded', $this->Schema->path . DS . $this->Schema->file)); $this->_stop(); } $table = null; @@ -312,26 +317,26 @@ class SchemaShell extends Shell { $create[$table] = $db->createSchema($Schema, $table); } if (empty($drop) || empty($create)) { - $this->out(__('Schema is up to date.')); + $this->out(__d('cake_console', 'Schema is up to date.')); $this->_stop(); } - $this->out("\n" . __('The following table(s) will be dropped.')); + $this->out("\n" . __d('cake_console', 'The following table(s) will be dropped.')); $this->out(array_keys($drop)); - if ('y' == $this->in(__('Are you sure you want to drop the table(s)?'), array('y', 'n'), 'n')) { - $this->out(__('Dropping table(s).')); + if ('y' == $this->in(__d('cake_console', 'Are you sure you want to drop the table(s)?'), array('y', 'n'), 'n')) { + $this->out(__d('cake_console', 'Dropping table(s).')); $this->__run($drop, 'drop', $Schema); } - $this->out("\n" . __('The following table(s) will be created.')); + $this->out("\n" . __d('cake_console', 'The following table(s) will be created.')); $this->out(array_keys($create)); - if ('y' == $this->in(__('Are you sure you want to create the table(s)?'), array('y', 'n'), 'y')) { - $this->out(__('Creating table(s).')); + if ('y' == $this->in(__d('cake_console', 'Are you sure you want to create the table(s)?'), array('y', 'n'), 'y')) { + $this->out(__d('cake_console', 'Creating table(s).')); $this->__run($create, 'create', $Schema); } - $this->out(__('End create.')); + $this->out(__d('cake_console', 'End create.')); } /** @@ -343,7 +348,7 @@ class SchemaShell extends Shell { function __update(&$Schema, $table = null) { $db = ConnectionManager::getDataSource($this->Schema->connection); - $this->out(__('Comparing Database to Schema...')); + $this->out(__d('cake_console', 'Comparing Database to Schema...')); $options = array(); if (isset($this->params['force'])) { $options['models'] = false; @@ -362,19 +367,19 @@ class SchemaShell extends Shell { } if (empty($contents)) { - $this->out(__('Schema is up to date.')); + $this->out(__d('cake_console', 'Schema is up to date.')); $this->_stop(); } - $this->out("\n" . __('The following statements will run.')); + $this->out("\n" . __d('cake_console', 'The following statements will run.')); $this->out(array_map('trim', $contents)); - if ('y' == $this->in(__('Are you sure you want to alter the tables?'), array('y', 'n'), 'n')) { + if ('y' == $this->in(__d('cake_console', 'Are you sure you want to alter the tables?'), array('y', 'n'), 'n')) { $this->out(); - $this->out(__('Updating Database...')); + $this->out(__d('cake_console', 'Updating Database...')); $this->__run($contents, 'update', $Schema); } - $this->out(__('End update.')); + $this->out(__d('cake_console', 'End update.')); } /** @@ -384,7 +389,7 @@ class SchemaShell extends Shell { */ function __run($contents, $event, &$Schema) { if (empty($contents)) { - $this->err(__('Sql could not be run')); + $this->err(__d('cake_console', 'Sql could not be run')); return; } Configure::write('debug', 2); @@ -392,10 +397,10 @@ class SchemaShell extends Shell { foreach ($contents as $table => $sql) { if (empty($sql)) { - $this->out(__('%s is up to date.', $table)); + $this->out(__d('cake_console', '%s is up to date.', $table)); } else { if ($this->__dry === true) { - $this->out(__('Dry run for %s :', $table)); + $this->out(__d('cake_console', 'Dry run for %s :', $table)); $this->out($sql); } else { if (!$Schema->before(array($event => $table))) { @@ -411,7 +416,7 @@ class SchemaShell extends Shell { if (!empty($error)) { $this->out($error); } else { - $this->out(__('%s updated.', $table)); + $this->out(__d('cake_console', '%s updated.', $table)); } } } @@ -425,26 +430,26 @@ class SchemaShell extends Shell { */ public function getOptionParser() { $plugin = array( - 'help' => __('The plugin to use.'), + 'help' => __d('cake_console', 'The plugin to use.'), ); $connection = array( - 'help' => __('Set the db config to use.'), + 'help' => __d('cake_console', 'Set the db config to use.'), 'default' => 'default' ); $path = array( - 'help' => __('Path to read and write schema.php'), + 'help' => __d('cake_console', 'Path to read and write schema.php'), 'default' => CONFIGS . 'schema' ); $file = array( - 'help' => __('File name to read and write.'), + 'help' => __d('cake_console', 'File name to read and write.'), 'default' => 'schema.php' ); $name = array( - 'help' => __('Classname to use. If its Plugin.class, both name and plugin options will be set.') + 'help' => __d('cake_console', 'Classname to use. If its Plugin.class, both name and plugin options will be set.') ); $snapshot = array( 'short' => 's', - 'help' => __('Snapshot number to use/make.') + 'help' => __d('cake_console', 'Snapshot number to use/make.') ); $dry = array( 'help' => 'Perform a dry run on create and update commands. Queries will be output instead of run.', @@ -452,11 +457,11 @@ class SchemaShell extends Shell { ); $force = array( 'short' => 'f', - 'help' => __('Force "generate" to create a new schema'), + 'help' => __d('cake_console', 'Force "generate" to create a new schema'), 'boolean' => true ); $write = array( - 'help' => __('Write the dumped SQL to a file.') + 'help' => __d('cake_console', 'Write the dumped SQL to a file.') ); $parser = parent::getOptionParser(); @@ -470,42 +475,42 @@ class SchemaShell extends Shell { 'arguments' => compact('name') ) ))->addSubcommand('generate', array( - 'help' => __('Reads from --connection and writes to --path. Generate snapshots with -s'), + 'help' => __d('cake_console', 'Reads from --connection and writes to --path. Generate snapshots with -s'), 'parser' => array( 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'snapshot', 'force'), 'arguments' => array( - 'snapshot' => array('help' => __('Generate a snapshot.')) + 'snapshot' => array('help' => __d('cake_console', 'Generate a snapshot.')) ) ) ))->addSubcommand('dump', array( - 'help' => __('Dump database SQL based on a schema file to stdout.'), + 'help' => __d('cake_console', 'Dump database SQL based on a schema file to stdout.'), 'parser' => array( 'options' => compact('plugin', 'path', 'file', 'name', 'connection'), 'arguments' => compact('name') ) ))->addSubcommand('create', array( - 'help' => __('Drop and create tables based on the schema file.'), + 'help' => __d('cake_console', 'Drop and create tables based on the schema file.'), 'parser' => array( 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot'), 'args' => array( 'name' => array( - 'help' => __('Name of schema to use.') + 'help' => __d('cake_console', 'Name of schema to use.') ), 'table' => array( - 'help' => __('Only create the specified table.') + 'help' => __d('cake_console', 'Only create the specified table.') ) ) ) ))->addSubcommand('update', array( - 'help' => __('Alter the tables based on the schema file.'), + 'help' => __d('cake_console', 'Alter the tables based on the schema file.'), 'parser' => array( 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'dry', 'snapshot'), 'args' => array( 'name' => array( - 'help' => __('Name of schema to use.') + 'help' => __d('cake_console', 'Name of schema to use.') ), 'table' => array( - 'help' => __('Only create the specified table.') + 'help' => __d('cake_console', 'Only create the specified table.') ) ) ) diff --git a/cake/console/shells/tasks/bake.php b/lib/Cake/Console/Command/Task/BakeTask.php similarity index 93% rename from cake/console/shells/tasks/bake.php rename to lib/Cake/Console/Command/Task/BakeTask.php index bd7f59e69..58fc783ef 100644 --- a/cake/console/shells/tasks/bake.php +++ b/lib/Cake/Console/Command/Task/BakeTask.php @@ -50,7 +50,7 @@ class BakeTask extends Shell { public function getPath() { $path = $this->path; if (isset($this->plugin)) { - $path = $this->_pluginPath($this->plugin) . Inflector::pluralize(Inflector::underscore($this->name)) . DS; + $path = $this->_pluginPath($this->plugin) . $this->name . DS; } return $path; } diff --git a/cake/console/shells/tasks/controller.php b/lib/Cake/Console/Command/Task/ControllerTask.php similarity index 77% rename from cake/console/shells/tasks/controller.php rename to lib/Cake/Console/Command/Task/ControllerTask.php index f1cac43eb..6f4723c64 100644 --- a/cake/console/shells/tasks/controller.php +++ b/lib/Cake/Console/Command/Task/ControllerTask.php @@ -17,7 +17,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -include_once dirname(__FILE__) . DS . 'bake.php'; +App::uses('BakeTask', 'Console/Command/Task'); /** * Task class for creating and updating controller files. @@ -71,13 +71,13 @@ class ControllerTask extends BakeTask { $actions = ''; if (!empty($this->params['public'])) { - $this->out(__('Baking basic crud methods for ') . $controller); + $this->out(__d('cake_console', 'Baking basic crud methods for ') . $controller); $actions .= $this->bakeActions($controller); } if (!empty($this->params['admin'])) { $admin = $this->Project->getPrefix(); if ($admin) { - $this->out(__('Adding %s methods', $admin)); + $this->out(__d('cake_console', 'Adding %s methods', $admin)); $actions .= "\n" . $this->bakeActions($controller, $admin); } } @@ -106,7 +106,8 @@ class ControllerTask extends BakeTask { foreach ($this->__tables as $table) { $model = $this->_modelName($table); $controller = $this->_controllerName($model); - if (App::import('Model', $model)) { + App::uses($model, 'Model'); + if (class_exists($model)) { $actions = $this->bakeActions($controller); if ($this->bake($controller, $actions) && $unitTestExists) { $this->bakeTest($controller); @@ -123,7 +124,7 @@ class ControllerTask extends BakeTask { protected function _interactive() { $this->interactive = true; $this->hr(); - $this->out(__("Bake Controller\nPath: %s", $this->path)); + $this->out(__d('cake_console', "Bake Controller\nPath: %s", $this->path)); $this->hr(); if (empty($this->connection)) { @@ -132,7 +133,7 @@ class ControllerTask extends BakeTask { $controllerName = $this->getName(); $this->hr(); - $this->out(__('Baking %sController', $controllerName)); + $this->out(__d('cake_console', 'Baking %sController', $controllerName)); $this->hr(); $helpers = $components = array(); @@ -142,18 +143,17 @@ class ControllerTask extends BakeTask { $useDynamicScaffold = 'n'; $wannaBakeCrud = 'y'; - $controllerFile = strtolower(Inflector::underscore($controllerName)); - $question[] = __("Would you like to build your controller interactively?"); - if (file_exists($this->path . $controllerFile .'_controller.php')) { - $question[] = __("Warning: Choosing no will overwrite the %sController.", $controllerName); + $question[] = __d('cake_console', "Would you like to build your controller interactively?"); + if (file_exists($this->path . $controllerName .'Controller.php')) { + $question[] = __d('cake_console', "Warning: Choosing no will overwrite the %sController.", $controllerName); } $doItInteractive = $this->in(implode("\n", $question), array('y','n'), 'y'); if (strtolower($doItInteractive) == 'y') { $this->interactive = true; $useDynamicScaffold = $this->in( - __("Would you like to use dynamic scaffolding?"), array('y','n'), 'n' + __d('cake_console', "Would you like to use dynamic scaffolding?"), array('y','n'), 'n' ); if (strtolower($useDynamicScaffold) == 'y') { @@ -166,7 +166,7 @@ class ControllerTask extends BakeTask { $components = $this->doComponents(); $wannaUseSession = $this->in( - __("Would you like to use Session flash messages?"), array('y','n'), 'y' + __d('cake_console', "Would you like to use Session flash messages?"), array('y','n'), 'y' ); } } else { @@ -184,7 +184,7 @@ class ControllerTask extends BakeTask { $baked = false; if ($this->interactive === true) { $this->confirmController($controllerName, $useDynamicScaffold, $helpers, $components); - $looksGood = $this->in(__('Look okay?'), array('y','n'), 'y'); + $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y','n'), 'y'); if (strtolower($looksGood) == 'y') { $baked = $this->bake($controllerName, $actions, $helpers, $components); @@ -209,17 +209,17 @@ class ControllerTask extends BakeTask { public function confirmController($controllerName, $useDynamicScaffold, $helpers, $components) { $this->out(); $this->hr(); - $this->out(__('The following controller will be created:')); + $this->out(__d('cake_console', 'The following controller will be created:')); $this->hr(); - $this->out(__("Controller Name:\n\t%s", $controllerName)); + $this->out(__d('cake_console', "Controller Name:\n\t%s", $controllerName)); if (strtolower($useDynamicScaffold) == 'y') { $this->out("var \$scaffold;"); } $properties = array( - 'helpers' => __('Helpers:'), - 'components' => __('Components:'), + 'helpers' => __d('cake_console', 'Helpers:'), + 'components' => __d('cake_console', 'Components:'), ); foreach ($properties as $var => $title) { @@ -246,11 +246,11 @@ class ControllerTask extends BakeTask { */ protected function _askAboutMethods() { $wannaBakeCrud = $this->in( - __("Would you like to create some basic class methods \n(index(), add(), view(), edit())?"), + __d('cake_console', "Would you like to create some basic class methods \n(index(), add(), view(), edit())?"), array('y','n'), 'n' ); $wannaBakeAdminCrud = $this->in( - __("Would you like to create the basic class methods for admin routing?"), + __d('cake_console', "Would you like to create the basic class methods for admin routing?"), array('y','n'), 'n' ); return array($wannaBakeCrud, $wannaBakeAdminCrud); @@ -269,10 +269,11 @@ class ControllerTask extends BakeTask { $currentModelName = $modelImport = $this->_modelName($controllerName); $plugin = $this->plugin; if ($plugin) { - $modelImport = $plugin . '.' . $modelImport; + $plugin .= '.'; } - if (!App::import('Model', $modelImport)) { - $this->err(__('You must have a model for this class to build basic methods. Please try again.')); + App::uses($modelImport, $plugin . 'Model'); + if (!class_exists($modelImport)) { + $this->err(__d('cake_console', 'You must have a model for this class to build basic methods. Please try again.')); $this->_stop(); } @@ -282,9 +283,13 @@ class ControllerTask extends BakeTask { $singularName = Inflector::variable($currentModelName); $singularHumanName = $this->_singularHumanName($controllerName); $pluralHumanName = $this->_pluralName($controllerName); + $displayField = $modelObj->displayField; + $primaryKey = $modelObj->primaryKey; - $this->Template->set(compact('plugin', 'admin', 'controllerPath', 'pluralName', 'singularName', 'singularHumanName', - 'pluralHumanName', 'modelObj', 'wannaUseSession', 'currentModelName')); + $this->Template->set(compact('plugin', 'admin', 'controllerPath', 'pluralName', 'singularName', + 'singularHumanName', 'pluralHumanName', 'modelObj', 'wannaUseSession', 'currentModelName', + 'displayField', 'primaryKey' + )); $actions = $this->Template->generate('actions', 'controller_actions'); return $actions; } @@ -309,7 +314,7 @@ class ControllerTask extends BakeTask { $contents = $this->Template->generate('classes', 'controller'); $path = $this->getPath(); - $filename = $path . $this->_controllerPath($controllerName) . '_controller.php'; + $filename = $path . $this->_controllerName($controllerName) . 'Controller.php'; if ($this->createFile($filename, $contents)) { return $contents; } @@ -336,8 +341,8 @@ class ControllerTask extends BakeTask { */ public function doHelpers() { return $this->_doPropertyChoices( - __("Would you like this controller to use other helpers\nbesides HtmlHelper and FormHelper?"), - __("Please provide a comma separated list of the other\nhelper names you'd like to use.\nExample: 'Ajax, Javascript, Time'") + __d('cake_console', "Would you like this controller to use other helpers\nbesides HtmlHelper and FormHelper?"), + __d('cake_console', "Please provide a comma separated list of the other\nhelper names you'd like to use.\nExample: 'Ajax, Javascript, Time'") ); } @@ -348,8 +353,8 @@ class ControllerTask extends BakeTask { */ public function doComponents() { return $this->_doPropertyChoices( - __("Would you like this controller to use any components?"), - __("Please provide a comma separated list of the component names you'd like to use.\nExample: 'Acl, Security, RequestHandler'") + __d('cake_console', "Would you like this controller to use any components?"), + __d('cake_console', "Please provide a comma separated list of the component names you'd like to use.\nExample: 'Acl, Security, RequestHandler'") ); } @@ -385,7 +390,7 @@ class ControllerTask extends BakeTask { $this->__tables = $this->Model->getAllTables($useDbConfig); if ($this->interactive == true) { - $this->out(__('Possible Controllers based on your current database:')); + $this->out(__d('cake_console', 'Possible Controllers based on your current database:')); $this->_controllerNames = array(); $count = count($this->__tables); for ($i = 0; $i < $count; $i++) { @@ -408,14 +413,14 @@ class ControllerTask extends BakeTask { $enteredController = ''; while ($enteredController == '') { - $enteredController = $this->in(__("Enter a number from the list above,\ntype in the name of another controller, or 'q' to exit"), null, 'q'); + $enteredController = $this->in(__d('cake_console', "Enter a number from the list above,\ntype in the name of another controller, or 'q' to exit"), null, 'q'); if ($enteredController === 'q') { - $this->out(__('Exit')); + $this->out(__d('cake_console', 'Exit')); return $this->_stop(); } if ($enteredController == '' || intval($enteredController) > count($controllers)) { - $this->err(__("The Controller name you supplied was empty,\nor the number you selected was not an option. Please try again.")); + $this->err(__d('cake_console', "The Controller name you supplied was empty,\nor the number you selected was not an option. Please try again.")); $enteredController = ''; } } @@ -436,24 +441,24 @@ class ControllerTask extends BakeTask { public function getOptionParser() { $parser = parent::getOptionParser(); return $parser->description( - __('Bake a controller for a model. Using options you can bake public, admin or both.') + __d('cake_console', 'Bake a controller for a model. Using options you can bake public, admin or both.') )->addArgument('name', array( - 'help' => __('Name of the controller to bake. Can use Plugin.name to bake controllers into plugins.') + 'help' => __d('cake_console', 'Name of the controller to bake. Can use Plugin.name to bake controllers into plugins.') ))->addOption('public', array( - 'help' => __('Bake a controller with basic crud actions (index, view, add, edit, delete).'), + 'help' => __d('cake_console', 'Bake a controller with basic crud actions (index, view, add, edit, delete).'), 'boolean' => true ))->addOption('admin', array( - 'help' => __('Bake a controller with crud actions for one of the Routing.prefixes.'), + 'help' => __d('cake_console', 'Bake a controller with crud actions for one of the Routing.prefixes.'), 'boolean' => true ))->addOption('plugin', array( 'short' => 'p', - 'help' => __('Plugin to bake the controller into.') + 'help' => __d('cake_console', 'Plugin to bake the controller into.') ))->addOption('connection', array( 'short' => 'c', - 'help' => __('The connection the controller\'s model is on.') + 'help' => __d('cake_console', 'The connection the controller\'s model is on.') ))->addSubcommand('all', array( - 'help' => __('Bake all controllers with CRUD methods.') - ))->epilog(__('Omitting all arguments and options will enter into an interactive mode.')); + 'help' => __d('cake_console', 'Bake all controllers with CRUD methods.') + ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')); } /** @@ -494,4 +499,4 @@ class ControllerTask extends BakeTask { $this->out(); $this->_stop(); } -} +} \ No newline at end of file diff --git a/cake/console/shells/tasks/db_config.php b/lib/Cake/Console/Command/Task/DbConfigTask.php similarity index 96% rename from cake/console/shells/tasks/db_config.php rename to lib/Cake/Console/Command/Task/DbConfigTask.php index c3c2b36e1..2ffdd4ada 100644 --- a/cake/console/shells/tasks/db_config.php +++ b/lib/Cake/Console/Command/Task/DbConfigTask.php @@ -104,7 +104,7 @@ class DbConfigTask extends Shell { } } - $driver = $this->in('Driver:', array('db2', 'firebird', 'mssql', 'mysql', 'odbc', 'oracle', 'postgres', 'sqlite', 'sybase'), 'mysql'); + $driver = $this->in('Driver:', array('mssql', 'mysql', 'oracle', 'postgres', 'sqlite'), 'mysql'); $persistent = $this->in('Persistent Connection?', array('y', 'n'), 'n'); if (strtolower($persistent) == 'n') { @@ -351,7 +351,7 @@ class DbConfigTask extends Shell { * @return void */ public function getConfig() { - App::import('Model', 'ConnectionManager', false); + App::uses('ConnectionManager', 'Model'); $useDbConfig = 'default'; $configs = get_class_vars($this->databaseClassName); @@ -361,7 +361,7 @@ class DbConfigTask extends Shell { $connections = array_keys($configs); if (count($connections) > 1) { - $useDbConfig = $this->in(__('Use Database Config') .':', $connections, 'default'); + $useDbConfig = $this->in(__d('cake_console', 'Use Database Config') .':', $connections, 'default'); } return $useDbConfig; } @@ -374,7 +374,7 @@ class DbConfigTask extends Shell { public function getOptionParser() { $parser = parent::getOptionParser(); return $parser->description( - __('Bake new database configuration settings.') + __d('cake_console', 'Bake new database configuration settings.') ); } } diff --git a/cake/console/shells/tasks/extract.php b/lib/Cake/Console/Command/Task/ExtractTask.php similarity index 77% rename from cake/console/shells/tasks/extract.php rename to lib/Cake/Console/Command/Task/ExtractTask.php index 9965876e2..8e20fabe2 100644 --- a/cake/console/shells/tasks/extract.php +++ b/lib/Cake/Console/Command/Task/ExtractTask.php @@ -16,7 +16,7 @@ * @since CakePHP(tm) v 1.2.0.5012 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'File'); +App::uses('File', 'Utility'); /** * Language string extractor * @@ -112,11 +112,11 @@ class ExtractTask extends Shell { $this->__paths = explode(',', $this->params['paths']); } else { $defaultPath = APP_PATH; - $message = __("What is the full path you would like to extract?\nExample: %s\n[Q]uit [D]one", $this->Dispatch->params['root'] . DS . 'myapp'); + $message = __d('cake_console', "What is the full path you would like to extract?\nExample: %s\n[Q]uit [D]one", $defaultPath); while (true) { $response = $this->in($message, null, $defaultPath); if (strtoupper($response) === 'Q') { - $this->out(__('Extract Aborted')); + $this->out(__d('cake_console', 'Extract Aborted')); $this->_stop(); } elseif (strtoupper($response) === 'D') { $this->out(); @@ -125,7 +125,7 @@ class ExtractTask extends Shell { $this->__paths[] = $response; $defaultPath = 'D'; } else { - $this->err(__('The directory path you supplied was not found. Please try again.')); + $this->err(__d('cake_console', 'The directory path you supplied was not found. Please try again.')); } $this->out(); } @@ -134,17 +134,17 @@ class ExtractTask extends Shell { if (isset($this->params['output'])) { $this->__output = $this->params['output']; } else { - $message = __("What is the full path you would like to output?\nExample: %s\n[Q]uit", $this->__paths[0] . DS . 'locale'); + $message = __d('cake_console', "What is the full path you would like to output?\nExample: %s\n[Q]uit", $this->__paths[0] . DS . 'locale'); while (true) { $response = $this->in($message, null, $this->__paths[0] . DS . 'locale'); if (strtoupper($response) === 'Q') { - $this->out(__('Extract Aborted')); + $this->out(__d('cake_console', 'Extract Aborted')); $this->_stop(); } elseif (is_dir($response)) { $this->__output = $response . DS; break; } else { - $this->err(__('The directory path you supplied was not found. Please try again.')); + $this->err(__d('cake_console', 'The directory path you supplied was not found. Please try again.')); } $this->out(); } @@ -154,7 +154,7 @@ class ExtractTask extends Shell { $this->__merge = !(strtolower($this->params['merge']) === 'no'); } else { $this->out(); - $response = $this->in(__('Would you like to merge all domains strings into the default.pot file?'), array('y', 'n'), 'n'); + $response = $this->in(__d('cake_console', 'Would you like to merge all domains strings into the default.pot file?'), array('y', 'n'), 'n'); $this->__merge = strtolower($response) === 'y'; } @@ -173,13 +173,13 @@ class ExtractTask extends Shell { function __extract() { $this->out(); $this->out(); - $this->out(__('Extracting...')); + $this->out(__d('cake_console', 'Extracting...')); $this->hr(); - $this->out(__('Paths:')); + $this->out(__d('cake_console', 'Paths:')); foreach ($this->__paths as $path) { $this->out(' ' . $path); } - $this->out(__('Output Directory: ') . $this->__output); + $this->out(__d('cake_console', 'Output Directory: ') . $this->__output); $this->hr(); $this->__extractTokens(); $this->__buildFiles(); @@ -187,7 +187,7 @@ class ExtractTask extends Shell { $this->__paths = $this->__files = $this->__storage = array(); $this->__strings = $this->__tokens = array(); $this->out(); - $this->out(__('Done.')); + $this->out(__d('cake_console', 'Done.')); } /** @@ -197,17 +197,17 @@ class ExtractTask extends Shell { */ public function getOptionParser() { $parser = parent::getOptionParser(); - return $parser->description(__('CakePHP Language String Extraction:')) - ->addOption('app', array('help' => __('Directory where your application is located.'))) - ->addOption('paths', array('help' => __('Comma separted list of paths, full paths are needed.'))) + return $parser->description(__d('cake_console', 'CakePHP Language String Extraction:')) + ->addOption('app', array('help' => __d('cake_console', 'Directory where your application is located.'))) + ->addOption('paths', array('help' => __d('cake_console', 'Comma separted list of paths, full paths are needed.'))) ->addOption('merge', array( - 'help' => __('Merge all domain strings into the default.po file.'), + 'help' => __d('cake_console', 'Merge all domain strings into the default.po file.'), 'choices' => array('yes', 'no') )) - ->addOption('output', array('help' => __('Full path to output directory.'))) - ->addOption('files', array('help' => __('Comma separated list of files, full paths are needed.'))) + ->addOption('output', array('help' => __d('cake_console', 'Full path to output directory.'))) + ->addOption('files', array('help' => __d('cake_console', 'Comma separated list of files, full paths are needed.'))) ->addOption('exclude', array( - 'help' => __('Comma separated list of directories to exclude. Any path containing a path segment with the provided values will be skipped. E.g. test,vendors') + 'help' => __d('cake_console', 'Comma separated list of directories to exclude. Any path containing a path segment with the provided values will be skipped. E.g. test,vendors') )); } @@ -217,25 +217,25 @@ class ExtractTask extends Shell { * @return void */ public function help() { - $this->out(__('CakePHP Language String Extraction:')); + $this->out(__d('cake_console', 'CakePHP Language String Extraction:')); $this->hr(); - $this->out(__('The Extract script generates .pot file(s) with translations')); - $this->out(__('By default the .pot file(s) will be place in the locale directory of -app')); - $this->out(__('By default -app is ROOT/app')); + $this->out(__d('cake_console', 'The Extract script generates .pot file(s) with translations')); + $this->out(__d('cake_console', 'By default the .pot file(s) will be place in the locale directory of -app')); + $this->out(__d('cake_console', 'By default -app is ROOT/app')); $this->hr(); - $this->out(__('Usage: cake i18n extract ...')); + $this->out(__d('cake_console', 'Usage: cake i18n extract ...')); $this->out(); - $this->out(__('Params:')); - $this->out(__(' -app [path...]: directory where your application is located')); - $this->out(__(' -root [path...]: path to install')); - $this->out(__(' -core [path...]: path to cake directory')); - $this->out(__(' -paths [comma separated list of paths, full path is needed]')); - $this->out(__(' -merge [yes|no]: Merge all domains strings into the default.pot file')); - $this->out(__(' -output [path...]: Full path to output directory')); - $this->out(__(' -files: [comma separated list of files, full path to file is needed]')); + $this->out(__d('cake_console', 'Params:')); + $this->out(__d('cake_console', ' -app [path...]: directory where your application is located')); + $this->out(__d('cake_console', ' -root [path...]: path to install')); + $this->out(__d('cake_console', ' -core [path...]: path to cake directory')); + $this->out(__d('cake_console', ' -paths [comma separated list of paths, full path is needed]')); + $this->out(__d('cake_console', ' -merge [yes|no]: Merge all domains strings into the default.pot file')); + $this->out(__d('cake_console', ' -output [path...]: Full path to output directory')); + $this->out(__d('cake_console', ' -files: [comma separated list of files, full path to file is needed]')); $this->out(); - $this->out(__('Commands:')); - $this->out(__(' cake i18n extract help: Shows this help message.')); + $this->out(__d('cake_console', 'Commands:')); + $this->out(__d('cake_console', ' cake i18n extract help: Shows this help message.')); $this->out(); } @@ -248,7 +248,7 @@ class ExtractTask extends Shell { function __extractTokens() { foreach ($this->__files as $file) { $this->__file = $file; - $this->out(__('Processing %s...', $file)); + $this->out(__d('cake_console', 'Processing %s...', $file)); $code = file_get_contents($file); $allTokens = token_get_all($code); @@ -411,11 +411,11 @@ class ExtractTask extends Shell { $response = ''; while ($overwriteAll === false && $File->exists() && strtoupper($response) !== 'Y') { $this->out(); - $response = $this->in(__('Error: %s already exists in this location. Overwrite? [Y]es, [N]o, [A]ll', $filename), array('y', 'n', 'a'), 'y'); + $response = $this->in(__d('cake_console', 'Error: %s already exists in this location. Overwrite? [Y]es, [N]o, [A]ll', $filename), array('y', 'n', 'a'), 'y'); if (strtoupper($response) === 'N') { $response = ''; while ($response == '') { - $response = $this->in(__("What would you like to name this file?\nExample: %s", 'new_' . $filename), null, 'new_' . $filename); + $response = $this->in(__d('cake_console', "What would you like to name this file?\nExample: %s", 'new_' . $filename), null, 'new_' . $filename); $File = new File($this->__output . $response); $filename = $response; } @@ -483,7 +483,7 @@ class ExtractTask extends Shell { * @access private */ function __markerError($file, $line, $marker, $count) { - $this->out(__("Invalid marker content in %s:%s\n* %s(", $file, $line, $marker), true); + $this->out(__d('cake_console', "Invalid marker content in %s:%s\n* %s(", $file, $line, $marker), true); $count += 2; $tokenCount = count($this->__tokens); $parenthesis = 1; diff --git a/cake/console/shells/tasks/fixture.php b/lib/Cake/Console/Command/Task/FixtureTask.php similarity index 85% rename from cake/console/shells/tasks/fixture.php rename to lib/Cake/Console/Command/Task/FixtureTask.php index 8fd60782b..daf3e412d 100644 --- a/cake/console/shells/tasks/fixture.php +++ b/lib/Cake/Console/Command/Task/FixtureTask.php @@ -16,7 +16,10 @@ * @since CakePHP(tm) v 1.3 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -include_once dirname(__FILE__) . DS . 'bake.php'; + +App::uses('BakeTask', 'Console/Command/Task'); +App::uses('Model', 'Model'); + /** * Task class for creating and updating fixtures files. * @@ -54,7 +57,7 @@ class FixtureTask extends BakeTask { */ public function __construct($stdout = null, $stderr = null, $stdin = null) { parent::__construct($stdout, $stderr, $stdin); - $this->path = APP . 'tests' . DS . 'fixtures' . DS; + $this->path = APP . 'tests' . DS . 'Fixture' . DS; } /** @@ -65,25 +68,25 @@ class FixtureTask extends BakeTask { public function getOptionParser() { $parser = parent::getOptionParser(); return $parser->description( - __('Generate fixtures for use with the test suite. You can use `bake fixture all` to bake all fixtures.') + __d('cake_console', 'Generate fixtures for use with the test suite. You can use `bake fixture all` to bake all fixtures.') )->addArgument('name', array( - 'help' => __('Name of the fixture to bake. Can use Plugin.name to bake plugin fixtures.') + 'help' => __d('cake_console', 'Name of the fixture to bake. Can use Plugin.name to bake plugin fixtures.') ))->addOption('count', array( - 'help' => __('When using generated data, the number of records to include in the fixture(s).'), + 'help' => __d('cake_console', 'When using generated data, the number of records to include in the fixture(s).'), 'short' => 'n', 'default' => 10 ))->addOption('connection', array( - 'help' => __('Which database configuration to use for baking.'), + 'help' => __d('cake_console', 'Which database configuration to use for baking.'), 'short' => 'c', 'default' => 'default' ))->addOption('plugin', array( - 'help' => __('CamelCased name of the plugin to bake fixtures for.'), + 'help' => __d('cake_console', 'CamelCased name of the plugin to bake fixtures for.'), 'short' => 'p', ))->addOption('records', array( 'help' => 'Used with --count and /all commands to pull [n] records from the live tables, where [n] is either --count or the default of 10', 'short' => 'r', 'boolean' => true - ))->epilog(__('Omitting all arguments and options will enter into an interactive mode.'));; + ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.'));; } /** @@ -155,16 +158,16 @@ class FixtureTask extends BakeTask { */ public function importOptions($modelName) { $options = array(); - $doSchema = $this->in(__('Would you like to import schema for this fixture?'), array('y', 'n'), 'n'); + $doSchema = $this->in(__d('cake_console', 'Would you like to import schema for this fixture?'), array('y', 'n'), 'n'); if ($doSchema == 'y') { $options['schema'] = $modelName; } - $doRecords = $this->in(__('Would you like to use record importing for this fixture?'), array('y', 'n'), 'n'); + $doRecords = $this->in(__d('cake_console', 'Would you like to use record importing for this fixture?'), array('y', 'n'), 'n'); if ($doRecords == 'y') { $options['records'] = true; } if ($doRecords == 'n') { - $prompt = __("Would you like to build this fixture with data from %s's table?", $modelName); + $prompt = __d('cake_console', "Would you like to build this fixture with data from %s's table?", $modelName); $fromTable = $this->in($prompt, array('y', 'n'), 'n'); if (strtolower($fromTable) == 'y') { $options['fromTable'] = true; @@ -182,10 +185,10 @@ class FixtureTask extends BakeTask { * @return string Baked fixture content */ public function bake($model, $useTable = false, $importOptions = array()) { - if (!class_exists('CakeSchema')) { - App::import('Model', 'CakeSchema', false); - } - $table = $schema = $records = $import = $modelImport = $recordImport = null; + App::uses('CakeSchema', 'Model'); + $table = $schema = $records = $import = $modelImport = null; + $importBits = array(); + if (!$useTable) { $useTable = Inflector::tableize($model); } elseif ($useTable != Inflector::tableize($model)) { @@ -194,16 +197,17 @@ class FixtureTask extends BakeTask { if (!empty($importOptions)) { if (isset($importOptions['schema'])) { - $modelImport = "'model' => '{$importOptions['schema']}'"; + $modelImport = true; + $importBits[] = "'model' => '{$importOptions['schema']}'"; } if (isset($importOptions['records'])) { - $recordImport = "'records' => true"; + $importBits[] = "'records' => true"; } - if ($modelImport && $recordImport) { - $modelImport .= ', '; + if ($this->connection != 'default') { + $importBits[] .= "'connection' => '{$this->connection}'"; } - if (!empty($modelImport) || !empty($recordImport)) { - $import = sprintf("array(%s%s)", $modelImport, $recordImport); + if (!empty($importBits)) { + $import = sprintf("array(%s)", implode(', ', $importBits)); } } @@ -245,7 +249,7 @@ class FixtureTask extends BakeTask { $vars = array_merge($defaults, $otherVars); $path = $this->getPath(); - $filename = Inflector::underscore($model) . '_fixture.php'; + $filename = Inflector::camelize($model) . 'Fixture.php'; $this->Template->set('model', $model); $this->Template->set($vars); @@ -264,7 +268,7 @@ class FixtureTask extends BakeTask { public function getPath() { $path = $this->path; if (isset($this->plugin)) { - $path = $this->_pluginPath($this->plugin) . 'tests' . DS . 'fixtures' . DS; + $path = $this->_pluginPath($this->plugin) . 'tests' . DS . 'Fixture' . DS; } return $path; } @@ -383,14 +387,13 @@ class FixtureTask extends BakeTask { protected function _getRecordsFromTable($modelName, $useTable = null) { if ($this->interactive) { $condition = null; - $prompt = __("Please provide a SQL fragment to use as conditions\nExample: WHERE 1=1 LIMIT 10"); + $prompt = __d('cake_console', "Please provide a SQL fragment to use as conditions\nExample: WHERE 1=1 LIMIT 10"); while (!$condition) { $condition = $this->in($prompt, null, 'WHERE 1=1 LIMIT 10'); } } else { $condition = 'WHERE 1=1 LIMIT ' . (isset($this->params['count']) ? $this->params['count'] : 10); } - App::import('Model', 'Model', false); $modelObject = new Model(array('name' => $modelName, 'table' => $useTable, 'ds' => $this->connection)); $records = $modelObject->find('all', array( 'conditions' => $condition, diff --git a/cake/console/shells/tasks/model.php b/lib/Cake/Console/Command/Task/ModelTask.php similarity index 81% rename from cake/console/shells/tasks/model.php rename to lib/Cake/Console/Command/Task/ModelTask.php index 5ac132dd1..1c63147fb 100644 --- a/cake/console/shells/tasks/model.php +++ b/lib/Cake/Console/Command/Task/ModelTask.php @@ -17,7 +17,10 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -include_once dirname(__FILE__) . DS . 'bake.php'; +App::uses('BakeTask', 'Console/Command/Task'); +App::uses('ConnectionManager', 'Model'); +App::uses('Model', 'Model'); +App::uses('Validation', 'Utility'); /** * Task class for creating and updating model files. @@ -71,7 +74,6 @@ class ModelTask extends BakeTask { * */ public function execute() { - App::import('Model', 'Model', false); parent::execute(); if (empty($this->args)) { @@ -110,7 +112,7 @@ class ModelTask extends BakeTask { continue; } $modelClass = Inflector::classify($table); - $this->out(__('Baking %s', $modelClass)); + $this->out(__d('cake_console', 'Baking %s', $modelClass)); $object = $this->_getModelObject($modelClass); if ($this->bake($object, false) && $unitTestExists) { $this->bakeFixture($modelClass); @@ -149,7 +151,7 @@ class ModelTask extends BakeTask { $this->out($i + 1 .'. ' . $option); } if (empty($prompt)) { - $prompt = __('Make a selection from the choices above'); + $prompt = __d('cake_console', 'Make a selection from the choices above'); } $choice = $this->in($prompt, null, $default); if (intval($choice) > 0 && intval($choice) <= $max) { @@ -188,7 +190,7 @@ class ModelTask extends BakeTask { $primaryKey = $this->findPrimaryKey($fields); } } else { - $this->err(__('Table %s does not exist, cannot bake a model without a table.', $useTable)); + $this->err(__d('cake_console', 'Table %s does not exist, cannot bake a model without a table.', $useTable)); $this->_stop(); return false; } @@ -197,13 +199,13 @@ class ModelTask extends BakeTask { $displayField = $this->findDisplayField($tempModel->schema()); } - $prompt = __("Would you like to supply validation criteria \nfor the fields in your model?"); + $prompt = __d('cake_console', "Would you like to supply validation criteria \nfor the fields in your model?"); $wannaDoValidation = $this->in($prompt, array('y','n'), 'y'); if (array_search($useTable, $this->_tables) !== false && strtolower($wannaDoValidation) == 'y') { $validate = $this->doValidation($tempModel); } - $prompt = __("Would you like to define model associations\n(hasMany, hasOne, belongsTo, etc.)?"); + $prompt = __d('cake_console', "Would you like to define model associations\n(hasMany, hasOne, belongsTo, etc.)?"); $wannaDoAssoc = $this->in($prompt, array('y','n'), 'y'); if (strtolower($wannaDoAssoc) == 'y') { $associations = $this->doAssociations($tempModel); @@ -211,24 +213,24 @@ class ModelTask extends BakeTask { $this->out(); $this->hr(); - $this->out(__('The following Model will be created:')); + $this->out(__d('cake_console', 'The following Model will be created:')); $this->hr(); $this->out("Name: " . $currentModelName); if ($this->connection !== 'default') { - $this->out(__("DB Config: %s", $this->connection)); + $this->out(__d('cake_console', "DB Config: %s", $this->connection)); } if ($fullTableName !== Inflector::tableize($currentModelName)) { - $this->out(__('DB Table: %s', $fullTableName)); + $this->out(__d('cake_console', 'DB Table: %s', $fullTableName)); } if ($primaryKey != 'id') { - $this->out(__('Primary Key: %s', $primaryKey)); + $this->out(__d('cake_console', 'Primary Key: %s', $primaryKey)); } if (!empty($validate)) { - $this->out(__('Validation: %s', print_r($validate, true))); + $this->out(__d('cake_console', 'Validation: %s', print_r($validate, true))); } if (!empty($associations)) { - $this->out(__('Associations:')); + $this->out(__d('cake_console', 'Associations:')); $assocKeys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'); foreach ($assocKeys as $assocKey) { $this->_printAssociation($currentModelName, $assocKey, $associations); @@ -236,7 +238,7 @@ class ModelTask extends BakeTask { } $this->hr(); - $looksGood = $this->in(__('Look okay?'), array('y','n'), 'y'); + $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y','n'), 'y'); if (strtolower($looksGood) == 'y') { $vars = compact('associations', 'validate', 'primaryKey', 'useTable', 'displayField'); @@ -281,7 +283,7 @@ class ModelTask extends BakeTask { break; } } - return $this->in(__('What is the primaryKey?'), null, $name); + return $this->in(__d('cake_console', 'What is the primaryKey?'), null, $name); } /** @@ -292,12 +294,12 @@ class ModelTask extends BakeTask { */ public function findDisplayField($fields) { $fieldNames = array_keys($fields); - $prompt = __("A displayField could not be automatically detected\nwould you like to choose one?"); + $prompt = __d('cake_console', "A displayField could not be automatically detected\nwould you like to choose one?"); $continue = $this->in($prompt, array('y', 'n')); if (strtolower($continue) == 'n') { return false; } - $prompt = __('Choose a field from the options above:'); + $prompt = __d('cake_console', 'Choose a field from the options above:'); $choice = $this->inOptions($fieldNames, $prompt); return $fieldNames[$choice]; } @@ -308,7 +310,7 @@ class ModelTask extends BakeTask { * @param object $model Model to have validations generated for. * @return array $validate Array of user selected validations. */ - public function doValidation(&$model) { + public function doValidation($model) { if (!is_object($model)) { return false; } @@ -365,10 +367,10 @@ class ModelTask extends BakeTask { while ($anotherValidator == 'y') { if ($this->interactive) { $this->out(); - $this->out(__('Field: %s', $fieldName)); - $this->out(__('Type: %s', $metaData['type'])); + $this->out(__d('cake_console', 'Field: %s', $fieldName)); + $this->out(__d('cake_console', 'Type: %s', $metaData['type'])); $this->hr(); - $this->out(__('Please select one of the following validation options:')); + $this->out(__d('cake_console', 'Please select one of the following validation options:')); $this->hr(); } @@ -376,8 +378,8 @@ class ModelTask extends BakeTask { for ($i = 1; $i < $defaultChoice; $i++) { $prompt .= $i . ' - ' . $this->_validations[$i] . "\n"; } - $prompt .= __("%s - Do not do any validation on this field.\n", $defaultChoice); - $prompt .= __("... or enter in a valid regex validation string.\n"); + $prompt .= __d('cake_console', "%s - Do not do any validation on this field.\n", $defaultChoice); + $prompt .= __d('cake_console', "... or enter in a valid regex validation string.\n"); $methods = array_flip($this->_validations); $guess = $defaultChoice; @@ -400,11 +402,11 @@ class ModelTask extends BakeTask { if ($this->interactive === true) { $choice = $this->in($prompt, null, $guess); if (in_array($choice, $alreadyChosen)) { - $this->out(__("You have already chosen that validation rule,\nplease choose again")); + $this->out(__d('cake_console', "You have already chosen that validation rule,\nplease choose again")); continue; } if (!isset($this->_validations[$choice]) && is_numeric($choice)) { - $this->out(__('Please make a valid selection.')); + $this->out(__d('cake_console', 'Please make a valid selection.')); continue; } $alreadyChosen[] = $choice; @@ -426,7 +428,7 @@ class ModelTask extends BakeTask { } } if ($this->interactive == true && $choice != $defaultChoice) { - $anotherValidator = $this->in(__('Would you like to add another validation rule?'), array('y', 'n'), 'n'); + $anotherValidator = $this->in(__d('cake_console', 'Would you like to add another validation rule?'), array('y', 'n'), 'n'); } else { $anotherValidator = 'n'; } @@ -440,12 +442,12 @@ class ModelTask extends BakeTask { * @param object $model * @return array $assocaitons */ - public function doAssociations(&$model) { + public function doAssociations($model) { if (!is_object($model)) { return false; } if ($this->interactive === true) { - $this->out(__('One moment while the associations are detected.')); + $this->out(__d('cake_console', 'One moment while the associations are detected.')); } $fields = $model->schema(true); @@ -473,9 +475,9 @@ class ModelTask extends BakeTask { if ($this->interactive === true) { $this->hr(); if (empty($associations)) { - $this->out(__('None found.')); + $this->out(__d('cake_console', 'None found.')); } else { - $this->out(__('Please confirm the following associations:')); + $this->out(__d('cake_console', 'Please confirm the following associations:')); $this->hr(); $associations = $this->confirmAssociations($model, $associations); } @@ -491,7 +493,7 @@ class ModelTask extends BakeTask { * @param array $associations Array of inprogress associations * @return array $associations with belongsTo added in. */ - public function findBelongsTo(&$model, $associations) { + public function findBelongsTo($model, $associations) { $fields = $model->schema(true); foreach ($fields as $fieldName => $field) { $offset = strpos($fieldName, '_id'); @@ -520,7 +522,7 @@ class ModelTask extends BakeTask { * @param array $associations Array of inprogress associations * @return array $associations with hasOne and hasMany added in. */ - public function findHasOneAndMany(&$model, $associations) { + public function findHasOneAndMany($model, $associations) { $foreignKey = $this->_modelKey($model->name); foreach ($this->_tables as $otherTable) { $tempOtherModel = $this->_getModelObject($this->_modelName($otherTable), $otherTable); @@ -563,7 +565,7 @@ class ModelTask extends BakeTask { * @param array $associations Array of inprogress associations * @return array $associations with hasAndBelongsToMany added in. */ - public function findHasAndBelongsToMany(&$model, $associations) { + public function findHasAndBelongsToMany($model, $associations) { $foreignKey = $this->_modelKey($model->name); foreach ($this->_tables as $otherTable) { $tempOtherModel = $this->_getModelObject($this->_modelName($otherTable), $otherTable); @@ -603,7 +605,7 @@ class ModelTask extends BakeTask { * @param array $associations Array of associations to be confirmed. * @return array Array of confirmed associations */ - public function confirmAssociations(&$model, $associations) { + public function confirmAssociations($model, $associations) { foreach ($associations as $type => $settings) { if (!empty($associations[$type])) { $count = count($associations[$type]); @@ -632,19 +634,19 @@ class ModelTask extends BakeTask { * @return array Array of associations. */ public function doMoreAssociations($model, $associations) { - $prompt = __('Would you like to define some additional model associations?'); + $prompt = __d('cake_console', 'Would you like to define some additional model associations?'); $wannaDoMoreAssoc = $this->in($prompt, array('y','n'), 'n'); $possibleKeys = $this->_generatePossibleKeys(); while (strtolower($wannaDoMoreAssoc) == 'y') { $assocs = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'); - $this->out(__('What is the association type?')); - $assocType = intval($this->inOptions($assocs, __('Enter a number'))); + $this->out(__d('cake_console', 'What is the association type?')); + $assocType = intval($this->inOptions($assocs, __d('cake_console', 'Enter a number'))); - $this->out(__("For the following options be very careful to match your setup exactly.\nAny spelling mistakes will cause errors.")); + $this->out(__d('cake_console', "For the following options be very careful to match your setup exactly.\nAny spelling mistakes will cause errors.")); $this->hr(); - $alias = $this->in(__('What is the alias for this association?')); - $className = $this->in(__('What className will %s use?', $alias), null, $alias ); + $alias = $this->in(__d('cake_console', 'What is the alias for this association?')); + $className = $this->in(__d('cake_console', 'What className will %s use?', $alias), null, $alias ); $suggestedForeignKey = null; if ($assocType == 0) { @@ -659,22 +661,22 @@ class ModelTask extends BakeTask { $showKeys = null; } } else { - $otherTable = $this->in(__('What is the table for this model?')); + $otherTable = $this->in(__d('cake_console', 'What is the table for this model?')); $showKeys = $possibleKeys[$otherTable]; } $suggestedForeignKey = $this->_modelKey($model->name); } if (!empty($showKeys)) { - $this->out(__('A helpful List of possible keys')); - $foreignKey = $this->inOptions($showKeys, __('What is the foreignKey?')); + $this->out(__d('cake_console', 'A helpful List of possible keys')); + $foreignKey = $this->inOptions($showKeys, __d('cake_console', 'What is the foreignKey?')); $foreignKey = $showKeys[intval($foreignKey)]; } if (!isset($foreignKey)) { - $foreignKey = $this->in(__('What is the foreignKey? Specify your own.'), null, $suggestedForeignKey); + $foreignKey = $this->in(__d('cake_console', 'What is the foreignKey? Specify your own.'), null, $suggestedForeignKey); } if ($assocType == 3) { - $associationForeignKey = $this->in(__('What is the associationForeignKey?'), null, $this->_modelKey($model->name)); - $joinTable = $this->in(__('What is the joinTable?')); + $associationForeignKey = $this->in(__d('cake_console', 'What is the associationForeignKey?'), null, $this->_modelKey($model->name)); + $joinTable = $this->in(__d('cake_console', 'What is the joinTable?')); } $associations[$assocs[$assocType]] = array_values((array)$associations[$assocs[$assocType]]); $count = count($associations[$assocs[$assocType]]); @@ -686,7 +688,7 @@ class ModelTask extends BakeTask { $associations[$assocs[$assocType]][$i]['associationForeignKey'] = $associationForeignKey; $associations[$assocs[$assocType]][$i]['joinTable'] = $joinTable; } - $wannaDoMoreAssoc = $this->in(__('Define another association?'), array('y','n'), 'y'); + $wannaDoMoreAssoc = $this->in(__d('cake_console', 'Define another association?'), array('y','n'), 'y'); } return $associations; } @@ -739,7 +741,7 @@ class ModelTask extends BakeTask { $out = $this->Template->generate('classes', 'model'); $path = $this->getPath(); - $filename = $path . Inflector::underscore($name) . '.php'; + $filename = $path . $name . '.php'; $this->out("\nBaking model class for $name...", 1, Shell::QUIET); $this->createFile($filename, $out); ClassRegistry::flush(); @@ -767,7 +769,7 @@ class ModelTask extends BakeTask { $this->_tables = $this->getAllTables($useDbConfig); if ($this->interactive === true) { - $this->out(__('Possible Models based on your current database:')); + $this->out(__d('cake_console', 'Possible Models based on your current database:')); $this->_modelNames = array(); $count = count($this->_tables); for ($i = 0; $i < $count; $i++) { @@ -789,7 +791,6 @@ class ModelTask extends BakeTask { if (!isset($useDbConfig)) { $useDbConfig = $this->connection; } - App::import('Model', 'ConnectionManager', false); $db = ConnectionManager::getDataSource($useDbConfig); $useTable = Inflector::tableize($modelName); @@ -798,11 +799,11 @@ class ModelTask extends BakeTask { if (array_search($useTable, $this->_tables) === false) { $this->out(); - $this->out(__("Given your model named '%s',\nCake would expect a database table named '%s'", $modelName, $fullTableName)); - $tableIsGood = $this->in(__('Do you want to use this table?'), array('y','n'), 'y'); + $this->out(__d('cake_console', "Given your model named '%s',\nCake would expect a database table named '%s'", $modelName, $fullTableName)); + $tableIsGood = $this->in(__d('cake_console', 'Do you want to use this table?'), array('y','n'), 'y'); } if (strtolower($tableIsGood) == 'n') { - $useTable = $this->in(__('What is the name of the table?')); + $useTable = $this->in(__d('cake_console', 'What is the name of the table?')); } return $useTable; } @@ -818,7 +819,6 @@ class ModelTask extends BakeTask { if (!isset($useDbConfig)) { $useDbConfig = $this->connection; } - App::import('Model', 'ConnectionManager', false); $tables = array(); $db = ConnectionManager::getDataSource($useDbConfig); @@ -834,7 +834,7 @@ class ModelTask extends BakeTask { $tables = $db->listSources(); } if (empty($tables)) { - $this->err(__('Your database does not have any tables.')); + $this->err(__d('cake_console', 'Your database does not have any tables.')); $this->_stop(); } return $tables; @@ -851,15 +851,15 @@ class ModelTask extends BakeTask { $enteredModel = ''; while ($enteredModel == '') { - $enteredModel = $this->in(__("Enter a number from the list above,\ntype in the name of another model, or 'q' to exit"), null, 'q'); + $enteredModel = $this->in(__d('cake_console', "Enter a number from the list above,\ntype in the name of another model, or 'q' to exit"), null, 'q'); if ($enteredModel === 'q') { - $this->out(__('Exit')); + $this->out(__d('cake_console', 'Exit')); $this->_stop(); } if ($enteredModel == '' || intval($enteredModel) > count($this->_modelNames)) { - $this->err(__("The model name you supplied was empty,\nor the number you selected was not an option. Please try again.")); + $this->err(__d('cake_console', "The model name you supplied was empty,\nor the number you selected was not an option. Please try again.")); $enteredModel = ''; } } @@ -879,18 +879,18 @@ class ModelTask extends BakeTask { public function getOptionParser() { $parser = parent::getOptionParser(); return $parser->description( - __('Bake models.') + __d('cake_console', 'Bake models.') )->addArgument('name', array( - 'help' => __('Name of the model to bake. Can use Plugin.name to bake plugin models.') + 'help' => __d('cake_console', 'Name of the model to bake. Can use Plugin.name to bake plugin models.') ))->addSubcommand('all', array( - 'help' => __('Bake all model files with associations and validation.') + 'help' => __d('cake_console', 'Bake all model files with associations and validation.') ))->addOption('plugin', array( 'short' => 'p', - 'help' => __('Plugin to bake the model into.') + 'help' => __d('cake_console', 'Plugin to bake the model into.') ))->addOption('connection', array( 'short' => 'c', - 'help' => __('The connection the model table is on.') - ))->epilog(__('Omitting all arguments and options will enter into an interactive mode.')); + 'help' => __d('cake_console', 'The connection the model table is on.') + ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')); } /** diff --git a/cake/console/shells/tasks/plugin.php b/lib/Cake/Console/Command/Task/PluginTask.php similarity index 82% rename from cake/console/shells/tasks/plugin.php rename to lib/Cake/Console/Command/Task/PluginTask.php index 118273d45..1b6033137 100644 --- a/cake/console/shells/tasks/plugin.php +++ b/lib/Cake/Console/Command/Task/PluginTask.php @@ -16,7 +16,9 @@ * @since CakePHP(tm) v 1.2 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'File'); + +App::uses('File', 'Utility'); +App::uses('Folder', 'Utility'); /** * Task class for creating a plugin @@ -54,8 +56,8 @@ class PluginTask extends Shell { $plugin = Inflector::camelize($this->args[0]); $pluginPath = $this->_pluginPath($plugin); if (is_dir($pluginPath)) { - $this->out(__('Plugin: %s', $plugin)); - $this->out(__('Path: %s', $pluginPath)); + $this->out(__d('cake_console', 'Plugin: %s', $plugin)); + $this->out(__d('cake_console', 'Path: %s', $pluginPath)); } else { $this->_interactive($plugin); } @@ -72,11 +74,11 @@ class PluginTask extends Shell { */ protected function _interactive($plugin = null) { while ($plugin === null) { - $plugin = $this->in(__('Enter the name of the plugin in CamelCase format')); + $plugin = $this->in(__d('cake_console', 'Enter the name of the plugin in CamelCase format')); } if (!$this->bake($plugin)) { - $this->error(__("An error occured trying to bake: %s in %s", $plugin, $this->path . Inflector::underscore($pluginPath))); + $this->error(__d('cake_console', "An error occured trying to bake: %s in %s", $plugin, $this->path . Inflector::underscore($pluginPath))); } } @@ -95,11 +97,11 @@ class PluginTask extends Shell { $this->findPath($pathOptions); } $this->hr(); - $this->out(__("Plugin Name: %s", $plugin)); - $this->out(__("Plugin Directory: %s", $this->path . $pluginPath)); + $this->out(__d('cake_console', "Plugin Name: %s", $plugin)); + $this->out(__d('cake_console', "Plugin Directory: %s", $this->path . $pluginPath)); $this->hr(); - $looksGood = $this->in(__('Look okay?'), array('y', 'n', 'q'), 'y'); + $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n', 'q'), 'y'); if (strtolower($looksGood) == 'y') { $Folder = new Folder($this->path . $pluginPath); @@ -154,7 +156,7 @@ class PluginTask extends Shell { $this->createFile($this->path . $pluginPath . DS . $modelFileName, $out); $this->hr(); - $this->out(__('Created: %s in %s', $plugin, $this->path . $pluginPath), 2); + $this->out(__d('cake_console', 'Created: %s in %s', $plugin, $this->path . $pluginPath), 2); } return true; @@ -172,7 +174,7 @@ class PluginTask extends Shell { foreach ($pathOptions as $i => $option) { $this->out($i + 1 .'. ' . $option); } - $prompt = __('Choose a plugin path from the paths above.'); + $prompt = __d('cake_console', 'Choose a plugin path from the paths above.'); $choice = $this->in($prompt); if (intval($choice) > 0 && intval($choice) <= $max) { $valid = true; @@ -192,7 +194,7 @@ class PluginTask extends Shell { 'Create the directory structure, AppModel and AppController classes for a new plugin. ' . 'Can create plugins in any of your bootstrapped plugin paths.' )->addArgument('name', array( - 'help' => __('CamelCased name of the plugin to create.') + 'help' => __d('cake_console', 'CamelCased name of the plugin to create.') )); } diff --git a/cake/console/shells/tasks/project.php b/lib/Cake/Console/Command/Task/ProjectTask.php similarity index 64% rename from cake/console/shells/tasks/project.php rename to lib/Cake/Console/Command/Task/ProjectTask.php index 433ce9616..368512741 100644 --- a/cake/console/shells/tasks/project.php +++ b/lib/Cake/Console/Command/Task/ProjectTask.php @@ -17,7 +17,10 @@ * @since CakePHP(tm) v 1.2 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'File'); + +App::uses('File', 'Utility'); +App::uses('String', 'Utility'); +App::uses('Security', 'Utility'); /** * Task class for creating new project apps and plugins @@ -49,16 +52,8 @@ class ProjectTask extends Shell { $project = $_SERVER['PWD'] . DS . $project; } - if (empty($this->params['skel'])) { - $core = App::core('shells'); - $skelPath = dirname($core[0]) . DS . 'templates' . DS . 'skel'; - if (is_dir($skelPath) === true) { - $this->params['skel'] = $skelPath; - } - } - while (!$project) { - $prompt = __("What is the full path for this app including the app directory name?\n Example:"); + $prompt = __d('cake_console', "What is the full path for this app including the app directory name?\n Example:"); $default = APP_PATH . 'myapp'; $project = $this->in($prompt . $default, null, $default); } @@ -66,7 +61,7 @@ class ProjectTask extends Shell { if ($project) { $response = false; while ($response == false && is_dir($project) === true && file_exists($project . 'config' . 'core.php')) { - $prompt = __('A project already exists in this location: %s Overwrite?', $project); + $prompt = __d('cake_console', 'A project already exists in this location: %s Overwrite?', $project); $response = $this->in($prompt, array('y','n'), 'n'); if (strtolower($response) === 'n') { $response = $project = false; @@ -78,51 +73,51 @@ class ProjectTask extends Shell { if ($this->bake($project)) { $path = Folder::slashTerm($project); if ($this->createHome($path)) { - $this->out(__(' * Welcome page created')); + $this->out(__d('cake_console', ' * Welcome page created')); } else { - $this->err(__('The Welcome page was NOT created')); + $this->err(__d('cake_console', 'The Welcome page was NOT created')); $success = false; } if ($this->securitySalt($path) === true) { - $this->out(__(' * Random hash key created for \'Security.salt\'')); + $this->out(__d('cake_console', ' * Random hash key created for \'Security.salt\'')); } else { - $this->err(__('Unable to generate random hash for \'Security.salt\', you should change it in %s', CONFIGS . 'core.php')); + $this->err(__d('cake_console', 'Unable to generate random hash for \'Security.salt\', you should change it in %s', CONFIGS . 'core.php')); $success = false; } if ($this->securityCipherSeed($path) === true) { - $this->out(__(' * Random seed created for \'Security.cipherSeed\'')); + $this->out(__d('cake_console', ' * Random seed created for \'Security.cipherSeed\'')); } else { - $this->err(__('Unable to generate random seed for \'Security.cipherSeed\', you should change it in %s', CONFIGS . 'core.php')); + $this->err(__d('cake_console', 'Unable to generate random seed for \'Security.cipherSeed\', you should change it in %s', CONFIGS . 'core.php')); $success = false; } if ($this->corePath($path) === true) { - $this->out(__(' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/index.php', CAKE_CORE_INCLUDE_PATH)); - $this->out(__(' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/test.php', CAKE_CORE_INCLUDE_PATH)); - $this->out(__(' * Remember to check these value after moving to production server')); + $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/index.php', CAKE_CORE_INCLUDE_PATH)); + $this->out(__d('cake_console', ' * CAKE_CORE_INCLUDE_PATH set to %s in webroot/test.php', CAKE_CORE_INCLUDE_PATH)); + $this->out(__d('cake_console', ' * Remember to check these value after moving to production server')); } else { - $this->err(__('Unable to set CAKE_CORE_INCLUDE_PATH, you should change it in %s', $path . 'webroot' .DS .'index.php')); + $this->err(__d('cake_console', 'Unable to set CAKE_CORE_INCLUDE_PATH, you should change it in %s', $path . 'webroot' .DS .'index.php')); $success = false; } if ($this->consolePath($path) === true) { - $this->out(__(' * app/console/cake.php path set.')); + $this->out(__d('cake_console', ' * app/Console/cake.php path set.')); } else { - $this->err(__('Unable to set console path for app/console.')); + $this->err(__d('cake_console', 'Unable to set console path for app/Console.')); $success = false; } $Folder = new Folder($path); if (!$Folder->chmod($path . 'tmp', 0777)) { - $this->err(__('Could not set permissions on %s', $path . DS .'tmp')); - $this->out(__('chmod -R 0777 %s', $path . DS .'tmp')); + $this->err(__d('cake_console', 'Could not set permissions on %s', $path . DS .'tmp')); + $this->out(__d('cake_console', 'chmod -R 0777 %s', $path . DS .'tmp')); $success = false; } if ($success) { - $this->out(__('Project baked successfully!')); + $this->out(__d('cake_console', 'Project baked successfully!')); } else { - $this->out(__('Project baked but with some issues..')); + $this->out(__d('cake_console', 'Project baked but with some issues..')); } return $path; } @@ -140,27 +135,35 @@ class ProjectTask extends Shell { * @access private */ function bake($path, $skel = null, $skip = array('empty')) { - if (!$skel) { + if (!$skel && !empty($this->params['skel'])) { $skel = $this->params['skel']; } while (!$skel) { - $skel = $this->in(__("What is the path to the directory layout you wish to copy?\nExample: %s", APP, null, ROOT . DS . 'myapp' . DS)); - if ($skel == '') { - $this->err(__('The directory path you supplied was empty. Please try again.')); + $skel = $this->in( + __d('cake_console', "What is the path to the directory layout you wish to copy?"), + null, + CAKE . 'Console' . DS . 'templates' . DS . 'skel' + ); + if (!$skel) { + $this->err(__d('cake_console', 'The directory path you supplied was empty. Please try again.')); } else { while (is_dir($skel) === false) { - $skel = $this->in(__('Directory path does not exist please choose another:')); + $skel = $this->in( + __d('cake_console', 'Directory path does not exist please choose another:'), + null, + CAKE . 'Console' . DS . 'templates' . DS . 'skel' + ); } } } $app = basename($path); - $this->out(__('Skel Directory: ') . $skel); - $this->out(__('Will be copied to: ') . $path); + $this->out(__d('cake_console', 'Skel Directory: ') . $skel); + $this->out(__d('cake_console', 'Will be copied to: ') . $path); $this->hr(); - $looksGood = $this->in(__('Look okay?'), array('y', 'n', 'q'), 'y'); + $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y', 'n', 'q'), 'y'); if (strtolower($looksGood) == 'y') { $Folder = new Folder($skel); @@ -170,10 +173,10 @@ class ProjectTask extends Shell { if ($Folder->copy(array('to' => $path, 'skip' => $skip))) { $this->hr(); - $this->out(__('Created: %s in %s', $app, $path)); + $this->out(__d('cake_console', 'Created: %s in %s', $app, $path)); $this->hr(); } else { - $this->err(__("Could not create '%s' properly.", $app)); + $this->err(__d('cake_console', "Could not create '%s' properly.", $app)); return false; } @@ -183,7 +186,7 @@ class ProjectTask extends Shell { return true; } elseif (strtolower($looksGood) == 'q') { - $this->out(__('Bake Aborted.')); + $this->out(__d('cake_console', 'Bake Aborted.')); } else { $this->execute(false); return false; @@ -199,7 +202,7 @@ class ProjectTask extends Shell { public function createHome($dir) { $app = basename($dir); $path = $dir . 'views' . DS . 'pages' . DS; - $source = CAKE . 'console' . DS . 'templates' . DS .'default' . DS . 'views' . DS . 'home.ctp'; + $source = LIBS . 'Console' . DS . 'templates' . DS .'default' . DS . 'views' . DS . 'home.ctp'; include($source); return $this->createFile($path.'home.ctp', $output); } @@ -212,10 +215,10 @@ class ProjectTask extends Shell { * @return boolean success */ public function consolePath($path) { - $File = new File($path . 'console' . DS . 'cake.php'); + $File = new File($path . 'Console' . DS . 'cake.php'); $contents = $File->read(); if (preg_match('/(__CAKE_PATH__)/', $contents, $match)) { - $path = CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'console' . DS; + $path = LIBS . 'Console' . DS; $replacement = "'" . str_replace(DS, "' . DIRECTORY_SEPARATOR . '", $path) . "'"; $result = str_replace($match[0], $replacement, $contents); if ($File->write($result)) { @@ -236,9 +239,6 @@ class ProjectTask extends Shell { $File = new File($path . 'config' . DS . 'core.php'); $contents = $File->read(); if (preg_match('/([\s]*Configure::write\(\'Security.salt\',[\s\'A-z0-9]*\);)/', $contents, $match)) { - if (!class_exists('Security')) { - require LIBS . 'security.php'; - } $string = Security::generateAuthKey(); $result = str_replace($match[0], "\t" . 'Configure::write(\'Security.salt\', \''.$string.'\');', $contents); if ($File->write($result)) { @@ -260,7 +260,7 @@ class ProjectTask extends Shell { $contents = $File->read(); if (preg_match('/([\s]*Configure::write\(\'Security.cipherSeed\',[\s\'A-z0-9]*\);)/', $contents, $match)) { if (!class_exists('Security')) { - require LIBS . 'security.php'; + require LIBS . 'Utility' . DS . 'security.php'; } $string = substr(bin2hex(Security::generateAuthKey()), 0, 30); $result = str_replace($match[0], "\t" . 'Configure::write(\'Security.cipherSeed\', \''.$string.'\');', $contents); @@ -284,7 +284,7 @@ class ProjectTask extends Shell { $contents = $File->read(); if (preg_match('/([\s]*define\(\'CAKE_CORE_INCLUDE_PATH\',[\s\'A-z0-9]*\);)/', $contents, $match)) { $root = strpos(CAKE_CORE_INCLUDE_PATH, '/') === 0 ? " DS . '" : "'"; - $result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', " . $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "');", $contents); + $result = str_replace($match[0], "\n\t\tdefine('CAKE_CORE_INCLUDE_PATH', " . $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "');", $contents); if (!$File->write($result)) { return false; } @@ -295,7 +295,7 @@ class ProjectTask extends Shell { $File = new File($path . 'webroot' . DS . 'test.php'); $contents = $File->read(); if (preg_match('/([\s]*define\(\'CAKE_CORE_INCLUDE_PATH\',[\s\'A-z0-9]*\);)/', $contents, $match)) { - $result = str_replace($match[0], "\t\tdefine('CAKE_CORE_INCLUDE_PATH', " . $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "');", $contents); + $result = str_replace($match[0], "\n\t\tdefine('CAKE_CORE_INCLUDE_PATH', " . $root . str_replace(DS, "' . DS . '", trim(CAKE_CORE_INCLUDE_PATH, DS)) . "');", $contents); if (!$File->write($result)) { return false; } @@ -316,8 +316,8 @@ class ProjectTask extends Shell { $path = (empty($this->configPath)) ? CONFIGS : $this->configPath; $File = new File($path . 'core.php'); $contents = $File->read(); - if (preg_match('%([/\s]*Configure::write\(\'Routing.prefixes\',[\s\'a-z,\)\(]*\);)%', $contents, $match)) { - $result = str_replace($match[0], "\t" . 'Configure::write(\'Routing.prefixes\', array(\''.$name.'\'));', $contents); + if (preg_match('%(\s*[/]*Configure::write\(\'Routing.prefixes\',[\s\'a-z,\)\(]*\);)%', $contents, $match)) { + $result = str_replace($match[0], "\n" . 'Configure::write(\'Routing.prefixes\', array(\''.$name.'\'));', $contents); if ($File->write($result)) { Configure::write('Routing.prefixes', array($name)); return true; @@ -343,7 +343,7 @@ class ProjectTask extends Shell { } if ($this->interactive) { $this->out(); - $this->out(__('You have more than one routing prefix configured')); + $this->out(__d('cake_console', 'You have more than one routing prefix configured')); } $options = array(); foreach ($prefixes as $i => $prefix) { @@ -352,19 +352,19 @@ class ProjectTask extends Shell { $this->out($i + 1 . '. ' . $prefix); } } - $selection = $this->in(__('Please choose a prefix to bake with.'), $options, 1); + $selection = $this->in(__d('cake_console', 'Please choose a prefix to bake with.'), $options, 1); return $prefixes[$selection - 1] . '_'; } if ($this->interactive) { $this->hr(); $this->out('You need to enable Configure::write(\'Routing.prefixes\',array(\'admin\')) in /app/config/core.php to use prefix routing.'); - $this->out(__('What would you like the prefix route to be?')); - $this->out(__('Example: www.example.com/admin/controller')); + $this->out(__d('cake_console', 'What would you like the prefix route to be?')); + $this->out(__d('cake_console', 'Example: www.example.com/admin/controller')); while ($admin == '') { - $admin = $this->in(__('Enter a routing prefix:'), null, 'admin'); + $admin = $this->in(__d('cake_console', 'Enter a routing prefix:'), null, 'admin'); } if ($this->cakeAdmin($admin) !== true) { - $this->out(__('Unable to write to /app/config/core.php.')); + $this->out(__d('cake_console', 'Unable to write to /app/config/core.php.')); $this->out('You need to enable Configure::write(\'Routing.prefixes\',array(\'admin\')) in /app/config/core.php to use prefix routing.'); $this->_stop(); } @@ -381,14 +381,15 @@ class ProjectTask extends Shell { public function getOptionParser() { $parser = parent::getOptionParser(); return $parser->description( - __('Generate a new CakePHP project skeleton.') + __d('cake_console', 'Generate a new CakePHP project skeleton.') )->addArgument('name', array( - 'help' => __('Application directory to make, if it starts with "/" the path is absolute.') + 'help' => __d('cake_console', 'Application directory to make, if it starts with "/" the path is absolute.') ))->addOption('empty', array( - 'help' => __('Create empty files in each of the directories. Good if you are using git') + 'help' => __d('cake_console', 'Create empty files in each of the directories. Good if you are using git') ))->addOption('skel', array( - 'help' => __('The directory layout to use for the new application skeleton. Defaults to cake/console/templates/skel of CakePHP used to create the project.') + 'default' => current(App::core('Console')) . DS . 'templates' . DS . 'skel', + 'help' => __d('cake_console', 'The directory layout to use for the new application skeleton. Defaults to cake/console/templates/skel of CakePHP used to create the project.') )); } -} +} \ No newline at end of file diff --git a/cake/console/shells/tasks/template.php b/lib/Cake/Console/Command/Task/TemplateTask.php similarity index 92% rename from cake/console/shells/tasks/template.php rename to lib/Cake/Console/Command/Task/TemplateTask.php index 108ffa8a4..189cf7f83 100644 --- a/cake/console/shells/tasks/template.php +++ b/lib/Cake/Console/Command/Task/TemplateTask.php @@ -16,7 +16,8 @@ * @since CakePHP(tm) v 1.3 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'Folder'); + +App::uses('Folder', 'Utility'); class TemplateTask extends Shell { @@ -53,12 +54,13 @@ class TemplateTask extends Shell { * @return array Array of bake themes that are installed. */ protected function _findThemes() { - $paths = App::path('shells'); - $core = array_pop($paths); + $paths = App::path('Console'); + $core = current(App::core('Console')); $separator = DS === '/' ? '/' : '\\\\'; $core = preg_replace('#shells' . $separator . '$#', '', $core); - $paths[] = $core; + $Folder = new Folder($core . 'templates' . DS . 'default'); + $contents = $Folder->read(); $themeFolders = $contents[0]; @@ -67,6 +69,7 @@ class TemplateTask extends Shell { $paths[] = $this->_pluginPath($plugin) . 'console' . DS . 'shells' . DS; $paths[] = $this->_pluginPath($plugin) . 'vendors' . DS . 'shells' . DS; } + $paths[] = $core; // TEMPORARY TODO remove when all paths are DS terminated foreach ($paths as $i => $path) { @@ -167,8 +170,8 @@ class TemplateTask extends Shell { } $this->hr(); - $this->out(__('You have more than one set of templates installed.')); - $this->out(__('Please choose the template set you wish to use:')); + $this->out(__d('cake_console', 'You have more than one set of templates installed.')); + $this->out(__d('cake_console', 'Please choose the template set you wish to use:')); $this->hr(); $i = 1; @@ -178,7 +181,7 @@ class TemplateTask extends Shell { $indexedPaths[$i] = $path; $i++; } - $index = $this->in(__('Which bake theme would you like to use?'), range(1, $i - 1), 1); + $index = $this->in(__d('cake_console', 'Which bake theme would you like to use?'), range(1, $i - 1), 1); $themeNames = array_keys($this->templatePaths); $this->params['theme'] = $themeNames[$index - 1]; return $indexedPaths[$index]; @@ -205,7 +208,7 @@ class TemplateTask extends Shell { return $templatePath; } } - $this->err(__('Could not find template for %s', $filename)); + $this->err(__d('cake_console', 'Could not find template for %s', $filename)); return false; } } diff --git a/cake/console/shells/tasks/test.php b/lib/Cake/Console/Command/Task/TestTask.php similarity index 76% rename from cake/console/shells/tasks/test.php rename to lib/Cake/Console/Command/Task/TestTask.php index 0fe453040..56ecd502e 100644 --- a/cake/console/shells/tasks/test.php +++ b/lib/Cake/Console/Command/Task/TestTask.php @@ -17,8 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -include_once dirname(__FILE__) . DS . 'bake.php'; -App::import('Model', 'ClassRegistry'); +App::uses('BakeTask', 'Console/Command/Task'); +App::uses('ClassRegistry', 'Utility'); /** * Task class for creating and updating test files. @@ -49,7 +49,13 @@ class TestTask extends BakeTask { * @var array * @access public */ - public $classTypes = array('Model', 'Controller', 'Component', 'Behavior', 'Helper'); + public $classTypes = array( + 'Model' => 'Model', + 'Controller' => 'Controller', + 'Component' => 'Controller/Component', + 'Behavior' => 'Model/Behavior', + 'Helper' => 'View/Helper' + ); /** * Internal list of fixtures that have been added so far. @@ -89,14 +95,14 @@ class TestTask extends BakeTask { protected function _interactive($type = null) { $this->interactive = true; $this->hr(); - $this->out(__('Bake Tests')); - $this->out(__('Path: %s', $this->path)); + $this->out(__d('cake_console', 'Bake Tests')); + $this->out(__d('cake_console', 'Path: %s', $this->path)); $this->hr(); if ($type) { $type = Inflector::camelize($type); - if (!in_array($type, $this->classTypes)) { - $this->error(__('Incorrect type provided. Please choose one of %s', implode(', ', $this->classTypes))); + if (!isset($this->classTypes[$type])) { + $this->error(__d('cake_console', 'Incorrect type provided. Please choose one of %s', implode(', ', array_keys($this->classTypes)))); } } else { $type = $this->getObjectType(); @@ -113,13 +119,17 @@ class TestTask extends BakeTask { */ public function bake($type, $className) { if ($this->typeCanDetectFixtures($type) && $this->isLoadableClass($type, $className)) { - $this->out(__('Bake is detecting possible fixtures...')); + $this->out(__d('cake_console', 'Bake is detecting possible fixtures...')); $testSubject = $this->buildTestSubject($type, $className); $this->generateFixtureList($testSubject); } elseif ($this->interactive) { $this->getUserFixtures(); } - $fullClassName = $this->getRealClassName($type, $className); + $fullClassName = $className; + + if (!$this->interactive) { + $fullClassName = $this->getRealClassName($type, $className); + } $methods = array(); if (class_exists($fullClassName)) { @@ -154,20 +164,22 @@ class TestTask extends BakeTask { */ public function getObjectType() { $this->hr(); - $this->out(__('Select an object type:')); + $this->out(__d('cake_console', 'Select an object type:')); $this->hr(); $keys = array(); - foreach ($this->classTypes as $key => $option) { - $this->out(++$key . '. ' . $option); - $keys[] = $key; + $i = 0; + foreach ($this->classTypes as $option => $package) { + $this->out(++$i . '. ' . $option); + $keys[] = $i; } $keys[] = 'q'; - $selection = $this->in(__('Enter the type of object to bake a test for or (q)uit'), $keys, 'q'); + $selection = $this->in(__d('cake_console', 'Enter the type of object to bake a test for or (q)uit'), $keys, 'q'); if ($selection == 'q') { return $this->_stop(); } - return $this->classTypes[$selection - 1]; + $types = array_keys($this->classTypes); + return $types[$selection - 1]; } /** @@ -177,14 +189,28 @@ class TestTask extends BakeTask { * @return string Class name the user chose. */ public function getClassName($objectType) { - $options = App::objects(strtolower($objectType)); - $this->out(__('Choose a %s class', $objectType)); + $type = strtolower($objectType); + if ($this->plugin) { + $path = Inflector::pluralize($type); + if ($type === 'helper') { + $path = 'View/Helper'; + } elseif ($type === 'component') { + $path = 'Controller/Component'; + } elseif ($type === 'behavior') { + $path = 'Model/Behavior'; + } + $plugin = $this->plugin . '.'; + $options = App::objects($plugin . $type); + } else { + $options = App::objects($type); + } + $this->out(__d('cake_console', 'Choose a %s class', $objectType)); $keys = array(); foreach ($options as $key => $option) { $this->out(++$key . '. ' . $option); $keys[] = $key; } - $selection = $this->in(__('Choose an existing class, or enter the name of a class that does not exist')); + $selection = $this->in(__d('cake_console', 'Choose an existing class, or enter the name of a class that does not exist')); if (isset($options[$selection - 1])) { return $options[$selection - 1]; } @@ -243,7 +269,7 @@ class TestTask extends BakeTask { * @return string Real classname */ public function getRealClassName($type, $class) { - if (strtolower($type) == 'model') { + if (strtolower($type) == 'model' || empty($this->classTypes[$type])) { return $class; } return $class . $type; @@ -276,7 +302,7 @@ class TestTask extends BakeTask { * @param object $subject The object you want to generate fixtures for. * @return array Array of fixtures to be included in the test. */ - public function generateFixtureList(&$subject) { + public function generateFixtureList($subject) { $this->_fixtures = array(); if (is_a($subject, 'Model')) { $this->_processModel($subject); @@ -293,7 +319,7 @@ class TestTask extends BakeTask { * @param Model $subject A Model class to scan for associations and pull fixtures off of. * @return void */ - protected function _processModel(&$subject) { + protected function _processModel($subject) { $this->_addFixture($subject->name); $associated = $subject->getAssociated(); foreach ($associated as $alias => $type) { @@ -317,7 +343,7 @@ class TestTask extends BakeTask { * @param Controller $subject A controller to pull model names off of. * @return void */ - protected function _processController(&$subject) { + protected function _processController($subject) { $subject->constructClasses(); $models = array(Inflector::classify($subject->name)); if (!empty($subject->uses)) { @@ -352,10 +378,10 @@ class TestTask extends BakeTask { * @return array Array of fixtures the user wants to add. */ public function getUserFixtures() { - $proceed = $this->in(__('Bake could not detect fixtures, would you like to add some?'), array('y','n'), 'n'); + $proceed = $this->in(__d('cake_console', 'Bake could not detect fixtures, would you like to add some?'), array('y','n'), 'n'); $fixtures = array(); if (strtolower($proceed) == 'y') { - $fixtureList = $this->in(__("Please provide a comma separated list of the fixtures names you'd like to use.\nExample: 'app.comment, app.post, plugin.forums.post'")); + $fixtureList = $this->in(__d('cake_console', "Please provide a comma separated list of the fixtures names you'd like to use.\nExample: 'app.comment, app.post, plugin.forums.post'")); $fixtureListTrimmed = str_replace(' ', '', $fixtureList); $fixtures = explode(',', $fixtureListTrimmed); } @@ -403,12 +429,14 @@ class TestTask extends BakeTask { * @return string filename the test should be created on. */ public function testCaseFileName($type, $className) { - $path = $this->getPath();; - $path .= 'cases' . DS . strtolower($type) . 's' . DS; - if (strtolower($type) == 'controller') { + $path = $this->getPath() . 'Case' . DS; + if (isset($this->classTypes[$type])) { + $path .= $this->classTypes[$type] . DS; + } + if (!$this->interactive) { $className = $this->getRealClassName($type, $className); } - return $path . Inflector::underscore($className) . '.test.php'; + return $path . Inflector::camelize($className) . 'Test.php'; } /** @@ -418,15 +446,29 @@ class TestTask extends BakeTask { */ public function getOptionParser() { $parser = parent::getOptionParser(); - return $parser->description(__('Bake test case skeletons for classes.')) + return $parser->description(__d('cake_console', 'Bake test case skeletons for classes.')) ->addArgument('type', array( - 'help' => __('Type of class to bake, can be any of the following: controller, model, helper, component or behavior.'), + 'help' => __d('cake_console', 'Type of class to bake, can be any of the following: controller, model, helper, component or behavior.'), 'choices' => array('controller', 'model', 'helper', 'component', 'behavior') ))->addArgument('name', array( - 'help' => __('An existing class to bake tests for.') + 'help' => __d('cake_console', 'An existing class to bake tests for.') ))->addOption('plugin', array( 'short' => 'p', - 'help' => __('CamelCased name of the plugin to bake tests for.') - ))->epilog(__('Omitting all arguments and options will enter into an interactive mode.')); + 'help' => __d('cake_console', 'CamelCased name of the plugin to bake tests for.') + ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')); + } + +/** + * Gets the path for output. Checks the plugin property + * and returns the correct path. + * + * @return string Path to output. + */ + public function getPath() { + $path = $this->path; + if (isset($this->plugin)) { + $path = $this->_pluginPath($this->plugin) . 'tests' . DS; + } + return $path; } } diff --git a/cake/console/shells/tasks/view.php b/lib/Cake/Console/Command/Task/ViewTask.php similarity index 79% rename from cake/console/shells/tasks/view.php rename to lib/Cake/Console/Command/Task/ViewTask.php index 51c84f2f3..5e9a78c50 100644 --- a/cake/console/shells/tasks/view.php +++ b/lib/Cake/Console/Command/Task/ViewTask.php @@ -16,8 +16,9 @@ * @since CakePHP(tm) v 1.2 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Controller', 'Controller', false); -include_once dirname(__FILE__) . DS . 'bake.php'; + +App::uses('Controller', 'Controller'); +App::uses('BakeTask', 'Console/Command/Task'); /** * Task class for creating and updating view files. @@ -146,7 +147,7 @@ class ViewTask extends BakeTask { protected function _methodsToBake() { $methods = array_diff( array_map('strtolower', get_class_methods($this->controllerName . 'Controller')), - array_map('strtolower', get_class_methods('appcontroller')) + array_map('strtolower', get_class_methods('AppController')) ); $scaffoldActions = false; if (empty($methods)) { @@ -188,7 +189,8 @@ class ViewTask extends BakeTask { $model = $this->_modelName($table); $this->controllerName = $this->_controllerName($model); $this->controllerPath = Inflector::underscore($this->controllerName); - if (App::import('Model', $model)) { + App::uses($model, 'Model'); + if (class_exists($model)) { $vars = $this->__loadController(); if (!$actions) { $actions = $this->_methodsToBake(); @@ -219,17 +221,17 @@ class ViewTask extends BakeTask { $this->controllerPath = strtolower(Inflector::underscore($this->controllerName)); - $prompt = __("Would you like bake to build your views interactively?\nWarning: Choosing no will overwrite %s views if it exist.", $this->controllerName); + $prompt = __d('cake_console', "Would you like bake to build your views interactively?\nWarning: Choosing no will overwrite %s views if it exist.", $this->controllerName); $interactive = $this->in($prompt, array('y', 'n'), 'n'); if (strtolower($interactive) == 'n') { $this->interactive = false; } - $prompt = __("Would you like to create some CRUD views\n(index, add, view, edit) for this controller?\nNOTE: Before doing so, you'll need to create your controller\nand model classes (including associated models)."); + $prompt = __d('cake_console', "Would you like to create some CRUD views\n(index, add, view, edit) for this controller?\nNOTE: Before doing so, you'll need to create your controller\nand model classes (including associated models)."); $wannaDoScaffold = $this->in($prompt, array('y','n'), 'y'); - $wannaDoAdmin = $this->in(__("Would you like to create the views for admin routing?"), array('y','n'), 'n'); + $wannaDoAdmin = $this->in(__d('cake_console', "Would you like to create the views for admin routing?"), array('y','n'), 'n'); if (strtolower($wannaDoScaffold) == 'y' || strtolower($wannaDoAdmin) == 'y') { $vars = $this->__loadController(); @@ -248,7 +250,7 @@ class ViewTask extends BakeTask { } $this->hr(); $this->out(); - $this->out(__("View Scaffolding Complete.\n")); + $this->out(__d('cake_console', "View Scaffolding Complete.\n")); } else { $this->customAction(); } @@ -266,20 +268,21 @@ class ViewTask extends BakeTask { */ private function __loadController() { if (!$this->controllerName) { - $this->err(__('Controller not found')); + $this->err(__d('cake_console', 'Controller not found')); } - $import = $this->controllerName; + $plugin = null; if ($this->plugin) { - $import = $this->plugin . '.' . $this->controllerName; + $plugin = $this->plugin . '.'; } - if (!App::import('Controller', $import)) { - $file = $this->controllerPath . '_controller.php'; - $this->err(__("The file '%s' could not be found.\nIn order to bake a view, you'll need to first create the controller.", $file)); + $controllerClassName = $this->controllerName . 'Controller'; + App::uses($controllerClassName, $plugin . 'Controller'); + if (!class_exists($controllerClassName)) { + $file = $controllerClassName . '.php'; + $this->err(__d('cake_console', "The file '%s' could not be found.\nIn order to bake a view, you'll need to first create the controller.", $file)); $this->_stop(); } - $controllerClassName = $this->controllerName . 'Controller'; $controllerObj = new $controllerClassName(); $controllerObj->plugin = $this->plugin; $controllerObj->constructClasses(); @@ -328,25 +331,25 @@ class ViewTask extends BakeTask { public function customAction() { $action = ''; while ($action == '') { - $action = $this->in(__('Action Name? (use lowercase_underscored function name)')); + $action = $this->in(__d('cake_console', 'Action Name? (use lowercase_underscored function name)')); if ($action == '') { - $this->out(__('The action name you supplied was empty. Please try again.')); + $this->out(__d('cake_console', 'The action name you supplied was empty. Please try again.')); } } $this->out(); $this->hr(); - $this->out(__('The following view will be created:')); + $this->out(__d('cake_console', 'The following view will be created:')); $this->hr(); - $this->out(__('Controller Name: %s', $this->controllerName)); - $this->out(__('Action Name: %s', $action)); - $this->out(__('Path: %s', $this->params['app'] . DS . $this->controllerPath . DS . Inflector::underscore($action) . ".ctp")); + $this->out(__d('cake_console', 'Controller Name: %s', $this->controllerName)); + $this->out(__d('cake_console', 'Action Name: %s', $action)); + $this->out(__d('cake_console', 'Path: %s', $this->params['app'] . DS . $this->controllerPath . DS . Inflector::underscore($action) . ".ctp")); $this->hr(); - $looksGood = $this->in(__('Look okay?'), array('y','n'), 'y'); + $looksGood = $this->in(__d('cake_console', 'Look okay?'), array('y','n'), 'y'); if (strtolower($looksGood) == 'y') { $this->bake($action, ' '); $this->_stop(); } else { - $this->out(__('Bake Aborted.')); + $this->out(__d('cake_console', 'Bake Aborted.')); } } @@ -428,25 +431,25 @@ class ViewTask extends BakeTask { public function getOptionParser() { $parser = parent::getOptionParser(); return $parser->description( - __('Bake views for a controller, using built-in or custom templates.') + __d('cake_console', 'Bake views for a controller, using built-in or custom templates.') )->addArgument('controller', array( - 'help' => __('Name of the controller views to bake. Can be Plugin.name as a shortcut for plugin baking.') + 'help' => __d('cake_console', 'Name of the controller views to bake. Can be Plugin.name as a shortcut for plugin baking.') ))->addArgument('action', array( - 'help' => __("Will bake a single action's file. core templates are (index, add, edit, view)") + 'help' => __d('cake_console', "Will bake a single action's file. core templates are (index, add, edit, view)") ))->addArgument('alias', array( - 'help' => __('Will bake the template in but create the filename after .') + 'help' => __d('cake_console', 'Will bake the template in but create the filename after .') ))->addOption('plugin', array( 'short' => 'p', - 'help' => __('Plugin to bake the view into.') + 'help' => __d('cake_console', 'Plugin to bake the view into.') ))->addOption('admin', array( - 'help' => __('Set to only bake views for a prefix in Routing.prefixes'), + 'help' => __d('cake_console', 'Set to only bake views for a prefix in Routing.prefixes'), 'boolean' => true ))->addOption('connection', array( 'short' => 'c', - 'help' => __('The connection the connected model is on.') + 'help' => __d('cake_console', 'The connection the connected model is on.') ))->addSubcommand('all', array( - 'help' => __('Bake all CRUD action views for all controllers. Requires models and controllers to exist.') - ))->epilog(__('Omitting all arguments and options will enter into an interactive mode.')); + 'help' => __d('cake_console', 'Bake all CRUD action views for all controllers. Requires models and controllers to exist.') + ))->epilog(__d('cake_console', 'Omitting all arguments and options will enter into an interactive mode.')); } /** @@ -455,7 +458,7 @@ class ViewTask extends BakeTask { * @return array $associations * @access private */ - private function __associations(&$model) { + private function __associations($model) { $keys = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'); $associations = array(); diff --git a/cake/console/shells/testsuite.php b/lib/Cake/Console/Command/TestsuiteShell.php similarity index 62% rename from cake/console/shells/testsuite.php rename to lib/Cake/Console/Command/TestsuiteShell.php index b8eb079b8..d0d778484 100644 --- a/cake/console/shells/testsuite.php +++ b/lib/Cake/Console/Command/TestsuiteShell.php @@ -18,7 +18,13 @@ * @since CakePHP(tm) v 1.2.0.4433 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -class TestSuiteShell extends Shell { + +App::uses('Shell', 'Console'); +App::uses('CakeTestSuiteDispatcher', 'TestSuite'); +App::uses('CakeTestSuiteCommand', 'TestSuite'); +App::uses('CakeTestLoader', 'TestSuite'); + +class TestsuiteShell extends Shell { /** * Dispatcher object for the run. @@ -38,111 +44,113 @@ class TestSuiteShell extends Shell { 'The CakePHP Testsuite allows you to run test cases from the command line', 'If run with no command line arguments, a list of available core test cases will be shown' ))->addArgument('category', array( - 'help' => __('app, core or name of a plugin.'), + 'help' => __d('cake_console', 'app, core or name of a plugin.'), 'required' => true ))->addArgument('file', array( - 'help' => __('file name with folder prefix and without the test.php suffix.'), + 'help' => __d('cake_console', 'file name with folder prefix and without the test.php suffix.'), 'required' => false, ))->addOption('log-junit', array( - 'help' => __(' Log test execution in JUnit XML format to file.'), + 'help' => __d('cake_console', ' Log test execution in JUnit XML format to file.'), 'default' => false ))->addOption('log-json', array( - 'help' => __(' Log test execution in TAP format to file.'), + 'help' => __d('cake_console', ' Log test execution in TAP format to file.'), 'default' => false ))->addOption('log-tap', array( - 'help' => __(' Log test execution in TAP format to file.'), + 'help' => __d('cake_console', ' Log test execution in TAP format to file.'), 'default' => false ))->addOption('log-dbus', array( - 'help' => __('Log test execution to DBUS.'), + 'help' => __d('cake_console', 'Log test execution to DBUS.'), 'default' => false ))->addOption('coverage-html', array( - 'help' => __(' Generate code coverage report in HTML format.'), + 'help' => __d('cake_console', ' Generate code coverage report in HTML format.'), 'default' => false ))->addOption('coverage-clover', array( - 'help' => __(' Write code coverage data in Clover XML format.'), + 'help' => __d('cake_console', ' Write code coverage data in Clover XML format.'), 'default' => false ))->addOption('testdox-html', array( - 'help' => __(' Write agile documentation in HTML format to file.'), + 'help' => __d('cake_console', ' Write agile documentation in HTML format to file.'), 'default' => false ))->addOption('testdox-text', array( - 'help' => __(' Write agile documentation in Text format to file.'), + 'help' => __d('cake_console', ' Write agile documentation in Text format to file.'), 'default' => false ))->addOption('filter', array( - 'help' => __(' Filter which tests to run.'), + 'help' => __d('cake_console', ' Filter which tests to run.'), 'default' => false ))->addOption('group', array( - 'help' => __(' Only runs tests from the specified group(s).'), + 'help' => __d('cake_console', ' Only runs tests from the specified group(s).'), 'default' => false ))->addOption('exclude-group', array( - 'help' => __(' Exclude tests from the specified group(s).'), + 'help' => __d('cake_console', ' Exclude tests from the specified group(s).'), 'default' => false ))->addOption('list-groups', array( - 'help' => __('List available test groups.'), + 'help' => __d('cake_console', 'List available test groups.'), 'boolean' => true ))->addOption('loader', array( - 'help' => __('TestSuiteLoader implementation to use.'), + 'help' => __d('cake_console', 'TestSuiteLoader implementation to use.'), 'default' => false ))->addOption('repeat', array( - 'help' => __(' Runs the test(s) repeatedly.'), + 'help' => __d('cake_console', ' Runs the test(s) repeatedly.'), 'default' => false ))->addOption('tap', array( - 'help' => __('Report test execution progress in TAP format.'), + 'help' => __d('cake_console', 'Report test execution progress in TAP format.'), 'boolean' => true ))->addOption('testdox', array( - 'help' => __('Report test execution progress in TestDox format.'), + 'help' => __d('cake_console', 'Report test execution progress in TestDox format.'), 'default' => false, 'boolean' => true ))->addOption('no-colors', array( - 'help' => __('Do not use colors in output.'), + 'help' => __d('cake_console', 'Do not use colors in output.'), 'boolean' => true ))->addOption('stderr', array( - 'help' => __('Write to STDERR instead of STDOUT.'), + 'help' => __d('cake_console', 'Write to STDERR instead of STDOUT.'), 'boolean' => true ))->addOption('stop-on-error', array( - 'help' => __('Stop execution upon first error or failure.'), + 'help' => __d('cake_console', 'Stop execution upon first error or failure.'), 'boolean' => true ))->addOption('stop-on-failure', array( - 'help' => __('Stop execution upon first failure.'), + 'help' => __d('cake_console', 'Stop execution upon first failure.'), 'boolean' => true ))->addOption('stop-on-skipped ', array( - 'help' => __('Stop execution upon first skipped test.'), + 'help' => __d('cake_console', 'Stop execution upon first skipped test.'), 'boolean' => true ))->addOption('stop-on-incomplete', array( - 'help' => __('Stop execution upon first incomplete test.'), + 'help' => __d('cake_console', 'Stop execution upon first incomplete test.'), 'boolean' => true ))->addOption('strict', array( - 'help' => __('Mark a test as incomplete if no assertions are made.'), + 'help' => __d('cake_console', 'Mark a test as incomplete if no assertions are made.'), 'boolean' => true ))->addOption('wait', array( - 'help' => __('Waits for a keystroke after each test.'), + 'help' => __d('cake_console', 'Waits for a keystroke after each test.'), 'boolean' => true ))->addOption('process-isolation', array( - 'help' => __('Run each test in a separate PHP process.'), + 'help' => __d('cake_console', 'Run each test in a separate PHP process.'), 'boolean' => true ))->addOption('no-globals-backup', array( - 'help' => __('Do not backup and restore $GLOBALS for each test.'), + 'help' => __d('cake_console', 'Do not backup and restore $GLOBALS for each test.'), 'boolean' => true ))->addOption('static-backup ', array( - 'help' => __('Backup and restore static attributes for each test.'), + 'help' => __d('cake_console', 'Backup and restore static attributes for each test.'), 'boolean' => true ))->addOption('syntax-check', array( - 'help' => __('Try to check source files for syntax errors.'), + 'help' => __d('cake_console', 'Try to check source files for syntax errors.'), 'boolean' => true ))->addOption('bootstrap', array( - 'help' => __(' A "bootstrap" PHP file that is run before the tests.'), + 'help' => __d('cake_console', ' A "bootstrap" PHP file that is run before the tests.'), 'default' => false - ))->addOption('configuraion', array( - 'help' => __(' Read configuration from XML file.'), + ))->addOption('configuration', array( + 'help' => __d('cake_console', ' Read configuration from XML file.'), 'default' => false ))->addOption('no-configuration', array( - 'help' => __('Ignore default configuration file (phpunit.xml).'), + 'help' => __d('cake_console', 'Ignore default configuration file (phpunit.xml).'), 'boolean' => true ))->addOption('include-path', array( - 'help' => __(' Prepend PHP include_path with given path(s).'), + 'help' => __d('cake_console', ' Prepend PHP include_path with given path(s).'), 'default' => false ))->addOption('directive', array( - 'help' => __('key[=value] Sets a php.ini value.'), + 'help' => __d('cake_console', 'key[=value] Sets a php.ini value.'), 'default' => false + ))->addOption('fixture', array( + 'help' => __d('cake_console', 'Choose a custom fixture manager.'), )); return $parser; @@ -154,18 +162,8 @@ class TestSuiteShell extends Shell { * @return void */ public function initialize() { - require_once CAKE . 'tests' . DS . 'lib' . DS . 'cake_test_suite_dispatcher.php'; - - $corePath = App::core('cake'); - if (isset($corePath[0])) { - define('TEST_CAKE_CORE_INCLUDE_PATH', rtrim($corePath[0], DS) . DS); - } else { - define('TEST_CAKE_CORE_INCLUDE_PATH', CAKE_CORE_INCLUDE_PATH); - } - $this->_dispatcher = new CakeTestSuiteDispatcher(); $this->_dispatcher->loadTestFramework(); - require_once CAKE . 'tests' . DS . 'lib' . DS . 'test_manager.php'; } /** @@ -178,6 +176,7 @@ class TestSuiteShell extends Shell { return; } $params = array( + 'core' => false, 'app' => false, 'plugin' => null, 'output' => 'text', @@ -185,14 +184,16 @@ class TestSuiteShell extends Shell { $category = $this->args[0]; - if ($category == 'app') { + if ($category == 'core') { + $params['core'] = true; + } elseif ($category == 'app') { $params['app'] = true; } elseif ($category != 'core') { $params['plugin'] = $category; } if (isset($this->args[1])) { - $params['case'] = Inflector::underscore($this->args[1]); + $params['case'] = $this->args[1]; } return $params; } @@ -231,7 +232,7 @@ class TestSuiteShell extends Shell { * @return void */ public function main() { - $this->out(__('CakePHP Test Shell')); + $this->out(__d('cake_console', 'CakePHP Test Shell')); $this->hr(); $args = $this->parseArgs(); @@ -251,12 +252,10 @@ class TestSuiteShell extends Shell { * @return void */ protected function run($runnerArgs, $options = array()) { - require_once CAKE . 'tests' . DS . 'lib' . DS . 'test_runner.php'; - restore_error_handler(); restore_error_handler(); - $testCli = new TestRunner($runnerArgs); + $testCli = new CakeTestSuiteCommand('CakeTestLoader', $runnerArgs); $testCli->run($options); } @@ -267,7 +266,7 @@ class TestSuiteShell extends Shell { */ public function available() { $params = $this->parseArgs(); - $testCases = TestManager::getTestCaseList($params); + $testCases = CakeTestLoader::generateTestList($params); $app = $params['app']; $plugin = $params['plugin']; @@ -282,7 +281,7 @@ class TestSuiteShell extends Shell { } if (empty($testCases)) { - $this->out(__("No test cases available \n\n")); + $this->out(__d('cake_console', "No test cases available \n\n")); return $this->out($this->OptionParser->help()); } @@ -290,15 +289,15 @@ class TestSuiteShell extends Shell { $i = 1; $cases = array(); foreach ($testCases as $testCaseFile => $testCase) { - $case = explode(DS, str_replace('.test.php', '', $testCase)); - $case[count($case) - 1] = Inflector::camelize($case[count($case) - 1]); + $case = explode(DS, str_replace('Test.php', '', $testCase)); + $case[count($case) - 1] = $case[count($case) - 1]; $case = implode('/', $case); $this->out("[$i] $case"); $cases[$i] = $case; $i++; } - while ($choice = $this->in(__('What test case would you like to run?'), null, 'q')) { + while ($choice = $this->in(__d('cake_console', 'What test case would you like to run?'), null, 'q')) { if (is_numeric($choice) && isset($cases[$choice])) { $this->args[0] = $category; $this->args[1] = $cases[$choice]; diff --git a/cake/console/libs/console_error_handler.php b/lib/Cake/Console/ConsoleErrorHandler.php similarity index 87% rename from cake/console/libs/console_error_handler.php rename to lib/Cake/Console/ConsoleErrorHandler.php index 80136bbcf..9020bd1be 100644 --- a/cake/console/libs/console_error_handler.php +++ b/lib/Cake/Console/ConsoleErrorHandler.php @@ -16,8 +16,9 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'ErrorHandler'); -require_once 'console_output.php'; +App::uses('ErrorHandler', 'Error'); +App::uses('ConsoleOutput', 'Console'); +App::uses('CakeLog', 'Log'); /** * Error Handler for Cake console. Does simple printing of the @@ -57,7 +58,7 @@ class ConsoleErrorHandler extends ErrorHandler { public static function handleException(Exception $exception) { $stderr = self::getStderr(); $stderr->write(sprintf( - __("Error: %s\n%s"), + __d('cake_console', "Error: %s\n%s"), $exception->getMessage(), $exception->getTraceAsString() )); @@ -79,11 +80,10 @@ class ConsoleErrorHandler extends ErrorHandler { } $stderr = self::getStderr(); list($name, $log) = self::_mapErrorCode($code); - $message = __('%s in [%s, line %s]', $description, $file, $line); - $stderr->write(__("%s Error: %s\n", $name, $message)); + $message = __d('cake_console', '%s in [%s, line %s]', $description, $file, $line); + $stderr->write(__d('cake_console', "%s Error: %s\n", $name, $message)); if (Configure::read('debug') == 0) { - App::import('Core', 'CakeLog'); CakeLog::write($log, $message); } } diff --git a/cake/console/libs/console_input.php b/lib/Cake/Console/ConsoleInput.php similarity index 100% rename from cake/console/libs/console_input.php rename to lib/Cake/Console/ConsoleInput.php diff --git a/cake/console/libs/console_input_argument.php b/lib/Cake/Console/ConsoleInputArgument.php similarity index 93% rename from cake/console/libs/console_input_argument.php rename to lib/Cake/Console/ConsoleInputArgument.php index 263475e9d..885ce2180 100644 --- a/cake/console/libs/console_input_argument.php +++ b/lib/Cake/Console/ConsoleInputArgument.php @@ -95,10 +95,10 @@ class ConsoleInputArgument { } $optional = ''; if (!$this->isRequired()) { - $optional = __(' (optional)'); + $optional = __d('cake_console', ' (optional)'); } if (!empty($this->_choices)) { - $optional .= __(' (choices: %s)', implode('|', $this->_choices)); + $optional .= __d('cake_console', ' (choices: %s)', implode('|', $this->_choices)); } return sprintf('%s%s%s', $name, $this->_help, $optional); } @@ -140,7 +140,7 @@ class ConsoleInputArgument { } if (!in_array($value, $this->_choices)) { throw new ConsoleException(sprintf( - __('"%s" is not a valid value for %s. Please use one of "%s"'), + __d('cake_console', '"%s" is not a valid value for %s. Please use one of "%s"'), $value, $this->_name, implode(', ', $this->_choices) )); } diff --git a/cake/console/libs/console_input_option.php b/lib/Cake/Console/ConsoleInputOption.php similarity index 94% rename from cake/console/libs/console_input_option.php rename to lib/Cake/Console/ConsoleInputOption.php index 3c9049248..61497e5e4 100644 --- a/cake/console/libs/console_input_option.php +++ b/lib/Cake/Console/ConsoleInputOption.php @@ -119,10 +119,10 @@ class ConsoleInputOption { public function help($width = 0) { $default = $short = ''; if (!empty($this->_default) && $this->_default !== true) { - $default = __(' (default: %s)', $this->_default); + $default = __d('cake_console', ' (default: %s)', $this->_default); } if (!empty($this->_choices)) { - $default .= __(' (choices: %s)', implode('|', $this->_choices)); + $default .= __d('cake_console', ' (choices: %s)', implode('|', $this->_choices)); } if (!empty($this->_short)) { $short = ', -' . $this->_short; @@ -180,7 +180,7 @@ class ConsoleInputOption { } if (!in_array($value, $this->_choices)) { throw new ConsoleException(sprintf( - __('"%s" is not a valid value for --%s. Please use one of "%s"'), + __d('cake_console', '"%s" is not a valid value for --%s. Please use one of "%s"'), $value, $this->_name, implode(', ', $this->_choices) )); } diff --git a/cake/console/libs/console_input_subcommand.php b/lib/Cake/Console/ConsoleInputSubcommand.php similarity index 100% rename from cake/console/libs/console_input_subcommand.php rename to lib/Cake/Console/ConsoleInputSubcommand.php diff --git a/cake/console/libs/console_option_parser.php b/lib/Cake/Console/ConsoleOptionParser.php similarity index 96% rename from cake/console/libs/console_option_parser.php rename to lib/Cake/Console/ConsoleOptionParser.php index a96a0759a..6c221502b 100644 --- a/cake/console/libs/console_option_parser.php +++ b/lib/Cake/Console/ConsoleOptionParser.php @@ -16,10 +16,15 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once CONSOLE_LIBS . 'console_input_option.php'; -require_once CONSOLE_LIBS . 'console_input_argument.php'; -require_once CONSOLE_LIBS . 'console_input_subcommand.php'; -require_once CONSOLE_LIBS . 'help_formatter.php'; + +App::uses('TaskCollection', 'Console'); +App::uses('ConsoleOutput', 'Console'); +App::uses('ConsoleInput', 'Console'); +App::uses('ConsoleInputSubcommand', 'Console'); +App::uses('ConsoleInputOption', 'Console'); +App::uses('ConsoleInputArgument', 'Console'); +App::uses('ConsoleOptionParser', 'Console'); +App::uses('HelpFormatter', 'Console'); /** * Handles parsing the ARGV in the command line and provides support @@ -129,11 +134,11 @@ class ConsoleOptionParser { if ($defaultOptions) { $this->addOption('verbose', array( 'short' => 'v', - 'help' => __('Enable verbose output.'), + 'help' => __d('cake_console', 'Enable verbose output.'), 'boolean' => true ))->addOption('quiet', array( 'short' => 'q', - 'help' => __('Enable quiet output.'), + 'help' => __d('cake_console', 'Enable quiet output.'), 'boolean' => true )); } @@ -456,7 +461,7 @@ class ConsoleOptionParser { foreach ($this->_args as $i => $arg) { if ($arg->isRequired() && !isset($args[$i]) && empty($params['help'])) { throw new ConsoleException( - __('Missing required arguments. %s is required.', $arg->name()) + __d('cake_console', 'Missing required arguments. %s is required.', $arg->name()) ); } } @@ -550,7 +555,7 @@ class ConsoleOptionParser { */ protected function _parseOption($name, $params) { if (!isset($this->_options[$name])) { - throw new ConsoleException(__('Unknown option `%s`', $name)); + throw new ConsoleException(__d('cake_console', 'Unknown option `%s`', $name)); } $option = $this->_options[$name]; $isBoolean = $option->isBoolean(); @@ -584,7 +589,7 @@ class ConsoleOptionParser { } $next = count($args); if (!isset($this->_args[$next])) { - throw new ConsoleException(__('Too many arguments.')); + throw new ConsoleException(__d('cake_console', 'Too many arguments.')); } if ($this->_args[$next]->validChoice($argument)) { diff --git a/cake/console/libs/console_output.php b/lib/Cake/Console/ConsoleOutput.php similarity index 100% rename from cake/console/libs/console_output.php rename to lib/Cake/Console/ConsoleOutput.php diff --git a/cake/console/libs/help_formatter.php b/lib/Cake/Console/HelpFormatter.php similarity index 97% rename from cake/console/libs/help_formatter.php rename to lib/Cake/Console/HelpFormatter.php index f454fa8b2..94a32af88 100644 --- a/cake/console/libs/help_formatter.php +++ b/lib/Cake/Console/HelpFormatter.php @@ -14,7 +14,7 @@ * @link http://cakephp.org CakePHP(tm) Project * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'String', false); +App::uses('String', 'Utility'); /** * HelpFormatter formats help for console shells. Can format to either @@ -69,7 +69,7 @@ class HelpFormatter { } $out[] = ''; $out[] = sprintf( - __('To see help on a subcommand use `cake %s [subcommand] --help`'), + __d('cake_console', 'To see help on a subcommand use `cake %s [subcommand] --help`'), $parser->command() ); $out[] = ''; diff --git a/cake/console/shells/shell.php b/lib/Cake/Console/Shell.php similarity index 94% rename from cake/console/shells/shell.php rename to lib/Cake/Console/Shell.php index dd59dbb2c..ad5b716fa 100644 --- a/cake/console/shells/shell.php +++ b/lib/Cake/Console/Shell.php @@ -16,10 +16,13 @@ * @since CakePHP(tm) v 1.2.0.5012 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once CONSOLE_LIBS . 'task_collection.php'; -require_once CONSOLE_LIBS . 'console_output.php'; -require_once CONSOLE_LIBS . 'console_input.php'; -require_once CONSOLE_LIBS . 'console_option_parser.php'; + +App::uses('TaskCollection', 'Console'); +App::uses('ConsoleOutput', 'Console'); +App::uses('ConsoleInput', 'Console'); +App::uses('ConsoleInputSubcommand', 'Console'); +App::uses('ConsoleOptionParser', 'Console'); +App::uses('File', 'Utility'); /** * Base class for command-line utilities for automating programmer chores. @@ -557,7 +560,7 @@ class Shell extends Object { * @param string $message An optional error message */ public function error($title, $message = null) { - $this->err(__('Error: %s', $title)); + $this->err(__d('cake_console', 'Error: %s', $title)); if (!empty($message)) { $this->err($message); @@ -593,31 +596,27 @@ class Shell extends Object { $this->out(); if (is_file($path) && $this->interactive === true) { - $this->out(__('File `%s` exists', $path)); - $key = $this->in(__('Do you want to overwrite?'), array('y', 'n', 'q'), 'n'); + $this->out(__d('cake_console', 'File `%s` exists', $path)); + $key = $this->in(__d('cake_console', 'Do you want to overwrite?'), array('y', 'n', 'q'), 'n'); if (strtolower($key) == 'q') { - $this->out(__('Quitting.'), 2); + $this->out(__d('cake_console', 'Quitting.'), 2); $this->_stop(); } elseif (strtolower($key) != 'y') { - $this->out(__('Skip `%s`', $path), 2); + $this->out(__d('cake_console', 'Skip `%s`', $path), 2); return false; } } else { - $this->out(__('Creating file %s', $path)); - } - - if (!class_exists('File')) { - require LIBS . 'file.php'; + $this->out(__d('cake_console', 'Creating file %s', $path)); } if ($File = new File($path, true)) { $data = $File->prepare($contents); $File->write($data); - $this->out(__('Wrote `%s`', $path)); + $this->out(__d('cake_console', 'Wrote `%s`', $path)); return true; } else { - $this->err(__('Could not write to `%s`.', $path), 2); + $this->err(__d('cake_console', 'Could not write to `%s`.', $path), 2); return false; } } @@ -628,7 +627,10 @@ class Shell extends Object { * @return boolean Success */ protected function _checkUnitTest() { - if (App::import('vendor', 'simpletest' . DS . 'simpletest')) { + if (App::import('Vendor', 'phpunit', array('file' => 'PHPUnit' . DS . 'Autoload.php'))) { + return true; + } + if (@include 'PHPUnit' . DS . 'Autoload.php') { return true; } $prompt = 'PHPUnit is not installed. Do you want to bake unit test files anyway?'; @@ -661,7 +663,7 @@ class Shell extends Object { * @return string Path to controller */ protected function _controllerPath($name) { - return strtolower(Inflector::underscore($name)); + return Inflector::underscore($name); } /** diff --git a/cake/console/shell_dispatcher.php b/lib/Cake/Console/ShellDispatcher.php similarity index 91% rename from cake/console/shell_dispatcher.php rename to lib/Cake/Console/ShellDispatcher.php index 1b520500b..465b6d303 100644 --- a/cake/console/shell_dispatcher.php +++ b/lib/Cake/Console/ShellDispatcher.php @@ -105,7 +105,7 @@ class ShellDispatcher { if (!isset($this->args[0]) || !isset($this->params['working'])) { $message = "This file has been loaded incorrectly and cannot continue.\n" . - "Please make sure that " . DIRECTORY_SEPARATOR . "cake" . DIRECTORY_SEPARATOR . "console is in your system path,\n" . + "Please make sure that " . DIRECTORY_SEPARATOR . "cake" . DIRECTORY_SEPARATOR . "console is in your system path,\n" . "and check the cookbook for the correct usage of this command.\n" . "(http://book.cakephp.org/)"; throw new CakeException($message); @@ -127,17 +127,16 @@ class ShellDispatcher { define('APP_PATH', $this->params['working'] . DS); define('WWW_ROOT', APP_PATH . $this->params['webroot'] . DS); if (!is_dir(ROOT . DS . APP_DIR . DS . 'tmp')) { - define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'console' . DS . 'templates' . DS . 'skel' . DS . 'tmp' . DS); + define('TMP', CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'templates' . DS . 'skel' . DS . 'tmp' . DS); } - $boot = file_exists(ROOT . DS . APP_DIR . DS . 'config' . DS . 'bootstrap.php'); - require CORE_PATH . 'cake' . DS . 'bootstrap.php'; + require CORE_PATH . 'Cake' . DS . 'bootstrap.php'; if (!file_exists(APP_PATH . 'config' . DS . 'core.php')) { - include_once CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'console' . DS . 'templates' . DS . 'skel' . DS . 'config' . DS . 'core.php'; + include_once CAKE_CORE_INCLUDE_PATH . DS . 'Cake' . DS . 'Console' . DS . 'templates' . DS . 'skel' . DS . 'config' . DS . 'core.php'; App::build(); } - require_once CONSOLE_LIBS . 'console_error_handler.php'; + require_once CONSOLE_LIBS . 'ConsoleErrorHandler.php'; set_exception_handler(array('ConsoleErrorHandler', 'handleException')); set_error_handler(array('ConsoleErrorHandler', 'handleError'), Configure::read('Error.level')); @@ -207,14 +206,14 @@ class ShellDispatcher { protected function _getShell($shell) { list($plugin, $shell) = pluginSplit($shell, true); - $loaded = App::import('Shell', $plugin . $shell); + $class = Inflector::camelize($shell) . 'Shell'; - - if (!$loaded) { - throw new MissingShellFileException(array('shell' => $shell)); - } + + App::uses('Shell', 'Console'); + App::uses($class, $plugin . 'Console/Command'); + if (!class_exists($class)) { - throw new MissingShellClassException(array('shell' => $class)); + throw new MissingShellFileException(array('shell' => $shell)); } $Shell = new $class(); return $Shell; @@ -229,9 +228,9 @@ class ShellDispatcher { $this->_parsePaths($args); $defaults = array( - 'app' => 'app', - 'root' => dirname(dirname(dirname(__FILE__))), - 'working' => null, + 'app' => 'app', + 'root' => dirname(dirname(dirname(dirname(__FILE__)))), + 'working' => null, 'webroot' => 'webroot' ); $params = array_merge($defaults, array_intersect_key($this->params, $defaults)); @@ -244,6 +243,9 @@ class ShellDispatcher { } $params = str_replace('\\', '/', $params); + if (isset($params['working'])) { + $params['working'] = trim($params['working']); + } if (!empty($params['working']) && (!isset($this->args[0]) || isset($this->args[0]) && $this->args[0]{0} !== '.')) { if (empty($this->params['app']) && $params['working'] != $params['root']) { $params['root'] = dirname($params['working']); @@ -260,7 +262,10 @@ class ShellDispatcher { } $params['app'] = basename($params['app']); - $params['working'] = rtrim($params['root'], '/') . '/' . $params['app']; + $params['working'] = rtrim($params['root'], '/'); + if (!$isWin || !preg_match('/^[A-Z]:$/i', $params['app'])) { + $params['working'] .= '/' . $params['app']; + } if (!empty($matches[0]) || !empty($isWin)) { $params = str_replace('/', '\\', $params); @@ -317,4 +322,4 @@ class ShellDispatcher { protected function _stop($status = 0) { exit($status); } -} \ No newline at end of file +} diff --git a/cake/console/libs/task_collection.php b/lib/Cake/Console/TaskCollection.php similarity index 86% rename from cake/console/libs/task_collection.php rename to lib/Cake/Console/TaskCollection.php index 32f0b31a4..3c911a2ce 100644 --- a/cake/console/libs/task_collection.php +++ b/lib/Cake/Console/TaskCollection.php @@ -15,7 +15,8 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'ObjectCollection'); + +App::uses('ObjectCollection', 'Utility'); class TaskCollection extends ObjectCollection { /** @@ -48,11 +49,10 @@ class TaskCollection extends ObjectCollection { * * @param string $task Task name to load * @param array $settings Settings for the task. - * @param boolean $enable Whether or not this task should be enabled by default * @return Task A task object, Either the existing loaded task or a new one. * @throws MissingTaskFileException, MissingTaskClassException when the task could not be found */ - public function load($task, $settings = array(), $enable = true) { + public function load($task, $settings = array()) { list($plugin, $name) = pluginSplit($task, true); if (isset($this->_loaded[$name])) { @@ -60,10 +60,8 @@ class TaskCollection extends ObjectCollection { } $taskFile = Inflector::underscore($name); $taskClass = $name . 'Task'; + App::uses($taskClass, $plugin . 'Console/Command/Task'); if (!class_exists($taskClass)) { - if (!App::import('Shell', $plugin . $this->taskPathPrefix . $name)) { - throw new MissingTaskFileException($taskFile . '.php'); - } if (!class_exists($taskClass)) { throw new MissingTaskClassException($taskClass); } @@ -72,6 +70,7 @@ class TaskCollection extends ObjectCollection { $this->_loaded[$name] = new $taskClass( $this->_Shell->stdout, $this->_Shell->stderr, $this->_Shell->stdin ); + $enable = isset($settings['enabled']) ? $settings['enabled'] : true; if ($enable === true) { $this->_enabled[] = $name; } diff --git a/cake/console/cake b/lib/Cake/Console/cake similarity index 100% rename from cake/console/cake rename to lib/Cake/Console/cake diff --git a/cake/console/cake.bat b/lib/Cake/Console/cake.bat similarity index 90% rename from cake/console/cake.bat rename to lib/Cake/Console/cake.bat index 40a271425..a22cfcacd 100644 --- a/cake/console/cake.bat +++ b/lib/Cake/Console/cake.bat @@ -25,7 +25,7 @@ SET app=%0 SET lib=%~dp0 -php -q "%lib%cake.php" -working "%CD%" %* +php -q "%lib%cake.php" -working "%CD% " %* echo. diff --git a/cake/console/cake.php b/lib/Cake/Console/cake.php similarity index 90% rename from cake/console/cake.php rename to lib/Cake/Console/cake.php index c9bce3193..4c8188b2c 100644 --- a/cake/console/cake.php +++ b/lib/Cake/Console/cake.php @@ -19,7 +19,6 @@ * @since CakePHP(tm) v 1.2.0.5012 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR. 'shell_dispatcher.php'); +require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR. 'ShellDispatcher.php'); return ShellDispatcher::run($argv); - diff --git a/cake/console/templates/default/actions/controller_actions.ctp b/lib/Cake/Console/templates/default/actions/controller_actions.ctp similarity index 93% rename from cake/console/templates/default/actions/controller_actions.ctp rename to lib/Cake/Console/templates/default/actions/controller_actions.ctp index e6f0f8e83..1b59ba650 100644 --- a/cake/console/templates/default/actions/controller_actions.ctp +++ b/lib/Cake/Console/templates/default/actions/controller_actions.ctp @@ -18,11 +18,22 @@ */ ?> +/** + * index method + * + * @return void + */ public function index() { $this->->recursive = 0; $this->set('', $this->paginate()); } +/** + * view method + * + * @param string $id + * @return void + */ public function view($id = null) { $this->->id = $id; if (!$this->->exists()) { @@ -32,6 +43,11 @@ } +/** + * add method + * + * @return void + */ public function add() { if ($this->request->is('post')) { $this->->create(); @@ -66,6 +82,12 @@ } +/** + * edit method + * + * @param string $id + * @return void + */ public function edit($id = null) { $this->->id = $id; if (!$this->->exists()) { @@ -104,6 +126,12 @@ ?> } +/** + * delete method + * + * @param string $id + * @return void + */ public function delete($id = null) { if (!$this->request->is('post')) { throw new MethodNotAllowedException(); diff --git a/cake/console/templates/default/classes/controller.ctp b/lib/Cake/Console/templates/default/classes/controller.ctp similarity index 88% rename from cake/console/templates/default/classes/controller.ctp rename to lib/Cake/Console/templates/default/classes/controller.ctp index 52f968824..f4dc9c9eb 100644 --- a/cake/console/templates/default/classes/controller.ctp +++ b/lib/Cake/Console/templates/default/classes/controller.ctp @@ -21,14 +21,23 @@ echo " +/** + * Controller + * + */ class Controller extends AppController { - public $name = ''; +/** + * Scaffold + * + * @var mixed + */ public $scaffold; -/* Fixture generated on: */ +/* Fixture generated on: */ + +/** + * Fixture + * + */ class Fixture extends CakeTestFixture { - public $name = ''; +/** + * Table name + * + * @var string + */ public $table = ''; +/** + * Import + * + * @var array + */ public $import = ; +/** + * Fields + * + * @var array + */ public $fields = ; +/** + * Records + * + * @var array + */ public $records = ; } diff --git a/cake/console/templates/default/classes/model.ctp b/lib/Cake/Console/templates/default/classes/model.ctp similarity index 90% rename from cake/console/templates/default/classes/model.ctp rename to lib/Cake/Console/templates/default/classes/model.ctp index ece196dba..f824e8a16 100644 --- a/cake/console/templates/default/classes/model.ctp +++ b/lib/Cake/Console/templates/default/classes/model.ctp @@ -20,23 +20,43 @@ */ echo " +/** + * Model + * + */ class extends AppModel { - public $name = ''; +/** + * Use database config + * + * @var string + */ public $useDbConfig = ''; +/** + * Primary key field + * + * @var string + */ public $primaryKey = ''; +/** + * Display field + * + * @var string + */ public $displayField = ''; $validations): echo "\t\t'$field' => array(\n"; @@ -58,6 +78,7 @@ endif; foreach ($associations as $assoc): if (!empty($assoc)): ?> + //The Associations below have been created with all possible keys, those that are not needed can be removed $relation): $out = "\n\t\t'{$relation['alias']}' => array(\n"; @@ -87,6 +109,7 @@ endforeach; if (!empty($associations['hasMany'])): $belongsToCount = count($associations['hasMany']); + echo "\n/**\n * hasMany associations\n *\n * @var array\n */"; echo "\n\tpublic \$hasMany = array("; foreach ($associations['hasMany'] as $i => $relation): $out = "\n\t\t'{$relation['alias']}' => array(\n"; @@ -112,6 +135,7 @@ endif; if (!empty($associations['hasAndBelongsToMany'])): $habtmCount = count($associations['hasAndBelongsToMany']); + echo "\n/**\n * hasAndBelongsToMany associations\n *\n * @var array\n */"; echo "\n\tpublic \$hasAndBelongsToMany = array("; foreach ($associations['hasAndBelongsToMany'] as $i => $relation): $out = "\n\t\t'{$relation['alias']}' => array(\n"; diff --git a/cake/console/templates/default/classes/test.ctp b/lib/Cake/Console/templates/default/classes/test.ctp similarity index 68% rename from cake/console/templates/default/classes/test.ctp rename to lib/Cake/Console/templates/default/classes/test.ctp index f9dd98b0b..331347099 100644 --- a/cake/console/templates/default/classes/test.ctp +++ b/lib/Cake/Console/templates/default/classes/test.ctp @@ -18,35 +18,80 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ echo " -App::import('', ''); +App::uses('', ''); +/** + * Test + * + */ class Test extends { +/** + * Auto render + * + * @var boolean + */ public $autoRender = false; +/** + * Redirect action + * + * @param mixed $url + * @param mixed $status + * @param boolean $exit + * @return void + */ public function redirect($url, $status = null, $exit = true) { $this->redirectUrl = $url; } } +/** + * Test Case + * + */ class TestCase extends CakeTestCase { +/** + * Fixtures + * + * @var array + */ public $fixtures = array(''); - public function startTest() { +/** + * setUp method + * + * @return void + */ + public function setUp() { + parent::setUp(); + $this-> } - public function endTest() { +/** + * tearDown method + * + * @return void + */ + public function tearDown() { unset($this->); ClassRegistry::flush(); + + parent::tearDown(); } +/** + * test method + * + * @return void + */ public function test() { } diff --git a/cake/console/templates/default/views/form.ctp b/lib/Cake/Console/templates/default/views/form.ctp similarity index 95% rename from cake/console/templates/default/views/form.ctp rename to lib/Cake/Console/templates/default/views/form.ctp index ce2b525f9..b466611d3 100644 --- a/cake/console/templates/default/views/form.ctp +++ b/lib/Cake/Console/templates/default/views/form.ctp @@ -19,7 +19,7 @@
Form->create('{$modelClass}');?>\n";?>
- ", Inflector::humanize($action), $singularHumanName); ?> + ", Inflector::humanize($action), $singularHumanName); ?> Sweet, \"" . Inflector::humanize($app) . "\" got Baked by CakePHP!\n"; $output .=" 0): Debugger::checkSecurityKeys(); endif; @@ -52,27 +52,38 @@ endif; ?>

getDataSource('default'); ?>

+ isConnected()): + echo ''; + echo __('Cake is able to connect to the database.'); + echo ''; + else: + echo ''; + echo __('Cake is NOT able to connect to the database.'); + echo ''; + endif; + ?> +

+ isConnected()): - echo ''; - echo __('Cake is able to connect to the database.'); - echo ''; - else: - echo ''; - echo __('Cake is NOT able to connect to the database.'); - echo ''; - endif; -?> -

\n"; -$output .= "\n"; + App::uses('Validation', 'Utility'); + if (!Validation::alphaNumeric('cakephp')) { + echo '

'; + __('PCRE has not been compiled with Unicode support.'); + echo '
'; + __('Recompile PCRE with Unicode support by adding --enable-unicode-properties when configuring'); + echo '

'; + } +?>\n"; $output .= "

\n"; $output .= "

\n"; $output .= " 'File')); + /** * 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) * * App::build(array( * 'plugins' => array('/full/path/to/plugins/', '/next/full/path/to/plugins/'), * 'models' => array('/full/path/to/models/', '/next/full/path/to/models/'), * 'views' => array('/full/path/to/views/', '/next/full/path/to/views/'), - * 'controllers' => array(/full/path/to/controllers/', '/next/full/path/to/controllers/'), + * 'controllers' => array('/full/path/to/controllers/', '/next/full/path/to/controllers/'), * 'datasources' => array('/full/path/to/datasources/', '/next/full/path/to/datasources/'), * 'behaviors' => array('/full/path/to/behaviors/', '/next/full/path/to/behaviors/'), * 'components' => array('/full/path/to/components/', '/next/full/path/to/components/'), diff --git a/cake/console/templates/skel/config/core.php b/lib/Cake/Console/templates/skel/config/core.php similarity index 91% rename from cake/console/templates/skel/config/core.php rename to lib/Cake/Console/templates/skel/config/core.php index 9744da06c..3a7613b85 100644 --- a/cake/console/templates/skel/config/core.php +++ b/lib/Cake/Console/templates/skel/config/core.php @@ -283,4 +283,40 @@ * )); * */ - Cache::config('default', array('engine' => 'File')); + +// Pick the caching engine to use. If APC is enabled use it. +$engine = 'File'; +if (extension_loaded('apc')) { + $engine = 'Apc'; +} + +// In development mode, caches should expire quickly. +$duration = '+999 days'; +if (Configure::read('debug') >= 1) { + $duration = '+10 seconds'; +} + +/** + * Configure the cache used for general framework caching. Path information, + * object listings, and translation cache files are stored with this configuration. + */ +Cache::config('_cake_core_', array( + 'engine' => $engine, + 'prefix' => 'cake_core_', + 'path' => CACHE . 'persistent' . DS, + 'serialize' => ($engine === 'File'), + 'duration' => $duration +)); + +/** + * Configure the cache for model, and datasource caches. This cache configuration + * is used to store schema descriptions, and table listings in connections. + */ +Cache::config('_cake_model_', array( + 'engine' => $engine, + 'prefix' => 'cake_model_', + 'path' => CACHE . 'models' . DS, + 'serialize' => ($engine === 'File'), + 'duration' => $duration +)); + diff --git a/cake/console/templates/skel/config/database.php.default b/lib/Cake/Console/templates/skel/config/database.php.default similarity index 70% rename from cake/console/templates/skel/config/database.php.default rename to lib/Cake/Console/templates/skel/config/database.php.default index 0952dac47..b7eb4bba2 100644 --- a/cake/console/templates/skel/config/database.php.default +++ b/lib/Cake/Console/templates/skel/config/database.php.default @@ -28,39 +28,38 @@ * You can specify multiple configurations for production, development and testing. * * driver => The name of a supported driver; valid options are as follows: - * mysql - MySQL 4 & 5, - * sqlite - SQLite (PHP5 only), - * postgres - PostgreSQL 7 and higher, - * mssql - Microsoft SQL Server 2000 and higher, - * oracle - Oracle 8 and higher + * Datasabe/Mysql - MySQL 4 & 5, + * Datasabe/Sqlite - SQLite (PHP5 only), + * Datasabe/Postgres - PostgreSQL 7 and higher, + * Datasabe/Mssql - Microsoft SQL Server 2000 and higher, + * Datasabe/Oracle - Oracle 8 and higher * * You can add custom database drivers (or override existing drivers) by adding the - * appropriate file to app/models/datasources/dbo. Drivers should be named 'dbo_x.php', - * where 'x' is the name of the database. + * appropriate file to app/models/datasources/database. Drivers should be named 'MyDriver.php', + * * * persistent => true / false * Determines whether or not the database should use a persistent connection * * host => - * the host you connect to the database. To add a socket or port number, use 'port' => # + * the host you connect to the database. To add a socket or port number, use 'port' => # * * prefix => * Uses the given prefix for all the tables in this database. This setting can be overridden * on a per-table basis with the Model::$tablePrefix property. * * schema => - * For Postgresspecifies which schema you would like to use the tables in. Postgres defaults to - * 'public', DB2 defaults to empty. + * For Postgres specifies which schema you would like to use the tables in. Postgres defaults to 'public'. * * encoding => - * For MySQL, Postgres and Sqlite, specifies the character encoding to use when connecting to the - * database. Uses database default. + * For MySQL, Postgres specifies the character encoding to use when connecting to the + * database. Uses database default not specified. * */ class DATABASE_CONFIG { public $default = array( - 'driver' => 'mysql', + 'datasource' => 'Database/Mysql', 'persistent' => false, 'host' => 'localhost', 'login' => 'user', @@ -70,7 +69,7 @@ class DATABASE_CONFIG { ); public $test = array( - 'driver' => 'mysql', + 'datasource' => 'Database/Mysql', 'persistent' => false, 'host' => 'localhost', 'login' => 'user', diff --git a/cake/console/templates/skel/config/routes.php b/lib/Cake/Console/templates/skel/config/routes.php similarity index 100% rename from cake/console/templates/skel/config/routes.php rename to lib/Cake/Console/templates/skel/config/routes.php diff --git a/cake/console/templates/skel/config/schema/db_acl.php b/lib/Cake/Console/templates/skel/config/schema/db_acl.php similarity index 100% rename from cake/console/templates/skel/config/schema/db_acl.php rename to lib/Cake/Console/templates/skel/config/schema/db_acl.php diff --git a/cake/console/templates/skel/config/schema/db_acl.sql b/lib/Cake/Console/templates/skel/config/schema/db_acl.sql similarity index 100% rename from cake/console/templates/skel/config/schema/db_acl.sql rename to lib/Cake/Console/templates/skel/config/schema/db_acl.sql diff --git a/cake/console/templates/skel/config/schema/i18n.php b/lib/Cake/Console/templates/skel/config/schema/i18n.php similarity index 100% rename from cake/console/templates/skel/config/schema/i18n.php rename to lib/Cake/Console/templates/skel/config/schema/i18n.php diff --git a/cake/console/templates/skel/config/schema/i18n.sql b/lib/Cake/Console/templates/skel/config/schema/i18n.sql similarity index 100% rename from cake/console/templates/skel/config/schema/i18n.sql rename to lib/Cake/Console/templates/skel/config/schema/i18n.sql diff --git a/cake/console/templates/skel/config/schema/sessions.php b/lib/Cake/Console/templates/skel/config/schema/sessions.php similarity index 100% rename from cake/console/templates/skel/config/schema/sessions.php rename to lib/Cake/Console/templates/skel/config/schema/sessions.php diff --git a/cake/console/templates/skel/config/schema/sessions.sql b/lib/Cake/Console/templates/skel/config/schema/sessions.sql similarity index 100% rename from cake/console/templates/skel/config/schema/sessions.sql rename to lib/Cake/Console/templates/skel/config/schema/sessions.sql diff --git a/cake/console/templates/skel/index.php b/lib/Cake/Console/templates/skel/index.php similarity index 100% rename from cake/console/templates/skel/index.php rename to lib/Cake/Console/templates/skel/index.php diff --git a/cake/console/templates/skel/tests/cases/controllers/empty b/lib/Cake/Console/templates/skel/locale/eng/LC_MESSAGES/empty similarity index 100% rename from cake/console/templates/skel/tests/cases/controllers/empty rename to lib/Cake/Console/templates/skel/locale/eng/LC_MESSAGES/empty diff --git a/cake/console/templates/skel/tests/cases/datasources/empty b/lib/Cake/Console/templates/skel/plugins/empty similarity index 100% rename from cake/console/templates/skel/tests/cases/datasources/empty rename to lib/Cake/Console/templates/skel/plugins/empty diff --git a/cake/console/templates/skel/tests/cases/helpers/empty b/lib/Cake/Console/templates/skel/tests/Case/Controller/Component/empty similarity index 100% rename from cake/console/templates/skel/tests/cases/helpers/empty rename to lib/Cake/Console/templates/skel/tests/Case/Controller/Component/empty diff --git a/cake/console/templates/skel/tests/cases/models/empty b/lib/Cake/Console/templates/skel/tests/Case/Controller/empty similarity index 100% rename from cake/console/templates/skel/tests/cases/models/empty rename to lib/Cake/Console/templates/skel/tests/Case/Controller/empty diff --git a/cake/console/templates/skel/tests/cases/shells/empty b/lib/Cake/Console/templates/skel/tests/Case/Model/Behavior/empty similarity index 100% rename from cake/console/templates/skel/tests/cases/shells/empty rename to lib/Cake/Console/templates/skel/tests/Case/Model/Behavior/empty diff --git a/cake/console/templates/skel/tests/fixtures/empty b/lib/Cake/Console/templates/skel/tests/Case/Model/empty similarity index 100% rename from cake/console/templates/skel/tests/fixtures/empty rename to lib/Cake/Console/templates/skel/tests/Case/Model/empty diff --git a/cake/console/templates/skel/tmp/cache/models/empty b/lib/Cake/Console/templates/skel/tests/Case/View/Helper/empty old mode 100755 new mode 100644 similarity index 100% rename from cake/console/templates/skel/tmp/cache/models/empty rename to lib/Cake/Console/templates/skel/tests/Case/View/Helper/empty diff --git a/cake/console/templates/skel/tmp/cache/persistent/empty b/lib/Cake/Console/templates/skel/tests/Fixture/empty old mode 100755 new mode 100644 similarity index 100% rename from cake/console/templates/skel/tmp/cache/persistent/empty rename to lib/Cake/Console/templates/skel/tests/Fixture/empty diff --git a/cake/console/templates/skel/tmp/cache/views/empty b/lib/Cake/Console/templates/skel/tmp/cache/models/empty old mode 100755 new mode 100644 similarity index 100% rename from cake/console/templates/skel/tmp/cache/views/empty rename to lib/Cake/Console/templates/skel/tmp/cache/models/empty diff --git a/cake/console/templates/skel/tmp/logs/empty b/lib/Cake/Console/templates/skel/tmp/cache/persistent/empty similarity index 100% rename from cake/console/templates/skel/tmp/logs/empty rename to lib/Cake/Console/templates/skel/tmp/cache/persistent/empty diff --git a/cake/console/templates/skel/tmp/sessions/empty b/lib/Cake/Console/templates/skel/tmp/cache/views/empty similarity index 100% rename from cake/console/templates/skel/tmp/sessions/empty rename to lib/Cake/Console/templates/skel/tmp/cache/views/empty diff --git a/cake/console/templates/skel/tmp/tests/empty b/lib/Cake/Console/templates/skel/tmp/logs/empty similarity index 100% rename from cake/console/templates/skel/tmp/tests/empty rename to lib/Cake/Console/templates/skel/tmp/logs/empty diff --git a/cake/console/templates/skel/vendors/empty b/lib/Cake/Console/templates/skel/tmp/sessions/empty similarity index 100% rename from cake/console/templates/skel/vendors/empty rename to lib/Cake/Console/templates/skel/tmp/sessions/empty diff --git a/cake/console/templates/skel/views/elements/empty b/lib/Cake/Console/templates/skel/tmp/tests/empty similarity index 100% rename from cake/console/templates/skel/views/elements/empty rename to lib/Cake/Console/templates/skel/tmp/tests/empty diff --git a/cake/console/templates/skel/views/errors/empty b/lib/Cake/Console/templates/skel/vendors/empty similarity index 100% rename from cake/console/templates/skel/views/errors/empty rename to lib/Cake/Console/templates/skel/vendors/empty diff --git a/cake/console/templates/skel/webroot/.htaccess b/lib/Cake/Console/templates/skel/webroot/.htaccess similarity index 68% rename from cake/console/templates/skel/webroot/.htaccess rename to lib/Cake/Console/templates/skel/webroot/.htaccess index f9d8b938b..8e7f16397 100644 --- a/cake/console/templates/skel/webroot/.htaccess +++ b/lib/Cake/Console/templates/skel/webroot/.htaccess @@ -2,5 +2,5 @@ RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule ^(.*)$ index.php?url=$1 [QSA,L] + RewriteRule ^(.*)$ index.php/$1 [QSA,L] \ No newline at end of file diff --git a/cake/console/templates/skel/webroot/css.php b/lib/Cake/Console/templates/skel/webroot/css.php similarity index 100% rename from cake/console/templates/skel/webroot/css.php rename to lib/Cake/Console/templates/skel/webroot/css.php diff --git a/cake/console/templates/skel/webroot/css/cake.generic.css b/lib/Cake/Console/templates/skel/webroot/css/cake.generic.css similarity index 100% rename from cake/console/templates/skel/webroot/css/cake.generic.css rename to lib/Cake/Console/templates/skel/webroot/css/cake.generic.css diff --git a/cake/console/templates/skel/webroot/favicon.ico b/lib/Cake/Console/templates/skel/webroot/favicon.ico similarity index 100% rename from cake/console/templates/skel/webroot/favicon.ico rename to lib/Cake/Console/templates/skel/webroot/favicon.ico diff --git a/cake/console/templates/skel/webroot/img/cake.icon.png b/lib/Cake/Console/templates/skel/webroot/img/cake.icon.png similarity index 100% rename from cake/console/templates/skel/webroot/img/cake.icon.png rename to lib/Cake/Console/templates/skel/webroot/img/cake.icon.png diff --git a/cake/console/templates/skel/webroot/img/cake.power.gif b/lib/Cake/Console/templates/skel/webroot/img/cake.power.gif similarity index 100% rename from cake/console/templates/skel/webroot/img/cake.power.gif rename to lib/Cake/Console/templates/skel/webroot/img/cake.power.gif diff --git a/cake/console/templates/skel/webroot/index.php b/lib/Cake/Console/templates/skel/webroot/index.php similarity index 86% rename from cake/console/templates/skel/webroot/index.php rename to lib/Cake/Console/templates/skel/webroot/index.php index 5955688f6..77b9db786 100644 --- a/cake/console/templates/skel/webroot/index.php +++ b/lib/Cake/Console/templates/skel/webroot/index.php @@ -49,7 +49,7 @@ * */ if (!defined('CAKE_CORE_INCLUDE_PATH')) { - define('CAKE_CORE_INCLUDE_PATH', ROOT); + define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . 'lib'); } /** @@ -67,13 +67,14 @@ define('APP_PATH', ROOT . DS . APP_DIR . DS); define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); } - if (!include(CORE_PATH . 'cake' . DS . 'bootstrap.php')) { + if (!include(CORE_PATH . 'Cake' . DS . 'bootstrap.php')) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } - if (isset($_GET['url']) && $_GET['url'] === 'favicon.ico') { + + if (isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] == '/favicon.ico') { return; - } else { - require LIBS . 'dispatcher.php'; - $Dispatcher = new Dispatcher(); - $Dispatcher->dispatch(new CakeRequest(isset($_GET['url']) ? $_GET['url'] : null)); } + + require LIBS . 'Routing' . DS .'Dispatcher.php'; + $Dispatcher = new Dispatcher(); + $Dispatcher->dispatch(new CakeRequest()); diff --git a/cake/console/templates/skel/views/helpers/empty b/lib/Cake/Console/templates/skel/webroot/js/empty similarity index 100% rename from cake/console/templates/skel/views/helpers/empty rename to lib/Cake/Console/templates/skel/webroot/js/empty diff --git a/cake/console/templates/skel/webroot/test.php b/lib/Cake/Console/templates/skel/webroot/test.php similarity index 84% rename from cake/console/templates/skel/webroot/test.php rename to lib/Cake/Console/templates/skel/webroot/test.php index eddcc437f..cb9180331 100644 --- a/cake/console/templates/skel/webroot/test.php +++ b/lib/Cake/Console/templates/skel/webroot/test.php @@ -67,21 +67,14 @@ if (!defined('CORE_PATH')) { define('APP_PATH', ROOT . DS . APP_DIR . DS); define('CORE_PATH', CAKE_CORE_INCLUDE_PATH . DS); } -if (!include(CORE_PATH . 'cake' . DS . 'bootstrap.php')) { +if (!include(CORE_PATH . 'Cake' . DS . 'bootstrap.php')) { trigger_error("CakePHP core could not be found. Check the value of CAKE_CORE_INCLUDE_PATH in APP/webroot/index.php. It should point to the directory containing your " . DS . "cake core directory and your " . DS . "vendors root directory.", E_USER_ERROR); } -$corePath = App::core('cake'); -if (isset($corePath[0])) { - define('TEST_CAKE_CORE_INCLUDE_PATH', rtrim($corePath[0], DS) . DS); -} else { - define('TEST_CAKE_CORE_INCLUDE_PATH', CAKE_CORE_INCLUDE_PATH); -} - if (Configure::read('debug') < 1) { - die(__('Debug setting does not allow access to this url.', true)); + die(__('Debug setting does not allow access to this url.')); } -require_once CAKE_TESTS_LIB . 'cake_test_suite_dispatcher.php'; +require_once CAKE_TESTS_LIB . 'CakeTestSuiteDispatcher.php'; CakeTestSuiteDispatcher::run(); diff --git a/cake/libs/controller/app_controller.php b/lib/Cake/Controller/AppController.php similarity index 96% rename from cake/libs/controller/app_controller.php rename to lib/Cake/Controller/AppController.php index 07c117dff..383cca2be 100644 --- a/cake/libs/controller/app_controller.php +++ b/lib/Cake/Controller/AppController.php @@ -20,6 +20,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Controller', 'Controller'); + /** * This is a placeholder class. * Create the same file in app/app_controller.php diff --git a/cake/libs/controller/cake_error_controller.php b/lib/Cake/Controller/CakeErrorController.php similarity index 84% rename from cake/libs/controller/cake_error_controller.php rename to lib/Cake/Controller/CakeErrorController.php index f55649672..7fd3b46f4 100644 --- a/cake/libs/controller/cake_error_controller.php +++ b/lib/Cake/Controller/CakeErrorController.php @@ -22,10 +22,8 @@ class CakeErrorController extends AppController { * @access public * @return void */ - function __construct() { - parent::__construct(); - $this->_set(Router::getPaths()); - $this->request = Router::getRequest(false); + function __construct($request = null) { + parent::__construct($request); $this->constructClasses(); $this->Components->trigger('initialize', array(&$this)); $this->_set(array('cacheAction' => false, 'viewPath' => 'errors')); diff --git a/cake/libs/controller/component.php b/lib/Cake/Controller/Component.php similarity index 98% rename from cake/libs/controller/component.php rename to lib/Cake/Controller/Component.php index f55840d1f..0993c171b 100644 --- a/cake/libs/controller/component.php +++ b/lib/Cake/Controller/Component.php @@ -15,7 +15,7 @@ * @since CakePHP(tm) v 1.2 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Controller', 'ComponentCollection', false); +App::uses('ComponentCollection', 'Controller'); /** * Base class for an individual Component. Components provide resuable bits of diff --git a/cake/libs/controller/components/acl.php b/lib/Cake/Controller/Component/AclComponent.php similarity index 94% rename from cake/libs/controller/components/acl.php rename to lib/Cake/Controller/Component/AclComponent.php index 6795ab335..fde44da62 100644 --- a/cake/libs/controller/components/acl.php +++ b/lib/Cake/Controller/Component/AclComponent.php @@ -19,6 +19,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Component', 'Controller'); + /** * Access Control List factory class. * @@ -66,7 +68,7 @@ class AclComponent extends Component { list($plugin, $name) = pluginSplit($name); $name .= 'Component'; } else { - throw new CakeException(__('Could not find %s.', $name)); + throw new CakeException(__d('cake_dev', 'Could not find %s.', $name)); } } $this->adapter($name); @@ -90,7 +92,7 @@ class AclComponent extends Component { $adapter = new $adapter(); } if (!$adapter instanceof AclInterface) { - throw new CakeException(__('AclComponent adapters must implement AclInterface')); + throw new CakeException(__d('cake_dev', 'AclComponent adapters must implement AclInterface')); } $this->_Instance = $adapter; $this->_Instance->initialize($this); @@ -161,7 +163,7 @@ class AclComponent extends Component { * @deprecated */ public function grant($aro, $aco, $action = "*") { - trigger_error(__('AclComponent::grant() is deprecated, use allow() instead'), E_USER_WARNING); + trigger_error(__d('cake_dev', 'AclComponent::grant() is deprecated, use allow() instead'), E_USER_WARNING); return $this->_Instance->allow($aro, $aco, $action); } @@ -175,7 +177,7 @@ class AclComponent extends Component { * @deprecated */ public function revoke($aro, $aco, $action = "*") { - trigger_error(__('AclComponent::revoke() is deprecated, use deny() instead'), E_USER_WARNING); + trigger_error(__d('cake_dev', 'AclComponent::revoke() is deprecated, use deny() instead'), E_USER_WARNING); return $this->_Instance->deny($aro, $aco, $action); } } @@ -262,9 +264,7 @@ class DbAcl extends Object implements AclInterface { */ function __construct() { parent::__construct(); - if (!class_exists('AclNode')) { - require LIBS . 'model' . DS . 'db_acl.php'; - } + App::uses('AclNode', 'Model'); $this->Aro = ClassRegistry::init(array('class' => 'Aro', 'alias' => 'Aro')); $this->Aco = ClassRegistry::init(array('class' => 'Aco', 'alias' => 'Aco')); } @@ -299,12 +299,12 @@ class DbAcl extends Object implements AclInterface { $acoPath = $this->Aco->node($aco); if (empty($aroPath) || empty($acoPath)) { - trigger_error(__("DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING); + trigger_error(__d('cake_dev', "DbAcl::check() - Failed ARO/ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING); return false; } if ($acoPath == null || $acoPath == array()) { - trigger_error(__("DbAcl::check() - Failed ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING); + trigger_error(__d('cake_dev', "DbAcl::check() - Failed ACO node lookup in permissions check. Node references:\nAro: ") . print_r($aro, true) . "\nAco: " . print_r($aco, true), E_USER_WARNING); return false; } @@ -312,7 +312,7 @@ class DbAcl extends Object implements AclInterface { $acoNode = $acoPath[0]; if ($action != '*' && !in_array('_' . $action, $permKeys)) { - trigger_error(__("ACO permissions key %s does not exist in DbAcl::check()", $action), E_USER_NOTICE); + trigger_error(__d('cake_dev', "ACO permissions key %s does not exist in DbAcl::check()", $action), E_USER_NOTICE); return false; } @@ -386,7 +386,7 @@ class DbAcl extends Object implements AclInterface { $save = array(); if ($perms == false) { - trigger_error(__('DbAcl::allow() - Invalid node'), E_USER_WARNING); + trigger_error(__d('cake_dev', 'DbAcl::allow() - Invalid node'), E_USER_WARNING); return false; } if (isset($perms[0])) { @@ -657,7 +657,7 @@ class IniAcl extends Object implements AclInterface { * @return array INI section structure */ public function readConfigFile($filename) { - App::import('Core', 'config/IniReader'); + App::uses('IniReader', 'Configure'); $iniFile = new IniReader(dirname($filename) . DS); return $iniFile->read(basename($filename)); } diff --git a/lib/Cake/Controller/Component/Auth/ActionsAuthorize.php b/lib/Cake/Controller/Component/Auth/ActionsAuthorize.php new file mode 100644 index 000000000..684fb47a0 --- /dev/null +++ b/lib/Cake/Controller/Component/Auth/ActionsAuthorize.php @@ -0,0 +1,40 @@ +_Collection->load('Acl'); + return $Acl->check($user, $this->action($request)); + } +} \ No newline at end of file diff --git a/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php b/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php new file mode 100644 index 000000000..aba2a8328 --- /dev/null +++ b/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php @@ -0,0 +1,111 @@ + 1).` + * + * @var array + */ + public $settings = array( + 'fields' => array( + 'username' => 'username', + 'password' => 'password' + ), + 'userModel' => 'User', + 'scope' => array() + ); + +/** + * A Component collection, used to get more components. + * + * @var ComponentCollection + */ + protected $_Collection; + +/** + * Constructor + * + * @param ComponentCollection $collection The Component collection used on this request. + * @param array $settings Array of settings to use. + */ + public function __construct(ComponentCollection $collection, $settings) { + $this->_Collection = $collection; + $this->settings = Set::merge($this->settings, $settings); + } + +/** + * Find a user record using the standard options. + * + * @param string $username The username/identifier. + * @param string $password The unhashed password. + * @return Mixed Either false on failure, or an array of user data. + */ + protected function _findUser($username, $password) { + $userModel = $this->settings['userModel']; + list($plugin, $model) = pluginSplit($userModel); + $fields = $this->settings['fields']; + + $conditions = array( + $model . '.' . $fields['username'] => $username, + $model . '.' . $fields['password'] => AuthComponent::password($password), + ); + if (!empty($this->settings['scope'])) { + $conditions = array_merge($conditions, $this->settings['scope']); + } + $result = ClassRegistry::init($userModel)->find('first', array( + 'conditions' => $conditions, + 'recursive' => 0 + )); + if (empty($result) || empty($result[$model])) { + return false; + } + unset($result[$model][$fields['password']]); + return $result[$model]; + } + +/** + * Authenticate a user based on the request information. + * + * @param CakeRequest $request Request to get authentication information from. + * @param CakeResponse $response A response object that can have headers added. + * @return mixed Either false on failure, or an array of user data on success. + */ + abstract public function authenticate(CakeRequest $request, CakeResponse $response); + +/** + * Get a user based on information in the request. Primarily used by stateless authentication + * systems like basic and digest auth. + * + * @param CakeRequest $request Request object. + * @return mixed Either false or an array of user information + */ + public function getUser($request) { + return false; + } +} \ No newline at end of file diff --git a/lib/Cake/Controller/Component/Auth/BaseAuthorize.php b/lib/Cake/Controller/Component/Auth/BaseAuthorize.php new file mode 100644 index 000000000..f4b7cad27 --- /dev/null +++ b/lib/Cake/Controller/Component/Auth/BaseAuthorize.php @@ -0,0 +1,135 @@ +action(); + * - `actionMap` - Action -> crud mappings. Used by authorization objects that want to map actions to CRUD roles. + * + * @var array + */ + public $settings = array( + 'actionPath' => null, + 'actionMap' => array( + 'index' => 'read', + 'add' => 'create', + 'edit' => 'update', + 'view' => 'read', + 'delete' => 'delete', + 'remove' => 'delete' + ) + ); + +/** + * Constructor + * + * @param Controller $controller The controller for this request. + * @param string $settings An array of settings. This class does not use any settings. + */ + public function __construct(ComponentCollection $collection, $settings = array()) { + $this->_Collection = $collection; + $controller = $collection->getController(); + $this->controller($controller); + $this->settings = Set::merge($this->settings, $settings); + } + +/** + * Checks user authorization. + * + * @param array $user Active user data + * @param CakeRequest $request + * @return boolean + */ + abstract public function authorize($user, CakeRequest $request); + +/** + * Accessor to the controller object. + * + * @param mixed $controller null to get, a controller to set. + * @return mixed. + */ + public function controller($controller = null) { + if ($controller) { + if (!$controller instanceof Controller) { + throw new CakeException(__d('cake_dev', '$controller needs to be an instance of Controller')); + } + $this->_Controller = $controller; + return true; + } + return $this->_Controller; + } + +/** + * Get the action path for a given request. Primarily used by authorize objects + * that need to get information about the plugin, controller, and action being invoked. + * + * @param CakeRequest $request The request a path is needed for. + * @return string the action path for the given request. + */ + public function action($request, $path = '/:plugin/:controller/:action') { + $plugin = empty($request['plugin']) ? null : Inflector::camelize($request['plugin']) . '/'; + return str_replace( + array(':controller', ':action', ':plugin/'), + array(Inflector::camelize($request['controller']), $request['action'], $plugin), + $this->settings['actionPath'] . $path + ); + } + +/** + * Maps crud actions to actual controller names. Used to modify or get the current mapped actions. + * + * @param mixed $map Either an array of mappings, or undefined to get current values. + * @return mixed Either the current mappings or null when setting. + */ + public function mapActions($map = array()) { + if (empty($map)) { + return $this->settings['actionMap']; + } + $crud = array('create', 'read', 'update', 'delete'); + foreach ($map as $action => $type) { + if (in_array($action, $crud) && is_array($type)) { + foreach ($type as $typedAction) { + $this->settings['actionMap'][$typedAction] = $action; + } + } else { + $this->settings['actionMap'][$action] = $type; + } + } + } +} \ No newline at end of file diff --git a/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php b/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php new file mode 100644 index 000000000..148734629 --- /dev/null +++ b/lib/Cake/Controller/Component/Auth/BasicAuthenticate.php @@ -0,0 +1,122 @@ + array( + * 'authenticate' => array('Basic') + * ) + * ); + * }}} + * + * In your login function just call `$this->Auth->login()` without any checks for POST data. This + * will send the authentication headers, and trigger the login dialog in the browser/client. + * + * @package cake.libs.controller.components.auth + * @since 2.0 + */ +class BasicAuthenticate extends BaseAuthenticate { +/** + * Settings for this object. + * + * - `fields` The fields to use to identify a user by. + * - `userModel` The model name of the User, defaults to User. + * - `scope` Additional conditions to use when looking up and authenticating users, + * i.e. `array('User.is_active' => 1).` + * - `realm` The realm authentication is for. Defaults the server name. + * + * @var array + */ + public $settings = array( + 'fields' => array( + 'username' => 'username', + 'password' => 'password' + ), + 'userModel' => 'User', + 'scope' => array(), + 'realm' => '', + ); + +/** + * Constructor, completes configuration for basic authentication. + * + * @param ComponentCollection $collection The Component collection used on this request. + * @param array $settings An array of settings. + */ + public function __construct(ComponentCollection $collection, $settings) { + parent::__construct($collection, $settings); + if (empty($this->settings['realm'])) { + $this->settings['realm'] = env('SERVER_NAME'); + } + } + +/** + * Authenticate a user using basic HTTP auth. Will use the configured User model and attempt a + * login using basic HTTP auth. + * + * @param CakeRequest $request The request to authenticate with. + * @param CakeResponse $response The response to add headers to. + * @return mixed Either false on failure, or an array of user data on success. + */ + public function authenticate(CakeRequest $request, CakeResponse $response) { + $result = $this->getUser($request); + + if (empty($result)) { + $response->header($this->loginHeaders()); + $response->statusCode(401); + $response->send(); + return false; + } + return $result; + } + +/** + * Get a user based on information in the request. Used by cookie-less auth for stateless clients. + * + * @param CakeRequest $request Request object. + * @return mixed Either false or an array of user information + */ + public function getUser($request) { + $username = env('PHP_AUTH_USER'); + $pass = env('PHP_AUTH_PW'); + + if (empty($username) || empty($pass)) { + return false; + } + return $this->_findUser($username, $pass); + } + +/** + * Generate the login headers + * + * @return string Headers for logging in. + */ + public function loginHeaders() { + return sprintf('WWW-Authenticate: Basic realm="%s"', $this->settings['realm']); + } +} \ No newline at end of file diff --git a/lib/Cake/Controller/Component/Auth/ControllerAuthorize.php b/lib/Cake/Controller/Component/Auth/ControllerAuthorize.php new file mode 100644 index 000000000..641eb6aff --- /dev/null +++ b/lib/Cake/Controller/Component/Auth/ControllerAuthorize.php @@ -0,0 +1,66 @@ +request->params['admin'])) { + * return $user['role'] == 'admin'; + * } + * return !empty($user); + * } + * }}} + * + * the above is simple implementation that would only authorize users of the 'admin' role to access + * admin routing. + * + * @package cake.libs.controller.components.auth + * @since 2.0 + * @see AuthComponent::$authenticate + */ +class ControllerAuthorize extends BaseAuthorize { + +/** + * Get/set the controller this authorize object will be working with. Also checks that isAuthorized is implemented. + * + * @param mixed $controller null to get, a controller to set. + * @return mixed. + */ + public function controller($controller = null) { + if ($controller) { + if (!method_exists($controller, 'isAuthorized')) { + throw new CakeException(__d('cake_dev', '$controller does not implement an isAuthorized() method.')); + } + } + return parent::controller($controller); + } + +/** + * Checks user authorization using a controller callback. + * + * @param array $user Active user data + * @param CakeRequest $request + * @return boolean + */ + public function authorize($user, CakeRequest $request) { + return (bool) $this->_Controller->isAuthorized($user); + } + +} \ No newline at end of file diff --git a/lib/Cake/Controller/Component/Auth/CrudAuthorize.php b/lib/Cake/Controller/Component/Auth/CrudAuthorize.php new file mode 100644 index 000000000..91be83b79 --- /dev/null +++ b/lib/Cake/Controller/Component/Auth/CrudAuthorize.php @@ -0,0 +1,100 @@ +_setPrefixMappings(); + } + +/** + * sets the crud mappings for prefix routes. + * + * @return void + */ + protected function _setPrefixMappings() { + $crud = array('create', 'read', 'update', 'delete'); + $map = array_combine($crud, $crud); + + $prefixes = Router::prefixes(); + if (!empty($prefixes)) { + foreach ($prefixes as $prefix) { + $map = array_merge($map, array( + $prefix . '_index' => 'read', + $prefix . '_add' => 'create', + $prefix . '_edit' => 'update', + $prefix . '_view' => 'read', + $prefix . '_remove' => 'delete', + $prefix . '_create' => 'create', + $prefix . '_read' => 'read', + $prefix . '_update' => 'update', + $prefix . '_delete' => 'delete' + )); + } + } + $this->mapActions($map); + } + +/** + * Authorize a user using the mapped actions and the AclComponent. + * + * @param array $user The user to authorize + * @param CakeRequest $request The request needing authorization. + * @return boolean + */ + public function authorize($user, CakeRequest $request) { + if (!isset($this->settings['actionMap'][$request->params['action']])) { + trigger_error(__d('cake_dev', + 'CrudAuthorize::authorize() - Attempted access of un-mapped action "%1$s" in controller "%2$s"', + $request->action, + $request->controller + ), + E_USER_WARNING + ); + return false; + } + $Acl = $this->_Collection->load('Acl'); + return $Acl->check( + $user, + $this->action($request, ':controller'), + $this->settings['actionMap'][$request->params['action']] + ); + } +} \ No newline at end of file diff --git a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php new file mode 100644 index 000000000..69c3ae228 --- /dev/null +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -0,0 +1,262 @@ + array( + * 'authenticate' => array('Digest') + * ) + * ); + * }}} + * + * In your login function just call `$this->Auth->login()` without any checks for POST data. This + * will send the authentication headers, and trigger the login dialog in the browser/client. + * + * ### Generating passwords compatible with Digest authentication. + * + * Due to the Digest authentication specification, digest auth requires a special password value. You + * can generate this password using `DigestAuthenticate::password()` + * + * `$digestPass = DigestAuthenticate::password($username, env('SERVER_NAME'), $password);` + * + * Its recommended that you store this digest auth only password separate from password hashes used for other + * login methods. For example `User.digest_pass` could be used for a digest password, while `User.password` would + * store the password hash for use with other methods like Basic or Form. + * + * @package cake.libs.controller.components.auth + * @since 2.0 + */ +class DigestAuthenticate extends BaseAuthenticate { +/** + * Settings for this object. + * + * - `fields` The fields to use to identify a user by. + * - `userModel` The model name of the User, defaults to User. + * - `scope` Additional conditions to use when looking up and authenticating users, + * i.e. `array('User.is_active' => 1).` + * - `realm` The realm authentication is for, Defaults to the servername. + * - `nonce` A nonce used for authentication. Defaults to `uniqid()`. + * - `qop` Defaults to auth, no other values are supported at this time. + * - `opaque` A string that must be returned unchanged by clients. Defaults to `md5($settings['realm'])` + * + * @var array + */ + public $settings = array( + 'fields' => array( + 'username' => 'username', + 'password' => 'password' + ), + 'userModel' => 'User', + 'scope' => array(), + 'realm' => '', + 'qop' => 'auth', + 'nonce' => '', + 'opaque' => '' + ); + +/** + * Constructor, completes configuration for digest authentication. + * + * @param ComponentCollection $collection The Component collection used on this request. + * @param array $settings An array of settings. + */ + public function __construct(ComponentCollection $collection, $settings) { + parent::__construct($collection, $settings); + if (empty($this->settings['realm'])) { + $this->settings['realm'] = env('SERVER_NAME'); + } + if (empty($this->settings['nonce'])) { + $this->settings['nonce'] = uniqid(''); + } + if (empty($this->settings['opaque'])) { + $this->settings['opaque'] = md5($this->settings['realm']); + } + } +/** + * Authenticate a user using Digest HTTP auth. Will use the configured User model and attempt a + * login using Digest HTTP auth. + * + * @param CakeRequest $request The request to authenticate with. + * @param CakeResponse $response The response to add headers to. + * @return mixed Either false on failure, or an array of user data on success. + */ + public function authenticate(CakeRequest $request, CakeResponse $response) { + $user = $this->getUser($request); + + if (empty($user)) { + $response->header($this->loginHeaders()); + $response->statusCode(401); + $response->send(); + return false; + } + return $user; + } + +/** + * Get a user based on information in the request. Used by cookie-less auth for stateless clients. + * + * @param CakeRequest $request Request object. + * @return mixed Either false or an array of user information + */ + public function getUser($request) { + $digest = $this->_getDigest(); + if (empty($digest)) { + return false; + } + $user = $this->_findUser($digest['username'], null); + if (empty($user)) { + return false; + } + $password = $user[$this->settings['fields']['password']]; + unset($user[$this->settings['fields']['password']]); + if ($digest['response'] === $this->generateResponseHash($digest, $password)) { + return $user; + } + return false; + } +/** + * Find a user record using the standard options. + * + * @param string $username The username/identifier. + * @param string $password Unused password, digest doesn't require passwords. + * @return Mixed Either false on failure, or an array of user data. + */ + protected function _findUser($username, $password) { + $userModel = $this->settings['userModel']; + list($plugin, $model) = pluginSplit($userModel); + $fields = $this->settings['fields']; + + $conditions = array( + $model . '.' . $fields['username'] => $username, + ); + if (!empty($this->settings['scope'])) { + $conditions = array_merge($conditions, $this->settings['scope']); + } + $result = ClassRegistry::init($userModel)->find('first', array( + 'conditions' => $conditions, + 'recursive' => 0 + )); + if (empty($result) || empty($result[$model])) { + return false; + } + return $result[$model]; + } + +/** + * Gets the digest headers from the request/environment. + * + * @return array Array of digest information. + */ + protected function _getDigest() { + $digest = env('PHP_AUTH_DIGEST'); + if (empty($digest) && function_exists('apache_request_headers')) { + $headers = apache_request_headers(); + if (!empty($headers['Authorization']) && substr($headers['Authorization'], 0, 7) == 'Digest ') { + $digest = substr($headers['Authorization'], 7); + } + } + if (empty($digest)) { + return false; + } + return $this->parseAuthData($digest); + } + +/** + * Parse the digest authentication headers and split them up. + * + * @param string $digest The raw digest authentication headers. + * @return array An array of digest authentication headers + */ + public function parseAuthData($digest) { + if (substr($digest, 0, 7) == 'Digest ') { + $digest = substr($digest, 7); + } + $keys = $match = array(); + $req = array('nonce' => 1, 'nc' => 1, 'cnonce' => 1, 'qop' => 1, 'username' => 1, 'uri' => 1, 'response' => 1); + preg_match_all('/(\w+)=([\'"]?)([a-zA-Z0-9@=.\/_-]+)\2/', $digest, $match, PREG_SET_ORDER); + + foreach ($match as $i) { + $keys[$i[1]] = $i[3]; + unset($req[$i[1]]); + } + + if (empty($req)) { + return $keys; + } + return null; + } + +/** + * Generate the response hash for a given digest array. + * + * @param array $digest Digest information containing data from DigestAuthenticate::parseAuthData(). + * @param string $password The digest hash password generated with DigestAuthenticate::password() + * @return string Response hash + */ + public function generateResponseHash($digest, $password) { + return md5( + $password . + ':' . $digest['nonce'] . ':' . $digest['nc'] . ':' . $digest['cnonce'] . ':' . $digest['qop'] . ':' . + md5(env('REQUEST_METHOD') . ':' . $digest['uri']) + ); + } + +/** + * Creates an auth digest password hash to store + * + * @param string $username The username to use in the digest hash. + * @param string $password The unhashed password to make a digest hash for. + * @param string $realm The realm the password is for. + * @return string the hashed password that can later be used with Digest authentication. + */ + public static function password($username, $password, $realm) { + return md5($username . ':' . $realm . ':' . $password); + } + +/** + * Generate the login headers + * + * @return string Headers for logging in. + */ + public function loginHeaders() { + $options = array( + 'realm' => $this->settings['realm'], + 'qop' => $this->settings['qop'], + 'nonce' => $this->settings['nonce'], + 'opaque' => $this->settings['opaque'] + ); + $opts = array(); + foreach ($options as $k => $v) { + $opts[] = sprintf('%s="%s"', $k, $v); + } + return 'WWW-Authenticate: Digest ' . implode(',', $opts); + } +} \ No newline at end of file diff --git a/lib/Cake/Controller/Component/Auth/FormAuthenticate.php b/lib/Cake/Controller/Component/Auth/FormAuthenticate.php new file mode 100644 index 000000000..f0f708088 --- /dev/null +++ b/lib/Cake/Controller/Component/Auth/FormAuthenticate.php @@ -0,0 +1,68 @@ +Auth->authenticate = array( + * 'Form' => array( + * 'scope' => array('User.active' => 1) + * ) + * ) + * }}} + * + * When configuring FormAuthenticate you can pass in settings to which fields, model and additional conditions + * are used. See FormAuthenticate::$settings for more information. + * + * @package cake.libs.controller.components.auth + * @since 2.0 + * @see AuthComponent::$authenticate + */ +class FormAuthenticate extends BaseAuthenticate { + +/** + * Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields` + * to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if + * there is no post data, either username or password is missing, of if the scope conditions have not been met. + * + * @param CakeRequest $request The request that contains login information. + * @param CakeResponse $response Unused response object. + * @return mixed. False on login failure. An array of User data on success. + */ + public function authenticate(CakeRequest $request, CakeResponse $response) { + $userModel = $this->settings['userModel']; + list($plugin, $model) = pluginSplit($userModel); + + $fields = $this->settings['fields']; + if (empty($request->data[$model])) { + return false; + } + if ( + empty($request->data[$model][$fields['username']]) || + empty($request->data[$model][$fields['password']]) + ) { + return false; + } + return $this->_findUser( + $request->data[$model][$fields['username']], + $request->data[$model][$fields['password']] + ); + } + +} \ No newline at end of file diff --git a/lib/Cake/Controller/Component/AuthComponent.php b/lib/Cake/Controller/Component/AuthComponent.php new file mode 100644 index 000000000..28b7e1bea --- /dev/null +++ b/lib/Cake/Controller/Component/AuthComponent.php @@ -0,0 +1,710 @@ +Auth->authenticate = array( + * 'Form' => array( + * 'userModel' => 'Users.User' + * ) + * ); + * }}} + * + * Using the class name without 'Authenticate' as the key, you can pass in an array of settings for each + * authentication object. Additionally you can define settings that should be set to all authentications objects + * using the 'all' key: + * + * {{{ + * $this->Auth->authenticate = array( + * 'all' => array( + * 'userModel' => 'Users.User', + * 'scope' => array('User.active' => 1) + * ), + * 'Form', + * 'Basic' + * ); + * }}} + * + * You can also use AuthComponent::ALL instead of the string 'all'. + * + * @var array + * @link http://book.cakephp.org/view/1278/authenticate + */ + public $authenticate = array('Form'); + +/** + * Objects that will be used for authentication checks. + * + * @var array + */ + protected $_authenticateObjects = array(); + +/** + * An array of authorization objects to use for authorizing users. You can configure + * multiple adapters and they will be checked sequentially when authorization checks are done. + * + * {{{ + * $this->Auth->authorize = array( + * 'Crud' => array( + * 'actionPath' => 'controllers/' + * ) + * ); + * }}} + * + * Using the class name without 'Authorize' as the key, you can pass in an array of settings for each + * authorization object. Additionally you can define settings that should be set to all authorization objects + * using the 'all' key: + * + * {{{ + * $this->Auth->authorize = array( + * 'all' => array( + * 'actionPath' => 'controllers/' + * ), + * 'Crud', + * 'CustomAuth' + * ); + * }}} + * + * You can also use AuthComponent::ALL instead of the string 'all' + * + * @var mixed + * @link http://book.cakephp.org/view/1275/authorize + */ + public $authorize = false; + +/** + * Objects that will be used for authorization checks. + * + * @var array + */ + protected $_authorizeObjects = array(); + +/** + * The name of an optional view element to render when an Ajax request is made + * with an invalid or expired session + * + * @var string + * @link http://book.cakephp.org/view/1277/ajaxLogin + */ + public $ajaxLogin = null; + +/** + * Settings to use when Auth needs to do a flash message with SessionComponent::setFlash(). + * Available keys are: + * + * - `element` - The element to use, defaults to 'default'. + * - `key` - The key to use, defaults to 'auth' + * - `params` - The array of additional params to use, defaults to array() + * + * @var array + */ + public $flash = array( + 'element' => 'default', + 'key' => 'auth', + 'params' => array() + ); + +/** + * The session key name where the record of the current user is stored. If + * unspecified, it will be "Auth.User". + * + * @var string + * @link http://book.cakephp.org/view/1276/sessionKey + */ + public static $sessionKey = 'Auth.User'; + +/** + * A URL (defined as a string or array) to the controller action that handles + * logins. Defaults to `/users/login` + * + * @var mixed + * @link http://book.cakephp.org/view/1269/loginAction + */ + public $loginAction = array( + 'controller' => 'users', + 'action' => 'login', + 'plugin' => null + ); + +/** + * Normally, if a user is redirected to the $loginAction page, the location they + * were redirected from will be stored in the session so that they can be + * redirected back after a successful login. If this session value is not + * set, the user will be redirected to the page specified in $loginRedirect. + * + * @var mixed + * @link http://book.cakephp.org/view/1270/loginRedirect + */ + public $loginRedirect = null; + +/** + * The default action to redirect to after the user is logged out. While AuthComponent does + * not handle post-logout redirection, a redirect URL will be returned from AuthComponent::logout(). + * Defaults to AuthComponent::$loginAction. + * + * @var mixed + * @see AuthComponent::$loginAction + * @see AuthComponent::logout() + * @link http://book.cakephp.org/view/1271/logoutRedirect + */ + public $logoutRedirect = null; + +/** + * Error to display when user attempts to access an object or action to which they do not have + * acccess. + * + * @var string + * @link http://book.cakephp.org/view/1273/authError + */ + public $authError = null; + +/** + * Controller actions for which user validation is not required. + * + * @var array + * @see AuthComponent::allow() + * @link http://book.cakephp.org/view/1251/Setting-Auth-Component-Variables + */ + public $allowedActions = array(); + +/** + * Request object + * + * @var CakeRequest + */ + public $request; + +/** + * Response object + * + * @var CakeResponse + */ + public $response; + +/** + * Method list for bound controller + * + * @var array + */ + protected $_methods = array(); + +/** + * Initializes AuthComponent for use in the controller + * + * @param object $controller A reference to the instantiating controller object + * @return void + */ + public function initialize($controller) { + $this->request = $controller->request; + $this->response = $controller->response; + $this->_methods = $controller->methods; + + if (Configure::read('debug') > 0) { + Debugger::checkSecurityKeys(); + } + } + +/** + * Main execution method. Handles redirecting of invalid users, and processing + * of login form data. + * + * @param object $controller A reference to the instantiating controller object + * @return boolean + */ + public function startup($controller) { + if ($controller->name == 'CakeError') { + return true; + } + + $methods = array_flip($controller->methods); + $action = $controller->request->params['action']; + + $isMissingAction = ( + $controller->scaffold === false && + !isset($methods[$action]) + ); + + if ($isMissingAction) { + return true; + } + + if (!$this->__setDefaults()) { + return false; + } + $request = $controller->request; + + $url = ''; + + if (isset($request->url)) { + $url = $request->url; + } + $url = Router::normalize($url); + $loginAction = Router::normalize($this->loginAction); + + $allowedActions = $this->allowedActions; + $isAllowed = ( + $this->allowedActions == array('*') || + in_array($action, $allowedActions) + ); + + if ($loginAction != $url && $isAllowed) { + return true; + } + + if ($loginAction == $url) { + if (empty($request->data)) { + if (!$this->Session->check('Auth.redirect') && !$this->loginRedirect && env('HTTP_REFERER')) { + $this->Session->write('Auth.redirect', $controller->referer(null, true)); + } + } + return true; + } else { + if (!$this->_getUser()) { + if (!$request->is('ajax')) { + $this->flash($this->authError); + $this->Session->write('Auth.redirect', Router::reverse($request)); + $controller->redirect($loginAction); + return false; + } elseif (!empty($this->ajaxLogin)) { + $controller->viewPath = 'elements'; + echo $controller->render($this->ajaxLogin, $this->RequestHandler->ajaxLayout); + $this->_stop(); + return false; + } else { + $controller->redirect(null, 403); + } + } + } + if (empty($this->authorize) || $this->isAuthorized($this->user())) { + return true; + } + + $this->flash($this->authError); + $controller->redirect($controller->referer(), null, true); + return false; + } + +/** + * Attempts to introspect the correct values for object properties including + * $userModel and $sessionKey. + * + * @param object $controller A reference to the instantiating controller object + * @return boolean + * @access private + */ + function __setDefaults() { + $defaults = array( + 'logoutRedirect' => $this->loginAction, + 'authError' => __d('cake', 'You are not authorized to access that location.') + ); + foreach ($defaults as $key => $value) { + if (empty($this->{$key})) { + $this->{$key} = $value; + } + } + return true; + } + +/** + * Uses the configured Authorization adapters to check whether or not a user is authorized. + * Each adapter will be checked in sequence, if any of them return true, then the user will + * be authorized for the request. + * + * @param mixed $user The user to check the authorization of. If empty the user in the session will be used. + * @param CakeRequest $request The request to authenticate for. If empty, the current request will be used. + * @return boolean True if $user is authorized, otherwise false + */ + public function isAuthorized($user = null, $request = null) { + if (empty($user) && !$this->user()) { + return false; + } elseif (empty($user)) { + $user = $this->user(); + } + if (empty($request)) { + $request = $this->request; + } + if (empty($this->_authorizeObjects)) { + $this->constructAuthorize(); + } + foreach ($this->_authorizeObjects as $authorizer) { + if ($authorizer->authorize($user, $request) === true) { + return true; + } + } + return false; + } + +/** + * Loads the authorization objects configured. + * + * @return mixed Either null when authorize is empty, or the loaded authorization objects. + */ + public function constructAuthorize() { + if (empty($this->authorize)) { + return; + } + $this->_authorizeObjects = array(); + $config = Set::normalize($this->authorize); + $global = array(); + if (isset($config[AuthComponent::ALL])) { + $global = $config[AuthComponent::ALL]; + unset($config[AuthComponent::ALL]); + } + foreach ($config as $class => $settings) { + list($plugin, $class) = pluginSplit($class, true); + $className = $class . 'Authorize'; + App::uses($className, $plugin . 'Controller/Component/Auth'); + if (!class_exists($className)) { + throw new CakeException(__d('cake_dev', 'Authorization adapter "%s" was not found.', $class)); + } + if (!method_exists($className, 'authorize')) { + throw new CakeException(__d('cake_dev', 'Authorization objects must implement an authorize method.')); + } + $settings = array_merge($global, (array)$settings); + $this->_authorizeObjects[] = new $className($this->_Collection, $settings); + } + return $this->_authorizeObjects; + } + +/** + * Takes a list of actions in the current controller for which authentication is not required, or + * no parameters to allow all actions. + * + * You can use allow with either an array, or var args. + * + * `$this->Auth->allow(array('edit', 'add'));` or + * `$this->Auth->allow('edit', 'add');` + * + * allow() also supports '*' as a wildcard to mean all actions. + * + * `$this->Auth->allow('*');` + * + * @param mixed $action Controller action name or array of actions + * @param string $action Controller action name + * @param string ... etc. + * @return void + * @link http://book.cakephp.org/view/1257/allow + */ + public function allow() { + $args = func_get_args(); + if (empty($args) || $args == array('*')) { + $this->allowedActions = $this->_methods; + } else { + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; + } + $this->allowedActions = array_merge($this->allowedActions, $args); + } + } + +/** + * Removes items from the list of allowed/no authentication required actions. + * + * You can use deny with either an array, or var args. + * + * `$this->Auth->deny(array('edit', 'add'));` or + * `$this->Auth->deny('edit', 'add');` + * + * @param mixed $action Controller action name or array of actions + * @param string $action Controller action name + * @param string ... etc. + * @return void + * @see AuthComponent::allow() + * @link http://book.cakephp.org/view/1258/deny + */ + public function deny() { + $args = func_get_args(); + if (isset($args[0]) && is_array($args[0])) { + $args = $args[0]; + } + foreach ($args as $arg) { + $i = array_search($arg, $this->allowedActions); + if (is_int($i)) { + unset($this->allowedActions[$i]); + } + } + $this->allowedActions = array_values($this->allowedActions); + } + +/** + * Maps action names to CRUD operations. Used for controller-based authentication. Make sure + * to configure the authorize property before calling this method. As it delegates $map to all the + * attached authorize objects. + * + * @param array $map Actions to map + * @return void + * @link http://book.cakephp.org/view/1260/mapActions + */ + public function mapActions($map = array()) { + if (empty($this->_authorizeObjects)) { + $this->constructAuthorize(); + } + foreach ($this->_authorizeObjects as $auth) { + $auth->mapActions($map); + } + } + +/** + * Log a user in. If a $user is provided that data will be stored as the logged in user. If `$user` is empty or not + * specified, the request will be used to identify a user. If the identification was successful, + * the user record is written to the session key specified in AuthComponent::$sessionKey. + * + * @param mixed $user Either an array of user data, or null to identify a user using the current request. + * @return boolean True on login success, false on failure + * @link http://book.cakephp.org/view/1261/login + */ + public function login($user = null) { + $this->__setDefaults(); + $this->_loggedIn = false; + + if (empty($user)) { + $user = $this->identify($this->request, $this->response); + } + if ($user) { + $this->Session->write(self::$sessionKey, $user); + $this->_loggedIn = true; + } + return $this->_loggedIn; + } + +/** + * Logs a user out, and returns the login action to redirect to. + * + * @param mixed $url Optional URL to redirect the user to after logout + * @return string AuthComponent::$loginAction + * @see AuthComponent::$loginAction + * @link http://book.cakephp.org/view/1262/logout + */ + public function logout() { + $this->__setDefaults(); + $this->Session->delete(self::$sessionKey); + $this->Session->delete('Auth.redirect'); + $this->_loggedIn = false; + return Router::normalize($this->logoutRedirect); + } + +/** + * Get the current user from the session. + * + * @param string $key field to retrive. Leave null to get entire User record + * @return mixed User record. or null if no user is logged in. + * @link http://book.cakephp.org/view/1264/user + */ + public static function user($key = null) { + if (!CakeSession::check(self::$sessionKey)) { + return null; + } + + if ($key == null) { + return CakeSession::read(self::$sessionKey); + } else { + $user = CakeSession::read(self::$sessionKey); + if (isset($user[$key])) { + return $user[$key]; + } + return null; + } + } + +/** + * Similar to AuthComponent::user() except if the session user cannot be found, connected authentication + * objects will have their getUser() methods called. This lets stateless authentication methods function correctly. + * + * @return boolean true if a user can be found, false if one cannot. + */ + protected function _getUser() { + $user = $this->user(); + if ($user) { + return true; + } + if (empty($this->_authenticateObjects)) { + $this->constructAuthenticate(); + } + foreach ($this->_authenticateObjects as $auth) { + $result = $auth->getUser($this->request); + if (!empty($result) && is_array($result)) { + return true; + } + } + return false; + } + +/** + * If no parameter is passed, gets the authentication redirect URL. Pass a url in to + * set the destination a user should be redirected to upon logging in. Will fallback to + * AuthComponent::$loginRedirect if there is no stored redirect value. + * + * @param mixed $url Optional URL to write as the login redirect URL. + * @return string Redirect URL + */ + public function redirect($url = null) { + if (!is_null($url)) { + $redir = $url; + $this->Session->write('Auth.redirect', $redir); + } elseif ($this->Session->check('Auth.redirect')) { + $redir = $this->Session->read('Auth.redirect'); + $this->Session->delete('Auth.redirect'); + + if (Router::normalize($redir) == Router::normalize($this->loginAction)) { + $redir = $this->loginRedirect; + } + } else { + $redir = $this->loginRedirect; + } + return Router::normalize($redir); + } + +/** + * Use the configured authentication adapters, and attempt to identify the user + * by credentials contained in $request. + * + * @param CakeRequest $request The request that contains authentication data. + * @return array User record data, or false, if the user could not be identified. + */ + public function identify(CakeRequest $request, CakeResponse $response) { + if (empty($this->_authenticateObjects)) { + $this->constructAuthenticate(); + } + foreach ($this->_authenticateObjects as $auth) { + $result = $auth->authenticate($request, $response); + if (!empty($result) && is_array($result)) { + return $result; + } + } + return false; + } + +/** + * loads the configured authentication objects. + * + * @return mixed either null on empty authenticate value, or an array of loaded objects. + */ + public function constructAuthenticate() { + if (empty($this->authenticate)) { + return; + } + $this->_authenticateObjects = array(); + $config = Set::normalize($this->authenticate); + $global = array(); + if (isset($config[AuthComponent::ALL])) { + $global = $config[AuthComponent::ALL]; + unset($config[AuthComponent::ALL]); + } + foreach ($config as $class => $settings) { + list($plugin, $class) = pluginSplit($class, true); + $className = $class . 'Authenticate'; + App::uses($className, $plugin . 'Controller/Component/Auth'); + if (!class_exists($className)) { + throw new CakeException(__d('cake_dev', 'Authentication adapter "%s" was not found.', $class)); + } + if (!method_exists($className, 'authenticate')) { + throw new CakeException(__d('cake_dev', 'Authentication objects must implement an authenticate method.')); + } + $settings = array_merge($global, (array)$settings); + $this->_authenticateObjects[] = new $className($this->_Collection, $settings); + } + return $this->_authenticateObjects; + } + +/** + * Hash a password with the application's salt value (as defined with Configure::write('Security.salt'); + * + * @param string $password Password to hash + * @return string Hashed password + * @link http://book.cakephp.org/view/1263/password + */ + public static function password($password) { + return Security::hash($password, null, true); + } + +/** + * Component shutdown. If user is logged in, wipe out redirect. + * + * @param object $controller Instantiating controller + */ + public function shutdown($controller) { + if ($this->_loggedIn) { + $this->Session->delete('Auth.redirect'); + } + } + +/** + * Sets or gets whether the user is logged in + * + * @param boolean $logged sets the status of the user, true to logged in, false to logged out + * @return boolean true if the user is logged in, false otherwise + * @access public + */ + public function loggedIn($logged = null) { + if (!is_null($logged)) { + $this->_loggedIn = $logged; + } + return $this->_loggedIn; + } + +/** + * Set a flash message. Uses the Session component, and values from AuthComponent::$flash. + * + * @param string $message The message to set. + * @return void + */ + public function flash($message) { + $this->Session->setFlash($message, $this->flash['element'], $this->flash['params'], $this->flash['key']); + } +} diff --git a/cake/libs/controller/components/cookie.php b/lib/Cake/Controller/Component/CookieComponent.php similarity index 98% rename from cake/libs/controller/components/cookie.php rename to lib/Cake/Controller/Component/CookieComponent.php index 87fb4a802..cca49a5bf 100644 --- a/cake/libs/controller/components/cookie.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -17,10 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -/** - * Load Security class - */ -App::import('Core', 'Security'); +App::uses('Component', 'Controller'); +App::uses('Security', 'Utility'); /** * Cookie Component. @@ -174,6 +172,9 @@ class CookieComponent extends Component { public function __construct(ComponentCollection $collection, $settings = array()) { $this->key = Configure::read('Security.salt'); parent::__construct($collection, $settings); + if (isset($this->time)) { + $this->_expire($this->time); + } } /** diff --git a/cake/libs/controller/components/email.php b/lib/Cake/Controller/Component/EmailComponent.php old mode 100755 new mode 100644 similarity index 94% rename from cake/libs/controller/components/email.php rename to lib/Cake/Controller/Component/EmailComponent.php index 031ef8543..103ccafed --- a/cake/libs/controller/components/email.php +++ b/lib/Cake/Controller/Component/EmailComponent.php @@ -16,7 +16,9 @@ * @since CakePHP(tm) v 1.2.0.3467 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'Multibyte'); + +App::uses('Component', 'Controller'); +App::uses('Multibyte', 'I18n'); /** * EmailComponent @@ -157,7 +159,7 @@ class EmailComponent extends Component { /** * Line feed character(s) to be used when sending using mail() function - * If null PHP_EOL is used. + * By default PHP_EOL is used. * RFC2822 requires it to be CRLF but some Unix * mail transfer agents replace LF by CRLF automatically * (which leads to doubling CR if CRLF is used). @@ -165,7 +167,7 @@ class EmailComponent extends Component { * @var string * @access public */ - var $lineFeed = null; + var $lineFeed = PHP_EOL; /** * @deprecated see lineLength @@ -456,12 +458,12 @@ class EmailComponent extends Component { $viewClass = $this->Controller->view; if ($viewClass != 'View') { - list($plugin, $viewClass) = pluginSplit($viewClass); + list($plugin, $viewClass) = pluginSplit($viewClass, true); $viewClass = $viewClass . 'View'; - App::import('View', $this->Controller->view); + App::uses($viewClass, $plugin . 'View'); } - $View = new $viewClass($this->Controller, false); + $View = new $viewClass($this->Controller); $View->layout = $this->layout; $msg = array(); @@ -499,6 +501,7 @@ class EmailComponent extends Component { $msg[] = '--alt-' . $this->_boundary . '--'; $msg[] = ''; + ClassRegistry::removeObject('view'); return $msg; } @@ -528,6 +531,7 @@ class EmailComponent extends Component { } $msg = array_merge($msg, $content); + ClassRegistry::removeObject('view'); return $msg; } @@ -562,11 +566,7 @@ class EmailComponent extends Component { $headers = array(); if ($this->delivery == 'smtp') { - if (is_array($this->to)) { - $headers['To'] = implode(', ', array_map(array($this, '_formatAddress'), $this->to)); - } else { - $headers['To'] = $this->_formatAddress($this->to); - } + $headers['To'] = implode(', ', array_map(array($this, '_formatAddress'), (array)$this->to)); } $headers['From'] = $this->_formatAddress($this->from); @@ -581,11 +581,11 @@ class EmailComponent extends Component { } if (!empty($this->cc)) { - $headers['cc'] = implode(', ', array_map(array($this, '_formatAddress'), $this->cc)); + $headers['Cc'] = implode(', ', array_map(array($this, '_formatAddress'), (array)$this->cc)); } if (!empty($this->bcc) && $this->delivery != 'smtp') { - $headers['Bcc'] = implode(', ', array_map(array($this, '_formatAddress'), $this->bcc)); + $headers['Bcc'] = implode(', ', array_map(array($this, '_formatAddress'), (array)$this->bcc)); } if ($this->delivery == 'smtp') { $headers['Subject'] = $this->_encode($this->subject); @@ -725,7 +725,7 @@ class EmailComponent extends Component { $formatted = array(); if ($this->_lineLength !== null) { - trigger_error(__('_lineLength cannot be accessed please use lineLength'), E_USER_WARNING); + trigger_error(__d('cake_dev', '_lineLength cannot be accessed please use lineLength'), E_USER_WARNING); $this->lineLength = $this->_lineLength; } @@ -777,14 +777,15 @@ class EmailComponent extends Component { * @access private */ function _formatAddress($string, $smtp = false) { - $hasAlias = preg_match('/((.*)\s)?<(.+)>/', $string, $matches); + $hasAlias = preg_match('/((.*))?\s?<(.+)>/', $string, $matches); if ($smtp && $hasAlias) { return $this->_strip('<' . $matches[3] . '>'); } elseif ($smtp) { return $this->_strip('<' . $string . '>'); } + if ($hasAlias && !empty($matches[2])) { - return $this->_strip($matches[2] . ' <' . $matches[3] . '>'); + return $this->_encode($matches[2]) . $this->_strip(' <' . $matches[3] . '>'); } return $this->_strip($string); } @@ -819,13 +820,8 @@ class EmailComponent extends Component { * @access private */ function _mail() { - if ($this->lineFeed === null) { - $lineFeed = PHP_EOL; - } else { - $lineFeed = $this->lineFeed; - } - $header = implode($lineFeed, $this->_header); - $message = implode($lineFeed, $this->_message); + $header = implode($this->lineFeed, $this->_header); + $message = implode($this->lineFeed, $this->_message); if (is_array($this->to)) { $to = implode(', ', array_map(array($this, '_formatAddress'), $this->to)); } else { @@ -837,6 +833,18 @@ class EmailComponent extends Component { return @mail($to, $this->_encode($this->subject), $message, $header, $this->additionalParams); } + +/** + * Helper method to get socket, overridden in tests + * + * @param array $config Config data for the socket. + * @return void + * @access protected + */ + function _getSocket($config) { + $this->_smtpConnection = new CakeSocket($config); + } + /** * Sends out email via SMTP * @@ -844,7 +852,7 @@ class EmailComponent extends Component { * @access private */ function _smtp() { - App::import('Core', 'CakeSocket'); + App::uses('CakeSocket', 'Network'); $defaults = array( 'host' => 'localhost', @@ -853,7 +861,7 @@ class EmailComponent extends Component { 'timeout' => 30 ); $this->smtpOptions = array_merge($defaults, $this->smtpOptions); - $this->_smtpConnection = new CakeSocket($this->smtpOptions); + $this->_getSocket($this->smtpOptions); if (!$this->_smtpConnection->connect()) { $this->smtpError = $this->_smtpConnection->lastError(); @@ -867,7 +875,7 @@ class EmailComponent extends Component { if (isset($this->smtpOptions['client'])) { $host = $this->smtpOptions['client']; } elseif (!empty($httpHost)) { - $host = $httpHost; + list($host) = explode(':', $httpHost); } else { $host = 'localhost'; } diff --git a/cake/libs/controller/components/paginator.php b/lib/Cake/Controller/Component/PaginatorComponent.php similarity index 100% rename from cake/libs/controller/components/paginator.php rename to lib/Cake/Controller/Component/PaginatorComponent.php diff --git a/cake/libs/controller/components/request_handler.php b/lib/Cake/Controller/Component/RequestHandlerComponent.php similarity index 98% rename from cake/libs/controller/components/request_handler.php rename to lib/Cake/Controller/Component/RequestHandlerComponent.php index 3889f716c..56cf6c448 100644 --- a/cake/libs/controller/components/request_handler.php +++ b/lib/Cake/Controller/Component/RequestHandlerComponent.php @@ -19,6 +19,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Xml', 'Utility'); + /** * Request object for handling HTTP requests * @@ -132,6 +134,7 @@ class RequestHandlerComponent extends Component { } } } + $this->params = $controller->params; $this->_set($settings); } @@ -170,9 +173,6 @@ class RequestHandlerComponent extends Component { } if ($this->requestedWith('xml')) { - if (!class_exists('Xml')) { - App::import('Core', 'Xml'); - } try { $xml = Xml::build(trim(file_get_contents('php://input'))); @@ -541,7 +541,8 @@ class RequestHandlerComponent extends Component { ); if (!$isAdded) { - if (App::import('Helper', $helper)) { + App::uses($helper . 'Helper', 'View/Helper'); + if (class_exists($helper . 'Helper')) { $controller->helpers[] = $helper; } } @@ -585,7 +586,9 @@ class RequestHandlerComponent extends Component { } if ($cType != null) { - $this->response->type($cType); + if (empty($this->request->params['requested'])) { + $this->response->type($cType); + } if (!empty($options['charset'])) { $this->response->charset($options['charset']); diff --git a/cake/libs/controller/components/security.php b/lib/Cake/Controller/Component/SecurityComponent.php similarity index 66% rename from cake/libs/controller/components/security.php rename to lib/Cake/Controller/Component/SecurityComponent.php index daf0bc8bb..16cdc6413 100644 --- a/cake/libs/controller/components/security.php +++ b/lib/Cake/Controller/Component/SecurityComponent.php @@ -16,8 +16,10 @@ * @since CakePHP(tm) v 0.10.8.2156 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'String', false); -App::import('Core', 'Security', false); + +App::uses('Component', 'Controller'); +App::uses('String', 'Utility'); +App::uses('Security', 'Utility'); /** * SecurityComponent @@ -89,33 +91,6 @@ class SecurityComponent extends Component { */ public $requireAuth = array(); -/** - * List of actions that require an HTTP-authenticated login (basic or digest) - * - * @var array - * @access public - * @see SecurityComponent::requireLogin() - */ - public $requireLogin = array(); - -/** - * Login options for SecurityComponent::requireLogin() - * - * @var array - * @access public - * @see SecurityComponent::requireLogin() - */ - public $loginOptions = array('type' => '', 'prompt' => null); - -/** - * An associative array of usernames/passwords used for HTTP-authenticated logins. - * - * @var array - * @access public - * @see SecurityComponent::requireLogin() - */ - public $loginUsers = array(); - /** * Controllers from which actions of the current controller are allowed to receive * requests. @@ -211,11 +186,10 @@ class SecurityComponent extends Component { */ public function startup($controller) { $this->request = $controller->request; - $this->_action = strtolower($this->request->params['action']); + $this->_action = $this->request->params['action']; $this->_methodsRequired($controller); $this->_secureRequired($controller); $this->_authRequired($controller); - $this->_loginRequired($controller); $isPost = ($this->request->is('post') || $this->request->is('put')); $isRequestAction = ( @@ -299,134 +273,6 @@ class SecurityComponent extends Component { $this->_requireMethod('Auth', $args); } -/** - * Sets the actions that require an HTTP-authenticated request, or empty for all actions - * - * @return void - * @link http://book.cakephp.org/view/1302/requireLogin - */ - public function requireLogin() { - $args = func_get_args(); - $base = $this->loginOptions; - - foreach ($args as $i => $arg) { - if (is_array($arg)) { - $this->loginOptions = $arg; - unset($args[$i]); - } - } - $this->loginOptions = array_merge($base, $this->loginOptions); - $this->_requireMethod('Login', $args); - if (isset($this->loginOptions['users'])) { - $this->loginUsers =& $this->loginOptions['users']; - } - } - -/** - * Attempts to validate the login credentials for an HTTP-authenticated request - * - * @param string $type Either 'basic', 'digest', or null. If null/empty, will try both. - * @return mixed If successful, returns an array with login name and password, otherwise null. - * @link http://book.cakephp.org/view/1303/loginCredentials-string-type - */ - public function loginCredentials($type = null) { - switch (strtolower($type)) { - case 'basic': - $login = array('username' => env('PHP_AUTH_USER'), 'password' => env('PHP_AUTH_PW')); - if (!empty($login['username'])) { - return $login; - } - break; - case 'digest': - default: - $digest = null; - - if (version_compare(PHP_VERSION, '5.1') != -1) { - $digest = env('PHP_AUTH_DIGEST'); - } elseif (function_exists('apache_request_headers')) { - $headers = apache_request_headers(); - if (isset($headers['Authorization']) && !empty($headers['Authorization']) && substr($headers['Authorization'], 0, 7) == 'Digest ') { - $digest = substr($headers['Authorization'], 7); - } - } else { - // Server doesn't support digest-auth headers - trigger_error(__('SecurityComponent::loginCredentials() - Server does not support digest authentication'), E_USER_WARNING); - } - - if (!empty($digest)) { - return $this->parseDigestAuthData($digest); - } - break; - } - return null; - } - -/** - * Generates the text of an HTTP-authentication request header from an array of options. - * - * @param array $options Set of options for header - * @return string HTTP-authentication request header - * @link http://book.cakephp.org/view/1304/loginRequest-array-options - */ - public function loginRequest($options = array()) { - $options = array_merge($this->loginOptions, $options); - $this->_setLoginDefaults($options); - $auth = 'WWW-Authenticate: ' . ucfirst($options['type']); - $out = array('realm="' . $options['realm'] . '"'); - - if (strtolower($options['type']) == 'digest') { - $out[] = 'qop="auth"'; - $out[] = 'nonce="' . uniqid("") . '"'; - $out[] = 'opaque="' . md5($options['realm']) . '"'; - } - - return $auth . ' ' . implode(',', $out); - } - -/** - * Parses an HTTP digest authentication response, and returns an array of the data, or null on failure. - * - * @param string $digest Digest authentication response - * @return array Digest authentication parameters - * @link http://book.cakephp.org/view/1305/parseDigestAuthData-string-digest - */ - public function parseDigestAuthData($digest) { - if (substr($digest, 0, 7) == 'Digest ') { - $digest = substr($digest, 7); - } - $keys = array(); - $match = array(); - $req = array('nonce' => 1, 'nc' => 1, 'cnonce' => 1, 'qop' => 1, 'username' => 1, 'uri' => 1, 'response' => 1); - preg_match_all('/(\w+)=([\'"]?)([a-zA-Z0-9@=.\/_-]+)\2/', $digest, $match, PREG_SET_ORDER); - - foreach ($match as $i) { - $keys[$i[1]] = $i[3]; - unset($req[$i[1]]); - } - - if (empty($req)) { - return $keys; - } - return null; - } - -/** - * Generates a hash to be compared with an HTTP digest-authenticated response - * - * @param array $data HTTP digest response data, as parsed by SecurityComponent::parseDigestAuthData() - * @return string Digest authentication hash - * @access public - * @see SecurityComponent::parseDigestAuthData() - * @link http://book.cakephp.org/view/1306/generateDigestResponseHash-array-data - */ - function generateDigestResponseHash($data) { - return md5( - md5($data['username'] . ':' . $this->loginOptions['realm'] . ':' . $this->loginUsers[$data['username']]) . - ':' . $data['nonce'] . ':' . $data['nc'] . ':' . $data['cnonce'] . ':' . $data['qop'] . ':' . - md5(env('REQUEST_METHOD') . ':' . $data['uri']) - ); - } - /** * Black-hole an invalid request with a 404 error or custom callback. If SecurityComponent::$blackHoleCallback * is specified, it will use this callback by executing the method indicated in $error @@ -475,10 +321,10 @@ class SecurityComponent extends Component { foreach (array('Post', 'Get', 'Put', 'Delete') as $method) { $property = 'require' . $method; if (is_array($this->$property) && !empty($this->$property)) { - $require = array_map('strtolower', $this->$property); + $require = $this->$property; if (in_array($this->_action, $require) || $this->$property == array('*')) { - if (!$this->request->is(strtolower($method))) { - if (!$this->blackHole($controller, strtolower($method))) { + if (!$this->request->is($method)) { + if (!$this->blackHole($controller, $method)) { return null; } } @@ -496,7 +342,7 @@ class SecurityComponent extends Component { */ protected function _secureRequired($controller) { if (is_array($this->requireSecure) && !empty($this->requireSecure)) { - $requireSecure = array_map('strtolower', $this->requireSecure); + $requireSecure = $this->requireSecure; if (in_array($this->_action, $requireSecure) || $this->requireSecure == array('*')) { if (!$this->request->is('ssl')) { @@ -517,7 +363,7 @@ class SecurityComponent extends Component { */ protected function _authRequired($controller) { if (is_array($this->requireAuth) && !empty($this->requireAuth) && !empty($this->request->data)) { - $requireAuth = array_map('strtolower', $this->requireAuth); + $requireAuth = $this->requireAuth; if (in_array($this->request->params['action'], $requireAuth) || $this->requireAuth == array('*')) { if (!isset($controller->request->data['_Token'] )) { @@ -544,53 +390,6 @@ class SecurityComponent extends Component { return true; } -/** - * Check if login is required - * - * @param object $controller Instantiating controller - * @return bool true if login is required - */ - protected function _loginRequired($controller) { - if (is_array($this->requireLogin) && !empty($this->requireLogin)) { - $requireLogin = $this->requireLogin; - - if (in_array($this->_action, $this->requireLogin) || $this->requireLogin == array('*')) { - $login = $this->loginCredentials($this->loginOptions['type']); - - if ($login == null) { - $controller->header($this->loginRequest()); - - if (!empty($this->loginOptions['prompt'])) { - $this->_callback($controller, $this->loginOptions['prompt']); - } else { - $this->blackHole($controller, 'login'); - } - } else { - if (isset($this->loginOptions['login'])) { - $this->_callback($controller, $this->loginOptions['login'], array($login)); - } else { - if (strtolower($this->loginOptions['type']) == 'digest') { - if ($login && isset($this->loginUsers[$login['username']])) { - if ($login['response'] == $this->generateDigestResponseHash($login)) { - return true; - } - } - $this->blackHole($controller, 'login'); - } else { - if ( - !(in_array($login['username'], array_keys($this->loginUsers)) && - $this->loginUsers[$login['username']] == $login['password']) - ) { - $this->blackHole($controller, 'login'); - } - } - } - } - } - } - return true; - } - /** * Validate submitted form * @@ -689,7 +488,7 @@ class SecurityComponent extends Component { $tokenData = array(); if ($this->Session->check('_Token')) { $tokenData = $this->Session->read('_Token'); - if (!empty($tokenData['csrfTokens'])) { + if (!empty($tokenData['csrfTokens']) && is_array($tokenData['csrfTokens'])) { $token['csrfTokens'] = $this->_expireTokens($tokenData['csrfTokens']); } } @@ -738,22 +537,6 @@ class SecurityComponent extends Component { return $tokens; } -/** - * Sets the default login options for an HTTP-authenticated request - * - * @param array $options Default login options - * @return void - */ - protected function _setLoginDefaults(&$options) { - $options = array_merge(array( - 'type' => 'basic', - 'realm' => env('SERVER_NAME'), - 'qop' => 'auth', - 'nonce' => String::uuid() - ), array_filter($options)); - $options = array_merge(array('opaque' => md5($options['realm'])), $options); - } - /** * Calls a controller callback method * diff --git a/cake/libs/controller/components/session.php b/lib/Cake/Controller/Component/SessionComponent.php similarity index 95% rename from cake/libs/controller/components/session.php rename to lib/Cake/Controller/Component/SessionComponent.php index 09a9f6da6..9d2231150 100644 --- a/cake/libs/controller/components/session.php +++ b/lib/Cake/Controller/Component/SessionComponent.php @@ -16,9 +16,9 @@ * @since CakePHP(tm) v 0.10.0.1232 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -if (!class_exists('cakesession')) { - require LIBS . 'cake_session.php'; -} + +App::uses('Component', 'Controller'); +App::uses('CakeSession', 'Model/Datasource'); /** * Session Component. @@ -113,7 +113,9 @@ class SessionComponent extends Component { * * In your controller: $this->Session->setFlash('This has been saved'); * - * Additional params below can be passed to customize the output, or the Message.[key] + * Additional params below can be passed to customize the output, or the Message.[key]. + * You can also set additional parameters when rendering flash messages. See SessionHelper::flash() + * for more information on how to do that. * * @param string $message Message to be flashed * @param string $element Element to wrap flash message in. diff --git a/cake/libs/controller/component_collection.php b/lib/Cake/Controller/ComponentCollection.php similarity index 71% rename from cake/libs/controller/component_collection.php rename to lib/Cake/Controller/ComponentCollection.php index 3d9e23c47..909fd70e1 100644 --- a/cake/libs/controller/component_collection.php +++ b/lib/Cake/Controller/ComponentCollection.php @@ -15,7 +15,9 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'ObjectCollection'); + +App::uses('ObjectCollection', 'Utility'); +App::uses('Component', 'Controller'); class ComponentCollection extends ObjectCollection { @@ -57,6 +59,16 @@ class ComponentCollection extends ObjectCollection { * Loads/constructs a component. Will return the instance in the registry if it already exists. * You can use `$settings['enabled'] = false` to disable callbacks on a component when loading it. * Callbacks default to on. Disabled component methods work as normal, only callbacks are disabled. + * + * You can alias your component as an existing component by setting the 'className' key, i.e., + * {{{ + * public $components = array( + * 'Email' => array( + * 'className' => 'AliasedEmail' + * ); + * ); + * }}} + * All calls to the `Email` component would use `AliasedEmail` instead. * * @param string $component Component name to load * @param array $settings Settings for the component. @@ -64,31 +76,31 @@ class ComponentCollection extends ObjectCollection { * @throws MissingComponentFileException, MissingComponentClassException when the component could not be found */ public function load($component, $settings = array()) { - list($plugin, $name) = pluginSplit($component); - if (isset($this->_loaded[$name])) { - return $this->_loaded[$name]; + if (is_array($settings) && isset($settings['className'])) { + $alias = $component; + $component = $settings['className']; + } + list($plugin, $name) = pluginSplit($component, true); + if (!isset($alias)) { + $alias = $name; + } + if (isset($this->_loaded[$alias])) { + return $this->_loaded[$alias]; } $componentClass = $name . 'Component'; + App::uses($componentClass, $plugin . 'Controller/Component'); if (!class_exists($componentClass)) { - if (!App::import('Component', $component)) { - throw new MissingComponentFileException(array( - 'file' => Inflector::underscore($component) . '.php', - 'class' => $componentClass - )); - } - if (!class_exists($componentClass)) { - throw new MissingComponentClassException(array( - 'file' => Inflector::underscore($component) . '.php', - 'class' => $componentClass - )); - } + throw new MissingComponentClassException(array( + 'file' => Inflector::underscore($componentClass) . '.php', + 'class' => $componentClass + )); } - $this->_loaded[$name] = new $componentClass($this, $settings); + $this->_loaded[$alias] = new $componentClass($this, $settings); $enable = isset($settings['enabled']) ? $settings['enabled'] : true; if ($enable === true) { - $this->_enabled[] = $name; + $this->_enabled[] = $alias; } - return $this->_loaded[$name]; + return $this->_loaded[$alias]; } } \ No newline at end of file diff --git a/cake/libs/controller/controller.php b/lib/Cake/Controller/Controller.php similarity index 89% rename from cake/libs/controller/controller.php rename to lib/Cake/Controller/Controller.php index 758d41225..697629387 100644 --- a/cake/libs/controller/controller.php +++ b/lib/Cake/Controller/Controller.php @@ -20,10 +20,10 @@ /** * Include files */ -App::import('Core', 'CakeResponse', false); -App::import('Core', 'ClassRegistry', false); -App::import('Controller', 'Component', false); -App::import('View', 'View', false); +App::uses('CakeResponse', 'Network'); +App::uses('ClassRegistry', 'Utility'); +App::uses('ComponentCollection', 'Controller'); +App::uses('View', 'View'); /** * Application controller class for organization of business logic. @@ -31,12 +31,12 @@ App::import('View', 'View', false); * automatic model availability, redirection, callbacks, and more. * * Controllers should provide a number of 'action' methods. These are public methods on the controller - * that are not prefixed with a '_' and not part of Controller. Each action serves as an endpoint for + * that are not prefixed with a '_' and not part of Controller. Each action serves as an endpoint for * performing a specific action on a resource or collection of resources. For example adding or editing a new * object, or listing a set of objects. * * You can access request parameters, using `$this->request`. The request object contains all the POST, GET and FILES - * that were part of the request. + * that were part of the request. * * After performing the required actions, controllers are responsible for creating a response. This usually * takes the form of a generated View, or possibly a redirection to another controller action. In either case @@ -86,7 +86,7 @@ class Controller extends Object { /** * An instance of a CakeRequest object that contains information about the current request. * This object contains all the information about a request and several methods for reading - * additional information about the request. + * additional information about the request. * * @var CakeRequest */ @@ -134,6 +134,15 @@ class Controller extends Object { */ public $modelNames = array(); +/** + * The name of the view file to render. The name specified + * is the filename in /app/views/ without the .ctp extension. + * + * @var string + * @link http://book.cakephp.org/view/962/Page-related-Attributes-layout-and-pageTitle + */ + public $view = null; + /** * The name of the layout file to render the view inside of. The name specified * is the filename of the layout in /app/views/layouts without the .ctp @@ -182,7 +191,7 @@ class Controller extends Object { * * @var string */ - public $view = 'View'; + public $viewClass = 'View'; /** * Instance of the View created during rendering. Won't be set until after Controller::render() is called. @@ -302,18 +311,14 @@ class Controller extends Object { */ public function __construct($request = null) { if ($this->name === null) { - $r = null; - if (!preg_match('/(.*)Controller/i', get_class($this), $r)) { - echo __("Controller::__construct() : Can not get or parse my own class name, exiting."); - $this->_stop(); - } - $this->name = $r[1]; + $this->name = substr(get_class($this), 0, strlen(get_class($this)) -10); } if ($this->viewPath == null) { $this->viewPath = Inflector::underscore($this->name); } - $this->modelClass = Inflector::classify($this->name); + + $this->modelClass = Inflector::singularize($this->name); $this->modelKey = Inflector::underscore($this->modelClass); $this->Components = new ComponentCollection(); @@ -330,7 +335,7 @@ class Controller extends Object { } /** - * Provides backwards compatbility avoid problems with empty and isset to alias properties. + * Provides backwards compatibility to avoid problems with empty and isset to alias properties. * * @return void */ @@ -394,7 +399,14 @@ class Controller extends Object { /** * Sets the request objects and configures a number of controller properties - * based on the contents of the request. + * based on the contents of the request. The properties that get set are + * + * - $this->request - To the $request parameter + * - $this->plugin - To the $request->params['plugin'] + * - $this->view - To the $request->params['action'] + * - $this->autoLayout - To the false if $request->params['bare']; is set. + * - $this->autoRender - To false if $request->params['return'] == 1 + * - $this->passedArgs - The the combined results of params['named'] and params['pass] * * @param CakeRequest $request * @return void @@ -402,7 +414,7 @@ class Controller extends Object { public function setRequest(CakeRequest $request) { $this->request = $request; $this->plugin = isset($request->params['plugin']) ? $request->params['plugin'] : null; - + $this->view = isset($request->params['action']) ? $request->params['action'] : null; if (isset($request->params['pass']) && isset($request->params['named'])) { $this->passedArgs = array_merge($request->params['pass'], $request->params['named']); } @@ -431,7 +443,7 @@ class Controller extends Object { } $plugin = $pluginName . '.'; } - + if (is_subclass_of($this, $this->_mergeParent) || !empty($pluginController)) { $appVars = get_class_vars($this->_mergeParent); $uses = $appVars['uses']; @@ -447,7 +459,7 @@ class Controller extends Object { array_unshift($this->uses, $plugin . $this->modelClass); } } elseif ( - ($this->uses !== null || $this->uses !== false) && + ($this->uses !== null || $this->uses !== false) && is_array($this->uses) && !empty($appVars['uses']) ) { $this->uses = array_merge($this->uses, array_diff($appVars['uses'], $this->uses)); @@ -459,7 +471,7 @@ class Controller extends Object { $merge = array('components', 'helpers'); $appVars = get_class_vars($pluginController); if ( - ($this->uses !== null || $this->uses !== false) && + ($this->uses !== null || $this->uses !== false) && is_array($this->uses) && !empty($appVars['uses']) ) { $this->uses = array_merge($this->uses, array_diff($appVars['uses'], $this->uses)); @@ -636,7 +648,7 @@ class Controller extends Object { extract($status, EXTR_OVERWRITE); } $response = $this->Components->trigger( - 'beforeRedirect', + 'beforeRedirect', array(&$this, $url, $status, $exit), array('break' => true, 'breakOn' => false, 'collectReturn' => true) ); @@ -644,15 +656,13 @@ class Controller extends Object { if ($response === false) { return; } - if (is_array($response)) { - foreach ($response as $resp) { - if (is_array($resp) && isset($resp['url'])) { - extract($resp, EXTR_OVERWRITE); - } elseif ($resp !== null) { - $url = $resp; - } - } + extract($this->_parseBeforeRedirect($response, $url, $status, $exit), EXTR_OVERWRITE); + + $response = $this->beforeRedirect($url, $status, $exit); + if ($response === false) { + return; } + extract($this->_parseBeforeRedirect($response, $url, $status, $exit), EXTR_OVERWRITE); if (function_exists('session_write_close')) { session_write_close(); @@ -679,6 +689,28 @@ class Controller extends Object { } } +/** + * Parse beforeRedirect Response + * + * @param mixed $response Response from beforeRedirect callback + * @param mixed $url The same value of beforeRedirect + * @param integer $status The same value of beforeRedirect + * @param boolean $exit The same value of beforeRedirect + * @return array Array with keys url, status and exit + */ + protected function _parseBeforeRedirect($response, $url, $status, $exit) { + if (is_array($response)) { + foreach ($response as $resp) { + if (is_array($resp) && isset($resp['url'])) { + extract($resp, EXTR_OVERWRITE); + } elseif ($resp !== null) { + $url = $resp; + } + } + } + return compact('url', 'status', 'exit'); + } + /** * Convenience and object wrapper method for CakeResponse::header(). * @@ -736,20 +768,6 @@ class Controller extends Object { return call_user_func_array(array(&$this, $action), $args); } -/** - * Controller callback to tie into Auth component. - * Only called when AuthComponent::$authorize is set to 'controller'. - * - * @return bool true if authorized, false otherwise - * @link http://book.cakephp.org/view/1275/authorize - */ - public function isAuthorized() { - trigger_error(sprintf( - __('%sController::isAuthorized() is not defined.'), $this->name - ), E_USER_WARNING); - return false; - } - /** * Returns number of errors in a submitted FORM. * @@ -795,21 +813,20 @@ class Controller extends Object { /** * Instantiates the correct view class, hands it its data, and uses it to render the view output. * - * @param string $action Action name to render + * @param string $view View to use for rendering * @param string $layout Layout to use - * @param string $file File to use for rendering * @return string Full output string of view contents * @link http://book.cakephp.org/view/980/render */ - public function render($action = null, $layout = null, $file = null) { + public function render($view = null, $layout = null) { $this->beforeRender(); $this->Components->trigger('beforeRender', array(&$this)); - $viewClass = $this->view; - if ($this->view != 'View') { - list($plugin, $viewClass) = pluginSplit($viewClass); + $viewClass = $this->viewClass; + if ($this->viewClass != 'View') { + list($plugin, $viewClass) = pluginSplit($viewClass, true); $viewClass = $viewClass . 'View'; - App::import('View', $this->view); + App::uses($viewClass, $plugin . 'View'); } $this->request->params['models'] = $this->modelNames; @@ -845,7 +862,7 @@ class Controller extends Object { $this->autoRender = false; $this->View = $View; - return $this->response->body($View->render($action, $layout, $file)); + return $this->response->body($View->render($view, $layout)); } /** @@ -990,6 +1007,23 @@ class Controller extends Object { public function beforeRender() { } +/** + * The beforeRedirect method is invoked when the controller's redirect method is called but before any + * further action. If this method returns false the controller will not continue on to redirect the request. + * The $url, $status and $exit variables have same meaning as for the controller's method. You can also + * return a string which will be interpreted as the url to redirect to or return associative array with + * key 'url' and optionally 'status' and 'exit'. + * + * @param mixed $url A string or array-based URL pointing to another location within the app, + * or an absolute URL + * @param integer $status Optional HTTP status code (eg: 404) + * @param boolean $exit If true, exit() will be called after the redirect + * @return boolean + */ + public function beforeRedirect($url, $status = null, $exit = true) { + return true; + } + /** * Called after the controller action is run and rendered. * diff --git a/cake/libs/controller/pages_controller.php b/lib/Cake/Controller/PagesController.php similarity index 97% rename from cake/libs/controller/pages_controller.php rename to lib/Cake/Controller/PagesController.php index 65e8b0465..c842bc9ca 100644 --- a/cake/libs/controller/pages_controller.php +++ b/lib/Cake/Controller/PagesController.php @@ -19,6 +19,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('AppController', 'Controller'); + /** * Static content controller * diff --git a/cake/libs/controller/scaffold.php b/lib/Cake/Controller/Scaffold.php similarity index 93% rename from cake/libs/controller/scaffold.php rename to lib/Cake/Controller/Scaffold.php index 97a2533d7..054e3a1a3 100644 --- a/cake/libs/controller/scaffold.php +++ b/lib/Cake/Controller/Scaffold.php @@ -18,7 +18,7 @@ * @since Cake v 0.10.0.1076 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('View', 'Scaffold'); +App::uses('Scaffold', 'View'); /** * Scaffolding is a set of automatic actions for starting web development work faster. @@ -127,7 +127,7 @@ class Scaffold { $this->ScaffoldModel = $this->controller->{$this->modelClass}; $this->scaffoldTitle = Inflector::humanize($this->viewPath); $this->scaffoldActions = $controller->scaffold; - $title_for_layout = __('Scaffold :: ') . Inflector::humanize($request->action) . ' :: ' . $this->scaffoldTitle; + $title_for_layout = __d('cake', 'Scaffold :: ') . Inflector::humanize($request->action) . ' :: ' . $this->scaffoldTitle; $modelClass = $this->controller->modelClass; $primaryKey = $this->ScaffoldModel->primaryKey; $displayField = $this->ScaffoldModel->displayField; @@ -143,8 +143,8 @@ class Scaffold { 'singularHumanName', 'pluralHumanName', 'scaffoldFields', 'associations' )); - if ($this->controller->view) { - $this->controller->view = 'Scaffold'; + if ($this->controller->viewClass) { + $this->controller->viewClass = 'Scaffold'; } $this->_validSession = ( isset($this->controller->Session) && $this->controller->Session->valid() != false @@ -174,7 +174,7 @@ class Scaffold { $this->ScaffoldModel->id = $request->params['pass'][0]; } if (!$this->ScaffoldModel->exists()) { - throw new NotFoundException(__('Invalid %s', Inflector::humanize($this->modelKey))); + throw new NotFoundException(__d('cake', 'Invalid %s', Inflector::humanize($this->modelKey))); } $this->ScaffoldModel->recursive = 1; $this->controller->request->data = $this->ScaffoldModel->read(); @@ -231,10 +231,10 @@ class Scaffold { */ protected function _scaffoldSave(CakeRequest $request, $action = 'edit') { $formAction = 'edit'; - $success = __('updated'); + $success = __d('cake', 'updated'); if ($action === 'add') { $formAction = 'add'; - $success = __('saved'); + $success = __d('cake', 'saved'); } if ($this->controller->_beforeScaffold($action)) { @@ -243,7 +243,7 @@ class Scaffold { $this->ScaffoldModel->id = $request['pass'][0]; } if (!$this->ScaffoldModel->exists()) { - throw new NotFoundException(__('Invalid %s', Inflector::humanize($this->modelKey))); + throw new NotFoundException(__d('cake', 'Invalid %s', Inflector::humanize($this->modelKey))); } } @@ -254,7 +254,7 @@ class Scaffold { if ($this->ScaffoldModel->save($request->data)) { if ($this->controller->_afterScaffoldSave($action)) { - $message = __( + $message = __d('cake', 'The %1$s has been %2$s', Inflector::humanize($this->modelKey), $success @@ -265,7 +265,7 @@ class Scaffold { } } else { if ($this->_validSession) { - $this->controller->Session->setFlash(__('Please correct errors below.')); + $this->controller->Session->setFlash(__d('cake', 'Please correct errors below.')); } } } @@ -312,13 +312,13 @@ class Scaffold { } $this->ScaffoldModel->id = $id; if (!$this->ScaffoldModel->exists()) { - throw new NotFoundException(__('Invalid %s', Inflector::humanize($this->modelClass))); + throw new NotFoundException(__d('cake', 'Invalid %s', Inflector::humanize($this->modelClass))); } if ($this->ScaffoldModel->delete()) { - $message = __('The %1$s with id: %2$d has been deleted.', Inflector::humanize($this->modelClass), $id); + $message = __d('cake', 'The %1$s with id: %2$d has been deleted.', Inflector::humanize($this->modelClass), $id); return $this->_sendMessage($message); } else { - $message = __( + $message = __d('cake', 'There was an error deleting the %1$s with id: %2$d', Inflector::humanize($this->modelClass), $id diff --git a/lib/Cake/Core/App.php b/lib/Cake/Core/App.php new file mode 100644 index 000000000..014f812db --- /dev/null +++ b/lib/Cake/Core/App.php @@ -0,0 +1,820 @@ + array('extends' => null, 'core' => true), + 'file' => array('extends' => null, 'core' => true), + 'model' => array('extends' => 'AppModel', 'core' => false), + 'behavior' => array('extends' => 'ModelBehavior', 'core' => true), + 'controller' => array('suffix' => 'Controller', 'extends' => 'AppController', 'core' => true), + 'component' => array('suffix' => 'Component', 'extends' => null, 'core' => true), + 'lib' => array('extends' => null, 'core' => true), + 'view' => array('suffix' => 'View', 'extends' => null, 'core' => true), + 'helper' => array('suffix' => 'Helper', 'extends' => 'AppHelper', 'core' => true), + 'vendor' => array('extends' => null, 'core' => true), + 'shell' => array('suffix' => 'Shell', 'extends' => 'Shell', 'core' => true), + 'plugin' => array('extends' => null, 'core' => true) + ); + +/** + * Paths to search for files. + * + * @var array + */ + public static $search = array(); + +/** + * Whether or not to return the file that is loaded. + * + * @var boolean + */ + public static $return = false; + +/** + * Determines if $__maps and $__paths cache should be written. + * + * @var boolean + */ + private static $__cache = false; + +/** + * Holds key/value pairs of $type => file path. + * + * @var array + */ + private static $__map = array(); + +/** + * Holds paths for deep searching of files. + * + * @var array + */ + private static $__paths = array(); + +/** + * Holds loaded files. + * + * @var array + */ + private static $__loaded = array(); + +/** + * Holds and key => value array of object types. + * + * @var array + */ + private static $__objects = array(); + +/** + * Holds the location of each class + * + */ + private static $__classMap = array(); + +/** + * Holds the possible paths for each package name + * + */ + private static $__packages = array(); + +/** + * Holds the templates for each customizable package path in the application + * + */ + private static $__packageFormat = array(); + +/** + * Maps an old style CakePHP class type to the corresponding package + * + */ + public static $legacy = array( + 'models' => 'Model', + 'behaviors' => 'Model/Behavior', + 'datasources' => 'Model/Datasource', + 'controllers' => 'Controller', + 'components' => 'Controller/Component', + 'views' => 'View', + 'helpers' => 'View/Helper', + 'shells' => 'Console/Command', + 'libs' => 'Lib' + ); + +/** + * Inicates whether the class cache should be stored again because of an addition to it + * + */ + private static $_cacheChange = false; + +/** + * Inicates whether the object cache should be stored again because of an addition to it + * + */ + private static $_objectCacheChange = false; + +/** + * Used to read information stored path + * + * Usage: + * + * `App::path('Model'); will return all paths for models` + * + * `App::path('Model/Datasource', 'MyPlugin'); will return the path for datasources under the 'MyPlugin' plugin` + * + * @param string $type type of path + * @param string $plugin name of plugin + * @return string array + */ + public static function path($type, $plugin = null) { + if (!empty(self::$legacy[$type])) { + $type = self::$legacy[$type]; + } + + if (!empty($plugin)) { + $path = array(); + $pluginPath = self::pluginPath($plugin); + if (!empty(self::$__packageFormat[$type])) { + foreach (self::$__packageFormat[$type] as $f) { + $path[] = sprintf($f, $pluginPath); + } + } + $path[] = $pluginPath . 'Lib' . DS . $type . DS; + return $path; + } + + if (!isset(self::$__packages[$type])) { + return array(); + } + return self::$__packages[$type]; + } + +/** + * Sets up each package location on the file system. You can configure multiple search paths + * for each package, those will be used to look for files one folder at a time in the specified order + * All paths should be terminated with a Directory separator + * + * Usage: + * + * `App::build(array(Model' => array('/a/full/path/to/models/'))); will setup a new search path for the Model package` + * + * `App::build(array('Model' => array('/path/to/models/')), true); will setup the path as the only valid path for searching models` + * + * `App::build(array('View/Helper' => array('/path/to/models/', '/another/path/))); will setup multiple search paths for helpers` + * + * @param array $paths associative array with package names as keys and a list of directories for new search paths + * @param boolean $reset true will set paths, false merges paths [default] false + * @return void + */ + public static function build($paths = array(), $reset = false) { + if (empty(self::$__packageFormat)) { + self::$__packageFormat = array( + 'Model' => array( + '%s' . 'Model' . DS, + '%s' . 'models' . DS + ), + 'Model/Behavior' => array( + '%s' . 'Model' . DS . 'Behavior' . DS, + '%s' . 'models' . DS . 'behaviors' . DS + ), + 'Model/Datasource' => array( + '%s' . 'Model' . DS . 'Datasource' . DS, + '%s' . 'models' . DS . 'datasources' . DS + ), + 'Model/Datasource/Database' => array( + '%s' . 'Model' . DS . 'Datasource' . DS . 'Database' . DS, + '%s' . 'models' . DS . 'datasources' . DS . 'database' . DS + ), + 'Model/Datasource/Session' => array( + '%s' . 'Model' . DS . 'Datasource' . DS . 'Session' . DS, + '%s' . 'models' . DS . 'datasources' . DS . 'session' . DS + ), + 'Controller' => array( + '%s' . 'Controller' . DS, + '%s' . 'controllers' . DS + ), + 'Controller/Component' => array( + '%s' . 'Controller' . DS . 'Component' . DS, + '%s' . 'controllers' . DS . 'components' . DS + ), + 'View' => array( + '%s' . 'View' . DS, + '%s' . 'views' . DS + ), + 'View/Helper' => array( + '%s' . 'View' . DS . 'Helper' . DS, + '%s' . 'views' . DS . 'helpers' . DS + ), + 'Console' => array( + '%s' . 'Console' . DS, + '%s' . 'console' . DS + ), + 'Console/Command' => array( + '%s' . 'Console' . DS . 'Command' . DS, + '%s' . 'console' . DS . 'shells' . DS, + ), + 'Console/Command/Task' => array( + '%s' . 'Console' . DS . 'Command' . DS . 'Task' . DS, + '%s' . 'console' . DS . 'shells' . DS . 'tasks' . DS + ), + 'Lib' => array( + '%s' . 'Lib' . DS, + '%s' . 'libs' . DS + ), + 'locales' => array( + '%s' . 'locale' . DS + ), + 'vendors' => array('%s' . 'vendors' . DS, VENDORS), + 'plugins' => array(APP . 'plugins' . DS, CAKE_CORE_INCLUDE_PATH . DS . 'plugins' . DS) + ); + } + + if ($reset == true) { + foreach ($paths as $type => $new) { + if (!empty(self::$legacy[$type])) { + $type = self::$legacy[$type]; + } + self::$__packages[$type] = (array)$new; + } + return $paths; + } + + //Provides Backwards compatibility for old-style package names + $legacyPaths = array(); + foreach ($paths as $type => $path) { + if (!empty(self::$legacy[$type])) { + $type = self::$legacy[$type]; + } + $legacyPaths[$type] = $path; + } + + $paths = $legacyPaths; + $defaults = array(); + foreach (self::$__packageFormat as $package => $format) { + foreach ($format as $f) { + $defaults[$package][] = sprintf($f, APP); + } + } + + $mergeExclude = array('Lib', 'locales', 'vendors', 'plugins'); + $appLibs = empty($paths['Lib']) ? $defaults['Lib'] : $paths['Lib']; + + foreach ($defaults as $type => $default) { + if (empty(self::$__packages[$type]) || empty($paths)) { + self::$__packages[$type] = $default; + } + + if (!empty($paths[$type])) { + $path = array_merge((array)$paths[$type], self::$__packages[$type]); + } else { + $path = self::$__packages[$type]; + } + + self::$__packages[$type] = array_values(array_unique($path)); + } + } + +/** + * Gets the path that a plugin is on. Searches through the defined plugin paths. + * + * Usage: + * + * `App::pluginPath('MyPlugin'); will return the full path to 'MyPlugin' plugin'` + * + * @param string $plugin CamelCased/lower_cased plugin name to find the path of. + * @return string full path to the plugin. + */ + public static function pluginPath($plugin) { + $pluginDir = Inflector::underscore($plugin); + foreach (self::$__packages['plugins'] as $pluginPath) { + if (is_dir($pluginPath . $pluginDir)) { + return $pluginPath . $pluginDir . DS ; + } + } + return self::$__packages['plugins'][0] . $pluginDir . DS; + } + +/** + * Finds the path that a theme is on. Searches through the defined theme paths. + * + * Usage: + * + * `App::themePath('MyTheme'); will return the full path to the 'MyTheme' theme` + * + * @param string $theme lower_cased theme name to find the path of. + * @return string full path to the theme. + */ + public static function themePath($theme) { + $themeDir = 'themed' . DS . Inflector::underscore($theme); + foreach (self::$__packages['View'] as $path) { + if (is_dir($path . $themeDir)) { + return $path . $themeDir . DS ; + } + } + return self::$__packages['View'][0] . $themeDir . DS; + } + +/** + * Returns the full path to a package inside the CakePHP core + * + * Usage: + * + * `App::core('Cache/Engine'); will return the full path to the cache engines package` + * + * @param string $type + * @return string full path to package + */ + public static function core($type) { + if ($type) { + return isset($paths[$type]) ? $paths[$type] : array(LIBS . $type . DS); + } + } + +/** + * Returns an array of objects of the given type. + * + * Example usage: + * + * `App::objects('plugin');` returns `array('DebugKit', 'Blog', 'User');` + * + * `App::objects('Controller');` returns `array('PagesController', 'BlogController');` + * + * You can also search only within a plugin's objects by using the plugin dot + * syntax. + * + * `App::objects('MyPlugin.Model');` returns `array('MyPluginPost', 'MyPluginComment');` + * + * @param string $type Type of object, i.e. 'Model', 'Controller', 'View/Helper', 'file', 'class' or 'plugin' + * @param mixed $path Optional Scan only the path given. If null, paths for the chosen type will be used. + * @param boolean $cache Set to false to rescan objects of the chosen type. Defaults to true. + * @return mixed Either false on incorrect / miss. Or an array of found objects. + */ + public static function objects($type, $path = null, $cache = true) { + $objects = array(); + $extension = '/\.php$/'; + $includeDirectories = false; + $name = $type; + + if ($type === 'plugin') { + $type = 'plugins'; + } + + if ($type == 'plugins') { + $extension = '/.*/'; + $includeDirectories = true; + } + + list($plugin, $type) = pluginSplit($type); + + if (isset(self::$legacy[$type . 's'])) { + $type = self::$legacy[$type . 's']; + } + + if ($type === 'file' && !$path) { + return false; + } elseif ($type === 'file') { + $extension = '/\.php$/'; + $name = $type . str_replace(DS, '', $path); + } + + if (empty(self::$__objects) && $cache === true) { + self::$__objects = Cache::read('object_map', '_cake_core_'); + } + + $cacheLocation = empty($plugin) ? 'app' : $plugin; + + if ($cache !== true || !isset(self::$__objects[$cacheLocation][$name])) { + $objects = array(); + + if (empty($path)) { + $path = self::path($type, $plugin); + } + + $items = array(); + + foreach ((array)$path as $dir) { + if ($dir != APP && is_dir($dir)) { + $files = new RegexIterator(new DirectoryIterator($dir), $extension); + foreach ($files as $file) { + if (!$file->isDot()) { + $isDir = $file->isDir() ; + if ($isDir && $includeDirectories) { + $objects[] = basename($file); + } elseif (!$includeDirectories && !$isDir) { + $objects[] = substr(basename($file), 0, -4); + } + } + } + } + } + + if ($type !== 'file') { + foreach ($objects as $key => $value) { + $objects[$key] = Inflector::camelize($value); + } + } + + if ($cache === true) { + self::$__cache = true; + } + if ($plugin) { + return $objects; + } + self::$__objects[$cacheLocation][$name] = $objects; + self::$_objectCacheChange = true; + } + + return self::$__objects[$cacheLocation][$name]; + } + +/** + * Allows you to modify the object listings that App maintains inside of it + * Useful for testing + * + * @param string $type Type of object listing you are changing + * @param array $values The values $type should be set to. + * @return void + */ + public static function setObjects($type, $values) { + list($plugin, $type) = pluginSplit($type); + $cacheLocation = empty($plugin) ? 'app' : $plugin; + self::$__objects[$cacheLocation][$type] = $values; + } + +/** + * Declares a package for a class. This package location will be used + * by the automatic class loader if the class is tried to be used + * + * Usage: + * + * `App::uses('MyCustomController', 'Controller');` will setup the class to be found under Controller package + * + * `App::uses('MyHelper', 'MyPlugin.View/Helper');` will setup the helper class to be found in plugin's helper package + * + * @param string $className the name of the class to configure package for + * @param string $location the package name + */ + public static function uses($className, $location) { + self::$__classMap[$className] = $location; + } + +/** + * Method to handle the automatic class loading. It will look for each class' package + * defined using App::uses() and with this information it will resolve the package name to a full path + * to load the class from. File name for each class should follow the class name. For instance, + * if a class is name `MyCustomClass` the file name should be `MyCustomClass.php` + * + * @param string $className the name of the class to load + */ + public static function load($className) { + if (isset(self::$__classMap[$className])) { + if ($file = self::__mapped($className)) { + return include $file; + } + + $parts = explode('.', self::$__classMap[$className], 2); + list($plugin, $package) = count($parts) > 1 ? $parts : array(null, current($parts)); + $paths = self::path($package, $plugin); + + if (empty($plugin)) { + $appLibs = empty(self::$__packages['Lib']) ? APPLIBS : current(self::$__packages['Lib']); + $paths[] = $appLibs . $package . DS; + $paths[] = LIBS . $package . DS; + } + + foreach ($paths as $path) { + $file = $path . $className . '.php'; + if (file_exists($file)) { + self::__map($file, $className); + return include $file; + } + } + + //To help apps migrate to 2.0 old style file names are allowed + foreach ($paths as $path) { + $underscored = Inflector::underscore($className); + $tries = array($path . $underscored . '.php'); + $parts = explode('_', $underscored); + if (count($parts) > 1) { + array_pop($parts); + $tries[] = $path . implode('_', $parts) . '.php'; + } + foreach ($tries as $file) { + if (file_exists($file)) { + self::__map($file, $className); + return include $file; + } + } + } + } + + return false; + } + +/** + * Finds classes based on $name or specific file(s) to search. Calling App::import() will + * not construct any classes contained in the files. It will only find and require() the file. + * + * @link http://book.cakephp.org/view/934/Using-App-import + * @param mixed $type The type of Class if passed as a string, or all params can be passed as + * an single array to $type, + * @param string $name Name of the Class or a unique name for the file + * @param mixed $parent boolean true if Class Parent should be searched, accepts key => value + * array('parent' => $parent ,'file' => $file, 'search' => $search, 'ext' => '$ext'); + * $ext allows setting the extension of the file name + * based on Inflector::underscore($name) . ".$ext"; + * @param array $search paths to search for files, array('path 1', 'path 2', 'path 3'); + * @param string $file full name of the file to search for including extension + * @param boolean $return, return the loaded file, the file must have a return + * statement in it to work: return $variable; + * @return boolean true if Class is already in memory or if file is found and loaded, false if not + */ + public static function import($type = null, $name = null, $parent = true, $search = array(), $file = null, $return = false) { + $ext = $plugin = $directory = null; + + if (is_array($type)) { + extract($type, EXTR_OVERWRITE); + } + + if (is_array($parent)) { + extract($parent, EXTR_OVERWRITE); + } + + if ($name == null && $file == null) { + return false; + } + + if (is_array($name)) { + foreach ($name as $class) { + if (!App::import(compact('type', 'parent', 'search', 'file', 'return') + array('name' => $class))) { + return false; + } + } + return true; + } + + $originalType = $type = strtolower($type); + $specialPackage = in_array($type, array('file', 'vendor')); + if (!$specialPackage && isset(self::$legacy[$type . 's'])) { + $type = self::$legacy[$type . 's']; + } + list($plugin, $name) = pluginSplit($name); + if (!empty($plugin)) { + $plugin = Inflector::camelize($plugin); + } + + if (!$specialPackage) { + return self::_loadClass($name, $plugin, $type, $originalType, $parent); + } + + if ($type == 'file' && !empty($file)) { + return self::_loadFile($name, $plugin, $search, $file, $return); + } + + if ($type == 'vendor') { + return self::_loadVendor($name, $plugin, $file, $ext); + } + + return false; + } + +/** + * Helper function to include classes + * This is a compatibility wrapper around using App::uses() and automatic class loading + * + * @param string $name unique name of the file for identifying it inside the application + * @param string $plugin camel cased plugin name if any + * @param string $type name of the packed where the class is located + * @param string $file filename if known, the $name param will be used otherwise + * @param string $originalType type name as supplied initially by the user + * @param boolean $parent whether to load the class parent or not + * @return boolean true indicating the successful load and existence of the class + */ + private function _loadClass($name, $plugin, $type, $originalType, $parent) { + if ($type == 'Console/Command' && $name == 'Shell') { + $type = 'Console'; + } else if (isset(self::$types[$originalType]['suffix'])) { + $suffix = self::$types[$originalType]['suffix']; + $name .= ($suffix == $name) ? '' : $suffix; + } + + if ($parent && isset(self::$types[$originalType]['extends'])) { + $extends = self::$types[$originalType]['extends']; + App::uses($extends, $type); + if ($plugin && in_array($originalType, array('controller', 'model'))) { + App::uses($plugin . $extends, $plugin . '.' .$type); + } + } + if ($plugin) { + $plugin .= '.'; + } + $name = Inflector::camelize($name); + App::uses($name, $plugin . $type); + return class_exists($name); + } + +/** + * Helper function to include single files + * + * @param string $name unique name of the file for identifying it inside the application + * @param string $plugin camel cased plugin name if any + * @param array $search list of paths to search the file into + * @param string $file filename if known, the $name param will be used otherwise + * @param boolean $return whether this function should return the contents of the file after being parsed by php or just a success notice + * @return mixed, if $return contents of the file after php parses it, boolean indicating success otherwise + */ + private function _loadFile($name, $plugin, $search, $file, $return) { + $mapped = self::__mapped($name, $plugin); + if ($mapped) { + $file = $mapped; + } else if (!empty($search)) { + foreach ($search as $path) { + $found = false; + if (file_exists($path . $file)) { + $file = $path . $file; + $found = true; + break; + } + if (empty($found)) { + $file = false; + } + } + } + if (!empty($file) && file_exists($file)) { + self::__map($file, $name, $plugin); + $returnValue = include $file; + if ($return) { + return $returnValue; + } + return (bool) $returnValue; + } + return false; + } + +/** + * Helper function to load files from vendors folders + * + * @param string $name unique name of the file for identifying it inside the application + * @param string $plugin camel cased plugin name if any + * @param string $file file name if known + * @param string $ext file extension if known + * @return boolean true if the file was loaded successfully, false otherwise + */ + private function _loadVendor($name, $plugin, $file, $ext) { + if ($mapped = self::__mapped($name, $plugin)) { + return (bool) include_once($mapped); + } + $fileTries = array(); + $paths = ($plugin) ? App::path('vendors', $plugin) : App::path('vendors'); + if (empty($ext)) { + $ext = 'php'; + } + if (empty($file)) { + $fileTries[] = $name . '.' . $ext; + $fileTries[] = Inflector::underscore($name) . '.' . $ext; + } else { + $fileTries[] = $file; + } + + foreach ($fileTries as $file) { + foreach ($paths as $path) { + if (file_exists($path . $file)) { + self::__map($path . $file, $name, $plugin); + return (bool) include($path . $file); + } + } + } + return false; + } + +/** + * Initializes the cache for App, registers a shutdown function. + * + * @return void + */ + public static function init() { + self::$__map = (array)Cache::read('file_map', '_cake_core_'); + self::$__objects = (array)Cache::read('object_map', '_cake_core_'); + register_shutdown_function(array('App', 'shutdown')); + } + +/** + * Maps the $name to the $file. + * + * @param string $file full path to file + * @param string $name unique name for this map + * @param string $plugin camelized if object is from a plugin, the name of the plugin + * @return void + * @access private + */ + private static function __map($file, $name, $plugin = null) { + if ($plugin) { + self::$__map['Plugin'][$plugin][$name] = $file; + } else { + self::$__map[$name] = $file; + } + self::$_cacheChange = true; + } + +/** + * Returns a file's complete path. + * + * @param string $name unique name + * @param string $plugin camelized if object is from a plugin, the name of the plugin + * @return mixed, file path if found, false otherwise + * @access private + */ + private static function __mapped($name, $plugin = null) { + if ($plugin) { + if (isset(self::$__map['Plugin'][$plugin][$name])) { + return self::$__map['Plugin'][$plugin][$name]; + } + return false; + } + + if (isset(self::$__map[$name])) { + return self::$__map[$name]; + } + return false; + } + +/** + * Object destructor. + * + * Writes cache file if changes have been made to the $__map or $__paths + * + * @return void + */ + public static function shutdown() { + if (self::$__cache && self::$_cacheChange) { + Cache::write('file_map', array_filter(self::$__map), '_cake_core_'); + } + if (self::$__cache && self::$_objectCacheChange) { + Cache::write('object_map', self::$__objects, '_cake_core_'); + } + } +} \ No newline at end of file diff --git a/cake/libs/configure.php b/lib/Cake/Core/Configure.php similarity index 83% rename from cake/libs/configure.php rename to lib/Cake/Core/Configure.php index 1546ae087..ee139eb54 100644 --- a/cake/libs/configure.php +++ b/lib/Cake/Core/Configure.php @@ -21,7 +21,7 @@ * Configuration class. Used for managing runtime configuration information. * * Provides features for reading and writing to the runtime configuration, as well - * as methods for loading additional configuration files or storing runtime configuration + * as methods for loading additional configuration files or storing runtime configuration * for future use. * * @package cake.libs @@ -70,49 +70,13 @@ class Configure { )); if (!include(CONFIGS . 'core.php')) { - trigger_error(__("Can't find application core file. Please create %score.php, and make sure it is readable by PHP.", CONFIGS), E_USER_ERROR); - } - - if (empty(self::$_values['Cache']['disable'])) { - $cache = Cache::config('default'); - - if (empty($cache['settings'])) { - trigger_error(__('Cache not configured properly. Please check Cache::config(); in APP/config/core.php'), E_USER_WARNING); - $cache = Cache::config('default', array('engine' => 'File')); - } - $path = $prefix = $duration = null; - - if (!empty($cache['settings']['path'])) { - $path = realpath($cache['settings']['path']); - } else { - $prefix = $cache['settings']['prefix']; - } - - if (self::$_values['debug'] >= 1) { - $duration = '+10 seconds'; - } else { - $duration = '+999 days'; - } - - if (Cache::config('_cake_core_') === false) { - Cache::config('_cake_core_', array_merge((array)$cache['settings'], array( - 'prefix' => $prefix . 'cake_core_', 'path' => $path . DS . 'persistent' . DS, - 'serialize' => true, 'duration' => $duration - ))); - } - - if (Cache::config('_cake_model_') === false) { - Cache::config('_cake_model_', array_merge((array)$cache['settings'], array( - 'prefix' => $prefix . 'cake_model_', 'path' => $path . DS . 'models' . DS, - 'serialize' => true, 'duration' => $duration - ))); - } + trigger_error(__d('cake_dev', "Can't find application core file. Please create %score.php, and make sure it is readable by PHP.", CONFIGS), E_USER_ERROR); } App::init(); App::build(); if (!include(CONFIGS . 'bootstrap.php')) { - trigger_error(__("Can't find application bootstrap file. Please create %sbootstrap.php, and make sure it is readable by PHP.", CONFIGS), E_USER_ERROR); + trigger_error(__d('cake_dev', "Can't find application bootstrap file. Please create %sbootstrap.php, and make sure it is readable by PHP.", CONFIGS), E_USER_ERROR); } $level = -1; if (isset(self::$_values['Error']['level'])) { @@ -260,7 +224,7 @@ class Configure { } /** - * Add a new reader to Configure. Readers allow you to read configuration + * Add a new reader to Configure. Readers allow you to read configuration * files in various formats/storage locations. CakePHP comes with two built-in readers * PhpReader and IniReader. You can also implement your own reader classes in your application. * @@ -268,7 +232,7 @@ class Configure { * * `Configure::config('ini', new IniReader());` * - * @param string $name The name of the reader being configured. This alias is used later to + * @param string $name The name of the reader being configured. This alias is used later to * read values from a specific reader. * @param ConfigReaderInterface $reader The reader to append. * @return void @@ -290,7 +254,7 @@ class Configure { } /** - * Remove a configured reader. This will unset the reader + * Remove a configured reader. This will unset the reader * and make any future attempts to use it cause an Exception. * * @param string $name Name of the reader to drop. @@ -308,11 +272,11 @@ class Configure { * Loads stored configuration information from a resource. You can add * config file resource readers with `Configure::config()`. * - * Loaded configuration infomration will be merged with the current + * Loaded configuration information will be merged with the current * runtime configuration. You can load configuration files from plugins - * by preceeding the filename with the plugin name. + * by preceding the filename with the plugin name. * - * `Configure::load('Users.user', 'default')` + * `Configure::load('Users.user', 'default')` * * Would load the 'user' config file using the default config reader. You can load * app config files by giving the name of the resource you want loaded. @@ -321,15 +285,26 @@ class Configure { * * @link http://book.cakephp.org/view/929/load * @param string $key name of configuration resource to load. - * @param string $config Name of the configured reader to use to read the resource identfied by $key. + * @param string $config Name of the configured reader to use to read the resource identified by $key. + * @param boolean $merge if config files should be merged instead of simply overridden * @return mixed false if file not found, void if load successful. * @throws ConfigureException Will throw any exceptions the reader raises. */ - public static function load($key, $config = 'default') { + public static function load($key, $config = 'default', $merge = true) { if (!isset(self::$_readers[$config])) { return false; } $values = self::$_readers[$config]->read($key); + + if ($merge) { + $keys = array_keys($values); + foreach ($keys as $key) { + if (($c = self::read($key)) && is_array($values[$key]) && is_array($c)) { + $values[$key] = array_merge_recursive($c, $values[$key]); + } + } + } + return self::write($values); } @@ -343,7 +318,7 @@ class Configure { */ public static function version() { if (!isset(self::$_values['Cake']['version'])) { - require(CORE_PATH . 'cake' . DS . 'config' . DS . 'config.php'); + require(LIBS . 'config' . DS . 'config.php'); self::write($config); } return self::$_values['Cake']['version']; @@ -394,7 +369,7 @@ interface ConfigReaderInterface { * These sources can either be static resources like files, or dynamic ones like * a database, or other datasource. * - * @param string $key + * @param string $key * @return array An array of data to merge into the runtime configuration */ function read($key); diff --git a/cake/libs/object.php b/lib/Cake/Core/Object.php similarity index 99% rename from cake/libs/object.php rename to lib/Cake/Core/Object.php index 9096ae121..28a3d0d29 100644 --- a/cake/libs/object.php +++ b/lib/Cake/Core/Object.php @@ -20,6 +20,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Set', 'Utility'); + /** * Object class provides a few generic methods used in several subclasses. * @@ -64,9 +66,7 @@ class Object { if (empty($url)) { return false; } - if (!class_exists('dispatcher')) { - require LIBS . 'dispatcher.php'; - } + App::uses('Dispatcher', 'Routing'); if (in_array('return', $extra, true)) { $extra = array_merge($extra, array('return' => 0, 'autoRender' => 1)); } diff --git a/cake/libs/error/error_handler.php b/lib/Cake/Error/ErrorHandler.php similarity index 94% rename from cake/libs/error/error_handler.php rename to lib/Cake/Error/ErrorHandler.php index 775bd8d43..6787e23f7 100644 --- a/cake/libs/error/error_handler.php +++ b/lib/Cake/Error/ErrorHandler.php @@ -19,6 +19,11 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Debugger', 'Utility'); +App::uses('CakeLog', 'Log'); +App::uses('ExceptionRenderer', 'Error'); +App::uses('AppController', 'Controller'); + /** * * Error Handler provides basic error and exception handling for your application. It captures and @@ -102,12 +107,8 @@ class ErrorHandler { * @see http://php.net/manual/en/function.set-exception-handler.php */ public static function handleException(Exception $exception) { - App::import('Core', 'error/ExceptionRenderer'); $config = Configure::read('Exception'); if (!empty($config['log'])) { - if (!class_exists('CakeLog')) { - require LIBS . 'cake_log.php'; - } $message = sprintf("[%s] %s\n%s", get_class($exception), $exception->getMessage(), @@ -116,7 +117,7 @@ class ErrorHandler { CakeLog::write(LOG_ERR, $message); } if ($config['renderer'] !== 'ExceptionRenderer') { - App::import('Lib', $config['renderer']); + App::uses($config['renderer'], 'Error'); } $error = new $config['renderer']($exception); $error->render(); @@ -146,9 +147,6 @@ class ErrorHandler { $debug = Configure::read('debug'); if ($debug) { - if (!class_exists('Debugger')) { - require LIBS . 'debugger.php'; - } $data = array( 'level' => $log, 'code' => $code, @@ -162,14 +160,8 @@ class ErrorHandler { ); return Debugger::getInstance()->outputError($data); } else { - if (!class_exists('CakeLog')) { - require LIBS . 'cake_log.php'; - } $message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']'; if (!empty($errorConfig['trace'])) { - if (!class_exists('Debugger')) { - require LIBS . 'debugger.php'; - } $trace = Debugger::trace(array('start' => 1, 'format' => 'log')); $message .= "\nTrace:\n" . $trace . "\n"; } diff --git a/cake/libs/error/exception_renderer.php b/lib/Cake/Error/ExceptionRenderer.php similarity index 88% rename from cake/libs/error/exception_renderer.php rename to lib/Cake/Error/ExceptionRenderer.php index 5745564df..eb3fbfe95 100644 --- a/cake/libs/error/exception_renderer.php +++ b/lib/Cake/Error/ExceptionRenderer.php @@ -19,6 +19,10 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ + +App::uses('Sanitize', 'Utility'); +App::uses('Router', 'Routing'); + /** * Exception Renderer. * @@ -86,8 +90,6 @@ class ExceptionRenderer { * @param array $messages Error messages */ function __construct(Exception $exception) { - App::import('Core', 'Sanitize'); - $this->controller = $this->_getController($exception); if (method_exists($this->controller, 'apperror')) { @@ -100,6 +102,9 @@ class ExceptionRenderer { if ($exception instanceof CakeException && !$methodExists) { $method = '_cakeError'; + if (empty($template)) { + $template = 'error500'; + } if ($template == 'internalError') { $template = 'error500'; } @@ -138,14 +143,11 @@ class ExceptionRenderer { * @return Controller */ protected function _getController($exception) { - static $__previousError = null; - App::import('Controller', 'CakeError'); - - if ($__previousError != $exception) { - $__previousError = $exception; - $controller = new CakeErrorController(); - } else { - $controller = new Controller(); + App::uses('CakeErrorController', 'Controller'); + try { + $controller = new CakeErrorController(Router::getRequest(false)); + } catch (Exception $e) { + $controller = new Controller(Router::getRequest(false)); $controller->viewPath = 'errors'; } return $controller; @@ -169,7 +171,7 @@ class ExceptionRenderer { * @return void */ protected function _cakeError(CakeException $error) { - $url = Router::normalize($this->controller->request->here); + $url = $this->controller->request->here(); $code = $error->getCode(); $this->controller->response->statusCode($code); $this->controller->set(array( @@ -178,8 +180,12 @@ class ExceptionRenderer { 'name' => $error->getMessage(), 'error' => $error, )); - $this->controller->set($error->getAttributes()); - $this->_outputMessage($this->template); + try { + $this->controller->set($error->getAttributes()); + $this->_outputMessage($this->template); + } catch (Exception $e) { + $this->_outputMessage('error500'); + } } /** @@ -190,9 +196,9 @@ class ExceptionRenderer { public function error400($error) { $message = $error->getMessage(); if (Configure::read('debug') == 0 && $error instanceof CakeException) { - $message = __('Not Found'); + $message = __d('cake', 'Not Found'); } - $url = Router::normalize($this->controller->request->here); + $url = $this->controller->request->here(); $this->controller->response->statusCode($error->getCode()); $this->controller->set(array( 'name' => $message, @@ -208,11 +214,11 @@ class ExceptionRenderer { * @param array $params Parameters for controller */ public function error500($error) { - $url = Router::normalize($this->controller->request->here); + $url = $this->controller->request->here(); $code = ($error->getCode() > 500) ? $error->getCode() : 500; $this->controller->response->statusCode($code); $this->controller->set(array( - 'name' => __('An Internal Error Has Occurred'), + 'name' => __d('cake', 'An Internal Error Has Occurred'), 'message' => h($url), 'error' => $error, )); @@ -229,4 +235,4 @@ class ExceptionRenderer { $this->controller->afterFilter(); $this->controller->response->send(); } -} \ No newline at end of file +} diff --git a/cake/libs/error/exceptions.php b/lib/Cake/Error/exceptions.php similarity index 84% rename from cake/libs/error/exceptions.php rename to lib/Cake/Error/exceptions.php index 75224c557..d178005b6 100644 --- a/cake/libs/error/exceptions.php +++ b/lib/Cake/Error/exceptions.php @@ -20,12 +20,14 @@ /** * Parent class for all of the HTTP related exceptions in CakePHP. - * All HTTP status/error related exceptions should extend this class so + * All HTTP status/error related exceptions should extend this class so * catch blocks can be specifically typed. * * @package cake.libs */ -class HttpException extends RuntimeException { } +if (!class_exists('HttpException')) { + class HttpException extends RuntimeException { } +} /** * Represents an HTTP 400 error. @@ -182,7 +184,7 @@ class CakeException extends RuntimeException { public function __construct($message, $code = 500) { if (is_array($message)) { $this->_attributes = $message; - $message = __($this->_messageTemplate, $message); + $message = __d('cake_dev', $this->_messageTemplate, $message); } parent::__construct($message, $code); } @@ -198,12 +200,12 @@ class CakeException extends RuntimeException { } /** - * Missing Controller exception - used when a controller + * Missing Controller exception - used when a controller * cannot be found. * * @package cake.libs */ -class MissingControllerException extends CakeException { +class MissingControllerException extends CakeException { protected $_messageTemplate = 'Controller class %s could not be found.'; public function __construct($message, $code = 404) { @@ -212,12 +214,12 @@ class MissingControllerException extends CakeException { } /** - * Missing Action exception - used when a controller action + * Missing Action exception - used when a controller action * cannot be found. * * @package cake.libs */ -class MissingActionException extends CakeException { +class MissingActionException extends CakeException { protected $_messageTemplate = 'Action %s::%s() could not be found.'; public function __construct($message, $code = 404) { @@ -225,12 +227,12 @@ class MissingActionException extends CakeException { } } /** - * Private Action exception - used when a controller action + * Private Action exception - used when a controller action * is protected, or starts with a `_`. * * @package cake.libs */ -class PrivateActionException extends CakeException { +class PrivateActionException extends CakeException { protected $_messageTemplate = 'Private Action %s::%s() is not directly accessible.'; public function __construct($message, $code = 404, Exception $previous = null) { @@ -243,7 +245,7 @@ class PrivateActionException extends CakeException { * * @package cake.libs */ -class MissingComponentFileException extends CakeException { +class MissingComponentFileException extends CakeException { protected $_messageTemplate = 'Component File "%s" is missing.'; } @@ -252,7 +254,7 @@ class MissingComponentFileException extends CakeException { * * @package cake.libs */ -class MissingComponentClassException extends CakeException { +class MissingComponentClassException extends CakeException { protected $_messageTemplate = 'Component class "%s" is missing.'; } @@ -275,7 +277,7 @@ class MissingBehaviorClassException extends CakeException { } * * @package cake.libs */ -class MissingViewException extends CakeException { +class MissingViewException extends CakeException { protected $_messageTemplate = 'View file "%s" is missing.'; } @@ -284,7 +286,7 @@ class MissingViewException extends CakeException { * * @package cake.libs */ -class MissingLayoutException extends CakeException { +class MissingLayoutException extends CakeException { protected $_messageTemplate = 'Layout file "%s" is missing.'; } @@ -293,7 +295,7 @@ class MissingLayoutException extends CakeException { * * @package cake.libs */ -class MissingHelperFileException extends CakeException { +class MissingHelperFileException extends CakeException { protected $_messageTemplate = 'Helper File "%s" is missing.'; } @@ -302,7 +304,7 @@ class MissingHelperFileException extends CakeException { * * @package cake.libs */ -class MissingHelperClassException extends CakeException { +class MissingHelperClassException extends CakeException { protected $_messageTemplate = 'Helper class "%s" is missing.'; } @@ -330,7 +332,7 @@ class MissingConnectionException extends CakeException { * * @package cake.libs */ -class MissingTaskFileException extends CakeException { +class MissingTaskFileException extends CakeException { protected $_messageTemplate = 'Task file "%s" is missing.'; } @@ -339,7 +341,7 @@ class MissingTaskFileException extends CakeException { * * @package cake.libs */ -class MissingTaskClassException extends CakeException { +class MissingTaskClassException extends CakeException { protected $_messageTemplate = 'Task class "%s" is missing.'; } @@ -348,7 +350,7 @@ class MissingTaskClassException extends CakeException { * * @package cake.libs */ -class MissingShellMethodException extends CakeException { +class MissingShellMethodException extends CakeException { protected $_messageTemplate = "Unknown command %1\$s %2\$s.\nFor usage try `cake %1\$s --help`"; } @@ -357,7 +359,7 @@ class MissingShellMethodException extends CakeException { * * @package cake.libs */ -class MissingShellClassException extends CakeException { +class MissingShellClassException extends CakeException { protected $_messageTemplate = "Shell class %s could not be loaded."; } @@ -366,10 +368,28 @@ class MissingShellClassException extends CakeException { * * @package cake.libs */ -class MissingShellFileException extends CakeException { +class MissingShellFileException extends CakeException { protected $_messageTemplate = "Shell file %s could not be loaded."; } +/** + * Exception class to be thrown when a database file is not found + * + * @package cake.libs + */ +class MissingDatasourceConfigException extends CakeException { + protected $_messageTemplate = 'Database connection "%s" could not be loaded.'; +} + +/** + * Exception class to be thrown when a database file is not found + * + * @package cake.libs + */ +class MissingDatasourceFileException extends CakeException { + protected $_messageTemplate = 'Database connection "%s" could not be loaded.'; +} + /** * Exception class to be thrown when a database table is not found in the datasource * @@ -388,6 +408,15 @@ class MissingModelException extends CakeException { protected $_messageTemplate = 'Model %s could not be found.'; } +/** + * Exception Raised when a test loader could not be found + * + * @package cake.libs + */ +class MissingTestLoaderException extends CakeException { + protected $_messageTemplate = 'Test loader %s could not be found.'; +} + /** * Exception class for Cache. This exception will be thrown from Cache when it @@ -452,4 +481,3 @@ class XmlException extends CakeException { } * @package cake.libs */ class ConsoleException extends CakeException { } - diff --git a/cake/libs/i18n.php b/lib/Cake/I18n/I18n.php similarity index 98% rename from cake/libs/i18n.php rename to lib/Cake/I18n/I18n.php index 63cc47b19..e05e1bcdc 100644 --- a/cake/libs/i18n.php +++ b/lib/Cake/I18n/I18n.php @@ -20,8 +20,8 @@ /** * Included libraries. */ -App::import('Core', 'L10n'); -App::import('Core', 'Multibyte'); +App::uses('L10n', 'I18n'); +App::uses('Multibyte', 'I18n'); /** * I18n handles translation of Text and time format strings. @@ -99,7 +99,7 @@ class I18n { /** * Used by the translation functions in basics.php - * Can also be used like I18n::translate(); but only if the App::import('I18n'); has been used to load the class. + * Returns a translated string based on current language and translation files stored in locale folder * * @param string $singular String to translate * @param string $plural Plural string (if any) @@ -319,8 +319,10 @@ class I18n { $this->__domains[$domain][$this->__lang][$this->category] = array(); return $domain; } - - if ($head = $this->__domains[$domain][$this->__lang][$this->category][""]) { + + if (isset($this->__domains[$domain][$this->__lang][$this->category][""])) { + $head = $this->__domains[$domain][$this->__lang][$this->category][""]; + foreach (explode("\n", $head) as $line) { $header = strtok($line,":"); $line = trim(strtok("\n")); diff --git a/cake/libs/l10n.php b/lib/Cake/I18n/L10n.php similarity index 99% rename from cake/libs/l10n.php rename to lib/Cake/I18n/L10n.php index 2da41af34..c9bef1e79 100644 --- a/cake/libs/l10n.php +++ b/lib/Cake/I18n/L10n.php @@ -16,7 +16,7 @@ * @since CakePHP(tm) v 1.2.0.4116 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'CakeRequest'); +App::uses('CakeRequest', 'Network'); /** * Localization diff --git a/cake/libs/multibyte.php b/lib/Cake/I18n/Multibyte.php similarity index 99% rename from cake/libs/multibyte.php rename to lib/Cake/I18n/Multibyte.php index 123d3d11b..9ad06c093 100644 --- a/cake/libs/multibyte.php +++ b/lib/Cake/I18n/Multibyte.php @@ -1076,7 +1076,7 @@ class Multibyte { return null; } if (!Configure::configured('_cake_core_')) { - App::import('Core', 'config/PhpReader'); + App::uses('PhpReader', 'Configure'); Configure::config('_cake_core_', new PhpReader(CAKE . 'config' . DS)); } Configure::load('unicode' . DS . 'casefolding' . DS . $range, '_cake_core_'); diff --git a/cake/LICENSE.txt b/lib/Cake/LICENSE.txt similarity index 100% rename from cake/LICENSE.txt rename to lib/Cake/LICENSE.txt diff --git a/cake/libs/cake_log.php b/lib/Cake/Log/CakeLog.php similarity index 85% rename from cake/libs/cake_log.php rename to lib/Cake/Log/CakeLog.php index e632c2898..8305d4fba 100644 --- a/cake/libs/cake_log.php +++ b/lib/Cake/Log/CakeLog.php @@ -36,22 +36,6 @@ define('LOG_INFO', 6); } -/** - * CakeLogStreamInterface is the interface that should be implemented - * by all classes that are going to be used as Log streams. - * - * @package cake.libs - */ -interface CakeLogInterface { -/** - * Write method to handle writes being made to the Logger - * - * @param string $type - * @param string $message - * @return void - */ - public function write($type, $message); -} /** * Logs messages to configured Log adapters. One or more adapters can be configured @@ -98,7 +82,7 @@ class CakeLog { */ public static function config($key, $config) { if (empty($config['engine'])) { - throw new CakeLogException(__('Missing logger classname')); + throw new CakeLogException(__d('cake_dev', 'Missing logger classname')); } $loggerName = $config['engine']; unset($config['engine']); @@ -106,7 +90,7 @@ class CakeLog { $logger = new $className($config); if (!$logger instanceof CakeLogInterface) { throw new CakeLogException(sprintf( - __('logger class %s does not implement a write method.'), $loggerName + __d('cake_dev', 'logger class %s does not implement a write method.'), $loggerName )); } self::$_streams[$key] = $logger; @@ -121,17 +105,11 @@ class CakeLog { * @return mixed boolean false on any failures, string of classname to use if search was successful. */ protected static function _getLogger($loggerName) { - list($plugin, $loggerName) = pluginSplit($loggerName); + list($plugin, $loggerName) = pluginSplit($loggerName, true); - if ($plugin) { - App::import('Lib', $plugin . '.log/' . $loggerName); - } else { - if (!App::import('Lib', 'log/' . $loggerName)) { - App::import('Core', 'log/' . $loggerName); - } - } + App::uses($loggerName, $plugin . 'Log/Engine'); if (!class_exists($loggerName)) { - throw new CakeLogException(__('Could not load class %s', $loggerName)); + throw new CakeLogException(__d('cake_dev', 'Could not load class %s', $loggerName)); } return $loggerName; } @@ -162,9 +140,7 @@ class CakeLog { * @return void */ protected static function _autoConfig() { - if (!class_exists('FileLog')) { - App::import('Core', 'log/FileLog'); - } + self::_getLogger('FileLog'); self::$_streams['default'] = new FileLog(array('path' => LOGS)); } diff --git a/lib/Cake/Log/CakeLogInterface.php b/lib/Cake/Log/CakeLogInterface.php new file mode 100644 index 000000000..0b2cd1a3c --- /dev/null +++ b/lib/Cake/Log/CakeLogInterface.php @@ -0,0 +1,18 @@ + 'nested'); + public $actsAs = array('Tree' => array('nested')); /** * Constructor @@ -67,7 +64,7 @@ class AclNode extends AppModel { * @return array Node found in database */ public function node($ref = null) { - $db =& ConnectionManager::getDataSource($this->useDbConfig); + $db = $this->getDataSource(); $type = $this->alias; $result = null; @@ -136,7 +133,7 @@ class AclNode extends AppModel { $model = ClassRegistry::init(array('class' => $name, 'alias' => $name)); if (empty($model)) { - trigger_error(__("Model class '%s' not found in AclNode::node() when trying to bind %s object", $type, $this->alias), E_USER_WARNING); + trigger_error(__d('cake_dev', "Model class '%s' not found in AclNode::node() when trying to bind %s object", $type, $this->alias), E_USER_WARNING); return null; } @@ -181,141 +178,9 @@ class AclNode extends AppModel { $result = $db->read($this, $queryData, -1); if (!$result) { - trigger_error(__("AclNode::node() - Couldn't find %s node identified by \"%s\"", $type, print_r($ref, true)), E_USER_WARNING); + trigger_error(__d('cake_dev', "AclNode::node() - Couldn't find %s node identified by \"%s\"", $type, print_r($ref, true)), E_USER_WARNING); } } return $result; } } - -/** - * Access Control Object - * - * @package cake.libs.model - */ -class Aco extends AclNode { - -/** - * Model name - * - * @var string - * @access public - */ - public $name = 'Aco'; - -/** - * Binds to ARO nodes through permissions settings - * - * @var array - * @access public - */ - public $hasAndBelongsToMany = array('Aro' => array('with' => 'Permission')); -} - -/** - * Action for Access Control Object - * - * @package cake.libs.model - */ -class AcoAction extends AppModel { - -/** - * Model name - * - * @var string - * @access public - */ - public $name = 'AcoAction'; - -/** - * ACO Actions belong to ACOs - * - * @var array - * @access public - */ - public $belongsTo = array('Aco'); -} - -/** - * Access Request Object - * - * @package cake.libs.model - */ -class Aro extends AclNode { - -/** - * Model name - * - * @var string - * @access public - */ - public $name = 'Aro'; - -/** - * AROs are linked to ACOs by means of Permission - * - * @var array - * @access public - */ - public $hasAndBelongsToMany = array('Aco' => array('with' => 'Permission')); -} - -/** - * Permissions linking AROs with ACOs - * - * @package cake.libs.model - */ -class Permission extends AppModel { - -/** - * Model name - * - * @var string - * @access public - */ - public $name = 'Permission'; - -/** - * Explicitly disable in-memory query caching - * - * @var boolean - * @access public - */ - public $cacheQueries = false; - -/** - * Override default table name - * - * @var string - * @access public - */ - public $useTable = 'aros_acos'; - -/** - * Permissions link AROs with ACOs - * - * @var array - * @access public - */ - public $belongsTo = array('Aro', 'Aco'); - -/** - * No behaviors for this model - * - * @var array - * @access public - */ - public $actsAs = null; - -/** - * Constructor, used to tell this model to use the - * database configured for ACL - */ - function __construct() { - $config = Configure::read('Acl.database'); - if (!empty($config)) { - $this->useDbConfig = $config; - } - parent::__construct(); - } -} diff --git a/lib/Cake/Model/Aco.php b/lib/Cake/Model/Aco.php new file mode 100644 index 000000000..f8a92bcf4 --- /dev/null +++ b/lib/Cake/Model/Aco.php @@ -0,0 +1,48 @@ + array('with' => 'Permission')); +} \ No newline at end of file diff --git a/lib/Cake/Model/AcoAction.php b/lib/Cake/Model/AcoAction.php new file mode 100644 index 000000000..fe9734228 --- /dev/null +++ b/lib/Cake/Model/AcoAction.php @@ -0,0 +1,48 @@ + array('with' => 'Permission')); +} diff --git a/cake/libs/model/behaviors/acl.php b/lib/Cake/Model/Behavior/AclBehavior.php similarity index 52% rename from cake/libs/model/behaviors/acl.php rename to lib/Cake/Model/Behavior/AclBehavior.php index b03586657..ae72d960e 100644 --- a/cake/libs/model/behaviors/acl.php +++ b/lib/Cake/Model/Behavior/AclBehavior.php @@ -31,9 +31,8 @@ class AclBehavior extends ModelBehavior { * Maps ACL type options to ACL models * * @var array - * @access protected */ - private $__typeMaps = array('requester' => 'Aro', 'controlled' => 'Aco'); + private $__typeMaps = array('requester' => 'Aro', 'controlled' => 'Aco', 'both' => array('Aro', 'Aco')); /** * Sets up the configuation for the model, and loads ACL models if they haven't been already @@ -45,16 +44,21 @@ class AclBehavior extends ModelBehavior { if (is_string($config)) { $config = array('type' => $config); } - $this->settings[$model->name] = array_merge(array('type' => 'requester'), (array)$config); + $this->settings[$model->name] = array_merge(array('type' => 'controlled'), (array)$config); $this->settings[$model->name]['type'] = strtolower($this->settings[$model->name]['type']); - $type = $this->__typeMaps[$this->settings[$model->name]['type']]; + $types = $this->__typeMaps[$this->settings[$model->name]['type']]; if (!class_exists('AclNode')) { require LIBS . 'model' . DS . 'db_acl.php'; } - $model->{$type} = ClassRegistry::init($type); + if (!is_array($types)) { + $types = array($types); + } + foreach ($types as $type) { + $model->{$type} = ClassRegistry::init($type); + } if (!method_exists($model, 'parentNode')) { - trigger_error(__('Callback parentNode() not defined in %s', $model->alias), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Callback parentNode() not defined in %s', $model->alias), E_USER_WARNING); } } @@ -62,11 +66,18 @@ class AclBehavior extends ModelBehavior { * Retrieves the Aro/Aco node for this model * * @param mixed $ref + * @param string $type Only needed when Acl is set up as 'both', specify 'Aro' or 'Aco' to get the correct node * @return array * @link http://book.cakephp.org/view/1322/node */ - public function node($model, $ref = null) { - $type = $this->__typeMaps[$this->settings[$model->name]['type']]; + public function node($model, $ref = null, $type = null) { + if (empty($type)) { + $type = $this->__typeMaps[$this->settings[$model->name]['type']]; + if (is_array($type)) { + trigger_error(__('AclBehavior is setup with more then one type, please specify type parameter for node()', true), E_USER_WARNING); + return null; + } + } if (empty($ref)) { $ref = array('model' => $model->name, 'foreign_key' => $model->id); } @@ -80,22 +91,27 @@ class AclBehavior extends ModelBehavior { * @return void */ public function afterSave($model, $created) { - $type = $this->__typeMaps[$this->settings[$model->name]['type']]; - $parent = $model->parentNode(); - if (!empty($parent)) { - $parent = $this->node($model, $parent); + $types = $this->__typeMaps[$this->settings[$model->name]['type']]; + if (!is_array($types)) { + $types = array($types); } - $data = array( - 'parent_id' => isset($parent[0][$type]['id']) ? $parent[0][$type]['id'] : null, - 'model' => $model->alias, - 'foreign_key' => $model->id - ); - if (!$created) { - $node = $this->node($model); - $data['id'] = isset($node[0][$type]['id']) ? $node[0][$type]['id'] : null; + foreach ($types as $type) { + $parent = $model->parentNode(); + if (!empty($parent)) { + $parent = $this->node($model, $parent, $type); + } + $data = array( + 'parent_id' => isset($parent[0][$type]['id']) ? $parent[0][$type]['id'] : null, + 'model' => $model->alias, + 'foreign_key' => $model->id + ); + if (!$created) { + $node = $this->node($model, null, $type); + $data['id'] = isset($node[0][$type]['id']) ? $node[0][$type]['id'] : null; + } + $model->{$type}->create(); + $model->{$type}->save($data); } - $model->{$type}->create(); - $model->{$type}->save($data); } /** @@ -104,10 +120,15 @@ class AclBehavior extends ModelBehavior { * @return void */ public function afterDelete($model) { - $type = $this->__typeMaps[$this->settings[$model->name]['type']]; - $node = Set::extract($this->node($model), "0.{$type}.id"); - if (!empty($node)) { - $model->{$type}->delete($node); + $types = $this->__typeMaps[$this->settings[$model->name]['type']]; + if (!is_array($types)) { + $types = array($types); + } + foreach ($types as $type) { + $node = Set::extract($this->node($model, null, $type), "0.{$type}.id"); + if (!empty($node)) { + $model->{$type}->delete($node); + } } } } diff --git a/cake/libs/model/behaviors/containable.php b/lib/Cake/Model/Behavior/ContainableBehavior.php similarity index 99% rename from cake/libs/model/behaviors/containable.php rename to lib/Cake/Model/Behavior/ContainableBehavior.php index 03963a723..3c76f2a73 100644 --- a/cake/libs/model/behaviors/containable.php +++ b/lib/Cake/Model/Behavior/ContainableBehavior.php @@ -359,7 +359,7 @@ class ContainableBehavior extends ModelBehavior { if (!isset($Model->{$name}) || !is_object($Model->{$name})) { if ($throwErrors) { - trigger_error(__('Model "%s" is not associated with model "%s"', $Model->alias, $name), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Model "%s" is not associated with model "%s"', $Model->alias, $name), E_USER_WARNING); } continue; } diff --git a/cake/libs/model/behaviors/translate.php b/lib/Cake/Model/Behavior/TranslateBehavior.php similarity index 96% rename from cake/libs/model/behaviors/translate.php rename to lib/Cake/Model/Behavior/TranslateBehavior.php index 3f0c462d5..48c3d36e3 100644 --- a/cake/libs/model/behaviors/translate.php +++ b/lib/Cake/Model/Behavior/TranslateBehavior.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('I18n', 'I18n'); + /** * Translate behavior * @@ -53,7 +55,7 @@ class TranslateBehavior extends ModelBehavior { $db = ConnectionManager::getDataSource($model->useDbConfig); if (!$db->connected) { trigger_error( - __('Datasource %s for TranslateBehavior of model %s is not connected', $model->useDbConfig, $model->alias), + __d('cake_dev', 'Datasource %s for TranslateBehavior of model %s is not connected', $model->useDbConfig, $model->alias), E_USER_ERROR ); return false; @@ -90,7 +92,7 @@ class TranslateBehavior extends ModelBehavior { if (empty($locale)) { return $query; } - $db = ConnectionManager::getDataSource($model->useDbConfig); + $db = $model->getDataSource(); $RuntimeModel = $this->translateModel($model); if (!empty($RuntimeModel->tablePrefix)) { $tablePrefix = $RuntimeModel->tablePrefix; @@ -98,12 +100,16 @@ class TranslateBehavior extends ModelBehavior { $tablePrefix = $db->config['prefix']; } + if ($tablePrefix == $db->config['prefix']) { + $tablePrefix = null; + } + if (is_string($query['fields']) && 'COUNT(*) AS '.$db->name('count') == $query['fields']) { $query['fields'] = 'COUNT(DISTINCT('.$db->name($model->alias . '.' . $model->primaryKey) . ')) ' . $db->alias . 'count'; $query['joins'][] = array( 'type' => 'INNER', 'alias' => $RuntimeModel->alias, - 'table' => $db->name($tablePrefix . $RuntimeModel->useTable), + 'table' => $db->fullTableName($tablePrefix . $RuntimeModel->useTable), 'conditions' => array( $model->alias . '.' . $model->primaryKey => $db->identifier($RuntimeModel->alias.'.foreign_key'), $RuntimeModel->alias.'.model' => $model->name, @@ -149,7 +155,7 @@ class TranslateBehavior extends ModelBehavior { $query['joins'][] = array( 'type' => 'LEFT', 'alias' => 'I18n__'.$field.'__'.$_locale, - 'table' => $db->name($tablePrefix . $RuntimeModel->useTable), + 'table' => $db->fullTableName($tablePrefix . $RuntimeModel->useTable), 'conditions' => array( $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}__{$_locale}.foreign_key"), 'I18n__'.$field.'__'.$_locale.'.model' => $model->name, @@ -166,7 +172,7 @@ class TranslateBehavior extends ModelBehavior { $query['joins'][] = array( 'type' => 'LEFT', 'alias' => 'I18n__'.$field, - 'table' => $db->name($tablePrefix . $RuntimeModel->useTable), + 'table' => $db->fullTableName($tablePrefix . $RuntimeModel->useTable), 'conditions' => array( $model->alias . '.' . $model->primaryKey => $db->identifier("I18n__{$field}.foreign_key"), 'I18n__'.$field.'.model' => $model->name, @@ -331,9 +337,6 @@ class TranslateBehavior extends ModelBehavior { */ protected function _getLocale($model) { if (!isset($model->locale) || is_null($model->locale)) { - if (!class_exists('I18n')) { - App::import('Core', 'i18n'); - } $I18n = I18n::getInstance(); $I18n->l10n->get(Configure::read('Config.language')); $model->locale = $I18n->l10n->locale; @@ -423,7 +426,7 @@ class TranslateBehavior extends ModelBehavior { foreach (array('hasOne', 'hasMany', 'belongsTo', 'hasAndBelongsToMany') as $type) { if (isset($model->{$type}[$association]) || isset($model->__backAssociation[$type][$association])) { trigger_error( - __('Association %s is already binded to model %s', $association, $model->alias), + __d('cake_dev', 'Association %s is already binded to model %s', $association, $model->alias), E_USER_ERROR ); return false; diff --git a/cake/libs/model/behaviors/tree.php b/lib/Cake/Model/Behavior/TreeBehavior.php similarity index 100% rename from cake/libs/model/behaviors/tree.php rename to lib/Cake/Model/Behavior/TreeBehavior.php diff --git a/cake/libs/model/behavior_collection.php b/lib/Cake/Model/BehaviorCollection.php similarity index 79% rename from cake/libs/model/behavior_collection.php rename to lib/Cake/Model/BehaviorCollection.php index 965c315f4..82cb3ed77 100644 --- a/cake/libs/model/behavior_collection.php +++ b/lib/Cake/Model/BehaviorCollection.php @@ -18,7 +18,8 @@ * @since CakePHP(tm) v 1.2.0.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'ObjectCollection'); + +App::uses('ObjectCollection', 'Utility'); /** * Model behavior collection class. @@ -83,21 +84,34 @@ class BehaviorCollection extends ObjectCollection { * to load a behavior with callbacks disabled. By default callbacks are enabled. Disable behaviors * can still be used as normal. * + * You can alias your behavior as an existing behavior by setting the 'className' key, i.e., + * {{{ + * public $actsAs = array( + * 'Tree' => array( + * 'className' => 'AliasedTree' + * ); + * ); + * }}} + * All calls to the `Tree` behavior would use `AliasedTree` instead. + * * @param string $behavior CamelCased name of the behavior to load * @param array $config Behavior configuration parameters * @return boolean True on success, false on failure - * @throws MissingBehaviorFileException or MissingBehaviorClassException when a behavior could not be found. + * @throws MissingBehaviorClassException when a behavior could not be found. */ public function load($behavior, $config = array()) { - list($plugin, $name) = pluginSplit($behavior); + if (is_array($config) && isset($config['className'])) { + $alias = $behavior; + $behavior = $config['className']; + } + list($plugin, $name) = pluginSplit($behavior, true); + if (!isset($alias)) { + $alias = $name; + } + $class = $name . 'Behavior'; - if (!App::import('Behavior', $behavior)) { - throw new MissingBehaviorFileException(array( - 'file' => Inflector::underscore($behavior) . '.php', - 'class' => $class - )); - } + App::uses($class, $plugin . 'Model/Behavior'); if (!class_exists($class)) { throw new MissingBehaviorClassException(array( 'file' => Inflector::underscore($behavior) . '.php', @@ -105,19 +119,19 @@ class BehaviorCollection extends ObjectCollection { )); } - if (!isset($this->{$name})) { + if (!isset($this->{$alias})) { if (ClassRegistry::isKeySet($class)) { - $this->_loaded[$name] = ClassRegistry::getObject($class); + $this->_loaded[$alias] = ClassRegistry::getObject($class); } else { - $this->_loaded[$name] = new $class(); - ClassRegistry::addObject($class, $this->_loaded[$name]); + $this->_loaded[$alias] = new $class(); + ClassRegistry::addObject($class, $this->_loaded[$alias]); if (!empty($plugin)) { - ClassRegistry::addObject($plugin . '.' . $class, $this->_loaded[$name]); + ClassRegistry::addObject($plugin . '.' . $class, $this->_loaded[$alias]); } } - } elseif (isset($this->_loaded[$name]->settings) && isset($this->_loaded[$name]->settings[$this->modelName])) { + } elseif (isset($this->_loaded[$alias]->settings) && isset($this->_loaded[$alias]->settings[$this->modelName])) { if ($config !== null && $config !== false) { - $config = array_merge($this->_loaded[$name]->settings[$this->modelName], $config); + $config = array_merge($this->_loaded[$alias]->settings[$this->modelName], $config); } else { $config = array(); } @@ -125,12 +139,12 @@ class BehaviorCollection extends ObjectCollection { if (empty($config)) { $config = array(); } - $this->_loaded[$name]->setup(ClassRegistry::getObject($this->modelName), $config); + $this->_loaded[$alias]->setup(ClassRegistry::getObject($this->modelName), $config); - foreach ($this->_loaded[$name]->mapMethods as $method => $alias) { - $this->_mappedMethods[$method] = array($name, $alias); + foreach ($this->_loaded[$alias]->mapMethods as $method => $methodAlias) { + $this->_mappedMethods[$method] = array($alias, $methodAlias); } - $methods = get_class_methods($this->_loaded[$name]); + $methods = get_class_methods($this->_loaded[$alias]); $parentMethods = array_flip(get_class_methods('ModelBehavior')); $callbacks = array( 'setup', 'cleanup', 'beforeFind', 'afterFind', 'beforeSave', 'afterSave', @@ -144,16 +158,16 @@ class BehaviorCollection extends ObjectCollection { !in_array($m, $callbacks) ); if ($methodAllowed) { - $this->_methods[$m] = array($name, $m); + $this->_methods[$m] = array($alias, $m); } } } $configDisabled = isset($config['enabled']) && $config['enabled'] === false; - if (!in_array($name, $this->_enabled) && !$configDisabled) { - $this->enable($name); + if (!in_array($alias, $this->_enabled) && !$configDisabled) { + $this->enable($alias); } elseif ($configDisabled) { - $this->disable($name); + $this->disable($alias); } return true; } @@ -205,7 +219,7 @@ class BehaviorCollection extends ObjectCollection { $method = $this->hasMethod($method, true); if ($strict && empty($method)) { - trigger_error(__("BehaviorCollection::dispatchMethod() - Method %s not found in any attached behavior", $method), E_USER_WARNING); + trigger_error(__d('cake_dev', "BehaviorCollection::dispatchMethod() - Method %s not found in any attached behavior", $method), E_USER_WARNING); return null; } if (empty($method)) { diff --git a/cake/libs/model/cake_schema.php b/lib/Cake/Model/CakeSchema.php similarity index 93% rename from cake/libs/model/cake_schema.php rename to lib/Cake/Model/CakeSchema.php index a38e0ed7b..67f1cb87a 100644 --- a/cake/libs/model/cake_schema.php +++ b/lib/Cake/Model/CakeSchema.php @@ -16,8 +16,9 @@ * @since CakePHP(tm) v 1.2.0.5550 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'Model'); -App::import('Core', 'ConnectionManager'); +App::uses('Model', 'Model'); +App::uses('AppModel', 'Model'); +App::uses('ConnectionManager', 'Model'); /** * Base Class for Schema management @@ -27,7 +28,7 @@ App::import('Core', 'ConnectionManager'); class CakeSchema extends Object { /** - * Name of the App Schema + * Name of the schema * * @var string * @access public @@ -204,9 +205,8 @@ class CakeSchema extends Object { )); $db = ConnectionManager::getDataSource($connection); - App::import('Model', 'AppModel'); if (isset($this->plugin)) { - App::import('Model', Inflector::camelize($this->plugin) . 'AppModel'); + App::uses(Inflector::camelize($this->plugin) . 'AppModel', $this->plugin . '.Model'); } $tables = array(); @@ -219,28 +219,36 @@ class CakeSchema extends Object { if (!is_array($models) && $models !== false) { if (isset($this->plugin)) { - $models = App::objects('model', App::pluginPath($this->plugin) . 'models' . DS, false); + $models = App::objects($this->plugin . '.Model', null, false); } else { - $models = App::objects('model'); + $models = App::objects('Model'); } } if (is_array($models)) { foreach ($models as $model) { $importModel = $model; + $plugin = null; if (isset($this->plugin)) { - $importModel = $this->plugin . '.' . $model; + if ($model == $this->plugin . 'AppModel') { + continue; + } + $importModel = $model; + $plugin = $this->plugin . '.'; } - if (!App::import('Model', $importModel)) { + + App::uses($importModel, $plugin . 'Model'); + if (!class_exists($importModel)) { continue; } + $vars = get_class_vars($model); if (empty($vars['useDbConfig']) || $vars['useDbConfig'] != $connection) { continue; } $Object = ClassRegistry::init(array('class' => $model, 'ds' => $connection)); - + $db = $Object->getDataSource(); if (is_object($Object) && $Object->useTable !== false) { $fulltable = $table = $db->fullTableName($Object, false); if ($prefix && strpos($table, $prefix) !== 0) { @@ -263,11 +271,16 @@ class CakeSchema extends Object { } if (is_object($Object->$class)) { $withTable = $db->fullTableName($Object->$class, false); + if ($prefix && strpos($withTable, $prefix) !== 0) { + continue; + } if (in_array($withTable, $currentTables)) { $key = array_search($withTable, $currentTables); - $tables[$withTable] = $this->__columns($Object->$class); - $tables[$withTable]['indexes'] = $db->index($Object->$class); - $tables[$withTable]['tableParameters'] = $db->readTableParameters($withTable); + $noPrefixWith = str_replace($prefix, '', $withTable); + + $tables[$noPrefixWith] = $this->__columns($Object->$class); + $tables[$noPrefixWith]['indexes'] = $db->index($Object->$class); + $tables[$noPrefixWith]['tableParameters'] = $db->readTableParameters($withTable); unset($currentTables[$key]); } } @@ -337,8 +350,6 @@ class CakeSchema extends Object { $out = "class {$name}Schema extends CakeSchema {\n"; - $out .= "\tvar \$name = '{$name}';\n\n"; - if ($path !== $this->path) { $out .= "\tvar \$path = '{$path}';\n\n"; } @@ -365,7 +376,7 @@ class CakeSchema extends Object { $out .= "}\n"; $file = new SplFileObject($path . DS . $file, 'w+'); - $content = ""; + $content = ""; if ($file->fwrite($content)) { return $content; } @@ -572,15 +583,16 @@ class CakeSchema extends Object { * @return array Formatted columns */ public function __columns(&$Obj) { - $db = ConnectionManager::getDataSource($Obj->useDbConfig); + $db = $Obj->getDataSource(); $fields = $Obj->schema(true); + $columns = $props = array(); foreach ($fields as $name => $value) { if ($Obj->primaryKey == $name) { $value['key'] = 'primary'; } if (!isset($db->columns[$value['type']])) { - trigger_error(__('Schema generation error: invalid column type %s does not exist in DBO', $value['type']), E_USER_NOTICE); + trigger_error(__d('cake_dev', 'Schema generation error: invalid column type %s does not exist in DBO', $value['type']), E_USER_NOTICE); continue; } else { $defaultCol = $db->columns[$value['type']]; diff --git a/lib/Cake/Model/ConnectionManager.php b/lib/Cake/Model/ConnectionManager.php new file mode 100644 index 000000000..0f0ac3435 --- /dev/null +++ b/lib/Cake/Model/ConnectionManager.php @@ -0,0 +1,251 @@ +{$name}); + self::$_dataSources[$name]->configKeyName = $name; + + return self::$_dataSources[$name]; + } + +/** + * Gets the list of available DataSource connections + * + * @return array List of available connections + */ + public static function sourceList() { + if (empty(self::$_init)) { + self::init(); + } + return array_keys(self::$_dataSources); + } + +/** + * Gets a DataSource name from an object reference. + * + * @param object $source DataSource object + * @return string Datasource name, or null if source is not present + * in the ConnectionManager. + */ + public static function getSourceName($source) { + if (empty(self::$_init)) { + self::init(); + } + foreach (self::$_dataSources as $name => $ds) { + if ($ds === $source) { + return $name; + } + } + return ''; + } + +/** + * Loads the DataSource class for the given connection name + * + * @param mixed $connName A string name of the connection, as defined in app/config/database.php, + * or an array containing the filename (without extension) and class name of the object, + * to be found in app/models/datasources/ or cake/libs/model/datasources/. + * @return boolean True on success, null on failure or false if the class is already loaded + * @throws MissingDatasourceFileException + */ + public static function loadDataSource($connName) { + if (empty(self::$_init)) { + self::init(); + } + + if (is_array($connName)) { + $conn = $connName; + } else { + $conn = self::$_connectionsEnum[$connName]; + } + + if (class_exists($conn['classname'], false)) { + return false; + } + + $plugin = $package = null; + if (!empty($conn['plugin'])) { + $plugin = $conn['plugin'] . '.'; + } + if (!empty($conn['package'])) { + $package = '/' . $conn['package']; + } + + App::uses($conn['classname'], $plugin . 'Model/Datasource' . $package); + if (!class_exists($conn['classname'])) { + throw new MissingDatasourceFileException(array('class' => $conn['classname'], 'plugin' => $plugin)); + } + return true; + } + +/** + * Return a list of connections + * + * @return array An associative array of elements where the key is the connection name + * (as defined in Connections), and the value is an array with keys 'filename' and 'classname'. + */ + public static function enumConnectionObjects() { + if (empty(self::$_init)) { + self::init(); + } + return (array) self::$config; + } + +/** + * Dynamically creates a DataSource object at runtime, with the given name and settings + * + * @param string $name The DataSource name + * @param array $config The DataSource configuration settings + * @return object A reference to the DataSource object, or null if creation failed + */ + public static function create($name = '', $config = array()) { + if (empty(self::$_init)) { + self::init(); + } + + if (empty($name) || empty($config) || array_key_exists($name, self::$_connectionsEnum)) { + $null = null; + return $null; + } + self::$config->{$name} = $config; + self::$_connectionsEnum[$name] = self::_connectionData($config); + $return = self::getDataSource($name); + return $return; + } + +/** + * Gets a list of class and file names associated with the user-defined DataSource connections + * + * @return void + */ + protected static function _getConnectionObject($name) { + if (!empty(self::$config->{$name})) { + self::$_connectionsEnum[$name] = self::_connectionData(self::$config->{$name}); + } else { + throw new MissingDatasourceConfigException(array('config' => $name)); + } + } + +/** + * Returns the file, class name, and parent for the given driver. + * + * @return array An indexed array with: filename, classname, plugin and parent + */ + private static function _connectionData($config) { + $package = $classname = $plugin = null; + + list($plugin, $classname) = pluginSplit($config['datasource']); + if (strpos($classname, '/') !== false) { + $package = dirname($classname); + $classname = basename($classname); + } + return compact('package', 'classname', 'plugin'); + } + +/** + * Destructor. + * + */ + public static function shutdown() { + if (Configure::read('Session.defaults') == 'database' && function_exists('session_write_close')) { + session_write_close(); + } + } +} \ No newline at end of file diff --git a/cake/libs/cake_session.php b/lib/Cake/Model/Datasource/CakeSession.php similarity index 95% rename from cake/libs/cake_session.php rename to lib/Cake/Model/Datasource/CakeSession.php index a08fd49c3..d8219c448 100644 --- a/cake/libs/cake_session.php +++ b/lib/Cake/Model/Datasource/CakeSession.php @@ -21,9 +21,9 @@ * @since CakePHP(tm) v .0.10.0.1222 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -if (!class_exists('Security')) { - App::import('Core', 'Security'); -} + +App::uses('Set', 'Utility'); +App::uses('Security', 'Utility'); /** * Session class for Cake. @@ -135,7 +135,6 @@ class CakeSession { * @param boolean $start Should session be started right now */ public static function init($base = null, $start = true) { - App::import('Core', 'Security'); self::$time = time(); $checkAgent = Configure::read('Session.checkAgent'); @@ -255,7 +254,7 @@ class CakeSession { self::__overwrite($_SESSION, Set::remove($_SESSION, $name)); return (self::check($name) == false); } - self::__setError(2, __("%s doesn't exist", $name)); + self::__setError(2, __d('cake_dev', "%s doesn't exist", $name)); return false; } @@ -332,11 +331,12 @@ class CakeSession { * @return boolean */ protected static function _validAgentAndTime() { + $config = self::read('Config'); $validAgent = ( Configure::read('Session.checkAgent') === false || - self::$_userAgent == self::read('Config.userAgent') + self::$_userAgent == $config['userAgent'] ); - return ($validAgent && self::$time <= self::read('Config.time')); + return ($validAgent && self::$time <= $config['time']); } /** @@ -480,7 +480,7 @@ class CakeSession { foreach ($sessionConfig['ini'] as $setting => $value) { if (ini_set($setting, $value) === false) { throw new CakeSessionException(sprintf( - __('Unable to configure the session, setting %s failed.'), + __d('cake_dev', 'Unable to configure the session, setting %s failed.'), $setting )); } @@ -512,18 +512,15 @@ class CakeSession { */ protected static function _getHandler($handler) { list($plugin, $class) = pluginSplit($handler, true); - $found = App::import('Lib', $plugin . 'session/' . $class); - if (!$found) { - App::import('Core', 'session/' . $class); - } + App::uses($class, $plugin . 'Model/Datasource/Session'); if (!class_exists($class)) { - throw new CakeSessionException(__('Could not load %s to handle the session.', $class)); + throw new CakeSessionException(__d('cake_dev', 'Could not load %s to handle the session.', $class)); } $handler = new $class(); if ($handler instanceof CakeSessionHandlerInterface) { return $handler; } - throw new CakeSessionException(__('Chosen SessionHandler does not implement CakeSessionHandlerInterface it cannot be used with an engine key.')); + throw new CakeSessionException(__d('cake_dev', 'Chosen SessionHandler does not implement CakeSessionHandlerInterface it cannot be used with an engine key.')); } /** @@ -630,14 +627,14 @@ class CakeSession { self::$valid = false; return false; } - if (self::read('Config')) { + if ($config = self::read('Config')) { $sessionConfig = Configure::read('Session'); if (self::_validAgentAndTime()) { - $time = self::read('Config.time'); + $time = $config['time']; self::write('Config.time', self::$sessionTime); if (isset($sessionConfig['autoRegenerate']) && $sessionConfig['autoRegenerate'] === true) { - $check = self::read('Config.countdown'); + $check = $config['countdown']; $check -= 1; self::write('Config.countdown', $check); diff --git a/cake/libs/model/datasources/datasource.php b/lib/Cake/Model/Datasource/DataSource.php similarity index 75% rename from cake/libs/model/datasources/datasource.php rename to lib/Cake/Model/Datasource/DataSource.php index d38e8bf10..8f89e37de 100644 --- a/cake/libs/model/datasources/datasource.php +++ b/lib/Cake/Model/Datasource/DataSource.php @@ -32,112 +32,6 @@ class DataSource extends Object { */ public $connected = false; -/** - * Print full query debug info? - * - * @var boolean - * @access public - */ - public $fullDebug = false; - -/** - * Error description of last query - * - * @var unknown_type - * @access public - */ - public $error = null; - -/** - * String to hold how many rows were affected by the last SQL operation. - * - * @var string - * @access public - */ - public $affected = null; - -/** - * Number of rows in current resultset - * - * @var int - * @access public - */ - public $numRows = null; - -/** - * Time the last query took - * - * @var int - * @access public - */ - public $took = null; - -/** - * The starting character that this DataSource uses for quoted identifiers. - * - * @var string - * @access public - */ - public $startQuote = null; - -/** - * The ending character that this DataSource uses for quoted identifiers. - * - * @var string - * @access public - */ - public $endQuote = null; - -/** - * Result - * - * @var array - * @access protected - */ - protected $_result = null; - -/** - * Queries count. - * - * @var int - * @access protected - */ - protected $_queriesCnt = 0; - -/** - * Total duration of all queries. - * - * @var unknown_type - * @access protected - */ - protected $_queriesTime = null; - -/** - * Log of queries executed by this DataSource - * - * @var unknown_type - * @access protected - */ - protected $_queriesLog = array(); - -/** - * Maximum number of items in query log - * - * This is to prevent query log taking over too much memory. - * - * @var int Maximum number of queries in the queries log. - * @access protected - */ - protected $_queriesLogMax = 200; - -/** - * Caches serialzed results of executed queries - * - * @var array Maximum number of queries in the queries log. - * @access protected - */ - protected $_queryCache = array(); - /** * The default configuration of a specific DataSource * @@ -162,14 +56,6 @@ class DataSource extends Object { */ protected $_sources = null; -/** - * A reference to the physical connection of this DataSource - * - * @var array - * @access public - */ - public $connection = null; - /** * The DataSource configuration * @@ -178,14 +64,6 @@ class DataSource extends Object { */ public $config = array(); -/** - * The DataSource configuration key name - * - * @var string - * @access public - */ - public $configKeyName = null; - /** * Whether or not this DataSource is in the middle of a transaction * @@ -238,21 +116,7 @@ class DataSource extends Object { Cache::write($key, $data, '_cake_model_'); } - $this->_sources = $sources; - return $sources; - } - -/** - * Convenience method for DboSource::listSources(). Returns source names in lowercase. - * - * @param boolean $reset Whether or not the source list should be reset. - * @return array Array of sources available in this datasource - */ - public function sources($reset = false) { - if ($reset === true) { - $this->_sources = null; - } - return array_map('strtolower', $this->listSources()); + return $this->_sources = $sources; } /** @@ -261,7 +125,7 @@ class DataSource extends Object { * @param Model $model * @return array Array of Metadata for the $model */ - public function describe($model) { + public function describe(Model $model) { if ($this->cacheSources === false) { return null; } @@ -326,7 +190,7 @@ class DataSource extends Object { * @param array $values An Array of values to save. * @return boolean success */ - public function create($model, $fields = null, $values = null) { + public function create(Model $model, $fields = null, $values = null) { return false; } @@ -339,7 +203,7 @@ class DataSource extends Object { * @param array $queryData An array of query data used to find the data you want * @return mixed */ - public function read($model, $queryData = array()) { + public function read(Model $model, $queryData = array()) { return false; } @@ -353,7 +217,7 @@ class DataSource extends Object { * @param array $values Array of values to be update $fields to. * @return boolean Success */ - public function update($model, $fields = null, $values = null) { + public function update(Model $model, $fields = null, $values = null) { return false; } @@ -365,7 +229,7 @@ class DataSource extends Object { * @param Model $model The model class having record(s) deleted * @param mixed $id Primary key of the model */ - public function delete($model, $id = null) { + public function delete(Model $model, $id = null) { if ($id == null) { $id = $model->id; } @@ -412,20 +276,6 @@ class DataSource extends Object { return true; } -/** - * Returns true if the DataSource supports the given interface (method) - * - * @param string $interface The name of the interface (method) - * @return boolean True on success - */ - public function isInterfaceSupported($interface) { - static $methods = false; - if ($methods === false) { - $methods = array_map('strtolower', get_class_methods($this)); - } - return in_array(strtolower($interface), $methods); - } - /** * Sets the configuration for the DataSource. * Merges the $config information with the _baseConfig and the existing $config property. @@ -479,11 +329,12 @@ class DataSource extends Object { * @access public * @todo Remove and refactor $assocData, ensure uses of the method have the param removed too. */ - function insertQueryData($query, $data, $association, $assocData, &$model, &$linkModel, $stack) { + function insertQueryData($query, $data, $association, $assocData, Model $model, Model $linkModel, $stack) { $keys = array('{$__cakeID__$}', '{$__cakeForeignKey__$}'); foreach ($keys as $key) { $val = null; + $type = null; if (strpos($query, $key) !== false) { switch ($key) { @@ -507,6 +358,7 @@ class DataSource extends Object { $val = ''; } } + $type = $model->getColumnType($model->primaryKey); break; case '{$__cakeForeignKey__$}': foreach ($model->associations() as $id => $name) { @@ -514,6 +366,8 @@ class DataSource extends Object { if ($assocName === $association) { if (isset($assoc['foreignKey'])) { $foreignKey = $assoc['foreignKey']; + $assocModel = $model->$assocName; + $type = $assocModel->getColumnType($assocModel->primaryKey); if (isset($data[$model->alias][$foreignKey])) { $val = $data[$model->alias][$foreignKey]; @@ -542,7 +396,7 @@ class DataSource extends Object { if (empty($val) && $val !== '0') { return false; } - $query = str_replace($key, $this->value($val, $model->getColumnType($model->primaryKey)), $query); + $query = str_replace($key, $this->value($val, $type), $query); } } return $query; @@ -555,7 +409,7 @@ class DataSource extends Object { * @param string $key Key name to make * @return string Key name for model. */ - public function resolveKey($model, $key) { + public function resolveKey(Model $model, $key) { return $model->alias . $key; } @@ -566,8 +420,7 @@ class DataSource extends Object { */ public function __destruct() { if ($this->_transactionStarted) { - $null = null; - $this->rollback($null); + $this->rollback(); } if ($this->connected) { $this->close(); diff --git a/cake/libs/model/datasources/dbo/dbo_mssql.php b/lib/Cake/Model/Datasource/Database/Mssql.php similarity index 99% rename from cake/libs/model/datasources/dbo/dbo_mssql.php rename to lib/Cake/Model/Datasource/Database/Mssql.php index 91db76c5f..b09e58a77 100644 --- a/cake/libs/model/datasources/dbo/dbo_mssql.php +++ b/lib/Cake/Model/Datasource/Database/Mssql.php @@ -116,7 +116,7 @@ class DboMssql extends DboSource { function __construct($config, $autoConnect = true) { if ($autoConnect) { if (!function_exists('mssql_min_message_severity')) { - trigger_error(__("PHP SQL Server interface is not installed, cannot continue. For troubleshooting information, see http://php.net/mssql/"), E_USER_WARNING); + trigger_error(__d('cake_dev', "PHP SQL Server interface is not installed, cannot continue. For troubleshooting information, see http://php.net/mssql/"), E_USER_WARNING); } mssql_min_message_severity(15); mssql_min_error_severity(2); diff --git a/cake/libs/model/datasources/dbo/dbo_mysql.php b/lib/Cake/Model/Datasource/Database/Mysql.php similarity index 91% rename from cake/libs/model/datasources/dbo/dbo_mysql.php rename to lib/Cake/Model/Datasource/Database/Mysql.php index 1d6052f6a..b7b9da0eb 100644 --- a/cake/libs/model/datasources/dbo/dbo_mysql.php +++ b/lib/Cake/Model/Datasource/Database/Mysql.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('DboSource', 'Model/Datasource'); + /** * MySQL DBO driver object * @@ -24,7 +26,7 @@ * * @package cake.libs.model.datasources.dbo */ -class DboMysql extends DboSource { +class Mysql extends DboSource { /** * Datasource description @@ -148,14 +150,14 @@ class DboMysql extends DboSource { $flags[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . $config['encoding']; } $this->_connection = new PDO( - "mysql:{$config['host']};port={$config['port']};dbname={$config['database']}", + "mysql:host={$config['host']};port={$config['port']};dbname={$config['database']}", $config['login'], $config['password'], $flags ); $this->connected = true; } catch (PDOException $e) { - $this->errors[] = $e->getMessage(); + throw new MissingConnectionException(array('class' => $e->getMessage())); } $this->_useAlias = (bool)version_compare($this->getVersion(), "4.1", ">="); @@ -182,7 +184,7 @@ class DboMysql extends DboSource { if ($cache != null) { return $cache; } - $result = $this->_execute('SHOW TABLES FROM ' . $this->config['database']); + $result = $this->_execute('SHOW TABLES FROM ' . $this->name($this->config['database'])); if (!$result) { $result->closeCursor(); @@ -209,16 +211,19 @@ class DboMysql extends DboSource { $this->map = array(); $numFields = $results->columnCount(); $index = 0; - $j = 0; - while ($j < $numFields) { - $column = $results->getColumnMeta($j); - if (!empty($column['table']) && strpos($column['name'], $this->virtualFieldSeparator) === false) { - $this->map[$index++] = array($column['table'], $column['name']); + while ($numFields-- > 0) { + $column = $results->getColumnMeta($index); + if (empty($column['native_type'])) { + $type = ($column['len'] == 1) ? 'boolean' : 'string'; } else { - $this->map[$index++] = array(0, $column['name']); + $type = $column['native_type']; + } + if (!empty($column['table']) && strpos($column['name'], $this->virtualFieldSeparator) === false) { + $this->map[$index++] = array($column['table'], $column['name'], $type); + } else { + $this->map[$index++] = array(0, $column['name'], $type); } - $j++; } } @@ -231,14 +236,16 @@ class DboMysql extends DboSource { if ($row = $this->_result->fetch()) { $resultRow = array(); foreach ($this->map as $col => $meta) { - list($table, $column) = $meta; + list($table, $column, $type) = $meta; $resultRow[$table][$column] = $row[$col]; + if ($type === 'boolean' && !is_null($row[$col])) { + $resultRow[$table][$column] = $this->boolean($resultRow[$table][$column]); + } } return $resultRow; - } else { - $this->_result->closeCursor(); - return false; } + $this->_result->closeCursor(); + return false; } /** @@ -290,11 +297,14 @@ class DboMysql extends DboSource { } $fields = false; $cols = $this->_execute('SHOW FULL COLUMNS FROM ' . $this->fullTableName($model)); + if (!$cols) { + throw new CakeException(__d('cake_dev', 'Could not describe table for %s', $model->name)); + } foreach ($cols as $column) { $fields[$column->Field] = array( 'type' => $this->column($column->Type), - 'null' => ($column->Null == 'YES' ? true : false), + 'null' => ($column->Null === 'YES' ? true : false), 'default' => $column->Default, 'length' => $this->length($column->Type), ); @@ -399,7 +409,7 @@ class DboMysql extends DboSource { * @param string $enc Database encoding */ function setEncoding($enc) { - return $this->_execute('SET NAMES ' . $enc) != false; + return $this->_execute('SET NAMES ' . $enc) !== false; } /** @@ -489,7 +499,7 @@ class DboMysql extends DboSource { } $colList = array_merge($colList, $this->_alterIndexes($curTable, $indexes)); $colList = array_merge($colList, $this->_alterTableParameters($curTable, $tableParameters)); - $out .= "\t" . join(",\n\t", $colList) . ";\n\n"; + $out .= "\t" . implode(",\n\t", $colList) . ";\n\n"; } } return $out; @@ -506,7 +516,7 @@ class DboMysql extends DboSource { function dropSchema(CakeSchema $schema, $table = null) { $out = ''; foreach ($schema->tables as $curTable => $columns) { - if (!$table || $table == $curTable) { + if (!$table || $table === $curTable) { $out .= 'DROP TABLE IF EXISTS ' . $this->fullTableName($curTable) . ";\n"; } } @@ -573,7 +583,7 @@ class DboMysql extends DboSource { /** * Returns an detailed array of sources (tables) in the database. * - * @param string $name Table name to get parameters + * @param string $name Table name to get parameters * @return array Array of tablenames in the database */ function listDetailedSources($name = null) { @@ -601,7 +611,7 @@ class DboMysql extends DboSource { } } $result->closeCursor(); - if (is_string($name)) { + if (is_string($name) && isset($tables[$name])) { return $tables[$name]; } return $tables; @@ -618,7 +628,7 @@ class DboMysql extends DboSource { if (is_array($real)) { $col = $real['name']; if (isset($real['limit'])) { - $col .= '('.$real['limit'].')'; + $col .= '(' . $real['limit'] . ')'; } return $col; } @@ -632,19 +642,19 @@ class DboMysql extends DboSource { if (in_array($col, array('date', 'time', 'datetime', 'timestamp'))) { return $col; } - if (($col == 'tinyint' && $limit == 1) || $col == 'boolean') { + if (($col === 'tinyint' && $limit == 1) || $col === 'boolean') { return 'boolean'; } if (strpos($col, 'int') !== false) { return 'integer'; } - if (strpos($col, 'char') !== false || $col == 'tinytext') { + if (strpos($col, 'char') !== false || $col === 'tinytext') { return 'string'; } if (strpos($col, 'text') !== false) { return 'text'; } - if (strpos($col, 'blob') !== false || $col == 'binary') { + if (strpos($col, 'blob') !== false || $col === 'binary') { return 'binary'; } if (strpos($col, 'float') !== false || strpos($col, 'double') !== false || strpos($col, 'decimal') !== false) { diff --git a/cake/libs/model/datasources/dbo/dbo_oracle.php b/lib/Cake/Model/Datasource/Database/Oracle.php similarity index 99% rename from cake/libs/model/datasources/dbo/dbo_oracle.php rename to lib/Cake/Model/Datasource/Database/Oracle.php index 4b4444211..76dfe1e1c 100644 --- a/cake/libs/model/datasources/dbo/dbo_oracle.php +++ b/lib/Cake/Model/Datasource/Database/Oracle.php @@ -571,7 +571,7 @@ class DboOracle extends DboSource { */ function constraint($action, $table) { if (empty($table)) { - trigger_error(__('Must specify table to operate on constraints')); + trigger_error(__d('cake_dev', 'Must specify table to operate on constraints')); } $table = strtoupper($table); @@ -629,7 +629,7 @@ class DboOracle extends DboSource { return $constraints; break; default: - trigger_error(__('DboOracle::constraint() accepts only enable, disable, or list')); + trigger_error(__d('cake_dev', 'DboOracle::constraint() accepts only enable, disable, or list')); } } return true; @@ -976,7 +976,7 @@ class DboOracle extends DboSource { if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) { if (!isset($resultSet) || !is_array($resultSet)) { if (Configure::read('debug') > 0) { - echo '

' . __('SQL Error in model %s:', $model->alias) . ' '; + echo '
' . __d('cake_dev', 'SQL Error in model %s:', $model->alias) . ' '; if (isset($this->error) && $this->error != null) { echo $this->error; } diff --git a/cake/libs/model/datasources/dbo/dbo_postgres.php b/lib/Cake/Model/Datasource/Database/Postgres.php similarity index 97% rename from cake/libs/model/datasources/dbo/dbo_postgres.php rename to lib/Cake/Model/Datasource/Database/Postgres.php index e5e12d2bc..b964d73ff 100644 --- a/cake/libs/model/datasources/dbo/dbo_postgres.php +++ b/lib/Cake/Model/Datasource/Database/Postgres.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('DboSource', 'Model/Datasource'); + /** * PostgreSQL layer for DBO. * @@ -24,7 +26,7 @@ * * @package cake.libs.model.datasources.dbo */ -class DboPostgres extends DboSource { +class Postgres extends DboSource { /** * Driver description @@ -130,7 +132,7 @@ class DboPostgres extends DboSource { $this->_execute('SET search_path TO ' . $config['schema']); } } catch (PDOException $e) { - $this->errors[] = $e->getMessage(); + throw new MissingConnectionException(array('class' => $e->getMessage())); } return $this->connected; @@ -162,7 +164,6 @@ class DboPostgres extends DboSource { $result = $this->_execute($sql, array($schema)); if (!$result) { - $result->closeCursor(); return array(); } else { $tables = array(); @@ -241,6 +242,9 @@ class DboPostgres extends DboSource { $this->_sequenceMap[$table][$c->default] = $seq[1]; } } + if ($fields[$c->name]['type'] == 'boolean' && !empty($fields[$c->name]['default'])) { + $fields[$c->name]['default'] = constant($fields[$c->name]['default']); + } } $this->__cacheDescription($table, $fields); } @@ -248,7 +252,9 @@ class DboPostgres extends DboSource { $this->_sequenceMap[$table][$model->primaryKey] = $model->sequence; } - $cols->closeCursor(); + if ($cols) { + $cols->closeCursor(); + } return $fields; } @@ -706,7 +712,7 @@ class DboPostgres extends DboSource { switch ($type) { case 'bool': - $resultRow[$table][$column] = $this->boolean($row[$index], false); + $resultRow[$table][$column] = is_null($row[$index]) ? null : $this->boolean($row[$index]); break; case 'binary': case 'bytea': @@ -731,7 +737,7 @@ class DboPostgres extends DboSource { * @param boolean $quote true to quote a boolean to be used in a query, flase to return the boolean value * @return boolean Converted boolean value */ - function boolean($data, $quote = true) { + function boolean($data, $quote = false) { switch (true) { case ($data === true || $data === false): $result = $data; @@ -753,7 +759,7 @@ class DboPostgres extends DboSource { if ($quote) { return ($result) ? 'TRUE' : 'FALSE'; } - return (int) $result; + return (bool) $result; } /** diff --git a/cake/libs/model/datasources/dbo/dbo_sqlite.php b/lib/Cake/Model/Datasource/Database/Sqlite.php similarity index 94% rename from cake/libs/model/datasources/dbo/dbo_sqlite.php rename to lib/Cake/Model/Datasource/Database/Sqlite.php index 66859261e..d4daa3aac 100644 --- a/cake/libs/model/datasources/dbo/dbo_sqlite.php +++ b/lib/Cake/Model/Datasource/Database/Sqlite.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('DboSource', 'Model/Datasource'); + /** * DBO implementation for the SQLite3 DBMS. * @@ -24,7 +26,7 @@ * * @package cake.libs.model.datasources.dbo */ -class DboSqlite extends DboSource { +class Sqlite extends DboSource { /** * Datasource Description @@ -114,9 +116,8 @@ class DboSqlite extends DboSource { $this->_connection = new PDO('sqlite:' . $config['database'], null, null, $flags); $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->connected = true; - } - catch(PDOException $e) { - $this->errors[] = $e->getMessage(); + } catch(PDOException $e) { + throw new MissingConnectionException(array('class' => $e->getMessage())); } return $this->connected; } @@ -230,7 +231,7 @@ class DboSqlite extends DboSource { */ function truncate($table) { $this->_execute('DELETE FROM sqlite_sequence where name=' . $this->fullTableName($table)); - return $this->execute('DELETE FROM ' . $this->fullTableName($table)); + return $this->execute('DELETE FROM ' . $this->fullTableName($table)); } /** @@ -285,7 +286,7 @@ class DboSqlite extends DboSource { // so try to figure it out based on the querystring $querystring = $results->queryString; if (stripos($querystring, 'SELECT') === 0) { - $last = stripos($querystring, 'FROM'); + $last = strripos($querystring, 'FROM'); if ($last !== false) { $selectpart = substr($querystring, 7, $last - 8); $selects = explode(',', $selectpart); @@ -308,11 +309,19 @@ class DboSqlite extends DboSource { $columnName = str_ireplace('DISTINCT', '', $columnName); } + $metaType = false; + try { + $metaData = (array)$results->getColumnMeta($j); + if (!empty($metaData['sqlite:decl_type'])) { + $metaType = trim($metaData['sqlite:decl_type']); + } + } catch (Exception $e) {} + if (strpos($columnName, '.')) { $parts = explode('.', $columnName); - $this->map[$index++] = array(trim($parts[0]), trim($parts[1])); + $this->map[$index++] = array(trim($parts[0]), trim($parts[1]), $metaType); } else { - $this->map[$index++] = array(0, $columnName); + $this->map[$index++] = array(0, $columnName, $metaType); } $j++; } @@ -327,8 +336,11 @@ class DboSqlite extends DboSource { if ($row = $this->_result->fetch()) { $resultRow = array(); foreach ($this->map as $col => $meta) { - list($table, $column) = $meta; + list($table, $column, $type) = $meta; $resultRow[$table][$column] = $row[$col]; + if ($type == 'boolean' && !is_null($row[$col])) { + $resultRow[$table][$column] = $this->boolean($resultRow[$table][$column]); + } } return $resultRow; } else { @@ -375,12 +387,12 @@ class DboSqlite extends DboSource { extract($column); if (empty($name) || empty($type)) { - trigger_error('Column name or type not defined in schema', E_USER_WARNING); + trigger_error(__d('cake_dev', 'Column name or type not defined in schema'), E_USER_WARNING); return null; } if (!isset($this->columns[$type])) { - trigger_error(__('Column type %s does not exist', $type), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Column type %s does not exist', $type), E_USER_WARNING); return null; } @@ -461,7 +473,7 @@ class DboSqlite extends DboSource { $table = $this->fullTableName($model); if ($table) { $indexes = $this->query('PRAGMA index_list(' . $table . ')'); - + if (is_bool($indexes)) { return array(); } @@ -542,4 +554,4 @@ class DboSqlite extends DboSource { } return $out; } -} +} \ No newline at end of file diff --git a/cake/libs/model/datasources/dbo_source.php b/lib/Cake/Model/Datasource/DboSource.php old mode 100755 new mode 100644 similarity index 86% rename from cake/libs/model/datasources/dbo_source.php rename to lib/Cake/Model/Datasource/DboSource.php index 717e5ca92..e46d77fff --- a/cake/libs/model/datasources/dbo_source.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -16,7 +16,10 @@ * @since CakePHP(tm) v 0.10.0.1076 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'String'); + +App::uses('DataSource', 'Model/Datasource'); +App::uses('String', 'Utility'); +App::uses('View', 'View'); /** * DboSource @@ -68,7 +71,129 @@ class DboSource extends DataSource { * @var boolean. * @access public */ - public $cacheMethods = true ; + public $cacheMethods = true; + +/** + * Print full query debug info? + * + * @var boolean + * @access public + */ + public $fullDebug = false; + +/** + * Error description of last query + * + * @var unknown_type + * @access public + */ + public $error = null; + +/** + * String to hold how many rows were affected by the last SQL operation. + * + * @var string + * @access public + */ + public $affected = null; + +/** + * Number of rows in current resultset + * + * @var int + * @access public + */ + public $numRows = null; + +/** + * Time the last query took + * + * @var int + * @access public + */ + public $took = null; + +/** + * Result + * + * @var array + * @access protected + */ + protected $_result = null; + +/** + * Queries count. + * + * @var int + * @access protected + */ + protected $_queriesCnt = 0; + +/** + * Total duration of all queries. + * + * @var unknown_type + * @access protected + */ + protected $_queriesTime = null; + +/** + * Log of queries executed by this DataSource + * + * @var unknown_type + * @access protected + */ + protected $_queriesLog = array(); + +/** + * Maximum number of items in query log + * + * This is to prevent query log taking over too much memory. + * + * @var int Maximum number of queries in the queries log. + * @access protected + */ + protected $_queriesLogMax = 200; + +/** + * Caches serialzed results of executed queries + * + * @var array Maximum number of queries in the queries log. + * @access protected + */ + protected $_queryCache = array(); + +/** + * A reference to the physical connection of this DataSource + * + * @var array + * @access public + */ + public $connection = null; + +/** + * The DataSource configuration key name + * + * @var string + * @access public + */ + public $configKeyName = null; + +/** + * The starting character that this DataSource uses for quoted identifiers. + * + * @var string + * @access public + */ + public $startQuote = null; + +/** + * The ending character that this DataSource uses for quoted identifiers. + * + * @var string + * @access public + */ + public $endQuote = null; /** * Bypass automatic adding of joined fields/associations. @@ -142,12 +267,10 @@ class DboSource extends DataSource { parent::__construct($config); $this->fullDebug = Configure::read('debug') > 1; if (!$this->enabled()) { - return false; + return; } if ($autoConnect) { - return $this->connect(); - } else { - return true; + $this->connect(); } } @@ -176,7 +299,7 @@ class DboSource extends DataSource { } unset($this->_connection); $this->connected = false; - return !$this->connected; + return true; } /** @@ -188,22 +311,20 @@ class DboSource extends DataSource { return $this->_connection; } - /** * Returns a quoted and escaped string of $data for use in an SQL statement. * * @param string $data String to be prepared for use in an SQL statement * @param string $column The column into which this data will be inserted - * @param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided * @return string Quoted and escaped data */ - function value($data, $column = null, $safe = false) { + function value($data, $column = null) { if (is_array($data) && !empty($data)) { return array_map( array(&$this, 'value'), - $data, array_fill(0, count($data), $column), array_fill(0, count($data), $safe) + $data, array_fill(0, count($data), $column) ); - } elseif (is_object($data) && isset($data->type)) { + } elseif (is_object($data) && isset($data->type, $data->value)) { if ($data->type == 'identifier') { return $this->name($data->value); } elseif ($data->type == 'expression') { @@ -211,7 +332,7 @@ class DboSource extends DataSource { } } elseif (in_array($data, array('{$__cakeID__$}', '{$__cakeForeignKey__$}'), true)) { return $data; - } + } if ($data === null || (is_array($data) && empty($data))) { return 'NULL'; @@ -226,7 +347,7 @@ class DboSource extends DataSource { return $this->_connection->quote($data, PDO::PARAM_LOB); break; case 'boolean': - return $this->_connection->quote($this->boolean($data), PDO::PARAM_BOOL); + return $this->_connection->quote($this->boolean($data, true), PDO::PARAM_BOOL); break; case 'string': case 'text': @@ -305,7 +426,7 @@ class DboSource extends DataSource { * @return mixed Resource or object representing the result set, or false on failure */ public function execute($sql, $options = array(), $params = array()) { - $options = $options + array('log' => $this->fullDebug); + $options += array('log' => $this->fullDebug); $this->error = null; $t = microtime(true); @@ -361,7 +482,6 @@ class DboSource extends DataSource { $this->error = $e->getMessage(); return false; } - } /** @@ -382,10 +502,9 @@ class DboSource extends DataSource { * Returns number of affected rows in previous database operation. If no previous operation exists, * this returns false. * - * @param string $source * @return integer Number of affected rows */ - function lastAffected($source = null) { + function lastAffected() { if ($this->hasResult()) { return $this->_result->rowCount(); } @@ -396,11 +515,10 @@ class DboSource extends DataSource { * Returns number of rows in previous resultset. If no previous resultset exists, * this returns false. * - * @param string $source * @return integer Number of rows in resultset */ - function lastNumRows($source = null) { - return $this->lastAffected($source); + function lastNumRows() { + return $this->lastAffected(); } /** @@ -416,18 +534,17 @@ class DboSource extends DataSource { $page = null; $recursive = null; - if (count($args) == 1) { + if (count($args) === 1) { return $this->fetchAll($args[0]); - } elseif (count($args) > 1 && (strpos($args[0], 'findBy') === 0 || strpos($args[0], 'findAllBy') === 0)) { $params = $args[1]; - if (strpos($args[0], 'findBy') === 0) { + if (substr($args[0], 0, 6) === 'findBy') { $all = false; - $field = Inflector::underscore(preg_replace('/^findBy/i', '', $args[0])); + $field = Inflector::underscore(substr($args[0], 6)); } else { $all = true; - $field = Inflector::underscore(preg_replace('/^findAllBy/i', '', $args[0])); + $field = Inflector::underscore(substr($args[0], 9)); } $or = (strpos($field, '_or_') !== false); @@ -454,8 +571,7 @@ class DboSource extends DataSource { $conditions = array(); foreach ($field as $f) { - $conditions[$args[2]->alias . '.' . $f] = $params[$c]; - $c++; + $conditions[$args[2]->alias . '.' . $f] = $params[$c++]; } if ($or) { @@ -505,16 +621,14 @@ class DboSource extends DataSource { * @return array The fetched row as an array */ public function fetchRow($sql = null) { - if (!empty($sql) && is_string($sql) && strlen($sql) > 5) { - if (!$this->execute($sql)) { - return null; - } + if (is_string($sql) && strlen($sql) > 5 && !$this->execute($sql)) { + return null; } if ($this->hasResult()) { $this->resultSet($this->_result); $resultRow = $this->fetchResult(); - if (!empty($resultRow)) { + if (isset($resultRow[0])) { $this->fetchVirtualField($resultRow); } return $resultRow; @@ -545,8 +659,7 @@ class DboSource extends DataSource { $options['cache'] = $params; $params = array(); } - $defaults = array('cache' => true); - $options = $options + $defaults; + $options += array('cache' => true); $cache = $options['cache']; if ($cache && ($cached = $this->getQueryCache($sql, $params)) !== false) { return $cached; @@ -554,13 +667,17 @@ class DboSource extends DataSource { if ($result = $this->execute($sql, array(), $params)) { $out = array(); - $first = $this->fetchRow(); - if ($first != null) { - $out[] = $first; - } - while ($this->hasResult() && $item = $this->fetchResult()) { - $this->fetchVirtualField($item); - $out[] = $item; + if ($this->hasResult()) { + $first = $this->fetchRow(); + if ($first != null) { + $out[] = $first; + } + while ($item = $this->fetchResult()) { + if (isset($item[0])) { + $this->fetchVirtualField($item); + } + $out[] = $item; + } } if (!is_bool($result) && $cache) { @@ -571,9 +688,17 @@ class DboSource extends DataSource { return $this->_result; } return $out; - } else { - return false; } + return false; + } + +/** + * Fetches the next row from the current result set + * + * @return boolean + */ + public function fetchResult() { + return false; } /** @@ -614,11 +739,10 @@ class DboSource extends DataSource { */ public function field($name, $sql) { $data = $this->fetchRow($sql); - if (!isset($data[$name]) || empty($data[$name])) { + if (empty($data[$name])) { return false; - } else { - return $data[$name]; } + return $data[$name]; } /** @@ -703,7 +827,7 @@ class DboSource extends DataSource { ); } if ( - preg_match('/^([\w-]+(\.[\w-]+|\(.*\))*)\s+' . preg_quote($this->alias) . '\s*([\w-]+)$/', $data, $matches + preg_match('/^([\w-]+(\.[\w-]+|\(.*\))*)\s+' . preg_quote($this->alias) . '\s*([\w-]+)$/i', $data, $matches )) { return $this->cacheMethod( __FUNCTION__, $cacheKey, @@ -768,7 +892,6 @@ class DboSource extends DataSource { return; } if (PHP_SAPI != 'cli') { - App::import('Core', 'View'); $controller = null; $View = new View($controller, false); $View->set('logs', array($this->configKeyName => $log)); @@ -790,7 +913,7 @@ class DboSource extends DataSource { $this->_queriesCnt++; $this->_queriesTime += $this->took; $this->_queriesLog[] = array( - 'query' => $sql, + 'query' => $sql, 'error' => $this->error, 'affected' => $this->affected, 'numRows' => $this->numRows, @@ -818,11 +941,11 @@ class DboSource extends DataSource { if (Configure::read('debug') > 0) { $out = null; if ($error) { - trigger_error('' . __('SQL Error:') . " {$this->error}", E_USER_WARNING); + trigger_error('' . __d('cake_dev', 'SQL Error:') . " {$this->error}", E_USER_WARNING); } else { - $out = ('[' . __('Aff:%s Num:%s Took:%sms', $this->affected, $this->numRows, $this->took) . ']'); + $out = ('[' . __d('cake_dev', 'Aff:%s Num:%s Took:%sms', $this->affected, $this->numRows, $this->took) . ']'); } - pr(sprintf('

' . __('Query:') . ' %s %s

', $sql, $out)); + pr(sprintf('

' . __d('cake_dev', 'Query:') . ' %s %s

', $sql, $out)); } } @@ -891,10 +1014,9 @@ class DboSource extends DataSource { $model->setInsertID($id); $model->id = $id; return true; - } else { - $model->onError(); - return false; } + $model->onError(); + return false; } /** @@ -914,7 +1036,6 @@ class DboSource extends DataSource { $array = array(); $linkedModels = array(); $this->__bypass = false; - $this->__booleans = array(); if ($recursive === null && isset($queryData['recursive'])) { $recursive = $queryData['recursive']; @@ -936,7 +1057,7 @@ class DboSource extends DataSource { if ($model->recursive == -1) { $_associations = array(); - } else if ($model->recursive == 0) { + } elseif ($model->recursive == 0) { unset($_associations[2], $_associations[3]); } @@ -945,7 +1066,8 @@ class DboSource extends DataSource { $linkModel = $model->{$assoc}; $external = isset($assocData['external']); - if ($model->useDbConfig == $linkModel->useDbConfig) { + $linkModel->getDataSource(); + if ($model->useDbConfig === $linkModel->useDbConfig) { if (true === $this->generateAssociationQuery($model, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null)) { $linkedModels[$type . '/' . $assoc] = true; } @@ -953,29 +1075,28 @@ class DboSource extends DataSource { } } - $query = trim($this->generateAssociationQuery($model, $null, null, null, null, $queryData, false, $null)); + $query = trim($this->generateAssociationQuery($model, null, null, null, null, $queryData, false, $null)); $resultSet = $this->fetchAll($query, $model->cacheQueries); - if ($resultSet === false) { $model->onError(); return false; } - $filtered = $this->__filterResults($resultSet, $model); + $filtered = $this->_filterResults($resultSet, $model); if ($model->recursive > -1) { foreach ($_associations as $type) { foreach ($model->{$type} as $assoc => $assocData) { $linkModel = $model->{$assoc}; - if (empty($linkedModels[$type . '/' . $assoc])) { - if ($model->useDbConfig == $linkModel->useDbConfig) { + if (!isset($linkedModels[$type . '/' . $assoc])) { + if ($model->useDbConfig === $linkModel->useDbConfig) { $db = $this; } else { $db = ConnectionManager::getDataSource($linkModel->useDbConfig); } - } elseif ($model->recursive > 1 && ($type == 'belongsTo' || $type == 'hasOne')) { + } elseif ($model->recursive > 1 && ($type === 'belongsTo' || $type === 'hasOne')) { $db = $this; } @@ -985,12 +1106,12 @@ class DboSource extends DataSource { unset($db); if ($type === 'hasMany') { - $filtered []= $assoc; + $filtered[] = $assoc; } } } } - $this->__filterResults($resultSet, $model, $filtered); + $this->_filterResults($resultSet, $model, $filtered); } if (!is_null($recursive)) { @@ -1006,31 +1127,24 @@ class DboSource extends DataSource { * @param object $model Instance of model to operate against * @param array $filtered List of classes already filtered, to be skipped * @return array Array of results that have been filtered through $model->afterFind - * @access private */ - function __filterResults(&$results, &$model, $filtered = array()) { + protected function _filterResults(&$results, Model $model, $filtered = array()) { + $current = current($results); + if (!is_array($current)) { + return array(); + } + $keys = array_diff(array_keys($current), $filtered, array($model->alias)); $filtering = array(); - $count = count($results); - - for ($i = 0; $i < $count; $i++) { - if (is_array($results[$i])) { - $classNames = array_keys($results[$i]); - $count2 = count($classNames); - - for ($j = 0; $j < $count2; $j++) { - $className = $classNames[$j]; - if ($model->alias != $className && !in_array($className, $filtered)) { - if (!in_array($className, $filtering)) { - $filtering[] = $className; - } - - if (isset($model->{$className}) && is_object($model->{$className})) { - $data = $model->{$className}->afterFind(array(array($className => $results[$i][$className])), false); - } - if (isset($data[0][$className])) { - $results[$i][$className] = $data[0][$className]; - } - } + foreach ($keys as $className) { + if (!isset($model->{$className}) || !is_object($model->{$className})) { + continue; + } + $linkedModel = $model->{$className}; + $filtering[] = $className; + foreach ($results as &$result) { + $data = $linkedModel->afterFind(array(array($className => $result[$className])), false); + if (isset($data[0][$className])) { + $result[$className] = $data[0][$className]; } } } @@ -1053,9 +1167,9 @@ class DboSource extends DataSource { */ public function queryAssociation($model, &$linkModel, $type, $association, $assocData, &$queryData, $external = false, &$resultSet, $recursive, $stack) { if ($query = $this->generateAssociationQuery($model, $linkModel, $type, $association, $assocData, $queryData, $external, $resultSet)) { - if (!isset($resultSet) || !is_array($resultSet)) { + if (!is_array($resultSet)) { if (Configure::read('debug') > 0) { - echo '
' . __('SQL Error in model %s:', $model->alias) . ' '; + echo '
' . __d('cake_dev', 'SQL Error in model %s:', $model->alias) . ' '; if (isset($this->error) && $this->error != null) { echo $this->error; } @@ -1063,12 +1177,11 @@ class DboSource extends DataSource { } return null; } - $count = count($resultSet); if ($type === 'hasMany' && empty($assocData['limit']) && !empty($assocData['foreignKey'])) { $ins = $fetch = array(); - for ($i = 0; $i < $count; $i++) { - if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) { + foreach ($resultSet as &$result) { + if ($in = $this->insertQueryData('{$__cakeID__$}', $result, $association, $assocData, $model, $linkModel, $stack)) { $ins[] = $in; } } @@ -1096,12 +1209,12 @@ class DboSource extends DataSource { } } } - $this->__filterResults($fetch, $model); - return $this->__mergeHasMany($resultSet, $fetch, $association, $model, $linkModel, $recursive); + $this->_filterResults($fetch, $model); + return $this->__mergeHasMany($resultSet, $fetch, $association, $model, $linkModel); } elseif ($type === 'hasAndBelongsToMany') { $ins = $fetch = array(); - for ($i = 0; $i < $count; $i++) { - if ($in = $this->insertQueryData('{$__cakeID__$}', $resultSet[$i], $association, $assocData, $model, $linkModel, $stack)) { + foreach ($resultSet as &$result) { + if ($in = $this->insertQueryData('{$__cakeID__$}', $result, $association, $assocData, $model, $linkModel, $stack)) { $ins[] = $in; } } @@ -1111,7 +1224,7 @@ class DboSource extends DataSource { $query = str_replace('{$__cakeID__$}', '(' .implode(', ', $ins) .')', $query); $query = str_replace('= (', 'IN (', $query); } else { - $query = str_replace('{$__cakeID__$}',$ins[0], $query); + $query = str_replace('{$__cakeID__$}', $ins[0], $query); } $query = str_replace(' WHERE 1 = 1', '', $query); @@ -1123,29 +1236,25 @@ class DboSource extends DataSource { $habtmFieldsCount = count($habtmFields); $q = $this->insertQueryData($query, null, $association, $assocData, $model, $linkModel, $stack); - if ($q != false) { + if ($q !== false) { $fetch = $this->fetchAll($q, $model->cacheQueries); } else { $fetch = null; } } - for ($i = 0; $i < $count; $i++) { - $row =& $resultSet[$i]; - + $modelAlias = $model->alias; + $modelPK = $model->primaryKey; + foreach ($resultSet as &$row) { if ($type !== 'hasAndBelongsToMany') { - $q = $this->insertQueryData($query, $resultSet[$i], $association, $assocData, $model, $linkModel, $stack); - if ($q != false) { + $q = $this->insertQueryData($query, $row, $association, $assocData, $model, $linkModel, $stack); + if ($q !== false) { $fetch = $this->fetchAll($q, $model->cacheQueries); } else { $fetch = null; } } - $selfJoin = false; - - if ($linkModel->name === $model->name) { - $selfJoin = true; - } + $selfJoin = $linkModel->name === $model->name; if (!empty($fetch) && is_array($fetch)) { if ($recursive > 0) { @@ -1153,7 +1262,7 @@ class DboSource extends DataSource { foreach ($linkModel->{$type1} as $assoc1 => $assocData1) { $deepModel = $linkModel->{$assoc1}; - if (($type1 === 'belongsTo') || ($deepModel->alias === $model->alias && $type === 'belongsTo') || ($deepModel->alias != $model->alias)) { + if ($type1 === 'belongsTo' || ($deepModel->alias === $modelAlias && $type === 'belongsTo') || ($deepModel->alias !== $modelAlias)) { $tmpStack = $stack; $tmpStack[] = $assoc1; if ($linkModel->useDbConfig == $deepModel->useDbConfig) { @@ -1166,13 +1275,11 @@ class DboSource extends DataSource { } } } - if ($type == 'hasAndBelongsToMany') { + if ($type === 'hasAndBelongsToMany') { $uniqueIds = $merge = array(); foreach ($fetch as $j => $data) { - if ( - (isset($data[$with]) && $data[$with][$foreignKey] === $row[$model->alias][$model->primaryKey]) - ) { + if (isset($data[$with]) && $data[$with][$foreignKey] === $row[$modelAlias][$modelPK]) { if ($habtmFieldsCount <= 2) { unset($data[$with]); } @@ -1182,17 +1289,17 @@ class DboSource extends DataSource { if (empty($merge) && !isset($row[$association])) { $row[$association] = $merge; } else { - $this->__mergeAssociation($resultSet[$i], $merge, $association, $type); + $this->__mergeAssociation($row, $merge, $association, $type); } } else { - $this->__mergeAssociation($resultSet[$i], $fetch, $association, $type, $selfJoin); + $this->__mergeAssociation($row, $fetch, $association, $type, $selfJoin); } - if (isset($resultSet[$i][$association])) { - $resultSet[$i][$association] = $linkModel->afterFind($resultSet[$i][$association], false); + if (isset($row[$association])) { + $row[$association] = $linkModel->afterFind($row[$association], false); } } else { $tempArray[0][$association] = false; - $this->__mergeAssociation($resultSet[$i], $tempArray, $association, $type, $selfJoin); + $this->__mergeAssociation($row, $tempArray, $association, $type, $selfJoin); } } } @@ -1225,12 +1332,17 @@ class DboSource extends DataSource { * @param object $linkModel Model being merged * @return void */ - function __mergeHasMany(&$resultSet, $merge, $association, &$model, &$linkModel) { - foreach ($resultSet as $i => $value) { - $count = 0; - $merged[$association] = array(); - foreach ($merge as $j => $data) { - if (isset($value[$model->alias]) && $value[$model->alias][$model->primaryKey] === $data[$association][$model->hasMany[$association]['foreignKey']]) { + function __mergeHasMany(&$resultSet, $merge, $association, $model, $linkModel) { + $modelAlias = $model->alias; + $modelPK = $model->primaryKey; + $modelFK = $model->hasMany[$association]['foreignKey']; + foreach ($resultSet as &$result) { + if (!isset($result[$modelAlias])) { + continue; + } + $merged = array(); + foreach ($merge as $data) { + if ($result[$modelAlias][$modelPK] === $data[$association][$modelFK]) { if (count($data) > 1) { $data = array_merge($data[$association], $data); unset($data[$association]); @@ -1240,17 +1352,13 @@ class DboSource extends DataSource { unset($data[$key]); } } - $merged[$association][] = $data; + $merged[] = $data; } else { - $merged[$association][] = $data[$association]; + $merged[] = $data[$association]; } } - $count++; - } - if (isset($value[$model->alias])) { - $resultSet[$i] = Set::pushDiff($resultSet[$i], $merged); - unset($merged); } + $result = Set::pushDiff($result, array($association => $merged)); } } @@ -1264,18 +1372,18 @@ class DboSource extends DataSource { * @param boolean $selfJoin * @access private */ - function __mergeAssociation(&$data, $merge, $association, $type, $selfJoin = false) { + function __mergeAssociation(&$data, &$merge, $association, $type, $selfJoin = false) { if (isset($merge[0]) && !isset($merge[0][$association])) { $association = Inflector::pluralize($association); } - if ($type == 'belongsTo' || $type == 'hasOne') { + if ($type === 'belongsTo' || $type === 'hasOne') { if (isset($merge[$association])) { $data[$association] = $merge[$association][0]; } else { if (count($merge[0][$association]) > 1) { foreach ($merge[0] as $assoc => $data2) { - if ($assoc != $association) { + if ($assoc !== $association) { $merge[0][$association][$assoc] = $data2; } } @@ -1320,11 +1428,11 @@ class DboSource extends DataSource { } } else { foreach ($merge as $i => $row) { - if (count($row) == 1) { + if (count($row) === 1) { if (empty($data[$association]) || (isset($data[$association]) && !in_array($row[$association], $data[$association]))) { $data[$association][] = $row[$association]; } - } else if (!empty($row)) { + } elseif (!empty($row)) { $tmp = array_merge($row[$association], $row); unset($tmp[$association]); $data[$association][] = $tmp; @@ -1347,20 +1455,18 @@ class DboSource extends DataSource { * @param array $resultSet * @return mixed */ - public function generateAssociationQuery($model, &$linkModel, $type, $association = null, $assocData = array(), &$queryData, $external = false, &$resultSet) { + public function generateAssociationQuery($model, $linkModel, $type, $association = null, $assocData = array(), &$queryData, $external = false, &$resultSet) { $queryData = $this->__scrubQueryData($queryData); $assocData = $this->__scrubQueryData($assocData); + $modelAlias = $model->alias; if (empty($queryData['fields'])) { - $queryData['fields'] = $this->fields($model, $model->alias); + $queryData['fields'] = $this->fields($model, $modelAlias); } elseif (!empty($model->hasMany) && $model->recursive > -1) { - $assocFields = $this->fields($model, $model->alias, array("{$model->alias}.{$model->primaryKey}")); - $passedFields = $this->fields($model, $model->alias, $queryData['fields']); + $assocFields = $this->fields($model, $modelAlias, array("{$modelAlias}.{$model->primaryKey}")); + $passedFields = $this->fields($model, $modelAlias, $queryData['fields']); if (count($passedFields) === 1) { - $match = strpos($passedFields[0], $assocFields[0]); - $match1 = (bool)preg_match('/^[a-z]+\(/i', $passedFields[0]); - - if ($match === false && $match1 === false) { + if (strpos($passedFields[0], $assocFields[0]) === false && !preg_match('/^[a-z]+\(/i', $passedFields[0])) { $queryData['fields'] = array_merge($passedFields, $assocFields); } else { $queryData['fields'] = $passedFields; @@ -1371,12 +1477,12 @@ class DboSource extends DataSource { unset($assocFields, $passedFields); } - if ($linkModel == null) { + if ($linkModel === null) { return $this->buildStatement( array( 'fields' => array_unique($queryData['fields']), 'table' => $this->fullTableName($model), - 'alias' => $model->alias, + 'alias' => $modelAlias, 'limit' => $queryData['limit'], 'offset' => $queryData['offset'], 'joins' => $queryData['joins'], @@ -1391,12 +1497,11 @@ class DboSource extends DataSource { return $assocData['finderQuery']; } - $alias = $association; - $self = ($model->name == $linkModel->name); + $self = $model->name === $linkModel->name; $fields = array(); - if ((!$external && in_array($type, array('hasOne', 'belongsTo')) && $this->__bypass === false) || $external) { - $fields = $this->fields($linkModel, $alias, $assocData['fields']); + if ($external || (in_array($type, array('hasOne', 'belongsTo')) && $this->__bypass === false)) { + $fields = $this->fields($linkModel, $association, $assocData['fields']); } if (empty($assocData['offset']) && !empty($assocData['page'])) { $assocData['offset'] = ($assocData['page'] - 1) * $assocData['limit']; @@ -1408,12 +1513,12 @@ class DboSource extends DataSource { case 'belongsTo': $conditions = $this->__mergeConditions( $assocData['conditions'], - $this->getConstraint($type, $model, $linkModel, $alias, array_merge($assocData, compact('external', 'self'))) + $this->getConstraint($type, $model, $linkModel, $association, array_merge($assocData, compact('external', 'self'))) ); if (!$self && $external) { foreach ($conditions as $key => $condition) { - if (is_numeric($key) && strpos($condition, $model->alias . '.') !== false) { + if (is_numeric($key) && strpos($condition, $modelAlias . '.') !== false) { unset($conditions[$key]); } } @@ -1424,14 +1529,14 @@ class DboSource extends DataSource { 'conditions' => $conditions, 'table' => $this->fullTableName($linkModel), 'fields' => $fields, - 'alias' => $alias, + 'alias' => $association, 'group' => null )); - $query = array_merge(array('order' => $assocData['order'], 'limit' => $assocData['limit']), $query); + $query += array('order' => $assocData['order'], 'limit' => $assocData['limit']); } else { $join = array( 'table' => $this->fullTableName($linkModel), - 'alias' => $alias, + 'alias' => $association, 'type' => isset($assocData['type']) ? $assocData['type'] : 'LEFT', 'conditions' => trim($this->conditions($conditions, true, false, $model)) ); @@ -1447,15 +1552,15 @@ class DboSource extends DataSource { } break; case 'hasMany': - $assocData['fields'] = $this->fields($linkModel, $alias, $assocData['fields']); + $assocData['fields'] = $this->fields($linkModel, $association, $assocData['fields']); if (!empty($assocData['foreignKey'])) { - $assocData['fields'] = array_merge($assocData['fields'], $this->fields($linkModel, $alias, array("{$alias}.{$assocData['foreignKey']}"))); + $assocData['fields'] = array_merge($assocData['fields'], $this->fields($linkModel, $association, array("{$association}.{$assocData['foreignKey']}"))); } $query = array( - 'conditions' => $this->__mergeConditions($this->getConstraint('hasMany', $model, $linkModel, $alias, $assocData), $assocData['conditions']), + 'conditions' => $this->__mergeConditions($this->getConstraint('hasMany', $model, $linkModel, $association, $assocData), $assocData['conditions']), 'fields' => array_unique($assocData['fields']), 'table' => $this->fullTableName($linkModel), - 'alias' => $alias, + 'alias' => $association, 'order' => $assocData['order'], 'limit' => $assocData['limit'], 'group' => null @@ -1473,8 +1578,8 @@ class DboSource extends DataSource { $joinAlias = $joinTbl; if (is_array($joinFields) && !empty($joinFields)) { - $joinFields = $this->fields($model->{$with}, $model->{$with}->alias, $joinFields); $joinAssoc = $joinAlias = $model->{$with}->alias; + $joinFields = $this->fields($model->{$with}, $joinAlias, $joinFields); } else { $joinFields = array(); } @@ -1486,14 +1591,14 @@ class DboSource extends DataSource { 'conditions' => $assocData['conditions'], 'limit' => $assocData['limit'], 'table' => $this->fullTableName($linkModel), - 'alias' => $alias, - 'fields' => array_merge($this->fields($linkModel, $alias, $assocData['fields']), $joinFields), + 'alias' => $association, + 'fields' => array_merge($this->fields($linkModel, $association, $assocData['fields']), $joinFields), 'order' => $assocData['order'], 'group' => null, 'joins' => array(array( 'table' => $joinTbl, 'alias' => $joinAssoc, - 'conditions' => $this->getConstraint('hasAndBelongsToMany', $model, $linkModel, $joinAlias, $assocData, $alias) + 'conditions' => $this->getConstraint('hasAndBelongsToMany', $model, $linkModel, $joinAlias, $assocData, $association) )) ); break; @@ -1513,34 +1618,28 @@ class DboSource extends DataSource { * @return array Conditions array defining the constraint between $model and $association */ public function getConstraint($type, $model, $linkModel, $alias, $assoc, $alias2 = null) { - $assoc = array_merge(array('external' => false, 'self' => false), $assoc); + $assoc += array('external' => false, 'self' => false); - if (array_key_exists('foreignKey', $assoc) && empty($assoc['foreignKey'])) { + if (empty($assoc['foreignKey'])) { return array(); } switch (true) { - case ($assoc['external'] && $type == 'hasOne'): + case ($assoc['external'] && $type === 'hasOne'): return array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}'); - break; - case ($assoc['external'] && $type == 'belongsTo'): + case ($assoc['external'] && $type === 'belongsTo'): return array("{$alias}.{$linkModel->primaryKey}" => '{$__cakeForeignKey__$}'); - break; - case (!$assoc['external'] && $type == 'hasOne'): + case (!$assoc['external'] && $type === 'hasOne'): return array("{$alias}.{$assoc['foreignKey']}" => $this->identifier("{$model->alias}.{$model->primaryKey}")); - break; - case (!$assoc['external'] && $type == 'belongsTo'): + case (!$assoc['external'] && $type === 'belongsTo'): return array("{$model->alias}.{$assoc['foreignKey']}" => $this->identifier("{$alias}.{$linkModel->primaryKey}")); - break; - case ($type == 'hasMany'): + case ($type === 'hasMany'): return array("{$alias}.{$assoc['foreignKey']}" => array('{$__cakeID__$}')); - break; - case ($type == 'hasAndBelongsToMany'): + case ($type === 'hasAndBelongsToMany'): return array( array("{$alias}.{$assoc['foreignKey']}" => '{$__cakeID__$}'), array("{$alias}.{$assoc['associationForeignKey']}" => $this->identifier("{$alias2}.{$linkModel->primaryKey}")) ); - break; } return array(); } @@ -1627,22 +1726,18 @@ class DboSource extends DataSource { switch (strtolower($type)) { case 'select': return "SELECT {$fields} FROM {$table} {$alias} {$joins} {$conditions} {$group} {$order} {$limit}"; - break; case 'create': return "INSERT INTO {$table} ({$fields}) VALUES ({$values})"; - break; case 'update': if (!empty($alias)) { $aliases = "{$this->alias}{$alias} {$joins} "; } return "UPDATE {$table} {$aliases}SET {$fields} {$conditions}"; - break; case 'delete': if (!empty($alias)) { $aliases = "{$this->alias}{$alias} {$joins} "; } return "DELETE {$alias} FROM {$table} {$aliases}{$conditions}"; - break; case 'schema': foreach (array('columns', 'indexes', 'tableParameters') as $var) { if (is_array(${$var})) { @@ -1651,23 +1746,23 @@ class DboSource extends DataSource { ${$var} = ''; } } - if (trim($indexes) != '') { + if (trim($indexes) !== '') { $columns .= ','; } return "CREATE TABLE {$table} (\n{$columns}{$indexes}){$tableParameters};"; - break; case 'alter': - break; + return; } } /** * Merges a mixed set of string/array conditions * + * @param mixed $query + * @param mixed $assoc * @return array - * @access private */ - function __mergeConditions($query, $assoc) { + private function __mergeConditions($query, $assoc) { if (empty($assoc)) { return $query; } @@ -1852,7 +1947,7 @@ class DboSource extends DataSource { $joins = array_merge($model->getAssociated('hasOne'), $model->getAssociated('belongsTo')); foreach ($joins as $assoc) { - if (isset($model->{$assoc}) && $model->useDbConfig == $model->{$assoc}->useDbConfig) { + if (isset($model->{$assoc}) && $model->useDbConfig == $model->{$assoc}->useDbConfig && $model->{$assoc}->getDataSource()) { $assocData = $model->getAssociated($assoc); $join[] = $this->buildJoinStatement(array( 'table' => $this->fullTableName($model->{$assoc}), @@ -2025,7 +2120,7 @@ class DboSource extends DataSource { if (empty($assoc)) { $assoc = $model->alias; } - if (!strpos('.', $key)) { + if (strpos('.', $key) !== false) { return $this->name($model->alias) . '.' . $this->name($key); } return $key; @@ -2038,12 +2133,11 @@ class DboSource extends DataSource { * @return array */ public function __scrubQueryData($data) { - foreach (array('conditions', 'fields', 'joins', 'order', 'limit', 'offset', 'group') as $key) { - if (empty($data[$key])) { - $data[$key] = array(); - } + static $base = null; + if ($base === null) { + $base = array_fill_keys(array('conditions', 'fields', 'joins', 'order', 'limit', 'offset', 'group'), array()); } - return $data; + return (array)$data + $base; } /** @@ -2152,8 +2246,7 @@ class DboSource extends DataSource { $fields[$i] = $this->name(($prefix ? $alias . '.' : '') . $fields[$i]); } else { $value = array(); - $comma = strpos($fields[$i], ','); - if ($comma === false) { + if (strpos($fields[$i], ',') === false) { $build = explode('.', $fields[$i]); if (!Set::numeric($build)) { $fields[$i] = $this->name(implode('.', $build)); @@ -2231,11 +2324,11 @@ class DboSource extends DataSource { } return $this->cacheMethod(__FUNCTION__, $cacheKey, $clause . implode(' AND ', $out)); } - if ($conditions === false || $conditions === true) { + if (is_bool($conditions)) { return $this->cacheMethod(__FUNCTION__, $cacheKey, $clause . (int)$conditions . ' = 1'); } - if (empty($conditions) || trim($conditions) == '') { + if (empty($conditions) || trim($conditions) === '') { return $this->cacheMethod(__FUNCTION__, $cacheKey, $clause . '1 = 1'); } $clauses = '/^WHERE\\x20|^GROUP\\x20BY\\x20|^HAVING\\x20|^ORDER\\x20BY\\x20/i'; @@ -2243,11 +2336,7 @@ class DboSource extends DataSource { if (preg_match($clauses, $conditions, $match)) { $clause = ''; } - if (trim($conditions) == '') { - $conditions = ' 1 = 1'; - } else { - $conditions = $this->__quoteFields($conditions); - } + $conditions = $this->__quoteFields($conditions); return $this->cacheMethod(__FUNCTION__, $cacheKey, $clause . $conditions); } @@ -2260,7 +2349,6 @@ class DboSource extends DataSource { * @return string SQL fragment */ public function conditionKeysToString($conditions, $quoteValues = true, $model = null) { - $c = 0; $out = array(); $data = $columnType = null; $bool = array('and', 'or', 'not', 'and not', 'or not', 'xor', '||', '&&'); @@ -2272,7 +2360,7 @@ class DboSource extends DataSource { if (is_array($value)) { $valueInsert = ( !empty($value) && - (substr_count($key, '?') == count($value) || substr_count($key, ':') == count($value)) + (substr_count($key, '?') === count($value) || substr_count($key, ':') === count($value)) ); } @@ -2289,7 +2377,7 @@ class DboSource extends DataSource { $value = $this->conditionKeysToString($value, $quoteValues, $model); if (strpos($join, 'NOT') !== false) { - if (strtoupper(trim($key)) == 'NOT') { + if (strtoupper(trim($key)) === 'NOT') { $key = 'AND ' . trim($key); } $not = 'NOT '; @@ -2304,12 +2392,11 @@ class DboSource extends DataSource { } else { $out[] = '(' . $not . '(' . implode(') ' . strtoupper($key) . ' (', $value) . '))'; } - } else { if (is_object($value) && isset($value->type)) { - if ($value->type == 'identifier') { + if ($value->type === 'identifier') { $data .= $this->name($key) . ' = ' . $this->name($value->value); - } elseif ($value->type == 'expression') { + } elseif ($value->type === 'expression') { if (is_numeric($key)) { $data .= $value->value; } else { @@ -2351,7 +2438,6 @@ class DboSource extends DataSource { $data = null; } } - $c++; } return $out; } @@ -2371,7 +2457,7 @@ class DboSource extends DataSource { $operatorMatch .= '\\x20)|<[>=]?(?![^>]+>)\\x20?|[>=!]{1,3}(?!<)\\x20?)/is'; $bound = (strpos($key, '?') !== false || (is_array($value) && strpos($key, ':') !== false)); - if (!strpos($key, ' ')) { + if (strpos($key, ' ') === false) { $operator = '='; } else { list($key, $operator) = explode(' ', trim($key), 2); @@ -2390,9 +2476,8 @@ class DboSource extends DataSource { $virtual = true; } - $type = (is_object($model) ? $model->getColumnType($key) : null); - - $null = ($value === null || (is_array($value) && empty($value))); + $type = is_object($model) ? $model->getColumnType($key) : null; + $null = $value === null || (is_array($value) && empty($value)); if (strtolower($operator) === 'not') { $data = $this->conditionKeysToString( @@ -2409,7 +2494,7 @@ class DboSource extends DataSource { } if ($bound) { - return String::insert($key . ' ' . trim($operator), $value); + return String::insert($key . ' ' . trim($operator), $value); } if (!preg_match($operatorMatch, trim($operator))) { @@ -2455,7 +2540,7 @@ class DboSource extends DataSource { * @access private */ function __quoteFields($conditions) { - $start = $end = null; + $start = $end = null; $original = $conditions; if (!empty($this->startQuote)) { @@ -2497,7 +2582,7 @@ class DboSource extends DataSource { public function limit($limit, $offset = null) { if ($limit) { $rt = ''; - if (!strpos(strtolower($limit), 'limit') || strpos(strtolower($limit), 'limit') === 0) { + if (!strpos(strtolower($limit), 'limit')) { $rt = ' LIMIT'; } @@ -2534,7 +2619,7 @@ class DboSource extends DataSource { $dir = $direction; } - if (is_string($key) && strpos($key, ',') && !preg_match('/\(.+\,.+\)/', $key)) { + if (is_string($key) && strpos($key, ',') !== false && !preg_match('/\(.+\,.+\)/', $key)) { $key = array_map('trim', explode(',', $key)); } if (is_array($key)) { @@ -2567,7 +2652,7 @@ class DboSource extends DataSource { if (strpos($key, '.')) { $key = preg_replace_callback('/([a-zA-Z0-9_]{1,})\\.([a-zA-Z0-9_]{1,})/', array(&$this, '__quoteMatchedField'), $key); } - if (!preg_match('/\s/', $key) && !strpos($key, '.')) { + if (!preg_match('/\s/', $key) && strpos($key, '.') === false) { $key = $this->name($key); } $key .= ' ' . trim($dir); @@ -2640,14 +2725,14 @@ class DboSource extends DataSource { */ public function length($real) { if (!preg_match_all('/([\w\s]+)(?:\((\d+)(?:,(\d+))?\))?(\sunsigned)?(\szerofill)?/', $real, $result)) { - trigger_error(__("FIXME: Can't parse field: " . $real), E_USER_WARNING); + trigger_error(__d('cake_dev', "FIXME: Can't parse field: " . $real), E_USER_WARNING); $col = str_replace(array(')', 'unsigned'), '', $real); $limit = null; if (strpos($col, '(') !== false) { list($col, $limit) = explode('(', $col); } - if ($limit != null) { + if ($limit !== null) { return intval($limit); } return null; @@ -2665,10 +2750,10 @@ class DboSource extends DataSource { $isFloat = in_array($type, array('dec', 'decimal', 'float', 'numeric', 'double')); if ($isFloat && $offset) { - return $length.','.$offset; + return $length . ',' . $offset; } - if (($real[0] == $type) && (count($real) == 1)) { + if (($real[0] == $type) && (count($real) === 1)) { return null; } @@ -2680,7 +2765,7 @@ class DboSource extends DataSource { } elseif (in_array($type, array('enum', 'set'))) { $length = 0; foreach ($typeArr as $key => $enumValue) { - if ($key == 0) { + if ($key === 0) { continue; } $tmpLength = strlen($enumValue); @@ -2698,15 +2783,11 @@ class DboSource extends DataSource { * @param mixed $data Value to be translated * @return int Converted boolean value */ - public function boolean($data) { - if ($data === true || $data === false) { - if ($data === true) { - return 1; - } - return 0; - } else { - return (int) !empty($data); + public function boolean($data, $quote = false) { + if ($quote) { + return !empty($data) ? '1' : '0'; } + return !empty($data); } /** @@ -2752,7 +2833,7 @@ class DboSource extends DataSource { */ public function createSchema($schema, $tableName = null) { if (!is_a($schema, 'CakeSchema')) { - trigger_error(__('Invalid schema object'), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Invalid schema object'), E_USER_WARNING); return null; } $out = ''; @@ -2767,7 +2848,7 @@ class DboSource extends DataSource { if (is_string($col)) { $col = array('type' => $col); } - if (isset($col['key']) && $col['key'] == 'primary') { + if (isset($col['key']) && $col['key'] === 'primary') { $primary = $name; } if ($name !== 'indexes' && $name !== 'tableParameters') { @@ -2776,9 +2857,9 @@ class DboSource extends DataSource { $col['type'] = 'string'; } $cols[] = $this->buildColumn($col); - } elseif ($name == 'indexes') { + } elseif ($name === 'indexes') { $indexes = array_merge($indexes, $this->buildIndex($col, $table)); - } elseif ($name == 'tableParameters') { + } elseif ($name === 'tableParameters') { $tableParameters = array_merge($tableParameters, $this->buildTableParameters($col, $table)); } } @@ -2834,41 +2915,41 @@ class DboSource extends DataSource { extract(array_merge(array('null' => true), $column)); if (empty($name) || empty($type)) { - trigger_error(__('Column name or type not defined in schema'), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Column name or type not defined in schema'), E_USER_WARNING); return null; } if (!isset($this->columns[$type])) { - trigger_error(__('Column type %s does not exist', $type), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Column type %s does not exist', $type), E_USER_WARNING); return null; } $real = $this->columns[$type]; $out = $this->name($name) . ' ' . $real['name']; - if (isset($real['limit']) || isset($real['length']) || isset($column['limit']) || isset($column['length'])) { - if (isset($column['length'])) { - $length = $column['length']; - } elseif (isset($column['limit'])) { - $length = $column['limit']; - } elseif (isset($real['length'])) { - $length = $real['length']; - } else { - $length = $real['limit']; - } + if (isset($column['length'])) { + $length = $column['length']; + } elseif (isset($column['limit'])) { + $length = $column['limit']; + } elseif (isset($real['length'])) { + $length = $real['length']; + } elseif (isset($real['limit'])) { + $length = $real['limit']; + } + if (isset($length)) { $out .= '(' . $length . ')'; } - if (($column['type'] == 'integer' || $column['type'] == 'float' ) && isset($column['default']) && $column['default'] === '') { + if (($column['type'] === 'integer' || $column['type'] === 'float' ) && isset($column['default']) && $column['default'] === '') { $column['default'] = null; } $out = $this->_buildFieldParameters($out, $column, 'beforeDefault'); - if (isset($column['key']) && $column['key'] == 'primary' && $type == 'integer') { + if (isset($column['key']) && $column['key'] === 'primary' && $type === 'integer') { $out .= ' ' . $this->columns['primary_key']['name']; - } elseif (isset($column['key']) && $column['key'] == 'primary') { + } elseif (isset($column['key']) && $column['key'] === 'primary') { $out .= ' NOT NULL'; - } elseif (isset($column['default']) && isset($column['null']) && $column['null'] == false) { + } elseif (isset($column['default']) && isset($column['null']) && $column['null'] === false) { $out .= ' DEFAULT ' . $this->value($column['default'], $type) . ' NOT NULL'; } elseif (isset($column['default'])) { $out .= ' DEFAULT ' . $this->value($column['default'], $type); @@ -2876,14 +2957,13 @@ class DboSource extends DataSource { $out .= ' DEFAULT NULL'; } elseif ($type === 'timestamp' && !empty($column['null'])) { $out .= ' NULL'; - } elseif (isset($column['null']) && $column['null'] == false) { + } elseif (isset($column['null']) && $column['null'] === false) { $out .= ' NOT NULL'; } - if ($type == 'timestamp' && isset($column['default']) && strtolower($column['default']) == 'current_timestamp') { + if ($type === 'timestamp' && isset($column['default']) && strtolower($column['default']) === 'current_timestamp') { $out = str_replace(array("'CURRENT_TIMESTAMP'", "'current_timestamp'"), 'CURRENT_TIMESTAMP', $out); } - $out = $this->_buildFieldParameters($out, $column, 'afterDefault'); - return $out; + return $this->_buildFieldParameters($out, $column, 'afterDefault'); } /** @@ -2921,7 +3001,7 @@ class DboSource extends DataSource { $join = array(); foreach ($indexes as $name => $value) { $out = ''; - if ($name == 'PRIMARY') { + if ($name === 'PRIMARY') { $out .= 'PRIMARY '; $name = null; } else { @@ -2949,7 +3029,7 @@ class DboSource extends DataSource { */ public function readTableParameters($name) { $parameters = array(); - if ($this->isInterfaceSupported('listDetailedSources')) { + if (method_exists($this, 'listDetailedSources')) { $currentTableDetails = $this->listDetailedSources($name); foreach ($this->tableParameters as $paramName => $parameter) { if (!empty($parameter['column']) && !empty($currentTableDetails[$parameter['column']])) { @@ -2988,7 +3068,7 @@ class DboSource extends DataSource { */ public function introspectType($value) { if (!is_array($value)) { - if ($value === true || $value === false) { + if (is_bool($value)) { return 'boolean'; } if (is_float($value) && floatval($value) === $value) { @@ -3066,4 +3146,4 @@ class DboSource extends DataSource { return false; } -} +} \ No newline at end of file diff --git a/cake/libs/session/cache_session.php b/lib/Cake/Model/Datasource/Session/CacheSession.php similarity index 100% rename from cake/libs/session/cache_session.php rename to lib/Cake/Model/Datasource/Session/CacheSession.php diff --git a/cake/libs/session/database_session.php b/lib/Cake/Model/Datasource/Session/DatabaseSession.php similarity index 99% rename from cake/libs/session/database_session.php rename to lib/Cake/Model/Datasource/Session/DatabaseSession.php index 574d1f5c0..ceff5fdb0 100644 --- a/cake/libs/session/database_session.php +++ b/lib/Cake/Model/Datasource/Session/DatabaseSession.php @@ -106,6 +106,9 @@ class DatabaseSession implements CakeSessionHandlerInterface { * @access private */ public function write($id, $data) { + if (!$id) { + return false; + } $expires = time() + (Configure::read('Session.timeout') * 60); return ClassRegistry::getObject('Session')->save(compact('id', 'data', 'expires')); } diff --git a/cake/libs/model/model.php b/lib/Cake/Model/Model.php similarity index 96% rename from cake/libs/model/model.php rename to lib/Cake/Model/Model.php index 396da7d4e..8ed3b3ca9 100644 --- a/cake/libs/model/model.php +++ b/lib/Cake/Model/Model.php @@ -22,12 +22,13 @@ /** * Included libs */ -App::import('Core', 'ClassRegistry', false); -App::import('Core', 'Validation', false); -App::import('Core', 'String', false); -App::import('Model', 'BehaviorCollection', false); -App::import('Model', 'ModelBehavior', false); -App::import('Model', 'ConnectionManager', false); +App::uses('ClassRegistry', 'Utility'); +App::uses('Validation', 'Utility'); +App::uses('String', 'Utility'); +App::uses('BehaviorCollection', 'Model'); +App::uses('ModelBehavior', 'Model'); +App::uses('ConnectionManager', 'Model'); +App::uses('Xml', 'Utility'); /** * Object-relational mapper. @@ -331,9 +332,9 @@ class Model extends Object { public $__backAssociation = array(); public $__backInnerAssociation = array(); - + public $__backOriginalAssociation = array(); - + public $__backContainableAssociation = array(); /** @@ -360,13 +361,21 @@ class Model extends Object { */ private $__affectedRows = null; +/** + * Has the datasource been configured. + * + * @var boolean + * @see Model::getDataSource + */ + private $__sourceConfigured = false; + /** * List of valid finder method options, supplied as the first parameter to find(). * * @var array - * @access protected + * @access public */ - protected $_findMethods = array( + public $findMethods = array( 'all' => true, 'first' => true, 'count' => true, 'neighbors' => true, 'list' => true, 'threaded' => true ); @@ -444,7 +453,7 @@ class Model extends Object { } if (is_subclass_of($this, 'AppModel')) { - $merge = array('_findMethods'); + $merge = array('findMethods'); if ($this->actsAs !== null || $this->actsAs !== false) { $merge[] = 'actsAs'; } @@ -790,7 +799,7 @@ class Model extends Object { $db = ConnectionManager::getDataSource($this->useDbConfig); $db->cacheSources = ($this->cacheSources && $db->cacheSources); - if ($db->isInterfaceSupported('listSources')) { + if (method_exists($db, 'listSources')) { $sources = $db->listSources(); if (is_array($sources) && !in_array(strtolower($this->tablePrefix . $tableName), array_map('strtolower', $sources))) { throw new MissingTableException(array( @@ -826,7 +835,6 @@ class Model extends Object { } if (is_object($one)) { if ($one instanceof SimpleXMLElement || $one instanceof DOMNode) { - App::import('Core', 'Xml'); $one = $this->_normalizeXmlData(Xml::toArray($one)); } else { $one = Set::reverse($one); @@ -973,7 +981,7 @@ class Model extends Object { if (!is_array($this->_schema) || $field === true) { $db = $this->getDataSource(); $db->cacheSources = ($this->cacheSources && $db->cacheSources); - if ($db->isInterfaceSupported('describe') && $this->useTable !== false) { + if (method_exists($db, 'describe') && $this->useTable !== false) { $this->_schema = $db->describe($this, $field); } elseif ($this->useTable === false) { $this->_schema = array(); @@ -997,7 +1005,7 @@ class Model extends Object { public function getColumnTypes() { $columns = $this->schema(); if (empty($columns)) { - trigger_error(__('(Model::getColumnTypes) Unable to build model field data. If you are using a model without a database table, try implementing schema()'), E_USER_WARNING); + trigger_error(__d('cake_dev', '(Model::getColumnTypes) Unable to build model field data. If you are using a model without a database table, try implementing schema()'), E_USER_WARNING); } $cols = array(); foreach ($columns as $field => $values) { @@ -1067,7 +1075,7 @@ class Model extends Object { } /** - * Check that a method is callable on a model. This will check both the model's own methods, its + * Check that a method is callable on a model. This will check both the model's own methods, its * inherited methods and methods that could be callable through behaviors. * * @param string $method The method to be called. @@ -1146,11 +1154,11 @@ class Model extends Object { if ($data !== null && $data !== false) { foreach ($this->schema() as $field => $properties) { - if ($this->primaryKey !== $field && isset($properties['default'])) { + if ($this->primaryKey !== $field && isset($properties['default']) && $properties['default'] !== '') { $defaults[$field] = $properties['default']; } } - $this->set(Set::filter($defaults)); + $this->set($defaults); $this->set($data); } if ($filterKey) { @@ -1441,7 +1449,7 @@ class Model extends Object { * @param mixed $id ID of record in this model * @access private */ - function __saveMulti($joined, $id, &$db) { + function __saveMulti($joined, $id, $db) { foreach ($joined as $assoc => $data) { if (isset($this->hasAndBelongsToMany[$assoc])) { @@ -1874,7 +1882,7 @@ class Model extends Object { if (!$filters || !$this->exists()) { return false; } - $db = ConnectionManager::getDataSource($this->useDbConfig); + $db = $this->getDataSource(); $this->_deleteDependent($id, $cascade); $this->_deleteLinks($id); @@ -1951,7 +1959,7 @@ class Model extends Object { */ protected function _deleteLinks($id) { foreach ($this->hasAndBelongsToMany as $assoc => $data) { - $joinModel = $data['with']; + list($plugin, $joinModel) = pluginSplit($data['with']); $records = $this->{$joinModel}->find('all', array( 'conditions' => array_merge(array($this->{$joinModel}->escapeField($data['foreignKey']) => $id)), 'fields' => $this->{$joinModel}->primaryKey, @@ -2065,7 +2073,7 @@ class Model extends Object { /** * Queries the datasource and returns a result set array. * - * Also used to perform new-notation finds, where the first argument is type of find operation to perform + * Also used to perform notation finds, where the first argument is type of find operation to perform * (all / first / count / neighbors / list / threaded ), * second parameter options for finding ( indexed array, including: 'conditions', 'limit', * 'recursive', 'page', 'fields', 'offset', 'order') @@ -2101,44 +2109,32 @@ class Model extends Object { * * Behaviors and find types can also define custom finder keys which are passed into find(). * - * Specifying 'fields' for new-notation 'list': + * Specifying 'fields' for notation 'list': * * - If no fields are specified, then 'id' is used for key and 'model->displayField' is used for value. * - If a single field is specified, 'id' is used for key and specified field is used for value. * - If three fields are specified, they are used (in order) for key, value and group. * - Otherwise, first and second fields are used for key and value. * - * @param array $conditions SQL conditions array, or type of find operation (all / first / count / - * neighbors / list / threaded) - * @param mixed $fields Either a single string of a field name, or an array of field names, or - * options for matching - * @param string $order SQL ORDER BY conditions (e.g. "price DESC" or "name ASC") - * @param integer $recursive The number of levels deep to fetch associated records + * @param string $type Type of find operation (all / first / count / neighbors / list / threaded) + * @param array $query Option fields (conditions / fields / joins / limit / offset / order / page / group / callbacks) * @return array Array of records - * @access public * @link http://book.cakephp.org/view/1018/find */ - function find($conditions = null, $fields = array(), $order = null, $recursive = null) { - if (!is_string($conditions) || (is_string($conditions) && !array_key_exists($conditions, $this->_findMethods))) { - $type = 'first'; - $query = array_merge(compact('conditions', 'fields', 'order', 'recursive'), array('limit' => 1)); - } else { - list($type, $query) = array($conditions, $fields); - } - + public function find($type = 'first', $query = array()) { $this->findQueryType = $type; $this->id = $this->getID(); $query = array_merge( array( 'conditions' => null, 'fields' => null, 'joins' => array(), 'limit' => null, - 'offset' => null, 'order' => null, 'page' => null, 'group' => null, 'callbacks' => true + 'offset' => null, 'order' => null, 'page' => 1, 'group' => null, 'callbacks' => true ), (array)$query ); - if ($type != 'all') { - if ($this->_findMethods[$type] === true) { + if ($type !== 'all') { + if ($this->findMethods[$type] === true) { $query = $this->{'_find' . ucfirst($type)}('before', $query); } } @@ -2156,7 +2152,7 @@ class Model extends Object { if ($query['callbacks'] === true || $query['callbacks'] === 'before') { $return = $this->Behaviors->trigger( - 'beforeFind', + 'beforeFind', array(&$this, $query), array('break' => true, 'breakOn' => array(false, null), 'modParams' => 1) ); @@ -2175,15 +2171,11 @@ class Model extends Object { } } - if (!$db = $this->getDataSource()) { - return false; - } - - $results = $db->read($this, $query); + $results = $this->getDataSource()->read($this, $query); $this->resetAssociations(); if ($query['callbacks'] === true || $query['callbacks'] === 'after') { - $results = $this->__filterResults($results); + $results = $this->_filterResults($results); } $this->findQueryType = null; @@ -2191,7 +2183,7 @@ class Model extends Object { if ($type === 'all') { return $results; } else { - if ($this->_findMethods[$type] === true) { + if ($this->findMethods[$type] === true) { return $this->{'_find' . ucfirst($type)}('after', $query, $results); } } @@ -2204,14 +2196,13 @@ class Model extends Object { * @param array $query * @param array $data * @return array - * @access protected * @see Model::find() */ - function _findFirst($state, $query, $results = array()) { - if ($state == 'before') { + protected function _findFirst($state, $query, $results = array()) { + if ($state === 'before') { $query['limit'] = 1; return $query; - } elseif ($state == 'after') { + } elseif ($state === 'after') { if (empty($results[0])) { return false; } @@ -2226,11 +2217,10 @@ class Model extends Object { * @param array $query * @param array $data * @return int The number of records found, or false - * @access protected * @see Model::find() */ - function _findCount($state, $query, $results = array()) { - if ($state == 'before') { + protected function _findCount($state, $query, $results = array()) { + if ($state === 'before') { $db = $this->getDataSource(); if (empty($query['fields'])) { $query['fields'] = $db->calculate($this, 'count'); @@ -2241,7 +2231,7 @@ class Model extends Object { } $query['order'] = false; return $query; - } elseif ($state == 'after') { + } elseif ($state === 'after') { if (isset($results[0][0]['count'])) { return intval($results[0][0]['count']); } elseif (isset($results[0][$this->alias]['count'])) { @@ -2258,11 +2248,10 @@ class Model extends Object { * @param array $query * @param array $data * @return array Key/value pairs of primary keys/display field values of all records found - * @access protected * @see Model::find() */ - function _findList($state, $query, $results = array()) { - if ($state == 'before') { + protected function _findList($state, $query, $results = array()) { + if ($state === 'before') { if (empty($query['fields'])) { $query['fields'] = array("{$this->alias}.{$this->primaryKey}", "{$this->alias}.{$this->displayField}"); $list = array("{n}.{$this->alias}.{$this->primaryKey}", "{n}.{$this->alias}.{$this->displayField}", null); @@ -2271,14 +2260,14 @@ class Model extends Object { $query['fields'] = String::tokenize($query['fields']); } - if (count($query['fields']) == 1) { + if (count($query['fields']) === 1) { if (strpos($query['fields'][0], '.') === false) { $query['fields'][0] = $this->alias . '.' . $query['fields'][0]; } $list = array("{n}.{$this->alias}.{$this->primaryKey}", '{n}.' . $query['fields'][0], null); $query['fields'] = array("{$this->alias}.{$this->primaryKey}", $query['fields'][0]); - } elseif (count($query['fields']) == 3) { + } elseif (count($query['fields']) === 3) { for ($i = 0; $i < 3; $i++) { if (strpos($query['fields'][$i], '.') === false) { $query['fields'][$i] = $this->alias . '.' . $query['fields'][$i]; @@ -2301,7 +2290,7 @@ class Model extends Object { } list($query['list']['keyPath'], $query['list']['valuePath'], $query['list']['groupPath']) = $list; return $query; - } elseif ($state == 'after') { + } elseif ($state === 'after') { if (empty($results)) { return array(); } @@ -2320,8 +2309,7 @@ class Model extends Object { * @return array */ protected function _findNeighbors($state, $query, $results = array()) { - if ($state == 'before') { - $query = array_merge(array('recursive' => 0), $query); + if ($state === 'before') { extract($query); $conditions = (array)$conditions; if (isset($field) && isset($value)) { @@ -2338,7 +2326,7 @@ class Model extends Object { $query['field'] = $field; $query['value'] = $value; return $query; - } elseif ($state == 'after') { + } elseif ($state === 'after') { extract($query); unset($query['conditions'][$field . ' <']); $return = array(); @@ -2357,9 +2345,9 @@ class Model extends Object { if (!array_key_exists('prev', $return)) { $return['prev'] = $return2[0]; } - if (count($return2) == 2) { + if (count($return2) === 2) { $return['next'] = $return2[1]; - } elseif (count($return2) == 1 && !$return['prev']) { + } elseif (count($return2) === 1 && !$return['prev']) { $return['next'] = $return2[0]; } else { $return['next'] = null; @@ -2378,9 +2366,9 @@ class Model extends Object { * @return array Threaded results */ protected function _findThreaded($state, $query, $results = array()) { - if ($state == 'before') { + if ($state === 'before') { return $query; - } elseif ($state == 'after') { + } elseif ($state === 'after') { $return = $idMap = array(); $ids = Set::extract($results, '{n}.' . $this->alias . '.' . $this->primaryKey); @@ -2420,9 +2408,8 @@ class Model extends Object { * @param array Results to filter * @param boolean $primary If this is the primary model results (results from model where the find operation was performed) * @return array Set of filtered results - * @access private */ - function __filterResults($results, $primary = true) { + protected function _filterResults($results, $primary = true) { $return = $this->Behaviors->trigger( 'afterFind', array(&$this, $results, $primary), @@ -2615,7 +2602,7 @@ class Model extends Object { if (isset($validator['message'])) { $message = $validator['message']; } else { - $message = __('This field cannot be left blank'); + $message = __d('cake_dev', 'This field cannot be left blank'); } if ( @@ -2663,7 +2650,7 @@ class Model extends Object { } elseif (!is_array($validator['rule'])) { $valid = preg_match($rule, $data[$fieldName]); } elseif (Configure::read('debug') > 0) { - trigger_error(__('Could not find validation handler %s for %s', $rule, $fieldName), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Could not find validation handler %s for %s', $rule, $fieldName), E_USER_WARNING); } if (!$valid || (is_string($valid) && strlen($valid) > 0)) { @@ -2889,14 +2876,12 @@ class Model extends Object { /** * Gets the DataSource to which this model is bound. - * Not safe for use with some versions of PHP4, because this class is overloaded. * * @return object A DataSource object */ public function getDataSource() { - static $configured = false; - if (!$configured && $this->useTable !== false) { - $configured = true; + if (!$this->__sourceConfigured && $this->useTable !== false) { + $this->__sourceConfigured = true; $this->setSource($this->useTable); } return ConnectionManager::getDataSource($this->useDbConfig); @@ -2972,7 +2957,7 @@ class Model extends Object { return array($with, array_unique(array_merge($assoc[$with], $keys))); } trigger_error( - __('Invalid join model settings in %s', $model->alias), + __d('cake_dev', 'Invalid join model settings in %s', $model->alias), E_USER_WARNING ); } diff --git a/cake/libs/model/model_behavior.php b/lib/Cake/Model/ModelBehavior.php similarity index 100% rename from cake/libs/model/model_behavior.php rename to lib/Cake/Model/ModelBehavior.php diff --git a/lib/Cake/Model/Permission.php b/lib/Cake/Model/Permission.php new file mode 100644 index 000000000..5ca0f0682 --- /dev/null +++ b/lib/Cake/Model/Permission.php @@ -0,0 +1,84 @@ +useDbConfig = $config; + } + parent::__construct(); + } +} \ No newline at end of file diff --git a/cake/libs/cake_request.php b/lib/Cake/Network/CakeRequest.php similarity index 88% rename from cake/libs/cake_request.php rename to lib/Cake/Network/CakeRequest.php index b7a10058e..12dde4de8 100644 --- a/cake/libs/cake_request.php +++ b/lib/Cake/Network/CakeRequest.php @@ -15,7 +15,8 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'Set'); + +App::uses('Set', 'Utility'); /** * A class that helps wrap Request information and particulars about a single request. @@ -113,7 +114,7 @@ class CakeRequest implements ArrayAccess { * @return void */ public function __construct($url = null, $parseEnvironment = true) { - $this->base = $this->_base(); + $this->_base(); if (empty($url)) { $url = $this->_url(); } @@ -168,98 +169,50 @@ class CakeRequest implements ArrayAccess { } else { $query = $_GET; } + if (strpos($this->url, '?') !== false) { list(, $querystr) = explode('?', $this->url); parse_str($querystr, $queryArgs); - $query += $queryArgs; + $query += $queryArgs; } if (isset($this->params['url'])) { $query = array_merge($this->params['url'], $query); } - $query['url'] = $this->url; $this->query = $query; } /** - * Returns the REQUEST_URI from the server environment, or, failing that, - * constructs a new one, using the PHP_SELF constant and other variables. + * Get the request uri. Looks in PATH_INFO first, as this is the exact value we need prepared + * by PHP. Following that, REQUEST_URI, PHP_SELF, HTTP_X_REWRITE_URL and argv are checked in that order. + * Each of these server variables have the base path, and query strings stripped off * - * @return string URI - */ - protected function _uri() { - foreach (array('HTTP_X_REWRITE_URL', 'REQUEST_URI', 'argv') as $var) { - if ($uri = env($var)) { - if ($var == 'argv') { - $uri = $uri[0]; - } - break; - } - } - - $base = trim(Configure::read('App.baseUrl'), '/'); - - if ($base) { - $uri = preg_replace('/^(?:\/)?(?:' . preg_quote($base, '/') . ')?(?:url=)?/', '', $uri); - } - if (PHP_SAPI == 'isapi') { - $uri = preg_replace('/^(?:\/)?(?:\/)?(?:\?)?(?:url=)?/', '', $uri); - } - if (!empty($uri)) { - if (key($_GET) && strpos(key($_GET), '?') !== false) { - unset($_GET[key($_GET)]); - } - $uri = explode('?', $uri, 2); - - if (isset($uri[1])) { - parse_str($uri[1], $_GET); - } - $uri = $uri[0]; - } else { - $uri = env('QUERY_STRING'); - } - if (is_string($uri) && strpos($uri, 'index.php') !== false) { - list(, $uri) = explode('index.php', $uri, 2); - } - if (empty($uri) || $uri == '/' || $uri == '//') { - return ''; - } - return str_replace('//', '/', '/' . $uri); - } - -/** - * Returns and sets the $_GET[url] derived from the REQUEST_URI - * - * @return string URL + * @return string URI The CakePHP request path that is being accessed. */ protected function _url() { - if (empty($_GET['url'])) { - $uri = $this->_uri(); - $base = $this->base; - - $url = null; - $tmpUri = preg_replace('/^(?:\?)?(?:\/)?/', '', $uri); - $baseDir = trim(dirname($base) . '/', '/'); - - if ($tmpUri === '/' || $tmpUri == $baseDir || $tmpUri == $base) { - $url = '/'; - } else { - $elements = array(); - if ($base && strpos($uri, $base) !== false) { - $elements = explode($base, $uri); - } elseif (preg_match('/^[\/\?\/|\/\?|\?\/]/', $uri)) { - $elements = array(1 => preg_replace('/^[\/\?\/|\/\?|\?\/]/', '', $uri)); - } - - if (!empty($elements[1])) { - $url = $elements[1]; - } else { - $url = '/'; - } - } - } else { - $url = $_GET['url']; + if (!empty($_SERVER['PATH_INFO'])) { + return $_SERVER['PATH_INFO']; + } elseif (isset($_SERVER['REQUEST_URI'])) { + $uri = $_SERVER['REQUEST_URI']; + } elseif (isset($_SERVER['PHP_SELF']) && isset($_SERVER['SCRIPT_NAME'])) { + $uri = str_replace($_SERVER['SCRIPT_NAME'], '', $_SERVER['PHP_SELF']); + } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) { + $uri = $_SERVER['HTTP_X_REWRITE_URL']; + } elseif ($var = env('argv')) { + $uri = $var[0]; } - return $url; + + $base = $this->base; + + if (strlen($base) > 0 && strpos($uri, $base) === 0) { + $uri = substr($uri, strlen($base)); + } + if (strpos($uri, '?') !== false) { + $uri = parse_url($uri, PHP_URL_PATH); + } + if (empty($uri) || $uri == '/' || $uri == '//') { + return '/'; + } + return $uri; } /** @@ -272,17 +225,16 @@ class CakeRequest implements ArrayAccess { $config = Configure::read('App'); extract($config); - if (!$base) { + if (empty($base)) { $base = $this->base; } - if ($base !== false) { $this->webroot = $base . '/'; - return $base; + return $this->base = $base; } + if (!$baseUrl) { - $replace = array('<', '>', '*', '\'', '"'); - $base = str_replace($replace, '', dirname(env('PHP_SELF'))); + $base = dirname(env('SCRIPT_NAME')); if ($webroot === 'webroot' && $webroot === basename($base)) { $base = dirname($base); @@ -296,7 +248,7 @@ class CakeRequest implements ArrayAccess { } $this->webroot = $base .'/'; - return $base; + return $this->base = $base; } $file = '/' . basename($baseUrl); @@ -305,9 +257,12 @@ class CakeRequest implements ArrayAccess { if ($base === DS || $base === '.') { $base = ''; } - $this->webroot = $base .'/'; + $this->webroot = $base . '/'; - if (!empty($base)) { + $docRoot = env('DOCUMENT_ROOT'); + $docRootContainsWebroot = strpos($docRoot, $dir . '/' . $webroot); + + if (!empty($base) || !$docRootContainsWebroot) { if (strpos($this->webroot, $dir) === false) { $this->webroot .= $dir . '/' ; } @@ -315,7 +270,7 @@ class CakeRequest implements ArrayAccess { $this->webroot .= $webroot . '/'; } } - return $base . $file; + return $this->base = $base . $file; } /** @@ -425,7 +380,7 @@ class CakeRequest implements ArrayAccess { $type = strtolower(substr($name, 2)); return $this->is($type); } - throw new CakeException(__('Method %s does not exist', $name)); + throw new CakeException(__d('cake_dev', 'Method %s does not exist', $name)); } /** @@ -545,6 +500,23 @@ class CakeRequest implements ArrayAccess { return $this; } +/** + * Get the value of the current requests url. Will include named parameters and querystring arguments. + * + * @param boolean $base Include the base path, set to false to trim the base path off. + * @return string the current request url including query string args. + */ + public function here($base = true) { + $url = $this->here; + if (!empty($this->query)) { + $url .= '?' . http_build_query($this->query); + } + if (!$base) { + $url = preg_replace('/^' . preg_quote($this->base, '/') . '/', '', $url, 1); + } + return $url; + } + /** * Read an HTTP header from the Request information. * @@ -580,7 +552,8 @@ class CakeRequest implements ArrayAccess { /** * Get the domain name and include $tldLength segments of the tld. * - * @param int $tldLength Number of segments your tld contains + * @param int $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld. + * While `example.co.uk` contains 2. * @return string Domain name without subdomains. */ public function domain($tldLength = 1) { @@ -592,7 +565,8 @@ class CakeRequest implements ArrayAccess { /** * Get the subdomains for a host. * - * @param int $tldLength Number of segments your tld contains. + * @param int $tldLength Number of segments your tld contains. For example: `example.com` contains 1 tld. + * While `example.co.uk` contains 2. * @return array of subdomains. */ public function subdomains($tldLength = 1) { diff --git a/cake/libs/cake_response.php b/lib/Cake/Network/CakeResponse.php similarity index 99% rename from cake/libs/cake_response.php rename to lib/Cake/Network/CakeResponse.php index 9c200cbcb..e1abb8a3d 100644 --- a/cake/libs/cake_response.php +++ b/lib/Cake/Network/CakeResponse.php @@ -459,7 +459,7 @@ class CakeResponse { return $this->_status; } if (!isset($this->_statusCodes[$code])) { - throw new CakeException(__('Unknown status code')); + throw new CakeException(__d('cake_dev', 'Unknown status code')); } return $this->_status = $code; } diff --git a/cake/libs/cake_socket.php b/lib/Cake/Network/CakeSocket.php similarity index 97% rename from cake/libs/cake_socket.php rename to lib/Cake/Network/CakeSocket.php index 82610ff92..4d6c2c720 100644 --- a/cake/libs/cake_socket.php +++ b/lib/Cake/Network/CakeSocket.php @@ -16,7 +16,7 @@ * @since CakePHP(tm) v 1.2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'Validation'); +App::uses('Validation', 'Utility'); /** * Cake network socket connection class. @@ -117,7 +117,7 @@ class CakeSocket { } if (!empty($errNum) || !empty($errStr)) { - $this->setLastError($errStr, $errNum); + $this->setLastError($errNum, $errStr); throw new SocketException($errStr, $errNum); } @@ -221,7 +221,7 @@ class CakeSocket { $buffer = fread($this->connection, $length); $info = stream_get_meta_data($this->connection); if ($info['timed_out']) { - $this->setLastError(E_WARNING, __('Connection timed out')); + $this->setLastError(E_WARNING, __d('cake_dev', 'Connection timed out')); return false; } return $buffer; diff --git a/cake/libs/http/basic_authentication.php b/lib/Cake/Network/Http/BasicAuthentication.php similarity index 100% rename from cake/libs/http/basic_authentication.php rename to lib/Cake/Network/Http/BasicAuthentication.php diff --git a/cake/libs/http/digest_authentication.php b/lib/Cake/Network/Http/DigestAuthentication.php similarity index 100% rename from cake/libs/http/digest_authentication.php rename to lib/Cake/Network/Http/DigestAuthentication.php diff --git a/cake/libs/http_response.php b/lib/Cake/Network/Http/HttpResponse.php similarity index 97% rename from cake/libs/http_response.php rename to lib/Cake/Network/Http/HttpResponse.php index 51aff7a78..04322547f 100644 --- a/cake/libs/http_response.php +++ b/lib/Cake/Network/Http/HttpResponse.php @@ -126,11 +126,11 @@ class HttpResponse implements ArrayAccess { */ public function parseResponse($message) { if (!is_string($message)) { - throw new SocketException(__('Invalid response.')); + throw new SocketException(__d('cake_dev', 'Invalid response.')); } if (!preg_match("/^(.+\r\n)(.*)(?<=\r\n)\r\n/Us", $message, $match)) { - throw new SocketException(__('Invalid HTTP response.')); + throw new SocketException(__d('cake_dev', 'Invalid HTTP response.')); } list(, $statusLine, $header) = $match; @@ -198,7 +198,7 @@ class HttpResponse implements ArrayAccess { while ($chunkLength !== 0) { if (!preg_match("/^([0-9a-f]+) *(?:;(.+)=(.+))?\r\n/iU", $body, $match)) { - throw new SocketException(__('HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.')); + throw new SocketException(__d('cake_dev', 'HttpSocket::_decodeChunkedBody - Could not parse malformed chunk.')); } $chunkSize = 0; diff --git a/cake/libs/http_socket.php b/lib/Cake/Network/Http/HttpSocket.php similarity index 94% rename from cake/libs/http_socket.php rename to lib/Cake/Network/Http/HttpSocket.php index 9e820f921..926d70ee6 100644 --- a/cake/libs/http_socket.php +++ b/lib/Cake/Network/Http/HttpSocket.php @@ -16,8 +16,8 @@ * @since CakePHP(tm) v 1.2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'CakeSocket'); -App::import('Core', 'Router'); +App::uses('CakeSocket', 'Network'); +App::uses('Router', 'Routing'); /** * Cake network socket connection class. @@ -211,7 +211,7 @@ class HttpSocket extends CakeSocket { return; } if (!is_resource($resource)) { - throw new SocketException(__('Invalid resource.')); + throw new SocketException(__d('cake_dev', 'Invalid resource.')); } $this->_contentResource = $resource; } @@ -363,8 +363,10 @@ class HttpSocket extends CakeSocket { $this->disconnect(); } - if (!App::import('Lib', $this->responseClass)) { - throw new SocketException(__('Class %s not found.', $this->responseClass)); + list($plugin, $responseClass) = pluginSplit($this->responseClass, true); + App::uses($this->responseClass, $plugin . 'Network/Http'); + if (!class_exists($responseClass)) { + throw new SocketException(__d('cake_dev', 'Class %s not found.', $this->responseClass)); } $responseClass = $this->responseClass; $this->response = new $responseClass($response); @@ -530,12 +532,15 @@ class HttpSocket extends CakeSocket { return; } $method = key($this->_auth); - $authClass = Inflector::camelize($method) . 'Authentication'; - if (!App::import('Lib', 'http/' . $authClass)) { - throw new SocketException(__('Unknown authentication method.')); + list($plugin, $authClass) = pluginSplit($method, true); + $authClass = Inflector::camelize($authClass) . 'Authentication'; + App::uses($authClass, $plugin . 'Network/Http'); + + if (!class_exists($authClass)) { + throw new SocketException(__d('cake_dev', 'Unknown authentication method.')); } if (!method_exists($authClass, 'authentication')) { - throw new SocketException(sprintf(__('The %s do not support authentication.'), $authClass)); + throw new SocketException(sprintf(__d('cake_dev', 'The %s do not support authentication.'), $authClass)); } call_user_func_array("$authClass::authentication", array($this, &$this->_auth[$method])); } @@ -556,12 +561,15 @@ class HttpSocket extends CakeSocket { if (empty($this->_proxy['method']) || !isset($this->_proxy['user'], $this->_proxy['pass'])) { return; } - $authClass = Inflector::camelize($this->_proxy['method']) . 'Authentication'; - if (!App::import('Lib', 'http/' . $authClass)) { - throw new SocketException(__('Unknown authentication method for proxy.')); + list($plugin, $authClass) = pluginSplit($this->_proxy['method'], true); + $authClass = Inflector::camelize($authClass) . 'Authentication'; + App::uses($authClass, $plugin. 'Network/Http'); + + if (!class_exists($authClass)) { + throw new SocketException(__d('cake_dev', 'Unknown authentication method for proxy.')); } if (!method_exists($authClass, 'proxyAuthentication')) { - throw new SocketException(sprintf(__('The %s do not support proxy authentication.'), $authClass)); + throw new SocketException(sprintf(__d('cake_dev', 'The %s do not support proxy authentication.'), $authClass)); } call_user_func_array("$authClass::proxyAuthentication", array($this, &$this->_proxy)); } @@ -779,7 +787,7 @@ class HttpSocket extends CakeSocket { if (is_string($request)) { $isValid = preg_match("/(.+) (.+) (.+)\r\n/U", $request, $match); if (!$this->quirksMode && (!$isValid || ($match[2] == '*' && !in_array($match[3], $asteriskMethods)))) { - throw new SocketException(__('HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.')); + throw new SocketException(__d('cake_dev', 'HttpSocket::_buildRequestLine - Passed an invalid request line string. Activate quirks mode to do this.')); } return $request; } elseif (!is_array($request)) { @@ -797,7 +805,7 @@ class HttpSocket extends CakeSocket { } if (!$this->quirksMode && $request['uri'] === '*' && !in_array($request['method'], $asteriskMethods)) { - throw new SocketException(__('HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.', implode(',', $asteriskMethods))); + throw new SocketException(__d('cake_dev', 'HttpSocket::_buildRequestLine - The "*" asterisk character is only allowed for the following methods: %s. Activate quirks mode to work outside of HTTP/1.1 specs.', implode(',', $asteriskMethods))); } return $request['method'] . ' ' . $request['uri'] . ' ' . $versionToken . "\r\n"; } diff --git a/cake/libs/dispatcher.php b/lib/Cake/Routing/Dispatcher.php similarity index 88% rename from cake/libs/dispatcher.php rename to lib/Cake/Routing/Dispatcher.php index f8c833bc9..be0ebe77e 100644 --- a/cake/libs/dispatcher.php +++ b/lib/Cake/Routing/Dispatcher.php @@ -23,10 +23,13 @@ /** * List of helpers to include */ -App::import('Core', 'Router', false); -App::import('Core', 'CakeRequest', false); -App::import('Core', 'CakeResponse', false); -App::import('Controller', 'Controller', false); +App::uses('Router', 'Routing'); +App::uses('CakeRequest', 'Network'); +App::uses('CakeResponse', 'Network'); +App::uses('Controller', 'Controller'); +App::uses('Scaffold', 'Controller'); +App::uses('View', 'View'); +App::uses('Debugger', 'Utility'); /** * Dispatcher converts Requests into controller actions. It uses the dispatched Request @@ -37,22 +40,6 @@ App::import('Controller', 'Controller', false); */ class Dispatcher { -/** - * Current URL - * - * @var string - * @access public - */ - public $here = false; - -/** - * The request object - * - * @var CakeRequest - * @access public - */ - public $request = null; - /** * Response object used for asset/cached responses. * @@ -91,24 +78,20 @@ class Dispatcher { * are encountered. */ public function dispatch(CakeRequest $request, $additionalParams = array()) { - $this->here = $request->here; - - if ($this->asset($request->url) || $this->cached($request->url)) { + if ($this->asset($request->url) || $this->cached($request->here)) { return; } - $this->request = $this->parseParams($request, $additionalParams); - $controller = $this->_getController($this->request); + $request = $this->parseParams($request, $additionalParams); + Router::setRequestInfo($request); + $controller = $this->_getController($request); - if (!is_object($controller)) { - Router::setRequestInfo($request); + if (!($controller instanceof Controller)) { throw new MissingControllerException(array( 'controller' => Inflector::camelize($request->params['controller']) . 'Controller' )); } - Router::setRequestInfo($request); - if ($this->_isPrivateAction($request)) { throw new PrivateActionException(array( 'controller' => Inflector::camelize($request->params['controller']) . "Controller", @@ -130,14 +113,13 @@ class Dispatcher { $privateAction = $request->params['action'][0] === '_'; $prefixes = Router::prefixes(); - if (!empty($prefixes)) { - if (isset($request->params['prefix'])) { - $request->params['action'] = $request->params['prefix'] . '_' . $request->params['action']; - } elseif (strpos($request->params['action'], '_') > 0) { + if (!$privateAction && !empty($prefixes)) { + if (empty($request->params['prefix']) && strpos($request->params['action'], '_') > 0) { list($prefix, $action) = explode('_', $request->params['action']); $privateAction = in_array($prefix, $prefixes); } } + return $privateAction; } @@ -159,7 +141,6 @@ class Dispatcher { if (!isset($methods[$request->params['action']])) { if ($controller->scaffold !== false) { - App::import('Controller', 'Scaffold', false); return new Scaffold($controller, $request); } throw new MissingActionException(array( @@ -219,10 +200,7 @@ class Dispatcher { if (!$ctrlClass) { return false; } - $ctrlClass .= 'Controller'; - if (class_exists($ctrlClass)) { - return new $ctrlClass($request); - } + return new $ctrlClass($request); } /** @@ -241,8 +219,12 @@ class Dispatcher { $controller = Inflector::camelize($request->params['controller']); } if ($pluginPath . $controller) { - if (App::import('Controller', $pluginPath . $controller)) { - return $controller; + $class = $controller . 'Controller'; + App::uses('AppController', 'Controller'); + App::uses($pluginName . 'AppController', $pluginPath . 'Controller'); + App::uses($class, $pluginPath . 'Controller'); + if (class_exists($class)) { + return $class; } } return false; @@ -260,12 +242,11 @@ class Dispatcher { /** * Outputs cached dispatch view cache * - * @param string $url Requested URL + * @param string $path Requested URL path */ - public function cached($url) { + public function cached($path) { if (Configure::read('Cache.check') === true) { - $path = $this->here; - if ($this->here == '/') { + if ($path == '/') { $path = 'home'; } $path = strtolower(Inflector::slug($path)); @@ -277,9 +258,6 @@ class Dispatcher { } if (file_exists($filename)) { - if (!class_exists('View')) { - App::import('View', 'View', false); - } $controller = null; $view = new View($controller); return $view->renderCache($filename, microtime(true)); @@ -313,13 +291,13 @@ class Dispatcher { if (($isCss && empty($filters['css'])) || ($isJs && empty($filters['js']))) { $this->response->statusCode(404); $this->response->send(); - return $this->_stop(); + return true; } elseif ($isCss) { include WWW_ROOT . DS . $filters['css']; - $this->_stop(); + return true; } elseif ($isJs) { include WWW_ROOT . DS . $filters['js']; - $this->_stop(); + return true; } $controller = null; $pathSegments = explode('.', $url); diff --git a/cake/libs/route/cake_route.php b/lib/Cake/Routing/Route/CakeRoute.php similarity index 66% rename from cake/libs/route/cake_route.php rename to lib/Cake/Routing/Route/CakeRoute.php index be944951f..c40c84e18 100644 --- a/cake/libs/route/cake_route.php +++ b/lib/Cake/Routing/Route/CakeRoute.php @@ -173,7 +173,7 @@ class CakeRoute { /** * Checks to see if the given URL can be parsed by this route. - * If the route can be parsed an array of parameters will be returned if not + * If the route can be parsed an array of parameters will be returned; if not * false will be returned. String urls are parsed if they match a routes regular expression. * * @param string $url The url to attempt to parse. @@ -185,45 +185,167 @@ class CakeRoute { } if (!preg_match($this->_compiledRoute, $url, $route)) { return false; - } else { - foreach ($this->defaults as $key => $val) { - if ($key[0] === '[' && preg_match('/^\[(\w+)\]$/', $key, $header)) { - if (isset($this->__headerMap[$header[1]])) { - $header = $this->__headerMap[$header[1]]; - } else { - $header = 'http_' . $header[1]; - } - - $val = (array)$val; - $h = false; - - foreach ($val as $v) { - if (env(strtoupper($header)) === $v) { - $h = true; - } - } - if (!$h) { - return false; - } - } - } - array_shift($route); - $count = count($this->keys); - for ($i = 0; $i <= $count; $i++) { - unset($route[$i]); - } - $route['pass'] = $route['named'] = array(); - $route += $this->defaults; - - //move numerically indexed elements from the defaults into pass. - foreach ($route as $key => $value) { - if (is_integer($key)) { - $route['pass'][] = $value; - unset($route[$key]); - } - } - return $route; } + foreach ($this->defaults as $key => $val) { + if ($key[0] === '[' && preg_match('/^\[(\w+)\]$/', $key, $header)) { + if (isset($this->__headerMap[$header[1]])) { + $header = $this->__headerMap[$header[1]]; + } else { + $header = 'http_' . $header[1]; + } + $header = strtoupper($header); + + $val = (array)$val; + $h = false; + + foreach ($val as $v) { + if (env($header) === $v) { + $h = true; + } + } + if (!$h) { + return false; + } + } + } + array_shift($route); + $count = count($this->keys); + for ($i = 0; $i <= $count; $i++) { + unset($route[$i]); + } + $route['pass'] = $route['named'] = array(); + + // Assign defaults, set passed args to pass + foreach ($this->defaults as $key => $value) { + if (isset($route[$key])) { + continue; + } + if (is_integer($key)) { + $route['pass'][] = $value; + continue; + } + $route[$key] = $value; + } + + if (isset($route['_args_'])) { + list($pass, $named) = $this->_parseArgs($route['_args_'], $route); + $route['pass'] = array_merge($route['pass'], $pass); + $route['named'] = $named; + unset($route['_args_']); + } + + // restructure 'pass' key route params + if (isset($this->options['pass'])) { + $j = count($this->options['pass']); + while($j--) { + if (isset($route[$this->options['pass'][$j]])) { + array_unshift($route['pass'], $route[$this->options['pass'][$j]]); + } + } + } + return $route; + } + +/** + * Parse passed and Named parameters into a list of passed args, and a hash of named parameters. + * The local and global configuration for named parameters will be used. + * + * @param string $args A string with the passed & named params. eg. /1/page:2 + * @param string $context The current route context, which should contain controller/action keys. + * @return array Array of ($pass, $named) + */ + protected function _parseArgs($args, $context) { + $pass = $named = array(); + $args = explode('/', $args); + + $namedConfig = Router::namedConfig(); + $greedy = $namedConfig['greedyNamed']; + $rules = $namedConfig['rules']; + if (!empty($this->options['named'])) { + $greedy = isset($this->options['greedyNamed']) && $this->options['greedyNamed'] === true; + foreach ((array)$this->options['named'] as $key => $val) { + if (is_numeric($key)) { + $rules[$val] = true; + continue; + } + $rules[$key] = $val; + } + } + + foreach ($args as $param) { + if (empty($param) && $param !== '0' && $param !== 0) { + continue; + } + + $separatorIsPresent = strpos($param, $namedConfig['separator']) !== false; + if ((!isset($this->options['named']) || !empty($this->options['named'])) && $separatorIsPresent) { + list($key, $val) = explode($namedConfig['separator'], $param, 2); + $hasRule = isset($rules[$key]); + $passIt = (!$hasRule && !$greedy) || ($hasRule && !$this->_matchNamed($key, $val, $rules[$key], $context)); + if ($passIt) { + $pass[] = $param; + } else { + if (preg_match_all('/\[([A-Za-z0-9_-]+)?\]/', $key, $matches, PREG_SET_ORDER)) { + $matches = array_reverse($matches); + $parts = explode('[', $key); + $key = array_shift($parts); + $arr = $val; + foreach ($matches as $match) { + if (empty($match[1])) { + $arr = array($arr); + } else { + $arr = array( + $match[1] => $arr + ); + } + } + $val = $arr; + } + $named = array_merge_recursive($named, array($key => $val)); + } + } else { + $pass[] = $param; + } + } + return array($pass, $named); + } + +/** + * Return true if a given named $param's $val matches a given $rule depending on $context. Currently implemented + * rule types are controller, action and match that can be combined with each other. + * + * @param string $param The name of the named parameter + * @param string $val The value of the named parameter + * @param array $rule The rule(s) to apply, can also be a match string + * @param string $context An array with additional context information (controller / action) + * @return boolean + */ + protected function _matchNamed($param, $val, $rule, $context) { + if ($rule === true || $rule === false) { + return $rule; + } + if (is_string($rule)) { + $rule = array('match' => $rule); + } + if (!is_array($rule)) { + return false; + } + + $controllerMatches = ( + !isset($rule['controller'], $context['controller']) || + in_array($context['controller'], (array)$rule['controller']) + ); + if (!$controllerMatches) { + return false; + } + $actionMatches = ( + !isset($rule['action'], $context['action']) || + in_array($context['action'], (array)$rule['action']) + ); + if (!$actionMatches) { + return false; + } + return (!isset($rule['match']) || preg_match('/' . $rule['match'] . '/', $val)); } /** @@ -245,8 +367,8 @@ class CakeRoute { } /** - * Attempt to match a url array. If the url matches the route parameters + settings, then - * return a generated string url. If the url doesn't match the route parameters false will be returned. + * Attempt to match a url array. If the url matches the route parameters and settings, then + * return a generated string url. If the url doesn't match the route parameters, false will be returned. * This method handles the reverse routing or conversion of url arrays into string urls. * * @param array $url An array of parameters to check matching with. @@ -273,8 +395,9 @@ class CakeRoute { return false; } - $greedyNamed = Router::$named['greedy']; - $allowedNamedParams = Router::$named['rules']; + $namedConfig = Router::namedConfig(); + $greedyNamed = $namedConfig['greedyNamed']; + $allowedNamedParams = $namedConfig['rules']; $named = $pass = $_query = array(); @@ -331,7 +454,7 @@ class CakeRoute { } } } - return $this->_writeUrl(array_merge($url, compact('pass', 'named', '_query'))); + return $this->_writeUrl(array_merge($url, compact('pass', 'named'))); } /** @@ -351,7 +474,8 @@ class CakeRoute { $params['pass'] = implode('/', $params['pass']); } - $separator = Router::$named['separator']; + $namedConfig = Router::namedConfig(); + $separator = $namedConfig['separator']; if (!empty($params['named']) && is_array($params['named'])) { $named = array(); @@ -388,20 +512,4 @@ class CakeRoute { return $out; } -/** - * Generates a well-formed querystring from $q - * - * Will compose an array or nested array into a proper querystring. - * - * @param mixed $q An array of parameters to compose into a query string. - * @param bool $escape Whether or not to use escaped & - * @return string - */ - public function queryString($q, $escape = false) { - $join = '&'; - if ($escape === true) { - $join = '&'; - } - return '?' . http_build_query($q, null, $join); - } } \ No newline at end of file diff --git a/cake/libs/route/plugin_short_route.php b/lib/Cake/Routing/Route/PluginShortRoute.php similarity index 97% rename from cake/libs/route/plugin_short_route.php rename to lib/Cake/Routing/Route/PluginShortRoute.php index 9509c5d32..a0f2d18a9 100644 --- a/cake/libs/route/plugin_short_route.php +++ b/lib/Cake/Routing/Route/PluginShortRoute.php @@ -1,5 +1,5 @@ redirect[0]; } if (isset($this->options['persist']) && is_array($redirect)) { - $argOptions['context'] = array('action' => $redirect['action'], 'controller' => $redirect['controller']); - $redirect += Router::getArgs($params['_args_'], $argOptions) + array('url' => array()); + $redirect += array('named' => $params['named'], 'pass' => $params['pass'], 'url' => array()); $redirect = Router::reverse($redirect); } $status = 301; diff --git a/cake/libs/router.php b/lib/Cake/Routing/Router.php similarity index 84% rename from cake/libs/router.php rename to lib/Cake/Routing/Router.php index c0737ae25..fd60e2b8e 100644 --- a/cake/libs/router.php +++ b/lib/Cake/Routing/Router.php @@ -17,8 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'CakeRequest'); -App::import('Core', 'route/CakeRoute'); +App::uses('CakeRequest', 'Network'); +App::uses('CakeRoute', 'Routing/Route'); /** * Parses the request URL into controller, action, and parameters. Uses the connected routes @@ -85,7 +85,7 @@ class Router { const ID = '[0-9]+'; const UUID = '[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}'; - private static $__named = array( + private static $__namedExpressions = array( 'Action' => Router::ACTION, 'Year' => Router::YEAR, 'Month' => Router::MONTH, @@ -100,9 +100,9 @@ class Router { * @var string * @access public */ - public static $named = array( + protected static $_namedConfig = array( 'default' => array('page', 'fields', 'order', 'limit', 'recursive', 'sort', 'direction', 'step'), - 'greedy' => true, + 'greedyNamed' => true, 'separator' => ':', 'rules' => false, ); @@ -186,10 +186,10 @@ class Router { * Gets the named route elements for use in app/config/routes.php * * @return array Named route elements - * @see Router::$__named + * @see Router::$__namedExpressions */ public static function getNamedExpressions() { - return self::$__named; + return self::$__namedExpressions; } /** @@ -221,21 +221,29 @@ class Router { * Shows connecting a route with custom route parameters as well as providing patterns for those parameters. * Patterns for routing parameters do not need capturing groups, as one will be added for each route params. * - * $options offers two 'special' keys. `pass` and `persist` have special meaning in the $options array. + * $options offers four 'special' keys. `pass`, `named`, `persist` and `routeClass` + * have special meaning in the $options array. * * `pass` is used to define which of the routed parameters should be shifted into the pass array. Adding a * parameter to pass will remove it from the regular route array. Ex. `'pass' => array('slug')` * * `persist` is used to define which route parameters should be automatically included when generating - * new urls. You can override peristent parameters by redifining them in a url or remove them by + * new urls. You can override persistent parameters by redefining them in a url or remove them by * setting the parameter to `false`. Ex. `'persist' => array('lang')` * + * `routeClass` is used to extend and change how individual routes parse requests and handle reverse routing, + * via a custom routing class. Ex. `'routeClass' => 'SlugRoute'` + * + * `named` is used to configure named parameters at the route level. This key uses the same options + * as Router::connectNamed() + * * @param string $route A string describing the template of the route * @param array $defaults An array describing the default route parameters. These parameters will be used by default * and can supply routing parameters that are not dynamic. See above. * @param array $options An array matching the named elements in the route to regular expressions which that * element should match. Also contains additional parameters such as which routed parameters should be - * shifted into the passed arguments. As well as supplying patterns for routing parameters. + * shifted into the passed arguments, supplying patterns for routing parameters and supplying the name of a + * custom routing class. * @see routes * @return array Array of routes * @throws RouterException @@ -259,7 +267,7 @@ class Router { if (isset($options['routeClass'])) { $routeClass = $options['routeClass']; if (!is_subclass_of($routeClass, 'CakeRoute')) { - throw new RouterException(__('Route classes must extend CakeRoute')); + throw new RouterException(__d('cake_dev', 'Route classes must extend CakeRoute')); } unset($options['routeClass']); if ($routeClass == 'RedirectRoute' && isset($defaults['redirect'])) { @@ -282,7 +290,7 @@ class Router { * `Router::redirect('/home/*', array('controller' => 'posts', 'action' => 'view', array('persist' => true));` * * Redirects /home/* to /posts/view and passes the parameters to /posts/view. Using an array as the - * redirect destination allows you to use other routes to define where a url string should be redirected ot. + * redirect destination allows you to use other routes to define where a url string should be redirected to. * * `Router::redirect('/posts/*', 'http://google.com', array('status' => 302));` * @@ -303,7 +311,7 @@ class Router { * @return array Array of routes */ public static function redirect($route, $url, $options = array()) { - App::import('Core', 'route/RedirectRoute'); + App::uses('RedirectRoute', 'Routing/Route'); $options['routeClass'] = 'RedirectRoute'; if (is_string($url)) { $url = array('redirect' => $url); @@ -365,7 +373,7 @@ class Router { */ public static function connectNamed($named, $options = array()) { if (isset($options['separator'])) { - self::$named['separator'] = $options['separator']; + self::$_namedConfig['separator'] = $options['separator']; unset($options['separator']); } @@ -376,23 +384,33 @@ class Router { $options = array_merge(array('default' => false, 'reset' => false, 'greedy' => true), $options); } - if ($options['reset'] == true || self::$named['rules'] === false) { - self::$named['rules'] = array(); + if ($options['reset'] == true || self::$_namedConfig['rules'] === false) { + self::$_namedConfig['rules'] = array(); } if ($options['default']) { - $named = array_merge($named, self::$named['default']); + $named = array_merge($named, self::$_namedConfig['default']); } foreach ($named as $key => $val) { if (is_numeric($key)) { - self::$named['rules'][$val] = true; + self::$_namedConfig['rules'][$val] = true; } else { - self::$named['rules'][$key] = $val; + self::$_namedConfig['rules'][$key] = $val; } } - self::$named['greedy'] = $options['greedy']; - return self::$named; + self::$_namedConfig['greedyNamed'] = $options['greedy']; + return self::$_namedConfig; + } + +/** + * Gets the current named parameter configuration values. + * + * @return array + * @see Router::$_namedConfig + */ + public static function namedConfig() { + return self::$_namedConfig; } /** @@ -422,7 +440,10 @@ class Router { * @return array Array of mapped resources */ public static function mapResources($controller, $options = array()) { - $options = array_merge(array('prefix' => '/', 'id' => self::$__named['ID'] . '|' . self::$__named['UUID']), $options); + $options = array_merge(array( + 'prefix' => '/', + 'id' => self::ID . '|' . self::UUID + ), $options); $prefix = $options['prefix']; foreach ((array)$controller as $ctlName) { @@ -482,39 +503,13 @@ class Router { if (($r = $route->parse($url)) !== false) { self::$_currentRoute[] =& $route; - - $params = $route->options; - $argOptions = array(); - - if (array_key_exists('named', $params)) { - $argOptions['named'] = $params['named']; - unset($params['named']); - } - if (array_key_exists('greedy', $params)) { - $argOptions['greedy'] = $params['greedy']; - unset($params['greedy']); - } $out = $r; - - if (isset($out['_args_'])) { - $argOptions['context'] = array('action' => $out['action'], 'controller' => $out['controller']); - $parsedArgs = self::getArgs($out['_args_'], $argOptions); - $out['pass'] = array_merge($out['pass'], $parsedArgs['pass']); - $out['named'] = $parsedArgs['named']; - unset($out['_args_']); - } - - if (isset($params['pass'])) { - $j = count($params['pass']); - while($j--) { - if (isset($out[$params['pass'][$j]])) { - array_unshift($out['pass'], $out[$params['pass'][$j]]); - } - } - } break; } } + if (isset($out['prefix'])) { + $out['action'] = $out['prefix'] . '_' . $out['action']; + } if (!empty($ext) && !isset($out['url']['ext'])) { $out['url']['ext'] = $ext; @@ -588,7 +583,7 @@ class Router { */ private static function __connectDefaultRoutes() { if ($plugins = App::objects('plugin')) { - App::import('Core', 'route/PluginShortRoute'); + App::uses('PluginShortRoute', 'Routing/Route'); foreach ($plugins as $key => $value) { $plugins[$key] = Inflector::underscore($value); } @@ -617,7 +612,7 @@ class Router { self::connect('/:controller', array('action' => 'index')); self::connect('/:controller/:action/*'); - if (self::$named['rules'] === false) { + if (self::$_namedConfig['rules'] === false) { self::connectNamed(true); } self::$_defaultsMapped = true; @@ -731,7 +726,7 @@ class Router { * * @param $which A zero-based array index representing the route to move. For example, * if 3 routes have been added, the last route would be 2. - * @return boolean Retuns false if no route exists at the position specified by $which. + * @return boolean Returns false if no route exists at the position specified by $which. */ public static function promote($which = null) { if ($which === null) { @@ -752,7 +747,7 @@ class Router { * Returns an URL pointing to a combination of controller and action. Param * $url can be: * - * - Empty - the method will find address to actuall controller/action. + * - Empty - the method will find address to actual controller/action. * - '/' - the method will find base URL of application. * - A combination of controller/action - the method will find url for it. * @@ -841,7 +836,7 @@ class Router { } elseif (isset($url[$prefix]) && !$url[$prefix]) { unset($url[$prefix]); } - if (isset($url[$prefix]) && strpos($url['action'], $prefix) === 0) { + if (isset($url[$prefix]) && strpos($url['action'], $prefix . '_') === 0) { $url['action'] = substr($url['action'], strlen($prefix) + 1); } } @@ -967,10 +962,10 @@ class Router { if (is_array($value)) { $flattend = Set::flatten($value, ']['); foreach ($flattend as $namedKey => $namedValue) { - $output .= '/' . $name . "[$namedKey]" . self::$named['separator'] . $namedValue; + $output .= '/' . $name . "[$namedKey]" . self::$_namedConfig['separator'] . $namedValue; } } else { - $output .= '/' . $name . self::$named['separator'] . $value; + $output .= '/' . $name . self::$_namedConfig['separator'] . $value; } } } @@ -980,61 +975,6 @@ class Router { return $output; } -/** - * Takes an array of URL parameters and separates the ones that can be used as named arguments - * - * @param array $params Associative array of URL parameters. - * @param string $controller Name of controller being routed. Used in scoping. - * @param string $action Name of action being routed. Used in scoping. - * @return array - */ - public static function getNamedElements($params, $controller = null, $action = null) { - $named = array(); - - foreach ($params as $param => $val) { - if (isset(self::$named['rules'][$param])) { - $rule = self::$named['rules'][$param]; - if (Router::matchNamed($param, $val, $rule, compact('controller', 'action'))) { - $named[substr($param, 1)] = $val; - unset($params[$param]); - } - } - } - return array($named, $params); - } - -/** - * Return true if a given named $param's $val matches a given $rule depending on $context. Currently implemented - * rule types are controller, action and match that can be combined with each other. - * - * @param string $param The name of the named parameter - * @param string $val The value of the named parameter - * @param array $rule The rule(s) to apply, can also be a match string - * @param string $context An array with additional context information (controller / action) - * @return boolean - */ - public static function matchNamed($param, $val, $rule, $context = array()) { - if ($rule === true || $rule === false) { - return $rule; - } - if (is_string($rule)) { - $rule = array('match' => $rule); - } - if (!is_array($rule)) { - return false; - } - - $controllerMatches = !isset($rule['controller'], $context['controller']) || in_array($context['controller'], (array)$rule['controller']); - if (!$controllerMatches) { - return false; - } - $actionMatches = !isset($rule['action'], $context['action']) || in_array($context['action'], (array)$rule['action']); - if (!$actionMatches) { - return false; - } - return (!isset($rule['match']) || preg_match('/' . $rule['match'] . '/', $val)); - } - /** * Generates a well-formed querystring from $q * @@ -1068,7 +1008,7 @@ class Router { } /** - * Reverses a parsed parameter array into a string. Works similarily to Router::url(), but + * Reverses a parsed parameter array into a string. Works similarly to Router::url(), but * Since parsed URL's contain additional 'pass' and 'named' as well as 'url.url' keys. * Those keys need to be specially handled in order to reverse a params array into a string url. * @@ -1080,11 +1020,14 @@ class Router { */ public static function reverse($params) { if ($params instanceof CakeRequest) { + $url = $params->query; $params = $params->params; + } else { + $url = $params['url']; } $pass = $params['pass']; $named = $params['named']; - $url = $params['url']; + unset( $params['pass'], $params['named'], $params['paging'], $params['models'], $params['url'], $url['url'], $params['autoRender'], $params['bare'], $params['requested'], $params['return'] @@ -1198,70 +1141,7 @@ class Router { return self::$_validExtensions; } -/** - * Takes an passed params and converts it to args - * - * @param array $params - * @return array Array containing passed and named parameters - */ - public static function getArgs($args, $options = array()) { - $pass = $named = array(); - $args = explode('/', $args); - - $greedy = isset($options['greedy']) ? $options['greedy'] : self::$named['greedy']; - $context = array(); - if (isset($options['context'])) { - $context = $options['context']; - } - $rules = self::$named['rules']; - if (isset($options['named'])) { - $greedy = isset($options['greedy']) && $options['greedy'] === true; - foreach ((array)$options['named'] as $key => $val) { - if (is_numeric($key)) { - $rules[$val] = true; - continue; - } - $rules[$key] = $val; - } - } - - foreach ($args as $param) { - if (empty($param) && $param !== '0' && $param !== 0) { - continue; - } - - $separatorIsPresent = strpos($param, self::$named['separator']) !== false; - if ((!isset($options['named']) || !empty($options['named'])) && $separatorIsPresent) { - list($key, $val) = explode(self::$named['separator'], $param, 2); - $hasRule = isset($rules[$key]); - $passIt = (!$hasRule && !$greedy) || ($hasRule && !self::matchNamed($key, $val, $rules[$key], $context)); - if ($passIt) { - $pass[] = $param; - } else { - if (preg_match_all('/\[([A-Za-z0-9_-]+)?\]/', $key, $matches, PREG_SET_ORDER)) { - $matches = array_reverse($matches); - $parts = explode('[', $key); - $key = array_shift($parts); - $arr = $val; - foreach ($matches as $match) { - if (empty($match[1])) { - $arr = array($arr); - } else { - $arr = array( - $match[1] => $arr - ); - } - } - $val = $arr; - } - $named = array_merge_recursive($named, array($key => $val)); - } - } else { - $pass[] = $param; - } - } - return compact('pass', 'named'); - } } + //Save the initial state Router::reload(); diff --git a/cake/tests/lib/cake_test_case.php b/lib/Cake/TestSuite/CakeTestCase.php similarity index 97% rename from cake/tests/lib/cake_test_case.php rename to lib/Cake/TestSuite/CakeTestCase.php index 7581bd6a8..b769ebdf0 100644 --- a/cake/tests/lib/cake_test_case.php +++ b/lib/Cake/TestSuite/CakeTestCase.php @@ -19,19 +19,18 @@ PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); -require_once CAKE_TESTS_LIB . 'cake_fixture_manager.php'; -require_once CAKE_TESTS_LIB . 'cake_test_model.php'; -require_once CAKE_TESTS_LIB . 'cake_test_fixture.php'; +App::uses('CakeFixtureManager', 'TestSuite/Fixture'); +App::uses('CakeTestFixture', 'TestSuite/Fixture'); /** * CakeTestCase class * * @package cake.tests.lib */ -class CakeTestCase extends PHPUnit_Framework_TestCase { +abstract class CakeTestCase extends PHPUnit_Framework_TestCase { /** - * The class responsible for managinf the creation, loading and removing of fixtures + * The class responsible for managing the creation, loading and removing of fixtures * * @var CakeFixtureManager * @access public @@ -185,7 +184,7 @@ class CakeTestCase extends PHPUnit_Framework_TestCase { */ function loadFixtures() { if (empty($this->fixtureManager)) { - throw new Exception(__('No fixture manager to load the test fixture')); + throw new Exception(__d('cake_dev', 'No fixture manager to load the test fixture')); } $args = func_get_args(); foreach ($args as $class) { diff --git a/lib/Cake/TestSuite/CakeTestLoader.php b/lib/Cake/TestSuite/CakeTestLoader.php new file mode 100644 index 000000000..e00b716f4 --- /dev/null +++ b/lib/Cake/TestSuite/CakeTestLoader.php @@ -0,0 +1,106 @@ +_resolveTestFile($filePath, $params); + return parent::load('', $file); + } + +/** + * Convert path fragments used by Cake's test runner to absolute paths that can be fed to PHPUnit. + * + * @return void + */ + protected function _resolveTestFile($filePath, $params) { + $basePath = $this->_basePath($params) . DS . $filePath; + $ending = 'Test.php'; + return (strpos($basePath, $ending) === (strlen($basePath) - strlen($ending))) ? $basePath : $basePath . $ending; + } + +/** + * Generates the base path to a set of tests based on the parameters. + * + * @param array $params + * @return string The base path. + */ + protected static function _basePath($params) { + $result = null; + if (!empty($params['core'])) { + $result = CORE_TEST_CASES; + } elseif (!empty($params['app'])) { + $result = APP_TEST_CASES; + } else if (!empty($params['plugin'])) { + $pluginPath = App::pluginPath($params['plugin']); + $result = $pluginPath . 'tests' . DS . 'Case'; + } + return $result; + } + +/** + * Get the list of files for the test listing. + * + * @return void + */ + public static function generateTestList($params) { + $directory = self::_basePath($params); + $fileList = self::_getRecursiveFileList($directory); + + $testCases = array(); + foreach ($fileList as $testCaseFile) { + $case = str_replace($directory . DS, '', $testCaseFile); + $case = str_replace('Test.php', '', $case); + $testCases[$testCaseFile] = $case; + } + return $testCases; + } + +/** + * Gets a recursive list of files from a given directory and matches then against + * a given fileTestFunction, like isTestCaseFile() + * + * @param string $directory The directory to scan for files. + * @param mixed $fileTestFunction + */ + protected static function _getRecursiveFileList($directory = '.') { + $fileList = array(); + if (!is_dir($directory)) { + return $fileList; + } + + $files = new RegexIterator( + new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)), + '/.*Test.php$/' + ); + + foreach ($files as $file) { + $fileList[] = $file->getPathname(); + } + return $fileList; + } + +} diff --git a/lib/Cake/TestSuite/CakeTestRunner.php b/lib/Cake/TestSuite/CakeTestRunner.php new file mode 100644 index 000000000..0de3880ce --- /dev/null +++ b/lib/Cake/TestSuite/CakeTestRunner.php @@ -0,0 +1,95 @@ +addFileToBlacklist(__FILE__, 'DEFAULT'); + +/** + * A custom test runner for Cake's use of PHPUnit. + * + * @package cake.tests.lib + */ +class CakeTestRunner extends PHPUnit_TextUI_TestRunner { +/** + * Lets us pass in some options needed for cake's webrunner. + * + * @return void + */ + public function __construct($loader, $params) { + parent::__construct($loader); + $this->_params = $params; + } + +/** + * Actually run a suite of tests. Cake initializes fixtures here using the chosen fixture manager + * + * @param PHPUnit_Framework_Test $suite + * @param array $arguments + * @return void + */ + public function doRun(PHPUnit_Framework_Test $suite, array $arguments = array()) { + if (isset($arguments['printer'])) { + self::$versionStringPrinted = true; + } + + $fixture = $this->_getFixtureManager($arguments); + foreach ($suite->getIterator() as $test) { + if ($test instanceof CakeTestCase) { + $fixture->fixturize($test); + $test->fixtureManager = $fixture; + } + } + + $return = parent::doRun($suite, $arguments); + $fixture->shutdown(); + return $return; + } + +/** + * Create the test result and splice on our code coverage reports. + * + * @return PHPUnit_Framework_TestResult + */ + protected function createTestResult() { + $result = new PHPUnit_Framework_TestResult; + if (isset($this->_params['codeCoverage'])) { + $result->collectCodeCoverageInformation(true); + } + return $result; + } + +/** + * Get the fixture manager class specified or use the default one. + * + * @return instance of a fixture manager. + */ + protected function _getFixtureManager($arguments) { + if (isset($arguments['fixtureManager'])) { + App::uses($arguments['fixtureManager'], 'TestSuite'); + if (class_exists($arguments['fixtureManager'])) { + return new $arguments['fixtureManager']; + } + throw new RuntimeException(__d('cake_dev', 'Could not find fixture manager %s.', $arguments['fixtureManager'])); + } + App::uses('AppFixtureManager', 'TestSuite'); + if (class_exists('AppFixtureManager')) { + return new AppFixtureManager(); + } + return new CakeFixtureManager(); + } +} \ No newline at end of file diff --git a/cake/tests/lib/cake_test_suite.php b/lib/Cake/TestSuite/CakeTestSuite.php similarity index 59% rename from cake/tests/lib/cake_test_suite.php rename to lib/Cake/TestSuite/CakeTestSuite.php index f7d7497d5..7c5f49193 100644 --- a/cake/tests/lib/cake_test_suite.php +++ b/lib/Cake/TestSuite/CakeTestSuite.php @@ -16,25 +16,10 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); + class CakeTestSuite extends PHPUnit_Framework_TestSuite { -/** - * Instance of a fixture manager - * @var CakeFixtureManager - */ - protected $_fixtureManager = null; - -/** - * Sets the intances for the fixture manager that will be used by this class. - * - * @param CakeFixtureManager $manager the instance of the manager class - * @return void - * @access public - */ - public function setFixtureManager(CakeFixtureManager $manager) { - $this->_fixtureManager = $manager; - } - /** * Adds all the files in a directory to the test suite. Does not recurse through directories. * @@ -71,35 +56,4 @@ class CakeTestSuite extends PHPUnit_Framework_TestSuite { } } -/** - * Method that is called before the tests of this test suite are run. - * It will load fixtures accordingly for each test. - * - * @return void - * @access protected - */ - protected function setUp() { - parent::setUp(); - if (!$this->_fixtureManager) { - return; - } - $classes = array(); - foreach ($this->getIterator() as $test) { - $this->_fixtureManager->fixturize($test); - $test->fixtureManager = $this->_fixtureManager; - } - } - -/** - * Method that is called after all the tests of this test suite are run. - * - * @return void - * @access protected - */ - protected function tearDown() { - parent::tearDown(); - if ($this->_fixtureManager) { - $this->_fixtureManager->shutDown(); - } - } } \ No newline at end of file diff --git a/lib/Cake/TestSuite/CakeTestSuiteCommand.php b/lib/Cake/TestSuite/CakeTestSuiteCommand.php new file mode 100644 index 000000000..29dfd8f1d --- /dev/null +++ b/lib/Cake/TestSuite/CakeTestSuiteCommand.php @@ -0,0 +1,177 @@ +addFileToBlacklist(__FILE__, 'DEFAULT'); + +/** + * Class to customize loading of test suites from CLI + * + * @package cake.tests.lib + */ +class CakeTestSuiteCommand extends PHPUnit_TextUI_Command { + +/** + * Construct method + * + * @param array $params list of options to be used for this run + */ + public function __construct($loader, $params = array()) { + if ($loader && !class_exists($loader)) { + throw new MissingTestLoaderException(array('class' => $loader)); + } + $this->arguments['loader'] = $loader; + $this->arguments['test'] = $params['case']; + $this->arguments['testFile'] = $params; + $this->_params = $params; + + $this->longOptions['fixture='] = 'handleFixture'; + $this->longOptions['output='] = 'handleReporter'; + } + +/** + * Ugly hack to get around PHPUnit having a hard coded classname for the Runner. :( + * + * @param array $argv + * @param boolean $exit + */ + public function run(array $argv, $exit = true) { + $this->handleArguments($argv); + + $runner = $this->getRunner($this->arguments['loader']); + + if (is_object($this->arguments['test']) && + $this->arguments['test'] instanceof PHPUnit_Framework_Test) { + $suite = $this->arguments['test']; + } else { + $suite = $runner->getTest( + $this->arguments['test'], + $this->arguments['testFile'], + $this->arguments['syntaxCheck'] + ); + } + + if (count($suite) == 0) { + $skeleton = new PHPUnit_Util_Skeleton_Test( + $suite->getName(), + $this->arguments['testFile'] + ); + + $result = $skeleton->generate(true); + + if (!$result['incomplete']) { + eval(str_replace(array(''), '', $result['code'])); + $suite = new PHPUnit_Framework_TestSuite( + $this->arguments['test'] . 'Test' + ); + } + } + + if ($this->arguments['listGroups']) { + PHPUnit_TextUI_TestRunner::printVersionString(); + + print "Available test group(s):\n"; + + $groups = $suite->getGroups(); + sort($groups); + + foreach ($groups as $group) { + print " - $group\n"; + } + + exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); + } + + unset($this->arguments['test']); + unset($this->arguments['testFile']); + + try { + $result = $runner->doRun($suite, $this->arguments); + } + + catch (PHPUnit_Framework_Exception $e) { + print $e->getMessage() . "\n"; + } + + if ($exit) { + if (isset($result) && $result->wasSuccessful()) { + exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); + } + + else if (!isset($result) || $result->errorCount() > 0) { + exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT); + } + + else { + exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT); + } + } + } + +/** + * Create a runner for the command. + * + * @param $loader The loader to be used for the test run. + * @return CakeTestRunner + */ + public function getRunner($loader) { + return new CakeTestRunner($loader, $this->_params); + } + +/** + * Handler for customizing the FixtureManager class/ + * + * @param string $class Name of the class that will be the fixture manager + * @return void + */ + public function handleFixture($class) { + $this->arguments['fixtureManager'] = $class; + } + +/** + * Handles output flag used to change printing on webrunner. + * + * @return void + */ + public function handleReporter($reporter) { + $object = null; + + $type = strtolower($reporter); + $coreClass = 'Cake' . ucwords($reporter) . 'Reporter'; + App::uses($coreClass, 'TestSuite/Reporter'); + + $appClass = $reporter . 'Reporter'; + App::uses($appClass, 'TestSuite/Reporter'); + + if (!class_exists($appClass)) { + $object = new $coreClass(null, $this->_params); + } else { + $object = new $appClass(null, $this->_params); + } + return $this->arguments['printer'] = $object; + } +} \ No newline at end of file diff --git a/cake/tests/lib/cake_test_suite_dispatcher.php b/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php similarity index 75% rename from cake/tests/lib/cake_test_suite_dispatcher.php rename to lib/Cake/TestSuite/CakeTestSuiteDispatcher.php index 36937ed2c..2fef24987 100644 --- a/cake/tests/lib/cake_test_suite_dispatcher.php +++ b/lib/Cake/TestSuite/CakeTestSuiteDispatcher.php @@ -17,6 +17,11 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +define('CORE_TEST_CASES', LIBS . 'tests' . DS . 'Case'); +define('APP_TEST_CASES', TESTS . 'Case'); + +App::uses('CakeTestSuiteCommand', 'TestSuite'); + /** * CakeTestSuiteDispatcher handles web requests to the test suite and runs the correct action. * @@ -31,28 +36,15 @@ class CakeTestSuiteDispatcher { public $params = array( 'codeCoverage' => false, 'case' => null, + 'core' => false, 'app' => false, 'plugin' => null, 'output' => 'html', 'show' => 'groups', 'show_passes' => false, - 'filter' => false + 'filter' => false, + 'fixture' => null ); - -/** - * The classname for the TestManager being used - * - * @var string - */ - protected $_managerClass = 'TestManager'; - -/** - * The Instance of the Manager being used. - * - * @var TestManager subclass - */ - public $Manager; - /** * Baseurl for the request * @@ -185,50 +177,14 @@ class CakeTestSuiteDispatcher { * @return void */ function _testCaseList() { - $Reporter =& $this->getReporter(); + $command = new CakeTestSuiteCommand('', $this->params); + $Reporter = $command->handleReporter($this->params['output']); $Reporter->paintDocumentStart(); $Reporter->paintTestMenu(); $Reporter->testCaseList(); $Reporter->paintDocumentEnd(); } -/** - * Sets the Manager to use for the request. - * - * @return string The manager class name - * @static - */ - function &getManager() { - if (empty($this->Manager)) { - require_once CAKE_TESTS_LIB . 'test_manager.php'; - $this->Manager = new $this->_managerClass($this->params); - } - return $this->Manager; - } - -/** - * Gets the reporter based on the request parameters - * - * @return void - * @static - */ - function &getReporter() { - if (!self::$_Reporter) { - $type = strtolower($this->params['output']); - $coreClass = 'Cake' . ucwords($this->params['output']) . 'Reporter'; - $coreFile = CAKE_TESTS_LIB . 'reporter/cake_' . $type . '_reporter.php'; - - $appClass = $this->params['output'] . 'Reporter'; - $appFile = APPLIBS . 'test_suite/reporter/' . $type . '_reporter.php'; - if (include_once $coreFile) { - self::$_Reporter = new $coreClass(null, $this->params); - } elseif (include_once $appFile) { - self::$_Reporter = new $appClass(null, $this->params); - } - } - return self::$_Reporter; - } - /** * Sets the params, calling this will bypass the auto parameter parsing. * @@ -260,9 +216,11 @@ class CakeTestSuiteDispatcher { $this->_checkXdebug(); } } + if (empty($this->params['plugin']) && empty($this->params['app'])) { + $this->params['core'] = true; + } $this->params['baseUrl'] = $this->_baseUrl; $this->params['baseDir'] = $this->_baseDir; - $this->getManager(); } /** @@ -271,13 +229,30 @@ class CakeTestSuiteDispatcher { * @return void */ function _runTestCase() { + $commandArgs = array( + 'case' => $this->params['case'], + 'core' =>$this->params['core'], + 'app' => $this->params['app'], + 'plugin' => $this->params['plugin'], + 'codeCoverage' => $this->params['codeCoverage'], + 'baseUrl' => $this->_baseUrl, + 'baseDir' => $this->_baseDir, + ); + + $options = array( + '--filter', $this->params['filter'], + '--output', $this->params['output'], + '--fixture', $this->params['fixture'] + ); + restore_error_handler(); + try { - $Reporter = CakeTestSuiteDispatcher::getReporter(); - return $this->Manager->runTestCase($this->params['case'], $Reporter, $this->params['codeCoverage']); + $command = new CakeTestSuiteCommand('CakeTestLoader', $commandArgs); + $result = $command->run($options); } catch (MissingConnectionException $exception) { ob_end_clean(); $baseDir = $this->_baseDir; - include CAKE_TESTS_LIB . 'templates' . DS . 'missing_conenction.php'; + include CAKE_TESTS_LIB . 'templates' . DS . 'missing_connection.php'; exit(); } } diff --git a/cake/tests/lib/controller_test_case.php b/lib/Cake/TestSuite/ControllerTestCase.php similarity index 85% rename from cake/tests/lib/controller_test_case.php rename to lib/Cake/TestSuite/ControllerTestCase.php index 97e71303e..09ba4af67 100644 --- a/cake/tests/lib/controller_test_case.php +++ b/lib/Cake/TestSuite/ControllerTestCase.php @@ -19,9 +19,12 @@ PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); -require_once CAKE . 'libs' . DS . 'dispatcher.php'; -require_once CAKE_TESTS_LIB . 'cake_test_case.php'; -App::import('Core', array('Router', 'CakeRequest', 'CakeResponse', 'Helper')); +App::uses('Dispatcher', 'Routing'); +App::uses('CakeTestCase', 'TestSuite'); +App::uses('Router', 'Routing'); +App::uses('CakeRequest', 'Network'); +App::uses('CakeResponse', 'Network'); +App::uses('Helper', 'View'); /** * ControllerTestDispatcher class @@ -171,6 +174,7 @@ class ControllerTestCase extends CakeTestCase { * Tests a controller action. * * ### Options: + * * - `data` POST or GET data to pass * - `method` POST or GET * @@ -251,7 +255,13 @@ class ControllerTestCase extends CakeTestCase { * @return Controller Mocked controller */ public function generate($controller, $mocks = array()) { - if (!class_exists($controller.'Controller') && App::import('Controller', $controller) === false) { + list($plugin, $controller) = pluginSplit($controller); + if ($plugin) { + App::uses($plugin . 'AppController', $plugin . '.Controller'); + $plugin .= '.'; + } + App::uses($controller . 'Controller', $plugin . 'Controller'); + if (!class_exists($controller.'Controller')) { throw new MissingControllerException(array('controller' => $controller.'Controller')); } ClassRegistry::flush(); @@ -262,8 +272,9 @@ class ControllerTestCase extends CakeTestCase { 'components' => array() ), (array)$mocks); - $_controller = $this->getMock($controller.'Controller', $mocks['methods'], array(), '', false); - $_controller->name = $controller; + list($plugin, $name) = pluginSplit($controller); + $_controller = $this->getMock($name.'Controller', $mocks['methods'], array(), '', false); + $_controller->name = $name; $_controller->__construct(); $config = ClassRegistry::config('Model'); @@ -275,10 +286,12 @@ class ControllerTestCase extends CakeTestCase { if ($methods === true) { $methods = array(); } + ClassRegistry::init($model); + list($plugin, $name) = pluginSplit($model); $config = array_merge((array)$config, array('name' => $model)); - $_model = $this->getMock($model, $methods, array($config)); - ClassRegistry::removeObject($model); - ClassRegistry::addObject($model, $_model); + $_model = $this->getMock($name, $methods, array($config)); + ClassRegistry::removeObject($name); + ClassRegistry::addObject($name, $_model); } foreach ($mocks['components'] as $component => $methods) { @@ -289,14 +302,16 @@ class ControllerTestCase extends CakeTestCase { if ($methods === true) { $methods = array(); } - if (!App::import('Component', $component)) { + list($plugin, $name) = pluginSplit($component, true); + App::uses($name . 'Component', $plugin . 'Controller/Component'); + if (!class_exists($name . 'Component')) { throw new MissingComponentFileException(array( - 'file' => Inflector::underscore($component) . '.php', - 'class' => $componentClass + 'file' => $name . 'Component.php', + 'class' => $name.'Component' )); - } - $_component = $this->getMock($component.'Component', $methods, array(), '', false); - $_controller->Components->set($component, $_component); + } + $_component = $this->getMock($name.'Component', $methods, array(), '', false); + $_controller->Components->set($name, $_component); } $_controller->constructClasses(); diff --git a/cake/tests/lib/coverage/base_coverage_report.php b/lib/Cake/TestSuite/Coverage/BaseCoverageReport.php similarity index 99% rename from cake/tests/lib/coverage/base_coverage_report.php rename to lib/Cake/TestSuite/Coverage/BaseCoverageReport.php index 7960a6e75..3a04a946c 100644 --- a/cake/tests/lib/coverage/base_coverage_report.php +++ b/lib/Cake/TestSuite/Coverage/BaseCoverageReport.php @@ -101,7 +101,7 @@ abstract class BaseCoverageReport { } elseif ($this->pluginTest) { $path = App::pluginPath($this->pluginTest); } else { - $path = TEST_CAKE_CORE_INCLUDE_PATH; + $path = LIBS; } return $path; } diff --git a/cake/tests/lib/coverage/html_coverage_report.php b/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php similarity index 98% rename from cake/tests/lib/coverage/html_coverage_report.php rename to lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php index bdd18e972..e57e9e3de 100644 --- a/cake/tests/lib/coverage/html_coverage_report.php +++ b/lib/Cake/TestSuite/Coverage/HtmlCoverageReport.php @@ -16,10 +16,11 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once dirname(__FILE__) . '/base_coverage_report.php'; PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); +App::uses('BaseCoverageReport', 'TestSuite/Coverage'); + class HtmlCoverageReport extends BaseCoverageReport { /** diff --git a/cake/tests/lib/coverage/text_coverage_report.php b/lib/Cake/TestSuite/Coverage/TextCoverageReport.php similarity index 100% rename from cake/tests/lib/coverage/text_coverage_report.php rename to lib/Cake/TestSuite/Coverage/TextCoverageReport.php diff --git a/cake/tests/lib/cake_fixture_manager.php b/lib/Cake/TestSuite/Fixture/CakeFixtureManager.php similarity index 78% rename from cake/tests/lib/cake_fixture_manager.php rename to lib/Cake/TestSuite/Fixture/CakeFixtureManager.php index 2615847ca..51c0392d9 100644 --- a/cake/tests/lib/cake_fixture_manager.php +++ b/lib/Cake/TestSuite/Fixture/CakeFixtureManager.php @@ -18,6 +18,9 @@ */ PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); +App::uses('ConnectionManager', 'Model'); +App::uses('ClassRegistry', 'Utility'); + class CakeFixtureManager { /** @@ -54,7 +57,7 @@ class CakeFixtureManager { * @param CakeTestCase $test the test case to inspect * @return void */ - public function fixturize(CakeTestCase $test) { + public function fixturize($test) { if (empty($test->fixtures) || !empty($this->_processed[get_class($test)])) { $test->db = $this->_db; return; @@ -80,22 +83,7 @@ class CakeFixtureManager { if ($this->_initialized) { return; } - $testDbAvailable = in_array('test', array_keys(ConnectionManager::enumConnectionObjects())); - - $_prefix = null; - - if ($testDbAvailable) { - // Try for test DB - @$db = ConnectionManager::getDataSource('test'); - $testDbAvailable = $db->isConnected(); - } else { - throw new MissingConnectionException(__('You need to create a $test datasource connection to start using fixtures')); - } - - if (!$testDbAvailable) { - throw new MissingConnectionException(__('Unable to connect to the $test datasource')); - } - + $db = ConnectionManager::getDataSource('test'); $this->_db = $db; ClassRegistry::config(array('ds' => 'test')); $this->_initialized = true; @@ -114,47 +102,41 @@ class CakeFixtureManager { if (isset($this->_loaded[$fixture])) { continue; } + if (strpos($fixture, 'core.') === 0) { $fixture = substr($fixture, strlen('core.')); - foreach (App::core('cake') as $key => $path) { - $fixturePaths[] = $path . 'tests' . DS . 'fixtures'; - } + $fixturePaths[] = LIBS . 'tests' . DS . 'Fixture'; } elseif (strpos($fixture, 'app.') === 0) { $fixture = substr($fixture, strlen('app.')); $fixturePaths = array( - TESTS . 'fixtures', - VENDORS . 'tests' . DS . 'fixtures' + TESTS . 'Fixture' ); } elseif (strpos($fixture, 'plugin.') === 0) { $parts = explode('.', $fixture, 3); $pluginName = $parts[1]; $fixture = $parts[2]; $fixturePaths = array( - App::pluginPath($pluginName) . 'tests' . DS . 'fixtures', - TESTS . 'fixtures', - VENDORS . 'tests' . DS . 'fixtures' + App::pluginPath($pluginName) . 'tests' . DS . 'Fixture', + TESTS . 'Fixture' ); } else { $fixturePaths = array( - TESTS . 'fixtures', - VENDORS . 'tests' . DS . 'fixtures', - TEST_CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'tests' . DS . 'fixtures' + TESTS . 'Fixture', + LIBS . 'tests' . DS . 'Fixture' ); } foreach ($fixturePaths as $path) { - if (is_readable($path . DS . $fixture . '_fixture.php')) { - $fixtureFile = $path . DS . $fixture . '_fixture.php'; + $className = Inflector::camelize($fixture); + if (is_readable($path . DS . $className . 'Fixture.php')) { + $fixtureFile = $path . DS . $className . 'Fixture.php'; + require_once($fixtureFile); + $fixtureClass = $className . 'Fixture'; + $this->_loaded[$fixtureIndex] = new $fixtureClass($this->_db); + $this->_fixtureMap[$fixtureClass] = $this->_loaded[$fixtureIndex]; break; } } - - if (isset($fixtureFile)) { - require_once($fixtureFile); - $fixtureClass = Inflector::camelize($fixture) . 'Fixture'; - $this->_loaded[$fixtureIndex] = new $fixtureClass($this->_db); - $this->_fixtureMap[$fixtureClass] = $this->_loaded[$fixtureIndex]; - } } } @@ -252,7 +234,7 @@ class CakeFixtureManager { $fixture->truncate($db); $fixture->insert($db); } else { - throw new UnexpectedValueException(__('Referenced fixture class %s not found', $name)); + throw new UnexpectedValueException(__d('cake_dev', 'Referenced fixture class %s not found', $name)); } } diff --git a/cake/tests/lib/cake_test_fixture.php b/lib/Cake/TestSuite/Fixture/CakeTestFixture.php similarity index 89% rename from cake/tests/lib/cake_test_fixture.php rename to lib/Cake/TestSuite/Fixture/CakeTestFixture.php index ec56d09ec..a83854266 100644 --- a/cake/tests/lib/cake_test_fixture.php +++ b/lib/Cake/TestSuite/Fixture/CakeTestFixture.php @@ -19,6 +19,8 @@ PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); +App::uses('CakeSchema', 'Model'); + /** * Short description for class. * @@ -50,7 +52,13 @@ class CakeTestFixture { * */ public function __construct() { - App::import('Model', 'CakeSchema'); + if ($this->name === null) { + if (preg_match('/^(.*)Fixture$/', get_class($this), $matches)) { + $this->name = $matches[1]; + } else { + $this->name = get_class($this); + } + } $this->Schema = new CakeSchema(array('name' => 'TestSuite', 'connection' => 'test')); $this->init(); } @@ -66,9 +74,12 @@ class CakeTestFixture { is_array($this->import) ? $this->import : array('model' => $this->import) ); - if (isset($import['model']) && App::import('Model', $import['model'])) { - App::import('Model', $import['model']); - list(, $modelClass) = pluginSplit($import['model']); + if (isset($import['model'])) { + list($plugin, $modelClass) = pluginSplit($import['model'], true); + App::uses($modelClass, $plugin . 'Model'); + if (!class_exists($modelClass)) { + throw new MissingModelException(array('class' => $modelClass)); + } $model = new $modelClass(null, null, $import['connection']); $db = $model->getDataSource(); if (empty($model->tablePrefix)) { @@ -129,7 +140,7 @@ class CakeTestFixture { * @param object $db An instance of the database object used to create the fixture table * @return boolean True on success, false on failure */ - public function create(&$db) { + public function create($db) { if (!isset($this->fields) || empty($this->fields)) { return false; } @@ -146,7 +157,10 @@ class CakeTestFixture { * @param object $db An instance of the database object used to create the fixture table * @return boolean True on success, false on failure */ - public function drop(&$db) { + public function drop($db) { + if (empty($this->fields)) { + return false; + } $this->Schema->build(array($this->table => $this->fields)); return ( $db->execute($db->dropSchema($this->Schema), array('log' => false)) !== false @@ -160,7 +174,7 @@ class CakeTestFixture { * @param object $db An instance of the database into which the records will be inserted * @return boolean on success or if there are no records to insert, or false on failure */ - public function insert(&$db) { + public function insert($db) { if (!isset($this->_insert)) { $values = array(); if (isset($this->records) && !empty($this->records)) { @@ -181,7 +195,7 @@ class CakeTestFixture { * @param object $db A reference to a db instance * @return boolean */ - public function truncate(&$db) { + public function truncate($db) { $fullDebug = $db->fullDebug; $db->fullDebug = false; $return = $db->truncate($this->table); diff --git a/cake/tests/lib/cake_test_model.php b/lib/Cake/TestSuite/Fixture/CakeTestModel.php similarity index 95% rename from cake/tests/lib/cake_test_model.php rename to lib/Cake/TestSuite/Fixture/CakeTestModel.php index a896a50d9..39632a45b 100644 --- a/cake/tests/lib/cake_test_model.php +++ b/lib/Cake/TestSuite/Fixture/CakeTestModel.php @@ -16,7 +16,8 @@ * @since CakePHP(tm) v 1.2.0.4667 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -require_once LIBS.'model'.DS.'model.php'; + +App::uses('Model', 'Model'); /** * Short description for class. diff --git a/cake/tests/lib/reporter/cake_base_reporter.php b/lib/Cake/TestSuite/Reporter/CakeBaseReporter.php similarity index 90% rename from cake/tests/lib/reporter/cake_base_reporter.php rename to lib/Cake/TestSuite/Reporter/CakeBaseReporter.php index 9f4b3d3ec..aba62fde5 100644 --- a/cake/tests/lib/reporter/cake_base_reporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeBaseReporter.php @@ -16,6 +16,7 @@ * @since CakePHP(tm) v 1.3 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +require_once 'PHPUnit/TextUI/ResultPrinter.php'; PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); @@ -25,31 +26,9 @@ PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); * @package cake * @package cake.tests.lib */ -class CakeBaseReporter implements PHPUnit_Framework_TestListener { +class CakeBaseReporter extends PHPUnit_TextUI_ResultPrinter { -/** - * Time the test runs started. - * - * @var integer - * @access protected - */ - protected $_timeStart = 0; - -/** - * Time the test runs ended - * - * @var integer - * @access protected - */ - protected $_timeEnd = 0; - -/** - * Duration of all test methods. - * - * @var integer - * @access protected - */ - protected $_timeDuration = 0; + protected $_headerSent = false; /** * Array of request parameters. Usually parsed GET params. @@ -70,6 +49,7 @@ class CakeBaseReporter implements PHPUnit_Framework_TestListener { * The number of assertions done for a test suite */ protected $numAssertions = 0; + /** * Does nothing yet. The first output will * be sent on the first test start. @@ -81,7 +61,7 @@ class CakeBaseReporter implements PHPUnit_Framework_TestListener { * - app - App test being run. * - case - The case being run * - codeCoverage - Whether the case/group being run is being code covered. - * + * * @param string $charset The character set to output with. Defaults to UTF-8 * @param array $params Array of request parameters the reporter should use. See above. */ @@ -100,7 +80,7 @@ class CakeBaseReporter implements PHPUnit_Framework_TestListener { * @return mixed */ public function testCaseList() { - $testList = TestManager::getTestCaseList($this->params); + $testList = CakeTestLoader::generateTestList($this->params); return $testList; } @@ -121,7 +101,7 @@ class CakeBaseReporter implements PHPUnit_Framework_TestListener { * @return void */ public function paintDocumentEnd() { - + } /** @@ -131,7 +111,7 @@ class CakeBaseReporter implements PHPUnit_Framework_TestListener { * @return void */ public function paintTestMenu() { - + } /** @@ -146,6 +126,10 @@ class CakeBaseReporter implements PHPUnit_Framework_TestListener { return ''; } + public function printResult(PHPUnit_Framework_TestResult $result) { + $this->paintFooter($result); + } + public function paintResult(PHPUnit_Framework_TestResult $result) { $this->paintFooter($result); } @@ -200,7 +184,10 @@ class CakeBaseReporter implements PHPUnit_Framework_TestListener { * @param PHPUnit_Framework_TestSuite $suite */ public function startTestSuite(PHPUnit_Framework_TestSuite $suite) { - echo __('Running %s', $suite->getName()) . "\n"; + if (!$this->_headerSent) { + echo $this->paintHeader(); + } + echo __d('cake_dev', 'Running %s', $suite->getName()) . "\n"; } /** @@ -230,4 +217,4 @@ class CakeBaseReporter implements PHPUnit_Framework_TestListener { $this->paintPass($test, $time); } -} +} \ No newline at end of file diff --git a/cake/tests/lib/reporter/cake_html_reporter.php b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php old mode 100755 new mode 100644 similarity index 91% rename from cake/tests/lib/reporter/cake_html_reporter.php rename to lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php index 63153ba9c..428b11d85 --- a/cake/tests/lib/reporter/cake_html_reporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -16,7 +16,7 @@ * @since CakePHP(tm) v 1.2.0.4433 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -include_once dirname(__FILE__) . DS . 'cake_base_reporter.php'; +App::uses('CakeBaseReporter', 'TestSuite/Reporter'); PHP_CodeCoverage_Filter::getInstance()->addFileToBlacklist(__FILE__, 'DEFAULT'); @@ -36,6 +36,7 @@ class CakeHtmlReporter extends CakeBaseReporter { * @return void */ public function paintHeader() { + $this->_headerSent = true; $this->sendNoCacheHeaders(); $this->paintDocumentStart(); $this->paintTestMenu(); @@ -139,10 +140,8 @@ class CakeHtmlReporter extends CakeBaseReporter { echo "" . $result->errorCount() . " exceptions."; echo "
\n"; echo '
'; - echo '

Time taken by tests (in seconds): ' . $result->time() . '

'; - if (function_exists('memory_get_peak_usage')) { - echo '

Peak memory use: (in bytes): ' . number_format(memory_get_peak_usage()) . '

'; - } + echo '

Time: ' . $result->time() . ' seconds

'; + echo '

Peak memory: ' . number_format(memory_get_peak_usage()) . ' bytes

'; echo $this->_paintLinks(); echo '
'; if (isset($this->params['codeCoverage']) && $this->params['codeCoverage']) { @@ -158,8 +157,7 @@ class CakeHtmlReporter extends CakeBaseReporter { * @return void */ public function paintCoverage(array $coverage) { - $file = dirname(dirname(__FILE__)) . '/coverage/html_coverage_report.php'; - include_once $file; + App::uses('HtmlCoverageReport', 'TestSuite/Coverage'); $reporter = new HtmlCoverageReport($coverage, $this); echo $reporter->report(); } @@ -236,8 +234,8 @@ class CakeHtmlReporter extends CakeBaseReporter { echo "
  • \n"; echo "Failed"; echo "
    " . $this->_htmlEntities($message->toString()) . "
    \n"; - echo "
    " . __('Test case: %s', $testName) . "
    \n"; - echo "
    " . __('Stack trace:') . '
    ' . $trace . "
    \n"; + echo "
    " . __d('cake_dev', 'Test case: %s', $testName) . "
    \n"; + echo "
    " . __d('cake_dev', 'Stack trace:') . '
    ' . $trace . "
    \n"; echo "
  • \n"; } @@ -271,11 +269,11 @@ class CakeHtmlReporter extends CakeBaseReporter { $testName = get_class($test) . '(' . $test->getName() . ')'; echo "
  • \n"; - echo "Exception"; + echo "" . get_class($message) . ""; echo "
    " . $this->_htmlEntities($message->getMessage()) . "
    \n"; - echo "
    " . __('Test case: %s', $testName) . "
    \n"; - echo "
    " . __('Stack trace:') . '
    ' . $trace . "
    \n"; + echo "
    " . __d('cake_dev', 'Test case: %s', $testName) . "
    \n"; + echo "
    " . __d('cake_dev', 'Stack trace:') . '
    ' . $trace . "
    \n"; echo "
  • \n"; } @@ -340,6 +338,9 @@ class CakeHtmlReporter extends CakeBaseReporter { * @param PHPUnit_Framework_TestSuite $suite */ public function startTestSuite(PHPUnit_Framework_TestSuite $suite) { - echo '

    ' . __('Running %s', $suite->getName()) . '

    '; + if (!$this->_headerSent) { + echo $this->paintHeader(); + } + echo '

    ' . __d('cake_dev', 'Running %s', $suite->getName()) . '

    '; } -} +} \ No newline at end of file diff --git a/cake/tests/lib/reporter/cake_text_reporter.php b/lib/Cake/TestSuite/Reporter/CakeTextReporter.php similarity index 94% rename from cake/tests/lib/reporter/cake_text_reporter.php rename to lib/Cake/TestSuite/Reporter/CakeTextReporter.php index cf4cea447..17d9ee5d2 100644 --- a/cake/tests/lib/reporter/cake_text_reporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeTextReporter.php @@ -87,10 +87,9 @@ class CakeTextReporter extends CakeBaseReporter { ', Failures: ' . $result->failureCount() . ', Exceptions: ' . $result->errorCount() . "\n"; - echo 'Time taken by tests (in seconds): ' . $result->time() . "\n"; - if (function_exists('memory_get_peak_usage')) { - echo 'Peak memory use: (in bytes): ' . number_format(memory_get_peak_usage()) . "\n"; - } + echo 'Time: ' . $result->time() . " seconds\n"; + echo 'Peak memory: ' . number_format(memory_get_peak_usage()) . " bytes\n"; + if (isset($this->params['codeCoverage']) && $this->params['codeCoverage']) { $coverage = $result->getCodeCoverageInformation(); echo $this->paintCoverage($coverage); @@ -129,8 +128,7 @@ class CakeTextReporter extends CakeBaseReporter { * @return void */ public function paintSkip($message) { - parent::paintSkip($message); - echo "Skip: $message\n"; + printf("Skip: %s\n", $message->getMessage()); } /** diff --git a/cake/tests/lib/templates/footer.php b/lib/Cake/TestSuite/templates/footer.php similarity index 96% rename from cake/tests/lib/templates/footer.php rename to lib/Cake/TestSuite/templates/footer.php index 0f6ab6a69..059077000 100644 --- a/cake/tests/lib/templates/footer.php +++ b/lib/Cake/TestSuite/templates/footer.php @@ -26,7 +26,7 @@

    element('sql_dump'); diff --git a/cake/tests/lib/templates/header.php b/lib/Cake/TestSuite/templates/header.php similarity index 100% rename from cake/tests/lib/templates/header.php rename to lib/Cake/TestSuite/templates/header.php diff --git a/cake/tests/lib/templates/menu.php b/lib/Cake/TestSuite/templates/menu.php similarity index 100% rename from cake/tests/lib/templates/menu.php rename to lib/Cake/TestSuite/templates/menu.php diff --git a/cake/tests/lib/templates/missing_conenction.php b/lib/Cake/TestSuite/templates/missing_conenction.php similarity index 100% rename from cake/tests/lib/templates/missing_conenction.php rename to lib/Cake/TestSuite/templates/missing_conenction.php diff --git a/cake/tests/lib/templates/phpunit.php b/lib/Cake/TestSuite/templates/phpunit.php similarity index 100% rename from cake/tests/lib/templates/phpunit.php rename to lib/Cake/TestSuite/templates/phpunit.php diff --git a/cake/tests/lib/templates/xdebug.php b/lib/Cake/TestSuite/templates/xdebug.php similarity index 100% rename from cake/tests/lib/templates/xdebug.php rename to lib/Cake/TestSuite/templates/xdebug.php diff --git a/cake/libs/class_registry.php b/lib/Cake/Utility/ClassRegistry.php similarity index 94% rename from cake/libs/class_registry.php rename to lib/Cake/Utility/ClassRegistry.php index 25659089f..f4181f02b 100644 --- a/cake/libs/class_registry.php +++ b/lib/Cake/Utility/ClassRegistry.php @@ -132,7 +132,11 @@ class ClassRegistry { return $model; } - if (class_exists($class) || App::import($type, $pluginPath . $class)) { + App::uses('Model', 'Model'); + App::uses('AppModel', 'Model'); + App::uses($plugin . 'AppModel', $pluginPath . $type); + App::uses($class, $pluginPath . $type); + if (class_exists($class)) { ${$class} = new $class($settings); } elseif ($type === 'Model') { if ($plugin && class_exists($plugin . 'AppModel')) { @@ -145,7 +149,7 @@ class ClassRegistry { } if (!isset(${$class})) { - trigger_error(__('(ClassRegistry::init() could not create instance of %1$s class %2$s ', $class, $type), E_USER_WARNING); + trigger_error(__d('cake_dev', '(ClassRegistry::init() could not create instance of %1$s class %2$s ', $class, $type), E_USER_WARNING); return $false; } @@ -155,7 +159,7 @@ class ClassRegistry { $_this->map($alias, $class); } } elseif (is_numeric($settings)) { - trigger_error(__('(ClassRegistry::init() Attempted to create instance of a class with a numeric name'), E_USER_WARNING); + trigger_error(__d('cake_dev', '(ClassRegistry::init() Attempted to create instance of a class with a numeric name'), E_USER_WARNING); return $false; } } @@ -173,7 +177,7 @@ class ClassRegistry { * @param mixed $object Object to store * @return boolean True if the object was written, false if $key already exists */ - public static function addObject($key, &$object) { + public static function addObject($key, $object) { $_this = ClassRegistry::getInstance(); $key = Inflector::underscore($key); if (!isset($_this->__objects[$key])) { diff --git a/cake/libs/debugger.php b/lib/Cake/Utility/Debugger.php similarity index 96% rename from cake/libs/debugger.php rename to lib/Cake/Utility/Debugger.php index 942aa1c63..295f11d65 100644 --- a/cake/libs/debugger.php +++ b/lib/Cake/Utility/Debugger.php @@ -23,12 +23,8 @@ * Included libraries. * */ -if (!class_exists('CakeLog')) { - require_once LIBS . 'cake_log.php'; -} -if (!class_exists('String')) { - require_once LIBS . 'string.php'; -} +App::uses('CakeLog', 'Log'); +App::uses('String', 'Utility'); /** * Provide custom logging and error handling. @@ -404,12 +400,9 @@ class Debugger { } elseif (strpos($path, ROOT) === 0) { return str_replace(ROOT, 'ROOT', $path); } - $corePaths = App::core('cake'); - - foreach ($corePaths as $corePath) { - if (strpos($path, $corePath) === 0) { - return str_replace($corePath, 'CORE' .DS . 'cake' .DS, $path); - } + + if (strpos($path, LIBS) === 0) { + return str_replace($corePath, 'CORE' . DS, $path); } return $path; } @@ -654,11 +647,11 @@ class Debugger { */ public static function checkSecurityKeys() { if (Configure::read('Security.salt') == 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi') { - trigger_error(__('Please change the value of \'Security.salt\' in app/config/core.php to a salt value specific to your application'), E_USER_NOTICE); + trigger_error(__d('cake_dev', 'Please change the value of \'Security.salt\' in app/config/core.php to a salt value specific to your application'), E_USER_NOTICE); } if (Configure::read('Security.cipherSeed') === '76859309657453542496749683645') { - trigger_error(__('Please change the value of \'Security.cipherSeed\' in app/config/core.php to a numeric (digits only) seed value specific to your application'), E_USER_NOTICE); + trigger_error(__d('cake_dev', 'Please change the value of \'Security.cipherSeed\' in app/config/core.php to a numeric (digits only) seed value specific to your application'), E_USER_NOTICE); } } diff --git a/cake/libs/file.php b/lib/Cake/Utility/File.php similarity index 99% rename from cake/libs/file.php rename to lib/Cake/Utility/File.php index 49d030e4d..ff0eadaa1 100644 --- a/cake/libs/file.php +++ b/lib/Cake/Utility/File.php @@ -21,9 +21,7 @@ * Included libraries. * */ -if (!class_exists('Folder')) { - require LIBS . 'folder.php'; -} +App::uses('Folder', 'Utility'); /** * Convenience class for reading, writing and appending to files. diff --git a/cake/libs/folder.php b/lib/Cake/Utility/Folder.php similarity index 93% rename from cake/libs/folder.php rename to lib/Cake/Utility/Folder.php index 02b097227..f8d8f283a 100644 --- a/cake/libs/folder.php +++ b/lib/Cake/Utility/Folder.php @@ -345,11 +345,11 @@ class Folder { if ($recursive === false && is_dir($path)) { if (@chmod($path, intval($mode, 8))) { - $this->__messages[] = __('%s changed to %s', $path, $mode); + $this->__messages[] = __d('cake_dev', '%s changed to %s', $path, $mode); return true; } - $this->__errors[] = __('%s NOT changed to %s', $path, $mode); + $this->__errors[] = __d('cake_dev', '%s NOT changed to %s', $path, $mode); return false; } @@ -366,9 +366,9 @@ class Folder { } if (@chmod($fullpath, intval($mode, 8))) { - $this->__messages[] = __('%s changed to %s', $fullpath, $mode); + $this->__messages[] = __d('cake_dev', '%s changed to %s', $fullpath, $mode); } else { - $this->__errors[] = __('%s NOT changed to %s', $fullpath, $mode); + $this->__errors[] = __d('cake_deverloper', '%s NOT changed to %s', $fullpath, $mode); } } } @@ -453,7 +453,7 @@ class Folder { } if (is_file($pathname)) { - $this->__errors[] = __('%s is a file', $pathname); + $this->__errors[] = __d('cake_dev', '%s is a file', $pathname); return false; } $pathname = rtrim($pathname, DS); @@ -464,11 +464,11 @@ class Folder { $old = umask(0); if (mkdir($pathname, $mode)) { umask($old); - $this->__messages[] = __('%s created', $pathname); + $this->__messages[] = __d('cake_dev', '%s created', $pathname); return true; } else { umask($old); - $this->__errors[] = __('%s NOT created', $pathname); + $this->__errors[] = __d('cake_dev', '%s NOT created', $pathname); return false; } } @@ -541,9 +541,9 @@ class Folder { } if (is_file($file) === true) { if (@unlink($file)) { - $this->__messages[] = __('%s removed', $file); + $this->__messages[] = __d('cake_dev', '%s removed', $file); } else { - $this->__errors[] = __('%s NOT removed', $file); + $this->__errors[] = __d('cake_dev', '%s NOT removed', $file); } } elseif (is_dir($file) === true && $this->delete($file) === false) { return false; @@ -552,10 +552,10 @@ class Folder { } $path = substr($path, 0, strlen($path) - 1); if (rmdir($path) === false) { - $this->__errors[] = __('%s NOT removed', $path); + $this->__errors[] = __d('cake_dev', '%s NOT removed', $path); return false; } else { - $this->__messages[] = __('%s removed', $path); + $this->__messages[] = __d('cake_dev', '%s removed', $path); } } return true; @@ -590,7 +590,7 @@ class Folder { $mode = $options['mode']; if (!$this->cd($fromDir)) { - $this->__errors[] = __('%s not found', $fromDir); + $this->__errors[] = __d('cake_dev', '%s not found', $fromDir); return false; } @@ -599,7 +599,7 @@ class Folder { } if (!is_writable($toDir)) { - $this->__errors[] = __('%s not writable', $toDir); + $this->__errors[] = __d('cake_dev', '%s not writable', $toDir); return false; } @@ -613,9 +613,9 @@ class Folder { if (copy($from, $to)) { chmod($to, intval($mode, 8)); touch($to, filemtime($from)); - $this->__messages[] = __('%s copied to %s', $from, $to); + $this->__messages[] = __d('cake_dev', '%s copied to %s', $from, $to); } else { - $this->__errors[] = __('%s NOT copied to %s', $from, $to); + $this->__errors[] = __d('cake_dev', '%s NOT copied to %s', $from, $to); } } @@ -626,11 +626,11 @@ class Folder { $old = umask(0); chmod($to, $mode); umask($old); - $this->__messages[] = __('%s created', $to); + $this->__messages[] = __d('cake_dev', '%s created', $to); $options = array_merge($options, array('to'=> $to, 'from'=> $from)); $this->copy($options); } else { - $this->__errors[] = __('%s not created', $to); + $this->__errors[] = __d('cake_dev', '%s not created', $to); } } } @@ -666,7 +666,7 @@ class Folder { $options = (array)$options; } $options = array_merge( - array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), + array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), $options ); @@ -746,4 +746,4 @@ class Folder { $lastChar = $path[strlen($path) - 1]; return $lastChar === '/' || $lastChar === '\\'; } -} +} \ No newline at end of file diff --git a/cake/libs/inflector.php b/lib/Cake/Utility/Inflector.php similarity index 98% rename from cake/libs/inflector.php rename to lib/Cake/Utility/Inflector.php index 0e3eb0278..c45d20d44 100644 --- a/cake/libs/inflector.php +++ b/lib/Cake/Utility/Inflector.php @@ -540,17 +540,11 @@ class Inflector { * @param string $string the string you want to slug * @param string $replacement will replace keys in map * @param array $map extra elements to map to the replacement - * @deprecated $map param will be removed in future versions. Use Inflector::rules() instead * @return string * @access public * @link http://book.cakephp.org/view/1479/Class-methods */ - public static function slug($string, $replacement = '_', $map = array()) { - - if (is_array($replacement)) { - $map = $replacement; - $replacement = '_'; - } + public static function slug($string, $replacement = '_') { $quotedReplacement = preg_quote($replacement, '/'); $merge = array( @@ -559,7 +553,7 @@ class Inflector { sprintf('/^[%s]+|[%s]+$/', $quotedReplacement, $quotedReplacement) => '', ); - $map = $map + self::$_transliteration + $merge; + $map = self::$_transliteration + $merge; return preg_replace(array_keys($map), array_values($map), $string); } } diff --git a/cake/libs/object_collection.php b/lib/Cake/Utility/ObjectCollection.php similarity index 98% rename from cake/libs/object_collection.php rename to lib/Cake/Utility/ObjectCollection.php index a9750f3e8..73dfa79b3 100644 --- a/cake/libs/object_collection.php +++ b/lib/Cake/Utility/ObjectCollection.php @@ -105,7 +105,7 @@ abstract class ObjectCollection { $list = array_keys($this->_loaded); } if ($options['modParams'] !== false && !isset($params[$options['modParams']])) { - throw new CakeException(__('Cannot use modParams with indexes that do not exist.')); + throw new CakeException(__d('cake_dev', 'Cannot use modParams with indexes that do not exist.')); } foreach ($list as $name) { $result = call_user_func_array(array($this->_loaded[$name], $callback), $params); @@ -222,7 +222,7 @@ abstract class ObjectCollection { } /** - * Adds or overwrites an instatiated object to the collection + * Adds or overwrites an instantiated object to the collection * * @param string $name Name of the object * @param Object $object The object to use diff --git a/cake/libs/sanitize.php b/lib/Cake/Utility/Sanitize.php similarity index 99% rename from cake/libs/sanitize.php rename to lib/Cake/Utility/Sanitize.php index d538b46bd..151fbb6ca 100644 --- a/cake/libs/sanitize.php +++ b/lib/Cake/Utility/Sanitize.php @@ -263,7 +263,7 @@ class Sanitize { * * @param Model $model The model containing the data to be formatted */ - public static function formatColumns(&$model) { + public static function formatColumns($model) { foreach ($model->data as $name => $values) { if ($name == $model->alias) { $curModel =& $model; diff --git a/cake/libs/security.php b/lib/Cake/Utility/Security.php similarity index 95% rename from cake/libs/security.php rename to lib/Cake/Utility/Security.php index e8b01e2b8..fb20e187c 100644 --- a/cake/libs/security.php +++ b/lib/Cake/Utility/Security.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('String', 'Utility'); + /** * Security Library contains utility methods related to security * @@ -57,9 +59,6 @@ class Security { * @return string Hash */ public static function generateAuthKey() { - if (!class_exists('String')) { - App::import('Core', 'String'); - } return Security::hash(String::uuid()); } @@ -137,7 +136,7 @@ class Security { */ public static function cipher($text, $key) { if (empty($key)) { - trigger_error(__('You cannot use an empty key for Security::cipher()'), E_USER_WARNING); + trigger_error(__d('cake_dev', 'You cannot use an empty key for Security::cipher()'), E_USER_WARNING); return ''; } diff --git a/cake/libs/set.php b/lib/Cake/Utility/Set.php similarity index 97% rename from cake/libs/set.php rename to lib/Cake/Utility/Set.php index 14282682d..839372f19 100644 --- a/cake/libs/set.php +++ b/lib/Cake/Utility/Set.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('String', 'Utility'); + /** * Class used for manipulation of arrays. * @@ -42,7 +44,7 @@ class Set { $r = (array)current($args); while (($arg = next($args)) !== false) { foreach ((array)$arg as $key => $val) { - if (is_array($val) && isset($r[$key]) && is_array($r[$key])) { + if (!empty($r[$key]) && is_array($r[$key]) && is_array($val)) { $r[$key] = Set::merge($r[$key], $val); } elseif (is_int($key)) { $r[] = $val; @@ -61,10 +63,22 @@ class Set { * @param boolean $isArray Force to tell $var is an array when $var is empty * @return mixed Either filtered array, or true/false when in callback */ - public static function filter($var, $isArray = false) { - if (is_array($var) && (!empty($var) || $isArray)) { - return array_filter($var, array('Set', 'filter')); + public static function filter(array $var) { + foreach ($var as $k => $v) { + if (is_array($v)) { + $var[$k] = Set::filter($v); + } } + return array_filter($var, array('Set', '_filter')); + } + +/** + * Set::filter callback function + * + * @param array $var Array to filter. + * @return boolean + */ + protected static function _filter($var) { if ($var === 0 || $var === '0' || !empty($var)) { return true; } @@ -579,15 +593,14 @@ class Set { return $data; } - if (!is_array($path)) { - if (!class_exists('String')) { - App::import('Core', 'String'); - } + if (is_string($path) && strpos($path, '{') !== false) { $path = String::tokenize($path, '.', '{', '}'); + } elseif (is_string($path)) { + $path = explode('.', $path); } $tmp = array(); - if (!is_array($path) || empty($path)) { + if (empty($path)) { return null; } @@ -661,11 +674,12 @@ class Set { } $_list =& $list; + $count = count($path); foreach ($path as $i => $key) { if (is_numeric($key) && intval($key) > 0 || $key === '0') { $key = intval($key); } - if ($i === count($path) - 1) { + if ($i === $count - 1) { $_list[$key] = $data; } else { if (!isset($_list[$key])) { diff --git a/cake/libs/string.php b/lib/Cake/Utility/String.php similarity index 100% rename from cake/libs/string.php rename to lib/Cake/Utility/String.php diff --git a/cake/libs/validation.php b/lib/Cake/Utility/Validation.php similarity index 98% rename from cake/libs/validation.php rename to lib/Cake/Utility/Validation.php index aefa47756..e63342f86 100644 --- a/cake/libs/validation.php +++ b/lib/Cake/Utility/Validation.php @@ -16,9 +16,8 @@ * @since CakePHP(tm) v 1.2.0.3830 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -if (!class_exists('Multibyte')) { - App::import('Core', 'Multibyte', false); -} + +App::uses('Multibyte', 'I18n'); /** * Offers different validation methods. @@ -247,7 +246,7 @@ class Validation { } break; default: - self::$errors[] = __('You must define the $operator parameter for Validation::comparison()', true); + self::$errors[] = __d('cake_dev', 'You must define the $operator parameter for Validation::comparison()'); break; } return false; @@ -266,7 +265,7 @@ class Validation { extract(self::_defaults($check)); } if ($regex === null) { - self::$errors[] = __('You must define a regular expression for Validation::custom()', true); + self::$errors[] = __d('cake_dev', 'You must define a regular expression for Validation::custom()'); return false; } return self::_check($check, $regex); @@ -702,7 +701,7 @@ class Validation { /** * Checks that a value is a valid uuid - http://tools.ietf.org/html/rfc4122 - * + * * @param string $check Value to check * @return boolean Success * @access public @@ -725,11 +724,11 @@ class Validation { protected static function _pass($method, $check, $classPrefix) { $className = ucwords($classPrefix) . 'Validation'; if (!class_exists($className)) { - trigger_error(__('Could not find %s class, unable to complete validation.', $className), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Could not find %s class, unable to complete validation.', $className), E_USER_WARNING); return false; } if (!method_exists($className, $method)) { - trigger_error(__('Method %s does not exist on %s unable to complete validation.', $method, $className), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Method %s does not exist on %s unable to complete validation.', $method, $className), E_USER_WARNING); return false; } $check = (array)$check; @@ -845,4 +844,4 @@ class Validation { private static function __reset() { self::$errors = array(); } -} +} \ No newline at end of file diff --git a/cake/libs/xml.php b/lib/Cake/Utility/Xml.php similarity index 93% rename from cake/libs/xml.php rename to lib/Cake/Utility/Xml.php index 1a90ddf94..ab2f21e42 100644 --- a/cake/libs/xml.php +++ b/lib/Cake/Utility/Xml.php @@ -100,9 +100,9 @@ class Xml { $dom->load($input); return $dom; } elseif (!is_string($input)) { - throw new XmlException(__('Invalid input.')); + throw new XmlException(__d('cake_dev', 'Invalid input.')); } - throw new XmlException(__('XML cannot be read.')); + throw new XmlException(__d('cake_dev', 'XML cannot be read.')); } /** @@ -144,11 +144,11 @@ class Xml { */ public static function fromArray($input, $options = array()) { if (!is_array($input) || count($input) !== 1) { - throw new XmlException(__('Invalid input.')); + throw new XmlException(__d('cake_dev', 'Invalid input.')); } $key = key($input); if (is_integer($key)) { - throw new XmlException(__('The key of input must be alphanumeric')); + throw new XmlException(__d('cake_dev', 'The key of input must be alphanumeric')); } if (!is_array($options)) { @@ -181,7 +181,7 @@ class Xml { * @param string $format Either 'attribute' or 'tags'. This determines where nested keys go. * @return void */ - protected static function _fromArray(&$dom, &$node, &$data, $format) { + protected static function _fromArray($dom, $node, &$data, $format) { if (empty($data) || !is_array($data)) { return; } @@ -212,7 +212,7 @@ class Xml { } } else { if ($key[0] === '@') { - throw new XmlException(__('Invalid array')); + throw new XmlException(__d('cake_dev', 'Invalid array')); } if (array_keys($value) === range(0, count($value) - 1)) { // List foreach ($value as $item) { @@ -225,7 +225,7 @@ class Xml { } } } else { - throw new XmlException(__('Invalid array')); + throw new XmlException(__d('cake_dev', 'Invalid array')); } } } @@ -277,7 +277,7 @@ class Xml { $obj = simplexml_import_dom($obj); } if (!($obj instanceof SimpleXMLElement)) { - throw new XmlException(__('The input is not instance of SimpleXMLElement, DOMDocument or DOMNode.')); + throw new XmlException(__d('cake_dev', 'The input is not instance of SimpleXMLElement, DOMDocument or DOMNode.')); } $result = array(); $namespaces = array_merge(array('' => ''), $obj->getNamespaces(true)); diff --git a/cake/VERSION.txt b/lib/Cake/VERSION.txt similarity index 100% rename from cake/VERSION.txt rename to lib/Cake/VERSION.txt diff --git a/cake/libs/view/helper.php b/lib/Cake/View/Helper.php similarity index 93% rename from cake/libs/view/helper.php rename to lib/Cake/View/Helper.php index 16ea94798..cba5786ad 100644 --- a/cake/libs/view/helper.php +++ b/lib/Cake/View/Helper.php @@ -19,9 +19,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -if (!class_exists('Router')) { - App::import('Core', 'Router'); -} +App::uses('Router', 'Routing'); /** * Abstract base class for all other Helpers in CakePHP. @@ -105,30 +103,6 @@ class Helper extends Object { */ protected $_View; -/** - * Minimized attributes - * - * @var array - */ - protected $_minimizedAttributes = array( - 'compact', 'checked', 'declare', 'readonly', 'disabled', 'selected', - 'defer', 'ismap', 'nohref', 'noshade', 'nowrap', 'multiple', 'noresize' - ); - -/** - * Format to attribute - * - * @var string - */ - protected $_attributeFormat = '%s="%s"'; - -/** - * Format to attribute - * - * @var string - */ - protected $_minimizedAttributeFormat = '%s="%s"'; - /** * Default Constructor * @@ -150,7 +124,7 @@ class Helper extends Object { * @param array $params Array of params for the method. */ public function __call($method, $params) { - trigger_error(__('Method %1$s::%2$s does not exist', get_class($this), $method), E_USER_WARNING); + trigger_error(__d('cake_dev', 'Method %1$s::%2$s does not exist', get_class($this), $method), E_USER_WARNING); } /** @@ -198,22 +172,6 @@ class Helper extends Object { return $this->{$name} = $value; } -/** - * Parses tag templates into $this->tags. - * - * @param $name file name inside app/config to load. - * @return array merged tags from config/$name.php - */ - public function loadConfig($name = 'tags') { - if (file_exists(CONFIGS . $name .'.php')) { - require(CONFIGS . $name .'.php'); - if (isset($tags)) { - $this->tags = array_merge($this->tags, $tags); - } - } - return $this->tags; - } - /** * Finds URL for specified action. * @@ -280,11 +238,9 @@ class Helper extends Object { * @return string Path with a timestamp added, or not. */ public function assetTimestamp($path) { - $timestampEnabled = ( - (Configure::read('Asset.timestamp') === true && Configure::read('debug') > 0) || - Configure::read('Asset.timestamp') === 'force' - ); - if (strpos($path, '?') === false && $timestampEnabled) { + $stamp = Configure::read('Asset.timestamp'); + $timestampEnabled = $stamp === 'force' || ($stamp === true && Configure::read('debug') > 0); + if ($timestampEnabled && strpos($path, '?') === false) { $filepath = preg_replace('/^' . preg_quote($this->request->webroot, '/') . '/', '', $path); $webrootPath = WWW_ROOT . str_replace('/', DS, $filepath); if (file_exists($webrootPath)) { @@ -331,6 +287,7 @@ class Helper extends Object { } /** +<<<<<<< HEAD:lib/Cake/View/Helper.php * Returns a space-delimited string with items of the $options array. If a * key of $options array happens to be one of: * @@ -370,18 +327,19 @@ class Helper extends Object { * @return string Composed attributes. */ public function _parseAttributes($options, $exclude = null, $insertBefore = ' ', $insertAfter = null) { - if (is_array($options)) { - $options = array_merge(array('escape' => true), $options); + if (!is_string($options)) { + $options = (array) $options + array('escape' => true); if (!is_array($exclude)) { $exclude = array(); } - $filtered = array_diff_key($options, array_merge(array_flip($exclude), array('escape' => true))); + + $exclude = array('escape' => true) + array_flip($exclude); $escape = $options['escape']; $attributes = array(); - foreach ($filtered as $key => $value) { - if ($value !== false && $value !== null) { + foreach ($options as $key => $value) { + if (!isset($exclude[$key]) && $value !== false && $value !== null) { $attributes[] = $this->_formatAttribute($key, $value, $escape); } } @@ -426,7 +384,7 @@ class Helper extends Object { * @return void */ public function setEntity($entity, $setScope = false) { - $view =& $this->_View; + $view = $this->_View; if ($setScope) { $view->modelScope = false; } elseif (!empty($view->entityPath) && $view->entityPath == $entity) { @@ -473,7 +431,7 @@ class Helper extends Object { } if (ClassRegistry::isKeySet($model)) { - $ModelObj =& ClassRegistry::getObject($model); + $ModelObj = ClassRegistry::getObject($model); for ($i = 0; $i < $count; $i++) { if ( is_a($ModelObj, 'Model') && @@ -730,7 +688,7 @@ class Helper extends Object { } $habtmKey = $this->field(); - if (empty($result) && isset($data[$habtmKey][$habtmKey])) { + if (empty($result) && isset($data[$habtmKey][$habtmKey]) && is_array($data[$habtmKey])) { $result = $data[$habtmKey][$habtmKey]; } elseif (empty($result) && isset($data[$habtmKey]) && is_array($data[$habtmKey])) { if (ClassRegistry::isKeySet($habtmKey)) { diff --git a/cake/console/templates/skel/app_helper.php b/lib/Cake/View/Helper/AppHelper.php similarity index 96% rename from cake/console/templates/skel/app_helper.php rename to lib/Cake/View/Helper/AppHelper.php index 02955a34e..b293bfaba 100644 --- a/cake/console/templates/skel/app_helper.php +++ b/lib/Cake/View/Helper/AppHelper.php @@ -19,7 +19,7 @@ * @since CakePHP(tm) v 0.2.9 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Helper', 'Helper', false); +App::uses('Helper', 'View'); /** * This is a placeholder class. diff --git a/cake/libs/view/helpers/cache.php b/lib/Cake/View/Helper/CacheHelper.php similarity index 96% rename from cake/libs/view/helpers/cache.php rename to lib/Cake/View/Helper/CacheHelper.php index 34f1c9ef3..5bd804474 100644 --- a/cake/libs/view/helpers/cache.php +++ b/lib/Cake/View/Helper/CacheHelper.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('AppHelper', 'View/Helper'); + /** * CacheHelper helps create full page view caching. * @@ -213,8 +215,8 @@ class CacheHelper extends AppHelper { } else { $cacheTime = strtotime($timestamp, $now); } - $path = $this->request->here; - if ($this->here == '/') { + $path = $this->request->here(); + if ($path == '/') { $path = 'home'; } $cache = strtolower(Inflector::slug($path)); @@ -241,8 +243,10 @@ class CacheHelper extends AppHelper { $controller->layout = $this->layout = \'' . $this->_View->layout. '\'; $controller->request = $this->request = unserialize(\'' . str_replace("'", "\\'", serialize($this->request)) . '\'); $controller->theme = $this->theme = \'' . $this->_View->theme . '\'; + $controller->viewVars = unserialize(base64_decode(\'' . base64_encode(serialize($this->_View->viewVars)) . '\')); Router::setRequestInfo($controller->request);'; + if ($useCallbacks == true) { $file .= ' $controller->constructClasses(); @@ -251,6 +255,7 @@ class CacheHelper extends AppHelper { $file .= ' $this->loadHelpers(); + extract($this->viewVars, EXTR_SKIP); ?>'; $content = preg_replace("/(<\\?xml)/", "",$content); $file .= $content; diff --git a/cake/libs/view/helpers/form.php b/lib/Cake/View/Helper/FormHelper.php similarity index 92% rename from cake/libs/view/helpers/form.php rename to lib/Cake/View/Helper/FormHelper.php index dd1c7d85f..5140257e9 100644 --- a/cake/libs/view/helpers/form.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -19,6 +19,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('AppHelper', 'View/Helper'); + /** * Form helper library. * @@ -169,7 +171,8 @@ class FormHelper extends AppHelper { * * - `type` Form method defaults to POST * - `action` The controller action the form submits to, (optional). - * - `url` The url the form submits to. Can be a string or a url array, + * - `url` The url the form submits to. Can be a string or a url array. If you use 'url' + * you should leave 'action' undefined. * - `default` Allows for the creation of Ajax forms. * - `onsubmit` Used in conjunction with 'default' to create ajax forms. * - `inputDefaults` set the default $options for FormHelper::input(). Any options that would @@ -239,7 +242,14 @@ class FormHelper extends AppHelper { $this->_inputDefaults = $options['inputDefaults']; unset($options['inputDefaults']); - if (empty($options['url']) || is_array($options['url'])) { + if (!isset($options['id'])) { + $domId = isset($options['action']) ? $options['action'] : $this->request['action']; + $options['id'] = $this->domId($domId . 'Form'); + } + + if ($options['action'] === null && $options['url'] === null) { + $options['action'] = $this->request->here(false); + } elseif (empty($options['url']) || is_array($options['url'])) { if (empty($options['url']['controller'])) { if (!empty($model) && $model != $this->defaultModel) { $options['url']['controller'] = Inflector::underscore(Inflector::pluralize($model)); @@ -256,11 +266,8 @@ class FormHelper extends AppHelper { 'controller' => $this->_View->viewPath, 'action' => $options['action'], ); - if (!empty($options['action']) && !isset($options['id'])) { - $options['id'] = $this->domId($options['action'] . 'Form'); - } $options['action'] = array_merge($actionDefaults, (array)$options['url']); - if (empty($options['action'][0])) { + if (empty($options['action'][0]) && !empty($id)) { $options['action'][0] = $id; } } elseif (is_string($options['url'])) { @@ -314,12 +321,11 @@ class FormHelper extends AppHelper { } if (!empty($append)) { - $append = sprintf($this->Html->tags['block'], ' style="display:none;"', $append); + $append = $this->Html->useTag('block', ' style="display:none;"', $append); } $this->setEntity($model . '.', true); - $attributes = $this->_parseAttributes($htmlAttributes, null, ''); - return sprintf($this->Html->tags['form'], $attributes) . $append; + return $this->Html->useTag('form', $htmlAttributes) . $append; } /** @@ -360,10 +366,6 @@ class FormHelper extends AppHelper { unset($options['label']); } $submitOptions = $options; - - if (!$submit) { - $submit = __('Submit'); - } } $out .= $this->submit($submit, $submitOptions); } @@ -372,7 +374,7 @@ class FormHelper extends AppHelper { $this->fields = array(); } $this->setEntity(null); - $out .= $this->Html->tags['formend']; + $out .= $this->Html->useTag('formend'); $this->_View->modelScope = false; return $out; @@ -407,8 +409,7 @@ class FormHelper extends AppHelper { 'value' => urlencode($fields . ':' . $locked), 'id' => 'TokenFields' . mt_rand() )); - $out = sprintf($this->Html->tags['block'], ' style="display:none;"', $out); - return $out; + return $this->Html->useTag('block', ' style="display:none;"', $out); } /** @@ -505,7 +506,7 @@ class FormHelper extends AppHelper { if ($text != null) { $error = $text; } elseif (is_numeric($error)) { - $error = __('Error in field %s', Inflector::humanize($this->field())); + $error = __d('cake', 'Error in field %s', Inflector::humanize($this->field())); } if ($options['escape']) { $error = h($error); @@ -548,7 +549,7 @@ class FormHelper extends AppHelper { if (substr($text, -3) == '_id') { $text = substr($text, 0, strlen($text) - 3); } - $text = __(Inflector::humanize(Inflector::underscore($text))); + $text = __d('cake', Inflector::humanize(Inflector::underscore($text))); } if (is_string($options)) { @@ -562,11 +563,7 @@ class FormHelper extends AppHelper { $labelFor = $this->domId($fieldName); } - return sprintf( - $this->Html->tags['label'], - $labelFor, - $this->_parseAttributes($options), $text - ); + return $this->Html->useTag('label', $labelFor, $options, $text); } /** @@ -621,13 +618,13 @@ class FormHelper extends AppHelper { } if ($legend === true) { - $actionName = __('New %s'); + $actionName = __d('cake', 'New %s'); $isEdit = ( strpos($this->request->params['action'], 'update') !== false || strpos($this->request->params['action'], 'edit') !== false ); if ($isEdit) { - $actionName = __('Edit %s'); + $actionName = __d('cake', 'Edit %s'); } $modelName = Inflector::humanize(Inflector::underscore($model)); $legend = sprintf($actionName, __($modelName)); @@ -657,13 +654,9 @@ class FormHelper extends AppHelper { } if ($fieldset && $legend) { - return sprintf( - $this->Html->tags['fieldset'], - $fieldsetClass, - sprintf($this->Html->tags['legend'], $legend) . $out - ); + return $this->Html->useTag('fieldset', $fieldsetClass, $this->Html->useTag('legend', $legend) . $out); } elseif ($fieldset) { - return sprintf($this->Html->tags['fieldset'], $fieldsetClass, $out); + return $this->Html->useTag('fieldset', $fieldsetClass, $out); } else { return $out; } @@ -985,8 +978,11 @@ class FormHelper extends AppHelper { * - `value` - the value of the checkbox * - `checked` - boolean indicate that this checkbox is checked. * - `hiddenField` - boolean to indicate if you want the results of checkbox() to include - * a hidden input with a value of ''. + * a hidden input with a value of ''. * - `disabled` - create a disabled input. + * - `default` - Set the default value for the checkbox. This allows you to start checkboxes + * as checked, without having to check the POST data. A matching POST data value, will overwrite + * the default value. * * @param string $fieldName Name of a field, like this "Modelname.fieldname" * @param array $options Array of HTML attributes. @@ -995,13 +991,23 @@ class FormHelper extends AppHelper { * @link http://book.cakephp.org/view/1414/checkbox */ public function checkbox($fieldName, $options = array()) { + $valueOptions = array(); + if(isset($options['default'])){ + $valueOptions['default'] = $options['default']; + unset($options['default']); + } + $options = $this->_initInputField($fieldName, $options) + array('hiddenField' => true); - $value = current($this->value()); + $value = current($this->value($valueOptions)); $output = ""; if (empty($options['value'])) { $options['value'] = 1; - } elseif (!empty($value) && $value === $options['value']) { + } + if ( + (!isset($options['checked']) && !empty($value) && $value == $options['value']) || + !empty($options['checked']) + ) { $options['checked'] = 'checked'; } if ($options['hiddenField']) { @@ -1016,11 +1022,7 @@ class FormHelper extends AppHelper { } unset($options['hiddenField']); - return $output . sprintf( - $this->Html->tags['checkbox'], - $options['name'], - $this->_parseAttributes($options, array('name'), null, ' ') - ); + return $output . $this->Html->useTag('checkbox', $options['name'], array_diff_key($options, array('name' => ''))); } /** @@ -1046,6 +1048,7 @@ class FormHelper extends AppHelper { public function radio($fieldName, $options = array(), $attributes = array()) { $attributes = $this->_initInputField($fieldName, $attributes); $legend = false; + $disabled = array(); if (isset($attributes['legend'])) { $legend = $attributes['legend']; @@ -1071,6 +1074,11 @@ class FormHelper extends AppHelper { } else { $value = $this->value($fieldName); } + + if (isset($attributes['disabled'])) { + $disabled = $attributes['disabled']; + } + $out = array(); $hiddenField = isset($attributes['hiddenField']) ? $attributes['hiddenField'] : true; @@ -1082,20 +1090,20 @@ class FormHelper extends AppHelper { if (isset($value) && $optValue == $value) { $optionsHere['checked'] = 'checked'; } - $parsedOptions = $this->_parseAttributes( - array_merge($attributes, $optionsHere), - array('name', 'type', 'id'), '', ' ' - ); + if (!empty($disabled) && in_array($optValue, $disabled)) { + $optionsHere['disabled'] = true; + } $tagName = Inflector::camelize( $attributes['id'] . '_' . Inflector::slug($optValue) ); if ($label) { - $optTitle = sprintf($this->Html->tags['label'], $tagName, null, $optTitle); + $optTitle = $this->Html->useTag('label', $tagName, '', $optTitle); } - $out[] = sprintf( - $this->Html->tags['radio'], $attributes['name'], - $tagName, $parsedOptions, $optTitle + $allOptions = array_merge($attributes, $optionsHere); + $out[] = $this->Html->useTag('radio', $attributes['name'], $tagName, + array_diff_key($allOptions, array('name' => '', 'type' => '', 'id' => '')), + $optTitle ); } $hidden = null; @@ -1110,16 +1118,13 @@ class FormHelper extends AppHelper { $out = $hidden . implode($inbetween, $out); if ($legend) { - $out = sprintf( - $this->Html->tags['fieldset'], '', - sprintf($this->Html->tags['legend'], $legend) . $out - ); + $out = $this->Html->useTag('fieldset', '', $this->Html->useTag('legend', $legend) . $out); } return $out; } /** - * Missing method handler - implements various simple input types. Is used to create inputs + * Missing method handler - implements various simple input types. Is used to create inputs * of various types. e.g. `$this->Form->text();` will create `` while * `$this->Form->range();` will create `` * @@ -1142,7 +1147,7 @@ class FormHelper extends AppHelper { public function __call($method, $params) { $options = array(); if (empty($params)) { - throw new CakeException(__('Missing field name for FormHelper::%s', $method)); + throw new CakeException(__d('cake_dev', 'Missing field name for FormHelper::%s', $method)); } if (isset($params[1])) { $options = $params[1]; @@ -1151,11 +1156,7 @@ class FormHelper extends AppHelper { $options['type'] = $method; } $options = $this->_initInputField($params[0], $options); - return sprintf( - $this->Html->tags['input'], - $options['name'], - $this->_parseAttributes($options, array('name'), null, ' ') - ); + return $this->Html->useTag('input', $options['name'], array_diff_key($options, array('name' => ''))); } /** @@ -1182,12 +1183,7 @@ class FormHelper extends AppHelper { } unset($options['value']); } - return sprintf( - $this->Html->tags['textarea'], - $options['name'], - $this->_parseAttributes($options, array('type', 'name'), null, ' '), - $value - ); + return $this->Html->useTag('textarea', $options['name'], array_diff_key($options, array('type' => '', 'name' => '')), $value); } /** @@ -1215,11 +1211,7 @@ class FormHelper extends AppHelper { $this->__secure(null, '' . $options['value']); } - return sprintf( - $this->Html->tags['hidden'], - $options['name'], - $this->_parseAttributes($options, array('name', 'class'), '', ' ') - ); + return $this->Html->useTag('hidden', $options['name'], array_diff_key($options, array('name' => '', 'class' => ''))); } /** @@ -1240,8 +1232,7 @@ class FormHelper extends AppHelper { $this->__secure(array_merge($field, array($suffix))); } - $attributes = $this->_parseAttributes($options, array('name'), '', ' '); - return sprintf($this->Html->tags['file'], $options['name'], $attributes); + return $this->Html->useTag('file', $options['name'], array_diff_key($options, array('name' => ''))); } /** @@ -1263,12 +1254,7 @@ class FormHelper extends AppHelper { if ($options['escape']) { $title = h($title); } - return sprintf( - $this->Html->tags['button'], - $options['type'], - $this->_parseAttributes($options, array('type'), ' ', ''), - $title - ); + return $this->Html->useTag('button', $options['type'], array_diff_key($options, array('type' => '')), $title); } /** @@ -1322,7 +1308,6 @@ class FormHelper extends AppHelper { unset($options['confirm']); } - $url = $this->url($url); $formName = uniqid('post_'); $out = $this->create(false, array('url' => $url, 'name' => $formName, 'id' => $formName, 'style' => 'display:none;')); if (isset($options['data']) && is_array($options['data'])) { @@ -1377,8 +1362,8 @@ class FormHelper extends AppHelper { * @link http://book.cakephp.org/view/1431/submit */ public function submit($caption = null, $options = array()) { - if (!$caption) { - $caption = __('Submit'); + if (!is_string($caption) && empty($caption)) { + $caption = __d('cake', 'Submit'); } $out = null; $div = true; @@ -1406,11 +1391,7 @@ class FormHelper extends AppHelper { if (strpos($caption, '://') !== false) { unset($options['type']); - $out .= $before . sprintf( - $this->Html->tags['submitimage'], - $caption, - $this->_parseAttributes($options, null, '', ' ') - ) . $after; + $out .= $before . $this->Html->useTag('submitimage', $caption, $options) . $after; } elseif (preg_match('/\.(jpg|jpe|jpeg|gif|png|ico)$/', $caption)) { unset($options['type']); if ($caption{0} !== '/') { @@ -1419,17 +1400,10 @@ class FormHelper extends AppHelper { $caption = trim($caption, '/'); $url = $this->webroot($caption); } - $out .= $before . sprintf( - $this->Html->tags['submitimage'], - $url, - $this->_parseAttributes($options, null, '', ' ') - ) . $after; + $out .= $before . $this->Html->useTag('submitimage', $url, $options) . $after; } else { $options['value'] = $caption; - $out .= $before . sprintf( - $this->Html->tags['submit'], - $this->_parseAttributes($options, null, '', ' ') - ). $after; + $out .= $before . $this->Html->useTag('submit', $options) . $after; } if (isset($divOptions)) { @@ -1493,7 +1467,7 @@ class FormHelper extends AppHelper { $style = null; $tag = null; $attributes += array( - 'class' => null, + 'class' => null, 'escape' => true, 'secure' => null, 'empty' => '', @@ -1522,7 +1496,7 @@ class FormHelper extends AppHelper { if (isset($attributes) && array_key_exists('multiple', $attributes)) { $style = ($attributes['multiple'] === 'checkbox') ? 'checkbox' : null; $template = ($style) ? 'checkboxmultiplestart' : 'selectmultiplestart'; - $tag = $this->Html->tags[$template]; + $tag = $template; $hiddenAttributes = array( 'value' => '', 'id' => $attributes['id'] . ($style ? '' : '_'), @@ -1531,16 +1505,14 @@ class FormHelper extends AppHelper { ); $select[] = $this->hidden(null, $hiddenAttributes); } else { - $tag = $this->Html->tags['selectstart']; + $tag = 'selectstart'; } if (!empty($tag) || isset($template)) { if (!isset($secure) || $secure == true) { $this->__secure(); } - $select[] = sprintf($tag, $attributes['name'], $this->_parseAttributes( - $attributes, array('name', 'value')) - ); + $select[] = $this->Html->useTag($tag, $attributes['name'], array_diff_key($attributes, array('name' => '', 'value' => ''))); } $emptyMulti = ( $showEmpty !== null && $showEmpty !== false && !( @@ -1564,7 +1536,7 @@ class FormHelper extends AppHelper { )); $template = ($style == 'checkbox') ? 'checkboxmultipleend' : 'selectend'; - $select[] = $this->Html->tags[$template]; + $select[] = $this->Html->useTag($template); return implode("\n", $select); } @@ -1898,8 +1870,11 @@ class FormHelper extends AppHelper { if ($time[0] == 0 && $timeFormat == '12') { $time[0] = 12; } - $hour = $time[0]; - $min = $time[1]; + $hour = $min = null; + if (isset($time[1])) { + $hour = $time[0]; + $min = $time[1]; + } } } } @@ -2021,7 +1996,7 @@ class FormHelper extends AppHelper { return $options; } - $name = $this->_View->field; + $name = !empty($this->_View->field) ? $this->_View->field : $this->_View->model; if (!empty($this->_View->fieldSuffix)) { $name .= '[' . $this->_View->fieldSuffix . ']'; } @@ -2044,7 +2019,7 @@ class FormHelper extends AppHelper { function __selectOptions($elements = array(), $parents = array(), $showParents = null, $attributes = array()) { $select = array(); $attributes = array_merge( - array('escape' => true, 'style' => null, 'value' => null, 'class' => null), + array('escape' => true, 'style' => null, 'value' => null, 'class' => null), $attributes ); $selectedIsEmpty = ($attributes['value'] === '' || $attributes['value'] === null); @@ -2055,9 +2030,9 @@ class FormHelper extends AppHelper { if (is_array($title) && (!isset($title['name']) || !isset($title['value']))) { if (!empty($name)) { if ($attributes['style'] === 'checkbox') { - $select[] = $this->Html->tags['fieldsetend']; + $select[] = $this->Html->useTag('fieldsetend'); } else { - $select[] = $this->Html->tags['optiongroupend']; + $select[] = $this->Html->useTag('optiongroupend'); } $parents[] = $name; } @@ -2068,9 +2043,9 @@ class FormHelper extends AppHelper { if (!empty($name)) { $name = $attributes['escape'] ? h($name) : $name; if ($attributes['style'] === 'checkbox') { - $select[] = sprintf($this->Html->tags['fieldsetstart'], $name); + $select[] = $this->Html->useTag('fieldsetstart', $name); } else { - $select[] = sprintf($this->Html->tags['optiongroup'], $name, ''); + $select[] = $this->Html->useTag('optiongroup', $name, ''); } } $name = null; @@ -2113,18 +2088,14 @@ class FormHelper extends AppHelper { if (empty($attributes['class'])) { $attributes['class'] = 'checkbox'; + } elseif ($attributes['class'] === 'form-error') { + $attributes['class'] = 'checkbox ' . $attributes['class']; } $label = $this->label(null, $title, $label); - $item = sprintf( - $this->Html->tags['checkboxmultiple'], $name, - $this->_parseAttributes($htmlOptions) - ); + $item = $this->Html->useTag('checkboxmultiple', $name, $htmlOptions); $select[] = $this->Html->div($attributes['class'], $item . $label); } else { - $select[] = sprintf( - $this->Html->tags['selectoption'], - $name, $this->_parseAttributes($htmlOptions), $title - ); + $select[] = $this->Html->useTag('selectoption', $name, $htmlOptions, $title); } } } @@ -2186,18 +2157,18 @@ class FormHelper extends AppHelper { break; case 'month': if ($options['monthNames'] === true) { - $data['01'] = __('January'); - $data['02'] = __('February'); - $data['03'] = __('March'); - $data['04'] = __('April'); - $data['05'] = __('May'); - $data['06'] = __('June'); - $data['07'] = __('July'); - $data['08'] = __('August'); - $data['09'] = __('September'); - $data['10'] = __('October'); - $data['11'] = __('November'); - $data['12'] = __('December'); + $data['01'] = __d('cake', 'January'); + $data['02'] = __d('cake', 'February'); + $data['03'] = __d('cake', 'March'); + $data['04'] = __d('cake', 'April'); + $data['05'] = __d('cake', 'May'); + $data['06'] = __d('cake', 'June'); + $data['07'] = __d('cake', 'July'); + $data['08'] = __d('cake', 'August'); + $data['09'] = __d('cake', 'September'); + $data['10'] = __d('cake', 'October'); + $data['11'] = __d('cake', 'November'); + $data['12'] = __d('cake', 'December'); } else if (is_array($options['monthNames'])) { $data = $options['monthNames']; } else { @@ -2253,10 +2224,19 @@ class FormHelper extends AppHelper { } else { $secure = (isset($this->request['_Token']) && !empty($this->request['_Token'])); } + + $fieldName = null; + if ($secure && !empty($options['name'])) { + preg_match_all('/\[(.*?)\]/', $options['name'], $matches); + if (isset($matches[1])) { + $fieldName = $matches[1]; + } + } + $result = parent::_initInputField($field, $options); if ($secure) { - $this->__secure(); + $this->__secure($fieldName); } return $result; } diff --git a/cake/libs/view/helpers/html.php b/lib/Cake/View/Helper/HtmlHelper.php similarity index 76% rename from cake/libs/view/helpers/html.php rename to lib/Cake/View/Helper/HtmlHelper.php index c5165515f..f10afa305 100644 --- a/cake/libs/view/helpers/html.php +++ b/lib/Cake/View/Helper/HtmlHelper.php @@ -16,6 +16,9 @@ * @since CakePHP(tm) v 0.9.1 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ + +App::uses('AppHelper', 'View/Helper'); + /** * Html Helper class for easy use of HTML widgets. * @@ -29,18 +32,17 @@ class HtmlHelper extends AppHelper { * html tags used by this helper. * * @var array - * @access public */ - public $tags = array( + protected $_tags = array( 'meta' => '', 'metalink' => '', 'link' => '%s', 'mailto' => '%s', - 'form' => '
    ', + 'form' => '', 'formend' => '', - 'input' => '', - 'textarea' => '', - 'hidden' => '', + 'input' => '', + 'textarea' => '', + 'hidden' => '', 'checkbox' => '', 'checkboxmultiple' => '', 'radio' => '%s', @@ -90,6 +92,30 @@ class HtmlHelper extends AppHelper { 'javascriptend' => '' ); +/** + * Minimized attributes + * + * @var array + */ + protected $_minimizedAttributes = array( + 'compact', 'checked', 'declare', 'readonly', 'disabled', 'selected', + 'defer', 'ismap', 'nohref', 'noshade', 'nowrap', 'multiple', 'noresize' + ); + +/** + * Format to attribute + * + * @var string + */ + protected $_attributeFormat = '%s="%s"'; + +/** + * Format to attribute + * + * @var string + */ + protected $_minimizedAttributeFormat = '%s="%s"'; + /** * Breadcrumbs. * @@ -122,12 +148,26 @@ class HtmlHelper extends AppHelper { 'html4-strict' => '', 'html4-trans' => '', 'html4-frame' => '', + 'html5' => '', 'xhtml-strict' => '', 'xhtml-trans' => '', 'xhtml-frame' => '', 'xhtml11' => '' ); +/** + * Default Constructor + * + * @param View $View The View this helper is being attached to. + * @param array $settings Configuration settings for the helper. + */ + public function __construct(View $View, $settings = array()) { + parent::__construct($View, $settings); + if (!empty($settings['configFile'])) { + $this->loadConfig($settings['configFile']); + } + } + /** * Adds a link to the breadcrumbs array. * @@ -149,6 +189,7 @@ class HtmlHelper extends AppHelper { * - html4-strict: HTML4 Strict. * - html4-trans: HTML4 Transitional. * - html4-frame: HTML4 Frameset. + * - html5: HTML5. * - xhtml-strict: XHTML1 Strict. * - xhtml-trans: XHTML1 Transitional. * - xhtml-frame: XHTML1 Frameset. @@ -220,14 +261,14 @@ class HtmlHelper extends AppHelper { if (isset($options['link'])) { if (isset($options['rel']) && $options['rel'] === 'icon') { - $out = sprintf($this->tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' ')); + $out = sprintf($this->_tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' ')); $options['rel'] = 'shortcut icon'; } else { $options['link'] = $this->url($options['link'], true); } - $out .= sprintf($this->tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' ')); + $out .= sprintf($this->_tags['metalink'], $options['link'], $this->_parseAttributes($options, array('link'), ' ', ' ')); } else { - $out = sprintf($this->tags['meta'], $this->_parseAttributes($options, array('type'), ' ', ' ')); + $out = sprintf($this->_tags['meta'], $this->_parseAttributes($options, array('type'), ' ', ' ')); } if ($inline) { @@ -250,7 +291,7 @@ class HtmlHelper extends AppHelper { if (empty($charset)) { $charset = strtolower(Configure::read('App.encoding')); } - return sprintf($this->tags['charset'], (!empty($charset) ? $charset : 'utf-8')); + return sprintf($this->_tags['charset'], (!empty($charset) ? $charset : 'utf-8')); } /** @@ -310,7 +351,7 @@ class HtmlHelper extends AppHelper { } unset($options['default']); } - return sprintf($this->tags['link'], $url, $this->_parseAttributes($options), $title); + return sprintf($this->_tags['link'], $url, $this->_parseAttributes($options), $title); } /** @@ -365,12 +406,12 @@ class HtmlHelper extends AppHelper { } if ($rel == 'import') { - $out = sprintf($this->tags['style'], $this->_parseAttributes($options, array('inline'), '', ' '), '@import url(' . $url . ');'); + $out = sprintf($this->_tags['style'], $this->_parseAttributes($options, array('inline'), '', ' '), '@import url(' . $url . ');'); } else { if ($rel == null) { $rel = 'stylesheet'; } - $out = sprintf($this->tags['css'], $rel, $url, $this->_parseAttributes($options, array('inline'), '', ' ')); + $out = sprintf($this->_tags['css'], $rel, $url, $this->_parseAttributes($options, array('inline'), '', ' ')); } if ($options['inline']) { @@ -436,7 +477,7 @@ class HtmlHelper extends AppHelper { } } $attributes = $this->_parseAttributes($options, array('inline', 'once'), ' '); - $out = sprintf($this->tags['javascriptlink'], $url, $attributes); + $out = sprintf($this->_tags['javascriptlink'], $url, $attributes); if ($options['inline']) { return $out; @@ -468,9 +509,9 @@ class HtmlHelper extends AppHelper { unset($options['inline'], $options['safe']); $attributes = $this->_parseAttributes($options, ' ', ' '); if ($inline) { - return sprintf($this->tags['javascriptblock'], $attributes, $script); + return sprintf($this->_tags['javascriptblock'], $attributes, $script); } else { - $this->_View->addScript(sprintf($this->tags['javascriptblock'], $attributes, $script)); + $this->_View->addScript(sprintf($this->_tags['javascriptblock'], $attributes, $script)); return null; } } @@ -649,10 +690,10 @@ class HtmlHelper extends AppHelper { unset($options['url']); } - $image = sprintf($this->tags['image'], $path, $this->_parseAttributes($options, null, '', ' ')); + $image = sprintf($this->_tags['image'], $path, $this->_parseAttributes($options, null, '', ' ')); if ($url) { - return sprintf($this->tags['link'], $this->url($url), null, $image); + return sprintf($this->_tags['link'], $this->url($url), null, $image); } return $image; } @@ -670,9 +711,9 @@ class HtmlHelper extends AppHelper { public function tableHeaders($names, $trOptions = null, $thOptions = null) { $out = array(); foreach ($names as $arg) { - $out[] = sprintf($this->tags['tableheader'], $this->_parseAttributes($thOptions), $arg); + $out[] = sprintf($this->_tags['tableheader'], $this->_parseAttributes($thOptions), $arg); } - return sprintf($this->tags['tablerow'], $this->_parseAttributes($trOptions), join(' ', $out)); + return sprintf($this->_tags['tablerow'], $this->_parseAttributes($trOptions), join(' ', $out)); } /** @@ -722,10 +763,10 @@ class HtmlHelper extends AppHelper { } elseif ($useCount) { $cellOptions['class'] = 'column-' . ++$i; } - $cellsOut[] = sprintf($this->tags['tablecell'], $this->_parseAttributes($cellOptions), $cell); + $cellsOut[] = sprintf($this->_tags['tablecell'], $this->_parseAttributes($cellOptions), $cell); } $options = $this->_parseAttributes($count % 2 ? $oddTrOptions : $evenTrOptions); - $out[] = sprintf($this->tags['tablerow'], $options, implode(' ', $cellsOut)); + $out[] = sprintf($this->_tags['tablerow'], $options, implode(' ', $cellsOut)); } return implode("\n", $out); } @@ -758,7 +799,27 @@ class HtmlHelper extends AppHelper { } else { $tag = 'tag'; } - return sprintf($this->tags[$tag], $name, $this->_parseAttributes($options, null, ' ', ''), $text, $name); + return sprintf($this->_tags[$tag], $name, $this->_parseAttributes($options, null, ' ', ''), $text, $name); + } + +/** + * Returns a formatted existent block of $tags + * + * @param string $tag Tag name + * @return string Formatted block + */ + public function useTag($tag) { + if (!isset($this->_tags[$tag])) { + return ''; + } + $args = func_get_args(); + array_shift($args); + foreach ($args as &$arg) { + if (is_array($arg)) { + $arg = $this->_parseAttributes($arg, null, ' ', ''); + } + } + return vsprintf($this->_tags[$tag], $args); } /** @@ -809,7 +870,7 @@ class HtmlHelper extends AppHelper { } else { $tag = 'para'; } - return sprintf($this->tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $text); + return sprintf($this->_tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $text); } /** @@ -827,7 +888,7 @@ class HtmlHelper extends AppHelper { $options = array(); } $items = $this->__nestedListItem($list, $options, $itemOptions, $tag); - return sprintf($this->tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $items); + return sprintf($this->_tags[$tag], $this->_parseAttributes($options, null, ' ', ''), $items); } /** @@ -854,9 +915,146 @@ class HtmlHelper extends AppHelper { } else if (isset($itemOptions['odd']) && $index % 2 != 0) { $itemOptions['class'] = $itemOptions['odd']; } - $out .= sprintf($this->tags['li'], $this->_parseAttributes($itemOptions, array('even', 'odd'), ' ', ''), $item); + $out .= sprintf($this->_tags['li'], $this->_parseAttributes($itemOptions, array('even', 'odd'), ' ', ''), $item); $index++; } return $out; } + +/** + * Load Html configs + * + * @param mixed $configFile String with the config file (load using PhpReader) or an array with file and reader name + * @param string $path Path with config file + * @return mixed False to error or loaded configs + */ + public function loadConfig($configFile, $path = CONFIGS) { + $file = null; + $reader = 'php'; + + if (!is_array($configFile)) { + $file = $configFile; + } elseif (isset($configFile[0])) { + $file = $configFile[0]; + if (isset($configFile[1])) { + $reader = $configFile[1]; + } + } else { + throw new ConfigureException(__d('cake_dev', 'Cannot load the configuration file. Wrong "configFile" configuration.')); + } + + $readerClass = Inflector::camelize($reader) . 'Reader'; + App::uses($readerClass, 'Configure'); + if (!class_exists($readerClass)) { + throw new ConfigureException(__d('cake_dev', 'Cannot load the configuration file. Unknown reader.')); + } + + $readerObj = new $readerClass($path); + $configs = $readerObj->read($file); + if (isset($configs['tags']) && is_array($configs['tags'])) { + $this->_tags = array_merge($this->_tags, $configs['tags']); + } + if (isset($configs['minimizedAttributes']) && is_array($configs['minimizedAttributes'])) { + $this->_minimizedAttributes = array_merge($this->_minimizedAttributes, $configs['minimizedAttributes']); + } + if (isset($configs['docTypes']) && is_array($configs['docTypes'])) { + $this->__docTypes = array_merge($this->__docTypes, $configs['docTypes']); + } + if (isset($configs['attributeFormat'])) { + $this->_attributeFormat = $configs['attributeFormat']; + } + if (isset($configs['minimizedAttributeFormat'])) { + $this->_minimizedAttributeFormat = $configs['minimizedAttributeFormat']; + } + return $configs; + } + +/** + * Returns a space-delimited string with items of the $options array. If a + * key of $options array happens to be one of: + * + * - 'compact' + * - 'checked' + * - 'declare' + * - 'readonly' + * - 'disabled' + * - 'selected' + * - 'defer' + * - 'ismap' + * - 'nohref' + * - 'noshade' + * - 'nowrap' + * - 'multiple' + * - 'noresize' + * + * And its value is one of: + * + * - '1' (string) + * - 1 (integer) + * - true (boolean) + * - 'true' (string) + * + * Then the value will be reset to be identical with key's name. + * If the value is not one of these 3, the parameter is not output. + * + * 'escape' is a special option in that it controls the conversion of + * attributes to their html-entity encoded equivalents. Set to false to disable html-encoding. + * + * If value for any option key is set to `null` or `false`, that option will be excluded from output. + * + * @param array $options Array of options. + * @param array $exclude Array of options to be excluded, the options here will not be part of the return. + * @param string $insertBefore String to be inserted before options. + * @param string $insertAfter String to be inserted after options. + * @return string Composed attributes. + */ + public function _parseAttributes($options, $exclude = null, $insertBefore = ' ', $insertAfter = null) { + if (is_array($options)) { + $options = array_merge(array('escape' => true), $options); + + if (!is_array($exclude)) { + $exclude = array(); + } + $filtered = array_diff_key($options, array_merge(array_flip($exclude), array('escape' => true))); + $escape = $options['escape']; + $attributes = array(); + + foreach ($filtered as $key => $value) { + if ($value !== false && $value !== null) { + $attributes[] = $this->_formatAttribute($key, $value, $escape); + } + } + $out = implode(' ', $attributes); + } else { + $out = $options; + } + return $out ? $insertBefore . $out . $insertAfter : ''; + } + +/** + * Formats an individual attribute, and returns the string value of the composed attribute. + * Works with minimized attributes that have the same value as their name such as 'disabled' and 'checked' + * + * @param string $key The name of the attribute to create + * @param string $value The value of the attribute to create. + * @return string The composed attribute. + */ + protected function _formatAttribute($key, $value, $escape = true) { + $attribute = ''; + if (is_array($value)) { + $value = ''; + } + + if (is_numeric($key)) { + $attribute = sprintf($this->_minimizedAttributeFormat, $value, $value); + } elseif (in_array($key, $this->_minimizedAttributes)) { + if ($value === 1 || $value === true || $value === 'true' || $value === '1' || $value == $key) { + $attribute = sprintf($this->_minimizedAttributeFormat, $key, $key); + } + } else { + $attribute = sprintf($this->_attributeFormat, $key, ($escape ? h($value) : $value)); + } + return $attribute; + } + } diff --git a/cake/libs/view/helpers/jquery_engine.php b/lib/Cake/View/Helper/JqueryEngineHelper.php similarity index 98% rename from cake/libs/view/helpers/jquery_engine.php rename to lib/Cake/View/Helper/JqueryEngineHelper.php index b0864fba1..91e22d033 100644 --- a/cake/libs/view/helpers/jquery_engine.php +++ b/lib/Cake/View/Helper/JqueryEngineHelper.php @@ -21,7 +21,9 @@ * @package cake.libs.view.helpers * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Helper', 'Js'); + +App::uses('AppHelper', 'View/Helper'); +App::uses('JsBaseEngineHelper', 'View/Helper'); class JqueryEngineHelper extends JsBaseEngineHelper { /** @@ -263,7 +265,7 @@ class JqueryEngineHelper extends JsBaseEngineHelper { unset($options['update']); } $callbacks = array('success', 'error', 'beforeSend', 'complete'); - if (isset($options['dataExpression'])) { + if (!empty($options['dataExpression'])) { $callbacks[] = 'data'; unset($options['dataExpression']); } diff --git a/cake/libs/view/helpers/js.php b/lib/Cake/View/Helper/JsBaseEngineHelper.php similarity index 58% rename from cake/libs/view/helpers/js.php rename to lib/Cake/View/Helper/JsBaseEngineHelper.php index e285481ad..ade4ca558 100644 --- a/cake/libs/view/helpers/js.php +++ b/lib/Cake/View/Helper/JsBaseEngineHelper.php @@ -1,6 +1,6 @@ __engineName = $className . 'Engine'; - $engineClass = $engineName . 'Engine'; - $this->helpers[] = $engineClass; - parent::__construct($View, $settings); - } - -/** - * call__ Allows for dispatching of methods to the Engine Helper. - * methods in the Engines bufferedMethods list will be automatically buffered. - * You can control buffering with the buffer param as well. By setting the last parameter to - * any engine method to a boolean you can force or disable buffering. - * - * e.g. `$js->get('#foo')->effect('fadeIn', array('speed' => 'slow'), true);` - * - * Will force buffering for the effect method. If the method takes an options array you may also add - * a 'buffer' param to the options array and control buffering there as well. - * - * e.g. `$js->get('#foo')->event('click', $functionContents, array('buffer' => true));` - * - * The buffer parameter will not be passed onto the EngineHelper. - * - * @param string $method Method to be called - * @param array $params Parameters for the method being called. - * @return mixed Depends on the return of the dispatched method, or it could be an instance of the EngineHelper - */ - public function __call($method, $params) { - if ($this->{$this->__engineName} && method_exists($this->{$this->__engineName}, $method)) { - $buffer = false; - $engineHelper = $this->{$this->__engineName}; - if (in_array(strtolower($method), $engineHelper->bufferedMethods)) { - $buffer = true; - } - if (count($params) > 0) { - $lastParam = $params[count($params) - 1]; - $hasBufferParam = (is_bool($lastParam) || is_array($lastParam) && isset($lastParam['buffer'])); - if ($hasBufferParam && is_bool($lastParam)) { - $buffer = $lastParam; - unset($params[count($params) - 1]); - } elseif ($hasBufferParam && is_array($lastParam)) { - $buffer = $lastParam['buffer']; - unset($params['buffer']); - } - } - - $out = call_user_func_array(array(&$engineHelper, $method), $params); - if ($this->bufferScripts && $buffer && is_string($out)) { - $this->buffer($out); - return null; - } - if (is_object($out) && is_a($out, 'JsBaseEngineHelper')) { - return $this; - } - return $out; - } - if (method_exists($this, $method . '_')) { - return call_user_func(array(&$this, $method . '_'), $params); - } - trigger_error(__('JsHelper:: Missing Method %s is undefined', $method), E_USER_WARNING); - } - -/** - * Overwrite inherited Helper::value() - * See JsBaseEngineHelper::value() for more information on this method. - * - * @param mixed $val A PHP variable to be converted to JSON - * @param boolean $quoteStrings If false, leaves string values unquoted - * @return string a JavaScript-safe/JSON representation of $val - * @access public - **/ - function value($val, $quoteString = true) { - return $this->{$this->__engineName}->value($val, $quoteString); - } - -/** - * Writes all Javascript generated so far to a code block or - * caches them to a file and returns a linked script. If no scripts have been - * buffered this method will return null. If the request is an XHR(ajax) request - * onDomReady will be set to false. As the dom is already 'ready'. - * - * ### Options - * - * - `inline` - Set to true to have scripts output as a script block inline - * if `cache` is also true, a script link tag will be generated. (default true) - * - `cache` - Set to true to have scripts cached to a file and linked in (default false) - * - `clear` - Set to false to prevent script cache from being cleared (default true) - * - `onDomReady` - wrap cached scripts in domready event (default true) - * - `safe` - if an inline block is generated should it be wrapped in (default true) - * - * @param array $options options for the code block - * @return mixed Completed javascript tag if there are scripts, if there are no buffered - * scripts null will be returned. - */ - public function writeBuffer($options = array()) { - $domReady = $this->request->is('ajax'); - $defaults = array( - 'onDomReady' => $domReady, 'inline' => true, - 'cache' => false, 'clear' => true, 'safe' => true - ); - $options = array_merge($defaults, $options); - $script = implode("\n", $this->getBuffer($options['clear'])); - - if (empty($script)) { - return null; - } - - if ($options['onDomReady']) { - $script = $this->{$this->__engineName}->domReady($script); - } - $opts = $options; - unset($opts['onDomReady'], $opts['cache'], $opts['clear']); - - if (!$options['cache'] && $options['inline']) { - return $this->Html->scriptBlock($script, $opts); - } - - if ($options['cache'] && $options['inline']) { - $filename = md5($script); - if (!file_exists(JS . $filename . '.js')) { - cache(str_replace(WWW_ROOT, '', JS) . $filename . '.js', $script, '+999 days', 'public'); - } - return $this->Html->script($filename); - } - $this->Html->scriptBlock($script, $opts); - return null; - } - -/** - * Write a script to the buffered scripts. - * - * @param string $script Script string to add to the buffer. - * @param boolean $top If true the script will be added to the top of the - * buffered scripts array. If false the bottom. - * @return void - */ - public function buffer($script, $top = false) { - if ($top) { - array_unshift($this->__bufferedScripts, $script); - } else { - $this->__bufferedScripts[] = $script; - } - } - -/** - * Get all the buffered scripts - * - * @param boolean $clear Whether or not to clear the script caches (default true) - * @return array Array of scripts added to the request. - */ - public function getBuffer($clear = true) { - $this->_createVars(); - $scripts = $this->__bufferedScripts; - if ($clear) { - $this->__bufferedScripts = array(); - $this->__jsVars = array(); - } - return $scripts; - } - -/** - * Generates the object string for variables passed to javascript. - * - * @return string Generated JSON object of all set vars - */ - protected function _createVars() { - if (!empty($this->__jsVars)) { - $setVar = (strpos($this->setVariable, '.')) ? $this->setVariable : 'window.' . $this->setVariable; - $this->buffer($setVar . ' = ' . $this->object($this->__jsVars) . ';', true); - } - } - -/** - * Generate an 'Ajax' link. Uses the selected JS engine to create a link - * element that is enhanced with Javascript. Options can include - * both those for HtmlHelper::link() and JsBaseEngine::request(), JsBaseEngine::event(); - * - * ### Options - * - * - `confirm` - Generate a confirm() dialog before sending the event. - * - `id` - use a custom id. - * - `htmlAttributes` - additional non-standard htmlAttributes. Standard attributes are class, id, - * rel, title, escape, onblur and onfocus. - * - `buffer` - Disable the buffering and return a script tag in addition to the link. - * - * @param string $title Title for the link. - * @param mixed $url Mixed either a string URL or an cake url array. - * @param array $options Options for both the HTML element and Js::request() - * @return string Completed link. If buffering is disabled a script tag will be returned as well. - */ - public function link($title, $url = null, $options = array()) { - if (!isset($options['id'])) { - $options['id'] = 'link-' . intval(mt_rand()); - } - list($options, $htmlOptions) = $this->_getHtmlOptions($options); - $out = $this->Html->link($title, $url, $htmlOptions); - $this->get('#' . $htmlOptions['id']); - $requestString = $event = ''; - if (isset($options['confirm'])) { - $requestString = $this->confirmReturn($options['confirm']); - unset($options['confirm']); - } - $buffer = isset($options['buffer']) ? $options['buffer'] : null; - $safe = isset($options['safe']) ? $options['safe'] : true; - unset($options['buffer'], $options['safe']); - - $requestString .= $this->request($url, $options); - - if (!empty($requestString)) { - $event = $this->event('click', $requestString, $options + array('buffer' => $buffer)); - } - if (isset($buffer) && !$buffer) { - $opts = array('safe' => $safe); - $out .= $this->Html->scriptBlock($event, $opts); - } - return $out; - } - -/** - * Pass variables into Javascript. Allows you to set variables that will be - * output when the buffer is fetched with `JsHelper::getBuffer()` or `JsHelper::writeBuffer()` - * The Javascript variable used to output set variables can be controlled with `JsHelper::$setVariable` - * - * @param mixed $one Either an array of variables to set, or the name of the variable to set. - * @param mixed $two If $one is a string, $two is the value for that key. - * @return void - */ - public function set($one, $two = null) { - $data = null; - if (is_array($one)) { - if (is_array($two)) { - $data = array_combine($one, $two); - } else { - $data = $one; - } - } else { - $data = array($one => $two); - } - if ($data == null) { - return false; - } - $this->__jsVars = array_merge($this->__jsVars, $data); - } - -/** - * Uses the selected JS engine to create a submit input - * element that is enhanced with Javascript. Options can include - * both those for FormHelper::submit() and JsBaseEngine::request(), JsBaseEngine::event(); - * - * Forms submitting with this method, cannot send files. Files do not transfer over XmlHttpRequest - * and require an iframe or flash. - * - * ### Options - * - * - `url` The url you wish the XHR request to submit to. - * - `confirm` A string to use for a confirm() message prior to submitting the request. - * - `method` The method you wish the form to send by, defaults to POST - * - `buffer` Whether or not you wish the script code to be buffered, defaults to true. - * - Also see options for JsHelper::request() and JsHelper::event() - * - * @param string $title The display text of the submit button. - * @param array $options Array of options to use. See the options for the above mentioned methods. - * @return string Completed submit button. - */ - public function submit($caption = null, $options = array()) { - if (!isset($options['id'])) { - $options['id'] = 'submit-' . intval(mt_rand()); - } - $formOptions = array('div'); - list($options, $htmlOptions) = $this->_getHtmlOptions($options, $formOptions); - $out = $this->Form->submit($caption, $htmlOptions); - - $this->get('#' . $htmlOptions['id']); - - $options['data'] = $this->serializeForm(array('isForm' => false, 'inline' => true)); - $requestString = $url = ''; - if (isset($options['confirm'])) { - $requestString = $this->confirmReturn($options['confirm']); - unset($options['confirm']); - } - if (isset($options['url'])) { - $url = $options['url']; - unset($options['url']); - } - if (!isset($options['method'])) { - $options['method'] = 'post'; - } - $options['dataExpression'] = true; - - $buffer = isset($options['buffer']) ? $options['buffer'] : null; - $safe = isset($options['safe']) ? $options['safe'] : true; - unset($options['buffer'], $options['safe']); - - $requestString .= $this->request($url, $options); - if (!empty($requestString)) { - $event = $this->event('click', $requestString, $options + array('buffer' => $buffer)); - } - if (isset($buffer) && !$buffer) { - $opts = array('safe' => $safe); - $out .= $this->Html->scriptBlock($event, $opts); - } - return $out; - } - -/** - * Parse a set of Options and extract the Html options. - * Extracted Html Options are removed from the $options param. - * - * @param array $options Options to filter. - * @param array $additional Array of additional keys to extract and include in the return options array. - * @return array Array of js options and Htmloptions - */ - protected function _getHtmlOptions($options, $additional = array()) { - $htmlKeys = array_merge(array('class', 'id', 'escape', 'onblur', 'onfocus', 'rel', 'title'), $additional); - $htmlOptions = array(); - foreach ($htmlKeys as $key) { - if (isset($options[$key])) { - $htmlOptions[$key] = $options[$key]; - } - unset($options[$key]); - } - if (isset($options['htmlAttributes'])) { - $htmlOptions = array_merge($htmlOptions, $options['htmlAttributes']); - unset($options['htmlAttributes']); - } - return array($options, $htmlOptions); - } -} +App::uses('AppHelper', 'View/Helper'); /** * JsEngineBaseClass @@ -474,9 +73,9 @@ abstract class JsBaseEngineHelper extends AppHelper { /** * Constructor. * - * @return void */ - function __construct() { + function __construct($View, $settings = array()) { + parent::__construct($View, $settings); $this->useNative = function_exists('json_encode'); } @@ -648,7 +247,6 @@ abstract class JsBaseEngineHelper extends AppHelper { * @return string Escaped string. */ public function escape($string) { - App::import('Core', 'Multibyte'); return $this->_utf8ToHex($string); } @@ -1051,4 +649,4 @@ abstract class JsBaseEngineHelper extends AppHelper { } return $out; } -} +} \ No newline at end of file diff --git a/lib/Cake/View/Helper/JsHelper.php b/lib/Cake/View/Helper/JsHelper.php new file mode 100644 index 000000000..c9b3ecb4a --- /dev/null +++ b/lib/Cake/View/Helper/JsHelper.php @@ -0,0 +1,427 @@ +__engineName = $className . 'Engine'; + $engineClass = $engineName . 'Engine'; + $this->helpers[] = $engineClass; + parent::__construct($View, $settings); + } + +/** + * call__ Allows for dispatching of methods to the Engine Helper. + * methods in the Engines bufferedMethods list will be automatically buffered. + * You can control buffering with the buffer param as well. By setting the last parameter to + * any engine method to a boolean you can force or disable buffering. + * + * e.g. `$js->get('#foo')->effect('fadeIn', array('speed' => 'slow'), true);` + * + * Will force buffering for the effect method. If the method takes an options array you may also add + * a 'buffer' param to the options array and control buffering there as well. + * + * e.g. `$js->get('#foo')->event('click', $functionContents, array('buffer' => true));` + * + * The buffer parameter will not be passed onto the EngineHelper. + * + * @param string $method Method to be called + * @param array $params Parameters for the method being called. + * @return mixed Depends on the return of the dispatched method, or it could be an instance of the EngineHelper + */ + public function __call($method, $params) { + if ($this->{$this->__engineName} && method_exists($this->{$this->__engineName}, $method)) { + $buffer = false; + $engineHelper = $this->{$this->__engineName}; + if (in_array(strtolower($method), $engineHelper->bufferedMethods)) { + $buffer = true; + } + if (count($params) > 0) { + $lastParam = $params[count($params) - 1]; + $hasBufferParam = (is_bool($lastParam) || is_array($lastParam) && isset($lastParam['buffer'])); + if ($hasBufferParam && is_bool($lastParam)) { + $buffer = $lastParam; + unset($params[count($params) - 1]); + } elseif ($hasBufferParam && is_array($lastParam)) { + $buffer = $lastParam['buffer']; + unset($params['buffer']); + } + } + + $out = call_user_func_array(array(&$engineHelper, $method), $params); + if ($this->bufferScripts && $buffer && is_string($out)) { + $this->buffer($out); + return null; + } + if (is_object($out) && is_a($out, 'JsBaseEngineHelper')) { + return $this; + } + return $out; + } + if (method_exists($this, $method . '_')) { + return call_user_func(array(&$this, $method . '_'), $params); + } + trigger_error(__d('cake_dev', 'JsHelper:: Missing Method %s is undefined', $method), E_USER_WARNING); + } + +/** + * Overwrite inherited Helper::value() + * See JsBaseEngineHelper::value() for more information on this method. + * + * @param mixed $val A PHP variable to be converted to JSON + * @param boolean $quoteStrings If false, leaves string values unquoted + * @return string a JavaScript-safe/JSON representation of $val + * @access public + **/ + function value($val, $quoteString = true) { + return $this->{$this->__engineName}->value($val, $quoteString); + } + +/** + * Writes all Javascript generated so far to a code block or + * caches them to a file and returns a linked script. If no scripts have been + * buffered this method will return null. If the request is an XHR(ajax) request + * onDomReady will be set to false. As the dom is already 'ready'. + * + * ### Options + * + * - `inline` - Set to true to have scripts output as a script block inline + * if `cache` is also true, a script link tag will be generated. (default true) + * - `cache` - Set to true to have scripts cached to a file and linked in (default false) + * - `clear` - Set to false to prevent script cache from being cleared (default true) + * - `onDomReady` - wrap cached scripts in domready event (default true) + * - `safe` - if an inline block is generated should it be wrapped in (default true) + * + * @param array $options options for the code block + * @return mixed Completed javascript tag if there are scripts, if there are no buffered + * scripts null will be returned. + */ + public function writeBuffer($options = array()) { + $domReady = $this->request->is('ajax'); + $defaults = array( + 'onDomReady' => $domReady, 'inline' => true, + 'cache' => false, 'clear' => true, 'safe' => true + ); + $options = array_merge($defaults, $options); + $script = implode("\n", $this->getBuffer($options['clear'])); + + if (empty($script)) { + return null; + } + + if ($options['onDomReady']) { + $script = $this->{$this->__engineName}->domReady($script); + } + $opts = $options; + unset($opts['onDomReady'], $opts['cache'], $opts['clear']); + + if (!$options['cache'] && $options['inline']) { + return $this->Html->scriptBlock($script, $opts); + } + + if ($options['cache'] && $options['inline']) { + $filename = md5($script); + if (!file_exists(JS . $filename . '.js')) { + cache(str_replace(WWW_ROOT, '', JS) . $filename . '.js', $script, '+999 days', 'public'); + } + return $this->Html->script($filename); + } + $this->Html->scriptBlock($script, $opts); + return null; + } + +/** + * Write a script to the buffered scripts. + * + * @param string $script Script string to add to the buffer. + * @param boolean $top If true the script will be added to the top of the + * buffered scripts array. If false the bottom. + * @return void + */ + public function buffer($script, $top = false) { + if ($top) { + array_unshift($this->__bufferedScripts, $script); + } else { + $this->__bufferedScripts[] = $script; + } + } + +/** + * Get all the buffered scripts + * + * @param boolean $clear Whether or not to clear the script caches (default true) + * @return array Array of scripts added to the request. + */ + public function getBuffer($clear = true) { + $this->_createVars(); + $scripts = $this->__bufferedScripts; + if ($clear) { + $this->__bufferedScripts = array(); + $this->__jsVars = array(); + } + return $scripts; + } + +/** + * Generates the object string for variables passed to javascript. + * + * @return string Generated JSON object of all set vars + */ + protected function _createVars() { + if (!empty($this->__jsVars)) { + $setVar = (strpos($this->setVariable, '.')) ? $this->setVariable : 'window.' . $this->setVariable; + $this->buffer($setVar . ' = ' . $this->object($this->__jsVars) . ';', true); + } + } + +/** + * Generate an 'Ajax' link. Uses the selected JS engine to create a link + * element that is enhanced with Javascript. Options can include + * both those for HtmlHelper::link() and JsBaseEngine::request(), JsBaseEngine::event(); + * + * ### Options + * + * - `confirm` - Generate a confirm() dialog before sending the event. + * - `id` - use a custom id. + * - `htmlAttributes` - additional non-standard htmlAttributes. Standard attributes are class, id, + * rel, title, escape, onblur and onfocus. + * - `buffer` - Disable the buffering and return a script tag in addition to the link. + * + * @param string $title Title for the link. + * @param mixed $url Mixed either a string URL or an cake url array. + * @param array $options Options for both the HTML element and Js::request() + * @return string Completed link. If buffering is disabled a script tag will be returned as well. + */ + public function link($title, $url = null, $options = array()) { + if (!isset($options['id'])) { + $options['id'] = 'link-' . intval(mt_rand()); + } + list($options, $htmlOptions) = $this->_getHtmlOptions($options); + $out = $this->Html->link($title, $url, $htmlOptions); + $this->get('#' . $htmlOptions['id']); + $requestString = $event = ''; + if (isset($options['confirm'])) { + $requestString = $this->confirmReturn($options['confirm']); + unset($options['confirm']); + } + $buffer = isset($options['buffer']) ? $options['buffer'] : null; + $safe = isset($options['safe']) ? $options['safe'] : true; + unset($options['buffer'], $options['safe']); + + $requestString .= $this->request($url, $options); + + if (!empty($requestString)) { + $event = $this->event('click', $requestString, $options + array('buffer' => $buffer)); + } + if (isset($buffer) && !$buffer) { + $opts = array('safe' => $safe); + $out .= $this->Html->scriptBlock($event, $opts); + } + return $out; + } + +/** + * Pass variables into Javascript. Allows you to set variables that will be + * output when the buffer is fetched with `JsHelper::getBuffer()` or `JsHelper::writeBuffer()` + * The Javascript variable used to output set variables can be controlled with `JsHelper::$setVariable` + * + * @param mixed $one Either an array of variables to set, or the name of the variable to set. + * @param mixed $two If $one is a string, $two is the value for that key. + * @return void + */ + public function set($one, $two = null) { + $data = null; + if (is_array($one)) { + if (is_array($two)) { + $data = array_combine($one, $two); + } else { + $data = $one; + } + } else { + $data = array($one => $two); + } + if ($data == null) { + return false; + } + $this->__jsVars = array_merge($this->__jsVars, $data); + } + +/** + * Uses the selected JS engine to create a submit input + * element that is enhanced with Javascript. Options can include + * both those for FormHelper::submit() and JsBaseEngine::request(), JsBaseEngine::event(); + * + * Forms submitting with this method, cannot send files. Files do not transfer over XmlHttpRequest + * and require an iframe or flash. + * + * ### Options + * + * - `url` The url you wish the XHR request to submit to. + * - `confirm` A string to use for a confirm() message prior to submitting the request. + * - `method` The method you wish the form to send by, defaults to POST + * - `buffer` Whether or not you wish the script code to be buffered, defaults to true. + * - Also see options for JsHelper::request() and JsHelper::event() + * + * @param string $title The display text of the submit button. + * @param array $options Array of options to use. See the options for the above mentioned methods. + * @return string Completed submit button. + */ + public function submit($caption = null, $options = array()) { + if (!isset($options['id'])) { + $options['id'] = 'submit-' . intval(mt_rand()); + } + $formOptions = array('div'); + list($options, $htmlOptions) = $this->_getHtmlOptions($options, $formOptions); + $out = $this->Form->submit($caption, $htmlOptions); + + $this->get('#' . $htmlOptions['id']); + + $options['data'] = $this->serializeForm(array('isForm' => false, 'inline' => true)); + $requestString = $url = ''; + if (isset($options['confirm'])) { + $requestString = $this->confirmReturn($options['confirm']); + unset($options['confirm']); + } + if (isset($options['url'])) { + $url = $options['url']; + unset($options['url']); + } + if (!isset($options['method'])) { + $options['method'] = 'post'; + } + $options['dataExpression'] = true; + + $buffer = isset($options['buffer']) ? $options['buffer'] : null; + $safe = isset($options['safe']) ? $options['safe'] : true; + unset($options['buffer'], $options['safe']); + + $requestString .= $this->request($url, $options); + if (!empty($requestString)) { + $event = $this->event('click', $requestString, $options + array('buffer' => $buffer)); + } + if (isset($buffer) && !$buffer) { + $opts = array('safe' => $safe); + $out .= $this->Html->scriptBlock($event, $opts); + } + return $out; + } + +/** + * Parse a set of Options and extract the Html options. + * Extracted Html Options are removed from the $options param. + * + * @param array $options Options to filter. + * @param array $additional Array of additional keys to extract and include in the return options array. + * @return array Array of js options and Htmloptions + */ + protected function _getHtmlOptions($options, $additional = array()) { + $htmlKeys = array_merge( + array('class', 'id', 'escape', 'onblur', 'onfocus', 'rel', 'title', 'style'), + $additional + ); + $htmlOptions = array(); + foreach ($htmlKeys as $key) { + if (isset($options[$key])) { + $htmlOptions[$key] = $options[$key]; + } + unset($options[$key]); + } + if (isset($options['htmlAttributes'])) { + $htmlOptions = array_merge($htmlOptions, $options['htmlAttributes']); + unset($options['htmlAttributes']); + } + return array($options, $htmlOptions); + } +} \ No newline at end of file diff --git a/cake/libs/view/helpers/mootools_engine.php b/lib/Cake/View/Helper/MootoolsEngineHelper.php similarity index 98% rename from cake/libs/view/helpers/mootools_engine.php rename to lib/Cake/View/Helper/MootoolsEngineHelper.php index 5064db644..726ca624b 100644 --- a/cake/libs/view/helpers/mootools_engine.php +++ b/lib/Cake/View/Helper/MootoolsEngineHelper.php @@ -24,7 +24,8 @@ * @since CakePHP(tm) v 1.3 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Helper', 'Js'); + +App::uses('JsBaseEngineHelper', 'View/Helper'); class MootoolsEngineHelper extends JsBaseEngineHelper { /** @@ -251,7 +252,7 @@ class MootoolsEngineHelper extends JsBaseEngineHelper { } $options['url'] = $url; $options = $this->_prepareCallbacks('request', $options); - if (isset($options['dataExpression'])) { + if (!empty($options['dataExpression'])) { $callbacks[] = 'data'; unset($options['dataExpression']); } elseif (!empty($data)) { @@ -306,7 +307,7 @@ class MootoolsEngineHelper extends JsBaseEngineHelper { function drop($options = array()) { if (empty($options['drag'])) { trigger_error( - __('MootoolsEngine::drop() requires a "drag" option to properly function'), E_USER_WARNING + __d('cake_dev', 'MootoolsEngine::drop() requires a "drag" option to properly function'), E_USER_WARNING ); return false; } diff --git a/cake/libs/view/helpers/number.php b/lib/Cake/View/Helper/NumberHelper.php similarity index 77% rename from cake/libs/view/helpers/number.php rename to lib/Cake/View/Helper/NumberHelper.php index c88cd8ff2..011d5d9eb 100644 --- a/cake/libs/view/helpers/number.php +++ b/lib/Cake/View/Helper/NumberHelper.php @@ -19,6 +19,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('AppHelper', 'View/Helper'); + /** * Number helper library. * @@ -38,16 +40,16 @@ class NumberHelper extends AppHelper { */ protected $_currencies = array( 'USD' => array( - 'before' => '$', 'after' => 'c', 'zero' => 0, 'places' => 2, 'thousands' => ',', - 'decimals' => '.', 'negative' => '()', 'escape' => true + 'wholeSymbol' => '$', 'wholePosition' => 'before', 'fractionSymbol' => 'c', 'fractionPosition' => 'after', + 'zero' => 0, 'places' => 2, 'thousands' => ',', 'decimals' => '.', 'negative' => '()', 'escape' => true ), 'GBP' => array( - 'before'=>'£', 'after' => 'p', 'zero' => 0, 'places' => 2, 'thousands' => ',', - 'decimals' => '.', 'negative' => '()','escape' => false + 'wholeSymbol'=>'£', 'wholePosition' => 'before', 'fractionSymbol' => 'p', 'fractionPosition' => 'after', + 'zero' => 0, 'places' => 2, 'thousands' => ',', 'decimals' => '.', 'negative' => '()','escape' => false ), 'EUR' => array( - 'before'=>'€', 'after' => false, 'zero' => 0, 'places' => 2, 'thousands' => '.', - 'decimals' => ',', 'negative' => '()', 'escape' => false + 'wholeSymbol'=>'€', 'wholePosition' => 'before', 'fractionSymbol' => false, 'fractionPosition' => 'after', + 'zero' => 0, 'places' => 2, 'thousands' => '.', 'decimals' => ',', 'negative' => '()', 'escape' => false ) ); @@ -58,8 +60,8 @@ class NumberHelper extends AppHelper { * @access protected */ protected $_currencyDefaults = array( - 'before'=>'', 'after' => '', 'zero' => '0', 'places' => 2, 'thousands' => ',', - 'decimals' => '.','negative' => '()', 'escape' => true + 'wholeSymbol'=>'', 'wholePosition' => 'before', 'fractionSymbol' => '', 'fractionPosition' => 'after', + 'zero' => '0', 'places' => 2, 'thousands' => ',', 'decimals' => '.','negative' => '()', 'escape' => true ); /** @@ -86,15 +88,15 @@ class NumberHelper extends AppHelper { public function toReadableSize($size) { switch (true) { case $size < 1024: - return __n('%d Byte', '%d Bytes', $size, $size); + return __dn('cake', '%d Byte', '%d Bytes', $size, $size); case round($size / 1024) < 1024: - return __('%d KB', $this->precision($size / 1024, 0)); + return __d('cake', '%d KB', $this->precision($size / 1024, 0)); case round($size / 1024 / 1024, 2) < 1024: - return __('%.2f MB', $this->precision($size / 1024 / 1024, 2)); + return __d('cake', '%.2f MB', $this->precision($size / 1024 / 1024, 2)); case round($size / 1024 / 1024 / 1024, 2) < 1024: - return __('%.2f GB', $this->precision($size / 1024 / 1024 / 1024, 2)); + return __d('cake', '%.2f GB', $this->precision($size / 1024 / 1024 / 1024, 2)); default: - return __('%.2f TB', $this->precision($size / 1024 / 1024 / 1024 / 1024, 2)); + return __d('cake', '%.2f TB', $this->precision($size / 1024 / 1024 / 1024 / 1024, 2)); } } @@ -162,7 +164,7 @@ class NumberHelper extends AppHelper { * ### Options * * - `before` - The currency symbol to place before whole numbers ie. '$' - * - `after` - The currency symbol to place after decimal numbers ie. 'c'. Set to boolean false to + * - `after` - The currency symbol to place after decimal numbers ie. 'c'. Set to boolean false to * use no decimal symbol. eg. 0.35 => $0.35. * - `zero` - The text to use for zero values, can be a string or a number. ie. 0, 'Free!' * - `places` - Number of decimal places to use. ie. 2 @@ -190,26 +192,32 @@ class NumberHelper extends AppHelper { $options = array_merge($default, $options); - $result = null; + if (isset($options['before']) && $options['before'] !== '') { + $options['wholeSymbol'] = $options['before']; + } + if (isset($options['after']) && !$options['after'] !== '') { + $options['fractionSymbol'] = $options['after']; + } + $result = $options['before'] = $options['after'] = null; + + $symbolKey = 'whole'; if ($number == 0 ) { if ($options['zero'] !== 0 ) { return $options['zero']; } - $options['after'] = null; } elseif ($number < 1 && $number > -1 ) { - if ($options['after'] !== false) { + if ($options['fractionSymbol'] !== false) { $multiply = intval('1' . str_pad('', $options['places'], '0')); $number = $number * $multiply; - $options['before'] = null; $options['places'] = null; + $symbolKey = 'fraction'; } - } elseif (empty($options['before'])) { - $options['before'] = null; - } else { - $options['after'] = null; } + $position = $options[$symbolKey.'Position'] != 'after' ? 'before' : 'after'; + $options[$position] = $options[$symbolKey.'Symbol']; + $abs = abs($number); $result = $this->format($abs, $options); @@ -228,7 +236,7 @@ class NumberHelper extends AppHelper { * currency formats easier. * * {{{ $number->addFormat('NOK', array('before' => 'Kr. ')); }}} - * + * * You can now use `NOK` as a shortform when formatting currency amounts. * * {{{ $number->currency($value, 'NOK'); }}} @@ -251,4 +259,4 @@ class NumberHelper extends AppHelper { $this->_currencies[$formatName] = $options + $this->_currencyDefaults; } -} +} \ No newline at end of file diff --git a/cake/libs/view/helpers/paginator.php b/lib/Cake/View/Helper/PaginatorHelper.php similarity index 97% rename from cake/libs/view/helpers/paginator.php rename to lib/Cake/View/Helper/PaginatorHelper.php index 8fe9e40ec..fc8650e31 100644 --- a/cake/libs/view/helpers/paginator.php +++ b/lib/Cake/View/Helper/PaginatorHelper.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('AppHelper', 'View/Helper'); + /** * Pagination Helper class for easy generation of pagination links. * @@ -67,7 +69,7 @@ class PaginatorHelper extends AppHelper { * - `escape` Defines if the title field for the link should be escaped (default: true). * - `update` DOM id of the element updated with the results of the AJAX call. * If this key isn't specified Paginator will use plain HTML links. - * - `paging['paramType']` The type of parameters to use when creating links. Valid options are + * - `paging['paramType']` The type of parameters to use when creating links. Valid options are * 'querystring', 'named', and 'route'. See PaginatorComponent::$settings for more information. * - `convertKeys` - A list of keys in url arrays that should be converted to querysting params * if paramType == 'querystring'. @@ -93,19 +95,17 @@ class PaginatorHelper extends AppHelper { * @throws CakeException When the AjaxProvider helper does not implement a link method. */ function __construct(View $View, $settings = array()) { - parent::__construct($View, $settings); $ajaxProvider = isset($settings['ajax']) ? $settings['ajax'] : 'Js'; $this->helpers[] = $ajaxProvider; $this->_ajaxHelperClass = $ajaxProvider; - if (!class_exists($ajaxProvider . 'Helper')) { - App::import('Helper', $ajaxProvider); - } + App::uses($ajaxProvider . 'Helper', 'View/Helper'); $classname = $ajaxProvider . 'Helper'; if (!method_exists($classname, 'link')) { throw new CakeException(sprintf( - __('%s does not implement a link() method, it is incompatible with PaginatorHelper'), $classname + __d('cake_dev', '%s does not implement a link() method, it is incompatible with PaginatorHelper'), $classname )); } + parent::__construct($View, $settings); } /** @@ -292,20 +292,20 @@ class PaginatorHelper extends AppHelper { * - `escape` Whether you want the contents html entity encoded, defaults to true * - `model` The model to use, defaults to PaginatorHelper::defaultModel() * - * @param string $title Title for the link. - * @param string $key The name of the key that the recordset should be sorted. If $key is null - * $title will be used for the key, and a title will be generated by inflection. + * @param string $key The name of the key that the recordset should be sorted. + * @param string $title Title for the link. If $title is null $key will be used + * for the title and will be generated by inflection. * @param array $options Options for sorting link. See above for list of keys. * @return string A link sorting default by 'asc'. If the resultset is sorted 'asc' by the specified * key the returned link will sort by 'desc'. */ - public function sort($title, $key = null, $options = array()) { + public function sort($key, $title = null, $options = array()) { $options = array_merge(array('url' => array(), 'model' => null), $options); $url = $options['url']; unset($options['url']); - if (empty($key)) { - $key = $title; + if (empty($title)) { + $title = $key; $title = __(Inflector::humanize(preg_replace('/_id$/', '', $title))); } $dir = isset($options['direction']) ? $options['direction'] : 'asc'; @@ -314,7 +314,7 @@ class PaginatorHelper extends AppHelper { $sortKey = $this->sortKey($options['model']); $defaultModel = $this->defaultModel(); $isSorted = ( - $sortKey === $key || + $sortKey === $key || $sortKey === $defaultModel . '.' . $key || $key === $defaultModel . '.' . $sortKey ); @@ -553,7 +553,7 @@ class PaginatorHelper extends AppHelper { array( 'model' => $this->defaultModel(), 'format' => 'pages', - 'separator' => __(' of ') + 'separator' => __d('cake', ' of ') ), $options); @@ -603,12 +603,12 @@ class PaginatorHelper extends AppHelper { /** * Returns a set of numbers for the paged result set - * uses a modulus to decide how many numbers to show on each side of the current page (default: 8). + * uses a modulus to decide how many numbers to show on each side of the current page (default: 8). * * `$this->Paginator->numbers(array('first' => 2, 'last' => 2));` * * Using the first and last options you can create links to the beginning and end of the page set. - * + * * * ### Options * @@ -862,4 +862,4 @@ class PaginatorHelper extends AppHelper { } return $out; } -} +} \ No newline at end of file diff --git a/cake/libs/view/helpers/prototype_engine.php b/lib/Cake/View/Helper/PrototypeEngineHelper.php similarity index 94% rename from cake/libs/view/helpers/prototype_engine.php rename to lib/Cake/View/Helper/PrototypeEngineHelper.php index 69a088f79..79c5ac17a 100644 --- a/cake/libs/view/helpers/prototype_engine.php +++ b/lib/Cake/View/Helper/PrototypeEngineHelper.php @@ -19,7 +19,8 @@ * @since CakePHP(tm) v 1.3 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Helper', 'Js'); + +App::uses('JsBaseEngineHelper', 'View/Helper'); class PrototypeEngineHelper extends JsBaseEngineHelper { /** @@ -44,10 +45,8 @@ class PrototypeEngineHelper extends JsBaseEngineHelper { 'error' => 'onFailure' ), 'sortable' => array( - 'start' => 'onStart', 'sort' => 'onChange', 'complete' => 'onUpdate', - 'distance' => 'snap', ), 'drag' => array( 'snapGrid' => 'snap', @@ -242,7 +241,7 @@ class PrototypeEngineHelper extends JsBaseEngineHelper { } $safe = array_keys($this->_callbackArguments['request']); $options = $this->_prepareCallbacks('request', $options, $safe); - if (isset($options['dataExpression'])) { + if (!empty($options['dataExpression'])) { $safe[] = 'parameters'; unset($options['dataExpression']); } @@ -258,6 +257,9 @@ class PrototypeEngineHelper extends JsBaseEngineHelper { * * #### Note: Requires scriptaculous to be loaded. * + * The scriptaculous implementation of sortables does not suppot the 'start' + * and 'distance' options. + * * @param array $options Array of options for the sortable. * @return string Completed sortable script. * @access public @@ -326,10 +328,14 @@ class PrototypeEngineHelper extends JsBaseEngineHelper { unset($options['handle']); if (isset($options['min']) && isset($options['max'])) { - $options['range'] = array($options['min'], $options['max']); + $options['range'] = sprintf('$R(%s,%s)', $options['min'], $options['max']); unset($options['min'], $options['max']); } - $optionString = $this->_processOptions('slider', $options); + $options = $this->_mapOptions('slider', $options); + $options = $this->_prepareCallbacks('slider', $options); + $optionString = $this->_parseOptions( + $options, array_merge(array_keys($this->_callbackArguments['slider']), array('range')) + ); if (!empty($optionString)) { $optionString = ', {' . $optionString . '}'; } diff --git a/cake/libs/view/helpers/rss.php b/lib/Cake/View/Helper/RssHelper.php similarity index 99% rename from cake/libs/view/helpers/rss.php rename to lib/Cake/View/Helper/RssHelper.php index c1b7d219d..890e7c603 100644 --- a/cake/libs/view/helpers/rss.php +++ b/lib/Cake/View/Helper/RssHelper.php @@ -16,7 +16,9 @@ * @since CakePHP(tm) v 1.2 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'Xml'); + +App::uses('AppHelper', 'View/Helper'); +App::uses('Xml', 'Utility'); /** * RSS Helper class for easy output RSS structures. diff --git a/cake/libs/view/helpers/session.php b/lib/Cake/View/Helper/SessionHelper.php similarity index 59% rename from cake/libs/view/helpers/session.php rename to lib/Cake/View/Helper/SessionHelper.php index fb26c91c7..eaa5260af 100644 --- a/cake/libs/view/helpers/session.php +++ b/lib/Cake/View/Helper/SessionHelper.php @@ -16,9 +16,10 @@ * @since CakePHP(tm) v 1.1.7.3328 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -if (!class_exists('CakeSession')) { - require LIBS . 'cake_session.php'; -} + +App::uses('AppHelper', 'View/Helper'); +App::uses('CakeSession', 'Model/Datasource'); + /** * Session Helper. * @@ -32,7 +33,7 @@ class SessionHelper extends AppHelper { /** * Used to read a session values set in a controller for a key or return values for all keys. * - * In your view: `$session->read('Controller.sessKey');` + * In your view: `$this->Session->read('Controller.sessKey');` * Calling the method without a param will return all session vars * * @param string $name the name of the session key you want to read @@ -46,7 +47,7 @@ class SessionHelper extends AppHelper { /** * Used to check is a session key has been set * - * In your view: `$session->check('Controller.sessKey');` + * In your view: `$this->Session->check('Controller.sessKey');` * * @param string $name * @return boolean @@ -59,7 +60,7 @@ class SessionHelper extends AppHelper { /** * Returns last error encountered in a session * - * In your view: `$session->error();` + * In your view: `$this->Session->error();` * * @return string last error * @link http://book.cakephp.org/view/1466/Methods @@ -71,32 +72,64 @@ class SessionHelper extends AppHelper { /** * Used to render the message set in Controller::Session::setFlash() * - * In your view: $session->flash('somekey'); + * In your view: $this->Session->flash('somekey'); * Will default to flash if no param is passed * + * You can pass additional information into the flash message generation. This allows you + * to consolidate all the parameters for a given type of flash message into the view. + * + * {{{ + * echo $this->Session->flash('flash', array('params' => array('class' => 'new-flash'))); + * }}} + * + * The above would generate a flash message with a custom class name. Using $attrs['params'] you + * can pass additional data into the element rendering that will be made available as local variables + * when the element is rendered: + * + * {{{ + * echo $this->Session->flash('flash', array('params' => array('name' => $user['User']['name']))); + * }}} + * + * This would pass the current user's name into the flash message, so you could create peronsonalized + * messages without the controller needing access to that data. + * + * Lastly you can choose the element that is rendered when creating the flash message. Using + * custom elements allows you to fully customize how flash messages are generated. + * + * {{{ + * echo $this->Session->flash('flash', array('element' => 'my_custom_element')); + * }}} + * * @param string $key The [Message.]key you are rendering in the view. - * @return boolean|string Will return the value if $key is set, or false if not set. + * @return array $attrs Additional attributes to use for the creation of this flash message. + * Supports the 'params', and 'element' keys that are used in the helper. * @access public * @link http://book.cakephp.org/view/1466/Methods * @link http://book.cakephp.org/view/1467/flash */ - public function flash($key = 'flash') { + public function flash($key = 'flash', $attrs = array()) { $out = false; if (CakeSession::check('Message.' . $key)) { $flash = CakeSession::read('Message.' . $key); + $message = $flash['message']; + unset($flash['message']); + + if (!empty($attrs)) { + $flash = array_merge($flash, $attrs); + } if ($flash['element'] == 'default') { $class = 'message'; if (!empty($flash['params']['class'])) { $class = $flash['params']['class']; } - $out = '
    ' . $flash['message'] . '
    '; + $out = '
    ' . $message . '
    '; } elseif ($flash['element'] == '' || $flash['element'] == null) { - $out = $flash['message']; + $out = $message; } else { $tmpVars = $flash['params']; - $tmpVars['message'] = $flash['message']; + $tmpVars['message'] = $message; $out = $this->_View->element($flash['element'], $tmpVars); } CakeSession::delete('Message.' . $key); diff --git a/cake/libs/view/helpers/text.php b/lib/Cake/View/Helper/TextHelper.php similarity index 97% rename from cake/libs/view/helpers/text.php rename to lib/Cake/View/Helper/TextHelper.php index 12eff3893..4195c3ac0 100644 --- a/cake/libs/view/helpers/text.php +++ b/lib/Cake/View/Helper/TextHelper.php @@ -23,12 +23,9 @@ * Included libraries. * */ -if (!class_exists('HtmlHelper')) { - App::import('Helper', 'Html'); -} -if (!class_exists('Multibyte')) { - App::import('Core', 'Multibyte'); -} +App::uses('AppHelper', 'View/Helper'); +App::uses('HtmlHelper', 'Helper'); +App::uses('Multibyte', 'I18n'); /** * Text helper library. @@ -180,8 +177,9 @@ class TextHelper extends AppHelper { */ public function autoLinkEmails($text, $options = array()) { $this->_linkOptions = $options; + $atom = '[a-z0-9!#$%&\'*+\/=?^_`{|}~-]'; return preg_replace_callback( - '#([_A-Za-z0-9+-]+(?:\.[_A-Za-z0-9+-]+)*@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*)#', + '/(' . $atom . '+(?:\.' . $atom . '+)*@[a-z0-9-]+(?:\.[a-z0-9-]+)*)/i', array(&$this, '_linkEmails'), $text ); diff --git a/cake/libs/view/helpers/time.php b/lib/Cake/View/Helper/TimeHelper.php similarity index 88% rename from cake/libs/view/helpers/time.php rename to lib/Cake/View/Helper/TimeHelper.php index 32e9e3050..64781b79e 100644 --- a/cake/libs/view/helpers/time.php +++ b/lib/Cake/View/Helper/TimeHelper.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('AppHelper', 'View/Helper'); + /** * Time Helper class for easy use of time data. * @@ -27,11 +29,36 @@ */ class TimeHelper extends AppHelper { +/** + * The format to use when formatting a time using `TimeHelper::nice()` + * + * The format should use the locale strings as defined in the PHP docs under + * `strftime` (http://php.net/manual/en/function.strftime.php) + * + * @var string + * @see TimeHelper::format() + */ + public $niceFormat = '%a, %b %eS %Y, %H:%M'; + +/** + * Constructor + * + * @param View $View the view object the helper is attached to. + * @param array $settings Settings array Settings array + * @return void + */ + public function __construct(View $View, $settings = array()) { + if (isset($settings['niceFormat'])) { + $this->niceFormat = $settings['niceFormat']; + } + parent::__construct($View, $settings); + } + /** * Converts a string representing the format for the function strftime and returns a * windows safe and i18n aware format. * - * @param string $format Format with specifiers for strftime function. + * @param string $format Format with specifiers for strftime function. * Accepts the special specifier %S which mimics th modifier S for date() * @param string UNIX timestamp * @return string windows safe and date() function compatible format for strftime @@ -52,22 +79,22 @@ class TimeHelper extends AppHelper { * @return string converted element * @access private */ - function __translateSpecifier($specifier) { + private function __translateSpecifier($specifier) { switch ($specifier[1]) { case 'a': - $abday = __c('abday', 5); + $abday = __dc('cake', 'abday', 5); if (is_array($abday)) { return $abday[date('w', $this->__time)]; } break; case 'A': - $day = __c('day', 5); + $day = __dc('cake', 'day', 5); if (is_array($day)) { return $day[date('w', $this->__time)]; } break; case 'c': - $format = __c('d_t_fmt', 5); + $format = __dc('cake', 'd_t_fmt', 5); if ($format != 'd_t_fmt') { return $this->convertSpecifiers($format, $this->__time); } @@ -76,17 +103,26 @@ class TimeHelper extends AppHelper { return sprintf("%02d", date('Y', $this->__time) / 100); case 'D': return '%m/%d/%y'; + case 'e': + if (DS === '/') { + return '%e'; + } + $day = date('j', $this->__time); + if ($day < 10) { + $day = ' ' . $day; + } + return $day; case 'eS' : return date('jS', $this->__time); case 'b': case 'h': - $months = __c('abmon', 5); + $months = __dc('cake', 'abmon', 5); if (is_array($months)) { return $months[date('n', $this->__time) -1]; } return '%b'; case 'B': - $months = __c('mon', 5); + $months = __dc('cake', 'mon', 5); if (is_array($months)) { return $months[date('n', $this->__time) -1]; } @@ -97,14 +133,14 @@ class TimeHelper extends AppHelper { case 'P': $default = array('am' => 0, 'pm' => 1); $meridiem = $default[date('a',$this->__time)]; - $format = __c('am_pm', 5); + $format = __dc('cake', 'am_pm', 5); if (is_array($format)) { $meridiem = $format[$meridiem]; return ($specifier[1] == 'P') ? strtolower($meridiem) : strtoupper($meridiem); } break; case 'r': - $complete = __c('t_fmt_ampm', 5); + $complete = __dc('cake', 't_fmt_ampm', 5); if ($complete != 't_fmt_ampm') { return str_replace('%p',$this->__translateSpecifier(array('%p', 'p')),$complete); } @@ -118,13 +154,13 @@ class TimeHelper extends AppHelper { case 'u': return ($weekDay = date('w', $this->__time)) ? $weekDay : 7; case 'x': - $format = __c('d_fmt', 5); + $format = __dc('cake', 'd_fmt', 5); if ($format != 'd_fmt') { return $this->convertSpecifiers($format, $this->__time); } break; case 'X': - $format = __c('t_fmt', 5); + $format = __dc('cake', 't_fmt', 5); if ($format != 't_fmt') { return $this->convertSpecifiers($format, $this->__time); } @@ -186,19 +222,26 @@ class TimeHelper extends AppHelper { /** * Returns a nicely formatted date string for given Datetime string. * + * See http://php.net/manual/en/function.strftime.php for information on formatting + * using locale strings. + * * @param string $dateString Datetime string or Unix timestamp * @param int $userOffset User's offset from GMT (in hours) + * @param string $format The format to use. If null, `TimeHelper::$niceFormat` is used * @return string Formatted date string * @access public * @link http://book.cakephp.org/view/1471/Formatting */ - public function nice($dateString = null, $userOffset = null) { + public function nice($dateString = null, $userOffset = null, $format = null) { if ($dateString != null) { $date = $this->fromString($dateString, $userOffset); } else { $date = time(); } - $format = $this->convertSpecifiers('%a, %b %eS %Y, %H:%M', $date); + if (!$format) { + $format = $this->niceFormat; + } + $format = $this->convertSpecifiers($format, $date); return strftime($format, $date); } @@ -221,10 +264,10 @@ class TimeHelper extends AppHelper { $y = $this->isThisYear($date) ? '' : ' %Y'; - if ($this->isToday($date)) { - $ret = __('Today, %s', strftime("%H:%M", $date)); - } elseif ($this->wasYesterday($date)) { - $ret = __('Yesterday, %s', strftime("%H:%M", $date)); + if ($this->isToday($dateString, $userOffset)) { + $ret = __d('cake', 'Today, %s', strftime("%H:%M", $date)); + } elseif ($this->wasYesterday($dateString, $userOffset)) { + $ret = __d('cake', 'Yesterday, %s', strftime("%H:%M", $date)); } else { $format = $this->convertSpecifiers("%b %eS{$y}, %H:%M", $date); $ret = strftime($format, $date); @@ -329,7 +372,7 @@ class TimeHelper extends AppHelper { * @return boolean True if datetime string was yesterday * @access public * @link http://book.cakephp.org/view/1472/Testing-Time - * + * */ public function wasYesterday($dateString, $userOffset = null) { $date = $this->fromString($dateString, $userOffset); @@ -571,66 +614,50 @@ class TimeHelper extends AppHelper { $diff = $futureTime - $pastTime; if ($diff > abs($now - $this->fromString($end))) { - $relativeDate = __('on %s', date($format, $inSeconds)); + $relativeDate = __d('cake', 'on %s', date($format, $inSeconds)); } else { if ($years > 0) { // years and months and days - $relativeDate .= ($relativeDate ? ', ' : '') . $years . ' ' . __n('year', 'years', $years); - $relativeDate .= $months > 0 ? ($relativeDate ? ', ' : '') . $months . ' ' . __n('month', 'months', $months) : ''; - $relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . $weeks . ' ' . __n('week', 'weeks', $weeks) : ''; - $relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days) : ''; + $relativeDate .= ($relativeDate ? ', ' : '') . $years . ' ' . __dn('cake', 'year', 'years', $years); + $relativeDate .= $months > 0 ? ($relativeDate ? ', ' : '') . $months . ' ' . __dn('cake', 'month', 'months', $months) : ''; + $relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . $weeks . ' ' . __dn('cake', 'week', 'weeks', $weeks) : ''; + $relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __dn('cake', 'day', 'days', $days) : ''; } elseif (abs($months) > 0) { // months, weeks and days - $relativeDate .= ($relativeDate ? ', ' : '') . $months . ' ' . __n('month', 'months', $months); - $relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . $weeks . ' ' . __n('week', 'weeks', $weeks) : ''; - $relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days) : ''; + $relativeDate .= ($relativeDate ? ', ' : '') . $months . ' ' . __dn('cake', 'month', 'months', $months); + $relativeDate .= $weeks > 0 ? ($relativeDate ? ', ' : '') . $weeks . ' ' . __dn('cake', 'week', 'weeks', $weeks) : ''; + $relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __dn('cake', 'day', 'days', $days) : ''; } elseif (abs($weeks) > 0) { // weeks and days - $relativeDate .= ($relativeDate ? ', ' : '') . $weeks . ' ' . __n('week', 'weeks', $weeks); - $relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days) : ''; + $relativeDate .= ($relativeDate ? ', ' : '') . $weeks . ' ' . __dn('cake', 'week', 'weeks', $weeks); + $relativeDate .= $days > 0 ? ($relativeDate ? ', ' : '') . $days . ' ' . __dn('cake', 'day', 'days', $days) : ''; } elseif (abs($days) > 0) { // days and hours - $relativeDate .= ($relativeDate ? ', ' : '') . $days . ' ' . __n('day', 'days', $days); - $relativeDate .= $hours > 0 ? ($relativeDate ? ', ' : '') . $hours . ' ' . __n('hour', 'hours', $hours) : ''; + $relativeDate .= ($relativeDate ? ', ' : '') . $days . ' ' . __dn('cake', 'day', 'days', $days); + $relativeDate .= $hours > 0 ? ($relativeDate ? ', ' : '') . $hours . ' ' . __dn('cake', 'hour', 'hours', $hours) : ''; } elseif (abs($hours) > 0) { // hours and minutes - $relativeDate .= ($relativeDate ? ', ' : '') . $hours . ' ' . __n('hour', 'hours', $hours); - $relativeDate .= $minutes > 0 ? ($relativeDate ? ', ' : '') . $minutes . ' ' . __n('minute', 'minutes', $minutes) : ''; + $relativeDate .= ($relativeDate ? ', ' : '') . $hours . ' ' . __dn('cake', 'hour', 'hours', $hours); + $relativeDate .= $minutes > 0 ? ($relativeDate ? ', ' : '') . $minutes . ' ' . __dn('cake', 'minute', 'minutes', $minutes) : ''; } elseif (abs($minutes) > 0) { // minutes only - $relativeDate .= ($relativeDate ? ', ' : '') . $minutes . ' ' . __n('minute', 'minutes', $minutes); + $relativeDate .= ($relativeDate ? ', ' : '') . $minutes . ' ' . __dn('cake', 'minute', 'minutes', $minutes); } else { // seconds only - $relativeDate .= ($relativeDate ? ', ' : '') . $seconds . ' ' . __n('second', 'seconds', $seconds); + $relativeDate .= ($relativeDate ? ', ' : '') . $seconds . ' ' . __dn('cake', 'second', 'seconds', $seconds); } if (!$backwards) { - $relativeDate = __('%s ago', $relativeDate); + $relativeDate = __d('cake', '%s ago', $relativeDate); } } return $relativeDate; } -/** - * Alias for timeAgoInWords - * - * @param mixed $dateTime Datetime string (strtotime-compatible) or Unix timestamp - * @param mixed $options Default format string, if timestamp is used in $dateTime, or an array of options to be passed - * on to timeAgoInWords(). - * @return string Relative time string. - * @see TimeHelper::timeAgoInWords - * @access public - * @deprecated This method alias will be removed in future versions. - * @link http://book.cakephp.org/view/1471/Formatting - */ - function relativeTime($dateTime, $options = array()) { - return $this->timeAgoInWords($dateTime, $options); - } - /** * Returns true if specified datetime was within the interval specified, else false. * - * @param mixed $timeInterval the numeric value with space then time type. + * @param mixed $timeInterval the numeric value with space then time type. * Example of valid types: 6 hours, 2 days, 1 minute. * @param mixed $dateString the datestring or unix timestamp to compare * @param int $userOffset User's offset from GMT (in hours) @@ -641,7 +668,7 @@ class TimeHelper extends AppHelper { public function wasWithinLast($timeInterval, $dateString, $userOffset = null) { $tmp = str_replace(' ', '', $timeInterval); if (is_numeric($tmp)) { - $timeInterval = $tmp . ' ' . __('days'); + $timeInterval = $tmp . ' ' . __d('cake', 'days'); } $date = $this->fromString($dateString, $userOffset); @@ -725,4 +752,4 @@ class TimeHelper extends AppHelper { $format = $this->convertSpecifiers($format, $date); return strftime($format, $date); } -} +} \ No newline at end of file diff --git a/cake/libs/view/helper_collection.php b/lib/Cake/View/HelperCollection.php similarity index 68% rename from cake/libs/view/helper_collection.php rename to lib/Cake/View/HelperCollection.php index 9d5fcbf17..ee291525b 100644 --- a/cake/libs/view/helper_collection.php +++ b/lib/Cake/View/HelperCollection.php @@ -15,7 +15,8 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('Core', 'ObjectCollection'); + +App::uses('ObjectCollection', 'Utility'); class HelperCollection extends ObjectCollection { @@ -40,6 +41,16 @@ class HelperCollection extends ObjectCollection { * By setting `$enable` to false you can disable callbacks for a helper. Alternatively you * can set `$settings['enabled'] = false` to disable callbacks. This alias is provided so that when * declaring $helpers arrays you can disable callbacks on helpers. + * + * You can alias your helper as an existing helper by setting the 'className' key, i.e., + * {{{ + * public $helpers = array( + * 'Html' => array( + * 'className' => 'AliasedHtml' + * ); + * ); + * }}} + * All calls to the `Html` helper would use `AliasedHtml` instead. * * @param string $helper Helper name to load * @param array $settings Settings for the helper. @@ -47,37 +58,37 @@ class HelperCollection extends ObjectCollection { * @throws MissingHelperFileException, MissingHelperClassException when the helper could not be found */ public function load($helper, $settings = array()) { + if (is_array($settings) && isset($settings['className'])) { + $alias = $helper; + $helper = $settings['className']; + } list($plugin, $name) = pluginSplit($helper, true); - - if (isset($this->_loaded[$name])) { - return $this->_loaded[$name]; + if (!isset($alias)) { + $alias = $name; + } + + if (isset($this->_loaded[$alias])) { + return $this->_loaded[$alias]; } $helperClass = $name . 'Helper'; + App::uses($helperClass, $plugin . 'View/Helper'); if (!class_exists($helperClass)) { - if (!App::import('Helper', $helper)) { - throw new MissingHelperFileException(array( - 'class' => $helperClass, - 'file' => Inflector::underscore($name) . '.php' - )); - } - if (!class_exists($helperClass)) { - throw new MissingHelperClassException(array( - 'class' => $helperClass, - 'file' => Inflector::underscore($name) . '.php' - )); - } + throw new MissingHelperClassException(array( + 'class' => $helperClass, + 'file' => $helperClass . '.php' + )); } - $this->_loaded[$name] = new $helperClass($this->_View, $settings); + $this->_loaded[$alias] = new $helperClass($this->_View, $settings); $vars = array('request', 'theme', 'plugin'); foreach ($vars as $var) { - $this->_loaded[$name]->{$var} = $this->_View->{$var}; + $this->_loaded[$alias]->{$var} = $this->_View->{$var}; } $enable = isset($settings['enabled']) ? $settings['enabled'] : true; if ($enable === true) { - $this->_enabled[] = $name; + $this->_enabled[] = $alias; } - return $this->_loaded[$name]; + return $this->_loaded[$alias]; } } \ No newline at end of file diff --git a/cake/libs/view/media.php b/lib/Cake/View/MediaView.php similarity index 92% rename from cake/libs/view/media.php rename to lib/Cake/View/MediaView.php index 880383b30..70e92979c 100644 --- a/cake/libs/view/media.php +++ b/lib/Cake/View/MediaView.php @@ -16,7 +16,8 @@ * @since CakePHP(tm) v 1.2.0.5714 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('View', 'View', false); +App::uses('View', 'View'); +App::uses('CakeRequest', 'Network'); /** * Media View provides a custom view implementation for sending files to visitors. Its great @@ -38,7 +39,7 @@ App::import('View', 'View', false); * {{{ * class ExampleController extends AppController { * function download () { - * $this->view = 'Media'; + * $this->viewClass = 'Media'; * $params = array( * 'id' => 'example.zip', * 'name' => 'example', @@ -78,7 +79,6 @@ class MediaView extends View { if (is_object($controller) && isset($controller->response)) { $this->response = $controller->response; } else { - App::import('Core', 'CakeRequest'); $this->response = new CakeResponse; } } @@ -89,13 +89,9 @@ class MediaView extends View { * @return mixed */ function render() { - $name = $download = $extension = $id = $modified = $path = $size = $cache = $mimeType = $compress = null; + $name = $download = $extension = $id = $modified = $path = $cache = $mimeType = $compress = null; extract($this->viewVars, EXTR_OVERWRITE); - if ($size) { - $id = $id . '_' . $size; - } - if (is_dir($path)) { $path = $path . $id; } else { @@ -109,15 +105,12 @@ class MediaView extends View { throw new NotFoundException('The requested file was not found'); } - if (is_null($name)) { - $name = $id; - } - if (is_array($mimeType)) { $this->response->type($mimeType); } - if (isset($extension) && $this->response->type($extension) && $this->_isActive()) { + if (isset($extension) && $this->_isActive()) { + $extension = strtolower($extension); $chunkSize = 8192; $buffer = ''; $fileSize = @filesize($path); @@ -131,6 +124,9 @@ class MediaView extends View { } else { $modified = time(); } + if ($this->response->type($extension) === false) { + $download = true; + } if ($cache) { $this->response->cache($modified, $cache); @@ -155,7 +151,10 @@ class MediaView extends View { if (!empty($contentType)) { $this->response->type($contentType); } - $this->response->download($name . '.' . $extension); + if (is_null($name)) { + $name = $id; + } + $this->response->download($name); $this->response->header(array('Accept-Ranges' => 'bytes')); $httpRange = env('HTTP_RANGE'); @@ -176,7 +175,6 @@ class MediaView extends View { $this->response->header('Content-Length', $fileSize); } } else { - $this->response->type($extension); $this->response->header(array( 'Content-Length' => $fileSize )); @@ -237,7 +235,7 @@ class MediaView extends View { /** * Flushes the contents of the output buffer - * + * * @return void */ protected function _flushBuffer() { diff --git a/cake/libs/view/scaffold.php b/lib/Cake/View/ScaffoldView.php similarity index 95% rename from cake/libs/view/scaffold.php rename to lib/Cake/View/ScaffoldView.php index 6f051a211..746e84eea 100644 --- a/cake/libs/view/scaffold.php +++ b/lib/Cake/View/ScaffoldView.php @@ -18,7 +18,7 @@ * @since Cake v 0.10.0.1076 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('View', 'Theme'); +App::uses('ThemeView', 'View'); /** * ScaffoldView provides specific view file loading features for scaffolded views. @@ -80,7 +80,7 @@ class ScaffoldView extends ThemeView { } if ($name === 'scaffolds' . DS . $subDir . 'error') { - return LIBS . 'view' . DS . 'errors' . DS . 'scaffold_error.ctp'; + return LIBS . 'View' . DS . 'errors' . DS . 'scaffold_error.ctp'; } throw new MissingViewException($paths[0] . $name . $this->ext); diff --git a/cake/libs/view/theme.php b/lib/Cake/View/ThemeView.php similarity index 94% rename from cake/libs/view/theme.php rename to lib/Cake/View/ThemeView.php index 24e06e29b..df85282b7 100644 --- a/cake/libs/view/theme.php +++ b/lib/Cake/View/ThemeView.php @@ -16,14 +16,14 @@ * @since CakePHP(tm) v 0.10.0.1076 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::import('View', 'View'); +App::uses('View', 'View'); /** * Theme view class * * Allows the creation of multiple themes to be used in an app. Theme views are regular view files * that can provide unique HTML and static assets. If theme views are not found for the current view - * the default app view files will be used. You can set `$this->theme` and `$this->view = 'Theme'` + * the default app view files will be used. You can set `$this->theme` and `$this->viewClass = 'Theme'` * in your Controller to use the ThemeView. * * Example of theme path with `$this->theme = 'super_hot';` Would be `app/views/themed/super_hot/posts` @@ -58,7 +58,7 @@ class ThemeView extends View { $count = count($paths); for ($i = 0; $i < $count; $i++) { if (strpos($paths[$i], DS . 'plugins' . DS) === false - && strpos($paths[$i], DS . 'libs' . DS . 'view') === false) { + && strpos($paths[$i], DS . 'Cake' . DS . 'View') === false) { if ($plugin) { $themePaths[] = $paths[$i] . 'themed'. DS . $this->theme . DS . 'plugins' . DS . $plugin . DS; } diff --git a/cake/libs/view/view.php b/lib/Cake/View/View.php similarity index 87% rename from cake/libs/view/view.php rename to lib/Cake/View/View.php index ef1d46b9f..a9831356b 100644 --- a/cake/libs/view/view.php +++ b/lib/Cake/View/View.php @@ -20,17 +20,17 @@ /** * Included libraries. */ -App::import('View', 'HelperCollection', false); -App::import('View', 'Helper', false); +App::uses('HelperCollection', 'View'); +App::uses('Router', 'Routing'); /** * View, the V in the MVC triad. View interacts with Helpers and view variables passed * in from the controller to render the results of the controller action. Often this is HTML, * but can also take the form of JSON, XML, PDF's or streaming files. * - * CakePHP uses a two-step-view pattern. This means that the view content is rendered first, + * CakePHP uses a two-step-view pattern. This means that the view content is rendered first, * and then inserted into the selected layout. A special `$content_for_layout` variable is available - * in the layout, and it contains the rendered view. This also means you can pass data from the view to the + * in the layout, and it contains the rendered view. This also means you can pass data from the view to the * layout using `$this->set()` * * @package cake.libs.view @@ -87,6 +87,13 @@ class View extends Object { */ public $viewVars = array(); +/** + * Name of view to use with this View. + * + * @var string + */ + public $view = null; + /** * Name of layout to use with this View. * @@ -123,7 +130,7 @@ class View extends Object { * @var string */ public $subDir = null; - + /** * Theme name. If you are using themes, you should remember to use ThemeView as well. * @@ -212,7 +219,7 @@ class View extends Object { /** * An instance of a CakeRequest object that contains information about the current request. * This object contains all the information about a request and several methods for reading - * additional information about the request. + * additional information about the request. * * @var CakeRequest */ @@ -234,7 +241,7 @@ class View extends Object { * @var array */ private $__passedVars = array( - 'viewVars', 'autoLayout', 'ext', 'helpers', 'layout', 'name', + 'viewVars', 'autoLayout', 'ext', 'helpers', 'view', 'layout', 'name', 'layoutPath', 'viewPath', 'request', 'plugin', 'passedArgs', 'cacheAction' ); @@ -279,46 +286,47 @@ class View extends Object { /** * Renders a piece of PHP with provided parameters and returns HTML, XML, or any other string. * - * This realizes the concept of Elements, (or "partial layouts") and the $params array is used to send - * data to be used in the element. Elements can be cached improving performance by using the `cache` option. - * - * ### Special params + * This realizes the concept of Elements, (or "partial layouts") and the $params array is used to send + * data to be used in the element. Elements can be cached improving performance by using the `cache` option. * + * @param string $name Name of template file in the/app/views/elements/ folder + * @param array $data Array of data to be made available to the rendered view (i.e. the Element) + * @param array $options Array of options. Possible keys are: * - `cache` - Can either be `true`, to enable caching using the config in View::$elementCache. Or an array * If an array, the following keys can be used: * - `config` - Used to store the cached element in a custom cache configuration. * - `key` - Used to define the key used in the Cache::write(). It will be prefixed with `element_` * - `plugin` - Load an element from a specific plugin. - * - * @param string $name Name of template file in the/app/views/elements/ folder - * @param array $params Array of data to be made available to the for rendered - * view (i.e. the Element) - * @param boolean $callbacks Set to true to fire beforeRender and afterRender helper callbacks for this element. + * - `callbacks` - Set to true to fire beforeRender and afterRender helper callbacks for this element. * Defaults to false. * @return string Rendered Element */ - public function element($name, $params = array(), $callbacks = false) { + public function element($name, $data = array(), $options = array()) { $file = $plugin = $key = null; + $callbacks = false; - if (isset($params['plugin'])) { - $plugin = $params['plugin']; + if (isset($options['plugin'])) { + $plugin = $options['plugin']; } if (isset($this->plugin) && !$plugin) { $plugin = $this->plugin; } + if (isset($options['callbacks'])) { + $callbacks = $options['callbacks']; + } - if (isset($params['cache'])) { - $keys = array_merge(array($plugin, $name), array_keys($params)); + if (isset($options['cache'])) { + $keys = array_merge(array($plugin, $name), array_keys($options), array_keys($data)); $caching = array( 'config' => $this->elementCache, 'key' => implode('_', $keys) ); - if (is_array($params['cache'])) { + if (is_array($options['cache'])) { $defaults = array( 'config' => $this->elementCache, 'key' => $caching['key'] ); - $caching = array_merge($defaults, $params['cache']); + $caching = array_merge($defaults, $options['cache']); } $key = 'element_' . $caching['key']; $contents = Cache::read($key, $caching['config']); @@ -326,6 +334,7 @@ class View extends Object { return $contents; } } + $file = $this->_getElementFilename($name, $plugin); if ($file) { @@ -335,11 +344,11 @@ class View extends Object { if ($callbacks) { $this->Helpers->trigger('beforeRender', array($file)); } - $element = $this->_render($file, array_merge($this->viewVars, $params)); + $element = $this->_render($file, array_merge($this->viewVars, $data)); if ($callbacks) { $this->Helpers->trigger('afterRender', array($file, $element)); } - if (isset($params['cache'])) { + if (isset($options['cache'])) { Cache::write($key, $element, $caching['config']); } return $element; @@ -352,8 +361,7 @@ class View extends Object { } /** - * Renders view for given action and layout. If $file is given, that is used - * for a view filename (e.g. customFunkyView.ctp). + * Renders view for given view file and layout. * * Render triggers helper callbacks, which are fired before and after the view are rendered, * as well as before and after the layout. The helper callbacks are called @@ -365,14 +373,12 @@ class View extends Object { * * If View::$autoRender is false and no `$layout` is provided, the view will be returned bare. * - * @param string $action Name of action to render for, this will be used as the filename to render, unless - * $file is give as well. + * @param string $view Name of view file to use * @param string $layout Layout to use. - * @param string $file Custom filename for view. Providing this will render a specific file for the given action. * @return string Rendered Element * @throws CakeException if there is an error in the view. */ - public function render($action = null, $layout = null, $file = null) { + public function render($view = null, $layout = null) { if ($this->hasRendered) { return true; } @@ -381,11 +387,7 @@ class View extends Object { } $this->output = null; - if ($file != null) { - $action = $file; - } - - if ($action !== false && $viewFileName = $this->_getViewFileName($action)) { + if ($view !== false && $viewFileName = $this->_getViewFileName($view)) { $this->Helpers->trigger('beforeRender', array($viewFileName)); $this->output = $this->_render($viewFileName); $this->Helpers->trigger('afterRender', array($viewFileName)); @@ -395,7 +397,7 @@ class View extends Object { $layout = $this->layout; } if ($this->output === false) { - throw new CakeException(__("Error in view %s, got no content.", $viewFileName)); + throw new CakeException(__d('cake_dev', "Error in view %s, got no content.", $viewFileName)); } if ($layout && $this->autoLayout) { $this->output = $this->renderLayout($this->output, $layout); @@ -438,7 +440,7 @@ class View extends Object { $this->output = $this->_render($layoutFileName); if ($this->output === false) { - throw new CakeException(__("Error in layout %s, got no content.", $layoutFileName)); + throw new CakeException(__d('cake_dev', "Error in layout %s, got no content.", $layoutFileName)); } $this->Helpers->trigger('afterLayout', array($layoutFileName)); @@ -446,7 +448,7 @@ class View extends Object { } /** - * Render cached view. Works in concert with CacheHelper and Dispatcher to + * Render cached view. Works in concert with CacheHelper and Dispatcher to * render cached view files. * * @param string $filename the cache file to include @@ -623,7 +625,8 @@ class View extends Object { public function loadHelpers() { $helpers = HelperCollection::normalizeObjectArray($this->helpers); foreach ($helpers as $name => $properties) { - $this->Helpers->load($properties['class'], $properties['settings'], true); + list($plugin, $class) = pluginSplit($properties['class']); + $this->{$class} = $this->Helpers->load($properties['class'], $properties['settings']); } $this->_helpersLoaded = true; } @@ -678,14 +681,14 @@ class View extends Object { } if ($name === null) { - $name = $this->action; + $name = $this->view; } $name = str_replace('/', DS, $name); if (strpos($name, DS) === false && $name[0] !== '.') { $name = $this->viewPath . DS . $subDir . Inflector::underscore($name); } elseif (strpos($name, DS) !== false) { - if ($name{0} === DS || $name{1} === ':') { + if ($name[0] === DS || $name[1] === ':') { if (is_file($name)) { return $name; } @@ -697,11 +700,8 @@ class View extends Object { } } $paths = $this->_paths($this->plugin); - - $exts = array($this->ext); - if ($this->ext !== '.ctp') { - array_push($exts, '.ctp'); - } + + $exts = $this->_getExtensions(); foreach ($exts as $ext) { foreach ($paths as $path) { if (file_exists($path . $name . $ext)) { @@ -741,11 +741,8 @@ class View extends Object { } $paths = $this->_paths($this->plugin); $file = 'layouts' . DS . $subDir . $name; - - $exts = array($this->ext); - if ($this->ext !== '.ctp') { - array_push($exts, '.ctp'); - } + + $exts = $this->_getExtensions(); foreach ($exts as $ext) { foreach ($paths as $path) { if (file_exists($path . $file . $ext)) { @@ -756,6 +753,21 @@ class View extends Object { throw new MissingLayoutException(array('file' => $paths[0] . $file . $this->ext)); } + +/** + * Get the extensions that view files can use. + * + * @return array Array of extensions view files use. + * @access protected + */ + function _getExtensions() { + $exts = array($this->ext); + if ($this->ext !== '.ctp') { + array_push($exts, '.ctp'); + } + return $exts; + } + /** * Finds an element filename, returns false on failure. * @@ -765,9 +777,12 @@ class View extends Object { */ protected function _getElementFileName($name, $plugin = null) { $paths = $this->_paths($plugin); - foreach ($paths as $path) { - if (file_exists($path . 'elements' . DS . $name . $this->ext)) { - return $path . 'elements' . DS . $name . $this->ext; + $exts = $this->_getExtensions(); + foreach ($exts as $ext) { + foreach ($paths as $path) { + if (file_exists($path . 'elements' . DS . $name . $ext)) { + return $path . 'elements' . DS . $name . $ext; + } } } return false; @@ -785,8 +800,8 @@ class View extends Object { return $this->__paths; } $paths = array(); - $viewPaths = App::path('views'); - $corePaths = array_flip(App::core('views')); + $viewPaths = App::path('View'); + $corePaths = array_flip(App::core('View')); if (!empty($plugin)) { $count = count($viewPaths); @@ -795,9 +810,10 @@ class View extends Object { $paths[] = $viewPaths[$i] . 'plugins' . DS . $plugin . DS; } } - $paths[] = App::pluginPath($plugin) . 'views' . DS; + $paths = array_merge($paths, App::path('View', $plugin)); } - $this->__paths = array_merge($paths, $viewPaths); + + $this->__paths = array_unique(array_merge($paths, $viewPaths, array_keys($corePaths))); return $this->__paths; } } diff --git a/cake/libs/view/elements/email/html/default.ctp b/lib/Cake/View/elements/email/html/default.ctp similarity index 95% rename from cake/libs/view/elements/email/html/default.ctp rename to lib/Cake/View/elements/email/html/default.ctp index 3ab3f4cc6..cc94f2746 100644 --- a/cake/libs/view/elements/email/html/default.ctp +++ b/lib/Cake/View/elements/email/html/default.ctp @@ -20,6 +20,6 @@ $content = explode("\n", $content); foreach ($content as $line): - echo '

    ' . $line . '

    '; + echo '

    ' . $line . "

    \n"; endforeach; ?> \ No newline at end of file diff --git a/cake/libs/view/elements/email/text/default.ctp b/lib/Cake/View/elements/email/text/default.ctp similarity index 100% rename from cake/libs/view/elements/email/text/default.ctp rename to lib/Cake/View/elements/email/text/default.ctp diff --git a/cake/libs/view/elements/exception_stack_trace.ctp b/lib/Cake/View/elements/exception_stack_trace.ctp similarity index 100% rename from cake/libs/view/elements/exception_stack_trace.ctp rename to lib/Cake/View/elements/exception_stack_trace.ctp diff --git a/cake/libs/view/elements/sql_dump.ctp b/lib/Cake/View/elements/sql_dump.ctp similarity index 97% rename from cake/libs/view/elements/sql_dump.ctp rename to lib/Cake/View/elements/sql_dump.ctp index b770dfbaa..5bc41ea10 100644 --- a/cake/libs/view/elements/sql_dump.ctp +++ b/lib/Cake/View/elements/sql_dump.ctp @@ -26,7 +26,7 @@ if ($noLogs): $logs = array(); foreach ($sources as $source): $db =& ConnectionManager::getDataSource($source); - if (!$db->isInterfaceSupported('getLog')): + if (!method_exists($db, 'getLog')): continue; endif; $logs[$source] = $db->getLog(); diff --git a/cake/libs/view/errors/error400.ctp b/lib/Cake/View/errors/error400.ctp similarity index 85% rename from cake/libs/view/errors/error400.ctp rename to lib/Cake/View/errors/error400.ctp index b6487ee91..38e1aedaa 100644 --- a/cake/libs/view/errors/error400.ctp +++ b/lib/Cake/View/errors/error400.ctp @@ -18,13 +18,13 @@ ?>

    - : + : '{$url}'" ); ?>

    - 0 ): echo $this->element('exception_stack_trace'); endif; diff --git a/cake/libs/view/errors/error500.ctp b/lib/Cake/View/errors/error500.ctp similarity index 85% rename from cake/libs/view/errors/error500.ctp rename to lib/Cake/View/errors/error500.ctp index e032b9eed..247f2db78 100644 --- a/cake/libs/view/errors/error500.ctp +++ b/lib/Cake/View/errors/error500.ctp @@ -18,11 +18,11 @@ ?>

    - : - + : +

    - 0 ): echo $this->element('exception_stack_trace'); endif; -?> +?> \ No newline at end of file diff --git a/lib/Cake/View/errors/missing_action.ctp b/lib/Cake/View/errors/missing_action.ctp new file mode 100644 index 000000000..cac7d2e9b --- /dev/null +++ b/lib/Cake/View/errors/missing_action.ctp @@ -0,0 +1,43 @@ + +

    + : + ' . $action . '', '' . $controller . ''); ?> +

    +

    + : + ' . $controller . '::', '' . $action . '()', APP_DIR . DS . 'controllers' . DS . Inflector::underscore($controller) . '.php'); ?> +

    +
    +<?php
    +class  extends AppController {
    +
    +
    +	function  {
    +
    +	}
    +
    +}
    +?>
    +
    +

    + : + +

    +element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_behavior_class.ctp b/lib/Cake/View/errors/missing_behavior_class.ctp similarity index 52% rename from cake/libs/view/errors/missing_behavior_class.ctp rename to lib/Cake/View/errors/missing_behavior_class.ctp index e7c454069..3bc4dcb67 100644 --- a/cake/libs/view/errors/missing_behavior_class.ctp +++ b/lib/Cake/View/errors/missing_behavior_class.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - %s can not be found or does not exist.', $class); ?> + : + %s can not be found or does not exist.', $class); ?>

    - : - + : +

     <?php
    @@ -33,8 +33,8 @@ class  extends ModelBehavior {
     ?>
     

    - : - + : +

    -element('exception_stack_trace'); ?> +element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_behavior_file.ctp b/lib/Cake/View/errors/missing_behavior_file.ctp similarity index 50% rename from cake/libs/view/errors/missing_behavior_file.ctp rename to lib/Cake/View/errors/missing_behavior_file.ctp index 09e90b350..aa3e314c2 100644 --- a/cake/libs/view/errors/missing_behavior_file.ctp +++ b/lib/Cake/View/errors/missing_behavior_file.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - + : +

    - : - + : +

     <?php
    @@ -33,8 +33,8 @@ class  extends ModelBehavior {
     ?>
     

    - : - + : +

    -element('exception_stack_trace'); ?> +element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_component_class.ctp b/lib/Cake/View/errors/missing_component_class.ctp similarity index 51% rename from cake/libs/view/errors/missing_component_class.ctp rename to lib/Cake/View/errors/missing_component_class.ctp index cf06671dc..4465edba2 100644 --- a/cake/libs/view/errors/missing_component_class.ctp +++ b/lib/Cake/View/errors/missing_component_class.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - ' . $class . ''); ?> + : + ' . $class . ''); ?>

    - : - ' . $class . '', APP_DIR . DS . 'controllers' . DS . 'components' . DS . $file); ?> + : + ' . $class . '', APP_DIR . DS . 'controllers' . DS . 'components' . DS . $file); ?>

     <?php
    @@ -33,8 +33,8 @@ class  extends Component {
    ?>

    - : - + : +

    element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_component_file.ctp b/lib/Cake/View/errors/missing_component_file.ctp similarity index 52% rename from cake/libs/view/errors/missing_component_file.ctp rename to lib/Cake/View/errors/missing_component_file.ctp index 527afc9c3..aeb8c3269 100644 --- a/cake/libs/view/errors/missing_component_file.ctp +++ b/lib/Cake/View/errors/missing_component_file.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - + : +

    - : - ' . $class . '', APP_DIR . DS . 'controllers' . DS . 'components' . DS . $file); ?> + : + ' . $class . '', APP_DIR . DS . 'controllers' . DS . 'components' . DS . $file); ?>

     <?php
    @@ -33,8 +33,8 @@ class  extends Component {
    ?>

    - : - + : +

    element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_connection.ctp b/lib/Cake/View/errors/missing_connection.ctp similarity index 51% rename from cake/libs/view/errors/missing_connection.ctp rename to lib/Cake/View/errors/missing_connection.ctp index dfda66e3a..ae4887b8a 100644 --- a/cake/libs/view/errors/missing_connection.ctp +++ b/lib/Cake/View/errors/missing_connection.ctp @@ -16,18 +16,18 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - + : +

    - : - + : +

    - : - + : +

    element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_controller.ctp b/lib/Cake/View/errors/missing_controller.ctp similarity index 51% rename from cake/libs/view/errors/missing_controller.ctp rename to lib/Cake/View/errors/missing_controller.ctp index 7f9e7d27f..b57193943 100644 --- a/cake/libs/view/errors/missing_controller.ctp +++ b/lib/Cake/View/errors/missing_controller.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - ' . $controller . ''); ?> + : + ' . $controller . ''); ?>

    - : - ' . $controller . '', APP_DIR . DS . 'controllers' . DS . Inflector::underscore($controller) . '.php'); ?> + : + ' . $controller . '', APP_DIR . DS . 'controllers' . DS . Inflector::underscore($controller) . '.php'); ?>

     <?php
    @@ -33,8 +33,8 @@ class  extends AppController {
     ?>
     

    - : - + : +

    -element('exception_stack_trace'); ?> +element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_database.ctp b/lib/Cake/View/errors/missing_database.ctp similarity index 51% rename from cake/libs/view/errors/missing_database.ctp rename to lib/Cake/View/errors/missing_database.ctp index 7aa2d5e80..e7764506f 100644 --- a/cake/libs/view/errors/missing_database.ctp +++ b/lib/Cake/View/errors/missing_database.ctp @@ -16,18 +16,18 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - + : +

    - : - + : +

    - : - + : +

    element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/lib/Cake/View/errors/missing_datasource_config.ctp b/lib/Cake/View/errors/missing_datasource_config.ctp new file mode 100644 index 000000000..de6503a5a --- /dev/null +++ b/lib/Cake/View/errors/missing_datasource_config.ctp @@ -0,0 +1,29 @@ + +

    +

    + : + ' . $config . ''); ?> +

    +

    + : + +

    + +element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/lib/Cake/View/errors/missing_datasource_file.ctp b/lib/Cake/View/errors/missing_datasource_file.ctp new file mode 100644 index 000000000..3833504be --- /dev/null +++ b/lib/Cake/View/errors/missing_datasource_file.ctp @@ -0,0 +1,29 @@ + +

    +

    + : + ' . $class . ''); ?> +

    +

    + : + +

    + +element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_helper_class.ctp b/lib/Cake/View/errors/missing_helper_class.ctp similarity index 52% rename from cake/libs/view/errors/missing_helper_class.ctp rename to lib/Cake/View/errors/missing_helper_class.ctp index 842ded905..9117c87d5 100644 --- a/cake/libs/view/errors/missing_helper_class.ctp +++ b/lib/Cake/View/errors/missing_helper_class.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - %s can not be found or does not exist.', $class); ?> + : + %s can not be found or does not exist.', $class); ?>

    - : - + : +

     <?php
    @@ -33,8 +33,8 @@ class  extends AppHelper {
     ?>
     

    - : - + : +

    element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_helper_file.ctp b/lib/Cake/View/errors/missing_helper_file.ctp similarity index 51% rename from cake/libs/view/errors/missing_helper_file.ctp rename to lib/Cake/View/errors/missing_helper_file.ctp index 6ba0e9b6f..94f90f1e2 100644 --- a/cake/libs/view/errors/missing_helper_file.ctp +++ b/lib/Cake/View/errors/missing_helper_file.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - + : +

    - : - + : +

     <?php
    @@ -33,8 +33,8 @@ class  extends AppHelper {
     ?>
     

    - : - + : +

    element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_layout.ctp b/lib/Cake/View/errors/missing_layout.ctp similarity index 50% rename from cake/libs/view/errors/missing_layout.ctp rename to lib/Cake/View/errors/missing_layout.ctp index 011e59a64..ed35e35ab 100644 --- a/cake/libs/view/errors/missing_layout.ctp +++ b/lib/Cake/View/errors/missing_layout.ctp @@ -16,18 +16,18 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - ' . $file . ''); ?> + : + ' . $file . ''); ?>

    - : - ' . $file . ''); ?> + : + ' . $file . ''); ?>

    - : - + : +

    element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/missing_table.ctp b/lib/Cake/View/errors/missing_table.ctp similarity index 55% rename from cake/libs/view/errors/missing_table.ctp rename to lib/Cake/View/errors/missing_table.ctp index 1288dd06a..572579e0c 100644 --- a/cake/libs/view/errors/missing_table.ctp +++ b/lib/Cake/View/errors/missing_table.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - ' . $table . '', '' . $class . ''); ?> + : + ' . $table . '', '' . $class . ''); ?>

    - : - + : +

    element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/lib/Cake/View/errors/missing_view.ctp b/lib/Cake/View/errors/missing_view.ctp new file mode 100644 index 000000000..1e9727719 --- /dev/null +++ b/lib/Cake/View/errors/missing_view.ctp @@ -0,0 +1,33 @@ + +

    +

    + : + ' . Inflector::camelize($this->request->controller) . 'Controller::', '' . $this->request->action . '()'); ?> +

    +

    + : + +

    +

    + : + +

    + +element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/private_action.ctp b/lib/Cake/View/errors/private_action.ctp similarity index 55% rename from cake/libs/view/errors/private_action.ctp rename to lib/Cake/View/errors/private_action.ctp index 833f42112..e36a784eb 100644 --- a/cake/libs/view/errors/private_action.ctp +++ b/lib/Cake/View/errors/private_action.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - ' . $controller . '::', '' . $action . '()'); ?> + : + ' . $controller . '::', '' . $action . '()'); ?>

    - : - + : +

    element('exception_stack_trace'); ?> \ No newline at end of file diff --git a/cake/libs/view/errors/scaffold_error.ctp b/lib/Cake/View/errors/scaffold_error.ctp similarity index 60% rename from cake/libs/view/errors/scaffold_error.ctp rename to lib/Cake/View/errors/scaffold_error.ctp index 40f09c90a..2df21dcc1 100644 --- a/cake/libs/view/errors/scaffold_error.ctp +++ b/lib/Cake/View/errors/scaffold_error.ctp @@ -16,14 +16,14 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> -

    +

    - : - + : +

    - : - + : +

     <?php
    diff --git a/cake/libs/view/layouts/ajax.ctp b/lib/Cake/View/layouts/ajax.ctp
    similarity index 100%
    rename from cake/libs/view/layouts/ajax.ctp
    rename to lib/Cake/View/layouts/ajax.ctp
    diff --git a/cake/libs/view/layouts/default.ctp b/lib/Cake/View/layouts/default.ctp
    similarity index 81%
    rename from cake/libs/view/layouts/default.ctp
    rename to lib/Cake/View/layouts/default.ctp
    index f247f3c35..944b2f48c 100644
    --- a/cake/libs/view/layouts/default.ctp
    +++ b/lib/Cake/View/layouts/default.ctp
    @@ -15,13 +15,15 @@
      * @since         CakePHP(tm) v 0.10.0.1076
      * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
      */
    +
    +$cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework');
     ?>
     
     
     
     	Html->charset(); ?>
     	
    -		<?php echo __('CakePHP: the rapid development php framework:'); ?>
    +		<?php echo $cakeDescription ?>:
     		<?php echo $title_for_layout; ?>
     	
     	
     	
    @@ -46,7 +48,7 @@
    -

    +

      request->action != 'add'): ?>
    • Form->postLink( - __('Delete'), + __d('cake', 'Delete'), array('action' => 'delete', $this->Form->value($modelClass . '.' . $primaryKey)), null, - __('Are you sure you want to delete # %s?', $this->Form->value($modelClass . '.' . $primaryKey))); + __d('cake', 'Are you sure you want to delete # %s?', $this->Form->value($modelClass . '.' . $primaryKey))); ?>
    • -
    • Html->link(__('List') . ' ' . $pluralHumanName, array('action' => 'index'));?>
    • +
    • Html->link(__d('cake', 'List') . ' ' . $pluralHumanName, array('action' => 'index'));?>
    • $_data) { foreach ($_data as $_alias => $_details) { if ($_details['controller'] != $this->name && !in_array($_details['controller'], $done)) { - echo "\t\t
    • " . $this->Html->link(__('List %s', Inflector::humanize($_details['controller'])), array('controller' => $_details['controller'], 'action' =>'index')) . "
    • \n"; - echo "\t\t
    • " . $this->Html->link(__('New %s', Inflector::humanize(Inflector::underscore($_alias))), array('controller' => $_details['controller'], 'action' =>'add')) . "
    • \n"; + echo "\t\t
    • " . $this->Html->link(__d('cake', 'List %s', Inflector::humanize($_details['controller'])), array('controller' => $_details['controller'], 'action' =>'index')) . "
    • \n"; + echo "\t\t
    • " . $this->Html->link(__d('cake', 'New %s', Inflector::humanize(Inflector::underscore($_alias))), array('controller' => $_details['controller'], 'action' =>'add')) . "
    • \n"; $done[] = $_details['controller']; } } diff --git a/cake/libs/view/scaffolds/index.ctp b/lib/Cake/View/scaffolds/index.ctp similarity index 63% rename from cake/libs/view/scaffolds/index.ctp rename to lib/Cake/View/scaffolds/index.ctp index c3da1d4d8..d0def968e 100644 --- a/cake/libs/view/scaffolds/index.ctp +++ b/lib/Cake/View/scaffolds/index.ctp @@ -23,7 +23,7 @@ Paginator->sort($_field);?> - + '; - echo $this->Html->link(__('View'), array('action' => 'view', ${$singularVar}[$modelClass][$primaryKey])); - echo $this->Html->link(__('Edit'), array('action' => 'edit', ${$singularVar}[$modelClass][$primaryKey])); + echo $this->Html->link(__d('cake', 'View'), array('action' => 'view', ${$singularVar}[$modelClass][$primaryKey])); + echo $this->Html->link(__d('cake', 'Edit'), array('action' => 'edit', ${$singularVar}[$modelClass][$primaryKey])); echo $this->Form->postLink( - __('Delete'), + __d('cake', 'Delete'), array('action' => 'delete', ${$singularVar}[$modelClass][$primaryKey]), null, - __('Are you sure you want to delete').' #' . ${$singularVar}[$modelClass][$primaryKey] + __d('cake', 'Are you sure you want to delete').' #' . ${$singularVar}[$modelClass][$primaryKey] ); echo ''; echo ''; @@ -67,26 +67,26 @@ endforeach;

      Paginator->counter(array( - 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%') + 'format' => __d('cake', 'Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%') )); ?>

      - Paginator->prev('<< ' . __('previous'), array(), null, array('class' => 'disabled')); ?> + Paginator->prev('<< ' . __d('cake', 'previous'), array(), null, array('class' => 'disabled')); ?> | Paginator->numbers(); ?> - Paginator->next(__('next') .' >>', array(), null, array('class' => 'disabled')); ?> + Paginator->next(__d('cake', 'next') .' >>', array(), null, array('class' => 'disabled')); ?>
    -

    +

      -
    • Html->link(__('New %s', $singularHumanName), array('action' => 'add')); ?>
    • +
    • Html->link(__d('cake', 'New %s', $singularHumanName), array('action' => 'add')); ?>
    • $_data) { foreach ($_data as $_alias => $_details) { if ($_details['controller'] != $this->name && !in_array($_details['controller'], $done)) { - echo "
    • " . $this->Html->link(__('List %s', Inflector::humanize($_details['controller'])), array('controller' => $_details['controller'], 'action' => 'index')) . "
    • "; - echo "
    • " . $this->Html->link(__('New %s', Inflector::humanize(Inflector::underscore($_alias))), array('controller' => $_details['controller'], 'action' => 'add')) . "
    • "; + echo "
    • " . $this->Html->link(__d('cake', 'List %s', Inflector::humanize($_details['controller'])), array('controller' => $_details['controller'], 'action' => 'index')) . "
    • "; + echo "
    • " . $this->Html->link(__d('cake', 'New %s', Inflector::humanize(Inflector::underscore($_alias))), array('controller' => $_details['controller'], 'action' => 'add')) . "
    • "; $done[] = $_details['controller']; } } diff --git a/cake/libs/view/scaffolds/view.ctp b/lib/Cake/View/scaffolds/view.ctp similarity index 60% rename from cake/libs/view/scaffolds/view.ctp rename to lib/Cake/View/scaffolds/view.ctp index c31b7397f..ef2fe7006 100644 --- a/cake/libs/view/scaffolds/view.ctp +++ b/lib/Cake/View/scaffolds/view.ctp @@ -17,7 +17,7 @@ */ ?>
      -

      +

      -

      +

        " .$this->Html->link(__('Edit %s', $singularHumanName), array('action' => 'edit', ${$singularVar}[$modelClass][$primaryKey])). " \n"; - echo "\t\t
      • " .$this->Html->link(__('Delete %s', $singularHumanName), array('action' => 'delete', ${$singularVar}[$modelClass][$primaryKey]), null, __('Are you sure you want to delete').' #' . ${$singularVar}[$modelClass][$primaryKey] . '?'). "
      • \n"; - echo "\t\t
      • " .$this->Html->link(__('List %s', $pluralHumanName), array('action' => 'index')). "
      • \n"; - echo "\t\t
      • " .$this->Html->link(__('New %s', $singularHumanName), array('action' => 'add')). "
      • \n"; + echo "\t\t
      • " .$this->Html->link(__d('cake', 'Edit %s', $singularHumanName), array('action' => 'edit', ${$singularVar}[$modelClass][$primaryKey])). "
      • \n"; + echo "\t\t
      • " .$this->Html->link(__d('cake', 'Delete %s', $singularHumanName), array('action' => 'delete', ${$singularVar}[$modelClass][$primaryKey]), null, __d('cake', 'Are you sure you want to delete').' #' . ${$singularVar}[$modelClass][$primaryKey] . '?'). "
      • \n"; + echo "\t\t
      • " .$this->Html->link(__d('cake', 'List %s', $pluralHumanName), array('action' => 'index')). "
      • \n"; + echo "\t\t
      • " .$this->Html->link(__d('cake', 'New %s', $singularHumanName), array('action' => 'add')). "
      • \n"; $done = array(); foreach ($associations as $_type => $_data) { foreach ($_data as $_alias => $_details) { if ($_details['controller'] != $this->name && !in_array($_details['controller'], $done)) { - echo "\t\t
      • " . $this->Html->link(__('List %s', Inflector::humanize($_details['controller'])), array('controller' => $_details['controller'], 'action' => 'index')) . "
      • \n"; - echo "\t\t
      • " . $this->Html->link(__('New %s', Inflector::humanize(Inflector::underscore($_alias))), array('controller' => $_details['controller'], 'action' => 'add')) . "
      • \n"; + echo "\t\t
      • " . $this->Html->link(__d('cake', 'List %s', Inflector::humanize($_details['controller'])), array('controller' => $_details['controller'], 'action' => 'index')) . "
      • \n"; + echo "\t\t
      • " . $this->Html->link(__d('cake', 'New %s', Inflector::humanize(Inflector::underscore($_alias))), array('controller' => $_details['controller'], 'action' => 'add')) . "
      • \n"; $done[] = $_details['controller']; } } @@ -71,7 +71,7 @@ foreach ($scaffoldFields as $_field) { if (!empty($associations['hasOne'])) : foreach ($associations['hasOne'] as $_alias => $_details): ?> @@ -110,7 +110,7 @@ foreach ($relations as $_alias => $_details): $otherSingularVar = Inflector::variable($_alias); ?>