From c4adf366eec747494c27b50766c511ac0555010e Mon Sep 17 00:00:00 2001 From: s22 Tech <59073912+s22-tech@users.noreply.github.com> Date: Sun, 19 May 2024 10:56:25 -0700 Subject: [PATCH] Initial upload --- --TO DO | 33 + Read_Me.txt | 66 + VERSION | 1 + admin.php | 236 + async_header.php | 33 + bookmarks/add_bookmark.php | 2 + bookmarks/async_bookmarks.php | 44 + bookmarks/bookmarks.php | 229 + bookmarks/delete_bookmark.inc.php | 50 + bookmarks/delete_bookmark.php | 100 + bookmarks/edit_bookmark.php | 237 + bookmarks/move_bookmark.php | 60 + bookmarks/new_bookmark.php | 152 + change_password.php | 73 + composer.json | 12 + config/config.php | 77 + docs/-read_me.txt | 66 + docs/CHANGES | 39 + docs/INSTALL.txt | 4 + docs/installation.html | 366 ++ export.php | 300 + favicon.ico | Bin 0 -> 1150 bytes favicon.php | 305 + folders/async_folders.php | 9 + folders/delete_folder.php | 124 + folders/edit_folder.php | 123 + folders/folder.php | 356 ++ folders/move_folder.php | 65 + folders/new_folder.php | 42 + folders/select_folder.php | 26 + footer.php | 7 + header.min.php | 28 + header.php | 63 + images/ascending.gif | Bin 0 -> 82 bytes images/background.jpg | Bin 0 -> 23122 bytes images/bookmark.gif | Bin 0 -> 1120 bytes images/bookmark_image.gif | Bin 0 -> 1120 bytes images/delete.gif | Bin 0 -> 1029 bytes images/descending.gif | Bin 0 -> 82 bytes images/edit.gif | Bin 0 -> 1011 bytes images/folder.gif | Bin 0 -> 1004 bytes images/folder_open.gif | Bin 0 -> 997 bytes images/folder_open_red.gif | Bin 0 -> 970 bytes images/folder_red.gif | Bin 0 -> 977 bytes images/grad.png | Bin 0 -> 345 bytes images/loading.gif | Bin 0 -> 18300 bytes images/logo.png | Bin 0 -> 1982 bytes images/minus.gif | Bin 0 -> 880 bytes images/move.gif | Bin 0 -> 1001 bytes images/plus.gif | Bin 0 -> 881 bytes images/spacer.gif | Bin 0 -> 43 bytes import.php | 341 ++ includes/css/mobile.css | 73 + includes/css/mobiledark.css | 8 + includes/css/style.css | 287 + includes/css/styledark.css | 126 + includes/jquery/images/file.gif | Bin 0 -> 110 bytes includes/jquery/images/folder.gif | Bin 0 -> 106 bytes .../jquery/images/tv-collapsable-last.gif | Bin 0 -> 85 bytes includes/jquery/images/tv-collapsable.gif | Bin 0 -> 781 bytes includes/jquery/images/tv-expandable-last.gif | Bin 0 -> 89 bytes includes/jquery/images/tv-expandable.gif | Bin 0 -> 787 bytes includes/jquery/images/tv-item-last.gif | Bin 0 -> 65 bytes includes/jquery/images/tv-item.gif | Bin 0 -> 750 bytes includes/jquery/jquery-ui.min.js | 6 + includes/jquery/jquery.js | 4994 +++++++++++++++++ includes/jquery/jquery.treeview.js | 239 + index.php | 331 ++ install/install.php | 527 ++ lib/--mysql--orig.php | 35 + lib/--pdo.php | 62 + lib/--pngfix.js | 37 + lib/auth.php | 178 + lib/boolean_search.php | 275 + lib/lib.js | 125 + lib/lib.php | 594 ++ lib/login.php | 105 + lib/mysql.php | 50 + lib/webstart.php | 51 + register.php | 164 + settings.php | 398 ++ shared.php | 156 + sidebar.php | 169 + vendor/simplehtmldom/CHANGELOG.md | 369 ++ vendor/simplehtmldom/Debug.php | 149 + vendor/simplehtmldom/HtmlDocument.php | 1125 ++++ vendor/simplehtmldom/HtmlNode.php | 1441 +++++ vendor/simplehtmldom/HtmlWeb.php | 133 + vendor/simplehtmldom/README.md | 116 + vendor/simplehtmldom/composer.json | 58 + vendor/simplehtmldom/constants.php | 28 + vendor/simplehtmldom/simple_html_dom.php | 152 + 92 files changed, 16230 insertions(+) create mode 100644 --TO DO create mode 100644 Read_Me.txt create mode 100644 VERSION create mode 100644 admin.php create mode 100644 async_header.php create mode 100644 bookmarks/add_bookmark.php create mode 100644 bookmarks/async_bookmarks.php create mode 100644 bookmarks/bookmarks.php create mode 100644 bookmarks/delete_bookmark.inc.php create mode 100644 bookmarks/delete_bookmark.php create mode 100644 bookmarks/edit_bookmark.php create mode 100644 bookmarks/move_bookmark.php create mode 100644 bookmarks/new_bookmark.php create mode 100644 change_password.php create mode 100644 composer.json create mode 100644 config/config.php create mode 100644 docs/-read_me.txt create mode 100644 docs/CHANGES create mode 100644 docs/INSTALL.txt create mode 100644 docs/installation.html create mode 100644 export.php create mode 100644 favicon.ico create mode 100644 favicon.php create mode 100644 folders/async_folders.php create mode 100644 folders/delete_folder.php create mode 100644 folders/edit_folder.php create mode 100644 folders/folder.php create mode 100644 folders/move_folder.php create mode 100644 folders/new_folder.php create mode 100644 folders/select_folder.php create mode 100644 footer.php create mode 100644 header.min.php create mode 100644 header.php create mode 100644 images/ascending.gif create mode 100644 images/background.jpg create mode 100644 images/bookmark.gif create mode 100644 images/bookmark_image.gif create mode 100644 images/delete.gif create mode 100644 images/descending.gif create mode 100644 images/edit.gif create mode 100644 images/folder.gif create mode 100644 images/folder_open.gif create mode 100644 images/folder_open_red.gif create mode 100644 images/folder_red.gif create mode 100644 images/grad.png create mode 100644 images/loading.gif create mode 100644 images/logo.png create mode 100644 images/minus.gif create mode 100644 images/move.gif create mode 100644 images/plus.gif create mode 100644 images/spacer.gif create mode 100644 import.php create mode 100644 includes/css/mobile.css create mode 100644 includes/css/mobiledark.css create mode 100644 includes/css/style.css create mode 100644 includes/css/styledark.css create mode 100644 includes/jquery/images/file.gif create mode 100644 includes/jquery/images/folder.gif create mode 100644 includes/jquery/images/tv-collapsable-last.gif create mode 100644 includes/jquery/images/tv-collapsable.gif create mode 100644 includes/jquery/images/tv-expandable-last.gif create mode 100644 includes/jquery/images/tv-expandable.gif create mode 100644 includes/jquery/images/tv-item-last.gif create mode 100644 includes/jquery/images/tv-item.gif create mode 100644 includes/jquery/jquery-ui.min.js create mode 100644 includes/jquery/jquery.js create mode 100644 includes/jquery/jquery.treeview.js create mode 100644 index.php create mode 100644 install/install.php create mode 100644 lib/--mysql--orig.php create mode 100644 lib/--pdo.php create mode 100644 lib/--pngfix.js create mode 100644 lib/auth.php create mode 100644 lib/boolean_search.php create mode 100644 lib/lib.js create mode 100644 lib/lib.php create mode 100644 lib/login.php create mode 100644 lib/mysql.php create mode 100644 lib/webstart.php create mode 100644 register.php create mode 100644 settings.php create mode 100644 shared.php create mode 100644 sidebar.php create mode 100644 vendor/simplehtmldom/CHANGELOG.md create mode 100644 vendor/simplehtmldom/Debug.php create mode 100644 vendor/simplehtmldom/HtmlDocument.php create mode 100644 vendor/simplehtmldom/HtmlNode.php create mode 100644 vendor/simplehtmldom/HtmlWeb.php create mode 100644 vendor/simplehtmldom/README.md create mode 100644 vendor/simplehtmldom/composer.json create mode 100644 vendor/simplehtmldom/constants.php create mode 100644 vendor/simplehtmldom/simple_html_dom.php diff --git a/--TO DO b/--TO DO new file mode 100644 index 0000000..6662ee0 --- /dev/null +++ b/--TO DO @@ -0,0 +1,33 @@ +OBM II + + +TO DO + +• mobile layout is still pretty messed up + +• loading.gif shows twice on screen - once in the main section and once in the folders section - why? + +• $this->foreign_username appears to be empty in print_tree() in folders.php + The folders menu shows the "user's Bookmarks" but once you navigate, it changes to "My Bookmarks" and the icons change color. + +? the object orientation seems half-baked. Some files are classes but others aren't. + +• add password update in admin + +• make each column scroll independently from each other. + + + +DONE + +√ updated to work with PHP 8.0+ + +√ added simplehtmldom to cover all cases of favicon paths. + +√ fixed favicon.php +√ Refresh Icon button now works +√ Delete Favicons button now works + +√ updated mysql to mysqli + +√ general code cleanup, consistency diff --git a/Read_Me.txt b/Read_Me.txt new file mode 100644 index 0000000..2762ef7 --- /dev/null +++ b/Read_Me.txt @@ -0,0 +1,66 @@ +https://github.com/s22-tech/openbookmark + + +See http://www.frech.ch/openbookmark/installation.php for installation instructions. + +If you are upgrading from an old version, please manually create the following column on the `user` table: + theme varchar(50) NOT NULL default '' + + + +------ + + + +New Installation: + +Basically the installation of OpenBookmark is not a big deal. There is an install script that guides you through the install steps. Just make sure you know your servers database credentials. + + Download: First of all, download the latest Version of OpenBookmark and unpack the tarball in your Webserver's DocumentRoot direcotry. + Installation: Now point your browser to the freshly created directory on your webserver. If you did it well, the URL might look like this: + + http://www.yourserver.com/openbookmark/ + + If the configuration file "./config/config.php" is missing - and it most probably will be if you are installing a new version - then a page will be shown linking to the install script. After answering all the questions in the install script, a config section is being displayed. Copy the section and paste it to "./config/config.php". The section looks like this. After creating the config file you must delete the install.php file prior visiting OpenBookmark, just for security reasons. + + Login: Try visiting http://www.yourserver.com/openbookmark/ and login using the user that the install script created for you. The username and password is "admin". The first thing you should do is changing the password. Then open the admin script and start creating other users. You can find the admin script under the menu option "Tools". + + +Upgrade an existing Installation: + +If you have an already existing installation of OpenBookmark and you would like to upgrade, the install script will care about the needed steps. If you are wise, you will backup the working installation before using the new one: + + Backup files: I simply rename or move the old installation of OpenBookmark so that the new version can take place: + + # mv /path/to/openbookmark \ + /path/to/openbookmark-backup + + Backup the database: Then I backup the database content by feeding this command to the MySQL server: + + # mysqldump --user=bookmarkmgr \ + --password=password_of_bookmarkmgr \ + bookmarks \ + > /some/path/openbookmark-backup.sql + + Upgrade: Now proceed with the steps from the description above. Don't forget to copy the favicons to the new directory: + + # cp -a /path/to/openbookmark-backup/icons/* \ + /path/to/openbookmark/icons/ + + Admin user: If you upgraded and using at least version 0.8.7_beta now, the new admin script will be available. However, it will only be accessible by admin users. Thus you have to define one ore more users as admins now. To do so login to your MySQL server and do the following change in your database: + + # mysql -p bookmarks + Enter password: + ... + mysql> UPDATE user SET admin='1' WHERE username='some_user'; + + +Install favicon support: + + Since version 0.6.4 there is a nice feature with OpenBookmark that allows you to display the favicon of a webpage if one exists. To make this work, do the following steps: + + Make sure ImageMagick is installed on your server. This is used to convert the favicon to PNG, since some browsers cannot display ICO files. + + Edit the "./config/config.php" file and set the variables $convert and $identify to where the "convert" and "identify" executables are on your system. It might be something like "/usr/local/bin/convert" or "/usr/bin/convert". + + Make sure that the "./favicons" directory is writable, readable and executable by the user your webserver runs as. Just chmod it to 755 and it will be. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..9f8e9b6 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.0 \ No newline at end of file diff --git a/admin.php b/admin.php new file mode 100644 index 0000000..6341a20 --- /dev/null +++ b/admin.php @@ -0,0 +1,236 @@ + + +

Admin Page

+ + +
+ + + + +
+ + escape($new_username), + $mysql->escape($new_password), + $mysql->escape($new_admin) + ); + + if ($mysql->query($query)) { + $message1 = "User $new_username created."; + } + else { + message($mysql->error); + } + unset ($new_password, $_POST['new_password']); + } + } + ?> + +
+

Create User

+ +
+ + + + + + + + + + + + + + + + + + + + +
Username: + + +
Password: + + +
Admin: + + +
+ + +
+
+ +
+ +
+

Delete User

+ + escape($existing_user) + ); + if ($mysql->query($query)) { + $message2 = 'User $existing_user deleted.
'; + } + else { + message($mysql->error); + } + + $query = sprintf(" + DELETE FROM `obm_bookmarks` + WHERE md5(user)=md5('%s')", + $mysql->escape($existing_user) + ); + if (!$mysql->query($query)) { + message($mysql->error); + } + + $query = sprintf(" + DELETE FROM `obm_folders` + WHERE md5(user)=md5('%s')", + $mysql->escape($existing_user) + ); + if (!$mysql->query($query)) { + message($mysql->error); + } + list_users(); + } + else { + ?> + +

Are you sure you want to delete the user and all their Bookmarks and Folders?

+
" method="post" name="userdelete"> + + + +
+ + + +
+
+ query($query)) { + while ($row = mysqli_fetch_object($mysql->result)) { + echo ''; + if ($row->admin) { + echo ' ' . $row->username . "
\n"; + } + else { + echo ' ' . $row->username . "
\n"; + } + } + } + else { + message($mysql->error); + } + ?> +
+ + + +
+ + + +
+ +
+

Version

+ + + + + + + + + + + +
This Version:
Latest version:
+ +
+
+ + diff --git a/async_header.php b/async_header.php new file mode 100644 index 0000000..7155c9f --- /dev/null +++ b/async_header.php @@ -0,0 +1,33 @@ +install OpenBookmark.'); + } + else { + require_once (ABSOLUTE_PATH . 'config/config.php'); + } + require_once (ABSOLUTE_PATH . 'lib/mysql.php'); + $mysql = new mysql; + + require_once (ABSOLUTE_PATH . 'lib/auth.php'); + $auth = new Auth; + + require_once (ABSOLUTE_PATH . 'lib/lib.php'); + require_once (ABSOLUTE_PATH . 'lib/login.php'); + + //if (is_file (ABSOLUTE_PATH . 'install.php')) { + // message ('Remove "install.php" before using OpenBookmark.'); + //} + + if ($display_login_form) { + $auth->display_login_form(); + require_once (ABSOLUTE_PATH . 'footer.php'); + } + diff --git a/bookmarks/add_bookmark.php b/bookmarks/add_bookmark.php new file mode 100644 index 0000000..1f9f265 --- /dev/null +++ b/bookmarks/add_bookmark.php @@ -0,0 +1,2 @@ +escape($username), + $mysql->escape($folderid) + ); + + if ($mysql->query($query)) { + $bookmarks = []; + while ($row = mysqli_fetch_assoc($mysql->result)) { + array_push($bookmarks, $row); + } + list_bookmarks($bookmarks, + true, + false, + $settings['show_bookmark_icon'], + true, + $settings['show_bookmark_description'], + $settings['show_column_date'], + $settings['show_column_edit'], + $settings['show_column_move'], + $settings['show_column_delete'], + $settings['show_public'], + true, + false, + 'index.php' + ); + } + else { + message($mysql->error); + } diff --git a/bookmarks/bookmarks.php b/bookmarks/bookmarks.php new file mode 100644 index 0000000..9a6fcab --- /dev/null +++ b/bookmarks/bookmarks.php @@ -0,0 +1,229 @@ +'; + } + elseif ($order[0] == 'titledesc') { + $sort_t = 'titleasc'; + $img_t = ''; + } + else { + $sort_t = 'titleasc'; + $img_t = ''; + } + + if ($order[0] == 'dateasc') { + $sort_d = 'datedesc'; + $img_d = ''; + } + elseif ($order[0] == 'datedesc') { + $sort_d = 'dateasc'; + $img_d = ''; + } + else { + $sort_d = 'dateasc'; + $img_d = ''; + } + + echo '
' . PHP_EOL; + if ($show_folder) { + echo "\t" . '
 
' . PHP_EOL; + } + + if ($show_checkbox) { + echo "\t\t" . '
' . PHP_EOL; + echo "\t\t\t" . '' . PHP_EOL; + echo "\t\t" . '
' . PHP_EOL; + } + + if ($show_date) { + $query_data = [ + 'folderid' => $folderid, + 'expand' => implode(',', $expand), + 'order' => $sort_d, + ]; + if ($user) { + $query_data['user'] = $user; + } + $query_string = assemble_query_string($query_data); + + echo "\t\t" . '
' . PHP_EOL; + echo "\t\t\t" . '' . PHP_EOL; + echo "\t\t\t\t" . ' Date ' . $img_d . '' . PHP_EOL; + echo "\t\t\t" . '' . PHP_EOL; + + if ($show_edit) { + echo "\t\t\t" . '' . PHP_EOL; + } + if ($show_move) { + echo "\t\t\t" . '' . PHP_EOL; + } + if ($show_delete) { + echo "\t\t\t" . '' . PHP_EOL; + } + echo "\t\t" . '
' . PHP_EOL; + } + + echo "\t\t" . '' . PHP_EOL; + echo "\t" . '
' . PHP_EOL . PHP_EOL; + } + + + if ($show_folder) { + require_once($_SERVER['DOCUMENT_ROOT'] . '/folders/folder.php'); + $tree = new Folder(); + } + + echo '' . PHP_EOL; +} diff --git a/bookmarks/delete_bookmark.inc.php b/bookmarks/delete_bookmark.inc.php new file mode 100644 index 0000000..0436b42 --- /dev/null +++ b/bookmarks/delete_bookmark.inc.php @@ -0,0 +1,50 @@ +escape($bmlist), + $mysql->escape($username) + ); + if ($mysql->query($query)) { + $mysql->query(" + ALTER TABLE `obm_bookmarks` + AUTO_INCREMENT = 1" + ); + echo ''; + } + else { + message($mysql->error); + } + +// debug_logger(name:'bmlist', variable:$bmlist, 'array', file:__FILE__, function:__FUNCTION__); + + foreach ($icons_to_delete as $favicon) { + if (is_file($_SERVER['DOCUMENT_ROOT'] .'/icons/'. $favicon)) { + if (!str_contains($favicon, 'bookmark')) { + unlink($_SERVER['DOCUMENT_ROOT'] .'/icons/'. $favicon); + } + } + else { + debug_logger(name:'ERROR -- No favicon was found for deletion.', variable:$favicon, file:__FILE__, function:__FUNCTION__); + } + } + + // Close the window. + echo ""; + diff --git a/bookmarks/delete_bookmark.php b/bookmarks/delete_bookmark.php new file mode 100644 index 0000000..9bb6a39 --- /dev/null +++ b/bookmarks/delete_bookmark.php @@ -0,0 +1,100 @@ + + .button { + text-decoration: none; + padding: 15px 25px; + font-size: 1.1em; + cursor: pointer; + text-align: center; + text-decoration: none; + outline: none; + color: #fff; + background-color: #450775; + border: none; + border-radius: 10px; + } + + .button:hover { + background-color: #220440; + color: #fff; + } + + .button:active { + background-color: #230545; + box-shadow: 0 5px #e1d5ed; + transform: translateY(4px); + } + + CSS; + + $bmlist = set_get_num_list('bmlist'); + + if (count($bmlist) == 0) { + echo 'No Bookmarks selected.'; + } + else { + $bmlistq = implode(',', $bmlist); + $query = sprintf(" + SELECT `title`, `id`, `favicon`, `url` + FROM `obm_bookmarks` + WHERE `id` IN (%s) AND `user`='%s' + ORDER BY `title`", + $mysql->escape($bmlistq), + $mysql->escape($username) + ); + if ($mysql->query($query)) { + require_once($_SERVER['DOCUMENT_ROOT'] . '/bookmarks/bookmarks.php'); + $query_string = 'bmlist=' . implode(',', $bmlist); +?> + +

Delete These Bookmarks?

+
+ +result)) { + array_push($bookmarks, $row); + } + list_bookmarks($bookmarks, + false, + false, + $settings['show_bookmark_icon'], + false, + false, + false, + false, + false, + false, + false, + false + ); + + $bm_string = ''; + foreach ($bookmarks as $bookmark) { + $bm_string .= '&bookmarks[]='.$bookmark['favicon']; + } +?> + +
+ +
+ Delete Me +
+
+
+error); + } + } + + require_once($_SERVER['DOCUMENT_ROOT'] . '/footer.php'); +?> \ No newline at end of file diff --git a/bookmarks/edit_bookmark.php b/bookmarks/edit_bookmark.php new file mode 100644 index 0000000..c84af67 --- /dev/null +++ b/bookmarks/edit_bookmark.php @@ -0,0 +1,237 @@ + 1) { + // If there is more than one bookmark to edit, we just care about the public/projects field. + if (!isset($_POST['public'])) { + $qbmlist = implode(',', $bmlist); + $query = sprintf(" + SELECT `title`, `id`, `public`, `favicon` + FROM `bookmark` + WHERE `id` IN (%s) AND `user`='%s' + ORDER BY `title`", + $mysql->escape($qbmlist), + $mysql->escape($username) + ); + if ($mysql->query($query)) { + require_once($_SERVER['DOCUMENT_ROOT'] . '/bookmarks/bookmarks.php'); + $query_string = '?bmlist=' . implode('_"', $bmlist); +?> + +

Change public state:

+
+ + result)) { + array_push($bookmarks, $row); + } + list_bookmarks($bookmarks, + false, + false, + $settings['show_bookmark_icon'], + false, + false, + false, + false, + false, + false, + true, + false + ); + ?> + +
+ +
+
+

