Browse Source

Initial Commit

Michael Francis 14 năm trước cách đây
commit
2389d66da8
100 tập tin đã thay đổi với 4727 bổ sung0 xóa
  1. 319 0
      ACL.php
  2. 67 0
      CSRF
  3. BIN
      config/.DS_Store
  4. 86 0
      config/bootstrap.php
  5. BIN
      config/bootstrap/.DS_Store
  6. 55 0
      config/bootstrap/action.php
  7. 135 0
      config/bootstrap/auth.php
  8. 62 0
      config/bootstrap/cache.php
  9. 72 0
      config/bootstrap/connections.php
  10. 19 0
      config/bootstrap/console.php
  11. 37 0
      config/bootstrap/error.php
  12. 28 0
      config/bootstrap/errors.php
  13. 149 0
      config/bootstrap/g11n.php
  14. 127 0
      config/bootstrap/libraries.php
  15. 63 0
      config/bootstrap/media.php
  16. 49 0
      config/bootstrap/session.php
  17. 149 0
      config/routes.php
  18. 100 0
      controllers/AdminController.php
  19. 77 0
      controllers/AnimelistController.php
  20. 62 0
      controllers/ContentController.php
  21. 79 0
      controllers/FeedsController.php
  22. 36 0
      controllers/PagesController.php
  23. 41 0
      controllers/PhotosController.php
  24. 75 0
      controllers/ProfileController.php
  25. 41 0
      controllers/ProfilesController.php
  26. 37 0
      controllers/SearchController.php
  27. 25 0
      controllers/TopicController.php
  28. 473 0
      controllers/UsersController.php
  29. 0 0
      extensions/adapter/empty
  30. 59 0
      extensions/command/ImportUsers.php
  31. 0 0
      extensions/command/empty
  32. 0 0
      extensions/data/source/empty
  33. 0 0
      extensions/helper/empty
  34. 11 0
      index.php
  35. BIN
      libraries/.DS_Store
  36. 0 0
      libraries/_source/empty
  37. 1 0
      libraries/li3_access
  38. 1 0
      libraries/li3_flash_message
  39. 1 0
      libraries/li3_paginate
  40. 765 0
      libraries/openID/openid.php
  41. 8 0
      models/Anime.php
  42. 9 0
      models/Entry.php
  43. 62 0
      models/Photo.php
  44. 137 0
      models/Post.php
  45. 17 0
      models/Profile.php
  46. 28 0
      models/ProfilePic.php
  47. 13 0
      models/Topic.php
  48. 347 0
      models/User.php
  49. 46 0
      models/confirmKey.php
  50. 17 0
      models/contentList.php
  51. 18 0
      models/untitled.php
  52. 0 0
      resources/g11n/empty
  53. 0 0
      resources/tmp/logs/empty
  54. 0 0
      resources/tmp/tests/empty
  55. 19 0
      tests/cases/controllers/PhotosControllerTest.php
  56. 19 0
      tests/cases/controllers/ProfilesControllerTest.php
  57. 0 0
      tests/cases/controllers/empty
  58. 0 0
      tests/cases/extensions/adapter/empty
  59. 0 0
      tests/cases/extensions/command/empty
  60. 1 0
      tests/cases/extensions/data/source/empty
  61. 0 0
      tests/cases/extensions/helper/empty
  62. 16 0
      tests/cases/models/PhotoTest.php
  63. 16 0
      tests/cases/models/ProfileTest.php
  64. 0 0
      tests/cases/models/empty
  65. 0 0
      tests/functional/empty
  66. 0 0
      tests/integration/empty
  67. 0 0
      tests/mocks/empty
  68. BIN
      views/.DS_Store
  69. 11 0
      views/Admin/editUser.html.php
  70. 99 0
      views/Admin/index.html.php
  71. 103 0
      views/Admin/users.html.php
  72. 33 0
      views/Anime_list/add.html.php
  73. 3 0
      views/Anime_list/index.html
  74. 74 0
      views/Anime_list/index.html.php
  75. 84 0
      views/Anime_list/view.html.php
  76. 68 0
      views/Content/anime.html.php
  77. 7 0
      views/Content/index.html.php
  78. BIN
      views/Feeds/.DS_Store
  79. BIN
      views/Feeds/Carbon_files/avatar_9318cab29a1a_96.png
  80. BIN
      views/Feeds/Carbon_files/bg_caption.png
  81. BIN
      views/Feeds/Carbon_files/bg_search.png
  82. BIN
      views/Feeds/Carbon_files/bg_search_focus.png
  83. BIN
      views/Feeds/Carbon_files/bg_sidebar.png
  84. BIN
      views/Feeds/Carbon_files/bg_texture.png
  85. BIN
      views/Feeds/Carbon_files/button_nav_left.png
  86. BIN
      views/Feeds/Carbon_files/button_nav_right.png
  87. BIN
      views/Feeds/Carbon_files/caption_bot.png
  88. BIN
      views/Feeds/Carbon_files/caption_top.png
  89. 5 0
      views/Feeds/Carbon_files/count-1.js
  90. BIN
      views/Feeds/Carbon_files/count.js
  91. BIN
      views/Feeds/Carbon_files/divider.png
  92. BIN
      views/Feeds/Carbon_files/icon_comment.png
  93. BIN
      views/Feeds/Carbon_files/icon_fav.png
  94. BIN
      views/Feeds/Carbon_files/icon_link.png
  95. BIN
      views/Feeds/Carbon_files/icon_rss.png
  96. BIN
      views/Feeds/Carbon_files/icon_source.png
  97. BIN
      views/Feeds/Carbon_files/icon_tag.png
  98. 166 0
      views/Feeds/Carbon_files/jquery.min.js
  99. BIN
      views/Feeds/Carbon_files/photo_corner.png
  100. BIN
      views/Feeds/Carbon_files/portrait_frame.png

+ 319 - 0
ACL.php

@@ -0,0 +1,319 @@
+To Configure
+
+<?php
+
+Access::config(array(
+	'permissions' => array(
+		'adapter'   => 'Permissions',
+		'model'     => 'app\models\Perms',
+		'defaultNoUser'   => array(),
+		'defaultUser' => array(
+			'route' => array(
+				'users' => array(
+					'logout', 'account'
+				)
+			)
+		),
+		'userIdentifier' => 'PrincipalID'
+	)
+));
+
+Perms::applyFilter('find', function($self, $params, $chain) {
+	if($params['type'] != 'first') {
+		return $chain->next($self, $params, $chain);
+	}
+	$cacheKey = 'permissions_' . $params['options']['conditions']['id'];
+	$cache = Cache::read('default', $cacheKey);
+	if($cache) {
+		return $cache;
+	}
+	$result = $chain->next($self, $params, $chain);
+	Cache::write('default', $cacheKey, $result, '+1 day');
+	return $result;
+});
+?>
+
+<?php
+
+namespace li3_access\extensions\adapter\security\access;
+
+use lithium\core\ConfigException;
+use lithium\util\Set;
+
+class Permissions extends \lithium\core\Object {
+	const pathRoute = 'route';
+	const pathCustom = 'custom';
+	protected $_model = null;
+	public function __construct(array $config = array()) {
+		$defaults = array(
+			'model' => 'app\models\perms',
+			'defaultNoUser'  => array(),
+			'defaultUser' => array(),
+			'userIdentifier' => 'id'
+		);
+		parent::__construct($config + $defaults);
+		$this->_model = $this->_config['model'];
+	}
+
+	/**
+	 * @throws \lithium\core\ConfigException
+	 * @param  $user
+	 * @param  $request
+	 * @param array $options
+	 * @return array
+	 */
+	public function check($user, $request, array $options = array()) {
+		$config = $this->_config;
+		$model = $this->_model;
+		$params = compact('user', 'request', 'options');
+		return $this->_filter(__METHOD__, $params, function($self, $params) use($config, $model) {
+			$user = $params['user'];
+			$request = $params['request'];
+			$options = $params['options'];
+			$reqIsObject = is_object($request);
+			$path = array();
+
+			switch (true) {
+				case $reqIsObject:
+					$path = array(
+						Permissions::pathRoute,
+						$request->params['controller'],
+						$request->params['action']
+						);
+					break;
+				case (!$reqIsObject && is_string($request)):
+					$path = explode('.', $request);
+					array_unshift($path, Permissions::pathCustom);
+					break;
+				case (!$reqIsObject && is_array($request)):
+					$path = $request;
+					break;
+			}
+			switch(true) {
+				case !$user:
+					$hasAccess = $self->_processPath($path, $config['defaultNoUser']);
+					return $hasAccess ? false : $options;
+				case ($result = $self->_processPath($path, $config['defaultUser'])):
+					return $result ? false : $options;
+				default:
+					$userId = $config['userIdentifier'];
+					if(!isset($user[$userId])) {
+						$message = "The user identifier '{$userId}' is not available.";
+						throw new ConfigException($message);
+					}
+					$perms = $model::find('first', array(
+						'conditions' => array(
+							'id' =>  $user[$userId]
+						)
+					));
+					if(!$perms) {
+						return false;
+					}
+					$userPath = unserialize($perms->perms);
+					$result = $self->_processPath($path, $userPath);
+					return $result ? array() : $options;
+			}
+		});
+	}
+
+	/**
+	 * Adds a custom route to the users permission list.
+	 *
+	 * $customRoute is formatted as a dot path string, this is done as 'foo.bar.baz' for example.
+	 * Asterisks are usable at the end of the path however not in the middle. A user with access
+	 * to 'foo.bar.*' will have access to foo.bar.baz, foo.bar.aaa etc.
+	 *
+	 * @param  $user
+	 * @param  $customRoute
+	 * @return bool
+	 */
+	public function addCustomPath($user, $customRoute) {
+		if(!is_string($customRoute)) {
+			return false;
+		}
+		$parts = explode('.', $customRoute);
+		$value = array_pop($parts);
+		$parts = array_merge((array)self::pathCustom, $parts, (array)0);
+		return $this->add($user, Set::expand(array(implode('.', $parts) => $value)));
+	}
+
+	/**
+	 * Adds an action to the users permission list. If the action is set to * the user will have
+	 * access to all of the controllers actions.
+	 */
+	public function addAction($user, $controller, $action) {
+		return $this->add($user, array(
+			self::pathRoute => array(
+				$controller => array(
+					$action
+				)
+			)
+		));
+	}
+
+	/**
+	 * $user must contain the 'userIdentifier' key defined in config
+	 * $paths are the paths which are to be added this is an array representation of the path and
+	 * is from the origin, so 'route' or 'custom' must be specified. Multiple paths can be defined
+	 * using this function
+	 *
+	 * @throws \lithium\core\ConfigException
+	 * @param  $user
+	 * @param array $paths
+	 * @return bool
+	 */
+	public function add($user, array $paths = array()) {
+		$model = $this->_model;
+		$userId = $this->_config['userIdentifier'];
+		$params = compact('model', 'userId', 'user', 'paths');
+		return $this->_filter(__METHOD__, $params, function($self, $params) {
+			$model = $params['model'];
+			$userId = $params['userId'];
+			$user = $params['user'];
+			$paths = $params['paths'];
+
+			if(!isset($user[$userId])) {
+				throw new ConfigException("The user identifier '{$userId}' is not available.");
+			}
+			$result = $model::find('first', array(
+				'conditions' => array(
+					'id' => $user[$userId]
+				)
+			));
+			if(!$result) {
+				$perms = $model::create(array(
+					'id' => $user[$userId],
+					'perms' => serialize($paths)
+				));
+				return $perms->save();
+			}
+			$allowedPaths = unserialize($result->perms);
+			$allowedPaths = array_merge_recursive($allowedPaths, $paths);
+			$result->perms = serialize($allowedPaths);
+			return $result->save();
+		});
+	}
+
+	public function removeCustomPath($user, $customRoute) {
+		if(!is_string($customRoute)) {
+			return false;
+		}
+		$parts = explode('.', $customRoute);
+		$value = array_pop($parts);
+		$parts = array_merge((array)self::pathCustom, $parts, (array)0);
+		return $this->remove($user, Set::expand(array(implode('.', $parts) => $value)));
+	}
+
+	/**
+	 * Removes an action from a users permission list. Setting action to * removes all actions
+	 * in the controller thus removing the controller from the users permission list.
+	 */
+	public function removeAction($user, $controller, $action) {
+		return $this->remove($user, array(
+			self::pathRoute => array(
+				$controller => array(
+					$action
+				)
+			)
+		));
+	}
+
+	/**
+	 * use this to remove permissions from a user, multiple permissions can be defined in the paths
+	 * array. The user must have the configured userIdentifier available.
+	 *
+	 * @throws \lithium\core\ConfigException
+	 * @param  $user
+	 * @param array $paths
+	 * @return bool
+	 */
+	public function remove($user, array $paths = array()) {
+		$model = $this->_model;
+		$userId = $this->_config['userIdentifier'];
+		$params = compact('model', 'userId', 'user', 'paths');
+		return $this->_filter(__METHOD__, $params, function($self, $params) {
+			$model = $params['model'];
+			$userId = $params['userId'];
+			$user = $params['user'];
+			$paths = $params['paths'];
+
+			if (!isset($user[$userId])) {
+				throw new ConfigException("The user identifier '{$userId}' is not available.");
+			}
+			$result = $model::find('first', array(
+				'conditions' => array(
+					'id' => $user[$userId]
+				)
+			));
+			if (!$result) {
+				return true;
+			}
+			$allowedPaths = unserialize($result->perms);
+			$pathsFlat = Set::flatten($paths);
+			foreach ($pathsFlat as $path => $value) {
+				$pointer = &$allowedPaths;
+				$pathParts = explode('.', $path);
+				array_pop($pathParts);
+				foreach ($pathParts as $pathPart) {
+					if (!isset($pointer[$pathPart])) {
+						unset($pointer);
+						$pointer = null;
+						break;
+					}
+					$pointer = &$pointer[$pathPart];
+				}
+				switch(true) {
+					case !$pointer:
+						break;
+					case $value == '*':
+						$pointer = null;
+						break;
+					case (($index = array_search($value, $pointer)) !== false):
+						unset($pointer[$index]);
+						break;
+				}
+			}
+			$result->perms = serialize($self->_cleanPaths($allowedPaths));
+			return $result->save();
+		});
+	}
+
+	public function listPerms($user) {
+		$userId = $user[$this->_config['userIdentifier']];
+		$model  = $this->_model;
+		$result = $model::find('first', array(
+			'conditions' => array(
+				'id' => $userId
+			)
+		));
+		return $result ? unserialize($result->perms) : array();
+	}
+
+	public function _cleanPaths($paths) {
+		foreach ($paths as &$path) {
+			if (is_array($path)) {
+				$path = $this->_cleanPaths($path);
+			}
+		}
+		return array_filter($paths);
+	}
+
+	public function _processPath($path, &$allowedPaths) {
+		$pointer = &$allowedPaths;
+		foreach($path as $item) {
+			switch(true) {
+				case (in_array('*', $pointer)):
+					return true;
+				case (in_array($item, $pointer)):
+					$pointer = array();
+					continue;
+				case (!isset($pointer[$item])):
+					return false;
+			}
+			$pointer = &$pointer[$item];
+		}
+		return true;
+	}
+}
+
+?>

+ 67 - 0
CSRF

@@ -0,0 +1,67 @@
+// This code is brought to you by Sean Coates (seancoates.com):
+
+<?php
+
+namespace app\extensions\helper;
+use \app\extensions\storage\Session;
+use \lithium\util\String;
+
+class Form extends \lithium\template\helper\Form
+{
+	protected function _render($method, $string, $params, array $options = array()) {
+		if ($docsrf = isset($params['options']['docsrf'])) {
+			unset($params['options']['docsrf']);
+		}
+ 
+		// get default
+		$ret = parent::_render($method, $string, $params, $options);
+ 
+		// if we're not already in a create chain, and if we're docsrf...
+		if (((get_parent_class($this) . '::create') == $method
+			|| (get_class($this) . '::create') == $method)
+			&& $docsrf) {
+			// append a hidden field with the token
+			$ret .= $this->hidden(
+				\app\extensions\action\Request::CSRF_TOKEN_FIELD_NAME,
+				array('value' => Session::get_csrf_token())
+			);
+		}
+ 
+		return $ret;
+	}
+}
+
+?>
+
+<?php
+
+namespace app\extensions\storage;
+
+class Session extends \lithium\storage\Session
+{
+	public static function get_csrf_token($replace = false)
+	{
+		$token = null;
+		if (!$replace) {
+			$token = self::read('csrf_token');
+		}
+		if ($token) {
+			return $token;
+		}
+ 
+		// not found (or replacing); generate a new token
+		$token = md5(uniqid(microtime(true)));
+ 
+		self::write('csrf_token', $token);
+ 
+		return $token;
+	}
+ 
+	public static function check_csrf_token($token)
+	{
+		return $token === self::read('csrf_token');
+	}
+ 
+}
+
+?>

BIN
config/.DS_Store


+ 86 - 0
config/bootstrap.php

@@ -0,0 +1,86 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+/**
+ * This is the primary bootstrap file of your application, and is loaded immediately after the front
+ * controller (`webroot/index.php`) is invoked. It includes references to other feature-specific
+ * bootstrap files that you can turn on and off to configure the services needed for your
+ * application.
+ *
+ * Besides global configuration of external application resources, these files also include
+ * configuration for various classes to interact with one another, usually through _filters_.
+ * Filters are Lithium's system of creating interactions between classes without tight coupling. See
+ * the `Filters` class for more information.
+ *
+ * If you have other services that must be configured globally for the entire application, create a
+ * new bootstrap file and `require` it here.
+ *
+ * @see lithium\util\collection\Filters
+ */
+
+/**
+ * The libraries file contains the loading instructions for all plugins, frameworks and other class
+ * libraries used in the application, including the Lithium core, and the application itself. These
+ * instructions include library names, paths to files, and any applicable class-loading rules. This
+ * file also statically loads common classes to improve bootstrap performance.
+ */
+require __DIR__ . '/bootstrap/libraries.php';
+
+/**
+ * The error configuration allows you to use the filter system along with the advanced matching
+ * rules of the `ErrorHandler` class to provide a high level of control over managing exceptions in
+ * your application, with no impact on framework or application code.
+ */
+require __DIR__ . '/bootstrap/errors.php';
+
+/**
+ * This file contains configurations for connecting to external caching resources, as well as
+ * default caching rules for various systems within your application
+ */
+require __DIR__ . '/bootstrap/cache.php';
+
+/**
+ * Include this file if your application uses one or more database connections.
+ */
+require __DIR__ . '/bootstrap/connections.php';
+
+/**
+ * This file defines bindings between classes which are triggered during the request cycle, and
+ * allow the framework to automatically configure its environmental settings. You can add your own
+ * behavior and modify the dispatch cycle to suit your needs.
+ */
+require __DIR__ . '/bootstrap/action.php';
+
+/**
+ * This file contains configuration for session (and/or cookie) storage, and user or web service
+ * authentication.
+ */
+ require __DIR__ . '/bootstrap/session.php';
+ require __DIR__ . '/bootstrap/auth.php';
+// require __DIR__ . '/bootstrap/error.php';
+
+/**
+ * This file contains your application's globalization rules, including inflections,
+ * transliterations, localized validation, and how localized text should be loaded. Uncomment this
+ * line if you plan to globalize your site.
+ */
+// require __DIR__ . '/bootstrap/g11n.php';
+
+/**
+ * This file contains configurations for handling different content types within the framework,
+ * including converting data to and from different formats, and handling static media assets.
+ */
+require __DIR__ . '/bootstrap/media.php';
+
+/**
+ * This file configures console filters and settings, specifically output behavior and coloring.
+ */
+// require __DIR__ . '/bootstrap/console.php';
+
+
+?>

BIN
config/bootstrap/.DS_Store


+ 55 - 0
config/bootstrap/action.php

@@ -0,0 +1,55 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+/**
+ * This file contains a series of method filters that allow you to intercept different parts of
+ * Lithium's dispatch cycle. The filters below are used for on-demand loading of routing
+ * configuration, and automatically configuring the correct environment in which the application
+ * runs.
+ *
+ * For more information on in the filters system, see `lithium\util\collection\Filters`.
+ *
+ * @see lithium\util\collection\Filters
+ */
+
+use lithium\core\Libraries;
+use lithium\net\http\Router;
+use lithium\core\Environment;
+use lithium\action\Dispatcher;
+
+/**
+ * This filter intercepts the `run()` method of the `Dispatcher`, and first passes the `'request'`
+ * parameter (an instance of the `Request` object) to the `Environment` class to detect which
+ * environment the application is running in. Then, loads all application routes in all plugins,
+ * loading the default application routes last.
+ *
+ * Change this code if plugin routes must be loaded in a specific order (i.e. not the same order as
+ * the plugins are added in your bootstrap configuration), or if application routes must be loaded
+ * first (in which case the default catch-all routes should be removed).
+ *
+ * If `Dispatcher::run()` is called multiple times in the course of a single request, change the
+ * `include`s to `include_once`.
+ *
+ * @see lithium\action\Request
+ * @see lithium\core\Environment
+ * @see lithium\net\http\Router
+ */
+Dispatcher::applyFilter('run', function($self, $params, $chain) {
+	Environment::set($params['request']);
+
+	foreach (array_reverse(Libraries::get()) as $name => $config) {
+		if ($name === 'lithium') {
+			continue;
+		}
+		$file = "{$config['path']}/config/routes.php";
+		file_exists($file) ? include $file : null;
+	}
+	return $chain->next($self, $params, $chain);
+});
+
+?>

+ 135 - 0
config/bootstrap/auth.php

@@ -0,0 +1,135 @@
+<?php
+use lithium\storage\Session;
+use lithium\security\Auth;
+use lithium\util\String;
+use app\models\User; 
+use lithium\core\Libraries;
+use lithium\action\Dispatcher;
+use lithium\net\http\Router;
+use lithium\action\Response;
+
+
+Session::config(array(
+	'cookie' => array('adapter' => 'Cookie'),
+    'default' => array('adapter' => 'Php'),
+    'flash_message' => array('adapter' => 'Php')
+));
+
+Auth::config(array(
+    'default' => array(
+        'adapter'  => 'Form',
+        'model'    => 'User',
+        'cookie'   => '',
+        'fields'   => array('username', 'password'),
+        //'scope'    => array('active' => 'true'), //The active field must be true otherwise they can't auth, though we need
+        										//to eventually send them to a page that explains they are banned. 
+        'session'  => array('options' => array('name' => 'default')),
+        'filters'  => array(
+	        'password' => function($password) {
+	        		return $password; //prevents li3 from hashing the password before hand. 
+	        	},
+
+		        function($data) {
+			        if (!empty($data['username'])) {
+			        	
+			        	//Find the first element record that matches the username in the request and get the salt field
+			        	$salt = User::find('first', array('conditions' => array('username' => $data['username'])));
+			        	
+			        	//The password to query is the password from the request
+			        	//hashed with the users stored salt
+			        	$data['password'] = String::hashPassword($data['password'], $salt->salt); 
+	        	}
+	        	return $data;
+	        })
+    )
+));
+
+$secret = "cake";
+
+// Adds remember feature for form-based authentications.
+Auth::applyFilter('check', function($self, $params, $chain) use ($secret) {
+	$query = 'first';
+	$scope = array();
+	extract($self::invokeMethod('_config', array($params['name'])));
+	if ($result = $chain->next($self, $params, $chain)) {
+		$request = $params['credentials'];
+		if ($request && $adapter == 'Form' && !empty($request->data['remember'])) {
+			$data = array_intersect_key($result, array_combine($fields, $fields));
+			$data = serialize($data);
+			Session::write(
+				"Auth.{$params['name']}",
+				base64_encode($data),
+				array('name' => 'cookie')
+			);
+		}
+		return $result;
+	}
+	if ($adapter == 'Form') {
+		$data = Session::read("Auth.{$params['name']}", array('name' => 'cookie'));
+		if ($data) {
+			$data = base64_decode($data);
+			$data = unserialize($data);
+			if (array_keys($data) == $fields) {
+				$model = Libraries::locate('models', $model);
+				$data = array_map('strval', $data);
+				$user = $model::$query($scope + $data);
+				if ($user) {
+					return $self::set($params['name'], $user->data());
+				}
+			}
+		}
+	}
+	return $result;
+});
+
+// Removes remember cookie after sign out.
+Auth::applyFilter('clear', function($self, $params, $chain) {
+	$config = $self::invokeMethod('_config', array($params['name']));
+	if ($config['adapter'] == 'Form') {
+		if (Session::read("Auth.{$params['name']}", array('name' => 'cookie'))) {
+			Session::delete("Auth.{$params['name']}", array('name' => 'cookie'));
+		}
+	}
+	return $chain->next($self, $params, $chain);
+});
+
+//So that we can filter a bunch of methods in one
+Dispatcher::applyFilter('_callable', function($self, $params, $chain) {
+   
+   //Invoke the _callable method, then execute the logic below
+    $ctrl = $chain->next($self, $params, $chain);
+
+    //if the user is logged in
+    $user = Auth::check('default');
+    if($user)
+    {
+    	//check if they are accessing an admin function
+    	if ($ctrl->request->controller == 'admin' && !($user['level'] == 'root' || $user['level'] == 'admin'))
+    	{
+    		return function() use ($request) {
+    				
+    				//Users / index isn't public derp.
+        			return new Response(compact('request') + array('location' => '/'));
+        		};
+    	}
+    	
+    	//If they aren't trying to access admin, return
+    	return $ctrl;
+    }
+    //If they are performing a public action continue,
+    if (isset($ctrl->publicActions) && in_array($params['request']->action, $ctrl->publicActions)) {
+        return $ctrl;
+    }
+
+    //Otherwise, send them to the login page 
+    return function() use ($request) {
+        return new Response(compact('request') + array('location' => '/login'));
+    };
+
+
+});
+
+
+
+
+?>

