+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ */
+uses('object');
+
+/**
+ * Enter description here...
+ *
+ *
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ *
+ */
+class Flay extends Object {
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ */
+ var $text = null;
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ */
+ var $allow_html = false;
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $text
+ */
+ function __construct ($text=null) {
+ $this->text = $text;
+ parent::__construct();
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $text
+ * @return unknown
+ */
+ function to_html ($text=null) {
+ // trim whitespace and disable all HTML
+ $text = str_replace('<', '<', str_replace('>', '>', trim($text? $text: $this->text)));
+
+ // multi-paragraph functions
+ $text = preg_replace('#(?:[\n]{0,2})"""(.*)"""(?:[\n]{0,2})#s', "\n\n%BLOCKQUOTE%\n\n\\1\n\n%ENDBLOCKQUOTE%\n\n", $text);
+ $text = preg_replace('#(?:[\n]{0,2})===(.*)===(?:[\n]{0,2})#s', "\n\n%CENTER%\n\n\\1\n\n%ENDCENTER%\n\n", $text);
+
+ // pre-parse newlines
+ $text = preg_replace("#\r\n#", "\n", $text);
+ $text = preg_replace("#[\n]{2,}#", "%PARAGRAPH%", $text);
+ $text = preg_replace('#[\n]{1}#', "%LINEBREAK%", $text);
+
+ // split into paragraphs and parse
+ $out = '';
+ foreach (split('%PARAGRAPH%', $text) as $line) {
+
+ if ($line) {
+
+ // pre-parse links
+ $links = array();
+ $regs = null;
+ if (preg_match_all('#\[([^\[]{4,})\]#', $line, $regs)) {
+ foreach ($regs[1] as $reg) {
+ $links[] = $reg;
+ $line = str_replace("[{$reg}]",'%LINK'.(count($links)-1).'%', $line);
+ }
+ }
+
+ // MAIN TEXT FUNCTIONS
+ // bold
+ $line = ereg_replace("\*([^\*]*)\*", "\\1", $line);
+ // italic
+ $line = ereg_replace("_([^_]*)_", "\\1", $line);
+ // entities
+ $line = str_replace(' - ', ' – ', $line);
+ $line = str_replace(' -- ', ' — ', $line);
+ $line = str_replace('(C)', '©', $line);
+ $line = str_replace('(R)', '®', $line);
+ $line = str_replace('(TM)', '™', $line);
+
+ // guess e-mails
+ $emails = null;
+ if (preg_match_all("#([_A-Za-z0-9+-+]+(?:\.[_A-Za-z0-9+-]+)*@[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)*)#", $line, $emails)) {
+ foreach ($emails[1] as $email) {
+ $line = str_replace($email, "{$email}", $line);
+ }
+ }
+ // guess links
+ $urls = null;
+ if (preg_match_all("#((?:http|https|ftp|nntp)://[^ ]+)#", $line, $urls)) {
+ foreach ($urls[1] as $url) {
+ $line = str_replace($url, "{$url}", $line);
+ }
+ }
+ if (preg_match_all("#(www\.[^ ]+)#", $line, $urls)) {
+ foreach ($urls[1] as $url) {
+ $line = str_replace($url, "{$url}", $line);
+ }
+ }
+
+
+ // re-parse links
+ if (count($links)) {
+ for ($ii=0; $ii";
+ elseif (preg_match('#^([^\]\ ]+)(?: ([^\]]+))?$#', $links[$ii], $regs))
+ $with = "".(isset($regs[2])? $regs[2]: $regs[1])."";
+ else
+ $with = $links[$ii];
+
+ $line = str_replace("%LINK{$ii}%", $with, $line);
+ }
+ }
+
+ // re-parse newlines
+ $out .= str_replace('%LINEBREAK%', "
\n", "{$line}
\n");
+ }
+ }
+
+ // re-parse multilines
+ $out = str_replace('%BLOCKQUOTE%
', "", $out);
+ $out = str_replace('%ENDBLOCKQUOTE%
', "
", $out);
+ $out = str_replace('%CENTER%
', "", $out);
+ $out = str_replace('%ENDCENTER%
', "", $out);
+
+ return $out;
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $verbose
+ * @return unknown
+ */
+ function test ($verbose=false) {
+ $errors = $tests = 0;
+
+ $tests_to_html = array(
+ array(
+ 'text'=>"",
+ 'html'=>""
+ ),
+ array(
+ 'text'=>"This is a text.",
+ 'html'=>"This is a text.
\n"
+ ),
+ array(
+ 'text'=>"This is a line.\n\n\nThis is\n another one.\n\n",
+ 'html'=>"This is a line.
\nThis is
\n another one.
\n"
+ ),
+ array(
+ 'text'=>"This line has *bold*, _italic_, and a _combo *bold* and italic_ texts.",
+ 'html'=>"This line has bold, italic, and a combo bold and italic texts.
\n"
+ ),
+ array(
+ 'text'=>"This line has tags which are
not allowed.",
+ 'html'=>"This line has <b>tags</b> which are <br />not allowed.
\n",
+ ),
+ array(
+ 'text'=>"[http://sputnik.pl] is a link, but so is [http://sputnik.pl/bla/ this one], and [this is not.",
+ 'html'=>"http://sputnik.pl is a link, but so is this one, and [this is not.
\n"
+ ),
+ array(
+ 'text'=>"Why don't we try to insert an image.\n\n[http://sputnik.pl/test.jpg]",
+ 'html'=>"Why don't we try to insert an image.
\n\n"
+ ),
+ array(
+ 'text'=>"Auto-link my.name+real@my-server.com and example@example.com, should work.",
+ 'html'=>"Auto-link my.name+real@my-server.com and example@example.com, should work.
\n"
+ ),
+ array(
+ 'text'=>"\"\"\"This is a blockquote\"\"\"",
+ 'html'=>"\nThis is a blockquote
\n
\n"
+ ),
+ array(
+ 'text'=>"How about a blockquote?\"\"\"This is a multiline blockquote.\n\nThis is the second line.\"\"\"\nAnd this is not.",
+ 'html'=>"How about a blockquote?
\n\nThis is a multiline blockquote.
\nThis is the second line.
\n
\nAnd this is not.
\n"
+ ),
+ array(
+ 'text'=>"Now auto-link an url such as http://sputnik.pl or www.robocik-malowany.com/dupa[4] - or any other.",
+ 'html'=>"Now auto-link an url such as http://sputnik.pl or www.robocik-malowany.com/dupa[4] – or any other.
\n"
+ ),
+ array(
+ 'text'=>"===This be centered===",
+ 'html'=>"\nThis be centered
\n\n"
+ ),
+ array(
+ 'text'=>"===This be centered.\n\nAnd this be centered too,\nalong with this.===\nThis, alas, be not.",
+ 'html'=>"\nThis be centered.
\nAnd this be centered too,
\nalong with this.
\n\nThis, alas, be not.
\n"
+ ),
+ array(
+ 'text'=>"This tests (C)2004 Someone Else, \"Layer Your Apps(R)\" and Cake(TM).",
+ 'html'=>"This tests ©2004 Someone Else, \"Layer Your Apps®\" and Cake™.
\n"
+ ),
+ );
+
+ foreach ($tests_to_html as $test) {
+ $this->text = $test['text'];
+ if ($test['html'] != ($o = $this->to_html())) {
+ debug ("Flay test error:\n Provided: {$test['text']}\n Expected: {$test['html']}\n Received: {$o}", 1);
+ $errors++;
+ }
+ elseif ($verbose) {
+ debug ("Flay test ok:\n Provided: {$test['text']}\n Received: {$o}", 1);
+ }
+
+ $tests++;
+ }
+
+ debug ("Flay: {$tests} tests, {$errors} errors (".($errors?'FAILED':'PASSED').')');
+
+ return !$errors;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/libs/folder.php b/libs/folder.php
new file mode 100644
index 000000000..a87182967
--- /dev/null
+++ b/libs/folder.php
@@ -0,0 +1,116 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Purpose: Folder
+ * Folder structure browser, lists folders and files.
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ */
+uses('object');
+
+/**
+ * Enter description here...
+ *
+ *
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ *
+ */
+class Folder extends Object {
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ */
+ var $path = null;
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ */
+ var $sort = false;
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $path
+ */
+ function __construct ($path) {
+ $this->path = $path . (preg_match('#\/$#', $path)? '': '/');
+ parent::__construct();
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $sort
+ * @return unknown
+ */
+ function ls($sort=true) {
+ if ($dir = opendir($this->path)) {
+ $dirs = $files = array();
+ while (false !== ($n = readdir($dir))) {
+ if (!preg_match('#^\.+$#', $n)) {
+ if (is_dir($this->path.$n))
+ $dirs[] = $n;
+ else
+ $files[] = $n;
+ }
+ }
+
+ if ($sort || $this->sort) {
+ sort($dirs);
+ sort($files);
+ }
+
+ return array($dirs,$files);
+ }
+ else {
+ return false;
+ }
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $path
+ * @return unknown
+ */
+ function cd ($path) {
+ $new_path = preg('#^/#', $path)? $path: $this->path.$path;
+ return is_dir($new_path)? $this->path = $new_path: false;
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/libs/inflector.php b/libs/inflector.php
new file mode 100644
index 000000000..d5d3ca3c7
--- /dev/null
+++ b/libs/inflector.php
@@ -0,0 +1,253 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Purpose: Inflector
+ * I'm trying to port RoR Inflector class here.
+ * Inflector pluralizes and singularizes english nouns.
+ * Test with $i = new Inflector(); $i->test();
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ */
+uses('object');
+
+/**
+ * Enter description here...
+ *
+ *
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ *
+ */
+class Inflector extends Object {
+ // private
+
+/**
+ * Enter description here...
+ *
+ */
+ function __construct () {
+ parent::__construct();
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $word
+ * @return unknown
+ */
+ function pluralize ($word) {
+ $plural_rules = array(
+ '/(x|ch|ss|sh)$/' => '\1es', # search, switch, fix, box, process, address
+ '/series$/' => '\1series',
+ '/([^aeiouy]|qu)ies$/' => '\1y',
+ '/([^aeiouy]|qu)y$/' => '\1ies', # query, ability, agency
+ '/(?:([^f])fe|([lr])f)$/' => '\1\2ves', # half, safe, wife
+ '/sis$/' => 'ses', # basis, diagnosis
+ '/([ti])um$/' => '\1a', # datum, medium
+ '/person$/' => 'people', # person, salesperson
+ '/man$/' => 'men', # man, woman, spokesman
+ '/child$/' => 'children', # child
+ '/s$/' => 's', # no change (compatibility)
+ '/$/' => 's'
+ );
+ foreach ($plural_rules as $rule => $replacement) {
+ if (preg_match($rule, $word)) {
+ return preg_replace($rule, $replacement, $word);
+ }
+ }
+
+ return false;
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $word
+ * @return unknown
+ */
+ function singularize ($word) {
+ $singular_rules = array(
+ '/(x|ch|ss)es$/' => '\1',
+ '/movies$/' => 'movie',
+ '/series$/' => 'series',
+ '/([^aeiouy]|qu)ies$/' => '\1y',
+ '/([lr])ves$/' => '\1f',
+ '/([^f])ves$/' => '\1fe',
+ '/(analy|ba|diagno|parenthe|progno|synop|the)ses$/' => '\1sis',
+ '/([ti])a$/' => '\1um',
+ '/people$/' => 'person',
+ '/men$/' => 'man',
+ '/status$/' => 'status',
+ '/children$/' => 'child',
+ '/news$/' => 'news',
+ '/s$/' => ''
+ );
+
+ foreach ($singular_rules as $rule => $replacement) {
+ if (preg_match($rule, $word)) {
+ return preg_replace($rule, $replacement, $word);
+ }
+ }
+
+ return false;
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $lower_case_and_underscored_word
+ * @return unknown
+ */
+ function camelize($lower_case_and_underscored_word) {
+ return str_replace(" ","",ucwords(str_replace("_"," ",$lower_case_and_underscored_word)));
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $camel_cased_word
+ * @return unknown
+ */
+ function underscore($camel_cased_word) {
+ $camel_cased_word = preg_replace('/([A-Z]+)([A-Z])/','\1_\2',$camel_cased_word);
+ return strtolower(preg_replace('/([a-z])([A-Z])/','\1_\2',$camel_cased_word));
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $lower_case_and_underscored_word
+ * @return unknown
+ */
+ function humanize($lower_case_and_underscored_word) {
+ return ucwords(str_replace("_"," ",$lower_case_and_underscored_word));
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $class_name
+ * @return unknown
+ */
+ function tableize($class_name) {
+ return Inflector::pluralize(Inflector::underscore($class_name));
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $table_name
+ * @return unknown
+ */
+ function classify($table_name) {
+ return $this->camelize($this->singularize($table_name));
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $class_name
+ * @return unknown
+ */
+ function foreign_key($class_name) {
+ return $this->underscore($class_name) . "_id";
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $verbose
+ */
+ function test ($verbose=false) {
+ $singulars = array(
+ 'search', 'switch', 'fix', 'box', 'process', 'address', 'query', 'ability',
+ 'agency', 'half', 'safe', 'wife', 'basis', 'diagnosis', 'datum', 'medium',
+ 'person', 'salesperson', 'man', 'woman', 'spokesman', 'child', 'page', 'robot');
+ $plurals = array(
+ 'searches', 'switches', 'fixes', 'boxes', 'processes', 'addresses', 'queries', 'abilities',
+ 'agencies', 'halves', 'saves', 'wives', 'bases', 'diagnoses', 'data', 'media',
+ 'people', 'salespeople', 'men', 'women', 'spokesmen', 'children', 'pages', 'robots');
+
+ $pluralize_errors = 0;
+ $singularize_errors = 0;
+ $tests = 0;
+ foreach (array_combine($singulars, $plurals) as $singular => $plural) {
+ if ($this->pluralize($singular) != $plural) {
+ debug ("Inflector test {$singular} yelded ".$this->pluralize($singular)." (expected {$plural})");
+ $pluralize_errors++;
+ }
+ elseif ($verbose) {
+ debug ("Inflector test ok: {$singular} => {$plural}",1);
+ }
+
+ if ($this->singularize($plural) != $singular) {
+ debug ("Inflector test {$plural} yelded ".$this->singularize($plural)." (expected {$singular})");
+ $singularize_errors++;
+ }
+ elseif ($verbose) {
+ debug ("Inflector test ok: {$plural} => {$singular}",1);
+ }
+ $tests++;
+ }
+
+ $errors = $pluralize_errors + $singularize_errors;
+ debug ("Inflector: {$tests} tests, {$errors} errors (".($errors?'FAILED':'PASSED').')');
+ }
+}
+
+
+
+if (!function_exists('array_combine')) {
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $a1
+ * @param unknown_type $a2
+ * @return unknown
+ */
+ function array_combine($a1, $a2) {
+ $a1 = array_values($a1);
+ $a2 = array_values($a2);
+
+ if (count($a1) != count($a2)) return false; // different lenghts
+ if (count($a1) <= 0) return false; // arrays are the same and both are empty
+
+ $output = array();
+
+ for ($i = 0; $i < count($a1); $i++) {
+ $output[$a1[$i]] = $a2[$i];
+ }
+
+ return $output;
+ }
+}
+
+?>
diff --git a/libs/legacy.php b/libs/legacy.php
new file mode 100644
index 000000000..2d1618d5c
--- /dev/null
+++ b/libs/legacy.php
@@ -0,0 +1,41 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * with this hack you can use clone() in PHP4 code
+ * use "clone($object)" not "clone $object"! the former works in both PHP4 and PHP5
+ *
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+if (version_compare(phpversion(), '5.0') < 0) {
+ eval('
+ function clone($object) {
+ return $object;
+ }
+ ');
+}
+
+?>
\ No newline at end of file
diff --git a/libs/model.php b/libs/model.php
new file mode 100644
index 000000000..adb441713
--- /dev/null
+++ b/libs/model.php
@@ -0,0 +1,585 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Purpose: Model
+ * DBO-backed object data model, loosly based on RoR (www.rubyonrails.com).
+ * Automatically selects db table name based on pluralized lowercase object class name
+ * (i.e. class 'User' => table 'users'; class 'Man' => table 'men')
+ * The table is required to have at least 'id auto_increment', 'created datetime',
+ * and 'modified datetime' fields
+ *
+ * To do:
+ * - schema-related cross-table ($has_one, $has_many, $belongs_to)
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ */
+uses('object', 'validators', 'inflector');
+
+/**
+ * Enter description here...
+ *
+ *
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ *
+ */
+class Model extends Object {
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access public
+ */
+ var $parent = false;
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access public
+ */
+ var $use_table = false;
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access public
+ */
+ var $id = false;
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access public
+ */
+ var $data = array();
+ // protected
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access public
+ */
+ var $table = false;
+ // private
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access private
+ */
+ var $_table_info = null;
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access private
+ */
+ var $_one_to_many = array();
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access private
+ */
+ var $_one_to_one = array();
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access private
+ */
+ var $_has_multiple = array();
+
+/**
+ * Enter description here...
+ *
+ * append entries for validation as ('field_name' => '/^perl_compat_regexp$/') that has to match with preg_match()
+ * validate with Model::validate()
+ * @var unknown_type
+ */
+ var $validate = array();
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $id
+ */
+ function __construct ($id=false) {
+ global $DB;
+
+ $this->db = &$DB;
+
+ if ($id)
+ $this->id = $id;
+
+ $table_name = $this->use_table? $this->use_table: Inflector::tableize(get_class($this));
+ $this->use_table ($table_name);
+ parent::__construct();
+
+ $this->create_links();
+ }
+
+/**
+ * Enter description here...
+ *
+ */
+ function create_links () {
+ if (!empty($this->has_many))
+ $this->_has_multiple = explode(',', $this->has_many);
+
+ foreach ($this->_has_multiple as $model_name) {
+ // todo fix strip the model name
+ $model_name = Inflector::singularize($model_name);
+ $this->$model_name = new $model_name();
+ }
+
+ $this->relink();
+ }
+
+/**
+ * Enter description here...
+ *
+ */
+ function relink () {
+ foreach ($this->_has_multiple as $model) {
+ $name = Inflector::singularize($model);
+ $this->$name->clear_links();
+ $this->$name->link_many_to_one(get_class($this), $this->id);
+ }
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $model_name
+ * @param unknown_type $value
+ */
+ function link_many_to_one ($model_name, $value=null) {
+ $table_name = Inflector::tableize($model_name);
+ $field_name = Inflector::singularize($table_name).'_id';
+ $this->_one_to_many[] = array($table_name, $field_name, $value);
+ }
+
+/**
+ * Enter description here...
+ *
+ */
+ function clear_links () {
+ $this->_one_to_many = array();
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $table_name
+ */
+ function use_table ($table_name) {
+ if (!in_array($table_name, $this->db->tables()))
+ trigger_error (sprintf(ERROR_NO_MODEL_TABLE, get_class($this), $table_name), E_USER_ERROR);
+ else {
+ $this->table = $table_name;
+ $this->load_info();
+ }
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $one
+ * @param unknown_type $two
+ * @return unknown
+ */
+ function set ($one, $two=null) {
+ $data = is_array($one)? $one: array($one=>$two);
+
+ foreach ($data as $n => $v) {
+ if (!$this->has_field($n)) {
+ DEBUG?
+ trigger_error(sprintf(ERROR_NO_FIELD_IN_MODEL_DB, $n, $this->table), E_USER_ERROR):
+ trigger_error('Application error occured, trying to set a field name that doesn\'t exist.', E_USER_WARNING);
+ }
+
+ $n == 'id'? $this->id = $v: $this->data[$n] = $v;
+ }
+
+ return $data;
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $id
+ */
+ function set_id ($id) {
+ $this->id = $id;
+ $this->relink();
+ }
+
+/**
+ * Enter description here...
+ *
+ */
+ function load_info () {
+ if (empty($this->_table_info))
+ $this->_table_info = new neatArray($this->db->fields($this->table));
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $name
+ * @return unknown
+ */
+ function has_field ($name) {
+ return $this->_table_info->find_in('Field', $name);
+ }
+
+
+ // returns data from db
+ // requires $this->id
+ // expects coma-separated field list, array of field names, or empty for all fields
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $fields
+ * @return unknown
+ */
+ function read ($fields=null) {
+ return $this->id? $this->find("id = '{$this->id}'", $fields): false;
+ }
+
+ // returns a field value from db
+ // requires $this->id
+ // requires a field name
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $name
+ * @return unknown
+ */
+ function field ($name) {
+ if (isset($this->data[$name]))
+ return $this->data[$name];
+ else {
+ if ($this->id && $data = $this->read($name)) {
+ return isset($data[$name])? $data[$name]: false;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+
+ // saves $this->data to db
+ // if $this->id is set, updates a record, else inserts a records
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $data
+ * @return unknown
+ */
+ function save ($data=null) {
+ if ($data) $this->set($data);
+
+ if (!$this->validates())
+ return false;
+
+ $lines = array();
+ foreach ($this->data as $n => $v)
+ $lines[] = "{$n} = '{$v}'";
+
+ // finds if 'created' and 'updated' fields exists and generates sql to handle them
+ $update_sql = array();
+ if ($this->has_field('created') && !$this->id) $update_sql[] = 'created = NOW()';
+ if ($this->has_field('modified')) $update_sql[] = 'modified = NOW()';
+ $update_sql = count($update_sql)? ', '.join(', ', $update_sql): null;
+
+ if (count($lines)) {
+
+ if ($this->id) {
+ if ($this->db->q("UPDATE {$this->table} SET ".join(', ', $lines)."{$update_sql} WHERE id = '{$this->id}'")
+ && $this->db->last_affected()) {
+ $this->data = false;
+ return true;
+ }
+ else
+ return $this->db->has_any($this->table, "id = '{$this->id}'");
+ }
+ else {
+ if ($this->db->q("INSERT INTO {$this->table} SET ".join(', ', $lines).$update_sql)) {
+ $this->id = $this->db->last_insert_id();
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ // deletes a record from db
+ // requires $this->id
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $id
+ * @return unknown
+ */
+ function remove ($id=null) {
+ return $this->del($id);
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $id
+ * @return unknown
+ */
+ function del ($id=null) {
+ if ($id) $this->id = $id;
+ if ($this->id && $this->db->q("DELETE FROM {$this->table} WHERE id = '{$this->id}'")) {
+ $this->id = false;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ // returns true if record exists in db
+ // requires $this->id
+/**
+ * Enter description here...
+ *
+ * @return unknown
+ */
+ function exists () {
+ return $this->id? $this->db->has_any($this->table, "id = '{$this->id}'"): false;
+ }
+
+ // returns a row if found, or otherwise null
+ // expects sql conditions, or empty for no conditions
+ // expects coma-separated fields list, array of field names, or empty for all fields
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $conditions
+ * @param unknown_type $fields
+ * @return unknown
+ */
+ function find ($conditions = null, $fields = null) {
+ $data = $this->find_all($conditions, $fields, null, 1);
+ return empty($data[0])? false: $data[0];
+ }
+
+ // returns specified fields from db records matching conditions
+ // expects sql conditions, or empty for no conditions
+ // expects coma-separated fields list, array of field names, or empty for all fields
+ // expects sql order, or empty for default order
+ // expects limit, or empty for no limit
+ // expects page number for offset, or empty for no offset
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $conditions
+ * @param unknown_type $fields
+ * @param unknown_type $order
+ * @param unknown_type $limit
+ * @param unknown_type $page
+ * @return unknown
+ */
+ function find_all ($conditions = null, $fields = null, $order = null, $limit = null, $page = null) {
+ if (is_array($fields))
+ $f = $fields;
+ elseif ($fields)
+ $f = array($fields);
+ else
+ $f = array('*');
+
+ $joins = $whers = array();
+
+ foreach ($this->_one_to_many as $rule) {
+ list($table, $field, $value) = $rule;
+ $joins[] = "LEFT JOIN {$table} ON {$this->table}.{$field} = {$table}.id";
+ $whers[] = "{$this->table}.{$field} = '{$value}'";
+ }
+
+ $joins = count($joins)? join(' ', $joins): null;
+ $whers = count($whers)? '('.join(' AND ', $whers).')': null;
+ $conditions .= ($conditions && $whers? ' AND ': null).$whers;
+
+ $data = $this->db->all(
+ "SELECT "
+ .join(', ', $f)
+ ." FROM {$this->table} {$joins}"
+ .($conditions? " WHERE {$conditions}":null)
+ .($order? " ORDER BY {$order}": null)
+ .($limit? " LIMIT ".($page>0? $limit*($page-1): '0').",{$limit}": null), false, MYSQL_ASSOC);
+
+ return $data;
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $sql
+ * @param unknown_type $debug
+ * @return unknown
+ */
+ function find_by_sql ($sql, $debug=0) {
+ return $this->db->all($sql, $debug);
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $conditions
+ * @param unknown_type $fields
+ * @return unknown
+ */
+ function find_all_threaded ($conditions=null, $fields=null) {
+ return $this->_do_thread($this->find_all($conditions, $fields), null);
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $conditions
+ * @return unknown
+ */
+ function find_count ($conditions) {
+ list($data) = $this->find_all($conditions, 'COUNT(id) AS count');
+ return $data['count'];
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $data
+ * @param unknown_type $root
+ * @return unknown
+ */
+ function _do_thread ($data, $root) {
+ $out = array();
+
+ for ($ii=0; $ii_do_thread($data, $data[$ii]['id']): null;
+ $out[] = $tmp;
+ }
+ }
+
+ return $out;
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $conditions
+ * @param unknown_type $field
+ * @param unknown_type $value
+ * @return unknown
+ */
+ function find_neighbours ($conditions, $field, $value) {
+ list($prev) = $this->find_all($conditions." AND {$field} < '{$value}'", $field, "{$field} DESC", 1);
+ list($next) = $this->find_all($conditions." AND {$field} > '{$value}'", $field, "{$field} ASC", 1);
+
+ return array('prev'=>$prev['id'], 'next'=>$next['id']);
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $sql
+ * @return unknown
+ */
+ function query ($sql) {
+ return $this->db->q($sql);
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $data
+ * @return unknown
+ */
+ function validates ($data=null) {
+ $errors = count($this->invalid_fields($data));
+
+ return $errors == 0;
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $data
+ * @return unknown
+ */
+ function invalid_fields ($data=null) {
+ return $this->_invalid_fields($data);
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $data
+ * @return unknown
+ */
+ function _invalid_fields ($data=null) {
+ if (!isset($this->validate))
+ return true;
+
+ $data = ($data? $data: (isset($this->data)? $this->data: array()));
+ $errors = array();
+
+ foreach ($this->validate as $field_name=>$validator) {
+ if (isset($data[$field_name])) {
+ if (!preg_match($validator, $data[$field_name]))
+ $errors[$field_name] = 1;
+ }
+ }
+
+ return $errors;
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/libs/object.php b/libs/object.php
new file mode 100644
index 000000000..50e9ab0a9
--- /dev/null
+++ b/libs/object.php
@@ -0,0 +1,61 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Purpose: Object
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ *
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ *
+ */
+class Object {
+/**
+ * Enter description here...
+ *
+ * @return Object
+ */
+ function Object() {
+ $args= func_get_args();
+ call_user_func_array(array(&$this, '__construct'), $args);
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $args
+ */
+ function __construct($args=NULL) {
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/libs/router.php b/libs/router.php
new file mode 100644
index 000000000..230015e40
--- /dev/null
+++ b/libs/router.php
@@ -0,0 +1,142 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Purpose: Router
+ * Parses the request URL into controller, action, and params
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ */
+uses('object');
+
+/**
+ * Enter description here...
+ *
+ *
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ *
+ */
+class Router extends Object {
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ */
+ var $routes = array();
+
+/**
+ * Enter description here...
+ *
+ */
+ function __construct () {
+ parent::__construct();
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $route
+ * @param unknown_type $default
+ */
+ function connect ($route, $default=null) {
+ $parsed = $names = array ();
+
+ $r = null;
+ if ($route == '' || $route == '/') {
+ $this->routes[] = array('/^[\/]*$/', array(), $default);
+ }
+ else {
+ if (@preg_match_all('|(?:/([^/]+))|', $route, $r)) {
+
+ foreach ($r[1] as $element) {
+ if (preg_match('/^:(.+)$/', $element, $r)) {
+ $parsed[] = '(?:\/([^\/]+))?';
+ $names[] = $r[1];
+ }
+ elseif (preg_match('/^\*$/', $element, $r)) {
+ $parsed[] = '(.*)';
+ }
+ else {
+ $parsed[] = '/'.$element;
+ }
+ }
+ $regexp = '#^'.join('', $parsed).'$#';
+
+ $this->routes[] = array($regexp,$names,$default);
+ }
+ }
+
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $url
+ * @return unknown
+ */
+ function parse ($url) {
+ $out = array();
+ $r = null;
+
+ foreach ($this->routes as $route) {
+ list($regexp,$names,$defaults) = $route;
+
+ if (@preg_match($regexp, $url, $r)) {
+
+ array_shift($r);
+ $ii = 0;
+ foreach ($r as $found) {
+ if (isset($names[$ii]))
+ $out[$names[$ii]] = $found;
+ elseif (preg_match_all('/(?:\/([^\/]+))/', $found, $r)) {
+ $out['pass'] = $r[1];
+ }
+ $ii++;
+ }
+
+ if (is_array($defaults)) {
+ foreach ($defaults as $name => $value) {
+ if (preg_match('/[a-zA-Z_\-]/', $name))
+ $out[$name] = $value;
+ else
+ $out['pass'][] = $value;
+ }
+ }
+ break;
+ }
+ }
+
+ return $out;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/libs/template.php b/libs/template.php
new file mode 100644
index 000000000..82394a947
--- /dev/null
+++ b/libs/template.php
@@ -0,0 +1,289 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Purpose: Renderer
+ * Templating for Controller class.
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ */
+uses('object');
+
+/**
+ * Enter description here...
+ *
+ *
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ *
+ */
+class Template extends Object {
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access public
+ */
+ var $base = null;
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access public
+ */
+ var $layout = 'default';
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access public
+ */
+ var $auto_render = true;
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access public
+ */
+ var $auto_layout = true;
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access private
+ */
+ var $_view_vars = array();
+
+/**
+ * Enter description here...
+ *
+ * @var unknown_type
+ * @access private
+ */
+ var $_page_title = false;
+
+/**
+ * Enter description here...
+ *
+ */
+ function __construct () {
+ parent::__construct();
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $layout
+ */
+ function set_layout ($layout) {
+ $this->layout = $layout;
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $one
+ * @param unknown_type $two
+ * @return unknown
+ */
+ function set($one, $two=null) {
+ return $this->_set_array(is_array($one)? $one: array($one=>$two));
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $value
+ */
+ function set_title ($value) {
+ $this->_page_title = $value;
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $data
+ */
+ function _set_array($data) {
+ foreach ($data as $name => $value) {
+ if ($name == 'title')
+ $this->set_title ($value);
+ else
+ $this->_view_vars[$name] = $value;
+ }
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $message
+ * @param unknown_type $url
+ * @param unknown_type $time
+ */
+ function flash ($message, $url, $time=1) {
+ $this->auto_render = false;
+ $this->auto_layout = false;
+
+ $this->set('url', $this->base.$url);
+ $this->set('message', $message);
+ $this->set('time', $time);
+
+ $this->render(null,false,VIEWS.'layouts/flash.thtml');
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $action
+ * @param unknown_type $layout
+ * @param unknown_type $file
+ */
+ function render ($action=null, $layout=null, $file=null) {
+ $this->auto_render = false;
+
+ if (!$action) $action = $this->action;
+ if ($layout) $this->set_layout($layout);
+
+ $view_fn = $file? $file: $this->_get_view_fn($action);
+
+ if (!is_file($view_fn)) {
+ DEBUG? trigger_error (sprintf(ERROR_NO_VIEW, $action, $view_fn), E_USER_ERROR)
+ : $this->error('404', 'Not found', sprintf(ERROR_404, '', "missing view \"{$action}\""));
+ die();
+ }
+
+ $out = $this->_do_render($view_fn, $this->_view_vars, 0);
+
+ if ($out !== false) {
+ if ($this->layout && $this->auto_layout) $out = $this->render_layout($out);
+ if (CACHE_PAGES) $this->cache->append($out);
+ print $out;
+ }
+ else {
+ $out = $this->_do_render($view_fn, $this->_view_vars, false);
+ trigger_error (sprintf(ERROR_IN_VIEW, $view_fn, $out), E_USER_ERROR);
+ }
+
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $content_for_layout
+ * @return unknown
+ */
+ function render_layout ($content_for_layout) {
+ $layout_fn = $this->_get_layout_fn();
+
+ $data_for_layout = array_merge($this->_view_vars, array(
+ 'title_for_layout'=>$this->_page_title !== false? $this->_page_title: ucfirst($this->name),
+ 'content_for_layout'=>$content_for_layout));
+
+ if (is_file($layout_fn)) {
+ $out = $this->_do_render($layout_fn, $data_for_layout);
+
+ if ($out === false) {
+ $out = $this->_do_render($layout_fn, $data_for_layout, false);
+ trigger_error (sprintf(ERROR_IN_LAYOUT, $layout_fn, $out), E_USER_ERROR);
+ return false;
+ }
+ else {
+ return $out;
+ }
+ }
+ else {
+ trigger_error (sprintf(ERROR_NO_LAYOUT, $this->layout, $layout_fn), E_USER_ERROR);
+ return false;
+ }
+ }
+
+/**
+ * Enter description here...
+ *
+ * @return unknown
+ */
+ function _get_layout_fn() {
+ return VIEWS."layouts/{$this->layout}.thtml";
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $action
+ * @return unknown
+ */
+ function _get_view_fn($action) {
+ return VIEWS.$this->name."/{$action}.thtml";
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $___view_fn
+ * @param unknown_type $___data_for_view
+ * @param unknown_type $___play_safe
+ * @return unknown
+ */
+ function _do_render($___view_fn, $___data_for_view, $___play_safe = true) {
+ extract($___data_for_view, EXTR_SKIP); # load all view variables
+ $BASE = $this->base;
+ $params = &$this->params;
+ $page_title = $this->_page_title;
+ ob_start(); # start caching output (eval outputs directly so we need to cache)
+
+ # include the template
+ $___play_safe? @include($___view_fn): include($___view_fn);
+
+ $out = ob_get_contents(); # retrieve cached output
+ ob_end_clean(); # end caching output
+
+ return $out;
+ }
+
+/**
+ * Enter description here...
+ *
+ * trims a string to a specified length adding elipsis '..' if necessary
+ *
+ * @param unknown_type $string
+ * @param unknown_type $length
+ * @return unknown
+ */
+ function trim_to ($string, $length) {
+ return substr($string, 0, $length).(strlen($string)>$length? '..': null);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/libs/time.php b/libs/time.php
new file mode 100644
index 000000000..b4b1d0b98
--- /dev/null
+++ b/libs/time.php
@@ -0,0 +1,121 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Purpose: Time
+ * Time related functions, formatting for dates etc.
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ */
+uses ('object');
+
+/**
+ * Enter description here...
+ *
+ *
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ *
+ */
+class Time extends Object {
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $date_string
+ * @return unknown
+ */
+ function nice ($date_string=null) {
+ $date = $date_string? strtotime($date_string): time();
+ return date("D, M jS Y, H:i", $date);
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $date_string
+ * @return unknown
+ */
+ function nice_short ($date_string=null) {
+ $date = $date_string? Time::fromString($date_string): time();
+
+ $y = Time::isThisYear($date)? '': ' Y';
+
+ if (Time::isToday($date))
+ return "Today, ".date("H:i", $date);
+ elseif (Time::wasYesterday($date))
+ return "Yesterday, ".date("H:i", $date);
+ else
+ return date("M jS{$y}, H:i", $date);
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $date
+ * @return unknown
+ */
+ function isToday ($date) {
+ return date('Y-m-d', $date) == date('Y-m-d', time());
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $date
+ * @return unknown
+ */
+ function isThisYear ($date) {
+ return date('Y', $date) == date('Y', time());
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $date
+ * @return unknown
+ */
+ function wasYesterday ($date) {
+ return date('Y-m-d', $date) == date('Y-m-d', strtotime('yesterday'));
+ }
+
+/**
+ * Enter description here...
+ *
+ * @param unknown_type $date_string
+ * @return unknown
+ */
+ function fromString ($date_string) {
+ return strtotime($date_string);
+ }
+
+}
+
+?>
\ No newline at end of file
diff --git a/libs/validators.php b/libs/validators.php
new file mode 100644
index 000000000..1b92a9842
--- /dev/null
+++ b/libs/validators.php
@@ -0,0 +1,62 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Purpose: Tort Validators
+ * Used to validate data in Models.
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.libs
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ */
+define('VALID_NOT_EMPTY', '/.+/');
+
+/**
+ * Enter description here...
+ *
+ */
+define('VALID_NUMBER', '/^[0-9]+$/');
+
+/**
+ * Enter description here...
+ *
+ */
+define('VALID_EMAIL', '/^([a-z0-9][a-z0-9_\-\.\+]*)@([a-z0-9][a-z0-9\.\-]{0,63}\.[a-z]{2,3})$/i');
+
+/**
+ * Enter description here...
+ *
+ */
+define('VALID_TAG', '/[a-z_]+/i');
+
+/**
+ * Enter description here...
+ *
+ */
+define('VALID_TAGS', '/[a-z_ ]+/i');
+
+?>
\ No newline at end of file
diff --git a/public/.htaccess b/public/.htaccess
new file mode 100644
index 000000000..bee15b3c9
--- /dev/null
+++ b/public/.htaccess
@@ -0,0 +1,9 @@
+# Based on Rails 0.10.0 .htaccess (www.rubyonrails.com)
+
+# Redirect all requests not available on the filesystem to Cake
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^(.*)$ dispatch.php?url=$1 [QSA,L]
+
+# In case Cake experiences terminal errors
+ErrorDocument 500 500.html
diff --git a/public/500.html b/public/500.html
new file mode 100644
index 000000000..1eddd44c1
--- /dev/null
+++ b/public/500.html
@@ -0,0 +1,11 @@
+
+
+
+500 Server error
+
+
+
+Server error
+Cake has experienced a terminal error and it cannot continue. Please check your web server configuration.
+
+
diff --git a/public/css/default.css b/public/css/default.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/public/dispatch.php b/public/dispatch.php
new file mode 100644
index 000000000..6f0afaff6
--- /dev/null
+++ b/public/dispatch.php
@@ -0,0 +1,110 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Purpose: Dispatch
+ * The main "loop"
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.public
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+
+## DIRECTORY LAYOUT
+/**
+ * Enter description here...
+ *
+ */
+define ('ROOT', '../');
+/**
+ * Enter description here...
+ *
+ */
+define ('APP', ROOT.'app/');
+/**
+ * Enter description here...
+ *
+ */
+define ('MODELS', APP.'models/');
+/**
+ * Enter description here...
+ *
+ */
+define ('CONTROLLERS', APP.'controllers/');
+/**
+ * Enter description here...
+ *
+ */
+define ('VIEWS', APP.'views/');
+/**
+ * Enter description here...
+ *
+ */
+define ('CONFIGS', ROOT.'config/');
+/**
+ * Enter description here...
+ *
+ */
+define ('LIBS', ROOT.'libs/');
+/**
+ * Enter description here...
+ *
+ */
+define ('PUBLIC', ROOT.'public/');
+
+## STARTUP
+/**
+ * Enter description here...
+ *
+ */
+require (LIBS.'basics.php');
+uses ('dispatcher', 'dbo');
+uses_config();
+uses_database();
+uses_tags();
+
+## LOAD MODELS & CONTROLLERS
+##
+load_models ();
+load_controllers ();
+
+## START SESSION
+##
+session_start();
+
+## RUN THE SCRIPT
+##
+$url = empty($_GET['url'])? null: $_GET['url'];
+$DISPATCHER = new Dispatcher ();
+$DISPATCHER->dispatch($url);
+
+## PRINT TIMING
+##
+
+/**
+ * Enter description here...
+ *
+ */
+if (DEBUG) echo "";
+
+?>
diff --git a/public/files/put_downloadable_files_here b/public/files/put_downloadable_files_here
new file mode 100644
index 000000000..e69de29bb
diff --git a/public/img/put_images_here b/public/img/put_images_here
new file mode 100644
index 000000000..e69de29bb
diff --git a/public/index.php b/public/index.php
new file mode 100644
index 000000000..f20982f0c
--- /dev/null
+++ b/public/index.php
@@ -0,0 +1,36 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Enter description here...
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.public
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+
+/**
+ * Enter description here...
+ *
+ */
+header ('dispatch.php?url='.ltrim($_SERVER['PATH_INFO'],'/'));
+?>
diff --git a/scripts/add.bat b/scripts/add.bat
new file mode 100644
index 000000000..2eb456cfc
--- /dev/null
+++ b/scripts/add.bat
@@ -0,0 +1 @@
+@php -q scripts/add.php %1 %2 %3 %4 %5 %6 %7 %8 %9
\ No newline at end of file
diff --git a/scripts/add.php b/scripts/add.php
new file mode 100644
index 000000000..c2d4a2289
--- /dev/null
+++ b/scripts/add.php
@@ -0,0 +1,91 @@
+ + //
+// + Copyright: (c) 2005 Michal Tatarynowicz + //
+// + + //
+// + Author(s): (c) 2005 Michal Tatarynowicz + //
+// + + //
+// +------------------------------------------------------------------+ //
+// + Licensed under the Public Domain Licence + //
+// +------------------------------------------------------------------+ //
+//////////////////////////////////////////////////////////////////////////
+
+/**
+ * Enter description here...
+ *
+ * @filesource
+ * @modifiedby $LastChangedBy$
+ * @lastmodified $Date$
+ * @author Michal Tatarynowicz
+ * @copyright Copyright (c) 2005, Michal Tatarynowicz
+ * @package cake
+ * @subpackage cake.scripts
+ * @since Cake v 0.2.9
+ * @version $Revision$
+ * @license Public_Domain
+ *
+ */
+## DIRECTORIES
+##
+/**
+ * Enter description here...
+ *
+ */
+define ('ROOT', '../');
+
+/**
+ * Enter description here...
+ *
+ */
+define ('APP', ROOT.'app/');
+
+/**
+ * Enter description here...
+ *
+ */
+define ('MODELS', APP.'models/');
+
+/**
+ * Enter description here...
+ *
+ */
+define ('CONTROLLERS', APP.'controllers/');
+
+/**
+ * Enter description here...
+ *
+ */
+define ('VIEWS', APP.'views/');
+
+/**
+ * Enter description here...
+ *
+ */
+define ('CONFIGS', ROOT.'config/');
+
+/**
+ * Enter description here...
+ *
+ */
+define ('LIBS', ROOT.'libs/');
+
+/**
+ * Enter description here...
+ *
+ */
+define ('PUBLIC', ROOT.'public/');
+
+## LOAD LIBRARIES
+##
+require (LIBS.'basics.php');
+uses ('bake');
+#load_libs ();
+
+$script_name = array_shift($argv);
+$action = array_shift($argv);
+
+$bake = new Bake ($action, $argv);
+
+?>
\ No newline at end of file