Initial Kohana install
authorArtem Daniliants <artem@daniliants.com>
Fri, 5 Mar 2010 11:30:48 +0000 (13:30 +0200)
committerArtem Daniliants <artem@daniliants.com>
Fri, 5 Mar 2010 11:30:48 +0000 (13:30 +0200)
165 files changed:
Server/.htaccess [new file with mode: 0644]
Server/application/config/config.php [new file with mode: 0644]
Server/application/controllers/examples.php [new file with mode: 0644]
Server/application/controllers/welcome.php [new file with mode: 0644]
Server/application/views/welcome_content.php [new file with mode: 0644]
Server/index.php [new file with mode: 0644]
Server/install.php [new file with mode: 0644]
Server/system/config/cache.php [new file with mode: 0644]
Server/system/config/cache_memcache.php [new file with mode: 0644]
Server/system/config/cache_sqlite.php [new file with mode: 0644]
Server/system/config/cache_xcache.php [new file with mode: 0644]
Server/system/config/captcha.php [new file with mode: 0644]
Server/system/config/cookie.php [new file with mode: 0644]
Server/system/config/credit_cards.php [new file with mode: 0644]
Server/system/config/database.php [new file with mode: 0644]
Server/system/config/email.php [new file with mode: 0644]
Server/system/config/encryption.php [new file with mode: 0644]
Server/system/config/http.php [new file with mode: 0644]
Server/system/config/image.php [new file with mode: 0644]
Server/system/config/inflector.php [new file with mode: 0644]
Server/system/config/locale.php [new file with mode: 0644]
Server/system/config/mimes.php [new file with mode: 0644]
Server/system/config/pagination.php [new file with mode: 0644]
Server/system/config/profiler.php [new file with mode: 0644]
Server/system/config/routes.php [new file with mode: 0644]
Server/system/config/session.php [new file with mode: 0644]
Server/system/config/sql_types.php [new file with mode: 0644]
Server/system/config/upload.php [new file with mode: 0644]
Server/system/config/user_agents.php [new file with mode: 0644]
Server/system/config/view.php [new file with mode: 0644]
Server/system/controllers/captcha.php [new file with mode: 0644]
Server/system/controllers/template.php [new file with mode: 0644]
Server/system/core/Benchmark.php [new file with mode: 0644]
Server/system/core/Bootstrap.php [new file with mode: 0644]
Server/system/core/Event.php [new file with mode: 0644]
Server/system/core/Kohana.php [new file with mode: 0644]
Server/system/core/utf8.php [new file with mode: 0644]
Server/system/core/utf8/from_unicode.php [new file with mode: 0644]
Server/system/core/utf8/ltrim.php [new file with mode: 0644]
Server/system/core/utf8/ord.php [new file with mode: 0644]
Server/system/core/utf8/rtrim.php [new file with mode: 0644]
Server/system/core/utf8/str_ireplace.php [new file with mode: 0644]
Server/system/core/utf8/str_pad.php [new file with mode: 0644]
Server/system/core/utf8/str_split.php [new file with mode: 0644]
Server/system/core/utf8/strcasecmp.php [new file with mode: 0644]
Server/system/core/utf8/strcspn.php [new file with mode: 0644]
Server/system/core/utf8/stristr.php [new file with mode: 0644]
Server/system/core/utf8/strlen.php [new file with mode: 0644]
Server/system/core/utf8/strpos.php [new file with mode: 0644]
Server/system/core/utf8/strrev.php [new file with mode: 0644]
Server/system/core/utf8/strrpos.php [new file with mode: 0644]
Server/system/core/utf8/strspn.php [new file with mode: 0644]
Server/system/core/utf8/strtolower.php [new file with mode: 0644]
Server/system/core/utf8/strtoupper.php [new file with mode: 0644]
Server/system/core/utf8/substr.php [new file with mode: 0644]
Server/system/core/utf8/substr_replace.php [new file with mode: 0644]
Server/system/core/utf8/to_unicode.php [new file with mode: 0644]
Server/system/core/utf8/transliterate_to_ascii.php [new file with mode: 0644]
Server/system/core/utf8/trim.php [new file with mode: 0644]
Server/system/core/utf8/ucfirst.php [new file with mode: 0644]
Server/system/core/utf8/ucwords.php [new file with mode: 0644]
Server/system/fonts/DejaVuSerif.ttf [new file with mode: 0644]
Server/system/fonts/LICENSE [new file with mode: 0644]
Server/system/helpers/arr.php [new file with mode: 0644]
Server/system/helpers/cookie.php [new file with mode: 0644]
Server/system/helpers/date.php [new file with mode: 0644]
Server/system/helpers/download.php [new file with mode: 0644]
Server/system/helpers/email.php [new file with mode: 0644]
Server/system/helpers/expires.php [new file with mode: 0644]
Server/system/helpers/feed.php [new file with mode: 0644]
Server/system/helpers/file.php [new file with mode: 0644]
Server/system/helpers/form.php [new file with mode: 0644]
Server/system/helpers/format.php [new file with mode: 0644]
Server/system/helpers/html.php [new file with mode: 0644]
Server/system/helpers/inflector.php [new file with mode: 0644]
Server/system/helpers/num.php [new file with mode: 0644]
Server/system/helpers/remote.php [new file with mode: 0644]
Server/system/helpers/request.php [new file with mode: 0644]
Server/system/helpers/security.php [new file with mode: 0644]
Server/system/helpers/text.php [new file with mode: 0644]
Server/system/helpers/upload.php [new file with mode: 0644]
Server/system/helpers/url.php [new file with mode: 0644]
Server/system/helpers/valid.php [new file with mode: 0644]
Server/system/i18n/en_US/cache.php [new file with mode: 0644]
Server/system/i18n/en_US/calendar.php [new file with mode: 0644]
Server/system/i18n/en_US/captcha.php [new file with mode: 0644]
Server/system/i18n/en_US/core.php [new file with mode: 0644]
Server/system/i18n/en_US/database.php [new file with mode: 0644]
Server/system/i18n/en_US/encrypt.php [new file with mode: 0644]
Server/system/i18n/en_US/errors.php [new file with mode: 0644]
Server/system/i18n/en_US/event.php [new file with mode: 0644]
Server/system/i18n/en_US/image.php [new file with mode: 0644]
Server/system/i18n/en_US/orm.php [new file with mode: 0644]
Server/system/i18n/en_US/pagination.php [new file with mode: 0644]
Server/system/i18n/en_US/profiler.php [new file with mode: 0644]
Server/system/i18n/en_US/session.php [new file with mode: 0644]
Server/system/i18n/en_US/swift.php [new file with mode: 0644]
Server/system/i18n/en_US/upload.php [new file with mode: 0644]
Server/system/i18n/en_US/validation.php [new file with mode: 0644]
Server/system/libraries/Cache.php [new file with mode: 0644]
Server/system/libraries/Calendar.php [new file with mode: 0644]
Server/system/libraries/Calendar_Event.php [new file with mode: 0644]
Server/system/libraries/Captcha.php [new file with mode: 0644]
Server/system/libraries/Controller.php [new file with mode: 0644]
Server/system/libraries/Database.php [new file with mode: 0644]
Server/system/libraries/Database_Expression.php [new file with mode: 0644]
Server/system/libraries/Encrypt.php [new file with mode: 0644]
Server/system/libraries/Event_Observer.php [new file with mode: 0644]
Server/system/libraries/Event_Subject.php [new file with mode: 0644]
Server/system/libraries/Image.php [new file with mode: 0644]
Server/system/libraries/Input.php [new file with mode: 0644]
Server/system/libraries/Model.php [new file with mode: 0644]
Server/system/libraries/ORM.php [new file with mode: 0644]
Server/system/libraries/ORM_Iterator.php [new file with mode: 0644]
Server/system/libraries/ORM_Tree.php [new file with mode: 0644]
Server/system/libraries/ORM_Versioned.php [new file with mode: 0644]
Server/system/libraries/Pagination.php [new file with mode: 0644]
Server/system/libraries/Profiler.php [new file with mode: 0644]
Server/system/libraries/Profiler_Table.php [new file with mode: 0644]
Server/system/libraries/Router.php [new file with mode: 0644]
Server/system/libraries/Session.php [new file with mode: 0644]
Server/system/libraries/Tagcloud.php [new file with mode: 0644]
Server/system/libraries/URI.php [new file with mode: 0644]
Server/system/libraries/Validation.php [new file with mode: 0644]
Server/system/libraries/View.php [new file with mode: 0644]
Server/system/libraries/drivers/Cache.php [new file with mode: 0644]
Server/system/libraries/drivers/Cache/Apc.php [new file with mode: 0644]
Server/system/libraries/drivers/Cache/Eaccelerator.php [new file with mode: 0644]
Server/system/libraries/drivers/Cache/File.php [new file with mode: 0644]
Server/system/libraries/drivers/Cache/Memcache.php [new file with mode: 0644]
Server/system/libraries/drivers/Cache/Sqlite.php [new file with mode: 0644]
Server/system/libraries/drivers/Cache/Xcache.php [new file with mode: 0644]
Server/system/libraries/drivers/Captcha.php [new file with mode: 0644]
Server/system/libraries/drivers/Captcha/Alpha.php [new file with mode: 0644]
Server/system/libraries/drivers/Captcha/Basic.php [new file with mode: 0644]
Server/system/libraries/drivers/Captcha/Black.php [new file with mode: 0644]
Server/system/libraries/drivers/Captcha/Math.php [new file with mode: 0644]
Server/system/libraries/drivers/Captcha/Riddle.php [new file with mode: 0644]
Server/system/libraries/drivers/Captcha/Word.php [new file with mode: 0644]
Server/system/libraries/drivers/Database.php [new file with mode: 0644]
Server/system/libraries/drivers/Database/Mssql.php [new file with mode: 0644]
Server/system/libraries/drivers/Database/Mysql.php [new file with mode: 0644]
Server/system/libraries/drivers/Database/Mysqli.php [new file with mode: 0644]
Server/system/libraries/drivers/Database/Pdosqlite.php [new file with mode: 0644]
Server/system/libraries/drivers/Database/Pgsql.php [new file with mode: 0644]
Server/system/libraries/drivers/Image.php [new file with mode: 0644]
Server/system/libraries/drivers/Image/GD.php [new file with mode: 0644]
Server/system/libraries/drivers/Image/GraphicsMagick.php [new file with mode: 0644]
Server/system/libraries/drivers/Image/ImageMagick.php [new file with mode: 0644]
Server/system/libraries/drivers/Session.php [new file with mode: 0644]
Server/system/libraries/drivers/Session/Cache.php [new file with mode: 0644]
Server/system/libraries/drivers/Session/Cookie.php [new file with mode: 0644]
Server/system/libraries/drivers/Session/Database.php [new file with mode: 0644]
Server/system/views/kohana/template.php [new file with mode: 0644]
Server/system/views/kohana_calendar.php [new file with mode: 0644]
Server/system/views/kohana_error_disabled.php [new file with mode: 0644]
Server/system/views/kohana_error_page.php [new file with mode: 0644]
Server/system/views/kohana_errors.css [new file with mode: 0644]
Server/system/views/kohana_profiler.php [new file with mode: 0644]
Server/system/views/kohana_profiler_table.css [new file with mode: 0644]
Server/system/views/kohana_profiler_table.php [new file with mode: 0644]
Server/system/views/pagination/classic.php [new file with mode: 0644]
Server/system/views/pagination/digg.php [new file with mode: 0644]
Server/system/views/pagination/extended.php [new file with mode: 0644]
Server/system/views/pagination/punbb.php [new file with mode: 0644]