+ 62 - 0
config/bootstrap/cache.php

@@ -0,0 +1,62 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+/**
+ * This file creates a default cache configuration using the most optimized adapter available, and
+ * uses it to provide default caching for high-overhead operations.
+ */
+use lithium\storage\Cache;
+use lithium\core\Libraries;
+use lithium\action\Dispatcher;
+use lithium\storage\cache\adapter\Apc;
+
+if (PHP_SAPI === 'cli') {
+	return;
+}
+
+/**
+ * If APC is not available and the cache directory is not writeable, bail out. This block should be
+ * removed post-install, and the cache should be configured with the adapter you plan to use.
+ */
+$cachePath = Libraries::get(true, 'resources') . '/tmp/cache';
+
+if (!($apcEnabled = Apc::enabled()) && !is_writable($cachePath)) {
+	return;
+}
+
+/**
+ * This configures the default cache, based on whether ot not APC user caching is enabled. If it is
+ * not, file caching will be used. Most of this code is for getting you up and running only, and
+ * should be replaced with a hard-coded configuration, based on the cache(s) you plan to use.
+ */
+$default = array('adapter' => 'File', 'strategies' => array('Serializer'));
+
+if ($apcEnabled) {
+	$default = array('adapter' => 'Apc');
+}
+Cache::config(compact('default'));
+
+/**
+ * Caches paths for auto-loaded and service-located classes.
+ */
+Dispatcher::applyFilter('run', function($self, $params, $chain) {
+	$key = md5(LITHIUM_APP_PATH) . '.core.libraries';
+
+	if ($cache = Cache::read('default', $key)) {
+		$cache = (array) $cache + Libraries::cache();
+		Libraries::cache($cache);
+	}
+	$result = $chain->next($self, $params, $chain);
+
+	if ($cache != Libraries::cache()) {
+		Cache::write('default', $key, Libraries::cache(), '+1 day');
+	}
+	return $result;
+});
+
+?>

+ 72 - 0
config/bootstrap/connections.php

@@ -0,0 +1,72 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+/**
+ * ### Configuring backend database connections
+ *
+ * Lithium supports a wide variety relational and non-relational databases, and is designed to allow
+ * and encourage you to take advantage of multiple database technologies, choosing the most optimal
+ * one for each task.
+ *
+ * As with other `Adaptable`-based configurations, each database configuration is defined by a name,
+ * and an array of information detailing what database adapter to use, and how to connect to the
+ * database server. Unlike when configuring other classes, `Connections` uses two keys to determine
+ * which class to select. First is the `'type'` key, which specifies the type of backend to
+ * connect to. For relational databases, the type is set to `'database'`. For HTTP-based backends,
+ * like CouchDB, the type is `'http'`. Some backends have no type grouping, like MongoDB, which is
+ * unique and connects via a custom PECL extension. In this case, the type is set to `'MongoDb'`,
+ * and no `'adapter'` key is specified. In other cases, the `'adapter'` key identifies the unique
+ * adapter of the given type, i.e. `'MySql'` for the `'database'` type, or `'CouchDb'` for the
+ * `'http'` type. Note that while adapters are always specified in CamelCase form, types are
+ * specified either in CamelCase form, or in underscored form, depending on whether an `'adapter'`
+ * key is specified. See the examples below for more details.
+ *
+ * ### Multiple environments
+ *
+ * As with other `Adaptable` classes, `Connections` supports optionally specifying different
+ * configurations per named connection, depending on the current environment. For information on
+ * specifying environment-based configurations, see the `Environment` class.
+ *
+ * @see lithium\core\Adaptable
+ * @see lithium\core\Environment
+ */
+use lithium\data\Connections;
+
+/**
+ * Uncomment this configuration to use MongoDB as your default database.
+ */
+ Connections::add('default', array(
+ 	'type' => 'MongoDb',
+ 	'host' => 'localhost',
+ 	'database' => 'otakuhub',
+ 	'persistent' => 'foo'
+ ));
+
+/**
+ * Uncomment this configuration to use CouchDB as your default database.
+ */
+// Connections::add('default', array(
+// 	'type' => 'http',
+// 	'adapter' => 'CouchDb',
+// 	'host' => 'localhost',
+// 	'database' => 'my_app'
+// ));
+
+/**
+ * Uncomment this configuration to use MySQL as your default database.
+ */
+// Connections::add('default', array(
+// 	'type' => 'database',
+// 	'adapter' => 'MySql',
+// 	'host' => 'localhost',
+// 	'login' => 'root',
+// 	'password' => '',
+// 	'database' => 'my_app'
+// ));
+
+?>

+ 19 - 0
config/bootstrap/console.php

@@ -0,0 +1,19 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+use lithium\console\Dispatcher;
+
+Dispatcher::applyFilter('_call', function($self, $params, $chain) {
+	$params['callable']->response->styles(array(
+		'heading' => '\033[1;30;46m'
+	));
+	return $chain->next($self, $params, $chain);
+});
+
+
+?>

+ 37 - 0
config/bootstrap/error.php

@@ -0,0 +1,37 @@
+<?php
+/**
+ * First, import the relevant Lithium core classes.
+ */
+use \lithium\core\ErrorHandler;
+use \lithium\analysis\Logger;
+use lithium\action\Response;
+use lithium\net\http\Media;
+ 
+/**
+ * Then, set up a basic logging configuration that will write to a file.
+ */
+Logger::config(array(
+    'error' => array('adapter' => 'File')
+));
+ 
+ 
+ErrorHandler::apply('lithium\action\Dispatcher::run', array(), function($info, $params) {
+    $response = new Response(array('request' => $params['request']));
+ 
+    $message = "/(^Template not found|^Controller '\w+' not found|^Action '\w+' not found)/";
+    $template = (preg_match($message, $info['message'])) ? '404' : '500';
+ 
+    Logger::write('error', "{$info['file']} : {$info['line']} : {$info['message']}");
+    switch($template){
+        case '500':
+            debug($info);die;
+        break;
+    }
+    Media::render($response, compact('info', 'params'), array(
+        'controller' => 'errors',
+        'template' => $template,
+        'layout' => 'default',
+        'request' => $params['request']
+    ));
+    return $response;
+});

+ 28 - 0
config/bootstrap/errors.php

@@ -0,0 +1,28 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2011, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+use lithium\core\ErrorHandler;
+use lithium\action\Response;
+use lithium\net\http\Media;
+
+ErrorHandler::apply('lithium\action\Dispatcher::run', array(), function($info, $params) {
+	$response = new Response(array(
+		'request' => $params['request'],
+		'status' => $info['exception']->getCode()
+	));
+
+	Media::render($response, compact('info', 'params'), array(
+		'controller' => '_errors',
+		'template' => 'development',
+		'layout' => 'error',
+		'request' => $params['request']
+	));
+	return $response;
+});
+
+?>

+ 149 - 0
config/bootstrap/g11n.php

@@ -0,0 +1,149 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+/**
+ * This bootstrap file contains class configuration for all aspects of globalizing your application,
+ * including localization of text, validation rules, setting timezones and character inflections,
+ * and identifying a user's locale.
+ */
+use lithium\core\Libraries;
+use lithium\core\Environment;
+use lithium\g11n\Locale;
+use lithium\g11n\Catalog;
+use lithium\g11n\Message;
+use lithium\util\Inflector;
+use lithium\util\Validator;
+use lithium\net\http\Media;
+use lithium\action\Dispatcher as ActionDispatcher;
+use lithium\console\Dispatcher as ConsoleDispatcher;
+
+/**
+ * Sets the default timezone used by all date/time functions.
+ */
+date_default_timezone_set('UTC');
+
+/**
+ * Adds globalization specific settings to the environment.
+ *
+ * The settings for the current locale, time zone and currency are kept as environment
+ * settings. This allows for _centrally_ switching, _transparently_ setting and retrieving
+ * globalization related settings.
+ *
+ * The environment settings are:
+ *
+ *  - `'locale'` The effective locale.
+ *  - `'locales'` Application locales available mapped to names. The available locales are used
+ *               to negotiate he effective locale, the names can be used i.e. when displaying
+ *               a menu for choosing the locale to users.
+ */
+$locale = 'en';
+$locales = array('en' => 'English');
+
+Environment::set('production', compact('locale', 'locales'));
+Environment::set('development', compact('locale', 'locales'));
+Environment::set('test', array('locale' => 'en', 'locales' => array('en' => 'English')));
+
+/**
+ * Globalization (g11n) catalog configuration.  The catalog allows for obtaining and
+ * writing globalized data. Each configuration can be adjusted through the following settings:
+ *
+ *   - `'adapter'` _string_: The name of a supported adapter. The builtin adapters are `Memory` (a
+ *     simple adapter good for runtime data and testing), `Php`, `Gettext`, `Cldr` (for
+ *     interfacing with Unicode's common locale data repository) and `Code` (used mainly for
+ *     extracting message templates from source code).
+ *
+ *   - `'path'` All adapters with the exception of the `Memory` adapter require a directory
+ *     which holds the data.
+ *
+ *   - `'scope'` If you plan on using scoping i.e. for accessing plugin data separately you
+ *     need to specify a scope for each configuration, except for those using the `Memory`,
+ *     `Php` or `Gettext` adapter which handle this internally.
+ */
+Catalog::config(array(
+	'runtime' => array(
+		'adapter' => 'Memory'
+	),
+	// 'app' => array(
+	// 	'adapter' => 'Gettext',
+	// 	'path' => Libraries::get(true, 'resources') . '/g11n'
+	// ),
+	'lithium' => array(
+		'adapter' => 'Php',
+		'path' => LITHIUM_LIBRARY_PATH . '/lithium/g11n/resources/php'
+	)
+) + Catalog::config());
+
+/**
+ * Integration with `Inflector`.
+ */
+// Inflector::rules('transliteration', Catalog::read(true, 'inflection.transliteration', 'en'));
+
+/**
+ * Inflector configuration examples.  If your application has custom singular or plural rules, or
+ * extra non-ASCII characters to transliterate, you can configure that by uncommenting the lines
+ * below.
+ */
+// Inflector::rules('singular', array('rules' => array('/rata/' => '\1ratus')));
+// Inflector::rules('singular', array('irregular' => array('foo' => 'bar')));
+//
+// Inflector::rules('plural', array('rules' => array('/rata/' => '\1ratum')));
+// Inflector::rules('plural', array('irregular' => array('bar' => 'foo')));
+//
+// Inflector::rules('transliteration', array('/É|Ê/' => 'E'));
+//
+// Inflector::rules('uninflected', 'bord');
+// Inflector::rules('uninflected', array('bord', 'baird'));
+
+
+/**
+ * Integration with `View`. Embeds message translation aliases into the `View`
+ * class (or other content handler, if specified) when content is rendered. This
+ * enables translation functions, i.e. `<?=$t("Translated content"); ?>`.
+ */
+Media::applyFilter('_handle', function($self, $params, $chain) {
+	$params['handler'] += array('outputFilters' => array());
+	$params['handler']['outputFilters'] += Message::aliases();
+	return $chain->next($self, $params, $chain);
+});
+
+/**
+ * Integration with `Validator`. You can load locale dependent rules into the `Validator`
+ * by specifying them manually or retrieving them with the `Catalog` class.
+ */
+foreach (array('phone', 'postalCode', 'ssn') as $name) {
+	Validator::add($name, Catalog::read(true, "validation.{$name}", 'en_US'));
+}
+
+/**
+ * Intercepts dispatching processes in order to set the effective locale by using
+ * the locale of the request or if that is not available retrieving a locale preferred
+ * by the client.
+ */
+ActionDispatcher::applyFilter('_callable', function($self, $params, $chain) {
+	$request = $params['request'];
+	$controller = $chain->next($self, $params, $chain);
+
+	if (!$request->locale) {
+		$request->params['locale'] = Locale::preferred($request);
+	}
+	Environment::set(Environment::get(), array('locale' => $request->locale));
+	return $controller;
+});
+
+ConsoleDispatcher::applyFilter('_callable', function($self, $params, $chain) {
+	$request = $params['request'];
+	$command = $chain->next($self, $params, $chain);
+
+	if (!$request->locale) {
+		$request->params['locale'] = Locale::preferred($request);
+	}
+	Environment::set(Environment::get(), array('locale' => $request->locale));
+	return $command;
+});
+
+?>

+ 127 - 0
config/bootstrap/libraries.php

@@ -0,0 +1,127 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+/**
+ * The libraries file is where you configure the various plugins, frameworks, and other libraries
+ * to be used by your application, including your application itself. This file also defines some
+ * global constants used to tell Lithium where to find your application and support libraries
+ * (including Lithium itself). It uses the `Libraries` class to add configurations for the groups of
+ * classes used in your app.
+ *
+ * In Lithium, a _library_ is any collection of classes located in a single base directory, which
+ * all share the same class-to-file naming convention, and usually a common class or namespace
+ * prefix. While all collections of classes are considered libraries, there are two special types of
+ * libraries:
+ *
+ * - **Applications**: Applications are libraries which follow the organizational conventions that
+ *   Lithium defines for applications (see `Libraries::locate()` and `Libraries::paths()`), and
+ *   which also include a web-accessible document root (i.e. the `webroot/` folder), and can
+ *   dispatch HTTP requests (i.e. through `webroot/index.php`).
+ *
+ * - **Plugins**: Plugins are libraries which generally follow the same organizational conventions
+ *   as applications, but are designed to be used within the context of another application. They
+ *   _may_ include a public document root for supporting assets, but this requires a symlink from
+ *   `libraries/<plugin-name>/webroot` to `<app-name>/webroot/<plugin-name>` (recommended for
+ *   production), or a media filter to load plugin resources (see `/config/bootstrap/media.php`).
+ *
+ * Note that a library can be designed as both an application and a plugin, but this requires some
+ * special considerations in the bootstrap process, such as removing any `require` statements, and
+ * conditionally defining the constants below.
+ *
+ * By default, libraries are stored in the base `/libraries` directory, or in the
+ * application-specific `<app-name>/libraries` directory. Libraries can be loaded from either place
+ * without additional configuration, but note that if the same library is in both directories, the
+ * application-specific `libraries` directory will override the global one.
+ *
+ * The one exception to this is the _primary_ library, which is an application configured with
+ * `'default' => true` (see below); this library uses the `LITHIUM_APP_PATH` constant (also defined
+ * below) as its path. Note, however, that any library can be overridden with an arbitrary path by
+ * passing the `'path'` key to its configuration. See `Libraries::add()` for more options.
+ *
+ * @see lithium\core\Libraries
+ */
+
+/**
+ * This is the path to your application's directory.  It contains all the sub-folders for your
+ * application's classes and files.  You don't need to change this unless your webroot folder is
+ * stored outside of your app folder.
+ */
+define('LITHIUM_APP_PATH', dirname(dirname(__DIR__)));
+
+/**
+ * This is the path to the class libraries used by your application, and must contain a copy of the
+ * Lithium core.  By default, this directory is named `libraries`, and resides in the same
+ * directory as your application.  If you use the same libraries in multiple applications, you can
+ * set this to a shared path on your server.
+ */
+define('LITHIUM_LIBRARY_PATH', dirname(LITHIUM_APP_PATH) . '/libraries');
+
+/**
+ * Locate and load Lithium core library files.  Throws a fatal error if the core can't be found.
+ * If your Lithium core directory is named something other than `lithium`, change the string below.
+ */
+if (!include LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php') {
+	$message  = "Lithium core could not be found.  Check the value of LITHIUM_LIBRARY_PATH in ";
+	$message .= __FILE__ . ".  It should point to the directory containing your ";
+	$message .= "/libraries directory.";
+	throw new ErrorException($message);
+}
+
+use lithium\core\Libraries;
+
+/**
+ * Optimize default request cycle by loading common classes.  If you're implementing custom
+ * request/response or dispatch classes, you can safely remove these.  Actually, you can safely
+ * remove them anyway, they're just there to give slightly you better out-of-the-box performance.
+ */
+require LITHIUM_LIBRARY_PATH . '/lithium/core/Object.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/core/StaticObject.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/util/Collection.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/util/collection/Filters.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/util/Inflector.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/util/String.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/core/Adaptable.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/core/Environment.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/net/Message.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Message.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Media.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Request.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Response.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Route.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/net/http/Router.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/action/Controller.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/action/Dispatcher.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/action/Request.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/action/Response.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/template/View.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/template/view/Renderer.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/template/view/Compiler.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/template/view/adapter/File.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/storage/Cache.php';
+require LITHIUM_LIBRARY_PATH . '/lithium/storage/cache/adapter/Apc.php';
+
+
+/**
+ * Add the Lithium core library.  This sets default paths and initializes the autoloader.  You
+ * generally should not need to override any settings.
+ */
+Libraries::add('lithium');
+
+/**
+ * Add the application.  You can pass a `'path'` key here if this bootstrap file is outside of
+ * your main application, but generally you should not need to change any settings.
+ */
+Libraries::add('app', array('default' => true));
+
+/**
+ * Add some plugins:
+ */
+// Libraries::add('li3_docs');
+Libraries::add('li3_flash_message');
+Libraries::add('li3_paginate');
+?>

+ 63 - 0
config/bootstrap/media.php

@@ -0,0 +1,63 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+/**
+ * The `Collection` class, which serves as the base class for some of Lithium's data objects
+ * (`RecordSet` and `Document`) provides a way to manage data collections in a very flexible and
+ * intuitive way, using closures and SPL interfaces. The `to()` method allows a `Collection` (or
+ * subclass) to be converted to another format, such as an array. The `Collection` class also allows
+ * other classes to be connected as handlers to convert `Collection` objects to other formats.
+ *
+ * The following connects the `Media` class as a format handler, which allows `Collection`s to be
+ * exported to any format with a handler provided by `Media`, i.e. JSON. This enables things like
+ * the following:
+ * {{{
+ * $posts = Post::find('all');
+ * return $posts->to('json');
+ * }}}
+ */
+use lithium\util\Collection;
+
+Collection::formats('lithium\net\http\Media');
+
+/**
+ * This filter is a convenience method which allows you to automatically route requests for static
+ * assets stored within active plugins. For example, given a JavaScript file `bar.js` inside the
+ * `li3_foo` plugin installed in an application, requests to `http://app/path/li3_foo/js/bar.js`
+ * will be routed to `/path/to/app/libraries/plugins/li3_foo/webroot/js/bar.js` on the filesystem.
+ * In production, it is recommended that you disable this filter in favor of symlinking each
+ * plugin's `webroot` directory into your main application's `webroot` directory, or adding routing
+ * rules in your web server's configuration.
+ */
+use lithium\action\Dispatcher;
+use lithium\action\Response;
+use lithium\net\http\Media;
+
+Dispatcher::applyFilter('_callable', function($self, $params, $chain) {
+	list($library, $asset) = explode('/', $params['request']->url, 2) + array("", "");
+
+	if ($asset && ($path = Media::webroot($library)) && file_exists($file = "{$path}/{$asset}")) {
+		return function() use ($file) {
+			$info = pathinfo($file);
+			$media = Media::type($info['extension']);
+			$content = (array) $media['content'];
+
+			return new Response(array(
+				'headers' => array('Content-type' => reset($content)),
+				'body' => file_get_contents($file)
+			));
+		};
+	}
+	return $chain->next($self, $params, $chain);
+});
+
+Media::type('jpg', 'image/jpeg', array('cast' => false, 'encode' => function($data) {
+	return $data['photo']->file->getBytes();
+	}));
+
+?>

+ 49 - 0
config/bootstrap/session.php

@@ -0,0 +1,49 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+/**
+ * This configures your session storage. The Cookie storage adapter must be connected first, since
+ * it intercepts any writes where the `'expires'` key is set in the options array.
+ */
+use lithium\storage\Session;
+
+/*
+Session::config(array(
+	'cookie' => array('adapter' => 'Cookie'),
+	'default' => array('adapter' => 'Php')
+));
+*/
+/**
+ * Uncomment the lines below to enable forms-based authentication. This configuration will attempt
+ * to authenticate users against a `Users` model. In a controller, run
+ * `Auth::check('default', $this->request)` to authenticate a user. This will check the POST data of
+ * the request (`lithium\action\Request::$data`) to see if the fields match the `'fields'` key of
+ * the configuration below. If successful, it will write the data returned from `Users::first()` to
+ * the session using the default session configuration.
+ *
+ * Once the session data is written, you can call `Auth::check('default')` to check authentication
+ * status or retrieve the user's data from the session. Call `Auth::clear('default')` to remove the
+ * user's authentication details from the session. This effectively logs a user out of the system.
+ * To modify the form input that the adapter accepts, or how the configured model is queried, or how
+ * the data is stored in the session, see the `Form` adapter API or the `Auth` API, respectively.
+ *
+ * @see lithium\security\auth\adapter\Form
+ * @see lithium\action\Request::$data
+ * @see lithium\security\Auth
+ */
+// use lithium\security\Auth;
+
+// Auth::config(array(
+// 	'default' => array(
+// 		'adapter' => 'Form',
+// 		'model' => 'Users',
+// 		'fields' => array('username', 'password')
+// 	)
+// ));
+
+?>

+ 149 - 0
config/routes.php

@@ -0,0 +1,149 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+/**
+ * The routes file is where you define your URL structure, which is an important part of the
+ * [information architecture](http://en.wikipedia.org/wiki/Information_architecture) of your
+ * application. Here, you can use _routes_ to match up URL pattern strings to a set of parameters,
+ * usually including a controller and action to dispatch matching requests to. For more information,
+ * see the `Router` and `Route` classes.
+ *
+ * @see lithium\net\http\Router
+ * @see lithium\net\http\Route
+ */
+use lithium\net\http\Router;
+use lithium\core\Environment;
+use app\models\Photo;
+
+/**
+ * Here, we are connecting `'/'` (the base path) to controller called `'Pages'`,
+ * its action called `view()`, and we pass a param to select the view file
+ * to use (in this case, `/views/pages/home.html.php`; see `app\controllers\PagesController`
+ * for details).
+ *
+ * @see app\controllers\PagesController
+ */
+Router::connect('/', 'Pages::view');
+
+/**
+ * Connect the rest of `PagesController`'s URLs. This will route URLs like `/pages/about` to
+ * `PagesController`, rendering `/views/pages/about.html.php` as a static page.
+ */
+Router::connect('/pages/{:args}', 'Pages::view');
+
+
+/**
+ * Add the testing routes. These routes are only connected in non-production environments, and allow
+ * browser-based access to the test suite for running unit and integration tests for the Lithium
+ * core, as well as your own application and any other loaded plugins or frameworks. Browse to
+ * [http://path/to/app/test](/test) to run tests.
+ */
+if (!Environment::is('production')) {
+	Router::connect('/test/{:args}', array('controller' => 'lithium\test\Controller'));
+	Router::connect('/test', array('controller' => 'lithium\test\Controller'));
+}
+
+
+/* This is the login and logout routes */
+Router::connect('/login',  array('controller' => 'users', 'action' => 'login'));
+Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));
+
+/* Content routes */
+Router::connect('/anime', array('controller' => 'content', 'action' => 'anime'));
+Router::connect('/anime/{:args}', array('controller' => 'content', 'action' => 'anime'));
+
+//Pagination route
+Router::connect('/{:controller}/{:action}/page:{:page:[0-9]+}');
+
+
+/**
+* Define an anonymous function that we will pass to the router instead of linking to a controller action
+* The logic is quite simple:
+* Call the version() method on the Photo model class with $request->id (MongoId for image) and a set of options. This is passed as an array to allow adding more options later.
+* Finally just return a Response object with the image data as body (this is what version() returns) and the appropriate content type for the file ending.
+*
+* This method is limited, supports few formats etc but its a good start
+*/
+$imageSizer = function($request) {
+    $contentTypeMappings = array(
+        'jpg' => 'image/jpeg',
+        'jpeg' => 'image/jpeg',
+        'png' => 'image/png',
+        'gif' => 'image/gif'
+    );
+    // Generate file based image of this
+    $imageBody = Photo::version($request->id, array(
+        'width' => $request->width,
+        'height' => $request->height
+    ));
+    return new Response(array(
+        'headers' => array('Content-type' => $contentTypeMappings[$request->type]),
+        'body' => $imageBody
+    ));
+};
+
+/**
+This is a little bit more complicated.
+We state that the handler for when this route is matched is the anonymous function we've declared and
+we set up a pattern to match our two cases of image urls — both with and without size information.
+The regex is quite simple even if it looks complex:
+^/image/ <- begin with /image/
+(?P<foo>) is for setting up a named capture group. This equals doing {:foo:{pattern}} in Lithium.
+So we have 1 capture group named {id} that have to match by 24 signs (mongoid), and an optional part "_{width}x{height}" and finally the filtype.
+
+Im unsure if the keys array can be handled some other way, but it failed for me without it.
+*/
+$imageHandlingOptions = array(
+    'handler' => $imageSizer,
+    'pattern' => '@^/image/(?P<id>[0-9a-f]{24})(_(?P<width>[0-9]*)x(?P<height>[0-9]*)?)\.(?<type>[a-z]{2,4})@',
+    'keys' => array('id'=>'id', 'width'=>'width', 'height'=>'height', 'type'=>'type')
+);
+
+/**
+Finally we connect this as a route. The regex sent as the first param here is overriden by the more complex one we have defined in the options array.
+*/
+Router::connect('/image/{:id:[0-9a-f]{24}}.jpg', array(), $imageHandlingOptions);
+
+
+
+/**
+ * ### Database object routes
+ *
+ * The routes below are used primarily for accessing database objects, where `{:id}` corresponds to
+ * the primary key of the database object, and can be accessed in the controller as
+ * `$this->request->id`.
+ *
+ * If you're using a relational database, such as MySQL, SQLite or Postgres, where the primary key
+ * is an integer, uncomment the routes below to enable URLs like `/posts/edit/1138`,
+ * `/posts/view/1138.json`, etc.
+ */
+// Router::connect('/{:controller}/{:action}/{:id:\d+}.{:type}', array('id' => null));
+// Router::connect('/{:controller}/{:action}/{:id:\d+}');
+
+/**
+ * If you're using a document-oriented database, such as CouchDB or MongoDB, or another type of
+ * database which uses 24-character hexidecimal values as primary keys, uncomment the routes below.
+ */
+Router::connect('/{:controller}/{:action}/{:id:[0-9a-f]{24}}.{:type}', array('id' => null));
+Router::connect('/{:controller}/{:action}/{:id:[0-9a-f]{24}}');
+
+/**
+ * Finally, connect the default route. This route acts as a catch-all, intercepting requests in the
+ * following forms:
+ *
+ * - `/foo/bar`: Routes to `FooController::bar()` with no parameters passed.
+ * - `/foo/bar/param1/param2`: Routes to `FooController::bar('param1, 'param2')`.
+ * - `/foo`: Routes to `FooController::index()`, since `'index'` is assumed to be the action if none
+ *   is otherwise specified.
+ *
+ * In almost all cases, custom routes should be added above this one, since route-matching works in
+ * a top-down fashion.
+ */
+Router::connect('/{:controller}/{:action}/{:args}');
+
+?>

