diff --git a/README.md b/README.md index 4d0e627..c2f832c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,87 @@ -giftlist -======== +# Presentlist / Geschenkeliste # -Eine Geschenkliste / a Presentlist / ein Wunschzettel +=> !! For English => english is under german !! + +Presentlist ist eine Geschenkliste auf der man seine Wünsche zur Hochzeit, Geburtstag oder anderen Anlässen auflisten kann. Dabei kann man einen Titel, Beschreibung und auch ein Bild zum Geschnenk angeben, sowie Links zu Händlern oder dem Produkt angeben. Wenn sich dann jemand ein Geschenk von der Liste nimmt, ist es für die anderen nicht mehr sichtbar. Man kann gewählte Geschenke aber auch wieder freigeben und der Administrator sieht nicht wer sich welches Geschenk genommen hat. + +![](https://raw2.github.com/lightszentip/giftlist/gh-pages/screenshot01.PNG) +![](https://raw2.github.com/lightszentip/giftlist/gh-pages/screenshot03.PNG) +![](https://raw2.github.com/lightszentip/giftlist/gh-pages/screenshot04.PNG) + +## Funktionen ## +- Install Wizard +- Geschenkeliste +- Detail Ansicht von Geschenken +- Geschenk auswählen +- Geschenk freigeben +- Geschenk per Mail teilen +- Backend + - Geschenk anlegen / editieren / löschen + - Benutzer anlegen + - Profil editieren + - Passwort vergessen + - Login / Logout + - Wartungsmodus aktivieren + - Einstellungen ändern + + +## Requirements ## + +- PHP 5.3.7 oder höher +- MySQL Datenbank (andere sind aktuell nur durch bearbeiten der Sources möglich) +- PHP PDO Support für MySQL aktiv (extension=php_pdo_mysql.dll) + + +## Anleitung ## + +Die Zip Datei im gewüschten Ordner entpacken und die Url zum Ordner aufrufen. Danach wird man auf den Install Wizard weitergeleitet. Nach dem ausführen des Install Wizard den setup Ordner löschen. Danach sich anmelden und das Passwort und die Email Adresse des Admin Benutzers ändern. Durch das Ändern des Benutzernamens wird zudem die Sicherheit erhöht. + +Bei Fragen/Problemen/Erweiterungen und Feedback stehe ich gerne zur Verfügung. Entweder per Email oder durch erstellen eines Issues. + +## English ## + +The app presentlist is show the wishes from wedding, birthday or from other occasions. You can create a present with a title, description, image and links. If a user take a present from the list, it is not visible for other user. + + + +## Functions ## +- Install Wizard +- list with presents +- detail view of present +- use a present +- release a gift +- Backend + - create, edit, delete a present + - create user + - edit profile + - forgotten password + - Login / Logout + - maintenance mode + - change settings + + +## Requirements ## + +- PHP 5.3.7 or higher +- MySQL Database (other database only support by you edit the source files) +- PHP PDO Support for MySQL active (extension=php_pdo_mysql.dll) + + +## Instructions ## + +Unpack the zip file to the target dir and open the url in your browser. Follow the steps of install wizard. Delete the setup folder and change the password and email address of admin account. + +If you have a question, problems or feedback then you can send a mail or create a new issue. + +## Verwendete PHP Libraries / Used lbraries: ## + +- Rain TPL => [https://github.com/rainphp/raintpl](https://github.com/rainphp/raintpl) +- php-i18n von Philipp Schröer=> [https://github.com/Philipp15b/php-i18n?files=1](https://github.com/Philipp15b/php-i18n?files=1) +- Medoo DB => [http://medoo.in/api/new](http://medoo.in/api/new) +- PHP Setup / Installer Script => [http://www.effiziente-webprogrammierung.info/php-scripts/setup-wizard-installer](http://www.effiziente-webprogrammierung.info/php-scripts/setup-wizard-installer) +- PHP Login von http://www.php-login.net/ => [https://github.com/panique/php-login](https://github.com/panique/php-login) -> Version Advanced + +## Verwendete JS/HTML/CSS Komponeneten / Used JS/HTML/CSS components: ## + +- TableSorter von Christian Bach => [http://mottie.github.io/tablesorter/](https://github.com/Mottie/tablesorter) +- Bootstrap 3.1 => [http://getbootstrap.com/](http://getbootstrap.com/) \ No newline at end of file diff --git a/app/classes/controller/ControllerAdminStartpage.php b/app/classes/controller/ControllerAdminStartpage.php new file mode 100644 index 0000000..f106d79 --- /dev/null +++ b/app/classes/controller/ControllerAdminStartpage.php @@ -0,0 +1,73 @@ + view = new BackendView($login->getSecurityModel()); + $this -> request = $request; + $this -> messageResolver = AppFactory::getMessageResolver(); + $this -> presentDao = new PresentDao($jdbcTemplate); + } + + /** + * Process data + */ + public function process() { + $presentlist = $this -> presentDao -> getAll(); + $this -> view -> assign("presents", $presentlist -> getItems()); + $success = null; + if(!empty($this -> request['get']['success'])) { + $success = EscapeHelper::escape($this -> request['get']['success'], EscapeHelper::TARGET_STRING); + } + $isErrorPresent = false; + $isChangePresent = false; + if (!empty($success) && ($success == "createPresent" || $success == "editPresent" || $success == "deletePresent")) { + $args = EscapeHelper::escape($this -> request['get']['args'], EscapeHelper::TARGET_STRING); + $parameter = base64_decode($args); + list($paramPresentId, $paramResult) = split("&", $parameter); + $presentId = EscapeHelper::escape(str_replace("presentId=", "", $paramPresentId), EscapeHelper::TARGET_NUMBER); + if ($success == "createPresent") { + $present = $this -> presentDao -> getById($presentId); + $isChangePresent = true; + $this -> view -> assign("infomessage", $this -> messageResolver -> getMessage("adminpresenttable_create_present", $present -> getTitle())); + } else if ($success == "editPresent") { + $present = $this -> presentDao -> getById($presentId); + $isChangePresent = true; + $this -> view -> assign("infomessage", $this -> messageResolver -> getMessage("adminpresenttable_edit_present", $present -> getTitle())); + } else if ($success == "deletePresent") { + $result = EscapeHelper::escape(str_replace("result=", "", $paramResult), EscapeHelper::TARGET_STRING); + if ($result == 1) { + $isChangePresent = true; + $this -> view -> assign("infomessage", $this -> messageResolver -> getMessage("adminpresenttable_delete_present", $presentId)); + } else { + $isErrorPresent = true; + $this -> view -> assign("errormessage", $this -> messageResolver -> getMessage("adminpresenttable_delete_present_error", $presentId)); + } + } + } + $this -> view -> assign("changePresent", $isChangePresent); + $this -> view -> assign("errorPresent", $isErrorPresent); + } + /** + * Display Content + * @return type + */ + public function display() { + $this -> view -> setTemplate("backend_presenttable"); + $this -> view -> assign("view", "list"); + $this -> view -> assign("messageResolver", $this -> messageResolver); + return $this -> view -> loadTemplate(); + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerCreateEditPresent.php b/app/classes/controller/ControllerCreateEditPresent.php new file mode 100644 index 0000000..3f3e73b --- /dev/null +++ b/app/classes/controller/ControllerCreateEditPresent.php @@ -0,0 +1,144 @@ +view = new BackendView($login->getSecurityModel()); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->presentDao = new PresentDao($jdbcTemplate); + } + + /** + * + */ + public function process() { + $isNew = null; + if (!empty($this->request['post']['checknew'])) { + $isNew = EscapeHelper::escape($this->request['post']['checknew'], EscapeHelper::TARGET_STRING); + } + $error = new ErrorModel(); + $isError = false; + $isEdit = false; + if ($isNew == "true") { + $title = EscapeHelper::escape($this->request['post']['title'], EscapeHelper::TARGET_STRING); + $description = EscapeHelper::escape($this->request['post']['description'], EscapeHelper::TARGET_STRING); + $imagePath = EscapeHelper::escape($this->request['post']['imagePath'], EscapeHelper::TARGET_STRING); + $links = EscapeHelper::escape($this->request['post']['links'], EscapeHelper::TARGET_STRING); + if (HelperUtil::isNullOrEmptyString($title)) { + $error->addErrorField("title", "error_present_create_empty_title"); + } else { + if (strlen($title) > 50) { + $error->addErrorField("title", "error_present_create_size_title"); + } + } + if (!empty($imagePath)) { + if (!$this->str_starts_with($imagePath, "http")) { + $imagePath = "http://" . $imagePath; + } + if (!filter_var($imagePath, FILTER_VALIDATE_URL)) { + $error->addErrorField("title", "error_present_create_invalid_imagepath"); + } + } + if (!empty($description) && strlen($description) > 1200) { + $error->addErrorField("description", "error_present_create_size_description"); + } + if (!empty($links)) { + + function notEmpty($var) { + // Gibt zurück, ob der Eingabewert gerade ist + return (!(!isset($var) || trim($var) === '' || empty($var))); + } + + $links = array_filter($links, "notEmpty"); + } + if (count($links) == 0) { + $links = null; + } + $present = new PresentModel(); + $present->setTitle($title); + $present->setDescription($description); + $present->setImagePath($imagePath); + $present->setLinks($links); + if ($error->hasError()) { + $editId = EscapeHelper::escape($this->request['post']['editId'], EscapeHelper::TARGET_NUMBER); + if (!empty($editId)) { + $present->setId($editId); + } + $this->view->assign("present", $present); + } else { + $editId = EscapeHelper::escape($this->request['post']['editId'], EscapeHelper::TARGET_NUMBER); + if (!empty($editId)) { + $present->setId($editId); + $id = $this->presentDao->update($present); + if ($id != null) { + $targetLocation = APP_URL . "?mapping=admin&success=editPresent&args=" . base64_encode("presentId=$id"); + header("Location: $targetLocation"); + } else { + $error->addErrorField("present", $this->messageResolver->getMessage("error_present_create_db")); + $this->view->assign("present", $present); + } + } else { + $id = $this->presentDao->createPresent($present); + if ($id != null) { + $targetLocation = APP_URL . "?mapping=admin&success=createPresent&args=" . base64_encode("presentId=$id"); + header("Location: $targetLocation"); + } else { + $error->addErrorField("present", $this->messageResolver->getMessage("error_present_create_db")); + $this->view->assign("present", $present); + } + } + } + } else { + //edit ? + $presendId = EscapeHelper::escape($this->request['get']['id'], EscapeHelper::TARGET_NUMBER); + if (!empty($presendId)) { + $present = $this->presentDao->getById($presendId); + if ($present != null && $present->getStatus() != 1) { + $this->view->assign("present", $present); + $isEdit = true; + } else { + $this->view->assign("present", new PresentModel()); + $isError = true; + } + } else { + $this->view->assign("present", new PresentModel()); + } + } + $this->view->assign("isError", $isError); + $this->view->assign("isEdit", $isEdit); + $this->view->assign("error", $error); + } + + /** + * + * @return type + */ + public function display() { + $this->view->setTemplate("backend_createeditpresent"); + $this->view->assign("messageResolver", $this->messageResolver); + return $this->view->loadTemplate(); + } + + private function str_starts_with($haystack, $needle) { + return substr_compare($haystack, $needle, 0, strlen($needle)) === 0; + } + + private function str_ends_with($haystack, $needle) { + return substr_compare($haystack, $needle, -strlen($needle)) === 0; + } + +} + +?> \ No newline at end of file diff --git a/app/classes/controller/ControllerCreateUser.php b/app/classes/controller/ControllerCreateUser.php new file mode 100644 index 0000000..e197f91 --- /dev/null +++ b/app/classes/controller/ControllerCreateUser.php @@ -0,0 +1,35 @@ +view = new BackendView($login->getSecurityModel()); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->login = $login; + } + + public function process() { + $this->login->processRegister(); + } + + public function display() { + $this->view->setTemplate($this->login->getRegisterView()); + $this->view->assign("messageResolver", $this->messageResolver); + $this->view->assign($this->login->getRegisterViewVars()); + $this->view->assign("isRegisterConfirm", false); + return $this->view->loadTemplate(); + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerDeletePresent.php b/app/classes/controller/ControllerDeletePresent.php new file mode 100644 index 0000000..ff37da6 --- /dev/null +++ b/app/classes/controller/ControllerDeletePresent.php @@ -0,0 +1,41 @@ +view = new BackendView($login->getSecurityModel()); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->presentDao = new PresentDao($jdbcTemplate); + } + + public function process() { + $present = null; + if (!empty($this->request['get']['presentId'])) { + $presentId = EscapeHelper::escape($this->request['get']['presentId'], EscapeHelper::TARGET_NUMBER); + $present = $this->presentDao->getById($presentId); + } + $targetLocation = null; + if ($present != null && $present->getStatus() != 1) { + $result = $this->presentDao->delete($presentId); + if ($result) { + $targetLocation = APP_URL . "?mapping=admin&success=deletePresent&args=" . base64_encode("presentId=$presentId&result=1"); + } else { + $targetLocation = APP_URL . "?mapping=admin&success=deletePresent&args=" . base64_encode("presentId=$presentId&result=2"); + } + } else { + $targetLocation = APP_URL . "?mapping=admin&success=deletePresent&args=" . base64_encode("presentId=$presentId&result=2"); + } + header("Location: $targetLocation"); + } + + public function display() { + return $this->view->loadTemplate(); + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerLogin.php b/app/classes/controller/ControllerLogin.php new file mode 100644 index 0000000..12e19ef --- /dev/null +++ b/app/classes/controller/ControllerLogin.php @@ -0,0 +1,50 @@ +view = new LoginView($login->getSecurityModel()); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + if (empty($this->request['post']['next'])) { + $this->target = $defaultTarget; + } else { + $this->target = EscapeHelper::escape($this->request['post']['next'], EscapeHelper::TARGET_STRING); + } + $this->isError = false; + $this->login = $login; + } + + public function process() { + if (!$this->login->isAppLoggedIn()) { + $targetLocation = APP_URL . "?mapping=" . $this->target; + $this->isError = $this->login->appLoginRequest($targetLocation); + } else { + $targetLocation = APP_URL . "?mapping=" . $this->target; + header("Location: $targetLocation"); + } + } + + public function display() { + $this->view->setTemplate($this->login->getLoginView()); + $this->view->assign("messageResolver", $this->messageResolver); + $this->view->assign($this->login->getLoginViewVars()); + $this->view->assign("target", $this->target); + $this->view->assign("isErrorMessage", $this->isError); + return $this->view->loadTemplate(); + } + +} diff --git a/app/classes/controller/ControllerLogout.php b/app/classes/controller/ControllerLogout.php new file mode 100644 index 0000000..8da495c --- /dev/null +++ b/app/classes/controller/ControllerLogout.php @@ -0,0 +1,24 @@ +login = $login; + } + + public function process() { + $this->login->appLogout(); + $targetLocation = APP_URL; + header("Location: $targetLocation"); + } + + public function display() { + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerMaintenance.php b/app/classes/controller/ControllerMaintenance.php new file mode 100644 index 0000000..9f35a9a --- /dev/null +++ b/app/classes/controller/ControllerMaintenance.php @@ -0,0 +1,32 @@ + view = new FrontendView(); + $this -> messageResolver = AppFactory::getMessageResolver(); + $this -> configDao = new ConfigDao($jdbcTemplate); + } + + public function process() { + $this -> view -> assign("title", $this -> configDao->getByKey($this->confModeKeyTitle)); + $this -> view -> assign("subtitle", $this -> configDao->getByKey($this->confModeKeySubtitle)); + } + + public function display() { + $this -> view -> setTemplate("maintenance"); + return $this -> view -> loadTemplate(); + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerMaintenanceSettings.php b/app/classes/controller/ControllerMaintenanceSettings.php new file mode 100644 index 0000000..c64cf95 --- /dev/null +++ b/app/classes/controller/ControllerMaintenanceSettings.php @@ -0,0 +1,85 @@ +view = new BackendView($login->getSecurityModel()); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->configDao = new ConfigDao($jdbcTemplate); + } + + public function process() { + $isNew = null; + $success = null; + if (!empty($this->request['post']['checknew'])) { + $isNew = EscapeHelper::escape($this->request['post']['checknew'], EscapeHelper::TARGET_STRING); + } + if (!empty($this->request['get']['success'])) { + $success = EscapeHelper::escape($this->request['get']['success'], EscapeHelper::TARGET_STRING); + } + $error = new ErrorModel(); + if ($isNew == "true") { + $title = EscapeHelper::escape($this->request['post']['title'], EscapeHelper::TARGET_STRING); + $content = EscapeHelper::escape($this->request['post']['content'], EscapeHelper::TARGET_STRING); + if (!empty($title) && strlen($title) > 50) { + $error->addErrorField("title", "error_maintenance_settings_size_title"); + } + if (!empty($content) && strlen($content) > 255) { + $error->addErrorField("content", "error_maintenance_settings_size_content"); + } + if ($error->hasError()) { + $this->view->assign("content", $content); + $this->view->assign("title", $title); + } else { + $statusTitle = $this->configDao->update($this->confModeKeyTitle, $title); + $statusSubtitle = $this->configDao->update($this->confModeKeySubtitle, $content); + + if ($statusSubtitle && $statusTitle) { + $targetLocation = APP_URL . "?mapping=admin/settings/maintenance&success=save"; + header("Location: $targetLocation"); + } else { + $error->addErrorField("maintenance", $this->messageResolver->getMessage("error_maintenance_settings_db")); + $this->view->assign("content", $content); + $this->view->assign("title", $title); + } + } + } else { + $config = $this->configDao->getAll(); + $this->view->assign("title", $config[$this->confModeKeyTitle]); + $this->view->assign("content", $config[$this->confModeKeySubtitle]); + } + if ($success == "save") { + $this->view->assign("changemaintenance", $this->messageResolver->getMessage("maintenance_settings_save")); + } else if ($success == "on") { + $this->view->assign("changemaintenance", $this->messageResolver->getMessage("maintenance_settings_on")); + } else if ($success == "off") { + $this->view->assign("changemaintenance", $this->messageResolver->getMessage("maintenance_settings_off")); + } else { + $this->view->assign("changemaintenance", false); + } + $this->view->assign("modeStatus", $config[$this->confModeKeyMaintenance]); + $this->view->assign("error", $error); + } + + public function display() { + $this->view->setTemplate("backend_maintenance_settings"); + $this->view->assign("messageResolver", $this->messageResolver); + return $this->view->loadTemplate(); + } + +} diff --git a/app/classes/controller/ControllerMaintenanceSwitch.php b/app/classes/controller/ControllerMaintenanceSwitch.php new file mode 100644 index 0000000..403cc84 --- /dev/null +++ b/app/classes/controller/ControllerMaintenanceSwitch.php @@ -0,0 +1,29 @@ + configDao = new ConfigDao($jdbcTemplate); + $this ->status = $status; + } + + public function process() { + if($this->status == 1) { + $statusTitle = $this -> configDao -> update($this->confModeKeyMaintenance,"true"); + } else if($this->status == 0) { + $statusTitle = $this -> configDao -> update($this->confModeKeyMaintenance,"false"); + } + $targetLocation = APP_URL . "?mapping=admin/settings/maintenance&success=".($this ->status == 1 ? "on" : "").($this ->status == 0 ? "off" : ""); + header("Location: $targetLocation"); + } + + public function display() { + } + + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerPresentDetailView.php b/app/classes/controller/ControllerPresentDetailView.php new file mode 100644 index 0000000..94c2860 --- /dev/null +++ b/app/classes/controller/ControllerPresentDetailView.php @@ -0,0 +1,38 @@ +view = new FrontendView(); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->presentDao = new PresentDao($jdbcTemplate); + $this->appDebugger = AppFactory::getDebugger(IS_DEBUG); + } + + public function process() { + $isError = false; + if (!empty($this->request['get']['presentId'])) { + $presentId = EscapeHelper::escape($this->request['get']['presentId'], EscapeHelper::TARGET_NUMBER); + $present = $this->presentDao->getById($presentId); + $this->view->assign("present", $present); + } else { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_parameter_error")); + } + $this->view->assign("isError", $isError); + } + + public function display() { + $this->view->setTemplate("detailview"); + $this->view->assign("messageResolver", $this->messageResolver); + return $this->view->loadTemplate(); + } + +} diff --git a/app/classes/controller/ControllerPresentShare.php b/app/classes/controller/ControllerPresentShare.php new file mode 100644 index 0000000..b02bfb6 --- /dev/null +++ b/app/classes/controller/ControllerPresentShare.php @@ -0,0 +1,104 @@ +view = new AjaxView(); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->presentDao = new PresentDao($jdbcTemplate); + } + + public function process() { + $presentId = EscapeHelper::escape($this->request['post']['presentId'], EscapeHelper::TARGET_NUMBER); + $emailFrom = EscapeHelper::escape($this->request['post']['emailfrom'], EscapeHelper::TARGET_STRING); + $emailTo = EscapeHelper::escape($this->request['post']['emailto'], EscapeHelper::TARGET_STRING); + $nameFrom = EscapeHelper::escape($this->request['post']['namefrom'], EscapeHelper::TARGET_STRING); + $nameTo = EscapeHelper::escape($this->request['post']['nameto'], EscapeHelper::TARGET_STRING); + $content = EscapeHelper::escape($this->request['post']['content'], EscapeHelper::TARGET_STRING); + $error = new ErrorModel(); + if (HelperUtil::isNullOrEmptyString($emailFrom) && !filter_var($emailFrom, FILTER_VALIDATE_EMAIL)) { + $error->addErrorField("emailfrom", "error_share_emailfrom"); + } + if (HelperUtil::isNullOrEmptyString($emailTo)) { + $error->addErrorField("emailto", "error_share_emailto"); + } else if (!filter_var($emailTo, FILTER_VALIDATE_EMAIL)) { + $to = explode(';', $emailTo); + foreach ($to as $toMailAddress) { + if (!filter_var($toMailAddress, FILTER_VALIDATE_EMAIL)) { + $error->addErrorField("emailto", "error_share_emailto"); + } + } + } + if (HelperUtil::isNullOrEmptyString($nameFrom)) { + $error->addErrorField("namefrom", "error_share_namefrom"); + } + $present = null; + if (empty($presentId)) { + $error->addErrorField("content", "error_share_presentId"); + } else { + $present = $this->presentDao->getById($presentId); + if ($present == null) { + $error->addErrorField("content", "error_share_presentId"); + } + } + if ($error->hasError()) { + $this->view->assign("emailfrom", $emailFrom); + $this->view->assign("presentId", $presentId); + $this->view->assign("emailto", $emailTo); + $this->view->assign("namefrom", $nameFrom); + $this->view->assign("nameto", $nameTo); + $this->view->assign("content", $content); + } else { + $this->sendEmailUsePresent($emailTo, $emailFrom, $content, $nameFrom, $nameTo, $present); + $this->success = true; + } + $this->view->assign("error", $error); + } + + public function display() { + if ($this->success) { + $this->view->setTemplate("share_success"); + } else { + $this->view->setTemplate("share_modal"); + } + $this->view->assign("messageResolver", $this->messageResolver); + return $this->view->loadTemplate(); + } + + /** + * + * @param type $to + * @param type $from + * @param type $content + * @param type $nameFrom + * @param type $nameTo + * @param PresentModel $present + */ + private function sendEmailUsePresent($to, $from, $content, $nameFrom, $nameTo, PresentModel $present) { + $toAddresses = explode(';', $to); + $mailTemplate = new MailTemplate("emailshare", AppFactory::getTemplateEngine(TEMPLATE_PATH)); + $url = APP_URL . "?mapping=present/view&presentId=" . $present->getId(); + $info = $this->messageResolver->getMessage("email_share_present_info") . APP_NAME; + $subject = "[" . APP_ABBREVIATION . "]" . $this->messageResolver->getMessage("email_share_present_subject", array($nameFrom, $present->getTitle())); + if (!HelperUtil::isNullOrEmptyString($nameTo)) { + $salutation = $this->messageResolver->getMessage("email_share_present_toName") . " " . $nameTo . ","; + } else { + $salutation = $this->messageResolver->getMessage("email_share_present_toName") . ","; + } + $mailTemplate->assign("text", $this->messageResolver->getMessage("email_share_present_text_html", array($nameFrom, $present->getTitle(), $url, APP_NAME)) . "
" . $content); + $mailTemplate->assign("salutation", $salutation); + $mailTemplate->assign("info", $info); + $text = $salutation . "\n" . $this->messageResolver->getMessage("email_share_present_text", array($nameFrom, $present->getTitle(), $url, APP_NAME)) . "\n\n" . $content . "\n\n" . $info; + foreach ($toAddresses as $toAddress) { + HelperUtil::sendEmail($toAddress, $from, $from, $mailTemplate->getHtml(), $text, $subject); + } + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerProfile.php b/app/classes/controller/ControllerProfile.php new file mode 100644 index 0000000..2bf7339 --- /dev/null +++ b/app/classes/controller/ControllerProfile.php @@ -0,0 +1,53 @@ +view = new BackendView($login->getSecurityModel()); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->login = $login; + } + + public function process() { + $isEdit = false; + if (filter_has_var(INPUT_POST, "profil_data")) { + $this->login->processEditProfil(); + $isEdit = true; + } + if (filter_has_var(INPUT_POST, "profil_password")) { + $this->login->processEditPassword(); + $isEdit = true; + } + $login = $this->login->getProfilViewVars(); + if ($isEdit && !$login['login']->errors) { + $_SESSION['profil_messages'] = $login['login']->messages; + $targetLocation = APP_URL . "?mapping=user/profile&success=save"; + header("Location: $targetLocation"); + } + } + + public function display() { + if (filter_has_var(INPUT_GET, "success")) { + $messages = $_SESSION['profil_messages']; + $this->view->assign("messages", $messages); + unset($messages); + $_SESSION['profil_messages'] = null; + } else { + $this->view->assign("messages", null); + } + $this->view->setTemplate($this->login->getProfilView()); + $this->view->assign("messageResolver", $this->messageResolver); + $this->view->assign($this->login->getProfilViewVars()); + $security = $this->login->getSecurityModel(); + $this->view->assign("username", $security->getUserName()); + $this->view->assign("email", $security->getEmail()); + return $this->view->loadTemplate(); + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerRegister.php b/app/classes/controller/ControllerRegister.php new file mode 100644 index 0000000..a4171af --- /dev/null +++ b/app/classes/controller/ControllerRegister.php @@ -0,0 +1,31 @@ +view = new BackendView($login->getSecurityModel()); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->login = $login; + } + + public function process() { + if (!isset($this->request["post"]["register"]) && isset($this->request["get"]["id"]) && isset($this->request["get"]["verification_code"])) { + $this->login->processRegister(); + } + } + + public function display() { + $this->view->setTemplate($this->login->getRegisterView()); + $this->view->assign("messageResolver", $this->messageResolver); + $this->view->assign($this->login->getRegisterViewVars()); + $this->view->assign("isRegisterConfirm", true); + return $this->view->loadTemplate(); + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerReleasePresent.php b/app/classes/controller/ControllerReleasePresent.php new file mode 100644 index 0000000..5e9bc6d --- /dev/null +++ b/app/classes/controller/ControllerReleasePresent.php @@ -0,0 +1,90 @@ +view = new FrontendView(); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->presentDao = new PresentDao($jdbcTemplate); + $this->appLogger = AppFactory::getLogger(LOG_MODE); + $this->appDebugger = AppFactory::getDebugger(IS_DEBUG); + } + + public function process() { + $success = null; + $isError = false; + $isForm = false; + if (!empty($this->request['get']['success'])) { + $success = EscapeHelper::escape($this->request['get']['success'], EscapeHelper::TARGET_STRING); + } + if (!empty($success) && $success == "view") { + $args = EscapeHelper::escape($this->request['get']['args'], EscapeHelper::TARGET_STRING); + $parameter = base64_decode($args); + $presentId = EscapeHelper::escape(str_replace("presentId=", "", $parameter), EscapeHelper::TARGET_NUMBER); + $present = $this->presentDao->getById($presentId); + if ($present != null) { + $this->view->assign("present", $present); + $this->view->assign("isSuccess", true); + } else { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_notfound_present")); + } + } else { + $releaseCode = null; + $releaseButton = null; + if (!empty($this->request['post']['releasecode'])) { + $releaseCode = EscapeHelper::escape($this->request['post']['releasecode'], EscapeHelper::TARGET_STRING); + } + if (!empty($this->request['post']['releasebutton'])) { + $releaseButton = EscapeHelper::escape($this->request['post']['releasebutton'], EscapeHelper::TARGET_STRING); + } + if (!empty($releaseCode) && !empty($releaseButton)) { + $present = $this->presentDao->getByCode($releaseCode); + if ($present != null) { + $this->presentDao->releasePresent($present->getId()); + $this->appLogger->info('Das Geschenk ' . $present->getId() . ' wurde wieder freigegeben.'); + $targetLocation = APP_URL . "?success=view&args=" . base64_encode("presentId=$present -> getId()"); + header("Location: $targetLocation"); + } + } else { + $releaseCode = null; + if (!empty($this->request['get']['releasecode'])) { + $releaseCode = EscapeHelper::escape($this->request['get']['releasecode'], EscapeHelper::TARGET_STRING); + } + if (!empty($releaseCode)) { + $this->appDebugger->debug($releaseCode); + $present = $this->presentDao->getByCode($releaseCode); + $this->appDebugger->debug($present); + if ($present != null) { + $this->view->assign("present", $present); + $this->view->assign("isView", true); + $this->view->assign("releasebutton", rand(0, 99) . rand(0, 99) . rand(0, 99) . rand(0, 99)); + $this->view->assign("releasecode", $releaseCode); + } else { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_notfound_present")); + } + } else { + $isForm = true; + } + } + } + $this->view->assign("isForm", $isForm); + $this->view->assign("isError", $isError); + } + + public function display() { + $this->view->setTemplate("releasepresent"); + $this->view->assign("messageResolver", $this->messageResolver); + return $this->view->loadTemplate(); + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerResetPassword.php b/app/classes/controller/ControllerResetPassword.php new file mode 100644 index 0000000..34a5341 --- /dev/null +++ b/app/classes/controller/ControllerResetPassword.php @@ -0,0 +1,42 @@ +view = new AjaxView(TEMPLATE_PATH_BACKEND); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->login = $login; + } + + public function process() { + $isSuccess = false; + if (filter_input(INPUT_POST, "request_password_reset") != null && filter_input(INPUT_POST, "user_name") != null) { + $isSuccess = $this->login->setPasswordResetDatabaseTokenAndSendMail(); + } else if (filter_input(INPUT_POST, "submit_new_password") != null) { + $isSuccess = $this->login->editNewPassword(); + } else if (filter_input(INPUT_GET, "user_name") != null && filter_input(INPUT_GET, "verification_code") != null) { + $this->login->checkIfEmailVerificationCodeIsValid(); + } + $this->view->assign("isSuccess", $isSuccess); + } + + public function display() { + if ($this->login->resetLinkIsValid()) { + $this->view->setTemplate($this->login->getResetConfirmView()); + $this->view->assign("userName", $this->request["get"]["user_name"]); + $this->view->assign("verificationCode", $this->request["get"]["verification_code"]); + } else { + $this->view->setTemplate($this->login->getResetView()); + } + $this->view->assign("messageResolver", $this->messageResolver); + $this->view->assign($this->login->getProfilViewVars()); + return $this->view->loadTemplate(); + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerSettings.php b/app/classes/controller/ControllerSettings.php new file mode 100644 index 0000000..4539e4a --- /dev/null +++ b/app/classes/controller/ControllerSettings.php @@ -0,0 +1,119 @@ +view = new BackendView($login->getSecurityModel()); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->configDao = new ConfigDao($jdbcTemplate); + } + + public function process() { + $isNew = null; + $success = null; + if (!empty($this->request['post']['checknew'])) { + $isNew = EscapeHelper::escape($this->request['post']['checknew'], EscapeHelper::TARGET_STRING); + } + if (!empty($this->request['get']['success'])) { + $success = EscapeHelper::escape($this->request['get']['success'], EscapeHelper::TARGET_STRING); + } + $error = new ErrorModel(); + if ($isNew == "true") { + $logmode = EscapeHelper::escape($this->request['post']['logmode'], EscapeHelper::TARGET_STRING); + $domainUrl = EscapeHelper::escape($this->request['post']['domainurl'], EscapeHelper::TARGET_STRING); + $template = EscapeHelper::escape($this->request['post']['template'], EscapeHelper::TARGET_STRING); + $emailAddress = EscapeHelper::escape($this->request['post']['emailaddress'], EscapeHelper::TARGET_STRING); + $codelength = EscapeHelper::escape($this->request['post']['codelength'], EscapeHelper::TARGET_STRING); + $appname = EscapeHelper::escape($this->request['post']['appname'], EscapeHelper::TARGET_STRING); + $appabbreviation = EscapeHelper::escape($this->request['post']['appabbreviation'], EscapeHelper::TARGET_STRING); + if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL) || HelperUtil::isNullOrEmptyString($emailAddress)) { + $error->addErrorField("emailaddress", "error_settings_email"); + } + if (!filter_var($domainUrl, FILTER_VALIDATE_URL) || HelperUtil::isNullOrEmptyString($domainUrl)) { + $error->addErrorField("domainurl", "error_settings_url"); + } + if (HelperUtil::isNullOrEmptyString($appname)) { + $error->addErrorField("appname", "error_settings_appname"); + } + if (HelperUtil::isNullOrEmptyString($appabbreviation)) { + $error->addErrorField("appabbreviation", "error_settings_appabbreviation"); + } + $isLogModeMatch = false; + $isTemplateMatch = false; + foreach ($this->logModeArray as $key => $value) { + if ($logmode == $value) { + $isLogModeMatch = true; + } + } + if (!$isLogModeMatch) { + $error->addErrorField("logmode", "error_settings_logmode"); + } + foreach ($this->templateArray as $key => $value) { + if ($template == $value) { + $isTemplateMatch = true; + } + } + if (!$isTemplateMatch) { + $error->addErrorField("template", "error_settings_template"); + } + if ($error->hasError()) { + $this->view->assign("template", $template); + $this->view->assign("logmode", $logmode); + $this->view->assign("codelength", $codelength); + $this->view->assign("emailaddress", $emailAddress); + $this->view->assign("domainurl", $domainUrl); + $this->view->assign("appname", $appname); + $this->view->assign("appabbreviation", $appabbreviation); + } else { + $this->configDao->update($this->confModeKeyCodeLength, $codelength); + $this->configDao->update($this->confModeKeyUrl, $domainUrl); + $this->configDao->update($this->confModeKeyEmailAddress, $emailAddress); + $this->configDao->update($this->confModeKeyLogMode, $logmode); + $this->configDao->update($this->confModeKeyTemplate, $template); + $this->configDao->update($this->confModeKeyAppAbbreviation, $appabbreviation); + $this->configDao->update($this->confModeKeyAppName, $appname); + $targetLocation = APP_URL . "?mapping=admin/settings/all&success=save"; + header("Location: $targetLocation"); + } + } else { + $config = $this->configDao->getAll(); + $this->view->assign("logmode", $config[$this->confModeKeyLogMode]); + $this->view->assign("codelength", $config[$this->confModeKeyCodeLength]); + $this->view->assign("emailaddress", $config[$this->confModeKeyEmailAddress]); + $this->view->assign("template", $config[$this->confModeKeyTemplate]); + $this->view->assign("domainurl", $config[$this->confModeKeyUrl]); + $this->view->assign("appname", $config[$this->confModeKeyAppName]); + $this->view->assign("appabbreviation", $config[$this->confModeKeyAppAbbreviation]); + } + if (isset($success) && $success == "save") { + $this->view->assign("changesettings", $this->messageResolver->getMessage("settings_save")); + } else { + $this->view->assign("changesettings", false); + } + $this->view->assign("error", $error); + $this->view->assign("logmodes", $this->logModeArray); + $this->view->assign("templates", $this->templateArray); + } + + public function display() { + $this->view->setTemplate("backend_settings"); + $this->view->assign("messageResolver", $this->messageResolver); + return $this->view->loadTemplate(); + } + +} \ No newline at end of file diff --git a/app/classes/controller/ControllerStartpage.php b/app/classes/controller/ControllerStartpage.php new file mode 100644 index 0000000..c3baefb --- /dev/null +++ b/app/classes/controller/ControllerStartpage.php @@ -0,0 +1,43 @@ +view = new FrontendView(); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->presentDao = new PresentDao($jdbcTemplate); + } + + public function process() { + $view = null; + if (!empty($this->request['get']['view'])) { + $view = EscapeHelper::escape($this->request['get']['view'], EscapeHelper::TARGET_STRING); + } + if ($view == "grid") { + $this->view->assign("view", "grid"); + } else { + $this->view->assign("view", "list"); + } + $presentlist = $this->presentDao->getAllFreePresents(); + $this->view->assign("presents", $presentlist->getItems()); + $this->view->assign("error", new ErrorModel()); + } + + public function display() { + $this->view->setTemplate("presenttable"); + $this->view->assign("messageResolver", $this->messageResolver); + $this->view->assign("emailfrom", ""); + $this->view->assign("namefrom", ""); + $this->view->assign("emailto", ""); + $this->view->assign("nameto", ""); + $this->view->assign("content", ""); + return $this->view->loadTemplate(); + } + +} diff --git a/app/classes/controller/ControllerUsePresent.php b/app/classes/controller/ControllerUsePresent.php new file mode 100644 index 0000000..2c0d4f4 --- /dev/null +++ b/app/classes/controller/ControllerUsePresent.php @@ -0,0 +1,134 @@ +view = new FrontendView(); + $this->request = $request; + $this->messageResolver = AppFactory::getMessageResolver(); + $this->presentDao = new PresentDao($jdbcTemplate); + $this->appDebugger = AppFactory::getDebugger(IS_DEBUG); + } + + public function process() { + //VIEW or Process + $success = null; + $isError = false; + if (!empty($this->request['get']['success'])) { + $success = EscapeHelper::escape($this->request['get']['success'], EscapeHelper::TARGET_STRING); + } + if (!empty($success) && $success == "view") { + $args = EscapeHelper::escape($this->request['get']['args'], EscapeHelper::TARGET_STRING); + $parameter = base64_decode($args); + list($parameterCode, $parameterId) = split("&", $parameter); + $presentId = EscapeHelper::escape(str_replace("presentId=", "", $parameterId), EscapeHelper::TARGET_NUMBER); + $code = EscapeHelper::escape(str_replace("code=", "", $parameterCode), EscapeHelper::TARGET_STRING); + if (!empty($presentId) && !empty($code)) { + $present = $this->presentDao->getById($presentId); + if ($present->getCode() == $code) { + $this->view->assign("present", $present); + } else { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_parameter_error")); + } + } else { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_parameter_error")); + } + } else { + $presentId = EscapeHelper::escape($this->request['post']['presentId'], EscapeHelper::TARGET_NUMBER); + $email = null; + $isError = false; + $code = ""; + $emailInput = $this->request['post']['email']; + if (!empty($emailInput)) { + $this->appDebugger->debug($emailInput); + $emailInput = EscapeHelper::escape($emailInput, EscapeHelper::TARGET_STRING); + if (!empty($emailInput) && $emailInput != "" && HelperUtil::checkEmailAddress($emailInput)) { + $email = $emailInput; + } else { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_validate_email")); + } + } + $this->appDebugger->trace(); + $this->appDebugger->debug($presentId); + $this->appDebugger->debug($email); + if (!$isError) { + if (!empty($presentId) && $presentId > 0) { + $present = $this->presentDao->getById($presentId); + $this->appDebugger->debug($present); + if ($present != NULL && $present->getCode() == null) { + $generateCode = ""; + do { + $generateCode = $this->getCodeValue(); + } while ($this->presentDao->existCode($generateCode)); + + if ($this->presentDao->usePresent($presentId, $generateCode)) { + $this->view->assign("code", $generateCode); + $code = $generateCode; + if (!empty($email)) { + if (!$this->sendEmailUsePresent($email, $present, $generateCode)) { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_send_email")); + } + } + } else { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_update_present_db")); + } + } else { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_notfound_present")); + } + } else { + $isError = true; + $this->view->assign("error", $this->messageResolver->getMessage("error_empty_presentId")); + } + } + if (!$isError) { + $targetLocation = APP_URL . "?mapping=present/waehlen&success=view&args=" . base64_encode("code=$code&presentId=$presentId"); + header("Location: $targetLocation"); + } + } + $this->view->assign("isError", $isError); + } + + public function display() { + $this->view->setTemplate("usepresent"); + $this->view->assign("messageResolver", $this->messageResolver); + return $this->view->loadTemplate(); + } + + private function getCodeValue() { + $signs = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'U', 'V', 'W', 'X', 'Y', 'Z', '$', '%', '/', '(', '_', '-', ';', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'); + $int_array = count($signs); + $dates = array(date("Hmsdi"), date("Hdims"), date("msHdi")); + $code = hash("crc32b", $dates[rand(0, count($dates) - 1)] . rand(0, 99)); + for ($i = 0; $i < PRESENT_CODE_LENGTH_ADD; $i++) { + $code .= $signs[rand(0, $int_array - 1)]; + } + return $code; + } + + private function sendEmailUsePresent($to, PresentModel $present, $code) { + $mailTemplate = new MailTemplate("emailusepresent", AppFactory::getTemplateEngine(TEMPLATE_PATH)); + $url = APP_URL . "?mapping=present/release&releasecode=$code"; + $viewUrl = APP_URL . "?mapping=present/view&presentId=" . $present->getId(); + $salutation = $this->messageResolver->getMessage("email_use_present_salutation") . APP_NAME; + $info = $this->messageResolver->getMessage("email_use_present_info"); + $subject = APP_ABBREVIATION . $this->messageResolver->getMessage("email_use_present_subject"); + $mailTemplate->assign("text", $this->messageResolver->getMessage("email_use_present_text_html", array($present->getTitle(), $url, $viewUrl))); + $mailTemplate->assign("salutation", $salutation); + $mailTemplate->assign("info", $info); + $text = $salutation . "\n" . $this->messageResolver->getMessage("email_use_present_text", array($present->getTitle(), $url, $viewUrl)) . "\n\n" . $info; + return HelperUtil::sendEmail($to, PRESENT_EMAIL_FROM, PRESENT_EMAIL_REPLY, $mailTemplate->getHtml(), $text, $subject); + } + +} \ No newline at end of file diff --git a/app/classes/controller/index.html b/app/classes/controller/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/classes/controller/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/classes/dao/ConfigDao.php b/app/classes/dao/ConfigDao.php new file mode 100644 index 0000000..70f858e --- /dev/null +++ b/app/classes/dao/ConfigDao.php @@ -0,0 +1,43 @@ + jdbcTemplate = $jdbcTemplate; + } + + public function getAll() { + $tableDatas = $this -> jdbcTemplate -> selectColumn($this -> tableName, $this->allColumns); + $conf = array(); + foreach ($tableDatas as $data) { + $conf[$data["key"]] = $data["value"]; + } + return $conf; + } + + public function getByKey($key) { + return $this -> jdbcTemplate ->getByUnique($this->tableName, self::COLUMN_VALUE, array(self::COLUMN_KEY => $key)); + } + + public function update($key,$value) { + if($this -> jdbcTemplate -> isTrue($this->tableName, array(self::COLUMN_KEY => "$key"))) { + $data = $this -> jdbcTemplate ->update($this->tableName, array(self::COLUMN_VALUE => $value), array(self::COLUMN_KEY => $key)); + } else { + $id = $this -> jdbcTemplate ->insert($this->tableName, array(self::COLUMN_VALUE => $value,self::COLUMN_KEY => $key)); + } + return true; + } + +} +?> \ No newline at end of file diff --git a/app/classes/dao/PresentDao.php b/app/classes/dao/PresentDao.php new file mode 100644 index 0000000..d113a95 --- /dev/null +++ b/app/classes/dao/PresentDao.php @@ -0,0 +1,113 @@ + jdbcTemplate = $jdbcTemplate; + } + + public function getAll() { + $tableDatas = $this -> jdbcTemplate -> selectColumn($this -> tableName, $this->allColumns); + $c = new Collection(); + foreach ($tableDatas as $data) { + $c->addItem(new PresentModel($data),$data['id']); + } + return $c; + } + + public function getAllFreePresents() { + $tableDatas = $this -> jdbcTemplate -> selectColumnConditions($this -> tableName, $this->allColumns, array(self::COLUMN_STATUS => self::PRESENT_STATUS_NOTUSE)); + $c = new Collection(); + foreach ($tableDatas as $data) { + $c->addItem(new PresentModel($data),$data['id']); + } + return $c; + } + + public function existCode($code) { + return $this -> jdbcTemplate -> isTrue($this->tableName, array(self::COLUMN_CODE => "$code")); + } + + public function getById($presentId) { + $returnValue = null; + $data = $this -> jdbcTemplate ->getByUnique($this->tableName, $this->allColumns, array(self::COLUMN_ID => $presentId)); + if(!empty($data)) { + $returnValue = new PresentModel($data); + } + return $returnValue; + } + + public function update(PresentModel $present) { + $returnValue = null; + $data = $this -> jdbcTemplate ->update($this->tableName, array(self::COLUMN_EDIT_DATE => date("Y-m-d H:i:s"),self::COLUMN_DESCRIPTION => $present->getDescription(), self::COLUMN_IMAGEPATH => $present->getImagePath(), self::COLUMN_TITLE=>$present->getTitle(),self::COLUMN_LINKS=>$present->getLinks()), array(self::COLUMN_ID => $present->getId())); + if($data == 1){ + $returnValue = $present->getId(); + } + return $returnValue; + } + + public function delete($presentId) { + $returnValue = null; + $data = $this -> jdbcTemplate ->delete($this->tableName, array(self::COLUMN_ID => $presentId)); + if($data == 1){ + $returnValue = $presentId; + } + return $returnValue; + } + + public function getByCode($code) { + $returnValue = null; + $data = $this -> jdbcTemplate ->getByUnique($this->tableName, $this->allColumns, array("AND" => array(self::COLUMN_CODE => $code, self::COLUMN_STATUS => self::PRESENT_STATUS_USE))); + if(!empty($data)) { + $returnValue = new PresentModel($data); + } + return $returnValue; + } + + public function usePresent($presentId, $code) { + $status = self::PRESENT_STATUS_USE; + $rows = $this -> jdbcTemplate ->update($this->tableName, array(self::COLUMN_CODE=>$code,self::COLUMN_STATUS => $status), array(self::COLUMN_ID => $presentId)); + if($rows != 1) { + return false; + } else { + return true; + } + } + + public function releasePresent($presentId) { + $status = self::PRESENT_STATUS_NOTUSE; + $rows = $this -> jdbcTemplate ->update($this->tableName, array(self::COLUMN_EDIT_DATE => date("Y-m-d H:i:s"),self::COLUMN_CODE=>null,self::COLUMN_STATUS => $status), array(self::COLUMN_ID => $presentId)); + if($rows != 1) { + return false; + } else { + return true; + } + } + + public function createPresent(PresentModel $present) { + $id = $this -> jdbcTemplate ->insert($this->tableName, array(self::COLUMN_EDIT_DATE => date("Y-m-d H:i:s"),self::COLUMN_DESCRIPTION => $present->getDescription(), self::COLUMN_IMAGEPATH => $present->getImagePath(), self::COLUMN_TITLE=>$present->getTitle(),self::COLUMN_LINKS=>$present->getLinks(),self::COLUMN_STATUS=>PRESENT_STATUS_NOTUSE)); + return $id; + } + + +} +?> \ No newline at end of file diff --git a/app/classes/dao/index.html b/app/classes/dao/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/classes/dao/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/classes/index.html b/app/classes/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/classes/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/classes/loader.php b/app/classes/loader.php new file mode 100644 index 0000000..556f803 --- /dev/null +++ b/app/classes/loader.php @@ -0,0 +1,17 @@ + \ No newline at end of file diff --git a/app/classes/model/errorModel.php b/app/classes/model/errorModel.php new file mode 100644 index 0000000..c7e0bdc --- /dev/null +++ b/app/classes/model/errorModel.php @@ -0,0 +1,35 @@ +errorFields = array(); + $this->errorFieldMessage = array(); + } + + public function addErrorField($field, $msg) { + $this->errorFields[] = $field; + $this->errorFieldMessage[$field] = $msg; + $this->isError = true; + } + + public function hasErrors($field) { + foreach ($this->errorFields as $key => $value) { + if($value == $field) { + return true; + } + } + return false; + } + + public function getMessage($field) { + return $this->errorFieldMessage[$field]; + } + + public function hasError(){ + return $this->isError ; + } + +} diff --git a/app/classes/model/index.html b/app/classes/model/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/classes/model/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/classes/model/presentModel.php b/app/classes/model/presentModel.php new file mode 100644 index 0000000..5b2cea2 --- /dev/null +++ b/app/classes/model/presentModel.php @@ -0,0 +1,100 @@ + id = $dic[PresentDao::COLUMN_ID]; + $this -> title = $dic[PresentDao::COLUMN_TITLE]; + $this -> imagePath = $dic[PresentDao::COLUMN_IMAGEPATH]; + $this -> description = $dic[PresentDao::COLUMN_DESCRIPTION]; + $this -> status = $dic[PresentDao::COLUMN_STATUS]; + $this -> code = $dic[PresentDao::COLUMN_CODE]; + $this -> links = unserialize($dic[PresentDao::COLUMN_LINKS]); + } + } + + public function getId() { + return $this -> id; + } + + public function getTitle() { + return $this -> title; + } + + public function getImagePath() { + return $this -> imagePath; + } + + public function getDescription() { + return $this -> description; + } + + public function getStatus() { + return $this -> status; + } + + public function getCode() { + return $this -> code; + } + + public function getLinks() { + return $this -> links; + } + + public function setId($id) { + $this -> id = $id; + } + + public function setTitle($title) { + $this -> title = $title; + } + + public function setImagePath($imagePath) { + $this -> imagePath = $imagePath; + } + + public function isImage() { + return filter_var( $this -> imagePath, FILTER_VALIDATE_URL); + } + + public function setDescription($description) { + $this -> description = $description; + } + + public function setCode($code) { + $this -> code = $code; + } + + public function setStatus($status) { + $this -> status = $status; + } + + public function setLinks($links) { + $this -> links = $links; + } + + public function __toString() { + return "ID:$this->id -- Titel: '$this->titel' -- Status: ' $this->status'"; + } + + public function getDetails() { + $ausgabe = '

' . $this -> getTitle() . '

+

' . $this -> getDescription() . ' +

'; + $split_result = split(';', $this -> getLinks()); + $out_link = ""; + foreach ($split_result as $link) { + $out_link .= '' . $link . '
'; + } + $ausgabe .= '

' . $out_link . '

'; + return $ausgabe; + } + +} diff --git a/app/classes/model/securityModel.php b/app/classes/model/securityModel.php new file mode 100644 index 0000000..464d87c --- /dev/null +++ b/app/classes/model/securityModel.php @@ -0,0 +1,42 @@ +signIn = $signIn; + $this->userName = $userName; + $this->roles = $roles; + $this->email = $email; + } + + function isSignIn() { + if($this->signIn != null) { + return $this->signIn; + } + return false; + } + + function getUserName() { + return $this->userName; + } + + function getRoles() { + return $this->roles; + } + + function getEmail() { + return $this->email; + } + +} diff --git a/app/classes/routeFactory.php b/app/classes/routeFactory.php new file mode 100644 index 0000000..9f6642a --- /dev/null +++ b/app/classes/routeFactory.php @@ -0,0 +1,92 @@ + "ControllerCreateEditPresent", + "admin/present/edit" => "ControllerCreateEditPresent", + "admin/present/delete" => "ControllerDeletePresent", + "admin/settings/maintenance" => "ControllerMaintenanceSettings", + "admin" => "ControllerAdminStartpage", + "admin/settings/all" => "ControllerSettings", + "user/create" => "ControllerCreateUser", + "user/profile" => "ControllerProfile", + ); + private $defaultController = array("present/waehlen" => "ControllerUsePresent", + "present/share" => "ControllerPresentShare", + "present/release" => "ControllerReleasePresent", + "present/view" => "ControllerPresentDetailView", + "register" => "ControllerRegister", + "resetpassword" => "ControllerResetPassword", + ); + private $security; + private $login; + + function __construct() { + $this->login = new $this->securityService(); + $this->security = $this->login->getSecurityModel(); + } + + function getController($getRequest, $postRequest, $jdbcTemplate) { + $mapping = $this->getMapping($getRequest); + $request = array("get" => $getRequest, "post" => $postRequest); + if ($mapping == 'login') { + return new ControllerLogin($request, $this->login, "admin"); + } else if ($mapping == 'logout') { + return new ControllerLogout($this->login); + } + $resultController = null; + if (!array_key_exists($mapping, $this->adminController)) { + $resultController = $this->getNoLoginController($request, $mapping, $jdbcTemplate); + } else { + // We've been requested to log in + if ($this->security->isSignIn()) { + $resultController = $this->getLoginController($request, $mapping, $jdbcTemplate); + } else { + $resultController = new ControllerLogin($request, $this->login, $mapping); + } + } + if ($resultController == null) { + throw new Exception(); + } + return $resultController; + } + + private function getMapping($getRequest) { + $mapping = ""; + if (isset($getRequest['mapping'])) { + $mapping = htmlspecialchars($getRequest['mapping']); + } else if (empty($mapping) && $this->security->isSignIn()) { + $mapping = "admin"; + } + return $mapping; + } + + private function getLoginController($request, $mapping, $jdbcTemplate) { + if (array_key_exists($mapping, $this->adminController)) { + return new $this->adminController[$mapping]($request, $jdbcTemplate, $this->login); + } else if ($mapping == "admin/settings/maintenance/active") { + return new ControllerMaintenanceSwitch($jdbcTemplate, 1); + } else if ($mapping == "admin/settings/maintenance/inactive") { + return new ControllerMaintenanceSwitch($jdbcTemplate, 0); + } + } + + private function getNoLoginController($request, $mapping, $jdbcTemplate) { + if (MAINTENANCE && !$this->security->isSignIn()) { + return new ControllerMaintenance($jdbcTemplate); + } else { + if (empty($mapping)) { + return new ControllerStartpage($request, $jdbcTemplate, $this->login); + } else if (array_key_exists($mapping, $this->defaultController)) { + return new $this->defaultController[$mapping]($request, $jdbcTemplate, $this->login); + } + } + } + +} diff --git a/app/classes/view/AjaxView.php b/app/classes/view/AjaxView.php new file mode 100644 index 0000000..e9fb228 --- /dev/null +++ b/app/classes/view/AjaxView.php @@ -0,0 +1,57 @@ + template = new TemplateResolver(AppFactory::getTemplateEngine($templatePath)); + } + + /** + * Ordnet eine Variable einem bestimmten Schlüssel zu. + * + * @param String $key Schlüssel + * @param String $value Variable + */ + function assign($variable, $value = null) { + if (is_array($variable)) + $this -> templateVar += $variable; + else + $this -> templateVar[$variable] = $value; + } + + /** + * Setzt den Namen des Templates. + * + * @param String $template Name des Templates. + */ + public function setTemplate($templatePage = 'content') { + $this -> templatePage = $templatePage; + } + + /** + * Das Template-File laden und zurückgeben + * + * @param string $tpl Der Name des Template-Files (falls es nicht vorher + * über steTemplate() zugewiesen wurde). + * @return string Der Output des Templates. + */ + public function loadTemplate() { + $contentTemplate = new TemplateContentResolver($this->template, "content", $this -> templatePage); + $contentTemplate -> assign($this -> templateVar); + $layout = new TemplateGenerateLayout($contentTemplate, "ajax"); + return $layout -> getHtml(); + } + +} +?> \ No newline at end of file diff --git a/app/classes/view/BackendView.php b/app/classes/view/BackendView.php new file mode 100644 index 0000000..880b5e3 --- /dev/null +++ b/app/classes/view/BackendView.php @@ -0,0 +1,77 @@ +template = new TemplateResolver(AppFactory::getTemplateEngine(TEMPLATE_PATH_BACKEND)); + $this->security = $security; + } + + /** + * Ordnet eine Variable einem bestimmten Schlüssel zu. + * + * @param String $key Schlüssel + * @param String $value Variable + */ + function assign($variable, $value = null) { + if (is_array($variable)) + $this->templateVar += $variable; + else + $this->templateVar[$variable] = $value; + } + + /** + * Setzt den Namen des Templates. + * + * @param String $template Name des Templates. + */ + public function setTemplate($templatePage = 'content') { + $this->templatePage = $templatePage; + } + + /** + * Das Template-File laden und zurückgeben + * + * @param string $tpl Der Name des Template-Files (falls es nicht vorher + * über steTemplate() zugewiesen wurde). + * @return string Der Output des Templates. + */ + public function loadTemplate() { + $messageResolver = AppFactory::getMessageResolver(); + $contentTemplate = new TemplateContentResolver($this->template, "content", $this->templatePage); + $contentTemplate->assign($this->templateVar); + $navTemplate = new TemplateNavigationResolver($contentTemplate, "navigation", "backend_navigation"); + $navTemplate->assign("navToggle", $messageResolver->getMessage("navigation_toggle")); + $navTemplate->assign("signin", $messageResolver->getMessage("navigation_signinas") . $this->security->getUserName()); + $navTemplate->assign("messageResolver", $messageResolver); + if ($this->security->isSignIn()) { + $navTemplate->addNavItem("?mapping=admin", $messageResolver->getMessage("navigation_home_admin")); + $navTemplate->addNavItem("?mapping=admin/present/create", $messageResolver->getMessage("navigation_createpresent")); + $navTemplate->addNavItem("?mapping=admin/settings/maintenance", $messageResolver->getMessage("navigation_maintenance_settings")); + $navTemplate->addNavItem("?mapping=admin/settings/all", $messageResolver->getMessage("navigation_settings")); + $navTemplate->addNavItem("?mapping=user/create", $messageResolver->getMessage("navigation_createuser")); + } else { + $navTemplate->addNavItem("?mapping=", $messageResolver->getMessage("navigation_frontend")); + } + $headerTemplate = new TemplateHeaderResolver($navTemplate, "header", "backend_header"); + $headerTemplate->setStartpageLink(APP_URL); + $headerTemplate->setSubtitle($messageResolver->getMessage("application_subtitle")); + $layout = new TemplateGenerateLayout($headerTemplate, "backendlayout"); + $layout->assign("messageResolver", $messageResolver); + return $layout->getHtml(); + } + +} + +?> \ No newline at end of file diff --git a/app/classes/view/FrontendView.php b/app/classes/view/FrontendView.php new file mode 100644 index 0000000..a5ec155 --- /dev/null +++ b/app/classes/view/FrontendView.php @@ -0,0 +1,68 @@ + template = new TemplateResolver(AppFactory::getTemplateEngine(TEMPLATE_PATH)); + } + + /** + * Ordnet eine Variable einem bestimmten Schlüssel zu. + * + * @param String $key Schlüssel + * @param String $value Variable + */ + function assign($variable, $value = null) { + if (is_array($variable)) + $this -> templateVar += $variable; + else + $this -> templateVar[$variable] = $value; + } + + /** + * Setzt den Namen des Templates. + * + * @param String $template Name des Templates. + */ + public function setTemplate($templatePage = 'content') { + $this -> templatePage = $templatePage; + } + + /** + * Das Template-File laden und zurückgeben + * + * @param string $tpl Der Name des Template-Files (falls es nicht vorher + * über steTemplate() zugewiesen wurde). + * @return string Der Output des Templates. + */ + public function loadTemplate() { + $messageResolver = AppFactory::getMessageResolver(); + $contentTemplate = new TemplateContentResolver($this->template, "content", $this -> templatePage); + $contentTemplate -> assign($this -> templateVar); + $navTemplate = new TemplateNavigationResolver($contentTemplate, "navigation", "navigation"); + $navTemplate -> assign("navToggle",$messageResolver->getMessage("navigation_toggle")); + $navTemplate -> addNavItem("?mapping=", $messageResolver->getMessage("navigation_home")); + $navTemplate -> addNavItem("?mapping=present/release", $messageResolver->getMessage("navigation_changepresent")); + $headerTemplate = new TemplateHeaderResolver($navTemplate, "header", "header"); + $headerTemplate -> setStartpageLink(APP_URL); + $headerTemplate -> setSubtitle($messageResolver->getMessage("application_subtitle")); + $layout = new TemplateGenerateLayout($headerTemplate, "layout"); + $layout->assign("footer",$messageResolver->getMessage("application_copyright")); + $layout->assign("administrationlink","?mapping=admin"); + $layout->assign("administrationlinktext",$messageResolver->getMessage("navigation_admin")); + return $layout -> getHtml(); + } + +} +?> \ No newline at end of file diff --git a/app/classes/view/LoginView.php b/app/classes/view/LoginView.php new file mode 100644 index 0000000..304dc43 --- /dev/null +++ b/app/classes/view/LoginView.php @@ -0,0 +1,60 @@ +template = new TemplateResolver(AppFactory::getTemplateEngine(TEMPLATE_PATH_BACKEND)); + $this->security = $security; + } + + /** + * Ordnet eine Variable einem bestimmten Schlüssel zu. + * + * @param String $key Schlüssel + * @param String $value Variable + */ + function assign($variable, $value = null) { + if (is_array($variable)) { + $this->templateVar += $variable; + } else { + $this->templateVar[$variable] = $value; + } + } + + /** + * Setzt den Namen des Templates. + * + * @param String $template Name des Templates. + */ + public function setTemplate($templatePage = 'content') { + $this->templatePage = $templatePage; + } + + /** + * Das Template-File laden und zurückgeben + * + * @param string $tpl Der Name des Template-Files (falls es nicht vorher + * über steTemplate() zugewiesen wurde). + * @return string Der Output des Templates. + */ + public function loadTemplate() { + $messageResolver = AppFactory::getMessageResolver(); + $contentTemplate = new TemplateContentResolver($this->template, "content", $this->templatePage); + $contentTemplate->assign($this->templateVar); + $layout = new TemplateGenerateLayout($contentTemplate, "loginlayout"); + $layout->assign("messageResolver", $messageResolver); + return $layout->getHtml(); + } + +} diff --git a/app/config/config.inc.php b/app/config/config.inc.php new file mode 100644 index 0000000..86e5c48 --- /dev/null +++ b/app/config/config.inc.php @@ -0,0 +1,37 @@ +getAll(); + +define("APP_URL", $config['conf_domain_url']); +define("APP_VERSION", $config['conf_version']); +define("APP_URL_URL", str_replace("://","",substr(APP_URL, stripos(APP_URL, "://")))); +define("APP_DOMAIN", substr(APP_URL_URL, 0,stripos(APP_URL_URL, "/"))); +define("PRESENT_EMAIL_REPLY", $config['conf_email_address']); +define("PRESENT_EMAIL_FROM", PRESENT_EMAIL_REPLY); +define("PRESENT_CODE_LENGTH_ADD", $config['conf_code_length']); +define("LOG_MODE", ''.$config['conf_log_mode'].''); +define("TEMPLATE_STYLE", ''.$config['conf_template'].''); +define("APP_ABBREVIATION", ''.$config['conf_app_abbreviation'].''); +define("APP_NAME", ''.$config['conf_app_name'].''); + +if($config['conf_debug'] === 'false') { + define("IS_DEBUG", false);//TODO DB Config +} else { + define("IS_DEBUG", true);//TODO DB Config +} +if($config['conf_maintenance_mode'] === 'false') { + define("MAINTENANCE", false);//DB Config +} else { + define("MAINTENANCE", true);//DB Config +} +define('UL_DEBUG', IS_DEBUG); \ No newline at end of file diff --git a/app/index.php b/app/index.php new file mode 100644 index 0000000..aa0d0e9 --- /dev/null +++ b/app/index.php @@ -0,0 +1,43 @@ +debug($_SESSION); + } else { + require_once('./lang/sec_de.php'); + } + $appDebugger->trace(); + $appLogger = AppFactory::getLogger(LOG_MODE); + // Controller erstellen + $route = new RouteFactory(); + $controller = $route->getController(@$_GET, @$_POST, $jdbcTemplate); + $controller->process(); + + echo $controller->display(); +} +?> \ No newline at end of file diff --git a/app/lang/index.html b/app/lang/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lang/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lang/lang_de.ini b/app/lang/lang_de.ini new file mode 100644 index 0000000..1e3a82a --- /dev/null +++ b/app/lang/lang_de.ini @@ -0,0 +1,188 @@ +[application] +subtitle = "Eine Geschenkeliste zum kommunizieren der Geschenke und koordieren der Geschenke zwischen Angehörigen, Freunden und Bekannten." +title = "Geschenkeliste" +copyright="Copyright Lightszentip © 2014." + +[navigation] +home="Übersicht der Geschenke" +home_admin="Übersicht der Geschenke (Admin)" +changepresent = "Geschenk abwählen" +admin="Administration" +toggle="Toggle navigation" +help="Hilfe" +createpresent="Geschenk erstellen" +logout="Logout" +maintenance_settings="Wartungsmodus" +settings="Einstellungen" +signinas="Eingeloggt als " +version="Version" +createuser="Benutzer erstellen" +frontend="Frontend" +profile="Profil" +passwordforgotten="Passwort vergessen" + +[usepresent] +image="Bild" +title="Titel" +status="Status" +panel_title="Geschenk _{0}_ ausgewählt" +panel_subtitle="Sie haben das folgende Geschenk ausgewählt. Bitte notieren Sie sich den Code _{0}_, da nur mit diesem Code das Geschenk wieder freigegeben werden kann:" +description="Beschreibung" +links="Links" +modal_title="Geschenk wählen" +modal_email="Email address (optional)" +modal_emailhelp="Das Angeben der Email Adresse ist optional und schickt den Geschenkcode und die Angaben zum Geschenk an angegebene Adresse." +modal_close="Abbrechen" +modal_useit="Ich nehme das Geschenk" +modal_placeholder="Email Adresse eingeben (optional)" +share_modal_title="Geschenk teilen" +share_modal_email_to="Email Adresse des Empfängers" +share_modal_name_to="Name des Empfängers" +share_modal_email_from="Email Adresse des Absenders" +share_modal_name_from="Name des Absenders" +share_modal_share="Teilen" +share_modal_close="Abrechen" +share_modal_placeholder_email="Email Adresse eingeben" +share_modal_placeholder_optional=" (optional)" +share_modal_placeholder_name="Name" +share_modal_content="Mitteilung" +share_success_title="Das Geschenk wurde erfolgreich geteilt" +share_success_text="Das Geschenk wurde geteilt." +share_success_close="Schließen" +share_modal_emailto_info="Es können mit ; mehrere Empfänger angegeben werden" + +[presenttable] +image="Bild" +title="Titel" +status="Status" +description="Beschreibung" +links="Links zum Geschenk bei Händlern oder Herstellern" +button_useit = "Geschenk wählen" +page_size="Wähle die Anzahl Elemente auf einer Seite" +status_select="Wähle einen Status" +reset_filters="Filter zurücksetzen" +share="Teilen" +button_details="Details" + +[maintenance] +form_button_save="Eingabe speichern" +form_label_content="Subtitle" +form_label_title="Title" +form_title="Wartungsmodus (aktivieren/deaktivieren/Ändern)" +link_active="Wartungsmodus aktivieren" +link_inactive="Wartungsmodus deaktivieren" +settings_save="Änderungen wurde gespeichert" +settings_off="Der Wartungsmodus wurde deaktiviert." +settings_on="Der Wartungsmodus wurde aktiviert." + +[email] +use_present_text="Hallo,\n das Geschenk _{0}_ wurde von dir reserviert. Unter _{2}_ kannst du dir es nochmal im Detail anschauen. Freigeben kannst du es wieder unter der Url _{1}_, falls du es doch nicht schenken möchtest. Solange du es nicht freigibts kann es kein anderer auswählen." +use_present_text_html="Hallo,
das Geschenk _{0}_ wurde von dir reserviert. Unter _{2}_ kannst du dir es nochmal im Detail anschauen. Freigeben kannst du es wieder unter der Url _{1}_, falls du es doch nicht schenken möchtest. Solange du es nicht freigibts kann es kein anderer auswählen.
" +use_present_salutation="Die " +use_present_subject=" Geschenkcode" +use_present_info="Solltest du weitere Fragen haben, wende dich bitte auf der Seite unter Kontakt an die Verantwortlichen Personen." +share_present_toName="Hallo" +share_present_info="Die " +share_present_subject=" _{0}_ möchte dich auf das Geschenk _{1}_ hinweisen" +share_present_text="_{0}_ möchte dich auf das Geschenk _{1}_ auf _{3}_ unter _{2}_ hinweisen." +share_present_text_html="_{0}_ möchte dich auf das Geschenk _{1}_ auf _{3}_ unter _{2}_ hinweisen." + +[releasepresent] +form_label_code="Geschenkcode" +form_help_code="Hier bitte den Code eingeben der Ihnen beim auswählen des Geschenkes generiert wurde" +form_title="Geschenk abwählen" +form_button="Weiter" +form_button_confirm="Bestätigen" +text_view="Wenn Sie das folgende Geschenk wieder freigeben möchten, bestätigen Sie es mit dem Klicken auf den Button" +present_release="Das Geschenk wurde freigeben und kann jetzt wieder von anderen ausgewählt werden" + +[error] +title="Fehler" +parameter_error="Die aufgerufene Seite ist ungültig. Bitte versuchen Sie erneut diese Seite über die Navigation oder einen Button aufzurufen und verwenden Sie bitte nicht den Zurück Button des Browsers" +empty_presentId="Kein gültiges Geschenk ausgewählt" +send_email="Beim versenden der Nachricht gab es einen Fehler. Daher konnte keine Nachricht versendet werden. Bitte wenden Sie sich an den Administrator der Seite." +notfound_present="Keine gültiges Geschenk gefunden" +update_present_db="Leider konnte das Geschenk nicht ausgewählt werden. Bitte wiederholen Sie den Vorgang und wenden Sie sich an den Administrator falls dieser Fehler erneut auftritt." +validate_email="Die eingebene Email Adresse ist nicht valide. Bitte wiederholen Sie den Vorgang mit einer gültigen Email Adresse." +empty_code="Keinen gültigen Code ausgewählt" +present_create_empty_title="Bitte geben Sie den Titel des Geschenkes an" +present_create_invalid_imagepath="Die angegeben Url für das Bild ist nicht valide" +present_create_db="Das Geschenk konnte nicht gespeichert werden" +login="Der Benutzername oder das Passwort ist falsch." +presentnotfound_or_notfree="Es wurde kein Present gefunden oder es wurde schon gewählt und kann nicht mehr editiert werden." +present_create_size_title="Der Titel ist zu lang. Maximal sind 50 Zeichen erlaubt." +present_create_size_description="Die Beschreibung ist zu lang. Maximal sind 1200 Zeichen erlaubt." +maintenance_settings_size_title="Der Titel ist zu lang. Maximal sind 50 Zeichen erlaubt." +maintenance_settings_size_content="Die Beschreibung ist zu lang. Maximal sind 255 Zeichen erlaubt." +maintenance_settings_db="Leider können die Einstellungen nicht gespeichert werden. Bitte wiederholen Sie den Vorgang und wenden Sie sich an den Administrator falls dieser Fehler erneut auftritt." +settings_logmode="Der eingegebene Log Mode Wert ist ungültig." +settings_template="Das eingegebene Template existiert nicht." +settings_url="Die Eingabe für die Url ist nicht valide." +settings_email="Die Eingabe für Email ist nicht valide." +share_emailto="Bitte geben Sie einen Empfänger an" +share_namefrom="Bitte geben Sie einen Absender an" +share_emailfrom="Bitte geben Sie einen Absender an" +share_presentId="Es gab ein Problem mit dem Geschenk, bitte lade die Seite neu und versuche es dann nochmal zu teilen." +settings_appname="Bitte geben Sie einen Applikationsname ein" +settings_appabbreviation="Bitte geben Sie eine Abkürzung für den Applikationsname ein" + +[createeditpresent] +form_title="Geschenk hinzufügen/ändern" +form_label_title="Title" +form_label_description="Beschreibung" +form_label_imagePath="Link zum Bild" +form_label_links="Links zum Geschenk oder zu Beispielen" +form_button_add_link="Weiterer Link" +form_button_remove_link="Link entfernen" +form_button_save="Geschenk speichern" + +[login] +title="Anmelden" +rememberme="Autologin aktiv" +button_signin = "Login" +username="Benutzername" +password="Passwort" + +[createuser] +title="Benutzer erstellen" +login_username +button_save="Speichern" +username="Benutzername" +password="Passwort" + +[adminpresenttable] +status_free="Frei" +status_choose="Gewählt" +create_present = "Das Geschenk _{0}_ wurde erstellt." +edit_present = "Das Geschenk _{0}_ wurde verändert." +delete_present="Das Geschenk _{0}_ wurde gelöscht." +delete_present_error="Das Geschenk _{0}_ konnte nicht gelöscht werden." +button_edit = "Geschenk editieren" +button_delete = "Geschenk löschen" +button_delete_yes = "Ja" +button_delete_no = "Nein" + +[settings] +form_label_domainurl="Anwendungsurl" +form_title="Einstellungen" +form_label_emailaddress="Email Adresse" +form_label_emailaddress_info="Email Adresse die als Absender für die Emails angegeben wird" +form_button_save="Speichern" +form_label_logmode="Log Level" +form_label_template="Frontend Template" +form_label_codelength="Key Länge" +form_label_codelength_info="Länge des Keys zum freigeben eines Geschenkes (der Key hat eine bestimmte Länge und wird nochmal um die hier angegebene Länge erweitert)" +form_label_appname="Applikationsname" +form_label_appabbreviations="Applikations Abkürzung" +save="Einstellungen wurden gespeichert" + +[backend] +maintenance_active="Der Wartungsmodus ist aktiv" +maintenance_text="Solange der Wartungsmodus aktiv ist können keine Geschenke ausgewählt oder freigegeben werden." + +[detailview] +panel_title="Detail Ansicht des Geschenkes" +title="Title" +description="Beschreibung" +image="Bild" +links="Links" \ No newline at end of file diff --git a/app/lang/sec_de.php b/app/lang/sec_de.php new file mode 100644 index 0000000..4ae7d03 --- /dev/null +++ b/app/lang/sec_de.php @@ -0,0 +1,83 @@ +isDebug = $isDebug; + if ($this->isDebug) { + Kint::enabled($this->isDebug); + } + } + + function debug($debugVar) { + $this->debugValue($debugVar, false); + } + + function getDebug($debugVar) { + return $this->debugValue($debugVar, true); + } + + function debugServer() { + $this->debugValue($_SERVER, false); + } + + function trace() { + if ($this->isDebug) { + Kint::trace(); + } + } + + private function debugValue($debugVar, $isReturn = false) { + if ($this->isDebug) { + if ($isReturn) { + @Kint::dump($debugVar); + } else { + Kint::dump($debugVar); + } + } + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/AppFactory.php b/app/lib/classes/AppFactory.php new file mode 100644 index 0000000..9fabc93 --- /dev/null +++ b/app/lib/classes/AppFactory.php @@ -0,0 +1,56 @@ + \ No newline at end of file diff --git a/app/lib/classes/AppJdbcTemplateMedooImpl.php b/app/lib/classes/AppJdbcTemplateMedooImpl.php new file mode 100644 index 0000000..f8a3eb6 --- /dev/null +++ b/app/lib/classes/AppJdbcTemplateMedooImpl.php @@ -0,0 +1,147 @@ +tablePrefix = $tablePrefix; + $this->databaseObject = new medoo(array( + // required + 'database_type' => $databaseConnectionModel->getType(), 'database_name' => $databaseConnectionModel->getDatabaseName(), 'server' => $databaseConnectionModel->getServer(), 'username' => $databaseConnectionModel->getUser(), 'password' => $databaseConnectionModel->getPassword(), + // optional + 'charset' => 'utf8', + // driver_option for connection, read more from http://www.php.net/manual/en/pdo.setattribute.php + 'option' => array(PDO::ATTR_CASE => PDO::CASE_NATURAL))); + } + + function insert($tableName, $keyValueArray) { + return $this->databaseObject->insert($this->tablePrefix . $tableName, $keyValueArray); + } + + function update($tableName, $keyValueArray, $whereKeyValueArray) { + return $this->databaseObject->update($this->tablePrefix . $tableName, $keyValueArray, $whereKeyValueArray); + } + + function delete($tableName, $whereKeyValueArray) { + return $this->databaseObject->delete($this->tablePrefix . $tableName, $whereKeyValueArray); + } + + function selectColumn($tableName, $columns, $order = null, $limit = -1) { + $result = null; + $whereKeyValueArray = $this->whereClause(array(), $order, $limit); + if (count($whereKeyValueArray) > 0) { + $result = $this->databaseObject->select($this->tablePrefix . $tableName, $columns, $whereKeyValueArray); + } else { + $result = $this->databaseObject->select($this->tablePrefix . $tableName, $columns); + } + return $result; + } + + function selectColumnJoin($tableName, $columns, $joins, $order = null, $limit = -1) { + $result = null; + if (is_array($joins) && count($joins) > 0) { + $whereKeyValueArray = $this->whereClause(array(), $order, $limit); + if (count($whereKeyValueArray) > 0) { + $result = $this->databaseObject->select($this->tablePrefix . $tableName, $joins, $columns, $whereKeyValueArray); + } else { + $result = $this->databaseObject->select($this->tablePrefix . $tableName, $joins, $columns); + } + } else { + $result = $this->selectColumn($this->tablePrefix . $tableName, $columns, $order, $limit); + } + return $result; + } + + function selectColumnConditions($tableName, $columns, $whereKeyValueArray, $joins = null, $order = null, $limit = -1) { + $result = null; + $whereKeyValueArray = $this->whereClause($whereKeyValueArray, $order, $limit); + if (is_array($joins) && count($joins) > 0) { + $result = $this->databaseObject->select($this->tablePrefix . $tableName, $joins, $columns, $whereKeyValueArray); + } else { + $result = $this->databaseObject->select($this->tablePrefix . $tableName, $columns, $whereKeyValueArray); + } + return $result; + } + + function selectMax($tableName, $column, $whereKeyValueArray = null) { + $result = null; + if (!empty($whereKeyValueArray)) { + $result = $this->databaseObject->max($this->tablePrefix . $tableName, $columns, $whereKeyValueArray); + } else { + $result = $this->databaseObject->max($this->tablePrefix . $tableName, $columns); + } + return $result; + } + + function selectMin($tableName, $column, $whereKeyValueArray = null) { + $result = null; + if (!empty($whereKeyValueArray)) { + $result = $this->databaseObject->min($this->tablePrefix . $tableName, $column, $whereKeyValueArray); + } else { + $result = $this->databaseObject->min($this->tablePrefix . $tableName, $column); + } + return $result; + } + + function selectCount($tableName, $whereKeyValueArray = null) { + $result = null; + if (!empty($whereKeyValueArray)) { + $result = $this->databaseObject->count($this->tablePrefix . $tableName, $whereKeyValueArray); + } else { + $result = $this->databaseObject->count($this->tablePrefix . $tableName); + } + return $result; + } + + function getByUnique($tableName, $columns, $whereKeyValueArray = null) { + $result = null; + if (!empty($whereKeyValueArray)) { + $result = $this->databaseObject->get($this->tablePrefix . $tableName, $columns, $whereKeyValueArray); + } else { + $result = $this->databaseObject->get($this->tablePrefix . $tableName, $columns); + } + return $result; + } + + function isTrue($tableName, $whereKeyValueArray) { + return $this->databaseObject->has($this->tablePrefix . $tableName, $whereKeyValueArray); + } + + private function whereClause($whereKeyValueArray, $order, $limit) { + if (!empty($order)) { + $whereKeyValueArray["ORDER"] = $order; + } + if (!empty($limit) && $limit != -1) { + $whereKeyValueArray["LIMIT"] = $order; + } + return $whereKeyValueArray; + } + + function leftJoin($joinTableName, $joinTableColumn, $tableColumn) { + return join("<", $joinTableName, $joinTableColumn, $tableColumn); + } + + function rightJoin($joinTableName, $joinTableColumn, $tableColumn) { + return join(">", $joinTableName, $joinTableColumn, $tableColumn); + } + + function fullJoin($joinTableName, $joinTableColumn, $tableColumn) { + return join("<>", $joinTableName, $joinTableColumn, $tableColumn); + } + + function innerJoin($joinTableName, $joinTableColumn, $tableColumn) { + return join("><", $joinTableName, $joinTableColumn, $tableColumn); + } + + private function join($sign, $joinTableName, $joinTableColumn, $tableColumn) { + return array("[" . $sign . "]" . $tableName => array($tableColumn => $joinTableColumn)); + } + +} diff --git a/app/lib/classes/AppLoggerKLoggerImpl.php b/app/lib/classes/AppLoggerKLoggerImpl.php new file mode 100644 index 0000000..7f726aa --- /dev/null +++ b/app/lib/classes/AppLoggerKLoggerImpl.php @@ -0,0 +1,78 @@ +log = KLogger::instance(dirname(__FILE__) . "/../log/", $levelNumber); + } + + function info($msg, $obj = null) { + if (is_null($obj)) { + $this->log->logInfo($msg); + } else { + $this->log->logInfo($msg, $obj); + } + } + + function warn($msg, $obj = null) { + if (is_null($obj)) { + $this->log->logWarn($msg); + } else { + $this->log->logWarn($msg, $obj); + } + } + + function error($msg, $obj = null) { + if (is_null($obj)) { + $this->log->logError($msg); + } else { + $this->log->logError($msg, $obj); + } + } + + function fatal($msg, $obj = null) { + if (is_null($obj)) { + $this->log->logCrit($msg); + } else { + $this->log->logCrit($msg, $obj); + } + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/AppMessageResolverI18nImpl.php b/app/lib/classes/AppMessageResolverI18nImpl.php new file mode 100644 index 0000000..84a2d18 --- /dev/null +++ b/app/lib/classes/AppMessageResolverI18nImpl.php @@ -0,0 +1,43 @@ +i18n = new i18n($langdir, $langcache, $langdefault); + $this->i18n->setPrefix($langprefix); + $this->i18n->setForcedLang($langdefault); + // force english, even if another user language is available + $this->i18n->setSectionSeperator('_'); + $this->i18n->init(); + } + + public function getMessage($key, $args = null) { + $message = constant("MessagesI18n::$key"); + if (!empty($args)) { + if (is_array($args)) { + $counter = 0; + foreach ($args as $key => $value) { + $message = str_replace('_{' . $counter . '}_', $value, $message); + $counter++; + } + } else { + $message = str_replace('_{0}_', $args, $message); + } + } + return $message; + } + +} + +?> diff --git a/app/lib/classes/AppTemplateEngineRainImpl.php b/app/lib/classes/AppTemplateEngineRainImpl.php new file mode 100644 index 0000000..0a01843 --- /dev/null +++ b/app/lib/classes/AppTemplateEngineRainImpl.php @@ -0,0 +1,42 @@ +templateEngine = new RainTPL; + $this->templatePath = $templatePath; + } + + public function generateHtml($templateLayoutPage, $vars, $fragementName, $outputHtml = false) { + $template = clone $this->templateEngine; + $template->assign($vars); + $file = $this->templatePath . $templateLayoutPage . '.html'; + if (file_exists($file)) { + // $html = $this -> templateEngine -> draw($templateLayoutPage, true); + $html = $template->draw($templateLayoutPage, true); + if ($outputHtml) { + return $html; + } else { + return array($fragementName => $html); + } + } else { + // Template-File existiert nicht-> Fehlermeldung. + if ($outputHtml) { + return ""; + } else { + return array($fragementName => ""); + } + } + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/Collection.php b/app/lib/classes/Collection.php new file mode 100644 index 0000000..b63d62b --- /dev/null +++ b/app/lib/classes/Collection.php @@ -0,0 +1,53 @@ +items[] = $obj; + } else { + if (isset($this->items[$key])) { + throw new KeyHasUseException("Key $key already in use."); + } else { + $this->items[$key] = $obj; + } + } + } + + public function deleteItem($key) { + if (isset($this->items[$key])) { + unset($this->items[$key]); + } else { + throw new KeyInvalidException("Invalid key $key."); + } + } + + public function getItem($key) { + if (isset($this->items[$key])) { + return $this->items[$key]; + } else { + throw new KeyInvalidException("Invalid key $key."); + } + } + + public function getItems() { + return $this->items; + } + + public function keys() { + return array_keys($this->items); + } + + public function length() { + return count($this->items); + } + + public function keyExists($key) { + return isset($this->items[$key]); + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/DatabaseConnectionModel.php b/app/lib/classes/DatabaseConnectionModel.php new file mode 100644 index 0000000..87f25d0 --- /dev/null +++ b/app/lib/classes/DatabaseConnectionModel.php @@ -0,0 +1,47 @@ +dbName = $databaseName; + $this->password = $databasePassword; + $this->server = $databaseServer; + $this->type = $databaseType; + $this->user = $databaseUser; + $this->port = $databasePort; + } + + public function getUser() { + return $this->user; + } + + public function getPassword() { + return $this->password; + } + + public function getType() { + return $this->type; + } + + public function getDatabaseName() { + return $this->dbName; + } + + public function getServer() { + return $this->server; + } + + public function getPort() { + return $this->port; + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/InterfaceAppDebugger.php b/app/lib/classes/InterfaceAppDebugger.php new file mode 100644 index 0000000..463f55a --- /dev/null +++ b/app/lib/classes/InterfaceAppDebugger.php @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/app/lib/classes/InterfaceAppLogger.php b/app/lib/classes/InterfaceAppLogger.php new file mode 100644 index 0000000..470a0ab --- /dev/null +++ b/app/lib/classes/InterfaceAppLogger.php @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/app/lib/classes/InterfaceController.php b/app/lib/classes/InterfaceController.php new file mode 100644 index 0000000..6d8bf0b --- /dev/null +++ b/app/lib/classes/InterfaceController.php @@ -0,0 +1,18 @@ + \ No newline at end of file diff --git a/app/lib/classes/InterfaceJdbcTemplate.php b/app/lib/classes/InterfaceJdbcTemplate.php new file mode 100644 index 0000000..8e956fc --- /dev/null +++ b/app/lib/classes/InterfaceJdbcTemplate.php @@ -0,0 +1,39 @@ + \ No newline at end of file diff --git a/app/lib/classes/InterfaceMessageResolver.php b/app/lib/classes/InterfaceMessageResolver.php new file mode 100644 index 0000000..780de44 --- /dev/null +++ b/app/lib/classes/InterfaceMessageResolver.php @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/app/lib/classes/InterfaceSecurity.php b/app/lib/classes/InterfaceSecurity.php new file mode 100644 index 0000000..4f27030 --- /dev/null +++ b/app/lib/classes/InterfaceSecurity.php @@ -0,0 +1,54 @@ + \ No newline at end of file diff --git a/app/lib/classes/MailTemplate.php b/app/lib/classes/MailTemplate.php new file mode 100644 index 0000000..cb4d9c6 --- /dev/null +++ b/app/lib/classes/MailTemplate.php @@ -0,0 +1,31 @@ +templateLayoutPage = $templateLayoutPage; + $this->templateEngine = $templateEngine; + } + + public function assign($variable, $value = null) { + if (is_array($variable)) + $this->vars += $variable; + else + $this->vars[$variable] = $value; + } + + public function assignArray($name, $value = null) { + $this->vars[$name][] = $value; + } + + public function getHtml() { + return $this->templateEngine->generateHtml($this->templateLayoutPage, $this->vars, null, true); + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/TemplateContentResolver.php b/app/lib/classes/TemplateContentResolver.php new file mode 100644 index 0000000..4d1ee3a --- /dev/null +++ b/app/lib/classes/TemplateContentResolver.php @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/app/lib/classes/TemplateDecorator.php b/app/lib/classes/TemplateDecorator.php new file mode 100644 index 0000000..1d57e8b --- /dev/null +++ b/app/lib/classes/TemplateDecorator.php @@ -0,0 +1,51 @@ +fragementName = $fragementName; + $this->templateLayoutPage = $templateLayoutPage; + $this->templateResolver = $templateResolver; + } + + /** + * get template vars + * @return array vars for template + */ + protected function getVars() { + return $this->vars; + } + + /** + * Set template vars + * @param type $variable key for the value or a array with values + * @param type $value value for the key (optional) + */ + public function assign($variable, $value = null) { + if (is_array($variable)) + $this->vars += $variable; + else + $this->vars[$variable] = $value; + } + + public function assignArray($name, $value = null) { + $this->vars[$name][] = $value; + } + + public function getTemplateEngine() { + return $this->templateResolver->getTemplateEngine(); + } + + public function getResult() { + return $this->templateResolver->getResult() + $this->getTemplateEngine()->generateHtml($this->templateLayoutPage, $this->vars, $this->fragementName); + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/TemplateGenerateLayout.php b/app/lib/classes/TemplateGenerateLayout.php new file mode 100644 index 0000000..a26227b --- /dev/null +++ b/app/lib/classes/TemplateGenerateLayout.php @@ -0,0 +1,32 @@ +templateLayoutPage = $templateLayoutPage; + $this->templateResolver = $templateResolver; + } + + public function assign($variable, $value = null) { + if (is_array($variable)) + $this->vars += $variable; + else + $this->vars[$variable] = $value; + } + + public function assignArray($name, $value = null) { + $this->vars[$name][] = $value; + } + + public function getHtml() { + return $this->templateResolver->getTemplateEngine()->generateHtml($this->templateLayoutPage, array_merge($this->vars, $this->templateResolver->getResult()), null, true); + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/TemplateHeaderResolver.php b/app/lib/classes/TemplateHeaderResolver.php new file mode 100644 index 0000000..2744686 --- /dev/null +++ b/app/lib/classes/TemplateHeaderResolver.php @@ -0,0 +1,17 @@ + $link, 'title' => $title, 'disable' => $disable)); + ; + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/TemplateResolver.php b/app/lib/classes/TemplateResolver.php new file mode 100644 index 0000000..57bed68 --- /dev/null +++ b/app/lib/classes/TemplateResolver.php @@ -0,0 +1,21 @@ +templateEngine = $templateEngine; + } + + public function getResult() { + return array(); + } + + public function getTemplateEngine() { + return $this->templateEngine; + } + +} + +?> \ No newline at end of file diff --git a/app/lib/classes/index.html b/app/lib/classes/index.html new file mode 100644 index 0000000..d53f7da --- /dev/null +++ b/app/lib/classes/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/escape.helper.php b/app/lib/escape.helper.php new file mode 100644 index 0000000..ed39640 --- /dev/null +++ b/app/lib/escape.helper.php @@ -0,0 +1,117 @@ + $value) { + $newValue[$key] = htmlentities((string) $value); + } + return $newValue; + } else { + return htmlentities((string) $variable); + } + default : + throw new Exception('Invalid escape target ' . $target); + } + } + +} + +?> \ No newline at end of file diff --git a/app/lib/i18n.class.php b/app/lib/i18n.class.php new file mode 100644 index 0000000..a05651c --- /dev/null +++ b/app/lib/i18n.class.php @@ -0,0 +1,287 @@ +filePath = $filePath; + } + + if ($cachePath != NULL) { + $this->cachePath = $cachePath; + } + + if ($fallbackLang != NULL) { + $this->fallbackLang = $fallbackLang; + } + + if ($prefix != NULL) { + $this->prefix = $prefix; + } + } + + public function init() { + if ($this->isInitialized()) { + throw new BadMethodCallException('This object from class ' . __CLASS__ . ' is already initialized. It is not possible to init one object twice!'); + } + + $this->isInitialized = true; + + $this->userLangs = $this->getUserLangs(); + + // search for language file + $this->appliedLang = NULL; + foreach ($this->userLangs as $priority => $langcode) { + $this->langFilePath = str_replace('{LANGUAGE}', $langcode, $this->filePath); + if (file_exists($this->langFilePath)) { + $this->appliedLang = $langcode; + break; + } + } + if ($this->appliedLang == NULL) { + throw new RuntimeException('No language file was found.'); + } + + // search for cache file + $this->cacheFilePath = $this->cachePath . '/php_i18n_' . md5_file(__FILE__) . '_' . $this->appliedLang . '.cache.php'; + + // if no cache file exists or if it is older than the language file create a new one + if (!file_exists($this->cacheFilePath) || filemtime($this->cacheFilePath) < filemtime($this->langFilePath)) { + switch ($this->get_file_extension()) { + case 'ini': + $config = parse_ini_file($this->langFilePath, true); + break; + case 'yml': + require_once 'vendor/spyc.php'; + $config = spyc_load_file($this->langFilePath); + break; + default: + throw new InvalidArgumentException($this->get_file_extension() . " is not a valid extension!"); + } + + $compiled = "prefix . " {\n"; + $compiled .= $this->compile($config); + $compiled .= '}'; + + file_put_contents($this->cacheFilePath, $compiled); + chmod($this->cacheFilePath, 0777); + + } + + require_once $this->cacheFilePath; + } + + public function isInitialized() { + return $this->isInitialized; + } + + public function getAppliedLang() { + return $this->appliedLang; + } + + public function getCachePath() { + return $this->cachePath; + } + + public function getFallbackLang() { + return $this->fallbackLang; + } + + public function setFilePath($filePath) { + $this->fail_after_init(); + $this->filePath = $filePath; + } + + public function setCachePath($cachePath) { + $this->fail_after_init(); + $this->cachePath = $cachePath; + } + + public function setFallbackLang($fallbackLang) { + $this->fail_after_init(); + $this->fallbackLang = $fallbackLang; + } + + public function setPrefix($prefix) { + $this->fail_after_init(); + $this->prefix = $prefix; + } + + public function setForcedLang($forcedLang) { + $this->fail_after_init(); + $this->forcedLang = $forcedLang; + } + + public function setSectionSeperator($sectionSeperator) { + $this->fail_after_init(); + $this->sectionSeperator = $sectionSeperator; + } + + /** + * getUserLangs() + * Returns the user languages + * Normally it returns an array like this: + * 1. Forced language + * 2. Language in $_GET['lang'] + * 3. Language in $_SESSION['lang'] + * 4. HTTP_ACCEPT_LANGUAGE + * 5. Fallback language + * Note: duplicate values are deleted. + * + * @return array with the user languages sorted by priority. + */ + public function getUserLangs() { + $userLangs = array(); + + // Highest priority: forced language + if ($this->forcedLang != NULL) { + $userLangs[] = $this->forcedLang; + } + + // 2nd highest priority: GET parameter 'lang' + if (isset($_GET['lang']) && is_string($_GET['lang'])) { + $userLangs[] = $_GET['lang']; + } + + // 3rd highest priority: SESSION parameter 'lang' + if (isset($_SESSION['lang']) && is_string($_SESSION['lang'])) { + $userLangs[] = $_SESSION['lang']; + } + + // 4th highest priority: HTTP_ACCEPT_LANGUAGE + if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { + foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $part) { + $userLangs[] = strtolower(substr($part, 0, 2)); + } + } + + // Lowest priority: fallback + $userLangs[] = $this->fallbackLang; + + // remove duplicate elements + $userLangs = array_unique($userLangs); + + foreach ($userLangs as $key => $value) { + $userLangs[$key] = preg_replace('/[^a-zA-Z0-9]/', '', $value); // only allow a-z, A-Z and 0-9 + } + + return $userLangs; + } + + + /** + * Recursively compile an associative array to PHP code. + */ + protected function compile($config, $prefix = '') { + $code = ''; + foreach ($config as $key => $value) { + if (is_array($value)) { + $code .= $this->compile($value, $prefix . $key . $this->sectionSeperator); + } else { + $code .= 'const ' . $prefix . $key . ' = \'' . str_replace('\'', '\\\'', $value) . "';\n"; + } + } + return $code; + } + + protected function get_file_extension() { + return substr(strrchr($this->langFilePath, '.'), 1); + } + + protected function fail_after_init() { + if ($this->isInitialized()) { + throw new BadMethodCallException('This ' . __CLASS__ . ' object is already initalized, so you can not change any settings.'); + } + } + +} diff --git a/app/lib/index.html b/app/lib/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lib/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/kLogger/KLogger.php b/app/lib/kLogger/KLogger.php new file mode 100644 index 0000000..ec48f75 --- /dev/null +++ b/app/lib/kLogger/KLogger.php @@ -0,0 +1,410 @@ +logInfo('Returned a million search results'); //Prints to the log file + * $log->logFatal('Oh dear.'); //Prints to the log file + * $log->logDebug('x = 5'); //Prints nothing due to current severity threshhold + * + * @author Kenny Katzgrau + * @since July 26, 2008 — Last update July 1, 2012 + * @link http://codefury.net + * @version 0.2.0 + */ + +/** + * Class documentation + */ +class KLogger +{ + /** + * Error severity, from low to high. From BSD syslog RFC, secion 4.1.1 + * @link http://www.faqs.org/rfcs/rfc3164.html + */ + const EMERG = 0; // Emergency: system is unusable + const ALERT = 1; // Alert: action must be taken immediately + const CRIT = 2; // Critical: critical conditions + const ERR = 3; // Error: error conditions + const WARN = 4; // Warning: warning conditions + const NOTICE = 5; // Notice: normal but significant condition + const INFO = 6; // Informational: informational messages + const DEBUG = 7; // Debug: debug messages + + //custom logging level + /** + * Log nothing at all + */ + const OFF = 8; + /** + * Alias for CRIT + * @deprecated + */ + const FATAL = 2; + + /** + * Internal status codes + */ + const STATUS_LOG_OPEN = 1; + const STATUS_OPEN_FAILED = 2; + const STATUS_LOG_CLOSED = 3; + + /** + * We need a default argument value in order to add the ability to easily + * print out objects etc. But we can't use NULL, 0, FALSE, etc, because those + * are often the values the developers will test for. So we'll make one up. + */ + const NO_ARGUMENTS = 'KLogger::NO_ARGUMENTS'; + + /** + * Current status of the log file + * @var integer + */ + private $_logStatus = self::STATUS_LOG_CLOSED; + /** + * Holds messages generated by the class + * @var array + */ + private $_messageQueue = array(); + /** + * Path to the log file + * @var string + */ + private $_logFilePath = null; + /** + * Current minimum logging threshold + * @var integer + */ + private $_severityThreshold = self::INFO; + /** + * This holds the file handle for this instance's log file + * @var resource + */ + private $_fileHandle = null; + + /** + * Standard messages produced by the class. Can be modified for il8n + * @var array + */ + private $_messages = array( + //'writefail' => 'The file exists, but could not be opened for writing. Check that appropriate permissions have been set.', + 'writefail' => 'The file could not be written to. Check that appropriate permissions have been set.', + 'opensuccess' => 'The log file was opened successfully.', + 'openfail' => 'The file could not be opened. Check permissions.', + ); + + /** + * Default severity of log messages, if not specified + * @var integer + */ + private static $_defaultSeverity = self::DEBUG; + /** + * Valid PHP date() format string for log timestamps + * @var string + */ + private static $_dateFormat = 'Y-m-d G:i:s'; + /** + * Octal notation for default permissions of the log file + * @var integer + */ + private static $_defaultPermissions = 0777; + /** + * Array of KLogger instances, part of Singleton pattern + * @var array + */ + private static $instances = array(); + + /** + * Partially implements the Singleton pattern. Each $logDirectory gets one + * instance. + * + * @param string $logDirectory File path to the logging directory + * @param integer $severity One of the pre-defined severity constants + * @return KLogger + */ + public static function instance($logDirectory = false, $severity = false) + { + if ($severity === false) { + $severity = self::$_defaultSeverity; + } + + if ($logDirectory === false) { + if (count(self::$instances) > 0) { + return current(self::$instances); + } else { + $logDirectory = dirname(__FILE__); + } + } + + if (in_array($logDirectory, self::$instances)) { + return self::$instances[$logDirectory]; + } + + self::$instances[$logDirectory] = new self($logDirectory, $severity); + + return self::$instances[$logDirectory]; + } + + /** + * Class constructor + * + * @param string $logDirectory File path to the logging directory + * @param integer $severity One of the pre-defined severity constants + * @return void + */ + public function __construct($logDirectory, $severity) + { + $logDirectory = rtrim($logDirectory, '\\/'); + + if ($severity === self::OFF) { + return; + } + + $this->_logFilePath = $logDirectory + . DIRECTORY_SEPARATOR + . 'log_' + . date('Y-m-d') + . '.txt'; + + $this->_severityThreshold = $severity; + if (!file_exists($logDirectory)) { + mkdir($logDirectory, self::$_defaultPermissions, true); + } + + if (file_exists($this->_logFilePath) && !is_writable($this->_logFilePath)) { + $this->_logStatus = self::STATUS_OPEN_FAILED; + $this->_messageQueue[] = $this->_messages['writefail']; + return; + } + + if (($this->_fileHandle = fopen($this->_logFilePath, 'a'))) { + $this->_logStatus = self::STATUS_LOG_OPEN; + $this->_messageQueue[] = $this->_messages['opensuccess']; + } else { + $this->_logStatus = self::STATUS_OPEN_FAILED; + $this->_messageQueue[] = $this->_messages['openfail']; + } + } + + /** + * Class destructor + */ + public function __destruct() + { + if ($this->_fileHandle) { + fclose($this->_fileHandle); + } + } + /** + * Writes a $line to the log with a severity level of DEBUG + * + * @param string $line Information to log + * @return void + */ + public function logDebug($line, $args = self::NO_ARGUMENTS) + { + $this->log($line, self::DEBUG); + } + + /** + * Returns (and removes) the last message from the queue. + * @return string + */ + public function getMessage() + { + return array_pop($this->_messageQueue); + } + + /** + * Returns the entire message queue (leaving it intact) + * @return array + */ + public function getMessages() + { + return $this->_messageQueue; + } + + /** + * Empties the message queue + * @return void + */ + public function clearMessages() + { + $this->_messageQueue = array(); + } + + /** + * Sets the date format used by all instances of KLogger + * + * @param string $dateFormat Valid format string for date() + */ + public static function setDateFormat($dateFormat) + { + self::$_dateFormat = $dateFormat; + } + + /** + * Writes a $line to the log with a severity level of INFO. Any information + * can be used here, or it could be used with E_STRICT errors + * + * @param string $line Information to log + * @return void + */ + public function logInfo($line, $args = self::NO_ARGUMENTS) + { + $this->log($line, self::INFO, $args); + } + + /** + * Writes a $line to the log with a severity level of NOTICE. Generally + * corresponds to E_STRICT, E_NOTICE, or E_USER_NOTICE errors + * + * @param string $line Information to log + * @return void + */ + public function logNotice($line, $args = self::NO_ARGUMENTS) + { + $this->log($line, self::NOTICE, $args); + } + + /** + * Writes a $line to the log with a severity level of WARN. Generally + * corresponds to E_WARNING, E_USER_WARNING, E_CORE_WARNING, or + * E_COMPILE_WARNING + * + * @param string $line Information to log + * @return void + */ + public function logWarn($line, $args = self::NO_ARGUMENTS) + { + $this->log($line, self::WARN, $args); + } + + /** + * Writes a $line to the log with a severity level of ERR. Most likely used + * with E_RECOVERABLE_ERROR + * + * @param string $line Information to log + * @return void + */ + public function logError($line, $args = self::NO_ARGUMENTS) + { + $this->log($line, self::ERR, $args); + } + + /** + * Writes a $line to the log with a severity level of FATAL. Generally + * corresponds to E_ERROR, E_USER_ERROR, E_CORE_ERROR, or E_COMPILE_ERROR + * + * @param string $line Information to log + * @return void + * @deprecated Use logCrit + */ + public function logFatal($line, $args = self::NO_ARGUMENTS) + { + $this->log($line, self::FATAL, $args); + } + + /** + * Writes a $line to the log with a severity level of ALERT. + * + * @param string $line Information to log + * @return void + */ + public function logAlert($line, $args = self::NO_ARGUMENTS) + { + $this->log($line, self::ALERT, $args); + } + + /** + * Writes a $line to the log with a severity level of CRIT. + * + * @param string $line Information to log + * @return void + */ + public function logCrit($line, $args = self::NO_ARGUMENTS) + { + $this->log($line, self::CRIT, $args); + } + + /** + * Writes a $line to the log with a severity level of EMERG. + * + * @param string $line Information to log + * @return void + */ + public function logEmerg($line, $args = self::NO_ARGUMENTS) + { + $this->log($line, self::EMERG, $args); + } + + /** + * Writes a $line to the log with the given severity + * + * @param string $line Text to add to the log + * @param integer $severity Severity level of log message (use constants) + */ + public function log($line, $severity, $args = self::NO_ARGUMENTS) + { + if ($this->_severityThreshold >= $severity) { + $status = $this->_getTimeLine($severity); + + $line = "$status $line"; + + if($args !== self::NO_ARGUMENTS) { + /* Print the passed object value */ + $line = $line . '; ' . var_export($args, true); + } + + $this->writeFreeFormLine($line . PHP_EOL); + } + } + + /** + * Writes a line to the log without prepending a status or timestamp + * + * @param string $line Line to write to the log + * @return void + */ + public function writeFreeFormLine($line) + { + if ($this->_logStatus == self::STATUS_LOG_OPEN + && $this->_severityThreshold != self::OFF) { + if (fwrite($this->_fileHandle, $line) === false) { + $this->_messageQueue[] = $this->_messages['writefail']; + } + } + } + + private function _getTimeLine($level) + { + $time = date(self::$_dateFormat); + + switch ($level) { + case self::EMERG: + return "$time - EMERG -->"; + case self::ALERT: + return "$time - ALERT -->"; + case self::CRIT: + return "$time - CRIT -->"; + case self::FATAL: # FATAL is an alias of CRIT + return "$time - FATAL -->"; + case self::NOTICE: + return "$time - NOTICE -->"; + case self::INFO: + return "$time - INFO -->"; + case self::WARN: + return "$time - WARN -->"; + case self::DEBUG: + return "$time - DEBUG -->"; + case self::ERR: + return "$time - ERROR -->"; + default: + return "$time - LOG -->"; + } + } +} diff --git a/app/lib/kLogger/index.html b/app/lib/kLogger/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lib/kLogger/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/kint/Kint.class.php b/app/lib/kint/Kint.class.php new file mode 100644 index 0000000..9541885 --- /dev/null +++ b/app/lib/kint/Kint.class.php @@ -0,0 +1,742 @@ + 0 ) { + self::$enabled = $value; + return; + } + + # ...and a getter + return self::$enabled; + } + + public static function _init() + { + # init settings + if ( isset( $GLOBALS['_kint_settings'] ) ) { + foreach ( $GLOBALS['_kint_settings'] as $key => $val ) { + self::$$key = $val; + } + } + + require KINT_DIR . 'decorators/rich.php'; + require KINT_DIR . 'decorators/concise.php'; + } + + /** + * Prints a debug backtrace + * + * @param array $trace [OPTIONAL] you can pass your own trace, otherwise, `debug_backtrace` will be called + * + * @return void + */ + public static function trace( $trace = null ) + { + if ( !Kint::enabled() ) return; + + echo Kint_Decorators_Rich::_css(); + + isset( $trace ) or $trace = debug_backtrace( true ); + + $output = array(); + foreach ( $trace as $step ) { + self::$traceCleanupCallback and $step = call_user_func( self::$traceCleanupCallback, $step ); + + # if the user defined trace cleanup function returns null, skip this line + if ( $step === null ) { + continue; + } + + if ( !isset( $step['function'] ) ) { + # invalid trace step + continue; + } + + if ( isset( $step['file'] ) AND isset( $step['line'] ) ) { + # include the source of this step + $source = self::_showSource( $step['file'], $step['line'] ); + } + + if ( isset( $step['file'] ) ) { + $file = $step['file']; + + if ( isset( $step['line'] ) ) { + $line = $step['line']; + } + } + + + $function = $step['function']; + + if ( in_array( $step['function'], self::$_statements ) ) { + if ( empty( $step['args'] ) ) { + # no arguments + $args = array(); + } else { + # sanitize the file path + $args = array( self::shortenPath( $step['args'][0] ) ); + } + } elseif ( isset( $step['args'] ) ) { + if ( empty( $step['class'] ) && !function_exists( $step['function'] ) ) { + # introspection on closures or language constructs in a stack trace is impossible before PHP 5.3 + $params = null; + } else { + try { + if ( isset( $step['class'] ) ) { + if ( method_exists( $step['class'], $step['function'] ) ) { + $reflection = new ReflectionMethod( $step['class'], $step['function'] ); + } else if ( isset( $step['type'] ) && $step['type'] == '::' ) { + $reflection = new ReflectionMethod( $step['class'], '__callStatic' ); + } else { + $reflection = new ReflectionMethod( $step['class'], '__call' ); + } + } else { + $reflection = new ReflectionFunction( $step['function'] ); + } + + # get the function parameters + $params = $reflection->getParameters(); + } catch ( Exception $e ) { + $params = null; # avoid various PHP version incompatibilities + } + } + + $args = array(); + foreach ( $step['args'] as $i => $arg ) { + if ( isset( $params[$i] ) ) { + # assign the argument by the parameter name + $args[$params[$i]->name] = $arg; + } else { + # assign the argument by number + $args[$i] = $arg; + } + } + } + + if ( isset( $step['class'] ) ) { + # Class->method() or Class::method() + $function = $step['class'] . $step['type'] . $step['function']; + } + + if ( isset( $step['object'] ) ) { + $function = $step['class'] . $step['type'] . $step['function']; + } + + $output[] = array( + 'function' => $function, + 'args' => isset( $args ) ? $args : null, + 'file' => isset( $file ) ? $file : null, + 'line' => isset( $line ) ? $line : null, + 'source' => isset( $source ) ? $source : null, + 'object' => isset( $step['object'] ) ? $step['object'] : null, + ); + + unset( $function, $args, $file, $line, $source ); + } + + require KINT_DIR . 'view/trace.phtml'; + } + + /** + * dump information about variables + * + * @param mixed $data + * + * @return void|string + */ + public static function dump( $data = null ) + { + if ( !Kint::enabled() ) return; + + # find caller information + $trace = debug_backtrace(); + list( $names, $modifier, $callee, $previousCaller ) = self::_getPassedNames( $trace ); + if ( $names === array( null ) && func_num_args() === 1 && $data === 1 ) { + $call = reset( $trace ); + if ( !isset( $call['file'] ) && isset( $call['class'] ) && $call['class'] === __CLASS__ ) { + array_shift( $trace ); + $call = reset( $trace ); + } + + while ( isset( $call['file'] ) && $call['file'] === __FILE__ ) { + array_shift( $trace ); + $call = reset( $trace ); + } + + self::trace( $trace ); + return; + } + + # process modifiers: @, + and - + switch ( $modifier ) { + case '-': + self::$_firstRun = true; + while ( ob_get_level() ) { + ob_end_clean(); + } + break; + + case '!': + self::$expandedByDefault = true; + break; + case '+': + $maxLevelsOldValue = self::$maxLevels; + self::$maxLevels = false; + break; + case '@': + $firstRunOldValue = self::$_firstRun; + self::$_firstRun = true; + break; + } + + + $data = func_num_args() === 0 + ? array( "[[no arguments passed]]" ) + : func_get_args(); + + + $output = Kint_Decorators_Rich::_css(); + $output .= Kint_Decorators_Rich::_wrapStart( $callee ); + + foreach ( $data as $k => $argument ) { + $output .= self::_dump( $argument, $names[$k] ); + } + $output .= Kint_Decorators_Rich::_wrapEnd( $callee, $previousCaller ); + + self::$_firstRun = false; + + switch ( $modifier ) { + case '+': + self::$maxLevels = $maxLevelsOldValue; + echo $output; + break; + case '@': + self::$_firstRun = $firstRunOldValue; + return $output; + break; + default: + echo $output; + break; + } + + return ''; + } + + protected static function _dump( $var, $name = '' ) + { + kintParser::reset(); + return Kint_Decorators_Rich::decorate( + kintParser::factory( $var, $name ) + ); + } + + + /** + * generic path display callback, can be configured in the settings + * + * @param string $file + * @param int $line [OPTIONAL] + * + * @return string + */ + public static function shortenPath( $file, $line = null ) + { + $file = str_replace( '\\', '/', $file ); + $shortenedName = $file; + foreach ( self::$appRootDirs as $path => $replaceString ) { + $path = str_replace( '\\', '/', $path ); + + if ( strpos( $file, $path ) === 0 ) { + $shortenedName = $replaceString . substr( $file, strlen( $path ) ); + break; + } + } + + + if ( !$line ) { # means this is called from resource type dump + return $shortenedName; + } + + if ( !self::$fileLinkFormat ) { + return "{$shortenedName} line {$line}"; + } + + $url = str_replace( array( '%f', '%l' ), array( $file, $line ), self::$fileLinkFormat ); + $class = ( strpos( $url, 'http://' ) === 0 ) ? 'class="kint-ide-link"' : ''; + + return "{$shortenedName} line {$line}"; + } + + + /** + * trace helper, shows the place in code inline + * + * @param string $file full path to file + * @param int $lineNumber the line to display + * @param int $padding surrounding lines to show besides the main one + * + * @return bool|string + */ + private static function _showSource( $file, $lineNumber, $padding = 7 ) + { + if ( !$file OR !is_readable( $file ) ) { + # continuing will cause errors + return false; + } + + # open the file and set the line position + $file = fopen( $file, 'r' ); + $line = 0; + + # Set the reading range + $range = array( + 'start' => $lineNumber - $padding, + 'end' => $lineNumber + $padding + ); + + # set the zero-padding amount for line numbers + $format = '% ' . strlen( $range['end'] ) . 'd'; + + $source = ''; + while ( ( $row = fgets( $file ) ) !== false ) { + # increment the line number + if ( ++$line > $range['end'] ) { + break; + } + + if ( $line >= $range['start'] ) { + # make the row safe for output + $row = htmlspecialchars( $row, ENT_NOQUOTES ); + + # trim whitespace and sanitize the row + $row = '' . sprintf( $format, $line ) . ' ' . $row; + + if ( $line === $lineNumber ) { + # apply highlighting to this row + $row = '
' . $row . '
'; + } else { + $row = '
' . $row . '
'; + } + + # add to the captured source + $source .= $row; + } + } + + # close the file + fclose( $file ); + + return $source; + } + + + /** + * returns parameter names that the function was passed, as well as any predefined symbols before function + * call (modifiers) + * + * @param array $trace + * + * @return array( $parameters, $modifier, $callee, $previousCaller ) + */ + private static function _getPassedNames( $trace ) + { + $previousCaller = array(); + while ( $callee = array_pop( $trace ) ) { + if ( strtolower( $callee['function'] ) === 'd' || + strtolower( $callee['function'] ) === 'dd' || + ( isset( $callee['class'] ) && strtolower( $callee['class'] ) === strtolower( __CLASS__ ) + && strtolower( $callee['function'] ) === 'dump' ) + ) { + break; + } else { + $previousCaller = $callee; + } + } + + if ( !isset( $callee['file'] ) || !is_readable( $callee['file'] ) ) { + return false; + } + + # open the file and read it up to the position where the function call expression ended + $file = fopen( $callee['file'], 'r' ); + $line = 0; + $source = ''; + while ( ( $row = fgets( $file ) ) !== false ) { + if ( ++$line > $callee['line'] ) break; + $source .= $row; + } + fclose( $file ); + $source = self::_removeAllButCode( $source ); + + + $codePattern = empty( $callee['class'] ) + ? $callee['function'] + : $callee['class'] . "\x07*" . $callee['type'] . "\x07*" . $callee['function']; + # get the position of the last call to the function + preg_match_all( "#[\x07{(](\\+|-|!|@)?{$codePattern}\x07*(\\()#i", $source, $matches, PREG_OFFSET_CAPTURE ); + $match = end( $matches[2] ); + $modifier = end( $matches[1] ); + $modifier = $modifier[0]; + + $passedParameters = str_replace( "\x07", '', substr( $source, $match[1] + 1 ) ); + # we now have a string like this: + # ); + + # remove everything in brackets and quotes, we don't need nested statements nor literal strings which would + # only complicate separating individual arguments + $c = strlen( $passedParameters ); + $inString = $escaped = false; + $i = 0; + $inBrackets = 0; + while ( $i < $c ) { + $letter = $passedParameters[$i]; + if ( $inString === false ) { + if ( $letter === '\'' || $letter === '"' ) { + $inString = $letter; + } elseif ( $letter === '(' ) { + $inBrackets++; + } elseif ( $letter === ')' ) { + $inBrackets--; + if ( $inBrackets === -1 ) { # this means we are out of the brackets that denote passed parameters + $passedParameters = substr( $passedParameters, 0, $i ); + break; + } + } + } elseif ( $letter === $inString && !$escaped ) { + $inString = false; + } + + # place an untype-able character instead of whatever was inside quotes or brackets, we don't + # need that info. We'll later replace it with '...' + if ( $inBrackets > 0 ) { + if ( $inBrackets > 1 || $letter !== '(' ) { + $passedParameters[$i] = "\x07"; + } + } + if ( $inString !== false ) { + if ( $letter !== $inString || $escaped ) { + $passedParameters[$i] = "\x07"; + } + } + + $escaped = !$escaped && ( $letter === '\\' ); + $i++; + } + + # by now we have an unnested arguments list, lets make it to an array for processing further + $arguments = explode( ',', preg_replace( "#\x07+#", '...', $passedParameters ) ); + + # test each argument whether it was passed literary or was it an expression or a variable name + $parameters = array(); + $blacklist = array( 'null', 'true', 'false', 'array(...)', 'array()', '"..."', 'b"..."', ); + foreach ( $arguments as $argument ) { + + if ( is_numeric( $argument ) + || in_array( str_replace( "'", '"', strtolower( $argument ) ), $blacklist, true ) + ) { + $parameters[] = null; + } else { + $parameters[] = trim( $argument ); + } + } + + return array( $parameters, $modifier, $callee, $previousCaller ); + } + + /** + * removes comments and zaps whitespace & true, T_INLINE_HTML => true, T_DOC_COMMENT => true ); + + defined( 'T_NS_SEPARATOR' ) or define( 'T_NS_SEPARATOR', 380 ); + + $whiteSpaceTokens = array( + T_WHITESPACE => true, T_CLOSE_TAG => true, + T_OPEN_TAG => true, T_OPEN_TAG_WITH_ECHO => true, + ); + + foreach ( $tokens as $token ) { + if ( is_array( $token ) ) { + if ( isset( $commentTokens[$token[0]] ) ) continue; + + if ( $token[0] === T_NEW ) { + $token = 'new '; + } elseif ( $token[0] === T_NS_SEPARATOR ) { + $token = "\\\x07"; + } elseif ( isset( $whiteSpaceTokens[$token[0]] ) ) { + $token = "\x07"; + } else { + $token = $token[1]; + } + } elseif ( $token === ';' ) { + $token = "\x07"; + } + + $newStr .= $token; + } + return $newStr; + } +} + + +if ( !function_exists( 'd' ) ) { + /** + * Alias of Kint::dump() + * + * @return string + */ + function d() + { + if ( !Kint::enabled() ) return null; + + $args = func_get_args(); + return call_user_func_array( array( 'Kint', 'dump' ), $args ); + } +} + +if ( !function_exists( 'dd' ) ) { + /** + * Alias of Kint::dump() + * [!!!] IMPORTANT: execution will halt after call to this function + * + * @return string + */ + function dd() + { + if ( !Kint::enabled() ) return; + + $args = func_get_args(); + call_user_func_array( array( 'Kint', 'dump' ), $args ); + die; + } +} + +if ( !function_exists( 's' ) ) { + + /** + * Alias of kintLite() + * + * @return string + */ + function s() + { + if ( !Kint::enabled() ) return; + + $argv = func_get_args(); + echo '
';
+		foreach ( $argv as $k => $v ) {
+			$k && print( "\n\n" );
+			echo kintLite( $v );
+		}
+		echo '
' . "\n"; + } + + /** + * Alias of kintLite() + * [!!!] IMPORTANT: execution will halt after call to this function + * + * @return string + */ + function sd() + { + if ( !Kint::enabled() ) return; + + echo '
';
+		foreach ( func_get_args() as $k => $v ) {
+			$k && print( "\n\n" );
+			echo kintLite( $v );
+		}
+		echo '
'; + die; + + } + +} + + +/** + * lightweight version of Kint::dump(). Uses whitespace for formatting instead of html + * sadly not DRY yet + * + * @param $var + * @param int $level + * + * @return string + */ +function kintLite( &$var, $level = 0 ) +{ + + // initialize function names into variables for prettier string output (html and implode are also DRY) + $html = "htmlspecialchars"; + $implode = "implode"; + $strlen = "strlen"; + $count = "count"; + $getClass = "get_class"; + + + if ( $var === null ) { + return 'NULL'; + } elseif ( is_bool( $var ) ) { + return 'bool ' . ( $var ? 'TRUE' : 'FALSE' ); + } elseif ( is_float( $var ) ) { + return 'float ' . $var; + } elseif ( is_int( $var ) ) { + return 'integer ' . $var; + } elseif ( is_resource( $var ) ) { + if ( ( $type = get_resource_type( $var ) ) === 'stream' AND $meta = stream_get_meta_data( $var ) ) { + + if ( isset( $meta['uri'] ) ) { + $file = $meta['uri']; + + return "resource ({$type}) {$html( $file, 0 )}"; + } else { + return "resource ({$type})"; + } + } else { + return "resource ({$type})"; + } + } elseif ( is_string( $var ) ) { + return "string ({$strlen( $var )}) \"{$html( $var )}\""; + } elseif ( is_array( $var ) ) { + $output = array(); + $space = str_repeat( $s = ' ', $level ); + + static $marker; + + if ( $marker === null ) { + // Make a unique marker + $marker = uniqid( "\x00" ); + } + + if ( empty( $var ) ) { + return "array()"; + } elseif ( isset( $var[$marker] ) ) { + $output[] = "[\n$space$s*RECURSION*\n$space]"; + } elseif ( $level < 7 ) { + $isSeq = array_keys( $var ) === range( 0, count( $var ) - 1 ); + + $output[] = "["; + + $var[$marker] = true; + + + foreach ( $var as $key => &$val ) { + if ( $key === $marker ) continue; + + $key = $space . $s . ( $isSeq ? "" : "'{$html( $key, 0 )}' => " ); + + $dump = kintLite( $val, $level + 1 ); + $output[] = "{$key}{$dump}"; + } + + unset( $var[$marker] ); + $output[] = "$space]"; + + } else { + $output[] = "[\n$space$s*depth too great*\n$space]"; + } + return "array({$count( $var )}) {$implode( "\n", $output )}"; + } elseif ( is_object( $var ) ) { + if ( $var instanceof SplFileInfo ) { + return "object SplFileInfo " . $var->getRealPath(); + } + + // Copy the object as an array + $array = (array)$var; + + $output = array(); + $space = str_repeat( $s = ' ', $level ); + + $hash = spl_object_hash( $var ); + + // Objects that are being dumped + static $objects = array(); + + if ( empty( $array ) ) { + return "object {$getClass( $var )} {}"; + } elseif ( isset( $objects[$hash] ) ) { + $output[] = "{\n$space$s*RECURSION*\n$space}"; + } elseif ( $level < 7 ) { + $output[] = "{"; + $objects[$hash] = true; + + foreach ( $array as $key => & $val ) { + if ( $key[0] === "\x00" ) { + + $access = $key[1] === "*" ? "protected" : "private"; + + // Remove the access level from the variable name + $key = substr( $key, strrpos( $key, "\x00" ) + 1 ); + } else { + $access = "public"; + } + + $output[] = "$space$s$access $key -> " . kintLite( $val, $level + 1 ); + } + unset( $objects[$hash] ); + $output[] = "$space}"; + + } else { + $output[] = "{\n$space$s*depth too great*\n$space}"; + } + + return "object {$getClass( $var )} ({$count( $array )}) {$implode( "\n", $output )}"; + } else { + return gettype( $var ) . htmlspecialchars( var_export( $var, true ), ENT_NOQUOTES ); + } +} + +Kint::_init(); diff --git a/app/lib/kint/LICENCE b/app/lib/kint/LICENCE new file mode 100644 index 0000000..936fe1f --- /dev/null +++ b/app/lib/kint/LICENCE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Rokas Šleinius (raveren@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/app/lib/kint/composer.json b/app/lib/kint/composer.json new file mode 100644 index 0000000..cbed1f5 --- /dev/null +++ b/app/lib/kint/composer.json @@ -0,0 +1,24 @@ +{ + "name": "raveren/kint", + "description": "Kint - debugging helper for PHP developers", + "keywords": ["kint", "php", "debug"], + "type": "library", + "homepage": "https://github.com/raveren/kint", + "license": "MIT", + "authors": [ + { + "name": "Rokas Šleinius", + "homepage": "https://github.com/raveren" + }, + { + "name": "Contributors", + "homepage": "https://github.com/raveren/kint/contributors" + } + ], + "require": { + "php": ">=5.2.0" + }, + "autoload": { + "files": ["Kint.class.php"] + } +} \ No newline at end of file diff --git a/app/lib/kint/config.default.php b/app/lib/kint/config.default.php new file mode 100644 index 0000000..6be4a50 --- /dev/null +++ b/app/lib/kint/config.default.php @@ -0,0 +1,130 @@ + '<ROOT>' ) + * + * [!] EXAMPLE (for Kohana framework): + * + * $_kintSettings['appRootDirs'] = array( + * APPPATH => 'APPPATH', // make sure the constants are already defined at the time of including this config file + * SYSPATH => 'SYSPATH', + * MODPATH => 'MODPATH', + * DOCROOT => 'DOCROOT', + * ); + * + * [!] EXAMPLE #2 (for a semi-universal approach) + * + * $_kintSettings['appRootDirs'] = array( + * realpath( __DIR__ . '/../../..' ) => 'ROOT', // go up as many levels as needed in the realpath() param + * ); + * + * $_kintSettings['fileLinkFormat'] = 'http://localhost:8091/?message=%f:%l'; + * + */ +$_kintSettings['appRootDirs'] = array( + $_SERVER['DOCUMENT_ROOT'] => '../../../;' +); + + +/** + * @var callable|null + * + * @param array $step each step of the backtrace is passed to this callback to clean it up or skip it entirely + * + * @return array|null you can return null if you want to bypass outputting this step + * + * [!] EXAMPLE: + * + * $_kintSettings['traceCleanupCallback'] = function( $traceStep ) { + * if ( isset( $traceStep['class'] ) && strtolower( $traceStep['class'] ) === 'errorHandler' ) { + * return null; + * } + * + * if ( isset( $traceStep['function'] ) && strtolower( $traceStep['function'] ) === '__tostring' ) { + * $traceStep['function'] = "[object converted to string]"; + * } + * + * return $traceStep; + * }; + */ +$_kintSettings['traceCleanupCallback'] = null; + + +/** @var int max length of string before it is truncated and displayed separately in full. Zero or false to disable */ +$_kintSettings['maxStrLength'] = 60; + +/** @var array possible alternative char encodings in order of probability, eg. array('windows-1251') */ +$_kintSettings['charEncodings'] = array(); + + +/** @var int max array/object levels to go deep, if zero no limits are applied */ +$_kintSettings['maxLevels'] = 5; + + +/** @var bool whether dumped indexed arrays that are in ideal sequence are displayed */ +$_kintSettings['hideSequentialKeys'] = true; + + +/** @var string name of theme for rich view */ +$_kintSettings['theme'] = 'original'; + + +/** + * @var callback filters array/object keys before outputting; return false if you do not wish to see it in the output + * + * @param string $key the key being output + * @param mixed $val the contents of the dumped element in case you need it + * + * @return bool return false to skip displaying + * + * [!] EXAMPLE: + * + * $_kintSettings['keyFilterCallback'] = function( $key, $val ) { + * if ( preg_match( '#_mt$#', $key ) ) { + * return false; + * } + * + * if ( $val === '--testing--' ) { + * return false; + * } + * + * // no need to return true to continue output + * }; + * + */ +$_kintSettings['keyFilterCallback'] = null; + + +/** @var bool only set to true if you want to develop kint and know what you're doing */ +$_kintSettings['devel'] = false; + + +unset( $_kintSettings ); \ No newline at end of file diff --git a/app/lib/kint/decorators/concise.php b/app/lib/kint/decorators/concise.php new file mode 100644 index 0000000..4385845 --- /dev/null +++ b/app/lib/kint/decorators/concise.php @@ -0,0 +1,58 @@ +extendedValue + * + * @param kintVariableData $kintVar + * + * @return string + */ + public static function decorate( kintVariableData $kintVar ) + { + if ( $kintVar->extendedValue !== null || !empty( $kintVar->alternatives ) ) { + return Kint_Decorators_Rich::decorate( $kintVar ); + } + + if ( $kintVar->value !== null ) { + $output = 'name !== null ) { + $output .= $kintVar->name . " "; + } + + if ( $kintVar->type !== null ) { + $output .= $kintVar->type; + if ( $kintVar->subtype !== null ) { + $output .= " " . $kintVar->subtype; + } + $output .= " "; + } + + if ( $kintVar->operator !== null ) { + $output .= $kintVar->operator . ""; + } + + if ( $kintVar->size !== null ) { + $output .= "(" . $kintVar->size . ") "; + } + + $output = trim( $output ) . '">' . $kintVar->value . ''; + } else { + $output = 'NULL'; + } + + return $output; + } +} \ No newline at end of file diff --git a/app/lib/kint/decorators/plain.php b/app/lib/kint/decorators/plain.php new file mode 100644 index 0000000..203e60c --- /dev/null +++ b/app/lib/kint/decorators/plain.php @@ -0,0 +1,54 @@ +'; + + $extendedPresent = $kintVar->extendedValue !== null || $kintVar->alternatives !== null; + + if ( $extendedPresent ) { + $class = 'kint-parent'; + if ( Kint::$expandedByDefault ) { + $class .= ' kint-show'; + } + $output .= '
'; + } else { + $output .= '
'; + } + + $output .= self::_drawHeader( $kintVar ) . $kintVar->value . '
'; + + + if ( $extendedPresent ) { + $output .= '
'; + } + + if ( isset( $kintVar->extendedValue ) ) { + + if ( is_array( $kintVar->extendedValue ) ) { + foreach ( $kintVar->extendedValue as $v ) { + $output .= self::decorate( $v ); + } + } elseif ( is_string( $kintVar->extendedValue ) ) { + $output .= '
' . $kintVar->extendedValue . '
'; + } else { + $output .= self::decorate( $kintVar->extendedValue ); //it's kint's container + } + + } elseif ( isset( $kintVar->alternatives ) ) { + $output .= "
    "; + + foreach ( $kintVar->alternatives as $k => $var ) { + $active = $k === 0 ? ' class="kint-active-tab"' : ''; + $output .= "" . self::_drawHeader( $var, false ) . ''; + } + + $output .= "
    "; + + foreach ( $kintVar->alternatives as $var ) { + $output .= "
  • "; + + $var = $var->value; + + if ( is_array( $var ) ) { + foreach ( $var as $v ) { + $output .= self::decorate( $v ); + } + } elseif ( is_string( $var ) ) { + $output .= '
    ' . $var . '
    '; + } elseif ( isset( $var ) ) { + throw new Exception( + 'Kint has encountered an error, ' + . 'please paste this report to https://github.com/raveren/kint/issues
    ' + . 'Error encountered at ' . basename( __FILE__ ) . ':' . __LINE__ . '
    ' + . ' variables: ' + . htmlspecialchars( var_export( $kintVar->alternatives, true ), ENT_QUOTES ) + ); + } + + $output .= "
  • "; + } + + $output .= "
"; + } + if ( $extendedPresent ) { + $output .= '
'; + } + + $output .= ''; + + return $output; + } + + private static function _drawHeader( kintVariableData $kintVar, $verbose = true ) + { + $output = ''; + if ( $verbose ) { + if ( $kintVar->access !== null ) { + $output .= "" . $kintVar->access . " "; + } + + if ( $kintVar->name !== null && $kintVar->name !== '' ) { + $output .= "" . $kintVar->name . " "; + } + + if ( $kintVar->operator !== null ) { + $output .= $kintVar->operator . " "; + } + } + + if ( $kintVar->type !== null ) { + $output .= "" . $kintVar->type; + if ( $kintVar->subtype !== null ) { + $output .= " " . $kintVar->subtype; + } + $output .= " "; + } + + + if ( $kintVar->size !== null ) { + $output .= "(" . $kintVar->size . ") "; + } + + return $output; + } + + + /** + * produces css and js required for display. May be called multiple times, will only produce output once per + * pageload or until `-` or `@` modifier is used + * + * @return string + */ + protected static function _css() + { + if ( !self::$_firstRun ) return ''; + self::$_firstRun = false; + + $baseDir = KINT_DIR . 'view/inc/'; + + if ( !is_readable( $cssFile = $baseDir . self::$theme . '.css' ) ) { + $cssFile = $baseDir . 'original.css'; + } + + return '' + . '\n"; + } + + + /** + * called for each dump, opens the html tag + * + * @param array $callee caller information taken from debug backtrace + * + * @return string + */ + protected static function _wrapStart( $callee ) + { + // colors looping outputs the same (i.e. if same line in code dumps variables multiple time, + // we assume it's in a loop) + + $uid = isset( $callee['file'] ) ? crc32( $callee['file'] . $callee['line'] ) : 'no-file'; + + if ( isset( self::$_usedColors[$uid] ) ) { + $class = self::$_usedColors[$uid]; + } else { + $class = sizeof( self::$_usedColors ); + self::$_usedColors[$uid] = $class; + } + + $class = "kint_{$class}"; + + + return "
"; + } + + + /** + * closes Kint::_wrapStart() started html tags and displays callee information + * + * @param array $callee caller information taken from debug backtrace + * @param array $prevCaller previous caller information taken from debug backtrace + * + * @return string + */ + protected static function _wrapEnd( $callee, $prevCaller ) + { + if ( !Kint::$displayCalledFrom ) { + return '
'; + } + + $callingFunction = ''; + if ( isset( $prevCaller['class'] ) ) { + $callingFunction = $prevCaller['class']; + } + if ( isset( $prevCaller['type'] ) ) { + $callingFunction .= $prevCaller['type']; + } + if ( isset( $prevCaller['function'] ) && !in_array( $prevCaller['function'], Kint::$_statements ) ) { + $callingFunction .= $prevCaller['function'] . '()'; + } + $callingFunction and $callingFunction = " in ({$callingFunction})"; + + + $calleeInfo = isset( $callee['file'] ) + ? 'Called from ' . self::shortenPath( $callee['file'], $callee['line'] ) + : ''; + + + return $calleeInfo || $callingFunction + ? "
{$calleeInfo}{$callingFunction}
" + : ""; + } + +} \ No newline at end of file diff --git a/app/lib/kint/index.html b/app/lib/kint/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lib/kint/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/arrayobject.php b/app/lib/kint/parsers/custom/arrayobject.php new file mode 100644 index 0000000..4c15e29 --- /dev/null +++ b/app/lib/kint/parsers/custom/arrayobject.php @@ -0,0 +1,26 @@ +getParentClass(); + + if ( $parentClass !== false && $parentClass->name === 'ArrayObject' ) { + $arrayCopy = $variable->getArrayCopy(); + foreach ( $arrayCopy as $k => $var ) { + $t = kintParser::factory( $var ); + $t->name = "'{$k}'"; + $t->operator = '=>'; + $this->value[] = $t; + } + + $this->type = 'ArrayObject contents'; + $this->size = count( $arrayCopy ); + } else { + return false; + } + } +} diff --git a/app/lib/kint/parsers/custom/classmethods.php b/app/lib/kint/parsers/custom/classmethods.php new file mode 100644 index 0000000..58c7f4c --- /dev/null +++ b/app/lib/kint/parsers/custom/classmethods.php @@ -0,0 +1,151 @@ +getMethods() as $method) { + $params = array(); + + // Access type + $access = implode(' ', \Reflection::getModifierNames($method->getModifiers())); + + // Method parameters + foreach($method->getParameters() as $param) { + $paramString = ''; + + if ( $param->isArray() ) { + $paramString .= 'array '; + } else { + try { + if (( $paramClassName = $param->getClass() )) { + $paramString .= $paramClassName->name . ' '; + } + } catch ( ReflectionException $e ) { + preg_match( '/\[\s\<\w+?>\s([\w]+)/s', $param->__toString(), $matches ); + $paramClassName = isset( $matches[1] ) ? $matches[1] : ''; + + $paramString .= ' UNDEFINED CLASS (' . $paramClassName . ') '; + } + } + + $paramString .= ($param->isPassedByReference() ? '&' : '') . '$' . $param->getName(); + + if($param->isDefaultValueAvailable()) { + if(is_array($param->getDefaultValue())) { + $arrayValues = array(); + foreach($param->getDefaultValue() as $key => $value) { + $arrayValues[] = $key . ' => ' . $value; + } + + $defaultValue = 'array(' . implode(', ', $arrayValues) . ')'; + } elseif($param->getDefaultValue() === null){ + $defaultValue = 'NULL'; + } elseif($param->getDefaultValue() === false){ + $defaultValue = 'false'; + } elseif($param->getDefaultValue() === true){ + $defaultValue = 'true'; + } elseif($param->getDefaultValue() === ''){ + $defaultValue = '""'; + } else { + $defaultValue = $param->getDefaultValue(); + } + + $paramString .= ' = ' . $defaultValue; + } + + $params[] = $paramString; + } + + $output = new \kintVariableData(); + + // Simple DocBlock parser, look for @return + if(($docBlock = $method->getDocComment())) { + $matches = array(); + if(preg_match_all('/@(\w+)\s+(.*)\r?\n/m', $docBlock, $matches)) { + $lines = array_combine($matches[1], $matches[2]); + if(isset($lines['return'])) { + $output->operator = '->'; + # since we're outputting code, assumption that the string is utf8 is most likely correct + # and saves resources + $output->type = self::_escape( $lines['return'], 'UTF-8' ); + } + } + } + + $output->name = ($method->returnsReference() ? '&' : '') . $method->getName() . '(' + . implode(', ', $params) . ')'; + $output->access = $access; + + if(is_string($docBlock)) { + $lines = array(); + foreach(explode("\n", $docBlock) as $line) { + $line = trim($line); + + if(in_array($line, array('/**', '/*', '*/'))) { + continue; + }elseif(strpos($line, '*') === 0) { + $line = substr($line, 1); + } + + $lines[] = self::_escape( trim( $line ), 'UTF-8' ); + } + + $output->extendedValue = implode("\n", $lines) . "\n\n"; + } + + $declaringClass = $method->getDeclaringClass(); + $declaringClassName = $declaringClass->getName(); + + if($declaringClassName !== $className) { + $output->extendedValue .= "Inherited from {$declaringClassName}\n"; + } + + $fileName = \Kint::shortenPath($method->getFileName(), $method->getStartLine()); + + if($fileName) { + $output->extendedValue .= "Defined in {$fileName}"; + } + + $sortName = $access . $method->getName(); + + if($method->isPrivate()) { + $private[$sortName] = $output; + } elseif($method->isProtected()) { + $protected[$sortName] = $output; + } else { + $public[$sortName] = $output; + } + } + + if(!$private && !$protected && !$public) { + self::$cache[$className] = false; + } + + ksort($public); + ksort($protected); + ksort($private); + + self::$cache[$className] = $public + $protected + $private; + } + + $this->value = self::$cache[$className]; + $this->type = 'Available methods'; + $this->size = count(self::$cache[$className]); + } +} \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/classstatics.php b/app/lib/kint/parsers/custom/classstatics.php new file mode 100644 index 0000000..1c6d0e4 --- /dev/null +++ b/app/lib/kint/parsers/custom/classstatics.php @@ -0,0 +1,54 @@ +getProperties( ReflectionProperty::IS_STATIC ) as $property ) { + if ( $property->isPrivate() ) { + if ( !method_exists( $property, 'setAccessible' ) ) { + break; + } + $property->setAccessible( true ); + $access = "private"; + } elseif ( $property->isProtected() ) { + $property->setAccessible( true ); + $access = "protected"; + } else { + $access = 'public'; + } + + if ( Kint::$keyFilterCallback + && call_user_func( Kint::$keyFilterCallback, $property->getName(), $property->getValue() ) === false + ) { + continue; + } + + $_ = $property->getValue(); + $output = kintParser::factory( $_, '$' . $property->getName() ); + + $output->access = $access; + $output->operator = '::'; + $extendedValue[] = $output; + } + + foreach ( $reflection->getConstants() as $constant => $val ) { + $output = kintParser::factory( $val, $constant ); + + $output->access = 'constant'; + $output->operator = '::'; + $extendedValue[] = $output; + } + + if ( empty( $extendedValue ) ) return false; + + $this->value = $extendedValue; + $this->type = 'Static class properties'; + $this->size = count( $extendedValue ); + } +} \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/color.php b/app/lib/kint/parsers/custom/color.php new file mode 100644 index 0000000..21d1f39 --- /dev/null +++ b/app/lib/kint/parsers/custom/color.php @@ -0,0 +1,400 @@ +'#f0f8ff','antiquewhite'=>'#faebd7','aqua'=>'#00ffff','aquamarine'=>'#7fffd4','azure'=>'#f0ffff', + 'beige'=>'#f5f5dc','bisque'=>'#ffe4c4','black'=>'#000000','blanchedalmond'=>'#ffebcd','blue'=>'#0000ff', + 'blueviolet'=>'#8a2be2','brown'=>'#a52a2a','burlywood'=>'#deb887','cadetblue'=>'#5f9ea0','chartreuse'=>'#7fff00', + 'chocolate'=>'#d2691e','coral'=>'#ff7f50','cornflowerblue'=>'#6495ed','cornsilk'=>'#fff8dc','crimson'=>'#dc143c', + 'cyan'=>'#00ffff','darkblue'=>'#00008b','darkcyan'=>'#008b8b','darkgoldenrod'=>'#b8860b','darkgray'=>'#a9a9a9', + 'darkgrey'=>'#a9a9a9','darkgreen'=>'#006400','darkkhaki'=>'#bdb76b','darkmagenta'=>'#8b008b', + 'darkolivegreen'=>'#556b2f','darkorange'=>'#ff8c00','darkorchid'=>'#9932cc','darkred'=>'#8b0000', + 'darksalmon'=>'#e9967a','darkseagreen'=>'#8fbc8f','darkslateblue'=>'#483d8b','darkslategray'=>'#2f4f4f', + 'darkslategrey'=>'#2f4f4f','darkturquoise'=>'#00ced1','darkviolet'=>'#9400d3','deeppink'=>'#ff1493', + 'deepskyblue'=>'#00bfff','dimgray'=>'#696969','dimgrey'=>'#696969','dodgerblue'=>'#1e90ff', + 'firebrick'=>'#b22222','floralwhite'=>'#fffaf0','forestgreen'=>'#228b22','fuchsia'=>'#ff00ff', + 'gainsboro'=>'#dcdcdc','ghostwhite'=>'#f8f8ff','gold'=>'#ffd700','goldenrod'=>'#daa520','gray'=>'#808080', + 'grey'=>'#808080','green'=>'#008000','greenyellow'=>'#adff2f','honeydew'=>'#f0fff0','hotpink'=>'#ff69b4', + 'indianred'=>'#cd5c5c','indigo'=>'#4b0082','ivory'=>'#fffff0','khaki'=>'#f0e68c','lavender'=>'#e6e6fa', + 'lavenderblush'=>'#fff0f5','lawngreen'=>'#7cfc00','lemonchiffon'=>'#fffacd','lightblue'=>'#add8e6', + 'lightcoral'=>'#f08080','lightcyan'=>'#e0ffff','lightgoldenrodyellow'=>'#fafad2','lightgray'=>'#d3d3d3', + 'lightgrey'=>'#d3d3d3','lightgreen'=>'#90ee90','lightpink'=>'#ffb6c1','lightsalmon'=>'#ffa07a', + 'lightseagreen'=>'#20b2aa','lightskyblue'=>'#87cefa','lightslategray'=>'#778899','lightslategrey'=>'#778899', + 'lightsteelblue'=>'#b0c4de','lightyellow'=>'#ffffe0','lime'=>'#00ff00','limegreen'=>'#32cd32','linen'=>'#faf0e6', + 'magenta'=>'#ff00ff','maroon'=>'#800000','mediumaquamarine'=>'#66cdaa','mediumblue'=>'#0000cd', + 'mediumorchid'=>'#ba55d3','mediumpurple'=>'#9370d8','mediumseagreen'=>'#3cb371','mediumslateblue'=>'#7b68ee', + 'mediumspringgreen'=>'#00fa9a','mediumturquoise'=>'#48d1cc','mediumvioletred'=>'#c71585', + 'midnightblue'=>'#191970','mintcream'=>'#f5fffa','mistyrose'=>'#ffe4e1','moccasin'=>'#ffe4b5', + 'navajowhite'=>'#ffdead','navy'=>'#000080','oldlace'=>'#fdf5e6','olive'=>'#808000','olivedrab'=>'#6b8e23', + 'orange'=>'#ffa500','orangered'=>'#ff4500','orchid'=>'#da70d6','palegoldenrod'=>'#eee8aa','palegreen'=>'#98fb98', + 'paleturquoise'=>'#afeeee','palevioletred'=>'#d87093','papayawhip'=>'#ffefd5','peachpuff'=>'#ffdab9', + 'peru'=>'#cd853f','pink'=>'#ffc0cb','plum'=>'#dda0dd','powderblue'=>'#b0e0e6','purple'=>'#800080', + 'red'=>'#ff0000','rosybrown'=>'#bc8f8f','royalblue'=>'#4169e1','saddlebrown'=>'#8b4513','salmon'=>'#fa8072', + 'sandybrown'=>'#f4a460','seagreen'=>'#2e8b57','seashell'=>'#fff5ee','sienna'=>'#a0522d','silver'=>'#c0c0c0', + 'skyblue'=>'#87ceeb','slateblue'=>'#6a5acd','slategray'=>'#708090','slategrey'=>'#708090','snow'=>'#fffafa', + 'springgreen'=>'#00ff7f','steelblue'=>'#4682b4','tan'=>'#d2b48c','teal'=>'#008080','thistle'=>'#d8bfd8', + 'tomato'=>'#ff6347','turquoise'=>'#40e0d0','violet'=>'#ee82ee','wheat'=>'#f5deb3','white'=>'#ffffff', + 'whitesmoke'=>'#f5f5f5','yellow'=>'#ffff00','yellowgreen'=>'#9acd32' + ); + + + protected function _parse( & $variable ) + { + if ( !self::_fits( $variable ) ) return false; + + $this->type = 'CSS color'; + $variants = self::_convert( $variable ); + $this->value = + "
{$variable}
" . + "hex : {$variants['hex']}\n" . + "rgb : {$variants['rgb']}\n" . + ( isset( $variants['name'] ) ? "name: {$variants['name']}\n" : '' ) . + "hsl : {$variants['hsl']}"; + } + + + private static function _fits( $variable ) + { + if ( !is_string( $variable ) ) return false; + + $var = strtolower( trim( $variable ) ); + + return isset( self::$_css3Named[$var] ) + || preg_match( + '/^(?:#[0-9A-Fa-f]{3}|#[0-9A-Fa-f]{6}|(?:rgb|hsl)a?\s*\((?:\s*[0-9.%]+\s*,?){3,4}\))$/', + $var + ); + } + + private static function _convert( $color ) + { + $color = strtolower( $color ); + $decimalColors = array(); + $variants = array( + 'hex' => null, + 'rgb' => null, + 'name' => null, + 'hsl' => null, + ); + + if ( isset( self::$_css3Named[$color] ) ) { + $variants['name'] = $color; + $color = self::$_css3Named[$color]; + } + + if ( $color{0} === '#' ) { + $variants['hex'] = $color; + $color = substr( $color, 1 ); + if ( strlen( $color ) === 6 ) { + $colors = str_split( $color, 2 ); + } else { + $colors = array( + $color{0} . $color{0}, + $color{1} . $color{1}, + $color{2} . $color{2}, + ); + } + + $decimalColors = array_map( 'hexdec', $colors ); + } elseif ( substr( $color, 0, 3 ) === 'rgb' ) { + $variants['rgb'] = $color; + preg_match_all( '#([0-9.%]+)#', $color, $matches ); + $decimalColors = $matches[1]; + foreach ( $decimalColors as &$color ) { + if ( strpos( $color, '%' ) !== false ) { + $color = str_replace( '%', '', $color ) * 2.55; + } + } + + + } elseif ( substr( $color, 0, 3 ) === 'hsl' ) { + $variants['hsl'] = $color; + preg_match_all( '#([0-9.%]+)#', $color, $matches ); + + $colors = $matches[1]; + $colors[0] /= 360; + $colors[1] = str_replace( '%', '', $colors[1] ) / 100; + $colors[2] = str_replace( '%', '', $colors[2] ) / 100; + + $decimalColors = self::_HSLtoRGB( $colors ); + if ( isset( $colors[3] ) ) { + $decimalColors[] = $colors[3]; + } + } + + if ( isset( $decimalColors[3] ) ) { + $alpha = $decimalColors[3]; + unset( $decimalColors[3] ); + } else { + $alpha = null; + } + foreach ( $variants as $type => &$variant ) { + if ( isset( $variant ) ) continue; + + switch ( $type ) { + case 'hex': + $variant = '#'; + foreach ( $decimalColors as &$color ) { + $variant .= str_pad( dechex( $color ), 2, "0", STR_PAD_LEFT ); + } + $variant .= isset( $alpha ) ? ' (alpha omitted)' : ''; + break; + case 'rgb': + $rgb = $decimalColors; + if ( isset( $alpha ) ) { + $rgb[] = $alpha; + $a = 'a'; + } else { + $a = ''; + } + $variant = "rgb{$a}( " . implode( ', ', $rgb ) . " )"; + break; + case 'hsl': + $rgb = self::_RGBtoHSL( $decimalColors ); + if ( $rgb === null ) { + unset( $variants[$type] ); + break; + } + if ( isset( $alpha ) ) { + $rgb[] = $alpha; + $a = 'a'; + } else { + $a = ''; + } + + $variant = "hsl{$a}( " . implode( ', ', $rgb ) . " )"; + break; + case 'name': + // [!] name in initial variants array must go after hex + if ( ( $key = array_search( $variants['hex'], self::$_css3Named, true ) ) !== false ) { + $variant = $key; + } else { + unset( $variants[$type] ); + } + break; + } + + } + + return $variants; + } + + + private static function _HSLtoRGB( array $hsl ) + { + list( $h, $s, $l ) = $hsl; + $m2 = ( $l <= 0.5 ) ? $l * ( $s + 1 ) : $l + $s - $l * $s; + $m1 = $l * 2 - $m2; + return array( + round( self::_hue2rgb( $m1, $m2, $h + 0.33333 ) * 255 ), + round( self::_hue2rgb( $m1, $m2, $h ) * 255 ), + round( self::_hue2rgb( $m1, $m2, $h - 0.33333 ) * 255 ), + ); + } + + + /** + * Helper function for _color_hsl2rgb(). + */ + private static function _hue2rgb( $m1, $m2, $h ) + { + $h = ( $h < 0 ) ? $h + 1 : ( ( $h > 1 ) ? $h - 1 : $h ); + if ( $h * 6 < 1 ) return $m1 + ( $m2 - $m1 ) * $h * 6; + if ( $h * 2 < 1 ) return $m2; + if ( $h * 3 < 2 ) return $m1 + ( $m2 - $m1 ) * ( 0.66666 - $h ) * 6; + return $m1; + } + + + private static function _RGBtoHSL( array $rgb ) + { + list( $clrR, $clrG, $clrB ) = $rgb; + + $clrMin = min( $clrR, $clrG, $clrB ); + $clrMax = max( $clrR, $clrG, $clrB ); + $deltaMax = $clrMax - $clrMin; + + $L = ( $clrMax + $clrMin ) / 510; + + if ( 0 == $deltaMax ) { + $H = 0; + $S = 0; + } else { + if ( 0.5 > $L ) { + $S = $deltaMax / ( $clrMax + $clrMin ); + } else { + $S = $deltaMax / ( 510 - $clrMax - $clrMin ); + } + + if ( $clrMax == $clrR ) { + $H = ( $clrG - $clrB ) / ( 6.0 * $deltaMax ); + } else if ( $clrMax == $clrG ) { + $H = 1 / 3 + ( $clrB - $clrR ) / ( 6.0 * $deltaMax ); + } else { + $H = 2 / 3 + ( $clrR - $clrG ) / ( 6.0 * $deltaMax ); + } + + if ( 0 > $H ) $H += 1; + if ( 1 < $H ) $H -= 1; + } + return array( + round( $H * 360 ), + round( $S * 100 ) . '%', + round( $L * 100 ) . '%' + ); + + } +} + +/* ************* + * TEST DATA + * +dd(array( +'hsl(0, 100%,50%)', +'hsl(30, 100%,50%)', +'hsl(60, 100%,50%)', +'hsl(90, 100%,50%)', +'hsl(120,100%,50%)', +'hsl(150,100%,50%)', +'hsl(180,100%,50%)', +'hsl(210,100%,50%)', +'hsl(240,100%,50%)', +'hsl(270,100%,50%)', +'hsl(300,100%,50%)', +'hsl(330,100%,50%)', +'hsl(360,100%,50%)', +'hsl(120,100%,25%)', +'hsl(120,100%,50%)', +'hsl(120,100%,75%)', +'hsl(120,100%,50%)', +'hsl(120, 67%,50%)', +'hsl(120, 33%,50%)', +'hsl(120, 0%,50%)', +'hsl(120, 60%,70%)', +'#f03', +'#F03', +'#ff0033', +'#FF0033', +'rgb(255,0,51)', +'rgb(255, 0, 51)', +'rgb(100%,0%,20%)', +'rgb(100%, 0%, 20%)', +'hsla(240,100%,50%,0.05)', +'hsla(240,100%,50%, 0.4)', +'hsla(240,100%,50%, 0.7)', +'hsla(240,100%,50%, 1)', +'rgba(255,0,0,0.1)', +'rgba(255,0,0,0.4)', +'rgba(255,0,0,0.7)', +'rgba(255,0,0, 1)', +'black', +'silver', +'gray', +'white', +'maroon', +'red', +'purple', +'fuchsia', +'green', +'lime', +'olive', +'yellow', +'navy', +'blue', +'teal', +'aqua', +'orange', +'aliceblue', +'antiquewhite', +'aquamarine', +'azure', +'beige', +'bisque', +'blanchedalmond', +'blueviolet', +'brown', +'burlywood', +'cadetblue', +'chartreuse', +'chocolate', +'coral', +'cornflowerblue', +'cornsilk', +'crimson', +'darkblue', +'darkcyan', +'darkgoldenrod', +'darkgray', +'darkgreen', +'darkgrey', +'darkkhaki', +'darkmagenta', +'darkolivegreen', +'darkorange', +'darkorchid', +'darkred', +'darksalmon', +'darkseagreen', +'darkslateblue', +'darkslategray', +'darkslategrey', +'darkturquoise', +'darkviolet', +'deeppink', +'deepskyblue', +'dimgray', +'dimgrey', +'dodgerblue', +'firebrick', +'floralwhite', +'forestgreen', +'gainsboro', +'ghostwhite', +'gold', +'goldenrod', +'greenyellow', +'grey', +'honeydew', +'hotpink', +'indianred', +'indigo', +'ivory', +'khaki', +'lavender', +'lavenderblush', +'lawngreen', +'lemonchiffon', +'lightblue', +'lightcoral', +'lightcyan', +'lightgoldenrodyellow', +'lightgray', +'lightgreen', +'lightgrey', +'lightpink', +'lightsalmon', +'lightseagreen', +'lightskyblue', +'lightslategray', +'lightslategrey', +'lightsteelblue', +'lightyellow', +'limegreen', +'linen', +'mediumaquamarine', +'mediumblue', +'mediumorchid', +'mediumpurple', +'mediumseagreen', +'mediumslateblue', +'mediumspringgreen', +'mediumturquoise', +'mediumvioletred', +'midnightblue', +'mintcream', +'mistyrose', +'moccasin', +'navajowhite', +'oldlace', +'olivedrab', +));*/ \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/index.html b/app/lib/kint/parsers/custom/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lib/kint/parsers/custom/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/json.php b/app/lib/kint/parsers/custom/json.php new file mode 100644 index 0000000..0327468 --- /dev/null +++ b/app/lib/kint/parsers/custom/json.php @@ -0,0 +1,17 @@ +value = kintParser::factory( $val )->extendedValue; + $this->type = 'JSON'; + } +} \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/microtime.php b/app/lib/kint/parsers/custom/microtime.php new file mode 100644 index 0000000..a51a051 --- /dev/null +++ b/app/lib/kint/parsers/custom/microtime.php @@ -0,0 +1,54 @@ +value = @date( 'Y-m-d H:i:s', $sec ) . '.' . substr( $usec, 2, 4 ); + + $numberOfCalls = count( self::$_times ); + if ( $numberOfCalls > 0 ) { # meh, faster than count($times) > 1 + $lap = $time - end( self::$_times ); + self::$_laps[] = $lap; + + $this->value .= "\nSINCE LAST CALL: " . round( $lap, 4 ) . 's.'; + if ( $numberOfCalls > 1 ) { + $this->value .= "\nSINCE START: " . round( $time - self::$_times[0], 4 ) . 's.'; + $this->value .= "\nAVERAGE DURATION: " + . round( array_sum( self::$_laps ) / $numberOfCalls, 4 ) . 's.'; + } + } + + $unit = array( 'B', 'KB', 'MB', 'GB', 'TB' ); + $this->value .= "\nMEMORY USAGE: " . $size . " bytes (" + . round( $size / pow( 1024, ( $i = floor( log( $size, 1024 ) ) ) ), 3 ) . ' ' . $unit[$i] . ")"; + + self::$_times[] = $time; + $this->type = 'Stats'; + } + + /* + function test() { + $x = ''; + d( microtime() ); + for ( $i = 0; $i < 10; $i++ ) { + $x .= str_repeat( 'x', mt_rand( 128 * 1024, 5 * 1024 * 1024 ) ); + usleep( mt_rand( 0, 1000 * 1000 ) ); + d( microtime() ); + } + unset( $x ); + dd( microtime() ); + } + */ +} \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/splfileinfo.php b/app/lib/kint/parsers/custom/splfileinfo.php new file mode 100644 index 0000000..6b14f67 --- /dev/null +++ b/app/lib/kint/parsers/custom/splfileinfo.php @@ -0,0 +1,12 @@ +type = 'object'; + $this->subtype = 'SplFileInfo'; + $this->value = Kint::shortenPath( $variable->getRealPath() ); + } +} \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/splobjectstorage.php b/app/lib/kint/parsers/custom/splobjectstorage.php new file mode 100644 index 0000000..c355771 --- /dev/null +++ b/app/lib/kint/parsers/custom/splobjectstorage.php @@ -0,0 +1,20 @@ +rewind(); + while ( $variable->valid() ) { + $current = $variable->current(); + $this->value[] = kintParser::factory( $current ); + $variable->next(); + } + + $this->type = 'Storage contents'; + $this->size = $variable->count(); + } +} \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/timestamp.php b/app/lib/kint/parsers/custom/timestamp.php new file mode 100644 index 0000000..4c5f487 --- /dev/null +++ b/app/lib/kint/parsers/custom/timestamp.php @@ -0,0 +1,22 @@ +type = 'timestamp'; + # avoid dreaded "Timezone must be set" error + $this->value = @date( 'Y-m-d H:i:s', $variable ); + } +} \ No newline at end of file diff --git a/app/lib/kint/parsers/custom/xml.php b/app/lib/kint/parsers/custom/xml.php new file mode 100644 index 0000000..50d0def --- /dev/null +++ b/app/lib/kint/parsers/custom/xml.php @@ -0,0 +1,18 @@ +value = kintParser::factory( $xml )->extendedValue; + $this->type = 'XML'; + } +} \ No newline at end of file diff --git a/app/lib/kint/parsers/index.html b/app/lib/kint/parsers/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lib/kint/parsers/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/kint/parsers/parser.class.php b/app/lib/kint/parsers/parser.class.php new file mode 100644 index 0000000..6dd4ef6 --- /dev/null +++ b/app/lib/kint/parsers/parser.class.php @@ -0,0 +1,571 @@ + self::$_level, + 'objects' => self::$_objects, + ); + + self::$_level++; + + $name = self::_escape( $name ); + $varData = new kintVariableData; + $varData->name = $name; + + # first parse the variable based on its type + $varType = gettype( $variable ); + $varType === 'unknown type' and $varType = 'unknown'; # PHP 5.4 inconsistency + $methodName = '_parse_' . $varType; + + # base type parser returning false means "stop processing further": e.g. recursion + if ( self::$methodName( $variable, $varData ) === false ) { + self::$_level--; + return $varData; + } + + if ( !self::$_skipAlternatives) { + # if an alternative returns something that can be represented in an alternative way, don't :) + self::$_skipAlternatives = true; + + # now check whether the variable can be represented in a different way + foreach ( self::$_customDataTypes as $parserClass ) { + $className = 'Kint_Parsers_' . $parserClass; + + /** @var $object kintParser */ + $object = new $className; + $object->name = $name; # the parser may overwrite the name value, so set it first + + if ( $object->_parse( $variable ) !== false ) { + $varData->alternatives[] = $object; + } + } + + + # combine extended values with alternative representations if applicable + if ( !empty( $varData->alternatives ) && isset( $varData->extendedValue ) ) { + $a = new kintVariableData; + + $a->value = $varData->extendedValue; + $a->type = $varData->type; + $a->size = $varData->size; + + array_unshift( $varData->alternatives, $a ); + $varData->extendedValue = null; + } + + self::$_skipAlternatives = false; + } + + self::$_level = $revert['level']; + self::$_objects = $revert['objects']; + return $varData; + } + + private static function _checkDepth() + { + return Kint::$maxLevels != 0 && self::$_level > Kint::$maxLevels; + } + + private static function _isArrayTabular( $variable ) + { + foreach ( $variable as $row ) { + if ( is_array( $row ) && !empty( $row ) ) { + if ( isset( $keys ) ) { + if ( $keys === array_keys( $row ) ) { // two rows have same keys in a row? Close enough. + return true; + } + } else { + + foreach ( $row as $col ) { + if ( !is_scalar( $col ) && $col !== null ) { + break 2; + } + } + + $keys = array_keys( $row ); + } + } else { + break; + } + } + + return false; + } + + private static $_dealingWithGlobals = false; + + private static function _parse_array( &$variable, kintVariableData $variableData ) + { + isset( self::$_marker ) or self::$_marker = "\x00" . uniqid(); + + # naturally, $GLOBALS variable is an intertwined recursion nightmare, use black magic + $globalsDetector = false; + if ( array_key_exists( 'GLOBALS', $variable ) && is_array( $variable['GLOBALS'] ) ) { + $globalsDetector = "\x01" . uniqid(); + + $variable['GLOBALS'][$globalsDetector] = true; + if ( isset( $variable[$globalsDetector] ) ) { + unset( $variable[$globalsDetector] ); + self::$_dealingWithGlobals = true; + } else { + unset( $variable['GLOBALS'][$globalsDetector] ); + $globalsDetector = false; + } + } + + $variableData->type = 'array'; + $variableData->size = count( $variable ); + + if ( $variableData->size === 0 ) { + return; + } + if ( isset( $variable[self::$_marker] ) ) { # recursion; todo mayhaps show from where + if ( self::$_dealingWithGlobals ) { + $variableData->value = '*RECURSION*'; + } else { + unset( $variable[self::$_marker] ); + $variableData->value = self::$_marker; + } + return false; + } + if ( self::_checkDepth() ) { + $variableData->extendedValue = "*DEPTH TOO GREAT*"; + return false; + } + + $isSequential = self::_isSequential( $variable ); + + $tabular = self::_isArrayTabular( $variable ); + if ( $tabular ) { + + $firstRow = true; + $extendedValue = ''; + $arrayKeys = array(); + + + // assure no values are unreported if an extra key appears in one of the lines + foreach ( $variable as $row ) { + // todo process all keys in _isArrayTabular() + if ( !is_array( $row ) ) { + $tabular = false; + break; + } + $arrayKeys = array_unique( array_merge( $arrayKeys, array_keys( $row ) ) ); + + if ( Kint::$keyFilterCallback ) { + foreach ( $arrayKeys as $k => $key ) { + if ( call_user_func( Kint::$keyFilterCallback, $key ) === false ) { + unset( $arrayKeys[$k] ); + } + } + } + } + } + + + if ( $tabular ) { + $variable[self::$_marker] = true; + foreach ( $variable as $rowIndex => &$row ) { + if ( $rowIndex === self::$_marker ) continue; + + if ( isset( $row[self::$_marker] ) ) { + $variableData->value = "*RECURSION*"; + return false; + } + + + $extendedValue .= ''; + $output = ''; + if ( $firstRow ) { + $extendedValue .= ''; + } + + foreach ( $arrayKeys as $key ) { + if ( $firstRow ) { + $extendedValue .= ''; + } + + if ( !array_key_exists( $key, $row ) ) { + $output .= ''; + continue; + } + + # display strings in their full length so as not to trigger rich decoration + $maxStrLength = kint::$maxStrLength; + kint::$maxStrLength = false; + $var = kintParser::factory( $row[$key] ); + kint::$maxStrLength = $maxStrLength; + + if ( $var->value === self::$_marker ) { + $variableData->value = '*RECURSION*'; + return false; + } elseif ( $var->value === '*RECURSION*' ) { + $output .= ''; + } else { + $output .= ''; + } + unset( $var ); + } + + if ( $firstRow ) { + $extendedValue .= ''; + $firstRow = false; + } + + $extendedValue .= $output . ''; + } + + $variableData->extendedValue = $extendedValue . '
' . ( $isSequential ? '#' . ( $rowIndex + 1 ) : $rowIndex ) . '' . htmlspecialchars( $key ) . '' . Kint_Decorators_Concise::decorate( $var ) . '' . Kint_Decorators_Concise::decorate( $var ) . '
'; + + } else { + $variable[self::$_marker] = true; + $extendedValue = array(); + + foreach ( $variable as $key => & $val ) { + if ( $key === self::$_marker + || ( Kint::$keyFilterCallback && call_user_func( Kint::$keyFilterCallback, $key, $val ) === false ) + ) { + continue; + } + + + $output = kintParser::factory( $val, $isSequential ? null : "'{$key}'" ); + if ( $output->value === self::$_marker ) { + $variableData->value = "*RECURSION*"; // recursion occurred on a higher level, thus $this is recursion + return false; + } + if ( !$isSequential ) { + $output->operator = '=>'; + } + $extendedValue[] = $output; + } + $variableData->extendedValue = $extendedValue; + } + + if ( $globalsDetector ) { + self::$_dealingWithGlobals = false; + } + + unset( $variable[self::$_marker] ); + } + + + private static function _parse_object( &$variable, kintVariableData $variableData ) + { + + // copy the object as an array + $array = (array)$variable; + $hash = spl_object_hash( $variable ); + + + $variableData->type = 'object'; + $variableData->subtype = get_class( $variable ); + $variableData->size = count( $array ); + + if ( isset( self::$_objects[$hash] ) ) { + $variableData->value = '*RECURSION*'; + return false; + } + if ( self::_checkDepth() ) { + $variableData->extendedValue = "*DEPTH TOO GREAT*"; + return false; + } + + self::$_objects[$hash] = true; + + + if ( empty( $array ) ) return; + + + $extendedValue = array(); + foreach ( $array as $key => & $value ) { + if ( Kint::$keyFilterCallback + && call_user_func_array( Kint::$keyFilterCallback, array( $key, $value ) ) === false + ) { + continue; + } + + /* casting object to array: + * integer properties are inaccessible; + * private variables have the class name prepended to the variable name; + * protected variables have a '*' prepended to the variable name. + * These prepended values have null bytes on either side. + * http://www.php.net/manual/en/language.types.array.php#language.types.array.casting + */ + if ( $key[0] === "\x00" ) { + + $access = $key[1] === "*" ? "protected" : "private"; + + // Remove the access level from the variable name + $key = substr( $key, strrpos( $key, "\x00" ) + 1 ); + } else { + $access = "public"; + } + + $key = self::_escape( $key ); + $output = kintParser::factory( $value, $key ); + $output->access = $access; + $output->operator = '->'; + $extendedValue[] = $output; + } + + $variableData->extendedValue = $extendedValue; + } + + + private static function _parse_boolean( &$variable, kintVariableData $variableData ) + { + $variableData->type = 'bool'; + $variableData->value = $variable ? 'TRUE' : 'FALSE'; + } + + private static function _parse_double( &$variable, kintVariableData $variableData ) + { + $variableData->type = 'float'; + $variableData->value = $variable; + } + + private static function _parse_integer( &$variable, kintVariableData $variableData ) + { + $variableData->type = 'integer'; + $variableData->value = $variable; + } + + private static function _parse_null( &$variable, kintVariableData $variableData ) + { + $variableData->type = 'NULL'; + } + + private static function _parse_resource( &$variable, kintVariableData $variableData ) + { + $variableData->type = 'resource'; + $variableData->subtype = get_resource_type( $variable ); + + if ( $variableData->subtype === 'stream' && $meta = stream_get_meta_data( $variable ) ) { + + if ( isset( $meta['uri'] ) ) { + $file = $meta['uri']; + + if ( function_exists( 'stream_is_local' ) ) { + // Only exists on PHP >= 5.2.4 + if ( stream_is_local( $file ) ) { + $file = Kint::shortenPath( $file ); + } + } + + $variableData->value = $file; + } + } + } + + private static function _parse_string( &$variable, kintVariableData $variableData ) + { + $variableData->type = 'string'; + + $encoding = self::_detectEncoding( $variable ); + if ( $encoding !== 'ASCII' ) { + $variableData->subtype = $encoding; + } + + $variableData->size = self::_strlen( $variable, $encoding ); + $strippedString = self::_stripWhitespace( $variable ); + if ( Kint::$maxStrLength && $variableData->size > Kint::$maxStrLength ) { + + // encode and truncate + $variableData->value = '"' + . self::_escape( self::_substr( $strippedString, Kint::$maxStrLength, $encoding ), $encoding ) + . ' …"'; + $variableData->extendedValue = self::_escape( $variable, $encoding ); + + } elseif ( $variable !== $strippedString ) { // omit no data from display + + $variableData->value = '"' . self::_escape( $variable, $encoding ) . '"'; + $variableData->extendedValue = self::_escape( $variable, $encoding ); + } else { + $variableData->value = '"' . self::_escape( $variable, $encoding ) . '"'; + } + } + + private static function _parse_unknown( &$variable, kintVariableData $variableData ) + { + $variableData->type = "UNKNOWN"; + $variableData->subtype = gettype( $variable ); + $variableData->value = var_export( $variable, true ); + } + +} + + +class kintVariableData +{ + /** @var string */ + public $type; + /** @var string */ + public $access; + /** @var string */ + public $name; + /** @var string */ + public $operator; + /** @var string */ + public $subtype; + /** @var int */ + public $size; + /** + * @var kintVariableData[] array of kintVariableData objects or strings; displayed collapsed, each element from + * the array is a separate possible representation of the dumped var + */ + public $extendedValue; + /** @var kintVariableData[] array of alternative representations for same variable */ + public $alternatives; + /** @var string inline value */ + public $value; + + + /* ******************************************* + * HELPERS + */ + + protected static function _escape( $value, $encoding = null ) + { + $encoding or $encoding = self::_detectEncoding( $value ); + + if ( $encoding === 'UTF-8' ) { + # when possible force invisible characters to have some sort of display + $value = preg_replace( '/[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\x9F]/u', '�', $value ); + } + + $value = htmlspecialchars( $value, ENT_QUOTES ); + if ( function_exists( 'mb_encode_numericentity' ) ) { + return mb_encode_numericentity( + $value, + array( 0x80, 0xffff, 0, 0xffff, ), + $encoding + ); + } else { + return $value; + } + } + + protected static function _detectEncoding( $value ) + { + if ( function_exists( 'mb_detect_encoding' ) ) { + $mbDetected = mb_detect_encoding( $value ); + if ( $mbDetected === 'ASCII' ) { + return 'ASCII'; + } + } + + if ( empty( Kint::$charEncodings ) || !function_exists( 'iconv' ) ) { + return !empty( $mbDetected ) ? $mbDetected : 'UTF-8'; + } + + $md5 = md5( $value ); + foreach ( array_merge( array( 'UTF-8' ), Kint::$charEncodings ) as $encoding ) { + # fuck knows why, //IGNORE and //TRANSLIT still throw notice + if ( md5( @iconv( $encoding, $encoding, $value ) ) === $md5 ) { + return $encoding; + } + } + + return 'ASCII'; + } + + /** + * zaps all excess whitespace from string, compacts it but hurts readability + * + * @param string $string + * + * @return string + */ + protected static function _stripWhitespace( $string ) + { + return preg_replace( '[\s+]', ' ', $string ); + } + + + /** + * returns whether the array: + * 1) is numeric and + * 2) in sequence starting from zero + * + * @param array $array + * + * @return bool + */ + protected static function _isSequential( array $array ) + { + return Kint::$hideSequentialKeys + ? array_keys( $array ) === range( 0, count( $array ) - 1 ) + : false; + } + + protected static function _strlen( $string, $encoding = null ) + { + $encoding or $encoding = self::_detectEncoding( $string ); + + return function_exists( 'mb_strlen' ) + ? mb_strlen( $string, $encoding ) + : strlen( $string ); + } + + protected static function _substr( $string, $end, $encoding = null ) + { + $encoding or $encoding = self::_detectEncoding( $string ); + + return function_exists( 'mb_substr' ) + ? mb_substr( $string, 0, $end, $encoding ) + : substr( $string, 0, $end ); + } +} diff --git a/app/lib/kint/scripts/index.html b/app/lib/kint/scripts/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lib/kint/scripts/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/kint/scripts/source.reg b/app/lib/kint/scripts/source.reg new file mode 100644 index 0000000..3d80930 --- /dev/null +++ b/app/lib/kint/scripts/source.reg @@ -0,0 +1,12 @@ +REGEDIT4 + +[HKEY_CLASSES_ROOT\source] +@="URL:source Protocol" +"URL Protocol"="" + +[HKEY_CLASSES_ROOT\source\shell] + +[HKEY_CLASSES_ROOT\source\shell\open] + +[HKEY_CLASSES_ROOT\source\shell\open\command] +@="wscript.exe \"C:\\Program Files\\bin\\source.vbs\" \"%1\"" \ No newline at end of file diff --git a/app/lib/kint/scripts/source.vbs b/app/lib/kint/scripts/source.vbs new file mode 100644 index 0000000..3345dbe --- /dev/null +++ b/app/lib/kint/scripts/source.vbs @@ -0,0 +1,80 @@ +'INSTALLATION: +'set editor link format to 'source::' +'move this file to C:\Program Files\bin\source.vbs and run source.reg +'customize directory mappings and editor command below + +'***************** +'start of settings +'***************** +Dim command, protocol, change_slashes, debug +Set dirmap = CreateObject("Scripting.Dictionary") + +'list of server paths (as regular expressions) +'and matching local paths (as regexp replace strings) +'use this to replace the beginning of the path +'if none of the regular expressions match, the script will show an error + +'local setup, when PHP and editor runs from the same machine +dirmap.Add "^([C-Z]:\\)", "$1" + +'a typical remote Linux setup +'dirmap.Add "^/var/www/", "C:\Projects\" +'dirmap.Add "^/usr/share/php5/", "C:\Projects\debug-source" + +'command to execute; %f is the file name, %l is the line number +'dont forget to quote file names (quotes can be escaped by writing twice) +command = """C:\Program Files\Notepad++\notepad++.exe"" -n%l ""%f""" + +'if true, forward slashes will be changed to backslashes in the filename +'(after the regex replacements) +change_slashes = True + +'protocol name used in the source edit links +protocol = "source" + +'if true, alerts the command before executing it +debug = False + +'*************** +'end of settings +'*************** + +Select Case WScript.Arguments.Count + Case 0 + WScript.Echo "Wrong source link" + WScript.Quit +End Select + +Dim link, split, file, line, found, strArgs + +link = Mid(WScript.Arguments.Item(0), Len(protocol) + 2) +split = InStrRev(link, ":") +file = Left(link, split - 1) +line = Mid(link, split + 1) + +found = False +For Each serverPath In dirmap + Set regexp = New RegExp + regexp.Pattern = serverPath + If regexp.Test(file) Then + found = True + Exit For + End If +Next +If Not found Then + WScript.Echo "don't know where to find " & file & " locally" + WScript.Quit +End If +file = regexp.Replace(file, dirmap.Item(serverPath)) +if change_slashes Then + file = Replace(file, "/", "\") +End If + +strArgs = command +strArgs = Replace(strArgs, "%l", line) +strArgs = Replace(strArgs, "%f", file) +If debug Then + WScript.Echo strArgs +End If +Set oShell = CreateObject ("Wscript.Shell") +oShell.Run strArgs, 0, false \ No newline at end of file diff --git a/app/lib/kint/view/inc/kint.js b/app/lib/kint/view/inc/kint.js new file mode 100644 index 0000000..753740f --- /dev/null +++ b/app/lib/kint/view/inc/kint.js @@ -0,0 +1,8 @@ +(function(){var e=!1; +if("undefined"===typeof kintInitialized){kintInitialized=1;var f=[],g=-1,h=function(b,a){"undefined"===typeof a&&(a="kint-show");return RegExp("(\\s|^)"+a+"(\\s|$)").test(b.className)},k=function(b,a){"undefined"===typeof a&&(a="kint-show");j(b,a).className+=" "+a},j=function(b,a){"undefined"===typeof a&&(a="kint-show");b.className=b.className.replace(RegExp("(\\s|^)"+a+"(\\s|$)")," ");return b},l=function(b){do b=b.nextElementSibling;while("dd"!==b.nodeName.toLowerCase());return b},m=function(b,a){var c= +l(b);"undefined"===typeof a&&(a=h(b));a?j(b):k(b);1===c.childNodes.length&&(c=c.childNodes[0].childNodes[0],h(c,"kint-parent")&&m(c,a))},n=function(b,a){var c=l(b).getElementsByClassName("kint-parent"),d=c.length;for("undefined"===typeof a&&(a=h(b));d--;)m(c[d],a);m(b,a)},p=function(b){var a=b,c=0;b.parentNode.getElementsByClassName("kint-active-tab")[0].className="";for(b.className="kint-active-tab";a=a.previousSibling;)1===a.nodeType&&c++;b=b.parentNode.nextSibling.childNodes;for(var d=0;dli:not(.kint-active-tab)"),0).forEach(function(b){(0!==b.offsetWidth||0!==b.offsetHeight)&&f.push(b)})},s=function(b){var a=document.querySelector(".kint-focused");a&&j(a,"kint-focused");if(-1!== +b){a=f[b];k(a,"kint-focused");var c=function(a){return a.offsetTop+(a.offsetParent?c(a.offsetParent):0)};window.scrollTo(0,c(a)-window.innerHeight/2)}g=b},t=function(b,a){b?0>--a&&(a=f.length-1):++a>=f.length&&(a=0);s(a);return e};window.addEventListener("click",function(b){var a=b.target,c=a.nodeName.toLowerCase();if(q(a)){if("dfn"===c){var d=a,u=window.getSelection(),v=document.createRange();v.selectNodeContents(d);u.removeAllRanges();u.addRange(v);a=a.parentNode}else"var"===c&&(a=a.parentNode, +c=a.nodeName.toLowerCase());if("li"===c&&"kint-tabs"===a.parentNode.className)return"kint-active-tab"!==a.className&&(p(a),-1!==g&&r()),e;if("nav"===c)return setTimeout(function(){0dl dl{padding:0 0 0 15px;border-left:1px dashed #b6cedb}.kint nav{display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle;content:' ';cursor:pointer;background:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAA8CAMAAACO5hB7AAAACVBMVEX///82b4tctzBls0NMAAAAQklEQVR42rWRIQ4AAAgCwf8/2qgER2BeuwJsgAqIzekMfMryPL9XQSkobE6vwKcsz/N7FfPvh09lnPf/b+7673+f0uHuAZ/EdkNQAAAAAElFTkSuQmCC") no-repeat scroll 0 0 transparent}.kint dt.kint-parent:hover nav{background-position:0 -15px}.kint dt.kint-parent.kint-show:hover>nav{background-position:0 -45px}.kint dt.kint-show>nav{background-position:0 -30px}.kint dt.kint-parent+dd{display:none}.kint dt.kint-parent.kint-show+dd{display:block}.kint var{color:#0092db;font-style:normal}.kint dt:hover var{color:#5cb730}.kint dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint pre{color:#1d1e1e;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #b6cedb;background:#e0eaef;display:block}.kint footer{padding:0 3px 3px;font-size:.7em}.kint a{color:#1d1e1e;text-shadow:none}.kint a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint ul{list-style:none;padding-left:12px}.kint ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#e0eaef;border:1px solid #b6cedb;border-top:0}.kint ul.kint-tabs li{background:#c1d4df;cursor:pointer;display:inline-block;height:23px;line-height:23px;margin:0 4px 4px;padding:0 10px 2px;border:1px solid #b6cedb}.kint ul.kint-tabs li:hover{border:1px solid #0092db}.kint ul.kint-tabs li:hover var{color:#5cb730}.kint ul.kint-tabs li.kint-active-tab{background:#e0eaef;border:1px solid #b6cedb;border-top:0;font-weight:bold;margin-top:-1px;padding-bottom:2px;padding-top:4px;border-right:1px solid #b6cedb}.kint ul.kint-tabs li+li{margin-left:0}.kint dt:hover+dd>ul>li.kint-active-tab{border-color:#0092db}.kint dt:hover+dd>ul>li.kint-active-tab var{color:#5cb730}.kint ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-report{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-report *{text-align:left;padding:0;margin:0;font-size:9pt;overflow:hidden;font-family:Consolas,"Courier New",monospace;color:#1d1e1e}.kint-report dt{padding:0;border:0;background:0}.kint-report dt.kint-parent{max-width:180px;min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-report dt.kint-parent.kint-show{border-bottom:1px solid #b6cedb}.kint-report td,.kint-report th{border:1px solid #b6cedb;vertical-align:top}.kint-report td{background:#e0eaef;white-space:pre}.kint-report td>dl{border:0;padding:0}.kint-report dl,.kint-report pre,.kint-report label{padding:0}.kint-report pre{border-top:0;border-bottom:0;border-right:0}.kint-report label[for]:before{display:none}.kint-report th:first-child{background:0;border:0}.kint-report td:first-child,.kint-report th{font-weight:bold;background:#c1d4df;color:#1d1e1e}.kint-report td.kint-empty{background:#d33682!important}.kint-report tr:hover>td{box-shadow:0 0 1px 0 #0092db inset}.kint-report tr:hover var{color:#5cb730}.kint-trace .kint-source{line-height:1.08em}.kint-trace .kint-source span{padding-right:1px;border-right:3px inset #0092db}.kint-trace .kint-source .kint-highlight{background:#c1d4df}.kint-trace .kint-parent>b{min-width:18px;display:inline-block;text-align:right;color:#1d1e1e}.kint-trace var{margin-right:5px}.kint-focused{box-shadow:0 0 3px 2px #5cb730}.kint-color-preview{box-shadow:0 0 2px 0 #b6cedb;height:16px;text-align:center;text-shadow:-1px 0 #839496,0 1px #839496,1px 0 #839496,0 -1px #839496;width:230px;color:#fdf6e3}.kint>dl>dt{background:-webkit-linear-gradient(top,#e3ecf0 0,#c0d4df 100%);background:linear-gradient(to bottom,#e3ecf0 0,#c0d4df 100%)}.kint ul.kint-tabs{background:-webkit-linear-gradient(top,#9dbed0 0,#b2ccda 100%);background:linear-gradient(to bottom,#9dbed0 0,#b2ccda 100%)}.kint:not(.kint-trace)>dl>dd>ul.kint-tabs li{background:#e0eaef}.kint:not(.kint-trace)>dl>dd>ul.kint-tabs li.kint-active-tab{background:#c1d4df}.kint.kint-trace>dl>dt{background:-webkit-linear-gradient(top,#c0d4df 0,#e3ecf0 100%);background:linear-gradient(to bottom,#c0d4df 0,#e3ecf0 100%)}.kint .kint-source .kint-highlight{background:#f0eb96} \ No newline at end of file diff --git a/app/lib/kint/view/inc/solarized-dark.css b/app/lib/kint/view/inc/solarized-dark.css new file mode 100644 index 0000000..58c2958 --- /dev/null +++ b/app/lib/kint/view/inc/solarized-dark.css @@ -0,0 +1 @@ +.kint::selection{background:#268bd2;color:#839496}.kint::-moz-selection{background:#268bd2;color:#839496}.kint::-webkit-selection{background:#268bd2;color:#839496}.kint{font-family:Consolas,"Courier New",monospace;color:#839496;padding:0;margin:10px 0;font-size:10pt;line-height:15px;white-space:nowrap;overflow-x:auto;text-align:left}.kint *{float:none!important;padding:0;margin:0}.kint dt{background:#002b36;border:1px solid #586e75;color:#839496;display:block;font-weight:bold;list-style:none outside none;padding:5px}.kint dt:hover{border-color:#268bd2}.kint>dl dl{padding:0 0 0 15px;border-left:1px dashed #586e75}.kint nav{display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle;content:' ';cursor:pointer;background:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAA8CAMAAACO5hB7AAAA7VBMVEVYbnWToaH///9YbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnWToaFYbnVYbnWToaGToaFYbnWToaFYbnWToaFYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnWToaEeRtj1AAAATXRSTlMAAACLab0B7iP2R7CL9iPuaUewAb36F0/QnPoX0JxPYQaurepi6QV8FhV7MzFhM6586RYFMa3qYnsVBpNQ+ZGOGJ3PkM9QkZAY+Y6TnV7gnYsAAAEcSURBVHhebdHVbgMxEEBRu8sUZmqapBBoSuGUmWb+/3NayxtrLOe+Hck745XZgd6/eb3CVcKt7HmR+gKxlCGOETG5vFbOoahR6NxI5zHt6nuq+2dqnqfzzH3mfcz70vb8H6MJt5u6a96hS30E4PjEFgAEp2fKNojKUfVEOoS044ex7u3YPE/nmfvM+5j3pe17T9oe/77O41w+n4vnrbrwZxbTshVhvtx5Kb8vliRLRWmeSQSTjJq/El5x5fUXYmNN9hcQC5y4g/hGvVksNtT8451rns2IScb7mn567ll2GNpWr9YWfvQgzWsKs8HOA/m960g6rjTzA8HAV/NHwiOmPLwDKA/J/gggYsRVgFvqbr/fpWYv90zzZKKs9Qfx00Jx65oxLAAAAABJRU5ErkJggg==") no-repeat scroll 0 0 transparent}.kint dt.kint-parent:hover nav{background-position:0 -15px}.kint dt.kint-parent.kint-show:hover>nav{background-position:0 -45px}.kint dt.kint-show>nav{background-position:0 -30px}.kint dt.kint-parent+dd{display:none}.kint dt.kint-parent.kint-show+dd{display:block}.kint var{color:#268bd2;font-style:normal}.kint dt:hover var{color:#2aa198}.kint dfn{font-style:normal;font-family:monospace;color:#93a1a1}.kint pre{color:#839496;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #586e75;background:#002b36;display:block}.kint footer{padding:0 3px 3px;font-size:.7em}.kint a{color:#839496;text-shadow:none}.kint a:hover{color:#93a1a1;border-bottom:1px dotted #93a1a1}.kint ul{list-style:none;padding-left:15px}.kint ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#002b36;border:1px solid #586e75;border-top:0}.kint ul.kint-tabs li{background:#073642;cursor:pointer;display:inline-block;height:24px;line-height:24px;margin:0 5px 5px;padding:0 12px 3px;border:1px solid #586e75}.kint ul.kint-tabs li:hover{border:1px solid #268bd2}.kint ul.kint-tabs li:hover var{color:#2aa198}.kint ul.kint-tabs li.kint-active-tab{background:#002b36;border:1px solid #586e75;border-top:0;font-weight:bold;margin-top:-1px;padding-bottom:3px;padding-top:4px;border-right:1px solid #586e75}.kint ul.kint-tabs li+li{margin-left:0}.kint dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2}.kint dt:hover+dd>ul>li.kint-active-tab var{color:#2aa198}.kint ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-report{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-report *{text-align:left;padding:0;margin:0;font-size:9pt;overflow:hidden;font-family:Consolas,"Courier New",monospace;color:#839496}.kint-report dt{padding:0;border:0;background:0}.kint-report dt.kint-parent{max-width:180px;min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-report dt.kint-parent.kint-show{border-bottom:1px solid #586e75}.kint-report td,.kint-report th{border:1px solid #586e75;vertical-align:top}.kint-report td{background:#002b36;white-space:pre}.kint-report td>dl{border:0;padding:0}.kint-report dl,.kint-report pre,.kint-report label{padding:0}.kint-report pre{border-top:0;border-bottom:0;border-right:0}.kint-report label[for]:before{display:none}.kint-report th:first-child{background:0;border:0}.kint-report td:first-child,.kint-report th{font-weight:bold;background:#073642;color:#93a1a1}.kint-report td.kint-empty{background:#d33682!important}.kint-report tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-report tr:hover var{color:#2aa198}.kint-trace .kint-source{line-height:1.1em}.kint-trace .kint-source span{padding-right:1px;border-right:3px inset #268bd2}.kint-trace .kint-source .kint-highlight{background:#073642}.kint-trace .kint-parent>b{min-width:18px;display:inline-block;text-align:right;color:#93a1a1}.kint-trace var{margin-right:5px}.kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-color-preview{box-shadow:0 0 2px 0 #b6cedb;height:16px;text-align:center;text-shadow:-1px 0 #839496,0 1px #839496,1px 0 #839496,0 -1px #839496;width:230px;color:#fdf6e3}body{background:#073642;color:#fff}.kint{background:#073642;box-shadow:0 0 5px 3px #073642}.kint>dl>dt,.kint ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset} \ No newline at end of file diff --git a/app/lib/kint/view/inc/solarized.css b/app/lib/kint/view/inc/solarized.css new file mode 100644 index 0000000..1519cba --- /dev/null +++ b/app/lib/kint/view/inc/solarized.css @@ -0,0 +1 @@ +.kint::selection{background:#268bd2;color:#657b83}.kint::-moz-selection{background:#268bd2;color:#657b83}.kint::-webkit-selection{background:#268bd2;color:#657b83}.kint{font-family:Consolas,"Courier New",monospace;color:#657b83;padding:0;margin:10px 0;font-size:10pt;line-height:15px;white-space:nowrap;overflow-x:auto;text-align:left}.kint *{float:none!important;padding:0;margin:0}.kint dt{background:#fdf6e3;border:1px solid #93a1a1;color:#657b83;display:block;font-weight:bold;list-style:none outside none;padding:5px}.kint dt:hover{border-color:#268bd2}.kint>dl dl{padding:0 0 0 15px;border-left:1px dashed #93a1a1}.kint nav{display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle;content:' ';cursor:pointer;background:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAA8CAMAAACO5hB7AAAA7VBMVEVYbnWToaH///9YbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnWToaFYbnVYbnWToaGToaFYbnWToaFYbnWToaFYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnWToaEeRtj1AAAATXRSTlMAAACLab0B7iP2R7CL9iPuaUewAb36F0/QnPoX0JxPYQaurepi6QV8FhV7MzFhM6586RYFMa3qYnsVBpNQ+ZGOGJ3PkM9QkZAY+Y6TnV7gnYsAAAEcSURBVHhebdHVbgMxEEBRu8sUZmqapBBoSuGUmWb+/3NayxtrLOe+Hck745XZgd6/eb3CVcKt7HmR+gKxlCGOETG5vFbOoahR6NxI5zHt6nuq+2dqnqfzzH3mfcz70vb8H6MJt5u6a96hS30E4PjEFgAEp2fKNojKUfVEOoS044ex7u3YPE/nmfvM+5j3pe17T9oe/77O41w+n4vnrbrwZxbTshVhvtx5Kb8vliRLRWmeSQSTjJq/El5x5fUXYmNN9hcQC5y4g/hGvVksNtT8451rns2IScb7mn567ll2GNpWr9YWfvQgzWsKs8HOA/m960g6rjTzA8HAV/NHwiOmPLwDKA/J/gggYsRVgFvqbr/fpWYv90zzZKKs9Qfx00Jx65oxLAAAAABJRU5ErkJggg==") no-repeat scroll 0 0 transparent}.kint dt.kint-parent:hover nav{background-position:0 -15px}.kint dt.kint-parent.kint-show:hover>nav{background-position:0 -45px}.kint dt.kint-show>nav{background-position:0 -30px}.kint dt.kint-parent+dd{display:none}.kint dt.kint-parent.kint-show+dd{display:block}.kint var{color:#268bd2;font-style:normal}.kint dt:hover var{color:#2aa198}.kint dfn{font-style:normal;font-family:monospace;color:#586e75}.kint pre{color:#657b83;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #93a1a1;background:#fdf6e3;display:block}.kint footer{padding:0 3px 3px;font-size:.7em}.kint a{color:#657b83;text-shadow:none}.kint a:hover{color:#586e75;border-bottom:1px dotted #586e75}.kint ul{list-style:none;padding-left:15px}.kint ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#fdf6e3;border:1px solid #93a1a1;border-top:0}.kint ul.kint-tabs li{background:#eee8d5;cursor:pointer;display:inline-block;height:24px;line-height:24px;margin:0 5px 5px;padding:0 12px 3px;border:1px solid #93a1a1}.kint ul.kint-tabs li:hover{border:1px solid #268bd2}.kint ul.kint-tabs li:hover var{color:#2aa198}.kint ul.kint-tabs li.kint-active-tab{background:#fdf6e3;border:1px solid #93a1a1;border-top:0;font-weight:bold;margin-top:-1px;padding-bottom:3px;padding-top:4px;border-right:1px solid #93a1a1}.kint ul.kint-tabs li+li{margin-left:0}.kint dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2}.kint dt:hover+dd>ul>li.kint-active-tab var{color:#2aa198}.kint ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-report{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-report *{text-align:left;padding:0;margin:0;font-size:9pt;overflow:hidden;font-family:Consolas,"Courier New",monospace;color:#657b83}.kint-report dt{padding:0;border:0;background:0}.kint-report dt.kint-parent{max-width:180px;min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-report dt.kint-parent.kint-show{border-bottom:1px solid #93a1a1}.kint-report td,.kint-report th{border:1px solid #93a1a1;vertical-align:top}.kint-report td{background:#fdf6e3;white-space:pre}.kint-report td>dl{border:0;padding:0}.kint-report dl,.kint-report pre,.kint-report label{padding:0}.kint-report pre{border-top:0;border-bottom:0;border-right:0}.kint-report label[for]:before{display:none}.kint-report th:first-child{background:0;border:0}.kint-report td:first-child,.kint-report th{font-weight:bold;background:#eee8d5;color:#586e75}.kint-report td.kint-empty{background:#d33682!important}.kint-report tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-report tr:hover var{color:#2aa198}.kint-trace .kint-source{line-height:1.1em}.kint-trace .kint-source span{padding-right:1px;border-right:3px inset #268bd2}.kint-trace .kint-source .kint-highlight{background:#eee8d5}.kint-trace .kint-parent>b{min-width:18px;display:inline-block;text-align:right;color:#586e75}.kint-trace var{margin-right:5px}.kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-color-preview{box-shadow:0 0 2px 0 #b6cedb;height:16px;text-align:center;text-shadow:-1px 0 #839496,0 1px #839496,1px 0 #839496,0 -1px #839496;width:230px;color:#fdf6e3}.kint>dl>dt,.kint ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset} \ No newline at end of file diff --git a/app/lib/kint/view/index.html b/app/lib/kint/view/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lib/kint/view/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/kint/view/js/_kint.js b/app/lib/kint/view/js/_kint.js new file mode 100644 index 0000000..b272062 --- /dev/null +++ b/app/lib/kint/view/js/_kint.js @@ -0,0 +1,344 @@ +/** +java -jar compiler.jar --js $FileName$ --js_output_file ../inc/kint.js --compilation_level ADVANCED_OPTIMIZATIONS --output_wrapper "(function(){%output%})()" +*/ + +if ( typeof kintInitialized === 'undefined' ) { + kintInitialized = 1; + var kint = { + visiblePluses : [], // all visible toggle carets + currentPlus : -1, // currently selected caret + + selectText : function( element ) { + var selection = window.getSelection(), + range = document.createRange(); + + range.selectNodeContents(element); + selection.removeAllRanges(); + selection.addRange(range); + }, + + hasClass : function( target, className ) { + if ( typeof className === 'undefined' ) { + className = 'kint-show'; + } + + return new RegExp('(\\s|^)' + className + '(\\s|$)').test(target.className); + }, + + addClass : function( ele, className ) { + if ( typeof className === 'undefined' ) { + className = 'kint-show'; + } + + kint.removeClass(ele, className).className += (" " + className); + }, + + removeClass : function( ele, className ) { + if ( typeof className === 'undefined' ) { + className = 'kint-show'; + } + + ele.className = ele.className.replace( + new RegExp('(\\s|^)' + className + '(\\s|$)'), ' ' + ); + return ele; + }, + + next : function( element ) { + do { + element = element.nextElementSibling; + } while ( element.nodeName.toLowerCase() !== 'dd' ); + + return element; + }, + + toggle : function( element, hide ) { + var parent = kint.next(element); + + if ( typeof hide === 'undefined' ) { + hide = kint.hasClass(element); + } + + if ( hide ) { + kint.removeClass(element); + } else { + kint.addClass(element); + } + + if ( parent.childNodes.length === 1 ) { + parent = parent.childNodes[0].childNodes[0]; // reuse variable cause I can + + if ( kint.hasClass(parent, 'kint-parent') ) { + kint.toggle(parent, hide) + } + } + }, + + toggleChildren : function( element, hide ) { + var parent = kint.next(element) + , nodes = parent.getElementsByClassName('kint-parent') + , i = nodes.length; + + if ( typeof hide === 'undefined' ) { + hide = kint.hasClass(element); + } + + while ( i-- ) { + kint.toggle(nodes[i], hide); + } + kint.toggle(element, hide); + }, + + toggleAll : function( caret ) { + var elements = document.getElementsByClassName('kint-parent'), + i = elements.length, + visible = kint.hasClass(caret.parentNode); + + while ( i-- ) { + kint.toggle(elements[i], visible); + } + }, + + switchTab : function( target ) { + var lis, el = target, index = 0; + + target.parentNode.getElementsByClassName('kint-active-tab')[0].className = ''; + target.className = 'kint-active-tab'; + + // take the index of clicked title tab and make the same n-th content tab visible + while ( el = el.previousSibling ) el.nodeType === 1 && index++; + lis = target.parentNode.nextSibling.childNodes; + for ( var i = 0; i < lis.length; i++ ) { + if ( i === index ) { + lis[i].style.display = 'block'; + + if ( lis[i].childNodes.length === 1 ) { + el = lis[i].childNodes[0].childNodes[0]; + + if ( kint.hasClass(el, 'kint-parent') ) { + kint.toggle(el, false) + } + } + } else { + lis[i].style.display = 'none'; + } + } + }, + + isSibling : function( el ) { + for ( ; ; ) { + el = el.parentNode; + if ( !el || kint.hasClass(el, 'kint') ) { + break; + } + } + + return !!el; + }, + + fetchVisiblePluses : function() { + kint.visiblePluses = []; + Array.prototype.slice.call(document.querySelectorAll('.kint nav, .kint-tabs>li:not(.kint-active-tab)'), 0) + .forEach( + function( el ) { + if ( el.offsetWidth !== 0 || el.offsetHeight !== 0 ) { + kint.visiblePluses.push(el) + } + } + ); + }, + + keyCallBacks : { + cleanup : function( i ) { + var focusedClass = 'kint-focused'; + var prevElement = document.querySelector('.' + focusedClass); + prevElement && kint.removeClass(prevElement, focusedClass); + + if ( i !== -1 ) { + var el = kint.visiblePluses[i]; + kint.addClass(el, focusedClass); + + + var offsetTop = function( el ) { + return el.offsetTop + ( el.offsetParent ? offsetTop(el.offsetParent) : 0 ); + }; + + var top = offsetTop(el) - (window.innerHeight / 2 ); + window.scrollTo(0, top); + } + + kint.currentPlus = i; + }, + + moveCursor : function( up, i ) { + // todo make the first VISIBLE plus active + if ( up ) { + if ( --i < 0 ) { + i = kint.visiblePluses.length - 1; + } + } else { + if ( ++i >= kint.visiblePluses.length ) { + i = 0; + } + } + + kint.keyCallBacks.cleanup(i); + return false; + } + } + }; + + window.addEventListener("click", function( e ) { + var target = e.target + , nodeName = target.nodeName.toLowerCase(); + + if ( !kint.isSibling(target) ) return; + + // auto-select name of variable + if ( nodeName === 'dfn' ) { + kint.selectText(target); + target = target.parentNode; + } else if ( nodeName === 'var' ) { // stupid workaround for misc elements + target = target.parentNode; // to not stop event from further propagating + nodeName = target.nodeName.toLowerCase() + } + + // switch tabs + if ( nodeName === 'li' && target.parentNode.className === 'kint-tabs' ) { + if ( target.className !== 'kint-active-tab' ) { + kint.switchTab(target); + if ( kint.currentPlus !== -1 ) kint.fetchVisiblePluses(); + } + return false; + } + + // handle clicks on the navigation caret + if ( nodeName === 'nav' ) { + // ensure doubleclick has different behaviour, see below + setTimeout(function() { + var timer = parseInt(target.kintTimer, 10); + if ( timer > 0 ) { + target.kintTimer--; + } else { + kint.toggleChildren(target.parentNode); //
+ if ( kint.currentPlus !== -1 ) kint.fetchVisiblePluses(); + } + }, 300); + e.stopPropagation(); + return false; + } else if ( kint.hasClass(target, 'kint-parent') ) { + kint.toggle(target); + if ( kint.currentPlus !== -1 ) kint.fetchVisiblePluses(); + return false; + } else if ( kint.hasClass(target, 'kint-ide-link') ) { + e.preventDefault(); + var ajax = new XMLHttpRequest(); // add ajax call to contact editor but prevent link default action + ajax.open('GET', target.href); + ajax.send(null); + return false; + } + }, false); + + window.addEventListener("dblclick", function( e ) { + var target = e.target; + if ( !kint.isSibling(target) ) return; + + + if ( target.nodeName.toLowerCase() === 'nav' ) { + target.kintTimer = 2; + kint.toggleAll(target); + if ( kint.currentPlus !== -1 ) kint.fetchVisiblePluses(); + e.stopPropagation(); + } + }, false); + + // keyboard navigation + window.onkeydown = function( e ) { + + // do nothing if alt key is pressed or if we're actually typing somewhere + if ( e.target !== document.body || e.altKey ) return; + + var keyCode = e.keyCode + , shiftKey = e.shiftKey + , i = kint.currentPlus; + + + if ( keyCode === 68 ) { // 'd' : toggles navigation on/off + if ( i === -1 ) { + kint.fetchVisiblePluses(); + return kint.keyCallBacks.moveCursor(false, i); + } else { + kint.keyCallBacks.cleanup(-1); + return false; + } + } else { + if ( i === -1 ) return; + + if ( keyCode === 9 ) { // TAB : moves up/down depending on shift key + return kint.keyCallBacks.moveCursor(shiftKey, i); + } else if ( keyCode === 38 ) { // ARROW UP : moves up + return kint.keyCallBacks.moveCursor(true, i); + } else if ( keyCode === 40 ) { // ARROW DOWN : down + return kint.keyCallBacks.moveCursor(false, i); + } else { + if ( i === -1 ) { + return; + } + } + } + + + var kintNode = kint.visiblePluses[i]; + if ( kintNode.nodeName.toLowerCase() === 'li' ) { // we're on a trace tab + if ( keyCode === 32 || keyCode === 13 ) { // SPACE/ENTER + kint.switchTab(kintNode); + kint.fetchVisiblePluses(); + return kint.keyCallBacks.moveCursor(true, i); + } else if ( keyCode === 39 ) { // arrows + return kint.keyCallBacks.moveCursor(false, i); + } else if ( keyCode === 37 ) { + return kint.keyCallBacks.moveCursor(true, i); + } + } + + kintNode = kintNode.parentNode; // simple dump + if ( keyCode === 32 || keyCode === 13 ) { // SPACE/ENTER : toggles + kint.toggle(kintNode); + kint.fetchVisiblePluses(); + return false; + } else if ( keyCode === 39 || keyCode === 37 ) { // ARROW LEFT/RIGHT : respectively hides/shows and traverses + var visible = kint.hasClass(kintNode); + var hide = keyCode === 37; + + if ( visible ) { + kint.toggleChildren(kintNode, hide); // expand/collapse all children if immediate ones are showing + } else { + if ( hide ) { // LEFT + // traverse to parent and THEN hide + do {kintNode = kintNode.parentNode} while ( kintNode && kintNode.nodeName.toLowerCase() !== 'dd' ); + + if ( kintNode ) { + kintNode = kintNode.previousElementSibling; + + i = -1; + var parentPlus = kintNode.querySelector('nav'); + while ( parentPlus !== kint.visiblePluses[++i] ) {} + kint.keyCallBacks.cleanup(i) + } else { // we are at root + kintNode = kint.visiblePluses[i].parentNode; + } + } + kint.toggle(kintNode, hide); + } + kint.fetchVisiblePluses(); + return false; + } + }; +} + +// debug purposes only, removed in minified source +function clg( i ) { + if ( !window.console )return; + var l = arguments.length, o = 0; + while ( o < l )console.log(arguments[o++]) +} diff --git a/app/lib/kint/view/js/index.html b/app/lib/kint/view/js/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lib/kint/view/js/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/kint/view/less/_kint.less b/app/lib/kint/view/less/_kint.less new file mode 100644 index 0000000..7fed5d0 --- /dev/null +++ b/app/lib/kint/view/less/_kint.less @@ -0,0 +1,340 @@ +@border: 1px solid @border-color; + +.selection() { + background : @border-color-hover; + color : @text-color; +} + +// +// BASE STYLES +// -------------------------------------------------- + +.kint::selection { .selection() } + +.kint::-moz-selection { .selection() } + +.kint::-webkit-selection { .selection() } + +.kint { + font-family : @default-font; + color : @text-color; + padding : 0; + margin : 10px 0; + font-size : 10pt; + line-height : 15px; + white-space : nowrap; + overflow-x : auto; + text-align : left; + + * { + float : none !important; + padding : 0; + margin : 0; + } + + dt { + background : @main-background; + border : @border; + color : @text-color; + display : block; + font-weight : bold; + list-style : none outside none; + padding : @spacing * 1px; + + &:hover { + border-color : @border-color-hover; + } + } + + > dl dl { + padding : 0 0 0 15px; + border-left : 1px dashed @border-color; + } + +// +// DROPDOWN CARET +// -------------------------------------------------- + + nav { + display : inline-block; + height : 15px; + width : 15px; + margin-right : 3px; + vertical-align : middle; + content : ' '; + cursor : pointer; + background : @caret-image no-repeat scroll 0 0 transparent; + } + + dt.kint-parent:hover nav { + background-position : 0 -15px; + } + + dt.kint-parent.kint-show:hover > nav { + background-position : 0 -45px; + } + + dt.kint-show > nav { + background-position : 0 -30px; + } + + dt.kint-parent + dd { + display : none; + } + + dt.kint-parent.kint-show + dd { + display : block; + } + +// +// INDIVIDUAL ITEMS +// -------------------------------------------------- + + var { + color : @variable-type-color; + font-style : normal; + } + + dt:hover var { + color : @variable-type-color-hover; + } + + dfn { + font-style : normal; + font-family : monospace; + color : @variable-name-color; + } + + pre { + color : @text-color; + margin : 0 0 0 15px; + padding : 5px; + overflow-y : hidden; + border-top : 0; + border : @border; + background : @main-background; + display : block; + } + + footer { + padding : 0 3px 3px; + font-size : .7em + } + + a { + color : @text-color; + text-shadow : none; + + &:hover { + color : @variable-name-color; + border-bottom : 1px dotted @variable-name-color; + } + } + +// +// TABS +// -------------------------------------------------- + + ul { + list-style : none; + padding-left : @spacing * 3px; + } + + ul.kint-tabs { + margin : 0 0 0 @spacing * 3px; + padding-left : 0; + background : @main-background; + border : @border; + border-top : 0; + + li { + background : @secondary-background; + cursor : pointer; + display : inline-block; + height : 16px + ceil(8px * (@spacing / 5)); + line-height : 16px + ceil(8px * (@spacing / 5)); + margin : 0 @spacing * 1px @spacing * 1px; + padding : 0 2px + @spacing * 2px floor(3px * (@spacing / 5)); + border : @border; + + &:hover { + border : 1px solid @border-color-hover; + } + + &:hover var { + color : @variable-type-color-hover; + } + + &.kint-active-tab { + background : @main-background; + border : @border; + border-top : 0; + font-weight : bold; + margin-top : -1px; + padding-bottom : floor(3px * (@spacing / 5)); + padding-top : 1px + ceil(3px * (@spacing / 5)); + border-right : @border; + } + } + + li+li { + margin-left : 0 + } + } + + dt:hover + dd > ul > li.kint-active-tab { + border-color : @border-color-hover; + } + + dt:hover + dd > ul > li.kint-active-tab var { + color : @variable-type-color-hover; + } + + ul:not(.kint-tabs)>li:not(:first-child) { + display : none; + } +} + +// +// REPORT +// -------------------------------------------------- + +.kint-report { + border-collapse : collapse; + empty-cells : show; + border-spacing : 0; + + * { + text-align : left; + padding : 0; + margin : 0; + font-size : 9pt; + overflow : hidden; + font-family : @default-font; + color : @text-color; + } + + dt { + padding : 0; + border : 0; + background: none; + } + + dt.kint-parent { + max-width : 180px; + min-width : 100%; + overflow : hidden; + text-overflow : ellipsis; + white-space : nowrap; + } + + dt.kint-parent.kint-show { + border-bottom: @border; + } + + td, + th { + border : @border; + vertical-align : top; + } + + td { + background : @main-background; + white-space : pre; + } + + td > dl { + border : 0; + padding : 0; + } + + dl, + pre, + label { + padding : 0; + } + + pre { + border-top : 0; + border-bottom : 0; + border-right : 0; + } + + label[for]:before { + display : none; + } + + th:first-child { + background : 0; + border : 0; + } + + td:first-child, + th { + font-weight : bold; + background : @secondary-background; + color : @variable-name-color; + } + + td.kint-empty { + background : #d33682 !important; + } + + tr:hover { + > td { + box-shadow : 0px 0px 1px 0px @border-color-hover inset; + } + + var { + color: @variable-type-color-hover; + } + + } +} + +// +// TRACE +// -------------------------------------------------- +.kint-trace { + .kint-source { + line-height : 1em + 0.02 * @spacing + } + + .kint-source span { + padding-right : 1px; + border-right : 3px inset @variable-type-color; + } + + .kint-source .kint-highlight { + background : @secondary-background; + } + + .kint-parent > b { + min-width : 18px; + display : inline-block; + text-align : right; + color : @variable-name-color; + } + + var { + margin-right : 5px; + } +} + +// +// MISC +// -------------------------------------------------- + +// keyboard navigation caret +.kint-focused { + .keyboard-caret +} + +.kint-color-preview { + box-shadow : 0 0 2px 0 #b6cedb; + height : 16px; + text-align : center; + text-shadow : -1px 0 #839496, 0 1px #839496, 1px 0 #839496, 0 -1px #839496; + width : 230px; + color : #fdf6e3; +} \ No newline at end of file diff --git a/app/lib/kint/view/less/index.html b/app/lib/kint/view/less/index.html new file mode 100644 index 0000000..c942a79 --- /dev/null +++ b/app/lib/kint/view/less/index.html @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/kint/view/less/original.less b/app/lib/kint/view/less/original.less new file mode 100644 index 0000000..9da7ba9 --- /dev/null +++ b/app/lib/kint/view/less/original.less @@ -0,0 +1,49 @@ +@import "_kint.less"; + +@default-font: Consolas, "Courier New", monospace; +@spacing : 4; + +@main-background: #e0eaef; +@secondary-background : #c1d4df; + +@text-color: #1d1e1e; +@variable-name-color: #1d1e1e; +@variable-type-color: #0092db; +@variable-type-color-hover: #5cb730; + +@border-color: #b6cedb; +@border-color-hover: #0092db; + +@caret-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAA8CAMAAACO5hB7AAAACVBMVEX///82b4tctzBls0NMAAAAQklEQVR42rWRIQ4AAAgCwf8/2qgER2BeuwJsgAqIzekMfMryPL9XQSkobE6vwKcsz/N7FfPvh09lnPf/b+7673+f0uHuAZ/EdkNQAAAAAElFTkSuQmCC"); + +.keyboard-caret() { + box-shadow : 0 0 3px 2px #5cb730; +} + +.kint { + > dl > dt { + background : -webkit-linear-gradient(top, #e3ecf0 0, #c0d4df 100%); + background : linear-gradient(to bottom, #e3ecf0 0, #c0d4df 100%); + } + + ul.kint-tabs { + background : -webkit-linear-gradient(top, #9dbed0 0px, #b2ccda 100%); + background : linear-gradient(to bottom, #9dbed0 0px, #b2ccda 100%); + } + + &:not(.kint-trace) > dl > dd > ul.kint-tabs li { + background : @main-background; + &.kint-active-tab { + background : @secondary-background; + } + } + + &.kint-trace > dl > dt { + background : -webkit-linear-gradient(top, #c0d4df 0px, #e3ecf0 100%); + background : linear-gradient(to bottom, #c0d4df 0px, #e3ecf0 100%); + } + + .kint-source .kint-highlight { + background : #f0eb96; + } +} \ No newline at end of file diff --git a/app/lib/kint/view/less/solarized-dark.less b/app/lib/kint/view/less/solarized-dark.less new file mode 100644 index 0000000..0d1dc23 --- /dev/null +++ b/app/lib/kint/view/less/solarized-dark.less @@ -0,0 +1,37 @@ +@import "_kint.less"; + +@default-font: Consolas, "Courier New", monospace; +@spacing : 5; + +@main-background: #002b36; // base 03 +@secondary-background : #073642; // base 02 + +@text-color: #839496; // base 0 +@variable-name-color: #93a1a1; // base 1 +@variable-type-color: #268bd2; // blue +@variable-type-color-hover: #2aa198; // cyan + +@border-color: #586e75; // base 01 +@border-color-hover: #268bd2; // blue + +@caret-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAA8CAMAAACO5hB7AAAA7VBMVEVYbnWToaH///9YbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnWToaFYbnVYbnWToaGToaFYbnWToaFYbnWToaFYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnWToaEeRtj1AAAATXRSTlMAAACLab0B7iP2R7CL9iPuaUewAb36F0/QnPoX0JxPYQaurepi6QV8FhV7MzFhM6586RYFMa3qYnsVBpNQ+ZGOGJ3PkM9QkZAY+Y6TnV7gnYsAAAEcSURBVHhebdHVbgMxEEBRu8sUZmqapBBoSuGUmWb+/3NayxtrLOe+Hck745XZgd6/eb3CVcKt7HmR+gKxlCGOETG5vFbOoahR6NxI5zHt6nuq+2dqnqfzzH3mfcz70vb8H6MJt5u6a96hS30E4PjEFgAEp2fKNojKUfVEOoS044ex7u3YPE/nmfvM+5j3pe17T9oe/77O41w+n4vnrbrwZxbTshVhvtx5Kb8vliRLRWmeSQSTjJq/El5x5fUXYmNN9hcQC5y4g/hGvVksNtT8451rns2IScb7mn567ll2GNpWr9YWfvQgzWsKs8HOA/m960g6rjTzA8HAV/NHwiOmPLwDKA/J/gggYsRVgFvqbr/fpWYv90zzZKKs9Qfx00Jx65oxLAAAAABJRU5ErkJggg=="); + +.keyboard-caret() { + box-shadow : 0 0 3px 2px #859900 inset; // green + border-radius : 7px; +} + +body { + background : @secondary-background; + color : #fff; // for non-kint elements to remain at least semi-readable +} + +.kint { + background : @secondary-background; + box-shadow : 0 0 5px 3px @secondary-background; + + > dl > dt, + ul.kint-tabs { + box-shadow : 4px 0 2px -3px @variable-type-color inset; + } +} \ No newline at end of file diff --git a/app/lib/kint/view/less/solarized.less b/app/lib/kint/view/less/solarized.less new file mode 100644 index 0000000..9a76181 --- /dev/null +++ b/app/lib/kint/view/less/solarized.less @@ -0,0 +1,27 @@ +@import "_kint.less"; + +@default-font: Consolas, "Courier New", monospace; +@spacing : 5; + +@main-background: #fdf6e3; // base 3 +@secondary-background : #eee8d5; // base 2 + +@text-color: #657b83; // base 00 +@variable-name-color: #586e75; // base 01 +@variable-type-color: #268bd2; // blue +@variable-type-color-hover: #2aa198; // cyan + +@border-color: #93a1a1; // base 1 +@border-color-hover: #268bd2; // blue + +@caret-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAA8CAMAAACO5hB7AAAA7VBMVEVYbnWToaH///9YbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnWToaFYbnVYbnWToaGToaFYbnWToaFYbnWToaFYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnVYbnWToaGToaGToaGToaGToaGToaGToaGToaGToaFYbnWToaEeRtj1AAAATXRSTlMAAACLab0B7iP2R7CL9iPuaUewAb36F0/QnPoX0JxPYQaurepi6QV8FhV7MzFhM6586RYFMa3qYnsVBpNQ+ZGOGJ3PkM9QkZAY+Y6TnV7gnYsAAAEcSURBVHhebdHVbgMxEEBRu8sUZmqapBBoSuGUmWb+/3NayxtrLOe+Hck745XZgd6/eb3CVcKt7HmR+gKxlCGOETG5vFbOoahR6NxI5zHt6nuq+2dqnqfzzH3mfcz70vb8H6MJt5u6a96hS30E4PjEFgAEp2fKNojKUfVEOoS044ex7u3YPE/nmfvM+5j3pe17T9oe/77O41w+n4vnrbrwZxbTshVhvtx5Kb8vliRLRWmeSQSTjJq/El5x5fUXYmNN9hcQC5y4g/hGvVksNtT8451rns2IScb7mn567ll2GNpWr9YWfvQgzWsKs8HOA/m960g6rjTzA8HAV/NHwiOmPLwDKA/J/gggYsRVgFvqbr/fpWYv90zzZKKs9Qfx00Jx65oxLAAAAABJRU5ErkJggg=="); + +.keyboard-caret() { + box-shadow : 0 0 3px 2px #859900 inset; // green + border-radius : 7px; +} + +.kint > dl > dt, +.kint ul.kint-tabs { + box-shadow : 4px 0 2px -3px @variable-type-color inset; +} \ No newline at end of file diff --git a/app/lib/kint/view/trace.phtml b/app/lib/kint/view/trace.phtml new file mode 100644 index 0000000..3641862 --- /dev/null +++ b/app/lib/kint/view/trace.phtml @@ -0,0 +1,77 @@ + Kint::$enabled, + 'displayCalledFrom' => Kint::$displayCalledFrom, +); +Kint::$enabled = true; +Kint::$displayCalledFrom = false; + +echo '
'; + +foreach ( $output as $i => $step ) { + echo '
' + . '' . ( $i + 1 ) . ' ' + . '' + . ''; + + if ( isset( $step['file'] ) ) { + echo Kint::shortenPath( $step['file'], $step['line'] ); + } else { + echo 'PHP internal call'; + } + + echo ''; + + echo $step['function']; + + if ( isset( $step['args'] ) ) { + echo '(' . implode( ', ', array_keys( $step['args'] ) ) . ')'; + } + echo '
'; + $firstTab = ' class="kint-active-tab"'; + echo '
    '; + + if ( !empty( $step['source'] ) ) { + echo "Source"; + $firstTab = ''; + } + + if ( !empty( $step['args'] ) ) { + echo "Arguments"; + $firstTab = ''; + } + + if ( !empty( $step['object'] ) ) { + kintParser::reset(); + $calleDump = kintParser::factory( $step['object'] ); + + echo "Callee object [{$calleDump->subtype}]"; + $firstTab = ''; + } + + + echo '
    '; + + + if ( !empty( $step['source'] ) ) { + echo "
  • {$step['source']}
  • "; + } + + if ( !empty( $step['args'] ) ) { + echo "
  • "; + foreach ( $step['args'] as $k => $arg ) { + kintParser::reset(); + echo Kint_Decorators_Rich::decorate( kintParser::factory( $arg, $k ) ); + } + echo "
  • "; + } + if ( !empty( $step['object'] ) ) { + echo "
  • " . Kint_Decorators_Rich::decorate( $calleDump ) . "
  • "; + } + + echo '
'; +} +echo '
'; +Kint::$enabled = $settings['enabled']; +Kint::$displayCalledFrom = $settings['displayCalledFrom']; +unset( $settings ); diff --git a/app/lib/lib.autoloader.php b/app/lib/lib.autoloader.php new file mode 100644 index 0000000..6d2e453 --- /dev/null +++ b/app/lib/lib.autoloader.php @@ -0,0 +1,10 @@ + + + 403 Forbidden + + + +

Directory access is forbidden.

+ + + \ No newline at end of file diff --git a/app/lib/medoo/medoo.min.php b/app/lib/medoo/medoo.min.php new file mode 100644 index 0000000..0178d1d --- /dev/null +++ b/app/lib/medoo/medoo.min.php @@ -0,0 +1,24 @@ +database_type);if(is_string($options)){if($type=='sqlite'){$this->database_file=$options;}else {$this->database_name=$options;}}else {foreach($options as $option=>$value){$this->$option=$value;}}$type=strtolower($this->database_type);if(isset($this->port)&&is_int($this->port*1)){$port='port='.$this->port.';';}switch($type){case 'mysql':case 'pgsql':$this->pdo=new PDO($type.':host='.$this->server.';'.$port.'dbname='.$this->database_name,$this->username,$this->password,$this->option);$this->pdo->exec('SET NAMES \''.$this->charset.'\'');break;case 'mssql':case 'sybase':$this->pdo=new PDO($type.':host='.$this->server.';'.$port.'dbname='.$this->database_name.','.$this->username.','.$this->password,$this->option);$this->pdo->exec('SET NAMES \''.$this->charset.'\'');break;case 'sqlite':$this->pdo=new PDO($type.':'.$this->database_file,null,null,$this->option);break;}}catch(PDOException$e){ throw new Exception($e->getMessage());}} public function query($query){$this->queryString=$query;return $this->pdo->query($query);} public function exec($query){$this->queryString=$query;return $this->pdo->exec($query);} public function quote($string){return $this->pdo->quote($string);} protected function column_quote($string){return '`'.str_replace('.','`.`',$string).'`';} protected function array_quote($array){$temp=array();foreach($array as $value){$temp[]=is_int($value)?$value:$this->pdo->quote($value);}return implode($temp,',');} protected function inner_conjunct($data,$conjunctor,$outer_conjunctor){$haystack=array();foreach($data as $value){$haystack[]='('.$this->data_implode($value,$conjunctor).')';}return implode($outer_conjunctor.' ',$haystack);} protected function data_implode($data,$conjunctor,$outer_conjunctor=null){$wheres=array();foreach($data as $key=>$value){if(($key=='AND'||$key=='OR')&&is_array($value)){$wheres[]=0!==count(array_diff_key($value,array_keys(array_keys($value))))?'('.$this->data_implode($value,' '.$key).')':'('.$this->inner_conjunct($value,' '.$key,$conjunctor).')';}else {preg_match('/([\w\.]+)(\[(\>|\>\=|\<|\<\=|\!|\<\>)\])?/i',$key,$match);if(isset($match[3])){if($match[3]==''){$wheres[]=$this->column_quote($match[1]).' '.$match[3].'= '.$this->quote($value);}elseif($match[3]=='!'){$column=$this->column_quote($match[1]);switch(gettype($value)){case 'NULL':$wheres[]=$column.' IS NOT NULL';break;case 'array':$wheres[]=$column.' NOT IN ('.$this->array_quote($value).')';break;case 'integer':$wheres[]=$column.' != '.$value;break;case 'string':$wheres[]=$column.' != '.$this->quote($value);break;}}else {if($match[3]=='<>'){if(is_array($value)){if(is_numeric($value[0])&&is_numeric($value[1])){$wheres[]=$this->column_quote($match[1]).' BETWEEN '.$value[0].' AND '.$value[1];}else {$wheres[]=$this->column_quote($match[1]).' BETWEEN '.$this->quote($value[0]).' AND '.$this->quote($value[1]);}}}else {if(is_numeric($value)){$wheres[]=$this->column_quote($match[1]).' '.$match[3].' '.$value;}else {$datetime=strtotime($value);if($datetime){$wheres[]=$this->column_quote($match[1]).' '.$match[3].' '.$this->quote(date('Y-m-d H:i:s',$datetime));}}}}}else {if(is_int($key)){$wheres[]=$this->quote($value);}else {$column=$this->column_quote($match[1]);switch(gettype($value)){case 'NULL':$wheres[]=$column.' IS NULL';break;case 'array':$wheres[]=$column.' IN ('.$this->array_quote($value).')';break;case 'integer':$wheres[]=$column.' = '.$value;break;case 'string':$wheres[]=$column.' = '.$this->quote($value);break;}}}}}return implode($conjunctor.' ',$wheres);} public function where_clause($where){$where_clause='';if(is_array($where)){$single_condition=array_diff_key($where,array_flip(explode(' ','AND OR GROUP ORDER HAVING LIMIT LIKE MATCH')));if($single_condition!=array()){$where_clause=' WHERE '.$this->data_implode($single_condition,'');}if(isset($where['AND'])){$where_clause=' WHERE '.$this->data_implode($where['AND'],' AND');}if(isset($where['OR'])){$where_clause=' WHERE '.$this->data_implode($where['OR'],' OR');}if(isset($where['LIKE'])){$like_query=$where['LIKE'];if(is_array($like_query)){$is_OR=isset($like_query['OR']);if($is_OR||isset($like_query['AND'])){$connector=$is_OR?'OR':'AND';$like_query=$is_OR?$like_query['OR']:$like_query['AND'];}else {$connector='AND';}$clause_wrap=array();foreach($like_query as $column=>$keyword){if(is_array($keyword)){foreach($keyword as $key){$clause_wrap[]=$this->column_quote($column).' LIKE '.$this->quote('%'.$key.'%');}}else {$clause_wrap[]=$this->column_quote($column).' LIKE '.$this->quote('%'.$keyword.'%');}}$where_clause.=($where_clause!=''?' AND ':' WHERE ').'('.implode($clause_wrap,' '.$connector.' ').')';}}if(isset($where['MATCH'])){$match_query=$where['MATCH'];if(is_array($match_query)&&isset($match_query['columns'])&&isset($match_query['keyword'])){$where_clause.=($where_clause!=''?' AND ':' WHERE ').' MATCH (`'.str_replace('.','`.`',implode($match_query['columns'],'`, `')).'`) AGAINST ('.$this->quote($match_query['keyword']).')';}}if(isset($where['GROUP'])){$where_clause.=' GROUP BY '.$this->column_quote($where['GROUP']);}if(isset($where['ORDER'])){preg_match('/(^[a-zA-Z0-9_\-\.]*)(\s*(DESC|ASC))?/',$where['ORDER'],$order_match);$where_clause.=' ORDER BY `'.str_replace('.','`.`',$order_match[1]).'` '.(isset($order_match[3])?$order_match[3]:'');if(isset($where['HAVING'])){$where_clause.=' HAVING '.$this->data_implode($where['HAVING'],'');}}if(isset($where['LIMIT'])){if(is_numeric($where['LIMIT'])){$where_clause.=' LIMIT '.$where['LIMIT'];}if(is_array($where['LIMIT'])&&is_numeric($where['LIMIT'][0])&&is_numeric($where['LIMIT'][1])){$where_clause.=' LIMIT '.$where['LIMIT'][0].','.$where['LIMIT'][1];}}}else {if($where!=null){$where_clause.=' '.$where;}}return $where_clause;} public function select($table,$join,$columns=null,$where=null){$table='`'.$table.'`';$join_key=is_array($join)?array_keys($join):null;if(strpos($join_key[0],'[')!==false){$table_join=array();$join_array=array('>'=>'LEFT','<'=>'RIGHT','<>'=>'FULL','><'=>'INNER');foreach($join as $sub_table=>$relation){preg_match('/(\[(\<|\>|\>\<|\<\>)\])?([a-zA-Z0-9_\-]*)/',$sub_table,$match);if($match[2]!=''&&$match[3]!=''){if(is_string($relation)){$relation='USING (`'.$relation.'`)';}if(is_array($relation)){if(isset($relation[0])){$relation='USING (`'.implode($relation,'`, `').'`)';}else {$relation='ON '.$table.'.`'.key($relation).'` = `'.$match[3].'`.`'.current($relation).'`';}}$table_join[]=$join_array[$match[2]].' JOIN `'.$match[3].'` '.$relation;}}$table.=' '.implode($table_join,' ');}else {$where=$columns;$columns=$join;}$where_clause=$this->where_clause($where);$query=$this->query('SELECT '.(is_array($columns)?$this->column_quote(implode('`, `',$columns)):($columns=='*'?'*':'`'.$columns.'`')).' FROM '.$table.$where_clause);return $query?$query->fetchAll((is_string($columns)&&$columns!='*')?PDO::FETCH_COLUMN:PDO::FETCH_ASSOC):false;} public function insert($table,$datas){$lastId=array();if(!isset($datas[0])){$datas=array($datas);}foreach($datas as $data){$keys=implode("`, `",array_keys($data));$values=array();foreach($data as $key=>$value){switch(gettype($value)){case 'NULL':$values[]='NULL';break;case 'array':$values[]=$this->quote(serialize($value));break;case 'integer':case 'string':$values[]=$this->quote($value);break;}}$this->exec('INSERT INTO `'.$table.'` (`'.$keys.'`) VALUES ('.implode($values,', ').')');$lastId[]=$this->pdo->lastInsertId();}return count($lastId)>1?$lastId:$lastId[0];} public function update($table,$data,$where=null){$fields=array();foreach($data as $key=>$value){$key='`'.$key.'`';if(is_array($value)){$fields[]=$key.'='.$this->quote(serialize($value));}else {preg_match('/([\w]+)(\[(\+|\-)\])?/i',$key,$match);if(isset($match[3])){if(is_numeric($value)){$fields[]=$match[1].' = '.$match[1].' '.$match[3].' '.$value;}}else {switch(gettype($value)){case 'NULL':$fields[]=$key.' = NULL';break;case 'array':$fields[]=$key.' = '.$this->quote(serialize($value));break;case 'integer':case 'string':$fields[]=$key.' = '.$this->quote($value);break;}}}}return $this->exec('UPDATE `'.$table.'` SET '.implode(', ',$fields).$this->where_clause($where));} public function delete($table,$where){return $this->exec('DELETE FROM `'.$table.'`'.$this->where_clause($where));} public function replace($table,$columns,$search=null,$replace=null,$where=null){if(is_array($columns)){$replace_query=array();foreach($columns as $column=>$replacements){foreach($replacements as $replace_search=>$replace_replacement){$replace_query[]=$column.' = REPLACE(`'.$column.'`, '.$this->quote($replace_search).', '.$this->quote($replace_replacement).')';}}$replace_query=implode(', ',$replace_query);$where=$search;}else {if(is_array($search)){$replace_query=array();foreach($search as $replace_search=>$replace_replacement){$replace_query[]=$columns.' = REPLACE(`'.$columns.'`, '.$this->quote($replace_search).', '.$this->quote($replace_replacement).')';}$replace_query=implode(', ',$replace_query);$where=$replace;}else {$replace_query=$columns.' = REPLACE(`'.$columns.'`, '.$this->quote($search).', '.$this->quote($replace).')';}}return $this->exec('UPDATE `'.$table.'` SET '.$replace_query.$this->where_clause($where));} public function get($table,$columns,$where=null){if(!isset($where)){$where=array();}$where['LIMIT']=1;$data=$this->select($table,$columns,$where);return isset($data[0])?$data[0]:false;} public function has($table,$where){return $this->query('SELECT EXISTS(SELECT 1 FROM `'.$table.'`'.$this->where_clause($where).')')->fetchColumn()==='1';} public function count($table,$where=null){return 0+($this->query('SELECT COUNT(*) FROM `'.$table.'`'.$this->where_clause($where))->fetchColumn());} public function max($table,$column,$where=null){return 0+($this->query('SELECT MAX(`'.$column.'`) FROM `'.$table.'`'.$this->where_clause($where))->fetchColumn());} public function min($table,$column,$where=null){return 0+($this->query('SELECT MIN(`'.$column.'`) FROM `'.$table.'`'.$this->where_clause($where))->fetchColumn());} public function avg($table,$column,$where=null){return 0+($this->query('SELECT AVG(`'.$column.'`) FROM `'.$table.'`'.$this->where_clause($where))->fetchColumn());} public function sum($table,$column,$where=null){return 0+($this->query('SELECT SUM(`'.$column.'`) FROM `'.$table.'`'.$this->where_clause($where))->fetchColumn());} public function error(){return $this->pdo->errorInfo();} public function last_query(){return $this->queryString;} public function info(){return array('server'=>$this->pdo->getAttribute(PDO::ATTR_SERVER_INFO),'client'=>$this->pdo->getAttribute(PDO::ATTR_CLIENT_VERSION),'driver'=>$this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME),'version'=>$this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION),'connection'=>$this->pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS));} +} +?> \ No newline at end of file diff --git a/app/lib/medoo/medoo.php b/app/lib/medoo/medoo.php new file mode 100644 index 0000000..9108474 --- /dev/null +++ b/app/lib/medoo/medoo.php @@ -0,0 +1,641 @@ +database_type); + + if (is_string($options)) + { + if ($type == 'sqlite') + { + $this->database_file = $options; + } + else + { + $this->database_name = $options; + } + } + else + { + foreach ($options as $option => $value) + { + $this->$option = $value; + } + } + + $type = strtolower($this->database_type); + + if ( + isset($this->port) && + is_int($this->port * 1) + ) + { + $port = 'port=' . $this->port . ';'; + } + + switch ($type) + { + case 'mysql': + case 'pgsql': + $this->pdo = new PDO( + $type . ':host=' . $this->server . ';' . $port . 'dbname=' . $this->database_name, + $this->username, + $this->password, + $this->option + ); + $this->pdo->exec('SET NAMES \'' . $this->charset . '\''); + break; + + case 'mssql': + case 'sybase': + $this->pdo = new PDO( + $type . ':host=' . $this->server . ';' . $port . 'dbname=' . $this->database_name . ',' . + $this->username . ',' . + $this->password, + $this->option + ); + $this->pdo->exec('SET NAMES \'' . $this->charset . '\''); + break; + + case 'sqlite': + $this->pdo = new PDO( + $type . ':' . $this->database_file, + null, + null, + $this->option + ); + break; + } + } + catch (PDOException $e) { + throw new Exception($e->getMessage()); + } + } + + public function query($query) + { + $this->queryString = $query; + + return $this->pdo->query($query); + } + + public function exec($query) + { + $this->queryString = $query; + + return $this->pdo->exec($query); + } + + public function quote($string) + { + return $this->pdo->quote($string); + } + + protected function column_quote($string) + { + return '`' . str_replace('.', '`.`', $string) . '`'; + } + + protected function array_quote($array) + { + $temp = array(); + + foreach ($array as $value) + { + $temp[] = is_int($value) ? $value : $this->pdo->quote($value); + } + + return implode($temp, ','); + } + + protected function inner_conjunct($data, $conjunctor, $outer_conjunctor) + { + $haystack = array(); + + foreach ($data as $value) + { + $haystack[] = '(' . $this->data_implode($value, $conjunctor) . ')'; + } + + return implode($outer_conjunctor . ' ', $haystack); + } + + protected function data_implode($data, $conjunctor, $outer_conjunctor = null) + { + $wheres = array(); + + foreach ($data as $key => $value) + { + if ( + ($key == 'AND' || $key == 'OR') && + is_array($value) + ) + { + $wheres[] = 0 !== count(array_diff_key($value, array_keys(array_keys($value)))) ? + '(' . $this->data_implode($value, ' ' . $key) . ')' : + '(' . $this->inner_conjunct($value, ' ' . $key, $conjunctor) . ')'; + } + else + { + preg_match('/([\w\.]+)(\[(\>|\>\=|\<|\<\=|\!|\<\>)\])?/i', $key, $match); + if (isset($match[3])) + { + if ($match[3] == '') + { + $wheres[] = $this->column_quote($match[1]) . ' ' . $match[3] . '= ' . $this->quote($value); + } + elseif ($match[3] == '!') + { + $column = $this->column_quote($match[1]); + + switch (gettype($value)) + { + case 'NULL': + $wheres[] = $column . ' IS NOT NULL'; + break; + + case 'array': + $wheres[] = $column . ' NOT IN (' . $this->array_quote($value) . ')'; + break; + + case 'integer': + $wheres[] = $column . ' != ' . $value; + break; + + case 'string': + $wheres[] = $column . ' != ' . $this->quote($value); + break; + } + } + else + { + if ($match[3] == '<>') + { + if (is_array($value)) + { + if (is_numeric($value[0]) && is_numeric($value[1])) + { + $wheres[] = $this->column_quote($match[1]) . ' BETWEEN ' . $value[0] . ' AND ' . $value[1]; + } + else + { + $wheres[] = $this->column_quote($match[1]) . ' BETWEEN ' . $this->quote($value[0]) . ' AND ' . $this->quote($value[1]); + } + } + } + else + { + if (is_numeric($value)) + { + $wheres[] = $this->column_quote($match[1]) . ' ' . $match[3] . ' ' . $value; + } + else + { + $datetime = strtotime($value); + + if ($datetime) + { + $wheres[] = $this->column_quote($match[1]) . ' ' . $match[3] . ' ' . $this->quote(date('Y-m-d H:i:s', $datetime)); + } + } + } + } + } + else + { + if (is_int($key)) + { + $wheres[] = $this->quote($value); + } + else + { + $column = $this->column_quote($match[1]); + switch (gettype($value)) + { + case 'NULL': + $wheres[] = $column . ' IS NULL'; + break; + + case 'array': + $wheres[] = $column . ' IN (' . $this->array_quote($value) . ')'; + break; + + case 'integer': + $wheres[] = $column . ' = ' . $value; + break; + + case 'string': + $wheres[] = $column . ' = ' . $this->quote($value); + break; + } + } + } + } + } + + return implode($conjunctor . ' ', $wheres); + } + + public function where_clause($where) + { + $where_clause = ''; + + if (is_array($where)) + { + $single_condition = array_diff_key($where, array_flip( + explode(' ', 'AND OR GROUP ORDER HAVING LIMIT LIKE MATCH') + )); + + if ($single_condition != array()) + { + $where_clause = ' WHERE ' . $this->data_implode($single_condition, ''); + } + if (isset($where['AND'])) + { + $where_clause = ' WHERE ' . $this->data_implode($where['AND'], ' AND'); + } + if (isset($where['OR'])) + { + $where_clause = ' WHERE ' . $this->data_implode($where['OR'], ' OR'); + } + if (isset($where['LIKE'])) + { + $like_query = $where['LIKE']; + if (is_array($like_query)) + { + $is_OR = isset($like_query['OR']); + + if ($is_OR || isset($like_query['AND'])) + { + $connector = $is_OR ? 'OR' : 'AND'; + $like_query = $is_OR ? $like_query['OR'] : $like_query['AND']; + } + else + { + $connector = 'AND'; + } + + $clause_wrap = array(); + foreach ($like_query as $column => $keyword) + { + if (is_array($keyword)) + { + foreach ($keyword as $key) + { + $clause_wrap[] = $this->column_quote($column) . ' LIKE ' . $this->quote('%' . $key . '%'); + } + } + else + { + $clause_wrap[] = $this->column_quote($column) . ' LIKE ' . $this->quote('%' . $keyword . '%'); + } + } + $where_clause .= ($where_clause != '' ? ' AND ' : ' WHERE ') . '(' . implode($clause_wrap, ' ' . $connector . ' ') . ')'; + } + } + if (isset($where['MATCH'])) + { + $match_query = $where['MATCH']; + if (is_array($match_query) && isset($match_query['columns']) && isset($match_query['keyword'])) + { + $where_clause .= ($where_clause != '' ? ' AND ' : ' WHERE ') . ' MATCH (`' . str_replace('.', '`.`', implode($match_query['columns'], '`, `')) . '`) AGAINST (' . $this->quote($match_query['keyword']) . ')'; + } + } + if (isset($where['GROUP'])) + { + $where_clause .= ' GROUP BY ' . $this->column_quote($where['GROUP']); + } + if (isset($where['ORDER'])) + { + preg_match('/(^[a-zA-Z0-9_\-\.]*)(\s*(DESC|ASC))?/', $where['ORDER'], $order_match); + + $where_clause .= ' ORDER BY `' . str_replace('.', '`.`', $order_match[1]) . '` ' . (isset($order_match[3]) ? $order_match[3] : ''); + + if (isset($where['HAVING'])) + { + $where_clause .= ' HAVING ' . $this->data_implode($where['HAVING'], ''); + } + } + if (isset($where['LIMIT'])) + { + if (is_numeric($where['LIMIT'])) + { + $where_clause .= ' LIMIT ' . $where['LIMIT']; + } + if ( + is_array($where['LIMIT']) && + is_numeric($where['LIMIT'][0]) && + is_numeric($where['LIMIT'][1]) + ) + { + $where_clause .= ' LIMIT ' . $where['LIMIT'][0] . ',' . $where['LIMIT'][1]; + } + } + } + else + { + if ($where != null) + { + $where_clause .= ' ' . $where; + } + } + + return $where_clause; + } + + public function select($table, $join, $columns = null, $where = null) + { + $table = '`' . $table . '`'; + $join_key = is_array($join) ? array_keys($join) : null; + + if (strpos($join_key[0], '[') !== false) + { + $table_join = array(); + + $join_array = array( + '>' => 'LEFT', + '<' => 'RIGHT', + '<>' => 'FULL', + '><' => 'INNER' + ); + + foreach($join as $sub_table => $relation) + { + preg_match('/(\[(\<|\>|\>\<|\<\>)\])?([a-zA-Z0-9_\-]*)/', $sub_table, $match); + + if ($match[2] != '' && $match[3] != '') + { + if (is_string($relation)) + { + $relation = 'USING (`' . $relation . '`)'; + } + + if (is_array($relation)) + { + // For ['column1', 'column2'] + if (isset($relation[0])) + { + $relation = 'USING (`' . implode($relation, '`, `') . '`)'; + } + // For ['column1' => 'column2'] + else + { + $relation = 'ON ' . $table . '.`' . key($relation) . '` = `' . $match[3] . '`.`' . current($relation) . '`'; + } + } + + $table_join[] = $join_array[ $match[2] ] . ' JOIN `' . $match[3] . '` ' . $relation; + } + } + + $table .= ' ' . implode($table_join, ' '); + } + else + { + $where = $columns; + $columns = $join; + } + + $where_clause = $this->where_clause($where); + + $query = + $this->query('SELECT ' . + ( + is_array($columns) ? $this->column_quote( implode('`, `', $columns) ) : + ($columns == '*' ? '*' : '`' . $columns . '`') + ) . + ' FROM ' . $table . $where_clause + ); + + return $query ? $query->fetchAll( + (is_string($columns) && $columns != '*') ? PDO::FETCH_COLUMN : PDO::FETCH_ASSOC + ) : false; + } + + public function insert($table, $datas) + { + $lastId = array(); + + // Check indexed or associative array + if (!isset($datas[0])) + { + $datas = array($datas); + } + + foreach ($datas as $data) + { + $keys = implode("`, `", array_keys($data)); + $values = array(); + + foreach ($data as $key => $value) + { + switch (gettype($value)) + { + case 'NULL': + $values[] = 'NULL'; + break; + + case 'array': + $values[] = $this->quote(serialize($value)); + break; + + case 'integer': + case 'string': + $values[] = $this->quote($value); + break; + } + } + + $this->exec('INSERT INTO `' . $table . '` (`' . $keys . '`) VALUES (' . implode($values, ', ') . ')'); + + $lastId[] = $this->pdo->lastInsertId(); + } + + return count($lastId) > 1 ? $lastId : $lastId[ 0 ]; + } + + public function update($table, $data, $where = null) + { + $fields = array(); + + foreach ($data as $key => $value) + { + $key = '`' . $key . '`'; + + if (is_array($value)) + { + $fields[] = $key . '=' . $this->quote(serialize($value)); + } + else + { + preg_match('/([\w]+)(\[(\+|\-)\])?/i', $key, $match); + if (isset($match[3])) + { + if (is_numeric($value)) + { + $fields[] = $match[1] . ' = ' . $match[1] . ' ' . $match[3] . ' ' . $value; + } + } + else + { + switch (gettype($value)) + { + case 'NULL': + $fields[] = $key . ' = NULL'; + break; + + case 'array': + $fields[] = $key . ' = ' . $this->quote(serialize($value)); + break; + + case 'integer': + case 'string': + $fields[] = $key . ' = ' . $this->quote($value); + break; + } + } + } + } + + return $this->exec('UPDATE `' . $table . '` SET ' . implode(', ', $fields) . $this->where_clause($where)); + } + + public function delete($table, $where) + { + return $this->exec('DELETE FROM `' . $table . '`' . $this->where_clause($where)); + } + + public function replace($table, $columns, $search = null, $replace = null, $where = null) + { + if (is_array($columns)) + { + $replace_query = array(); + + foreach ($columns as $column => $replacements) + { + foreach ($replacements as $replace_search => $replace_replacement) + { + $replace_query[] = $column . ' = REPLACE(`' . $column . '`, ' . $this->quote($replace_search) . ', ' . $this->quote($replace_replacement) . ')'; + } + } + $replace_query = implode(', ', $replace_query); + $where = $search; + } + else + { + if (is_array($search)) + { + $replace_query = array(); + + foreach ($search as $replace_search => $replace_replacement) + { + $replace_query[] = $columns . ' = REPLACE(`' . $columns . '`, ' . $this->quote($replace_search) . ', ' . $this->quote($replace_replacement) . ')'; + } + $replace_query = implode(', ', $replace_query); + $where = $replace; + } + else + { + $replace_query = $columns . ' = REPLACE(`' . $columns . '`, ' . $this->quote($search) . ', ' . $this->quote($replace) . ')'; + } + } + + return $this->exec('UPDATE `' . $table . '` SET ' . $replace_query . $this->where_clause($where)); + } + + public function get($table, $columns, $where = null) + { + if (!isset($where)) + { + $where = array(); + } + $where['LIMIT'] = 1; + + $data = $this->select($table, $columns, $where); + + return isset($data[0]) ? $data[0] : false; + } + + public function has($table, $where) + { + return $this->query('SELECT EXISTS(SELECT 1 FROM `' . $table . '`' . $this->where_clause($where) . ')')->fetchColumn() === '1'; + } + + public function count($table, $where = null) + { + return 0 + ($this->query('SELECT COUNT(*) FROM `' . $table . '`' . $this->where_clause($where))->fetchColumn()); + } + + public function max($table, $column, $where = null) + { + return 0 + ($this->query('SELECT MAX(`' . $column . '`) FROM `' . $table . '`' . $this->where_clause($where))->fetchColumn()); + } + + public function min($table, $column, $where = null) + { + return 0 + ($this->query('SELECT MIN(`' . $column . '`) FROM `' . $table . '`' . $this->where_clause($where))->fetchColumn()); + } + + public function avg($table, $column, $where = null) + { + return 0 + ($this->query('SELECT AVG(`' . $column . '`) FROM `' . $table . '`' . $this->where_clause($where))->fetchColumn()); + } + + public function sum($table, $column, $where = null) + { + return 0 + ($this->query('SELECT SUM(`' . $column . '`) FROM `' . $table . '`' . $this->where_clause($where))->fetchColumn()); + } + + public function error() + { + return $this->pdo->errorInfo(); + } + + public function last_query() + { + return $this->queryString; + } + + public function info() + { + return array( + 'server' => $this->pdo->getAttribute(PDO::ATTR_SERVER_INFO), + 'client' => $this->pdo->getAttribute(PDO::ATTR_CLIENT_VERSION), + 'driver' => $this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME), + 'version' => $this->pdo->getAttribute(PDO::ATTR_SERVER_VERSION), + 'connection' => $this->pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS) + ); + } +} +?> \ No newline at end of file diff --git a/app/lib/rain.tpl.class.php b/app/lib/rain.tpl.class.php new file mode 100644 index 0000000..1e37e2d --- /dev/null +++ b/app/lib/rain.tpl.class.php @@ -0,0 +1,1042 @@ +), stylesheet (), script (This is a p

+ * @before $.metadata.setType("elem", "script") + * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label" + * @desc Reads metadata from a nested script element + * + * @param String type The encoding type + * @param String name The name of the attribute to be used to get metadata (optional) + * @cat Plugins/Metadata + * @descr Sets the type of encoding to be used when loading metadata for the first time + * @type undefined + * @see metadata() + */ + +(function($) { + +$.extend({ + metadata : { + defaults : { + type: 'class', + name: 'metadata', + cre: /(\{.*\})/, + single: 'metadata' + }, + setType: function( type, name ){ + this.defaults.type = type; + this.defaults.name = name; + }, + get: function( elem, opts ){ + var data, m, e, attr, + settings = $.extend({},this.defaults,opts); + // check for empty string in single property + if ( !settings.single.length ) { settings.single = 'metadata'; } + + data = $.data(elem, settings.single); + // returned cached data if it already exists + if ( data ) { return data; } + + data = "{}"; + + if ( settings.type === "class" ) { + m = settings.cre.exec( elem.className ); + if ( m ) { data = m[1]; } + } else if ( settings.type === "elem" ) { + if( !elem.getElementsByTagName ) { return undefined; } + e = elem.getElementsByTagName(settings.name); + if ( e.length ) { data = $.trim(e[0].innerHTML); } + } else if ( elem.getAttribute !== undefined ) { + attr = elem.getAttribute( settings.name ); + if ( attr ) { data = attr; } + } + + if ( data.indexOf( '{' ) <0 ) { data = "{" + data + "}"; } + + data = eval("(" + data + ")"); + + $.data( elem, settings.single, data ); + return data; + } + } +}); + +/** + * Returns the metadata object for the first member of the jQuery object. + * + * @name metadata + * @descr Returns element's metadata object + * @param Object opts An object contianing settings to override the defaults + * @type jQuery + * @cat Plugins/Metadata + */ +$.fn.metadata = function( opts ){ + return $.metadata.get( this[0], opts ); +}; + +})(jQuery); \ No newline at end of file diff --git a/app/res/js/jquery.min.js b/app/res/js/jquery.min.js new file mode 100644 index 0000000..4f7ccaa --- /dev/null +++ b/app/res/js/jquery.min.js @@ -0,0 +1,5 @@ +/*! jQuery v2.1.0 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k="".trim,l={},m=a.document,n="2.1.0",o=function(a,b){return new o.fn.init(a,b)},p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};o.fn=o.prototype={jquery:n,constructor:o,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=o.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return o.each(this,a,b)},map:function(a){return this.pushStack(o.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},o.extend=o.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||o.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(o.isPlainObject(d)||(e=o.isArray(d)))?(e?(e=!1,f=c&&o.isArray(c)?c:[]):f=c&&o.isPlainObject(c)?c:{},g[b]=o.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},o.extend({expando:"jQuery"+(n+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===o.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return a-parseFloat(a)>=0},isPlainObject:function(a){if("object"!==o.type(a)||a.nodeType||o.isWindow(a))return!1;try{if(a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(b){return!1}return!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=o.trim(a),a&&(1===a.indexOf("use strict")?(b=m.createElement("script"),b.text=a,m.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":k.call(a)},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?o.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),o.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||o.guid++,f):void 0},now:Date.now,support:l}),o.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=o.type(a);return"function"===c||o.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s="sizzle"+-new Date,t=a.document,u=0,v=0,w=eb(),x=eb(),y=eb(),z=function(a,b){return a===b&&(j=!0),0},A="undefined",B=1<<31,C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=D.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",M=L.replace("w","w#"),N="\\["+K+"*("+L+")"+K+"*(?:([*^$|!~]?=)"+K+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+M+")|)|)"+K+"*\\]",O=":("+L+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+N.replace(3,8)+")*)|.*)\\)|)",P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(O),U=new RegExp("^"+M+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L.replace("w","w*")+")"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=/'|\\/g,ab=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),bb=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{G.apply(D=H.call(t.childNodes),t.childNodes),D[t.childNodes.length].nodeType}catch(cb){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function db(a,b,d,e){var f,g,h,i,j,m,p,q,u,v;if((b?b.ownerDocument||b:t)!==l&&k(b),b=b||l,d=d||[],!a||"string"!=typeof a)return d;if(1!==(i=b.nodeType)&&9!==i)return[];if(n&&!e){if(f=Z.exec(a))if(h=f[1]){if(9===i){if(g=b.getElementById(h),!g||!g.parentNode)return d;if(g.id===h)return d.push(g),d}else if(b.ownerDocument&&(g=b.ownerDocument.getElementById(h))&&r(b,g)&&g.id===h)return d.push(g),d}else{if(f[2])return G.apply(d,b.getElementsByTagName(a)),d;if((h=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(h)),d}if(c.qsa&&(!o||!o.test(a))){if(q=p=s,u=b,v=9===i&&a,1===i&&"object"!==b.nodeName.toLowerCase()){m=ob(a),(p=b.getAttribute("id"))?q=p.replace(_,"\\$&"):b.setAttribute("id",q),q="[id='"+q+"'] ",j=m.length;while(j--)m[j]=q+pb(m[j]);u=$.test(a)&&mb(b.parentNode)||b,v=m.join(",")}if(v)try{return G.apply(d,u.querySelectorAll(v)),d}catch(w){}finally{p||b.removeAttribute("id")}}}return xb(a.replace(P,"$1"),b,d,e)}function eb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function fb(a){return a[s]=!0,a}function gb(a){var b=l.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function hb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function ib(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||B)-(~a.sourceIndex||B);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function jb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function kb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function lb(a){return fb(function(b){return b=+b,fb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function mb(a){return a&&typeof a.getElementsByTagName!==A&&a}c=db.support={},f=db.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},k=db.setDocument=function(a){var b,e=a?a.ownerDocument||a:t,g=e.defaultView;return e!==l&&9===e.nodeType&&e.documentElement?(l=e,m=e.documentElement,n=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){k()},!1):g.attachEvent&&g.attachEvent("onunload",function(){k()})),c.attributes=gb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=gb(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(e.getElementsByClassName)&&gb(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=gb(function(a){return m.appendChild(a).id=s,!e.getElementsByName||!e.getElementsByName(s).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==A&&n){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ab,bb);return function(a){var c=typeof a.getAttributeNode!==A&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==A?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==A&&n?b.getElementsByClassName(a):void 0},p=[],o=[],(c.qsa=Y.test(e.querySelectorAll))&&(gb(function(a){a.innerHTML="",a.querySelectorAll("[t^='']").length&&o.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||o.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll(":checked").length||o.push(":checked")}),gb(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&o.push("name"+K+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||o.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),o.push(",.*:")})),(c.matchesSelector=Y.test(q=m.webkitMatchesSelector||m.mozMatchesSelector||m.oMatchesSelector||m.msMatchesSelector))&&gb(function(a){c.disconnectedMatch=q.call(a,"div"),q.call(a,"[s!='']:x"),p.push("!=",O)}),o=o.length&&new RegExp(o.join("|")),p=p.length&&new RegExp(p.join("|")),b=Y.test(m.compareDocumentPosition),r=b||Y.test(m.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},z=b?function(a,b){if(a===b)return j=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===t&&r(t,a)?-1:b===e||b.ownerDocument===t&&r(t,b)?1:i?I.call(i,a)-I.call(i,b):0:4&d?-1:1)}:function(a,b){if(a===b)return j=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],k=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:i?I.call(i,a)-I.call(i,b):0;if(f===g)return ib(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)k.unshift(c);while(h[d]===k[d])d++;return d?ib(h[d],k[d]):h[d]===t?-1:k[d]===t?1:0},e):l},db.matches=function(a,b){return db(a,null,null,b)},db.matchesSelector=function(a,b){if((a.ownerDocument||a)!==l&&k(a),b=b.replace(S,"='$1']"),!(!c.matchesSelector||!n||p&&p.test(b)||o&&o.test(b)))try{var d=q.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return db(b,l,null,[a]).length>0},db.contains=function(a,b){return(a.ownerDocument||a)!==l&&k(a),r(a,b)},db.attr=function(a,b){(a.ownerDocument||a)!==l&&k(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!n):void 0;return void 0!==f?f:c.attributes||!n?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},db.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},db.uniqueSort=function(a){var b,d=[],e=0,f=0;if(j=!c.detectDuplicates,i=!c.sortStable&&a.slice(0),a.sort(z),j){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return i=null,a},e=db.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=db.selectors={cacheLength:50,createPseudo:fb,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ab,bb),a[3]=(a[4]||a[5]||"").replace(ab,bb),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||db.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&db.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2];return V.CHILD.test(a[0])?null:(a[3]&&void 0!==a[4]?a[2]=a[4]:c&&T.test(c)&&(b=ob(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ab,bb).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=w[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&w(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==A&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=db.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),t=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&t){k=q[s]||(q[s]={}),j=k[a]||[],n=j[0]===u&&j[1],m=j[0]===u&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[u,n,m];break}}else if(t&&(j=(b[s]||(b[s]={}))[a])&&j[0]===u)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(t&&((l[s]||(l[s]={}))[a]=[u,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||db.error("unsupported pseudo: "+a);return e[s]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?fb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:fb(function(a){var b=[],c=[],d=g(a.replace(P,"$1"));return d[s]?fb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:fb(function(a){return function(b){return db(a,b).length>0}}),contains:fb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:fb(function(a){return U.test(a||"")||db.error("unsupported lang: "+a),a=a.replace(ab,bb).toLowerCase(),function(b){var c;do if(c=n?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===m},focus:function(a){return a===l.activeElement&&(!l.hasFocus||l.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:lb(function(){return[0]}),last:lb(function(a,b){return[b-1]}),eq:lb(function(a,b,c){return[0>c?c+b:c]}),even:lb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:lb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:lb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:lb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function qb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=v++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[u,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[s]||(b[s]={}),(h=i[d])&&h[0]===u&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function rb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function sb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function tb(a,b,c,d,e,f){return d&&!d[s]&&(d=tb(d)),e&&!e[s]&&(e=tb(e,f)),fb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||wb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:sb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=sb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=sb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ub(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],i=g||d.relative[" "],j=g?1:0,k=qb(function(a){return a===b},i,!0),l=qb(function(a){return I.call(b,a)>-1},i,!0),m=[function(a,c,d){return!g&&(d||c!==h)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>j;j++)if(c=d.relative[a[j].type])m=[qb(rb(m),c)];else{if(c=d.filter[a[j].type].apply(null,a[j].matches),c[s]){for(e=++j;f>e;e++)if(d.relative[a[e].type])break;return tb(j>1&&rb(m),j>1&&pb(a.slice(0,j-1).concat({value:" "===a[j-2].type?"*":""})).replace(P,"$1"),c,e>j&&ub(a.slice(j,e)),f>e&&ub(a=a.slice(e)),f>e&&pb(a))}m.push(c)}return rb(m)}function vb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,i,j,k){var m,n,o,p=0,q="0",r=f&&[],s=[],t=h,v=f||e&&d.find.TAG("*",k),w=u+=null==t?1:Math.random()||.1,x=v.length;for(k&&(h=g!==l&&g);q!==x&&null!=(m=v[q]);q++){if(e&&m){n=0;while(o=a[n++])if(o(m,g,i)){j.push(m);break}k&&(u=w)}c&&((m=!o&&m)&&p--,f&&r.push(m))}if(p+=q,c&&q!==p){n=0;while(o=b[n++])o(r,s,g,i);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=E.call(j));s=sb(s)}G.apply(j,s),k&&!f&&s.length>0&&p+b.length>1&&db.uniqueSort(j)}return k&&(u=w,h=t),r};return c?fb(f):f}g=db.compile=function(a,b){var c,d=[],e=[],f=y[a+" "];if(!f){b||(b=ob(a)),c=b.length;while(c--)f=ub(b[c]),f[s]?d.push(f):e.push(f);f=y(a,vb(e,d))}return f};function wb(a,b,c){for(var d=0,e=b.length;e>d;d++)db(a,b[d],c);return c}function xb(a,b,e,f){var h,i,j,k,l,m=ob(a);if(!f&&1===m.length){if(i=m[0]=m[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&c.getById&&9===b.nodeType&&n&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(ab,bb),b)||[])[0],!b)return e;a=a.slice(i.shift().value.length)}h=V.needsContext.test(a)?0:i.length;while(h--){if(j=i[h],d.relative[k=j.type])break;if((l=d.find[k])&&(f=l(j.matches[0].replace(ab,bb),$.test(i[0].type)&&mb(b.parentNode)||b))){if(i.splice(h,1),a=f.length&&pb(i),!a)return G.apply(e,f),e;break}}}return g(a,m)(f,b,!n,e,$.test(a)&&mb(b.parentNode)||b),e}return c.sortStable=s.split("").sort(z).join("")===s,c.detectDuplicates=!!j,k(),c.sortDetached=gb(function(a){return 1&a.compareDocumentPosition(l.createElement("div"))}),gb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||hb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&gb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||hb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),gb(function(a){return null==a.getAttribute("disabled")})||hb(J,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),db}(a);o.find=t,o.expr=t.selectors,o.expr[":"]=o.expr.pseudos,o.unique=t.uniqueSort,o.text=t.getText,o.isXMLDoc=t.isXML,o.contains=t.contains;var u=o.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(o.isFunction(b))return o.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return o.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return o.filter(b,a,c);b=o.filter(b,a)}return o.grep(a,function(a){return g.call(b,a)>=0!==c})}o.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?o.find.matchesSelector(d,a)?[d]:[]:o.find.matches(a,o.grep(b,function(a){return 1===a.nodeType}))},o.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(o(a).filter(function(){for(b=0;c>b;b++)if(o.contains(e[b],this))return!0}));for(b=0;c>b;b++)o.find(a,e[b],d);return d=this.pushStack(c>1?o.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?o(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=o.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof o?b[0]:b,o.merge(this,o.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:m,!0)),v.test(c[1])&&o.isPlainObject(b))for(c in b)o.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=m.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=m,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):o.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(o):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),o.makeArray(a,this))};A.prototype=o.fn,y=o(m);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};o.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&o(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),o.fn.extend({has:function(a){var b=o(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(o.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?o(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&o.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?o.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(o(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(o.unique(o.merge(this.get(),o(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}o.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return o.dir(a,"parentNode")},parentsUntil:function(a,b,c){return o.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return o.dir(a,"nextSibling")},prevAll:function(a){return o.dir(a,"previousSibling")},nextUntil:function(a,b,c){return o.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return o.dir(a,"previousSibling",c)},siblings:function(a){return o.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return o.sibling(a.firstChild)},contents:function(a){return a.contentDocument||o.merge([],a.childNodes)}},function(a,b){o.fn[a]=function(c,d){var e=o.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=o.filter(d,e)),this.length>1&&(C[a]||o.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return o.each(a.match(E)||[],function(a,c){b[c]=!0}),b}o.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):o.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){o.each(b,function(b,c){var d=o.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&o.each(arguments,function(a,b){var c;while((c=o.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?o.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},o.extend({Deferred:function(a){var b=[["resolve","done",o.Callbacks("once memory"),"resolved"],["reject","fail",o.Callbacks("once memory"),"rejected"],["notify","progress",o.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return o.Deferred(function(c){o.each(b,function(b,f){var g=o.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&o.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?o.extend(a,d):d}},e={};return d.pipe=d.then,o.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&o.isFunction(a.promise)?e:0,g=1===f?a:o.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&o.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;o.fn.ready=function(a){return o.ready.promise().done(a),this},o.extend({isReady:!1,readyWait:1,holdReady:function(a){a?o.readyWait++:o.ready(!0)},ready:function(a){(a===!0?--o.readyWait:o.isReady)||(o.isReady=!0,a!==!0&&--o.readyWait>0||(H.resolveWith(m,[o]),o.fn.trigger&&o(m).trigger("ready").off("ready")))}});function I(){m.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),o.ready()}o.ready.promise=function(b){return H||(H=o.Deferred(),"complete"===m.readyState?setTimeout(o.ready):(m.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},o.ready.promise();var J=o.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===o.type(c)){e=!0;for(h in c)o.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,o.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(o(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};o.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=o.expando+Math.random()}K.uid=1,K.accepts=o.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,o.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(o.isEmptyObject(f))o.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,o.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{o.isArray(b)?d=b.concat(b.map(o.camelCase)):(e=o.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!o.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?o.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}o.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),o.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length; +while(c--)d=g[c].name,0===d.indexOf("data-")&&(d=o.camelCase(d.slice(5)),P(f,d,e[d]));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=o.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),o.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||o.isArray(c)?d=L.access(a,b,o.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=o.queue(a,b),d=c.length,e=c.shift(),f=o._queueHooks(a,b),g=function(){o.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:o.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),o.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length",l.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="",l.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";l.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return m.activeElement}catch(a){}}o.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=o.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof o!==U&&o.event.triggered!==b.type?o.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n&&(l=o.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=o.event.special[n]||{},k=o.extend({type:n,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&o.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(n,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),o.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],n=q=h[1],p=(h[2]||"").split(".").sort(),n){l=o.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||o.removeEvent(a,n,r.handle),delete i[n])}else for(n in i)o.event.remove(a,n+b[j],c,d,!0);o.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,p=[d||m],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||m,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+o.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[o.expando]?b:new o.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:o.makeArray(c,[b]),n=o.event.special[q]||{},e||!n.trigger||n.trigger.apply(d,c)!==!1)){if(!e&&!n.noBubble&&!o.isWindow(d)){for(i=n.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||m)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:n.bindType||q,l=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),l&&l.apply(g,c),l=k&&g[k],l&&l.apply&&o.acceptData(g)&&(b.result=l.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||n._default&&n._default.apply(p.pop(),c)!==!1||!o.acceptData(d)||k&&o.isFunction(d[q])&&!o.isWindow(d)&&(h=d[k],h&&(d[k]=null),o.event.triggered=q,d[q](),o.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=o.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=o.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=o.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((o.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?o(e,this).index(i)>=0:o.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return o.nodeName(a,"table")&&o.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)o.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=o.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&o.nodeName(a,b)?o.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}o.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=o.contains(a.ownerDocument,a);if(!(l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||o.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,n=a.length;n>m;m++)if(e=a[m],e||0===e)if("object"===o.type(e))o.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;o.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===o.inArray(e,d))&&(i=o.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f,g,h=o.event.special,i=0;void 0!==(c=a[i]);i++){if(o.acceptData(c)&&(f=c[L.expando],f&&(b=L.cache[f]))){if(d=Object.keys(b.events||{}),d.length)for(g=0;void 0!==(e=d[g]);g++)h[e]?o.event.remove(c,e):o.removeEvent(c,e,b.handle);L.cache[f]&&delete L.cache[f]}delete M.cache[c[M.expando]]}}}),o.fn.extend({text:function(a){return J(this,function(a){return void 0===a?o.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?o.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||o.cleanData(ob(c)),c.parentNode&&(b&&o.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(o.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return o.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(o.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,o.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,k=this.length,m=this,n=k-1,p=a[0],q=o.isFunction(p);if(q||k>1&&"string"==typeof p&&!l.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(k&&(c=o.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=o.map(ob(c,"script"),kb),g=f.length;k>j;j++)h=c,j!==n&&(h=o.clone(h,!0,!0),g&&o.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,o.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&o.contains(i,h)&&(h.src?o._evalUrl&&o._evalUrl(h.src):o.globalEval(h.textContent.replace(hb,"")))}return this}}),o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){o.fn[a]=function(a){for(var c,d=[],e=o(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),o(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d=o(c.createElement(b)).appendTo(c.body),e=a.getDefaultComputedStyle?a.getDefaultComputedStyle(d[0]).display:o.css(d[0],"display");return d.detach(),e}function tb(a){var b=m,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||o("