+ +

+ + +
+ +error); + } + } + else { + $bmlist = implode(',', $bmlist); + $query = sprintf(" + UPDATE `obm_bookmarks` + SET `public` = '%d' + WHERE `id` IN (%s) + AND `user` = '%s'", + $mysql->escape($post_public), + $mysql->escape($bmlist), + $mysql->escape($username) + ); + if ($mysql->query($query)) { + echo 'Bookmark successfully updated
' . PHP_EOL; + echo ''; + } + else { + message($mysql->error); + } + } + + } + elseif (count($bmlist) < 1) { + message('No Bookmark to edit.'); + } + elseif ($post_title == '' || $post_url == '' || $refresh_icon) { + $query = sprintf(" + SELECT `title`, `url`, `description`, `childof`, `id`, `favicon`, `public` + FROM `obm_bookmarks` + WHERE `id` = '%d' + AND `user` = '%s' + AND `deleted` != '1'", + $mysql->escape($bmlist[0]), + $mysql->escape($username) + ); + $icon = $new_fav = ''; + if ($mysql->query($query)) { + if (mysqli_num_rows($mysql->result) != 1) { + message('No Bookmark to edit'); + } + else { + $row = mysqli_fetch_object($mysql->result); + + require_once($_SERVER['DOCUMENT_ROOT'] . '/folders/folder.php'); + $tree = new Folder(); + $query_string = '?expand=' . implode(',', $tree->get_path_to_root($row->childof)) . '&folderid=' . $row->childof; + $path = $tree->print_path($row->childof); + + if (!empty($refresh_icon) && $settings['show_bookmark_icon']) { + $current_url = get_current_url($row->url); + if (parse_url($post_url, PHP_URL_HOST) !== $current_url) { + message('• It looks like the URL for '.$row->title .' ' . + '
  has changed to:' . + '

  https://'. $current_url . + '

  Change it and try again.'); + } + // If the Refresh Icon button is clicked... + if ($post_url) { + $used_url = $post_url; + } + else { + $used_url = $row->url; + } + require_once($_SERVER['DOCUMENT_ROOT'] . '/favicon.php'); + $favicon = new Favicon($used_url); + $new_fav = $favicon->favicon; +debug_logger(name:'favicon->favicon >>', variable:$new_fav, file:__FILE__, function:__FUNCTION__); + if ($new_fav) { + $update_query = sprintf(" + UPDATE `obm_bookmarks` + SET `favicon` = '%s' + WHERE `user` = '%s' AND `id` = '%d'", + $mysql->escape($new_fav), + $mysql->escape($username), + $mysql->escape($bmlist[0]) + ); +debug_logger(name:'bm-query', variable:$update_query, file:__FILE__, function:__FUNCTION__); + if (!$mysql->query($update_query)) { + message($mysql->error); + } + if (!empty($row->favicon)) { /* && is_file($row->favicon) */ + @unlink($_SERVER['DOCUMENT_ROOT'] .'/icons/'. $row->favicon); + } + $icon = ''; + } + else { + message('• edit_bookmark.php — no favicon was retrieved.'); + } + } + elseif ($row->favicon) { /* && is_file($row->favicon) */ + $icon = ''; + } + } + } + else { + message($mysql->error); + } +?> + +

Edit Bookmark

+
+

Title
+ + +
+favicon) { + echo "Saved favicon: $row->favicon"; + } + elseif (strlen($new_fav) > 22) { + echo strlen($new_fav) . " New favicon: '$new_fav'"; + } + else { + echo ''; + } + echo '
folderid: '. $folderid; +?> + +

+

URL
+ +

Description
+

+


+ +

+

Tags
+

+ + + + Public public ? "checked" : "";?>> +
+ + +escape($post_title), + $mysql->escape($post_url), + $mysql->escape($post_description), + $mysql->escape($post_childof), + $mysql->escape($post_public), + $mysql->escape($bmlist[0]), + $mysql->escape($username) + ); + if ($mysql->query($query)) { + echo 'Bookmark successfully updated.
'. PHP_EOL; + echo ''; + } + else { + message($mysql->error); + } + } + + require_once($_SERVER['DOCUMENT_ROOT'] . '/footer.php'); +?> diff --git a/bookmarks/move_bookmark.php b/bookmarks/move_bookmark.php new file mode 100644 index 0000000..e202d24 --- /dev/null +++ b/bookmarks/move_bookmark.php @@ -0,0 +1,60 @@ + + +

Move bookmarks to:

+
+ +
+ + make_tree(0); + $tree->print_tree(); + ?> + +
+
+ + + + + +
+ + + +escape($folderid), + $mysql->escape(implode (',', $bmlist)), + $mysql->escape($username)); +debug_logger(name:'move-bookmarks', variable:$query, file:__FILE__, function:__FUNCTION__); + + if ($mysql->query($query)) { + echo 'Bookmarks moved.
'. PHP_EOL; + echo ''; + } + else { + message($mysql->error); + } + } + + require_once($_SERVER['DOCUMENT_ROOT'] . '/footer.php'); +?> diff --git a/bookmarks/new_bookmark.php b/bookmarks/new_bookmark.php new file mode 100644 index 0000000..759d1f0 --- /dev/null +++ b/bookmarks/new_bookmark.php @@ -0,0 +1,152 @@ +get_path_to_root($post_childof)) . '&folderid=' . $post_childof; + + if ($post_title == '' || $post_url == '') { + $path = $tree->print_path($folderid); + if ($post_title != '') { + $title = $post_title; + } + else { + $title = $get_title; + } + if ($post_url != '') { + $url = $post_url; + } + else if ($get_url != '') { + $url = $get_url; + } + else { + $url = 'https://'; + } + if (strtolower(basename($_SERVER['SCRIPT_NAME'])) === 'add_bookmark.php') { + $js_onclick = 'history.back()'; + } + else { + $js_onclick = 'self.close()'; + } + // Continues below... +?> + +

New Bookmark

+
+

Title +
+

+

URL +
+

+

Description +
+

+

+
+ +

+

Tags +
+

+ + + Public > +
+ + +escape($username), + $mysql->escape($post_title), + $mysql->escape($post_url), + $mysql->escape($post_description), + $mysql->escape($post_childof), + $mysql->escape($post_public) + ); + if ($mysql->query($query)) { + echo 'Bookmark successfully created.
' . PHP_EOL; + $bm_id = mysqli_insert_id($mysql->conn); // Returns the value generated for an AUTO_INCREMENT column by the last query. + // https://www.php.net/manual/en/mysqli.insert-id.php + // Using $mysql->insert_id produces "Undefined property: mysql::$insert_id". +// $bm_id = $pdo->lastInsertId(); // PDO equivalent -- https://www.php.net/pdo.lastinsertid + } + else { + message($mysql->error); + } + unset($_SESSION['title'], $_SESSION['url']); + +debug_logger(variable:$post_url, name:'post_url', file:__FILE__, function:__FUNCTION__); + +/////////////////////////// +// SAVE Favicon +// Saving the favicon in a separate second step is done because +// we want to make sure the bookmark is saved in any case, +// since the favicon is not as important. +/////////////////////////// + if ($settings['show_bookmark_icon']) { + require_once($_SERVER['DOCUMENT_ROOT'] . '/favicon.php'); + $favicon = new Favicon($post_url); +debug_logger(variable:print_r($favicon, true), name:'favicon-object', file:__FILE__, function:__FUNCTION__); + + if (!empty($favicon->favicon)) { + $update_query = sprintf(" + UPDATE `obm_bookmarks` + SET `favicon` = '%s' + WHERE `user` = '%s' + AND `id` = '%d'", + $mysql->escape($favicon->favicon), + $mysql->escape($username), + $mysql->escape($bm_id) + ); +debug_logger(variable:$update_query, name:'update-query', file:__FILE__, function:__FUNCTION__); + if (!$mysql->query($update_query)) { + message($mysql->error); + } + $icon = ''; + } + else { + $icon = $bookmark_image; +debug_logger(variable:$icon, name:'favicon->favicon was NOT set', file:__FILE__, function:__FUNCTION__); +debug_logger(variable:debug_backtrace(), name:'debug_backtrace()', file:__FILE__, function:__FUNCTION__); + } + } + + if (strtolower(basename($_SERVER['SCRIPT_NAME'])) === 'add_bookmark.php') { + echo 'Back to '.$icon.' '.$post_title.'
' . PHP_EOL; + echo 'Open '.$folder_opened.' folder containing new Bookmark
' . PHP_EOL; + } + else { + echo ''; + # I know, the following is ugly, but I found no other way to do it. + # When creating a bookmark out of the personal toolbar, there is no + # window.opener that can be closed. Thus javascript exits with an error + # without finishing itself (self.close()). + echo ''; + } + } + require_once($_SERVER['DOCUMENT_ROOT'] . '/footer.php'); +?> \ No newline at end of file diff --git a/change_password.php b/change_password.php new file mode 100644 index 0000000..d4759fc --- /dev/null +++ b/change_password.php @@ -0,0 +1,73 @@ +escape($password), + $mysql->escape($username) + ); + + if ($mysql->query($query)) { + $pw_message = 'Password changed.
'. PHP_EOL; + } + else { + message($mysql->error); + } + } + unset($_POST['set_password1'], $_POST['set_password2'], $password); + } + +?> + +

Change Password

+ +
+ + + + + + + + + + + + + + + +
New Password
Verify new Password
+ + + + + +
+
+ + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..bb5068c --- /dev/null +++ b/composer.json @@ -0,0 +1,12 @@ +{ + "name": "s22-tech/openbookmark", + "type": "project", + "description": "An open source bookmark manager.", + "version": "v2.0", + "homepage": "https://github.com/s22-tech/openbookmark", + "license": "GPL-3.0+", + "require": { + "php": ">=8.0", + "simplehtmldom/simplehtmldom": "^1.9.1" + } +} diff --git a/config/config.php b/config/config.php new file mode 100644 index 0000000..49398da --- /dev/null +++ b/config/config.php @@ -0,0 +1,77 @@ + 'ob_cookie', + 'domain' => '', + 'path' => '/', + 'seed' => '4Xp2yHprO6oTy5', + 'expire' => time() + 31_536_000, + ]; + + // Feel free to add values to this list as you like, according to the PHP documentation. + ## http://www.php.net/manual/en/function.date.php + $cfg['date_formats'] = [ + 'd/m/Y', + 'Y-m-d', + 'm/d/Y', + 'd.m.Y', + 'F j, Y', + 'dS \o\f F Y', + 'dS F Y', + 'd F Y', + 'd. M Y', + 'Y F d', + 'F d, Y', + 'M. d, Y', + 'm/d/Y', + 'm-d-Y', + 'm.d.Y', + 'm.d.y', + ]; + + $cfg['convert_favicons'] = true; + $cfg['icon_size'] = '24x24'; + $cfg['convert'] = '/usr/bin/convert'; + $cfg['identify'] = '/usr/bin/identify'; + $cfg['timeout'] = 5; + [$cfg['icon_w'], $cfg['icon_h']] = explode('x', $cfg['icon_size']); + + $cfg['locale'] = 'en-US'; + $cfg['user_agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/124.0.2478.109'; + + $folder_closed = ''; + $folder_opened = ''; + $folder_closed_public = ''; + $folder_opened_public = ''; + + $plus = ' '; + $minus = ' '; + $neutral = ' '; + $edit_image = ''; + $move_image = ''; + $delete_image = ''; + $bookmark_image = ''; + + + +/* +javascript:(function(){bmadd=window.open('https://obm.domain.com/bookmarks/new_bookmark.php?title='+encodeURIComponent(document.title)+'&url='+encodeURIComponent(location.href),'bmadd','toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes,width=500,height=500,left=50,top=50');setTimeout(function(){bmadd.focus();});})(); +*/ diff --git a/docs/-read_me.txt b/docs/-read_me.txt new file mode 100644 index 0000000..2762ef7 --- /dev/null +++ b/docs/-read_me.txt @@ -0,0 +1,66 @@ +https://github.com/s22-tech/openbookmark + + +See http://www.frech.ch/openbookmark/installation.php for installation instructions. + +If you are upgrading from an old version, please manually create the following column on the `user` table: + theme varchar(50) NOT NULL default '' + + + +------ + + + +New Installation: + +Basically the installation of OpenBookmark is not a big deal. There is an install script that guides you through the install steps. Just make sure you know your servers database credentials. + + Download: First of all, download the latest Version of OpenBookmark and unpack the tarball in your Webserver's DocumentRoot direcotry. + Installation: Now point your browser to the freshly created directory on your webserver. If you did it well, the URL might look like this: + + http://www.yourserver.com/openbookmark/ + + If the configuration file "./config/config.php" is missing - and it most probably will be if you are installing a new version - then a page will be shown linking to the install script. After answering all the questions in the install script, a config section is being displayed. Copy the section and paste it to "./config/config.php". The section looks like this. After creating the config file you must delete the install.php file prior visiting OpenBookmark, just for security reasons. + + Login: Try visiting http://www.yourserver.com/openbookmark/ and login using the user that the install script created for you. The username and password is "admin". The first thing you should do is changing the password. Then open the admin script and start creating other users. You can find the admin script under the menu option "Tools". + + +Upgrade an existing Installation: + +If you have an already existing installation of OpenBookmark and you would like to upgrade, the install script will care about the needed steps. If you are wise, you will backup the working installation before using the new one: + + Backup files: I simply rename or move the old installation of OpenBookmark so that the new version can take place: + + # mv /path/to/openbookmark \ + /path/to/openbookmark-backup + + Backup the database: Then I backup the database content by feeding this command to the MySQL server: + + # mysqldump --user=bookmarkmgr \ + --password=password_of_bookmarkmgr \ + bookmarks \ + > /some/path/openbookmark-backup.sql + + Upgrade: Now proceed with the steps from the description above. Don't forget to copy the favicons to the new directory: + + # cp -a /path/to/openbookmark-backup/icons/* \ + /path/to/openbookmark/icons/ + + Admin user: If you upgraded and using at least version 0.8.7_beta now, the new admin script will be available. However, it will only be accessible by admin users. Thus you have to define one ore more users as admins now. To do so login to your MySQL server and do the following change in your database: + + # mysql -p bookmarks + Enter password: + ... + mysql> UPDATE user SET admin='1' WHERE username='some_user'; + + +Install favicon support: + + Since version 0.6.4 there is a nice feature with OpenBookmark that allows you to display the favicon of a webpage if one exists. To make this work, do the following steps: + + Make sure ImageMagick is installed on your server. This is used to convert the favicon to PNG, since some browsers cannot display ICO files. + + Edit the "./config/config.php" file and set the variables $convert and $identify to where the "convert" and "identify" executables are on your system. It might be something like "/usr/local/bin/convert" or "/usr/bin/convert". + + Make sure that the "./favicons" directory is writable, readable and executable by the user your webserver runs as. Just chmod it to 755 and it will be. diff --git a/docs/CHANGES b/docs/CHANGES new file mode 100644 index 0000000..7d074d8 --- /dev/null +++ b/docs/CHANGES @@ -0,0 +1,39 @@ +2024-05-18 +- More code cleanup for PHP 8.3 +- Changed favicon format to SVG as they are much smaller files. +- Favicons are named per domain now, so there won't be multiple icons saved for the same domain. E.g.if you save a lot of YouTube videos, you don't need a separate icon for all of them. Just one will do the trick. Helps keep your inode count down. + +2021-04-11, Version 0.9.1 beta +- Refactored the code for PHP 8 by s22_tech. +- Cleaned up the code as I went -- still a lot more to do. +- Swapped out Google search for DuckDuckGo. + +2008-04-20, Version 0.8.9 beta +- Added the possibility to either convert favicon using ImageMagick or + leave them in the ICO format. Updating favicon.php and install.php accordingly. + +2008-05-04, Version 0.8.10 beta +- Changed the "Select folder" link to a button in /bookmarks/edit_bookmark.php and /bookmarks/new_bookmark.php files. +- Fixed HTML encoded strings when importing bookmarks in Netscape format. +- Fixed some typos in index.php and added the "My Bookmarks" link in search mode. + +2008-05-17, Version 0.8.11_beta +- Added a link to use OpenBookmark as a real Firefox Sidebar. Many thanks to Adam Patterson. +- You can find the link "Change Password" under "Settings" from now on. +- Added completely new search lib. Many thanks to John-Paul Durrieu as well for other hints and suggestions. + +2008-07-22, Version 0.8.12_beta +- Changed the look of the menu headers +- Changed the look of the footer +- Added sort by Title and Date to bookmarks header + +2008-08-01, Version 0.8.13_beta +- Adjusted order function so that arrow changes direction when changing order. + +2008-08-12, Version 0.8.14_beta +- Getting rid of dangerous $GLOBALS in export.php, import.php and folders.php. + +2008-04-16, Version 0.8.8 beta +- New design. +- Added the possibility to change the public/projects status on multiple bookmarks. +- Added the possibility to mark bookmarks and folders public/projects when importing them. diff --git a/docs/INSTALL.txt b/docs/INSTALL.txt new file mode 100644 index 0000000..8e52f78 --- /dev/null +++ b/docs/INSTALL.txt @@ -0,0 +1,4 @@ +See http://www.frech.ch/online-bookmarks/installation.php for installation instructions. + +If you are upgrading from an old version, please manually create the following column on the `user` table: + theme varchar(50) NOT NULL default '' \ No newline at end of file diff --git a/docs/installation.html b/docs/installation.html new file mode 100644 index 0000000..223be4d --- /dev/null +++ b/docs/installation.html @@ -0,0 +1,366 @@ + + + + + + + + Online-Bookmarks / Installation + + + + + +
+
+

Online-Bookmarks / Installation

+
+
+ +
+ + + +
+ +
+ +I am having a break! + + +

+Online-Bookmarks has been developed for over seven years now. There +where incredible many comments, feedbacks, ideas and help from people all over +the world. In fact there have been so many, that I was not able to +answer all of them. I really do appreciate every single message that reached me. But +I need to get some distance of this application for the next couple of month, +mainly because of this. +Thanks to all of you supporting this tool, +especially the one that made a donation. +In the meantime the latest version will remain available for download. +The same is also available on SourceForge.net +CVS. +

+ +
+ + +
+ + + + + + +
+ + + +
+ +So long, Stefan
+August 22nd 2008 + + +
+ + +New Installation:
+

+Basically the Installation of Online-Bookmarks is not a big deal. +There is an install script that guides you through the install steps. +Just make sure you know your servers database credentials. +If you will have troubles anyway, you can look for help in the +forum, if you can't find help there +and you really do not feel like testing around for hours, drop me a message +with the subject "Online-Bookmarks" and I will try to help you. + +

    +
  1. Download: + First of all, download + the latest Version of Online-Bookmarks and unpack the tarball + in your Webserver's DocumentRoot direcotry. +
  2. + +
  3. Installation: + Now point your browser to the freshly created directory on your + webserver. If you did it well, the URL might look like this: +
    http://www.yourserver.com/online-bookmarks/
    + If the configuration file "./config/config.php" is missing - and + it most probably will if you are installing a new version + - then a page will be shown linking to the install + script. After answering all the questions in the install script, + a config section is being displayed. Copy the section and paste it + to "./config/config.php". The section looks like + this. After + creating the config file you must delete the install.php file prior + visiting Online-Bookmarks, just for security reasons. +
  4. + +
  5. Login: + Try visiting http://www.yourserver.com/online-bookmarks/ + and login using the user that the install script created for you. + Its username and password is "admin". The first thing you should + do is changing the password. Then open the admin script and start + creating other users. You can find the admin script under the menu + option "Tools". This admin user and the admin script are available + from Online-Bookmarks version 0.8.7_beta. +
  6. +
+ +
+ +Upgrade an existing Installation:

+If you have an already existing installation of Online-Bookmarks +and you would like to upgrade, the install script will care about +the needed steps. If you are wise, you will backup the working +installation before using the new one: + +
    +
  1. Backup files: + I simply rename or move the old installation of Online-Bookmarks so that + the new version can take place: +
    +# mv /path/to/online-bookmarks \
    +     /path/to/online-bookmarks-backup
    +
    +
  2. + +
  3. Backup the database: + Then I backup the database content by feeding this command to the MySQL server: +
    +# mysqldump --user=bookmarkmgr                 \
    +            --password=password_of_bookmarkmgr \
    +            bookmarks                          \
    +            > /some/path/online-bookmarks-backup.sql
    +
    +
  4. + +
  5. Upgrade: + Now proceed with the steps from the description above. Don't forget to + copy the favicons to the new directory: +
    +# cp -a /path/to/online-bookmarks-backup/icons/* \
    +        /path/to/online-bookmarks/icons/
    +
    +
  6. + +
  7. Admin user: + If you upgraded and using at least version 0.8.7_beta now, the new + admin script will be available. However, it will only be accessible + by admin users. Thus you have to define one ore more users as admins + now. To do so login to your MySQL server and do the following + change in your database: + +
    +# mysql -p bookmarks
    +Enter password:
    +...
    +mysql> UPDATE user SET admin='1' WHERE username='some_user';
    +
    +
  8. + +
+ +
+ +Install favicon support:

+Since version 0.6.4 there comes a nice feature with Online-Bookmarks that allows you to display the favicon +of a webpage if one exists. To make this work do the following steps: +
    +
  1. Make sure ImageMagick is installed on your server. + This is used to convert the favicon to PNG, since some browsers cannot display ICO files. +
  2. + +
  3. Edit the "./config/config.php" file and set the variables $convert and $identify to where + the "convert" and "identify" executables are on your system. It might be something like "/usr/local/bin/convert" + or "/usr/bin/convert". +
  4. + +
  5. Make sure that the "./favicons" directory is writable, readable and executable by the user your + webserver runs as. Just chmod it to 777 and it will be. +
  6. +
+ +
+ +
+ + +
+ + + + diff --git a/export.php b/export.php new file mode 100644 index 0000000..6eeae76 --- /dev/null +++ b/export.php @@ -0,0 +1,300 @@ + + +

Export Bookmarks

+ + +
+ + + + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ Export Bookmarks to Browser: + "> + +
Character encoding + +
+ Folder to export: + +
; height:350px; overflow:auto;"> + +make_tree(0); + $tree->print_tree(); +?> + +
+
+ + + + +
+
+ +
+ +
+ +
+ +' . PHP_EOL; + echo 'Bookmarks' . PHP_EOL; + echo '

Bookmarks

' . PHP_EOL; + echo '

' . PHP_EOL; + $export = new Export(); + $export->make_tree ($folderid); + echo '

' . PHP_EOL; + } + else if ($browser == 'opera') { + echo 'Opera Hotlist version 2.0' . PHP_EOL; + echo 'Options: encoding = utf8, version=3' . PHP_EOL . PHP_EOL; + $export = new Export(); + $export->make_tree($folderid); + } + } + + class Export + { + function export() { + global $settings, $browser; + // Collect the folder data. + require_once($_SERVER['DOCUMENT_ROOT'] . '/folders/folder.php'); + $this->tree = new Folder(); + $this->tree->folders[0] = ['id' => 0, 'childof' => null, 'name' => $settings['root_folder_name']]; + + global $username, $mysql; + $this->browser = $browser; + + $this->counter = 0; + + $this->charset = set_post_charset(); + + // Collect the bookmark data. + $query = sprintf (" + SELECT `title`, `url`, `description`, `childof`, `id` + FROM `obm_bookmarks` + WHERE user = '%s' + AND deleted != '1'", + $mysql->escape ($username) + ); + + if ($mysql->query ($query)) { + while ($row = mysqli_fetch_assoc ($mysql->result)) { + if (!isset ($this->bookmarks[$row['childof']])) { + $this->bookmarks[$row['childof']] = []; + } + array_push($this->bookmarks[$row['childof']], $row); + } + } + else { + message($mysql->error); + } + } + + function make_tree($id) { + if (isset($this->tree->children[$id])) { + $this->counter++; + foreach ($this->tree->children[$id] as $value) { + $this->print_folder ($value); + $this->make_tree ($value); + $this->print_folder_close (); + } + $this->counter--; + } + $this->print_bookmarks ($id); + } + + + function print_folder($folderid) { + $spacer = str_repeat(' ', $this->counter); + $foldername = html_entity_decode($this->tree->folders[$folderid]['name'], ENT_QUOTES, $this->charset); + if ($this->browser == 'netscape') { + echo $spacer . '

' . $foldername . '

'. PHP_EOL; + echo $spacer . '

'. PHP_EOL; + } + else if ($this->browser == 'IE') { + echo $spacer . '

' . $foldername . '

'. PHP_EOL; + echo $spacer . '

'. PHP_EOL; + } + else if ($this->browser == "opera") { + echo PHP_EOL .'#FOLDER'. PHP_EOL; + echo "\t".'NAME=' . $foldername . PHP_EOL; + } + } + + function print_folder_close() { + $spacer = str_repeat(' ', $this->counter); + if ($this->browser == 'netscape' || $this->browser == 'IE') { + echo $spacer . '

'. PHP_EOL; + } + else if ($this->browser == "opera") { + echo "\n-\n"; + } + } + + function print_bookmarks($folderid) { + $spacer = str_repeat(' ', $this->counter); + if (isset ($this->bookmarks[$folderid])) { + foreach ($this->bookmarks[$folderid] as $value) { + $url = html_entity_decode($value['url'], ENT_QUOTES, $this->charset); + $title = html_entity_decode($value['title'], ENT_QUOTES, $this->charset); + if ($value['description'] != '') { + $description = html_entity_decode($value['description'], ENT_QUOTES, $this->charset); + } + else { + $description = ''; + } + + if ($this->browser == 'netscape') { + echo $spacer . '

' . $title . "\n"; + if ($description != '') { + echo $spacer . '
' . $description . PHP_EOL; + } + } + else if ($this->browser == 'IE') { + echo $spacer . '
' . $title . ''. PHP_EOL; + # Unfortunately description for bookmarks in MS Internet Explorer is not supported. + # Thats why we just ignore the output of the description here. + } + else if ($this->browser == 'opera') { + echo PHP_EOL .'#URL'. PHP_EOL; + echo "\t".'NAME=' . $title . PHP_EOL; + echo "\t".'URL=' . $url . PHP_EOL; + if ($description != '') { + # Opera cannot handle the \r\n character, so we fix this. + $description = str_replace ("\r\n", ' ', $description); + echo "\t".'DESCRIPTION=' . $description . PHP_EOL; + } + } + } + } + } + } +?> \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8b9106c9b7784cd8983d5623b240ae261e121139 GIT binary patch literal 1150 zcmb7@dq`7J9LH}ymhX+t*VMU%8QLEPL1mEEAN7wRQ4xd`4DB)f!$?9x(gaaLN->r_ z$o|uWvLZx6D=eX+^1+(#sT1ec)>3!3uA6iB+ix{vjAC>ypL@>vJw6<`_b|*RdPE|I z-U>z)#xRKt!(d7O#j%*^C5D>pc<`c^YvBnPJhyx-GhnOJ_QNvEi`t3-%Z$i|*@?0uRCz6QGLulD+of@p!-)b5hm;xC=dsaQSjdO$NUbtKd{(ax?Dg(d zPrr5d@I2IO>!{>hP}-cx{rUqbv*Z~i2c0MN3k!wXf`sz<*Zz)tweij^s|W249zAXz zUF$qr$a9H2#hepImR6B(aA23tjy+ly(#uBp_t%X(`RXY*sT%T^E~tLIB{Ry|Et9uLX0^TiU< z8Wvjp>w~R}`)uRYCLVPr56U?=w%;|J4A$eHKiX+k->?EjdM7f+Y;IY-KGHuQY@Ky& zp|I8L!QPJVNNhG}gVhJ-Ga3!y7vHce3CE3e=jNIN^MQNN*T8;;86pgX-pf@Va)#-r T+gwY3do38o>BB{{7Z33hnwow3 literal 0 HcmV?d00001 diff --git a/favicon.php b/favicon.php new file mode 100644 index 0000000..a57bdc7 --- /dev/null +++ b/favicon.php @@ -0,0 +1,305 @@ +url = $url; + + if ($settings['show_bookmark_icon']) { +debug_logger(name:'--------', variable:'-------------------------', file:'-----', function:'-----'); +debug_logger(name:'URL', variable:$url, newline:false, file:__FILE__, function:__FUNCTION__, time:true); + + if ($this->parsed_url = $this->return_parse_url($url)) { + if ($this->favicon_url = $this->get_favicon_url()) { + $this->download_favicon_image(); + $this->icon_name = $this->rename_favicon($url . '/'. $this->temp_icon_name); + $favicon_url_path = $_SERVER['DOCUMENT_ROOT'] . '/icons/'. $this->icon_name; + +debug_logger(name:'this->temp_icon_name', variable:$this->temp_icon_name, newline:false, file:__FILE__, function:__FUNCTION__); +debug_logger(name:'this->favicon_url', variable:$this->favicon_url, newline:false, file:__FILE__, function:__FUNCTION__); +debug_logger(name:'this->icon_name', variable:$this->icon_name, newline:false, file:__FILE__, function:__FUNCTION__); +debug_logger(name:'favicon_url_path', variable:$favicon_url_path, file:__FILE__, function:__FUNCTION__); + + $tmp_file = $_SERVER['DOCUMENT_ROOT'] . '/tmp/'. $this->temp_icon_name; + [$fav_ext, $ident] = $this->identify_fav($tmp_file); +debug_logger(name:'tmp_file', variable:$tmp_file, newline:false, file:__FILE__, function:__FUNCTION__); +debug_logger(name:'fav_ext', variable:$fav_ext, newline:false, file:__FILE__, function:__FUNCTION__); +debug_logger(name:'ident', variable:$ident, file:__FILE__, function:__FUNCTION__); + + if ($cfg['convert_favicons']) { + $this->favicon = $this->convert_favicon($tmp_file, $fav_ext, $ident); +debug_logger(name:'converted favicon', variable:$this->favicon, file:__FILE__, function:__FUNCTION__); + } + else { + // Move the file from the tmp dir. + rename($tmp_file, $favicon_url_path); + $this->favicon = $favicon_url_path; +debug_logger(name:'no conversion favicon', variable:$this->favicon, file:__FILE__, function:__FUNCTION__); + } + } + else { + echo '• favicon.php — no favicon was retrieved.
'; + } + } + } + if (isset($this->favicon)) { + return $this->favicon; + } + else { + return false; + } + } + + ### + ### Check the image type, and convert/resize it if required. + ### Returns the absolute path of the (converted) .png file + ### + function convert_favicon($tmp_file, $fav_ext, $ident) : string { + global $cfg; + $tmp_ext = pathinfo($tmp_file, PATHINFO_EXTENSION); + $tmp_file = str_replace('.'.$tmp_ext, '.'.$fav_ext, $tmp_file); // Replace extension with correct one. + +debug_logger(name:'ident-status', variable:$ident, newline:false, file:__FILE__, function:__FUNCTION__); +debug_logger(name:'tmp_file', variable:$tmp_file, newline:false, file:__FILE__, function:__FUNCTION__); +debug_logger(name:'fav_ext', variable:$fav_ext, file:__FILE__, function:__FUNCTION__); + + $new_name = $this->rename_favicon($this->url); +debug_logger(name:'new_name', variable:$new_name, newline:false, file:__FILE__, function:__FUNCTION__); + + $save_path_name = $_SERVER['DOCUMENT_ROOT'] . '/icons/'. $new_name; +debug_logger(name:'save_path_name', variable:$save_path_name, newline:false, file:__FILE__, function:__FUNCTION__); + +// if (strtolower($fav_ext) === 'svg') { +// $convert = "{$cfg['convert']} -background none -size {$cfg['icon_size']} $tmp_file $save_path_name"; +// } +// else { +// $convert = "{$cfg['convert']} $tmp_file -resize {$cfg['icon_size']}\> -unsharp 0x1 $save_path_name"; +// } + + if ($ident && $fav_ext !== 'svg') { + $convert = "{$cfg['convert']} $tmp_file -resize {$cfg['icon_size']}\> -unsharp 0x1 $save_path_name"; +debug_logger(name:'convert-cmd', variable:$convert, newline:false, file:__FILE__, function:__FUNCTION__); + + // Convert image to .png, and resize to $cfg['icon_size'] if original is larger. + ## https://legacy.imagemagick.org/Usage/resize/ + system("$convert", $status); +debug_logger(name:'SUCCESS--conversion status', variable:$status, file:__FILE__, function:__FUNCTION__); + if (file_exists($tmp_file)) { + unlink($tmp_file); + } + } + else { +debug_logger(name:'MOVED--no conversion', variable:$this->icon_name, newline:false, file:__FILE__, function:__FUNCTION__); + $rename = rename($tmp_file, $save_path_name); // Move the file. +debug_logger(name:'tmp_file', variable:$tmp_file, newline:false, file:__FILE__, function:__FUNCTION__); +debug_logger(name:'rename-move', variable:$rename, file:__FILE__, function:__FUNCTION__); + } + return basename($save_path_name); + } + + + /////////////////////////////// + // Download and Save Favicon + // https://www.php.net/manual/en/function.curl-setopt.php + /////////////////////////////// + function download_favicon_image() { + global $cfg; + $options = [ + CURLOPT_URL => $this->favicon_url, + CURLOPT_USERAGENT => $cfg['user_agent'], + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_CONNECTTIMEOUT => 2, + CURLOPT_TIMEOUT => 10, + ]; + $ch = curl_init(); + curl_setopt_array($ch, $options); + $response = curl_exec($ch); + curl_close($ch); + + $bytes = file_put_contents($_SERVER['DOCUMENT_ROOT'] . '/tmp/'. $this->temp_icon_name, $response); +debug_logger(name:'dl-size', variable:$bytes . ' bytes', file:__FILE__, function:__FUNCTION__); + + return true; + } + + + + function get_favicon_url() { + $host_url = $this->parsed_url['scheme'] . '://' . $this->parsed_url['host']; + $host_url = rtrim($host_url, '/'); +debug_logger(name:'host_url', variable:$host_url, newline:false, file:__FILE__, function:__FUNCTION__); + + ## https://github.com/simplehtmldom/simplehtmldom + ## https://sourceforge.net/p/simplehtmldom/bugs/ + ## https://simplehtmldom.sourceforge.io/docs/1.9/ + $dom = new HtmlWeb(); + $html = $dom->load($host_url); + +debug_logger(name:'html', variable:$html, newline:false, file:__FILE__, function:__FUNCTION__); + + if (empty($html)) { + echo '• favicon.php — $html is blank.
'; + return; + } + + $favicon_url = ''; + foreach ($html->find('link') as $e) { + if (!empty($e->rel)) { + if (strtolower(trim($e->rel)) === 'shortcut icon' || strtolower(trim($e->rel)) === 'icon') { +debug_logger(name:'••• e->rel', variable:$e->rel, newline:false, file:__FILE__, function:__FUNCTION__); + $favicon_url = $e->href; + break; + } + elseif (strtolower(trim($e->rel)) === 'apple-touch-icon') { +debug_logger(name:'••• e->rel', variable:$e->rel, newline:false, file:__FILE__, function:__FUNCTION__); + $favicon_url = $e->href; + break; + } + } + } + debug_logger(name:'get-favicon--ORIG', variable:$favicon_url, newline:false, file:__FILE__, function:__FUNCTION__); + + if (empty($favicon_url)) return; // So as not to populate the /tmp/ directory. + + // Remove extraneous parameters. + if (str_contains($favicon_url, '?')) { + [$favicon_url] = explode('?', $favicon_url); + } + + // If link doesn't start with http... + if (str_starts_with($favicon_url, '//')) { + $favicon_url = 'https:'. $favicon_url; + debug_logger(name:'get-favicon--2', variable:$favicon_url, newline:false, file:__FILE__, function:__FUNCTION__); + } + elseif (str_starts_with($favicon_url, '/')) { + $favicon_url = $host_url . $favicon_url; + debug_logger(name:'get-favicon--3', variable:$favicon_url, newline:false, file:__FILE__, function:__FUNCTION__); + } + elseif (!str_starts_with($favicon_url, 'http')) { + $favicon_url = $host_url .'/'. $favicon_url; + debug_logger(name:'get-favicon--4', variable:$favicon_url, newline:false, file:__FILE__, function:__FUNCTION__); + } + + $html->clear(); + unset($html); + + debug_logger(name:'get-favicon--FINAL', variable:$favicon_url, file:__FILE__, function:__FUNCTION__); + + $this->temp_icon_name = basename(parse_url($favicon_url, PHP_URL_PATH)); + + return $favicon_url; + } + + + ### + ### Returns an array with parts of the given URL. + ### + function return_parse_url($url) { + if ($parsed = parse_url($url)) { + if (empty($parsed['scheme']) || $parsed['scheme'] == '') { + $parsed['scheme'] = 'https'; + } + if (empty($parsed['host']) || $parsed['host'] == '') { + debug_logger(name:'parsed[host]', variable:$parsed['host'], file:__FILE__, function:__FUNCTION__); + return false; + } + if (empty($parsed['port']) || $parsed['port'] == '') { + $parsed['port'] = 80; + } + if (empty($parsed['path']) || $parsed['path'] == '') { + $parsed['path'] = '/'; + } + return ($parsed); + } + else { + return false; + } + } + + + function rename_favicon($domain) { + $parsed = parse_url($domain); + $host_name = $parsed['host']; + $host_name = str_replace('.', '-', $host_name); + $parts = explode('-', $host_name); + $last = array_pop($parts); + $parts = [implode('-', $parts), $last]; // Get domain w/o the extension. + $host_name = $parts[0]; + $host_name = str_replace('www-', '', $host_name); + $ext = pathinfo($this->favicon_url, PATHINFO_EXTENSION); + $ext = strlen($ext) < 3 ? 'png' : $ext; +debug_logger(name:'•••favicon_name', variable:$host_name . '.' . $ext, file:__FILE__, function:__FUNCTION__); + return $host_name . '.' . $ext; + } + + + function identify_fav($tmp_file) { + global $cfg; + $tmp_ext = pathinfo($tmp_file, PATHINFO_EXTENSION); + exec($cfg['identify'] .' '. $tmp_file, $output); +debug_logger(name:'identify output', variable:$output, newline:false, file:__FILE__, function:__FUNCTION__); +debug_logger(name:'identify tmp_file', variable:$tmp_file, file:__FILE__, function:__FUNCTION__); + if ($output) { + $idents = explode(' ', $output[0]); + $file_ext = strtolower($idents[1]); + $file_ext = ($file_ext === 'jpeg') ? 'jpg' : $file_ext; + + if (count($idents) > 1 && !str_starts_with($idents[0], 'identify')) { + $file_to_convert = $idents[0]; + } + else { + $file_to_convert = $tmp_file; + } + +// if ($file_ext !== $tmp_ext) { + $info = pathinfo($file_to_convert); + return [$file_ext, true]; +// } + } + else { + return ['png', false]; + } + } + + + function get_current_url($url) { + // If an old URL gets redirected to a new one. + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); + curl_close($ch); + + return $code; + } + +} + +__halt_compiler(); + +debug_logger(name:$name, variable:$variable, $type, $file, $function) +prints out: +error_log('• '. basename($file) .':'.$function.'()->$'. $name .': '. $variable . PHP_EOL, 3, $cfg['error_log']); +e.g.: +• favicon.php:__construct()->$__construct1: https://www.invizbox.com/products/invizbox-2-pro/#select-plan \ No newline at end of file diff --git a/folders/async_folders.php b/folders/async_folders.php new file mode 100644 index 0000000..e750f01 --- /dev/null +++ b/folders/async_folders.php @@ -0,0 +1,9 @@ +make_tree(0); + $tree->print_tree('index.php'); diff --git a/folders/delete_folder.php b/folders/delete_folder.php new file mode 100644 index 0000000..be6f2ff --- /dev/null +++ b/folders/delete_folder.php @@ -0,0 +1,124 @@ +get_children($folderid); + + // We need $parent_folders for JavaScript code below. + $parent_folders = $tree->get_path_to_root($folderid); + if (count($parent_folders) > 1) { + $parent_folder = $parent_folders[1]; + } + else { + $parent_folder = 0; + } + + array_push($tree->get_children, $folderid); + $folders = implode(',', $tree->get_children); + // First delete all subfolders. + $query = sprintf(" + DELETE FROM `obm_folders` + WHERE `childof` IN (%s) AND `user` = '%s'", + $mysql->escape($folders), + $mysql->escape($username) + ); + if (!$mysql->query($query)) { + message($mysql->error); + } + + // Of course, we want to delete all bookmarks as well. + $query = sprintf(" + DELETE FROM `obm_bookmarks` + WHERE `childof` IN (%s) AND `user` = '%s'", + $mysql->escape($folders), + $mysql->escape($username) + ); + if (!$mysql->query($query)) { + message($mysql->error); + } + + // Now delete the folder itself. + $query = sprintf(" + DELETE FROM `obm_folders` + WHERE `id`=%d AND `user` = '%s'", + $mysql->escape($folderid), + $mysql->escape($username) + ); + if (!$mysql->query($query)) { + message($mysql->error); + } +?> + + + +escape($folderid), + $mysql->escape($username) + ); + + if ($mysql->query($query)) { + if (mysqli_num_rows($mysql->result) == 0) { + message('Folder does not exist'); + } + $row = mysqli_fetch_object($mysql->result); +?> + +

Delete this Folder?

+

public ? $folder_opened_public : $folder_opened; echo ' ' . $row->name; ?>