+ 100 - 0
controllers/AdminController.php

@@ -0,0 +1,100 @@
+<?php
+namespace app\controllers;
+
+use app\models\User;
+use lithium\security\Auth;
+use lithium\util\String;
+use li3_access\security\Access;
+use li3_flash_message\extensions\storage\FlashMessage;
+use lithium\action\Dispatcher;
+
+class AdminController extends \lithium\action\Controller {
+	public function index()
+	{
+		$limit = 5;
+		$page = $this->request->page ?: 1;
+		//$order = array('created' => 'DESC');
+		$total = User::count();
+		$users = User::all(compact('limit','page'));
+		$this->render(array('layout' => 'admin', 'data' =>  compact('users', 'total', 'page', 'limit')));	
+	}
+
+	public function users()
+	{
+		$users = User::all();
+		$this->render(array('layout' => 'admin', 'data' => compact('users')));
+		//Should have paginate for when there is more users.
+	}
+
+	
+	//This is basically admins version of signup
+	public function addUser()
+	{
+		$sucsess = false;
+
+		//If the request isn't empty
+		if($this->request->data) {
+			//Does admins data need to be validated?
+			$user = User::Create($this->request->data);
+			$sucsess = $user->save();
+		}
+		if ($sucsess) {
+			return $this->redirect('Users');
+		}
+	
+		FlashMessage::set($user->name . "was added sucessfully.");
+	}
+
+	public function editUser($username = NULL)
+	{
+		if ($username != NULL)
+		{
+			$user = User::find('first', array('conditions' => compact('username')));
+		
+			if($this->request->data)
+			{
+				$user->set($this->request->data);
+				if ($user->save(null, array('validate' => false)))
+				{
+					FlashMessage::set('User updated sucsessfully');
+					$this->redirect('Admin::index');
+				}
+				else
+				{
+					FlashMessage::set('There was an error');
+					$this->redirect('Admin::index');
+
+				}
+			}
+			else
+			{
+				//unset($user->password);
+				return compact('user');
+			}
+		}
+	}
+
+	public function removeUser($username)
+	{
+		/*
+		//Form data needs to have $username and $confirm = true to do the delete.
+		if($this->request->data)
+		{
+			//If the user has confirmed the deletion of the user.
+			if($this->request->data->confirm)
+			{ */
+				$user = User::find('first', array('conditions' => compact('username')));
+				$user->delete();
+				FlashMessage::set("User was deleted sucsessfully.");
+				$this->redirect('Admin');	
+			//}
+		}
+		/*else
+		{
+			//Render the form
+			$this->render(array('layout' => 'form', 'data' => compact('users')));
+
+		}*/
+	//}
+}
+?>

+ 77 - 0
controllers/AnimelistController.php

@@ -0,0 +1,77 @@
+<?php
+
+namespace app\controllers;
+
+use app\models\contentList;
+use app\models\User;
+use app\models\Anime;
+
+
+class AnimeListController extends \lithium\action\Controller {
+	public $publicActions = array('view');
+	public function view($username, $sort = "all")
+	{
+		$user = User::find('first', array('conditions' => compact('username')));
+
+		
+		$watching = array();
+		$paused = array();
+		$dropped = array();
+		$planning = array();
+		$finished = array();
+		
+
+		foreach($user->animelist as $entry)
+		{
+			switch($entry->my_status)
+			{
+				case "Completed": $finished[] = $entry; break;
+				case "Watching": $watching[] = $entry; break;
+				case "On-Hold" : $paused[] = $entry; break;
+				case "Dropped" : $dropped[] = $entry; break;
+				case "Plan to Watch": $planning[] = $entry; break;
+			}
+		}
+
+		
+		//In the future we can use set or something
+		switch($sort)
+		{
+			case "planning" : return compact('user', 'planning'); break;
+			case "completed" : return compact('user', 'finished'); break;
+			case "onhold": return compact('user', 'paused'); break;
+			case "watching" : return compact('user', 'watching'); break;
+			case "dropped": return compact('user', 'dropped');
+			default: return compact('user', 'watching', 'paused', 'dropped', 'planning', 'finished'); break;
+		}
+	}
+
+	public function add($id)
+	{
+		if (empty($this->request->data))
+		{
+			$anime = Anime::find('first', array('conditions' => array('special_id' => $id)));
+			$entry = null;
+			return compact('anime', 'entry');
+		}
+
+		$entry = Entry::create($this->request->data);
+
+		if (isset($this->request->data['tags']))
+		{
+				$entry->my_tags = explode(' ', $this->request->data['tags']);
+				unset($this->request->data['tags']);
+		}
+		
+		if ($entry->validates()) {
+			$entry->add($username);
+
+			return $this->redirects('Animelist::Index');	
+		}
+
+		return $entry; 
+		
+	}
+
+
+}

+ 62 - 0
controllers/ContentController.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace app\controllers;
+use app\models\anime;
+
+class ContentController extends \lithium\action\Controller {
+	public $publicActions = array('anime');
+
+	public function index($type) //type has to equal something
+	{
+
+
+		
+		switch($type) {
+			case "anime":  $content = Anime::all(compact('limit','page','order'));
+						   $total = Anime::count();
+				           break;
+
+			case "manga":  
+
+			case "kdrama": $content = Kdrama::all(compact('limit', 'page', 'order'));
+						   $total = Kdrama::count();
+						   break;
+			}
+
+		return compact('content', 'total', 'page', 'limit');	
+	}
+
+	public function manga($id = null)
+	{
+		if ($id != null)
+		{
+			
+		}
+		else
+		{
+			$content = Manga::all(compact('limit', 'page', 'order'));
+			$total = Manga::count();
+		}
+	}
+
+	public function anime($id = null)
+	{
+		$limit = 20;
+		$page = $this->request->page ?: 1;
+		$order = array('title' => 'ASC');
+		$content;
+		$total;
+
+		if ($id != null)
+		{
+			$content = Anime::find('first', array('conditions' => array('special_id' => $id), 'order' => array('title' => 'ASC')));
+			return compact('content');
+		}
+		else
+		{
+			$content = Anime::all(compact('limit','page','order'));
+			$total = Anime::count();
+			$this->render(array('template' => 'index', 'data' => compact('limit', 'page', 'content', 'total')));
+		}
+	}	
+}

+ 79 - 0
controllers/FeedsController.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace app\FeedsController; 
+
+
+use lithium\security\Auth;
+use app\models\Post;
+
+class FeedsController extends \lithium\action\Controller {
+	//Class Variables
+	//public $validates =
+
+
+	public function index() 
+	{
+		//If the user isn't authenticated
+		if(!Auth::check('default')) 
+		{ 
+			//Redirect them to the login/welcome page
+			$this->redirect('Users::login'); 
+		}	
+		
+		//else
+		//Figure out what user is logged in (from their session cookie presumably)
+		/* Display the users last 20 posts in decending order. */
+		$user = Session::read('username'); 
+
+		//Since there can only be one of each username, getting the first occurence of $user should be fine
+		$query = User::find('first', array('conditions' => array('username' => $user)));
+		$feed = $query->posts; 
+
+
+		return compact($feed); //Return the feed array to the 
+	}
+
+	/**
+	* New needs to do a few things
+	* 1) Validation, 
+	*	 Ensure that the post is unique,
+	*	 Flood protection
+	*	 Spam Protection at some point
+	* 2) Storage 
+	*	The post needs to be stored in the users feed as well as users who are friends with them
+	*	 
+	*/
+	public function new()
+	{
+		
+	}
+
+	/**
+	* Hide needs to put a "HIDES" edge on the graph
+	* By getting the users document from the database, querying its id
+	*then doing something like $thisUser->hides($username)
+	*/
+	public function hide($username)
+	{
+		
+	}
+
+	
+	/**
+	*Does the same sort of validation as new, but deletes a post obviously :P
+	*/
+	public function delete($id)
+	{
+		$user = Auth::check('default');
+		$post = Post::find($id);
+
+		if ($post->username == $user['username']) {
+			$post->delete();
+		}
+
+		return $this->redirect('Feed::Index');
+
+	}
+}
+
+?>

+ 36 - 0
controllers/PagesController.php

@@ -0,0 +1,36 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+namespace app\controllers;
+
+/**
+ * This controller is used for serving static pages by name, which are located in the `/views/pages`
+ * folder.
+ *
+ * A Lithium application's default routing provides for automatically routing and rendering
+ * static pages using this controller. The default route (`/`) will render the `home` template, as
+ * specified in the `view()` action.
+ *
+ * Additionally, any other static templates in `/views/pages` can be called by name in the URL. For
+ * example, browsing to `/pages/about` will render `/views/pages/about.html.php`, if it exists.
+ *
+ * Templates can be nested within directories as well, which will automatically be accounted for.
+ * For example, browsing to `/pages/about/company` will render
+ * `/views/pages/about/company.html.php`.
+ */
+class PagesController extends \lithium\action\Controller {
+	// !--Waring--! this makes all pages accessibe to non-logged in uses. 
+	// :TODO: Fix this.
+	public $publicActions = array('view');
+	public function view() {
+		$path = func_get_args() ?: array('home');
+		return $this->render(array('template' => join('/', $path)));
+	}
+}
+
+?>

+ 41 - 0
controllers/PhotosController.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace app\controllers;
+
+use app\models\Photo;
+
+class PhotosController extends \lithium\action\Controller {
+
+	public function index() {
+		$photos = Photo::all();
+		return compact('photos');
+	}
+
+	public function view() {
+		$photo = Photo::first($this->request->id);
+		return compact('photo');
+	}
+
+	public function add() {
+		$photo = Photo::create();
+
+		if (($this->request->data) && $photo->save($this->request->data)) {
+			$this->redirect(array('Photos::view', 'id' => $photo->id));
+		}
+		return compact('photo');
+	}
+
+	public function edit() {
+		$photo = Photo::find($this->request->id);
+
+		if (!$photo) {
+			$this->redirect('Photos::index');
+		}
+		if (($this->request->data) && $photo->save($this->request->data)) {
+			$this->redirect(array('Photos::view', 'args' => array($photo->id)));
+		}
+		return compact('photo');
+	}
+}
+
+?>

+ 75 - 0
controllers/ProfileController.php

@@ -0,0 +1,75 @@
+<?php 
+
+namespace app\controllers;
+use app\models\User;
+use \lithium\security\Auth;
+
+class ProfileController extends \lithium\action\Controller {
+	public $publicActions = array("view");
+
+	public function view($username)
+	{
+		//Find the user profile
+		$user = User::find('first', array('conditions' => compact('username')));
+		//If the user variable isn't empty a user was found. 
+		if (!empty($user))
+		{
+			
+			//The only issue(?) is that this will update the profile views even if the user views their own profile, maybe we should fix that.  
+			$user->incrementViews();
+		
+			$photo = null;
+			$profile = $user->profile; 
+			return compact('user', 'photo', 'profile');
+		}
+		else
+		{
+			//Tell the user that user wasn't found.
+		}
+	} 
+
+	public function create()
+	{
+		
+	}
+
+	public function edit($username)
+	{
+		$user = Auth::check('default');
+		
+		if ($user) {
+			$user = User::find('first', array('conditions' => array('username' => $user['username'])));
+			$profile = $user->profile;
+			$photo;
+			
+
+			if (empty($this->request->data)) {
+				return compact('profile', 'user');
+			}
+
+			//If a photo was uploaded
+			if (isset($this->request->data['photo']))
+			{
+				/* Update / Add the profile picture */
+				//Store the image in grid FS
+				$photo = Photo::create($this->request->data["photo"]);
+
+				//We don't to resave the photo in the profile data
+				unset($this->request->data["photo"]);
+
+				//Save the photo 
+				$photo->save();
+
+				//Since images are accessed via /image/mongoid we just store the mongo id so we
+				//can substitue it in the <img src=""> tag.
+				$user->profilepic = $photo->_id->__toString();
+			}
+
+			$user->profile = $this->request->data;
+				
+			if ($user->save(null, array('validate' =>false))) {
+				return $this->redirect("/profile/view/$user->username");
+			}
+		}
+	}
+}

+ 41 - 0
controllers/ProfilesController.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace app\controllers;
+
+use app\models\Profile;
+
+class ProfilesController extends \lithium\action\Controller {
+
+	public function index() {
+		$profiles = Profile::all();
+		return compact('profiles');
+	}
+
+	public function view() {
+		$profile = Profile::first($this->request->id);
+		return compact('profile');
+	}
+
+	public function add() {
+		$profile = Profile::create();
+
+		if (($this->request->data) && $profile->save($this->request->data)) {
+			$this->redirect(array('Profiles::view', 'args' => array($profile->id)));
+		}
+		return compact('profile');
+	}
+
+	public function edit() {
+		$profile = Profile::find($this->request->id);
+
+		if (!$profile) {
+			$this->redirect('Profiles::index');
+		}
+		if (($this->request->data) && $profile->save($this->request->data)) {
+			$this->redirect(array('Profiles::view', 'args' => array($profile->id)));
+		}
+		return compact('profile');
+	}
+}
+
+?>

+ 37 - 0
controllers/SearchController.php

@@ -0,0 +1,37 @@
+<?php 
+
+namespace app\controllers; 
+
+use app\models\Anime;
+use \MongoRegex;
+
+class SearchController extends \lithium\action\Controller {
+	public function index($type, $by = "series_title")
+	{
+
+		if (empty($this->request->query['search'])) {
+			//Redirect them or something 
+		}
+
+
+		$searchParam = '/' . $this->request->query['search'] . '/i';
+		
+		$content;
+		$limit = 20; 
+		$page = $this->request->page ?: 1;
+		$total; //<-- number of search results
+
+
+		switch($type)
+		{
+			case "anime": $content = Anime::find('all', array('conditions' => array('title' => array('like' => $searchParam)), $limit, $page)); 
+			$total = Anime::count(array('title' => array('like' => $searchParam)));
+			break;
+			case "kdrama": break;
+			case "manga": break; 
+		}
+		return compact('content', 'type', 'by', 'limit', 'total', 'page');
+	}
+
+
+}

+ 25 - 0
controllers/TopicController.php

@@ -0,0 +1,25 @@
+<?php
+
+namespace app\controllers;
+use app\models\Topic;
+
+class TopicController extends \lithium\action\Controller {
+	public function index()
+	{
+		//We'll write this eventually 
+	}	
+	
+	public function view($topicname)
+	{
+		$topic = Topic::find('first', array('conditions' => compact('topicname')));
+	}
+
+	public function new()
+	{
+		if ($this->request->data)
+		{
+			$topic = Topic::create($this->request->data);
+			$topic->save();
+		}
+	}
+}

+ 473 - 0
controllers/UsersController.php

@@ -0,0 +1,473 @@
+<?php
+
+namespace app\controllers;
+
+use lithium\storage\Session;
+use app\models\User;
+use app\models\confirmKey;
+use app\models\ProfilePic;
+use app\models\Post;
+use lithium\security\Auth;
+use lithium\util\String;
+use \MongoDate;
+use li3_flash_message\extensions\storage\FlashMessage;
+use app\libraries\openID\LightOpenID;
+
+class UsersController extends \lithium\action\Controller {
+	public $secret = "marshmellows"; //I don't know why either?
+	
+	//Make login a public action.
+	public $publicActions = array('login', 'logout', 'signup', 'confirm');
+
+	/* User profile implementation */
+	/* So, like twitter if you friend someone but they don't friend you, 
+	 * You can see their posts, but they don't see yours. Furthermore, posts that start with a @username 
+	 * shouldn't be shown to the user either.
+	 *
+	 * Now say for instance the the user isn't logged in but visits the profile of another user. It should show the users posts 
+	 * that aren't set to private. this should be as easy as Posts::find('all', array('conditions' => array('level' != private)))
+	 * However, we need to differentiate posts that are Hidden (posts that begin with a @username), Friends only (set by user) or 
+	 * Public (by default all posts.) there should be a method that filters the new post method, that takes a post, determines
+	 *  what access level it should be then passes that back to the calling method (in save?)
+	 *
+	 * Of course, for logged in users, we need to do a multiselect I guess, something like find posts where access level is hidden
+	 * friends only, and public, ordered by date (descending) limit 20 or so (use pagination plugin)
+	 *
+	 * Finally, there should be an an option to make all posts private, this can be done by the postlevel() method, it can check i
+	 * the user has the private option set, then if true return private for all posts :)
+	  */
+
+	public function index($username = null)
+	{
+		//If no username was entered, 
+		if ($username == null)
+		{
+			//Show a user list?
+			// TODO: Pagination 
+			//Show a list of all users
+			$users = User::all();
+			return compact('users');
+			//maybe we can use the endpoint hook and show a "network activity feed"
+			//For example show all public posts as they get posted using ajax ?
+			//Maybe we should have a route for this? /activity maybe?
+		}
+		//Otherwise get that user
+		$user = User::find('first', array('conditions' => compact('username')));
+	
+		//find all posts, sort by date, order descending, limit to 20
+		$feed; 
+
+		//Dont know if php will keep counts return on the stack so I'm storing it to avoid calling it 3 times.
+		$tmpCount = count($user->feed);
+
+		//If the user has 20 or more posts then query 20, otherwise query the number of posts the user has
+		$count = ($tmpCount >= 20) ? 20 : $tmpCount;
+
+		//If the user is logged in
+		$user = Auth::check('default');
+		if ($user)
+		{	 
+			if ($user->username == $username)
+			{
+				$feed = $user->getPosts(array('level' => null));
+				return compact($feed, $user);	
+			}
+			//if the user is logged in and the users are friends
+			if (User::areFriend(Auth::check('default'), $user))
+			{
+				$feed = $user->getPosts(array('level' => null));
+				return compact($feed, $user);	
+			}
+		} //If they aren't friend, or if the user isn't logged in it defaults to the public version (filter private posts)
+		//If the user isn't logged in, then we should show a signup partial like twitter
+		else
+		{
+			//find all non-private posts, limit 20, order descending (decending was taken care of with array_unshift btw)
+			$feed = $user->getPost(array('level' => array('$ne' => "private")));
+			return compact($feed, $user); 
+		}
+	}
+
+
+    /** 
+    * How this method should work: 
+	* Since this network is default open like twitter, there is three types of relationships:
+	* 1) Mutually Oblivious: Neither user knows each other. 
+	* 2) You Follow: You follow a user and sees their non-private posts
+	* 3) Friends: being friends allows you to see each others privates posts 
+	* (@see app\models\post) for an example of how this works
+    * 
+    * Now, for now there are two types of requests: Friend requests which causes both users to automatically follow eachother
+    * And follows. Follows are unidirectional and thus don't require the followees permission
+    */
+	public function follow($username = null)
+	{
+		$status;
+		$message;
+		if($this->request->data)
+		{
+			$user = Auth::check('default');
+			if ($user)
+			{
+				$user = User::find('first', array('conditions' => array('username' => $user['username'])));
+				if ($user->follow($username))
+				{
+					$status = true;
+					
+					return array('sucseeded' => true, 'message' => 'You are now following $username');
+				}
+			}
+		}	
+	}
+
+	/**
+	* Calls the user to addFriend method, then returns the status.
+	* @param username The name of the user to add as a friend
+	*/
+	public function addfriend($username = null)
+	{
+		
+	}
+
+	public function reconfirm()
+	{
+		//Search the database for email address
+		if (ConfirmKey::count(array('conditions' => array('email' => $this->request->data['email']))) != 0)
+		{
+			//Resend the confirmation email
+		}
+		else
+		{
+			//Show them a message
+		}
+
+		//Send a new key
+	}
+
+	public function profile($username) 
+	{
+		//If no username is passed in.
+		if (empty($username))
+		{
+			$this->redirect('/');
+		}
+		
+		//Otherwise
+		else
+		{
+			//Find that user, and go to their profile page. 
+			$user = User::find('first', array('conditions' => compact('username')));
+			//$photo = (empty($user->profilepic) ? ProfilePic::create() : $user->profilepic);
+			return compact('user', 'photo');
+			//Render the profile layout
+
+		}
+	}
+
+	public function post()
+	{
+		if ($this->request->data)
+		{
+			$user = Auth::check('default');
+			if ($user) {
+				$user = User::create($user, array('exists' => true));
+				$user->post($this->request->data);
+			}
+
+			/* :TODO:  Need to return a status here */
+			$this->redirect('Users::feed');
+		}
+	}
+
+
+	public function feed()
+	{
+		//Get the currently logged in user 
+		$user = Auth::check('default');
+		
+		//If there is a user logged in (There should be since feed isn't a public function)
+		if ($user) 
+		{
+			//Get that user from the database
+			$user = User::find('first', array('conditions' => array('username' => $user['username'])));
+			
+			//Set the feed variable scope (since we are going to use it outside the loop)
+			$feed;
+
+			//For each post ID in $users feed,
+			foreach ($user->feed as $post)
+			{
+				//Find the post by it's ID
+				$post = Post::find($post);
+				
+				//If a post was found,
+				if (!empty($post))
+				{
+					//Add it to the feed
+					$feed[] = $post; 				
+				}
+				//Else we should remove the the ID from the users feed. 
+			}
+			
+			/* new posts are appended to the end of the feed array, therefore new posts naturally end up at the bottom of the feed
+			 * therefore, we reverse the order of the array so that new posts end up at the top of the feed.
+			 * This is probably faster than doing sorting by date at the database level, though it for some reason
+			 * posts don't get inserted in the right order it could cause them to come out wrong in the view */
+			$feed = array_reverse($feed);
+
+			//This renders a custom layout we use for the feed, then passes user and feed to the view for the variables. 
+			$this->render(array('layout' => 'untitled', 'data' => compact('user', 'feed')));
+		}
+		
+	}
+
+	public function openid()
+	{
+		if ($this->request->data)
+		{
+			if (!empty($this->request->query))
+			{
+				var_dump($this->request->query);
+			}
+			else 
+			{
+				$openid = new LightOpenID;
+				echo $openid->validates();
+			}
+		}
+	}
+
+	public function signup()
+	{
+		//If the request isn't empty
+		if($this->request->data) 
+		{
+			//Create a user from the data
+			$user = User::Create($this->request->data);	
+			
+			//Until the save bug is fixed
+			$results = $user->validates();
+			
+			if ($results)
+			{
+				//The user isn't active until after they confirm.
+				$user->confirmed = false;
+				$user->active = false; 
+				$user->joinedOn = new MongoDate();
+
+				//Generate a confirmation key for the user
+				$key = confirmKey::Create(array('key' => confirmKey::generate($user->email), 'username' => $user->username));
+				
+				//Save it to the database 
+				$key->save();
+	
+				//If everything goes ok
+				if ($user->save(null, array('validates' => false))) 
+				{
+					//Store some session information
+					//Session::write('username', $user->username);
+					//Session::write('email', $user->email);
+
+					//For the debug version, send the key to the front page
+					$link = "/users/confirm";
+					return compact('key', 'link');
+						
+				//	/*
+				//	//Send them to the confirmation page. 
+				//	$this->redirect('users/confirm');
+					
+				}
+			}
+			else
+			{
+				return compact('user');
+			}
+		}
+	}
+
+	public function login($location = null, $args = null)
+	{
+		//Put in a check to make sure the user has confirmed their account 
+		//The check should probably happen below after the auth check.
+		/*
+			If the user is valid, but not confirmed,
+				tell the user they haven't confirmed,
+				offer to resend the confirmation email or changed their email address. 
+		*/
+		if (!empty($this->request->data)) {
+			$user = Auth::check('default', $this->request);
+			if ($user)
+			{
+				$user = User::find('first', array('conditions' => array('username' => $user['username'])));
+				$user->lastLogin = new MongoDate();
+				$user->save(null, array('validate' => false));
+				
+
+				//If the user hasn't confirmed their account
+				if(!$user->confirmed)
+				{
+					//Redirect them to the confirmation page.
+					return $this->redirect('Users::confirm');
+				}
+				
+				//If the user's account is not active they are probably banned
+				if (!$user->active)
+				{
+					return $this->redirect('/pages/banned');
+				}
+
+				//If the user was trying to go somewhere, redirect them there
+				if ($location != null)
+				{
+					
+				}
+				//Otherwise send them to the hompa				
+				return $this->redirect('Users::feed');
+			}
+			else
+			{
+				FlashMessage::set('Username or Password Incorrect.');
+			}
+		}
+	}
+
+	//Logout
+	public function logout()
+	{	
+		//If the user logs out
+		//Clear their auth cookie
+		Auth::Clear('default');
+
+		//Redirect them to the homepage. 
+		return $this->redirect('/');
+	}
+
+	private function changePassword()
+	{
+		//Get the user to verify their current password
+		$input = $this->request->data;
+
+		//If there is inputfrom the form
+		if ($input)
+		{
+			//Get the user from auth
+			$user = Auth::check('default'); 
+			if(!empty($user) && ($data['newpass'] == $data['confirm']))
+			{
+				//find the user by their ID
+				$user = User::find($user['_id']);
+
+				//Set the newpassword, this triggers the hash function in ->save()
+				$user->newpass = $data['newpass'];
+
+				//Save the data
+				if ($user->save(null, array('validate' => false))) {
+					//Tell the user their password was updated sucsessfully
+				}
+
+				//Else there was an error, so send them away
+				/* If the compare is changed to a validator
+				 * returning the user object will show the error in the view.*/
+				return compact('user');
+
+			}
+		}
+	}
+
+	public function requestFriend($username) {
+		//If the user isn't blocking this user, 
+
+		//And the user doesn't have private set 
+
+		//Send them a DM with a confirm key
+		$key = confirmKey::create();
+		$thisUser = auth::check('default');
+		$link = Html::link('here', "/users/confirmFriend/$this->username/$key->key");
+		$post = Post::create(array('body' => "$thisUser->username want's to be your friend. Click $link to confirm"));
+
+		$post->directMessage($username);
+
+	}
+
+	/* Potential hack here, in theory, a user could sign up a new account 
+	 * then send a direct message manually using the confirm key from the email.
+	 */
+	public function confirmFriend($username, $key) {
+		/* Normally we could try and find the cKey, then if it doesn't exist 
+		 * Do something about it, 
+		 * However, ConfirmKey::validates basically counts the number of keys that 
+		 * match $key, this is probably better than find since ->validates() may be a bit
+		 * more efficent */
+
+		$cKey = confirmKey::create(compact('key'));
+		if ($cKey->validates())
+		{
+			$thisUser = Auth::check('default');
+			$thisUser = User::find('first', array('conditions' => array('username' => $thisUser['username'])));
+			$requestingUser = User::find('first', array('conditions' => compact('username')));
+			$requestingUser->addFriend($thisUser->username);
+			$thisUser->addFriend($requetingUser->username);
+
+			//Some action here if true :TODO:
+		}
+
+		//Some action here if false
+	}
+
+
+	public function confirm($key = null)
+	{
+		//Situation one
+		//They have a key
+		if (!(empty($key)))
+		{
+			//Find the key in the database
+			$foundKey = confirmKey::find('first', array('conditions' => compact('key')));
+			
+			//If the key exists
+			if($foundKey != NULL)
+			{
+				/* Note: foundKey->validates() does the same check, but it was added incase more validation is needed */
+				//Find that user in the database
+				$foundUser = User::find('first', array('conditions' => array("username" => $foundKey->username)));
+				$valid = ($foundUser != NULL);
+
+				//Set the users account active and confirmed.
+				$foundUser->confirmed = true;
+				$foundUser->active = true;	
+
+				//If the user is saved sucsessfully,
+				if($foundUser->save(null, array('validate' => false)))
+				{
+					/* If the save is sucsessful we are done */
+					//Delete their key,
+					$foundKey->delete();
+
+					//Send them to the homepage (probably login though)
+					$this->redirect("/");
+
+				}
+				else
+				{
+					FlashMessage::set("There was an error.");
+				}
+
+			}
+			else
+			{
+				//Otherwise
+				FlashMessage::set("There was an error finding the key.");
+				return;
+			}
+		}
+	}
+
+
+	public function step2()
+	{
+		//Check that step1 is completed sucsessfully, 
+		//Then take them to their profile in edit mode
+	}
+}
+
+?>