diff --git a/Server/.htaccess b/Server/.htaccess
new file mode 100644 (file)
index 0000000..b79e25f
--- /dev/null
@@ -0,0 +1,15 @@
+# Turn on URL rewriting
+RewriteEngine On
+
+# Installation directory
+RewriteBase /
+
+# Protect application and system files from being viewed
+RewriteRule ^(application|modules|system) - [F,L]
+
+# Allow any files or directories that exist to be displayed directly
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+
+# Rewrite all other URLs to index.php/URL
+RewriteRule .* index.php/$0 [PT,L]
diff --git a/Server/application/config/config.php b/Server/application/config/config.php
new file mode 100644 (file)
index 0000000..8c45192
--- /dev/null
@@ -0,0 +1,125 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Base path of the web site. If this includes a domain, eg: localhost/kohana/
+ * then a full URL will be used, eg: http://localhost/kohana/. If it only includes
+ * the path, and a site_protocol is specified, the domain will be auto-detected.
+ */
+$config['site_domain'] = '/kohana/';
+
+/**
+ * Force a default protocol to be used by the site. If no site_protocol is
+ * specified, then the current protocol is used, or when possible, only an
+ * absolute path (with no protocol/domain) is used.
+ */
+$config['site_protocol'] = '';
+
+/**
+ * Name of the front controller for this application. Default: index.php
+ *
+ * This can be removed by using URL rewriting.
+ */
+$config['index_page'] = 'index.php';
+
+/**
+ * Fake file extension that will be added to all generated URLs. Example: .html
+ */
+$config['url_suffix'] = '';
+
+/**
+ * Length of time of the internal cache in seconds. 0 or FALSE means no caching.
+ * The internal cache stores file paths and config entries across requests and
+ * can give significant speed improvements at the expense of delayed updating.
+ */
+$config['internal_cache'] = FALSE;
+
+/**
+ * Internal cache directory.
+ */
+$config['internal_cache_path'] = APPPATH.'cache/';
+
+/**
+ * Enable internal cache encryption - speed/processing loss
+ * is neglible when this is turned on. Can be turned off
+ * if application directory is not in the webroot.
+ */
+$config['internal_cache_encrypt'] = FALSE;
+
+/**
+ * Encryption key for the internal cache, only used
+ * if internal_cache_encrypt is TRUE.
+ *
+ * Make sure you specify your own key here!
+ *
+ * The cache is deleted when/if the key changes.
+ */
+$config['internal_cache_key'] = 'foobar-changeme';
+
+/**
+ * Enable or disable gzip output compression. This can dramatically decrease
+ * server bandwidth usage, at the cost of slightly higher CPU usage. Set to
+ * the compression level (1-9) that you want to use, or FALSE to disable.
+ *
+ * Do not enable this option if you are using output compression in php.ini!
+ */
+$config['output_compression'] = FALSE;
+
+/**
+ * Enable or disable global XSS filtering of GET, POST, and SERVER data. This
+ * option also accepts a string to specify a specific XSS filtering tool.
+ */
+$config['global_xss_filtering'] = TRUE;
+
+/**
+ * Enable or disable hooks.
+ */
+$config['enable_hooks'] = FALSE;
+
+/**
+ * Log thresholds:
+ *  0 - Disable logging
+ *  1 - Errors and exceptions
+ *  2 - Warnings
+ *  3 - Notices
+ *  4 - Debugging
+ */
+$config['log_threshold'] = 1;
+
+/**
+ * Message logging directory.
+ */
+$config['log_directory'] = APPPATH.'logs';
+
+/**
+ * Enable or disable displaying of Kohana error pages. This will not affect
+ * logging. Turning this off will disable ALL error pages.
+ */
+$config['display_errors'] = TRUE;
+
+/**
+ * Enable or disable statistics in the final output. Stats are replaced via
+ * specific strings, such as {execution_time}.
+ *
+ * @see http://docs.kohanaphp.com/general/configuration
+ */
+$config['render_stats'] = TRUE;
+
+/**
+ * Filename prefixed used to determine extensions. For example, an
+ * extension to the Controller class would be named MY_Controller.php.
+ */
+$config['extension_prefix'] = 'MY_';
+
+/**
+ * Additional resource paths, or "modules". Each path can either be absolute
+ * or relative to the docroot. Modules can include any resource that can exist
+ * in your application directory, configuration files, controllers, views, etc.
+ */
+$config['modules'] = array
+(
+       // MODPATH.'auth',      // Authentication
+       // MODPATH.'kodoc',     // Self-generating documentation
+       // MODPATH.'gmaps',     // Google Maps integration
+       // MODPATH.'archive',   // Archive utility
+       // MODPATH.'payment',   // Online payments
+       // MODPATH.'unit_test', // Unit testing
+);
diff --git a/Server/application/controllers/examples.php b/Server/application/controllers/examples.php
new file mode 100644 (file)
index 0000000..849418b
--- /dev/null
@@ -0,0 +1,470 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Contains examples of various Kohana library examples. You can access these
+ * samples in your own installation of Kohana by going to ROOT_URL/examples.
+ * This controller should NOT be used in production. It is for demonstration
+ * purposes only!
+ *
+ * $Id: examples.php 4298 2009-04-30 17:06:05Z kiall $
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007-2008 Kohana Team
+ * @license    http://kohanaphp.com/license.html
+ */
+class Examples_Controller extends Controller {
+
+       // Do not allow to run in production
+       const ALLOW_PRODUCTION = FALSE;
+
+       /**
+        * Displays a list of available examples
+        */
+       function index()
+       {
+               // Get the methods that are only in this class and not the parent class.
+               $examples = array_diff
+               (
+                       get_class_methods(__CLASS__),
+                       get_class_methods(get_parent_class($this))
+               );
+
+               sort($examples);
+
+               echo "<strong>Examples:</strong>\n";
+               echo "<ul>\n";
+
+               foreach ($examples as $method)
+               {
+                       if ($method == __FUNCTION__)
+                               continue;
+
+                       echo '<li>'.html::anchor('examples/'.$method, $method)."</li>\n";
+               }
+
+               echo "</ul>\n";
+               echo '<p>'.Kohana::lang('core.stats_footer')."</p>\n";
+       }
+
+       /**
+        * Demonstrates how to archive a directory. First enable the archive module
+        */
+       //public function archive($build = FALSE)
+       //{
+       //      if ($build === 'build')
+       //      {
+       //              // Load archive
+       //              $archive = new Archive('zip');
+
+       //              // Download the application/views directory
+       //              $archive->add(APPPATH.'views/', 'app_views/', TRUE);
+
+       //              // Download the built archive
+       //              $archive->download('test.zip');
+       //      }
+       //      else
+       //      {
+       //              echo html::anchor(Router::$current_uri.'/build', 'Download views');
+       //      }
+       //}
+
+       /**
+        * Demonstrates how to parse RSS feeds by using DOMDocument.
+        */
+       function rss()
+       {
+               // Parse an external atom feed
+               $feed = feed::parse('http://dev.kohanaphp.com/projects/kohana2/activity.atom');
+
+               // Show debug info
+               echo Kohana::debug($feed);
+
+               echo Kohana::lang('core.stats_footer');
+       }
+
+       /**
+        * Demonstrates the Session library and using session data.
+        */
+       function session()
+       {
+               // Gets the singleton instance of the Session library
+               $s = Session::instance();
+
+               echo 'SESSID: <pre>'.session_id()."</pre>\n";
+
+               echo '<pre>'.print_r($_SESSION, TRUE)."</pre>\n";
+
+               echo '<br/>{execution_time} seconds';
+       }
+
+       /**
+        * Demonstrates how to use the form helper with the Validation libraryfor file uploads .
+        */
+       function form()
+       {
+               // Anything submitted?
+               if ($_POST)
+               {
+                       // Merge the globals into our validation object.
+                       $post = Validation::factory(array_merge($_POST, $_FILES));
+
+                       // Ensure upload helper is correctly configured, config/upload.php contains default entries.
+                       // Uploads can be required or optional, but should be valid
+                       $post->add_rules('imageup1', 'upload::required', 'upload::valid', 'upload::type[gif,jpg,png]', 'upload::size[1M]');
+                       $post->add_rules('imageup2', 'upload::required', 'upload::valid', 'upload::type[gif,jpg,png]', 'upload::size[1M]');
+
+                       // Alternative syntax for multiple file upload validation rules
+                       //$post->add_rules('imageup.*', 'upload::required', 'upload::valid', 'upload::type[gif,jpg,png]', 'upload::size[1M]');
+
+                       if ($post->validate() )
+                       {
+                               // It worked!
+                               // Move (and rename) the files from php upload folder to configured application folder
+                               upload::save('imageup1');
+                               upload::save('imageup2');
+                               echo 'Validation successfull, check your upload folder!';
+                       }
+                       else
+                       {
+                               // You got validation errors
+                               echo '<p>validation errors: '.var_export($post->errors(), TRUE).'</p>';
+                               echo Kohana::debug($post);
+                       }
+               }
+
+               // Display the form
+               echo form::open('examples/form', array('enctype' => 'multipart/form-data'));
+               echo form::label('imageup', 'Image Uploads').':<br/>';
+               // Use discrete upload fields
+               // Alternative syntax for multiple file uploads
+               // echo form::upload('imageup[]').'<br/>';
+
+               echo form::upload('imageup1').'<br/>';
+               echo form::upload('imageup2').'<br/>';
+               echo form::submit('upload', 'Upload!');
+               echo form::close();
+
+       }
+
+       /**
+        * Demontrates how to use the Validation library to validate an arbitrary array.
+        */
+       function validation()
+       {
+               // To demonstrate Validation being able to validate any array, I will
+               // be using a pre-built array. When you load validation with no arguments
+               // it will default to validating the POST array.
+               $data = array
+               (
+                       'user' => 'hello',
+                       'pass' => 'bigsecret',
+                       'reme' => '1'
+               );
+
+               $validation = new Validation($data);
+
+               $validation->add_rules('user', 'required', 'length[1,12]')->pre_filter('trim', 'user');
+               $validation->add_rules('pass', 'required')->post_filter('sha1', 'pass');
+               $validation->add_rules('reme', 'required');
+
+               $result = $validation->validate();
+
+               var_dump($validation->errors());
+               var_dump($validation->as_array());
+
+               // Yay!
+               echo '{execution_time} ALL DONE!';
+       }
+
+       /**
+        * Demontrates how to use the Captcha library.
+        */
+       public function captcha()
+       {
+               // Look at the counters for valid and invalid
+               // responses in the Session Profiler.
+               new Profiler;
+
+               // Load Captcha library, you can supply the name
+               // of the config group you would like to use.
+               $captcha = new Captcha;
+
+               // Ban bots (that accept session cookies) after 50 invalid responses.
+               // Be careful not to ban real people though! Set the threshold high enough.
+               if ($captcha->invalid_count() > 49)
+                       exit('Bye! Stupid bot.');
+
+               // Form submitted
+               if ($_POST)
+               {
+                       // Captcha::valid() is a static method that can be used as a Validation rule also.
+                       if (Captcha::valid($this->input->post('captcha_response')))
+                       {
+                               echo '<p style="color:green">Good answer!</p>';
+                       }
+                       else
+                       {
+                               echo '<p style="color:red">Wrong answer!</p>';
+                       }
+
+                       // Validate other fields here
+               }
+
+               // Show form
+               echo form::open();
+               echo '<p>Other form fields here...</p>';
+
+               // Don't show Captcha anymore after the user has given enough valid
+               // responses. The "enough" count is set in the captcha config.
+               if ( ! $captcha->promoted())
+               {
+                       echo '<p>';
+                       echo $captcha->render(); // Shows the Captcha challenge (image/riddle/etc)
+                       echo '</p>';
+                       echo form::input('captcha_response');
+               }
+               else
+               {
+                       echo '<p>You have been promoted to human.</p>';
+               }
+
+               // Close form
+               echo form::submit(array('value' => 'Check'));
+               echo form::close();
+       }
+
+       /**
+        * Demonstrates the features of the Database library.
+        *
+        * Table Structure:
+        *  CREATE TABLE `pages` (
+        *  `id` mediumint( 9 ) NOT NULL AUTO_INCREMENT ,
+        *  `page_name` varchar( 100 ) NOT NULL ,
+        *  `title` varchar( 255 ) NOT NULL ,
+        *  `content` longtext NOT NULL ,
+        *  `menu` tinyint( 1 ) NOT NULL default '0',
+        *  `filename` varchar( 255 ) NOT NULL ,
+        *  `order` mediumint( 9 ) NOT NULL ,
+        *  `date` int( 11 ) NOT NULL ,
+        *  `child_of` mediumint( 9 ) NOT NULL default '0',
+        *  PRIMARY KEY ( `id` ) ,
+        *  UNIQUE KEY `filename` ( `filename` )
+        *  ) ENGINE = MYISAM DEFAULT CHARSET = utf8 PACK_KEYS =0;
+        *
+       */
+       function database()
+       {
+               $db = new Database;
+
+               $table = 'pages';
+               echo 'Does the '.$table.' table exist? ';
+               if ($db->table_exists($table))
+               {
+                       echo '<p>YES! Lets do some work =)</p>';
+
+                       $query = $db->select('DISTINCT pages.*')->from($table)->get();
+                       echo $db->last_query();
+                       echo '<h3>Iterate through the result:</h3>';
+                       foreach ($query as $item)
+                       {
+                               echo '<p>'.$item->title.'</p>';
+                       }
+                       echo '<h3>Numrows using count(): '.count($query).'</h3>';
+                       echo 'Table Listing:<pre>'.print_r($db->list_tables(), TRUE).'</pre>';
+
+                       echo '<h3>Try Query Binding with objects:</h3>';
+                       $sql = 'SELECT * FROM '.$table.' WHERE id = ?';
+                       $query = $db->query($sql, array(1));
+                       echo '<p>'.$db->last_query().'</p>';
+                       $query->result(TRUE);
+                       foreach ($query as $item)
+                       {
+                               echo '<pre>'.print_r($item, true).'</pre>';
+                       }
+
+                       echo '<h3>Try Query Binding with arrays (returns both associative and numeric because I pass MYSQL_BOTH to result():</h3>';
+                       $sql = 'SELECT * FROM '.$table.' WHERE id = ?';
+                       $query = $db->query($sql, array(1));
+                       echo '<p>'.$db->last_query().'</p>';
+                       $query->result(FALSE, MYSQL_BOTH);
+                       foreach ($query as $item)
+                       {
+                               echo '<pre>'.print_r($item, true).'</pre>';
+                       }
+
+                       echo '<h3>Look, we can also manually advance the result pointer!</h3>';
+                       $query = $db->select('title')->from($table)->get();
+                       echo 'First:<pre>'.print_r($query->current(), true).'</pre><br />';
+                       $query->next();
+                       echo 'Second:<pre>'.print_r($query->current(), true).'</pre><br />';
+                       $query->next();
+                       echo 'Third:<pre>'.print_r($query->current(), true).'</pre>';
+                       echo '<h3>And we can reset it to the beginning:</h3>';
+                       $query->rewind();
+                       echo 'Rewound:<pre>'.print_r($query->current(), true).'</pre>';
+
+                       echo '<p>Number of rows using count_records(): '.$db->count_records('pages').'</p>';
+               }
+               else
+               {
+                       echo 'NO! The '.$table.' table doesn\'t exist, so we can\'t continue =( ';
+               }
+               echo "<br/><br/>\n";
+               echo 'done in {execution_time} seconds';
+       }
+
+       /**
+        * Demonstrates how to use the Pagination library and Pagination styles.
+        */
+       function pagination()
+       {
+               $pagination = new Pagination(array(
+                       // Base_url will default to the current URI
+                       // 'base_url'    => 'welcome/pagination_example/page/x',
+
+                       // The URI segment (integer) in which the pagination number can be found
+                       // The URI segment (string) that precedes the pagination number (aka "label")
+                       'uri_segment'    => 'page',
+
+                       // You could also use the query string for pagination instead of the URI segments
+                       // Just set this to the $_GET key that contains the page number
+                       // 'query_string'   => 'page',
+
+                       // The total items to paginate through (probably need to use a database COUNT query here)
+                       'total_items'    => 254,
+
+                       // The amount of items you want to display per page
+                       'items_per_page' => 10,
+
+                       // The pagination style: classic (default), digg, extended or punbb
+                       // Easily add your own styles to views/pagination and point to the view name here
+                       'style'          => 'classic',
+
+                       // If there is only one page, completely hide all pagination elements
+                       // Pagination->render() will return an empty string
+                       'auto_hide'      => TRUE,
+               ));
+
+               // Just echo to display the links (__toString() rocks!)
+               echo 'Classic style: '.$pagination;
+
+               // You can also use the render() method and pick a style on the fly if you want
+               echo '<hr /> Digg style:     ', $pagination->render('digg');
+               echo '<hr /> Extended style: ', $pagination->render('extended');
+               echo '<hr /> PunBB style:    ', $pagination->render('punbb');
+               echo 'done in {execution_time} seconds';
+       }
+
+       /**
+        * Demonstrates the User_Agent library.
+        */
+       function user_agent()
+       {
+               foreach (array('agent', 'browser', 'version') as $key)
+               {
+                       echo $key.': '.Kohana::user_agent($key).'<br/>'."\n";
+               }
+
+               echo "<br/><br/>\n";
+               echo 'done in {execution_time} seconds';
+       }
+
+       /**
+        * Demonstrates the Payment library.
+        */
+       /*function payment()
+       {
+               $credit_card = new Payment;
+
+               // You can also pass the driver name to the library to use multiple ones:
+               $credit_card = new Payment('Paypal');
+               $credit_card = new Payment('Authorize');
+
+               // You can specify one parameter at a time:
+               $credit_card->login = 'this';
+               $credit_card->first_name = 'Jeremy';
+               $credit_card->last_name = 'Bush';
+               $credit_card->card_num = '1234567890';
+               $credit_card->exp_date = '0910';
+               $credit_card->amount = '478.41';
+
+               // Or you can also set fields with an array and the <Payment.set_fields> method:
+               $credit_card->set_fields(array('login' => 'test',
+                                              'first_name' => 'Jeremy',
+                                              'last_name' => 'Bush',
+                                              'card_num' => '1234567890',
+                                              'exp_date' => '0910',
+                                              'amount' => '487.41'));
+
+               echo '<pre>'.print_r($credit_card, true).'</pre>';
+
+               echo 'Success? ';
+               echo ($response = $credit_card->process() == TRUE) ? 'YES!' : $response;
+       }*/
+
+       function calendar()
+       {
+               $profiler = new Profiler;
+
+               $calendar = new Calendar($this->input->get('month', date('m')), $this->input->get('year', date('Y')));
+               $calendar->attach($calendar->event()
+                               ->condition('year', 2008)
+                               ->condition('month', 8)
+                               ->condition('day', 8)
+                               ->output(html::anchor('http://forum.kohanaphp.com/comments.php?DiscussionID=275', 'Learning about Kohana Calendar')));
+
+               echo $calendar->render();
+       }
+
+       /**
+        * Demonstrates how to use the Image libarary..
+        */
+       function image()
+       {
+               // For testing only, save the new image in DOCROOT
+               $dir = realpath(DOCROOT);
+
+               // Original Image filename
+               $image = DOCROOT.'kohana.png';
+
+               // Create an instance of Image, with file
+               // The orginal image is not affected
+               $image = new Image($image);
+
+               // Most methods are chainable
+               // Resize the image, crop the center left
+               $image->resize(200, 100)->crop(150, 50, 'center', 'left');
+
+               // Display image in browser.
+               // Keep the actions, to be applied when saving the image.
+               $image->render($keep_actions = TRUE);
+
+               // Save the image, as a jpeg
+               // Here the actions will be discarded, by default.
+               $image->save($dir.'/mypic_thumb.jpg');
+
+               //echo Kohana::debug($image);
+       }
+
+       /**
+        * Demonstrates how to use vendor software with Kohana.
+        */
+       function vendor()
+       {
+               // Let's do a little Markdown shall we.
+               $br = "\n\n";
+               $output = '#Marked Down!#'.$br;
+               $output .= 'This **_markup_** is created *on-the-fly*, by ';
+               $output .= '[php-markdown-extra](http://michelf.com/projects/php-markdown/extra)'.$br;
+               $output .= 'It\'s *great* for user <input> & writing about `<HTML>`'.$br;
+               $output .= 'It\'s also good at footnotes :-) [^1]'.$br;
+               $output .= '[^1]: A footnote.';
+
+               // looks in system/vendor for Markdown.php
+               require Kohana::find_file('vendor', 'Markdown');
+
+               echo Markdown($output);
+
+               echo 'done in {execution_time} seconds';
+       }
+} // End Examples
diff --git a/Server/application/controllers/welcome.php b/Server/application/controllers/welcome.php
new file mode 100644 (file)
index 0000000..8941953
--- /dev/null
@@ -0,0 +1,54 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Default Kohana controller. This controller should NOT be used in production.
+ * It is for demonstration purposes only!
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007-2008 Kohana Team
+ * @license    http://kohanaphp.com/license.html
+ */
+class Welcome_Controller extends Template_Controller {
+
+       // Disable this controller when Kohana is set to production mode.
+       // See http://docs.kohanaphp.com/installation/deployment for more details.
+       const ALLOW_PRODUCTION = FALSE;
+
+       // Set the name of the template to use
+       public $template = 'kohana/template';
+
+       public function index()
+       {
+               // In Kohana, all views are loaded and treated as objects.
+               $this->template->content = new View('welcome_content');
+
+               // You can assign anything variable to a view by using standard OOP
+               // methods. In my welcome view, the $title variable will be assigned
+               // the value I give it here.
+               $this->template->title = 'Welcome to Kohana!';
+
+               // An array of links to display. Assiging variables to views is completely
+               // asyncronous. Variables can be set in any order, and can be any type
+               // of data, including objects.
+               $this->template->content->links = array
+               (
+                       'Home Page'     => 'http://kohanaphp.com/',
+                       'Documentation' => 'http://docs.kohanaphp.com/',
+                       'Forum'         => 'http://forum.kohanaphp.com/',
+                       'License'       => 'Kohana License.html',
+                       'Donate'        => 'http://kohanaphp.com/donate',
+               );
+       }
+
+       public function __call($method, $arguments)
+       {
+               // Disable auto-rendering
+               $this->auto_render = FALSE;
+
+               // By defining a __call method, all pages routed to this controller
+               // that result in 404 errors will be handled by this method, instead of
+               // being displayed as "Page Not Found" errors.
+               echo 'This text is generated by __call. If you expected the index page, you need to use: welcome/index/'.substr(Router::$current_uri, 8);
+       }
+
+} // End Welcome Controller
\ No newline at end of file
diff --git a/Server/application/views/welcome_content.php b/Server/application/views/welcome_content.php
new file mode 100644 (file)
index 0000000..0adcab6
--- /dev/null
@@ -0,0 +1,15 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.'); ?>
+<div class="box">
+       <p>This is the default Kohana index page. You may also access this page as <code><?php echo html::anchor('welcome/index', 'welcome/index') ?></code>.</p>
+
+       <p>
+               To change what gets displayed for this page, edit <code>application/controllers/welcome.php</code>.<br />
+               To change this text, edit <code>application/views/welcome_content.php</code>.
+       </p>
+</div>
+
+<ul>
+<?php foreach ($links as $title => $url): ?>
+       <li><?php echo ($title === 'License') ? html::file_anchor($url, html::specialchars($title)) : html::anchor($url, html::specialchars($title)) ?></li>
+<?php endforeach ?>
+</ul>
\ No newline at end of file
diff --git a/Server/index.php b/Server/index.php
new file mode 100644 (file)
index 0000000..4217a28
--- /dev/null
@@ -0,0 +1,107 @@
+<?php
+/**
+ * This file acts as the "front controller" to your application. You can
+ * configure your application, modules, and system directories here.
+ * PHP error_reporting level may also be changed.
+ *
+ * @see http://kohanaphp.com
+ */
+
+/**
+ * Define the website environment status. When this flag is set to TRUE, some
+ * module demonstration controllers will result in 404 errors. For more information
+ * about this option, read the documentation about deploying Kohana.
+ *
+ * @see http://docs.kohanaphp.com/installation/deployment
+ */
+define('IN_PRODUCTION', FALSE);
+
+/**
+ * Website application directory. This directory should contain your application
+ * configuration, controllers, models, views, and other resources.
+ *
+ * This path can be absolute or relative to this file.
+ */
+$kohana_application = 'application';
+
+/**
+ * Kohana modules directory. This directory should contain all the modules used
+ * by your application. Modules are enabled and disabled by the application
+ * configuration file.
+ *
+ * This path can be absolute or relative to this file.
+ */
+$kohana_modules = 'modules';
+
+/**
+ * Kohana system directory. This directory should contain the core/ directory,
+ * and the resources you included in your download of Kohana.
+ *
+ * This path can be absolute or relative to this file.
+ */
+$kohana_system = 'system';
+
+/**
+ * Test to make sure that Kohana is running on PHP 5.2 or newer. Once you are
+ * sure that your environment is compatible with Kohana, you can comment this
+ * line out. When running an application on a new server, uncomment this line
+ * to check the PHP version quickly.
+ */
+version_compare(PHP_VERSION, '5.2', '<') and exit('Kohana requires PHP 5.2 or newer.');
+
+/**
+ * Set the error reporting level. Unless you have a special need, E_ALL is a
+ * good level for error reporting.
+ */
+error_reporting(E_ALL & ~E_STRICT);
+
+/**
+ * Turning off display_errors will effectively disable Kohana error display
+ * and logging. You can turn off Kohana errors in application/config/config.php
+ */
+ini_set('display_errors', TRUE);
+
+/**
+ * If you rename all of your .php files to a different extension, set the new
+ * extension here. This option can left to .php, even if this file has a
+ * different extension.
+ */
+define('EXT', '.php');
+
+//
+// DO NOT EDIT BELOW THIS LINE, UNLESS YOU FULLY UNDERSTAND THE IMPLICATIONS.
+// ----------------------------------------------------------------------------
+// $Id: index.php 3915 2009-01-20 20:52:20Z zombor $
+//
+
+$kohana_pathinfo = pathinfo(__FILE__);
+// Define the front controller name and docroot
+define('DOCROOT', $kohana_pathinfo['dirname'].DIRECTORY_SEPARATOR);
+define('KOHANA',  $kohana_pathinfo['basename']);
+
+// If the front controller is a symlink, change to the real docroot
+is_link(KOHANA) and chdir(dirname(realpath(__FILE__)));
+
+// If kohana folders are relative paths, make them absolute.
+$kohana_application = file_exists($kohana_application) ? $kohana_application : DOCROOT.$kohana_application;
+$kohana_modules = file_exists($kohana_modules) ? $kohana_modules : DOCROOT.$kohana_modules;
+$kohana_system = file_exists($kohana_system) ? $kohana_system : DOCROOT.$kohana_system;
+
+// Define application and system paths
+define('APPPATH', str_replace('\\', '/', realpath($kohana_application)).'/');
+define('MODPATH', str_replace('\\', '/', realpath($kohana_modules)).'/');
+define('SYSPATH', str_replace('\\', '/', realpath($kohana_system)).'/');
+
+// Clean up
+unset($kohana_application, $kohana_modules, $kohana_system);
+
+if (file_exists(DOCROOT.'install'.EXT))
+{
+       // Load the installation tests
+       include DOCROOT.'install'.EXT;
+}
+else
+{
+       // Initialize Kohana
+       require SYSPATH.'core/Bootstrap'.EXT;
+}
\ No newline at end of file
diff --git a/Server/install.php b/Server/install.php
new file mode 100644 (file)
index 0000000..a380710
--- /dev/null
@@ -0,0 +1,154 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+
+<title>Kohana Installation</title>
+
+<style type="text/css">
+body { width: 42em; margin: 0 auto; font-family: sans-serif; font-size: 90%; }
+
+#tests table { border-collapse: collapse; width: 100%; }
+       #tests table th,
+       #tests table td { padding: 0.2em 0.4em; text-align: left; vertical-align: top; }
+       #tests table th { width: 12em; font-weight: normal; font-size: 1.2em; }
+       #tests table tr:nth-child(odd) { background: #eee; }
+       #tests table td.pass { color: #191; }
+       #tests table td.fail { color: #911; }
+               #tests #results { color: #fff; }
+               #tests #results p { padding: 0.8em 0.4em; }
+               #tests #results p.pass { background: #191; }
+               #tests #results p.fail { background: #911; }
+</style>
+
+</head>
+<body>
+
+<h1>Environment Tests</h1>
+
+<p>The following tests have been run to determine if Kohana will work in your environment. If any of the tests have failed, consult the <a href="http://docs.kohanaphp.com/installation">documentation</a> for more information on how to correct the problem.</p>
+
+<div id="tests">
+<?php $failed = FALSE ?>
+<table cellspacing="0">
+<tr>
+<th>PHP Version</th>
+<?php if (version_compare(PHP_VERSION, '5.2', '>=')): ?>
+<td class="pass"><?php echo PHP_VERSION ?></td>
+<?php else: $failed = TRUE ?>
+<td class="fail">Kohana requires PHP 5.2 or newer, this version is <?php echo PHP_VERSION ?>.</td>
+<?php endif ?>
+</tr>
+<tr>
+<th>System Directory</th>
+<?php if (is_dir(SYSPATH) AND is_file(SYSPATH.'core/Bootstrap'.EXT)): ?>
+<td class="pass"><?php echo SYSPATH ?></td>
+<?php else: $failed = TRUE ?>
+<td class="fail">The configured <code>system</code> directory does not exist or does not contain required files.</td>
+<?php endif ?>
+</tr>
+<tr>
+<th>Application Directory</th>
+<?php if (is_dir(APPPATH) AND is_file(APPPATH.'config/config'.EXT)): ?>
+<td class="pass"><?php echo APPPATH ?></td>
+<?php else: $failed = TRUE ?>
+<td class="fail">The configured <code>application</code> directory does not exist or does not contain required files.</td>
+<?php endif ?>
+</tr>
+<tr>
+<th>Modules Directory</th>
+<?php if (is_dir(MODPATH)): ?>
+<td class="pass"><?php echo MODPATH ?></td>
+<?php else: $failed = TRUE ?>
+<td class="fail">The configured <code>modules</code> directory does not exist or does not contain required files.</td>
+<?php endif ?>
+</tr>
+<tr>
+<th>PCRE UTF-8</th>
+<?php if ( !function_exists('preg_match')): $failed = TRUE ?>
+<td class="fail"><a href="http://php.net/pcre">PCRE</a> support is missing.</td>
+<?php elseif ( ! @preg_match('/^.$/u', 'ñ')): $failed = TRUE ?>
+<td class="fail"><a href="http://php.net/pcre">PCRE</a> has not been compiled with UTF-8 support.</td>
+<?php elseif ( ! @preg_match('/^\pL$/u', 'ñ')): $failed = TRUE ?>
+<td class="fail"><a href="http://php.net/pcre">PCRE</a> has not been compiled with Unicode property support.</td>
+<?php else: ?>
+<td class="pass">Pass</td>
+<?php endif ?>
+</tr>
+<tr>
+<th>Reflection Enabled</th>
+<?php if (class_exists('ReflectionClass')): ?>
+<td class="pass">Pass</td>
+<?php else: $failed = TRUE ?>
+<td class="fail">PHP <a href="http://www.php.net/reflection">reflection</a> is either not loaded or not compiled in.</td>
+<?php endif ?>
+</tr>
+<tr>
+<th>Filters Enabled</th>
+<?php if (function_exists('filter_list')): ?>
+<td class="pass">Pass</td>
+<?php else: $failed = TRUE ?>
+<td class="fail">The <a href="http://www.php.net/filter">filter</a> extension is either not loaded or not compiled in.</td>
+<?php endif ?>
+</tr>
+<tr>
+<th>Iconv Extension Loaded</th>
+<?php if (extension_loaded('iconv')): ?>
+<td class="pass">Pass</td>
+<?php else: $failed = TRUE ?>
+<td class="fail">The <a href="http://php.net/iconv">iconv</a> extension is not loaded.</td>
+<?php endif ?>
+</tr>
+
+<tr>
+<th>SPL Enabled</th>
+<?php if (function_exists('spl_autoload_register')): ?>
+<td class="pass">Pass</td>
+<?php else: $failed = TRUE ?>
+<td class="fail"><a href="http://php.net/spl">SPL</a> is not enabled.</td>
+<?php endif ?>
+</tr>
+
+<?php if (extension_loaded('mbstring')): ?>
+<tr>
+<th>Mbstring Not Overloaded</th>
+<?php if (ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING): $failed = TRUE ?>
+<td class="fail">The <a href="http://php.net/mbstring">mbstring</a> extension is overloading PHP's native string functions.</td>
+<?php else: ?>
+<td class="pass">Pass</td>
+</tr>
+<?php endif ?>
+<?php else: // check for utf8_[en|de]code when mbstring is not available ?>
+<tr>
+<th>XML support</th>
+<?php if ( ! function_exists('utf8_encode')): $failed = TRUE ?>
+<td class="fail">PHP is compiled without <a href="http://php.net/xml">XML</a> support, thus lacking support for <code>utf8_encode()</code>/<code>utf8_decode()</code>.</td>
+<?php else: ?>
+<td class="pass">Pass</td>
+<?php endif ?>
+</tr>
+<?php endif ?>
+<tr>
+<th>URI Determination</th>
+<?php if (isset($_SERVER['REQUEST_URI']) OR isset($_SERVER['PHP_SELF'])): ?>
+<td class="pass">Pass</td>
+<?php else: $failed = TRUE ?>
+<td class="fail">Neither <code>$_SERVER['REQUEST_URI']</code> or <code>$_SERVER['PHP_SELF']</code> is available.</td>
+<?php endif ?>
+</tr>
+
+</table>
+
+<div id="results">
+<?php if ($failed === TRUE): ?>
+<p class="fail">Kohana may not work correctly with your environment.</p>
+<?php else: ?>
+<p class="pass">Your environment passed all requirements. Remove or rename the <code>install<?php echo EXT ?></code> file now.</p>
+<?php endif ?>
+</div>
+
+</div>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/Server/system/config/cache.php b/Server/system/config/cache.php
new file mode 100644 (file)
index 0000000..ccd3da4
--- /dev/null
@@ -0,0 +1,32 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Cache
+ *
+ * Cache settings, defined as arrays, or "groups". If no group name is
+ * used when loading the cache library, the group named "default" will be used.
+ *
+ * Each group can be used independently, and multiple groups can be used at once.
+ *
+ * Group Options:
+ *  driver   - Cache backend driver. Kohana comes with file, database, and memcache drivers.
+ *              > File cache is fast and reliable, but requires many filesystem lookups.
+ *              > Database cache can be used to cache items remotely, but is slower.
+ *              > Memcache is very high performance, but prevents cache tags from being used.
+ *
+ *  params   - Driver parameters, specific to each driver.
+ *
+ *  lifetime - Default lifetime of caches in seconds. By default caches are stored for
+ *             thirty minutes. Specific lifetime can also be set when creating a new cache.
+ *             Setting this to 0 will never automatically delete caches.
+ *
+ *  requests - Average number of cache requests that will processed before all expired
+ *             caches are deleted. This is commonly referred to as "garbage collection".
+ *             Setting this to 0 or a negative number will disable automatic garbage collection.
+ */
+$config['default'] = array
+(
+       'driver'   => 'file',
+       'params'   => APPPATH.'cache',
+       'lifetime' => 1800,
+       'requests' => 1000
+);
diff --git a/Server/system/config/cache_memcache.php b/Server/system/config/cache_memcache.php
new file mode 100644 (file)
index 0000000..43d8f20
--- /dev/null
@@ -0,0 +1,20 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Cache:Memcache
+ *
+ * memcache server configuration.
+ */
+$config['servers'] = array
+(
+       array
+       (
+               'host' => '127.0.0.1',
+               'port' => 11211,
+               'persistent' => FALSE,
+       )
+);
+
+/**
+ * Enable cache data compression.
+ */
+$config['compression'] = FALSE;
diff --git a/Server/system/config/cache_sqlite.php b/Server/system/config/cache_sqlite.php
new file mode 100644 (file)
index 0000000..818b893
--- /dev/null
@@ -0,0 +1,10 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Cache:SQLite
+ */
+$config['schema'] =
+'CREATE TABLE caches(
+       id VARCHAR(127) PRIMARY KEY,
+       tags VARCHAR(255),
+       expiration INTEGER,
+       cache TEXT);';
\ No newline at end of file
diff --git a/Server/system/config/cache_xcache.php b/Server/system/config/cache_xcache.php
new file mode 100644 (file)
index 0000000..47aac25
--- /dev/null
@@ -0,0 +1,12 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Cache:Xcache
+ *
+ * Xcache administrator username.
+ */
+$config['PHP_AUTH_USER'] = 'kohana';
+
+/**
+ * Xcache administrator password.
+ */
+$config['PHP_AUTH_PW'] = 'kohana';
diff --git a/Server/system/config/captcha.php b/Server/system/config/captcha.php
new file mode 100644 (file)
index 0000000..9241ec6
--- /dev/null
@@ -0,0 +1,29 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Core
+ *
+ * Captcha configuration is defined in groups which allows you to easily switch
+ * between different Captcha settings for different forms on your website.
+ * Note: all groups inherit and overwrite the default group.
+ *
+ * Group Options:
+ *  style      - Captcha type, e.g. basic, alpha, word, math, riddle
+ *  width      - Width of the Captcha image
+ *  height     - Height of the Captcha image
+ *  complexity - Difficulty level (0-10), usage depends on chosen style
+ *  background - Path to background image file
+ *  fontpath   - Path to font folder
+ *  fonts      - Font files
+ *  promote    - Valid response count threshold to promote user (FALSE to disable)
+ */
+$config['default'] = array
+(
+       'style'      => 'basic',
+       'width'      => 150,
+       'height'     => 50,
+       'complexity' => 4,
+       'background' => '',
+       'fontpath'   => SYSPATH.'fonts/',
+       'fonts'      => array('DejaVuSerif.ttf'),
+       'promote'    => FALSE,
+);
\ No newline at end of file
diff --git a/Server/system/config/cookie.php b/Server/system/config/cookie.php
new file mode 100644 (file)
index 0000000..b6ddfe4
--- /dev/null
@@ -0,0 +1,32 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Core
+ *
+ * Domain, to restrict the cookie to a specific website domain. For security,
+ * you are encouraged to set this option. An empty setting allows the cookie
+ * to be read by any website domain.
+ */
+$config['domain'] = '';
+
+/**
+ * Restrict cookies to a specific path, typically the installation directory.
+ */
+$config['path'] = '/';
+
+/**
+ * Lifetime of the cookie. A setting of 0 makes the cookie active until the
+ * users browser is closed or the cookie is deleted.
+ */
+$config['expire'] = 0;
+
+/**
+ * Enable this option to only allow the cookie to be read when using the a
+ * secure protocol.
+ */
+$config['secure'] = FALSE;
+
+/**
+ * Enable this option to disable the cookie from being accessed when using a
+ * secure protocol. This option is only available in PHP 5.2 and above.
+ */
+$config['httponly'] = FALSE;
\ No newline at end of file
diff --git a/Server/system/config/credit_cards.php b/Server/system/config/credit_cards.php
new file mode 100644 (file)
index 0000000..bfc9842
--- /dev/null
@@ -0,0 +1,60 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Credit card validation configuration.
+ * 
+ * Options for each credit card:
+ *  length - All the allowed card number lengths, in a comma separated string
+ *  prefix - The digits the card needs to start with, in regex format
+ *  luhn   - Enable or disable card number validation by the Luhn algorithm
+ */
+$config = array
+(
+       'default' => array
+       (
+               'length' => '13,14,15,16,17,18,19',
+               'prefix' => '',
+               'luhn'   => TRUE
+       ),
+       'american express' => array
+       (
+               'length' => '15',
+               'prefix' => '3[47]',
+               'luhn'   => TRUE
+       ),
+       'diners club' => array
+       (
+               'length' => '14,16',
+               'prefix' => '36|55|30[0-5]',
+               'luhn'   => TRUE
+       ),
+       'discover' => array
+       (
+               'length' => '16',
+               'prefix' => '6(?:5|011)',
+               'luhn'   => TRUE,
+       ),
+       'jcb' => array
+       (
+               'length' => '15,16',
+               'prefix' => '3|1800|2131',
+               'luhn'   => TRUE
+       ),
+       'maestro' => array
+       (
+               'length' => '16,18',
+               'prefix' => '50(?:20|38)|6(?:304|759)',
+               'luhn'   => TRUE
+       ),
+       'mastercard' => array
+       (
+               'length' => '16',
+               'prefix' => '5[1-5]',
+               'luhn'   => TRUE
+       ),
+       'visa' => array
+       (
+               'length' => '13,16',
+               'prefix' => '4',
+               'luhn'   => TRUE
+       ),
+);
\ No newline at end of file
diff --git a/Server/system/config/database.php b/Server/system/config/database.php
new file mode 100644 (file)
index 0000000..6519156
--- /dev/null
@@ -0,0 +1,45 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Database
+ *
+ * Database connection settings, defined as arrays, or "groups". If no group
+ * name is used when loading the database library, the group named "default"
+ * will be used.
+ *
+ * Each group can be connected to independently, and multiple groups can be
+ * connected at once.
+ *
+ * Group Options:
+ *  benchmark     - Enable or disable database benchmarking
+ *  persistent    - Enable or disable a persistent connection
+ *  connection    - Array of connection specific parameters; alternatively,
+ *                  you can use a DSN though it is not as fast and certain
+ *                  characters could create problems (like an '@' character
+ *                  in a password):
+ *                  'connection'    => 'mysql://dbuser:secret@localhost/kohana'
+ *  character_set - Database character set
+ *  table_prefix  - Database table prefix
+ *  object        - Enable or disable object results
+ *  cache         - Enable or disable query caching
+ *     escape        - Enable automatic query builder escaping
+ */
+$config['default'] = array
+(
+       'benchmark'     => TRUE,
+       'persistent'    => FALSE,
+       'connection'    => array
+       (
+               'type'     => 'mysql',
+               'user'     => 'dbuser',
+               'pass'     => 'p@ssw0rd',
+               'host'     => 'localhost',
+               'port'     => FALSE,
+               'socket'   => FALSE,
+               'database' => 'kohana'
+       ),
+       'character_set' => 'utf8',
+       'table_prefix'  => '',
+       'object'        => TRUE,
+       'cache'         => FALSE,
+       'escape'        => TRUE
+);
\ No newline at end of file
diff --git a/Server/system/config/email.php b/Server/system/config/email.php
new file mode 100644 (file)
index 0000000..c768367
--- /dev/null
@@ -0,0 +1,22 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * SwiftMailer driver, used with the email helper.
+ *
+ * @see http://www.swiftmailer.org/wikidocs/v3/connections/nativemail
+ * @see http://www.swiftmailer.org/wikidocs/v3/connections/sendmail
+ * @see http://www.swiftmailer.org/wikidocs/v3/connections/smtp
+ *
+ * Valid drivers are: native, sendmail, smtp
+ */
+$config['driver'] = 'native';
+
+/**
+ * To use secure connections with SMTP, set "port" to 465 instead of 25.
+ * To enable TLS, set "encryption" to "tls".
+ *
+ * Driver options:
+ * @param   null    native: no options
+ * @param   string  sendmail: executable path, with -bs or equivalent attached
+ * @param   array   smtp: hostname, (username), (password), (port), (auth), (encryption)
+ */
+$config['options'] = NULL;
diff --git a/Server/system/config/encryption.php b/Server/system/config/encryption.php
new file mode 100644 (file)
index 0000000..589a9de
--- /dev/null
@@ -0,0 +1,31 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Encrypt
+ *
+ * Encrypt configuration is defined in groups which allows you to easily switch
+ * between different encryption settings for different uses.
+ * Note: all groups inherit and overwrite the default group.
+ *
+ * Group Options:
+ *  key    - Encryption key used to do encryption and decryption. The default option
+ *           should never be used for a production website.
+ *
+ *           For best security, your encryption key should be at least 16 characters
+ *           long and contain letters, numbers, and symbols.
+ *           @note Do not use a hash as your key. This significantly lowers encryption entropy.
+ *
+ *  mode   - MCrypt encryption mode. By default, MCRYPT_MODE_NOFB is used. This mode
+ *           offers initialization vector support, is suited to short strings, and
+ *           produces the shortest encrypted output.
+ *           @see http://php.net/mcrypt
+ *
+ *  cipher - MCrypt encryption cipher. By default, the MCRYPT_RIJNDAEL_128 cipher is used.
+ *           This is also known as 128-bit AES.
+ *           @see http://php.net/mcrypt
+ */
+$config['default'] = array
+(
+       'key'    => 'K0H@NA+PHP_7hE-SW!FtFraM3w0R|<',
+       'mode'   => MCRYPT_MODE_NOFB,
+       'cipher' => MCRYPT_RIJNDAEL_128
+);
diff --git a/Server/system/config/http.php b/Server/system/config/http.php
new file mode 100644 (file)
index 0000000..3c4a86a
--- /dev/null
@@ -0,0 +1,19 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+
+// HTTP-EQUIV type meta tags
+$config['meta_equiv'] = array
+(
+       'cache-control',
+       'content-type', 'content-script-type', 'content-style-type',
+       'content-disposition',
+       'content-language',
+       'default-style',
+       'expires',
+       'ext-cache',
+       'pics-label',
+       'pragma',
+       'refresh',
+       'set-cookie',
+       'vary',
+       'window-target',
+);
\ No newline at end of file
diff --git a/Server/system/config/image.php b/Server/system/config/image.php
new file mode 100644 (file)
index 0000000..e38b7cb
--- /dev/null
@@ -0,0 +1,13 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Image
+ *
+ * Driver name. Default: GD
+ */
+$config['driver'] = 'GD';
+
+/**
+ * Driver parameters:
+ * ImageMagick - set the "directory" parameter to your ImageMagick installation directory
+ */
+$config['params'] = array();
\ No newline at end of file
diff --git a/Server/system/config/inflector.php b/Server/system/config/inflector.php
new file mode 100644 (file)
index 0000000..6dcfc2d
--- /dev/null
@@ -0,0 +1,58 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+
+$config['uncountable'] = array
+(
+       'access',
+       'advice',
+       'art',
+       'baggage',
+       'dances',
+       'equipment',
+       'fish',
+       'fuel',
+       'furniture',
+       'food',
+       'heat',
+       'honey',
+       'homework',
+       'impatience',
+       'information',
+       'knowledge',
+       'luggage',
+       'money',
+       'music',
+       'news',
+       'patience',
+       'progress',
+       'pollution',
+       'research',
+       'rice',
+       'sand',
+       'series',
+       'sheep',
+       'sms',
+       'species',
+       'staff',
+       'toothpaste',
+       'traffic',
+       'understanding',
+       'water',
+       'weather',
+       'work',
+);
+
+$config['irregular'] = array
+(
+       'child' => 'children',
+       'clothes' => 'clothing',
+       'man' => 'men',
+       'movie' => 'movies',
+       'person' => 'people',
+       'woman' => 'women',
+       'mouse' => 'mice',
+       'goose' => 'geese',
+       'ox' => 'oxen',
+       'leaf' => 'leaves',
+       'course' => 'courses',
+       'size' => 'sizes',
+);
diff --git a/Server/system/config/locale.php b/Server/system/config/locale.php
new file mode 100644 (file)
index 0000000..3a26882
--- /dev/null
@@ -0,0 +1,16 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Core
+ *
+ * Default language locale name(s).
+ * First item must be a valid i18n directory name, subsequent items are alternative locales
+ * for OS's that don't support the first (e.g. Windows). The first valid locale in the array will be used.
+ * @see http://php.net/setlocale
+ */
+$config['language'] = array('en_US', 'English_United States');
+
+/**
+ * Locale timezone. Defaults to use the server timezone.
+ * @see http://php.net/timezones
+ */
+$config['timezone'] = '';
\ No newline at end of file
diff --git a/Server/system/config/mimes.php b/Server/system/config/mimes.php
new file mode 100644 (file)
index 0000000..6a960f2
--- /dev/null
@@ -0,0 +1,224 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Core
+ *
+ * A list of mime types. Our list is generally more complete and accurate than
+ * the operating system MIME list.
+ *
+ * If there are any missing options, please create a ticket on our issue tracker,
+ * http://kohanaphp.com/trac/newticket. Be sure to give the filename and
+ * expected MIME type, as well as any additional information you can provide.
+ */
+$config = array
+(
+       '323'   => array('text/h323'),
+       '7z'    => array('application/x-7z-compressed'),
+       'abw'   => array('application/x-abiword'),
+       'acx'   => array('application/internet-property-stream'),
+       'ai'    => array('application/postscript'),
+       'aif'   => array('audio/x-aiff'),
+       'aifc'  => array('audio/x-aiff'),
+       'aiff'  => array('audio/x-aiff'),
+       'asf'   => array('video/x-ms-asf'),
+       'asr'   => array('video/x-ms-asf'),
+       'asx'   => array('video/x-ms-asf'),
+       'atom'  => array('application/atom+xml'),
+       'avi'   => array('video/avi', 'video/msvideo', 'video/x-msvideo'),
+       'bin'   => array('application/octet-stream','application/macbinary'),
+       'bmp'   => array('image/bmp'),
+       'c'     => array('text/x-csrc'),
+       'c++'   => array('text/x-c++src'),
+       'cab'   => array('application/x-cab'),
+       'cc'    => array('text/x-c++src'),
+       'cda'   => array('application/x-cdf'),
+       'class' => array('application/octet-stream'),
+       'cpp'   => array('text/x-c++src'),
+       'cpt'   => array('application/mac-compactpro'),
+       'csh'   => array('text/x-csh'),
+       'css'   => array('text/css'),
+       'csv'   => array('text/x-comma-separated-values', 'application/vnd.ms-excel', 'text/comma-separated-values', 'text/csv'),
+       'dbk'   => array('application/docbook+xml'),
+       'dcr'   => array('application/x-director'),
+       'deb'   => array('application/x-debian-package'),
+       'diff'  => array('text/x-diff'),
+       'dir'   => array('application/x-director'),
+       'divx'  => array('video/divx'),
+       'dll'   => array('application/octet-stream', 'application/x-msdos-program'),
+       'dmg'   => array('application/x-apple-diskimage'),
+       'dms'   => array('application/octet-stream'),
+       'doc'   => array('application/msword'),
+       'dvi'   => array('application/x-dvi'),
+       'dxr'   => array('application/x-director'),
+       'eml'   => array('message/rfc822'),
+       'eps'   => array('application/postscript'),
+       'evy'   => array('application/envoy'),
+       'exe'   => array('application/x-msdos-program', 'application/octet-stream'),
+       'fla'   => array('application/octet-stream'),
+       'flac'  => array('application/x-flac'),
+       'flc'   => array('video/flc'),
+       'fli'   => array('video/fli'),
+       'flv'   => array('video/x-flv'),
+       'gif'   => array('image/gif'),
+       'gtar'  => array('application/x-gtar'),
+       'gz'    => array('application/x-gzip'),
+       'h'     => array('text/x-chdr'),
+       'h++'   => array('text/x-c++hdr'),
+       'hh'    => array('text/x-c++hdr'),
+       'hpp'   => array('text/x-c++hdr'),
+       'hqx'   => array('application/mac-binhex40'),
+       'hs'    => array('text/x-haskell'),
+       'htm'   => array('text/html'),
+       'html'  => array('text/html'),
+       'ico'   => array('image/x-icon'),
+       'ics'   => array('text/calendar'),
+       'iii'   => array('application/x-iphone'),
+       'ins'   => array('application/x-internet-signup'),
+       'iso'   => array('application/x-iso9660-image'),
+       'isp'   => array('application/x-internet-signup'),
+       'jar'   => array('application/java-archive'),
+       'java'  => array('application/x-java-applet'),
+       'jpe'   => array('image/jpeg', 'image/pjpeg'),
+       'jpeg'  => array('image/jpeg', 'image/pjpeg'),
+       'jpg'   => array('image/jpeg', 'image/pjpeg'),
+       'js'    => array('application/x-javascript'),
+       'json'  => array('application/json'),
+       'latex' => array('application/x-latex'),
+       'lha'   => array('application/octet-stream'),
+       'log'   => array('text/plain', 'text/x-log'),
+       'lzh'   => array('application/octet-stream'),
+       'm4a'   => array('audio/mpeg'),
+       'm4p'   => array('video/mp4v-es'),
+       'm4v'   => array('video/mp4'),
+       'man'   => array('application/x-troff-man'),
+       'mdb'   => array('application/x-msaccess'),
+       'midi'  => array('audio/midi'),
+       'mid'   => array('audio/midi'),
+       'mif'   => array('application/vnd.mif'),
+       'mka'   => array('audio/x-matroska'),
+       'mkv'   => array('video/x-matroska'),
+       'mov'   => array('video/quicktime'),
+       'movie' => array('video/x-sgi-movie'),
+       'mp2'   => array('audio/mpeg'),
+       'mp3'   => array('audio/mpeg'),
+       'mp4'   => array('application/mp4','audio/mp4','video/mp4'),
+       'mpa'   => array('video/mpeg'),
+       'mpe'   => array('video/mpeg'),
+       'mpeg'  => array('video/mpeg'),
+       'mpg'   => array('video/mpeg'),
+       'mpg4'  => array('video/mp4'),
+       'mpga'  => array('audio/mpeg'),
+       'mpp'   => array('application/vnd.ms-project'),
+       'mpv'   => array('video/x-matroska'),
+       'mpv2'  => array('video/mpeg'),
+       'ms'    => array('application/x-troff-ms'),
+       'msg'   => array('application/msoutlook','application/x-msg'),
+       'msi'   => array('application/x-msi'),
+       'nws'   => array('message/rfc822'),
+       'oda'   => array('application/oda'),
+       'odb'   => array('application/vnd.oasis.opendocument.database'),
+       'odc'   => array('application/vnd.oasis.opendocument.chart'),
+       'odf'   => array('application/vnd.oasis.opendocument.forumla'),
+       'odg'   => array('application/vnd.oasis.opendocument.graphics'),
+       'odi'   => array('application/vnd.oasis.opendocument.image'),
+       'odm'   => array('application/vnd.oasis.opendocument.text-master'),
+       'odp'   => array('application/vnd.oasis.opendocument.presentation'),
+       'ods'   => array('application/vnd.oasis.opendocument.spreadsheet'),
+       'odt'   => array('application/vnd.oasis.opendocument.text'),
+       'oga'   => array('audio/ogg'),
+       'ogg'   => array('application/ogg'),
+       'ogv'   => array('video/ogg'),
+       'otg'   => array('application/vnd.oasis.opendocument.graphics-template'),
+       'oth'   => array('application/vnd.oasis.opendocument.web'),
+       'otp'   => array('application/vnd.oasis.opendocument.presentation-template'),
+       'ots'   => array('application/vnd.oasis.opendocument.spreadsheet-template'),
+       'ott'   => array('application/vnd.oasis.opendocument.template'),
+       'p'     => array('text/x-pascal'),
+       'pas'   => array('text/x-pascal'),
+       'patch' => array('text/x-diff'),
+       'pbm'   => array('image/x-portable-bitmap'),
+       'pdf'   => array('application/pdf', 'application/x-download'),
+       'php'   => array('application/x-httpd-php'),
+       'php3'  => array('application/x-httpd-php'),
+       'php4'  => array('application/x-httpd-php'),
+       'php5'  => array('application/x-httpd-php'),
+       'phps'  => array('application/x-httpd-php-source'),
+       'phtml' => array('application/x-httpd-php'),
+       'pl'    => array('text/x-perl'),
+       'pm'    => array('text/x-perl'),
+       'png'   => array('image/png', 'image/x-png'),
+       'po'    => array('text/x-gettext-translation'),
+       'pot'   => array('application/vnd.ms-powerpoint'),
+       'pps'   => array('application/vnd.ms-powerpoint'),
+       'ppt'   => array('application/powerpoint'),
+       'ps'    => array('application/postscript'),
+       'psd'   => array('application/x-photoshop', 'image/x-photoshop'),
+       'pub'   => array('application/x-mspublisher'),
+       'py'    => array('text/x-python'),
+       'qt'    => array('video/quicktime'),
+       'ra'    => array('audio/x-realaudio'),
+       'ram'   => array('audio/x-realaudio', 'audio/x-pn-realaudio'),
+       'rar'   => array('application/rar'),
+       'rgb'   => array('image/x-rgb'),
+       'rm'    => array('audio/x-pn-realaudio'),
+       'rpm'   => array('audio/x-pn-realaudio-plugin', 'application/x-redhat-package-manager'),
+       'rss'   => array('application/rss+xml'),
+       'rtf'   => array('text/rtf'),
+       'rtx'   => array('text/richtext'),
+       'rv'    => array('video/vnd.rn-realvideo'),
+       'sea'   => array('application/octet-stream'),
+       'sh'    => array('text/x-sh'),
+       'shtml' => array('text/html'),
+       'sit'   => array('application/x-stuffit'),
+       'smi'   => array('application/smil'),
+       'smil'  => array('application/smil'),
+       'so'    => array('application/octet-stream'),
+       'src'   => array('application/x-wais-source'),
+       'svg'   => array('image/svg+xml'),
+       'swf'   => array('application/x-shockwave-flash'),
+       't'     => array('application/x-troff'),
+       'tar'   => array('application/x-tar'),
+       'tcl'   => array('text/x-tcl'),
+       'tex'   => array('application/x-tex'),
+       'text'  => array('text/plain'),
+       'texti' => array('application/x-texinfo'),
+       'textinfo' => array('application/x-texinfo'),
+       'tgz'   => array('application/x-tar'),
+       'tif'   => array('image/tiff'),
+       'tiff'  => array('image/tiff'),
+       'torrent' => array('application/x-bittorrent'),
+       'tr'    => array('application/x-troff'),
+       'tsv'   => array('text/tab-separated-values'),
+       'txt'   => array('text/plain'),
+       'wav'   => array('audio/x-wav'),
+       'wax'   => array('audio/x-ms-wax'),
+       'wbxml' => array('application/wbxml'),
+       'wm'    => array('video/x-ms-wm'),
+       'wma'   => array('audio/x-ms-wma'),
+       'wmd'   => array('application/x-ms-wmd'),
+       'wmlc'  => array('application/wmlc'),
+       'wmv'   => array('video/x-ms-wmv', 'application/octet-stream'),
+       'wmx'   => array('video/x-ms-wmx'),
+       'wmz'   => array('application/x-ms-wmz'),
+       'word'  => array('application/msword', 'application/octet-stream'),
+       'wp5'   => array('application/wordperfect5.1'),
+       'wpd'   => array('application/vnd.wordperfect'),
+       'wvx'   => array('video/x-ms-wvx'),
+       'xbm'   => array('image/x-xbitmap'),
+       'xcf'   => array('image/xcf'),
+       'xhtml' => array('application/xhtml+xml'),
+       'xht'   => array('application/xhtml+xml'),
+       'xl'    => array('application/excel', 'application/vnd.ms-excel'),
+       'xla'   => array('application/excel', 'application/vnd.ms-excel'),
+       'xlc'   => array('application/excel', 'application/vnd.ms-excel'),
+       'xlm'   => array('application/excel', 'application/vnd.ms-excel'),
+       'xls'   => array('application/excel', 'application/vnd.ms-excel'),
+       'xlt'   => array('application/excel', 'application/vnd.ms-excel'),
+       'xml'   => array('text/xml'),
+       'xof'   => array('x-world/x-vrml'),
+       'xpm'   => array('image/x-xpixmap'),
+       'xsl'   => array('text/xml'),
+       'xvid'  => array('video/x-xvid'),
+       'xwd'   => array('image/x-xwindowdump'),
+       'z'     => array('application/x-compress'),
+       'zip'   => array('application/x-zip', 'application/zip', 'application/x-zip-compressed')
+);
diff --git a/Server/system/config/pagination.php b/Server/system/config/pagination.php
new file mode 100644 (file)
index 0000000..808fc31
--- /dev/null
@@ -0,0 +1,25 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Pagination
+ *
+ * Pagination configuration is defined in groups which allows you to easily switch
+ * between different pagination settings for different website sections.
+ * Note: all groups inherit and overwrite the default group.
+ *
+ * Group Options:
+ *  directory      - Views folder in which your pagination style templates reside
+ *  style          - Pagination style template (matches view filename)
+ *  uri_segment    - URI segment (int or 'label') in which the current page number can be found
+ *  query_string   - Alternative to uri_segment: query string key that contains the page number
+ *  items_per_page - Number of items to display per page
+ *  auto_hide      - Automatically hides pagination for single pages
+ */
+$config['default'] = array
+(
+       'directory'      => 'pagination',
+       'style'          => 'classic',
+       'uri_segment'    => 3,
+       'query_string'   => '',
+       'items_per_page' => 20,
+       'auto_hide'      => FALSE,
+);
diff --git a/Server/system/config/profiler.php b/Server/system/config/profiler.php
new file mode 100644 (file)
index 0000000..98ab5a4
--- /dev/null
@@ -0,0 +1,8 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Profiler
+ *
+ * Array of section names to display in the Profiler, TRUE to display all of them.
+ * Built in sections are benchmarks, database, session, post and cookies, custom sections can be used too.
+ */
+$config['show'] = TRUE;
diff --git a/Server/system/config/routes.php b/Server/system/config/routes.php
new file mode 100644 (file)
index 0000000..c677fde
--- /dev/null
@@ -0,0 +1,7 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Core
+ *
+ * Sets the default route to "welcome"
+ */
+$config['_default'] = 'welcome';
diff --git a/Server/system/config/session.php b/Server/system/config/session.php
new file mode 100644 (file)
index 0000000..e287bae
--- /dev/null
@@ -0,0 +1,47 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package Session
+ *
+ * Session driver name.
+ */
+$config['driver'] = 'cookie';
+
+/**
+ * Session storage parameter, used by drivers.
+ */
+$config['storage'] = '';
+
+/**
+ * Session name.
+ * It must contain only alphanumeric characters and underscores. At least one letter must be present.
+ */
+$config['name'] = 'kohanasession';
+
+/**
+ * Session parameters to validate: user_agent, ip_address, expiration.
+ */
+$config['validate'] = array('user_agent');
+
+/**
+ * Enable or disable session encryption.
+ * Note: this has no effect on the native session driver.
+ * Note: the cookie driver always encrypts session data. Set to TRUE for stronger encryption.
+ */
+$config['encryption'] = FALSE;
+
+/**
+ * Session lifetime. Number of seconds that each session will last.
+ * A value of 0 will keep the session active until the browser is closed (with a limit of 24h).
+ */
+$config['expiration'] = 7200;
+
+/**
+ * Number of page loads before the session id is regenerated.
+ * A value of 0 will disable automatic session id regeneration.
+ */
+$config['regenerate'] = 3;
+
+/**
+ * Percentage probability that the gc (garbage collection) routine is started.
+ */
+$config['gc_probability'] = 2;
\ No newline at end of file
diff --git a/Server/system/config/sql_types.php b/Server/system/config/sql_types.php
new file mode 100644 (file)
index 0000000..4034c6f
--- /dev/null
@@ -0,0 +1,58 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Database
+ *
+ * SQL data types. If there are missing values, please report them:
+ *
+ * @link  http://trac.kohanaphp.com/newticket
+ */
+$config = array
+(
+       'tinyint'                       => array('type' => 'int', 'max' => 127),
+       'smallint'                      => array('type' => 'int', 'max' => 32767),
+       'mediumint'                     => array('type' => 'int', 'max' => 8388607),
+       'int'                           => array('type' => 'int', 'max' => 2147483647),
+       'integer'                       => array('type' => 'int', 'max' => 2147483647),
+       'bigint'                        => array('type' => 'int', 'max' => 9223372036854775807),
+       'float'                         => array('type' => 'float'),
+       'float unsigned'        => array('type' => 'float', 'min' => 0),
+       'boolean'                       => array('type' => 'boolean'),
+       'time'                          => array('type' => 'string', 'format' => '00:00:00'),
+       'time with time zone' => array('type' => 'string'),
+       'date'                          => array('type' => 'string', 'format' => '0000-00-00'),
+       'year'                          => array('type' => 'string', 'format' => '0000'),
+       'datetime'                      => array('type' => 'string', 'format' => '0000-00-00 00:00:00'),
+       'timestamp with time zone' => array('type' => 'string'),
+       'char'                          => array('type' => 'string', 'exact' => TRUE),
+       'binary'                        => array('type' => 'string', 'binary' => TRUE, 'exact' => TRUE),
+       'varchar'                       => array('type' => 'string'),
+       'varbinary'                     => array('type' => 'string', 'binary' => TRUE),
+       'blob'                          => array('type' => 'string', 'binary' => TRUE),
+       'text'                          => array('type' => 'string')
+);
+
+// DOUBLE
+$config['double'] = $config['double precision'] = $config['decimal'] = $config['real'] = $config['numeric'] = $config['float'];
+$config['double unsigned'] = $config['float unsigned'];
+
+// BIT
+$config['bit'] = $config['boolean'];
+
+// TIMESTAMP
+$config['timestamp'] = $config['timestamp without time zone'] = $config['datetime'];
+
+// ENUM
+$config['enum'] = $config['set'] = $config['varchar'];
+
+// TEXT
+$config['tinytext'] = $config['mediumtext'] = $config['longtext'] = $config['text'];
+
+// BLOB
+$config['tsvector'] = $config['tinyblob'] = $config['mediumblob'] = $config['longblob'] = $config['clob'] = $config['bytea'] = $config['blob'];
+
+// CHARACTER
+$config['character'] = $config['char'];
+$config['character varying'] = $config['varchar'];
+
+// TIME
+$config['time without time zone'] = $config['time'];
diff --git a/Server/system/config/upload.php b/Server/system/config/upload.php
new file mode 100644 (file)
index 0000000..df26a2d
--- /dev/null
@@ -0,0 +1,17 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Core
+ *
+ * This path is relative to your index file. Absolute paths are also supported.
+ */
+$config['directory'] = DOCROOT.'upload';
+
+/**
+ * Enable or disable directory creation.
+ */
+$config['create_directories'] = FALSE;
+
+/**
+ * Remove spaces from uploaded filenames.
+ */
+$config['remove_spaces'] = TRUE;
\ No newline at end of file
diff --git a/Server/system/config/user_agents.php b/Server/system/config/user_agents.php
new file mode 100644 (file)
index 0000000..c968aeb
--- /dev/null
@@ -0,0 +1,112 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Core
+ *
+ * This file contains four arrays of user agent data.  It is used by the
+ * User Agent library to help identify browser, platform, robot, and
+ * mobile device data. The array keys are used to identify the device
+ * and the array values are used to set the actual name of the item.
+ */
+$config['platform'] = array
+(
+       'windows nt 6.0' => 'Windows Vista',
+       'windows nt 5.2' => 'Windows 2003',
+       'windows nt 5.0' => 'Windows 2000',
+       'windows nt 5.1' => 'Windows XP',
+       'windows nt 4.0' => 'Windows NT',
+       'winnt4.0'       => 'Windows NT',
+       'winnt 4.0'      => 'Windows NT',
+       'winnt'          => 'Windows NT',
+       'windows 98'     => 'Windows 98',
+       'win98'          => 'Windows 98',
+       'windows 95'     => 'Windows 95',
+       'win95'          => 'Windows 95',
+       'windows'        => 'Unknown Windows OS',
+       'os x'           => 'Mac OS X',
+       'intel mac'      => 'Intel Mac',
+       'ppc mac'        => 'PowerPC Mac',
+       'powerpc'        => 'PowerPC',
+       'ppc'            => 'PowerPC',
+       'cygwin'         => 'Cygwin',
+       'linux'          => 'Linux',
+       'debian'         => 'Debian',
+       'openvms'        => 'OpenVMS',
+       'sunos'          => 'Sun Solaris',
+       'amiga'          => 'Amiga',
+       'beos'           => 'BeOS',
+       'apachebench'    => 'ApacheBench',
+       'freebsd'        => 'FreeBSD',
+       'netbsd'         => 'NetBSD',
+       'bsdi'           => 'BSDi',
+       'openbsd'        => 'OpenBSD',
+       'os/2'           => 'OS/2',
+       'warp'           => 'OS/2',
+       'aix'            => 'AIX',
+       'irix'           => 'Irix',
+       'osf'            => 'DEC OSF',
+       'hp-ux'          => 'HP-UX',
+       'hurd'           => 'GNU/Hurd',
+       'unix'           => 'Unknown Unix OS',
+);
+
+// The order of this array should NOT be changed. Many browsers return
+// multiple browser types so we want to identify the sub-type first.
+$config['browser'] = array
+(
+       'Opera'             => 'Opera',
+       'MSIE'              => 'Internet Explorer',
+       'Internet Explorer' => 'Internet Explorer',
+       'Shiira'            => 'Shiira',
+       'Firefox'           => 'Firefox',
+       'Chimera'           => 'Chimera',
+       'Phoenix'           => 'Phoenix',
+       'Firebird'          => 'Firebird',
+       'Camino'            => 'Camino',
+       'Netscape'          => 'Netscape',
+       'OmniWeb'           => 'OmniWeb',
+       'Chrome'            => 'Chrome',
+       'Safari'            => 'Safari',
+       'Konqueror'         => 'Konqueror',
+       'Epiphany'          => 'Epiphany',
+       'Galeon'            => 'Galeon',
+       'Mozilla'           => 'Mozilla',
+       'icab'              => 'iCab',
+       'lynx'              => 'Lynx',
+       'links'             => 'Links',
+       'hotjava'           => 'HotJava',
+       'amaya'             => 'Amaya',
+       'IBrowse'           => 'IBrowse',
+);
+
+$config['mobile'] = array
+(
+       'mobileexplorer' => 'Mobile Explorer',
+       'openwave'       => 'Open Wave',
+       'opera mini'     => 'Opera Mini',
+       'operamini'      => 'Opera Mini',
+       'elaine'         => 'Palm',
+       'palmsource'     => 'Palm',
+       'digital paths'  => 'Palm',
+       'avantgo'        => 'Avantgo',
+       'xiino'          => 'Xiino',
+       'palmscape'      => 'Palmscape',
+       'nokia'          => 'Nokia',
+       'ericsson'       => 'Ericsson',
+       'blackBerry'     => 'BlackBerry',
+       'motorola'       => 'Motorola',
+       'iphone'         => 'iPhone',
+       'android'        => 'Android',
+);
+
+// There are hundreds of bots but these are the most common.
+$config['robot'] = array
+(
+       'googlebot'   => 'Googlebot',
+       'msnbot'      => 'MSNBot',
+       'slurp'       => 'Inktomi Slurp',
+       'yahoo'       => 'Yahoo',
+       'askjeeves'   => 'AskJeeves',
+       'fastcrawler' => 'FastCrawler',
+       'infoseek'    => 'InfoSeek Robot 1.0',
+       'lycos'       => 'Lycos',
+);
\ No newline at end of file
diff --git a/Server/system/config/view.php b/Server/system/config/view.php
new file mode 100644 (file)
index 0000000..6bed22e
--- /dev/null
@@ -0,0 +1,17 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * @package  Core
+ *
+ * Allowed non-php view types. Most file extensions are supported.
+ */
+$config['allowed_filetypes'] = array
+(
+       'gif',
+       'jpg', 'jpeg',
+       'png',
+       'tif', 'tiff',
+       'swf',
+       'htm', 'html',
+       'css',
+       'js'
+);
diff --git a/Server/system/controllers/captcha.php b/Server/system/controllers/captcha.php
new file mode 100644 (file)
index 0000000..a689e69
--- /dev/null
@@ -0,0 +1,23 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Outputs the dynamic Captcha resource.
+ * Usage: Call the Captcha controller from a view, e.g.
+ *        <img src="<?php echo url::site('captcha') ?>" />
+ *
+ * $Id: captcha.php 3769 2008-12-15 00:48:56Z zombor $
+ *
+ * @package    Captcha
+ * @author     Kohana Team
+ * @copyright  (c) 2007-2008 Kohana Team
+ * @license    http://kohanaphp.com/license.html
+ */
+class Captcha_Controller extends Controller {
+
+       public function __call($method, $args)
+       {
+               // Output the Captcha challenge resource (no html)
+               // Pull the config group name from the URL
+               Captcha::factory($this->uri->segment(2))->render(FALSE);
+       }
+
+} // End Captcha_Controller
\ No newline at end of file
diff --git a/Server/system/controllers/template.php b/Server/system/controllers/template.php
new file mode 100644 (file)
index 0000000..34d1a22
--- /dev/null
@@ -0,0 +1,54 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Allows a template to be automatically loaded and displayed. Display can be
+ * dynamically turned off in the controller methods, and the template file
+ * can be overloaded.
+ *
+ * To use it, declare your controller to extend this class:
+ * `class Your_Controller extends Template_Controller`
+ *
+ * $Id: template.php 3769 2008-12-15 00:48:56Z zombor $
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007-2008 Kohana Team
+ * @license    http://kohanaphp.com/license.html
+ */
+abstract class Template_Controller extends Controller {
+
+       // Template view name
+       public $template = 'template';
+
+       // Default to do auto-rendering
+       public $auto_render = TRUE;
+
+       /**
+        * Template loading and setup routine.
+        */
+       public function __construct()
+       {
+               parent::__construct();
+
+               // Load the template
+               $this->template = new View($this->template);
+
+               if ($this->auto_render == TRUE)
+               {
+                       // Render the template immediately after the controller method
+                       Event::add('system.post_controller', array($this, '_render'));
+               }
+       }
+
+       /**
+        * Render the loaded template.
+        */
+       public function _render()
+       {
+               if ($this->auto_render == TRUE)
+               {
+                       // Render the template when the class is destroyed
+                       $this->template->render(TRUE);
+               }
+       }
+
+} // End Template_Controller
\ No newline at end of file
diff --git a/Server/system/core/Benchmark.php b/Server/system/core/Benchmark.php
new file mode 100644 (file)
index 0000000..ce230f1
--- /dev/null
@@ -0,0 +1,125 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Simple benchmarking.
+ *
+ * $Id: Benchmark.php 4149 2009-04-01 13:32:50Z Shadowhand $
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @license    http://kohanaphp.com/license.html
+ */
+final class Benchmark {
+
+       // Benchmark timestamps
+       private static $marks;
+
+       /**
+        * Set a benchmark start point.
+        *
+        * @param   string  benchmark name
+        * @return  void
+        */
+       public static function start($name)
+       {
+               if ( ! isset(self::$marks[$name]))
+               {
+                       self::$marks[$name] = array();
+               }
+
+               $mark = array
+               (
+                       'start'        => microtime(TRUE),
+                       'stop'         => FALSE,
+                       'memory_start' => self::memory_usage(),
+                       'memory_stop'  => FALSE
+               );
+
+               array_unshift(self::$marks[$name], $mark);
+       }
+
+       /**
+        * Set a benchmark stop point.
+        *
+        * @param   string  benchmark name
+        * @return  void
+        */
+       public static function stop($name)
+       {
+               if (isset(self::$marks[$name]) AND self::$marks[$name][0]['stop'] === FALSE)
+               {
+                       self::$marks[$name][0]['stop'] = microtime(TRUE);
+                       self::$marks[$name][0]['memory_stop'] = self::memory_usage();
+               }
+       }
+
+       /**
+        * Get the elapsed time between a start and stop.
+        *
+        * @param   string   benchmark name, TRUE for all
+        * @param   integer  number of decimal places to count to
+        * @return  array
+        */
+       public static function get($name, $decimals = 4)
+       {
+               if ($name === TRUE)
+               {
+                       $times = array();
+                       $names = array_keys(self::$marks);
+
+                       foreach ($names as $name)
+                       {
+                               // Get each mark recursively
+                               $times[$name] = self::get($name, $decimals);
+                       }
+
+                       // Return the array
+                       return $times;
+               }
+
+               if ( ! isset(self::$marks[$name]))
+                       return FALSE;
+
+               if (self::$marks[$name][0]['stop'] === FALSE)
+               {
+                       // Stop the benchmark to prevent mis-matched results
+                       self::stop($name);
+               }
+
+               // Return a string version of the time between the start and stop points
+               // Properly reading a float requires using number_format or sprintf
+               $time = $memory = 0;
+               for ($i = 0; $i < count(self::$marks[$name]); $i++)
+               {
+                       $time += self::$marks[$name][$i]['stop'] - self::$marks[$name][$i]['start'];
+                       $memory += self::$marks[$name][$i]['memory_stop'] - self::$marks[$name][$i]['memory_start'];
+               }
+
+               return array
+               (
+                       'time'   => number_format($time, $decimals),
+                       'memory' => $memory,
+                       'count'  => count(self::$marks[$name])
+               );
+       }
+
+       /**
+        * Returns the current memory usage. This is only possible if the
+        * memory_get_usage function is supported in PHP.
+        *
+        * @return  integer
+        */
+       private static function memory_usage()
+       {
+               static $func;
+
+               if ($func === NULL)
+               {
+                       // Test if memory usage can be seen
+                       $func = function_exists('memory_get_usage');
+               }
+
+               return $func ? memory_get_usage() : 0;
+       }
+
+} // End Benchmark
diff --git a/Server/system/core/Bootstrap.php b/Server/system/core/Bootstrap.php
new file mode 100644 (file)
index 0000000..1334190
--- /dev/null
@@ -0,0 +1,58 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Kohana process control file, loaded by the front controller.
+ * 
+ * $Id: Bootstrap.php 4409 2009-06-06 00:48:26Z zombor $
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @license    http://kohanaphp.com/license.html
+ */
+
+define('KOHANA_VERSION',  '2.3.4');
+define('KOHANA_CODENAME', 'buteo regalis');
+
+// Test of Kohana is running in Windows
+define('KOHANA_IS_WIN', DIRECTORY_SEPARATOR === '\\');
+
+// Kohana benchmarks are prefixed to prevent collisions
+define('SYSTEM_BENCHMARK', 'system_benchmark');
+
+// Load benchmarking support
+require SYSPATH.'core/Benchmark'.EXT;
+
+// Start total_execution
+Benchmark::start(SYSTEM_BENCHMARK.'_total_execution');
+
+// Start kohana_loading
+Benchmark::start(SYSTEM_BENCHMARK.'_kohana_loading');
+
+// Load core files
+require SYSPATH.'core/utf8'.EXT;
+require SYSPATH.'core/Event'.EXT;
+require SYSPATH.'core/Kohana'.EXT;
+
+// Prepare the environment
+Kohana::setup();
+
+// End kohana_loading
+Benchmark::stop(SYSTEM_BENCHMARK.'_kohana_loading');
+
+// Start system_initialization
+Benchmark::start(SYSTEM_BENCHMARK.'_system_initialization');
+
+// Prepare the system
+Event::run('system.ready');
+
+// Determine routing
+Event::run('system.routing');
+
+// End system_initialization
+Benchmark::stop(SYSTEM_BENCHMARK.'_system_initialization');
+
+// Make the magic happen!
+Event::run('system.execute');
+
+// Clean up and exit
+Event::run('system.shutdown');
diff --git a/Server/system/core/Event.php b/Server/system/core/Event.php
new file mode 100644 (file)
index 0000000..06468a8
--- /dev/null
@@ -0,0 +1,232 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Process queuing/execution class. Allows an unlimited number of callbacks
+ * to be added to 'events'. Events can be run multiple times, and can also
+ * process event-specific data. By default, Kohana has several system events.
+ *
+ * $Id: Event.php 4390 2009-06-04 03:05:36Z zombor $
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @license    http://kohanaphp.com/license.html
+ * @link       http://docs.kohanaphp.com/general/events
+ */
+final class Event {
+
+       // Event callbacks
+       private static $events = array();
+
+       // Cache of events that have been run
+       private static $has_run = array();
+
+       // Data that can be processed during events
+       public static $data;
+
+       /**
+        * Add a callback to an event queue.
+        *
+        * @param   string   event name
+        * @param   array    http://php.net/callback
+        * @return  boolean
+        */
+       public static function add($name, $callback)
+       {
+               if ( ! isset(self::$events[$name]))
+               {
+                       // Create an empty event if it is not yet defined
+                       self::$events[$name] = array();
+               }
+               elseif (in_array($callback, self::$events[$name], TRUE))
+               {
+                       // The event already exists
+                       return FALSE;
+               }
+
+               // Add the event
+               self::$events[$name][] = $callback;
+
+               return TRUE;
+       }
+
+       /**
+        * Add a callback to an event queue, before a given event.
+        *
+        * @param   string   event name
+        * @param   array    existing event callback
+        * @param   array    event callback
+        * @return  boolean
+        */
+       public static function add_before($name, $existing, $callback)
+       {
+               if (empty(self::$events[$name]) OR ($key = array_search($existing, self::$events[$name])) === FALSE)
+               {
+                       // Just add the event if there are no events
+                       return self::add($name, $callback);
+               }
+               else
+               {
+                       // Insert the event immediately before the existing event
+                       return self::insert_event($name, $key, $callback);
+               }
+       }
+
+       /**
+        * Add a callback to an event queue, after a given event.
+        *
+        * @param   string   event name
+        * @param   array    existing event callback
+        * @param   array    event callback
+        * @return  boolean
+        */
+       public static function add_after($name, $existing, $callback)
+       {
+               if (empty(self::$events[$name]) OR ($key = array_search($existing, self::$events[$name])) === FALSE)
+               {
+                       // Just add the event if there are no events
+                       return self::add($name, $callback);
+               }
+               else
+               {
+                       // Insert the event immediately after the existing event
+                       return self::insert_event($name, $key + 1, $callback);
+               }
+       }
+
+       /**
+        * Inserts a new event at a specfic key location.
+        *
+        * @param   string   event name
+        * @param   integer  key to insert new event at
+        * @param   array    event callback
+        * @return  void
+        */
+       private static function insert_event($name, $key, $callback)
+       {
+               if (in_array($callback, self::$events[$name], TRUE))
+                       return FALSE;
+
+               // Add the new event at the given key location
+               self::$events[$name] = array_merge
+               (
+                       // Events before the key
+                       array_slice(self::$events[$name], 0, $key),
+                       // New event callback
+                       array($callback),
+                       // Events after the key
+                       array_slice(self::$events[$name], $key)
+               );
+
+               return TRUE;
+       }
+
+       /**
+        * Replaces an event with another event.
+        *
+        * @param   string   event name
+        * @param   array    event to replace
+        * @param   array    new callback
+        * @return  boolean
+        */
+       public static function replace($name, $existing, $callback)
+       {
+               if (empty(self::$events[$name]) OR ($key = array_search($existing, self::$events[$name], TRUE)) === FALSE)
+                       return FALSE;
+
+               if ( ! in_array($callback, self::$events[$name], TRUE))
+               {
+                       // Replace the exisiting event with the new event
+                       self::$events[$name][$key] = $callback;
+               }
+               else
+               {
+                       // Remove the existing event from the queue
+                       unset(self::$events[$name][$key]);
+
+                       // Reset the array so the keys are ordered properly
+                       self::$events[$name] = array_values(self::$events[$name]);
+               }
+
+               return TRUE;
+       }
+
+       /**
+        * Get all callbacks for an event.
+        *
+        * @param   string  event name
+        * @return  array
+        */
+       public static function get($name)
+       {
+               return empty(self::$events[$name]) ? array() : self::$events[$name];
+       }
+
+       /**
+        * Clear some or all callbacks from an event.
+        *
+        * @param   string  event name
+        * @param   array   specific callback to remove, FALSE for all callbacks
+        * @return  void
+        */
+       public static function clear($name, $callback = FALSE)
+       {
+               if ($callback === FALSE)
+               {
+                       self::$events[$name] = array();
+               }
+               elseif (isset(self::$events[$name]))
+               {
+                       // Loop through each of the event callbacks and compare it to the
+                       // callback requested for removal. The callback is removed if it
+                       // matches.
+                       foreach (self::$events[$name] as $i => $event_callback)
+                       {
+                               if ($callback === $event_callback)
+                               {
+                                       unset(self::$events[$name][$i]);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Execute all of the callbacks attached to an event.
+        *
+        * @param   string   event name
+        * @param   array    data can be processed as Event::$data by the callbacks
+        * @return  void
+        */
+       public static function run($name, & $data = NULL)
+       {
+               if ( ! empty(self::$events[$name]))
+               {
+                       // So callbacks can access Event::$data
+                       self::$data =& $data;
+                       $callbacks  =  self::get($name);
+
+                       foreach ($callbacks as $callback)
+                       {
+                               call_user_func($callback);
+                       }
+
+                       // Do this to prevent data from getting 'stuck'
+                       $clear_data = '';
+                       self::$data =& $clear_data;
+               }
+
+               // The event has been run!
+               self::$has_run[$name] = $name;
+       }
+
+       /**
+        * Check if a given event has been run.
+        *
+        * @param   string   event name
+        * @return  boolean
+        */
+       public static function has_run($name)
+       {
+               return isset(self::$has_run[$name]);
+       }
+
+} // End Event
\ No newline at end of file
diff --git a/Server/system/core/Kohana.php b/Server/system/core/Kohana.php
new file mode 100644 (file)
index 0000000..c934b12
--- /dev/null
@@ -0,0 +1,1788 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Provides Kohana-specific helper functions. This is where the magic happens!
+ *
+ * $Id: Kohana.php 4372 2009-05-28 17:00:34Z ixmatus $
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007-2008 Kohana Team
+ * @license    http://kohanaphp.com/license.html
+ */
+final class Kohana {
+
+       // The singleton instance of the controller
+       public static $instance;
+
+       // Output buffering level
+       private static $buffer_level;
+
+       // Will be set to TRUE when an exception is caught
+       public static $has_error = FALSE;
+
+       // The final output that will displayed by Kohana
+       public static $output = '';
+
+       // The current user agent
+       public static $user_agent;
+
+       // The current locale
+       public static $locale;
+
+       // Configuration
+       private static $configuration;
+
+       // Include paths
+       private static $include_paths;
+
+       // Logged messages
+       private static $log;
+
+       // Cache lifetime
+       private static $cache_lifetime;
+
+       // Log levels
+       private static $log_levels = array
+       (
+               'error' => 1,
+               'alert' => 2,
+               'info'  => 3,
+               'debug' => 4,
+       );
+
+       // Internal caches and write status
+       private static $internal_cache = array();
+       private static $write_cache;
+       private static $internal_cache_path;
+       private static $internal_cache_key;
+       private static $internal_cache_encrypt;
+
+       /**
+        * Sets up the PHP environment. Adds error/exception handling, output
+        * buffering, and adds an auto-loading method for loading classes.
+        *
+        * This method is run immediately when this file is loaded, and is
+        * benchmarked as environment_setup.
+        *
+        * For security, this function also destroys the $_REQUEST global variable.
+        * Using the proper global (GET, POST, COOKIE, etc) is inherently more secure.
+        * The recommended way to fetch a global variable is using the Input library.
+        * @see http://www.php.net/globals
+        *
+        * @return  void
+        */
+       public static function setup()
+       {
+               static $run;
+
+               // This function can only be run once
+               if ($run === TRUE)
+                       return;
+
+               // Start the environment setup benchmark
+               Benchmark::start(SYSTEM_BENCHMARK.'_environment_setup');
+
+               // Define Kohana error constant
+               define('E_KOHANA', 42);
+
+               // Define 404 error constant
+               define('E_PAGE_NOT_FOUND', 43);
+
+               // Define database error constant
+               define('E_DATABASE_ERROR', 44);
+
+               if (self::$cache_lifetime = self::config('core.internal_cache'))
+               {
+                       // Are we using encryption for caches?
+                       self::$internal_cache_encrypt   = self::config('core.internal_cache_encrypt');
+                       
+                       if(self::$internal_cache_encrypt===TRUE)
+                       {
+                               self::$internal_cache_key = self::config('core.internal_cache_key');
+                               
+                               // Be sure the key is of acceptable length for the mcrypt algorithm used
+                               self::$internal_cache_key = substr(self::$internal_cache_key, 0, 24);
+                       }
+                       
+                       // Set the directory to be used for the internal cache
+                       if ( ! self::$internal_cache_path = self::config('core.internal_cache_path'))
+                       {
+                               self::$internal_cache_path = APPPATH.'cache/';
+                       }
+
+                       // Load cached configuration and language files
+                       self::$internal_cache['configuration'] = self::cache('configuration', self::$cache_lifetime);
+                       self::$internal_cache['language']      = self::cache('language', self::$cache_lifetime);
+
+                       // Load cached file paths
+                       self::$internal_cache['find_file_paths'] = self::cache('find_file_paths', self::$cache_lifetime);
+
+                       // Enable cache saving
+                       Event::add('system.shutdown', array(__CLASS__, 'internal_cache_save'));
+               }
+
+               // Disable notices and "strict" errors
+               $ER = error_reporting(~E_NOTICE & ~E_STRICT);
+
+               // Set the user agent
+               self::$user_agent = ( ! empty($_SERVER['HTTP_USER_AGENT']) ? trim($_SERVER['HTTP_USER_AGENT']) : '');
+
+               if (function_exists('date_default_timezone_set'))
+               {
+                       $timezone = self::config('locale.timezone');
+
+                       // Set default timezone, due to increased validation of date settings
+                       // which cause massive amounts of E_NOTICEs to be generated in PHP 5.2+
+                       date_default_timezone_set(empty($timezone) ? date_default_timezone_get() : $timezone);
+               }
+
+               // Restore error reporting
+               error_reporting($ER);
+
+               // Start output buffering
+               ob_start(array(__CLASS__, 'output_buffer'));
+
+               // Save buffering level
+               self::$buffer_level = ob_get_level();
+
+               // Set autoloader
+               spl_autoload_register(array('Kohana', 'auto_load'));
+
+               // Set error handler
+               set_error_handler(array('Kohana', 'exception_handler'));
+
+               // Set exception handler
+               set_exception_handler(array('Kohana', 'exception_handler'));
+
+               // Send default text/html UTF-8 header
+               header('Content-Type: text/html; charset=UTF-8');
+
+               // Load locales
+               $locales = self::config('locale.language');
+
+               // Make first locale UTF-8
+               $locales[0] .= '.UTF-8';
+
+               // Set locale information
+               self::$locale = setlocale(LC_ALL, $locales);
+
+               if (self::$configuration['core']['log_threshold'] > 0)
+               {
+                       // Set the log directory
+                       self::log_directory(self::$configuration['core']['log_directory']);
+
+                       // Enable log writing at shutdown
+                       register_shutdown_function(array(__CLASS__, 'log_save'));
+               }
+
+               // Enable Kohana routing
+               Event::add('system.routing', array('Router', 'find_uri'));
+               Event::add('system.routing', array('Router', 'setup'));
+
+               // Enable Kohana controller initialization
+               Event::add('system.execute', array('Kohana', 'instance'));
+
+               // Enable Kohana 404 pages
+               Event::add('system.404', array('Kohana', 'show_404'));
+
+               // Enable Kohana output handling
+               Event::add('system.shutdown', array('Kohana', 'shutdown'));
+
+               if (self::config('core.enable_hooks') === TRUE)
+               {
+                       // Find all the hook files
+                       $hooks = self::list_files('hooks', TRUE);
+
+                       foreach ($hooks as $file)
+                       {
+                               // Load the hook
+                               include $file;
+                       }
+               }
+
+               // Setup is complete, prevent it from being run again
+               $run = TRUE;
+
+               // Stop the environment setup routine
+               Benchmark::stop(SYSTEM_BENCHMARK.'_environment_setup');
+       }
+
+       /**
+        * Loads the controller and initializes it. Runs the pre_controller,
+        * post_controller_constructor, and post_controller events. Triggers
+        * a system.404 event when the route cannot be mapped to a controller.
+        *
+        * This method is benchmarked as controller_setup and controller_execution.
+        *
+        * @return  object  instance of controller
+        */
+       public static function & instance()
+       {
+               if (self::$instance === NULL)
+               {
+                       Benchmark::start(SYSTEM_BENCHMARK.'_controller_setup');
+
+                       // Include the Controller file
+                       require Router::$controller_path;
+
+                       try
+                       {
+                               // Start validation of the controller
+                               $class = new ReflectionClass(ucfirst(Router::$controller).'_Controller');
+                       }
+                       catch (ReflectionException $e)
+                       {
+                               // Controller does not exist
+                               Event::run('system.404');
+                       }
+
+                       if ($class->isAbstract() OR (IN_PRODUCTION AND $class->getConstant('ALLOW_PRODUCTION') == FALSE))
+                       {
+                               // Controller is not allowed to run in production
+                               Event::run('system.404');
+                       }
+
+                       // Run system.pre_controller
+                       Event::run('system.pre_controller');
+
+                       // Create a new controller instance
+                       $controller = $class->newInstance();
+
+                       // Controller constructor has been executed
+                       Event::run('system.post_controller_constructor');
+
+                       try
+                       {
+                               // Load the controller method
+                               $method = $class->getMethod(Router::$method);
+
+                               // Method exists
+                               if (Router::$method[0] === '_')
+                               {
+                                       // Do not allow access to hidden methods
+                                       Event::run('system.404');
+                               }
+
+                               if ($method->isProtected() or $method->isPrivate())
+                               {
+                                       // Do not attempt to invoke protected methods
+                                       throw new ReflectionException('protected controller method');
+                               }
+
+                               // Default arguments
+                               $arguments = Router::$arguments;
+                       }
+                       catch (ReflectionException $e)
+                       {
+                               // Use __call instead
+                               $method = $class->getMethod('__call');
+
+                               // Use arguments in __call format
+                               $arguments = array(Router::$method, Router::$arguments);
+                       }
+
+                       // Stop the controller setup benchmark
+                       Benchmark::stop(SYSTEM_BENCHMARK.'_controller_setup');
+
+                       // Start the controller execution benchmark
+                       Benchmark::start(SYSTEM_BENCHMARK.'_controller_execution');
+
+                       // Execute the controller method
+                       $method->invokeArgs($controller, $arguments);
+
+                       // Controller method has been executed
+                       Event::run('system.post_controller');
+
+                       // Stop the controller execution benchmark
+                       Benchmark::stop(SYSTEM_BENCHMARK.'_controller_execution');
+               }
+
+               return self::$instance;
+       }
+
+       /**
+        * Get all include paths. APPPATH is the first path, followed by module
+        * paths in the order they are configured, follow by the SYSPATH.
+        *
+        * @param   boolean  re-process the include paths
+        * @return  array
+        */
+       public static function include_paths($process = FALSE)
+       {
+               if ($process === TRUE)
+               {
+                       // Add APPPATH as the first path
+                       self::$include_paths = array(APPPATH);
+
+                       foreach (self::$configuration['core']['modules'] as $path)
+                       {
+                               if ($path = str_replace('\\', '/', realpath($path)))
+                               {
+                                       // Add a valid path
+                                       self::$include_paths[] = $path.'/';
+                               }
+                       }
+
+                       // Add SYSPATH as the last path
+                       self::$include_paths[] = SYSPATH;
+               }
+
+               return self::$include_paths;
+       }
+
+       /**
+        * Get a config item or group.
+        *
+        * @param   string   item name
+        * @param   boolean  force a forward slash (/) at the end of the item
+        * @param   boolean  is the item required?
+        * @return  mixed
+        */
+       public static function config($key, $slash = FALSE, $required = TRUE)
+       {
+               if (self::$configuration === NULL)
+               {
+                       // Load core configuration
+                       self::$configuration['core'] = self::config_load('core');
+
+                       // Re-parse the include paths
+                       self::include_paths(TRUE);
+               }
+
+               // Get the group name from the key
+               $group = explode('.', $key, 2);
+               $group = $group[0];
+
+               if ( ! isset(self::$configuration[$group]))
+               {
+                       // Load the configuration group
+                       self::$configuration[$group] = self::config_load($group, $required);
+               }
+
+               // Get the value of the key string
+               $value = self::key_string(self::$configuration, $key);
+
+               if ($slash === TRUE AND is_string($value) AND $value !== '')
+               {
+                       // Force the value to end with "/"
+                       $value = rtrim($value, '/').'/';
+               }
+
+               return $value;
+       }
+
+       /**
+        * Sets a configuration item, if allowed.
+        *
+        * @param   string   config key string
+        * @param   string   config value
+        * @return  boolean
+        */
+       public static function config_set($key, $value)
+       {
+               // Do this to make sure that the config array is already loaded
+               self::config($key);
+
+               if (substr($key, 0, 7) === 'routes.')
+               {
+                       // Routes cannot contain sub keys due to possible dots in regex
+                       $keys = explode('.', $key, 2);
+               }
+               else
+               {
+                       // Convert dot-noted key string to an array
+                       $keys = explode('.', $key);
+               }
+
+               // Used for recursion
+               $conf =& self::$configuration;
+               $last = count($keys) - 1;
+
+               foreach ($keys as $i => $k)
+               {
+                       if ($i === $last)
+                       {
+                               $conf[$k] = $value;
+                       }
+                       else
+                       {
+                               $conf =& $conf[$k];
+                       }
+               }
+
+               if ($key === 'core.modules')
+               {
+                       // Reprocess the include paths
+                       self::include_paths(TRUE);
+               }
+
+               return TRUE;
+       }
+
+       /**
+        * Load a config file.
+        *
+        * @param   string   config filename, without extension
+        * @param   boolean  is the file required?
+        * @return  array
+        */
+       public static function config_load($name, $required = TRUE)
+       {
+               if ($name === 'core')
+               {
+                       // Load the application configuration file
+                       require APPPATH.'config/config'.EXT;
+
+                       if ( ! isset($config['site_domain']))
+                       {
+                               // Invalid config file
+                               die('Your Kohana application configuration file is not valid.');
+                       }
+
+                       return $config;
+               }
+
+               if (isset(self::$internal_cache['configuration'][$name]))
+                       return self::$internal_cache['configuration'][$name];
+
+               // Load matching configs
+               $configuration = array();
+
+               if ($files = self::find_file('config', $name, $required))
+               {
+                       foreach ($files as $file)
+                       {
+                               require $file;
+
+                               if (isset($config) AND is_array($config))
+                               {
+                                       // Merge in configuration
+                                       $configuration = array_merge($configuration, $config);
+                               }
+                       }
+               }
+
+               if ( ! isset(self::$write_cache['configuration']))
+               {
+                       // Cache has changed
+                       self::$write_cache['configuration'] = TRUE;
+               }
+
+               return self::$internal_cache['configuration'][$name] = $configuration;
+       }
+
+       /**
+        * Clears a config group from the cached configuration.
+        *
+        * @param   string  config group
+        * @return  void
+        */
+       public static function config_clear($group)
+       {
+               // Remove the group from config
+               unset(self::$configuration[$group], self::$internal_cache['configuration'][$group]);
+
+               if ( ! isset(self::$write_cache['configuration']))
+               {
+                       // Cache has changed
+                       self::$write_cache['configuration'] = TRUE;
+               }
+       }
+
+       /**
+        * Add a new message to the log.
+        *
+        * @param   string  type of message
+        * @param   string  message text
+        * @return  void
+        */
+       public static function log($type, $message)
+       {
+               if (self::$log_levels[$type] <= self::$configuration['core']['log_threshold'])
+               {
+                       $message = array(date('Y-m-d H:i:s P'), $type, $message);
+
+                       // Run the system.log event
+                       Event::run('system.log', $message);
+
+                       self::$log[] = $message;
+               }
+       }
+
+       /**
+        * Save all currently logged messages.
+        *
+        * @return  void
+        */
+       public static function log_save()
+       {
+               if (empty(self::$log) OR self::$configuration['core']['log_threshold'] < 1)
+                       return;
+
+               // Filename of the log
+               $filename = self::log_directory().date('Y-m-d').'.log'.EXT;
+
+               if ( ! is_file($filename))
+               {
+                       // Write the SYSPATH checking header
+                       file_put_contents($filename,
+                               '<?php defined(\'SYSPATH\') or die(\'No direct script access.\'); ?>'.PHP_EOL.PHP_EOL);
+
+                       // Prevent external writes
+                       chmod($filename, 0644);
+               }
+
+               // Messages to write
+               $messages = array();
+
+               do
+               {
+                       // Load the next mess
+                       list ($date, $type, $text) = array_shift(self::$log);
+
+                       // Add a new message line
+                       $messages[] = $date.' --- '.$type.': '.$text;
+               }
+               while ( ! empty(self::$log));
+
+               // Write messages to log file
+               file_put_contents($filename, implode(PHP_EOL, $messages).PHP_EOL, FILE_APPEND);
+       }
+
+       /**
+        * Get or set the logging directory.
+        *
+        * @param   string  new log directory
+        * @return  string
+        */
+       public static function log_directory($dir = NULL)
+       {
+               static $directory;
+
+               if ( ! empty($dir))
+               {
+                       // Get the directory path
+                       $dir = realpath($dir);
+
+                       if (is_dir($dir) AND is_writable($dir))
+                       {
+                               // Change the log directory
+                               $directory = str_replace('\\', '/', $dir).'/';
+                       }
+                       else
+                       {
+                               // Log directory is invalid
+                               throw new Kohana_Exception('core.log_dir_unwritable', $dir);
+                       }
+               }
+
+               return $directory;
+       }
+
+       /**
+        * Load data from a simple cache file. This should only be used internally,
+        * and is NOT a replacement for the Cache library.
+        *
+        * @param   string   unique name of cache
+        * @param   integer  expiration in seconds
+        * @return  mixed
+        */
+       public static function cache($name, $lifetime)
+       {
+               if ($lifetime > 0)
+               {
+                       $path = self::$internal_cache_path.'kohana_'.$name;
+
+                       if (is_file($path))
+                       {
+                               // Check the file modification time
+                               if ((time() - filemtime($path)) < $lifetime)
+                               {
+                                       // Cache is valid! Now, do we need to decrypt it?
+                                       if(self::$internal_cache_encrypt===TRUE)
+                                       {
+                                               $data           = file_get_contents($path);
+                                               
+                                               $iv_size        = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
+                                               $iv                     = mcrypt_create_iv($iv_size, MCRYPT_RAND);
+                                               
+                                               $decrypted_text = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, self::$internal_cache_key, $data, MCRYPT_MODE_ECB, $iv);
+                                               
+                                               $cache  = unserialize($decrypted_text);
+                                               
+                                               // If the key changed, delete the cache file
+                                               if(!$cache)
+                                                       unlink($path);
+
+                                               // If cache is false (as above) return NULL, otherwise, return the cache
+                                               return ($cache ? $cache : NULL);
+                                       }
+                                       else
+                                       {
+                                               return unserialize(file_get_contents($path));
+                                       }
+                               }
+                               else
+                               {
+                                       // Cache is invalid, delete it
+                                       unlink($path);
+                               }
+                       }
+               }
+
+               // No cache found
+               return NULL;
+       }
+
+       /**
+        * Save data to a simple cache file. This should only be used internally, and
+        * is NOT a replacement for the Cache library.
+        *
+        * @param   string   cache name
+        * @param   mixed    data to cache
+        * @param   integer  expiration in seconds
+        * @return  boolean
+        */
+       public static function cache_save($name, $data, $lifetime)
+       {
+               if ($lifetime < 1)
+                       return FALSE;
+
+               $path = self::$internal_cache_path.'kohana_'.$name;
+
+               if ($data === NULL)
+               {
+                       // Delete cache
+                       return (is_file($path) and unlink($path));
+               }
+               else
+               {
+                       // Using encryption? Encrypt the data when we write it
+                       if(self::$internal_cache_encrypt===TRUE)
+                       {
+                               // Encrypt and write data to cache file
+                               $iv_size        = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
+                               $iv                     = mcrypt_create_iv($iv_size, MCRYPT_RAND);
+                               
+                               // Serialize and encrypt!
+                               $encrypted_text = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, self::$internal_cache_key, serialize($data), MCRYPT_MODE_ECB, $iv);
+                               
+                               return (bool) file_put_contents($path, $encrypted_text);
+                       }
+                       else
+                       {
+                               // Write data to cache file
+                               return (bool) file_put_contents($path, serialize($data));
+                       }
+               }
+       }
+
+       /**
+        * Kohana output handler. Called during ob_clean, ob_flush, and their variants.
+        *
+        * @param   string  current output buffer
+        * @return  string
+        */
+       public static function output_buffer($output)
+       {
+               // Could be flushing, so send headers first
+               if ( ! Event::has_run('system.send_headers'))
+               {
+                       // Run the send_headers event
+                       Event::run('system.send_headers');
+               }
+               
+               self::$output   = $output;
+               
+               // Set and return the final output
+               return self::$output;
+       }
+
+       /**
+        * Closes all open output buffers, either by flushing or cleaning, and stores the Kohana
+        * output buffer for display during shutdown.
+        *
+        * @param   boolean  disable to clear buffers, rather than flushing
+        * @return  void
+        */
+       public static function close_buffers($flush = TRUE)
+       {
+               if (ob_get_level() >= self::$buffer_level)
+               {
+                       // Set the close function
+                       $close = ($flush === TRUE) ? 'ob_end_flush' : 'ob_end_clean';
+
+                       while (ob_get_level() > self::$buffer_level)
+                       {
+                               // Flush or clean the buffer
+                               $close();
+                       }
+
+                       // Store the Kohana output buffer
+                       ob_end_clean();
+               }
+       }
+
+       /**
+        * Triggers the shutdown of Kohana by closing the output buffer, runs the system.display event.
+        *
+        * @return  void
+        */
+       public static function shutdown()
+       {
+               // Close output buffers
+               self::close_buffers(TRUE);
+
+               // Run the output event
+               Event::run('system.display', self::$output);
+
+               // Render the final output
+               self::render(self::$output);
+       }
+
+       /**
+        * Inserts global Kohana variables into the generated output and prints it.
+        *
+        * @param   string  final output that will displayed
+        * @return  void
+        */
+       public static function render($output)
+       {
+               if (self::config('core.render_stats') === TRUE)
+               {
+                       // Fetch memory usage in MB
+                       $memory = function_exists('memory_get_usage') ? (memory_get_usage() / 1024 / 1024) : 0;
+
+                       // Fetch benchmark for page execution time
+                       $benchmark = Benchmark::get(SYSTEM_BENCHMARK.'_total_execution');
+
+                       // Replace the global template variables
+                       $output = str_replace(
+                               array
+                               (
+                                       '{kohana_version}',
+                                       '{kohana_codename}',
+                                       '{execution_time}',
+                                       '{memory_usage}',
+                                       '{included_files}',
+                               ),
+                               array
+                               (
+                                       KOHANA_VERSION,
+                                       KOHANA_CODENAME,
+                                       $benchmark['time'],
+                                       number_format($memory, 2).'MB',
+                                       count(get_included_files()),
+                               ),
+                               $output
+                       );
+               }
+
+               if ($level = self::config('core.output_compression') AND ini_get('output_handler') !== 'ob_gzhandler' AND (int) ini_get('zlib.output_compression') === 0)
+               {
+                       if ($level < 1 OR $level > 9)
+                       {
+                               // Normalize the level to be an integer between 1 and 9. This
+                               // step must be done to prevent gzencode from triggering an error
+                               $level = max(1, min($level, 9));
+                       }
+
+                       if (stripos(@$_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
+                       {
+                               $compress = 'gzip';
+                       }
+                       elseif (stripos(@$_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') !== FALSE)
+                       {
+                               $compress = 'deflate';
+                       }
+               }
+
+               if (isset($compress) AND $level > 0)
+               {
+                       switch ($compress)
+                       {
+                               case 'gzip':
+                                       // Compress output using gzip
+                                       $output = gzencode($output, $level);
+                               break;
+                               case 'deflate':
+                                       // Compress output using zlib (HTTP deflate)
+                                       $output = gzdeflate($output, $level);
+                               break;
+                       }
+
+                       // This header must be sent with compressed content to prevent
+                       // browser caches from breaking
+                       header('Vary: Accept-Encoding');
+
+                       // Send the content encoding header
+                       header('Content-Encoding: '.$compress);
+
+                       // Sending Content-Length in CGI can result in unexpected behavior
+                       if (stripos(PHP_SAPI, 'cgi') === FALSE)
+                       {
+                               header('Content-Length: '.strlen($output));
+                       }
+               }
+
+               echo $output;
+       }
+
+       /**
+        * Displays a 404 page.
+        *
+        * @throws  Kohana_404_Exception
+        * @param   string  URI of page
+        * @param   string  custom template
+        * @return  void
+        */
+       public static function show_404($page = FALSE, $template = FALSE)
+       {
+               throw new Kohana_404_Exception($page, $template);
+       }
+
+       /**
+        * Dual-purpose PHP error and exception handler. Uses the kohana_error_page
+        * view to display the message.
+        *
+        * @param   integer|object  exception object or error code
+        * @param   string          error message
+        * @param   string          filename
+        * @param   integer         line number
+        * @return  void
+        */
+       public static function exception_handler($exception, $message = NULL, $file = NULL, $line = NULL)
+       {
+               try
+               {
+                       // PHP errors have 5 args, always
+                       $PHP_ERROR = (func_num_args() === 5);
+       
+                       // Test to see if errors should be displayed
+                       if ($PHP_ERROR AND (error_reporting() & $exception) === 0)
+                               return;
+       
+                       // This is useful for hooks to determine if a page has an error
+                       self::$has_error = TRUE;
+       
+                       // Error handling will use exactly 5 args, every time
+                       if ($PHP_ERROR)
+                       {
+                               $code     = $exception;
+                               $type     = 'PHP Error';
+                               $template = 'kohana_error_page';
+                       }
+                       else
+                       {
+                               $code     = $exception->getCode();
+                               $type     = get_class($exception);
+                               $message  = $exception->getMessage();
+                               $file     = $exception->getFile();
+                               $line     = $exception->getLine();
+                               $template = ($exception instanceof Kohana_Exception) ? $exception->getTemplate() : 'kohana_error_page';
+                       }
+       
+                       if (is_numeric($code))
+                       {
+                               $codes = self::lang('errors');
+       
+                               if ( ! empty($codes[$code]))
+                               {
+                                       list($level, $error, $description) = $codes[$code];
+                               }
+                               else
+                               {
+                                       $level = 1;
+                                       $error = $PHP_ERROR ? 'Unknown Error' : get_class($exception);
+                                       $description = '';
+                               }
+                       }
+                       else
+                       {
+                               // Custom error message, this will never be logged
+                               $level = 5;
+                               $error = $code;
+                               $description = '';
+                       }
+       
+                       // Remove the DOCROOT from the path, as a security precaution
+                       $file = str_replace('\\', '/', realpath($file));
+                       $file = preg_replace('|^'.preg_quote(DOCROOT).'|', '', $file);
+       
+                       if ($level <= self::$configuration['core']['log_threshold'])
+                       {
+                               // Log the error
+                               self::log('error', self::lang('core.uncaught_exception', $type, $message, $file, $line));
+                       }
+       
+                       if ($PHP_ERROR)
+                       {
+                               $description = self::lang('errors.'.E_RECOVERABLE_ERROR);
+                               $description = is_array($description) ? $description[2] : '';
+       
+                               if ( ! headers_sent())
+                               {
+                                       // Send the 500 header
+                                       header('HTTP/1.1 500 Internal Server Error');
+                               }
+                       }
+                       else
+                       {
+                               if (method_exists($exception, 'sendHeaders') AND ! headers_sent())
+                               {
+                                       // Send the headers if they have not already been sent
+                                       $exception->sendHeaders();
+                               }
+                       }
+       
+                       // Close all output buffers except for Kohana
+                       while (ob_get_level() > self::$buffer_level)
+                       {
+                               ob_end_clean();
+                       }
+       
+                       // Test if display_errors is on
+                       if (self::$configuration['core']['display_errors'] === TRUE)
+                       {
+                               if ( ! IN_PRODUCTION AND $line != FALSE)
+                               {
+                                       // Remove the first entry of debug_backtrace(), it is the exception_handler call
+                                       $trace = $PHP_ERROR ? array_slice(debug_backtrace(), 1) : $exception->getTrace();
+       
+                                       // Beautify backtrace
+                                       $trace = self::backtrace($trace);
+                               }
+       
+                               // Load the error
+                               require self::find_file('views', empty($template) ? 'kohana_error_page' : $template);
+                       }
+                       else
+                       {
+                               // Get the i18n messages
+                               $error   = self::lang('core.generic_error');
+                               $message = self::lang('core.errors_disabled', url::site(), url::site(Router::$current_uri));
+       
+                               // Load the errors_disabled view
+                               require self::find_file('views', 'kohana_error_disabled');
+                       }
+       
+                       if ( ! Event::has_run('system.shutdown'))
+                       {
+                               // Run the shutdown even to ensure a clean exit
+                               Event::run('system.shutdown');
+                       }
+       
+                       // Turn off error reporting
+                       error_reporting(0);
+                       exit;
+               }
+               catch (Exception $e)
+               {
+                       if (IN_PRODUCTION)
+                       {
+                               die('Fatal Error');
+                       }
+                       else
+                       {
+                               die('Fatal Error: '.$e->getMessage().' File: '.$e->getFile().' Line: '.$e->getLine());
+                       }
+               }
+       }
+
+       /**
+        * Provides class auto-loading.
+        *
+        * @throws  Kohana_Exception
+        * @param   string  name of class
+        * @return  bool
+        */
+       public static function auto_load($class)
+       {
+               if (class_exists($class, FALSE))
+                       return TRUE;
+
+               if (($suffix = strrpos($class, '_')) > 0)
+               {
+                       // Find the class suffix
+                       $suffix = substr($class, $suffix + 1);
+               }
+               else
+               {
+                       // No suffix
+                       $suffix = FALSE;
+               }
+
+               if ($suffix === 'Core')
+               {
+                       $type = 'libraries';
+                       $file = substr($class, 0, -5);
+               }
+               elseif ($suffix === 'Controller')
+               {
+                       $type = 'controllers';
+                       // Lowercase filename
+                       $file = strtolower(substr($class, 0, -11));
+               }
+               elseif ($suffix === 'Model')
+               {
+                       $type = 'models';
+                       // Lowercase filename
+                       $file = strtolower(substr($class, 0, -6));
+               }
+               elseif ($suffix === 'Driver')
+               {
+                       $type = 'libraries/drivers';
+                       $file = str_replace('_', '/', substr($class, 0, -7));
+               }
+               else
+               {
+                       // This could be either a library or a helper, but libraries must
+                       // always be capitalized, so we check if the first character is
+                       // uppercase. If it is, we are loading a library, not a helper.
+                       $type = ($class[0] < 'a') ? 'libraries' : 'helpers';
+                       $file = $class;
+               }
+
+               if ($filename = self::find_file($type, $file))
+               {
+                       // Load the class
+                       require $filename;
+               }
+               else
+               {
+                       // The class could not be found
+                       return FALSE;
+               }
+
+               if ($filename = self::find_file($type, self::$configuration['core']['extension_prefix'].$class))
+               {
+                       // Load the class extension
+                       require $filename;
+               }
+               elseif ($suffix !== 'Core' AND class_exists($class.'_Core', FALSE))
+               {
+                       // Class extension to be evaluated
+                       $extension = 'class '.$class.' extends '.$class.'_Core { }';
+
+                       // Start class analysis
+                       $core = new ReflectionClass($class.'_Core');
+
+                       if ($core->isAbstract())
+                       {
+                               // Make the extension abstract
+                               $extension = 'abstract '.$extension;
+                       }
+
+                       // Transparent class extensions are handled using eval. This is
+                       // a disgusting hack, but it gets the job done.
+                       eval($extension);
+               }
+
+               return TRUE;
+       }
+
+       /**
+        * Find a resource file in a given directory. Files will be located according
+        * to the order of the include paths. Configuration and i18n files will be
+        * returned in reverse order.
+        *
+        * @throws  Kohana_Exception  if file is required and not found
+        * @param   string   directory to search in
+        * @param   string   filename to look for (without extension)
+        * @param   boolean  file required
+        * @param   string   file extension
+        * @return  array    if the type is config, i18n or l10n
+        * @return  string   if the file is found
+        * @return  FALSE    if the file is not found
+        */
+       public static function find_file($directory, $filename, $required = FALSE, $ext = FALSE)
+       {
+               // NOTE: This test MUST be not be a strict comparison (===), or empty
+               // extensions will be allowed!
+               if ($ext == '')
+               {
+                       // Use the default extension
+                       $ext = EXT;
+               }
+               else
+               {
+                       // Add a period before the extension
+                       $ext = '.'.$ext;
+               }
+
+               // Search path
+               $search = $directory.'/'.$filename.$ext;
+
+               if (isset(self::$internal_cache['find_file_paths'][$search]))
+                       return self::$internal_cache['find_file_paths'][$search];
+
+               // Load include paths
+               $paths = self::$include_paths;
+
+               // Nothing found, yet
+               $found = NULL;
+
+               if ($directory === 'config' OR $directory === 'i18n')
+               {
+                       // Search in reverse, for merging
+                       $paths = array_reverse($paths);
+
+                       foreach ($paths as $path)
+                       {
+                               if (is_file($path.$search))
+                               {
+                                       // A matching file has been found
+                                       $found[] = $path.$search;
+                               }
+                       }
+               }
+               else
+               {
+                       foreach ($paths as $path)
+                       {
+                               if (is_file($path.$search))
+                               {
+                                       // A matching file has been found
+                                       $found = $path.$search;
+
+                                       // Stop searching
+                                       break;
+                               }
+                       }
+               }
+
+               if ($found === NULL)
+               {
+                       if ($required === TRUE)
+                       {
+                               // Directory i18n key
+                               $directory = 'core.'.inflector::singular($directory);
+
+                               // If the file is required, throw an exception
+                               throw new Kohana_Exception('core.resource_not_found', self::lang($directory), $filename);
+                       }
+                       else
+                       {
+                               // Nothing was found, return FALSE
+                               $found = FALSE;
+                       }
+               }
+
+               if ( ! isset(self::$write_cache['find_file_paths']))
+               {
+                       // Write cache at shutdown
+                       self::$write_cache['find_file_paths'] = TRUE;
+               }
+
+               return self::$internal_cache['find_file_paths'][$search] = $found;
+       }
+
+       /**
+        * Lists all files and directories in a resource path.
+        *
+        * @param   string   directory to search
+        * @param   boolean  list all files to the maximum depth?
+        * @param   string   full path to search (used for recursion, *never* set this manually)
+        * @return  array    filenames and directories
+        */
+       public static function list_files($directory, $recursive = FALSE, $path = FALSE)
+       {
+               $files = array();
+
+               if ($path === FALSE)
+               {
+                       $paths = array_reverse(self::include_paths());
+
+                       foreach ($paths as $path)
+                       {
+                               // Recursively get and merge all files
+                               $files = array_merge($files, self::list_files($directory, $recursive, $path.$directory));
+                       }
+               }
+               else
+               {
+                       $path = rtrim($path, '/').'/';
+
+                       if (is_readable($path))
+                       {
+                               $items = (array) glob($path.'*');
+
+                               if ( ! empty($items))
+                               {
+                                       foreach ($items as $index => $item)
+                                       {
+                                               $files[] = $item = str_replace('\\', '/', $item);
+
+                                               // Handle recursion
+                                               if (is_dir($item) AND $recursive == TRUE)
+                                               {
+                                                       // Filename should only be the basename
+                                                       $item = pathinfo($item, PATHINFO_BASENAME);
+
+                                                       // Append sub-directory search
+                                                       $files = array_merge($files, self::list_files($directory, TRUE, $path.$item));
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               return $files;
+       }
+
+       /**
+        * Fetch an i18n language item.
+        *
+        * @param   string  language key to fetch
+        * @param   array   additional information to insert into the line
+        * @return  string  i18n language string, or the requested key if the i18n item is not found
+        */
+       public static function lang($key, $args = array())
+       {
+               // Extract the main group from the key
+               $group = explode('.', $key, 2);
+               $group = $group[0];
+
+               // Get locale name
+               $locale = self::config('locale.language.0');
+
+               if ( ! isset(self::$internal_cache['language'][$locale][$group]))
+               {
+                       // Messages for this group
+                       $messages = array();
+
+                       if ($files = self::find_file('i18n', $locale.'/'.$group))
+                       {
+                               foreach ($files as $file)
+                               {
+                                       include $file;
+
+                                       // Merge in configuration
+                                       if ( ! empty($lang) AND is_array($lang))
+                                       {
+                                               foreach ($lang as $k => $v)
+                                               {
+                                                       $messages[$k] = $v;
+                                               }
+                                       }
+                               }
+                       }
+
+                       if ( ! isset(self::$write_cache['language']))
+                       {
+                               // Write language cache
+                               self::$write_cache['language'] = TRUE;
+                       }
+
+                       self::$internal_cache['language'][$locale][$group] = $messages;
+               }
+
+               // Get the line from cache
+               $line = self::key_string(self::$internal_cache['language'][$locale], $key);
+
+               if ($line === NULL)
+               {
+                       self::log('error', 'Missing i18n entry '.$key.' for language '.$locale);
+
+                       // Return the key string as fallback
+                       return $key;
+               }
+
+               if (is_string($line) AND func_num_args() > 1)
+               {
+                       $args = array_slice(func_get_args(), 1);
+
+                       // Add the arguments into the line
+                       $line = vsprintf($line, is_array($args[0]) ? $args[0] : $args);
+               }
+
+               return $line;
+       }
+
+       /**
+        * Returns the value of a key, defined by a 'dot-noted' string, from an array.
+        *
+        * @param   array   array to search
+        * @param   string  dot-noted string: foo.bar.baz
+        * @return  string  if the key is found
+        * @return  void    if the key is not found
+        */
+       public static function key_string($array, $keys)
+       {
+               if (empty($array))
+                       return NULL;
+
+               // Prepare for loop
+               $keys = explode('.', $keys);
+
+               do
+               {
+                       // Get the next key
+                       $key = array_shift($keys);
+
+                       if (isset($array[$key]))
+                       {
+                               if (is_array($array[$key]) AND ! empty($keys))
+                               {
+                                       // Dig down to prepare the next loop
+                                       $array = $array[$key];
+                               }
+                               else
+                               {
+                                       // Requested key was found
+                                       return $array[$key];
+                               }
+                       }
+                       else
+                       {
+                               // Requested key is not set
+                               break;
+                       }
+               }
+               while ( ! empty($keys));
+
+               return NULL;
+       }
+
+       /**
+        * Sets values in an array by using a 'dot-noted' string.
+        *
+        * @param   array   array to set keys in (reference)
+        * @param   string  dot-noted string: foo.bar.baz
+        * @return  mixed   fill value for the key
+        * @return  void
+        */
+       public static function key_string_set( & $array, $keys, $fill = NULL)
+       {
+               if (is_object($array) AND ($array instanceof ArrayObject))
+               {
+                       // Copy the array
+                       $array_copy = $array->getArrayCopy();
+
+                       // Is an object
+                       $array_object = TRUE;
+               }
+               else
+               {
+                       if ( ! is_array($array))
+                       {
+                               // Must always be an array
+                               $array = (array) $array;
+                       }
+
+                       // Copy is a reference to the array
+                       $array_copy =& $array;
+               }
+
+               if (empty($keys))
+                       return $array;
+
+               // Create keys
+               $keys = explode('.', $keys);
+
+               // Create reference to the array
+               $row =& $array_copy;
+
+               for ($i = 0, $end = count($keys) - 1; $i <= $end; $i++)
+               {
+                       // Get the current key
+                       $key = $keys[$i];
+
+                       if ( ! isset($row[$key]))
+                       {
+                               if (isset($keys[$i + 1]))
+                               {
+                                       // Make the value an array
+                                       $row[$key] = array();
+                               }
+                               else
+                               {
+                                       // Add the fill key
+                                       $row[$key] = $fill;
+                               }
+                       }
+                       elseif (isset($keys[$i + 1]))
+                       {
+                               // Make the value an array
+                               $row[$key] = (array) $row[$key];
+                       }
+
+                       // Go down a level, creating a new row reference
+                       $row =& $row[$key];
+               }
+
+               if (isset($array_object))
+               {
+                       // Swap the array back in
+                       $array->exchangeArray($array_copy);
+               }
+       }
+
+       /**
+        * Retrieves current user agent information:
+        * keys:  browser, version, platform, mobile, robot, referrer, languages, charsets
+        * tests: is_browser, is_mobile, is_robot, accept_lang, accept_charset
+        *
+        * @param   string   key or test name
+        * @param   string   used with "accept" tests: user_agent(accept_lang, en)
+        * @return  array    languages and charsets
+        * @return  string   all other keys
+        * @return  boolean  all tests
+        */
+       public static function user_agent($key = 'agent', $compare = NULL)
+       {
+               static $info;
+
+               // Return the raw string
+               if ($key === 'agent')
+                       return self::$user_agent;
+
+               if ($info === NULL)
+               {
+                       // Parse the user agent and extract basic information
+                       $agents = self::config('user_agents');
+
+                       foreach ($agents as $type => $data)
+                       {
+                               foreach ($data as $agent => $name)
+                               {
+                                       if (stripos(self::$user_agent, $agent) !== FALSE)
+                                       {
+                                               if ($type === 'browser' AND preg_match('|'.preg_quote($agent).'[^0-9.]*+([0-9.][0-9.a-z]*)|i', self::$user_agent, $match))
+                                               {
+                                                       // Set the browser version
+                                                       $info['version'] = $match[1];
+                                               }
+
+                                               // Set the agent name
+                                               $info[$type] = $name;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               if (empty($info[$key]))
+               {
+                       switch ($key)
+                       {
+                               case 'is_robot':
+                               case 'is_browser':
+                               case 'is_mobile':
+                                       // A boolean result
+                                       $return = ! empty($info[substr($key, 3)]);
+                               break;
+                               case 'languages':
+                                       $return = array();
+                                       if ( ! empty($_SERVER['HTTP_ACCEPT_LANGUAGE']))
+                                       {
+                                               if (preg_match_all('/[-a-z]{2,}/', strtolower(trim($_SERVER['HTTP_ACCEPT_LANGUAGE'])), $matches))
+                                               {
+                                                       // Found a result
+                                                       $return = $matches[0];
+                                               }
+                                       }
+                               break;
+                               case 'charsets':
+                                       $return = array();
+                                       if ( ! empty($_SERVER['HTTP_ACCEPT_CHARSET']))
+                                       {
+                                               if (preg_match_all('/[-a-z0-9]{2,}/', strtolower(trim($_SERVER['HTTP_ACCEPT_CHARSET'])), $matches))
+                                               {
+                                                       // Found a result
+                                                       $return = $matches[0];
+                                               }
+                                       }
+                               break;
+                               case 'referrer':
+                                       if ( ! empty($_SERVER['HTTP_REFERER']))
+                                       {
+                                               // Found a result
+                                               $return = trim($_SERVER['HTTP_REFERER']);
+                                       }
+                               break;
+                       }
+
+                       // Cache the return value
+                       isset($return) and $info[$key] = $return;
+               }
+
+               if ( ! empty($compare))
+               {
+                       // The comparison must always be lowercase
+                       $compare = strtolower($compare);
+
+                       switch ($key)
+                       {
+                               case 'accept_lang':
+                                       // Check if the lange is accepted
+                                       return in_array($compare, self::user_agent('languages'));
+                               break;
+                               case 'accept_charset':
+                                       // Check if the charset is accepted
+                                       return in_array($compare, self::user_agent('charsets'));
+                               break;
+                               default:
+                                       // Invalid comparison
+                                       return FALSE;
+                               break;
+                       }
+               }
+
+               // Return the key, if set
+               return isset($info[$key]) ? $info[$key] : NULL;
+       }
+
+       /**
+        * Quick debugging of any variable. Any number of parameters can be set.
+        *
+        * @return  string
+        */
+       public static function debug()
+       {
+               if (func_num_args() === 0)
+                       return;
+
+               // Get params
+               $params = func_get_args();
+               $output = array();
+
+               foreach ($params as $var)
+               {
+                       $output[] = '<pre>('.gettype($var).') '.html::specialchars(print_r($var, TRUE)).'</pre>';
+               }
+
+               return implode("\n", $output);
+       }
+
+       /**
+        * Displays nice backtrace information.
+        * @see http://php.net/debug_backtrace
+        *
+        * @param   array   backtrace generated by an exception or debug_backtrace
+        * @return  string
+        */
+       public static function backtrace($trace)
+       {
+               if ( ! is_array($trace))
+                       return;
+
+               // Final output
+               $output = array();
+
+               foreach ($trace as $entry)
+               {
+                       $temp = '<li>';
+
+                       if (isset($entry['file']))
+                       {
+                               $temp .= self::lang('core.error_file_line', preg_replace('!^'.preg_quote(DOCROOT).'!', '', $entry['file']), $entry['line']);
+                       }
+
+                       $temp .= '<pre>';
+
+                       if (isset($entry['class']))
+                       {
+                               // Add class and call type
+                               $temp .= $entry['class'].$entry['type'];
+                       }
+
+                       // Add function
+                       $temp .= $entry['function'].'( ';
+
+                       // Add function args
+                       if (isset($entry['args']) AND is_array($entry['args']))
+                       {
+                               // Separator starts as nothing
+                               $sep = '';
+
+                               while ($arg = array_shift($entry['args']))
+                               {
+                                       if (is_string($arg) AND is_file($arg))
+                                       {
+                                               // Remove docroot from filename
+                                               $arg = preg_replace('!^'.preg_quote(DOCROOT).'!', '', $arg);
+                                       }
+
+                                       $temp .= $sep.html::specialchars(print_r($arg, TRUE));
+
+                                       // Change separator to a comma
+                                       $sep = ', ';
+                               }
+                       }
+
+                       $temp .= ' )</pre></li>';
+
+                       $output[] = $temp;
+               }
+
+               return '<ul class="backtrace">'.implode("\n", $output).'</ul>';
+       }
+
+       /**
+        * Saves the internal caches: configuration, include paths, etc.
+        *
+        * @return  boolean
+        */
+       public static function internal_cache_save()
+       {
+               if ( ! is_array(self::$write_cache))
+                       return FALSE;
+
+               // Get internal cache names
+               $caches = array_keys(self::$write_cache);
+
+               // Nothing written
+               $written = FALSE;
+
+               foreach ($caches as $cache)
+               {
+                       if (isset(self::$internal_cache[$cache]))
+                       {
+                               // Write the cache file
+                               self::cache_save($cache, self::$internal_cache[$cache], self::$configuration['core']['internal_cache']);
+
+                               // A cache has been written
+                               $written = TRUE;
+                       }
+               }
+
+               return $written;
+       }
+
+} // End Kohana
+
+/**
+ * Creates a generic i18n exception.
+ */
+class Kohana_Exception extends Exception {
+
+       // Template file
+       protected $template = 'kohana_error_page';
+
+       // Header
+       protected $header = FALSE;
+
+       // Error code
+       protected $code = E_KOHANA;
+
+       /**
+        * Set exception message.
+        *
+        * @param  string  i18n language key for the message
+        * @param  array   addition line parameters
+        */
+       public function __construct($error)
+       {
+               $args = array_slice(func_get_args(), 1);
+
+               // Fetch the error message
+               $message = Kohana::lang($error, $args);
+
+               if ($message === $error OR empty($message))
+               {
+                       // Unable to locate the message for the error
+                       $message = 'Unknown Exception: '.$error;
+               }
+
+               // Sets $this->message the proper way
+               parent::__construct($message);
+       }
+
+       /**
+        * Magic method for converting an object to a string.
+        *
+        * @return  string  i18n message
+        */
+       public function __toString()
+       {
+               return (string) $this->message;
+       }
+
+       /**
+        * Fetch the template name.
+        *
+        * @return  string
+        */
+       public function getTemplate()
+       {
+               return $this->template;
+       }
+
+       /**
+        * Sends an Internal Server Error header.
+        *
+        * @return  void
+        */
+       public function sendHeaders()
+       {
+               // Send the 500 header
+               header('HTTP/1.1 500 Internal Server Error');
+       }
+
+} // End Kohana Exception
+
+/**
+ * Creates a custom exception.
+ */
+class Kohana_User_Exception extends Kohana_Exception {
+
+       /**
+        * Set exception title and message.
+        *
+        * @param   string  exception title string
+        * @param   string  exception message string
+        * @param   string  custom error template
+        */
+       public function __construct($title, $message, $template = FALSE)
+       {
+               Exception::__construct($message);
+
+               $this->code = $title;
+
+               if ($template !== FALSE)
+               {
+                       $this->template = $template;
+               }
+       }
+
+} // End Kohana PHP Exception
+
+/**
+ * Creates a Page Not Found exception.
+ */
+class Kohana_404_Exception extends Kohana_Exception {
+
+       protected $code = E_PAGE_NOT_FOUND;
+
+       /**
+        * Set internal properties.
+        *
+        * @param  string  URL of page
+        * @param  string  custom error template
+        */
+       public function __construct($page = FALSE, $template = FALSE)
+       {
+               if ($page === FALSE)
+               {
+                       // Construct the page URI using Router properties
+                       $page = Router::$current_uri.Router::$url_suffix.Router::$query_string;
+               }
+
+               Exception::__construct(Kohana::lang('core.page_not_found', $page));
+
+               $this->template = $template;
+       }
+
+       /**
+        * Sends "File Not Found" headers, to emulate server behavior.
+        *
+        * @return void
+        */
+       public function sendHeaders()
+       {
+               // Send the 404 header
+               header('HTTP/1.1 404 File Not Found');
+       }
+
+} // End Kohana 404 Exception
diff --git a/Server/system/core/utf8.php b/Server/system/core/utf8.php
new file mode 100644 (file)
index 0000000..9f20f42
--- /dev/null
@@ -0,0 +1,743 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * A port of phputf8 to a unified file/class. Checks PHP status to ensure that
+ * UTF-8 support is available and normalize global variables to UTF-8. It also
+ * provides multi-byte aware replacement string functions.
+ *
+ * This file is licensed differently from the rest of Kohana. As a port of
+ * phputf8, which is LGPL software, this file is released under the LGPL.
+ *
+ * PCRE needs to be compiled with UTF-8 support (--enable-utf8).
+ * Support for Unicode properties is highly recommended (--enable-unicode-properties).
+ * @see http://php.net/manual/reference.pcre.pattern.modifiers.php
+ *
+ * UTF-8 conversion will be much more reliable if the iconv extension is loaded.
+ * @see http://php.net/iconv
+ *
+ * The mbstring extension is highly recommended, but must not be overloading
+ * string functions.
+ * @see http://php.net/mbstring
+ *
+ * $Id: utf8.php 3769 2008-12-15 00:48:56Z zombor $
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+
+if ( ! preg_match('/^.$/u', 'ñ'))
+{
+       trigger_error
+       (
+               '<a href="http://php.net/pcre">PCRE</a> has not been compiled with UTF-8 support. '.
+               'See <a href="http://php.net/manual/reference.pcre.pattern.modifiers.php">PCRE Pattern Modifiers</a> '.
+               'for more information. This application cannot be run without UTF-8 support.',
+               E_USER_ERROR
+       );
+}
+
+if ( ! extension_loaded('iconv'))
+{
+       trigger_error
+       (
+               'The <a href="http://php.net/iconv">iconv</a> extension is not loaded. '.
+               'Without iconv, strings cannot be properly translated to UTF-8 from user input. '.
+               'This application cannot be run without UTF-8 support.',
+               E_USER_ERROR
+       );
+}
+
+if (extension_loaded('mbstring') AND (ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING))
+{
+       trigger_error
+       (
+               'The <a href="http://php.net/mbstring">mbstring</a> extension is overloading PHP\'s native string functions. '.
+               'Disable this by setting mbstring.func_overload to 0, 1, 4 or 5 in php.ini or a .htaccess file.'.
+               'This application cannot be run without UTF-8 support.',
+               E_USER_ERROR
+       );
+}
+
+// Check PCRE support for Unicode properties such as \p and \X.
+$ER = error_reporting(0);
+define('PCRE_UNICODE_PROPERTIES', (bool) preg_match('/^\pL$/u', 'ñ'));
+error_reporting($ER);
+
+// SERVER_UTF8 ? use mb_* functions : use non-native functions
+if (extension_loaded('mbstring'))
+{
+       mb_internal_encoding('UTF-8');
+       define('SERVER_UTF8', TRUE);
+}
+else
+{
+       define('SERVER_UTF8', FALSE);
+}
+
+// Convert all global variables to UTF-8.
+$_GET    = utf8::clean($_GET);
+$_POST   = utf8::clean($_POST);
+$_COOKIE = utf8::clean($_COOKIE);
+$_SERVER = utf8::clean($_SERVER);
+
+if (PHP_SAPI == 'cli')
+{
+       // Convert command line arguments
+       $_SERVER['argv'] = utf8::clean($_SERVER['argv']);
+}
+
+final class utf8 {
+
+       // Called methods
+       static $called = array();
+
+       /**
+        * Recursively cleans arrays, objects, and strings. Removes ASCII control
+        * codes and converts to UTF-8 while silently discarding incompatible
+        * UTF-8 characters.
+        *
+        * @param   string  string to clean
+        * @return  string
+        */
+       public static function clean($str)
+       {
+               if (is_array($str) OR is_object($str))
+               {
+                       foreach ($str as $key => $val)
+                       {
+                               // Recursion!
+                               $str[self::clean($key)] = self::clean($val);
+                       }
+               }
+               elseif (is_string($str) AND $str !== '')
+               {
+                       // Remove control characters
+                       $str = self::strip_ascii_ctrl($str);
+
+                       if ( ! self::is_ascii($str))
+                       {
+                               // Disable notices
+                               $ER = error_reporting(~E_NOTICE);
+
+                               // iconv is expensive, so it is only used when needed
+                               $str = iconv('UTF-8', 'UTF-8//IGNORE', $str);
+
+                               // Turn notices back on
+                               error_reporting($ER);
+                       }
+               }
+
+               return $str;
+       }
+
+       /**
+        * Tests whether a string contains only 7bit ASCII bytes. This is used to
+        * determine when to use native functions or UTF-8 functions.
+        *
+        * @param   string  string to check
+        * @return  bool
+        */
+       public static function is_ascii($str)
+       {
+               return ! preg_match('/[^\x00-\x7F]/S', $str);
+       }
+
+       /**
+        * Strips out device control codes in the ASCII range.
+        *
+        * @param   string  string to clean
+        * @return  string
+        */
+       public static function strip_ascii_ctrl($str)
+       {
+               return preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S', '', $str);
+       }
+
+       /**
+        * Strips out all non-7bit ASCII bytes.
+        *
+        * @param   string  string to clean
+        * @return  string
+        */
+       public static function strip_non_ascii($str)
+       {
+               return preg_replace('/[^\x00-\x7F]+/S', '', $str);
+       }
+
+       /**
+        * Replaces special/accented UTF-8 characters by ASCII-7 'equivalents'.
+        *
+        * @author  Andreas Gohr <andi@splitbrain.org>
+        *
+        * @param   string   string to transliterate
+        * @param   integer  -1 lowercase only, +1 uppercase only, 0 both cases
+        * @return  string
+        */
+       public static function transliterate_to_ascii($str, $case = 0)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _transliterate_to_ascii($str, $case);
+       }
+
+       /**
+        * Returns the length of the given string.
+        * @see http://php.net/strlen
+        *
+        * @param   string   string being measured for length
+        * @return  integer
+        */
+       public static function strlen($str)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _strlen($str);
+       }
+
+       /**
+        * Finds position of first occurrence of a UTF-8 string.
+        * @see http://php.net/strlen
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   haystack
+        * @param   string   needle
+        * @param   integer  offset from which character in haystack to start searching
+        * @return  integer  position of needle
+        * @return  boolean  FALSE if the needle is not found
+        */
+       public static function strpos($str, $search, $offset = 0)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _strpos($str, $search, $offset);
+       }
+
+       /**
+        * Finds position of last occurrence of a char in a UTF-8 string.
+        * @see http://php.net/strrpos
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   haystack
+        * @param   string   needle
+        * @param   integer  offset from which character in haystack to start searching
+        * @return  integer  position of needle
+        * @return  boolean  FALSE if the needle is not found
+        */
+       public static function strrpos($str, $search, $offset = 0)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _strrpos($str, $search, $offset);
+       }
+
+       /**
+        * Returns part of a UTF-8 string.
+        * @see http://php.net/substr
+        *
+        * @author  Chris Smith <chris@jalakai.co.uk>
+        *
+        * @param   string   input string
+        * @param   integer  offset
+        * @param   integer  length limit
+        * @return  string
+        */
+       public static function substr($str, $offset, $length = NULL)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _substr($str, $offset, $length);
+       }
+
+       /**
+        * Replaces text within a portion of a UTF-8 string.
+        * @see http://php.net/substr_replace
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   input string
+        * @param   string   replacement string
+        * @param   integer  offset
+        * @return  string
+        */
+       public static function substr_replace($str, $replacement, $offset, $length = NULL)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _substr_replace($str, $replacement, $offset, $length);
+       }
+
+       /**
+        * Makes a UTF-8 string lowercase.
+        * @see http://php.net/strtolower
+        *
+        * @author  Andreas Gohr <andi@splitbrain.org>
+        *
+        * @param   string   mixed case string
+        * @return  string
+        */
+       public static function strtolower($str)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _strtolower($str);
+       }
+
+       /**
+        * Makes a UTF-8 string uppercase.
+        * @see http://php.net/strtoupper
+        *
+        * @author  Andreas Gohr <andi@splitbrain.org>
+        *
+        * @param   string   mixed case string
+        * @return  string
+        */
+       public static function strtoupper($str)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _strtoupper($str);
+       }
+
+       /**
+        * Makes a UTF-8 string's first character uppercase.
+        * @see http://php.net/ucfirst
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   mixed case string
+        * @return  string
+        */
+       public static function ucfirst($str)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _ucfirst($str);
+       }
+
+       /**
+        * Makes the first character of every word in a UTF-8 string uppercase.
+        * @see http://php.net/ucwords
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   mixed case string
+        * @return  string
+        */
+       public static function ucwords($str)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _ucwords($str);
+       }
+
+       /**
+        * Case-insensitive UTF-8 string comparison.
+        * @see http://php.net/strcasecmp
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   string to compare
+        * @param   string   string to compare
+        * @return  integer  less than 0 if str1 is less than str2
+        * @return  integer  greater than 0 if str1 is greater than str2
+        * @return  integer  0 if they are equal
+        */
+       public static function strcasecmp($str1, $str2)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _strcasecmp($str1, $str2);
+       }
+
+       /**
+        * Returns a string or an array with all occurrences of search in subject (ignoring case).
+        * replaced with the given replace value.
+        * @see     http://php.net/str_ireplace
+        *
+        * @note    It's not fast and gets slower if $search and/or $replace are arrays.
+        * @author  Harry Fuecks <hfuecks@gmail.com
+        *
+        * @param   string|array  text to replace
+        * @param   string|array  replacement text
+        * @param   string|array  subject text
+        * @param   integer       number of matched and replaced needles will be returned via this parameter which is passed by reference
+        * @return  string        if the input was a string
+        * @return  array         if the input was an array
+        */
+       public static function str_ireplace($search, $replace, $str, & $count = NULL)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _str_ireplace($search, $replace, $str, $count);
+       }
+
+       /**
+        * Case-insenstive UTF-8 version of strstr. Returns all of input string
+        * from the first occurrence of needle to the end.
+        * @see http://php.net/stristr
+        *
+        * @author Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   input string
+        * @param   string   needle
+        * @return  string   matched substring if found
+        * @return  boolean  FALSE if the substring was not found
+        */
+       public static function stristr($str, $search)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _stristr($str, $search);
+       }
+
+       /**
+        * Finds the length of the initial segment matching mask.
+        * @see http://php.net/strspn
+        *
+        * @author Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   input string
+        * @param   string   mask for search
+        * @param   integer  start position of the string to examine
+        * @param   integer  length of the string to examine
+        * @return  integer  length of the initial segment that contains characters in the mask
+        */
+       public static function strspn($str, $mask, $offset = NULL, $length = NULL)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _strspn($str, $mask, $offset, $length);
+       }
+
+       /**
+        * Finds the length of the initial segment not matching mask.
+        * @see http://php.net/strcspn
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   input string
+        * @param   string   mask for search
+        * @param   integer  start position of the string to examine
+        * @param   integer  length of the string to examine
+        * @return  integer  length of the initial segment that contains characters not in the mask
+        */
+       public static function strcspn($str, $mask, $offset = NULL, $length = NULL)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _strcspn($str, $mask, $offset, $length);
+       }
+
+       /**
+        * Pads a UTF-8 string to a certain length with another string.
+        * @see http://php.net/str_pad
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   input string
+        * @param   integer  desired string length after padding
+        * @param   string   string to use as padding
+        * @param   string   padding type: STR_PAD_RIGHT, STR_PAD_LEFT, or STR_PAD_BOTH
+        * @return  string
+        */
+       public static function str_pad($str, $final_str_length, $pad_str = ' ', $pad_type = STR_PAD_RIGHT)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _str_pad($str, $final_str_length, $pad_str, $pad_type);
+       }
+
+       /**
+        * Converts a UTF-8 string to an array.
+        * @see http://php.net/str_split
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   input string
+        * @param   integer  maximum length of each chunk
+        * @return  array
+        */
+       public static function str_split($str, $split_length = 1)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _str_split($str, $split_length);
+       }
+
+       /**
+        * Reverses a UTF-8 string.
+        * @see http://php.net/strrev
+        *
+        * @author  Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   string to be reversed
+        * @return  string
+        */
+       public static function strrev($str)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _strrev($str);
+       }
+
+       /**
+        * Strips whitespace (or other UTF-8 characters) from the beginning and
+        * end of a string.
+        * @see http://php.net/trim
+        *
+        * @author  Andreas Gohr <andi@splitbrain.org>
+        *
+        * @param   string   input string
+        * @param   string   string of characters to remove
+        * @return  string
+        */
+       public static function trim($str, $charlist = NULL)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _trim($str, $charlist);
+       }
+
+       /**
+        * Strips whitespace (or other UTF-8 characters) from the beginning of a string.
+        * @see http://php.net/ltrim
+        *
+        * @author  Andreas Gohr <andi@splitbrain.org>
+        *
+        * @param   string   input string
+        * @param   string   string of characters to remove
+        * @return  string
+        */
+       public static function ltrim($str, $charlist = NULL)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _ltrim($str, $charlist);
+       }
+
+       /**
+        * Strips whitespace (or other UTF-8 characters) from the end of a string.
+        * @see http://php.net/rtrim
+        *
+        * @author  Andreas Gohr <andi@splitbrain.org>
+        *
+        * @param   string   input string
+        * @param   string   string of characters to remove
+        * @return  string
+        */
+       public static function rtrim($str, $charlist = NULL)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _rtrim($str, $charlist);
+       }
+
+       /**
+        * Returns the unicode ordinal for a character.
+        * @see http://php.net/ord
+        *
+        * @author Harry Fuecks <hfuecks@gmail.com>
+        *
+        * @param   string   UTF-8 encoded character
+        * @return  integer
+        */
+       public static function ord($chr)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _ord($chr);
+       }
+
+       /**
+        * Takes an UTF-8 string and returns an array of ints representing the Unicode characters.
+        * Astral planes are supported i.e. the ints in the output can be > 0xFFFF.
+        * Occurrances of the BOM are ignored. Surrogates are not allowed.
+        *
+        * The Original Code is Mozilla Communicator client code.
+        * The Initial Developer of the Original Code is Netscape Communications Corporation.
+        * Portions created by the Initial Developer are Copyright (C) 1998 the Initial Developer.
+        * Ported to PHP by Henri Sivonen <hsivonen@iki.fi>, see http://hsivonen.iki.fi/php-utf8/.
+        * Slight modifications to fit with phputf8 library by Harry Fuecks <hfuecks@gmail.com>.
+        *
+        * @param   string   UTF-8 encoded string
+        * @return  array    unicode code points
+        * @return  boolean  FALSE if the string is invalid
+        */
+       public static function to_unicode($str)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _to_unicode($str);
+       }
+
+       /**
+        * Takes an array of ints representing the Unicode characters and returns a UTF-8 string.
+        * Astral planes are supported i.e. the ints in the input can be > 0xFFFF.
+        * Occurrances of the BOM are ignored. Surrogates are not allowed.
+        *
+        * The Original Code is Mozilla Communicator client code.
+        * The Initial Developer of the Original Code is Netscape Communications Corporation.
+        * Portions created by the Initial Developer are Copyright (C) 1998 the Initial Developer.
+        * Ported to PHP by Henri Sivonen <hsivonen@iki.fi>, see http://hsivonen.iki.fi/php-utf8/.
+        * Slight modifications to fit with phputf8 library by Harry Fuecks <hfuecks@gmail.com>.
+        *
+        * @param   array    unicode code points representing a string
+        * @return  string   utf8 string of characters
+        * @return  boolean  FALSE if a code point cannot be found
+        */
+       public static function from_unicode($arr)
+       {
+               if ( ! isset(self::$called[__FUNCTION__]))
+               {
+                       require SYSPATH.'core/utf8/'.__FUNCTION__.EXT;
+
+                       // Function has been called
+                       self::$called[__FUNCTION__] = TRUE;
+               }
+
+               return _from_unicode($arr);
+       }
+
+} // End utf8
\ No newline at end of file
diff --git a/Server/system/core/utf8/from_unicode.php b/Server/system/core/utf8/from_unicode.php
new file mode 100644 (file)
index 0000000..66c6742
--- /dev/null
@@ -0,0 +1,68 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::from_unicode
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _from_unicode($arr)
+{
+       ob_start();
+
+       $keys = array_keys($arr);
+
+       foreach ($keys as $k)
+       {
+               // ASCII range (including control chars)
+               if (($arr[$k] >= 0) AND ($arr[$k] <= 0x007f))
+               {
+                       echo chr($arr[$k]);
+               }
+               // 2 byte sequence
+               elseif ($arr[$k] <= 0x07ff)
+               {
+                       echo chr(0xc0 | ($arr[$k] >> 6));
+                       echo chr(0x80 | ($arr[$k] & 0x003f));
+               }
+               // Byte order mark (skip)
+               elseif ($arr[$k] == 0xFEFF)
+               {
+                       // nop -- zap the BOM
+               }
+               // Test for illegal surrogates
+               elseif ($arr[$k] >= 0xD800 AND $arr[$k] <= 0xDFFF)
+               {
+                       // Found a surrogate
+                       trigger_error('utf8::from_unicode: Illegal surrogate at index: '.$k.', value: '.$arr[$k], E_USER_WARNING);
+                       return FALSE;
+               }
+               // 3 byte sequence
+               elseif ($arr[$k] <= 0xffff)
+               {
+                       echo chr(0xe0 | ($arr[$k] >> 12));
+                       echo chr(0x80 | (($arr[$k] >> 6) & 0x003f));
+                       echo chr(0x80 | ($arr[$k] & 0x003f));
+               }
+               // 4 byte sequence
+               elseif ($arr[$k] <= 0x10ffff)
+               {
+                       echo chr(0xf0 | ($arr[$k] >> 18));
+                       echo chr(0x80 | (($arr[$k] >> 12) & 0x3f));
+                       echo chr(0x80 | (($arr[$k] >> 6) & 0x3f));
+                       echo chr(0x80 | ($arr[$k] & 0x3f));
+               }
+               // Out of range
+               else
+               {
+                       trigger_error('utf8::from_unicode: Codepoint out of Unicode range at index: '.$k.', value: '.$arr[$k], E_USER_WARNING);
+                       return FALSE;
+               }
+       }
+
+       $result = ob_get_contents();
+       ob_end_clean();
+       return $result;
+}
diff --git a/Server/system/core/utf8/ltrim.php b/Server/system/core/utf8/ltrim.php
new file mode 100644 (file)
index 0000000..556fe07
--- /dev/null
@@ -0,0 +1,22 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::ltrim
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _ltrim($str, $charlist = NULL)
+{
+       if ($charlist === NULL)
+               return ltrim($str);
+
+       if (utf8::is_ascii($charlist))
+               return ltrim($str, $charlist);
+
+       $charlist = preg_replace('#[-\[\]:\\\\^/]#', '\\\\$0', $charlist);
+
+       return preg_replace('/^['.$charlist.']+/u', '', $str);
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/ord.php b/Server/system/core/utf8/ord.php
new file mode 100644 (file)
index 0000000..76e3187
--- /dev/null
@@ -0,0 +1,88 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::ord
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _ord($chr)
+{
+       $ord0 = ord($chr);
+
+       if ($ord0 >= 0 AND $ord0 <= 127)
+       {
+               return $ord0;
+       }
+
+       if ( ! isset($chr[1]))
+       {
+               trigger_error('Short sequence - at least 2 bytes expected, only 1 seen', E_USER_WARNING);
+               return FALSE;
+       }
+
+       $ord1 = ord($chr[1]);
+
+       if ($ord0 >= 192 AND $ord0 <= 223)
+       {
+               return ($ord0 - 192) * 64 + ($ord1 - 128);
+       }
+
+       if ( ! isset($chr[2]))
+       {
+               trigger_error('Short sequence - at least 3 bytes expected, only 2 seen', E_USER_WARNING);
+               return FALSE;
+       }
+
+       $ord2 = ord($chr[2]);
+
+       if ($ord0 >= 224 AND $ord0 <= 239)
+       {
+               return ($ord0 - 224) * 4096 + ($ord1 - 128) * 64 + ($ord2 - 128);
+       }
+
+       if ( ! isset($chr[3]))
+       {
+               trigger_error('Short sequence - at least 4 bytes expected, only 3 seen', E_USER_WARNING);
+               return FALSE;
+       }
+
+       $ord3 = ord($chr[3]);
+
+       if ($ord0 >= 240 AND $ord0 <= 247)
+       {
+               return ($ord0 - 240) * 262144 + ($ord1 - 128) * 4096 + ($ord2-128) * 64 + ($ord3 - 128);
+       }
+
+       if ( ! isset($chr[4]))
+       {
+               trigger_error('Short sequence - at least 5 bytes expected, only 4 seen', E_USER_WARNING);
+               return FALSE;
+       }
+
+       $ord4 = ord($chr[4]);
+
+       if ($ord0 >= 248 AND $ord0 <= 251)
+       {
+               return ($ord0 - 248) * 16777216 + ($ord1-128) * 262144 + ($ord2 - 128) * 4096 + ($ord3 - 128) * 64 + ($ord4 - 128);
+       }
+
+       if ( ! isset($chr[5]))
+       {
+               trigger_error('Short sequence - at least 6 bytes expected, only 5 seen', E_USER_WARNING);
+               return FALSE;
+       }
+
+       if ($ord0 >= 252 AND $ord0 <= 253)
+       {
+               return ($ord0 - 252) * 1073741824 + ($ord1 - 128) * 16777216 + ($ord2 - 128) * 262144 + ($ord3 - 128) * 4096 + ($ord4 - 128) * 64 + (ord($chr[5]) - 128);
+       }
+
+       if ($ord0 >= 254 AND $ord0 <= 255)
+       {
+               trigger_error('Invalid UTF-8 with surrogate ordinal '.$ord0, E_USER_WARNING);
+               return FALSE;
+       }
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/rtrim.php b/Server/system/core/utf8/rtrim.php
new file mode 100644 (file)
index 0000000..efa0e19
--- /dev/null
@@ -0,0 +1,22 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::rtrim
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _rtrim($str, $charlist = NULL)
+{
+       if ($charlist === NULL)
+               return rtrim($str);
+
+       if (utf8::is_ascii($charlist))
+               return rtrim($str, $charlist);
+
+       $charlist = preg_replace('#[-\[\]:\\\\^/]#', '\\\\$0', $charlist);
+
+       return preg_replace('/['.$charlist.']++$/uD', '', $str);
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/str_ireplace.php b/Server/system/core/utf8/str_ireplace.php
new file mode 100644 (file)
index 0000000..97ad71a
--- /dev/null
@@ -0,0 +1,70 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::str_ireplace
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _str_ireplace($search, $replace, $str, & $count = NULL)
+{
+       if (utf8::is_ascii($search) AND utf8::is_ascii($replace) AND utf8::is_ascii($str))
+               return str_ireplace($search, $replace, $str, $count);
+
+       if (is_array($str))
+       {
+               foreach ($str as $key => $val)
+               {
+                       $str[$key] = utf8::str_ireplace($search, $replace, $val, $count);
+               }
+               return $str;
+       }
+
+       if (is_array($search))
+       {
+               $keys = array_keys($search);
+
+               foreach ($keys as $k)
+               {
+                       if (is_array($replace))
+                       {
+                               if (array_key_exists($k, $replace))
+                               {
+                                       $str = utf8::str_ireplace($search[$k], $replace[$k], $str, $count);
+                               }
+                               else
+                               {
+                                       $str = utf8::str_ireplace($search[$k], '', $str, $count);
+                               }
+                       }
+                       else
+                       {
+                               $str = utf8::str_ireplace($search[$k], $replace, $str, $count);
+                       }
+               }
+               return $str;
+       }
+
+       $search = utf8::strtolower($search);
+       $str_lower = utf8::strtolower($str);
+
+       $total_matched_strlen = 0;
+       $i = 0;
+
+       while (preg_match('/(.*?)'.preg_quote($search, '/').'/s', $str_lower, $matches))
+       {
+               $matched_strlen = strlen($matches[0]);
+               $str_lower = substr($str_lower, $matched_strlen);
+
+               $offset = $total_matched_strlen + strlen($matches[1]) + ($i * (strlen($replace) - 1));
+               $str = substr_replace($str, $replace, $offset, strlen($search));
+
+               $total_matched_strlen += $matched_strlen;
+               $i++;
+       }
+
+       $count += $i;
+       return $str;
+}
diff --git a/Server/system/core/utf8/str_pad.php b/Server/system/core/utf8/str_pad.php
new file mode 100644 (file)
index 0000000..aab4ccc
--- /dev/null
@@ -0,0 +1,54 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::str_pad
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _str_pad($str, $final_str_length, $pad_str = ' ', $pad_type = STR_PAD_RIGHT)
+{
+       if (utf8::is_ascii($str) AND utf8::is_ascii($pad_str))
+       {
+               return str_pad($str, $final_str_length, $pad_str, $pad_type);
+       }
+
+       $str_length = utf8::strlen($str);
+
+       if ($final_str_length <= 0 OR $final_str_length <= $str_length)
+       {
+               return $str;
+       }
+
+       $pad_str_length = utf8::strlen($pad_str);
+       $pad_length = $final_str_length - $str_length;
+
+       if ($pad_type == STR_PAD_RIGHT)
+       {
+               $repeat = ceil($pad_length / $pad_str_length);
+               return utf8::substr($str.str_repeat($pad_str, $repeat), 0, $final_str_length);
+       }
+
+       if ($pad_type == STR_PAD_LEFT)
+       {
+               $repeat = ceil($pad_length / $pad_str_length);
+               return utf8::substr(str_repeat($pad_str, $repeat), 0, floor($pad_length)).$str;
+       }
+
+       if ($pad_type == STR_PAD_BOTH)
+       {
+               $pad_length /= 2;
+               $pad_length_left = floor($pad_length);
+               $pad_length_right = ceil($pad_length);
+               $repeat_left = ceil($pad_length_left / $pad_str_length);
+               $repeat_right = ceil($pad_length_right / $pad_str_length);
+
+               $pad_left = utf8::substr(str_repeat($pad_str, $repeat_left), 0, $pad_length_left);
+               $pad_right = utf8::substr(str_repeat($pad_str, $repeat_right), 0, $pad_length_left);
+               return $pad_left.$str.$pad_right;
+       }
+
+       trigger_error('utf8::str_pad: Unknown padding type (' . $pad_type . ')', E_USER_ERROR);
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/str_split.php b/Server/system/core/utf8/str_split.php
new file mode 100644 (file)
index 0000000..bc382cb
--- /dev/null
@@ -0,0 +1,33 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::str_split
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _str_split($str, $split_length = 1)
+{
+       $split_length = (int) $split_length;
+
+       if (utf8::is_ascii($str))
+       {
+               return str_split($str, $split_length);
+       }
+
+       if ($split_length < 1)
+       {
+               return FALSE;
+       }
+
+       if (utf8::strlen($str) <= $split_length)
+       {
+               return array($str);
+       }
+
+       preg_match_all('/.{'.$split_length.'}|[^\x00]{1,'.$split_length.'}$/us', $str, $matches);
+
+       return $matches[0];
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/strcasecmp.php b/Server/system/core/utf8/strcasecmp.php
new file mode 100644 (file)
index 0000000..d06d3eb
--- /dev/null
@@ -0,0 +1,19 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::strcasecmp
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _strcasecmp($str1, $str2)
+{
+       if (utf8::is_ascii($str1) AND utf8::is_ascii($str2))
+               return strcasecmp($str1, $str2);
+
+       $str1 = utf8::strtolower($str1);
+       $str2 = utf8::strtolower($str2);
+       return strcmp($str1, $str2);
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/strcspn.php b/Server/system/core/utf8/strcspn.php
new file mode 100644 (file)
index 0000000..20d3e80
--- /dev/null
@@ -0,0 +1,30 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::strcspn
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _strcspn($str, $mask, $offset = NULL, $length = NULL)
+{
+       if ($str == '' OR $mask == '')
+               return 0;
+
+       if (utf8::is_ascii($str) AND utf8::is_ascii($mask))
+               return ($offset === NULL) ? strcspn($str, $mask) : (($length === NULL) ? strcspn($str, $mask, $offset) : strcspn($str, $mask, $offset, $length));
+
+       if ($str !== NULL OR $length !== NULL)
+       {
+               $str = utf8::substr($str, $offset, $length);
+       }
+
+       // Escape these characters:  - [ ] . : \ ^ /
+       // The . and : are escaped to prevent possible warnings about POSIX regex elements
+       $mask = preg_replace('#[-[\].:\\\\^/]#', '\\\\$0', $mask);
+       preg_match('/^[^'.$mask.']+/u', $str, $matches);
+
+       return isset($matches[0]) ? utf8::strlen($matches[0]) : 0;
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/stristr.php b/Server/system/core/utf8/stristr.php
new file mode 100644 (file)
index 0000000..73ea139
--- /dev/null
@@ -0,0 +1,28 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::stristr
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _stristr($str, $search)
+{
+       if (utf8::is_ascii($str) AND utf8::is_ascii($search))
+               return stristr($str, $search);
+
+       if ($search == '')
+               return $str;
+
+       $str_lower = utf8::strtolower($str);
+       $search_lower = utf8::strtolower($search);
+
+       preg_match('/^(.*?)'.preg_quote($search, '/').'/s', $str_lower, $matches);
+
+       if (isset($matches[1]))
+               return substr($str, strlen($matches[1]));
+
+       return FALSE;
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/strlen.php b/Server/system/core/utf8/strlen.php
new file mode 100644 (file)
index 0000000..f186a9c
--- /dev/null
@@ -0,0 +1,21 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::strlen
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _strlen($str)
+{
+       // Try mb_strlen() first because it's faster than combination of is_ascii() and strlen()
+       if (SERVER_UTF8)
+               return mb_strlen($str);
+
+       if (utf8::is_ascii($str))
+               return strlen($str);
+
+       return strlen(utf8_decode($str));
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/strpos.php b/Server/system/core/utf8/strpos.php
new file mode 100644 (file)
index 0000000..4a34dbe
--- /dev/null
@@ -0,0 +1,30 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::strpos
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _strpos($str, $search, $offset = 0)
+{
+       $offset = (int) $offset;
+
+       if (SERVER_UTF8)
+               return mb_strpos($str, $search, $offset);
+
+       if (utf8::is_ascii($str) AND utf8::is_ascii($search))
+               return strpos($str, $search, $offset);
+
+       if ($offset == 0)
+       {
+               $array = explode($search, $str, 2);
+               return isset($array[1]) ? utf8::strlen($array[0]) : FALSE;
+       }
+
+       $str = utf8::substr($str, $offset);
+       $pos = utf8::strpos($str, $search);
+       return ($pos === FALSE) ? FALSE : $pos + $offset;
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/strrev.php b/Server/system/core/utf8/strrev.php
new file mode 100644 (file)
index 0000000..89c428c
--- /dev/null
@@ -0,0 +1,18 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::strrev
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _strrev($str)
+{
+       if (utf8::is_ascii($str))
+               return strrev($str);
+
+       preg_match_all('/./us', $str, $matches);
+       return implode('', array_reverse($matches[0]));
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/strrpos.php b/Server/system/core/utf8/strrpos.php
new file mode 100644 (file)
index 0000000..1ac8f9c
--- /dev/null
@@ -0,0 +1,30 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::strrpos
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _strrpos($str, $search, $offset = 0)
+{
+       $offset = (int) $offset;
+
+       if (SERVER_UTF8)
+               return mb_strrpos($str, $search, $offset);
+
+       if (utf8::is_ascii($str) AND utf8::is_ascii($search))
+               return strrpos($str, $search, $offset);
+
+       if ($offset == 0)
+       {
+               $array = explode($search, $str, -1);
+               return isset($array[0]) ? utf8::strlen(implode($search, $array)) : FALSE;
+       }
+
+       $str = utf8::substr($str, $offset);
+       $pos = utf8::strrpos($str, $search);
+       return ($pos === FALSE) ? FALSE : $pos + $offset;
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/strspn.php b/Server/system/core/utf8/strspn.php
new file mode 100644 (file)
index 0000000..bc7e52f
--- /dev/null
@@ -0,0 +1,30 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::strspn
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _strspn($str, $mask, $offset = NULL, $length = NULL)
+{
+       if ($str == '' OR $mask == '')
+               return 0;
+
+       if (utf8::is_ascii($str) AND utf8::is_ascii($mask))
+               return ($offset === NULL) ? strspn($str, $mask) : (($length === NULL) ? strspn($str, $mask, $offset) : strspn($str, $mask, $offset, $length));
+
+       if ($offset !== NULL OR $length !== NULL)
+       {
+               $str = utf8::substr($str, $offset, $length);
+       }
+
+       // Escape these characters:  - [ ] . : \ ^ /
+       // The . and : are escaped to prevent possible warnings about POSIX regex elements
+       $mask = preg_replace('#[-[\].:\\\\^/]#', '\\\\$0', $mask);
+       preg_match('/^[^'.$mask.']+/u', $str, $matches);
+
+       return isset($matches[0]) ? utf8::strlen($matches[0]) : 0;
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/strtolower.php b/Server/system/core/utf8/strtolower.php
new file mode 100644 (file)
index 0000000..ff4da85
--- /dev/null
@@ -0,0 +1,84 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::strtolower
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _strtolower($str)
+{
+       if (SERVER_UTF8)
+               return mb_strtolower($str);
+
+       if (utf8::is_ascii($str))
+               return strtolower($str);
+
+       static $UTF8_UPPER_TO_LOWER = NULL;
+
+       if ($UTF8_UPPER_TO_LOWER === NULL)
+       {
+               $UTF8_UPPER_TO_LOWER = array(
+                       0x0041=>0x0061, 0x03A6=>0x03C6, 0x0162=>0x0163, 0x00C5=>0x00E5, 0x0042=>0x0062,
+                       0x0139=>0x013A, 0x00C1=>0x00E1, 0x0141=>0x0142, 0x038E=>0x03CD, 0x0100=>0x0101,
+                       0x0490=>0x0491, 0x0394=>0x03B4, 0x015A=>0x015B, 0x0044=>0x0064, 0x0393=>0x03B3,
+                       0x00D4=>0x00F4, 0x042A=>0x044A, 0x0419=>0x0439, 0x0112=>0x0113, 0x041C=>0x043C,
+                       0x015E=>0x015F, 0x0143=>0x0144, 0x00CE=>0x00EE, 0x040E=>0x045E, 0x042F=>0x044F,
+                       0x039A=>0x03BA, 0x0154=>0x0155, 0x0049=>0x0069, 0x0053=>0x0073, 0x1E1E=>0x1E1F,
+                       0x0134=>0x0135, 0x0427=>0x0447, 0x03A0=>0x03C0, 0x0418=>0x0438, 0x00D3=>0x00F3,
+                       0x0420=>0x0440, 0x0404=>0x0454, 0x0415=>0x0435, 0x0429=>0x0449, 0x014A=>0x014B,
+                       0x0411=>0x0431, 0x0409=>0x0459, 0x1E02=>0x1E03, 0x00D6=>0x00F6, 0x00D9=>0x00F9,
+                       0x004E=>0x006E, 0x0401=>0x0451, 0x03A4=>0x03C4, 0x0423=>0x0443, 0x015C=>0x015D,
+                       0x0403=>0x0453, 0x03A8=>0x03C8, 0x0158=>0x0159, 0x0047=>0x0067, 0x00C4=>0x00E4,
+                       0x0386=>0x03AC, 0x0389=>0x03AE, 0x0166=>0x0167, 0x039E=>0x03BE, 0x0164=>0x0165,
+                       0x0116=>0x0117, 0x0108=>0x0109, 0x0056=>0x0076, 0x00DE=>0x00FE, 0x0156=>0x0157,
+                       0x00DA=>0x00FA, 0x1E60=>0x1E61, 0x1E82=>0x1E83, 0x00C2=>0x00E2, 0x0118=>0x0119,
+                       0x0145=>0x0146, 0x0050=>0x0070, 0x0150=>0x0151, 0x042E=>0x044E, 0x0128=>0x0129,
+                       0x03A7=>0x03C7, 0x013D=>0x013E, 0x0422=>0x0442, 0x005A=>0x007A, 0x0428=>0x0448,
+                       0x03A1=>0x03C1, 0x1E80=>0x1E81, 0x016C=>0x016D, 0x00D5=>0x00F5, 0x0055=>0x0075,
+                       0x0176=>0x0177, 0x00DC=>0x00FC, 0x1E56=>0x1E57, 0x03A3=>0x03C3, 0x041A=>0x043A,
+                       0x004D=>0x006D, 0x016A=>0x016B, 0x0170=>0x0171, 0x0424=>0x0444, 0x00CC=>0x00EC,
+                       0x0168=>0x0169, 0x039F=>0x03BF, 0x004B=>0x006B, 0x00D2=>0x00F2, 0x00C0=>0x00E0,
+                       0x0414=>0x0434, 0x03A9=>0x03C9, 0x1E6A=>0x1E6B, 0x00C3=>0x00E3, 0x042D=>0x044D,
+                       0x0416=>0x0436, 0x01A0=>0x01A1, 0x010C=>0x010D, 0x011C=>0x011D, 0x00D0=>0x00F0,
+                       0x013B=>0x013C, 0x040F=>0x045F, 0x040A=>0x045A, 0x00C8=>0x00E8, 0x03A5=>0x03C5,
+                       0x0046=>0x0066, 0x00DD=>0x00FD, 0x0043=>0x0063, 0x021A=>0x021B, 0x00CA=>0x00EA,
+                       0x0399=>0x03B9, 0x0179=>0x017A, 0x00CF=>0x00EF, 0x01AF=>0x01B0, 0x0045=>0x0065,
+                       0x039B=>0x03BB, 0x0398=>0x03B8, 0x039C=>0x03BC, 0x040C=>0x045C, 0x041F=>0x043F,
+                       0x042C=>0x044C, 0x00DE=>0x00FE, 0x00D0=>0x00F0, 0x1EF2=>0x1EF3, 0x0048=>0x0068,
+                       0x00CB=>0x00EB, 0x0110=>0x0111, 0x0413=>0x0433, 0x012E=>0x012F, 0x00C6=>0x00E6,
+                       0x0058=>0x0078, 0x0160=>0x0161, 0x016E=>0x016F, 0x0391=>0x03B1, 0x0407=>0x0457,
+                       0x0172=>0x0173, 0x0178=>0x00FF, 0x004F=>0x006F, 0x041B=>0x043B, 0x0395=>0x03B5,
+                       0x0425=>0x0445, 0x0120=>0x0121, 0x017D=>0x017E, 0x017B=>0x017C, 0x0396=>0x03B6,
+                       0x0392=>0x03B2, 0x0388=>0x03AD, 0x1E84=>0x1E85, 0x0174=>0x0175, 0x0051=>0x0071,
+                       0x0417=>0x0437, 0x1E0A=>0x1E0B, 0x0147=>0x0148, 0x0104=>0x0105, 0x0408=>0x0458,
+                       0x014C=>0x014D, 0x00CD=>0x00ED, 0x0059=>0x0079, 0x010A=>0x010B, 0x038F=>0x03CE,
+                       0x0052=>0x0072, 0x0410=>0x0430, 0x0405=>0x0455, 0x0402=>0x0452, 0x0126=>0x0127,
+                       0x0136=>0x0137, 0x012A=>0x012B, 0x038A=>0x03AF, 0x042B=>0x044B, 0x004C=>0x006C,
+                       0x0397=>0x03B7, 0x0124=>0x0125, 0x0218=>0x0219, 0x00DB=>0x00FB, 0x011E=>0x011F,
+                       0x041E=>0x043E, 0x1E40=>0x1E41, 0x039D=>0x03BD, 0x0106=>0x0107, 0x03AB=>0x03CB,
+                       0x0426=>0x0446, 0x00DE=>0x00FE, 0x00C7=>0x00E7, 0x03AA=>0x03CA, 0x0421=>0x0441,
+                       0x0412=>0x0432, 0x010E=>0x010F, 0x00D8=>0x00F8, 0x0057=>0x0077, 0x011A=>0x011B,
+                       0x0054=>0x0074, 0x004A=>0x006A, 0x040B=>0x045B, 0x0406=>0x0456, 0x0102=>0x0103,
+                       0x039B=>0x03BB, 0x00D1=>0x00F1, 0x041D=>0x043D, 0x038C=>0x03CC, 0x00C9=>0x00E9,
+                       0x00D0=>0x00F0, 0x0407=>0x0457, 0x0122=>0x0123,
+               );
+       }
+
+       $uni = utf8::to_unicode($str);
+
+       if ($uni === FALSE)
+               return FALSE;
+
+       for ($i = 0, $c = count($uni); $i < $c; $i++)
+       {
+               if (isset($UTF8_UPPER_TO_LOWER[$uni[$i]]))
+               {
+                       $uni[$i] = $UTF8_UPPER_TO_LOWER[$uni[$i]];
+               }
+       }
+
+       return utf8::from_unicode($uni);
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/strtoupper.php b/Server/system/core/utf8/strtoupper.php
new file mode 100644 (file)
index 0000000..f3ded73
--- /dev/null
@@ -0,0 +1,84 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::strtoupper
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _strtoupper($str)
+{
+       if (SERVER_UTF8)
+               return mb_strtoupper($str);
+
+       if (utf8::is_ascii($str))
+               return strtoupper($str);
+
+       static $UTF8_LOWER_TO_UPPER = NULL;
+
+       if ($UTF8_LOWER_TO_UPPER === NULL)
+       {
+               $UTF8_LOWER_TO_UPPER = array(
+                       0x0061=>0x0041, 0x03C6=>0x03A6, 0x0163=>0x0162, 0x00E5=>0x00C5, 0x0062=>0x0042,
+                       0x013A=>0x0139, 0x00E1=>0x00C1, 0x0142=>0x0141, 0x03CD=>0x038E, 0x0101=>0x0100,
+                       0x0491=>0x0490, 0x03B4=>0x0394, 0x015B=>0x015A, 0x0064=>0x0044, 0x03B3=>0x0393,
+                       0x00F4=>0x00D4, 0x044A=>0x042A, 0x0439=>0x0419, 0x0113=>0x0112, 0x043C=>0x041C,
+                       0x015F=>0x015E, 0x0144=>0x0143, 0x00EE=>0x00CE, 0x045E=>0x040E, 0x044F=>0x042F,
+                       0x03BA=>0x039A, 0x0155=>0x0154, 0x0069=>0x0049, 0x0073=>0x0053, 0x1E1F=>0x1E1E,
+                       0x0135=>0x0134, 0x0447=>0x0427, 0x03C0=>0x03A0, 0x0438=>0x0418, 0x00F3=>0x00D3,
+                       0x0440=>0x0420, 0x0454=>0x0404, 0x0435=>0x0415, 0x0449=>0x0429, 0x014B=>0x014A,
+                       0x0431=>0x0411, 0x0459=>0x0409, 0x1E03=>0x1E02, 0x00F6=>0x00D6, 0x00F9=>0x00D9,
+                       0x006E=>0x004E, 0x0451=>0x0401, 0x03C4=>0x03A4, 0x0443=>0x0423, 0x015D=>0x015C,
+                       0x0453=>0x0403, 0x03C8=>0x03A8, 0x0159=>0x0158, 0x0067=>0x0047, 0x00E4=>0x00C4,
+                       0x03AC=>0x0386, 0x03AE=>0x0389, 0x0167=>0x0166, 0x03BE=>0x039E, 0x0165=>0x0164,
+                       0x0117=>0x0116, 0x0109=>0x0108, 0x0076=>0x0056, 0x00FE=>0x00DE, 0x0157=>0x0156,
+                       0x00FA=>0x00DA, 0x1E61=>0x1E60, 0x1E83=>0x1E82, 0x00E2=>0x00C2, 0x0119=>0x0118,
+                       0x0146=>0x0145, 0x0070=>0x0050, 0x0151=>0x0150, 0x044E=>0x042E, 0x0129=>0x0128,
+                       0x03C7=>0x03A7, 0x013E=>0x013D, 0x0442=>0x0422, 0x007A=>0x005A, 0x0448=>0x0428,
+                       0x03C1=>0x03A1, 0x1E81=>0x1E80, 0x016D=>0x016C, 0x00F5=>0x00D5, 0x0075=>0x0055,
+                       0x0177=>0x0176, 0x00FC=>0x00DC, 0x1E57=>0x1E56, 0x03C3=>0x03A3, 0x043A=>0x041A,
+                       0x006D=>0x004D, 0x016B=>0x016A, 0x0171=>0x0170, 0x0444=>0x0424, 0x00EC=>0x00CC,
+                       0x0169=>0x0168, 0x03BF=>0x039F, 0x006B=>0x004B, 0x00F2=>0x00D2, 0x00E0=>0x00C0,
+                       0x0434=>0x0414, 0x03C9=>0x03A9, 0x1E6B=>0x1E6A, 0x00E3=>0x00C3, 0x044D=>0x042D,
+                       0x0436=>0x0416, 0x01A1=>0x01A0, 0x010D=>0x010C, 0x011D=>0x011C, 0x00F0=>0x00D0,
+                       0x013C=>0x013B, 0x045F=>0x040F, 0x045A=>0x040A, 0x00E8=>0x00C8, 0x03C5=>0x03A5,
+                       0x0066=>0x0046, 0x00FD=>0x00DD, 0x0063=>0x0043, 0x021B=>0x021A, 0x00EA=>0x00CA,
+                       0x03B9=>0x0399, 0x017A=>0x0179, 0x00EF=>0x00CF, 0x01B0=>0x01AF, 0x0065=>0x0045,
+                       0x03BB=>0x039B, 0x03B8=>0x0398, 0x03BC=>0x039C, 0x045C=>0x040C, 0x043F=>0x041F,
+                       0x044C=>0x042C, 0x00FE=>0x00DE, 0x00F0=>0x00D0, 0x1EF3=>0x1EF2, 0x0068=>0x0048,
+                       0x00EB=>0x00CB, 0x0111=>0x0110, 0x0433=>0x0413, 0x012F=>0x012E, 0x00E6=>0x00C6,
+                       0x0078=>0x0058, 0x0161=>0x0160, 0x016F=>0x016E, 0x03B1=>0x0391, 0x0457=>0x0407,
+                       0x0173=>0x0172, 0x00FF=>0x0178, 0x006F=>0x004F, 0x043B=>0x041B, 0x03B5=>0x0395,
+                       0x0445=>0x0425, 0x0121=>0x0120, 0x017E=>0x017D, 0x017C=>0x017B, 0x03B6=>0x0396,
+                       0x03B2=>0x0392, 0x03AD=>0x0388, 0x1E85=>0x1E84, 0x0175=>0x0174, 0x0071=>0x0051,
+                       0x0437=>0x0417, 0x1E0B=>0x1E0A, 0x0148=>0x0147, 0x0105=>0x0104, 0x0458=>0x0408,
+                       0x014D=>0x014C, 0x00ED=>0x00CD, 0x0079=>0x0059, 0x010B=>0x010A, 0x03CE=>0x038F,
+                       0x0072=>0x0052, 0x0430=>0x0410, 0x0455=>0x0405, 0x0452=>0x0402, 0x0127=>0x0126,
+                       0x0137=>0x0136, 0x012B=>0x012A, 0x03AF=>0x038A, 0x044B=>0x042B, 0x006C=>0x004C,
+                       0x03B7=>0x0397, 0x0125=>0x0124, 0x0219=>0x0218, 0x00FB=>0x00DB, 0x011F=>0x011E,
+                       0x043E=>0x041E, 0x1E41=>0x1E40, 0x03BD=>0x039D, 0x0107=>0x0106, 0x03CB=>0x03AB,
+                       0x0446=>0x0426, 0x00FE=>0x00DE, 0x00E7=>0x00C7, 0x03CA=>0x03AA, 0x0441=>0x0421,
+                       0x0432=>0x0412, 0x010F=>0x010E, 0x00F8=>0x00D8, 0x0077=>0x0057, 0x011B=>0x011A,
+                       0x0074=>0x0054, 0x006A=>0x004A, 0x045B=>0x040B, 0x0456=>0x0406, 0x0103=>0x0102,
+                       0x03BB=>0x039B, 0x00F1=>0x00D1, 0x043D=>0x041D, 0x03CC=>0x038C, 0x00E9=>0x00C9,
+                       0x00F0=>0x00D0, 0x0457=>0x0407, 0x0123=>0x0122,
+               );
+       }
+
+       $uni = utf8::to_unicode($str);
+
+       if ($uni === FALSE)
+               return FALSE;
+
+       for ($i = 0, $c = count($uni); $i < $c; $i++)
+       {
+               if (isset($UTF8_LOWER_TO_UPPER[$uni[$i]]))
+               {
+                       $uni[$i] = $UTF8_LOWER_TO_UPPER[$uni[$i]];
+               }
+       }
+
+       return utf8::from_unicode($uni);
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/substr.php b/Server/system/core/utf8/substr.php
new file mode 100644 (file)
index 0000000..daf66b8
--- /dev/null
@@ -0,0 +1,75 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::substr
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _substr($str, $offset, $length = NULL)
+{
+       if (SERVER_UTF8)
+               return ($length === NULL) ? mb_substr($str, $offset) : mb_substr($str, $offset, $length);
+
+       if (utf8::is_ascii($str))
+               return ($length === NULL) ? substr($str, $offset) : substr($str, $offset, $length);
+
+       // Normalize params
+       $str    = (string) $str;
+       $strlen = utf8::strlen($str);
+       $offset = (int) ($offset < 0) ? max(0, $strlen + $offset) : $offset; // Normalize to positive offset
+       $length = ($length === NULL) ? NULL : (int) $length;
+
+       // Impossible
+       if ($length === 0 OR $offset >= $strlen OR ($length < 0 AND $length <= $offset - $strlen))
+               return '';
+
+       // Whole string
+       if ($offset == 0 AND ($length === NULL OR $length >= $strlen))
+               return $str;
+
+       // Build regex
+       $regex = '^';
+
+       // Create an offset expression
+       if ($offset > 0)
+       {
+               // PCRE repeating quantifiers must be less than 65536, so repeat when necessary
+               $x = (int) ($offset / 65535);
+               $y = (int) ($offset % 65535);
+               $regex .= ($x == 0) ? '' : '(?:.{65535}){'.$x.'}';
+               $regex .= ($y == 0) ? '' : '.{'.$y.'}';
+       }
+
+       // Create a length expression
+       if ($length === NULL)
+       {
+               $regex .= '(.*)'; // No length set, grab it all
+       }
+       // Find length from the left (positive length)
+       elseif ($length > 0)
+       {
+               // Reduce length so that it can't go beyond the end of the string
+               $length = min($strlen - $offset, $length);
+
+               $x = (int) ($length / 65535);
+               $y = (int) ($length % 65535);
+               $regex .= '(';
+               $regex .= ($x == 0) ? '' : '(?:.{65535}){'.$x.'}';
+               $regex .= '.{'.$y.'})';
+       }
+       // Find length from the right (negative length)
+       else
+       {
+               $x = (int) (-$length / 65535);
+               $y = (int) (-$length % 65535);
+               $regex .= '(.*)';
+               $regex .= ($x == 0) ? '' : '(?:.{65535}){'.$x.'}';
+               $regex .= '.{'.$y.'}';
+       }
+
+       preg_match('/'.$regex.'/us', $str, $matches);
+       return $matches[1];
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/substr_replace.php b/Server/system/core/utf8/substr_replace.php
new file mode 100644 (file)
index 0000000..45e2d2a
--- /dev/null
@@ -0,0 +1,22 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::substr_replace
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _substr_replace($str, $replacement, $offset, $length = NULL)
+{
+       if (utf8::is_ascii($str))
+               return ($length === NULL) ? substr_replace($str, $replacement, $offset) : substr_replace($str, $replacement, $offset, $length);
+
+       $length = ($length === NULL) ? utf8::strlen($str) : (int) $length;
+       preg_match_all('/./us', $str, $str_array);
+       preg_match_all('/./us', $replacement, $replacement_array);
+
+       array_splice($str_array[0], $offset, $length, $replacement_array[0]);
+       return implode('', $str_array[0]);
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/to_unicode.php b/Server/system/core/utf8/to_unicode.php
new file mode 100644 (file)
index 0000000..93f741a
--- /dev/null
@@ -0,0 +1,141 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::to_unicode
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _to_unicode($str)
+{
+       $mState = 0; // cached expected number of octets after the current octet until the beginning of the next UTF8 character sequence
+       $mUcs4  = 0; // cached Unicode character
+       $mBytes = 1; // cached expected number of octets in the current sequence
+
+       $out = array();
+
+       $len = strlen($str);
+
+       for ($i = 0; $i < $len; $i++)
+       {
+               $in = ord($str[$i]);
+
+               if ($mState == 0)
+               {
+                       // When mState is zero we expect either a US-ASCII character or a
+                       // multi-octet sequence.
+                       if (0 == (0x80 & $in))
+                       {
+                               // US-ASCII, pass straight through.
+                               $out[] = $in;
+                               $mBytes = 1;
+                       }
+                       elseif (0xC0 == (0xE0 & $in))
+                       {
+                               // First octet of 2 octet sequence
+                               $mUcs4 = $in;
+                               $mUcs4 = ($mUcs4 & 0x1F) << 6;
+                               $mState = 1;
+                               $mBytes = 2;
+                       }
+                       elseif (0xE0 == (0xF0 & $in))
+                       {
+                               // First octet of 3 octet sequence
+                               $mUcs4 = $in;
+                               $mUcs4 = ($mUcs4 & 0x0F) << 12;
+                               $mState = 2;
+                               $mBytes = 3;
+                       }
+                       elseif (0xF0 == (0xF8 & $in))
+                       {
+                               // First octet of 4 octet sequence
+                               $mUcs4 = $in;
+                               $mUcs4 = ($mUcs4 & 0x07) << 18;
+                               $mState = 3;
+                               $mBytes = 4;
+                       }
+                       elseif (0xF8 == (0xFC & $in))
+                       {
+                               // First octet of 5 octet sequence.
+                               //
+                               // This is illegal because the encoded codepoint must be either
+                               // (a) not the shortest form or
+                               // (b) outside the Unicode range of 0-0x10FFFF.
+                               // Rather than trying to resynchronize, we will carry on until the end
+                               // of the sequence and let the later error handling code catch it.
+                               $mUcs4 = $in;
+                               $mUcs4 = ($mUcs4 & 0x03) << 24;
+                               $mState = 4;
+                               $mBytes = 5;
+                       }
+                       elseif (0xFC == (0xFE & $in))
+                       {
+                               // First octet of 6 octet sequence, see comments for 5 octet sequence.
+                               $mUcs4 = $in;
+                               $mUcs4 = ($mUcs4 & 1) << 30;
+                               $mState = 5;
+                               $mBytes = 6;
+                       }
+                       else
+                       {
+                               // Current octet is neither in the US-ASCII range nor a legal first octet of a multi-octet sequence.
+                               trigger_error('utf8::to_unicode: Illegal sequence identifier in UTF-8 at byte '.$i, E_USER_WARNING);
+                               return FALSE;
+                       }
+               }
+               else
+               {
+                       // When mState is non-zero, we expect a continuation of the multi-octet sequence
+                       if (0x80 == (0xC0 & $in))
+                       {
+                               // Legal continuation
+                               $shift = ($mState - 1) * 6;
+                               $tmp = $in;
+                               $tmp = ($tmp & 0x0000003F) << $shift;
+                               $mUcs4 |= $tmp;
+
+                               // End of the multi-octet sequence. mUcs4 now contains the final Unicode codepoint to be output
+                               if (0 == --$mState)
+                               {
+                                       // Check for illegal sequences and codepoints
+
+                                       // From Unicode 3.1, non-shortest form is illegal
+                                       if (((2 == $mBytes) AND ($mUcs4 < 0x0080)) OR
+                                               ((3 == $mBytes) AND ($mUcs4 < 0x0800)) OR
+                                               ((4 == $mBytes) AND ($mUcs4 < 0x10000)) OR
+                                               (4 < $mBytes) OR
+                                               // From Unicode 3.2, surrogate characters are illegal
+                                               (($mUcs4 & 0xFFFFF800) == 0xD800) OR
+                                               // Codepoints outside the Unicode range are illegal
+                                               ($mUcs4 > 0x10FFFF))
+                                       {
+                                               trigger_error('utf8::to_unicode: Illegal sequence or codepoint in UTF-8 at byte '.$i, E_USER_WARNING);
+                                               return FALSE;
+                                       }
+
+                                       if (0xFEFF != $mUcs4)
+                                       {
+                                               // BOM is legal but we don't want to output it
+                                               $out[] = $mUcs4;
+                                       }
+
+                                       // Initialize UTF-8 cache
+                                       $mState = 0;
+                                       $mUcs4  = 0;
+                                       $mBytes = 1;
+                               }
+                       }
+                       else
+                       {
+                               // ((0xC0 & (*in) != 0x80) AND (mState != 0))
+                               // Incomplete multi-octet sequence
+                               trigger_error('utf8::to_unicode: Incomplete multi-octet sequence in UTF-8 at byte '.$i, E_USER_WARNING);
+                               return FALSE;
+                       }
+               }
+       }
+
+       return $out;
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/transliterate_to_ascii.php b/Server/system/core/utf8/transliterate_to_ascii.php
new file mode 100644 (file)
index 0000000..07461fb
--- /dev/null
@@ -0,0 +1,77 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::transliterate_to_ascii
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _transliterate_to_ascii($str, $case = 0)
+{
+       static $UTF8_LOWER_ACCENTS = NULL;
+       static $UTF8_UPPER_ACCENTS = NULL;
+
+       if ($case <= 0)
+       {
+               if ($UTF8_LOWER_ACCENTS === NULL)
+               {
+                       $UTF8_LOWER_ACCENTS = array(
+                               'à' => 'a',  'ô' => 'o',  'ď' => 'd',  'ḟ' => 'f',  'ë' => 'e',  'š' => 's',  'ơ' => 'o',
+                               'ß' => 'ss', 'ă' => 'a',  'ř' => 'r',  'ț' => 't',  'ň' => 'n',  'ā' => 'a',  'ķ' => 'k',
+                               'ŝ' => 's',  'ỳ' => 'y',  'ņ' => 'n',  'ĺ' => 'l',  'ħ' => 'h',  'ṗ' => 'p',  'ó' => 'o',
+                               'ú' => 'u',  'ě' => 'e',  'é' => 'e',  'ç' => 'c',  'ẁ' => 'w',  'ċ' => 'c',  'õ' => 'o',
+                               'ṡ' => 's',  'ø' => 'o',  'ģ' => 'g',  'ŧ' => 't',  'ș' => 's',  'ė' => 'e',  'ĉ' => 'c',
+                               'ś' => 's',  'î' => 'i',  'ű' => 'u',  'ć' => 'c',  'ę' => 'e',  'ŵ' => 'w',  'ṫ' => 't',
+                               'ū' => 'u',  'č' => 'c',  'ö' => 'o',  'è' => 'e',  'ŷ' => 'y',  'ą' => 'a',  'ł' => 'l',
+                               'ų' => 'u',  'ů' => 'u',  'ş' => 's',  'ğ' => 'g',  'ļ' => 'l',  'ƒ' => 'f',  'ž' => 'z',
+                               'ẃ' => 'w',  'ḃ' => 'b',  'å' => 'a',  'ì' => 'i',  'ï' => 'i',  'ḋ' => 'd',  'ť' => 't',
+                               'ŗ' => 'r',  'ä' => 'a',  'í' => 'i',  'ŕ' => 'r',  'ê' => 'e',  'ü' => 'u',  'ò' => 'o',
+                               'ē' => 'e',  'ñ' => 'n',  'ń' => 'n',  'ĥ' => 'h',  'ĝ' => 'g',  'đ' => 'd',  'ĵ' => 'j',
+                               'ÿ' => 'y',  'ũ' => 'u',  'ŭ' => 'u',  'ư' => 'u',  'ţ' => 't',  'ý' => 'y',  'ő' => 'o',
+                               'â' => 'a',  'ľ' => 'l',  'ẅ' => 'w',  'ż' => 'z',  'ī' => 'i',  'ã' => 'a',  'ġ' => 'g',
+                               'ṁ' => 'm',  'ō' => 'o',  'ĩ' => 'i',  'ù' => 'u',  'į' => 'i',  'ź' => 'z',  'á' => 'a',
+                               'û' => 'u',  'þ' => 'th', 'ð' => 'dh', 'æ' => 'ae', 'µ' => 'u',  'ĕ' => 'e',
+                       );
+               }
+
+               $str = str_replace(
+                       array_keys($UTF8_LOWER_ACCENTS),
+                       array_values($UTF8_LOWER_ACCENTS),
+                       $str
+               );
+       }
+
+       if ($case >= 0)
+       {
+               if ($UTF8_UPPER_ACCENTS === NULL)
+               {
+                       $UTF8_UPPER_ACCENTS = array(
+                               'À' => 'A',  'Ô' => 'O',  'Ď' => 'D',  'Ḟ' => 'F',  'Ë' => 'E',  'Š' => 'S',  'Ơ' => 'O',
+                               'Ă' => 'A',  'Ř' => 'R',  'Ț' => 'T',  'Ň' => 'N',  'Ā' => 'A',  'Ķ' => 'K',  'Ĕ' => 'E',
+                               'Ŝ' => 'S',  'Ỳ' => 'Y',  'Ņ' => 'N',  'Ĺ' => 'L',  'Ħ' => 'H',  'Ṗ' => 'P',  'Ó' => 'O',
+                               'Ú' => 'U',  'Ě' => 'E',  'É' => 'E',  'Ç' => 'C',  'Ẁ' => 'W',  'Ċ' => 'C',  'Õ' => 'O',
+                               'Ṡ' => 'S',  'Ø' => 'O',  'Ģ' => 'G',  'Ŧ' => 'T',  'Ș' => 'S',  'Ė' => 'E',  'Ĉ' => 'C',
+                               'Ś' => 'S',  'Î' => 'I',  'Ű' => 'U',  'Ć' => 'C',  'Ę' => 'E',  'Ŵ' => 'W',  'Ṫ' => 'T',
+                               'Ū' => 'U',  'Č' => 'C',  'Ö' => 'O',  'È' => 'E',  'Ŷ' => 'Y',  'Ą' => 'A',  'Ł' => 'L',
+                               'Ų' => 'U',  'Ů' => 'U',  'Ş' => 'S',  'Ğ' => 'G',  'Ļ' => 'L',  'Ƒ' => 'F',  'Ž' => 'Z',
+                               'Ẃ' => 'W',  'Ḃ' => 'B',  'Å' => 'A',  'Ì' => 'I',  'Ï' => 'I',  'Ḋ' => 'D',  'Ť' => 'T',
+                               'Ŗ' => 'R',  'Ä' => 'A',  'Í' => 'I',  'Ŕ' => 'R',  'Ê' => 'E',  'Ü' => 'U',  'Ò' => 'O',
+                               'Ē' => 'E',  'Ñ' => 'N',  'Ń' => 'N',  'Ĥ' => 'H',  'Ĝ' => 'G',  'Đ' => 'D',  'Ĵ' => 'J',
+                               'Ÿ' => 'Y',  'Ũ' => 'U',  'Ŭ' => 'U',  'Ư' => 'U',  'Ţ' => 'T',  'Ý' => 'Y',  'Ő' => 'O',
+                               'Â' => 'A',  'Ľ' => 'L',  'Ẅ' => 'W',  'Ż' => 'Z',  'Ī' => 'I',  'Ã' => 'A',  'Ġ' => 'G',
+                               'Ṁ' => 'M',  'Ō' => 'O',  'Ĩ' => 'I',  'Ù' => 'U',  'Į' => 'I',  'Ź' => 'Z',  'Á' => 'A',
+                               'Û' => 'U',  'Þ' => 'Th', 'Ð' => 'Dh', 'Æ' => 'Ae',
+                       );
+               }
+
+               $str = str_replace(
+                       array_keys($UTF8_UPPER_ACCENTS),
+                       array_values($UTF8_UPPER_ACCENTS),
+                       $str
+               );
+       }
+
+       return $str;
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/trim.php b/Server/system/core/utf8/trim.php
new file mode 100644 (file)
index 0000000..7434102
--- /dev/null
@@ -0,0 +1,17 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::trim
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _trim($str, $charlist = NULL)
+{
+       if ($charlist === NULL)
+               return trim($str);
+
+       return utf8::ltrim(utf8::rtrim($str, $charlist), $charlist);
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/ucfirst.php b/Server/system/core/utf8/ucfirst.php
new file mode 100644 (file)
index 0000000..81a4b38
--- /dev/null
@@ -0,0 +1,18 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::ucfirst
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _ucfirst($str)
+{
+       if (utf8::is_ascii($str))
+               return ucfirst($str);
+
+       preg_match('/^(.?)(.*)$/us', $str, $matches);
+       return utf8::strtoupper($matches[1]).$matches[2];
+}
\ No newline at end of file
diff --git a/Server/system/core/utf8/ucwords.php b/Server/system/core/utf8/ucwords.php
new file mode 100644 (file)
index 0000000..2d4c94b
--- /dev/null
@@ -0,0 +1,26 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * utf8::ucwords
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007 Kohana Team
+ * @copyright  (c) 2005 Harry Fuecks
+ * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
+ */
+function _ucwords($str)
+{
+       if (SERVER_UTF8)
+               return mb_convert_case($str, MB_CASE_TITLE);
+
+       if (utf8::is_ascii($str))
+               return ucwords($str);
+
+       // [\x0c\x09\x0b\x0a\x0d\x20] matches form feeds, horizontal tabs, vertical tabs, linefeeds and carriage returns.
+       // This corresponds to the definition of a 'word' defined at http://php.net/ucwords
+       return preg_replace(
+               '/(?<=^|[\x0c\x09\x0b\x0a\x0d\x20])[^\x0c\x09\x0b\x0a\x0d\x20]/ue',
+               'utf8::strtoupper(\'$0\')',
+               $str
+       );
+}
\ No newline at end of file
diff --git a/Server/system/fonts/DejaVuSerif.ttf b/Server/system/fonts/DejaVuSerif.ttf
new file mode 100644 (file)
index 0000000..b7f4482
Binary files /dev/null and b/Server/system/fonts/DejaVuSerif.ttf differ
diff --git a/Server/system/fonts/LICENSE b/Server/system/fonts/LICENSE
new file mode 100644 (file)
index 0000000..254e2cc
--- /dev/null
@@ -0,0 +1,99 @@
+Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
+Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
+
+Bitstream Vera Fonts Copyright
+------------------------------
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
+a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute the
+Font Software, including without limitation the rights to use, copy, merge,
+publish, distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright and trademark notices and this permission notice shall
+be included in all copies of one or more of the Font Software typefaces.
+
+The Font Software may be modified, altered, or added to, and in particular
+the designs of glyphs or characters in the Fonts may be modified and
+additional glyphs or characters may be added to the Fonts, only if the fonts
+are renamed to names not containing either the words "Bitstream" or the word
+"Vera".
+
+This License becomes null and void to the extent applicable to Fonts or Font
+Software that has been modified and is distributed under the "Bitstream
+Vera" names.
+
+The Font Software may be sold as part of a larger software package but no
+copy of one or more of the Font Software typefaces may be sold by itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
+TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
+FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
+ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
+FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font Software
+without prior written authorization from the Gnome Foundation or Bitstream
+Inc., respectively. For further information, contact: fonts at gnome dot
+org. 
+
+Arev Fonts Copyright
+------------------------------
+
+Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and
+associated documentation files (the "Font Software"), to reproduce
+and distribute the modifications to the Bitstream Vera Font Software,
+including without limitation the rights to use, copy, merge, publish,
+distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Tavmjong Bah" or the word "Arev".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the 
+"Tavmjong Bah Arev" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the name of Tavmjong Bah shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealings in this Font Software without prior written authorization
+from Tavmjong Bah. For further information, contact: tavmjong @ free
+. fr.
+
+$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $
diff --git a/Server/system/helpers/arr.php b/Server/system/helpers/arr.php
new file mode 100644 (file)
index 0000000..9570c4b
--- /dev/null
@@ -0,0 +1,312 @@
+<?php defined('SYSPATH') OR die('No direct access allowed.');
+/**
+ * Array helper class.
+ *
+ * $Id: arr.php 4346 2009-05-11 17:08:15Z zombor $
+ *
+ * @package    Core
+ * @author     Kohana Team
+ * @copyright  (c) 2007-2008 Kohana Team
+ * @license    http://kohanaphp.com/license.html
+ */
+class arr_Core {
+
+       /**
+        * Return a callback array from a string, eg: limit[10,20] would become
+        * array('limit', array('10', '20'))
+        *
+        * @param   string  callback string
+        * @return  array
+        */
+       public static function callback_string($str)
+       {
+               // command[param,param]
+               if (preg_match('/([^\[]*+)\[(.+)\]/', (string) $str, $match))
+               {
+                       // command
+                       $command = $match[1];
+
+                       // param,param
+                       $params = preg_split('/(?<!\\\\),/', $match[2]);
+                       $params = str_replace('\,', ',', $params);
+               }
+               else
+               {
+                       // command
+                       $command = $str;
+
+                       // No params
+                       $params = NULL;
+               }
+
+               return array($command, $params);
+       }
+
+       /**
+        * Rotates a 2D array clockwise.
+        * Example, turns a 2x3 array into a 3x2 array.
+        *
+        * @param   array    array to rotate
+        * @param   boolean  keep the keys in the final rotated array. the sub arrays of the source array need to have the same key values.
+        *                   if your subkeys might not match, you need to pass FALSE here!
+        * @return  array
+        */
+       public static function rotate($source_array, $keep_keys = TRUE)
+       {
+               $new_array = array();
+               foreach ($source_array as $key => $value)
+               {
+                       $value = ($keep_keys === TRUE) ? $value : array_values($value);
+                       foreach ($value as $k => $v)
+                       {
+                               $new_array[$k][$key] = $v;
+                       }
+               }
+
+               return $new_array;
+       }
+
+       /**
+        * Removes a key from an array and returns the value.
+        *
+        * @param   string  key to return
+        * @param   array   array to work on
+        * @return  mixed   value of the requested array key
+        */
+       public static function remove($key, & $array)
+       {
+               if ( ! array_key_exists($key, $array))
+                       return NULL;
+
+               $val = $array[$key];
+               unset($array[$key]);
+
+               return $val;
+       }
+
+
+       /**
+        * Extract one or more keys from an array. Each key given after the first
+        * argument (the array) will be extracted. Keys that do not exist in the
+        * search array will be NULL in the extracted data.
+        *
+        * @param   array   array to search
+        * @param   string  key name
+        * @return  array
+        */
+       public static function extract(array $search, $keys)
+       {
+               // Get the keys, removing the $search array
+               $keys = array_slice(func_get_args(), 1);
+
+               $found = array();
+               foreach ($keys as $key)
+               {
+                       if (isset($search[$key]))
+                       {
+                               $found[$key] = $search[$key];
+                       }
+                       else
+                       {
+                               $found[$key] = NULL;
+                       }
+               }
+
+               return $found;
+       }
+
+       /**
+        * Because PHP does not have this function.
+        *
+        * @param   array   array to unshift
+        * @param   string  key to unshift
+        * @param   mixed   value to unshift
+        * @return  array
+        */
+       public static function unshift_assoc( array & $array, $key, $val)
+       {
+               $array = array_reverse($array, TRUE);
+               $array[$key] = $val;
+               $array = array_reverse($array, TRUE);
+
+               return $array;
+       }
+
+       /**
+        * Because PHP does not have this function, and array_walk_recursive creates
+        * references in arrays and is not truly recursive.
+        *
+        * @param   mixed  callback to apply to each member of the array
+        * @param   array  array to map to
+        * @return  array
+        */
+       public static function map_recursive($callback, array $array)
+       {
+               foreach ($array as $key => $val)
+               {
+                       // Map the callback to the key
+                       $array[$key] = is_array($val) ? arr::map_recursive($callback, $val) : call_user_func($callback, $val);
+               }
+
+               return $array;
+       }
+
+       /**
+        * @param mixed $needle     the value to search for
+        * @param array $haystack   an array of values to search in
+        * @param boolean $sort     sort the array now
+        * @return integer|FALSE    the index of the match or FALSE when not found
+        */
+       public static function binary_search($needle, $haystack, $sort = FALSE)
+       {
+               if ($sort)
+               {
+                       sort($haystack);
+               }
+
+               $high = count($haystack) - 1;
+               $low = 0;
+
+               while ($low <= $high)
+               {
+                       $mid = ($low + $high) >> 1;
+
+                       if ($haystack[$mid] < $needle)
+                       {
+                               $low = $mid + 1;
+                       }
+                       elseif ($haystack[$mid] > $needle)
+                       {
+                               $high = $mid - 1;
+                       }
+                       else
+                       {
+                               return $mid;
+                       }
+               }
+
+               return FALSE;
+       }
+
+
+       /**
+        * Emulates array_merge_recursive, but appends numeric keys and replaces
+        * associative keys, instead of appending all keys.
+        *
+        * @param   array  any number of arrays
+        * @return  array
+        */
+       public static function merge()
+       {
+               $total = func_num_args();
+
+               $result = array();
+               for ($i = 0; $i < $total; $i++)
+               {
+                       foreach (func_get_arg($i) as $key => $val)
+                       {
+                               if (isset($result[$key]))
+                               {
+                                       if (is_array($val))
+                                       {
+                                               // Arrays are merged recursively
+                                               $result[$key] = arr::merge($result[$key], $val);
+                                       }
+                                       elseif (is_int($key))
+                                       {
+                                               // Indexed arrays are appended
+                                               array_push($result, $val);
+                                       }
+                                       else
+