+ +
" method="post" name="fdelete"> + + +
+ +error); + } + } + + require_once ($_SERVER['DOCUMENT_ROOT'] . '/footer.php'); +?> \ No newline at end of file diff --git a/folders/edit_folder.php b/folders/edit_folder.php new file mode 100644 index 0000000..acf73a8 --- /dev/null +++ b/folders/edit_folder.php @@ -0,0 +1,123 @@ +escape($folderid), + $mysql->escape($username) + ); + + if ($mysql->query($query)) { + if (mysqli_num_rows($mysql->result) == 1) { + $row = mysqli_fetch_object($mysql->result); + } + else { + message('No folder to edit.'); + } + } + else { + message($mysql->error); + } +?> + +

Edit Folder

+
+

public ? $folder_opened_public : $folder_opened; ?>

+

public) echo 'checked' ?>> Public

+

Inherit Public Status to all Subfolders and Bookmarks

+ + +
+ + +escape($foldername), + $mysql->escape($public), + $mysql->escape($folderid), + $mysql->escape($username) + ); + + if ($mysql->query($query)) { + if ($inherit) { + require_once($_SERVER['DOCUMENT_ROOT'] . '/folders/folder.php'); + $tree = new Folder(); + $tree->get_children($folderid); + if (count($tree->get_children) > 0) { + $sub_folders = implode(',', $tree->get_children); + + // Set subfolders to public. + $query = sprintf(" + UPDATE `obm_folders` + SET `public` = '%d' + WHERE `id` IN (%s) AND `user` = '%s'", + $mysql->escape($public), + $mysql->escape($sub_folders), + $mysql->escape($username) + ); + if (! $mysql->query($query)) { + message($mysql->error); + } + + $sub_folders .= ',' . $folderid; + # Set bookmarks to public as well. + $query = sprintf(" + UPDATE `obm_bookmarks` + SET `public` = '%d' + WHERE `childof` IN (%s) AND `user` = '%s'", + $mysql->escape($public), + $mysql->escape($sub_folders), + $mysql->escape($username) + ); + if ($mysql->query($query)) { + echo ''; + } + else { + message($mysql->error); + } + } + else { + $query = sprintf(" + UPDATE `obm_bookmarks` + SET `public` = '%d' + WHERE `childof` = '%d' AND `user` = '%s'", + $mysql->escape($public), + $mysql->escape($folderid), + $mysql->escape($username) + ); + if ($mysql->query($query)) { + echo ''; + } + else { + message($mysql->error); + } + } + } + echo ''; + } + else { + message($mysql->error); + } + } + + require_once($_SERVER['DOCUMENT_ROOT'] . '/footer.php'); +?> \ No newline at end of file diff --git a/folders/folder.php b/folders/folder.php new file mode 100644 index 0000000..f090e18 --- /dev/null +++ b/folders/folder.php @@ -0,0 +1,356 @@ +username = $username; + $this->folderid = $folderid; + $this->expand = $expand; + $this->folders = []; + $this->tree = []; + $this->get_children = []; + $this->level = 0; + $this->foreign_username = false; +// echo '$user: '. $user . '
'; + +// This section collapses the folder tree upon bookmark deletions, etc. Why??? +// if ($user) { +// $this->get_shared_data($user); +// } +// else { +// $this->get_user_data(); +// } + $this->get_user_data(); + + if ($settings['simple_tree_mode']) { + $this->expand = $this->get_path_to_root($this->folderid); + } + + // Searching for invalid folderid in GET variable. + if (!array_key_exists($this->folderid, $this->folders)) { + $this->folderid = 0; + } + + // Searching for invalid expand entries. + foreach ($this->expand as $key => $value) { + if (!array_key_exists($value, $this->folders)) { + unset($this->expand[$key]); + } + } + } + + function get_user_data() { + global $mysql; + $query = sprintf(" + SELECT `id`, `childof`, `name`, `public` + FROM `obm_folders` + WHERE `user`='%s' AND `deleted`!='1' + ORDER BY `name`", + $mysql->escape($_SESSION['username']) + ); +// echo '
Result:' . PHP_EOL;
+// print_r(mysqli_fetch_assoc($mysql->result));
+// echo 'username: '. $_SESSION['username'] . PHP_EOL;
+// echo '
'; + if ($mysql->query($query)) { + while ($row = mysqli_fetch_assoc($mysql->result)) { + $this->folders[$row['id']] = $row; + if (empty($this->children[$row['childof']])) { + $this->children[$row['childof']] = []; + } + array_push($this->children[$row['childof']], $row['id']); + } + } + else { + message($mysql->error); + } + } + + function get_shared_data($user) { + global $mysql, $username; + + // Does the user exist in the database? + if (check_username($user)) { + $this->foreign_username = $user; + } + else { + $this->foreign_username = $username; + } + + // Get all shared folders for the given user. + $query = " + SELECT `id`, `childof`, `name`, `public` + FROM `obm_folders` + WHERE `public` = '1' AND `deleted` != '1' AND `user` = '$this->foreign_username' + ORDER BY `name`"; + + if ($mysql->query($query)) { + // Make two arrays: + // 1) $children containing arrays with children. The keys of these arrays are the id's of the parents. + // 2) $folders containing arrays with folder settings (id, childof, name, public). + $shared_children = []; + while ($row = mysqli_fetch_assoc($mysql->result)) { + $this->folders[$row['id']] = $row; + if (empty($this->children[$row['childof']])) { + $this->children[$row['childof']] = []; + } + array_push($this->children[$row['childof']], $row['id']); + array_push($shared_children, $row['id']); + } + + $this->children[0] = []; + // The 'childof' fields of each folder with no parent are being set to 0, so each becomes a child of the root folder. + foreach ($this->folders as $value) { + if (in_array($value['childof'], $shared_children)) { + continue; + } + else { + array_push($this->children[0], $value['id']); + $this->folders[$value['id']]['childof'] = 0; + } + } + } + else { + message($mysql->error); + } + } + + + // Assembles the tree. + function make_tree($id) { + if (isset($this->children)) { + $this->level++; + if (isset($this->children[$id])) { + foreach ($this->children[$id] as $value) { + array_push($this->tree, [ + 'level' => $this->level, + 'id' => $value, + 'name' => $this->folders[$value]['name'], + 'public' => $this->folders[$value]['public'], + ]); + // Check for children. + $symbol = &$this->tree[count($this->tree) - 1]['symbol']; + if (isset($this->children[$value])) { + if (in_array($value, $this->expand)) { + $symbol = 'minus'; + $this->make_tree($value); + } + else { + $symbol = 'plus'; + } + } + else { + $symbol = ''; + } + } + } + $this->level--; + } + } + + // Draws the tree. + function print_tree($scriptname='') { + global $settings, $folder_opened, $folder_closed, $folder_opened_public, $folder_closed_public, $plus, $minus, $neutral; + + if ($scriptname == '') $scriptname = $_SERVER['SCRIPT_NAME']; // e.g. index.php + + // Depending on who's bookmarks are being displayed, we set some variables differently. + if (!empty($this->foreign_username)) { + $root_folder_name = $this->foreign_username . "'s Bookmarks"; + $user_var = "&user=$this->foreign_username"; + } + else { + $root_folder_name = $settings['root_folder_name']; + $user_var = ''; + } + + $root_folder = [ + 'level' => 0, + 'id' => 0, + 'name' => $root_folder_name, + 'symbol' => null, + 'public' => 0, + ]; + if (isset($this->tree)) { + array_unshift($this->tree, $root_folder); + } + + // The top folder shows up too high at the top. Draw a little space there. + echo '
' . PHP_EOL; + +// usort($this->tree, function ($folder1, $folder2) { +// return $folder1['name'] <=> $folder2['name']; +// }); +// array_multisort(array_column($this->tree, 'name'), SORT_ASC, SORT_NATURAL|SORT_FLAG_CASE, $this->tree); +// echo '
'; print_r($this->tree); echo '
'; + + foreach ($this->tree as $key => $value) { + // This is the begining of the line that shows a folder + // with the symbol (plus, minus or neutral). + $spacer = '
'; + echo $spacer; + + if ($value['id'] == $this->folderid) { + $folder_name = '' . $value['name'] . ''; + if (!$this->foreign_username && $value['public']) { + $folder_image = $folder_opened_public; + } + else { + $folder_image = $folder_opened; + } + } + else { + $folder_name = $value['name']; + if (!$this->foreign_username && $value['public']) { + $folder_image = $folder_closed_public; + } + else { + $folder_image = $folder_closed; + } + } + + if ($key > 5) { + $anchor = '#' . $this->tree[$key - 5]['id']; + } + else { + $anchor = ''; + } + + if ($value['symbol'] == 'plus' || $value['symbol'] == 'minus') { + if ($value['symbol'] == 'plus') { + $symbol = $plus; + $expand_s = $this->add_to_expand_list($value['id']); + if ($settings['fast_folder_plus']) { + $expand_f = $expand_s; + } + else { + $expand_f = $this->expand; + } + } + elseif ($value['symbol'] == 'minus') { + $symbol = $minus; + $expand_s = $this->remove_from_expand_list($value['id']); + if ($settings['fast_folder_minus'] && $value['id'] == $this->folderid) { + $expand_f = $expand_s; + } + else { + $expand_f = $this->expand; + } + } + if ($settings['fast_symbol']) { + $folderid = $value['id']; + } + else { + $folderid = $this->folderid; + } + + // This prints the plus or minus symbol with it's appropriate link. + echo '' . $symbol . ''; + } + else { + $symbol = $neutral; + $expand_f = $this->expand; + echo $symbol; + } + + // This prints the folder name with it's appropriate HTML link... + echo '' . $folder_image . ' ' . $folder_name . ''; + echo '
' . PHP_EOL; + } + } + + ### + ### Removes a value from the expand list. + ### + function remove_from_expand_list($id) { + $expand = $this->expand; + foreach ($expand as $key => $value) { + if ($value == $id) { + unset($expand[$key]); + } + } + return $expand; + } + + ### + ### Adds a value to the expand list. + ### + function add_to_expand_list($id) { + $expand = $this->expand; + array_push($expand, $id); + return $expand; + } + + ### + ### Returns an array containing all folder id's from + ### a given folder up to the root folder. + ### + function get_path_to_root($id) { +// echo '$id: '. $id . '
'; + $path = []; + while ($id > 0) { + array_push($path, $id); + +// echo '
';
+// print_r($path);
+// echo 'x: '. $this->folders[$id] . '
'; +// echo '
'; + +// if (empty($this->folders[$id])) { + if (empty($path)) { + echo "Folder #{$id} does not have a parent"; //:debug + return []; + } + else { + $id = $this->folders[$id]['childof']; + } + } + return $path; + } + + ### + ### Prints a path. + ### + function print_path($id) { + global $settings, $cfg; + $parents = $this->get_path_to_root($id); + $parents = array_reverse($parents); + // The following if condition has been disabled. Could be enabled to + // allow the "show_root_folder" function. + $path = DIRECTORY_SEPARATOR . $settings['root_folder_name']; + foreach ($parents as $value) { + $path .= DIRECTORY_SEPARATOR . $this->folders[$value]['name']; + } + return $path; + } + + ### + ### Returns an array containing all folder id's that + ### are children from a given folder. + ### + function get_children($id) { + if (isset($this->children[$id])) { + foreach ($this->children[$id] as $value) { + array_push($this->get_children, $value); + $this->get_children($value); + } + } + } +} diff --git a/folders/move_folder.php b/folders/move_folder.php new file mode 100644 index 0000000..c6750f5 --- /dev/null +++ b/folders/move_folder.php @@ -0,0 +1,65 @@ +get_path_to_root($folderid); + +// echo '$folderid: '. $folderid . '
'; //:debug + + if ($sourcefolder == '') { +?> + +

Move Folder

+
+ +
+ + make_tree(0); + $tree->print_tree(); + ?> + +
+
+ + + + + +
+ + + +self.close();'; + } + elseif (in_array ($sourcefolder, $parents)) { + message ('A folder cannot be moved to one of its own subfolders.'); + } + elseif ($sourcefolder != '' && $sourcefolder != $folderid) { + $query = sprintf (" + UPDATE `obm_folders` + SET `childof`='%d' + WHERE `id`='%d' AND `user`='%s'", + $mysql->escape ($folderid), + $mysql->escape ($sourcefolder), + $mysql->escape ($username)); + + if ($mysql->query ($query)) { + echo 'Folder moved
' . PHP_EOL; + echo ''; + } + else { + message ($mysql->error); + } + } + require_once($_SERVER['DOCUMENT_ROOT'] . '/footer.php'); +?> \ No newline at end of file diff --git a/folders/new_folder.php b/folders/new_folder.php new file mode 100644 index 0000000..10b8e6a --- /dev/null +++ b/folders/new_folder.php @@ -0,0 +1,42 @@ + + +

New Folder

+
+

+

Public

+ + +
+ + + escape ($folderid), + $mysql->escape ($foldername), + $mysql->escape ($public), + $mysql->escape ($username)); + if ($mysql->query ($query)) { + echo 'Folder successfully created.
' . PHP_EOL; + echo ''; + } + else { + message ($mysql->error); + } + } + + require_once ($_SERVER['DOCUMENT_ROOT'].'/footer.php'); diff --git a/folders/select_folder.php b/folders/select_folder.php new file mode 100644 index 0000000..cf3282f --- /dev/null +++ b/folders/select_folder.php @@ -0,0 +1,26 @@ + + +

Select Folder

+ +
+ +make_tree(0); + $tree->print_tree(); + $path = $tree->print_path($folderid); +?> + +
+
+ + + + + diff --git a/footer.php b/footer.php new file mode 100644 index 0000000..b2a8250 --- /dev/null +++ b/footer.php @@ -0,0 +1,7 @@ + + + + + diff --git a/header.min.php b/header.min.php new file mode 100644 index 0000000..ec69314 --- /dev/null +++ b/header.min.php @@ -0,0 +1,28 @@ +install OpenBookmark II.'); + } + else { + require_once($_SERVER['DOCUMENT_ROOT'] . '/config/config.php'); + } + + require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/mysql.php'); + $mysql = new mysql; + + require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/auth.php'); + $auth = new Auth; + + require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/lib.php'); + require_once($_SERVER['DOCUMENT_ROOT'] . '/lib/login.php'); +?> + + + \ No newline at end of file diff --git a/header.php b/header.php new file mode 100644 index 0000000..d917cbe --- /dev/null +++ b/header.php @@ -0,0 +1,63 @@ +install OpenBookmark II.'); + } + else { + require_once($_SERVER['DOCUMENT_ROOT'] .'/config/config.php'); + } + require_once($_SERVER['DOCUMENT_ROOT'] .'/lib/mysql.php'); + $mysql = new mysql; + + require_once($_SERVER['DOCUMENT_ROOT'] .'/lib/auth.php'); + $auth = new Auth; + + require_once($_SERVER['DOCUMENT_ROOT'] .'/lib/lib.php'); + require_once($_SERVER['DOCUMENT_ROOT'] .'/lib/login.php'); +?> + + + + OpenBookmark + + + + + + + + + + + + + + + + ' : ''; ?> + + + +display_login_form (); + require_once($_SERVER['DOCUMENT_ROOT'] .'/footer.php'); + } + +?> \ No newline at end of file diff --git a/images/ascending.gif b/images/ascending.gif new file mode 100644 index 0000000000000000000000000000000000000000..c01166352bddd0afb8b47a8782dfa9049fda7a57 GIT binary patch literal 82 zcmZ?wbhEHb&d&b-|G(ltQRkx6#FEq$h4Rdj426)4R0VfW-v9>1pDc`A j42%pq3_t+V!oVcZ)4%dG8}FkolZ(~s^7brdVz34P1Lqi+ literal 0 HcmV?d00001 diff --git a/images/background.jpg b/images/background.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8bf788e08673aad8772197271d3f84088793de6b GIT binary patch literal 23122 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

x<~5?j7kZFR!{8_XJ_20deOzte$I|; z2yWRe=H`36_#ACm!r+;u|0-oPEW$?n?f35vAUjhBW7%;O+Y2J=5$2L24L7b`SA1V) zlStMsQUR{`u;==>*MDTb<1FGRzjgHpK)~6WorT+jyNU-npYh(SnDn1(w^hkeTm%0c z575Td;a@`hypCf^w%d`ImgyyD+0fULo_!p3R@$A$$u_kgbW8279w$Hv$x6a+{qR((r(dhzbEnE)MJaPioM+{0dUrNf`N;TVQ{>- z^Ey+`Po^?3-NPHcP@Ma|vzDuSL(B#u@zST_leajY+nFAa|TqS9L) z-9IbSCXx=6ak{7SW-xj@NS!<&k%zfL31Qw1wswAwZMUxGH8IuE^^12~}m~4wrXhj4IQY$u`gpAj`mgo#}kJ#5mO?ZJa4psVNwf z6wYz0-+EL{3n+>`yeD@gyP{vX4>3?Jv?wv zR2>}|y6%EJ^|&WEy%ZzDIl{FOtgSrm1d-vCwNCvi?b7aNb|_OH^U*=4m%b>rSOrIn z5vLad`#p*GwE^!-a3m+DH&nM9$y+OE!cN016wbL96V9?cj*<6gqFc|%F->>*#sG~F zwW4Bhhe6I^3=f|~i$cUTpBk)CIP`avxhnn6@52y&f5rbQS{=1O+0Rb9qiET91K_bK z5rqcM_9-+Ab|b5>7=JnP+}Mz#6QA4!n458x9rK}gNNz?p4iYTqf0pC8 zoE!oe{|YY}K+c^K1}R;QJDLrM3-LEm_VW#|T{LHIJk@dy{45*JiP~d~gg`6dtb-Q* zlX$g^rJoRsbX$-@F&W28;QDL3RrdqrSG1?`LxZ>yU+)vW=IJ-Ox2*N8X{(Rx)pkX5 z%Oj78jtnWs*M3V>6Slqg_$c@ZVDX^_Rc$Se=GYcb%XtkEoa`3C!*!`x-dwAKcqb&c z^!Qw52bq(R^frceN+=sjE&utBhNcwAByg(5AjlIK5Ce>HKlRPnRc@Pc+u+5~pjo1e zQ1}8SD_O1_V_T6EpzIK;%o0M~>U*no+UDChmy}+M;C^)ox2pu_vJ8l%NJsAC3h^ z`&BXIPO-DRvDNs51OEEqdZhBU7T(;lEu~O<8&Af3p+VN5p)VJC1p5??v-skI+|jqT zDF>g^kYVhc$h=6B6<+OWySeUfz5vI&Jo zigqg4LrU{MSN+vik~#IDDim?>AbWReq* z85V9xK>99O!&-Qyhai!$g6rDnk{V>bont4cfkUGg-2BU_4@pH&EFsMW0aXwVK^1M9 z71~pl$wyAI=Bi}*vQmZKA-zxUYLnQ*u#|5qq%q?vhTts;8Q~e(WRo57IE^sd7)s@T zKtPG8r;f4iQq|m zh3a<13troOKyz)T7;&z4oZf|pjK)_F8;bH_?gGLvYLN@q%fN+nBxOoL=3DfHh+37t>EyqHnaAs+!pJR;#Voci*1wC9aqC`N3I&NjX`! z4G_f((YArc$5V%E6SU?LKP-7~pP}aS z5Y#-~6iQ^~d#S^Hh9$XJne z3IpW}6VT10ltNA7McMm-lCAZE8@n>FMM>G?^E$=pohi?AK&Or{>z(;a^qZU^1frVnEX+EX=D z#1i;bl_cEZN^f6jWFDpxxtCUkh4*BU{{ze)hUst=b)?K!#`E&tC-cTgihvSq%lGe3 z;EZ!*(>JwR2}mB8Qi{~1Tg6^hj`w#1N0oE%q(WV|mAqPgd?!Jb7Sji}fONwrjWrvD zxZb#-e;vT^1zuP;o~88z+5=vaB=81LwSB98jS$IH?AOK+lk!7V~pcL7qx&7Kd>KsFnG zXz@Fv8HeyO9lk=4vcn+z57ESjSR3=I8fARXLH~|A>Zp@{fFX(sMzJ?R|G6chS128{ z26vZnnr=|wWoU;BjT%|RR21{Mu%~&*s?)e~TUq&tM6Kq)AP%7Dv-T!gT|exeo^rDz zM|+Pof;o_w(#U_#QDv3wUhT7};CQ);9eXq$8jh-#kkUlLs0jIsvz((>g^thZ!eN0z zPT?)+VZTpPJ)B=y>nDEcN4BRQQBq0K#h(J}OmnoqiqML$u{?;~J1Wn+$ct)kV2$&+ z>nbX1F8jy6K`nzHkWTe#>q0c$4M%Je=AosqfK$?jrfw6v>>Y`(-i$ba(QY+p$gWOs zk+bNQXTP{K=+ugON*Vvr7JxnnA%!GrS^pP2proTUecEJrdto93?bf5#Mn-1Ip2pg~^5s7oH zlL;<}47uv+(GfL9nBsbsz>T)*TsA)(z$i6Ke<<;uqZ^r%X%>zP*`NdZ!TmB8r0#0Y z2Qd+DJO(z)y)_EmgZ@B(>bX+@B&csPSzh5u>20Hdv2+WQ zcDlnUjh1Iq5Q`t7a+h}HQ*;L+KwpIc z7W$eD$bgI?(RfrToWI^ST6N1MXih&!oM{w(w`^s*YfTaVAO+GdLp(^WPK4V^AQRaM zI4r5SbZ&X{<)@JR-8oWRW*elp!z;v#A}FaXpKrn9X(@~e?OPa@LSNJ0QA4C>#}3#% zCb(TX_vdhhVI`7L0u@PsC z$kbkmh7h-R%(E6EMi>Isw!Do*QzBz7c6AiQa^Xb9G-ZqLW2j?1gxWukGU`%~wBua{zs! z`$3v9Rv2$)Izm;_w60yfA`Yr$Sp-t8!YuRhlqMh)7Kg_k{!s8g9X>3%?iWVrdOZ0=E=NM+^2 zwKtRp-&Fxd!7wdxOF<%Pd&bZ^9%zq|uPEM@`f$*#ikv=Xy_`G|>^lMco-r1Sh^}k7 z&Xm5ZRB)s3r`RBd>?M|~uIIiy-9CD2(QP9y_acwnB$!ofDyYX|L*>iQZy#Ei)T<)a z?`!&>--WS{{5eYA{2m27^1Gs0&HiEHt_Kq5g0p0@EhjM<^wa}gJPBDLhzNp3JrZ~0 z`j%7twFZ#u*S?In47N}84K13%x3g_*8_<*Xq zQC#d7CWR19p%3{JBefLw4hZQ7;>Vfd}PNylCJ3) zGuIYOA&)LO&QM;)J~i9BA~mxKBWWnR8WY-iRc3Q$Zo^k1Y1w^=AH=>km241CBV+?- zfIQ6!bdo4+4%wjnCcbRyB(QIiX6uzeQalOTrLPbw7<-y*yOPDiP7n3UBe}BSl5-`S zXRIenHu<6U9Jl^?*iTkJW|M-FgOt?zp<>g9fqhB^e0c&0@<1g}bk?NOpu(np#V=32 z|C4+B+ta&0+q}PC-asd8A4-i#>iZEfKG6=0wg07gxkHlPaL|Xt?coi+VrU{Sa)U=R zs5w45sUMW8`3cM#)F}#U&~)h9CWVZ)Nc01y5k^MNYDEB}bs0W}_Xs}VUc+;Lta$_( zzj*BTtyWj0an=t{kA8%CzDcB}E$NJeHh4RV;QH74sU{Z=(WA~B^9A>nl|IjS6p{6w zv5G~lc?yXA{DCz^7PEr+y|r9-es4uW3>DKki!=Y`9->4!;Zo|*LU2(1MjPKeGhY%V zWGBuL=h3QZXo-tr*)S-BErBzwXou!w&qIsQu3F+W8#=DCMA5%reO zCbJ3f9k1*2jdcG8)pdX^DQx1y?>X-L8McH38@2SbyFxzc5?hX|NMztgvK}~p^lNT0 z**0`E3Llpex#+*!35djV5HKX20u>2;7!YgVFPQYF-meD;Lyytmq{wdYOzwe+SYEzV z=@xmL?@kcM%m(l4zEXW~){Ll{eaJSBKrgp5LYTotmFrP*wrigA5R<$6Q%15z%a2wq zBn+V`8!G#P2Qd1WXI^az=cm9QCpmW2VIR`h+8V~4VG(EZj|{==>_00erDp_m8T-Z=ZZ!qJ87*Otpyc`3UOu>}3`_*HV2S?Su zS@n7yUsPd;+&Z%yjAA&S*Nd3keX-`)EvzG?J?gJH_!FH>^25YHlHyJbq z=d+PKkZ$0P-OL^&X?zlOOd>(H{wLTE z4{1=CVjQK#2mG=So}dQyN)i$zq~M;2(3I!`*qhN4$vwRm76A|Mgb*1X(Qw;=9{u*a zz>x3{82m&8jY~^d*fX?B3nyJ%LJQAV7{wo2QE@v{%ItUhPO~%3eE#H{M`BP!c3Sk_ z8YvU5C@Vd0_f~cNhe2Ljl;em~(=<^?>_l$o#DVb@2|ISbFoI5U&M_h};Y96%hCsC}vy&YIU+`??qD)BrPEuZCG&SRcP zTq1c81JvWTMEaD_koLc|Zo!c~ki!PC`y3kgeWX4v_r=J*K`Qw=wXRWt)V_8%avjYIFACv<`b#y6P2wW0WP zt`nF!+QL$%Z&^Em{O-AOpn5u5Q_$^3TwZEa04)zjS%5B1)IAP$J&GmozZuD4pa!uf z>NcTZDJcsE1v~ddiqhhoe;8IB3q42n)#B}!wj-E-lp8cBs@T*t*eWx~f!P=6%Yy%2 zrGZE=WHQQm_l&m4iX!PYe-!!_-AE=_{+;wd_YV#Y;`)bbDN z&asT-rXUAhSxAKmC8hh6j|-?Z>GDvvUfaV^*6G5!zU{1gu_Z@1-> zR`^f^5Fx4grOuRB&PtEw0NMU${V@8BqV_@dwxFpj#tYG${jK^)vxsNhG7={y2?`v; ztzpa}N~>jmd9rtxt^WZgl#)3@3M}8H9s+0*zYVuWILz~G*Ky#Ll1Gab3Xr%Cv1Tgy z2h15iSa4%E;!3gD2=f&9?&0Sg$fKb-Z}TZ@uv*cxq@FrPLJs%!#Q3u!;AN5=P0ml^ zX?&^8U6xC>@&-Y(CA#pA8R}LjjW>4iuDn<_9eed=8}d z<55N=?T=KA8*=*I1%G-hFhc_2Fo^EYX{_tDByqa;|poMQ?ep?*!4VT}{kvv@s!~ zd5)D{s7y2(IKCWxDN@Vl$Kd}Pp_vj_)Q!x0S^dHO0q>dffELTGj7+&QGa7KdxT?SnFxr}u*zbY+92~PBQz)9&ne`9}2}jm3 zDw#Zf1b>{iY)Q%5$1kirk79t3J+Muj1@K+NP;g8nI6qY48czOp&XEw~hyy7+74ltv znsB0joR=e|Vv9DWl}n3B9IW04K0cnM)hm4BhbzPdt&rf8@!T_c&okEKGR9}I)poIG z7CR6v6w!L)0R1yY2$TDryJzr*#ce&AHOCe+{+$~}eQXFR1?OW3XY;;UXth_irm13*L9kB*&n`Gg&ZsXdWS4?FYSLU(@jDp+5b9+ADuf z)caELy88nb0z?xp-{?QKWB4rk1B&eXK}3?T3zz^&2YSGA#18cy0}Q6T7%tKei`pD5(U14(tkGHTo=zcDwoo-#>-d0&gMw4gtEbrIbb@IYD$2^ zTHfc7Gb?<5Wiqf87;7%iYD*7Wx~>m}-FFfrg7hW!wolOUeZl8J^$i90)a>^(tlb*B z6dLVBtoIE_BJO+VDx4U*@$~YaK6lHJyOUI12{{p$yB1-+mJ7+W7N*OvU)gcL#Fn6Z zsy;R-l{p3zKgjaTZejXXXK5@Q(Wb?fCnenBbw@*fQ|2H5yRMUO&Nm75JWI1i3+tzU zn(&ORR*oBGNr)*Ct97im5^0v|w(<}t`6PpcL7s^vNxE^5dk^v8D%fY~llCzfeV{TP*nhRNodq$;Up1`t+# zG*dneJ*OC=|L!D)&-s$)C9lP*ju!7vrk~CuZlbkqv2SWXLPNP)CO}Y))$o=e0s9~B z+Ma)agFeqNy^pJfJSLF5QL$9Rk2Yi4Sj09nUUe(@Am(i@($BL5zHrLLJ8b)XG+@g^P<#z*W6z$>{#E~<;7^Okwoohc@0vX?YXsMYSx!3DCQN!mre{Til$SRr)bp1xXE+ z{e+t%GW(qu=qY^CcJ0kq9)r_C%%1$;5EqcZQkXFeh03V*nEwZKSjG>2I2fcp5qJ(F zXcht4*}`Q_!-xe30(^>1ls{zho-;j=>Etfk9(lC0iqAbd^LcbX3UNet@eg1jaADYN*jl)6;fJ62L#W@0M|QW3C)N1xO7zr@^(tj4G1su`Ils`N;#)7 zP#YDr~+iDI(}+|y>G2`W&6JHqf;7|7!daVcpSVDi=3Q|SBc)q)X9Yh>3uiYYE(z^h6wh6) zqitM4TaZ;$P`2|IjhSlH08W#`kWNv(#i#C%m;{?mbh%dDY&^Wha0OzNu&;*alFZW#;C#&!Fft! zaH|$4nl!;<^QSWJUN6&M2b`e5>Qt75Z2>9OD;h6*wO7pn0XDLh<4}4aLA{|a#m+G1 znegc0TdTpEQcnHYK`OTTH|x#xkQNaTQ<>N9?Qb=ss!{tS;MNP$*0wqUUM|6$oaG?I z@R1oR*7EYt(i_p=GF7@D=jz!h+C=gz(Jc0Ko75oh%|m>6tQ;OYK*|XIStb%FyLL9) z`>=0;$g88{q$Ye3=#p`F3bw_?N3~G`2#LW?6+Z9ruL7%x5JD_F)3+c|wg?i3M@@|_ zH_tH=e%WO3{UyX{DD>w+}J!5TvLAHf^X6OnCBhA)nsVN2C^48|-KJ|Ysh>y-#z zt1!WXyNvB%$%ve5E&mfKHrv&_qer!J40(!+QUikN<*}dNK?3__2{x8o5(bG&5)4J} z5%20v9*Qz(QH~U=yyA=XaxSk-g)tslAab$^?{u=l$5lQc=>1)ZUi-N5{FFz=wG2nY zZ~hLpRFO-KcsHC2Q(1=CgYTMBjIVTf#@f?Swoz-S5#l(b705|^u&o@a(dsaO7~ zLuUo(+t52UWhD;~iquRHi!mmF;q_aCzkPoeyGk$GY3h@U+F_OZ-u#Eo1R+k}XV)A~%j5V0>6m026J9?lYBx6C zux0HfY>|m=2)#Y&R4r$?+6a0M6=p6maT;ZRo_OfA>&n1cM4Mo` zs>n)AsqhcrTS$ljIw)Qc<}A$wl-Y~`$`Iu;zK#Ns_%EB*q_&YfZ#yd}v)ev`YDMrJ)-8m*x`=Y<$XAlVm?& zZ0cJScLWQ1&(DZnzxr0Uytbh3Xu=Sl>v?SPRlv+^>*8mL`S)#a{{Np8KSq3Lf83#{g#5TXi+%Lzq0fJ$7AQq4=MwTPX@8jyoR zpVJ=}#AWV4$`Z`Jk3DW1EMMsyj$2dMb>$mePM4T`j?2B2gFOhtz<(rr zXy>XvmJ-j;GdO*pT zJy=3hVT)UX9r*G*Ceu9WJf2*lGE=I;ugC#4iXl?z*6R3_+_X7jlK@F7?FIcofS5{< zMg3f+QWQ>C>eDJLU8GBU{o1W}t%VbR>`O0;*I-rnFO)cp>M*@Au9?Wou8Q+=J+Euo0pl=lpaWf+X>33UM}6p>#MTLRPjQoYo~Is zjg7#BdQMVmsvfm_ZTCY)bXEqi6e7n_yy8uT#}cH(=q;*xd8^yQbwpz-VcpIWD6?M_ z{xvmR`4VNDD$1H8GMZ&C1B`P4Zh~p>vPV06XE_Z+y2_jQ3Y2&fI_!9>f%V#=7cN}J zdT(%dy@8z%w-b$>H!__kX#-M`>85r9CCO&DNuUBGO{=D}_iW0KrN+|cJBGd9)^p(Pr=QPq z@e2B>VU}|2jK`2)c|i_BRVNKup>qJS(i?jlGC zG4vVd@f46Q=MRm;KYOK8w|Q1G43d$!?oK^A)Yn&+(7H}yL1>szpnSxh^Z|93X;dBa zQ`_Lk0q90EPm5zl@?&#u;~!3xKFfK5R#w2y0iXg&5;#}|!EBO9=sjyXS?(pD%T$RV zEJor!b~yB_Hyqo^DUoB^pEF2sqn?>G+lzSNe>J35OyxjsSmU>~06DU&B7gv3FgtAp{aS)XZ4Sj!0DF0CS&XQAmGyrPMAmaX=1po->T&8ShnYb_UqYyUsuv=QU-Q z<&3eJg z093u0E#0(6S5;H;QWI?^v*)f9P=dMODDtkE=I818F1232J z98d*|V4h~eP7fKU@Oc~nIQ;2>3W7)@JdD%Fr2rlCMJ*Ho^Oln^mMLu{pL6-8ky!{B z_VuY@buP*Rs&3jqI2`ldnWIN6_cD1`P_rk?<+%z-Jn(9JI471rEQa5_oxZ2P)_@_9 zBSe^Rj-=z7hr-tlXFb)NR~N5uaKxy2OGd5VB=q`K)`CFns1;>Ud11gKy)wa)+bJ{v zTHclN=XV4aQPUlb0BF3jO(&Nq^Gg2!X}7uouOgL0Zf}?G4xE$IAXD8E z5jZy1?8O7d(EnQyAnPi7_BdY_JZ>OyQI(Zg(Ve{@5Wd%+Q%;7l603HV> zv~Mn>nWL6C(HwyubCqm;(rYp()fuDm#@*zueKAFwq;exk3}qAjV)M@(r~>`O5j-cM zlNlur27j$qf+>8qiJ2GxNGPX2Ppv*LE=d+G!ap!GAOPneXB1gWEEjKYJ?bsHugC)D z%g?`j&;_jsk*cM#$dD|h6iFe-&N0`uO2N(0NmezPauj*FFOHxN{C-r+*R#_+LYDFm zwAkt^fhr8Dup7T4_kS9%HSD@xpR8X;Z*g&DrfiwaQ3EP7@B*Jq3IKi8%;W}5J~$*m zV-CkT%|h2U_qu)6vcsE}-SaT{LB|}`jUxWXThOevT`}d5T%nW8n~4+y(Y*~4C9o2? z5{Ct{nE(Thxu6PqCG=Mw9=5r*RJXYevUo_w)0}kenwwQ?N#%}NgBOjm9yHv4{Z$kz zI%y9pB=cLvDlD<2e5h=UllasPBF`PfA~6!YWg^RWEr4=3&olvg^TfIht&DA|U)#kK zm4#keL~I{8$0yenYE9R(7_FiW8z;&YicltcuaY6R!44|s66KNS9pVp(-VYU*;5Rw9%Z|>OUxZMi(S6jvM z?jyO>Es%*}x;$L%8QcosXKi-tewwAdo#myK%$B-^oOd?&F>GkbVagDBQn);LG}LGUG5zw&+!Md$C*FWGwD{(cBaPGs zPwxK!TH6+AmY!>f10FKR=KQOhw7!-(+({19P!2)l)yS`ijf=iUbMqd8fDKHfb1N^F zAEtI1p?e}r5t4F*q1*DI&O4APm$%B&21fv#5>IUL#aC;D-rJ+dVnKHPE079oH9rI3YnFx*}L);t>)~`;A&m5a_fp+a3PrU$FjIWdBtU*|u ze6P-XQn854Bl%$tyeZCo=_9;JC-Oq7kR{50=Vb?W2wFTgt z$n%*kjtCL(!y`RwgTB$OH0?@FYRRMyW!ogFAq+i=oQeSSDB{|8ra|k5UI_Lyv7}C1 z$c1s-9)_#vS90Ij$2^6M%G+Ce0fzScD*Uh`+~l&UE0Q0%?LZao=P;`7+#?-6bDyni zSv3Q$zlnNwg_X#8K4VIr^q-G z5~se!Nz)Z0<~XLf#F}Y+4*r!yOvmfe*MR4%zIelljPgDCmWAX zTAEp6dnKoMP7+f0PoL;}XamSGSLnp;U3rxD34u9(3_Zoc(nONL*w z%&OAJNdzc4$o0piMQ^elQBq6@w+s{OpXERjUci>@KF`1${py-oUg8v;!zM={4*e?4 z{hX;PJbPtF8<4Lev+f|8JCI>*_#ZT6@JQ+?0Za_{_Oe0(xFb2>FwgU?+l%Nfiwk*4 zksKt6jAPtZOitmVyI4eTAKr}eKmApwylIgc_W`{ zsIjat%P`)+e84AGJ%`e^e#*+^9lY{=s)EiUc`dFGDmy8Rf!Gd306$HgB#z!+F`^r= z+=Gs3b%affQBDhIJ+a>--l@T2Qh6kex55tq@y%@97-g|baLV%mf;JJ?(D$GW+fiyQ zQb}(mw~`r}Lkw$`n2~@9^s2}1FY%mYj@@%owY2KW0{okgIPHpU|qPcJ0Z-IA@EF2yP!R|e2x9ZnWsYY)%I9yf6ib+9&Cyp6{kgoj; zXOFD_XP6>r&Uwh~)0(qn6La~?h{_dWPatBhwVbbE7NRvM78oOFt|JlUrkk)C+MxXTs(ChluI zk{trE+&X90fHbd^6^W7(xL!ti`qXi`z*1NN&m>egWrHu1A!D~JPp_pJm95q?yQU{N zUQGZ!-{&q#RR`tAVcw>Notbvyo<|&-s}mPEBb?v^>*-HuE+?ErYQ;z&FR3Tf+JG#{ z<~HS+3=m4~>rp~_g+?CiYI_MD>drZK?R{R)WLz>Z^%^;nemfja~jB*L8SF$TN1hXjX)2#qQ6{?9971*x8SfB5DRQ~`f#t<$} za1BRl#2!x_NvjcU0hxwQas>cb8=XNQo`6$`!UNx-rpCk}P)}U(PIH{#k~2UHyA6;i zq`^EsQ$}s9mdfc zmsi`kx#VDWs}QmKD7G9d5aADgv;hIsF8XG!3L`85;eTmWEOwkoaFTw=|CMvhVE_VQ>7hN+VcM0 zb}FoUa=Wv}detlIr_+pr`rX!5e5a5%WPJrqCY>A?wi?p8^Wy}l0|N{&LG`FSwP*ya zSi8P=6UgB7pbaNjwLLv&us&doa>aRJ_zv}-Zc!xI*GPn&r_3N=^yf83YuC}|x4F~N zVP_GC1Nign>s>y(I?bjevfIMuRY?ddz%02m0aaj_BC*>nY{bU#e8-*$7^X%3iLh3vC|f7!>Uh#4fSN8Z00d*av^DTsL=`U~NxKxHi+-&Lctwa;}Al zKZu|THZn=9=(f`fOXx(A;UKw#WXKfYsTd_s9cx3wcRG)U=exI#-Dig5V$T)8-U(gX zdUX71ma`VAuUOgK4-jfPeaw=xJhsdfvGX?b#yV5{9i(0Oi^1`0x`wxUZ*+^xs7X=+ z+^?EYZyul?qJSrc=j>N-Or;fsxiO+)R5AOYQ*X`X*0C+*N6T4u??+sDXQv{oTg42) z;+kT8e4<&)My) z;#enAWsH(T6W6aw0HtTF={kV3)8)`^Y_&Z;7f2<$gozp>mib$wbNGt1&Z^^+&Dc)tpHSOSnOq6vlZOS2?rL(_rwLp3Gc^mO4QRH zFE-xSOT3oC2Y|XoaD+gOgN0@JPDiC>>T4=n!*Opr!!VJFVa`T6Vy$V{cb9kHWuATT zZ$>M$bDpC#0k<`tm4Bu~Z-1^vE-j@pvp|Iuzn}+_KN_cdh~30&a50C*GN<~`L~Rs~ z(T$;sY#a<#X>N>@Bb8uTc^l3!Itl=vN}OZt&KfpnEROAvOM7+e=~G)Q%os*3+Bqg9 zy|jhH9-TXM8LXEL93tr-=Ufqyk-^PsSUcZGEzH6s50DZl!UZ7p9`pdH5hXt{GAm%I z?f6uTt1-m8jvSoy&!s3bnVusvYyh8rp0vxO`{iTF102u=%V3DH5p_D;Loq0zZbwqM z!+U3%W}hvT^F6!FzHrG@VYRdCgW8{9-fS%UR0Ra!jOX#Gbz4hoMuvGU;+)AC#^u3Z zp%ehmB4GG;;QZP46)Y#sguo#on=QPaIQOcHB=hNa^F=R{aRg{#lW1+EoOC=9?OePO zYnms-9U9X2#Mj!rwzmOEqMZ>$cwB;;M-&0l&1)o*6>ta~`(mVt9ulZSV~hpw`PF?w z1&;0*3p*i^)C}Vo=zZzGXlr|T(MC&*ZYQTS0cJHVADUV+K{!M6AJU|j=}oEgd1$^; z7rtt|w(B@)S(r7l?_H-EBc5q)50iNI>N2km@_U1d0E!^W$tACw3gCk3zP))hui+_t z`?iBpxeatwq8UgT6_sL+WVnuL4AH9PQHM&sZhY-Nc;x|vSP_sg%lOa*jZ;s$x0Uk> zy5}muhk+p&2@~c`dt#qtyH*QtvTaqg$Qq?88)g!V%@kG(H zIP(hzIP{gp40)2ro4J=X4&KNpUp4NY>xG^CyIDcpmXy#&e-G;>0FHI zBTxRhzj#S(^GPh%Hg*kt9mDR9KtdjdfI3TvB>Pt+$bY=uMOV7hrHHHU8yN{FxUG4k zH+nbri^%HmyC6V#Ag_AHzqnaaCNQX(RKO$z{n5`)S^$}?_~*z6M9&Yc|<_$Wb>msAM=+Jt?VoGrXz03JF{fLqHualW>vwcIDWzD-<0?Q+t9n zD{{M7NhuNx@T1?-pwiAEM^BZ50iLyD_U1-bW(k#$FAI!=Ko@T9wp;~KjmHNKSM8%I z7E4Sy#zE;^{MWO+&c$t*QgS}Eehpq{fLrauV|Mb{=ch^lmg`uxvbcyam6BZi#B|46 zl1U@Ip50-M0btCIc@4)I_Nh`ox7x(bu^mprb_0-oshUNsv9wT0a%5P}^!WhC9X^x+ zX4cmFJ4qK&5Elb6`CJmdtUF?}WxBZgM%a)76yTmSSpG7;@impd_MM-I3`iI!+0C-D zV?SKy-nFNBB9&!#^I7eKoQw?OfG3wwzq+-WdmCuvo-K*A@Tt!xpi7mwNftYoa~=bz zB|tve>N8X6nxLliFzIgntf2j2#s z(%Mf8sug)Q?#Etz4P|I|QeSEQWZ!>i8-eG8L@rWIi-EaDPvbxmFj=0ISfBlmTMm zDeaUMVxV$)2O_H=l2+X#7Xu@P>S}AL-630SDI2r99Mb91t4?i#5#M&~_4c3%t==_o zFbT#w)|H?_cC)tbxC1R=I%-7pyK$65f-(eK8madx5^ zm2I19`MhV`3WnjsT?JNLvB2iFyh9v%TtX<7oXg2#*dU(uj|?$+itd5N!<9V_XaX59 z%p^$!h{|xva;NBN0*NOHjzFe2k#8s2?d{eWkN~QLfHG>;guYQpN-Lh=_n-&Ls8%Y8`%>X_E5@cZX0v(q*p9FrpkaOyV(4bDmHQX;>Uvq?0PyD%AZ zoKOH|X52{H%D*rjDzsB7xY)TPB<}4=4Z}^R$2#RVJ0mDL2Oa4x+_T%jK-%Q)IONa* zYTB2RU~U%GnTg^wVs`=D(_*<>jXpcHW+G%HVTWp(^%ZTAK;Wh-Id(wNTE!ZyX%N8u zXaYdnAw|b0kWZ~K7UD~?+pvql`Fa{j2{LW$ql%Ykx`E+*s8%B?a83mPS%o&nxm+H4 z@tUb}o26iODUa@wGBZ}Ku?!(pWDY)Knn|KrZd*JI1A#ylZTCZDAq$dNv3}$5sqQo7 zq80Cv?rGO(78PN^994U%SzI2tCy&B_FJ&WC^CDIo&za9rjAQ!MZ#_)F#-&MaFgjwc zTG>T$Y9zR4lVJ{{IKefS9@m;g3$!cXV9*8aS5$b;^i>SYwVOQFbc!9=<%u{d2YR07 z)f!a{Ngie@M2S{mj>7_g1&e43K>?SVxhPZws008qO;uJcCJE_MM9j|W#~|eXQ~@Fy fe;f?*X^MEKC00X1jIhM+TLDljaI;AA-QGi>$kjZ(=@N3F^e?lY!eyr^-Ks{@d-6iqd<#Z=bp=+o1Ys z=hlO6{`<~U=frPqp8qRV=Z1R7f&R@wyf2HMyZ=__F8UWaExZ2wyt7~L*Z=Eef6&Na gcU&y`b6{(H5TEUh2Q4CD84p_}(pDroFfdpH0KjUbKmY&$ literal 0 HcmV?d00001 diff --git a/images/bookmark_image.gif b/images/bookmark_image.gif new file mode 100644 index 0000000000000000000000000000000000000000..2c2aeadb865dcd8eacdfd2dba5df386af9630096 GIT binary patch literal 1120 zcmZ?wbhEHb3}6sq_|Cu(5)u*`8X6WB_V3@n|Ns9pjDpb+7)c?Z1M(~=FEDWYW8maa zF-TZ&u$hBh%w&hb!o%&{(sm*m6BQ1(Fl+hstSC@E(k-Fu=MoX9e6(N5de)R18&Zxp zGqTJOnQ6G>00X1jIhM+TLDljaI;AA-QGi>$kjZ(=@N3F^e?lY!eyr^-Ks{@d-6iqd<#Z=bp=+o1Ys z=hlO6{`<~U=frPqp8qRV=Z1R7f&R@wyf2HMyZ=__F8UWaExZ2wyt7~L*Z=Eef6&Na gcU&y`b6{(H5TEUh2Q4CD84p_}(pDroFfdpH0KjUbKmY&$ literal 0 HcmV?d00001 diff --git a/images/delete.gif b/images/delete.gif new file mode 100644 index 0000000000000000000000000000000000000000..3f80cb50ee10df749ba99d02e54e31e2367465b7 GIT binary patch literal 1029 zcmZ?wbhEHb6krfy_|CwPlarHIP*7M{SXNe6S6^RIaiF5&;Dl_$woIp%yxiW({3&(G zm$Vr#YcpQcVZ5Qkcw3k89uVm<-nJBcsK@wNpYf?a<7)%PcZQ4)tOXxi3w|_Y{A9@Z z)rj$zG2cp1cy;%YQzuWHIC1IHrQ5e} z-@SYH-o1NYP9OMj`oOR2=ij}!{o&Q!PjBx3e01mUqdWf|-TD9c&VvUJ9zJ~d;>C-X zK=9?$>#v{ReEss~+n3MpU;cmn{Qsx-pFe;8_~ZNc-@pF-`1b$Dw;w-#`~iZ$fBypk z!+(ZRFrXoz_>+Z^fuWv32jmJ+o?zg3#PFX(#$&?*$Huf%6D}5g;OCWQPq`71pnR}L zpJo1@3&{@}_*vbv1ZE1hEZ`JS{j$eVft^u~rH-XRa>cP`cA>0$Cw4Y3@0T|<9d^$sR%w}2t4Oj*zzU~nntdFCbKabp?8qd#Ls-scLei5Ac@cqSJUJH^ zI8HGyc$DM#so7na-JGQ@v2dAt9|Hs1iyMqB+#+ncZ0jVImT*khi@U*N^LSC>;RXf< FYXJLqRE7Wm literal 0 HcmV?d00001 diff --git a/images/descending.gif b/images/descending.gif new file mode 100644 index 0000000000000000000000000000000000000000..c7d38d6fb931d86aa21e5639f1c70d1558274f2c GIT binary patch literal 82 zcmZ?wbhEHbS-_yTx^@IO>JsEmcGw+c0m8%d4nH^oPS?-{dYa+=b4n>7ZVy< zKwuIOOrAV*=FE9Zmh4$Iaq+UHOO`BIyLRpN?b~P{-ksYnZ##8v@4KSxEt^nl;29661|2bqlKJ>GT*Kz&JJj`}>nuL19 z0fCN(M;p2IrS?QLIJvNL)}N6uC~)9tR*~8?<$(d?!TC(7A}0bJ+z-x^QZsWAh-m1X zGr#0ZiK1as6Z5=;x>KB0&Tbu?!4*yuofo{CC8=p;qj30hXONXu#)=;ft*^Z`LpWC) zOiX5FVNBz;2%MGX&L^Pz;8V|}Z#?3C!x2OAg|tO2FGU(Wyl literal 0 HcmV?d00001 diff --git a/images/folder.gif b/images/folder.gif new file mode 100644 index 0000000000000000000000000000000000000000..cebf3431c8ad1e1e0d673712ab1eac8abca3772a GIT binary patch literal 1004 zcmZ?wbhEHb6k-rz_|CxKxgi^_`V2&o=wL-xL1hXu|(9>Hn|f|9?>3+}zyL)ARpX*+@!I4+h=t#tg35s139DY1KjE7r~c1y$_P`I&Bu}#d7hi{F+A*OC2jo?Lp z4m3G1Of=vwideWP?QEN&#GDF4fx{epI$<2LS|%*q%=+mE8XhcQY-Z&WQm{x^z|hFZ z;B(~8snTqAK53H!9Fm)ryEp43h0G9W%w(1@V$1VrRBFDvTU^7V;=zG~$0Q{^N*ug@ ztl?NB?xn@N>uSU{)Jbe^l-|-P zv$aWfdyD*zR)t;dN_#q0_I9c6?@>R{t8u7b>*yri<5TocPBT0`!}!chlgkUN@2qrr zwAuODX217)!hal1_(=idI{$y^`~Q97@1N8D z|DXB)|D6B-m!3Fr;^M`N*REZ=d-v|Wd-v|&zyIyqx9{J-|NsAALqmgM6pV%dwL?Jh zCkrD3gE@l^$Y4;OaNsz^kk29Gu|dI+TUD!J#la1V&cdcV6C@&<-Fmtuj4!QlG-!6_ z(zlQjk#KC{5K{_T<+Ia~u|ZrpS?tIHrB>hBeAx;LhRF)7d=fD$B)m#iwDYnsaV$Cb zpyBfJ0DcAuMdxK#SBDuV>_|vVz9yw}XwwS8hmOo_TtXK%7=Ad!DJ=Tv)Le#x2boy8 zGC0-2Fh2y|#Tz$vA*#p2)&!^eD5%eZPDG_ZD@o?)16VZhLKKuX_@MZ$O2 O7mgVb!O6TF4AuZo%Cdq0 literal 0 HcmV?d00001 diff --git a/images/folder_open_red.gif b/images/folder_open_red.gif new file mode 100644 index 0000000000000000000000000000000000000000..ed96ad72d4da4e86ea4175a927a6d94825c4da44 GIT binary patch literal 970 zcmZ?wbhEHb6k-rz_|CxapW*-a@89p;yLau{wPVMQ_4M=<7Z=Uh}&kEZ6{y?eJ>S{@4udcJh&x#Z;cd-pzHyY^gm_O+IlYsJO?|Noz2 zXvi=MMnhnTgn;5t7DkX$bwC6tPcU#SXJF)z@z}87U^9oXmWaf{L>5MFMwbf?fzC`! zT*4Uv2Lc<9vM4w@$;@y#*fLpNJILn)!{P%h!Wu1eEQ_1HXK)$?@GJ;A%)-mhwI^o6 z0>|TvxeOvK5*{pVW)ao#n5*@biFKL2vWG$Erqw^j$Y(6V60jhl@jfe$l!%1Kf`-P!9m3KY4TTFD7$+!u%Uv*9 M^z`&}W+nz}0Hs`a`2YX_ literal 0 HcmV?d00001 diff --git a/images/grad.png b/images/grad.png new file mode 100644 index 0000000000000000000000000000000000000000..36e45492c402be9030e973ed7a621285f41e48f4 GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^+(0bB!3HFC-mwbTsbq`R4v%n*= z7^o5`%Pq{vFl&wkP>{XE)7O>#20J&86zjaBGY$iVWJ_ElN}Tg^b5rw57@Uhz6H8K4 z6v{J8G895GQWe}ieFNU7sOA9`?)7wW45_%)JK2+|ML~dBd*c89N6gds7ASLQsaN?{ zUEcSev5|@6llWpSZb7Gwye$bV3W8a4X2-Y&>ReuOJ$#R8dXd|ec!|v--l2sj=dfN- z{d~m6MYMXi4>J+RFBgC2#Kv8o zZ<42cPIg0Sv;X=N^Zc@xY0kde|DJJK(Y5CLuJt!}`LBH~uKDMDVblWg6Uhm>1(DGn kC3oH=x!&H}U;TqQ-OZZo+M#J{fF5D+boFyt=akR{0J0W;iU0rr literal 0 HcmV?d00001 diff --git a/images/loading.gif b/images/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..ad2c85a89867724d981de309fcaa52267cb15628 GIT binary patch literal 18300 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 D_OiLV literal 0 HcmV?d00001 diff --git a/images/logo.png b/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c66f905a8b20da033f3fbe16323596683781c97d GIT binary patch literal 1982 zcmV;v2SNCWP){Hs1qk6%kW7?b%7&=ZKrol}Ug5-lCNZ^4UaF&6*?^JK}f$k-9MquLQyR(&d-RkB_29P`u9OWxOC{ zdhc*a1hOZ8#@%%l0Gpz}A^|w4d#GDrW#GC9L3ES+c5rCq_ar!{bc`jTf6xb0m0>6} zCuSf76OhVX5Vb~=>2lmi45qT3ajuUlZ#4Wy-ZUeDzAe$Ws=nB~#@Dn2oUAVZ69K!g zU~wK;r|3_D5lKb_U?#xrlo2*YV@B?wP||c#O$9epiVa%Bb?74_P*03N>que#i}H-| zmY*EhwrFo;!>0RP3+I!?jDQ0lSqxSH=0t$!2~aIyz|#S8!Vw%oKqeRDw-g z(PCOe1HoEJL`2F2(NT@;VUFCPF_=C{HOj@-#clG7CDnnMCWoGB`cK7|YOXc4w+nTE z0*rqowY7-nnFylwzXrKCRj8d*51h6Pg~jdl&&NAT0iTgT@55fdr?IZjzecY#GclU6 z{m)`v02fe@LKH<9nJCoZF)Bb3GCizgerv3$RPY%I^!>>D72m4beeUIHfh$VUViYV! zK?TyjFeU|<8AW!Ks-U1l>E+W}j91tHB4(W&VzDE?fD*GL0{xGNHdWjidB$EfMrl_B zwM^$`QF@{Hq}>JDlUE`=K$=jd=y9O^h;rkm_UYk|ZE1mLspkqBUWUNn_PT??&wK9@ zofq<)^YT+E798#Zv`W?%4HM`Ek*a2@&kHSbYQi*6b4l}Mv$To$sL3?N(UAd9cS$*of(vpf-O%#a(Iv#3?bc{ zB{v8dKd*IPzayW1?4oWI2`EKHtgd{5z`&E$-m;~^n7=9MuYH0*|F+8O zgSQ3$?XDZ81Bvc_iE5+|rjYGTV?y8^>;975{%VVV^Xm1HTb!YDU|EG+Kzb_kFnO5e z4>BcdDi5_!wH`UEkq;5KM5S(hJ*gMT|LGX$c{sE#dSCc;cT`2@T|3h4GTl>jwNnsY z`s#t{-&>1aHn5IIs&-$sKCs;GrqWE87uX}1c*6!=ri%>y{?w)H+WfavJH2n!|M8iE zZ$<*AHwGf*HwDg!npBoL7>iTf4;@Ic`+xYa^ia`<`JlROo(;cisp^g1hJ|*`-?FcgrH>*M)jQcZfc9fIi_~Nm=I= zUEA@_vNrjaQug@22w3gx7T-0#tAp1J}XZBw@bKu&= zW7jVozj68G?Q3W5+&F*#_NB)UZa#T<^XbD|uUUqSn@^wKef|3J z`?t^EzJ2-r9f-dE`Sa_~pWlD~{{H{}KiH~KVl)H>R|x2UoCC@W4jiEjt{gHR8xk5= z*trB03=TLjG%?y#ytvSKxRsNiJBx(X*C>;6u%9JYpIS0Y<9cQ}tX~SQxAUgdKFb literal 0 HcmV?d00001 diff --git a/images/move.gif b/images/move.gif new file mode 100644 index 0000000000000000000000000000000000000000..1f2ec557ff054d02e1bfb62a9a474a00069727cb GIT binary patch literal 1001 zcmZ?wbhEHb|CRhJ`@I`lT4v6iIeqVx>HDV4 zTe4)&s)*`4;(&sG8n@4UOxOC~#?c2BS-o1P8-n}Eo z9-Te={L#z1?_S*g@apcTH}@Yrc<}Jy!$*%Ey?F8BB@lf1^!n@PH($TJ`S#`W`+N0|CQ-hEXtBLqPE-3nK$V8G{bUfuKCWz;TS> zEr*Q9h6G2$!~-6N9?I<95|#;13KWx1JLvPvZTRu=kq57mQ4>$eg{7>s#ImD~WCo@) ziZ}92Suk@ao1cu8uI{bEgjBUzv&@SRl{77D3{;jk;<$VBNV+e-B8S4omkeH0m?JhW zV-QSW^HH$ulNdD>8O8q`J>+46b<*Frk65U*BPsfQ+$=$3(5jEfWk+>`HK8V6X-N DjU*}D literal 0 HcmV?d00001 diff --git a/images/plus.gif b/images/plus.gif new file mode 100644 index 0000000000000000000000000000000000000000..7ae87180cd58ee17b41515dbc036fe6f71e692b6 GIT binary patch literal 881 zcmZ?wbhEHb1J}XZBw@bKu&= zV>d3JynXG=og3%x-@f$t!ObTRZ$5o^>($H0Z{I%u_~G@34{ttwdiV9~$M4@hfBW|3 z`*$Gv`sdHDKYxDz{rmg>|Nmf1Mv2i77>psH19B87FF0_7F*tI_cx*^$U}5JHP%t>) zz|h2KQE-F7!I_nlpFPcl<6{#m7lWEZ#)gdxPBt + +

Import Bookmarks

+ + +
+ + + + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ from Browser: + + +
+ select File: + + +
Character encoding: + +
Make them: + +
+ Destination Folder: + +
; height:350px; overflow:auto;"> + + make_tree(0); + $tree->print_tree(); + ?> + +
+
+

+ + + +
+
+
+ + import_opera(); + } + elseif ($_POST['browser'] === "netscape") { + $import->import_netscape(); + } + echo "$import->count_folders folders and $import->count_bookmarks bookmarks imported.
\n"; + echo 'My Bookmarks'; + } + +?> + +
+ +
+ +
+ +fp = fopen($_FILES['importfile']['tmp_name'], 'r'); + if ($this->fp === null) { + message('Failed to open file.'); + } + + $this->charset = set_post_charset(); + $this->public = set_post_bool_var('public', false); + + $this->count_folders = 0; + $this->count_bookmarks = 0; + + $this->username = $username; + $this->parent_folder = $parentfolder; + $this->current_folder = $this->parent_folder; + + $this->folder_depth = []; + + $this->mysql = $mysql; + } + + function import_opera() { + while (!feof($this->fp)) { + $line = trim (fgets($this->fp, 4096)); + + # A folder has been found. + if ($line === '#FOLDER') { + $item = 'Folder'; + } + # A bookmark has been found. + elseif ($line === '#URL') { + $item = 'Bookmark'; + } + # If a line starts with NAME= ... + elseif (substr ($line, 0, strlen('NAME=')) === 'NAME=') { + $line = substr ($line, strlen ('NAME=')); + # ... depending on the value of "$item" we assign the name to + # either folder or bookmark. + if ($item === 'Folder') { + $this->name_folder = input_validation($line, $this->charset); + } + elseif ($item === 'Bookmark') { + $this->name_bookmark = input_validation($line, $this->charset); + } + } + # Only bookmarks can have a description or/and an url. + elseif (substr ($line, 0, strlen ('DESCRIPTION=')) === 'DESCRIPTION=') { + $this->description = substr(input_validation($line, $this->charset), strlen('DESCRIPTION=')); + } + elseif (substr ($line, 0, strlen ('URL=')) === 'URL=') { + $this->url = substr(input_validation ($line, $this->charset), strlen('URL=')); + } + # Process the corresponding item, if there is an empty line found. + elseif ($line === '') { + if (isset ($item) && $item === 'Folder') { + $this->folder_new(); + unset($item); + } + elseif (isset ($item) && $item === 'Bookmark') { + $this->bookmark_new(); + unset($item); + } + } + # This indicates that the folder is being closed. + elseif ($line === '-') { + $this->folder_close(); + } + } + } + + function import_netscape() { + while (!feof($this->fp)) { + $line = trim(fgets($this->fp)); + # Netscape seems to store html encoded values. + $line = html_entity_decode($line, ENT_QUOTES, $this->charset); + + # A folder has been found. + if (preg_match ("/

name_folder = input_validation(preg_replace ("/^( *
<[^>]*>)([^<]*)(.*)/", '\\2', $line), $this->charset); + $this->folder_new (); + } + # A bookmark has been found. + elseif (preg_match('/
name_bookmark = input_validation(preg_replace ("/^( *
<[^>]*>)([^<]*)(.*)/", '\\2', $line), $this->charset); + $this->url = input_validation(preg_replace ("/([^H]*HREF=\")([^\"]*)(\".*)/", '\\2', $line), $this->charset); + $this->bookmark_new(); + $insert_id = mysql_insert_id(); + } + # This is a description. It is only being saved + # if a bookmark has been saved previously. + elseif (preg_match("/
*/", $line)) { + if (isset ($insert_id)) { + $this->description = input_validation (preg_replace ("/^( *
)(.*)/", '\\2', $line), $this->charset); + $query = sprintf("UPDATE `obm_bookmarks` SET `description`='%s' WHERE `id`='%d' AND `user`='%s'", + $this->mysql->escape($this->description), + $this->mysql->escape($insert_id), + $this->mysql->escape($this->username)); + + $this->mysql->query($query); + unset($this->description); + unset($insert_id); + } + } + # This indicates, that the folder is being closed. + elseif ($line === '

') { + $this->folder_close (); + } + } + } + + function folder_new() { + if (!isset($this->name_folder)) { + $this->name_folder === ''; + } + $query = sprintf("INSERT INTO `obm_folders` (childof, name, user, public) VALUES ('%d', '%s', '%s', '%d')", + $this->mysql->escape($this->current_folder), + $this->mysql->escape($this->name_folder), + $this->mysql->escape($this->username), + $this->mysql->escape($this->public)); + + if ($this->mysql->query($query)) { + $this->current_folder = mysql_insert_id(); + array_push($this->folder_depth, $this->current_folder); + unset($this->name_folder); + $this->count_folders++; + } + else { + message($this->mysql->error); + } + } + + function bookmark_new() { + if (!isset($this->name_bookmark)) { + $this->name_bookmark = ''; + } + if (!isset($this->url)) { + $this->url = ''; + } + if (!isset($this->description)) { + $this->description = ''; + } + $query = sprintf ("INSERT INTO `obm_bookmarks` (`user`, `title`, `url`, `description`, `childof`, `public`) + VALUES ('%s', '%s', '%s', '%s', '%d', '%d')", + $this->mysql->escape($this->username), + $this->mysql->escape($this->name_bookmark), + $this->mysql->escape($this->url), + $this->mysql->escape($this->description), + $this->mysql->escape($this->current_folder), + $this->mysql->escape($this->public) + ); + + if ($this->mysql->query($query)) { + unset($this->name_bookmark, $this->url, $this->description); + $this->count_bookmarks++; + } + else { + message($this->mysql->error); + } + } + + function folder_close() { + if (count($this->folder_depth) <= 1) { + $this->folder_depth = []; + $this->current_folder = $this->parent_folder; + } + else { + # Remove the last folder from the folder history. + unset($this->folder_depth[count($this->folder_depth) - 1]); + $this->folder_depth = array_values($this->folder_depth); + # Set the last folder to the current folder. + $this->current_folder = $this->folder_depth[count($this->folder_depth) - 1]; + } + } + } + + print_footer(); + require_once($_SERVER['DOCUMENT_ROOT'] . '/footer.php'); +?> diff --git a/includes/css/mobile.css b/includes/css/mobile.css new file mode 100644 index 0000000..5f7ac40 --- /dev/null +++ b/includes/css/mobile.css @@ -0,0 +1,73 @@ +/* mobile style */ +.desktop { + display: none; +} +.mobile { + display: block; +} +.navblock { + width: 49%; + float:left; + border: 1px solid #bbb; +} +h2.nav,ul.nav{ + margin-left: 0px; + margin-right: 0px; + width: 95%; + border: none; +} +ul.nav{ + width: 100%; +} +#menu-head { + width: auto; + margin-bottom: 5px; + float: none; +} +#folders-head { + width: auto; + float: none; +} +div #menu { + position: absolute; + top: 30px; + left: 5px; + z-index: 10; + width: auto; + background-color: white; +} + +div.folders { + float: none; + padding: 5px; + margin-bottom: 5px; + margin-right: 0px; + width: 100%; +} + +div#main { + margin-left: 0px; + margin-bottom: 5px; +} + +#openAll { + display:none; +} + +span.date { + display: none; +} + +.bookmark-move { + display: none; +} +.bookmarks input { + display: none; +} +.bookmarks { + margin-top: 5px; + border: 1px solid #bbb; +} +#footer { + display: none; +} \ No newline at end of file diff --git a/includes/css/mobiledark.css b/includes/css/mobiledark.css new file mode 100644 index 0000000..ce64fd6 --- /dev/null +++ b/includes/css/mobiledark.css @@ -0,0 +1,8 @@ +/* mobile style dark overrides */ +.navblock { + border: 1px solid #555; +} +.bookmarks { + margin-top: 5px; + border: 1px solid #555; +} diff --git a/includes/css/style.css b/includes/css/style.css new file mode 100644 index 0000000..60b9344 --- /dev/null +++ b/includes/css/style.css @@ -0,0 +1,287 @@ +/* General Settings */ +* { + color: #444; + font-family: Lato, Verdana, Georgia, Times, serif; + font-size: 1em; +} + +body { + background-color: white; + margin: 0; + padding: 5px; +} + +img { + border: 0px solid #FFFFFF; + vertical-align: middle; + margin: 0px; +} + +a:link { + text-decoration: none; +} +a:visited { + text-decoration: none; +} +a:hover { + text-decoration: underline; + color: #AE1A1A; +} +a:active { + text-decoration: none; +} + +fieldset { + margin: 10px; + float: none; +} + +/* Caption */ +h1#caption { + font-size: 2.5em; + margin: 0 0 0.5em 140px; + padding: 10px; + text-align: center; + font-family: Lato, Georgia, Times, serif; + background-color: #bbb; + display: block; +} + +h2.caption { + font-weight:bold; + margin: 5px; +} + +/* Menu and navigation */ +div#menu { + font-size: 1em; + float: left; + width: 130px; + margin: 0px 0px; + padding: 0; + margin-bottom: 10px; +} + +h2.nav { + font-size: 1em; + margin: 0; + padding: 3px; + /* background-color:#bbb; */ + background:#dadbdb url(../../images/grad.png) repeat-x; + width: 124px; +} + +ul.nav { + border: 1px solid #bbb; + margin: 0px 0px 10px 0px; + padding: 0; +} + +ul.nav li { + list-style: none; + margin: 0; + padding: 1px; +} + +ul.nav a { + display: block; + padding: 2px; + font-size: .9em; +} + +ul.nav a:link { + text-decoration: none; +} + +ul.nav a:visited { + text-decoration: none; +} + +ul.nav a:hover { + text-decoration: none; + /* color: #AE1A1A; */ + color: #555555; + background-color: #ddd; +} + +ul.nav a:active { + text-decoration: none; +} + +form.nav { + margin: 0px; +} + +/* Folders section */ +div.folders { + float: left; + overflow: auto; + padding-right: 20px; + padding-bottom: 5px; + margin-right: 5px; + border: 1px solid #BBB; +} + +a.f:link { + text-decoration: none; + color: #555555; +} + +a.f:visited { + text-decoration: none; + color: #555555; +} + +a.f:hover { + text-decoration: none; + color: #555555; +} + +a.f:active { + text-decoration: none; + color: #555555; +} + +span.active { + color: #000000; + background-color: #C1D2EE; + border:1px #316AC5 solid; + padding:1px; +} + +div.foldertop { + height: 5px; +} + +/* Bookmarks section */ +div.bookmarks { + overflow:auto; + padding: 0px; + display: block; + border-left: 1px solid #bbb; +} + +div.bookmark { + border-bottom: 1px solid #bbb; + padding: 4px; +} + +div.bookmarkcaption { + padding: 2px 2px 2px 4px; + /* background-color: #bbb; */ + background: url(../../images/grad.png) repeat-x; +} + +div.bookmark:hover { + background-color: #eee; +} + +div.bmleft { + float: left; + padding-right: 5px; +} + +div.bmright { + float: right; + margin-left: 10px; + padding: 0px; + margin: 0px; + text-align: center; +} + +div.link { + padding: 0px 0px 2px; +} + +span.private { + background-color: #E7FBE9; + color: #177F23; +} + +span.public { + background-color: #F9E7E9; + color: #E42037; +} + +div.description { + margin-top: 5px; +} + +div.description, span.private, span.public, span.date, a.footer { + font-size: smaller; +} + +.invisible { + visibility: hidden; +} + +p.shared { + margin: 10px; +} + +/* Main Content */ +div#main { + margin-left: 140px; + margin-bottom: 10px; +} + +div#content { + overflow:auto; + padding: 0px; + display: block; +} + +/* Footer */ +div#footer { + clear: both; + margin-top: 10px; + padding: 2px; + font-size: smaller; + font-style:italic; + position: fixed; + bottom:0; + left:0; + z-index: 999; + background-color: #fff; +} + +/* openbookmark additions */ +div #menu { + position: fixed; + top: 5px; + left: 10px; +} + +h2.mnu { + cursor: pointer; +} + h2.mnu:hover { + color:#eee; + } + +.loading-anim { + background-image: url('../../images/loading.gif'); + background-repeat:no-repeat; + /*background-attachment:fixed;*/ + background-position:center; +} + +.mobile { + display:none; +} + +#googlesearch { + position: relative; +} + +#googlesearch form { + position: fixed; + bottom:0; + right:0; + margin-right: 3px; + margin-bottom: 3px; + border: 1px solid #bbb; + z-index: 999; + padding: 3px; + background: #eee; +} diff --git a/includes/css/styledark.css b/includes/css/styledark.css new file mode 100644 index 0000000..effde7d --- /dev/null +++ b/includes/css/styledark.css @@ -0,0 +1,126 @@ +/* General Settings */ +* { + color: #aaa; +} +body { + background-color: #222; +} + #sidebarBody { + background-color: #000; + } + #sidebarBody a,#sidebarBody li { + color: #ddd !important; + } +img { + border: 0px solid #FFFFFF; +} +a:hover { + color: #ff0000; +} +/* Caption */ +h1#caption { + + background-color:#444; +} +/* Menu and navigation */ +div#menu { + + background-color: black; +} +h2.nav { + + + color: #333; +} +ul.nav { + border: 1px solid #555; + +} + +ul.nav a:hover { + + color: #ddd; + background-color: #777; +} +/* Folders section */ +div.folders { + + border: 1px solid #555; + background-color: black; +} + +a.f:link { + color: #ccc; +} +a.f:visited { + color: #ccc; +} +a.f:hover { + color: #ccc; +} +a.f:active { + color: #ccc; +} +.bookmarkcaption a.f { + color: #222; +} +.bookmark_href { + color: #ccc; +} +#openAll { + color: #222; +} + +span.active { + color: #000000; + background-color: #C1D2EE; + border:1px #316AC5 solid; +} +/* Bookmarks section */ +div.bookmarks { + + border-left: 1px solid #555; + background-color: black; +} +div.bookmark { + border-bottom: 1px solid #555; + background-color: #000; +} +div.bookmarkcaption { + background: url(images/grad.png) repeat-x; +} +div.bookmark:hover { + background-color: #333; +} +span.private { + background-color: #343; + color: #aaa; +} +span.public { + background-color: #434; + color: #aaa; +} +/* Main Content */ + +/* Footer */ +div#footer { + background-color: #000; +} + +/* openbookmark additions */ + + h2.mnu:hover { + color:#F00; + } + + #googlesearch form { + border: 1px solid #555; + background: #000; + } + +input { + color:#000; +} +select { + color:#000; +} \ No newline at end of file diff --git a/includes/jquery/images/file.gif b/includes/jquery/images/file.gif new file mode 100644 index 0000000000000000000000000000000000000000..7e6216798f8e5abfc81a2fe2e5cb32b7a2d82e10 GIT binary patch literal 110 zcmZ?wbhEHb!0m5Y~9sd L;uWgGz+epk&R;19 literal 0 HcmV?d00001 diff --git a/includes/jquery/images/folder.gif b/includes/jquery/images/folder.gif new file mode 100644 index 0000000000000000000000000000000000000000..2b31631ca2bfec3a8afb1bfdd4f8ed4c5bcc3a18 GIT binary patch literal 106 zcmZ?wbhEHb6ky=hKW2GJ7 I#Kd3?0MGg0inAdcV{h m&KuQ>!#3re=R9b^b+)pkV^-bj*+~+v*T3~X-xbWjU=0A^yc^^I literal 0 HcmV?d00001 diff --git a/includes/jquery/images/tv-collapsable.gif b/includes/jquery/images/tv-collapsable.gif new file mode 100644 index 0000000000000000000000000000000000000000..857262faecaaf363ab3d6fe1779ec6d6eb85c3f3 GIT binary patch literal 781 zcmV+o1M>VwNk%w1VGsbY1d##&0001hfPnx1{{R30A^8LW00062EC2ui01yDM1ONj6 zl#i(v>%SVDDcF0XR%^3A-Pw$vten~kQ$Df3Aka`(CO$Gso^r^Yw5H0V?n zhzPhSm>6YPq}a$PS^4Pr1Sw^iiP@yNHYv*a=~-xcg_@JQIl35Hb0`nuLOKm8KC~DS<3v0E6**q? zm=WYgJRM1XG#L`*NIfT6rgXWoPfM9EX~raUPod6jHxKRX)-%%2dP8&aESeALKBfJb z{&N}->OiRlsUEbN@TgXxSS5DV_*GAtOt_pV;K zdHL>L8W*r#zk~(%HT<_}V8w$G7iN4Ia^k0pDL0n<*m7jelcQGle3^4*(3?qjp86Se zXw#!rmv()+YHHc5VYjCJ8h7lgvw7FnecN|#;k&c`CLY}QaOK6l_GX^k`Elrut7En< z8ar$4wz&iMjvPGo>*TYS-+sP(`tR$*w;yjlK6?4;>9e=*9zXo~{OkALzyDu;0q*Bt zfdCpPAc6!Q$Y6pEF6dx{5KbuFauqfQ)^is|m*I39iud7rA?i2cfF&w;;)5wlxFUre zTKFP{Vrdv7hckLuBZxVQxFd-@n)oA%L8>?;i$%J4BaBJPNEVGt+SnwHPwF@&k5&43 zC6HMPxh0WZ8u=xXQ7SnmlV&+tCX{DNnI@HOTKOiHacVgymvwr1CzyGPxh9!?nu!*g zf2tWMn}fP}D4dDPxhS2D+W9D+k?J`qpN0B)DWGa0nkk{1D%vThpE4RMsG~YsDygSJ LnkuS<6aWA_b2fL3 literal 0 HcmV?d00001 diff --git a/includes/jquery/images/tv-expandable-last.gif b/includes/jquery/images/tv-expandable-last.gif new file mode 100644 index 0000000000000000000000000000000000000000..1ede2de78e046691bafcd19d8f953d820a8a939d GIT binary patch literal 89 zcmZ?wbhEHb6krfzn8?J?(9poZ!0`Y7e;}#&lZBCifr&u}$Yub^GcajQ>0inAdcV{h q&KuQ>!-85aE8abxaj=r>ESKDpU6s1x-4bq3f1UgO@4W^CgEatFOCAgW literal 0 HcmV?d00001 diff --git a/includes/jquery/images/tv-expandable.gif b/includes/jquery/images/tv-expandable.gif new file mode 100644 index 0000000000000000000000000000000000000000..305d57fc8b14c89431818b5f21d81e39072723b5 GIT binary patch literal 787 zcmV+u1MK`qNk%w1VGsbY1d##&0001hfPnx1{{R30A^8LW00062EC2ui01yDM1ONj6 zl#i(v>%SVDDcF0XR#Je|A>GGlz1le|i8=~as(Px~3Y#jsDi#ZROFE0Y zt6NK!%i1gaYZh!fj9iR%44mw|tk!J&OdZWO&0MX0?UpUQ4c-m+jU8@2E_d#|PTsDb zepk*OpEvJbzjqJ+%A4QU&sRWV1CsGaU6>nC( zTlseN`xS6l!D9)RHGCFv+PjSNHs1TVZ{)v|16Lk=xp3ygn-h0l>^L-J(UM71HfVqJ9X~WyIc2u{X2H>*|v-0Hm(~vZ{@z319vVQI`QMwlUHAU zy?OTM+oN}%ZaqA9@!H9AH}4%i`0?z^w?F?ref;(A>%+G%A3y#3{PXwZ-|t_501n8O zVg-J7plk^ax1e+le)phy5zaTEeiip@Au)_@Rj* z#?_LFEy{SJf-BlMBa1aMcq5NF;<%%OJqr1wk3m8>B$7oEd8C9%I=Q5hO;Y$Il~F=D zrG-^$d8L(EVz?!kU2^%QhGCjHrkG`Nm?oNQZV2a@Y`!UHoNdneB8f5Tn5T;+(%2`U zfATpfkbx4qr=f)!d8nd^GP)>}jY9gUq>)NFsil=-dMTEfa=NLfoqGAHsG*WNDw(CC RdaA0as=2DGt#VcX06Vosfm8qh literal 0 HcmV?d00001 diff --git a/includes/jquery/images/tv-item-last.gif b/includes/jquery/images/tv-item-last.gif new file mode 100644 index 0000000000000000000000000000000000000000..42a139ad59777163fb406f3692ebf5333ef379d9 GIT binary patch literal 65 zcmZ?wbhEHb6krfzXkcV$XlVHV|G(l-7DfgJMg|=QAOOiQFiG_EuVj0@Uuus3rEZ;L SYuWd=KJu9MtaBPGgEatO+7%uE literal 0 HcmV?d00001 diff --git a/includes/jquery/images/tv-item.gif b/includes/jquery/images/tv-item.gif new file mode 100644 index 0000000000000000000000000000000000000000..281e5dce6705bbba1be16919ccad1883d9a9b7b5 GIT binary patch literal 750 zcmVi2fsz(rj1Z(I%uk_Z1$dUHLJCFC+@t*{rh7DQ$tg6bPOd)Ib9R>WJIOY zC1?7iG(~*cW?M%k^nH`*-V=i`xtK z>l-Y#TUe}i?3nDfEc#3uZ90uwt$NLx?Ya%yEz9_=8%|Cu4t!3WF5E0v&bw~>jvTK% z&s^_(54|tlPyNqYKx_lG736l%TS9Q=7LIEO5uQVI6V+8@m(N{9djA*YZN%5n-ba2T z{gniGQeaAgD-E_p_)=j^h7xB!tcjDOO^Q1$_QV)c-%pP@K@JsJlw?wqOHnpe`IKc; zms4R@m3ft>&a5}LdNsJN672wB*X9FPF}IdUNW|t3S66 z{d%URkG?T6W3jmwM*e=bnBB3h1DQ g3W{i",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=V(e||this.defaultElement||this)[0],this.element=V(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=V(),this.hoverable=V(),this.focusable=V(),this.classesElementLookup={},e!==this&&(V.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=V(e.style?e.ownerDocument:e.document||e),this.window=V(this.document[0].defaultView||this.document[0].parentWindow)),this.options=V.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:V.noop,_create:V.noop,_init:V.noop,destroy:function(){var i=this;this._destroy(),V.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:V.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return V.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t]=V.widget.extend({},this.options[t]),n=0;n

"),i=e.children()[0];return V("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i},getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.widthx(k(s),k(n))?o.important="horizontal":o.important="vertical",u.using.call(this,t,o)}),a.offset(V.extend(h,{using:t}))})},V.ui.position={fit:{left:function(t,e){var i=e.within,s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,a=s-o,r=o+e.collisionWidth-n-s;e.collisionWidth>n?0n?0")[0],w=d.each;function P(t){return null==t?t+"":"object"==typeof t?p[e.call(t)]||"object":typeof t}function M(t,e,i){var s=v[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:Math.min(s.max,Math.max(0,t)))}function S(s){var n=m(),o=n._rgba=[];return s=s.toLowerCase(),w(g,function(t,e){var i=e.re.exec(s),i=i&&e.parse(i),e=e.space||"rgba";if(i)return i=n[e](i),n[_[e].cache]=i[_[e].cache],o=n._rgba=i._rgba,!1}),o.length?("0,0,0,0"===o.join()&&d.extend(o,B.transparent),n):B[s]}function H(t,e,i){return 6*(i=(i+1)%1)<1?t+(e-t)*i*6:2*i<1?e:3*i<2?t+(e-t)*(2/3-i)*6:t}y.style.cssText="background-color:rgba(1,1,1,.5)",b.rgba=-1o.mod/2?s+=o.mod:s-n>o.mod/2&&(s-=o.mod)),l[i]=M((n-s)*a+s,e)))}),this[e](l)},blend:function(t){if(1===this._rgba[3])return this;var e=this._rgba.slice(),i=e.pop(),s=m(t)._rgba;return m(d.map(e,function(t,e){return(1-i)*s[e]+i*t}))},toRgbaString:function(){var t="rgba(",e=d.map(this._rgba,function(t,e){return null!=t?t:2").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e={width:i.width(),height:i.height()},n=document.activeElement;try{n.id}catch(t){n=document.body}return i.wrap(t),i[0]!==n&&!V.contains(i[0],n)||V(n).trigger("focus"),t=i.parent(),"static"===i.css("position")?(t.css({position:"relative"}),i.css({position:"relative"})):(V.extend(s,{position:i.css("position"),zIndex:i.css("z-index")}),V.each(["top","left","bottom","right"],function(t,e){s[e]=i.css(e),isNaN(parseInt(s[e],10))&&(s[e]="auto")}),i.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),i.css(e),t.css(s).show()},removeWrapper:function(t){var e=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),t[0]!==e&&!V.contains(t[0],e)||V(e).trigger("focus")),t}}),V.extend(V.effects,{version:"1.13.0",define:function(t,e,i){return i||(i=e,e="effect"),V.effects.effect[t]=i,V.effects.effect[t].mode=e,i},scaledDimensions:function(t,e,i){if(0===e)return{height:0,width:0,outerHeight:0,outerWidth:0};var s="horizontal"!==i?(e||100)/100:1,e="vertical"!==i?(e||100)/100:1;return{height:t.height()*e,width:t.width()*s,outerHeight:t.outerHeight()*e,outerWidth:t.outerWidth()*s}},clipToBox:function(t){return{width:t.clip.right-t.clip.left,height:t.clip.bottom-t.clip.top,left:t.clip.left,top:t.clip.top}},unshift:function(t,e,i){var s=t.queue();1").insertAfter(t).css({display:/^(inline|ruby)/.test(t.css("display"))?"inline-block":"block",visibility:"hidden",marginTop:t.css("marginTop"),marginBottom:t.css("marginBottom"),marginLeft:t.css("marginLeft"),marginRight:t.css("marginRight"),float:t.css("float")}).outerWidth(t.outerWidth()).outerHeight(t.outerHeight()).addClass("ui-effects-placeholder"),t.data(j+"placeholder",e)),t.css({position:i,left:s.left,top:s.top}),e},removePlaceholder:function(t){var e=j+"placeholder",i=t.data(e);i&&(i.remove(),t.removeData(e))},cleanUp:function(t){V.effects.restoreStyle(t),V.effects.removePlaceholder(t)},setTransition:function(s,t,n,o){return o=o||{},V.each(t,function(t,e){var i=s.cssUnit(e);0");l.appendTo("body").addClass(t.className).css({top:s.top-a,left:s.left-r,height:i.innerHeight(),width:i.innerWidth(),position:n?"fixed":"absolute"}).animate(o,t.duration,t.easing,function(){l.remove(),"function"==typeof e&&e()})}}),V.fx.step.clip=function(t){t.clipInit||(t.start=V(t.elem).cssClip(),"string"==typeof t.end&&(t.end=G(t.end,t.elem)),t.clipInit=!0),V(t.elem).cssClip({top:t.pos*(t.end.top-t.start.top)+t.start.top,right:t.pos*(t.end.right-t.start.right)+t.start.right,bottom:t.pos*(t.end.bottom-t.start.bottom)+t.start.bottom,left:t.pos*(t.end.left-t.start.left)+t.start.left})},Y={},V.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,t){Y[t]=function(t){return Math.pow(t,e+2)}}),V.extend(Y,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;t<((e=Math.pow(2,--i))-1)/11;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),V.each(Y,function(t,e){V.easing["easeIn"+t]=e,V.easing["easeOut"+t]=function(t){return 1-e(1-t)},V.easing["easeInOut"+t]=function(t){return t<.5?e(2*t)/2:1-e(-2*t+2)/2}});y=V.effects,V.effects.define("blind","hide",function(t,e){var i={up:["bottom","top"],vertical:["bottom","top"],down:["top","bottom"],left:["right","left"],horizontal:["right","left"],right:["left","right"]},s=V(this),n=t.direction||"up",o=s.cssClip(),a={clip:V.extend({},o)},r=V.effects.createPlaceholder(s);a.clip[i[n][0]]=a.clip[i[n][1]],"show"===t.mode&&(s.cssClip(a.clip),r&&r.css(V.effects.clipToBox(a)),a.clip=o),r&&r.animate(V.effects.clipToBox(a),t.duration,t.easing),s.animate(a,{queue:!1,duration:t.duration,easing:t.easing,complete:e})}),V.effects.define("bounce",function(t,e){var i,s,n=V(this),o=t.mode,a="hide"===o,r="show"===o,l=t.direction||"up",h=t.distance,c=t.times||5,o=2*c+(r||a?1:0),u=t.duration/o,d=t.easing,p="up"===l||"down"===l?"top":"left",f="up"===l||"left"===l,g=0,t=n.queue().length;for(V.effects.createPlaceholder(n),l=n.css(p),h=h||n["top"==p?"outerHeight":"outerWidth"]()/3,r&&((s={opacity:1})[p]=l,n.css("opacity",0).css(p,f?2*-h:2*h).animate(s,u,d)),a&&(h/=Math.pow(2,c-1)),(s={})[p]=l;g").css({position:"absolute",visibility:"visible",left:-s*p,top:-i*f}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:p,height:f,left:n+(u?a*p:0),top:o+(u?r*f:0),opacity:u?0:1}).animate({left:n+(u?0:a*p),top:o+(u?0:r*f),opacity:u?1:0},t.duration||500,t.easing,m)}),V.effects.define("fade","toggle",function(t,e){var i="show"===t.mode;V(this).css("opacity",i?0:1).animate({opacity:i?1:0},{queue:!1,duration:t.duration,easing:t.easing,complete:e})}),V.effects.define("fold","hide",function(e,t){var i=V(this),s=e.mode,n="show"===s,o="hide"===s,a=e.size||15,r=/([0-9]+)%/.exec(a),l=!!e.horizFirst?["right","bottom"]:["bottom","right"],h=e.duration/2,c=V.effects.createPlaceholder(i),u=i.cssClip(),d={clip:V.extend({},u)},p={clip:V.extend({},u)},f=[u[l[0]],u[l[1]]],s=i.queue().length;r&&(a=parseInt(r[1],10)/100*f[o?0:1]),d.clip[l[0]]=a,p.clip[l[0]]=a,p.clip[l[1]]=0,n&&(i.cssClip(p.clip),c&&c.css(V.effects.clipToBox(p)),p.clip=u),i.queue(function(t){c&&c.animate(V.effects.clipToBox(d),h,e.easing).animate(V.effects.clipToBox(p),h,e.easing),t()}).animate(d,h,e.easing).animate(p,h,e.easing).queue(t),V.effects.unshift(i,s,4)}),V.effects.define("highlight","show",function(t,e){var i=V(this),s={backgroundColor:i.css("backgroundColor")};"hide"===t.mode&&(s.opacity=0),V.effects.saveStyle(i),i.css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(s,{queue:!1,duration:t.duration,easing:t.easing,complete:e})}),V.effects.define("size",function(s,e){var n,i=V(this),t=["fontSize"],o=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],a=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],r=s.mode,l="effect"!==r,h=s.scale||"both",c=s.origin||["middle","center"],u=i.css("position"),d=i.position(),p=V.effects.scaledDimensions(i),f=s.from||p,g=s.to||V.effects.scaledDimensions(i,0);V.effects.createPlaceholder(i),"show"===r&&(r=f,f=g,g=r),n={from:{y:f.height/p.height,x:f.width/p.width},to:{y:g.height/p.height,x:g.width/p.width}},"box"!==h&&"both"!==h||(n.from.y!==n.to.y&&(f=V.effects.setTransition(i,o,n.from.y,f),g=V.effects.setTransition(i,o,n.to.y,g)),n.from.x!==n.to.x&&(f=V.effects.setTransition(i,a,n.from.x,f),g=V.effects.setTransition(i,a,n.to.x,g))),"content"!==h&&"both"!==h||n.from.y!==n.to.y&&(f=V.effects.setTransition(i,t,n.from.y,f),g=V.effects.setTransition(i,t,n.to.y,g)),c&&(c=V.effects.getBaseline(c,p),f.top=(p.outerHeight-f.outerHeight)*c.y+d.top,f.left=(p.outerWidth-f.outerWidth)*c.x+d.left,g.top=(p.outerHeight-g.outerHeight)*c.y+d.top,g.left=(p.outerWidth-g.outerWidth)*c.x+d.left),delete f.outerHeight,delete f.outerWidth,i.css(f),"content"!==h&&"both"!==h||(o=o.concat(["marginTop","marginBottom"]).concat(t),a=a.concat(["marginLeft","marginRight"]),i.find("*[width]").each(function(){var t=V(this),e=V.effects.scaledDimensions(t),i={height:e.height*n.from.y,width:e.width*n.from.x,outerHeight:e.outerHeight*n.from.y,outerWidth:e.outerWidth*n.from.x},e={height:e.height*n.to.y,width:e.width*n.to.x,outerHeight:e.height*n.to.y,outerWidth:e.width*n.to.x};n.from.y!==n.to.y&&(i=V.effects.setTransition(t,o,n.from.y,i),e=V.effects.setTransition(t,o,n.to.y,e)),n.from.x!==n.to.x&&(i=V.effects.setTransition(t,a,n.from.x,i),e=V.effects.setTransition(t,a,n.to.x,e)),l&&V.effects.saveStyle(t),t.css(i),t.animate(e,s.duration,s.easing,function(){l&&V.effects.restoreStyle(t)})})),i.animate(g,{queue:!1,duration:s.duration,easing:s.easing,complete:function(){var t=i.offset();0===g.opacity&&i.css("opacity",f.opacity),l||(i.css("position","static"===u?"relative":u).offset(t),V.effects.saveStyle(i)),e()}})}),V.effects.define("scale",function(t,e){var i=V(this),s=t.mode,s=parseInt(t.percent,10)||(0===parseInt(t.percent,10)||"effect"!==s?0:100),s=V.extend(!0,{from:V.effects.scaledDimensions(i),to:V.effects.scaledDimensions(i,s,t.direction||"both"),origin:t.origin||["middle","center"]},t);t.fade&&(s.from.opacity=1,s.to.opacity=0),V.effects.effect.size.call(this,s,e)}),V.effects.define("puff","hide",function(t,e){t=V.extend(!0,{},t,{fade:!0,percent:parseInt(t.percent,10)||150});V.effects.effect.scale.call(this,t,e)}),V.effects.define("pulsate","show",function(t,e){var i=V(this),s=t.mode,n="show"===s,o=2*(t.times||5)+(n||"hide"===s?1:0),a=t.duration/o,r=0,l=1,s=i.queue().length;for(!n&&i.is(":visible")||(i.css("opacity",0).show(),r=1);l li > :first-child").add(t.find("> :not(li)").even())},heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var t=this.options;this.prevShow=this.prevHide=V(),this._addClass("ui-accordion","ui-widget ui-helper-reset"),this.element.attr("role","tablist"),t.collapsible||!1!==t.active&&null!=t.active||(t.active=0),this._processPanels(),t.active<0&&(t.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():V()}},_createIcons:function(){var t,e=this.options.icons;e&&(t=V(""),this._addClass(t,"ui-accordion-header-icon","ui-icon "+e.header),t.prependTo(this.headers),t=this.active.children(".ui-accordion-header-icon"),this._removeClass(t,e.header)._addClass(t,null,e.activeHeader)._addClass(this.headers,"ui-accordion-icons"))},_destroyIcons:function(){this._removeClass(this.headers,"ui-accordion-icons"),this.headers.children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeAttr("role"),this.headers.removeAttr("role aria-expanded aria-selected aria-controls tabIndex").removeUniqueId(),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role aria-hidden aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){"active"!==t?("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||!1!==this.options.active||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons())):this._activate(e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t),this._toggleClass(this.headers.add(this.headers.next()),null,"ui-state-disabled",!!t)},_keydown:function(t){if(!t.altKey&&!t.ctrlKey){var e=V.ui.keyCode,i=this.headers.length,s=this.headers.index(t.target),n=!1;switch(t.keyCode){case e.RIGHT:case e.DOWN:n=this.headers[(s+1)%i];break;case e.LEFT:case e.UP:n=this.headers[(s-1+i)%i];break;case e.SPACE:case e.ENTER:this._eventHandler(t);break;case e.HOME:n=this.headers[0];break;case e.END:n=this.headers[i-1]}n&&(V(t.target).attr("tabIndex",-1),V(n).attr("tabIndex",0),V(n).trigger("focus"),t.preventDefault())}},_panelKeyDown:function(t){t.keyCode===V.ui.keyCode.UP&&t.ctrlKey&&V(t.currentTarget).prev().trigger("focus")},refresh:function(){var t=this.options;this._processPanels(),!1===t.active&&!0===t.collapsible||!this.headers.length?(t.active=!1,this.active=V()):!1===t.active?this._activate(0):this.active.length&&!V.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(t.active=!1,this.active=V()):this._activate(Math.max(0,t.active-1)):t.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var t=this.headers,e=this.panels;"function"==typeof this.options.header?this.headers=this.options.header(this.element):this.headers=this.element.find(this.options.header),this._addClass(this.headers,"ui-accordion-header ui-accordion-header-collapsed","ui-state-default"),this.panels=this.headers.next().filter(":not(.ui-accordion-content-active)").hide(),this._addClass(this.panels,"ui-accordion-content","ui-helper-reset ui-widget-content"),e&&(this._off(t.not(this.headers)),this._off(e.not(this.panels)))},_refresh:function(){var i,t=this.options,e=t.heightStyle,s=this.element.parent();this.active=this._findActive(t.active),this._addClass(this.active,"ui-accordion-header-active","ui-state-active")._removeClass(this.active,"ui-accordion-header-collapsed"),this._addClass(this.active.next(),"ui-accordion-content-active"),this.active.next().show(),this.headers.attr("role","tab").each(function(){var t=V(this),e=t.uniqueId().attr("id"),i=t.next(),s=i.uniqueId().attr("id");t.attr("aria-controls",s),i.attr("aria-labelledby",e)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(t.event),"fill"===e?(i=s.height(),this.element.siblings(":visible").each(function(){var t=V(this),e=t.css("position");"absolute"!==e&&"fixed"!==e&&(i-=t.outerHeight(!0))}),this.headers.each(function(){i-=V(this).outerHeight(!0)}),this.headers.next().each(function(){V(this).height(Math.max(0,i-V(this).innerHeight()+V(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.headers.next().each(function(){var t=V(this).is(":visible");t||V(this).show(),i=Math.max(i,V(this).css("height","").height()),t||V(this).hide()}).height(i))},_activate:function(t){t=this._findActive(t)[0];t!==this.active[0]&&(t=t||this.active[0],this._eventHandler({target:t,currentTarget:t,preventDefault:V.noop}))},_findActive:function(t){return"number"==typeof t?this.headers.eq(t):V()},_setupEvents:function(t){var i={keydown:"_keydown"};t&&V.each(t.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(t){var e=this.options,i=this.active,s=V(t.currentTarget),n=s[0]===i[0],o=n&&e.collapsible,a=o?V():s.next(),r=i.next(),a={oldHeader:i,oldPanel:r,newHeader:o?V():s,newPanel:a};t.preventDefault(),n&&!e.collapsible||!1===this._trigger("beforeActivate",t,a)||(e.active=!o&&this.headers.index(s),this.active=n?V():s,this._toggle(a),this._removeClass(i,"ui-accordion-header-active","ui-state-active"),e.icons&&(i=i.children(".ui-accordion-header-icon"),this._removeClass(i,null,e.icons.activeHeader)._addClass(i,null,e.icons.header)),n||(this._removeClass(s,"ui-accordion-header-collapsed")._addClass(s,"ui-accordion-header-active","ui-state-active"),e.icons&&(n=s.children(".ui-accordion-header-icon"),this._removeClass(n,null,e.icons.header)._addClass(n,null,e.icons.activeHeader)),this._addClass(s.next(),"ui-accordion-content-active")))},_toggle:function(t){var e=t.newPanel,i=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=e,this.prevHide=i,this.options.animate?this._animate(e,i,t):(i.hide(),e.show(),this._toggleComplete(t)),i.attr({"aria-hidden":"true"}),i.prev().attr({"aria-selected":"false","aria-expanded":"false"}),e.length&&i.length?i.prev().attr({tabIndex:-1,"aria-expanded":"false"}):e.length&&this.headers.filter(function(){return 0===parseInt(V(this).attr("tabIndex"),10)}).attr("tabIndex",-1),e.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(t,i,e){var s,n,o,a=this,r=0,l=t.css("box-sizing"),h=t.length&&(!i.length||t.index()",delay:300,options:{icons:{submenu:"ui-icon-caret-1-e"},items:"> *",menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.lastMousePosition={x:null,y:null},this.element.uniqueId().attr({role:this.options.role,tabIndex:0}),this._addClass("ui-menu","ui-widget ui-widget-content"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault(),this._activateItem(t)},"click .ui-menu-item":function(t){var e=V(t.target),i=V(V.ui.safeActiveElement(this.document[0]));!this.mouseHandled&&e.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),e.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&i.closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":"_activateItem","mousemove .ui-menu-item":"_activateItem",mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this._menuItems().first();e||this.focus(t,i)},blur:function(t){this._delay(function(){V.contains(this.element[0],V.ui.safeActiveElement(this.document[0]))||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t,!0),this.mouseHandled=!1}})},_activateItem:function(t){var e,i;this.previousFilter||t.clientX===this.lastMousePosition.x&&t.clientY===this.lastMousePosition.y||(this.lastMousePosition={x:t.clientX,y:t.clientY},e=V(t.target).closest(".ui-menu-item"),i=V(t.currentTarget),e[0]===i[0]&&(i.is(".ui-state-active")||(this._removeClass(i.siblings().children(".ui-state-active"),null,"ui-state-active"),this.focus(t,i))))},_destroy:function(){var t=this.element.find(".ui-menu-item").removeAttr("role aria-disabled").children(".ui-menu-item-wrapper").removeUniqueId().removeAttr("tabIndex role aria-haspopup");this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeAttr("role aria-labelledby aria-expanded aria-hidden aria-disabled tabIndex").removeUniqueId().show(),t.children().each(function(){var t=V(this);t.data("ui-menu-submenu-caret")&&t.remove()})},_keydown:function(t){var e,i,s,n=!0;switch(t.keyCode){case V.ui.keyCode.PAGE_UP:this.previousPage(t);break;case V.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case V.ui.keyCode.HOME:this._move("first","first",t);break;case V.ui.keyCode.END:this._move("last","last",t);break;case V.ui.keyCode.UP:this.previous(t);break;case V.ui.keyCode.DOWN:this.next(t);break;case V.ui.keyCode.LEFT:this.collapse(t);break;case V.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case V.ui.keyCode.ENTER:case V.ui.keyCode.SPACE:this._activate(t);break;case V.ui.keyCode.ESCAPE:this.collapse(t);break;default:e=this.previousFilter||"",s=n=!1,i=96<=t.keyCode&&t.keyCode<=105?(t.keyCode-96).toString():String.fromCharCode(t.keyCode),clearTimeout(this.filterTimer),i===e?s=!0:i=e+i,e=this._filterMenuItems(i),(e=s&&-1!==e.index(this.active.next())?this.active.nextAll(".ui-menu-item"):e).length||(i=String.fromCharCode(t.keyCode),e=this._filterMenuItems(i)),e.length?(this.focus(t,e),this.previousFilter=i,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}n&&t.preventDefault()},_activate:function(t){this.active&&!this.active.is(".ui-state-disabled")&&(this.active.children("[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var t,e,s=this,n=this.options.icons.submenu,i=this.element.find(this.options.menus);this._toggleClass("ui-menu-icons",null,!!this.element.find(".ui-icon").length),e=i.filter(":not(.ui-menu)").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=V(this),e=t.prev(),i=V("").data("ui-menu-submenu-caret",!0);s._addClass(i,"ui-menu-icon","ui-icon "+n),e.attr("aria-haspopup","true").prepend(i),t.attr("aria-labelledby",e.attr("id"))}),this._addClass(e,"ui-menu","ui-widget ui-widget-content ui-front"),(t=i.add(this.element).find(this.options.items)).not(".ui-menu-item").each(function(){var t=V(this);s._isDivider(t)&&s._addClass(t,"ui-menu-divider","ui-widget-content")}),i=(e=t.not(".ui-menu-item, .ui-menu-divider")).children().not(".ui-menu").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),this._addClass(e,"ui-menu-item")._addClass(i,"ui-menu-item-wrapper"),t.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!V.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){var i;"icons"===t&&(i=this.element.find(".ui-menu-icon"),this._removeClass(i,null,this.options.icons.submenu)._addClass(i,null,e.submenu)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",String(t)),this._toggleClass(null,"ui-state-disabled",!!t)},focus:function(t,e){var i;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),i=this.active.children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",i.attr("id")),i=this.active.parent().closest(".ui-menu-item").children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),(i=e.children(".ui-menu")).length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(t){var e,i,s;this._hasScroll()&&(i=parseFloat(V.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(V.css(this.activeMenu[0],"paddingTop"))||0,e=t.offset().top-this.activeMenu.offset().top-i-s,i=this.activeMenu.scrollTop(),s=this.activeMenu.height(),t=t.outerHeight(),e<0?this.activeMenu.scrollTop(i+e):s",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var i,s,n,t=this.element[0].nodeName.toLowerCase(),e="textarea"===t,t="input"===t;this.isMultiLine=e||!t&&this._isContentEditable(this.element),this.valueMethod=this.element[e||t?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(t){if(this.element.prop("readOnly"))s=n=i=!0;else{s=n=i=!1;var e=V.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:i=!0,this._move("previousPage",t);break;case e.PAGE_DOWN:i=!0,this._move("nextPage",t);break;case e.UP:i=!0,this._keyEvent("previous",t);break;case e.DOWN:i=!0,this._keyEvent("next",t);break;case e.ENTER:this.menu.active&&(i=!0,t.preventDefault(),this.menu.select(t));break;case e.TAB:this.menu.active&&this.menu.select(t);break;case e.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(t),t.preventDefault());break;default:s=!0,this._searchTimeout(t)}}},keypress:function(t){if(i)return i=!1,void(this.isMultiLine&&!this.menu.element.is(":visible")||t.preventDefault());if(!s){var e=V.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:this._move("previousPage",t);break;case e.PAGE_DOWN:this._move("nextPage",t);break;case e.UP:this._keyEvent("previous",t);break;case e.DOWN:this._keyEvent("next",t)}}},input:function(t){if(n)return n=!1,void t.preventDefault();this._searchTimeout(t)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){clearTimeout(this.searching),this.close(t),this._change(t)}}),this._initSource(),this.menu=V("