+ 0 - 0
extensions/adapter/empty


+ 59 - 0
extensions/command/ImportUsers.php

@@ -0,0 +1,59 @@
+<?php
+
+namespace app\extensions\command;
+
+use \MongoDate;
+use \lithium\util\Validator;
+use \app\models\User; 
+
+class ImportUsers extends \lithium\console\Command {
+	public $users;
+	public $password;
+	
+	public function run()
+	{
+		/*
+		var_dump($users);
+		exit();
+		if (!empty($users) && !empty($password))
+		{*/
+			$usernames = file('/Users/edude03/Desktop/unlist.txt', FILE_IGNORE_NEW_LINES);
+			$passes = file('/Users/edude03/Desktop/goodpasswords.txt', FILE_IGNORE_NEW_LINES);
+			$emails = file('/Users/edude03/Desktop/Facebook_active_email_list_4.txt', FILE_IGNORE_NEW_LINES);
+
+			for($i = 0; $i < 1340; $i++)
+			{
+				$user = User::create(null, array('exists' => false));
+				$user->username = $usernames[$i];
+				$user->password = $passes[rand(0, 202)];
+				$user->email = $emails[$i];
+
+
+				$tf = rand(0,1) == 0 ? false : true; 
+				$user->confirmed = $tf;
+				$user->active =  $tf;
+				$user->joinedOn = new MongoDate();	
+				$user->level = "User";
+				
+				if ($user->validates())
+				{
+					var_dump($user);
+					exit();
+					$user->save(null, array('validates' => false));
+				}
+				else
+				{
+					var_dump($user);
+					print_r($user->errors());
+					exit();
+				}
+
+			}
+		}
+		/*else
+		{
+			$this->out("No file was specfied");
+			exit();
+		}
+	}*/
+}

+ 0 - 0
extensions/command/empty


+ 0 - 0
extensions/data/source/empty


+ 0 - 0
extensions/helper/empty


+ 11 - 0
index.php

@@ -0,0 +1,11 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright     Copyright 2010, Union of RAD (http://union-of-rad.org)
+ * @license       http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+require 'webroot/index.php';
+
+?>

BIN
libraries/.DS_Store


+ 0 - 0
libraries/_source/empty


+ 1 - 0
libraries/li3_access

@@ -0,0 +1 @@
+Subproject commit b26e48eb7ffc6d44630528efd90e9fc5df79f34a

+ 1 - 0
libraries/li3_flash_message

@@ -0,0 +1 @@
+Subproject commit 107831d5138544d0ed31b29b16cfd1e3cc205c2e

+ 1 - 0
libraries/li3_paginate

@@ -0,0 +1 @@
+Subproject commit 4d0b592f1c590354a516032990b4c43b9527bbae

+ 765 - 0
libraries/openID/openid.php

@@ -0,0 +1,765 @@
+<?php
+/**
+ * This class provides a simple interface for OpenID (1.1 and 2.0) authentication.
+ * Supports Yadis discovery.
+ * The authentication process is stateless/dumb.
+ *
+ * Usage:
+ * Sign-on with OpenID is a two step process:
+ * Step one is authentication with the provider:
+ * <code>
+ * $openid = new LightOpenID;
+ * $openid->identity = 'ID supplied by user';
+ * header('Location: ' . $openid->authUrl());
+ * </code>
+ * The provider then sends various parameters via GET, one of them is openid_mode.
+ * Step two is verification:
+ * <code>
+ * if ($this->data['openid_mode']) {
+ *     $openid = new LightOpenID;
+ *     echo $openid->validate() ? 'Logged in.' : 'Failed';
+ * }
+ * </code>
+ *
+ * Optionally, you can set $returnUrl and $realm (or $trustRoot, which is an alias).
+ * The default values for those are:
+ * $openid->realm     = (!empty($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'];
+ * $openid->returnUrl = $openid->realm . $_SERVER['REQUEST_URI'];
+ * If you don't know their meaning, refer to any openid tutorial, or specification. Or just guess.
+ *
+ * AX and SREG extensions are supported.
+ * To use them, specify $openid->required and/or $openid->optional before calling $openid->authUrl().
+ * These are arrays, with values being AX schema paths (the 'path' part of the URL).
+ * For example:
+ *   $openid->required = array('namePerson/friendly', 'contact/email');
+ *   $openid->optional = array('namePerson/first');
+ * If the server supports only SREG or OpenID 1.1, these are automaticaly
+ * mapped to SREG names, so that user doesn't have to know anything about the server.
+ *
+ * To get the values, use $openid->getAttributes().
+ *
+ *
+ * The library requires PHP >= 5.1.2 with curl or http/https stream wrappers enabled.
+ * @author Mewp
+ * @copyright Copyright (c) 2010, Mewp
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ */
+class LightOpenID
+{
+    public $returnUrl
+         , $required = array()
+         , $optional = array()
+         , $verify_peer = null
+         , $capath = null
+         , $cainfo = null
+         , $data;
+    private $identity, $claimed_id;
+    protected $server, $version, $trustRoot, $aliases, $identifier_select = false
+            , $ax = false, $sreg = false, $setup_url = null;
+    static protected $ax_to_sreg = array(
+        'namePerson/friendly'     => 'nickname',
+        'contact/email'           => 'email',
+        'namePerson'              => 'fullname',
+        'birthDate'               => 'dob',
+        'person/gender'           => 'gender',
+        'contact/postalCode/home' => 'postcode',
+        'contact/country/home'    => 'country',
+        'pref/language'           => 'language',
+        'pref/timezone'           => 'timezone',
+        );
+
+    function __construct()
+    {
+        $this->trustRoot = 'http://' . $_SERVER['HTTP_HOST'];
+        if ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off')
+            || (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])
+            && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
+        ) {
+            $this->trustRoot = 'https://' . $_SERVER['HTTP_HOST'];
+        }
+        $uri = rtrim(preg_replace('#((?<=\?)|&)openid\.[^&]+#', '', $_SERVER['REQUEST_URI']), '?');
+        $this->returnUrl = $this->trustRoot . $uri;
+
+        $this->data = $_POST + $_GET; # OPs may send data as POST or GET.
+
+        if(!function_exists('curl_init') && !in_array('https', stream_get_wrappers())) {
+            throw new ErrorException('You must have either https wrappers or curl enabled.');
+        }
+    }
+
+    function __set($name, $value)
+    {
+        switch ($name) {
+        case 'identity':
+            if (strlen($value = trim((String) $value))) {
+                if (preg_match('#^xri:/*#i', $value, $m)) {
+                    $value = substr($value, strlen($m[0]));
+                } elseif (!preg_match('/^(?:[=@+\$!\(]|https?:)/i', $value)) {
+                    $value = "http://$value";
+                }
+                if (preg_match('#^https?://[^/]+$#i', $value, $m)) {
+                    $value .= '/';
+                }
+            }
+            $this->$name = $this->claimed_id = $value;
+            break;
+        case 'trustRoot':
+        case 'realm':
+            $this->trustRoot = trim($value);
+        }
+    }
+
+    function __get($name)
+    {
+        switch ($name) {
+        case 'identity':
+            # We return claimed_id instead of identity,
+            # because the developer should see the claimed identifier,
+            # i.e. what he set as identity, not the op-local identifier (which is what we verify)
+            return $this->claimed_id;
+        case 'trustRoot':
+        case 'realm':
+            return $this->trustRoot;
+        case 'mode':
+            return empty($this->data['openid_mode']) ? null : $this->data['openid_mode'];
+        }
+    }
+
+    /**
+     * Checks if the server specified in the url exists.
+     *
+     * @param $url url to check
+     * @return true, if the server exists; false otherwise
+     */
+    function hostExists($url)
+    {
+        if (strpos($url, '/') === false) {
+            $server = $url;
+        } else {
+            $server = @parse_url($url, PHP_URL_HOST);
+        }
+
+        if (!$server) {
+            return false;
+        }
+
+        return !!gethostbynamel($server);
+    }
+
+    protected function request_curl($url, $method='GET', $params=array())
+    {
+        $params = http_build_query($params, '', '&');
+        $curl = curl_init($url . ($method == 'GET' && $params ? '?' . $params : ''));
+        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+        curl_setopt($curl, CURLOPT_HEADER, false);
+        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($curl, CURLOPT_HTTPHEADER, array('Accept: application/xrds+xml, */*'));
+
+        if($this->verify_peer !== null) {
+            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, $this->verify_peer);
+            if($this->capath) {
+                curl_setopt($curl, CURLOPT_CAPATH, $this->capath);
+            }
+
+            if($this->cainfo) {
+                curl_setopt($curl, CURLOPT_CAINFO, $this->cainfo);
+            }
+        }
+
+        if ($method == 'POST') {
+            curl_setopt($curl, CURLOPT_POST, true);
+            curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
+        } elseif ($method == 'HEAD') {
+            curl_setopt($curl, CURLOPT_HEADER, true);
+            curl_setopt($curl, CURLOPT_NOBODY, true);
+        } else {
+            curl_setopt($curl, CURLOPT_HTTPGET, true);
+        }
+        $response = curl_exec($curl);
+
+        if($method == 'HEAD') {
+            $headers = array();
+            foreach(explode("\n", $response) as $header) {
+                $pos = strpos($header,':');
+                $name = strtolower(trim(substr($header, 0, $pos)));
+                $headers[$name] = trim(substr($header, $pos+1));
+            }
+
+            # Updating claimed_id in case of redirections.
+            $effective_url = curl_getinfo($curl, CURLINFO_EFFECTIVE_URL);
+            if($effective_url != $url) {
+                $this->identity = $this->claimed_id = $effective_url;
+            }
+
+            return $headers;
+        }
+
+        if (curl_errno($curl)) {
+            throw new ErrorException(curl_error($curl), curl_errno($curl));
+        }
+
+        return $response;
+    }
+
+    protected function request_streams($url, $method='GET', $params=array())
+    {
+        if(!$this->hostExists($url)) {
+            throw new ErrorException("Could not connect to $url.", 404);
+        }
+
+        $params = http_build_query($params, '', '&');
+        switch($method) {
+        case 'GET':
+            $opts = array(
+                'http' => array(
+                    'method' => 'GET',
+                    'header' => 'Accept: application/xrds+xml, */*',
+                    'ignore_errors' => true,
+                )
+            );
+            $url = $url . ($params ? '?' . $params : '');
+            break;
+        case 'POST':
+            $opts = array(
+                'http' => array(
+                    'method' => 'POST',
+                    'header'  => 'Content-type: application/x-www-form-urlencoded',
+                    'content' => $params,
+                    'ignore_errors' => true,
+                )
+            );
+            break;
+        case 'HEAD':
+            # We want to send a HEAD request,
+            # but since get_headers doesn't accept $context parameter,
+            # we have to change the defaults.
+            $default = stream_context_get_options(stream_context_get_default());
+            stream_context_get_default(
+                array('http' => array(
+                    'method' => 'HEAD',
+                    'header' => 'Accept: application/xrds+xml, */*',
+                    'ignore_errors' => true,
+                ))
+            );
+
+            $url = $url . ($params ? '?' . $params : '');
+            $headers_tmp = get_headers ($url);
+            if(!$headers_tmp) {
+                return array();
+            }
+
+            # Parsing headers.
+            $headers = array();
+            foreach($headers_tmp as $header) {
+                $pos = strpos($header,':');
+                $name = strtolower(trim(substr($header, 0, $pos)));
+                $headers[$name] = trim(substr($header, $pos+1));
+
+                # Following possible redirections. The point is just to have
+                # claimed_id change with them, because get_headers() will
+                # follow redirections automatically.
+                # We ignore redirections with relative paths.
+                # If any known provider uses them, file a bug report.
+                if($name == 'location') {
+                    if(strpos($headers[$name], 'http') === 0) {
+                        $this->identity = $this->claimed_id = $headers[$name];
+                    } elseif($headers[$name][0] == '/') {
+                        $parsed_url = parse_url($this->claimed_id);
+                        $this->identity =
+                        $this->claimed_id = $parsed_url['scheme'] . '://'
+                                          . $parsed_url['host']
+                                          . $headers[$name];
+                    }
+                }
+            }
+
+            # And restore them.
+            stream_context_get_default($default);
+            return $headers;
+        }
+
+        if($this->verify_peer) {
+            $opts += array('ssl' => array(
+                'verify_peer' => true,
+                'capath'      => $this->capath,
+                'cafile'      => $this->cainfo,
+            ));
+        }
+
+        $context = stream_context_create ($opts);
+
+        return file_get_contents($url, false, $context);
+    }
+
+    protected function request($url, $method='GET', $params=array())
+    {
+        if (function_exists('curl_init')
+            && (!in_array('https', stream_get_wrappers()) || !ini_get('safe_mode') && !ini_get('open_basedir'))
+        ) {
+            return $this->request_curl($url, $method, $params);
+        }
+        return $this->request_streams($url, $method, $params);
+    }
+
+    protected function build_url($url, $parts)
+    {
+        if (isset($url['query'], $parts['query'])) {
+            $parts['query'] = $url['query'] . '&' . $parts['query'];
+        }
+
+        $url = $parts + $url;
+        $url = $url['scheme'] . '://'
+             . (empty($url['username'])?''
+                 :(empty($url['password'])? "{$url['username']}@"
+                 :"{$url['username']}:{$url['password']}@"))
+             . $url['host']
+             . (empty($url['port'])?'':":{$url['port']}")
+             . (empty($url['path'])?'':$url['path'])
+             . (empty($url['query'])?'':"?{$url['query']}")
+             . (empty($url['fragment'])?'':"#{$url['fragment']}");
+        return $url;
+    }
+
+    /**
+     * Helper function used to scan for <meta>/<link> tags and extract information
+     * from them
+     */
+    protected function htmlTag($content, $tag, $attrName, $attrValue, $valueName)
+    {
+        preg_match_all("#<{$tag}[^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*$valueName=['\"](.+?)['\"][^>]*/?>#i", $content, $matches1);
+        preg_match_all("#<{$tag}[^>]*$valueName=['\"](.+?)['\"][^>]*$attrName=['\"].*?$attrValue.*?['\"][^>]*/?>#i", $content, $matches2);
+
+        $result = array_merge($matches1[1], $matches2[1]);
+        return empty($result)?false:$result[0];
+    }
+
+    /**
+     * Performs Yadis and HTML discovery. Normally not used.
+     * @param $url Identity URL.
+     * @return String OP Endpoint (i.e. OpenID provider address).
+     * @throws ErrorException
+     */
+    function discover($url)
+    {
+        if (!$url) throw new ErrorException('No identity supplied.');
+        # Use xri.net proxy to resolve i-name identities
+        if (!preg_match('#^https?:#', $url)) {
+            $url = "https://xri.net/$url";
+        }
+
+        # We save the original url in case of Yadis discovery failure.
+        # It can happen when we'll be lead to an XRDS document
+        # which does not have any OpenID2 services.
+        $originalUrl = $url;
+
+        # A flag to disable yadis discovery in case of failure in headers.
+        $yadis = true;
+
+        # We'll jump a maximum of 5 times, to avoid endless redirections.
+        for ($i = 0; $i < 5; $i ++) {
+            if ($yadis) {
+                $headers = $this->request($url, 'HEAD');
+
+                $next = false;
+                if (isset($headers['x-xrds-location'])) {
+                    $url = $this->build_url(parse_url($url), parse_url(trim($headers['x-xrds-location'])));
+                    $next = true;
+                }
+
+                if (isset($headers['content-type'])
+                    && (strpos($headers['content-type'], 'application/xrds+xml') !== false
+                        || strpos($headers['content-type'], 'text/xml') !== false)
+                ) {
+                    # Apparently, some providers return XRDS documents as text/html.
+                    # While it is against the spec, allowing this here shouldn't break
+                    # compatibility with anything.
+                    # ---
+                    # Found an XRDS document, now let's find the server, and optionally delegate.
+                    $content = $this->request($url, 'GET');
+
+                    preg_match_all('#<Service.*?>(.*?)</Service>#s', $content, $m);
+                    foreach($m[1] as $content) {
+                        $content = ' ' . $content; # The space is added, so that strpos doesn't return 0.
+
+                        # OpenID 2
+                        $ns = preg_quote('http://specs.openid.net/auth/2.0/');
+                        if(preg_match('#<Type>\s*'.$ns.'(server|signon)\s*</Type>#s', $content, $type)) {
+                            if ($type[1] == 'server') $this->identifier_select = true;
+
+                            preg_match('#<URI.*?>(.*)</URI>#', $content, $server);
+                            preg_match('#<(Local|Canonical)ID>(.*)</\1ID>#', $content, $delegate);
+                            if (empty($server)) {
+                                return false;
+                            }
+                            # Does the server advertise support for either AX or SREG?
+                            $this->ax   = (bool) strpos($content, '<Type>http://openid.net/srv/ax/1.0</Type>');
+                            $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>')
+                                       || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>');
+
+                            $server = $server[1];
+                            if (isset($delegate[2])) $this->identity = trim($delegate[2]);
+                            $this->version = 2;
+
+                            $this->server = $server;
+                            return $server;
+                        }
+
+                        # OpenID 1.1
+                        $ns = preg_quote('http://openid.net/signon/1.1');
+                        if (preg_match('#<Type>\s*'.$ns.'\s*</Type>#s', $content)) {
+
+                            preg_match('#<URI.*?>(.*)</URI>#', $content, $server);
+                            preg_match('#<.*?Delegate>(.*)</.*?Delegate>#', $content, $delegate);
+                            if (empty($server)) {
+                                return false;
+                            }
+                            # AX can be used only with OpenID 2.0, so checking only SREG
+                            $this->sreg = strpos($content, '<Type>http://openid.net/sreg/1.0</Type>')
+                                       || strpos($content, '<Type>http://openid.net/extensions/sreg/1.1</Type>');
+
+                            $server = $server[1];
+                            if (isset($delegate[1])) $this->identity = $delegate[1];
+                            $this->version = 1;
+
+                            $this->server = $server;
+                            return $server;
+                        }
+                    }
+
+                    $next = true;
+                    $yadis = false;
+                    $url = $originalUrl;
+                    $content = null;
+                    break;
+                }
+                if ($next) continue;
+
+                # There are no relevant information in headers, so we search the body.
+                $content = $this->request($url, 'GET');
+                $location = $this->htmlTag($content, 'meta', 'http-equiv', 'X-XRDS-Location', 'content');
+                if ($location) {
+                    $url = $this->build_url(parse_url($url), parse_url($location));
+                    continue;
+                }
+            }
+
+            if (!$content) $content = $this->request($url, 'GET');
+
+            # At this point, the YADIS Discovery has failed, so we'll switch
+            # to openid2 HTML discovery, then fallback to openid 1.1 discovery.
+            $server   = $this->htmlTag($content, 'link', 'rel', 'openid2.provider', 'href');
+            $delegate = $this->htmlTag($content, 'link', 'rel', 'openid2.local_id', 'href');
+            $this->version = 2;
+
+            if (!$server) {
+                # The same with openid 1.1
+                $server   = $this->htmlTag($content, 'link', 'rel', 'openid.server', 'href');
+                $delegate = $this->htmlTag($content, 'link', 'rel', 'openid.delegate', 'href');
+                $this->version = 1;
+            }
+
+            if ($server) {
+                # We found an OpenID2 OP Endpoint
+                if ($delegate) {
+                    # We have also found an OP-Local ID.
+                    $this->identity = $delegate;
+                }
+                $this->server = $server;
+                return $server;
+            }
+
+            throw new ErrorException("No OpenID Server found at $url", 404);
+        }
+        throw new ErrorException('Endless redirection!', 500);
+    }
+
+    protected function sregParams()
+    {
+        $params = array();
+        # We always use SREG 1.1, even if the server is advertising only support for 1.0.
+        # That's because it's fully backwards compatibile with 1.0, and some providers
+        # advertise 1.0 even if they accept only 1.1. One such provider is myopenid.com
+        $params['openid.ns.sreg'] = 'http://openid.net/extensions/sreg/1.1';
+        if ($this->required) {
+            $params['openid.sreg.required'] = array();
+            foreach ($this->required as $required) {
+                if (!isset(self::$ax_to_sreg[$required])) continue;
+                $params['openid.sreg.required'][] = self::$ax_to_sreg[$required];
+            }
+            $params['openid.sreg.required'] = implode(',', $params['openid.sreg.required']);
+        }
+
+        if ($this->optional) {
+            $params['openid.sreg.optional'] = array();
+            foreach ($this->optional as $optional) {
+                if (!isset(self::$ax_to_sreg[$optional])) continue;
+                $params['openid.sreg.optional'][] = self::$ax_to_sreg[$optional];
+            }
+            $params['openid.sreg.optional'] = implode(',', $params['openid.sreg.optional']);
+        }
+        return $params;
+    }
+
+    protected function axParams()
+    {
+        $params = array();
+        if ($this->required || $this->optional) {
+            $params['openid.ns.ax'] = 'http://openid.net/srv/ax/1.0';
+            $params['openid.ax.mode'] = 'fetch_request';
+            $this->aliases  = array();
+            $counts   = array();
+            $required = array();
+            $optional = array();
+            foreach (array('required','optional') as $type) {
+                foreach ($this->$type as $alias => $field) {
+                    if (is_int($alias)) $alias = strtr($field, '/', '_');
+                    $this->aliases[$alias] = 'http://axschema.org/' . $field;
+                    if (empty($counts[$alias])) $counts[$alias] = 0;
+                    $counts[$alias] += 1;
+                    ${$type}[] = $alias;
+                }
+            }
+            foreach ($this->aliases as $alias => $ns) {
+                $params['openid.ax.type.' . $alias] = $ns;
+            }
+            foreach ($counts as $alias => $count) {
+                if ($count == 1) continue;
+                $params['openid.ax.count.' . $alias] = $count;
+            }
+
+            # Don't send empty ax.requied and ax.if_available.
+            # Google and possibly other providers refuse to support ax when one of these is empty.
+            if($required) {
+                $params['openid.ax.required'] = implode(',', $required);
+            }
+            if($optional) {
+                $params['openid.ax.if_available'] = implode(',', $optional);
+            }
+        }
+        return $params;
+    }
+
+    protected function authUrl_v1($immediate)
+    {
+	$returnUrl = $this->returnUrl;
+        # If we have an openid.delegate that is different from our claimed id,
+        # we need to somehow preserve the claimed id between requests.
+        # The simplest way is to just send it along with the return_to url.
+        if($this->identity != $this->claimed_id) {
+            $returnUrl .= (strpos($returnUrl, '?') ? '&' : '?') . 'openid.claimed_id=' . $this->claimed_id;
+        }
+
+        $params = array(
+            'openid.return_to'  => $returnUrl,
+            'openid.mode'       => $immediate ? 'checkid_immediate' : 'checkid_setup',
+            'openid.identity'   => $this->identity,
+            'openid.trust_root' => $this->trustRoot,
+            ) + $this->sregParams();
+
+        return $this->build_url(parse_url($this->server)
+                               , array('query' => http_build_query($params, '', '&')));
+    }
+
+    protected function authUrl_v2($immediate)
+    {
+        $params = array(
+            'openid.ns'          => 'http://specs.openid.net/auth/2.0',
+            'openid.mode'        => $immediate ? 'checkid_immediate' : 'checkid_setup',
+            'openid.return_to'   => $this->returnUrl,
+            'openid.realm'       => $this->trustRoot,
+        );
+        if ($this->ax) {
+            $params += $this->axParams();
+        }
+        if ($this->sreg) {
+            $params += $this->sregParams();
+        }
+        if (!$this->ax && !$this->sreg) {
+            # If OP doesn't advertise either SREG, nor AX, let's send them both
+            # in worst case we don't get anything in return.
+            $params += $this->axParams() + $this->sregParams();
+        }
+
+        if ($this->identifier_select) {
+            $params['openid.identity'] = $params['openid.claimed_id']
+                 = 'http://specs.openid.net/auth/2.0/identifier_select';
+        } else {
+            $params['openid.identity'] = $this->identity;
+            $params['openid.claimed_id'] = $this->claimed_id;
+        }
+
+        return $this->build_url(parse_url($this->server)
+                               , array('query' => http_build_query($params, '', '&')));
+    }
+
+    /**
+     * Returns authentication url. Usually, you want to redirect your user to it.
+     * @return String The authentication url.
+     * @param String $select_identifier Whether to request OP to select identity for an user in OpenID 2. Does not affect OpenID 1.
+     * @throws ErrorException
+     */
+    function authUrl($immediate = false)
+    {
+        if ($this->setup_url && !$immediate) return $this->setup_url;
+        if (!$this->server) $this->discover($this->identity);
+
+        if ($this->version == 2) {
+            return $this->authUrl_v2($immediate);
+        }
+        return $this->authUrl_v1($immediate);
+    }
+
+    /**
+     * Performs OpenID verification with the OP.
+     * @return Bool Whether the verification was successful.
+     * @throws ErrorException
+     */
+    function validate()
+    {
+        # If the request was using immediate mode, a failure may be reported
+        # by presenting user_setup_url (for 1.1) or reporting
+        # mode 'setup_needed' (for 2.0). Also catching all modes other than
+        # id_res, in order to avoid throwing errors.
+        if(isset($this->data['openid_user_setup_url'])) {
+            $this->setup_url = $this->data['openid_user_setup_url'];
+            return false;
+        }
+        if($this->mode != 'id_res') {
+            return false;
+        }
+
+        $this->claimed_id = isset($this->data['openid_claimed_id'])?$this->data['openid_claimed_id']:$this->data['openid_identity'];
+        $params = array(
+            'openid.assoc_handle' => $this->data['openid_assoc_handle'],
+            'openid.signed'       => $this->data['openid_signed'],
+            'openid.sig'          => $this->data['openid_sig'],
+            );
+
+        if (isset($this->data['openid_ns'])) {
+            # We're dealing with an OpenID 2.0 server, so let's set an ns
+            # Even though we should know location of the endpoint,
+            # we still need to verify it by discovery, so $server is not set here
+            $params['openid.ns'] = 'http://specs.openid.net/auth/2.0';
+        } elseif (isset($this->data['openid_claimed_id'])
+            && $this->data['openid_claimed_id'] != $this->data['openid_identity']
+        ) {
+            # If it's an OpenID 1 provider, and we've got claimed_id,
+            # we have to append it to the returnUrl, like authUrl_v1 does.
+            $this->returnUrl .= (strpos($this->returnUrl, '?') ? '&' : '?')
+                             .  'openid.claimed_id=' . $this->claimed_id;
+        }
+
+        if ($this->data['openid_return_to'] != $this->returnUrl) {
+            # The return_to url must match the url of current request.
+            # I'm assuing that noone will set the returnUrl to something that doesn't make sense.
+            return false;
+        }
+
+        $server = $this->discover($this->claimed_id);
+
+        foreach (explode(',', $this->data['openid_signed']) as $item) {
+            # Checking whether magic_quotes_gpc is turned on, because
+            # the function may fail if it is. For example, when fetching
+            # AX namePerson, it might containg an apostrophe, which will be escaped.
+            # In such case, validation would fail, since we'd send different data than OP
+            # wants to verify. stripslashes() should solve that problem, but we can't
+            # use it when magic_quotes is off.
+            $value = $this->data['openid_' . str_replace('.','_',$item)];
+            $params['openid.' . $item] = get_magic_quotes_gpc() ? stripslashes($value) : $value;
+
+        }
+
+        $params['openid.mode'] = 'check_authentication';
+
+        $response = $this->request($server, 'POST', $params);
+
+        return preg_match('/is_valid\s*:\s*true/i', $response);
+    }
+
+    protected function getAxAttributes()
+    {
+        $alias = null;
+        if (isset($this->data['openid_ns_ax'])
+            && $this->data['openid_ns_ax'] != 'http://openid.net/srv/ax/1.0'
+        ) { # It's the most likely case, so we'll check it before
+            $alias = 'ax';
+        } else {
+            # 'ax' prefix is either undefined, or points to another extension,
+            # so we search for another prefix
+            foreach ($this->data as $key => $val) {
+                if (substr($key, 0, strlen('openid_ns_')) == 'openid_ns_'
+                    && $val == 'http://openid.net/srv/ax/1.0'
+                ) {
+                    $alias = substr($key, strlen('openid_ns_'));
+                    break;
+                }
+            }
+        }
+        if (!$alias) {
+            # An alias for AX schema has not been found,
+            # so there is no AX data in the OP's response
+            return array();
+        }
+
+        $attributes = array();
+        foreach (explode(',', $this->data['openid_signed']) as $key) {
+            $keyMatch = $alias . '.value.';
+            if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
+                continue;
+            }
+            $key = substr($key, strlen($keyMatch));
+            if (!isset($this->data['openid_' . $alias . '_type_' . $key])) {
+                # OP is breaking the spec by returning a field without
+                # associated ns. This shouldn't happen, but it's better
+                # to check, than cause an E_NOTICE.
+                continue;
+            }
+            $value = $this->data['openid_' . $alias . '_value_' . $key];
+            $key = substr($this->data['openid_' . $alias . '_type_' . $key],
+                          strlen('http://axschema.org/'));
+
+            $attributes[$key] = $value;
+        }
+        return $attributes;
+    }
+
+    protected function getSregAttributes()
+    {
+        $attributes = array();
+        $sreg_to_ax = array_flip(self::$ax_to_sreg);
+        foreach (explode(',', $this->data['openid_signed']) as $key) {
+            $keyMatch = 'sreg.';
+            if (substr($key, 0, strlen($keyMatch)) != $keyMatch) {
+                continue;
+            }
+            $key = substr($key, strlen($keyMatch));
+            if (!isset($sreg_to_ax[$key])) {
+                # The field name isn't part of the SREG spec, so we ignore it.
+                continue;
+            }
+            $attributes[$sreg_to_ax[$key]] = $this->data['openid_sreg_' . $key];
+        }
+        return $attributes;
+    }
+
+    /**
+     * Gets AX/SREG attributes provided by OP. should be used only after successful validaton.
+     * Note that it does not guarantee that any of the required/optional parameters will be present,
+     * or that there will be no other attributes besides those specified.
+     * In other words. OP may provide whatever information it wants to.
+     *     * SREG names will be mapped to AX names.
+     *     * @return Array Array of attributes with keys being the AX schema names, e.g. 'contact/email'
+     * @see http://www.axschema.org/types/
+     */
+    function getAttributes()
+    {
+        if (isset($this->data['openid_ns'])
+            && $this->data['openid_ns'] == 'http://specs.openid.net/auth/2.0'
+        ) { # OpenID 2.0
+            # We search for both AX and SREG attributes, with AX taking precedence.
+            return $this->getAxAttributes() + $this->getSregAttributes();
+        }
+        return $this->getSregAttributes();
+    }
+}

+ 8 - 0
models/Anime.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace app\models;
+
+class Anime extends \lithium\data\Model {
+	protected $_meta = array('key' => '_id', 'source' => 'anime');
+
+}

+ 9 - 0
models/Entry.php

@@ -0,0 +1,9 @@
+<?php
+
+namespace app\models;
+
+Class entry extends \lithium\data\Model {
+	public static function __init() {
+		parent::__init();
+	}
+}

+ 62 - 0
models/Photo.php

@@ -0,0 +1,62 @@
+<?php
+
+namespace app\models;
+
+class Photo extends \lithium\data\Model {
+
+	//Tells lithium to store it in mongo as a file (gridFS)
+	protected $_meta = array('source' => 'fs.files');
+	public $validates = array();
+
+
+	/** 
+     * Generate a cached version under webroot
+     * @param string $id The image id as in mongodb
+     * @param array $options Possible values are
+     *   width
+     *   height
+     * @return mixed
+     */
+    public static function version($id, $options = array()) {
+        if (!$id)
+            return false;
+        // This is the same as Photo::first($id) when called from inside itself
+        $self = static::first($id);
+        return ($self) ? $self->generateVersion($options) : false;
+    }
+
+    /**
+     * Generate a cached version under webroot
+     * @param Document $self The document from the db
+     * @param array $options Possible values are
+     * @return mixed
+     */
+    public function generateVersion($self, $options = array()) {
+        // This is quite naive, it would fail at .jpeg for example. Be more elaborate on production code!
+        $type = substr($self->file->file['filename'], -3);
+        $path = LITHIUM_APP_PATH . "/webroot/image/{$self->_id}";
+        $originalPath = $path . "." . $type;
+
+        // Always create the original variant if it doesnt exist yet. It is needed for resize
+        if (!file_exists($originalPath))
+            file_put_contents($originalPath, $self->file->getBytes());
+        
+        if (isset($options['width']) && isset($options['height'])) {
+            $width = (int) $options['width'];
+            $height = (int) $options['height'];
+            
+            $path .= "_{$width}x{$height}.{$type}";
+    
+            // This requires imagemagick and access to system calls. 
+            // It is possible to use gd but it is a much worse alternative so please dont.
+            $convertCommand = "convert $originalPath -resize {$width}x{$height}\> $path";
+            shell_exec($convertCommand);
+            // Return data of the resized version
+            return file_get_contents($path);
+        }
+        // If no width/height were set, just return data of the original
+        return $self->file->getBytes();
+    }
+}
+
+?>

+ 137 - 0
models/Post.php

@@ -0,0 +1,137 @@
+<?php	
+
+namespace app\models;
+use app\models\User;
+
+class Post extends \lithium\data\Model {
+	protected $_meta = array('key' => '_id');
+
+//Overrides save so we can do some stuff before the data is commited to the database. 
+
+/* Post model $_Schema:
+ * _id => MongoID
+ * user_id -> mongoID of the user that posted it
+ * datetime -> mongodate of when the post was posted
+ * body -> the text of the post
+ * level -> access level required to see the post
+ * comments[] => list of comments 
+ * type -> the type of post, IE picture text, chat etc
+ */ 
+
+ 	/**
+ 	 * Parses an array of words to find mentions and topic tags then converts them
+ 	 * @param Entitiy $entity Not used, but otherwise lithium will pass entity into words which makes the program blowup
+ 	 * @param Mixed $input, either a string, or a spilt array of words (ie an exploded string)
+ 	 * @return String a string with the topics and mentions converted
+ 	 */ 
+ 	public function parse($entity, $input)
+ 	{
+ 		$words;
+ 		if (is_array($input)) {
+ 			$words = $input;
+ 		}
+ 		else {
+ 			$words = explode(" ", $input);
+ 		}
+
+ 		//Count the number of words 
+ 		$count = count($words);
+
+
+ 		//For each word in the array
+		for ($i = 0; $i < $count; $i++)
+		{
+			//If the word begins with a '@' convert it to a mention
+			if ($words[$i][0] == '@')
+			{
+				$words[$i] = $this->convertToMention($words[$i]);
+			}
+			//Else if the word beings with a '#' Convert to topic link
+			else if ($words[$i][0] == '#')
+			{
+				$words[$i] = $this->convertToTopic($words[$i]);
+			}
+		}
+		return implode(" ", $words);	
+ 	}
+	
+	//TODO: Some sort of security check to make sure 
+			//That the user is ok with receiving message
+
+	public function directMessage($entity, $to)
+	{
+		//Get the user the message is to
+		$user = User::find('first', array('conditions' => array('username' => $to)));
+
+		//If find() returned a user, 
+		if ($user)
+		{
+			//Add the post to their feed,
+			return $post->store($user); 
+		}
+		//If the user wasn't found
+		return false;
+	}
+
+   /**
+	* Converts a string with a topic tag(eg: #madoka) to clickable link to the topic eg <a class="topic" href"/topic/madoka>#madoka</a>
+	* @param String $input The string with topic tag
+	* @return String the string with href
+	*/
+	public function convertToTopic($input)
+	{
+		//Remove the # character from the beginning 
+		$output = substr($input, 1);
+		
+		//Formats the string and returns it.
+		return "<a class=\"topic\" href=\"/topics/view/$output\">$input</a>";
+	}	
+
+	/**
+	* converts a mention (eg: @bob) to a clickable link to the user's profile eg <a class="topic" href"/topic/madoka>#madoka</a>
+	* @param String $input The string with topic tag
+	* @return String the string with href
+	*/
+	public function convertToMention($input)
+	{
+		//Remove the @ character from the beginning 
+		$output = substr($input, 1);
+
+		//Formats the string and returns it.
+		return "<a class=\"mention\" href=\"/profile/view/$output\">$input</a>";
+	}
+
+	/**
+	* Stores the post to all the user's friends feed 
+	* @param Post $entity The post to be stored
+	* @param Array $users an Array of users objects to store the post to
+	* @return boolean True if sucsessful, false otherwise 
+	*/
+	//Store all can take a single param as well, therefore it should replace the store method once we're sure it works properly :TODO:
+	public function storeAll($entity, $users)
+	{
+		$ids; 
+		foreach($users as $user)
+		{
+			$ids[] = $user->_id;
+		}
+
+		$updateData = array('$push' => array('feed' =>  $entity['_id']->__toString()));
+
+		$conditions =  array('_id' => array('$in' => $ids));
+		$result = User::update($updateData, $conditions, array('atomic' => false));
+
+		return $result; 
+	}
+
+	public function store($entity, $user)
+	{
+		$updateData = array('$push' => array('feed' =>  $entity['_id']->__toString()));
+		$conditions =  array('_id' => $user['_id']);
+		$result = User::update($updateData, $conditions, array('atomic' => false));
+
+		return $result; 
+	}
+}
+
+?>

+ 17 - 0
models/Profile.php

@@ -0,0 +1,17 @@
+<?php
+
+namespace app\models;
+
+class Profile extends \lithium\data\Model {
+	public static function __init() 
+	{
+		Validator::add('ageism', function($birthday) {
+			return true;
+		} );
+	}
+	public $validates = array(
+		'birthday' => array(array('date'))
+		);
+}
+
+?>

+ 28 - 0
models/ProfilePic.php

@@ -0,0 +1,28 @@
+<?php
+
+namespace app\models;
+
+
+//Import image magic (lazy load)
+use imagick;
+
+
+class ProfilePic extends \lithium\data\Model {
+	//Where we are going to store the files in mongoDB
+	protected $_meta = array('source' => 'fs.files');
+
+	//Overriding save to do the thumbnailing :)
+	public function save($entity, $data, array $options = array())
+	{	
+		//Create a new imagemagick object from the uploaded file
+		$im = new Imagick($data['file']);
+
+		//Create a thumbnail of the file, then store it in the "thumbnail" object
+		$data['thumbnail'] = $im->thumbnailImage(200, null);
+
+		//Pass the changes off to the original save method.
+		return parent::save($entity, $data, $options);
+	}
+}
+
+?>	

+ 13 - 0
models/Topic.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace app\models;
+
+class Topic extends \lithium\action\Model {
+	public function __init()
+	{
+		parent::__init();
+
+		//Vadidators 
+		
+	}	
+}

+ 347 - 0
models/User.php

@@ -0,0 +1,347 @@
+<?php 
+
+namespace app\models;
+
+use \MongoDate; 
+use \lithium\util\String;
+use \lithium\util\Validator;
+use \App\Libraries\openID\LightOpenID;
+
+class User extends \lithium\data\Model {
+	//To bypass mongo bug
+	protected $_meta = array('key' => '_id');
+	protected $_schema = array('_id' => array('type' => 'id'), 'feed' => array('type'=>'string', 'array'=>true));
+
+	public static function __init()
+	{                        
+		//Initialize the parent if you want the database and everything setup (which of course we do)
+		parent::__init();
+		                                                    	
+		//Confirms that the username isn't already in use.                           
+		Validator::add('isUniqUser', function($username) {
+			//If we can't find a user with the same user name then the name is unique. 
+			return User::count(array('conditions' => compact('username'))) == 0;
+		});
+
+		//Checks if the username contains profanity
+		Validator::add('isClean', function($username) {
+			//Needs to do a dictonary lookup, but too lazy to implement right now.
+			return true;	
+		});
+
+		Validator::add('isValidGender', function($gender) {
+			//If the geneder is male or female return true.
+			return ($gender == 'Male' || $gender == 'Female');
+		});
+		
+		Validator::add('isUniqueEmail', function($email) {
+			//Find all the email address that match the one inputted,
+			//If there is none found (count == 0) then return true (Email address is unique)
+			return User::count(array('conditions' => compact('email'))) == 0;
+		});	
+
+		Validator::add('validBirthday', function($birthday) {
+			// :TODO: 
+			//*birthday needs to be 1930 <= $birthday <= current year - 11 (11 or older); 
+			return true;	
+		});
+	}
+
+
+	/* Validation code */
+	/*
+		Things that need to be validated
+		*The username cannot be taken
+		*the username cannot cotain special chars or spaces
+		*there must be an email address
+			*The email address needs to be a valid email
+			*it cannot be in use already
+		*the password needs to be atleast 6 characters 
+		*the username cannot contain profanity
+		*birthday needs to be 1930 <= $birthday <= current year - 11 (11 or older); 
+		*gender must be Male or Female
+	*/
+	public $validates = array(
+		'username' => array(array('isUniqUser',   'message' => "Username is already taken."),
+							array('notEmpty',     'message' => 'Please enter a Username.'),
+							array('isClean',      'message' => 'Profanity is not allowed in Usernames'),
+							array('alphaNumeric',  'message' => "Usernames cant contain special characters")
+							),
+
+		'email' => array(array('email', 		  'message' => 'The email address is not valid.'),
+						 array('notEmpty', 		  'message' => 'An email address must be entered.'),
+						 array('isUniqueEmail',	  'message' => 'That email address is already in use. Did you forget your password?')
+						),
+
+						
+		//Passwords validation is invented.
+		'password' => array(array('lengthBetween' =>array('min' => '6', 'max' =>'20'),
+												  'message' => 'Your password must be between 6 and 20 characters')
+						   ) /*,
+						   
+		//It's always possible for people to submit invalid data using cURL or something.
+		'gender'  => array('isValidGender',     'message' => 'Please check for dangly bits or lack thereof.')
+		*/
+	);
+	
+
+	/* Defaults */
+	/*
+		joindate = today,
+		accesslevel = "user"
+	*/
+
+	public function updateuser($entity, $data)
+	{
+		$conditions = array('_id' => $entity->_id, 'state' => 'default');
+		$options = array('multiple' => false, 'safe' => true, 'upsert'=>true);
+		return static::update($data, $conditions, $options);
+	}
+
+	/** 
+	 * Creates a post and stores it into the appropriate user(s) array(s)
+	 * @param User $entity the instance of the user posting the message
+	 * @param Array $data The data from the request (usually submiited from the form)
+	 * @param Array $options Currently not implemented 
+	 * @return null Nothing for now, though should return true or false in the future :TODO:
+	 */ 
+	public function post($entity, $data, array $options = array())
+	{
+		//TODO, fix all methods so that they don't take $data directly
+		//TODO add validators to these methods/models
+		
+		//Create the post
+		$post = Post::create(array('datetime' => new MongoDate(),
+								   'username' => $entity->username,
+								   'user_id' => $entity->_id,
+								   'level' => null));
+		//1. Parse 
+		//Break the string into an array of words
+		$search = explode(" ", $data['body']);
+
+		//if the first word is DM
+		if ($search[0] == "DM")
+		{
+			//Remove the '@' symbol before we search for that username
+			$to = substr($search[1], 1);
+
+			$post->type = "DM";
+			//:TODO: Catch the return incase it's false.
+			return $post->directMessage($to);
+		}
+
+		//If the post beings with a mention (it's a reply / note)
+		if ($search[0] == "@")
+		{
+			//Set the post level to hidden
+			$post->level = "hidden";
+		}
+
+
+		//Check if there are any mentions or topics
+		$post->body = $post->parse($search);
+
+
+		//Because there is a chance that parse will set post level to something
+		//We pass the current value to level since it will just
+		//return the same it not set.
+		//Yes, we could use an if ! null but whatever. 
+		$post->level = $this->postLevel($entity, $post, $post->level);
+		
+		//Save the post to the posts database. 
+		$post->save();
+		
+		//If the user has friends 
+		if (count($entity->friends) > 0)
+		{
+			//Save this posts to the feed of all the Users Friends 
+			$post->storeAll($entity->friends);
+		}
+		//Add this post to the user's feed array
+		$post->store($entity);
+
+
+
+
+		//$save = $entity->save(null, array('validate' => false));
+		/* In the future, there should be a way to make this method quicker and non-blocking*/
+		//For each friend, post it in their feed (friends is an array of usernames as strings)
+		/*if (!empty($entity->friends))
+		{
+			foreach ($entity->friends as $friend)
+			{
+				//Grab the friend from the database
+				$curFriend = User::find('first', array('conditions' => array('username' => $friend)));
+				
+				//Add the post to their feed.
+				//Array unshift puts the new post at the first element of the feed array.
+				$curFriend->feed = array_unshift($post->_id, $curFriend->feed); 
+				
+				//Save the friend to the database, 
+				$curFriend->save(array('validates' => false));
+
+				//Eventually, we can call a node.js endpoint here 
+				//To tell all subscribers that there is a new a post
+				//Something like "curl POST $post->_id nodeserver://endpoint/myFeed"
+			}
+		} */
+	}
+
+	/**
+	 * Store's the post to the specified user's feed 
+	 * @param User $user The user to add the post to
+	 * @param Post $post The post too add to the feed 
+	 * @return boolean True if the operation sucsceeded, false otherwise
+	 */
+	private function storePost($user, $post)
+	{
+		$updateData = array('$push' => array('feed' =>  $post['_id']->__toString()));
+		$conditions =  array('_id' => $user['_id']);
+		$result = User::update($updateData, $conditions, array('atomic' => false));
+
+		return $result; 
+	}
+
+
+	/**
+	 * Returns the appropriate post level for the post 
+	 * @see app\models\Post
+	 * @param User $user The user instance of the user that the post will be posted to
+	 * @param Post $post The Post to determine the level for
+	 * @param string $level The level (if you want to override the output)
+	 * @return string $level if one is passed in, otherwise hidden if the post begins with a mention or private if the user has his posts protected
+	 */
+	public static function postLevel($user, $post, $level = null)
+	{
+		//if for some crazy reason you need to set the post to a specific type using this
+		// method then if $level is not null, return $level
+		if ($level != null)
+		{
+			return $level;
+		}
+		//If the post is directed at user (begins with @username)
+			//This is done in parse right now
+			//return "hidden"
+		
+		//If the user has their post set to private
+		if (isset($user->settings['private']));
+		{
+			//return private
+			return "private";
+		}
+		
+		//If none of the above apply
+		return "public";
+	}
+
+	//When we switch to a graph database, there is a bidirection vertex function
+	//So we can cut this search down to one query, and one line of code :P
+	/**
+	 * Check wether user1 and user2 are friends
+	 *
+	 * @param string $user1 The username of the first user
+	 * @param string $user2 The username of the second user
+	 * @return boolean True if the users are friends, false otherwise 
+	 */
+	public static function areFriends($user1, $user2)
+	{
+		//Get the first user from the database, 
+		$usr1 = User::find('first', array('conditions' => array('username' => $user1)));
+
+		//If user 2 is in user1's friends,
+		if (in_array($user2, $usr1->friends))
+		{
+			$usr2 = User::find('first', array('conditions' => array('username' => $user2)));
+			//And user1 is in user2s friends
+			if (in_array($user1, $usr2->friends))
+			{
+				return true;
+			}
+		}
+		//otherwise
+		return false;
+	}
+
+	/**
+	* GetPosts gets posts from the user (entity) based on some params, and returns them
+	* @param User $entity, the calling object
+	* @param Array $options, the options that will be used, you can see the defaults below 
+	* @return array(), with all the posts found or false, if somehow that didn't happen  
+	*/
+	public function getPosts($entity, array $options = array())
+	{
+		$posts; 
+		$defaults = array(
+				'limit' => '20',
+				'qualifier' => 'all',
+				'level' => 'public',
+			);
+
+		//If the user passed in options 
+		if (!empty($options))
+		{
+			//merge the options with the defaults (upsert them) 
+			array_merge($defaults, $options);
+		}	
+
+		//var_dump($entity);
+		//exit();
+		//If the user has more posts than the limit, return the limit, if the have less return 
+		$count = (count($entity->feed) >= $defaults['limit']) ? $defaults['limit'] : count($entity->feed); 
+		if ($count == 0)
+		{
+			return false;
+		}
+		//else
+		var_dump(Post::find('all', array('conditions' => array('$in' => $entity->feed))));
+		exit();
+		for ($i = 0; $i < $count; $i++)
+		{
+			$posts[] = Post::find('all', array('conditions' => array('$in' => $entity->feed)));
+			$posts[] = Post::find($qaulifier, array('conditions' => array('_id' => $entity->feed[$i], 'level' => $defaults[level])));
+		}
+		return $posts;
+	}
+
+    /**
+	 * Increments the amount profile views for the user.
+	 * This is the command we are going to give to Mongo, which breaks down to db.users.update({_id : $id}, {$inc: {profileViews : 1}} )
+	 * Which says, find the user by their mongo ID, then increment their profile views by one.
+	 * @param User $entity The instance of user to increment
+	 * @param string $type Not implemented but in the future will allow you to increment anime manga and kdrama list views :TODO:
+	 * @return null 
+	*/
+	public function incrementViews($entity, $type = null)
+	{
+		if ($type = null)
+		{
+			$views = 'profileViews';
+		}
+		$updateData = array('$inc' => array('profileViews' => 1));
+		$conditions =  array('_id' => $entity['_id']);
+		$result = User::update($updateData, $conditions, array('atomic' => false));
+		return $result;
+
+	}
+
+
+	//Overrides save so we can do some stuff before the data is commited to the database. 
+	public function save($entity, $data = null, array $options = array()) 
+	{
+		//If the new password field is empty, or this is a new user 
+		if(!empty($entity->newpass) || !$entity->exists())
+		{
+			//Generate Salt for the user.
+			$salt = String::genSalt('bf', 6);
+
+			//Hash their password.
+			$data['password'] = String::hashPassword($entity->newpass, $salt);
+			$data['salt'] = $salt;
+			unset($entity->newpass);
+		}
+		//If the entity doesn't exist or if the password password has been modified
+		return parent::save($entity, $data, $options);
+	}
+}
+
+?>	

+ 46 - 0
models/confirmKey.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace app\models;
+
+
+use lithium\util\String;
+use lithium\util\Validator;
+
+class confirmKey extends \lithium\data\Model {
+	//Comfirmation Key "salt"
+	public $secret = "marshmellows"; //I don't know why either?
+	
+	//To bypass mongo bug
+	protected $_meta = array('key' => '_id');
+	//array('isValidKey', 'message' => 'Key does not exist');
+
+	public static function __init()
+	{
+		//Make sure the class we extend inits.
+		parent::__init();                                                                                                      
+
+		//Checks if the key is valid (in the database);
+		Validator::add('isValidKey', function($key) {
+			return confirmKey::count(array('conditions' => compact('key'))) == 1;
+		});
+	}
+	
+	//For now, this will remain, but eventually it should just filter the save
+	//Method since the confirmation key doesn't really need to be returned to the controller. 
+	public function generate($email)
+	{
+		//Doesn't need to be ultra secure since they just need to click the generated link
+		return String::hash($email.$this->secret, array('type' => 'crc32'));
+	}
+
+	/*
+     * Old Validates function
+	public function isValidKey($key)
+	{
+		//If they key is valid, it should be found in the database
+		//If there is 1 key that matches the input key,
+		return confirmKey::count(array('conditions' => compact('key'))) == 1;
+	}	
+	*/	
+}
+?>

+ 17 - 0
models/contentList.php

@@ -0,0 +1,17 @@
+<?php 
+
+namespace app\models;
+
+class contentList extends \lithium\data\Model {
+		public function update()
+		{
+			
+		}
+
+		public function add($entity, $data)
+		{
+			$updateData = array('$push' => array(''
+			$conditions =  array('_id' => $user['_id']);
+			$result = User::update($updateData, $conditions, array('atomic' => false));
+		}
+}

+ 18 - 0
models/untitled.php

@@ -0,0 +1,18 @@
+<?php
+
+session_start();
+
+if ($_POST["password"] == "chaaya")
+{
+	if($_POST["username"] == "achaaya")
+	{
+		$_Session["name"] = "Andrew Chaaya";
+		$_Session["grades"] = ""
+	}
+	else
+	{
+		$_Session["name"] = "Joanne Chaaya";
+	}
+}
+
+?>

+ 0 - 0
resources/g11n/empty


+ 0 - 0
resources/tmp/logs/empty


+ 0 - 0
resources/tmp/tests/empty


+ 19 - 0
tests/cases/controllers/PhotosControllerTest.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace app\tests\cases\controllers;
+
+use app\controllers\PhotosController;
+
+class PhotosControllerTest extends \lithium\test\Unit {
+
+	public function setUp() {}
+
+	public function tearDown() {}
+
+	public function testIndex() {}
+	public function testView() {}
+	public function testAdd() {}
+	public function testEdit() {}
+}
+
+?>

+ 19 - 0
tests/cases/controllers/ProfilesControllerTest.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace app\tests\cases\controllers;
+
+use app\controllers\ProfilesController;
+
+class ProfilesControllerTest extends \lithium\test\Unit {
+
+	public function setUp() {}
+
+	public function tearDown() {}
+
+	public function testIndex() {}
+	public function testView() {}
+	public function testAdd() {}
+	public function testEdit() {}
+}
+
+?>

+ 0 - 0
tests/cases/controllers/empty


+ 0 - 0
tests/cases/extensions/adapter/empty


+ 0 - 0
tests/cases/extensions/command/empty


+ 1 - 0
tests/cases/extensions/data/source/empty

@@ -0,0 +1 @@
+

+ 0 - 0
tests/cases/extensions/helper/empty


+ 16 - 0
tests/cases/models/PhotoTest.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace app\tests\cases\models;
+
+use app\models\Photo;
+
+class PhotoTest extends \lithium\test\Unit {
+
+	public function setUp() {}
+
+	public function tearDown() {}
+
+
+}
+
+?>

+ 16 - 0
tests/cases/models/ProfileTest.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace app\tests\cases\models;
+
+use app\models\Profile;
+
+class ProfileTest extends \lithium\test\Unit {
+
+	public function setUp() {}
+
+	public function tearDown() {}
+
+
+}
+
+?>

+ 0 - 0
tests/cases/models/empty


+ 0 - 0
tests/functional/empty


+ 0 - 0
tests/integration/empty


+ 0 - 0
tests/mocks/empty


BIN
views/.DS_Store


+ 11 - 0
views/Admin/editUser.html.php

@@ -0,0 +1,11 @@
+<?php if(isset($user)): ?>
+<?=$this->form->create($user); ?>
+<?php else: ?>
+<?=$this->form->create(); ?>
+<?php endif; ?>
+	<?=$this->form->field('username'); ?>
+	<?=$this->form->field('newpass', array('label' => 'New Password')); ?>
+	<?=$this->form->field('email'); ?>
+	<?=$this->form->select('level', array('User' => 'User', 'Mod' => 'Mod', 'Admin' => 'Admin', 'root' => 'Root'), array('value' => 1)); ?> 
+	<?=$this->form->submit('Save!'); ?>
+<?=$this->form->end(); ?>

+ 99 - 0
views/Admin/index.html.php

@@ -0,0 +1,99 @@
+<?=$this->flashMessage->output(); ?>
+<div id="content" class="clearfix">
+    <div class="clear"></div>
+    <div class="tmp"></div>
+    <div id="alert" class="">
+</div>
+
+
+
+<div id="page-content-outer">
+    <div id="page-content" class="wrapper content admin">
+        <div class="info-bar">
+            <h1 class="title">Users</h1>
+              <ul class="sub-tabs">
+                <li class="object-action modal"><a href="/users/signup"><span>New User</span></a></li>
+              </ul>
+        </div>
+
+        <ul class="tab_menu wrapper">
+            <li class="selected">
+                <a href="index.php?a=clients/get/all"><span>Users</span></a>
+            </li>
+            <li class="">
+                <a href="index.php?a=projects/get/all"><span>Projects</span></a>
+            </li>
+            <li class="">
+                <a href="index.php?a=invoices/get/all"><span>Invoices</span></a>
+            </li>
+            <li class="">
+                <a href="index.php?a=payments/get/all"><span>Payments</span></a>
+            </li>
+            <li>
+              <a href=""><span>Settings</span></a>
+            </li>
+
+            <li class=" messages">
+                <a href="index.php?a=messages/get/all"><span>&nbsp;</span></a>
+            </li>
+
+
+        </ul>
+        <div class="inner">
+            <table class="list ">
+                <tr class="table-header">
+                    <th align = center class="">Active</th>
+                    <th class="">Username</th>      
+                    <th class="">Real Name</th>
+                    <th class="">Email</th>
+                    <th class="">Join Date</th>
+                    <th class="">Access Level</th>
+
+                
+                    <!-- For the buttons -->
+                    <th class="action"></th>
+                    <th class="action"></th>
+                </tr>
+
+<?php foreach($users as $user): ?>
+<tr>
+  <td class="">
+      <input type="checkbox" <?=$user->active ? "checked" : ""; ?> >
+  </td>
+  <td class ="">
+    <a class="cell-link" href=""><?=$user->username ?></a>
+  </td>
+  <td class ="">
+    <a class="cell-link" href="">Some Filler</a>
+  </td>
+   <td class ="">
+    <a class="cell-link" href=""><?=$user->email ?></a>
+  </td>
+  <td class ="">
+    <a class="cell-link" href=""><?=date('m/d/y', $user->joinedOn->sec) ?></a>
+  </td>
+   <td class ="">
+    <a class="cell-link" href=""><?= (isset($user->level)) ? $user->level : "Not Set"; ?> </a>
+  </td>
+ 
+
+  <!-- Buttons -->
+   <td class="action">
+    <a class="small-button  modal" href="/admin/editUser/<?=$user->username?>"><span>Edit</span></a>
+  </td>
+     <td class="action">
+        <a class="small-button danger" href="/admin/removeUser/<?=$user->username?>"><span>Delete</span></a>
+     </td>
+<tr>
+<?php endforeach; ?>
+            
+                
+         </table>
+
+        </div>
+        <div class="footer">
+            <?php /* Note that the paginator method is hacked it ish specifically for use in this theme */ ?>
+            <?=$this->Paginator->paginate(array('separator' => '')); ?>
+        </div>
+    </div>
+</div></div> <!-- end content-->

+ 103 - 0
views/Admin/users.html.php

@@ -0,0 +1,103 @@
+<?=$this->flashMessage->output(); ?>
+<div id="content" class="clearfix">
+
+    <div class="clear"></div>
+    <div class="tmp"></div>
+    <div id="alert" class="">
+        </div>
+
+
+
+<div id="page-content-outer">
+    <div id="page-content" class="wrapper content admin">
+        <div class="info-bar">
+            <h1 class="title">Users</h1>
+              <ul class="sub-tabs">
+                <li class="object-action modal"><a href="/users/signup"><span>New User</span></a></li>
+              </ul>
+        </div>
+
+        <ul class="tab_menu wrapper">
+            <li class="selected">
+                <a href="/admin/users"><span>Users</span></a>
+            </li>
+            <li class="">
+                <a href=""><span>Animes</span></a>
+            </li>
+            <li class="">
+                <a href="index.php?a=invoices/get/all"><span>Manga</span></a>
+            </li>
+            <li class="">
+                <a href="index.php?a=payments/get/all"><span>K-Drama</span></a>
+            </li>
+            <li>
+              <a href=""><span>Settings</span></a>
+            </li>
+
+            <li class=" messages">
+                <a href="index.php?a=messages/get/all"><span>&nbsp;</span></a>
+            </li>
+
+
+        </ul>
+        <div class="inner">
+            <table class="list ">
+                <tr class="table-header">
+                    <th class="">Active</th>
+                    <th class="">Username</th>      
+                    <th class="">Real Name</th>
+                    <th class="">Email</th>
+                    <th class="">Join Date</th>
+                    <th class="">Access Level</th>
+
+                
+                    <!-- For the buttons -->
+                    <th class="action"></th>
+                    <th class="action"></th>
+                </tr>
+
+<?php foreach($users as $user): ?>
+<tr>
+  <td class="">
+      <input type="checkbox" checked>
+  </td>
+  <td class ="">
+    <a class="cell-link" href=""><?=$user->username ?></a>
+  </td>
+  <td class ="">
+    <a class="cell-link" href="">Some Filler</a>
+  </td>
+   <td class ="">
+    <a class="cell-link" href=""><?=$user->email ?></a>
+  </td>
+  <td class ="">
+    <a class="cell-link" href=""><?=date('m/d/y', $user->joinedOn->sec) ?></a>
+  </td>
+   <td class ="">
+    <a class="cell-link" href=""><?= (isset($user->level)) ? $user->level : "Not Set"; ?> </a>
+  </td>
+ 
+
+  <!-- Buttons -->
+   <td class="action">
+    <a class="small-button  modal" href="/admin/editUser/<?=$user->username?>"><span>Edit</span></a>
+  </td>
+     <td class="action">
+        <a class="small-button danger" href="/admin/removeUser/<?=$user->username?>"><span>Delete</span></a>
+     </td>
+<tr>
+<?php endforeach; ?>
+            
+                
+         </table>
+
+        </div>
+        <div class="footer">
+        <?php if (count($users) > 10): ?>
+        <div class="pagination"><ul class="clearfix"><li class='disabled'><div  >&laquo; Prev</div></li><li class='current'><a href='index.php?a=clients/get/all/1'>1</a></li><li ><a href='index.php?a=clients/get/all/2'>2</a></li><li class=''><a href='index.php?a=clients/get/all/2' >Next &raquo;</a>
+        </li></ul></div>
+        <?php endif; ?>      
+        
+        </div>
+    </div>
+</div></div> <!-- end content-->

+ 33 - 0
views/Anime_list/add.html.php

@@ -0,0 +1,33 @@
+<?php if (empty($anime)): ?>
+<p> Anime not found </p>
+<?php else: ?>
+<h1><?= $anime->series_title ?></h1>
+<?php 
+	echo $this->form->create($entry);
+	echo $this->form->hidden('series_animedb_id', array('value' => $anime->special_id));
+					/*
+					<series_title><![CDATA[.hack//Sign]]></series_title>
+					<series_type>TV</series_type>
+					<series_episodes>26</series_episodes>
+					*/
+
+	echo $this->form->field('my_watched_episodes', array('label' => 'Watched Episodes'));
+	echo $this->form->field('my_start_date', array('label' => 'Start Date'));
+	echo $this->form->field('my_finish_date', array('label' => 'Finish Date'));
+	//Make this Ajax in the future, but it will have to be removed 
+	//If we partner with CR or otherwise
+	//echo $this->form->field('my_fansub_group', );
+	echo $this->form->field('my_score', array('label' => 'Score'));
+	//echo $this->form->field()	//			<my_dvd></my_dvd>
+					//<my_storage></my_storage>
+	echo $this->form->label('my_status', 'Status');
+	echo $this->form->select('my_status', array('Plan to Watch', 'On-Hold', 'Completed', 'Watching'), array('value' => 0));				//<my_status>Plan to Watch</my_status>
+	echo $this->form->field('my_comments', array('label' => 'Comments'));
+	echo $this->form->field('my_times_watched', array('label' => 'Times Watched'));
+    echo $this->form->label('rewatch_value', 'Rewatch Value');
+    echo $this->form->select('rewatch_value', array('High', 'Medium', 'Low', 'None'), array('value' => 0));
+	echo $this->form->field('tags', array('type' => 'textarea'));
+	echo $this->form->field('rewatching', array('value' => false));
+	echo $this->form->submit('Save!');
+?>
+<?php endif; ?>

+ 3 - 0
views/Anime_list/index.html

@@ -0,0 +1,3 @@
+<h1><?= $user->username ?>'s AnimeList</h1>
+
+<?= print_r($watching); ?>

+ 74 - 0
views/Anime_list/index.html.php

@@ -0,0 +1,74 @@
+<h1><?= $user->username ?>'s AnimeList</h1>
+<hr/>
+<table><tr><?= $this->html->link("Completed", "/animelist/view/$user->username/completed"); ?> </tr></table>
+
+<?php if (isset($watching)): ?>
+<h2 class="ribbon">Watching</h2><button value="Add" style="float:right">
+<tr><th>Entry #</th><th>Anime Title</th><th>Score</th><th>Type</th><th>Progress</th></tr>
+<?php $i = 1; ?>
+<?php foreach ($watching as $anime): ?>
+	<tr>
+	<td><?= $i ?></td>
+	<td><?= $anime->series_title ?></td>
+	<td><?= ($anime->my_score != 0) ? $anime->my_score : "-"; ?></td>
+	<td><?= $anime->series_type ?></td>
+	<td><?= $anime->my_watched_episodes ?>/<?= ($anime->series_episodes != 0) ? $anime->series_episodes : "-"; ?></td>
+	</tr>
+<?php $i += 1; ?>
+<?php endforeach; ?>
+</table>
+<?php endif; ?>
+
+<?php if (isset($planning)): ?>
+<h2 class="ribbon">Plans to Watch</h2>
+<table>
+<tr><th>Entry #</th><th>Anime Title</th><th>Score</th><th>Type</th><th>Progress</th></tr>
+<?php $i = 1; ?>
+<?php foreach ($planning as $anime): ?>
+	<tr>
+	<td><?= $i ?></td>
+	<td><?= $anime->series_title ?></td>
+	<td><?= ($anime->my_score != 0) ? $anime->my_score : "-"; ?></td>
+	<td><?= $anime->series_type ?></td>
+	<td><?= $anime->my_watched_episodes ?>/<?= ($anime->series_episodes != 0) ? $anime->series_episodes : "-"; ?></td>
+	</tr>
+<?php $i += 1; ?>
+<?php endforeach; ?>
+</table>
+<?php endif; ?>
+
+<?php if(isset($paused)): ?>
+<h2 class="ribbon">Paused</h2>
+<table>
+<tr><th>Entry #</th><th>Anime Title</th><th>Score</th><th>Type</th><th>Progress</th></tr>
+<?php $i = 1; ?>
+<?php foreach ($paused as $anime): ?>
+	<tr>
+	<td><?= $i ?></td>
+	<td><?= $anime->series_title ?></td>
+	<td><?= ($anime->my_score != 0) ? $anime->my_score : "-"; ?></td>
+	<td><?= $anime->series_type ?></td>
+	<td><?= $anime->my_watched_episodes ?>/<?= ($anime->series_episodes != 0) ? $anime->series_episodes : "-"; ?></td>
+	</tr>
+<?php $i += 1; ?>
+<?php endforeach; ?>
+</table>
+<?php endif; ?>
+
+<?php if (isset($dropped)): ?>
+<h2 class="ribbon">Dropped</h2>
+<table>
+<tr><th>Entry #</th><th>Anime Title</th><th>Score</th><th>Type</th><th>Progress</th></tr>
+<?php $i = 1; ?>
+<?php foreach ($dropped as $anime): ?>
+	<tr>
+	<td><?= $i ?></td>
+	<td><?= $anime->series_title ?></td>
+	<td><?= ($anime->my_score != 0) ? $anime->my_score : "-"; ?></td>
+	<td><?= $anime->series_type ?></td>
+	<td><?= $anime->my_watched_episodes ?>/<?= ($anime->series_episodes != 0) ? $anime->series_episodes : "-"; ?></td>
+	</tr>
+<?php $i += 1; ?>
+<?php endforeach; ?>
+</table>
+<?php endif; ?>

+ 84 - 0
views/Anime_list/view.html.php

@@ -0,0 +1,84 @@
+<h2 class="ribbon full"><a style="color: #FFFFFF" href="/profile/view/<?= $user->username ?>"><?= $user->username ?>'s</a> AnimeList</h2>
+<div class="triangle-ribbon"></div>
+<br class="cl" />
+<table class="table"><tr>
+<td><?= $this->html->link("Completed", "#finished", array('class' => 'anchorLink')); ?> </td>
+<td><?= $this->html->link("Watching", "#watching", array('class' => 'anchorLink')); ?> </td>
+<td><?= $this->html->link("Plans to Watch", "#planning", array('class' => 'anchorLink')); ?> </td>
+<td><?= $this->html->link("On-Hold", "#paused", array('class' => 'anchorLink')); ?> </td>
+<td><?= $this->html->link("Dropped", "#dropped", array('class' => 'anchorLink')); ?> </td>
+</tr>
+</table>
+<?php function tableHelper($input, &$t) {
+echo '<table class="table">';
+echo "<tr><th>Entry #</th><th>Anime Title</th><th>Score</th><th>Type</th><th>Progress</th></tr>";
+$i = 1;
+foreach ($input as $anime) {
+	echo '<tr>';
+	echo "<td> $i </td>";
+	echo "<td> <a href=\"/anime/view/$anime->series_animedb_id/\">$anime->series_title </a></td>";
+	echo "<td>";
+	echo ($anime->my_score != 0) ? $anime->my_score : "-"; 
+	echo "</td>";
+	echo "<td> $anime->series_type </td>";
+	echo "<td>";
+	echo $anime->my_watched_episodes;
+	echo  "/"; 
+	echo ($anime->series_episodes != 0) ? $anime->series_episodes : "-";
+	echo "</td>";
+	echo "</tr>";
+$i += 1;
+}
+echo "</table>";
+}
+?>
+
+<div class="two_col container_12">
+<div class="grid_10">
+<?php if (isset($watching)): ?>
+<a name="watching" id="watching"><h2 class="ribbon">Watching</h2></a>
+<div class="triangle-ribbon"></div>
+<br class="cl" />	
+</div>
+<div class="grid_2">
+<button class="large" style="margin-left:40px; margin-top:10px"><a href="/animelist/add?iframe=true&height=100%&width=100%">Add</a></button>
+</div>
+</div>
+
+
+<?php tableHelper($watching, $this); ?>
+<?php endif; ?>
+
+<?php if (isset($finished)): ?>
+	<a name="finished" id="finished"><h2 class="ribbon">Finished Animes</h2></a>
+	<div class="triangle-ribbon"></div>
+	<br class="cl" />
+	<?php tableHelper($finished, $this); ?>
+<?php endif; ?>
+
+
+<?php if (isset($planning)): ?>
+<a name="planning" id="planning"><h2 class="ribbon">Plans to Watch</h2></a>
+<div class="triangle-ribbon"></div>
+<br class="cl" />
+
+<?php tableHelper($planning, $this); ?>
+<?php endif; ?>
+
+<?php if(isset($paused)): ?>
+<a name="paused" id="paused"><h2 class="ribbon">Paused</h2></a>
+<div class="triangle-ribbon"></div>
+<br class="cl" />
+
+<?php tableHelper($paused, $this); ?>
+<?php endif; ?>
+
+<?php if (isset($dropped)): ?>
+
+
+<a name="dropped" id="dropped"><h2 class="ribbon">Dropped</h2></a>
+<div class="triangle-ribbon"></div>
+<br class="cl" />
+
+<?php tableHelper($dropped, $this); ?>
+<?php endif; ?>

+ 68 - 0
views/Content/anime.html.php

@@ -0,0 +1,68 @@
+<h2 class="ribbon full"><?= $content->title ?></h2>
+<div class="triangle-ribbon"></div>
+<br class="cl" />
+
+<div class="container_12">
+<!-- Start Sidebar -->
+<div class="grid_4" id="sidebar">
+<img src="<?=$content->image ?>" >
+
+<h2 class="ribbon"> Alternative Titles </h2>
+<hr/>
+<p>
+<?php if(isset($content->alternative_titles)) : ?>
+<?php foreach($content->alternative_titles as $title): ?>
+	<?= $title ?>
+<?php endforeach; ?>
+<?php endif; ?>
+</p>
+<h2> Information </h2>
+<span> Type: <?= $content->view_type ?> </span>
+Episodes: <?= $content->episode_count ?><br/>
+Status: <?= $content->status ?><br/>
+Aired: <?= $content->aired ?><br/>
+Producers: <?php foreach($content->producers as $producer): ?>
+<a href="/producer/view/<?= $producer ?>"><?= $producer ?></a>,
+<?php endforeach; ?><br/>
+Genres: <?php foreach($content->genres as $genres): ?>
+<a href="/genres/view/<?= $genres ?>"><?= $genres ?></a>,
+<?php endforeach ?><br/>
+Duration: <?= $content->episode_duration ?><br/>
+Rating: <?= $content->rating ?><br/>
+
+<h2 class="ribbon">Statistics</h2>
+Score: <br/>
+Ranked: <br/>
+Popularity: <br/>
+Members:<br/>
+Favorited by: over 9000 Users<br/>
+
+<h2 class="ribbon">  My Info </h2>
+<hr/>
+<!-- End Sidebar -->
+</div>
+<div class="grid_8" id="content">
+<!-- Start Content -->
+<h2>Synopsis</h2>
+<hr/>
+<?= $content->synopsis ?>
+
+<h2>Related Animes</h2>
+<hr/>
+
+<h2>Characters And VA's </h2>
+<hr/>
+<?php foreach($content->cast as $char): ?>
+<?= $char->character ?>
+<?= $char->role ?>
+Played by:
+	<?php if (isset($char->people)): ?>
+		<?php foreach($char->people as $actor): ?>
+		<?= $actor->name ?>
+		<?= $actor->language ?>
+		<?php endforeach; ?>
+	<?php endif; ?>
+<?php endforeach; ?>
+</div>
+<br class="cl"/>
+</div>

+ 7 - 0
views/Content/index.html.php

@@ -0,0 +1,7 @@
+<table>
+<th>img</th><th>Name</th><th>Episodes</th><th>Type</th><th>Score</th>
+<?php foreach($content as $item): ?>
+<tr><td>"image"</td> <td><a href="/anime/<?= $item->special_id ?>"><?= $item->title ?></a></td> <td><?= $item->episode_count ?></td><td><?= $item->view_type ?></td><td><?= $item->mal_score ?></td></tr>
+<?php endforeach; ?>
+</table>
+<?=$this->Paginator->paginate(); ?>

BIN
views/Feeds/.DS_Store


BIN
views/Feeds/Carbon_files/avatar_9318cab29a1a_96.png


BIN
views/Feeds/Carbon_files/bg_caption.png


BIN
views/Feeds/Carbon_files/bg_search.png


BIN
views/Feeds/Carbon_files/bg_search_focus.png


BIN
views/Feeds/Carbon_files/bg_sidebar.png


BIN
views/Feeds/Carbon_files/bg_texture.png


BIN
views/Feeds/Carbon_files/button_nav_left.png


BIN
views/Feeds/Carbon_files/button_nav_right.png


BIN
views/Feeds/Carbon_files/caption_bot.png


BIN
views/Feeds/Carbon_files/caption_top.png


+ 5 - 0
views/Feeds/Carbon_files/count-1.js

@@ -0,0 +1,5 @@
+var DISQUSWIDGETS;
+
+if (typeof DISQUSWIDGETS != 'undefined') {
+    DISQUSWIDGETS.displayCount({"showReactions": false, "text": {"and": "and", "reactions": {"zero": "0 Reactions", "multiple": "{num} Reactions", "one": "1 Reaction"}, "comments": {"zero": "0 Comments", "multiple": "{num} Comments", "one": "1 Comment"}}, "counts": [{"uid": 1, "comments": 3}, {"uid": 0, "comments": 7}, {"uid": 3, "comments": 0}, {"uid": 2, "comments": 3}, {"uid": 5, "comments": 2}, {"uid": 4, "comments": 0}, {"uid": 6, "comments": 0}]});
+}

BIN
views/Feeds/Carbon_files/count.js


BIN
views/Feeds/Carbon_files/divider.png


BIN
views/Feeds/Carbon_files/icon_comment.png


BIN
views/Feeds/Carbon_files/icon_fav.png


BIN
views/Feeds/Carbon_files/icon_link.png


BIN
views/Feeds/Carbon_files/icon_rss.png


BIN
views/Feeds/Carbon_files/icon_source.png


BIN
views/Feeds/Carbon_files/icon_tag.png


+ 166 - 0
views/Feeds/Carbon_files/jquery.min.js

@@ -0,0 +1,166 @@
+/*!
+ * jQuery JavaScript Library v1.4.3
+ * http://jquery.com/
+ *
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2010, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Thu Oct 14 23:10:06 2010 -0400
+ */
+(function(E,A){function U(){return false}function ba(){return true}function ja(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ga(a){var b,d,e=[],f=[],h,k,l,n,s,v,B,D;k=c.data(this,this.nodeType?"events":"__events__");if(typeof k==="function")k=k.events;if(!(a.liveFired===this||!k||!k.live||a.button&&a.type==="click")){if(a.namespace)D=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var H=k.live.slice(0);for(n=0;n<H.length;n++){k=H[n];k.origType.replace(X,
+"")===a.type?f.push(k.selector):H.splice(n--,1)}f=c(a.target).closest(f,a.currentTarget);s=0;for(v=f.length;s<v;s++){B=f[s];for(n=0;n<H.length;n++){k=H[n];if(B.selector===k.selector&&(!D||D.test(k.namespace))){l=B.elem;h=null;if(k.preType==="mouseenter"||k.preType==="mouseleave"){a.type=k.preType;h=c(a.relatedTarget).closest(k.selector)[0]}if(!h||h!==l)e.push({elem:l,handleObj:k,level:B.level})}}}s=0;for(v=e.length;s<v;s++){f=e[s];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;
+a.handleObj=f.handleObj;D=f.handleObj.origHandler.apply(f.elem,arguments);if(D===false||a.isPropagationStopped()){d=f.level;if(D===false)b=false}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(Ha,"`").replace(Ia,"&")}function ka(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Ja.test(b))return c.filter(b,
+e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function la(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var k in e[h])c.event.add(this,h,e[h][k],e[h][k].data)}}})}function Ka(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}
+function ma(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?La:Ma,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function ca(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Na.test(a)?e(a,h):ca(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?
+e(a,""):c.each(b,function(f,h){ca(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(na.concat.apply([],na.slice(0,b)),function(){d[this]=a});return d}function oa(a){if(!da[a]){var b=c("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";da[a]=d}return da[a]}function ea(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var u=E.document,c=function(){function a(){if(!b.isReady){try{u.documentElement.doScroll("left")}catch(i){setTimeout(a,
+1);return}b.ready()}}var b=function(i,r){return new b.fn.init(i,r)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,k=/\S/,l=/^\s+/,n=/\s+$/,s=/\W/,v=/\d/,B=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,D=/^[\],:{}\s]*$/,H=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,G=/(?:^|:|,)(?:\s*\[)+/g,M=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,j=/(msie) ([\w.]+)/,o=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,
+q=[],t,x=Object.prototype.toString,C=Object.prototype.hasOwnProperty,P=Array.prototype.push,N=Array.prototype.slice,R=String.prototype.trim,Q=Array.prototype.indexOf,L={};b.fn=b.prototype={init:function(i,r){var y,z,F;if(!i)return this;if(i.nodeType){this.context=this[0]=i;this.length=1;return this}if(i==="body"&&!r&&u.body){this.context=u;this[0]=u.body;this.selector="body";this.length=1;return this}if(typeof i==="string")if((y=h.exec(i))&&(y[1]||!r))if(y[1]){F=r?r.ownerDocument||r:u;if(z=B.exec(i))if(b.isPlainObject(r)){i=
+[u.createElement(z[1])];b.fn.attr.call(i,r,true)}else i=[F.createElement(z[1])];else{z=b.buildFragment([y[1]],[F]);i=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,i)}else{if((z=u.getElementById(y[2]))&&z.parentNode){if(z.id!==y[2])return f.find(i);this.length=1;this[0]=z}this.context=u;this.selector=i;return this}else if(!r&&!s.test(i)){this.selector=i;this.context=u;i=u.getElementsByTagName(i);return b.merge(this,i)}else return!r||r.jquery?(r||f).find(i):b(r).find(i);
+else if(b.isFunction(i))return f.ready(i);if(i.selector!==A){this.selector=i.selector;this.context=i.context}return b.makeArray(i,this)},selector:"",jquery:"1.4.3",length:0,size:function(){return this.length},toArray:function(){return N.call(this,0)},get:function(i){return i==null?this.toArray():i<0?this.slice(i)[0]:this[i]},pushStack:function(i,r,y){var z=b();b.isArray(i)?P.apply(z,i):b.merge(z,i);z.prevObject=this;z.context=this.context;if(r==="find")z.selector=this.selector+(this.selector?" ":
+"")+y;else if(r)z.selector=this.selector+"."+r+"("+y+")";return z},each:function(i,r){return b.each(this,i,r)},ready:function(i){b.bindReady();if(b.isReady)i.call(u,b);else q&&q.push(i);return this},eq:function(i){return i===-1?this.slice(i):this.slice(i,+i+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(i){return this.pushStack(b.map(this,function(r,y){return i.call(r,
+y,r)}))},end:function(){return this.prevObject||b(null)},push:P,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var i=arguments[0]||{},r=1,y=arguments.length,z=false,F,I,K,J,fa;if(typeof i==="boolean"){z=i;i=arguments[1]||{};r=2}if(typeof i!=="object"&&!b.isFunction(i))i={};if(y===r){i=this;--r}for(;r<y;r++)if((F=arguments[r])!=null)for(I in F){K=i[I];J=F[I];if(i!==J)if(z&&J&&(b.isPlainObject(J)||(fa=b.isArray(J)))){if(fa){fa=false;clone=K&&b.isArray(K)?K:[]}else clone=
+K&&b.isPlainObject(K)?K:{};i[I]=b.extend(z,clone,J)}else if(J!==A)i[I]=J}return i};b.extend({noConflict:function(i){E.$=e;if(i)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(i){i===true&&b.readyWait--;if(!b.readyWait||i!==true&&!b.isReady){if(!u.body)return setTimeout(b.ready,1);b.isReady=true;if(!(i!==true&&--b.readyWait>0)){if(q){for(var r=0;i=q[r++];)i.call(u,b);q=null}b.fn.triggerHandler&&b(u).triggerHandler("ready")}}},bindReady:function(){if(!p){p=true;if(u.readyState==="complete")return setTimeout(b.ready,
+1);if(u.addEventListener){u.addEventListener("DOMContentLoaded",t,false);E.addEventListener("load",b.ready,false)}else if(u.attachEvent){u.attachEvent("onreadystatechange",t);E.attachEvent("onload",b.ready);var i=false;try{i=E.frameElement==null}catch(r){}u.documentElement.doScroll&&i&&a()}}},isFunction:function(i){return b.type(i)==="function"},isArray:Array.isArray||function(i){return b.type(i)==="array"},isWindow:function(i){return i&&typeof i==="object"&&"setInterval"in i},isNaN:function(i){return i==
+null||!v.test(i)||isNaN(i)},type:function(i){return i==null?String(i):L[x.call(i)]||"object"},isPlainObject:function(i){if(!i||b.type(i)!=="object"||i.nodeType||b.isWindow(i))return false;if(i.constructor&&!C.call(i,"constructor")&&!C.call(i.constructor.prototype,"isPrototypeOf"))return false;for(var r in i);return r===A||C.call(i,r)},isEmptyObject:function(i){for(var r in i)return false;return true},error:function(i){throw i;},parseJSON:function(i){if(typeof i!=="string"||!i)return null;i=b.trim(i);
+if(D.test(i.replace(H,"@").replace(w,"]").replace(G,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(i):(new Function("return "+i))();else b.error("Invalid JSON: "+i)},noop:function(){},globalEval:function(i){if(i&&k.test(i)){var r=u.getElementsByTagName("head")[0]||u.documentElement,y=u.createElement("script");y.type="text/javascript";if(b.support.scriptEval)y.appendChild(u.createTextNode(i));else y.text=i;r.insertBefore(y,r.firstChild);r.removeChild(y)}},nodeName:function(i,r){return i.nodeName&&i.nodeName.toUpperCase()===
+r.toUpperCase()},each:function(i,r,y){var z,F=0,I=i.length,K=I===A||b.isFunction(i);if(y)if(K)for(z in i){if(r.apply(i[z],y)===false)break}else for(;F<I;){if(r.apply(i[F++],y)===false)break}else if(K)for(z in i){if(r.call(i[z],z,i[z])===false)break}else for(y=i[0];F<I&&r.call(y,F,y)!==false;y=i[++F]);return i},trim:R?function(i){return i==null?"":R.call(i)}:function(i){return i==null?"":i.toString().replace(l,"").replace(n,"")},makeArray:function(i,r){var y=r||[];if(i!=null){var z=b.type(i);i.length==
+null||z==="string"||z==="function"||z==="regexp"||b.isWindow(i)?P.call(y,i):b.merge(y,i)}return y},inArray:function(i,r){if(r.indexOf)return r.indexOf(i);for(var y=0,z=r.length;y<z;y++)if(r[y]===i)return y;return-1},merge:function(i,r){var y=i.length,z=0;if(typeof r.length==="number")for(var F=r.length;z<F;z++)i[y++]=r[z];else for(;r[z]!==A;)i[y++]=r[z++];i.length=y;return i},grep:function(i,r,y){var z=[],F;y=!!y;for(var I=0,K=i.length;I<K;I++){F=!!r(i[I],I);y!==F&&z.push(i[I])}return z},map:function(i,
+r,y){for(var z=[],F,I=0,K=i.length;I<K;I++){F=r(i[I],I,y);if(F!=null)z[z.length]=F}return z.concat.apply([],z)},guid:1,proxy:function(i,r,y){if(arguments.length===2)if(typeof r==="string"){y=i;i=y[r];r=A}else if(r&&!b.isFunction(r)){y=r;r=A}if(!r&&i)r=function(){return i.apply(y||this,arguments)};if(i)r.guid=i.guid=i.guid||r.guid||b.guid++;return r},access:function(i,r,y,z,F,I){var K=i.length;if(typeof r==="object"){for(var J in r)b.access(i,J,r[J],z,F,y);return i}if(y!==A){z=!I&&z&&b.isFunction(y);
+for(J=0;J<K;J++)F(i[J],r,z?y.call(i[J],J,F(i[J],r)):y,I);return i}return K?F(i[0],r):A},now:function(){return(new Date).getTime()},uaMatch:function(i){i=i.toLowerCase();i=M.exec(i)||g.exec(i)||j.exec(i)||i.indexOf("compatible")<0&&o.exec(i)||[];return{browser:i[1]||"",version:i[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(i,r){L["[object "+r+"]"]=r.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=
+m.version}if(b.browser.webkit)b.browser.safari=true;if(Q)b.inArray=function(i,r){return Q.call(r,i)};if(!/\s/.test("\u00a0")){l=/^[\s\xA0]+/;n=/[\s\xA0]+$/}f=b(u);if(u.addEventListener)t=function(){u.removeEventListener("DOMContentLoaded",t,false);b.ready()};else if(u.attachEvent)t=function(){if(u.readyState==="complete"){u.detachEvent("onreadystatechange",t);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=u.documentElement,b=u.createElement("script"),d=u.createElement("div"),
+e="script"+c.now();d.style.display="none";d.innerHTML="   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],k=u.createElement("select"),l=k.appendChild(u.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),
+hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:l.selected,optDisabled:false,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};k.disabled=true;c.support.optDisabled=!l.disabled;b.type="text/javascript";try{b.appendChild(u.createTextNode("window."+e+"=1;"))}catch(n){}a.insertBefore(b,
+a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function s(){c.support.noCloneEvent=false;d.detachEvent("onclick",s)});d.cloneNode(true).fireEvent("onclick")}d=u.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=u.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var s=u.createElement("div");
+s.style.width=s.style.paddingLeft="1px";u.body.appendChild(s);c.boxModel=c.support.boxModel=s.offsetWidth===2;if("zoom"in s.style){s.style.display="inline";s.style.zoom=1;c.support.inlineBlockNeedsLayout=s.offsetWidth===2;s.style.display="";s.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=s.offsetWidth!==2}s.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var v=s.getElementsByTagName("td");c.support.reliableHiddenOffsets=v[0].offsetHeight===
+0;v[0].style.display="";v[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&v[0].offsetHeight===0;s.innerHTML="";u.body.removeChild(s).style.display="none"});a=function(s){var v=u.createElement("div");s="on"+s;var B=s in v;if(!B){v.setAttribute(s,"return;");B=typeof v[s]==="function"}return B};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",
+cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var pa={},Oa=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?pa:a;var e=a.nodeType,f=e?a[c.expando]:null,h=c.cache;if(!(e&&!f&&typeof b==="string"&&d===A)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=
+c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==A)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?pa:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);else if(d)delete f[e];else for(var k in a)delete a[k]}},acceptData:function(a){if(a.nodeName){var b=
+c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){if(typeof a==="undefined")return this.length?c.data(this[0]):null;else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===A){var e=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(e===A&&this.length){e=c.data(this[0],a);if(e===A&&this[0].nodeType===1){e=this[0].getAttribute("data-"+a);if(typeof e===
+"string")try{e=e==="true"?true:e==="false"?false:e==="null"?null:!c.isNaN(e)?parseFloat(e):Oa.test(e)?c.parseJSON(e):e}catch(f){}else e=A}}return e===A&&d[1]?this.data(d[0]):e}else return this.each(function(){var h=c(this),k=[d[0],b];h.triggerHandler("setData"+d[1]+"!",k);c.data(this,a,b);h.triggerHandler("changeData"+d[1]+"!",k)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e=c.data(a,b);if(!d)return e||
+[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===A)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,
+a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var qa=/[\n\t]/g,ga=/\s+/,Pa=/\r/g,Qa=/^(?:href|src|style)$/,Ra=/^(?:button|input)$/i,Sa=/^(?:button|input|object|select|textarea)$/i,Ta=/^a(?:rea)?$/i,ra=/^(?:radio|checkbox)$/i;c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,
+a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(s){var v=c(this);v.addClass(a.call(this,s,v.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ga),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1)if(f.className){for(var h=" "+f.className+" ",k=f.className,l=0,n=b.length;l<n;l++)if(h.indexOf(" "+b[l]+" ")<0)k+=" "+b[l];f.className=c.trim(k)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(n){var s=
+c(this);s.removeClass(a.call(this,n,s.attr("class")))});if(a&&typeof a==="string"||a===A)for(var b=(a||"").split(ga),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(qa," "),k=0,l=b.length;k<l;k++)h=h.replace(" "+b[k]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,
+f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,k=c(this),l=b,n=a.split(ga);f=n[h++];){l=e?l:!k.hasClass(f);k[l?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(qa," ").indexOf(a)>-1)return true;return false},
+val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var k=f[h];if(k.selected&&(c.support.optDisabled?!k.disabled:k.getAttribute("disabled")===null)&&(!k.parentNode.disabled||!c.nodeName(k.parentNode,"optgroup"))){a=c(k).val();if(b)return a;d.push(a)}}return d}if(ra.test(b.type)&&
+!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Pa,"")}return A}var l=c.isFunction(a);return this.each(function(n){var s=c(this),v=a;if(this.nodeType===1){if(l)v=a.call(this,n,s.val());if(v==null)v="";else if(typeof v==="number")v+="";else if(c.isArray(v))v=c.map(v,function(D){return D==null?"":D+""});if(c.isArray(v)&&ra.test(this.type))this.checked=c.inArray(s.val(),v)>=0;else if(c.nodeName(this,"select")){var B=c.makeArray(v);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),B)>=0});if(!B.length)this.selectedIndex=-1}else this.value=v}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return A;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==A;b=e&&c.props[b]||b;if(a.nodeType===1){var h=Qa.test(b);if((b in a||a[b]!==A)&&e&&!h){if(f){b==="type"&&Ra.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Sa.test(a.nodeName)||Ta.test(a.nodeName)&&a.href?0:A;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return A;a=!c.support.hrefNormalized&&e&&
+h?a.getAttribute(b,2):a.getAttribute(b);return a===null?A:a}}});var X=/\.(.*)$/,ha=/^(?:textarea|input|select)$/i,Ha=/\./g,Ia=/ /g,Ua=/[^\w\s.|`]/g,Va=function(a){return a.replace(Ua,"\\$&")},sa={focusin:0,focusout:0};c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var k=a.nodeType?"events":"__events__",l=h[k],n=h.handle;if(typeof l===
+"function"){n=l.handle;l=l.events}else if(!l){a.nodeType||(h[k]=h=function(){});h.events=l={}}if(!n)h.handle=n=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(n.elem,arguments):A};n.elem=a;b=b.split(" ");for(var s=0,v;k=b[s++];){h=f?c.extend({},f):{handler:d,data:e};if(k.indexOf(".")>-1){v=k.split(".");k=v.shift();h.namespace=v.slice(0).sort().join(".")}else{v=[];h.namespace=""}h.type=k;if(!h.guid)h.guid=d.guid;var B=l[k],D=c.event.special[k]||{};if(!B){B=l[k]=[];
+if(!D.setup||D.setup.call(a,e,v,n)===false)if(a.addEventListener)a.addEventListener(k,n,false);else a.attachEvent&&a.attachEvent("on"+k,n)}if(D.add){D.add.call(a,h);if(!h.handler.guid)h.handler.guid=d.guid}B.push(h);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,k=0,l,n,s,v,B,D,H=a.nodeType?"events":"__events__",w=c.data(a),G=w&&w[H];if(w&&G){if(typeof G==="function"){w=G;G=G.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||
+typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in G)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[k++];){v=f;l=f.indexOf(".")<0;n=[];if(!l){n=f.split(".");f=n.shift();s=RegExp("(^|\\.)"+c.map(n.slice(0).sort(),Va).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(B=G[f])if(d){v=c.event.special[f]||{};for(h=e||0;h<B.length;h++){D=B[h];if(d.guid===D.guid){if(l||s.test(D.namespace)){e==null&&B.splice(h--,1);v.remove&&v.remove.call(a,D)}if(e!=null)break}}if(B.length===0||e!=null&&B.length===1){if(!v.teardown||
+v.teardown.call(a,n)===false)c.removeEvent(a,f,w.handle);delete G[f]}}else for(h=0;h<B.length;h++){D=B[h];if(l||s.test(D.namespace)){c.event.remove(a,v,D.handler,h);B.splice(h--,1)}}}if(c.isEmptyObject(G)){if(b=w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,H);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=
+f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return A;a.result=A;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===
+false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){e=a.target;var k,l=f.replace(X,""),n=c.nodeName(e,"a")&&l==="click",s=c.event.special[l]||{};if((!s._default||s._default.call(d,a)===false)&&!n&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[l]){if(k=e["on"+l])e["on"+l]=null;c.event.triggered=true;e[l]()}}catch(v){}if(k)e["on"+l]=k;c.event.triggered=false}}},handle:function(a){var b,d,e;
+d=[];var f,h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var k=d.length;f<k;f++){var l=d[f];if(b||e.test(l.namespace)){a.handler=l.handler;a.data=
+l.data;a.handleObj=l;l=l.handler.apply(this,h);if(l!==A){a.result=l;if(l===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||u;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=u.documentElement;d=u.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
+d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==A)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ga,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
+Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=u.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=
+c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ba;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ba;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ba;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
+var ta=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},ua=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?ua:ta,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?ua:ta)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==
+"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=A;return ja("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=A;return ja("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
+va=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ha.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=va(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===A||f===e))if(e!=null||f){a.type="change";a.liveFired=
+A;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",va(a))}},setup:function(){if(this.type===
+"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ha.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ha.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}u.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){sa[b]++===0&&u.addEventListener(a,d,true)},teardown:function(){--sa[b]===
+0&&u.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=A}var k=b==="one"?c.proxy(f,function(n){c(this).unbind(n,k);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var l=this.length;h<l;h++)c.event.add(this[h],d,k,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,
+a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=
+1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var wa={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var k,l=0,n,s,v=h||this.selector;h=h?this:c(this.context);if(typeof d===
+"object"&&!d.preventDefault){for(k in d)h[b](k,e,d[k],v);return this}if(c.isFunction(e)){f=e;e=A}for(d=(d||"").split(" ");(k=d[l++])!=null;){n=X.exec(k);s="";if(n){s=n[0];k=k.replace(X,"")}if(k==="hover")d.push("mouseenter"+s,"mouseleave"+s);else{n=k;if(k==="focus"||k==="blur"){d.push(wa[k]+s);k+=s}else k=(wa[k]||k)+s;if(b==="live"){s=0;for(var B=h.length;s<B;s++)c.event.add(h[s],"live."+Y(k,v),{data:e,selector:v,handler:f,origType:k,origHandler:f,preType:n})}else h.unbind("live."+Y(k,v),f)}}return this}});
+c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
+(function(){function a(g,j,o,m,p,q){p=0;for(var t=m.length;p<t;p++){var x=m[p];if(x){x=x[g];for(var C=false;x;){if(x.sizcache===o){C=m[x.sizset];break}if(x.nodeType===1&&!q){x.sizcache=o;x.sizset=p}if(x.nodeName.toLowerCase()===j){C=x;break}x=x[g]}m[p]=C}}}function b(g,j,o,m,p,q){p=0;for(var t=m.length;p<t;p++){var x=m[p];if(x){x=x[g];for(var C=false;x;){if(x.sizcache===o){C=m[x.sizset];break}if(x.nodeType===1){if(!q){x.sizcache=o;x.sizset=p}if(typeof j!=="string"){if(x===j){C=true;break}}else if(l.filter(j,
+[x]).length>0){C=x;break}}x=x[g]}m[p]=C}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,k=true;[0,0].sort(function(){k=false;return 0});var l=function(g,j,o,m){o=o||[];var p=j=j||u;if(j.nodeType!==1&&j.nodeType!==9)return[];if(!g||typeof g!=="string")return o;var q=[],t,x,C,P,N=true,R=l.isXML(j),Q=g,L;do{d.exec("");if(t=d.exec(Q)){Q=t[3];q.push(t[1]);if(t[2]){P=t[3];
+break}}}while(t);if(q.length>1&&s.exec(g))if(q.length===2&&n.relative[q[0]])x=M(q[0]+q[1],j);else for(x=n.relative[q[0]]?[j]:l(q.shift(),j);q.length;){g=q.shift();if(n.relative[g])g+=q.shift();x=M(g,x)}else{if(!m&&q.length>1&&j.nodeType===9&&!R&&n.match.ID.test(q[0])&&!n.match.ID.test(q[q.length-1])){t=l.find(q.shift(),j,R);j=t.expr?l.filter(t.expr,t.set)[0]:t.set[0]}if(j){t=m?{expr:q.pop(),set:D(m)}:l.find(q.pop(),q.length===1&&(q[0]==="~"||q[0]==="+")&&j.parentNode?j.parentNode:j,R);x=t.expr?l.filter(t.expr,
+t.set):t.set;if(q.length>0)C=D(x);else N=false;for(;q.length;){t=L=q.pop();if(n.relative[L])t=q.pop();else L="";if(t==null)t=j;n.relative[L](C,t,R)}}else C=[]}C||(C=x);C||l.error(L||g);if(f.call(C)==="[object Array]")if(N)if(j&&j.nodeType===1)for(g=0;C[g]!=null;g++){if(C[g]&&(C[g]===true||C[g].nodeType===1&&l.contains(j,C[g])))o.push(x[g])}else for(g=0;C[g]!=null;g++)C[g]&&C[g].nodeType===1&&o.push(x[g]);else o.push.apply(o,C);else D(C,o);if(P){l(P,p,o,m);l.uniqueSort(o)}return o};l.uniqueSort=function(g){if(w){h=
+k;g.sort(w);if(h)for(var j=1;j<g.length;j++)g[j]===g[j-1]&&g.splice(j--,1)}return g};l.matches=function(g,j){return l(g,null,null,j)};l.matchesSelector=function(g,j){return l(j,null,null,[g]).length>0};l.find=function(g,j,o){var m;if(!g)return[];for(var p=0,q=n.order.length;p<q;p++){var t=n.order[p],x;if(x=n.leftMatch[t].exec(g)){var C=x[1];x.splice(1,1);if(C.substr(C.length-1)!=="\\"){x[1]=(x[1]||"").replace(/\\/g,"");m=n.find[t](x,j,o);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=j.getElementsByTagName("*"));
+return{set:m,expr:g}};l.filter=function(g,j,o,m){for(var p=g,q=[],t=j,x,C,P=j&&j[0]&&l.isXML(j[0]);g&&j.length;){for(var N in n.filter)if((x=n.leftMatch[N].exec(g))!=null&&x[2]){var R=n.filter[N],Q,L;L=x[1];C=false;x.splice(1,1);if(L.substr(L.length-1)!=="\\"){if(t===q)q=[];if(n.preFilter[N])if(x=n.preFilter[N](x,t,o,q,m,P)){if(x===true)continue}else C=Q=true;if(x)for(var i=0;(L=t[i])!=null;i++)if(L){Q=R(L,x,i,t);var r=m^!!Q;if(o&&Q!=null)if(r)C=true;else t[i]=false;else if(r){q.push(L);C=true}}if(Q!==
+A){o||(t=q);g=g.replace(n.match[N],"");if(!C)return[];break}}}if(g===p)if(C==null)l.error(g);else break;p=g}return t};l.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=l.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
+POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,j){var o=typeof j==="string",m=o&&!/\W/.test(j);o=o&&!m;if(m)j=j.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=o||q&&q.nodeName.toLowerCase()===
+j?q||false:q===j}o&&l.filter(j,g,true)},">":function(g,j){var o=typeof j==="string",m,p=0,q=g.length;if(o&&!/\W/.test(j))for(j=j.toLowerCase();p<q;p++){if(m=g[p]){o=m.parentNode;g[p]=o.nodeName.toLowerCase()===j?o:false}}else{for(;p<q;p++)if(m=g[p])g[p]=o?m.parentNode:m.parentNode===j;o&&l.filter(j,g,true)}},"":function(g,j,o){var m=e++,p=b,q;if(typeof j==="string"&&!/\W/.test(j)){q=j=j.toLowerCase();p=a}p("parentNode",j,m,g,q,o)},"~":function(g,j,o){var m=e++,p=b,q;if(typeof j==="string"&&!/\W/.test(j)){q=
+j=j.toLowerCase();p=a}p("previousSibling",j,m,g,q,o)}},find:{ID:function(g,j,o){if(typeof j.getElementById!=="undefined"&&!o)return(g=j.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,j){if(typeof j.getElementsByName!=="undefined"){for(var o=[],m=j.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&o.push(m[p]);return o.length===0?null:o}},TAG:function(g,j){return j.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,j,o,m,p,q){g=" "+g[1].replace(/\\/g,
+"")+" ";if(q)return g;q=0;for(var t;(t=j[q])!=null;q++)if(t)if(p^(t.className&&(" "+t.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))o||m.push(t);else if(o)j[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var j=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=j[1]+(j[2]||1)-0;g[3]=j[3]-0}g[0]=e++;return g},ATTR:function(g,j,o,
+m,p,q){j=g[1].replace(/\\/g,"");if(!q&&n.attrMap[j])g[1]=n.attrMap[j];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,j,o,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=l(g[3],null,null,j);else{g=l.filter(g[3],j,o,true^p);o||m.push.apply(m,g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
+true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,j,o){return!!l(o[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
+g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,j){return j===0},last:function(g,j,o,m){return j===m.length-1},even:function(g,j){return j%2===0},odd:function(g,j){return j%2===1},lt:function(g,j,o){return j<o[3]-0},gt:function(g,j,o){return j>o[3]-0},nth:function(g,j,o){return o[3]-
+0===j},eq:function(g,j,o){return o[3]-0===j}},filter:{PSEUDO:function(g,j,o,m){var p=j[1],q=n.filters[p];if(q)return q(g,o,j,m);else if(p==="contains")return(g.textContent||g.innerText||l.getText([g])||"").indexOf(j[3])>=0;else if(p==="not"){j=j[3];o=0;for(m=j.length;o<m;o++)if(j[o]===g)return false;return true}else l.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,j){var o=j[1],m=g;switch(o){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(o===
+"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":o=j[2];var p=j[3];if(o===1&&p===0)return true;var q=j[0],t=g.parentNode;if(t&&(t.sizcache!==q||!g.nodeIndex)){var x=0;for(m=t.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++x;t.sizcache=q}m=g.nodeIndex-p;return o===0?m===0:m%o===0&&m/o>=0}},ID:function(g,j){return g.nodeType===1&&g.getAttribute("id")===j},TAG:function(g,j){return j==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
+j},CLASS:function(g,j){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(j)>-1},ATTR:function(g,j){var o=j[1];o=n.attrHandle[o]?n.attrHandle[o](g):g[o]!=null?g[o]:g.getAttribute(o);var m=o+"",p=j[2],q=j[4];return o==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&o!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,j,o,m){var p=n.setFilters[j[2]];
+if(p)return p(g,o,j,m)}}},s=n.match.POS,v=function(g,j){return"\\"+(j-0+1)},B;for(B in n.match){n.match[B]=RegExp(n.match[B].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[B]=RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[B].source.replace(/\\(\d+)/g,v))}var D=function(g,j){g=Array.prototype.slice.call(g,0);if(j){j.push.apply(j,g);return j}return g};try{Array.prototype.slice.call(u.documentElement.childNodes,0)}catch(H){D=function(g,j){var o=j||[],m=0;if(f.call(g)==="[object Array]")Array.prototype.push.apply(o,
+g);else if(typeof g.length==="number")for(var p=g.length;m<p;m++)o.push(g[m]);else for(;g[m];m++)o.push(g[m]);return o}}var w,G;if(u.documentElement.compareDocumentPosition)w=function(g,j){if(g===j){h=true;return 0}if(!g.compareDocumentPosition||!j.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(j)&4?-1:1};else{w=function(g,j){var o=[],m=[],p=g.parentNode,q=j.parentNode,t=p;if(g===j){h=true;return 0}else if(p===q)return G(g,j);else if(p){if(!q)return 1}else return-1;
+for(;t;){o.unshift(t);t=t.parentNode}for(t=q;t;){m.unshift(t);t=t.parentNode}p=o.length;q=m.length;for(t=0;t<p&&t<q;t++)if(o[t]!==m[t])return G(o[t],m[t]);return t===p?G(g,m[t],-1):G(o[t],j,1)};G=function(g,j,o){if(g===j)return o;for(g=g.nextSibling;g;){if(g===j)return-1;g=g.nextSibling}return 1}}l.getText=function(g){for(var j="",o,m=0;g[m];m++){o=g[m];if(o.nodeType===3||o.nodeType===4)j+=o.nodeValue;else if(o.nodeType!==8)j+=l.getText(o.childNodes)}return j};(function(){var g=u.createElement("div"),
+j="script"+(new Date).getTime();g.innerHTML="<a name='"+j+"'/>";var o=u.documentElement;o.insertBefore(g,o.firstChild);if(u.getElementById(j)){n.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:A:[]};n.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}o.removeChild(g);
+o=g=null})();(function(){var g=u.createElement("div");g.appendChild(u.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(j,o){var m=o.getElementsByTagName(j[1]);if(j[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(j){return j.getAttribute("href",2)};g=null})();u.querySelectorAll&&
+function(){var g=l,j=u.createElement("div");j.innerHTML="<p class='TEST'></p>";if(!(j.querySelectorAll&&j.querySelectorAll(".TEST").length===0)){l=function(m,p,q,t){p=p||u;if(!t&&!l.isXML(p))if(p.nodeType===9)try{return D(p.querySelectorAll(m),q)}catch(x){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var C=p.id,P=p.id="__sizzle__";try{return D(p.querySelectorAll("#"+P+" "+m),q)}catch(N){}finally{if(C)p.id=C;else p.removeAttribute("id")}}return g(m,p,q,t)};for(var o in g)l[o]=g[o];
+j=null}}();(function(){var g=u.documentElement,j=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,o=false;try{j.call(u.documentElement,":sizzle")}catch(m){o=true}if(j)l.matchesSelector=function(p,q){try{if(o||!n.match.PSEUDO.test(q))return j.call(p,q)}catch(t){}return l(q,null,null,[p]).length>0}})();(function(){var g=u.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===
+0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(j,o,m){if(typeof o.getElementsByClassName!=="undefined"&&!m)return o.getElementsByClassName(j[1])};g=null}}})();l.contains=u.documentElement.contains?function(g,j){return g!==j&&(g.contains?g.contains(j):true)}:function(g,j){return!!(g.compareDocumentPosition(j)&16)};l.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var M=function(g,
+j){for(var o=[],m="",p,q=j.nodeType?[j]:j;p=n.match.PSEUDO.exec(g);){m+=p[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;p=0;for(var t=q.length;p<t;p++)l(g,q[p],o);return l.filter(m,o)};c.find=l;c.expr=l.selectors;c.expr[":"]=c.expr.filters;c.unique=l.uniqueSort;c.text=l.getText;c.isXMLDoc=l.isXML;c.contains=l.contains})();var Wa=/Until$/,Xa=/^(?:parents|prevUntil|prevAll)/,Ya=/,/,Ja=/^.[^:#\[\.,]*$/,Za=Array.prototype.slice,$a=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("",
+"find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var k=0;k<d;k++)if(b[k]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(ka(this,a,false),"not",a)},filter:function(a){return this.pushStack(ka(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,
+b){var d=[],e,f,h=this[0];if(c.isArray(a)){var k={},l,n=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:n})}h=h.parentNode;n++}}return d}k=$a.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(k?k.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||
+!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});
+c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",
+d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Wa.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||Ya.test(e))&&Xa.test(a))f=f.reverse();return this.pushStack(f,a,Za.call(arguments).join(","))}});
+c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===A||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var xa=/ jQuery\d+="(?:\d+|null)"/g,
+$=/^\s+/,ya=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,za=/<([\w:]+)/,ab=/<tbody/i,bb=/<|&#?\w+;/,Aa=/<(?:script|object|embed|option|style)/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,cb=/\=([^="'>\s]+\/)>/g,O={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],
+area:[1,"<map>","</map>"],_default:[0,"",""]};O.optgroup=O.option;O.tbody=O.tfoot=O.colgroup=O.caption=O.thead;O.th=O.td;if(!c.support.htmlSerialize)O._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==A)return this.empty().append((this[0]&&this[0].ownerDocument||u).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,
+d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},
+unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=
+c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));
+c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(xa,"").replace(cb,'="$1">').replace($,
+"")],e)[0]}else return this.cloneNode(true)});if(a===true){la(this,b);la(this.find("*"),b.find("*"))}return b},html:function(a){if(a===A)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(xa,""):null;else if(typeof a==="string"&&!Aa.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!O[(za.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ya,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?
+this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,
+true)},domManip:function(a,b,d){var e,f,h=a[0],k=[],l;if(!c.support.checkClone&&arguments.length===3&&typeof h==="string"&&Ba.test(h))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(h))return this.each(function(s){var v=c(this);a[0]=h.call(this,s,b?v.html():A);v.domManip(a,b,d)});if(this[0]){e=h&&h.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);l=e.fragment;if(f=l.childNodes.length===1?l=l.firstChild:
+l.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var n=this.length;f<n;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):this[f]:this[f],f>0||e.cacheable||this.length>1?l.cloneNode(true):l)}k.length&&c.each(k,Ka)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:u;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===u&&!Aa.test(a[0])&&(c.support.checkClone||
+!Ba.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=
+d.length;f<h;f++){var k=(f>0?this.clone(true):this).get();c(d[f])[b](k);e=e.concat(k)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||u;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||u;for(var f=[],h=0,k;(k=a[h])!=null;h++){if(typeof k==="number")k+="";if(k){if(typeof k==="string"&&!bb.test(k))k=b.createTextNode(k);else if(typeof k==="string"){k=k.replace(ya,"<$1></$2>");var l=(za.exec(k)||["",""])[1].toLowerCase(),n=O[l]||O._default,
+s=n[0],v=b.createElement("div");for(v.innerHTML=n[1]+k+n[2];s--;)v=v.lastChild;if(!c.support.tbody){s=ab.test(k);l=l==="table"&&!s?v.firstChild&&v.firstChild.childNodes:n[1]==="<table>"&&!s?v.childNodes:[];for(n=l.length-1;n>=0;--n)c.nodeName(l[n],"tbody")&&!l[n].childNodes.length&&l[n].parentNode.removeChild(l[n])}!c.support.leadingWhitespace&&$.test(k)&&v.insertBefore(b.createTextNode($.exec(k)[0]),v.firstChild);k=v.childNodes}if(k.nodeType)f.push(k);else f=c.merge(f,k)}}if(d)for(h=0;f[h];h++)if(e&&
+c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,k=0,l;(l=a[k])!=null;k++)if(!(l.nodeName&&c.noData[l.nodeName.toLowerCase()]))if(d=l[c.expando]){if((b=e[d])&&b.events)for(var n in b.events)f[n]?
+c.event.remove(l,n):c.removeEvent(l,n,b.handle);if(h)delete l[c.expando];else l.removeAttribute&&l.removeAttribute(c.expando);delete e[d]}}});var Ca=/alpha\([^)]*\)/i,db=/opacity=([^)]*)/,eb=/-([a-z])/ig,fb=/([A-Z])/g,Da=/^-?\d+(?:px)?$/i,gb=/^-?\d/,hb={position:"absolute",visibility:"hidden",display:"block"},La=["Left","Right"],Ma=["Top","Bottom"],W,ib=u.defaultView&&u.defaultView.getComputedStyle,jb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===A)return this;
+return c.access(this,a,b,true,function(d,e,f){return f!==A?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),k=a.style,l=c.cssHooks[h];b=c.cssProps[h]||
+h;if(d!==A){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!l||!("set"in l)||(d=l.set(a,d))!==A)try{k[b]=d}catch(n){}}}else{if(l&&"get"in l&&(f=l.get(a,false,e))!==A)return f;return k[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==A)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=
+e[f]},camelCase:function(a){return a.replace(eb,jb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=ma(d,b,f);else c.swap(d,hb,function(){h=ma(d,b,f)});return h+"px"}},set:function(d,e){if(Da.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return db.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":
+b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=d.filter||"";d.filter=Ca.test(f)?f.replace(Ca,e):d.filter+" "+e}};if(ib)W=function(a,b,d){var e;d=d.replace(fb,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return A;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};else if(u.documentElement.currentStyle)W=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],
+h=a.style;if(!Da.test(f)&&gb.test(f)){d=h.left;e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f};if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var kb=c.now(),lb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+mb=/^(?:select|textarea)/i,nb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ob=/^(?:GET|HEAD|DELETE)$/,Na=/\[\]$/,T=/\=\?(&|$)/,ia=/\?/,pb=/([?&])_=[^&]*/,qb=/^(\w+:)?\/\/([^\/?#]+)/,rb=/%20/g,sb=/#.*$/,Ea=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ea)return Ea.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=
+b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(k,l){if(l==="success"||l==="notmodified")h.html(f?c("<div>").append(k.responseText.replace(lb,"")).find(f):k.responseText);d&&h.each(d,[k.responseText,l,k])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
+!this.disabled&&(this.checked||mb.test(this.nodeName)||nb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
+getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
+script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),k=ob.test(h);b.url=b.url.replace(sb,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ia.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
+!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+kb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var l=E[d];E[d]=function(m){f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);if(c.isFunction(l))l(m);else{E[d]=A;try{delete E[d]}catch(p){}}v&&v.removeChild(B)}}if(b.dataType==="script"&&b.cache===null)b.cache=
+false;if(b.cache===false&&h==="GET"){var n=c.now(),s=b.url.replace(pb,"$1_="+n);b.url=s+(s===b.url?(ia.test(b.url)?"&":"?")+"_="+n:"")}if(b.data&&h==="GET")b.url+=(ia.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");n=(n=qb.exec(b.url))&&(n[1]&&n[1]!==location.protocol||n[2]!==location.host);if(b.dataType==="script"&&h==="GET"&&n){var v=u.getElementsByTagName("head")[0]||u.documentElement,B=u.createElement("script");if(b.scriptCharset)B.charset=b.scriptCharset;B.src=
+b.url;if(!d){var D=false;B.onload=B.onreadystatechange=function(){if(!D&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){D=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);B.onload=B.onreadystatechange=null;v&&B.parentNode&&v.removeChild(B)}}}v.insertBefore(B,v.firstChild);return A}var H=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!k||a&&a.contentType)w.setRequestHeader("Content-Type",
+b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}n||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(G){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
+c.triggerGlobal(b,"ajaxSend",[w,b]);var M=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){H||c.handleComplete(b,w,e,f);H=true;if(w)w.onreadystatechange=c.noop}else if(!H&&w&&(w.readyState===4||m==="timeout")){H=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
+c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&g.call&&g.call(w);M("abort")}}catch(j){}b.async&&b.timeout>0&&setTimeout(function(){w&&!H&&M("timeout")},b.timeout);try{w.send(k||b.data==null?null:b.data)}catch(o){c.handleError(b,w,null,o);c.handleComplete(b,w,e,f)}b.async||M();return w}},param:function(a,b){var d=[],e=function(h,k){k=c.isFunction(k)?k():k;d[d.length]=encodeURIComponent(h)+
+"="+encodeURIComponent(k)};if(b===A)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)ca(f,a[f],b,e);return d.join("&").replace(rb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",[b,a])},handleComplete:function(a,
+b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),e=a.getResponseHeader("Etag");
+if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});if(E.ActiveXObject)c.ajaxSettings.xhr=
+function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var da={},tb=/^(?:toggle|show|hide)$/,ub=/^([+\-]=)?([\d+.\-]+)(.*)$/,aa,na=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",3),a,b,d);else{a=
+0;for(b=this.length;a<b;a++){if(!c.data(this[a],"olddisplay")&&this[a].style.display==="none")this[a].style.display="";this[a].style.display===""&&c.css(this[a],"display")==="none"&&c.data(this[a],"olddisplay",oa(this[a].nodeName))}for(a=0;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",d)}for(a=
+0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,d,e);if(c.isEmptyObject(a))return this.each(f.complete);
+return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),k,l=this.nodeType===1,n=l&&c(this).is(":hidden"),s=this;for(k in a){var v=c.camelCase(k);if(k!==v){a[v]=a[k];delete a[k];k=v}if(a[k]==="hide"&&n||a[k]==="show"&&!n)return h.complete.call(this);if(l&&(k==="height"||k==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(oa(this.nodeName)===
+"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[k])){(h.specialEasing=h.specialEasing||{})[k]=a[k][1];a[k]=a[k][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(B,D){var H=new c.fx(s,h,B);if(tb.test(D))H[D==="toggle"?n?"show":"hide":D](a);else{var w=ub.exec(D),G=H.cur(true)||0;if(w){var M=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(s,B,(M||1)+g);
+G=(M||1)/H.cur(true)*G;c.style(s,B,G+g)}if(w[1])M=(w[1]==="-="?-1:1)*M+G;H.custom(G,M,g)}else H.custom(G,D,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
+d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
+Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(h){return f.step(h)}
+this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var f=this;a=c.fx;e.elem=this.elem;if(e()&&c.timers.push(e)&&!aa)aa=setInterval(a.tick,a.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
+this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(l,n){f.style["overflow"+n]=h.overflow[l]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
+this.options.show)for(var k in this.options.curAnim)c.style(this.elem,k,this.options.orig[k]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
+c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(aa);aa=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
+b.elem}).length};var vb=/^t(?:able|d|h)$/i,Fa=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in u.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(k){c.offset.setOffset(this,a,k)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=ea(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
+h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(s){c.offset.setOffset(this,a,s)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,e=b.ownerDocument,f,h=e.documentElement,k=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;
+for(var l=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==k&&b!==h;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;f=e?e.getComputedStyle(b,null):b.currentStyle;l-=b.scrollTop;n-=b.scrollLeft;if(b===d){l+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&vb.test(b.nodeName))){l+=parseFloat(f.borderTopWidth)||0;n+=parseFloat(f.borderLeftWidth)||0}d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&f.overflow!=="visible"){l+=
+parseFloat(f.borderTopWidth)||0;n+=parseFloat(f.borderLeftWidth)||0}f=f}if(f.position==="relative"||f.position==="static"){l+=k.offsetTop;n+=k.offsetLeft}if(c.offset.supportsFixedPosition&&f.position==="fixed"){l+=Math.max(h.scrollTop,k.scrollTop);n+=Math.max(h.scrollLeft,k.scrollLeft)}return{top:l,left:n}};c.offset={initialize:function(){var a=u.body,b=u.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
+height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
+f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
+"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),k=c.css(a,"top"),l=c.css(a,"left"),n=e==="absolute"&&c.inArray("auto",[k,l])>-1;e={};var s={};if(n)s=f.position();k=n?s.top:parseInt(k,10)||0;l=n?s.left:parseInt(l,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+k;if(b.left!=null)e.left=b.left-h.left+l;"using"in b?b.using.call(a,
+e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Fa.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||u.body;a&&!Fa.test(a.nodeName)&&
+c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==A)return this.each(function(){if(h=ea(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=ea(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
+c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(h){var k=c(this);k[d](e.call(this,h,k[d]()))});return c.isWindow(f)?f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b]:f.nodeType===9?Math.max(f.documentElement["client"+
+b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]):e===A?parseFloat(c.css(f,d)):this.css(d,typeof e==="string"?e:e+"px")}})})(window);

BIN
views/Feeds/Carbon_files/photo_corner.png


BIN
views/Feeds/Carbon_files/portrait_frame.png


Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác