]> gitweb.fluxo.info Git - lorea/elgg.git/commitdiff
initial commit.
authorroot <root@migration.vz.lan>
Tue, 23 Oct 2012 09:04:43 +0000 (09:04 +0000)
committerroot <root@migration.vz.lan>
Tue, 23 Oct 2012 09:04:43 +0000 (09:04 +0000)
69 files changed:
actions/get_connection.php [new file with mode: 0644]
actions/get_details.php [new file with mode: 0644]
actions/get_icons.php [new file with mode: 0644]
actions/get_state.php [new file with mode: 0644]
actions/get_statuses.php [new file with mode: 0644]
actions/join_groupchat.php [new file with mode: 0644]
actions/leave_groupchat.php [new file with mode: 0644]
actions/save_state.php [new file with mode: 0644]
classes/BeechatSync.php [new file with mode: 0644]
enablechat.php [new file with mode: 0644]
graphics/icons/bullet_arrow_down.png [new file with mode: 0644]
graphics/icons/bullet_arrow_up.png [new file with mode: 0644]
graphics/icons/bullet_black.png [new file with mode: 0644]
graphics/icons/bullet_blue.png [new file with mode: 0644]
graphics/icons/bullet_delete.png [new file with mode: 0644]
graphics/icons/bullet_error.png [new file with mode: 0644]
graphics/icons/bullet_green.png [new file with mode: 0644]
graphics/icons/bullet_orange.png [new file with mode: 0644]
graphics/icons/bullet_pink.png [new file with mode: 0644]
graphics/icons/bullet_purple.png [new file with mode: 0644]
graphics/icons/bullet_red.png [new file with mode: 0644]
graphics/icons/bullet_star.png [new file with mode: 0644]
graphics/icons/bullet_white.png [new file with mode: 0644]
graphics/icons/bullet_yellow.png [new file with mode: 0644]
graphics/icons/chat_icon.png [new file with mode: 0644]
graphics/icons/cog_edit.png [new file with mode: 0644]
graphics/icons/comment_edit.png [new file with mode: 0644]
graphics/icons/emoticon_evilgrin.png [new file with mode: 0644]
graphics/icons/emoticon_grin.png [new file with mode: 0644]
graphics/icons/emoticon_happy.png [new file with mode: 0644]
graphics/icons/emoticon_smile.png [new file with mode: 0644]
graphics/icons/emoticon_surprised.png [new file with mode: 0644]
graphics/icons/emoticon_tongue.png [new file with mode: 0644]
graphics/icons/emoticon_unhappy.png [new file with mode: 0644]
graphics/icons/emoticon_waii.png [new file with mode: 0644]
graphics/icons/emoticon_wink.png [new file with mode: 0644]
graphics/icons/heart.png [new file with mode: 0644]
graphics/icons/house.png [new file with mode: 0644]
graphics/icons/muc_icon.png [new file with mode: 0644]
graphics/icons/notification_pink.png [new file with mode: 0644]
graphics/icons/pointer.png [new file with mode: 0644]
graphics/icons/resultset_next.png [new file with mode: 0644]
graphics/icons/resultset_previous.png [new file with mode: 0644]
graphics/icons/statuses.png [new file with mode: 0644]
graphics/icons/vcard.png [new file with mode: 0644]
languages/en.php [new file with mode: 0644]
languages/es.php [new file with mode: 0644]
languages/fr.php [new file with mode: 0644]
lib/beechat.php [new file with mode: 0644]
manifest.xml [new file with mode: 0644]
sounds/newmessage.wav [new file with mode: 0644]
start.php [new file with mode: 0644]
views/default/beechat/beechat.js.php [new file with mode: 0644]
views/default/beechat/beechat.php [new file with mode: 0644]
views/default/beechat/beechat.userjs.php [new file with mode: 0644]
views/default/beechat/screen.css.php [new file with mode: 0644]
views/default/js/b64.js.php [new file with mode: 0644]
views/default/js/jquery.cookie.min.js.php [new file with mode: 0644]
views/default/js/jquery.localscroll-1.2.7-min.js.php [new file with mode: 0644]
views/default/js/jquery.scrollTo-min.js.php [new file with mode: 0755]
views/default/js/jquery.serialScroll-min.js.php [new file with mode: 0755]
views/default/js/jquery.tools.min.js.php [new file with mode: 0644]
views/default/js/json2.js.php [new file with mode: 0644]
views/default/js/md5.js.php [new file with mode: 0644]
views/default/js/sha1.js.php [new file with mode: 0644]
views/default/js/strophe.min.js.php [new file with mode: 0644]
views/default/js/strophe.muc.js [new file with mode: 0644]
views/default/js/strophe.muc.js.php [new file with mode: 0644]
views/default/settings/beechat/edit.php [new file with mode: 0755]

diff --git a/actions/get_connection.php b/actions/get_connection.php
new file mode 100644 (file)
index 0000000..a311741
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+       /**
+        * Beechat
+        * 
+        * @package beechat
+        * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+        * @author Beechannels <contact@beechannels.com>
+        * @copyright Beechannels 2007-2010
+        * @link http://beechannels.com/
+        */
+        
+       header('Content-type: application/json');
+       gatekeeper();
+       
+       global $SESSION;
+       
+       if ($SESSION->offsetExists('beechat_conn'))
+         echo $SESSION->offsetGet('beechat_conn');
+       
+       exit();
+?>
diff --git a/actions/get_details.php b/actions/get_details.php
new file mode 100644 (file)
index 0000000..4944fc4
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+       /**
+        * Beechat
+        * 
+        * @package beechat
+        * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+        * @author Beechannels <contact@beechannels.com>
+        * @copyright Beechannels 2007-2010
+        * @link http://beechannels.com/
+        */
+       
+       gatekeeper();
+       header('Content-type: application/json');
+       $user = $_SESSION['user'];
+       $t = array('username' => $user->username,
+                  'password' => $user->password);
+       
+       echo json_encode($t);
+       
+       exit();
+?>
diff --git a/actions/get_icons.php b/actions/get_icons.php
new file mode 100644 (file)
index 0000000..88e7bdd
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+       /**
+        * Beechat
+        * 
+        * @package beechat
+        * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+        * @author Beechannels <contact@beechannels.com>
+        * @copyright Beechannels 2007-2010
+        * @link http://beechannels.com/
+        */
+
+       header('Content-type: application/json');
+       gatekeeper();
+       global $CONFIG;
+
+       if (!empty($_POST['beechat_roster_items_usernames']))
+       {
+               $rosterItemsUsernames = explode(',', $_POST['beechat_roster_items_usernames']);
+               /*foreach ($rosterItemsUsernames as $rosterItem)
+               {
+               }*/
+               $userFriendsEntities = $_SESSION['user']->getFriends('', 0, 0);
+               
+               $res = array();
+               foreach ($rosterItemsUsernames as $value)
+               {
+                       $found = false;
+                       $splitjid = explode('@', $value);
+                       $jid_name = $splitjid[0];
+                       $jid_host = $splitjid[1];
+                       foreach ($userFriendsEntities as $friend)
+                       {
+                               if ((strtolower($friend->username) == strtolower($jid_name) && $jid_host == get_plugin_setting("domain", "beechat")))
+                               {
+                                       $res[$value] = array('small' => $friend->getIcon('small'), 'tiny' => $friend->getIcon('tiny'));
+                                       $found = true;
+                                       break;
+                               }
+                       }
+                       if (!$found) {
+                               $base = $CONFIG->wwwroot."mod/profile/graphics/default";
+                               $res[$value] = array('small' => $base."small.gif", 'tiny' => $base."tiny.gif");
+                       }
+               }
+               echo json_encode($res);
+       }
+       else
+               echo json_encode(null);
+
+       exit();
+
+?>
diff --git a/actions/get_state.php b/actions/get_state.php
new file mode 100644 (file)
index 0000000..6cfd2f7
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+       /**
+        * Beechat
+        * 
+        * @package beechat
+        * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+        * @author Beechannels <contact@beechannels.com>
+        * @copyright Beechannels 2007-2010
+        * @link http://beechannels.com/
+        */
+        
+       header('Content-type: application/json');
+       gatekeeper();
+       
+       global $SESSION;
+       
+       if ($SESSION->offsetExists('beechat_state'))
+         echo $SESSION->offsetGet('beechat_state');
+       
+       exit();
+?>
diff --git a/actions/get_statuses.php b/actions/get_statuses.php
new file mode 100644 (file)
index 0000000..c328e44
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+       /**
+        * Beechat
+        * 
+        * @package beechat
+        * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+        * @author Beechannels <contact@beechannels.com>
+        * @copyright Beechannels 2007-2010
+        * @link http://beechannels.com/
+        */
+
+       header('Content-type: application/json');
+       gatekeeper();
+       $usernames = get_input('beechat_roster_items_usernames');
+       if (!empty($usernames))
+       {
+               $iconSize = 'small';
+               $rosterItemsUsernames = explode(',', $usernames);
+               $userFriendsEntities = $_SESSION['user']->getFriends('', count($rosterItemsUsernames), 0);
+               
+               $res = array();
+               foreach ($rosterItemsUsernames as $value)
+               {
+                       foreach ($userFriendsEntities as $friend)
+                       {
+                               if (strtolower($friend->username) == strtolower($value))
+                               {
+                                       $status = get_entities_from_metadata("state", "current", "object", "status", $friend->get('guid'));
+                                       $res[$value] = ($status != false) ? $status[0]->description : '';
+                                       break;
+                               }
+                       }
+               }
+               echo json_encode($res);
+       }
+       else
+               echo json_encode(null);
+
+       exit();
+
+?>
diff --git a/actions/join_groupchat.php b/actions/join_groupchat.php
new file mode 100644 (file)
index 0000000..0d2d75c
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+$user = get_loggedin_user();
+$group = get_entity(get_input('group_guid'));
+
+if ($user && $group) {
+       if (!check_entity_relationship($user->guid, 'groupchat', $group->guid)) {
+               error_log("joinen ok");
+               add_entity_relationship($user->guid, 'groupchat', $group->guid);
+}
+}
+echo "OK";
+error_log("join ok");
+
+?>
diff --git a/actions/leave_groupchat.php b/actions/leave_groupchat.php
new file mode 100644 (file)
index 0000000..079ad48
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+
+$user = get_loggedin_user();
+$group = get_entity(get_input('group_guid'));
+
+if ($user && $group) {
+       if (check_entity_relationship($user->guid, 'groupchat', $group->guid))
+               remove_entity_relationship($user->guid, 'groupchat', $group->guid);
+}
+error_log("leave ok");
+echo "OK";
+?>
diff --git a/actions/save_state.php b/actions/save_state.php
new file mode 100644 (file)
index 0000000..f3a818f
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+       /**
+        * Beechat
+        * 
+        * @package beechat
+        * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+        * @author Beechannels <contact@beechannels.com>
+        * @copyright Beechannels 2007-2010
+        * @link http://beechannels.com/
+        */
+
+       gatekeeper();
+       
+       global $SESSION;
+       
+       if (!empty($_POST['beechat_state']))
+       {
+               $SESSION->offsetSet('beechat_state', get_input('beechat_state'));
+       } 
+       elseif (!empty($_POST['beechat_conn']))
+       {
+               $SESSION->offsetSet('beechat_conn', get_input('beechat_conn'));
+       }
+       
+       exit();
+?>
diff --git a/classes/BeechatSync.php b/classes/BeechatSync.php
new file mode 100644 (file)
index 0000000..e0a2f90
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+
+class BeechatSync {
+        static function onFriendCreate($event, $object_type, $relationship) {
+               if ($relationship->relationship == 'friendrequest') {
+                       elgg_load_library('elgg:beechat');
+                        $friend = get_entity($relationship->guid_two);
+                        // create friend request
+                       ejabberd_friend_request(elgg_get_logged_in_user_entity(), $friend);
+               }
+       }
+        static function onFriendDelete($event, $object_type, $relationship) {
+               if ($relationship->relationship == 'friendrequest') {
+                       elgg_load_library('elgg:beechat');
+                        $subject = get_entity($relationship->guid_two);
+                       // here friend is guid_one because is the one initiating
+                        $friend = get_entity($relationship->guid_one);
+                        $friends = $friend->isFriendsWith($subject->guid);
+                        if ($friends) {
+                                // accept friend request
+                               ejabberd_friend_accept(elgg_get_logged_in_user_entity(), $friend);
+                        } else {
+                                // decline friend request
+                               ejabberd_friend_deny(elgg_get_logged_in_user_entity(), $friend);
+                        }
+                }
+                elseif ($relationship->relationship == 'friend') {
+                       elgg_load_library('elgg:beechat');
+                        $subject = get_entity($relationship->guid_one);
+                        $friend = get_entity($relationship->guid_two);
+                        // delete friendship
+                       ejabberd_friend_remove(elgg_get_logged_in_user_entity(), $friend);
+                }
+
+       }
+
+}
diff --git a/enablechat.php b/enablechat.php
new file mode 100644 (file)
index 0000000..f344952
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+        require_once(dirname(dirname(dirname(__FILE__))) . "/engine/start.php");
+       if (isloggedin()) {
+               get_loggedin_user()->chatenabled = true;
+               system_message(elgg_echo("beechat:enabled"));
+       }
+       forward($_SERVER['HTTP_REFERER']);
+?>
diff --git a/graphics/icons/bullet_arrow_down.png b/graphics/icons/bullet_arrow_down.png
new file mode 100644 (file)
index 0000000..9b23c06
Binary files /dev/null and b/graphics/icons/bullet_arrow_down.png differ
diff --git a/graphics/icons/bullet_arrow_up.png b/graphics/icons/bullet_arrow_up.png
new file mode 100644 (file)
index 0000000..24df0f4
Binary files /dev/null and b/graphics/icons/bullet_arrow_up.png differ
diff --git a/graphics/icons/bullet_black.png b/graphics/icons/bullet_black.png
new file mode 100644 (file)
index 0000000..5761970
Binary files /dev/null and b/graphics/icons/bullet_black.png differ
diff --git a/graphics/icons/bullet_blue.png b/graphics/icons/bullet_blue.png
new file mode 100644 (file)
index 0000000..a7651ec
Binary files /dev/null and b/graphics/icons/bullet_blue.png differ
diff --git a/graphics/icons/bullet_delete.png b/graphics/icons/bullet_delete.png
new file mode 100644 (file)
index 0000000..bd6271b
Binary files /dev/null and b/graphics/icons/bullet_delete.png differ
diff --git a/graphics/icons/bullet_error.png b/graphics/icons/bullet_error.png
new file mode 100644 (file)
index 0000000..bca2b49
Binary files /dev/null and b/graphics/icons/bullet_error.png differ
diff --git a/graphics/icons/bullet_green.png b/graphics/icons/bullet_green.png
new file mode 100644 (file)
index 0000000..058ad26
Binary files /dev/null and b/graphics/icons/bullet_green.png differ
diff --git a/graphics/icons/bullet_orange.png b/graphics/icons/bullet_orange.png
new file mode 100644 (file)
index 0000000..fa63024
Binary files /dev/null and b/graphics/icons/bullet_orange.png differ
diff --git a/graphics/icons/bullet_pink.png b/graphics/icons/bullet_pink.png
new file mode 100644 (file)
index 0000000..0c9f73e
Binary files /dev/null and b/graphics/icons/bullet_pink.png differ
diff --git a/graphics/icons/bullet_purple.png b/graphics/icons/bullet_purple.png
new file mode 100644 (file)
index 0000000..52ba503
Binary files /dev/null and b/graphics/icons/bullet_purple.png differ
diff --git a/graphics/icons/bullet_red.png b/graphics/icons/bullet_red.png
new file mode 100644 (file)
index 0000000..0cd8031
Binary files /dev/null and b/graphics/icons/bullet_red.png differ
diff --git a/graphics/icons/bullet_star.png b/graphics/icons/bullet_star.png
new file mode 100644 (file)
index 0000000..fab774a
Binary files /dev/null and b/graphics/icons/bullet_star.png differ
diff --git a/graphics/icons/bullet_white.png b/graphics/icons/bullet_white.png
new file mode 100644 (file)
index 0000000..a9af8d4
Binary files /dev/null and b/graphics/icons/bullet_white.png differ
diff --git a/graphics/icons/bullet_yellow.png b/graphics/icons/bullet_yellow.png
new file mode 100644 (file)
index 0000000..6469cea
Binary files /dev/null and b/graphics/icons/bullet_yellow.png differ
diff --git a/graphics/icons/chat_icon.png b/graphics/icons/chat_icon.png
new file mode 100644 (file)
index 0000000..0e6d844
Binary files /dev/null and b/graphics/icons/chat_icon.png differ
diff --git a/graphics/icons/cog_edit.png b/graphics/icons/cog_edit.png
new file mode 100644 (file)
index 0000000..47b75a4
Binary files /dev/null and b/graphics/icons/cog_edit.png differ
diff --git a/graphics/icons/comment_edit.png b/graphics/icons/comment_edit.png
new file mode 100644 (file)
index 0000000..73db110
Binary files /dev/null and b/graphics/icons/comment_edit.png differ
diff --git a/graphics/icons/emoticon_evilgrin.png b/graphics/icons/emoticon_evilgrin.png
new file mode 100644 (file)
index 0000000..817bd50
Binary files /dev/null and b/graphics/icons/emoticon_evilgrin.png differ
diff --git a/graphics/icons/emoticon_grin.png b/graphics/icons/emoticon_grin.png
new file mode 100644 (file)
index 0000000..fc60c5e
Binary files /dev/null and b/graphics/icons/emoticon_grin.png differ
diff --git a/graphics/icons/emoticon_happy.png b/graphics/icons/emoticon_happy.png
new file mode 100644 (file)
index 0000000..6b7336e
Binary files /dev/null and b/graphics/icons/emoticon_happy.png differ
diff --git a/graphics/icons/emoticon_smile.png b/graphics/icons/emoticon_smile.png
new file mode 100644 (file)
index 0000000..ade4318
Binary files /dev/null and b/graphics/icons/emoticon_smile.png differ
diff --git a/graphics/icons/emoticon_surprised.png b/graphics/icons/emoticon_surprised.png
new file mode 100644 (file)
index 0000000..4520cfc
Binary files /dev/null and b/graphics/icons/emoticon_surprised.png differ
diff --git a/graphics/icons/emoticon_tongue.png b/graphics/icons/emoticon_tongue.png
new file mode 100644 (file)
index 0000000..ecafd2f
Binary files /dev/null and b/graphics/icons/emoticon_tongue.png differ
diff --git a/graphics/icons/emoticon_unhappy.png b/graphics/icons/emoticon_unhappy.png
new file mode 100644 (file)
index 0000000..fd5d030
Binary files /dev/null and b/graphics/icons/emoticon_unhappy.png differ
diff --git a/graphics/icons/emoticon_waii.png b/graphics/icons/emoticon_waii.png
new file mode 100644 (file)
index 0000000..458f936
Binary files /dev/null and b/graphics/icons/emoticon_waii.png differ
diff --git a/graphics/icons/emoticon_wink.png b/graphics/icons/emoticon_wink.png
new file mode 100644 (file)
index 0000000..a631949
Binary files /dev/null and b/graphics/icons/emoticon_wink.png differ
diff --git a/graphics/icons/heart.png b/graphics/icons/heart.png
new file mode 100644 (file)
index 0000000..d9ee53e
Binary files /dev/null and b/graphics/icons/heart.png differ
diff --git a/graphics/icons/house.png b/graphics/icons/house.png
new file mode 100644 (file)
index 0000000..fed6221
Binary files /dev/null and b/graphics/icons/house.png differ
diff --git a/graphics/icons/muc_icon.png b/graphics/icons/muc_icon.png
new file mode 100644 (file)
index 0000000..efdd60f
Binary files /dev/null and b/graphics/icons/muc_icon.png differ
diff --git a/graphics/icons/notification_pink.png b/graphics/icons/notification_pink.png
new file mode 100644 (file)
index 0000000..f40c184
Binary files /dev/null and b/graphics/icons/notification_pink.png differ
diff --git a/graphics/icons/pointer.png b/graphics/icons/pointer.png
new file mode 100644 (file)
index 0000000..4e50a0f
Binary files /dev/null and b/graphics/icons/pointer.png differ
diff --git a/graphics/icons/resultset_next.png b/graphics/icons/resultset_next.png
new file mode 100644 (file)
index 0000000..e252606
Binary files /dev/null and b/graphics/icons/resultset_next.png differ
diff --git a/graphics/icons/resultset_previous.png b/graphics/icons/resultset_previous.png
new file mode 100644 (file)
index 0000000..18f9cc1
Binary files /dev/null and b/graphics/icons/resultset_previous.png differ
diff --git a/graphics/icons/statuses.png b/graphics/icons/statuses.png
new file mode 100644 (file)
index 0000000..e409f61
Binary files /dev/null and b/graphics/icons/statuses.png differ
diff --git a/graphics/icons/vcard.png b/graphics/icons/vcard.png
new file mode 100644 (file)
index 0000000..c02f315
Binary files /dev/null and b/graphics/icons/vcard.png differ
diff --git a/languages/en.php b/languages/en.php
new file mode 100644 (file)
index 0000000..38f03be
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+$en_array = array(
+                 'beechat:icons:home' => 'Home',
+
+                 'beechat:contacts:button' => 'Chat',
+
+                 'beechat:availability:available' => 'Available',
+                 'beechat:availability:dnd' => 'Do not disturb',
+                 'beechat:availability:away' => 'Away',
+                 'beechat:availability:xa' => 'Extended away',
+                 'beechat:availability:offline' => 'Offline',
+
+                 'beechat:connection:state:offline' => 'Offline',
+                 'beechat:connection:state:connecting' => 'Connecting...',
+                 'beechat:connection:state:authenticating' => 'Authenticating...',
+                 'beechat:connection:state:online' => 'Online',
+                 'beechat:connection:state:failed' => 'Failed',
+                 'beechat:connection:state:disconnecting' => 'Disconnecting...',
+
+                 'beechat:chat:self' => 'Me',
+                 'beechat:chat:composing' => ' is typing.',
+
+                 'beechat:box:minimize' => 'Minimize',
+                 'beechat:box:close' => 'Close',
+                 'beechat:box:showhide' => 'Show/Hide this chat window',
+                 'beechat:enabled' => 'Chat enabled',
+                 'beechat:disabled' => 'Chat disabled',
+                 'beechat:enablechat' => 'Enable chat',
+                 'beechat:disablechat' => 'Disable chat',
+                 'beechat:domain' => 'Chat domain',
+                 'beechat:groupdomain' => 'MUC domain',
+                 'beechat:chatroom' => 'Group chat',
+                 'beechat:dbname' => 'Database name',
+                 'beechat:dbhost' => 'Database host',
+                 'beechat:dbuser' => 'Database user',
+                 'beechat:dbuser' => 'notification:method:xmpp',
+                 'notification:method:xmpp' => 'Xmpp/Jabber',
+                 'beechat:dbpassword' => 'Database password',
+                 'beechat:xmlrpcip' => 'Ejabberd IP'
+                 );
+
+add_translation('en', $en_array);
+
+?>
diff --git a/languages/es.php b/languages/es.php
new file mode 100644 (file)
index 0000000..78f009c
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+
+$es_array = array(
+                 'beechat:icons:home' => 'Home',
+
+                 'beechat:contacts:button' => 'Chat',
+
+                 'beechat:availability:available' => 'Disponible',
+                 'beechat:availability:dnd' => 'No molestar',
+                 'beechat:availability:away' => 'Fuera',
+                 'beechat:availability:xa' => 'Fuera bastante tiempo',
+                 'beechat:availability:offline' => 'Desconectado',
+
+                 'beechat:connection:state:offline' => 'Desconectado',
+                 'beechat:connection:state:connecting' => 'Conectando...',
+                 'beechat:connection:state:authenticating' => 'Iniciando...',
+                 'beechat:connection:state:online' => 'Conectado',
+                 'beechat:connection:state:failed' => 'Fallo',
+                 'beechat:connection:state:disconnecting' => 'Desconectando...',
+
+                 'beechat:chat:self' => 'Yo',
+                 'beechat:chat:composing' => ' esta escribiendo.',
+
+                 'beechat:box:minimize' => 'Minimizar',
+                 'beechat:box:close' => 'Cerrar',
+                 'beechat:box:showhide' => 'Mostrar/Ocultar esta ventana de chat',
+                 'beechat:enabled' => 'Chat activado',
+                 'beechat:disabled' => 'Chat desactivado',
+                 'beechat:enablechat' => 'Activar chat',
+                 'beechat:disablechat' => 'Desactivar chat',
+                 'beechat:domain' => 'Dominio Chat',
+                 'beechat:groupdomain' => 'Dominio MUC',
+                 'beechat:chatroom' => 'Chat del grupo',
+                 'beechat:dbname' => 'Database name',
+                 'beechat:dbhost' => 'Database host',
+                 'beechat:dbuser' => 'Database user',
+                 'beechat:dbpassword' => 'Database password',
+                 'beechat:xmlrpcip' => 'Ejabberd IP'
+                 );
+
+add_translation('es', $es_array);
+
+?>
diff --git a/languages/fr.php b/languages/fr.php
new file mode 100644 (file)
index 0000000..58b0eac
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+$fr_array = array(
+                 'beechat:icons:home' => 'Accueil',
+
+                 'beechat:contacts:button' => 'Chat',
+
+                 'beechat:availability:available' => 'Disponible',
+                 'beechat:availability:dnd' => 'Ne pas déranger',
+                 'beechat:availability:away' => 'Absent',
+                 'beechat:availability:xa' => 'Absence prolongée',
+                 'beechat:availability:offline' => 'Hors ligne',
+
+                 'beechat:connection:state:offline' => 'Hors ligne',
+                 'beechat:connection:state:connecting' => 'Connexion...',
+                 'beechat:connection:state:authenticating' => 'Authentification...',
+                 'beechat:connection:state:online' => 'En ligne',
+                 'beechat:connection:state:failed' => 'Échec',
+                 'beechat:connection:state:disconnecting' => 'Déconnexion...',
+
+                 'beechat:chat:self' => 'Moi',
+                 'beechat:chat:composing' => ' est en train d\'écrire.',
+
+                 'beechat:box:minimize' => 'Diminuer',
+                 'beechat:box:close' => 'Fermer',
+                 'beechat:box:showhide' => 'Montrer/Cacher cette fenêtre de chat'
+
+                 );
+
+add_translation('fr', $fr_array);
+
+?>
diff --git a/lib/beechat.php b/lib/beechat.php
new file mode 100644 (file)
index 0000000..a7db640
--- /dev/null
@@ -0,0 +1,250 @@
+<?
+/*
+       allow_change_subj
+        allow_private_messages
+        allow_query_users
+        allow_user_invites
+        anonymous
+        logging
+        max_users
+        members_by_default
+        members_only
+        moderated
+        password
+        password_protected
+        persistent
+        public
+        public_list
+        title
+
+muc_room_set_affiliation struct[{name, String}, {service, String},
+                                {jid, String}, {affiliation, Affiliation}]  Integer
+
+
+*/
+       //$request = xmlrpc_encode_request('muc_online_rooms', "global", (array('encoding' => 'utf-8')));
+
+
+function ejabberd_xmlrpc_send($request)
+{
+       $context = stream_context_create(array('http' => array(
+           'method' => "POST",
+           'header' => "User-Agent: XMLRPC::Client mod_xmlrpc\r\n" .
+                       "Content-Type: text/xml\r\n" .
+                       "Content-Length: ".strlen($request),
+           'content' => $request
+       )));
+
+       $file = file_get_contents("http://".get_plugin_setting("xmlrpcip", "beechat").":4560/RPC2", false, $context);
+
+       $response = xmlrpc_decode($file);
+       if (is_array($response) && xmlrpc_is_fault($response)) {
+           trigger_error("xmlrpc: $response[faultString] ($response[faultCode])");
+       } else {
+       //    print_r($response);
+       }
+}
+
+function ejabberd_xmlrpc_command($command, $params)
+{
+       //error_log("send xmlrpc: ".$command);
+       $request = xmlrpc_encode_request($command, $params, (array('encoding' => 'utf-8')));
+        return ejabberd_xmlrpc_send($request);
+}
+
+function xmpp_escape($name) {
+       // http://xmpp.org/extensions/xep-0106.html#escaping
+       $name = str_replace(' ', '\\20', $name);
+       $name = str_replace('"', '\\22', $name);
+       $name = str_replace('&', '\\26', $name);
+       $name = str_replace("'", '\\27', $name);
+       $name = str_replace('/', '\\2f', $name);
+       $name = str_replace(';', '\\3a', $name);
+       $name = str_replace('<', '\\3c', $name);
+       $name = str_replace('>', '\\3e', $name);
+       $name = str_replace('@', '\\40', $name);
+       $name = str_replace('\\', '\\5c', $name);
+       return $name;
+}
+
+class EjabberdMucRoom {
+       function __construct($group) {
+               $this->group = $group;
+       }
+       function setOption($name, $value) {
+               $group = $this->group;
+               $param=array("name"=>friendly_title($group->name),
+                       "service"=>get_plugin_setting("groupdomain", "beechat"),
+                       "option"=>$name,
+                       "value"=>$value);
+               ejabberd_xmlrpc_command('muc_room_change_option', $param);
+       }
+       function addMember($member) {
+               //"outcast" | "none" | "member" | "admin" | "owner"
+               $group = $this->group;
+               if ($member->guid === $group->owner_guid)
+                       $affiliation = "owner";
+               elseif ($group->canEdit($member->guid))
+                       $affiliation = "admin";
+               else
+                       $affiliation = "member";
+               $this->setAffiliation($member, $affiliation);
+       }
+
+       function setAffiliation($member, $affiliation) {
+               $group = $this->group;
+               $param = array("name" => friendly_title($group->name),
+                       "service" => get_plugin_setting("groupdomain", "beechat"),
+                       "jid" => xmpp_escape($member->username) . '@' . get_plugin_setting("domain", "beechat"),
+                       "affiliation" => $affiliation);
+               ejabberd_xmlrpc_command('muc_room_set_affiliation', $param);
+               //echo "set affiliation ".$member->username."<br/>";
+       }
+}
+
+function ejabberd_create_group($group)
+{
+       //echo "creating " . $group->name . "<br/>";
+       // create room
+       $param=array("name"=>friendly_title($group->name),
+                       "service"=>get_plugin_setting("groupdomain", "beechat"),
+                       "server"=>get_plugin_setting("domain", "beechat"));
+       ejabberd_xmlrpc_command('create_muc_room', $param);
+
+       // persistency
+
+       $room = new EjabberdMucRoom($group);
+       $room->setOption("persistent", true);
+       $room->setOption("title", $group->name);
+       // open to public?
+       if ($group->isPublicMembership()) {
+               $room->setOption("members_only", false);
+       }
+       else
+               $room->setOption("members_only", true);
+
+       if ($group->access_id === ACCESS_PUBLIC) {
+               $room->setOption("public_list", true);
+               $room->setOption("public", true);
+       }
+       else {
+               $room->setOption("public_list", false);
+               $room->setOption("public", false);
+       }
+       $members = $group->getMembers(0);
+       foreach($members as $member) {
+               $room->addMember($member);
+       }
+       $room->addMember(get_entity($group->owner_guid));
+}
+
+function ejabberd_destroy_group($group)
+{
+       $param=array("name"=>friendly_title($group->name),
+                       "service"=>get_plugin_setting("groupdomain", "beechat"),
+                       "server"=>get_plugin_setting("domain", "beechat"));
+       ejabberd_xmlrpc_command('delete_muc_room', $param);
+}
+
+function ejabberd_getjid($user, $do_external=false)
+{
+       if ($user->foreign || ($do_external && $user->alias && get_plugin_usersetting("usealias", $user->guid,"openid_client"))) {
+               if ($user->foreign)
+                       $webid = $user->webid;
+               else
+                       $webid = $user->alias;
+               if (strpos($webid, 'http') === 0) {
+                       // http or https addresses
+                       $hostparts = parse_url($webid);
+                        $urlparts = explode('/', $webid);
+                       $host = $hostparts['host'];
+                       $username = $urlparts[count($urlparts)-1];
+               } else {
+                       if (strpos($webid, ':') > 0) {
+                               $webidparts = explode(':', $webid);
+                               $hostparts = explode('@',$webidparts[1]);
+                       } else {
+                               $hostparts = explode('@',$webid);
+                       }
+                       $username = $hostparts[0];
+                       $host = $hostparts[1];
+               }
+       }
+       else {
+               $username = $user->username;
+               $host = get_plugin_setting("domain", "beechat");
+       }
+       return xmpp_escape($username) . '@' . $host;
+}
+
+function ejabberd_friend_command($user, $friend, $command, $is_out) // $user adds $friend
+{
+       error_log(" * ".$friend->username."->".ejabberd_getjid($user)." ".$command);
+       if ($friend->foreign) {
+               error_log(" * beechat: friend is foreign!");       
+               return;
+       }
+       $param = array("user" => friendly_title($friend->username),
+                       "server" => get_plugin_setting("domain", "beechat"),
+                       "from" => ejabberd_getjid($user),
+                       "subs" => $command);
+       if ($is_out) {
+               error_log("out");
+               ejabberd_xmlrpc_command('send_roster_request_out', $param);
+       }
+       else {
+               $param['reason'] = 'unknown';
+               ejabberd_xmlrpc_command('send_roster_request_in', $param);
+       }
+}
+
+
+function ejabberd_friend_request($user, $friend) // $user adds $friend
+{
+       error_log('ejabberd_friend_request');
+       ejabberd_friend_command($friend, $user, 'subscribe', true); // out:$user : $friend
+       error_log('ejabberd_friend_requested');
+}
+function ejabberd_friend_accept($user, $friend) // $user adds $friend
+{
+       error_log('ejabberd_friend_accept');
+       ejabberd_friend_command($friend, $user, 'subscribed', true);
+       // following might be needed to have symmetry (and important for remote)
+        if ($friend->foreign) {
+            // following is needed for xmpp nodes
+           ejabberd_friend_command($friend, $user, 'subscribe', true);
+       }
+       // ejabberd_friend_command($friend, $user, 'subscribed', false);
+       // following can't be faked
+        if (!$friend->foreign)
+           ejabberd_friend_command($user, $friend, 'subscribed', true);
+       error_log('ejabberd_friend_accepted');
+}
+function ejabberd_friend_deny($user, $friend) // $user adds $friend
+{
+       error_log('ejabberd_friedeny');
+       ejabberd_friend_command($friend, $user, 'unsubscribed', true);
+}
+function ejabberd_friend_remove($user, $friend) // $user adds $friend
+{
+       error_log('ejabberd_friend_remove');
+        if ($friend->foreign) {
+               ejabberd_friend_command($friend, $user, 'unsubscribed', true);
+               ejabberd_friend_command($friend, $user, 'unsubscribed', false);
+       }
+       else
+               ejabberd_friend_command($friend, $user, 'unsubscribed', false);
+        if (!$friend->foreign)
+               ejabberd_friend_command($user, $friend, 'unsubscribed', false);
+       error_log('ejabberd_friend_removed');
+}
+
+/*function ejabberd_send_chat($from, $to, $body) { // $user adds $friend
+       $param = array("body"=>$body,
+                       "from"=>$from,
+                       "to"=>$to);
+       ejabberd_xmlrpc_command('send_chat_message', $param);
+}*/
+
+
+?>
diff --git a/manifest.xml b/manifest.xml
new file mode 100644 (file)
index 0000000..8e880d3
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plugin_manifest xmlns="http://www.elgg.org/plugin_manifest/1.8">
+       <name>Beechat</name>
+       <author>Beechannels + Lorea dev</author>
+       <version>1.8</version>
+       <category>widget</category>
+       <description>XMPP chat for elgg.</description>
+       <website>http://www.elgg.org</website>
+       <copyright>See COPYRIGHT.txt</copyright>
+       <license>GNU General Public License version 2</license>
+       <requires>
+               <type>elgg_release</type>
+               <version>1.8</version>
+       </requires>
+       <activate_on_install>false</activate_on_install>
+</plugin_manifest>
diff --git a/sounds/newmessage.wav b/sounds/newmessage.wav
new file mode 100644 (file)
index 0000000..58cccd0
Binary files /dev/null and b/sounds/newmessage.wav differ
diff --git a/start.php b/start.php
new file mode 100644 (file)
index 0000000..2fe38b5
--- /dev/null
+++ b/start.php
@@ -0,0 +1,181 @@
+<?php
+       /**
+        * Beechat
+        * 
+        * @package beechat
+        * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+        * @author Beechannels <contact@beechannels.com>
+        * @copyright Beechannels 2007-2010
+        * @link http://beechannels.com/
+        */
+
+       GLOBAL $CONFIG;
+       
+       function beechat_create_group($event, $object_type, $object)
+       {
+               elgg_load_library('elgg:beechat');
+               ejabberd_create_group($object);
+       }
+
+       function beechat_delete_group($event, $object_type, $object)
+       {
+               elgg_load_library('elgg:beechat');
+               ejabberd_destroy_group($object);
+       }
+
+       function beechat_member_add($event, $object_type, $object)
+        {
+               if ($object->relationship === "member") {
+                       elgg_load_library('elgg:beechat');
+                       $user = get_entity($object->guid_one);
+                       $group = get_entity($object->guid_two);
+                       $room = new EjabberdMucRoom($group);
+                       $room->addMember($user);
+               }
+        }
+
+       function beechat_member_delete($event, $object_type, $object)
+        {
+               if ($object->relationship === "member") {
+                       elgg_load_library('elgg:beechat');
+                       $user = get_entity($object->guid_one);
+                       $group = get_entity($object->guid_two);
+                       $room = new EjabberdMucRoom($group);
+                       $room->setAffiliation($user, "none");
+               }
+        }
+
+       function beechat_init()
+       {
+               $pluginspath = elgg_get_plugins_path();
+               elgg_register_library('elgg:beechat', $pluginspath . 'beechat/lib/beechat.php');
+
+               elgg_register_event_handler('pagesetup', 'system', 'beechat_pagesetup');
+               // group actions disabled for now
+               /*if (elgg_get_plugin_setting("groupdomain", "beechat")) {
+                       register_elgg_event_handler('create', 'group', 'beechat_create_group');
+                       register_elgg_event_handler('delete', 'group', 'beechat_delete_group');
+               }
+               register_elgg_event_handler('create', 'member', 'beechat_member_add');
+               register_elgg_event_handler('delete', 'relationship', 'beechat_member_delete');*/
+
+
+               $actions_path = $pluginspath . 'beechat/actions/';
+               elgg_register_action('beechat/join_groupchat', $actions_path . 'join_groupchat.php');
+               elgg_register_action('beechat/leave_groupchat', $actions_path . 'leave_groupchat.php');
+               elgg_register_action('beechat/get_statuses', $actions_path . 'get_statuses.php');
+               elgg_register_action('beechat/get_icons', $actions_path . 'get_icons.php');
+               elgg_register_action('beechat/get_details', $actions_path . 'get_details.php');
+               elgg_register_action('beechat/get_connection', $actions_path . 'get_connection.php');
+               elgg_register_action('beechat/get_state', $actions_path . 'get_state.php');
+               elgg_register_action('beechat/save_state', $actions_path . 'save_state.php');
+
+               /*register_elgg_event_handler('create', 'friendrequest', 'beechat_xmpp_add_friendx');
+               #register_plugin_hook('action', 'friends/add', 'beechat_xmpp_add_friend', 1000);
+               register_plugin_hook('river_update', 'river_update', 'beechat_xmpp_approve_friendx');
+               register_plugin_hook('river_update_foreign', 'river_update', 'beechat_xmpp_approve_friendx');
+               #register_plugin_hook('action', 'friendrequest/approve', 'beechat_xmpp_approve_friend', 1000);
+
+
+               register_plugin_hook('action', 'friendrequest/decline', 'beechat_xmpp_decline_friend', 1000);
+               register_plugin_hook('action', 'friends/remove', 'beechat_xmpp_remove_friend', 1000);*/
+
+               // new friend sync
+               elgg_register_event_handler('delete', 'friend', array('BeechatSync', 'onFriendDelete'));
+               elgg_register_event_handler('create', 'friendrequest', array('BeechatSync', 'onFriendCreate'));
+               elgg_register_event_handler('delete', 'friendrequest', array('BeechatSync', 'onFriendDelete'));
+
+
+       
+               elgg_extend_view('js/initialise_elgg', 'js/json2.js');
+               elgg_extend_view('js/initialise_elgg', 'js/jquery.cookie.min.js');
+               elgg_extend_view('js/initialise_elgg', 'js/jquery.scrollTo-min.js');
+               elgg_extend_view('js/initialise_elgg', 'js/jquery.serialScroll-min.js');
+               elgg_extend_view('js/initialise_elgg', 'js/b64.js');
+               elgg_extend_view('js/initialise_elgg', 'js/sha1.js');
+               elgg_extend_view('js/initialise_elgg', 'js/md5.js');
+               elgg_extend_view('js/initialise_elgg', 'js/strophe.min.js');
+               elgg_extend_view('js/initialise_elgg', 'js/strophe.muc.js');
+               elgg_extend_view('js/initialise_elgg', 'js/jquery.tools.min.js');
+               elgg_extend_view('css', 'beechat/screen.css');
+               elgg_extend_view('js/initialise_elgg', 'beechat/beechat.js');
+               elgg_extend_view('page/elements/head', 'beechat/beechat.userjs');
+               
+               elgg_extend_view('page/elements/foot', 'beechat/beechat');
+
+               $domain = elgg_get_plugin_setting("domain", "beechat");
+               $group_domain = elgg_get_plugin_setting("groupdomain", "beechat");
+               $dbname = elgg_get_plugin_setting("dbname", "beechat");
+               $dbhost = elgg_get_plugin_setting("dbhost", "beechat");
+               $dbuser = elgg_get_plugin_setting("dbuser", "beechat");
+               $dbpassword = elgg_get_plugin_setting("dbpassword", "beechat");
+
+               global $CONFIG;
+               $CONFIG->chatsettings['domain'] = $domain;
+               $CONFIG->chatsettings['groupdomain'] = $group_domain;
+
+               register_notification_handler('xmpp', 'beechat_notifications');
+       //      register_plugin_hook('notify:entity:message','object','beechat_notifications_msg');
+       }
+
+       function beechat_notifications($from, $to, $subject, $topic, $params = array()) {
+               ejabberd_send_chat($to, "<div>".$topic."</div>");
+       }
+
+
+       function beechat_friendly_title($title) {
+               // need this because otherwise seems elgg
+               // gets in some problem trying to call the view
+               //$title = iconv('UTF-8', 'ASCII//TRANSLIT', $title);
+               $title = preg_replace("/[^\w ]/","",$title);
+               $title = str_replace(" ","-",$title);
+               $title = str_replace("--","-",$title);
+               $title = trim($title);
+               $title = strtolower($title);
+               return $title;
+       }
+
+       function beechat_pagesetup()
+       {
+               global $CONFIG;
+               if (get_context() == 'groups' && isloggedin()) {
+                       if (get_plugin_setting("groupdomain", "beechat")) {
+                               $user = get_loggedin_user();
+                               $group = page_owner_entity();
+                               if (!$group || !($group instanceof ElggGroup))
+                                       return;
+                               if ($user->chatenabled && get_plugin_setting("groupdomain", "beechat")) {
+                                       if ($group->isPublicMembership() || $group->isMember($user))
+                                       add_submenu_item(elgg_echo('beechat:chatroom'), "javascript:g_beechat_user.joinRoom('".beechat_friendly_title($group->name)."@".$CONFIG->chatsettings['groupdomain']."', '".$group->guid."')");
+                               }
+                       }
+               }
+               elseif (get_context() == 'settings' && isloggedin()) {
+                       if (get_loggedin_user()->chatenabled) {
+                               add_submenu_item(elgg_echo('beechat:disablechat'), $CONFIG->wwwroot . "mod/beechat/disablechat.php");
+                       }
+                       else
+                               add_submenu_item(elgg_echo('beechat:enablechat'), $CONFIG->wwwroot . "mod/beechat/enablechat.php");
+               }
+       }
+
+
+       function ejabberd_send_chat($user, $body) { // $user adds $friend
+               $from = 'notify@'.get_plugin_setting("domain", "beechat").'/net';
+               if ($user->alias) {
+                       
+               }
+               elgg_load_library('elgg:beechat');
+               $to = ejabberd_getjid($user, true);
+                #xmlrpc_set_type(&$body, "base64"); 
+               $param = array("body"=>$body,
+                               "from"=>$from,
+                               "to"=>$to);
+               ejabberd_xmlrpc_command('send_html_message', $param);
+       }
+
+
+
+
+elgg_register_event_handler('init', 'system', 'beechat_init');
+?>
diff --git a/views/default/beechat/beechat.js.php b/views/default/beechat/beechat.js.php
new file mode 100644 (file)
index 0000000..3cdd29d
--- /dev/null
@@ -0,0 +1,2468 @@
+/**
+ * Beechat
+ * 
+ * @package beechat
+ * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+ * @author Beechannels <contact@beechannels.com>
+ * @copyright Beechannels 2007-2010
+ * @link http://beechannels.com/
+ */ 
+
+/** Globals
+ *
+ */
+g_beechat_user = null;
+g_beechat_roster_items = null;
+g_beechat_rooms = new Array();
+
+function debugXMPP(msg) {
+       try {
+               //console.log(msg)
+       }
+               catch (err) {
+       }
+       //$('#layout_footer').html($('#layout_footer').html()+'<br/>'+msg);
+}
+
+/** Class: BeeChat
+ *  An object container for all BeeChat mod functions
+ *
+ */
+BeeChat = {
+    BOSH_SERVICE: '/http-bind/',
+    DOMAIN: '<?php echo $vars['config']->chatsettings['domain'] ?>',
+    RESOURCE: 'beebac',
+    INACTIVITY_PERIOD_LENGTH: 60,
+
+    NS: {
+       CHAT_STATES: 'http://jabber.org/protocol/chatstates'
+    },
+
+    Message: {
+       Types: {
+           NORMAL: 'normal',
+           CHAT: 'chat',
+           GROUPCHAT: 'groupchat',
+           HEADLINE: 'headline',
+           ERROR: 'error'
+       },
+
+       ChatStates: {
+           COMPOSING: 'composing',
+           PAUSED: 'paused',
+           ACTIVE: 'active',
+           INACTIVE: 'inactive',
+           GONE: 'gone'
+       }
+    },
+
+    IQ: {
+       Types: {
+           GET: 'get',
+           RESULT: 'result',
+           SET: 'set',
+           ERROR: 'error'
+       }
+    },
+
+    Presence: {
+       Types: {
+           UNAVAILABLE: 'unavailable',
+           SUBSCRIBE: 'subscribe',
+           SUBSCRIBED: 'subscribed',
+           UNSUBSCRIBE: 'unsubscribe',
+           UNSUBSCRIBED: 'unsubscribed',
+           PROBE: 'probe',
+           ERROR: 'error'
+       },
+
+       ChildElements: {
+           SHOW: 'show',
+           STATUS: 'status',
+           PRIORITY: 'priority'
+       },
+
+       ShowElements: {
+           CHAT: 'chat',
+           DND: 'dnd',
+           AWAY: 'away',
+           XA: 'xa'
+       }
+    },
+
+    Roster: {
+       DEFAULT_GROUP: 'Contacts'
+    },
+
+
+    Events: {
+       Identifiers: {
+           UPDATE_CONNECTION_STATE: 0,
+           UPDATE_ROSTER: 1,
+           RECV_PRESENCE: 2,
+           RECV_CHAT_MESSAGE: 3
+       },
+       Messages: {
+           ConnectionStates: {
+               CONNECTING: "<?php echo elgg_echo('beechat:connection:state:connecting'); ?>",
+               AUTHENTICATING: "<?php echo elgg_echo('beechat:connection:state:authenticating'); ?>",
+               FAILED: "<?php echo elgg_echo('beechat:connection:state:failed'); ?>",
+               DISCONNECTING: "<?php echo elgg_echo('beechat:connection:state:disconnecting'); ?>",
+               OFFLINE: "<?php echo elgg_echo('beechat:connection:state:offline'); ?>",
+               ONLINE: "<?php echo elgg_echo('beechat:connection:state:online'); ?>"
+           }
+       }
+    }
+};
+
+
+/** Class: BeeChat.Core
+ *  An object container for all BeeChat Core functions
+ *
+ */
+BeeChat.Core = {
+    ReferenceTables: {
+       AvailabilityRates: {
+           AVAILABLE: 0,
+           ONLINE: 0,
+           CHAT: 0,
+           DND: 1,
+           AWAY: 2,
+           XA: 3,
+           UNAVAILABLE: 10,
+           OFFLINE: 10
+       }
+    }
+};
+
+
+/** Class: BeeChat.Core.User
+ *  Create a BeeChat.Core.User object
+ *
+ *  Parameters:
+ *    (String) jid - The user's jabber id
+ *
+ *  Returns:
+ *    A new BeeChat.Core.User.
+ */
+BeeChat.Core.User = function(jid)
+{
+    if (!(this instanceof arguments.callee))
+       return new BeeChat.Core.User(jid);
+
+    /** Private members
+     *
+     */
+    var _connection = null;
+    var _attached = false;
+    var _initialized = false;
+    var _jid = null;
+    var _roster = null;
+    var _msgTemp = [];
+    var _funcs = [];
+
+    /** Constructor
+     *
+     */
+    this.init = function(jid)
+    {
+       _jid = jid;
+       _roster = new BeeChat.Core.Roster();
+    }
+
+    /** Accessors
+     *
+     */
+    this.getConnection = function()
+    {
+       return _connection;
+    }
+
+    this.getJid = function()
+    {
+       return _jid;
+    }
+
+    this.getRoster = function()
+    {
+       return _roster;
+    }
+
+    this.isAttached = function()
+    {
+       return _attached;
+    }
+
+    this.isInitialized = function()
+    {
+       return _initialized;
+    }
+
+    /** Mutators
+     *
+     */
+    this.setInitialized = function(isInitialized)
+    {
+       _initialized = isInitialized;
+    }
+
+    /** Function: addObserver
+     *  Add an observer for a specified type of event
+     *
+     *  Parameters:
+     *    (BeeChat.Events.Identifiers) eventType - The type of event to observer
+     *    (Object) pFunc - A function to call when the event will be triggered
+     */
+    this.addObserver = function(eventType, pFunc)
+    {
+       if (jQuery.inArray(pFunc, _funcs) == -1) {
+           if (!_funcs[eventType])
+               _funcs[eventType] = [];
+           _funcs[eventType].push(pFunc);
+       }
+    }
+
+    /** Function: removeObserver
+     *  Remove an observer
+     *
+     *  Parameters:
+     *    (Object) pFunc - The registered function
+     */
+    this.removeObserver = function(pFunc)
+    {
+       var index = null;
+
+       for (var key in _funcs) {
+           if (typeof _funcs[key] != 'object')
+               continue;
+           if ((index = jQuery.inArray(pFunc, _funcs[key])) != -1)
+               _funcs.splice(index, 1);
+       }
+    }
+
+    /** Function: connect
+     *  Connect the user to the BOSH service
+     *
+     *  Parameters:
+     *    (String) password - The user's password
+     *
+     */
+    this.connect = function(password)
+    {
+       debugXMPP('connect');
+       if (_connection == null)
+           _connection = new Strophe.Connection(BeeChat.BOSH_SERVICE);
+       _connection.connect(_jid, password, _onConnect);
+    }
+
+    /** Function: attach
+     *  Attach user's connection to an existing XMPP session
+     *
+     *  Parameters:
+     *    (String) sid - The SID of the existing XMPP session
+     *    (String) rid - The RID of the existing XMPP session
+     */
+    this.attach = function(sid, rid)
+    {
+       if (_connection == null) {
+           _connection = new Strophe.Connection(BeeChat.BOSH_SERVICE);
+       }
+       _connection.attach(_jid, sid, rid, _onConnect);
+       _attached = true;
+       _onConnect(Strophe.Status.CONNECTED);
+    }
+
+    /** Function: disconnect
+     *  Disconnect the user from the BOSH service
+     *
+     */
+    this.disconnect = function()
+    {
+       debugXMPP('disconnect');
+       if (_connection != null) {
+           _connection.disconnect();
+           _connection = null;
+       }
+    }
+
+    /** Function: requestSessionPause
+     *  Request a session pause to the server connection manager
+     *
+     */
+    this.requestSessionPause = function()
+    {
+       var req = $build('body', {
+               rid: _connection.rid,
+               sid: _connection.sid,
+               pause: BeeChat.INACTIVITY_PERIOD_LENGTH,
+               xmlns: Strophe.NS.HTTPBIND
+           });
+
+       _attached = false;
+       _connection.send(req.tree());
+    }
+
+    /** Function: requestRoster
+     *  Request a new roster to the server
+     *
+     */
+    this.requestRoster = function()
+    {
+       var req = $iq({from: _jid, type: BeeChat.IQ.Types.GET})
+       .c('query', {xmlns: Strophe.NS.ROSTER});
+
+       _connection.send(req.tree());
+    }
+
+    /** Function: sendInitialPresence
+     *  Send initial presence to the server in order to signal availability for communications
+     *
+     */
+    this.sendInitialPresence = function()
+    {
+       _connection.send($pres().tree());
+       _initialized = true;
+    }
+
+    /** Function: sendChatMessage
+     *  Send a chat message to the server
+     *
+     *  Parameters:
+     *    (String) addressee - The addressee of the chat message
+     *    (String) msg - The chat message
+     *
+     */
+    this.sendChatMessage = function(addressee, msg, msgtype)
+    {
+       if (msgtype == null)
+               msgtype = BeeChat.Message.Types.CHAT;
+       var req = $msg({
+               type: msgtype,
+               to: addressee,
+               from: _connection.jid
+           }).c('body').t(msg).up().c(BeeChat.Message.ChatStates.ACTIVE, {xmlns: BeeChat.NS.CHAT_STATES});
+
+       _connection.send(req.tree());
+    }
+
+    /** Function: sendChatStateMessage
+     *  Send a chat state message to the server
+     *
+     *  Parameters:
+     *    (String) addressee - The addressee of the chat state message
+     *    (BeeChat.Message.ChatsState) state - The chat state that will be send
+     *
+     */
+    this.sendChatStateMessage = function(addressee, state)
+    {
+       var req = $msg({
+               type: BeeChat.Message.Types.CHAT,
+               to: addressee,
+               from: _connection.jid
+           }).c(state, {xmlns: BeeChat.NS.CHAT_STATES});
+
+       _connection.send(req.tree());
+    }
+
+    /** Function: sendPresenceAvailabiliy
+     *  Send a detailed presence stanza to the server
+     *
+     *  Parameters:
+     *    (BeeChat.Presence.ShowElements) availability - The availability status
+     *    (String) details - Detailed status information
+     *
+     */
+    this.sendPresenceAvailability = function(availability, details)
+    {
+       var req = $pres()
+       .c(BeeChat.Presence.ChildElements.SHOW).t(availability).up()
+       .c(BeeChat.Presence.ChildElements.STATUS).t(details).up()
+       .c(BeeChat.Presence.ChildElements.PRIORITY).t('1');
+
+       _connection.send(req.tree());
+    }
+
+    /** PrivateFunction: _fire
+     *  Triggers registered funcs of registered observers for a specified type of event
+     *
+     */
+    function _fire(eventType, data, scope)
+    {
+       if (_funcs[eventType] != undefined) {
+           for (var i = 0; i < _funcs[eventType].length; i++)
+               _funcs[eventType][i].call((scope || window), data);
+       }
+    }
+    this.joinRoom = function(roomname, room_guid) {
+           var roomJid = roomname;
+           _connection['muc'].join(roomJid, BeeChat.UI.Resources.Strings.ChatMessages.SELF, false, false, '');
+           if (!(roomJid in g_beechat_rooms)) {
+                   g_beechat_rooms[roomJid] = room_guid;
+                   $.ajax({
+                       url: BeeChat.UI.addActionTokens('<?php echo $vars['url'] . "action/beechat/join_groupchat?group_guid="; ?>'+room_guid, '&'),
+                       async: true   });
+           }
+
+
+    }
+
+    this.reconnectRooms = function() {
+       $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().each(function() {
+               if (roomJid in g_beechat_rooms)
+                       delete g_beechat_rooms[roomJid];
+               var contactBareJid = $(this).attr('bareJid');
+               var isroom = ($(this).attr('isroom')=='true')?true:false;
+               if (isroom) {
+                   _connection['muc'].join(contactBareJid, BeeChat.UI.Resources.Strings.ChatMessages.SELF, false, false, '');
+               }
+       });
+    }
+
+    this.leaveRoom = function(roomJid) {
+           if (roomJid in g_beechat_rooms) {
+                       $.ajax({
+                               url: BeeChat.UI.addActionTokens('<?php echo $vars['url'] . "action/beechat/leave_groupchat?group_guid="; ?>'+g_beechat_rooms[roomJid], '&'),
+                               async: true   });
+
+           }
+           _connection['muc'].leave(roomJid, BeeChat.UI.Resources.Strings.ChatMessages.SELF, function(){});
+    }
+
+    /** PrivateFunction: _onConnect
+     *  Connection state manager
+     *
+     *  Parameters:
+     *    (Strophe.Status) status - A Strophe connection status constant
+     *
+     */
+    function _onConnect(status)
+    {
+       var msg = null;
+
+       if (status == Strophe.Status.CONNECTING) 
+{
+           msg = BeeChat.Events.Messages.ConnectionStates.CONNECTING;
+       }
+       else if (status == Strophe.Status.AUTHENTICATING) {
+           msg = BeeChat.Events.Messages.ConnectionStates.AUTHENTICATING;
+       }
+       else if (status == Strophe.Status.AUTHFAIL)
+           msg = BeeChat.Events.Messages.ConnectionStates.FAILED;
+       else if (status == Strophe.Status.CONNFAIL)
+           msg = BeeChat.Events.Messages.ConnectionStates.FAILED;
+       else if (status == Strophe.Status.DISCONNECTING)
+           msg = BeeChat.Events.Messages.ConnectionStates.DISCONNECTING;
+       else if (status == Strophe.Status.DISCONNECTED)
+           msg = BeeChat.Events.Messages.ConnectionStates.OFFLINE;
+       else if (status == Strophe.Status.CONNECTED) {
+           msg = BeeChat.Events.Messages.ConnectionStates.ONLINE;
+           _connection.addHandler(_onIQResult, null, 'iq', BeeChat.IQ.Types.RESULT, null, null);
+           _connection.addHandler(_onPresence, null, 'presence', null, null, null);
+           _connection.addHandler(_onMessageChat, null, 'message', BeeChat.Message.Types.CHAT, null, null);
+           _connection.addHandler(_onMessageChatRoom, null, 'message', BeeChat.Message.Types.GROUPCHAT, null, null);
+       }
+
+       _fire(BeeChat.Events.Identifiers.UPDATE_CONNECTION_STATE, msg);
+    }
+
+    /** PrivateFunction: _onIQResult
+     *  Manage received IQ stanza of 'result' type
+     *
+     *  Parameters:
+     *    (XMLElement) iq - The iq stanza received
+     *
+     */
+    function _onIQResult(iq)
+    {
+       _roster.updateFromIQResult(iq);
+       _fire(BeeChat.Events.Identifiers.UPDATE_ROSTER, _roster.getItems());
+
+       return true;
+    }
+
+    /** PrivateFunction: _onPresence
+     *  Manage received presence stanza
+     *
+     *  Parameters:
+     *    (XMLElement) presence - The presence stanza received
+     *
+     */
+    function _onPresence(presence)
+    {
+       var xquery = presence.getElementsByTagName("x");
+       debugXMPP('_onPresence'+xquery);
+       if (xquery.length > 0)
+       {
+           //Ignore MUC user protocol
+           for (var i = 0; i < xquery.length; i++)
+           {
+               var xmlns = xquery[i].getAttribute("xmlns");
+               if (xmlns && xmlns.match(Strophe.NS.MUC + '#user'))
+               {
+                       var contactBareJid = $(presence).attr('from').split('/')[0];
+                       var userNick = $(presence).attr('from').split('/')[1];
+                       var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid);
+                       if ($(presence).attr('type') != 'unavailable') {
+                               BeeChat.UI.ChatBoxes.updateRoster(contactBareJid, userNick, presence);
+                       }
+                       else {
+                               if (chatBoxElm.length) {
+                                       BeeChat.UI.ChatBoxes.updateRoster(contactBareJid, userNick, presence);
+                               }
+                       }
+                       return true;
+               }
+       
+               if (xmlns && xmlns.match(Strophe.NS.MUC))
+               {
+                       var contactBareJid = $(presence).attr('from').split('/')[0];
+                       var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid);
+
+                       if ($(presence).attr('type') != 'unavailable' && $(presence).attr('type') != 'error') {
+                               if (chatBoxElm.length == 0) {
+                                           BeeChat.UI.ScrollBoxes.addRoom(contactBareJid);
+                               }
+                       }
+                       return true;
+               }
+
+            }
+       }
+
+       if (Strophe.getBareJidFromJid($(presence).attr('from')).toLowerCase() != Strophe.getBareJidFromJid(_jid).toLowerCase()) {
+           _roster.updateFromPresence(presence);
+       }
+       _fire(BeeChat.Events.Identifiers.RECV_PRESENCE, _roster.getOnlineItems());
+       return true;
+    }
+
+    /** PrivateFunction: _onMessageChat
+     *  Manage received message stanza of 'chat' type
+     *
+     *  Parameters:
+     *    (XMLElement) message - The message stanza received
+     *
+     */
+    function _onMessageChatRoom(message)
+    {
+       var roomJid = $(message).attr('from').split('/');
+       
+//     BeeChat.UI.ChatBoxes.updateChatState($(message).attr('from'), message);
+       BeeChat.UI.ChatBoxes.update(roomJid[0], roomJid[1], Strophe.getText($(message).find('body')[0]), true);
+
+        return true;
+    }
+
+    function _onMessageChat(message)
+    {
+       var data = {
+           contactBareJid: Strophe.getBareJidFromJid($(message).attr('from')),
+           msg: message
+       };
+       _msgTemp.push(data);
+       //alert("message");
+       if (_initialized == true) {
+           for (var key in _msgTemp) {
+               if (typeof _msgTemp[key] != 'object')
+                   continue;
+               _fire(BeeChat.Events.Identifiers.RECV_CHAT_MESSAGE, _msgTemp[key]);
+               _msgTemp.shift();
+           }
+       }
+
+       return true;
+    }
+
+    this.init(jid);
+};
+
+
+/** Constructor: BeeChat.Core.Roster
+ *  Create a BeeChat.Core.Roster object
+ *
+ *  Parameters:
+ *    (Object) items - The roster's items in object notation
+ *
+ *  Returns:
+ *    A new BeeChat.Core.Roster.
+ */
+BeeChat.Core.Roster = function()
+{
+    if (!(this instanceof arguments.callee))
+       return new BeeChat.Core.Roster();
+
+    /** Private members
+     *
+     */
+    _items = null;
+
+
+    /** Constructor
+     *
+     */
+    this.init = function()
+    {
+       _items = (arguments.length > 0) ? arguments[0] : {};
+    }
+
+    /** Accessors
+     *
+     */
+    this.getItems = function()
+    {
+       return _items;
+    }
+
+    /** Mutators
+     *
+     */
+    this.setItems = function(items)
+    {
+       for (var key in items) {
+           _items[key] = new BeeChat.Core.RosterItem(items[key]);
+       }
+    }
+
+    this.setIcons = function(icons)
+    {
+       if (_items) {
+           for (var key in icons) {
+               if (_items[key]) {
+                   _items[key].icon_small = icons[key].small;
+                   _items[key].icon_tiny = icons[key].tiny;
+               }
+
+       /*        if (_items[key]) {
+                   _items[key].icon_small = icons[key].small;
+                   _items[key].icon_tiny = icons[key].tiny;
+               }*/
+           }
+       }
+    }
+
+    this.setStatuses = function(statuses)
+    {
+       if (_items) {
+           for (var key in statuses)  {
+               if (_items[key]) {
+                   _items[key].status = statuses[key];
+               }
+           }
+       }
+    }
+
+    /** Function: updateFromIQResult
+     *  Update the roster items from an IQ result stanza
+     *
+     *  Parameters:
+     *    (XMLElement) iq - The IQ result stanza
+     */
+    this.updateFromIQResult = function(iq)
+    {
+       $(iq).find('item').each(function() {
+               var attr = {
+                   bareJid: Strophe.getBareJidFromJid($(this).attr('jid')).toLowerCase(),
+                   name: $(this).attr('name'),
+                   subscription: $(this).attr('subscription'),
+                   groups: [],
+                   presences: {}
+               };
+
+               $(this).find('group').each(function() {
+                       attr['groups'].push($(this).text());
+                   });
+
+               if (attr['groups'].length == 0)
+                   attr['groups'].push(BeeChat.Roster.DEFAULT_GROUP);
+
+               if (!_items[attr.bareJid])
+                   _items[attr.bareJid] = new BeeChat.Core.RosterItem(attr);
+               else {
+                   _items[attr.bareJid].bareJid = attr.bareJid;
+                   _items[attr.bareJid].name = attr.name;
+                   _items[attr.bareJid].subscription = attr.subscription;
+                   _items[attr.bareJid].groups = attr.groups;
+               }
+           });
+    }
+
+    /** Function: updateFromPresence
+     *  Update the roster items from a presence stanza
+     *
+     *  Parameters:
+     *    (XMLElement) presence - The presence stanza
+     *
+     *  Returns:
+     *    (String) The bare jid of the roster item who updated his presence
+     */
+    this.updateFromPresence = function(presence)
+    {
+       var jid = $(presence).attr('from').toLowerCase();
+       var attr = {
+           bareJid: Strophe.getBareJidFromJid(jid),
+           name: null,
+           subscription: null,
+           groups: null,
+           presences: {}
+       };
+
+       attr.presences[jid] = {};
+       attr.presences[jid].type = (!$(presence).attr('type')) ? 'available' : $(presence).attr('type');
+       //alert($(presence).attr('from')+presence.toString());
+       //alert("presencetype"+attr.presences[jid].type);
+
+       if (attr.presences[jid].type == 'available') {
+           $(presence).children().each(function() {
+                   if (this.tagName == BeeChat.Presence.ChildElements.SHOW)
+                       attr.presences[jid].show = $(this).text();
+                   if (this.tagName == BeeChat.Presence.ChildElements.STATUS)
+                       attr.presences[jid].status = $(this).text();
+               });
+
+           if (!attr.presences[jid].show)
+               attr.presences[jid].show = 'chat';
+       } else {
+           attr.presences[jid].show = 'offline';
+       }
+
+       if (!_items[attr.bareJid])
+           _items[attr.bareJid] = new BeeChat.Core.RosterItem(attr);
+       else
+           _items[attr.bareJid].presences[jid] = attr.presences[jid];
+    }
+
+    /** Function: getOnlineItems
+     *
+     *
+     */
+    this.getOnlineItems = function()
+    {
+       var sortedOnlineBareJid = [];
+       var sortedOnlineItems = {};
+
+       for (var key in _items) {
+           if (typeof _items[key] != 'object')
+               continue;
+
+           var pres = _items[key].getStrongestPresence();
+
+           if (pres != null && pres.type == 'available') {
+               sortedOnlineBareJid.push(key);
+           }
+       }
+
+       if (sortedOnlineBareJid.length > 1) {
+           sortedOnlineBareJid.sort();
+           sortedOnlineBareJid.sort(statusSort);
+       }
+
+       for (var key in sortedOnlineBareJid) {
+           sortedOnlineItems[sortedOnlineBareJid[key]] = _items[sortedOnlineBareJid[key]];
+       }
+
+       return (sortedOnlineItems);
+    }
+
+    /** Function: getSizeOnlineItems
+     *  Return the number of available items
+     *
+     *  Returns:
+     *    (int) The number of available items
+     */
+    this.getSizeOnlineItems = function()
+    {
+       var n = 0;
+
+       for (var key in _items) {
+           if (typeof _items[key] != 'object')
+               continue;
+
+           var pres = _items[key].getStrongestPresence();
+
+           if (pres != null && pres.type == 'available')
+               ++n;
+       }
+       return (n);
+    }
+
+    /** Function: getItemsUsernamesAsList
+     *
+     */
+    this.getItemsUsernamesAsList = function()
+    {
+       var data = '';
+
+       for (var key in _items) {
+           if (typeof _items[key] != 'object')
+               continue;
+           data = data + Strophe.getBareJidFromJid(key) + ',';
+         //  data = data + Strophe.getNodeFromJid(key) + ',';
+       }
+
+       return (data);
+    }
+
+    /** PrivateFunction: statusSort
+     *
+     */
+    function statusSort(x, y)
+    {
+       var xPres = _items[x].getStrongestPresence();
+       var yPres = _items[y].getStrongestPresence();
+
+       if (xPres != null && yPres != null)
+           return (BeeChat.Core.Roster.Utils.comparePresences(xPres, yPres));
+       return (0);
+    }
+
+    this.init();
+};
+
+BeeChat.Core.Roster.Utils = {
+
+    /** Function: comparePresences
+     *  Compare the two presences x and y
+     *
+     *  Parameters:
+     *    (Object) xPres - The x presence in object notation
+     *    (Object) yPres - The y presence in object notation
+     *
+     *  Returns:
+     *    0 if presence are equal, 1 if x > y, -1 if y > x
+     *
+     *  Note:
+     *    Presences are tagged in the following order:
+     *      ONLINE < DND < AWAY < XA < OFFLINE
+     *
+     */
+    comparePresences: function(xPres, yPres)
+    {
+       var xRate = 0;
+       var yRate = 0;
+
+       if (xPres.type == 'unavailable')
+           xRate += BeeChat.Core.ReferenceTables.AvailabilityRates[xPres.type.toUpperCase()];
+       if (yPres.type == 'unavailable')
+           yRate += BeeChat.Core.ReferenceTables.AvailabilityRates[yPres.type.toUpperCase()];
+
+       if (xPres.show != null)
+           xRate += BeeChat.Core.ReferenceTables.AvailabilityRates[xPres.show.toUpperCase()];
+       if (yPres.show != null)
+           yRate =+ BeeChat.Core.ReferenceTables.AvailabilityRates[yPres.show.toUpperCase()];
+
+       if (xRate > yRate)
+           return (1);
+       else if (xRate == yRate)
+           return (0);
+       return (-1);
+    }
+};
+
+
+/** Constructor: BeeChat.Core.RosterItem
+ *  Create a BeeChat.Core.RosterItem object
+ *
+ *  Parameters:
+ *    (Object) attr - The RosterItem's attributes in object notation
+ *
+ *  Returns:
+ *    A new BeeChat.Core.RosterItem.
+ */
+BeeChat.Core.RosterItem = function()
+{
+    this.bareJid = (arguments.length > 0) ? arguments[0].bareJid : null;
+    this.name = (arguments.length > 0) ? arguments[0].name : null;
+    this.subscription = (arguments.length > 0) ? arguments[0].subscription : null;
+    this.groups = (arguments.length > 0) ? arguments[0].groups : null;
+    this.presences = (arguments.length > 0) ? arguments[0].presences : null;
+    this.icon_small = (arguments.length > 0) ? arguments[0].icon_small : null;
+    this.icon_tiny = (arguments.length > 0) ? arguments[0].icon_tiny : null;
+    this.status = (arguments.length > 0) ? arguments[0].status : null;
+};
+BeeChat.Core.RosterItem.prototype = {
+    /** Function: getStrongestPresence
+     *  Return the strongest presence of the RosterItem
+     *
+     */
+    getStrongestPresence: function()
+    {
+       var res = null;
+
+       for (var key in this.presences) {
+           if (typeof this.presences[key] != 'object')
+               continue;
+           if (res == null)
+               res = this.presences[key];
+           else
+               if (BeeChat.Core.Roster.Utils.comparePresences(this.presences[key], res) == -1)
+                   res = this.presences[key];
+       }
+       return (res);
+    }
+};
+
+
+/** Class: BeeChat.UI
+ *  An object container for all BeeChat UI functions
+ *
+ */
+BeeChat.UI = {
+    HAS_FOCUS: true,
+
+    Resources: {
+       Paths: {
+           ICONS: '<?php echo $vars['config']->url; ?>mod/beechat/graphics/icons/',
+           MEMBER_PROFILE: '<?php echo $vars['url']; ?>pg/profile/'
+       },
+
+       Sounds: {
+           NEW_MESSAGE: 'beechat_sounds_new_message'
+       },
+
+       /*
+       Cookies: {
+           DOMAIN: 'beechannels.com',
+           FILENAME_CONN: 'beechat_conn'
+       },
+       */
+
+       Emoticons: {
+           FILENAME_SMILE: 'emoticon_smile.png',
+           FILENAME_UNHAPPY: 'emoticon_unhappy.png',
+           FILENAME_GRIN: 'emoticon_grin.png',
+           FILENAME_EVILGRIN: 'emoticon_evilgrin.png',
+           FILENAME_SURPRISED: 'emoticon_surprised.png',
+           FILENAME_TONGUE: 'emoticon_tongue.png',
+           FILENAME_WINK: 'emoticon_wink.png'
+       },
+
+       Strings: {
+           Availability: {
+               AVAILABLE: "<?php echo elgg_echo('beechat:availability:available'); ?>",
+               CHAT: "<?php echo elgg_echo('beechat:availability:available'); ?>",
+               ONLINE: "<?php echo elgg_echo('beechat:availability:available'); ?>",
+               DND: "<?php echo elgg_echo('beechat:availability:dnd'); ?>",
+               AWAY: "<?php echo elgg_echo('beechat:availability:away'); ?>",
+               XA:"<?php echo elgg_echo('beechat:availability:xa'); ?>",
+               OFFLINE: "<?php echo elgg_echo('beechat:availability:offline'); ?>"
+           },
+
+           Contacts: {
+               BUTTON: "<?php echo elgg_echo('beechat:contacts:button'); ?>"
+           },
+
+           ChatMessages: {
+               SELF: "<?php echo $_SESSION['user']->name; ?>",
+               COMPOSING: "<?php echo elgg_echo('beechat:chat:composing'); ?>"
+           },
+
+           Box: {
+               MINIMIZE: "<?php echo elgg_echo('beechat:box:minimize'); ?>",
+               CLOSE: "<?php echo elgg_echo('beechat:box:close'); ?>",
+               SHOWHIDE: "<?php echo elgg_echo('beechat:box:showhide'); ?>"
+           }
+       },
+
+       StyleClasses: {
+           Availability: {
+               Left: {
+                   ONLINE: 'beechat_left_availability_chat',
+                   DND: 'beechat_left_availability_dnd',
+                   AWAY: 'beechat_left_availability_away',
+                   XA: 'beechat_left_availability_xa',
+                   OFFLINE: 'beechat_left_availability_offline',
+                   ROOM: 'beechat_left_availability_room'
+               },
+
+               Right: {
+                   ONLINE: 'beechat_right_availability_chat',
+                   DND: 'beechat_right_availability_dnd',
+                   AWAY: 'beechat_right_availability_away',
+                   XA: 'beechat_right_availability_xa',
+                   OFFLINE: 'beechat_right_availability_offline',
+                   ROOM: 'beechat_right_availability_room'
+               },
+
+               Control: {
+                   UP: 'beechat_availability_switcher_control_up',
+                   DOWN: 'beechat_availability_switcher_control_down'
+               }
+           },
+
+           ChatBox: {
+               MAIN: 'beechat_chatbox',
+               MAINROOM: 'beechat_chatbox_room',
+               TOP: 'beechat_chatbox_top',
+               SUBTOP: 'beechat_chatbox_subtop',
+               TOP_ICON: 'beechat_chatbox_top_icon',
+               TOP_CONTROLS: 'beechat_chatbox_top_controls',
+               CONTENT: 'beechat_chatbox_content',
+               INPUT: 'beechat_chatbox_input',
+               BOTTOM: 'beechat_chatbox_bottom',
+               CONTROL: 'beechat_chatbox_control',
+               STATE: 'beechat_chatbox_state',
+               MESSAGE: 'beechat_chatbox_message',
+               MESSAGE_SENDER: 'beechat_chatbox_message_sender',
+               MESSAGE_DATE: 'beechat_chatbox_message_date',
+               CHATROOM: 'beechat_chatbox_chatroom',
+               ROOMROSTER: 'beechat_chatbox_roomroster',
+               ROSTER_ITEM: 'beechat_chatbox_roomrosteritem'
+           },
+
+           ScrollBox: {
+               SELECTED: 'beechat_scrollbox_selected'
+           },
+
+           BOX_CONTROL: 'beechat_box_control',
+           LABEL: 'beechat_label',
+           UNREAD_COUNT: 'beechat_unread_count'
+       },
+
+       Elements: {
+           ID_DIV_BAR: 'beechat',
+           ID_DIV_BAR_CENTER: 'beechat_center',
+           ID_DIV_BAR_RIGHT: 'beechat_right',
+
+           ID_TOOLTIP_TRIGGER: 'beechat_tooltip_trigger',
+
+           ID_SPAN_CONTACTS_BUTTON: 'beechat_contacts_button',
+           ID_SPAN_CLOSE_BOX: 'beechat_box_control_close',
+
+           ID_DIV_CONTACTS: 'beechat_contacts',
+           ID_DIV_CONTACTS_CONTROLS: 'beechat_contacts_controls',
+           ID_SPAN_CONTACTS_CONTROL_MINIMIZE: 'beechat_contacts_control_minimize',
+           ID_DIV_CONTACTS_CONTENT: 'beechat_contacts_content',
+           ID_UL_CONTACTS_LIST: 'beechat_contacts_list',
+
+           ID_DIV_AVAILABILITY_SWITCHER: 'beechat_availability_switcher',
+           ID_SPAN_AVAILABILITY_SWITCHER_CONTROL: 'beechat_availability_switcher_control',
+           ID_SPAN_CURRENT_AVAILABILITY: 'beechat_current_availability',
+           ID_UL_AVAILABILITY_SWITCHER_LIST: 'beechat_availability_switcher_list',
+
+           ID_DIV_CHATBOXES: 'beechat_chatboxes',
+
+           ID_DIV_SCROLLBOXES: 'beechat_scrollboxes'
+       }
+    },
+
+
+    /** Function: initialize
+     *  Initialize the BeeChat UI
+     *
+     */
+    initialize: function(ts, token)
+    {
+       this.ts = ts;
+       this.token = token;
+       $('#' + BeeChat.UI.Resources.Elements.ID_TOOLTIP_TRIGGER).tooltip({
+               offset: [-3, 8],
+               effect: 'fade'
+           });
+
+       $('#accountlinks').find('li').filter('[class=last]').bind('click', function() {
+               if (g_beechat_user != null)
+                   g_beechat_user.disconnect();
+           });
+
+       BeeChat.UI.AvailabilitySwitcher.initialize(BeeChat.Presence.ShowElements.CHAT);
+       BeeChat.UI.ContactsList.initialize();
+       BeeChat.UI.ScrollBoxes.initialize();
+       BeeChat.UI.loadConnection();
+    },
+
+    /** Function: getUserDetails
+     *  Retrieve user details
+     *
+     *  Returns:
+     *    User details in object notation.
+     *
+     */
+    addActionTokens: function(url_string, sep)
+    {
+       if (sep == null)
+               sep = "?";
+       return url_string + sep + "__elgg_ts="+this.ts + "&__elgg_token=" + this.token;
+    },
+
+    getUserDetails: function(cb_func)
+    {
+       var json = null;
+       var self = this;
+
+       $.ajax({
+               url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_details"; ?>'),
+               async: true,
+               dataType: 'json',
+               success: function(data) {
+                       cb_func(data);
+               }
+           });
+
+       return (json);
+    },
+
+    /** Function: connect
+     *  Create the user and connect him to the BOSH service
+     *
+     *  Parameters:
+     *    (Object) conn - Running connection informations in object notation
+     */
+    connect: function()
+    {
+       var conn = (arguments.length > 0) ? arguments[0] : null;
+       var userDetails = {
+           jid: (conn != null) ? conn.jid : null,
+           password: null
+       }
+       var self = this;
+       //alert("connect");
+       if (conn == null || (conn != null && conn.attached)) {
+           BeeChat.UI.getUserDetails(function(retrievedUserDetails) {
+               userDetails.jid = retrievedUserDetails.username + '@' + BeeChat.DOMAIN + '/' + BeeChat.RESOURCE;
+               userDetails.password = retrievedUserDetails.password;
+               self.connect_end(conn, userDetails)
+           });
+       }
+       else
+               this.connect_end(conn, userDetails)
+    },
+
+    connect_end: function(conn, userDetails)
+    {
+       g_beechat_user = new BeeChat.Core.User(userDetails.jid);
+       g_beechat_user.addObserver(BeeChat.Events.Identifiers.UPDATE_CONNECTION_STATE, BeeChat.UI.updateConnectionStatus);
+       g_beechat_user.addObserver(BeeChat.Events.Identifiers.UPDATE_ROSTER, BeeChat.UI.onRosterUpdate);
+       g_beechat_user.addObserver(BeeChat.Events.Identifiers.RECV_PRESENCE, BeeChat.UI.ContactsList.update);
+       g_beechat_user.addObserver(BeeChat.Events.Identifiers.RECV_CHAT_MESSAGE, BeeChat.UI.onChatMessage);
+
+       if (conn == null || (conn != null && conn.attached))
+           g_beechat_user.connect(userDetails.password);
+       else
+           g_beechat_user.attach(conn.sid, conn.rid);
+    },
+    /** Function: disconnect
+     *  Terminate the user's XMPP session
+     *
+     */
+    disconnect: function()
+    {
+       g_beechat_user.disconnect();
+    },
+
+    /** Function: updateConnectionStatus
+     *
+     */
+    updateConnectionStatus: function(connStatusMsg)
+    {
+       BeeChat.UI.ContactsList.updateButtonText(connStatusMsg);
+       if (connStatusMsg == BeeChat.Events.Messages.ConnectionStates.ONLINE) {
+           if (!g_beechat_user.isAttached()) {
+               debugXMPP("not attached");
+               BeeChat.UI.ScrollBoxes.isOpened = true;
+               g_beechat_user.requestRoster();
+               g_beechat_user.reconnectRooms();
+               //BeeChat.UI.ContactsList.toggleDisplay();
+               $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST).show();
+               $('.' + BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT + '>textarea').removeAttr('disabled');
+               for (room_idx in g_user_rooms) {
+                       var room = g_user_rooms[room_idx];
+                       var chatBox = BeeChat.UI.ChatBoxes.getChatBoxElm(room[0]);
+                       if (chatBox.length == 0) {
+                               g_beechat_user.joinRoom(room[0], room[1])
+                       }
+               }
+
+           }
+           if (g_beechat_user.isAttached()) {
+               debugXMPP("attached");
+               BeeChat.UI.loadState();
+           }
+
+
+           $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'online');
+           BeeChat.UI.saveConnection();
+       }
+       else if (connStatusMsg == BeeChat.Events.Messages.ConnectionStates.OFFLINE) {
+           var contactsBoxElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CONTACTS);
+
+           if (!contactsBoxElm.is(':hidden'))
+               BeeChat.UI.ContactsList.toggleDisplay();
+
+           $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST).empty();
+           BeeChat.UI.AvailabilitySwitcher.initialize(BeeChat.Presence.ShowElements.CHAT);
+           BeeChat.UI.ContactsList.updateButtonText(BeeChat.UI.Resources.Strings.Contacts.BUTTON);
+           $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'offline');
+           $('.' + BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT + '>textarea').attr('disabled', 'true');
+           $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().hide();
+           $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES).find('ul').children()
+           .attr('class', BeeChat.UI.Resources.StyleClasses.LABEL + ' ' + BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[BeeChat.Presence.Types.UNAVAILABLE.toUpperCase()]);
+           g_beechat_user = null;
+           BeeChat.UI.saveConnection();
+       }
+    },
+
+    /** Function: saveConnection
+     *  Save connection informations (non sensible data) in $_SESSION.
+     *
+     */
+    saveConnection: function()
+    {
+       var conn = null;
+
+       if (g_beechat_user != null) {
+           var userConn = g_beechat_user.getConnection();
+
+           conn = {
+               'jid': userConn.jid,
+               'sid': userConn.sid,
+               'rid': userConn.rid,
+               'attached': g_beechat_user.isAttached()
+           };
+       }
+       var self = this;
+
+       $.ajax({
+               type: 'POST',
+               async: false,
+               url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/save_state"; ?>'),
+               data: { beechat_conn: JSON.stringify(conn) }
+           });
+
+       /*
+       $.cookie(BeeChat.UI.Resources.Cookies.FILENAME_CONN, null);
+       $.cookie(BeeChat.UI.Resources.Cookies.FILENAME_CONN, JSON.stringify(conn), {path: '/', domain: BeeChat.UI.Resources.Cookies.DOMAIN});
+       */
+    },
+
+    /** Function: loadConnection
+     *  Check if a connection already exists. In the case that a connection exists,
+     *  this function triggers the connection process.
+     *
+     */
+    loadConnection: function()
+    {
+       var self = this;
+       $.ajax({
+               type: 'GET',
+               async: false,
+               cache: false,
+               dataType: 'json',
+               url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_connection"; ?>'),
+               success: function(conn) {
+                   if (conn != null) {
+                       if (conn.attached)
+                           BeeChat.UI.connect();
+                       else
+                           BeeChat.UI.connect(conn);
+                       }
+               },
+               error: function() {
+                   BeeChat.UI.connect();
+               }
+           });
+
+       /*
+       var conn = JSON.parse($.cookie(BeeChat.UI.Resources.Cookies.FILENAME_CONN));
+
+       if (conn != null) {
+           if (conn.attached)
+               BeeChat.UI.connect();
+           else
+               BeeChat.UI.connect(conn);
+       } else
+           BeeChat.UI.connect();
+       */
+    },
+
+    /** Function: saveState
+     *  Save app state in $_SESSION
+     *
+     */
+    saveState: function()
+    {
+       var self = this;
+       var currentAvailabilityClass = $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CURRENT_AVAILABILITY).attr('class');
+       var currentAvailability = currentAvailabilityClass.substr(currentAvailabilityClass.lastIndexOf('_') + 1);
+
+       var data = {
+           availability: currentAvailability,
+           contacts: g_beechat_roster_items,
+           chats: {},
+           contacts_list: {
+               minimized: $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CONTACTS).is(':hidden')
+           }
+       };
+
+       $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().each(function() {
+               var contactBareJid = $(this).attr('bareJid');
+               //var contactBareJid = $(this).data('bareJid');
+               var isroom = ($(this).attr('isroom') == 'true');
+               if (isroom)
+                       var roster = $(this).find('div').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.ROOMROSTER + ']');
+               data.chats[contactBareJid] = {
+                   'html_content': escape($(this).children().filter('[bareJid=' + contactBareJid + ']').html()),
+                   'roster_content': isroom?escape(roster.html()):'',
+                   'isroom': $(this).attr('isroom'),
+                   'group_guid': (contactBareJid in g_beechat_rooms)?g_beechat_rooms[contactBareJid]:0,
+                   'minimized': $(this).is(':hidden'),
+                   'unread': BeeChat.UI.UnreadCountBox.getElm(contactBareJid).text()
+               };
+           });
+
+       $.ajax({
+               type: 'POST',
+               async: false,
+               url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/save_state"; ?>'),
+               data: { beechat_state: JSON.stringify(data) }
+           });
+    },
+
+    /** Function: loadState
+     *  Load app state from $_SESSION
+     *
+     */
+    loadState: function()
+    {
+       var self = this;
+       $.ajax({
+               type: 'GET',
+               async: true,
+               cache: false,
+               dataType: 'json',
+               url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_state"; ?>'),
+               error: function() {
+                       alert('error getting state');
+               },
+               success: function(json) {
+                   debugXMPP('loadState');
+                   BeeChat.UI.AvailabilitySwitcher.initialize(json.availability);
+
+                   if (!json.contacts_list.minimized) {
+                       $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CONTACTS).show();
+                       BeeChat.UI.ContactsList.showedStyle();
+                   }
+
+                   g_beechat_user.getRoster().setItems(json.contacts);
+                    self.loadRosterItemsIcons();
+                    self.loadRosterItemsStatuses();
+                   g_beechat_roster_items = g_beechat_user.getRoster().getItems();
+                   BeeChat.UI.ContactsList.update(g_beechat_user.getRoster().getOnlineItems())
+                   g_beechat_user.setInitialized(true);
+
+                   var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES);
+                   var scrollBoxElmToShow = null;
+
+                   // Load save chats
+                   for (var key in json.chats) {
+                       var isroom = (json.chats[key].isroom == 'true');
+                       if (isroom)
+                               BeeChat.UI.ScrollBoxes.addRoom(key);
+                       else
+                               BeeChat.UI.ScrollBoxes.add(key);
+
+                       var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(key);
+                       chatBoxElm.hide();
+
+                       if (!json.chats[key].minimized) {
+                           scrollBoxElmToShow = BeeChat.UI.ScrollBoxes.getScrollBoxElm(key);
+                       }
+
+                       var chatBoxContentElm = chatBoxElm.children().filter('[bareJid=' + key + ']');
+
+                       chatBoxContentElm.append(unescape(json.chats[key].html_content));
+                       chatBoxContentElm.attr({scrollTop: chatBoxContentElm.attr('scrollHeight')});
+                       if (isroom) {
+                               g_beechat_rooms[key] = json.chats[key].room_guid;
+                               var rosterElm = chatBoxElm.find('div').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.ROOMROSTER + ']');
+                               rosterElm.append(unescape(json.chats[key].roster_content));
+                       }
+
+                       BeeChat.UI.UnreadCountBox.update(key, json.chats[key].unread);
+                   }
+                   if (scrollBoxElmToShow != null)
+                       scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(scrollBoxElmToShow));
+                   else
+                       scrollBoxesElm.trigger('goto', 0);
+
+                  // g_beechat_user.sendPresenceAvailability(json.availability, '');
+                   BeeChat.UI.ScrollBoxes.isInitialized = true;
+                   BeeChat.UI.ScrollBoxes.isOpened = true;
+
+                         for (var key in json.chats) {
+                                       if (json.chats[key].minimized) {
+                                               BeeChat.UI.ChatBoxes.getChatBoxElm(key).hide();
+                                               BeeChat.UI.ScrollBoxes.unselect(key);
+                                       }
+                                       else {
+                                               BeeChat.UI.ChatBoxes.getChatBoxElm(key).show();
+                                               BeeChat.UI.ScrollBoxes.select(key);
+                                       }
+                               }
+                   for (room_idx in g_user_rooms) {
+                       var room = g_user_rooms[room_idx];
+                       var chatBox = BeeChat.UI.ChatBoxes.getChatBoxElm(room[0]);
+                       if (chatBox.length == 0) {
+                               g_beechat_user.joinRoom(room[0], room[1])
+                       }
+                   }
+
+               },
+               error: function() {
+                   BeeChat.UI.ContactsList.initialize();
+               }
+           });
+    },
+
+    /** Function: loadRosterItemsIcons
+     *
+     */
+    loadRosterItemsIcons: function()
+    {
+       var data = g_beechat_user.getRoster().getItemsUsernamesAsList();
+       var self = this;
+
+       $.ajax({
+               type: 'POST',
+               url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_icons"; ?>'),
+               async: true,
+               cache: false,
+               data: {'beechat_roster_items_usernames': data},
+               dataType: 'json',
+               success: function(json) {
+                   g_beechat_user.getRoster().setIcons(json);
+                   g_beechat_roster_items = g_beechat_user.getRoster().getItems();
+
+                   BeeChat.UI.ContactsList.update(g_beechat_user.getRoster().getOnlineItems())
+               }
+           });
+    },
+
+    /** Function: loadRosterItemsStatuses
+     *
+     */
+    loadRosterItemsStatuses: function()
+    {
+       var data = g_beechat_user.getRoster().getItemsUsernamesAsList();
+//alert(data)
+       var self = this;
+       $.ajax({
+               type: 'POST',
+               url: self.addActionTokens('<?php echo $vars['url'] . "action/beechat/get_statuses"; ?>'),
+               async: true,
+               cache: false,
+               data: {'beechat_roster_items_usernames': data},
+               dataType: 'json',
+               success: function(json) {
+                   g_beechat_user.getRoster().setStatuses(json);
+                   g_beechat_roster_items = g_beechat_user.getRoster().getItems();
+                   BeeChat.UI.ContactsList.update(g_beechat_user.getRoster().getOnlineItems())
+               }
+           });
+    },
+
+    /** Function: onRosterUpdate
+     *  Notified by core on a roster update
+     *
+     */
+    onRosterUpdate: function(rosterItems)
+    {
+       g_beechat_roster_items = rosterItems;
+               //alert("get roster");
+       if (!g_beechat_user.isInitialized()) {
+               //alert("load roster" + rosterItems.length);
+           BeeChat.UI.loadRosterItemsStatuses();
+           BeeChat.UI.loadRosterItemsIcons();
+           g_beechat_user.sendInitialPresence();
+       }
+    },
+
+    /** Function: onChatMessage
+     *
+     */
+    onChatMessage: function(data)
+    {
+       if ($(data.msg).find('body').length == 0) {
+           BeeChat.UI.ChatBoxes.updateChatState(data.contactBareJid, data.msg);
+       }
+       else {
+           BeeChat.UI.ChatBoxes.update(data.contactBareJid, BeeChat.UI.Utils.getContactName(data.contactBareJid), Strophe.getText($(data.msg).find('body')[0]));
+       }
+    }
+};
+
+
+/** Class: BeeChat.UI.Resources.ReferenceTables
+ *  An object container for all reference tables
+ *
+ */
+BeeChat.UI.Resources.ReferenceTables = {
+    Styles: {
+       Availability: {
+           Left: {
+               AVAILABLE: BeeChat.UI.Resources.StyleClasses.Availability.Left.ONLINE,
+               CHAT: BeeChat.UI.Resources.StyleClasses.Availability.Left.ONLINE,
+               DND: BeeChat.UI.Resources.StyleClasses.Availability.Left.DND,
+               AWAY: BeeChat.UI.Resources.StyleClasses.Availability.Left.AWAY,
+               XA: BeeChat.UI.Resources.StyleClasses.Availability.Left.XA,
+               UNAVAILABLE: BeeChat.UI.Resources.StyleClasses.Availability.Left.OFFLINE,
+               OFFLINE: BeeChat.UI.Resources.StyleClasses.Availability.Left.OFFLINE,
+               ROOM: BeeChat.UI.Resources.StyleClasses.Availability.Left.ROOM
+           },
+
+           Right: {
+               AVAILABLE: BeeChat.UI.Resources.StyleClasses.Availability.Right.ONLINE,
+               CHAT: BeeChat.UI.Resources.StyleClasses.Availability.Right.ONLINE,
+               DND: BeeChat.UI.Resources.StyleClasses.Availability.Right.DND,
+               AWAY: BeeChat.UI.Resources.StyleClasses.Availability.Right.AWAY,
+               XA: BeeChat.UI.Resources.StyleClasses.Availability.Right.XA,
+               UNAVAILABLE: BeeChat.UI.Resources.StyleClasses.Availability.Right.OFFLINE,
+               OFFLINE: BeeChat.UI.Resources.StyleClasses.Availability.Right.OFFLINE,
+               ROOM: BeeChat.UI.Resources.StyleClasses.Availability.Right.ROOM
+           }
+       }
+    }
+};
+
+
+/** Class: BeeChat.UI.ContactsList
+ *  An object container for all ContactsList functions
+ *
+ */
+BeeChat.UI.ContactsList = {
+    /** Function: initialize
+     *  Initialize the contacts list by binding elements
+     *
+     */
+    initialize: function()
+    {
+               $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_CONTROL_MINIMIZE).unbind('click').bind('click', BeeChat.UI.ContactsList.toggleDisplay);
+       $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).unbind('click').bind('click', function() {
+               if (g_beechat_user == null)
+                   BeeChat.UI.connect();
+               else
+                   BeeChat.UI.ContactsList.toggleDisplay();
+           });
+    },
+
+    /** Function: update
+     *  Update the contacts list content
+     *
+     *  Parameters:
+     *    (Object)(BeeChat.Core.RosterItem) onlineRosterItems - A hash of RosterItems in object notation
+     *
+     */
+    update: function(onlineRosterItems)
+    {
+       var contactsListElm = $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST);
+
+       contactsListElm.children().each(function() {
+               var contactBareJid = $(this).attr('bareJid');
+
+               if (g_beechat_roster_items != null) {
+                   if ($.inArray(contactBareJid, onlineRosterItems) == -1) {
+                       BeeChat.UI.ScrollBoxes.updateAvailability(contactBareJid);
+                       $(this).remove();
+                   }
+               }
+           });
+
+       for (var key in onlineRosterItems) {
+           if (typeof onlineRosterItems[key] != 'object')
+               continue;
+
+           var contactElm = contactsListElm.find('li').filter('[bareJid=' + key + ']');
+
+           if (contactElm.length == 0) {
+               contactElm = $('<li></li>')
+                   .attr('bareJid', key)
+                   .append($('<img />')
+                           .attr('src', g_beechat_roster_items[key].icon_tiny))
+                   .append(BeeChat.UI.Utils.getTruncatedContactName(key, 25))
+                   .appendTo(contactsListElm)
+                   .bind('click', function() {
+                                       if (!BeeChat.UI.ChatBoxes.getChatBoxElm($(this).attr('bareJid')).is(':visible')) {
+                                               BeeChat.UI.ContactsList.toggleDisplay();
+                                       }
+
+                           BeeChat.UI.ScrollBoxes.add($(this).attr('bareJid'), false, true);
+                       });
+           }
+
+           BeeChat.UI.ContactsList.updateContactAvailability(contactElm, key);
+       }
+
+       BeeChat.UI.ContactsList.updateButtonText(BeeChat.UI.Resources.Strings.Contacts.BUTTON + ' (<strong>' + g_beechat_user.getRoster().getSizeOnlineItems() + '</strong>)');
+    },
+
+    /** Function: updateContactAvailability
+     *
+     */
+    updateContactAvailability: function(contactElm, contactBareJid)
+    {
+       // Update from contactsList
+       contactElm.attr('class', BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Right[g_beechat_roster_items[contactBareJid].getStrongestPresence().show.toUpperCase()]);
+
+       // Update from scrollBoxes
+       BeeChat.UI.ScrollBoxes.updateAvailability(contactBareJid);
+    },
+
+    /** Function: updateButtonText
+     *
+     *
+     */
+    updateButtonText: function(msg)
+    {
+       $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).html(msg);
+    },
+
+    /** Function: toggleDisplay
+     *  Toggle the contacts box display (hide | show)
+     *
+     */
+    toggleDisplay: function()
+    {
+       var contactsBoxElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CONTACTS);
+
+       contactsBoxElm.toggle();
+       if (contactsBoxElm.is(':hidden')) {
+           BeeChat.UI.ContactsList.hiddenStyle();
+       } else {
+           BeeChat.UI.ContactsList.showedStyle();
+       }
+       $('#' + BeeChat.UI.Resources.Elements.ID_UL_AVAILABILITY_SWITCHER_LIST).hide();
+    },
+
+    /** Function: hiddenStyle
+     *
+     */
+    hiddenStyle: function()
+    {
+       $('#' + BeeChat.UI.Resources.Elements.ID_DIV_BAR_RIGHT).css({'border-left': '1px solid #BBBBBB', 'border-right': '1px solid #BBBBBB', 'background-color': '#DDDDDD'});
+    },
+
+    /** Function: showedStyle
+     *
+     */
+    showedStyle: function()
+    {
+       $('#' + BeeChat.UI.Resources.Elements.ID_DIV_BAR_RIGHT).css({'border-left': '1px solid #666666', 'border-right': '1px solid #666666', 'background-color': 'white'});
+    }
+};
+
+
+/** Class: BeeChat.UI.AvailabilitySwitcher
+ *  An object container for all AvailabilitySwitcher functions
+ *
+ */
+BeeChat.UI.AvailabilitySwitcher = {
+    /** Function: initialize
+     *  Initialize the availability switcher by setting the current user's availability
+     *  and binding actions
+     *
+     */
+    initialize: function(availability)
+    {
+               $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CURRENT_AVAILABILITY).unbind('click').bind('click', BeeChat.UI.AvailabilitySwitcher.toggleListDisplay);
+               
+               $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_AVAILABILITY_SWITCHER_CONTROL).unbind('click').bind('click', BeeChat.UI.AvailabilitySwitcher.toggleListDisplay);
+               
+               $('#' + BeeChat.UI.Resources.Elements.ID_UL_AVAILABILITY_SWITCHER_LIST).find('li').each(function() {
+               $(this).unbind('click').bind('click', function() {
+                       var availabilityClass = $(this).attr('class');
+                       var availability = availabilityClass.substr(availabilityClass.lastIndexOf('_') + 1);
+
+                       if (availability == 'offline')
+                           BeeChat.UI.disconnect();
+                       else {
+                           g_beechat_user.sendPresenceAvailability(availability, '');
+                           BeeChat.UI.AvailabilitySwitcher.update(availability);
+                           $('#' + BeeChat.UI.Resources.Elements.ID_UL_AVAILABILITY_SWITCHER_LIST).hide('slow');
+                           $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST).show('slow');
+                       }
+                   });
+           });
+       BeeChat.UI.AvailabilitySwitcher.update(availability);
+    },
+
+    /** Function: update
+     *  Update the current user's availability
+     *
+     *  Parameters:
+     *    (BeeChat.Presence.ShowElements) availability - The current user's availability
+     */
+    update: function(availability)
+    {
+       var upperCasedAvailability = availability.toUpperCase();
+
+       $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CURRENT_AVAILABILITY)
+       .attr('class', BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[upperCasedAvailability])
+       .text(BeeChat.UI.Resources.Strings.Availability[upperCasedAvailability]);
+
+       if (availability == 'chat')
+           $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'online');
+       else if (availability == 'xa' || availability == 'away')
+           $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'away');
+       else if (availability == 'dnd')
+           $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_CONTACTS_BUTTON).attr('class', 'dnd');
+    },
+
+    /** Function: switchControlClass
+     *
+     */
+    switchControlClass: function()
+    {
+       var switcherControlElm = $('#' + BeeChat.UI.Resources.Elements.ID_SPAN_AVAILABILITY_SWITCHER_CONTROL);
+
+       if (switcherControlElm.attr('class') == BeeChat.UI.Resources.StyleClasses.Availability.Control.UP)
+           switcherControlElm.attr('class', BeeChat.UI.Resources.StyleClasses.Availability.Control.DOWN);
+       else
+           switcherControlElm.attr('class', BeeChat.UI.Resources.StyleClasses.Availability.Control.UP);
+    },
+
+    /** Function: toggleListDisplay
+     *
+     */
+    toggleListDisplay: function()
+    {
+               BeeChat.UI.AvailabilitySwitcher.switchControlClass();
+               $('#' + BeeChat.UI.Resources.Elements.ID_UL_CONTACTS_LIST).toggle('slow');
+               $('#' + BeeChat.UI.Resources.Elements.ID_UL_AVAILABILITY_SWITCHER_LIST).toggle('slow');
+    }
+};
+
+
+/** Class: BeeChat.UI.ScrollBoxes
+ *  An object container for all ScrollBoxes related functions
+ *
+ */
+BeeChat.UI.ScrollBoxes = {
+    isInitialized: false,
+    isOpened: false,
+
+    /** Function: initialize
+     *
+     */
+    initialize: function() {
+       var $prev = $('#beechat_center_prev'),
+       $next = $('#beechat_center_next');
+
+       $('#' + BeeChat.UI.Resources.Elements.ID_DIV_BAR_CENTER).serialScroll({
+                   target: '#beechat_scrollboxes',
+                   items: 'li',
+                   prev: '#beechat_center_prev',
+                   next: '#beechat_center_next',
+                   axys: 'x',
+                   start: 2,
+                   step: -1,
+                   interval: 0,
+                   duration: 0,
+                   cycle: false,
+                   force: true,
+                   jump: true,
+                   lock: true,
+                   lazy: true,
+                   constant: true,
+
+                   onBefore: function(e, elem, $pane, $items, pos) {
+                     $next.add($prev).hide();
+                     $prev.add($next).hide();
+                     if (pos != 0) {
+                         $next.show();
+                     }
+                     if (pos != $items.length - 1)
+                         $prev.show();
+                   },
+
+                   onAfter: function(elem) {
+                       BeeChat.UI.ChatBoxes.takeStand($(elem).attr('bareJid'));
+                       BeeChat.UI.ScrollBoxes.isInitialized = true;
+                   }
+           });
+    },
+
+    /** Function: add
+     *  Add a scrollbox to the scrollboxes bar
+     *
+     */
+    addRoom: function(contactBareJid)
+    {
+       debugXMPP('addRoom' + contactBareJid);
+        BeeChat.UI.ScrollBoxes.add(contactBareJid, true);
+       var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid);
+       scrollBoxElm.attr('class', BeeChat.UI.Resources.StyleClasses.Availability.Left.ROOM);
+    },
+
+    add: function(contactBareJid, isroom)
+    {
+       var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES);
+       var scrollBoxElm = scrollBoxesElm.find('ul').children().filter('[bareJid=' + contactBareJid + ']');
+
+       if (scrollBoxElm.length == 0) {
+           var availClass = null;
+            var pres = null;
+            if (g_beechat_roster_items != undefined)
+               pres = g_beechat_roster_items[contactBareJid] != null ? g_beechat_roster_items[contactBareJid].getStrongestPresence() : null;
+
+           if (pres != null)
+               availClass = BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[pres.show.toUpperCase()];
+           else
+               availClass = BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[BeeChat.Presence.Types.UNAVAILABLE.toUpperCase()];
+
+           scrollBoxElm = $('<li></li>')
+               .attr('class', BeeChat.UI.Resources.StyleClasses.LABEL + ' ' + availClass)
+               .attr('bareJid', contactBareJid)
+               .attr('isroom', isroom?'true':'false')
+               .attr('title', BeeChat.UI.Resources.Strings.Box.SHOWHIDE)
+               .text(BeeChat.UI.Utils.getTruncatedContactName(contactBareJid, 11))
+               .append($('<span></span>')
+                       .attr('class', BeeChat.UI.Resources.StyleClasses.BOX_CONTROL)
+                       .attr('id', BeeChat.UI.Resources.Elements.ID_SPAN_CLOSE_BOX)
+                       .text('X')
+                       .attr('title', BeeChat.UI.Resources.Strings.Box.CLOSE)
+                       .bind('click', function() {
+                               if (isroom)
+                                       g_beechat_user.leaveRoom(contactBareJid);
+                               var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES);
+
+                               BeeChat.UI.ChatBoxes.remove($(this).parent().attr('bareJid'));
+                               scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(BeeChat.UI.ScrollBoxes.getSelectedScrollBoxElm()));
+                           }));
+
+           scrollBoxesElm.find('ul').append(scrollBoxElm);
+           BeeChat.UI.ChatBoxes.add(contactBareJid, isroom);
+           if (arguments.length == 3 && arguments[2])
+               scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(scrollBoxElm));
+           if (!isroom) {
+                   BeeChat.UI.loadRosterItemsStatuses();
+                   BeeChat.UI.loadRosterItemsIcons();
+           }
+       } else {
+           scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(scrollBoxElm));
+       }
+    },
+
+    /** Function: remove
+     *
+     */
+    remove: function(contactBareJid)
+    {
+       BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid).remove();
+    },
+
+    /** Function: unselect
+     *
+     */
+    unselect: function(contactBareJid)
+    {
+       var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid);
+       scrollBoxElm.attr('class', (scrollBoxElm.attr('class')).replace(/beechat_scrollbox_selected/, ''));
+    },
+
+    /** Function: select
+     *
+     */
+    select: function(contactBareJid)
+    {
+       var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid);
+       var scrollBoxElmClasses = scrollBoxElm.attr('class');
+
+       if (scrollBoxElmClasses.search(/beechat_scrollbox_selected/) == -1)
+           scrollBoxElm.attr('class', scrollBoxElmClasses + ' ' + BeeChat.UI.Resources.StyleClasses.ScrollBox.SELECTED);
+    },
+
+    /** Function: updateAvailability
+     *
+     */
+    updateAvailability: function(contactBareJid)
+    {
+       var pres = g_beechat_roster_items[contactBareJid].getStrongestPresence();
+       var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid);
+       var scrollBoxElmClasses = scrollBoxElm.attr('class');
+       var updatedAvailability = null;
+
+       if (pres != null)
+           updatedAvailability = BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[pres.show.toUpperCase()];
+       else
+           updatedAvailability = BeeChat.UI.Resources.ReferenceTables.Styles.Availability.Left[BeeChat.Presence.Types.UNAVAILABLE.toUpperCase()];
+
+       if (scrollBoxElmClasses == undefined || scrollBoxElmClasses.search(/(beechat_left_availability_)/g) == -1) {
+           scrollBoxElm.attr('class', BeeChat.UI.Resources.StyleClasses.LABEL + ' ' + updatedAvailability);
+       } else {
+           updatedAvailability = updatedAvailability.replace(/(beechat_left_availability)/g, '');
+
+           scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_chat)/g, updatedAvailability);
+           scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_dnd)/g, updatedAvailability);
+           scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_away)/g, updatedAvailability);
+           scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_xa)/g, updatedAvailability);
+           scrollBoxElmClasses = scrollBoxElmClasses.replace(/(_offline)/g, updatedAvailability);
+
+           scrollBoxElm.attr('class', scrollBoxElmClasses);
+       }
+    },
+
+    /** Function: getSelectedScrollBoxElm
+     *
+     */
+    getSelectedScrollBoxElm: function(contactBareJid)
+    {
+       var elm = undefined;
+
+       $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES).find('ul').children().each(function() {
+               if ($(this).attr('class').search(/beechat_scrollbox_selected/) != -1)
+                   elm = $(this);
+           });
+
+       return (elm);
+    },
+
+    /** Function: getScrollBoxElm
+     *
+     */
+    getScrollBoxElm: function(contactBareJid)
+    {
+       return $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES).find('ul').children().filter('[bareJid=' + contactBareJid + ']');
+    }
+};
+
+
+/** Class: BeeChat.UI.ChatBoxes
+ *  An object container for all ChatBoxes related functions
+ *
+ */
+BeeChat.UI.ChatBoxes = {
+    dateLastComposing: {},
+    lastTimedPauses: {},
+
+    /** Function: add
+     *
+     */
+    add: function(contactBareJid, isroom)
+    {
+       var chatBoxes = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES);
+
+       if ($(chatBoxes).children().filter('[bareJid=' + contactBareJid + ']').length == 0) {
+           var chatBox = $('<div></div>')
+               .attr('class', isroom ? BeeChat.UI.Resources.StyleClasses.ChatBox.MAIN : BeeChat.UI.Resources.StyleClasses.ChatBox.MAIN)
+               .attr('bareJid', contactBareJid)
+               .attr('isroom', isroom ? 'true' : 'false')
+               .hide();
+
+           var chatBoxTop = $('<div></div>')
+               .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.TOP);
+           if (!isroom)
+               chatBoxTop.append($('<a></a>')
+                       .attr('href', BeeChat.UI.Resources.Paths.MEMBER_PROFILE + Strophe.getNodeFromJid(contactBareJid))
+                       .append($('<img />')
+                               .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.TOP_ICON)
+                               .attr('src', (g_beechat_roster_items != null && g_beechat_roster_items[contactBareJid] != undefined)?g_beechat_roster_items[contactBareJid].icon_small:'')))
+           chatBoxTop.append($('<span></span>')
+                       .attr('class', BeeChat.UI.Resources.StyleClasses.LABEL)
+                       .html(isroom?BeeChat.UI.Utils.getTruncatedContactName(contactBareJid).split('@')[0]:'<a href="' + BeeChat.UI.Resources.Paths.MEMBER_PROFILE + Strophe.getNodeFromJid(contactBareJid) + '">' + BeeChat.UI.Utils.getTruncatedContactName(contactBareJid) + '</a>'))
+               .append($('<div></div>')
+                       .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.TOP_CONTROLS)
+                       .append($('<span></span>')
+                               .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.CONTROL)
+                               .attr('id', BeeChat.UI.Resources.Elements.ID_SPAN_CLOSE_BOX)
+                               .text('X')
+                               .attr('title', BeeChat.UI.Resources.Strings.Box.CLOSE)
+                               .bind('click', function() {
+                                       if (isroom)
+                                               g_beechat_user.leaveRoom(contactBareJid);
+                                       BeeChat.UI.ChatBoxes.remove($(this).parent().parent().parent().attr('bareJid'));
+                                   }))
+                       .append($('<span></span>')
+                               .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.CONTROL)
+                               .attr('id', BeeChat.UI.Resources.Elements.ID_SPAN_CLOSE_BOX)
+                               .text('_')
+                               .attr('title', BeeChat.UI.Resources.Strings.Box.MINIMIZE)
+                               .css({'font-size': '1.6em', 'position': 'relative', 'line-height': '4px'})
+                               .bind('click', function() {
+                                       BeeChat.UI.ScrollBoxes.unselect($(this).parent().parent().parent().attr('bareJid'));
+                                       $(this).parent().parent().parent().fadeOut('slow');
+                                   })));
+
+           var chatBoxSubTop = $('<div></div>')
+               .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.SUBTOP)
+               .append(BeeChat.UI.Utils.getTruncatedContactStatus((g_beechat_roster_items != null && g_beechat_roster_items[contactBareJid] != undefined && g_beechat_roster_items[contactBareJid].status != undefined) ? g_beechat_roster_items[contactBareJid].status : ''));
+
+           var chatBoxContent = $('<div></div>')
+               .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.CONTENT)
+               .attr('bareJid', contactBareJid);
+
+           var chatBoxInput = $('<div></div>')
+               .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT)
+               .append($('<textarea></textarea>')
+                       .attr('bareJid', contactBareJid)
+                       .bind('keypress', isroom?BeeChat.UI.ChatBoxes.onRoomTypingMessage:BeeChat.UI.ChatBoxes.onTypingMessage)
+                       .bind('keyup', function(e) {
+                               if ((e.keyCode ? e.keyCode : e.which) == 13)
+                                   $(this).val('');
+                           }));
+
+           var chatBoxBottom = $('<div></div>')
+               .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.BOTTOM)
+               .append($('<span></span>')
+                       .append($('<span></span>')));
+           if (isroom) {
+               //var chatBoxBox = $('<div></div>')
+               //      .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.CHATROOM)
+               var chatBoxRoster = $('<div></div>')
+                       .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.ROOMROSTER)
+               //chatBoxBox.append(chatBoxTop).append(chatBoxSubTop).append(chatBoxContent).append(chatBoxInput).append(chatBoxBottom)
+               //chatBox.append(chatBoxRoster).append(chatBoxBox).appendTo(chatBoxes);
+               chatBox.append(chatBoxTop).append(chatBoxSubTop).append(chatBoxContent).append(chatBoxInput).append(chatBoxBottom).append(chatBoxRoster).appendTo(chatBoxes);
+           }
+           else
+               chatBox.append(chatBoxTop).append(chatBoxSubTop).append(chatBoxContent).append(chatBoxInput).append(chatBoxBottom).appendTo(chatBoxes);
+       }
+    },
+
+    /** Function: takeStand
+     *
+     */
+    takeStand: function(contactBareJid)
+    {
+       var chatBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children();
+       var chatBoxElm = chatBoxesElm.filter('[bareJid=' + contactBareJid + ']');
+       var chatBoxContentElm = chatBoxElm.children().filter('[bareJid=' + contactBareJid + ']');
+       var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES);
+       var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid);
+
+       if (!chatBoxElm.is(':hidden')) {
+           BeeChat.UI.ScrollBoxes.unselect(contactBareJid);
+           chatBoxElm.hide();
+       } else {
+           // Hide all other chatboxes
+           $.each(chatBoxesElm.filter('[bareJid!=' + contactBareJid + ']'), function() {
+                   BeeChat.UI.ScrollBoxes.unselect($(this).attr('bareJid'));
+                   $(this).hide();
+               });
+           // Add selected scrollbox style
+           BeeChat.UI.ScrollBoxes.select(contactBareJid);
+           // Remove UnreadCountBox
+           BeeChat.UI.UnreadCountBox.remove(contactBareJid);
+           // Position the chatbox
+           var pos = scrollBoxElm.position().left - (chatBoxElm.width() - scrollBoxElm.width()) + 24;
+           chatBoxElm.css({'left': pos});
+           if (!BeeChat.UI.ScrollBoxes.isOpened)
+                       return;
+           chatBoxElm.show().css({'left': pos});
+           // Scroll down the content of the chatbox
+           chatBoxContentElm.attr({scrollTop: chatBoxContentElm.attr('scrollHeight')});
+           // Focus textarea
+           chatBoxElm.children().filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT + ']').find('textarea').focus();
+       }
+    },
+
+    /** Function: onTypingMessage
+     *
+     */
+    onRoomTypingMessage: function(e) {
+        BeeChat.UI.ChatBoxes._onTypingMessage(e, true, this);
+    },
+
+    onTypingMessage: function(e) {
+        BeeChat.UI.ChatBoxes._onTypingMessage(e, false, this);
+    },
+
+    _onTypingMessage: function(e, isroom, self)
+    {
+       var keyCode = (e.keyCode) ? e.keyCode : e.which;
+       var contactBareJid = $(self).attr('bareJid');
+
+       var msgtype = BeeChat.Message.Types.CHAT;
+       if (isroom)
+               msgtype = BeeChat.Message.Types.GROUPCHAT;
+
+       if (keyCode == 13 && $(self).val() != '') {
+           g_beechat_user.sendChatMessage(contactBareJid, jQuery.trim($(self).val()), msgtype);
+           if (!isroom)
+               BeeChat.UI.ChatBoxes.update(contactBareJid, BeeChat.UI.Utils.truncateString(BeeChat.UI.Resources.Strings.ChatMessages.SELF, 24), $(self).val(), isroom);
+           clearTimeout(BeeChat.UI.ChatBoxes.lastTimedPauses[contactBareJid]);
+           BeeChat.UI.ChatBoxes.lastTimedPauses[contactBareJid] = null;
+       } else {
+           var nowTime = new Date().getTime();
+
+           if (BeeChat.UI.ChatBoxes.dateLastComposing[contactBareJid] == null || BeeChat.UI.ChatBoxes.dateLastComposing[contactBareJid] + 2000 < nowTime) {
+               BeeChat.UI.ChatBoxes.dateLastComposing[contactBareJid] = nowTime;
+               g_beechat_user.sendChatStateMessage(contactBareJid, BeeChat.Message.ChatStates.COMPOSING);
+           }
+
+           clearTimeout(BeeChat.UI.ChatBoxes.lastTimedPauses[contactBareJid]);
+           BeeChat.UI.ChatBoxes.lastTimedPauses[contactBareJid] = setTimeout('g_beechat_user.sendChatStateMessage(\'' + contactBareJid + '\', BeeChat.Message.ChatStates.PAUSED)', 2000);
+
+           var chatBoxTextAreaElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).children().filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.INPUT + ']').find('textarea');
+           chatBoxTextAreaElm.attr({scrollTop: chatBoxTextAreaElm.attr('scrollHeight')});
+       }
+    },
+
+    updateRoster: function(contactBareJid, fromName, presence)
+    {
+       var availability = $(presence).attr('type');
+       var item = $(presence).find('item');
+       var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid);
+
+       if (chatBoxElm.length == 0) {
+               BeeChat.UI.ScrollBoxes.addRoom(contactBareJid);
+           chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid);
+       }
+
+       //var chatBoxContentElm = chatBoxElm.children().filter('[bareJid=' + contactBareJid + ']');
+
+       var roster = chatBoxElm.find('div').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.ROOMROSTER + ']');
+       if (availability == 'unavailable') {
+               roster.find('div').filter('[contactName='+fromName+']').remove();
+       }
+       else {
+               var hasName = roster.find('div').filter('[contactName='+fromName+']');
+               if (hasName.length == 0) {
+                       roster.append($('<div>' + fromName + '</div>')
+                               .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.ROSTER_ITEM)
+                               .attr('title', item.attr('affiliation') + '/' + item.attr('role'))
+                               .attr('contactName', fromName))
+               }
+       }
+    },
+
+
+    /** Function: update
+     *
+     */
+    update: function(contactBareJid, fromName, msg, isroom)
+    {
+       var chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid);
+
+       if (chatBoxElm.length == 0) {
+            if (isroom)
+               BeeChat.UI.ScrollBoxes.addRoom(contactBareJid);
+           else
+               BeeChat.UI.ScrollBoxes.add(contactBareJid);
+           chatBoxElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid);
+       }
+
+       var chatBoxContentElm = chatBoxElm.children().filter('[bareJid=' + contactBareJid + ']');
+
+       chatBoxContentElm.find('p').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.STATE + ']').remove();
+
+       var chatBoxLastMessageElm = $(chatBoxContentElm).find('div').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE + ']').filter(':last');
+
+       if (chatBoxLastMessageElm && chatBoxLastMessageElm.find('span').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE_SENDER + ']').text() == fromName) {
+           chatBoxLastMessageElm.append('<p>' + BeeChat.UI.Utils.getPrintableChatMessage(msg) + '</p>');
+       } else {
+           chatBoxContentElm.append($('<div></div>')
+                                    .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE)
+                                    .append($('<span></span>')
+                                            .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE_SENDER)
+                                            .text(fromName))
+                                    .append($('<span></span>')
+                                            .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.MESSAGE_DATE)
+                                            .text(BeeChat.UI.Utils.getNowFormattedTime()))
+                                    .append('<p>' + BeeChat.UI.Utils.getPrintableChatMessage(msg) + '</p>'));
+       }
+
+       chatBoxContentElm.attr({scrollTop: chatBoxContentElm.attr('scrollHeight')});
+
+       var scrollBoxesElm = $('#' + BeeChat.UI.Resources.Elements.ID_DIV_SCROLLBOXES);
+       var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid);
+
+       if (BeeChat.UI.ScrollBoxes.isInitialized == false) {
+           scrollBoxesElm.trigger('goto', scrollBoxesElm.find('ul').children().index(scrollBoxElm));
+       }
+
+       if (chatBoxElm.is(':hidden')) {
+           BeeChat.UI.UnreadCountBox.update(contactBareJid);
+//         if (BeeChat.UI.HAS_FOCUS)
+//             document.getElementById(BeeChat.UI.Resources.Sounds.NEW_MESSAGE).Play();
+       }
+
+//     if (!BeeChat.UI.HAS_FOCUS)
+//         document.getElementById(BeeChat.UI.Resources.Sounds.NEW_MESSAGE).Play();
+    },
+
+    /** Function: updateChatState
+     *
+     */
+    updateChatState: function(contactBareJid, msg)
+    {
+       var chatBoxContentElm = BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).children().filter('[bareJid=' + contactBareJid + ']');
+
+       $(msg).children().each(function() {
+               if (this.tagName == BeeChat.Message.ChatStates.COMPOSING) {
+                   if (chatBoxContentElm.find('p').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.STATE + ']').length == 0) {
+                       $('<p></p>')
+                           .attr('class', BeeChat.UI.Resources.StyleClasses.ChatBox.STATE)
+                           .html(BeeChat.UI.Utils.getContactName(contactBareJid) + BeeChat.UI.Resources.Strings.ChatMessages.COMPOSING + "</br />")
+                           .appendTo(chatBoxContentElm);
+                   }
+               } else if (this.tagName == BeeChat.Message.ChatStates.PAUSED) {
+                   chatBoxContentElm.find('p').filter('[class=' + BeeChat.UI.Resources.StyleClasses.ChatBox.STATE + ']').remove();
+               }
+           });
+       chatBoxContentElm.attr({scrollTop: chatBoxContentElm.attr('scrollHeight')});
+    },
+
+    /** Function: remove
+     *
+     */
+    remove: function(contactBareJid)
+    {
+       BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).remove();
+       BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid).remove();
+    },
+
+    /** Function: show
+     *
+     */
+    show: function(contactBareJid)
+    {
+       BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).show();
+    },
+
+    /** Function: hide
+     *
+     */
+    hide: function(contactBareJid)
+    {
+       BeeChat.UI.ChatBoxes.getChatBoxElm(contactBareJid).hide();
+    },
+
+    /** Function: getChatBoxElm
+     *
+     */
+    getChatBoxElm: function(contactBareJid)
+    {
+       return $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().filter('[bareJid=' + contactBareJid + ']');
+    }
+};
+
+BeeChat.UI.UnreadCountBox = {
+    /** Function: add
+     *
+     */
+    add: function(contactBareJid)
+    {
+       BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid)
+       .append($('<span></span>')
+               .attr('class', BeeChat.UI.Resources.StyleClasses.UNREAD_COUNT));
+    },
+
+    /** Function: remove
+     *
+     */
+    remove: function(contactBareJid)
+    {
+       BeeChat.UI.UnreadCountBox.getElm(contactBareJid).remove();
+    },
+
+    /** Function: update
+     *
+     */
+    update: function(contactBareJid)
+    {
+       if (arguments.length > 1 && !arguments[1])
+           return;
+
+       var unreadCountBoxElm = BeeChat.UI.UnreadCountBox.getElm(contactBareJid);
+       if (unreadCountBoxElm.length == 0) {
+           BeeChat.UI.UnreadCountBox.add(contactBareJid);
+           unreadCountBoxElm = BeeChat.UI.UnreadCountBox.getElm(contactBareJid);
+       }
+       if (arguments.length == 1) {
+           var unreadCount = unreadCountBoxElm.text();
+           unreadCountBoxElm.text(++unreadCount);
+       } else
+           unreadCountBoxElm.text(arguments[1]);
+    },
+
+    /** Function: getElm
+     *
+     */
+    getElm: function(contactBareJid)
+    {
+       return BeeChat.UI.ScrollBoxes.getScrollBoxElm(contactBareJid).find('span').filter('[class=' + BeeChat.UI.Resources.StyleClasses.UNREAD_COUNT +' ]');
+    }
+};
+
+/** Class: BeeChat.UI.Utils
+ *  An object container for all UI utilities functions
+ *
+ */
+BeeChat.UI.Utils = {
+    /** Function: getTruncatedContactName
+     *
+     */
+    getTruncatedContactName: function(bareJid)
+    {
+       return (BeeChat.UI.Utils.truncateString(BeeChat.UI.Utils.getContactName(bareJid), (arguments.length == 2) ? arguments[1] : 21));
+    },
+
+    /** Function: getTruncatedContactStatus
+     *
+     */
+    getTruncatedContactStatus: function(contactStatus)
+    {
+       return (BeeChat.UI.Utils.truncateString(contactStatus, (arguments.length == 2 ? arguments[1] : 50)));
+    },
+
+    /** Function: getContactName
+     *
+     */
+    getContactName: function(bareJid)
+    {
+       var contactName = bareJid;
+
+       if (g_beechat_roster_items != null && g_beechat_roster_items[bareJid])
+           contactName = g_beechat_roster_items[bareJid].name;
+       // no contact name so we show bareJid
+       if (!contactName || contactName == '')
+               contactName = bareJid;
+
+       return (contactName);
+    },
+
+    /** Function: getPrintableChatMessage
+     *
+     */
+    getPrintableChatMessage: function(msg)
+    {
+       var val = new String;
+       val = $('<div>' + msg + '</div>');
+       msg = val.text();
+
+       msg = jQuery.trim(msg);
+       msg = BeeChat.UI.Utils.replaceLinks(msg);
+       msg = BeeChat.UI.Utils.replaceSmileys(msg);
+
+       return msg;
+    },
+
+    /** Function: getNowFormattedTime
+     *
+     */
+    getNowFormattedTime: function()
+    {
+       var date = new Date();
+
+       var hours = date.getHours();
+       var minutes = date.getMinutes();
+       var seconds = date.getSeconds();
+
+       if (hours < 10)
+           hours = '0' + hours;
+       if (minutes < 10)
+           minutes = '0' + minutes;
+       if (seconds < 10)
+           seconds = '0' + seconds;
+       return (hours + ':' + minutes + ':' + seconds);
+    },
+
+
+    /** Function: replaceSmileys
+     *  Replace smileys founded in a string to beautiful icons :)
+     *
+     *  Parameters:
+     *    (String) str - The string containing smileys
+     *
+     */
+    replaceSmileys: function(str)
+    {
+       str = str.replace(/(;\))/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_WINK + '" />');
+       str = str.replace(/(:\))/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_SMILE + '" />');
+       str = str.replace(/(:\()/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_UNHAPPY + '" />');
+       str = str.replace(/(:D)/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_GRIN + '" />');
+       str = str.replace(/(:o)/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_SURPRISED + '" />');
+       str = str.replace(/(xD)/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_EVILGRIN + '" />');
+       str = str.replace(/(:p)/gi, '<img src="' + BeeChat.UI.Resources.Paths.ICONS + BeeChat.UI.Resources.Emoticons.FILENAME_TONGUE + '" />');
+
+       return (str);
+    },
+
+    /** Function: replaceLinks
+     *  Transform links founded in a string to clickable links
+     *
+     *  Parameters:
+     *    (String) str - The string where will be replaced links
+     */
+    replaceLinks: function(str)
+    {
+       var xpr =
+       /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi;
+
+       return (str.replace(xpr, '<a href="$1" target="_blank">$1</a>'));
+    },
+
+    /** Function: truncateString
+     *  Truncate a string at a specified length
+     *
+     *  Parameters:
+     *    (String) str - The string to truncate
+     *    (int) len - The maximum length of str
+     */
+    truncateString: function(str, len)
+    {
+       if (str != null && str.length > len)
+           return ((str.substr(0, len) + '...'));
+       return (str);
+    }
+};
+
+
+/** Executed when the DOM is ready
+ *
+ */
+function init_beechat(ts, token) {
+       if (typeof document.body.style.maxHeight === "undefined") { // IE6
+           return;
+       }
+
+       BeeChat.UI.initialize(ts, token);
+}
+
+/** Window resizing
+ *
+ */
+$(window).resize(function() {
+       if (typeof document.body.style.maxHeight === "undefined") { // IE6
+           return;
+       }
+
+       $('#' + BeeChat.UI.Resources.Elements.ID_DIV_CHATBOXES).children().each(function() {
+               var scrollBoxElm = BeeChat.UI.ScrollBoxes.getScrollBoxElm($(this).attr('bareJid'));
+               var pos = scrollBoxElm.position().left - ($(this).width() - scrollBoxElm.width()) + 24;
+
+               $(this).css({'left': pos});
+           });
+});
+
+
+/** Executed when the page is unloaded
+ *
+ */
+$(window).unload(function() {
+       if (typeof document.body.style.maxHeight === "undefined") { // IE6
+           return;
+       }
+
+       if (!$('#beechat').length)
+               return;
+
+       if (g_beechat_user != null) {
+           g_beechat_user.requestSessionPause();
+           BeeChat.UI.saveState();
+       }
+
+       BeeChat.UI.saveConnection();
+    });
+
+
+/** Check whether the BeeChat tab is active or not
+ *
+ */
+$(window).bind('blur', function() {
+       BeeChat.UI.HAS_FOCUS = false;
+    });
+
+$(window).bind('focus', function() {
+       BeeChat.UI.HAS_FOCUS = true;
+    });
diff --git a/views/default/beechat/beechat.php b/views/default/beechat/beechat.php
new file mode 100644 (file)
index 0000000..d1e9e17
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+       /**
+        * Beechat
+        * 
+        * @package beechat
+        * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+        * @author Beechannels <contact@beechannels.com>
+        * @copyright Beechannels 2007-2010
+        * @link http://beechannels.com/
+        */
+
+if (isloggedin() && get_loggedin_user()->chatenabled && elgg_get_context() != 'admin') {
+?>      
+<div id="beechat">
+  <div id="beechat_left">
+    <a id="beechat_tooltip_trigger" href="<?php echo $vars['url']; ?>"><img src="<?php echo $vars['config']->wwwroot; ?>favicon.ico" /></a>
+    <div class="tooltip tooltipchat">
+      <h3><?php echo elgg_echo('beechat:icons:home'); ?></h3>
+    </div>
+  </div>
+  <div id="beechat_center">
+    <span id="beechat_center_prev" class="prev"></span>
+    <div id="beechat_scrollboxes"><ul></ul></div>
+    <span id="beechat_center_next" class="next"></span>
+  </div>
+  <div id="beechat_right">
+    <span id="beechat_contacts_button" class="offline">
+      <?php echo elgg_echo('beechat:contacts:button'); ?>
+    </span>
+  </div>
+  <div id="beechat_contacts">
+    <div id="beechat_contacts_top">
+      <span class="beechat_label"><?php echo elgg_echo('beechat:contacts:button'); ?></span>
+      <div id="beechat_contacts_controls">
+       <span id="beechat_contacts_control_minimize" class="beechat_control" title="<?php echo elgg_echo('beechat:box:minimize'); ?>">_</span>
+      </div>
+      <br clear="all" />
+    </div>
+    <div id="beechat_availability_switcher">
+      <span id="beechat_current_availability"></span>
+      <span class="beechat_availability_switcher_control_down" id="beechat_availability_switcher_control"></span>
+    </div>
+    <div id="beechat_contacts_content">
+      <ul id="beechat_contacts_list"></ul>
+      <ul id="beechat_availability_switcher_list">
+       <li class="beechat_left_availability_chat"><?php echo elgg_echo('beechat:availability:available'); ?></li>
+       <li class="beechat_left_availability_dnd"><?php echo elgg_echo('beechat:availability:dnd'); ?></li>
+       <li class="beechat_left_availability_away"><?php echo elgg_echo('beechat:availability:away'); ?></li>
+       <li class="beechat_left_availability_xa"><?php echo elgg_echo('beechat:availability:xa'); ?></li>
+       <li class="beechat_left_availability_offline"><?php echo elgg_echo('beechat:availability:offline'); ?></li>
+      </ul>
+    </div>
+    <div id="beechat_contacts_bottom">
+      <span id="beechat_contacts_bottom_bar"></span>
+    </div>
+  </div>
+  <div id="beechat_chatboxes"></div>
+</div>
+<!-- SOUNDS -->
+<!--
+<embed src="<?php echo $vars['config']->staticurl; ?>mod/beechat/sounds/newmessage.wav" autostart=false width=0 height=0
+       id="beechat_sounds_new_message"
+       enablejavascript="true" />
+-->
+
+<?php
+        $ts = time();
+        $token = generate_action_token($ts);
+?>
+
+<script>
+       $(function () {
+               var e = document.createElement('script');
+               e.async = true;
+               e.type = 'text/javascript';
+                e.text = 'init_beechat("<?php echo $ts; ?>","<?php echo $token; ?>");';
+                document.getElementById('beechat').appendChild(e);
+
+       })
+</script>       
+
+<?php
+ }
+?>
diff --git a/views/default/beechat/beechat.userjs.php b/views/default/beechat/beechat.userjs.php
new file mode 100644 (file)
index 0000000..f147d8b
--- /dev/null
@@ -0,0 +1,54 @@
+<script type="text/javascript">
+BeeChat.Events.Messages = {
+           ConnectionStates: {
+               CONNECTING: "<?php echo elgg_echo('beechat:connection:state:connecting'); ?>",
+               AUTHENTICATING: "<?php echo elgg_echo('beechat:connection:state:authenticating'); ?>",
+               FAILED: "<?php echo elgg_echo('beechat:connection:state:failed'); ?>",
+               DISCONNECTING: "<?php echo elgg_echo('beechat:connection:state:disconnecting'); ?>",
+               OFFLINE: "<?php echo elgg_echo('beechat:connection:state:offline'); ?>",
+               ONLINE: "<?php echo elgg_echo('beechat:connection:state:online'); ?>"
+           }
+       }
+
+BeeChat.UI.Resources.Strings = {
+           Availability: {
+               AVAILABLE: "<?php echo elgg_echo('beechat:availability:available'); ?>",
+               CHAT: "<?php echo elgg_echo('beechat:availability:available'); ?>",
+               ONLINE: "<?php echo elgg_echo('beechat:availability:available'); ?>",
+               DND: "<?php echo elgg_echo('beechat:availability:dnd'); ?>",
+               AWAY: "<?php echo elgg_echo('beechat:availability:away'); ?>",
+               XA:"<?php echo elgg_echo('beechat:availability:xa'); ?>",
+               OFFLINE: "<?php echo elgg_echo('beechat:availability:offline'); ?>"
+           },
+
+           Contacts: {
+               BUTTON: "<?php echo elgg_echo('beechat:contacts:button'); ?>"
+           },
+
+           ChatMessages: {
+               SELF: "<?php echo $_SESSION['user']->name; ?>",
+               COMPOSING: "<?php echo elgg_echo('beechat:chat:composing'); ?>"
+           },
+
+           Box: {
+               MINIMIZE: "<?php echo elgg_echo('beechat:box:minimize'); ?>",
+               CLOSE: "<?php echo elgg_echo('beechat:box:close'); ?>",
+               SHOWHIDE: "<?php echo elgg_echo('beechat:box:showhide'); ?>"
+           }
+       }
+g_user_rooms = new Array();
+<?php
+if (isloggedin()) {
+       $user = get_loggedin_user();
+       $chatrooms = elgg_get_entities_from_relationship(array('relationship' => 'groupchat',
+                                                               'relationship_guid' => $user->guid,
+                                                               'inverse_relationship' => false,
+                                                               'limit' => 0));
+       if (!empty($chatrooms)) {
+         foreach($chatrooms as $chatroom) {
+           echo "g_user_rooms.push(['".beechat_friendly_title($chatroom->name)."@".get_plugin_setting("groupdomain", "beechat")."', '".$chatroom->guid."']);";
+         }
+       }
+}
+?>
+</script>
diff --git a/views/default/beechat/screen.css.php b/views/default/beechat/screen.css.php
new file mode 100644 (file)
index 0000000..05336ef
--- /dev/null
@@ -0,0 +1,672 @@
+<?php
+   global $CONFIG;
+   $url = $CONFIG->wwwroot;
+
+?>
+/**
+ * Beechat
+ * 
+ * @package beechat
+ * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
+ * @author Beechannels <contact@beechannels.com>
+ * @copyright Beechannels 2007-2010
+ * @link http://beechannels.com/
+ */
+
+div#beechat {
+    display: block !important;
+    display: none;
+    position: fixed;
+    left: 1%;
+    right: 1%;
+    bottom: 0;
+    margin: 0;
+    padding: 0;
+    height: 20px;
+    z-index: 999;
+
+    font-family: Arial, Helvetica, "Liberation Sans", FreeSans, sans-serif;
+    font-size: 0.9em;
+    color: #222222;
+    background-color: #DDDDDD;
+    border-top: 1px solid #BBBBBB;
+    border-left: 1px solid #BBBBBB;
+}
+div#beechat a img {
+    border: none;
+}
+div#beechat a {
+    text-decoration: none;
+}
+div#beechat img {
+    vertical-align: middle;
+}
+div#beechat a:hover {
+    text-decoration: underline;
+}
+.beechat_control {
+    cursor: pointer;
+    color: #CCCCFF;
+    font-size: 1.6em;
+}
+.beechat_control:hover {
+    color: white;
+}
+.beechat_box_control {
+    cursor: pointer;
+    color: #888888;
+    font-size: 1em;
+}
+.beechat_box_control:hover {
+    color: #222222;
+}
+.beechat_chatbox_control {
+    cursor: pointer;
+    color: #CCCCFF;
+    font-size: 1.6em;
+}
+.beechat_chatbox_control:hover {
+    color: white;
+}
+.beechat_label {
+    font-weight: bold;
+    font-size: 1.1em;
+}
+
+/*
+** -
+** left side
+** -
+*/
+div#beechat_left {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 116px;
+    height: 18px;
+    margin: 0;
+    padding: 1px 2px;
+}
+
+
+/*
+** -
+** right side
+** -
+*/
+div#beechat_right {
+    position: absolute;
+    top: 0;
+    right: 0;
+    width: 220px;
+    height: 20px;
+    margin: 0;
+    padding: 0 0 0 0;
+
+    border-left: 1px solid #BBBBBB;
+    border-right: 1px solid #BBBBBB;
+}
+div#beechat_contacts {
+    position: absolute;
+    right: 0px;
+    bottom: 0;
+    width: 222px;
+    height: 240px;
+    margin: 0 auto 20px auto;
+    padding: 0;
+    display: none;
+
+    background-color: white;
+}
+div#beechat_contacts_top {
+    color: white;
+    background-color: #193C60;
+    width: 220px;
+    height: 32px;
+
+    border-top: 1px solid #0B2C4F;
+    border-left: 1px solid #0B2C4F;
+    border-right: 1px solid #0B2C4F;
+}
+div#beechat_contacts_top .beechat_label {
+    float: left;
+    height: 20px;
+    padding: 6px;
+}
+div#beechat_contacts_controls {
+    margin: 0;
+    padding: 0;
+}
+div#beechat_contacts_controls span#beechat_contacts_control_minimize {
+    position: relative;
+    top: -7px;
+    float: right;
+    display: block;
+    width: 20px;
+    height: 20px;
+    padding: 2px;
+
+    font-size: 1.6em;
+    font-weigth: bold;
+    text-align: center;
+}
+span#beechat_contacts_button {
+    display: block;
+    width: 190px;
+    padding: 2px 6px 0 24px;
+    height: 18px;
+    cursor: pointer;
+    font-size: 1.1em;
+    font-weight: normal;
+
+    background-image: url('<?php echo $url; ?>mod/beechat/graphics/icons/statuses.png');
+}
+span#beechat_contacts_button.online {
+    background-position: 4px -750px;
+    background-repeat: no-repeat;
+}
+span#beechat_contacts_button.dnd {
+    background-position: 4px -796px;
+    background-repeat: no-repeat;
+}
+span#beechat_contacts_button.away {
+    background-position: 4px -842px;
+    background-repeat: no-repeat;
+}
+span#beechat_contacts_button.offline {
+    background-position: 4px -888px;
+    background-repeat: no-repeat;
+}
+span#beechat_contacts_button:hover {
+    background-color: white;
+}
+div#beechat_availability_switcher {
+    width: 218px;
+    height: 24px;
+    margin: 0;
+    padding: 0 0 0 2px;
+
+    background-color: #EEEEEE;
+    border-left: 1px solid #666666;
+    border-right: 1px solid #666666;
+    border-bottom: 1px solid #BBBBBB;
+}
+span#beechat_current_availability {
+    float: left;
+    padding: 4px 4px 4px 22px;
+
+    font-weight: bold;
+    cursor: pointer;
+}
+span#beechat_current_availability:hover {
+    text-decoration: underline;
+}
+span#beechat_availability_switcher_control {
+    float: right;
+    width: 24px;
+    height: 20px;
+    cursor: pointer;
+}
+span.beechat_availability_switcher_control_up {
+    background: no-repeat 50% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_arrow_up.png');
+}
+span.beechat_availability_switcher_control_down {
+    background: no-repeat 50% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_arrow_down.png');
+}
+ul#beechat_availability_switcher_list {
+    display: none;
+    padding:0;
+    margin:0;
+    list-style:none;
+}
+ul#beechat_availability_switcher_list li {
+    margin: 0;
+    padding: 4px 4px 4px 24px;
+
+    cursor: pointer;
+}
+ul#beechat_availability_switcher_list li:hover {
+    background-color: #EEEEEE;
+}
+div#beechat_contacts_content {
+    width: 220px;
+    height: 164px;
+    overflow: auto;
+
+    border-left: 1px solid #666666;
+    border-right: 1px solid #666666;
+    background-color: white;
+}
+ul#beechat_contacts_list {
+    background-color: white;
+    padding:0;
+    margin:0;
+    list-style:none;
+}
+ul#beechat_contacts_list li img {
+    margin: 0 4px 0 0;
+    width: 25px;
+    height: 25px;
+}
+ul#beechat_contacts_list li {
+    margin: 0;
+    padding: 4px 4px 4px 6px;
+
+    cursor: pointer;
+    color: #333;
+}
+ul#beechat_contacts_list li:hover {
+    background-color: #F5F6F8;
+    color: #333;
+}
+div#beechat_contacts_bottom {
+    width: 220px;
+    height: 18px;
+
+    border-left: 1px solid #666666;
+    border-right: 1px solid #666666;
+}
+span#beechat_contacts_bottom_bar {
+    position: absolute;
+    display: block;
+    bottom: 0;
+    width: 210px;
+    height: 1px;
+
+    background-color: #BBBBBB;
+    margin: auto 4px;
+}
+
+
+/*
+** -
+** center area
+** -
+*/
+div#beechat_center {
+    float: right;
+    display: block;
+    width: 586px;
+    height: 20px;
+    margin: 0 220px 0 100px;
+    *margin: 0 312px 0 100px;
+    padding: 0;
+}
+div#beechat_center .next, div#beechat_center .prev {
+    display: none;
+
+    border-left: 1px solid #BBBBBB;
+    cursor: pointer;
+}
+div#beechat_center .next {
+    position: absolute;
+    right: 220px;
+    width: 24px;
+    height: 20px;
+
+    background: no-repeat 50% url("<?php echo $url; ?>mod/beechat/graphics/icons/resultset_next.png");
+}
+div#beechat_center .prev {
+    position: absolute;
+    right: 872px;
+    width: 24px;
+    height: 20px;
+
+    background: no-repeat 50% url("<?php echo $url; ?>mod/beechat/graphics/icons/resultset_previous.png");
+}
+div#beechat_scrollboxes {
+    float: right;
+    overflow: hidden;
+    width: 628px;
+    height: 21px;
+    margin: 0 24px 0 24px;
+    text-align: left;
+}
+div#beechat_scrollboxes ul {
+    width: 200000em;
+    list-style: none;
+    padding:0;
+    margin:0;
+}
+div#beechat_scrollboxes ul li {
+    float: right;
+    display: block;
+    width: 130px;
+    height: 20px;
+    padding: 1px 0 0 22px;
+
+    cursor: pointer;
+    border-left: 1px solid #BBBBBB;
+}
+div#beechat_scrollboxes ul li:hover {
+    color: #000000;
+    background-color: white;
+}
+div#beechat_scrollboxes ul li.beechat_scrollbox_selected {
+    border-left: 1px solid #666666;
+    border-right: 1px solid #666666;
+    background-color: white;
+}
+div#beechat_scrollboxes ul li span.beechat_unread_count {
+    float: right;
+    display: block;
+    width: 16px;
+    height: 14px;
+    padding-top: 2px;
+    margin: 0 6px 0 0;
+
+    text-align: center;
+    font-size: 0.7em;
+    color: white;
+    background: no-repeat 0% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/notification_pink.png');
+}
+div#beechat_scrollboxes ul li span#beechat_box_control_close {
+    float: right;
+    width: auto;
+    padding: 1px 4px;
+    height: 20px;
+}
+
+/*
+** --
+** availability classes
+** --
+*/
+.beechat_left_availability_chat {
+    background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_green.png');
+}
+.beechat_left_availability_dnd {
+    background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_delete.png');
+}
+.beechat_left_availability_away {
+    background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_orange.png');
+}
+.beechat_left_availability_xa {
+    background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_red.png');
+}
+.beechat_left_availability_offline {
+    background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_black.png');
+}
+.beechat_left_availability_room {
+    background: no-repeat 2% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/muc_icon.png');
+}
+
+
+
+.beechat_right_availability_chat {
+    background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_green.png');
+}
+.beechat_right_availability_dnd {
+    background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_delete.png');
+}
+.beechat_right_availability_away {
+    background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_orange.png');
+}
+.beechat_right_availability_xa {
+    background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_red.png');
+}
+.beechat_right_availability_offline {
+    background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/bullet_black.png');
+}
+.beechat_right_availability_room {
+    background: no-repeat 96% 50% url('<?php echo $url; ?>mod/beechat/graphics/icons/muc_icon.png');
+}
+
+/*
+** --
+** tooltips
+** --
+*/
+div.tooltip.tooltipchat {
+    display: none;
+    padding: 4px;
+    width: auto;
+    background: transparent no-repeat left bottom url('<?php echo $url; ?>mod/beechat/graphics/icons/pointer.png');
+}
+div.tooltip.tooltipchat h3 {
+    margin: 0;
+    padding: 4px;
+
+    font-weight: normal;
+    font-size: 0.9em;
+    color: white;
+    background-color: #222222;
+}
+
+
+/*
+** --
+** chatboxes
+** --
+*/
+div.beechat_chatbox {
+    position: absolute;
+    width: 240px;
+    height: 300px;
+    bottom: 25px;
+    margin: 0;
+    padding: 0;
+
+    background-color: #DDDDDD;
+}
+div.beechat_chatbox a {
+    color: white;
+}
+div.beechat_chatbox a:hover {
+    text-decoration: underline;
+}
+div.beechat_chatbox_roomroster {
+    position: absolute;
+    width: 100px;
+    height: 276px;
+    left: -101px;
+    bottom: -2px;
+    margin: 0;
+    padding: 0;
+    overflow: auto;
+
+    border: 1px solid #4B6C8F;
+
+    background-color: #EEEEEE;
+}
+div.beechat_chatbox_roomrosteritem {
+    background-color: #FFFFFF;
+    margin: 3px;
+    padding-left: 2px;
+}
+div.beechat_chatbox_chatroom {
+    position: absolute;
+    width: 240px;
+    height: 300px;
+    left: 100px;
+    bottom: 0px;
+    margin: 0;
+    padding: 0;
+
+    background-color: #DDDDDD;
+}
+div.beechat_chatbox_chatroom a {
+    color: white;
+}
+div.beechat_chatbox_chatroom a:hover {
+    text-decoration: underline;
+}
+
+div.beechat_chatbox_room {
+    position: absolute;
+    width: 340px;
+    height: 300px;
+    bottom: 25px;
+    margin: 0;
+    padding: 0;
+
+    background-color: #DDDDDD;
+}
+div.beechat_chatbox_room a {
+    color: white;
+}
+div.beechat_chatbox_room a:hover {
+    text-decoration: underline;
+}
+div.beechat_chatbox_top {
+    width: 238px;
+    height: 24px;
+    margin: 0;
+    padding: 0;
+
+    font-size: 0.9em;
+    color: white;
+    background-color: #193C60;
+    border-top: 1px solid #0B2C4F;
+    border-left: 1px solid #0B2C4F;
+    border-right: 1px solid #0B2C4F;
+}
+div.beechat_chatbox_top .beechat_chatbox_top_icon {
+    position: absolute;
+    top: 4px;
+    left: 4px;
+    z-index: 2;
+
+    widht: 50px;
+    height: 50px;
+}
+div.beechat_chatbox_top .beechat_label {
+    float: left;
+    height: 13px;
+    padding: 4px 6px 6px 6px;
+
+    margin-left: 54px;
+}
+div.beechat_chatbox_top_controls {
+    margin: 0;
+    padding: 0;
+}
+div.beechat_chatbox_top_controls .beechat_chatbox_control {
+    float: right;
+    display: block;
+    width: 20px;
+    height: 19px;
+    padding: 2px;
+    margin: 0;
+
+    font-size: 1.2em;
+    font-weight: bold;
+    text-align: center;
+}
+div.beechat_chatbox_subtop {
+    width: 172px;
+    height: 30px;
+    padding: 2px 6px 2px 60px;
+
+    border-left: 1px solid #666666;
+    border-right: 1px solid #666666;
+    border-bottom: 1px solid #CCCCCC;
+    background-color: #DDDDDD;
+}
+div.beechat_chatbox_content {
+    width: 238px;
+    height: 202px;
+    margin: 0;
+    padding: 0;
+    overflow: auto;
+
+    border-left: 1px solid #666666;
+    border-right: 1px solid #666666;
+    background-color: white;
+}
+div.beechat_chatbox_content div.beechat_chatbox_message {
+    width: auto;
+    height: auto;
+    margin: 0;
+    padding: 2px;
+    border-top: 1px solid #DDDDDD;
+}
+div.beechat_chatbox_message span.beechat_chatbox_message_sender {
+    position: relative;
+    top: 0;
+    left: 6px;
+    font-weight: bold;
+    font-size: 1em;
+}
+div.beechat_chatbox_message span.beechat_chatbox_message_date {
+    float: right;
+    margin: 0 6px 0 0;
+}
+div.beechat_chatbox_content a {
+    color: #003399;
+}
+div.beechat_chatbox_content a:hover {
+    text-decoration: underline;
+}
+div.beechat_chatbox_content p {
+    margin: 0;
+    padding: 2px 6px;
+}
+div.beechat_chatbox_content p.beechat_chatbox_state {
+    font-size: 1em;
+    color: #888888;
+}
+div.beechat_chatbox_input {
+    width: 238px;
+    height: 40px;
+    margin: 0;
+    padding: 0;
+
+    border-top: 2px solid #BBBBBB;
+    border-left: 1px solid #666666;
+    border-right: 1px solid #666666;
+    background-color: #DDDDDD;
+}
+div.beechat_chatbox_input textarea {
+    width: 204px;
+    height: 32px;
+    max-width: 240px;
+    max-height: 40px;
+    padding: 4px 4px 4px 30px;
+    margin: auto;
+    overflow: hidden;
+    vertical-align: top;
+    resize: none;
+
+    font-size: 1em;
+    font-family: Arial, Helvetica, "Liberation Sans", FreeSans, sans-serif;
+    outline: none;
+    border: none;
+    background: white no-repeat 4px 3px url('<?php echo $url; ?>mod/beechat/graphics/icons/chat_icon.png');
+}
+div.beechat_chatbox_input textarea:focus {
+    outline: none;
+    border: none;
+    background-color: white;
+}
+div.beechat_chatbox_bottom {
+    position: absolute;
+    width: 238px;
+    height: 1px;
+
+    background-color: white;
+    border-left: 1px solid #666666;
+    border-right: 1px solid #666666;
+    border-bottom: 1px solid #666666;
+    z-index: 2;
+}
+div.beechat_chatbox_bottom span {
+    position: absolute;
+    display: block;
+    right: 0;
+    top: 0;
+    width: 152px;
+    height: 1px;
+
+    border-bottom: 1px solid white;
+}
+div.beechat_chatbox_bottom span span {
+    position: absolute;
+    display: block;
+    width: 146px;
+    height: 1px;
+    right: 4px;
+    top: 0;
+
+    border-bottom: 1px solid #BBBBBB;
+}
diff --git a/views/default/js/b64.js.php b/views/default/js/b64.js.php
new file mode 100644 (file)
index 0000000..201bdbd
--- /dev/null
@@ -0,0 +1,74 @@
+// This code was written by Tyler Akins and has been placed in the
+// public domain.  It would be nice if you left this header intact.
+// Base64 code from Tyler Akins -- http://rumkin.com
+
+var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+/**
+ * Encodes a string in base64
+ * @param {String} input The string to encode in base64.
+ */
+function encode64(input) {
+   var output = "";
+   var chr1, chr2, chr3;
+   var enc1, enc2, enc3, enc4;
+   var i = 0;
+
+   do {
+      chr1 = input.charCodeAt(i++);
+      chr2 = input.charCodeAt(i++);
+      chr3 = input.charCodeAt(i++);
+
+      enc1 = chr1 >> 2;
+      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+      enc4 = chr3 & 63;
+
+      if (isNaN(chr2)) {
+         enc3 = enc4 = 64;
+      } else if (isNaN(chr3)) {
+         enc4 = 64;
+      }
+
+      output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
+         keyStr.charAt(enc3) + keyStr.charAt(enc4);
+   } while (i < input.length);
+
+   return output;
+}
+
+/**
+ * Decodes a base64 string.
+ * @param {String} input The string to decode.
+ */
+function decode64(input) {
+   var output = "";
+   var chr1, chr2, chr3;
+   var enc1, enc2, enc3, enc4;
+   var i = 0;
+
+   // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
+   input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+   do {
+      enc1 = keyStr.indexOf(input.charAt(i++));
+      enc2 = keyStr.indexOf(input.charAt(i++));
+      enc3 = keyStr.indexOf(input.charAt(i++));
+      enc4 = keyStr.indexOf(input.charAt(i++));
+
+      chr1 = (enc1 << 2) | (enc2 >> 4);
+      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+      chr3 = ((enc3 & 3) << 6) | enc4;
+
+      output = output + String.fromCharCode(chr1);
+
+      if (enc3 != 64) {
+         output = output + String.fromCharCode(chr2);
+      }
+      if (enc4 != 64) {
+         output = output + String.fromCharCode(chr3);
+      }
+   } while (i < input.length);
+
+   return output;
+}
diff --git a/views/default/js/jquery.cookie.min.js.php b/views/default/js/jquery.cookie.min.js.php
new file mode 100644 (file)
index 0000000..cb09af9
--- /dev/null
@@ -0,0 +1,10 @@
+/**
+ * Cookie plugin
+ *
+ * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ */
+jQuery.cookie=function(name,value,options){if(typeof value!='undefined'){options=options||{};if(value===null){value='';options=$.extend({},options);options.expires=-1;}var expires='';if(options.expires&&(typeof options.expires=='number'||options.expires.toUTCString)){var date;if(typeof options.expires=='number'){date=new Date();date.setTime(date.getTime()+(options.expires*24*60*60*1000));}else{date=options.expires;}expires='; expires='+date.toUTCString();}var path=options.path?'; path='+(options.path):'';var domain=options.domain?'; domain='+(options.domain):'';var secure=options.secure?'; secure':'';document.cookie=[name,'=',encodeURIComponent(value),expires,path,domain,secure].join('');}else{var cookieValue=null;if(document.cookie&&document.cookie!=''){var cookies=document.cookie.split(';');for(var i=0;i<cookies.length;i++){var cookie=jQuery.trim(cookies[i]);if(cookie.substring(0,name.length+1)==(name+'=')){cookieValue=decodeURIComponent(cookie.substring(name.length+1));break;}}}return cookieValue;}};
\ No newline at end of file
diff --git a/views/default/js/jquery.localscroll-1.2.7-min.js.php b/views/default/js/jquery.localscroll-1.2.7-min.js.php
new file mode 100644 (file)
index 0000000..fa583a4
--- /dev/null
@@ -0,0 +1,9 @@
+/**
+ * jQuery.LocalScroll - Animated scrolling navigation, using anchors.
+ * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Dual licensed under MIT and GPL.
+ * Date: 3/11/2009
+ * @author Ariel Flesler
+ * @version 1.2.7
+ **/
+;(function($){var l=location.href.replace(/#.*/,'');var g=$.localScroll=function(a){$('body').localScroll(a)};g.defaults={duration:1e3,axis:'y',event:'click',stop:true,target:window,reset:true};g.hash=function(a){if(location.hash){a=$.extend({},g.defaults,a);a.hash=false;if(a.reset){var e=a.duration;delete a.duration;$(a.target).scrollTo(0,a);a.duration=e}i(0,location,a)}};$.fn.localScroll=function(b){b=$.extend({},g.defaults,b);return b.lazy?this.bind(b.event,function(a){var e=$([a.target,a.target.parentNode]).filter(d)[0];if(e)i(a,e,b)}):this.find('a,area').filter(d).bind(b.event,function(a){i(a,this,b)}).end().end();function d(){return!!this.href&&!!this.hash&&this.href.replace(this.hash,'')==l&&(!b.filter||$(this).is(b.filter))}};function i(a,e,b){var d=e.hash.slice(1),f=document.getElementById(d)||document.getElementsByName(d)[0];if(!f)return;if(a)a.preventDefault();var h=$(b.target);if(b.lock&&h.is(':animated')||b.onBefore&&b.onBefore.call(b,a,f,h)===false)return;if(b.stop)h.stop(true);if(b.hash){var j=f.id==d?'id':'name',k=$('<a> </a>').attr(j,d).css({position:'absolute',top:$(window).scrollTop(),left:$(window).scrollLeft()});f[j]='';$('body').prepend(k);location=e.hash;k.remove();f[j]=d}h.scrollTo(f,b).trigger('notify.serialScroll',[f])}})(jQuery);
\ No newline at end of file
diff --git a/views/default/js/jquery.scrollTo-min.js.php b/views/default/js/jquery.scrollTo-min.js.php
new file mode 100755 (executable)
index 0000000..5e78778
--- /dev/null
@@ -0,0 +1,11 @@
+/**
+ * jQuery.ScrollTo - Easy element scrolling using jQuery.
+ * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Dual licensed under MIT and GPL.
+ * Date: 5/25/2009
+ * @author Ariel Flesler
+ * @version 1.4.2
+ *
+ * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
+ */
+;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
\ No newline at end of file
diff --git a/views/default/js/jquery.serialScroll-min.js.php b/views/default/js/jquery.serialScroll-min.js.php
new file mode 100755 (executable)
index 0000000..d716124
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * jQuery.SerialScroll - Animated scrolling of series
+ * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Dual licensed under MIT and GPL.
+ * Date: 06/14/2009
+ * @author Ariel Flesler
+ * @version 1.2.2
+ * http://flesler.blogspot.com/2008/02/jqueryserialscroll.html
+ */
+;(function(a){var b=a.serialScroll=function(c){return a(window).serialScroll(c)};b.defaults={duration:1e3,axis:"x",event:"click",start:0,step:1,lock:!0,cycle:!0,constant:!0};a.fn.serialScroll=function(c){return this.each(function(){var t=a.extend({},b.defaults,c),s=t.event,i=t.step,r=t.lazy,e=t.target?this:document,u=a(t.target||this,e),p=u[0],m=t.items,h=t.start,g=t.interval,k=t.navigation,l;if(!r){m=d()}if(t.force){f({},h)}a(t.prev||[],e).bind(s,-i,q);a(t.next||[],e).bind(s,i,q);if(!p.ssbound){u.bind("prev.serialScroll",-i,q).bind("next.serialScroll",i,q).bind("goto.serialScroll",f)}if(g){u.bind("start.serialScroll",function(v){if(!g){o();g=!0;n()}}).bind("stop.serialScroll",function(){o();g=!1})}u.bind("notify.serialScroll",function(x,w){var v=j(w);if(v>-1){h=v}});p.ssbound=!0;if(t.jump){(r?u:d()).bind(s,function(v){f(v,j(v.target))})}if(k){k=a(k,e).bind(s,function(v){v.data=Math.round(d().length/k.length)*k.index(this);f(v,this)})}function q(v){v.data+=h;f(v,this)}function f(B,z){if(!isNaN(z)){B.data=z;z=p}var C=B.data,v,D=B.type,A=t.exclude?d().slice(0,-t.exclude):d(),y=A.length,w=A[C],x=t.duration;if(D){B.preventDefault()}if(g){o();l=setTimeout(n,t.interval)}if(!w){v=C<0?0:y-1;if(h!=v){C=v}else{if(!t.cycle){return}else{C=y-v-1}}w=A[C]}if(!w||t.lock&&u.is(":animated")||D&&t.onBefore&&t.onBefore(B,w,u,d(),C)===!1){return}if(t.stop){u.queue("fx",[]).stop()}if(t.constant){x=Math.abs(x/i*(h-C))}u.scrollTo(w,x,t).trigger("notify.serialScroll",[C])}function n(){u.trigger("next.serialScroll")}function o(){clearTimeout(l)}function d(){return a(m,p)}function j(w){if(!isNaN(w)){return w}var x=d(),v;while((v=x.index(w))==-1&&w!=p){w=w.parentNode}return v}})}})(jQuery);
\ No newline at end of file
diff --git a/views/default/js/jquery.tools.min.js.php b/views/default/js/jquery.tools.min.js.php
new file mode 100644 (file)
index 0000000..1574af4
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * jQuery Tools 1.2.2 - The missing UI library for the Web
+ * 
+ * [tabs, tabs.slideshow, tooltip, tooltip.slide, tooltip.dynamic, scrollable, scrollable.autoscroll, scrollable.navigator, overlay]
+ * 
+ * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
+ * 
+ * http://flowplayer.org/tools/
+ * 
+ * File generated: Mon Jun 07 08:32:38 GMT 2010
+ */
+(function(c){function p(d,a,b){var e=this,l=d.add(this),h=d.find(b.tabs),j=a.jquery?a:d.children(a),i;h.length||(h=d.children());j.length||(j=d.parent().find(a));j.length||(j=c(a));c.extend(this,{click:function(f,g){var k=h.eq(f);if(typeof f=="string"&&f.replace("#","")){k=h.filter("[href*="+f.replace("#","")+"]");f=Math.max(h.index(k),0)}if(b.rotate){var n=h.length-1;if(f<0)return e.click(n,g);if(f>n)return e.click(0,g)}if(!k.length){if(i>=0)return e;f=b.initialIndex;k=h.eq(f)}if(f===i)return e;
+g=g||c.Event();g.type="onBeforeClick";l.trigger(g,[f]);if(!g.isDefaultPrevented()){o[b.effect].call(e,f,function(){g.type="onClick";l.trigger(g,[f])});i=f;h.removeClass(b.current);k.addClass(b.current);return e}},getConf:function(){return b},getTabs:function(){return h},getPanes:function(){return j},getCurrentPane:function(){return j.eq(i)},getCurrentTab:function(){return h.eq(i)},getIndex:function(){return i},next:function(){return e.click(i+1)},prev:function(){return e.click(i-1)}});c.each("onBeforeClick,onClick".split(","),
+function(f,g){c.isFunction(b[g])&&c(e).bind(g,b[g]);e[g]=function(k){c(e).bind(g,k);return e}});if(b.history&&c.fn.history){c.tools.history.init(h);b.event="history"}h.each(function(f){c(this).bind(b.event,function(g){e.click(f,g);return g.preventDefault()})});j.find("a[href^=#]").click(function(f){e.click(c(this).attr("href"),f)});if(location.hash)e.click(location.hash);else if(b.initialIndex===0||b.initialIndex>0)e.click(b.initialIndex)}c.tools=c.tools||{version:"1.2.2"};c.tools.tabs={conf:{tabs:"a",
+current:"current",onBeforeClick:null,onClick:null,effect:"default",initialIndex:0,event:"click",rotate:false,history:false},addEffect:function(d,a){o[d]=a}};var o={"default":function(d,a){this.getPanes().hide().eq(d).show();a.call()},fade:function(d,a){var b=this.getConf(),e=b.fadeOutSpeed,l=this.getPanes();e?l.fadeOut(e):l.hide();l.eq(d).fadeIn(b.fadeInSpeed,a)},slide:function(d,a){this.getPanes().slideUp(200);this.getPanes().eq(d).slideDown(400,a)},ajax:function(d,a){this.getPanes().eq(0).load(this.getTabs().eq(d).attr("href"),
+a)}},m;c.tools.tabs.addEffect("horizontal",function(d,a){m||(m=this.getPanes().eq(0).width());this.getCurrentPane().animate({width:0},function(){c(this).hide()});this.getPanes().eq(d).animate({width:m},function(){c(this).show();a.call()})});c.fn.tabs=function(d,a){var b=this.data("tabs");if(b)return b;if(c.isFunction(a))a={onBeforeClick:a};a=c.extend({},c.tools.tabs.conf,a);this.each(function(){b=new p(c(this),d,a);c(this).data("tabs",b)});return a.api?b:this}})(jQuery);
+(function(d){function r(g,a){function p(f){var e=d(f);return e.length<2?e:g.parent().find(f)}var c=this,j=g.add(this),b=g.data("tabs"),h,l,m,n=false,o=p(a.next).click(function(){b.next()}),k=p(a.prev).click(function(){b.prev()});d.extend(c,{getTabs:function(){return b},getConf:function(){return a},play:function(){if(!h){var f=d.Event("onBeforePlay");j.trigger(f);if(f.isDefaultPrevented())return c;n=false;h=setInterval(b.next,a.interval);j.trigger("onPlay");b.next()}},pause:function(){if(!h)return c;
+var f=d.Event("onBeforePause");j.trigger(f);if(f.isDefaultPrevented())return c;h=clearInterval(h);m=clearInterval(m);j.trigger("onPause")},stop:function(){c.pause();n=true}});d.each("onBeforePlay,onPlay,onBeforePause,onPause".split(","),function(f,e){d.isFunction(a[e])&&c.bind(e,a[e]);c[e]=function(s){return c.bind(e,s)}});if(a.autopause){var t=b.getTabs().add(o).add(k).add(b.getPanes());t.hover(function(){c.pause();l=clearInterval(l)},function(){n||(l=setTimeout(c.play,a.interval))})}if(a.autoplay)m=
+setTimeout(c.play,a.interval);else c.stop();a.clickable&&b.getPanes().click(function(){b.next()});if(!b.getConf().rotate){var i=a.disabledClass;b.getIndex()||k.addClass(i);b.onBeforeClick(function(f,e){if(e){k.removeClass(i);e==b.getTabs().length-1?o.addClass(i):o.removeClass(i)}else k.addClass(i)})}}var q;q=d.tools.tabs.slideshow={conf:{next:".forward",prev:".backward",disabledClass:"disabled",autoplay:false,autopause:true,interval:3E3,clickable:true,api:false}};d.fn.slideshow=function(g){var a=
+this.data("slideshow");if(a)return a;g=d.extend({},q.conf,g);this.each(function(){a=new r(d(this),g);d(this).data("slideshow",a)});return g.api?a:this}})(jQuery);
+(function(f){function p(a,b,c){var h=c.relative?a.position().top:a.offset().top,e=c.relative?a.position().left:a.offset().left,i=c.position[0];h-=b.outerHeight()-c.offset[0];e+=a.outerWidth()+c.offset[1];var j=b.outerHeight()+a.outerHeight();if(i=="center")h+=j/2;if(i=="bottom")h+=j;i=c.position[1];a=b.outerWidth()+a.outerWidth();if(i=="center")e-=a/2;if(i=="left")e-=a;return{top:h,left:e}}function t(a,b){var c=this,h=a.add(c),e,i=0,j=0,m=a.attr("title"),q=n[b.effect],k,r=a.is(":input"),u=r&&a.is(":checkbox, :radio, select, :button"),
+s=a.attr("type"),l=b.events[s]||b.events[r?u?"widget":"input":"def"];if(!q)throw'Nonexistent effect "'+b.effect+'"';l=l.split(/,\s*/);if(l.length!=2)throw"Tooltip: bad events configuration for "+s;a.bind(l[0],function(d){if(b.predelay){clearTimeout(i);j=setTimeout(function(){c.show(d)},b.predelay)}else c.show(d)}).bind(l[1],function(d){if(b.delay){clearTimeout(j);i=setTimeout(function(){c.hide(d)},b.delay)}else c.hide(d)});if(m&&b.cancelDefault){a.removeAttr("title");a.data("title",m)}f.extend(c,
+{show:function(d){if(!e){if(m)e=f(b.layout).addClass(b.tipClass).appendTo(document.body).hide().append(m);else if(b.tip)e=f(b.tip).eq(0);else{e=a.next();e.length||(e=a.parent().next())}if(!e.length)throw"Cannot find tooltip for "+a;}if(c.isShown())return c;e.stop(true,true);var g=p(a,e,b);d=d||f.Event();d.type="onBeforeShow";h.trigger(d,[g]);if(d.isDefaultPrevented())return c;g=p(a,e,b);e.css({position:"absolute",top:g.top,left:g.left});k=true;q[0].call(c,function(){d.type="onShow";k="full";h.trigger(d)});
+g=b.events.tooltip.split(/,\s*/);e.bind(g[0],function(){clearTimeout(i);clearTimeout(j)});g[1]&&!a.is("input:not(:checkbox, :radio), textarea")&&e.bind(g[1],function(o){o.relatedTarget!=a[0]&&a.trigger(l[1].split(" ")[0])});return c},hide:function(d){if(!e||!c.isShown())return c;d=d||f.Event();d.type="onBeforeHide";h.trigger(d);if(!d.isDefaultPrevented()){k=false;n[b.effect][1].call(c,function(){d.type="onHide";k=false;h.trigger(d)});return c}},isShown:function(d){return d?k=="full":k},getConf:function(){return b},
+getTip:function(){return e},getTrigger:function(){return a}});f.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","),function(d,g){f.isFunction(b[g])&&f(c).bind(g,b[g]);c[g]=function(o){f(c).bind(g,o);return c}})}f.tools=f.tools||{version:"1.2.2"};f.tools.tooltip={conf:{effect:"toggle",fadeOutSpeed:"fast",predelay:0,delay:30,opacity:1,tip:0,position:["top","center"],offset:[0,0],relative:false,cancelDefault:true,events:{def:"mouseenter,mouseleave",input:"focus,blur",widget:"focus mouseenter,blur mouseleave",
+tooltip:"mouseenter,mouseleave"},layout:"<div/>",tipClass:"tooltip"},addEffect:function(a,b,c){n[a]=[b,c]}};var n={toggle:[function(a){var b=this.getConf(),c=this.getTip();b=b.opacity;b<1&&c.css({opacity:b});c.show();a.call()},function(a){this.getTip().hide();a.call()}],fade:[function(a){var b=this.getConf();this.getTip().fadeTo(b.fadeInSpeed,b.opacity,a)},function(a){this.getTip().fadeOut(this.getConf().fadeOutSpeed,a)}]};f.fn.tooltip=function(a){var b=this.data("tooltip");if(b)return b;a=f.extend(true,
+{},f.tools.tooltip.conf,a);if(typeof a.position=="string")a.position=a.position.split(/,?\s/);this.each(function(){b=new t(f(this),a);f(this).data("tooltip",b)});return a.api?b:this}})(jQuery);
+(function(d){var i=d.tools.tooltip;d.extend(i.conf,{direction:"up",bounce:false,slideOffset:10,slideInSpeed:200,slideOutSpeed:200,slideFade:!d.browser.msie});var e={up:["-","top"],down:["+","top"],left:["-","left"],right:["+","left"]};i.addEffect("slide",function(g){var a=this.getConf(),f=this.getTip(),b=a.slideFade?{opacity:a.opacity}:{},c=e[a.direction]||e.up;b[c[1]]=c[0]+"="+a.slideOffset;a.slideFade&&f.css({opacity:0});f.show().animate(b,a.slideInSpeed,g)},function(g){var a=this.getConf(),f=a.slideOffset,
+b=a.slideFade?{opacity:0}:{},c=e[a.direction]||e.up,h=""+c[0];if(a.bounce)h=h=="+"?"-":"+";b[c[1]]=h+"="+f;this.getTip().animate(b,a.slideOutSpeed,function(){d(this).hide();g.call()})})})(jQuery);
+(function(g){function j(a){var c=g(window),d=c.width()+c.scrollLeft(),h=c.height()+c.scrollTop();return[a.offset().top<=c.scrollTop(),d<=a.offset().left+a.width(),h<=a.offset().top+a.height(),c.scrollLeft()>=a.offset().left]}function k(a){for(var c=a.length;c--;)if(a[c])return false;return true}var i=g.tools.tooltip;i.dynamic={conf:{classNames:"top right bottom left"}};g.fn.dynamic=function(a){if(typeof a=="number")a={speed:a};a=g.extend({},i.dynamic.conf,a);var c=a.classNames.split(/\s/),d;this.each(function(){var h=
+g(this).tooltip().onBeforeShow(function(e,f){e=this.getTip();var b=this.getConf();d||(d=[b.position[0],b.position[1],b.offset[0],b.offset[1],g.extend({},b)]);g.extend(b,d[4]);b.position=[d[0],d[1]];b.offset=[d[2],d[3]];e.css({visibility:"hidden",position:"absolute",top:f.top,left:f.left}).show();f=j(e);if(!k(f)){if(f[2]){g.extend(b,a.top);b.position[0]="top";e.addClass(c[0])}if(f[3]){g.extend(b,a.right);b.position[1]="right";e.addClass(c[1])}if(f[0]){g.extend(b,a.bottom);b.position[0]="bottom";e.addClass(c[2])}if(f[1]){g.extend(b,
+a.left);b.position[1]="left";e.addClass(c[3])}if(f[0]||f[2])b.offset[0]*=-1;if(f[1]||f[3])b.offset[1]*=-1}e.css({visibility:"visible"}).hide()});h.onBeforeShow(function(){var e=this.getConf();this.getTip();setTimeout(function(){e.position=[d[0],d[1]];e.offset=[d[2],d[3]]},0)});h.onHide(function(){var e=this.getTip();e.removeClass(a.classNames)});ret=h});return a.api?ret:this}})(jQuery);
+(function(e){function n(f,c){var a=e(c);return a.length<2?a:f.parent().find(c)}function t(f,c){var a=this,l=f.add(a),g=f.children(),k=0,m=c.vertical;j||(j=a);if(g.length>1)g=e(c.items,f);e.extend(a,{getConf:function(){return c},getIndex:function(){return k},getSize:function(){return a.getItems().size()},getNaviButtons:function(){return o.add(p)},getRoot:function(){return f},getItemWrap:function(){return g},getItems:function(){return g.children(c.item).not("."+c.clonedClass)},move:function(b,d){return a.seekTo(k+
+b,d)},next:function(b){return a.move(1,b)},prev:function(b){return a.move(-1,b)},begin:function(b){return a.seekTo(0,b)},end:function(b){return a.seekTo(a.getSize()-1,b)},focus:function(){return j=a},addItem:function(b){b=e(b);if(c.circular){e(".cloned:last").before(b);e(".cloned:first").replaceWith(b.clone().addClass(c.clonedClass))}else g.append(b);l.trigger("onAddItem",[b]);return a},seekTo:function(b,d,h){if(c.circular&&b===0&&k==-1&&d!==0)return a;if(!c.circular&&b<0||b>a.getSize()||b<-1)return a;
+var i=b;if(b.jquery)b=a.getItems().index(b);else i=a.getItems().eq(b);var q=e.Event("onBeforeSeek");if(!h){l.trigger(q,[b,d]);if(q.isDefaultPrevented()||!i.length)return a}i=m?{top:-i.position().top}:{left:-i.position().left};k=b;j=a;if(d===undefined)d=c.speed;g.animate(i,d,c.easing,h||function(){l.trigger("onSeek",[b])});return a}});e.each(["onBeforeSeek","onSeek","onAddItem"],function(b,d){e.isFunction(c[d])&&e(a).bind(d,c[d]);a[d]=function(h){e(a).bind(d,h);return a}});if(c.circular){var r=a.getItems().slice(-1).clone().prependTo(g),
+s=a.getItems().eq(1).clone().appendTo(g);r.add(s).addClass(c.clonedClass);a.onBeforeSeek(function(b,d,h){if(!b.isDefaultPrevented())if(d==-1){a.seekTo(r,h,function(){a.end(0)});return b.preventDefault()}else d==a.getSize()&&a.seekTo(s,h,function(){a.begin(0)})});a.seekTo(0,0)}var o=n(f,c.prev).click(function(){a.prev()}),p=n(f,c.next).click(function(){a.next()});!c.circular&&a.getSize()>1&&a.onBeforeSeek(function(b,d){o.toggleClass(c.disabledClass,d<=0);p.toggleClass(c.disabledClass,d>=a.getSize()-
+1)});c.mousewheel&&e.fn.mousewheel&&f.mousewheel(function(b,d){if(c.mousewheel){a.move(d<0?1:-1,c.wheelSpeed||50);return false}});c.keyboard&&e(document).bind("keydown.scrollable",function(b){if(!(!c.keyboard||b.altKey||b.ctrlKey||e(b.target).is(":input")))if(!(c.keyboard!="static"&&j!=a)){var d=b.keyCode;if(m&&(d==38||d==40)){a.move(d==38?-1:1);return b.preventDefault()}if(!m&&(d==37||d==39)){a.move(d==37?-1:1);return b.preventDefault()}}});e(a).trigger("onBeforeSeek",[c.initialIndex])}e.tools=e.tools||
+{version:"1.2.2"};e.tools.scrollable={conf:{activeClass:"active",circular:false,clonedClass:"cloned",disabledClass:"disabled",easing:"swing",initialIndex:0,item:null,items:".items",keyboard:true,mousewheel:false,next:".next",prev:".prev",speed:400,vertical:false,wheelSpeed:0}};var j;e.fn.scrollable=function(f){var c=this.data("scrollable");if(c)return c;f=e.extend({},e.tools.scrollable.conf,f);this.each(function(){c=new t(e(this),f);e(this).data("scrollable",c)});return f.api?c:this}})(jQuery);
+(function(c){var g=c.tools.scrollable;g.autoscroll={conf:{autoplay:true,interval:3E3,autopause:true}};c.fn.autoscroll=function(d){if(typeof d=="number")d={interval:d};var b=c.extend({},g.autoscroll.conf,d),h;this.each(function(){var a=c(this).data("scrollable");if(a)h=a;var e,i,f=true;a.play=function(){if(!e){f=false;e=setInterval(function(){a.next()},b.interval);a.next()}};a.pause=function(){e=clearInterval(e)};a.stop=function(){a.pause();f=true};b.autopause&&a.getRoot().add(a.getNaviButtons()).hover(function(){a.pause();
+clearInterval(i)},function(){f||(i=setTimeout(a.play,b.interval))});b.autoplay&&setTimeout(a.play,b.interval)});return b.api?h:this}})(jQuery);
+(function(d){function p(c,g){var h=d(g);return h.length<2?h:c.parent().find(g)}var m=d.tools.scrollable;m.navigator={conf:{navi:".navi",naviItem:null,activeClass:"active",indexed:false,idPrefix:null,history:false}};d.fn.navigator=function(c){if(typeof c=="string")c={navi:c};c=d.extend({},m.navigator.conf,c);var g;this.each(function(){function h(a,b,i){e.seekTo(b);if(j){if(location.hash)location.hash=a.attr("href").replace("#","")}else return i.preventDefault()}function f(){return k.find(c.naviItem||
+"> *")}function n(a){var b=d("<"+(c.naviItem||"a")+"/>").click(function(i){h(d(this),a,i)}).attr("href","#"+a);a===0&&b.addClass(l);c.indexed&&b.text(a+1);c.idPrefix&&b.attr("id",c.idPrefix+a);return b.appendTo(k)}function o(a,b){a=f().eq(b.replace("#",""));a.length||(a=f().filter("[href="+b+"]"));a.click()}var e=d(this).data("scrollable"),k=p(e.getRoot(),c.navi),q=e.getNaviButtons(),l=c.activeClass,j=c.history&&d.fn.history;if(e)g=e;e.getNaviButtons=function(){return q.add(k)};f().length?f().each(function(a){d(this).click(function(b){h(d(this),
+a,b)})}):d.each(e.getItems(),function(a){n(a)});e.onBeforeSeek(function(a,b){var i=f().eq(b);!a.isDefaultPrevented()&&i.length&&f().removeClass(l).eq(b).addClass(l)});e.onAddItem(function(a,b){b=n(e.getItems().index(b));j&&b.history(o)});j&&f().history(o)});return c.api?g:this}})(jQuery);
+(function(a){function t(d,b){var c=this,i=d.add(c),o=a(window),k,f,m,g=a.tools.expose&&(b.mask||b.expose),n=Math.random().toString().slice(10);if(g){if(typeof g=="string")g={color:g};g.closeOnClick=g.closeOnEsc=false}var p=b.target||d.attr("rel");f=p?a(p):d;if(!f.length)throw"Could not find Overlay: "+p;d&&d.index(f)==-1&&d.click(function(e){c.load(e);return e.preventDefault()});a.extend(c,{load:function(e){if(c.isOpened())return c;var h=q[b.effect];if(!h)throw'Overlay: cannot find effect : "'+b.effect+
+'"';b.oneInstance&&a.each(s,function(){this.close(e)});e=e||a.Event();e.type="onBeforeLoad";i.trigger(e);if(e.isDefaultPrevented())return c;m=true;g&&a(f).expose(g);var j=b.top,r=b.left,u=f.outerWidth({margin:true}),v=f.outerHeight({margin:true});if(typeof j=="string")j=j=="center"?Math.max((o.height()-v)/2,0):parseInt(j,10)/100*o.height();if(r=="center")r=Math.max((o.width()-u)/2,0);h[0].call(c,{top:j,left:r},function(){if(m){e.type="onLoad";i.trigger(e)}});g&&b.closeOnClick&&a.mask.getMask().one("click",
+c.close);b.closeOnClick&&a(document).bind("click."+n,function(l){a(l.target).parents(f).length||c.close(l)});b.closeOnEsc&&a(document).bind("keydown."+n,function(l){l.keyCode==27&&c.close(l)});return c},close:function(e){if(!c.isOpened())return c;e=e||a.Event();e.type="onBeforeClose";i.trigger(e);if(!e.isDefaultPrevented()){m=false;q[b.effect][1].call(c,function(){e.type="onClose";i.trigger(e)});a(document).unbind("click."+n).unbind("keydown."+n);g&&a.mask.close();return c}},getOverlay:function(){return f},
+getTrigger:function(){return d},getClosers:function(){return k},isOpened:function(){return m},getConf:function(){return b}});a.each("onBeforeLoad,onStart,onLoad,onBeforeClose,onClose".split(","),function(e,h){a.isFunction(b[h])&&a(c).bind(h,b[h]);c[h]=function(j){a(c).bind(h,j);return c}});k=f.find(b.close||".close");if(!k.length&&!b.close){k=a('<div class="close"></div>');f.prepend(k)}k.click(function(e){c.close(e)});b.load&&c.load()}a.tools=a.tools||{version:"1.2.2"};a.tools.overlay={addEffect:function(d,
+b,c){q[d]=[b,c]},conf:{close:null,closeOnClick:true,closeOnEsc:true,closeSpeed:"fast",effect:"default",fixed:!a.browser.msie||a.browser.version>6,left:"center",load:false,mask:null,oneInstance:true,speed:"normal",target:null,top:"10%"}};var s=[],q={};a.tools.overlay.addEffect("default",function(d,b){var c=this.getConf(),i=a(window);if(!c.fixed){d.top+=i.scrollTop();d.left+=i.scrollLeft()}d.position=c.fixed?"fixed":"absolute";this.getOverlay().css(d).fadeIn(c.speed,b)},function(d){this.getOverlay().fadeOut(this.getConf().closeSpeed,
+d)});a.fn.overlay=function(d){var b=this.data("overlay");if(b)return b;if(a.isFunction(d))d={onBeforeLoad:d};d=a.extend(true,{},a.tools.overlay.conf,d);this.each(function(){b=new t(a(this),d);s.push(b);a(this).data("overlay",b)});return d.api?b:this}})(jQuery);
diff --git a/views/default/js/json2.js.php b/views/default/js/json2.js.php
new file mode 100644 (file)
index 0000000..7ae5032
--- /dev/null
@@ -0,0 +1,476 @@
+/*
+    http://www.JSON.org/json2.js
+    2009-06-29
+
+    Public Domain.
+
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+    See http://www.JSON.org/js.html
+
+    This file creates a global JSON object containing two methods: stringify
+    and parse.
+
+        JSON.stringify(value, replacer, space)
+            value       any JavaScript value, usually an object or array.
+
+            replacer    an optional parameter that determines how object
+                        values are stringified for objects. It can be a
+                        function or an array of strings.
+
+            space       an optional parameter that specifies the indentation
+                        of nested structures. If it is omitted, the text will
+                        be packed without extra whitespace. If it is a number,
+                        it will specify the number of spaces to indent at each
+                        level. If it is a string (such as '\t' or '&nbsp;'),
+                        it contains the characters used to indent at each level.
+
+            This method produces a JSON text from a JavaScript value.
+
+            When an object value is found, if the object contains a toJSON
+            method, its toJSON method will be called and the result will be
+            stringified. A toJSON method does not serialize: it returns the
+            value represented by the name/value pair that should be serialized,
+            or undefined if nothing should be serialized. The toJSON method
+            will be passed the key associated with the value, and this will be
+            bound to the object holding the key.
+
+            For example, this would serialize Dates as ISO strings.
+
+                Date.prototype.toJSON = function (key) {
+                    function f(n) {
+                        // Format integers to have at least two digits.
+                        return n < 10 ? '0' + n : n;
+                    }
+
+                    return this.getUTCFullYear()   + '-' +
+                         f(this.getUTCMonth() + 1) + '-' +
+                         f(this.getUTCDate())      + 'T' +
+                         f(this.getUTCHours())     + ':' +
+                         f(this.getUTCMinutes())   + ':' +
+                         f(this.getUTCSeconds())   + 'Z';
+                };
+
+            You can provide an optional replacer method. It will be passed the
+            key and value of each member, with this bound to the containing
+            object. The value that is returned from your method will be
+            serialized. If your method returns undefined, then the member will
+            be excluded from the serialization.
+
+            If the replacer parameter is an array of strings, then it will be
+            used to select the members to be serialized. It filters the results
+            such that only members with keys listed in the replacer array are
+            stringified.
+
+            Values that do not have JSON representations, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays they will be replaced with null. You can use
+            a replacer function to replace those with JSON values.
+            JSON.stringify(undefined) returns undefined.
+
+            The optional space parameter produces a stringification of the
+            value that is filled with line breaks and indentation to make it
+            easier to read.
+
+            If the space parameter is a non-empty string, then that string will
+            be used for indentation. If the space parameter is a number, then
+            the indentation will be that many spaces.
+
+            Example:
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+            text = JSON.stringify([new Date()], function (key, value) {
+                return this[key] instanceof Date ?
+                    'Date(' + this[key] + ')' : value;
+            });
+            // text is '["Date(---current time---)"]'
+
+
+        JSON.parse(text, reviver)
+            This method parses a JSON text to produce an object or array.
+            It can throw a SyntaxError exception.
+
+            The optional reviver parameter is a function that can filter and
+            transform the results. It receives each of the keys and values,
+            and its return value is used instead of the original value.
+            If it returns what it received, then the structure is not modified.
+            If it returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. Values that look like ISO date strings will
+            // be converted to Date objects.
+
+            myData = JSON.parse(text, function (key, value) {
+                var a;
+                if (typeof value === 'string') {
+                    a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+                    if (a) {
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+                            +a[5], +a[6]));
+                    }
+                }
+                return value;
+            });
+
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+                var d;
+                if (typeof value === 'string' &&
+                        value.slice(0, 5) === 'Date(' &&
+                        value.slice(-1) === ')') {
+                    d = new Date(value.slice(5, -1));
+                    if (d) {
+                        return d;
+                    }
+                }
+                return value;
+            });
+
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+*/
+
+/*jslint evil: true */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
+    test, toJSON, toString, valueOf
+*/
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+var JSON = JSON || {};
+
+(function () {
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function (key) {
+
+            return isFinite(this.valueOf()) ?
+                   this.getUTCFullYear()   + '-' +
+                 f(this.getUTCMonth() + 1) + '-' +
+                 f(this.getUTCDate())      + 'T' +
+                 f(this.getUTCHours())     + ':' +
+                 f(this.getUTCMinutes())   + ':' +
+                 f(this.getUTCSeconds())   + 'Z' : null;
+        };
+
+        String.prototype.toJSON =
+        Number.prototype.toJSON =
+        Boolean.prototype.toJSON = function (key) {
+            return this.valueOf();
+        };
+    }
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ?
+            '"' + string.replace(escapable, function (a) {
+                var c = meta[a];
+                return typeof c === 'string' ? c :
+                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+            }) + '"' :
+            '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+                typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+            return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+        case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+// Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                v = partial.length === 0 ? '[]' :
+                    gap ? '[\n' + gap +
+                            partial.join(',\n' + gap) + '\n' +
+                                mind + ']' :
+                          '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    k = rep[i];
+                    if (typeof k === 'string') {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+            v = partial.length === 0 ? '{}' :
+                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+                        mind + '}' : '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                    (typeof replacer !== 'object' ||
+                     typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function' ?
+                    walk({'': j}, '') : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());
diff --git a/views/default/js/md5.js.php b/views/default/js/md5.js.php
new file mode 100644 (file)
index 0000000..4284f62
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
+var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
+var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
+function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
+function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
+function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
+function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
+function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function md5_vm_test()
+{
+  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
+}
+
+/*
+ * Calculate the MD5 of an array of little-endian words, and a bit length
+ */
+function core_md5(x, len)
+{
+  /* append padding */
+  x[len >> 5] |= 0x80 << ((len) % 32);
+  x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+  var a =  1732584193;
+  var b = -271733879;
+  var c = -1732584194;
+  var d =  271733878;
+
+  var olda, oldb, oldc, oldd;
+  for(var i = 0; i < x.length; i += 16)
+  {
+    olda = a;
+    oldb = b;
+    oldc = c;
+    oldd = d;
+
+    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
+    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
+    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
+    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
+    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
+    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
+    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
+    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
+    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
+    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
+    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
+    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
+    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
+    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
+
+    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
+    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
+    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
+    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
+    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
+    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
+    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
+    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
+    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
+    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
+    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
+    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
+    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
+    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
+    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
+
+    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
+    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
+    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
+    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
+    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
+    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
+    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
+    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
+    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
+    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
+    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
+    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
+    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
+    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
+    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
+
+    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
+    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
+    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
+    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
+    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
+    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
+    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
+    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
+    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
+    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
+    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
+    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
+    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
+    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
+    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+
+    a = safe_add(a, olda);
+    b = safe_add(b, oldb);
+    c = safe_add(c, oldc);
+    d = safe_add(d, oldd);
+  }
+  return [a, b, c, d];
+}
+
+/*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+function md5_cmn(q, a, b, x, s, t)
+{
+  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
+}
+function md5_ff(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+}
+function md5_gg(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+}
+function md5_hh(a, b, c, d, x, s, t)
+{
+  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
+}
+function md5_ii(a, b, c, d, x, s, t)
+{
+  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+}
+
+/*
+ * Calculate the HMAC-MD5, of a key and some data
+ */
+function core_hmac_md5(key, data)
+{
+  var bkey = str2binl(key);
+  if(bkey.length > 16) { bkey = core_md5(bkey, key.length * chrsz); }
+
+  var ipad = new Array(16), opad = new Array(16);
+  for(var i = 0; i < 16; i++)
+  {
+    ipad[i] = bkey[i] ^ 0x36363636;
+    opad[i] = bkey[i] ^ 0x5C5C5C5C;
+  }
+
+  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
+  return core_md5(opad.concat(hash), 512 + 128);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+  return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+  return (num << cnt) | (num >>> (32 - cnt));
+}
+
+/*
+ * Convert a string to an array of little-endian words
+ * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
+ */
+function str2binl(str)
+{
+  var bin = [];
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < str.length * chrsz; i += chrsz)
+  {
+    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
+  }
+  return bin;
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2str(bin)
+{
+  var str = "";
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < bin.length * 32; i += chrsz)
+  {
+    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
+  }
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a hex string.
+ */
+function binl2hex(binarray)
+{
+  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i++)
+  {
+    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
+           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
+  }
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a base-64 string
+ */
+function binl2b64(binarray)
+{
+  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  var str = "";
+  var triplet, j;
+  for(var i = 0; i < binarray.length * 4; i += 3)
+  {
+    triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16) |
+              (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) |
+              ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
+    for(j = 0; j < 4; j++)
+    {
+      if(i * 8 + j * 6 > binarray.length * 32) { str += b64pad; }
+      else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); }
+    }
+  }
+  return str;
+}
diff --git a/views/default/js/sha1.js.php b/views/default/js/sha1.js.php
new file mode 100644 (file)
index 0000000..db3bf05
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
+ * in FIPS PUB 180-1
+ * Version 2.1a Copyright Paul Johnston 2000 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for details.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
+var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
+var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
+function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
+function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
+function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
+function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
+function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function sha1_vm_test()
+{
+  return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
+}
+
+/*
+ * Calculate the SHA-1 of an array of big-endian words, and a bit length
+ */
+function core_sha1(x, len)
+{
+  /* append padding */
+  x[len >> 5] |= 0x80 << (24 - len % 32);
+  x[((len + 64 >> 9) << 4) + 15] = len;
+
+  var w = new Array(80);
+  var a =  1732584193;
+  var b = -271733879;
+  var c = -1732584194;
+  var d =  271733878;
+  var e = -1009589776;
+
+  var i, j, t, olda, oldb, oldc, oldd, olde;
+  for (i = 0; i < x.length; i += 16)
+  {
+    olda = a;
+    oldb = b;
+    oldc = c;
+    oldd = d;
+    olde = e;
+
+    for (j = 0; j < 80; j++)
+    {
+      if (j < 16) { w[j] = x[i + j]; }
+      else { w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); }
+      t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
+                       safe_add(safe_add(e, w[j]), sha1_kt(j)));
+      e = d;
+      d = c;
+      c = rol(b, 30);
+      b = a;
+      a = t;
+    }
+
+    a = safe_add(a, olda);
+    b = safe_add(b, oldb);
+    c = safe_add(c, oldc);
+    d = safe_add(d, oldd);
+    e = safe_add(e, olde);
+  }
+  return [a, b, c, d, e];
+}
+
+/*
+ * Perform the appropriate triplet combination function for the current
+ * iteration
+ */
+function sha1_ft(t, b, c, d)
+{
+  if (t < 20) { return (b & c) | ((~b) & d); }
+  if (t < 40) { return b ^ c ^ d; }
+  if (t < 60) { return (b & c) | (b & d) | (c & d); }
+  return b ^ c ^ d;
+}
+
+/*
+ * Determine the appropriate additive constant for the current iteration
+ */
+function sha1_kt(t)
+{
+  return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
+         (t < 60) ? -1894007588 : -899497514;
+}
+
+/*
+ * Calculate the HMAC-SHA1 of a key and some data
+ */
+function core_hmac_sha1(key, data)
+{
+  var bkey = str2binb(key);
+  if (bkey.length > 16) { bkey = core_sha1(bkey, key.length * chrsz); }
+
+  var ipad = new Array(16), opad = new Array(16);
+  for (var i = 0; i < 16; i++)
+  {
+    ipad[i] = bkey[i] ^ 0x36363636;
+    opad[i] = bkey[i] ^ 0x5C5C5C5C;
+  }
+
+  var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
+  return core_sha1(opad.concat(hash), 512 + 160);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+  return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function rol(num, cnt)
+{
+  return (num << cnt) | (num >>> (32 - cnt));
+}
+
+/*
+ * Convert an 8-bit or 16-bit string to an array of big-endian words
+ * In 8-bit function, characters >255 have their hi-byte silently ignored.
+ */
+function str2binb(str)
+{
+  var bin = [];
+  var mask = (1 << chrsz) - 1;
+  for (var i = 0; i < str.length * chrsz; i += chrsz)
+  {
+    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
+  }
+  return bin;
+}
+
+/*
+ * Convert an array of big-endian words to a string
+ */
+function binb2str(bin)
+{
+  var str = "";
+  var mask = (1 << chrsz) - 1;
+  for (var i = 0; i < bin.length * 32; i += chrsz)
+  {
+    str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
+  }
+  return str;
+}
+
+/*
+ * Convert an array of big-endian words to a hex string.
+ */
+function binb2hex(binarray)
+{
+  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+  var str = "";
+  for (var i = 0; i < binarray.length * 4; i++)
+  {
+    str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
+           hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8  )) & 0xF);
+  }
+  return str;
+}
+
+/*
+ * Convert an array of big-endian words to a base-64 string
+ */
+function binb2b64(binarray)
+{
+  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  var str = "";
+  var triplet, j;
+  for (var i = 0; i < binarray.length * 4; i += 3)
+  {
+    triplet = (((binarray[i   >> 2] >> 8 * (3 -  i   %4)) & 0xFF) << 16) |
+              (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) |
+               ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
+    for (j = 0; j < 4; j++)
+    {
+      if (i * 8 + j * 6 > binarray.length * 32) { str += b64pad; }
+      else { str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); }
+    }
+  }
+  return str;
+}
diff --git a/views/default/js/strophe.min.js.php b/views/default/js/strophe.min.js.php
new file mode 100644 (file)
index 0000000..f0eb179
--- /dev/null
@@ -0,0 +1 @@
+var Base64=(function(){var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var obj={encode:function(input){var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;do{chr1=input.charCodeAt(i++);chr2=input.charCodeAt(i++);chr3=input.charCodeAt(i++);enc1=chr1>>2;enc2=((chr1&3)<<4)|(chr2>>4);enc3=((chr2&15)<<2)|(chr3>>6);enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64}else{if(isNaN(chr3)){enc4=64}}output=output+keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4)}while(i<input.length);return output},decode:function(input){var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{enc1=keyStr.indexOf(input.charAt(i++));enc2=keyStr.indexOf(input.charAt(i++));enc3=keyStr.indexOf(input.charAt(i++));enc4=keyStr.indexOf(input.charAt(i++));chr1=(enc1<<2)|(enc2>>4);chr2=((enc2&15)<<4)|(enc3>>2);chr3=((enc3&3)<<6)|enc4;output=output+String.fromCharCode(chr1);if(enc3!=64){output=output+String.fromCharCode(chr2)}if(enc4!=64){output=output+String.fromCharCode(chr3)}}while(i<input.length);return output}};return obj})();var MD5=(function(){var hexcase=0;var b64pad="";var chrsz=8;var safe_add=function(x,y){var lsw=(x&65535)+(y&65535);var msw=(x>>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&65535)};var bit_rol=function(num,cnt){return(num<<cnt)|(num>>>(32-cnt))};var str2binl=function(str){var bin=[];var mask=(1<<chrsz)-1;for(var i=0;i<str.length*chrsz;i+=chrsz){bin[i>>5]|=(str.charCodeAt(i/chrsz)&mask)<<(i%32)}return bin};var binl2str=function(bin){var str="";var mask=(1<<chrsz)-1;for(var i=0;i<bin.length*32;i+=chrsz){str+=String.fromCharCode((bin[i>>5]>>>(i%32))&mask)}return str};var binl2hex=function(binarray){var hex_tab=hexcase?"0123456789ABCDEF":"0123456789abcdef";var str="";for(var i=0;i<binarray.length*4;i++){str+=hex_tab.charAt((binarray[i>>2]>>((i%4)*8+4))&15)+hex_tab.charAt((binarray[i>>2]>>((i%4)*8))&15)}return str};var binl2b64=function(binarray){var tab="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var str="";var triplet,j;for(var i=0;i<binarray.length*4;i+=3){triplet=(((binarray[i>>2]>>8*(i%4))&255)<<16)|(((binarray[i+1>>2]>>8*((i+1)%4))&255)<<8)|((binarray[i+2>>2]>>8*((i+2)%4))&255);for(j=0;j<4;j++){if(i*8+j*6>binarray.length*32){str+=b64pad}else{str+=tab.charAt((triplet>>6*(3-j))&63)}}}return str};var md5_cmn=function(q,a,b,x,s,t){return safe_add(bit_rol(safe_add(safe_add(a,q),safe_add(x,t)),s),b)};var md5_ff=function(a,b,c,d,x,s,t){return md5_cmn((b&c)|((~b)&d),a,b,x,s,t)};var md5_gg=function(a,b,c,d,x,s,t){return md5_cmn((b&d)|(c&(~d)),a,b,x,s,t)};var md5_hh=function(a,b,c,d,x,s,t){return md5_cmn(b^c^d,a,b,x,s,t)};var md5_ii=function(a,b,c,d,x,s,t){return md5_cmn(c^(b|(~d)),a,b,x,s,t)};var core_md5=function(x,len){x[len>>5]|=128<<((len)%32);x[(((len+64)>>>9)<<4)+14]=len;var a=1732584193;var b=-271733879;var c=-1732584194;var d=271733878;var olda,oldb,oldc,oldd;for(var i=0;i<x.length;i+=16){olda=a;oldb=b;oldc=c;oldd=d;a=md5_ff(a,b,c,d,x[i+0],7,-680876936);d=md5_ff(d,a,b,c,x[i+1],12,-389564586);c=md5_ff(c,d,a,b,x[i+2],17,606105819);b=md5_ff(b,c,d,a,x[i+3],22,-1044525330);a=md5_ff(a,b,c,d,x[i+4],7,-176418897);d=md5_ff(d,a,b,c,x[i+5],12,1200080426);c=md5_ff(c,d,a,b,x[i+6],17,-1473231341);b=md5_ff(b,c,d,a,x[i+7],22,-45705983);a=md5_ff(a,b,c,d,x[i+8],7,1770035416);d=md5_ff(d,a,b,c,x[i+9],12,-1958414417);c=md5_ff(c,d,a,b,x[i+10],17,-42063);b=md5_ff(b,c,d,a,x[i+11],22,-1990404162);a=md5_ff(a,b,c,d,x[i+12],7,1804603682);d=md5_ff(d,a,b,c,x[i+13],12,-40341101);c=md5_ff(c,d,a,b,x[i+14],17,-1502002290);b=md5_ff(b,c,d,a,x[i+15],22,1236535329);a=md5_gg(a,b,c,d,x[i+1],5,-165796510);d=md5_gg(d,a,b,c,x[i+6],9,-1069501632);c=md5_gg(c,d,a,b,x[i+11],14,643717713);b=md5_gg(b,c,d,a,x[i+0],20,-373897302);a=md5_gg(a,b,c,d,x[i+5],5,-701558691);d=md5_gg(d,a,b,c,x[i+10],9,38016083);c=md5_gg(c,d,a,b,x[i+15],14,-660478335);b=md5_gg(b,c,d,a,x[i+4],20,-405537848);a=md5_gg(a,b,c,d,x[i+9],5,568446438);d=md5_gg(d,a,b,c,x[i+14],9,-1019803690);c=md5_gg(c,d,a,b,x[i+3],14,-187363961);b=md5_gg(b,c,d,a,x[i+8],20,1163531501);a=md5_gg(a,b,c,d,x[i+13],5,-1444681467);d=md5_gg(d,a,b,c,x[i+2],9,-51403784);c=md5_gg(c,d,a,b,x[i+7],14,1735328473);b=md5_gg(b,c,d,a,x[i+12],20,-1926607734);a=md5_hh(a,b,c,d,x[i+5],4,-378558);d=md5_hh(d,a,b,c,x[i+8],11,-2022574463);c=md5_hh(c,d,a,b,x[i+11],16,1839030562);b=md5_hh(b,c,d,a,x[i+14],23,-35309556);a=md5_hh(a,b,c,d,x[i+1],4,-1530992060);d=md5_hh(d,a,b,c,x[i+4],11,1272893353);c=md5_hh(c,d,a,b,x[i+7],16,-155497632);b=md5_hh(b,c,d,a,x[i+10],23,-1094730640);a=md5_hh(a,b,c,d,x[i+13],4,681279174);d=md5_hh(d,a,b,c,x[i+0],11,-358537222);c=md5_hh(c,d,a,b,x[i+3],16,-722521979);b=md5_hh(b,c,d,a,x[i+6],23,76029189);a=md5_hh(a,b,c,d,x[i+9],4,-640364487);d=md5_hh(d,a,b,c,x[i+12],11,-421815835);c=md5_hh(c,d,a,b,x[i+15],16,530742520);b=md5_hh(b,c,d,a,x[i+2],23,-995338651);a=md5_ii(a,b,c,d,x[i+0],6,-198630844);d=md5_ii(d,a,b,c,x[i+7],10,1126891415);c=md5_ii(c,d,a,b,x[i+14],15,-1416354905);b=md5_ii(b,c,d,a,x[i+5],21,-57434055);a=md5_ii(a,b,c,d,x[i+12],6,1700485571);d=md5_ii(d,a,b,c,x[i+3],10,-1894986606);c=md5_ii(c,d,a,b,x[i+10],15,-1051523);b=md5_ii(b,c,d,a,x[i+1],21,-2054922799);a=md5_ii(a,b,c,d,x[i+8],6,1873313359);d=md5_ii(d,a,b,c,x[i+15],10,-30611744);c=md5_ii(c,d,a,b,x[i+6],15,-1560198380);b=md5_ii(b,c,d,a,x[i+13],21,1309151649);a=md5_ii(a,b,c,d,x[i+4],6,-145523070);d=md5_ii(d,a,b,c,x[i+11],10,-1120210379);c=md5_ii(c,d,a,b,x[i+2],15,718787259);b=md5_ii(b,c,d,a,x[i+9],21,-343485551);a=safe_add(a,olda);b=safe_add(b,oldb);c=safe_add(c,oldc);d=safe_add(d,oldd)}return[a,b,c,d]};var core_hmac_md5=function(key,data){var bkey=str2binl(key);if(bkey.length>16){bkey=core_md5(bkey,key.length*chrsz)}var ipad=new Array(16),opad=new Array(16);for(var i=0;i<16;i++){ipad[i]=bkey[i]^909522486;opad[i]=bkey[i]^1549556828}var hash=core_md5(ipad.concat(str2binl(data)),512+data.length*chrsz);return core_md5(opad.concat(hash),512+128)};var obj={hexdigest:function(s){return binl2hex(core_md5(str2binl(s),s.length*chrsz))},b64digest:function(s){return binl2b64(core_md5(str2binl(s),s.length*chrsz))},hash:function(s){return binl2str(core_md5(str2binl(s),s.length*chrsz))},hmac_hexdigest:function(key,data){return binl2hex(core_hmac_md5(key,data))},hmac_b64digest:function(key,data){return binl2b64(core_hmac_md5(key,data))},hmac_hash:function(key,data){return binl2str(core_hmac_md5(key,data))},test:function(){return MD5.hexdigest("abc")==="900150983cd24fb0d6963f7d28e17f72"}};return obj})();if(!Function.prototype.bind){Function.prototype.bind=function(obj){var func=this;return function(){return func.apply(obj,arguments)}}}if(!Function.prototype.prependArg){Function.prototype.prependArg=function(arg){var func=this;return function(){var newargs=[arg];for(var i=0;i<arguments.length;i++){newargs.push(arguments[i])}return func.apply(this,newargs)}}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(elt){var len=this.length;var from=Number(arguments[1])||0;from=(from<0)?Math.ceil(from):Math.floor(from);if(from<0){from+=len}for(;from<len;from++){if(from in this&&this[from]===elt){return from}}return -1}}(function(callback){var Strophe;function $build(name,attrs){return new Strophe.Builder(name,attrs)}function $msg(attrs){return new Strophe.Builder("message",attrs)}function $iq(attrs){return new Strophe.Builder("iq",attrs)}function $pres(attrs){return new Strophe.Builder("presence",attrs)}Strophe={VERSION:"1.0.1",NS:{HTTPBIND:"http://jabber.org/protocol/httpbind",BOSH:"urn:xmpp:xbosh",CLIENT:"jabber:client",AUTH:"jabber:iq:auth",ROSTER:"jabber:iq:roster",PROFILE:"jabber:iq:profile",DISCO_INFO:"http://jabber.org/protocol/disco#info",DISCO_ITEMS:"http://jabber.org/protocol/disco#items",MUC:"http://jabber.org/protocol/muc",SASL:"urn:ietf:params:xml:ns:xmpp-sasl",STREAM:"http://etherx.jabber.org/streams",BIND:"urn:ietf:params:xml:ns:xmpp-bind",SESSION:"urn:ietf:params:xml:ns:xmpp-session",VERSION:"jabber:iq:version",STANZAS:"urn:ietf:params:xml:ns:xmpp-stanzas"},addNamespace:function(name,value){Strophe.NS[name]=value},Status:{ERROR:0,CONNECTING:1,CONNFAIL:2,AUTHENTICATING:3,AUTHFAIL:4,CONNECTED:5,DISCONNECTED:6,DISCONNECTING:7,ATTACHED:8},LogLevel:{DEBUG:0,INFO:1,WARN:2,ERROR:3,FATAL:4},ElementType:{NORMAL:1,TEXT:3},TIMEOUT:1.1,SECONDARY_TIMEOUT:0.1,forEachChild:function(elem,elemName,func){var i,childNode;for(i=0;i<elem.childNodes.length;i++){childNode=elem.childNodes[i];if(childNode.nodeType==Strophe.ElementType.NORMAL&&(!elemName||this.isTagEqual(childNode,elemName))){func(childNode)}}},isTagEqual:function(el,name){return el.tagName.toLowerCase()==name.toLowerCase()},_xmlGenerator:null,_makeGenerator:function(){var doc;if(window.ActiveXObject){doc=new ActiveXObject("Microsoft.XMLDOM");doc.appendChild(doc.createElement("strophe"))}else{doc=document.implementation.createDocument("jabber:client","strophe",null)}return doc},xmlElement:function(name){if(!name){return null}var node=null;if(!Strophe._xmlGenerator){Strophe._xmlGenerator=Strophe._makeGenerator()}node=Strophe._xmlGenerator.createElement(name);var a,i,k;for(a=1;a<arguments.length;a++){if(!arguments[a]){continue}if(typeof(arguments[a])=="string"||typeof(arguments[a])=="number"){node.appendChild(Strophe.xmlTextNode(arguments[a]))}else{if(typeof(arguments[a])=="object"&&typeof(arguments[a].sort)=="function"){for(i=0;i<arguments[a].length;i++){if(typeof(arguments[a][i])=="object"&&typeof(arguments[a][i].sort)=="function"){node.setAttribute(arguments[a][i][0],arguments[a][i][1])}}}else{if(typeof(arguments[a])=="object"){for(k in arguments[a]){if(arguments[a].hasOwnProperty(k)){node.setAttribute(k,arguments[a][k])}}}}}}return node},xmlescape:function(text){text=text.replace(/\&/g,"&amp;");text=text.replace(/</g,"&lt;");text=text.replace(/>/g,"&gt;");return text},xmlTextNode:function(text){text=Strophe.xmlescape(text);if(!Strophe._xmlGenerator){Strophe._xmlGenerator=Strophe._makeGenerator()}return Strophe._xmlGenerator.createTextNode(text)},getText:function(elem){if(!elem){return null}var str="";if(elem.childNodes.length===0&&elem.nodeType==Strophe.ElementType.TEXT){str+=elem.nodeValue}for(var i=0;i<elem.childNodes.length;i++){if(elem.childNodes[i].nodeType==Strophe.ElementType.TEXT){str+=elem.childNodes[i].nodeValue}}return str},copyElement:function(elem){var i,el;if(elem.nodeType==Strophe.ElementType.NORMAL){el=Strophe.xmlElement(elem.tagName);for(i=0;i<elem.attributes.length;i++){el.setAttribute(elem.attributes[i].nodeName.toLowerCase(),elem.attributes[i].value)}for(i=0;i<elem.childNodes.length;i++){el.appendChild(Strophe.copyElement(elem.childNodes[i]))}}else{if(elem.nodeType==Strophe.ElementType.TEXT){el=Strophe.xmlTextNode(elem.nodeValue)}}return el},escapeNode:function(node){return node.replace(/^\s+|\s+$/g,"").replace(/\\/g,"\\5c").replace(/ /g,"\\20").replace(/\"/g,"\\22").replace(/\&/g,"\\26").replace(/\'/g,"\\27").replace(/\//g,"\\2f").replace(/:/g,"\\3a").replace(/</g,"\\3c").replace(/>/g,"\\3e").replace(/@/g,"\\40")},unescapeNode:function(node){return node.replace(/\\20/g," ").replace(/\\22/g,'"').replace(/\\26/g,"&").replace(/\\27/g,"'").replace(/\\2f/g,"/").replace(/\\3a/g,":").replace(/\\3c/g,"<").replace(/\\3e/g,">").replace(/\\40/g,"@").replace(/\\5c/g,"\\")},getNodeFromJid:function(jid){if(jid.indexOf("@")<0){return null}return jid.split("@")[0]},getDomainFromJid:function(jid){var bare=Strophe.getBareJidFromJid(jid);if(bare.indexOf("@")<0){return bare}else{var parts=bare.split("@");parts.splice(0,1);return parts.join("@")}},getResourceFromJid:function(jid){var s=jid.split("/");if(s.length<2){return null}s.splice(0,1);return s.join("/")},getBareJidFromJid:function(jid){return jid.split("/")[0]},log:function(level,msg){return},debug:function(msg){this.log(this.LogLevel.DEBUG,msg)},info:function(msg){this.log(this.LogLevel.INFO,msg)},warn:function(msg){this.log(this.LogLevel.WARN,msg)},error:function(msg){this.log(this.LogLevel.ERROR,msg)},fatal:function(msg){this.log(this.LogLevel.FATAL,msg)},serialize:function(elem){var result;if(!elem){return null}if(typeof(elem.tree)==="function"){elem=elem.tree()}var nodeName=elem.nodeName;var i,child;if(elem.getAttribute("_realname")){nodeName=elem.getAttribute("_realname")}result="<"+nodeName;for(i=0;i<elem.attributes.length;i++){if(elem.attributes[i].nodeName!="_realname"){result+=" "+elem.attributes[i].nodeName.toLowerCase()+"='"+elem.attributes[i].value.replace("&","&amp;").replace("'","&apos;").replace("<","&lt;")+"'"}}if(elem.childNodes.length>0){result+=">";for(i=0;i<elem.childNodes.length;i++){child=elem.childNodes[i];if(child.nodeType==Strophe.ElementType.NORMAL){result+=Strophe.serialize(child)}else{if(child.nodeType==Strophe.ElementType.TEXT){result+=child.nodeValue}}}result+="</"+nodeName+">"}else{result+="/>"}return result},_requestId:0,_connectionPlugins:{},addConnectionPlugin:function(name,ptype){Strophe._connectionPlugins[name]=ptype}};Strophe.Builder=function(name,attrs){if(name=="presence"||name=="message"||name=="iq"){if(attrs&&!attrs.xmlns){attrs.xmlns=Strophe.NS.CLIENT}else{if(!attrs){attrs={xmlns:Strophe.NS.CLIENT}}}}this.nodeTree=Strophe.xmlElement(name,attrs);this.node=this.nodeTree};Strophe.Builder.prototype={tree:function(){return this.nodeTree},toString:function(){return Strophe.serialize(this.nodeTree)},up:function(){this.node=this.node.parentNode;return this},attrs:function(moreattrs){for(var k in moreattrs){if(moreattrs.hasOwnProperty(k)){this.node.setAttribute(k,moreattrs[k])}}return this},c:function(name,attrs){var child=Strophe.xmlElement(name,attrs);this.node.appendChild(child);this.node=child;return this},cnode:function(elem){this.node.appendChild(elem);this.node=elem;return this},t:function(text){var child=Strophe.xmlTextNode(text);this.node.appendChild(child);return this}};Strophe.Handler=function(handler,ns,name,type,id,from,options){this.handler=handler;this.ns=ns;this.name=name;this.type=type;this.id=id;this.options=options||{matchbare:false};if(!this.options.matchBare){this.options.matchBare=false}if(this.options.matchBare){this.from=Strophe.getBareJidFromJid(from)}else{this.from=from}this.user=true};Strophe.Handler.prototype={isMatch:function(elem){var nsMatch;var from=null;if(this.options.matchBare){from=Strophe.getBareJidFromJid(elem.getAttribute("from"))}else{from=elem.getAttribute("from")}nsMatch=false;if(!this.ns){nsMatch=true}else{var self=this;Strophe.forEachChild(elem,null,function(elem){if(elem.getAttribute("xmlns")==self.ns){nsMatch=true}});nsMatch=nsMatch||elem.getAttribute("xmlns")==this.ns}if(nsMatch&&(!this.name||Strophe.isTagEqual(elem,this.name))&&(!this.type||elem.getAttribute("type")===this.type)&&(!this.id||elem.getAttribute("id")===this.id)&&(!this.from||from===this.from)){return true}return false},run:function(elem){var result=null;try{result=this.handler(elem)}catch(e){if(e.sourceURL){Strophe.fatal("error: "+this.handler+" "+e.sourceURL+":"+e.line+" - "+e.name+": "+e.message)}else{if(e.fileName){if(typeof(console)!="undefined"){console.trace();console.error(this.handler," - error - ",e,e.message)}Strophe.fatal("error: "+this.handler+" "+e.fileName+":"+e.lineNumber+" - "+e.name+": "+e.message)}else{Strophe.fatal("error: "+this.handler)}}throw e}return result},toString:function(){return"{Handler: "+this.handler+"("+this.name+","+this.id+","+this.ns+")}"}};Strophe.TimedHandler=function(period,handler){this.period=period;this.handler=handler;this.lastCalled=new Date().getTime();this.user=true};Strophe.TimedHandler.prototype={run:function(){this.lastCalled=new Date().getTime();return this.handler()},reset:function(){this.lastCalled=new Date().getTime()},toString:function(){return"{TimedHandler: "+this.handler+"("+this.period+")}"}};Strophe.Request=function(elem,func,rid,sends){this.id=++Strophe._requestId;this.xmlData=elem;this.data=Strophe.serialize(elem);this.origFunc=func;this.func=func;this.rid=rid;this.date=NaN;this.sends=sends||0;this.abort=false;this.dead=null;this.age=function(){if(!this.date){return 0}var now=new Date();return(now-this.date)/1000};this.timeDead=function(){if(!this.dead){return 0}var now=new Date();return(now-this.dead)/1000};this.xhr=this._newXHR()};Strophe.Request.prototype={getResponse:function(){var node=null;if(this.xhr.responseXML&&this.xhr.responseXML.documentElement){node=this.xhr.responseXML.documentElement;if(node.tagName=="parsererror"){Strophe.error("invalid response received");Strophe.error("responseText: "+this.xhr.responseText);Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML));throw"parsererror"}}else{if(this.xhr.responseText){Strophe.error("invalid response received");Strophe.error("responseText: "+this.xhr.responseText);Strophe.error("responseXML: "+Strophe.serialize(this.xhr.responseXML))}}return node},_newXHR:function(){var xhr=null;if(window.XMLHttpRequest){xhr=new XMLHttpRequest();if(xhr.overrideMimeType){xhr.overrideMimeType("text/xml")}}else{if(window.ActiveXObject){xhr=new ActiveXObject("Microsoft.XMLHTTP")}}xhr.onreadystatechange=this.func.prependArg(this);return xhr}};Strophe.Connection=function(service){this.service=service;this.jid="";this.rid=Math.floor(Math.random()*4294967295);this.sid=null;this.streamId=null;this.do_session=false;this.do_bind=false;this.timedHandlers=[];this.handlers=[];this.removeTimeds=[];this.removeHandlers=[];this.addTimeds=[];this.addHandlers=[];this._idleTimeout=null;this._disconnectTimeout=null;this.authenticated=false;this.disconnecting=false;this.connected=false;this.errors=0;this.paused=false;this.hold=1;this.wait=60;this.window=5;this._data=[];this._requests=[];this._uniqueId=Math.round(Math.random()*10000);this._sasl_success_handler=null;this._sasl_failure_handler=null;this._sasl_challenge_handler=null;this._idleTimeout=setTimeout(this._onIdle.bind(this),100);for(var k in Strophe._connectionPlugins){if(Strophe._connectionPlugins.hasOwnProperty(k)){var ptype=Strophe._connectionPlugins[k];var F=function(){};F.prototype=ptype;this[k]=new F();this[k].init(this)}}};Strophe.Connection.prototype={reset:function(){this.rid=Math.floor(Math.random()*4294967295);this.sid=null;this.streamId=null;this.do_session=false;this.do_bind=false;this.timedHandlers=[];this.handlers=[];this.removeTimeds=[];this.removeHandlers=[];this.addTimeds=[];this.addHandlers=[];this.authenticated=false;this.disconnecting=false;this.connected=false;this.errors=0;this._requests=[];this._uniqueId=Math.round(Math.random()*10000)},pause:function(){this.paused=true},resume:function(){this.paused=false},getUniqueId:function(suffix){if(typeof(suffix)=="string"||typeof(suffix)=="number"){return ++this._uniqueId+":"+suffix}else{return ++this._uniqueId+""}},connect:function(jid,pass,callback,wait,hold){this.jid=jid;this.pass=pass;this.connect_callback=callback;this.disconnecting=false;this.connected=false;this.authenticated=false;this.errors=0;this.wait=wait||this.wait;this.hold=hold||this.hold;this.domain=Strophe.getDomainFromJid(this.jid);var body=this._buildBody().attrs({to:this.domain,"xml:lang":"en",wait:this.wait,hold:this.hold,content:"text/xml; charset=utf-8",ver:"1.6","xmpp:version":"1.0","xmlns:xmpp":Strophe.NS.BOSH});this._changeConnectStatus(Strophe.Status.CONNECTING,null);this._requests.push(new Strophe.Request(body.tree(),this._onRequestStateChange.bind(this).prependArg(this._connect_cb.bind(this)),body.tree().getAttribute("rid")));this._throttledRequestHandler()},attach:function(jid,sid,rid,callback,wait,hold,wind){this.jid=jid;this.sid=sid;this.rid=rid;this.connect_callback=callback;this.domain=Strophe.getDomainFromJid(this.jid);this.authenticated=true;this.connected=true;this.wait=wait||this.wait;this.hold=hold||this.hold;this.window=wind||this.window;this._changeConnectStatus(Strophe.Status.ATTACHED,null)},xmlInput:function(elem){return},xmlOutput:function(elem){return},rawInput:function(data){return},rawOutput:function(data){return},send:function(elem){if(elem===null){return}if(typeof(elem.sort)==="function"){for(var i=0;i<elem.length;i++){this._queueData(elem[i])}}else{if(typeof(elem.tree)==="function"){this._queueData(elem.tree())}else{this._queueData(elem)}}this._throttledRequestHandler();clearTimeout(this._idleTimeout);this._idleTimeout=setTimeout(this._onIdle.bind(this),100)},flush:function(){clearTimeout(this._idleTimeout);this._onIdle()},sendIQ:function(elem,callback,errback,timeout){var timeoutHandler=null;var that=this;if(typeof(elem.tree)==="function"){elem=elem.tree()}var id=elem.getAttribute("id");if(!id){id=this.getUniqueId("sendIQ");elem.setAttribute("id",id)}var handler=this.addHandler(function(stanza){if(timeoutHandler){that.deleteTimedHandler(timeoutHandler)}var iqtype=stanza.getAttribute("type");if(iqtype==="result"){if(callback){callback(stanza)}}else{if(iqtype==="error"){if(errback){errback(stanza)}}else{throw {name:"StropheError",message:"Got bad IQ type of "+iqtype}}}},null,"iq",null,id);if(timeout){timeoutHandler=this.addTimedHandler(timeout,function(){that.deleteHandler(handler);if(errback){errback(null)}return false})}this.send(elem);return id},_queueData:function(element){if(element===null||!element.tagName||!element.childNodes){throw {name:"StropheError",message:"Cannot queue non-DOMElement."}}this._data.push(element)},_sendRestart:function(){this._data.push("restart");this._throttledRequestHandler();clearTimeout(this._idleTimeout);this._idleTimeout=setTimeout(this._onIdle.bind(this),100)},addTimedHandler:function(period,handler){var thand=new Strophe.TimedHandler(period,handler);this.addTimeds.push(thand);return thand},deleteTimedHandler:function(handRef){this.removeTimeds.push(handRef)},addHandler:function(handler,ns,name,type,id,from,options){var hand=new Strophe.Handler(handler,ns,name,type,id,from,options);this.addHandlers.push(hand);return hand},deleteHandler:function(handRef){this.removeHandlers.push(handRef)},disconnect:function(reason){this._changeConnectStatus(Strophe.Status.DISCONNECTING,reason);Strophe.info("Disconnect was called because: "+reason);if(this.connected){this._disconnectTimeout=this._addSysTimedHandler(3000,this._onDisconnectTimeout.bind(this));this._sendTerminate()}},_changeConnectStatus:function(status,condition){for(var k in Strophe._connectionPlugins){if(Strophe._connectionPlugins.hasOwnProperty(k)){var plugin=this[k];if(plugin.statusChanged){try{plugin.statusChanged(status,condition)}catch(err){Strophe.error(""+k+" plugin caused an exception changing status: "+err)}}}}if(this.connect_callback){try{this.connect_callback(status,condition)}catch(e){Strophe.error("User connection callback caused an exception: "+e)}}},_buildBody:function(){var bodyWrap=$build("body",{rid:this.rid++,xmlns:Strophe.NS.HTTPBIND});if(this.sid!==null){bodyWrap.attrs({sid:this.sid})}return bodyWrap},_removeRequest:function(req){Strophe.debug("removing request");var i;for(i=this._requests.length-1;i>=0;i--){if(req==this._requests[i]){this._requests.splice(i,1)}}req.xhr.onreadystatechange=function(){};this._throttledRequestHandler()},_restartRequest:function(i){var req=this._requests[i];if(req.dead===null){req.dead=new Date()}this._processRequest(i)},_processRequest:function(i){var req=this._requests[i];var reqStatus=-1;try{if(req.xhr.readyState==4){reqStatus=req.xhr.status}}catch(e){Strophe.error("caught an error in _requests["+i+"], reqStatus: "+reqStatus)}if(typeof(reqStatus)=="undefined"){reqStatus=-1}var time_elapsed=req.age();var primaryTimeout=(!isNaN(time_elapsed)&&time_elapsed>Math.floor(Strophe.TIMEOUT*this.wait));var secondaryTimeout=(req.dead!==null&&req.timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait));var requestCompletedWithServerError=(req.xhr.readyState==4&&(reqStatus<1||reqStatus>=500));if(primaryTimeout||secondaryTimeout||requestCompletedWithServerError){if(secondaryTimeout){Strophe.error("Request "+this._requests[i].id+" timed out (secondary), restarting")}req.abort=true;req.xhr.abort();req.xhr.onreadystatechange=function(){};this._requests[i]=new Strophe.Request(req.xmlData,req.origFunc,req.rid,req.sends);req=this._requests[i]}if(req.xhr.readyState===0){Strophe.debug("request id "+req.id+"."+req.sends+" posting");req.date=new Date();try{req.xhr.open("POST",this.service,true)}catch(e2){Strophe.error("XHR open failed.");if(!this.connected){this._changeConnectStatus(Strophe.Status.CONNFAIL,"bad-service")}this.disconnect();return}var sendFunc=function(){req.xhr.send(req.data)};if(req.sends>1){var backoff=Math.pow(req.sends,3)*1000;setTimeout(sendFunc,backoff)}else{sendFunc()}req.sends++;this.xmlOutput(req.xmlData);this.rawOutput(req.data)}else{Strophe.debug("_processRequest: "+(i===0?"first":"second")+" request has readyState of "+req.xhr.readyState)}},_throttledRequestHandler:function(){if(!this._requests){Strophe.debug("_throttledRequestHandler called with undefined requests")}else{Strophe.debug("_throttledRequestHandler called with "+this._requests.length+" requests")}if(!this._requests||this._requests.length===0){return}if(this._requests.length>0){this._processRequest(0)}if(this._requests.length>1&&Math.abs(this._requests[0].rid-this._requests[1].rid)<this.window-1){this._processRequest(1)}},_onRequestStateChange:function(func,req){Strophe.debug("request id "+req.id+"."+req.sends+" state changed to "+req.xhr.readyState);if(req.abort){req.abort=false;return}var reqStatus;if(req.xhr.readyState==4){reqStatus=0;try{reqStatus=req.xhr.status}catch(e){}if(typeof(reqStatus)=="undefined"){reqStatus=0}if(this.disconnecting){if(reqStatus>=400){this._hitError(reqStatus);return}}var reqIs0=(this._requests[0]==req);var reqIs1=(this._requests[1]==req);if((reqStatus>0&&reqStatus<500)||req.sends>5){this._removeRequest(req);Strophe.debug("request id "+req.id+" should now be removed")}if(reqStatus==200){if(reqIs1||(reqIs0&&this._requests.length>0&&this._requests[0].age()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait))){this._restartRequest(0)}Strophe.debug("request id "+req.id+"."+req.sends+" got 200");func(req);this.errors=0}else{Strophe.error("request id "+req.id+"."+req.sends+" error "+reqStatus+" happened");if(reqStatus===0||(reqStatus>=400&&reqStatus<600)||reqStatus>=12000){this._hitError(reqStatus);if(reqStatus>=400&&reqStatus<500){this._changeConnectStatus(Strophe.Status.DISCONNECTING,null);this._doDisconnect()}}}if(!((reqStatus>0&&reqStatus<10000)||req.sends>5)){this._throttledRequestHandler()}}},_hitError:function(reqStatus){this.errors++;Strophe.warn("request errored, status: "+reqStatus+", number of errors: "+this.errors);if(this.errors>4){this._onDisconnectTimeout()}},_doDisconnect:function(){Strophe.info("_doDisconnect was called");this.authenticated=false;this.disconnecting=false;this.sid=null;this.streamId=null;this.rid=Math.floor(Math.random()*4294967295);if(this.connected){this._changeConnectStatus(Strophe.Status.DISCONNECTED,null);this.connected=false}this.handlers=[];this.timedHandlers=[];this.removeTimeds=[];this.removeHandlers=[];this.addTimeds=[];this.addHandlers=[]},_dataRecv:function(req){try{var elem=req.getResponse()}catch(e){if(e!="parsererror"){throw e}this.disconnect("strophe-parsererror")}if(elem===null){return}this.xmlInput(elem);this.rawInput(Strophe.serialize(elem));var i,hand;while(this.removeHandlers.length>0){hand=this.removeHandlers.pop();i=this.handlers.indexOf(hand);if(i>=0){this.handlers.splice(i,1)}}while(this.addHandlers.length>0){this.handlers.push(this.addHandlers.pop())}if(this.disconnecting&&this._requests.length===0){this.deleteTimedHandler(this._disconnectTimeout);this._disconnectTimeout=null;this._doDisconnect();return}var typ=elem.getAttribute("type");var cond,conflict;if(typ!==null&&typ=="terminate"){cond=elem.getAttribute("condition");conflict=elem.getElementsByTagName("conflict");if(cond!==null){if(cond=="remote-stream-error"&&conflict.length>0){cond="conflict"}this._changeConnectStatus(Strophe.Status.CONNFAIL,cond)}else{this._changeConnectStatus(Strophe.Status.CONNFAIL,"unknown")}this.disconnect();return}var self=this;Strophe.forEachChild(elem,null,function(child){var i,newList;newList=self.handlers;self.handlers=[];for(i=0;i<newList.length;i++){var hand=newList[i];if(hand.isMatch(child)&&(self.authenticated||!hand.user)){if(hand.run(child)){self.handlers.push(hand)}}else{self.handlers.push(hand)}}})},_sendTerminate:function(){Strophe.info("_sendTerminate was called");var body=this._buildBody().attrs({type:"terminate"});if(this.authenticated){body.c("presence",{xmlns:Strophe.NS.CLIENT,type:"unavailable"})}this.disconnecting=true;var req=new Strophe.Request(body.tree(),this._onRequestStateChange.bind(this).prependArg(this._dataRecv.bind(this)),body.tree().getAttribute("rid"));this._requests.push(req);this._throttledRequestHandler()},_connect_cb:function(req){Strophe.info("_connect_cb was called");this.connected=true;var bodyWrap=req.getResponse();if(!bodyWrap){return}this.xmlInput(bodyWrap);this.rawInput(Strophe.serialize(bodyWrap));var typ=bodyWrap.getAttribute("type");var cond,conflict;if(typ!==null&&typ=="terminate"){cond=bodyWrap.getAttribute("condition");conflict=bodyWrap.getElementsByTagName("conflict");if(cond!==null){if(cond=="remote-stream-error"&&conflict.length>0){cond="conflict"}this._changeConnectStatus(Strophe.Status.CONNFAIL,cond)}else{this._changeConnectStatus(Strophe.Status.CONNFAIL,"unknown")}return}if(!this.sid){this.sid=bodyWrap.getAttribute("sid")}if(!this.stream_id){this.stream_id=bodyWrap.getAttribute("authid")}var wind=bodyWrap.getAttribute("requests");if(wind){this.window=parseInt(wind,10)}var hold=bodyWrap.getAttribute("hold");if(hold){this.hold=parseInt(hold,10)}var wait=bodyWrap.getAttribute("wait");if(wait){this.wait=parseInt(wait,10)}var do_sasl_plain=false;var do_sasl_digest_md5=false;var do_sasl_anonymous=false;var mechanisms=bodyWrap.getElementsByTagName("mechanism");var i,mech,auth_str,hashed_auth_str;if(mechanisms.length>0){for(i=0;i<mechanisms.length;i++){mech=Strophe.getText(mechanisms[i]);if(mech=="DIGEST-MD5"){do_sasl_digest_md5=true}else{if(mech=="PLAIN"){do_sasl_plain=true}else{if(mech=="ANONYMOUS"){do_sasl_anonymous=true}}}}}else{var body=this._buildBody();this._requests.push(new Strophe.Request(body.tree(),this._onRequestStateChange.bind(this).prependArg(this._connect_cb.bind(this)),body.tree().getAttribute("rid")));this._throttledRequestHandler();return}if(Strophe.getNodeFromJid(this.jid)===null&&do_sasl_anonymous){this._changeConnectStatus(Strophe.Status.AUTHENTICATING,null);this._sasl_success_handler=this._addSysHandler(this._sasl_success_cb.bind(this),null,"success",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);this.send($build("auth",{xmlns:Strophe.NS.SASL,mechanism:"ANONYMOUS"}).tree())}else{if(Strophe.getNodeFromJid(this.jid)===null){this._changeConnectStatus(Strophe.Status.CONNFAIL,"x-strophe-bad-non-anon-jid");this.disconnect()}else{if(do_sasl_digest_md5){this._changeConnectStatus(Strophe.Status.AUTHENTICATING,null);this._sasl_challenge_handler=this._addSysHandler(this._sasl_challenge1_cb.bind(this),null,"challenge",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);this.send($build("auth",{xmlns:Strophe.NS.SASL,mechanism:"DIGEST-MD5"}).tree())}else{if(do_sasl_plain){auth_str=Strophe.getBareJidFromJid(this.jid);auth_str=auth_str+"\u0000";auth_str=auth_str+Strophe.getNodeFromJid(this.jid);auth_str=auth_str+"\u0000";auth_str=auth_str+this.pass;this._changeConnectStatus(Strophe.Status.AUTHENTICATING,null);this._sasl_success_handler=this._addSysHandler(this._sasl_success_cb.bind(this),null,"success",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);hashed_auth_str=Base64.encode(auth_str);this.send($build("auth",{xmlns:Strophe.NS.SASL,mechanism:"PLAIN"}).t(hashed_auth_str).tree())}else{this._changeConnectStatus(Strophe.Status.AUTHENTICATING,null);this._addSysHandler(this._auth1_cb.bind(this),null,null,null,"_auth_1");this.send($iq({type:"get",to:this.domain,id:"_auth_1"}).c("query",{xmlns:Strophe.NS.AUTH}).c("username",{}).t(Strophe.getNodeFromJid(this.jid)).tree())}}}}},_sasl_challenge1_cb:function(elem){var attribMatch=/([a-z]+)=("[^"]+"|[^,"]+)(?:,|$)/;var challenge=Base64.decode(Strophe.getText(elem));var cnonce=MD5.hexdigest(Math.random()*1234567890);var realm="";var host=null;var nonce="";var qop="";var matches;this.deleteHandler(this._sasl_failure_handler);while(challenge.match(attribMatch)){matches=challenge.match(attribMatch);challenge=challenge.replace(matches[0],"");matches[2]=matches[2].replace(/^"(.+)"$/,"$1");switch(matches[1]){case"realm":realm=matches[2];break;case"nonce":nonce=matches[2];break;case"qop":qop=matches[2];break;case"host":host=matches[2];break}}var digest_uri="xmpp/"+this.domain;if(host!==null){digest_uri=digest_uri+"/"+host}var A1=MD5.hash(Strophe.getNodeFromJid(this.jid)+":"+realm+":"+this.pass)+":"+nonce+":"+cnonce;var A2="AUTHENTICATE:"+digest_uri;var responseText="";responseText+="username="+this._quote(Strophe.getNodeFromJid(this.jid))+",";responseText+="realm="+this._quote(realm)+",";responseText+="nonce="+this._quote(nonce)+",";responseText+="cnonce="+this._quote(cnonce)+",";responseText+='nc="00000001",';responseText+='qop="auth",';responseText+="digest-uri="+this._quote(digest_uri)+",";responseText+="response="+this._quote(MD5.hexdigest(MD5.hexdigest(A1)+":"+nonce+":00000001:"+cnonce+":auth:"+MD5.hexdigest(A2)))+",";responseText+='charset="utf-8"';this._sasl_challenge_handler=this._addSysHandler(this._sasl_challenge2_cb.bind(this),null,"challenge",null,null);this._sasl_success_handler=this._addSysHandler(this._sasl_success_cb.bind(this),null,"success",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);this.send($build("response",{xmlns:Strophe.NS.SASL}).t(Base64.encode(responseText)).tree());return false},_quote:function(str){return'"'+str.replace(/\\/g,"\\\\").replace(/"/g,'\\"')+'"'},_sasl_challenge2_cb:function(elem){this.deleteHandler(this._sasl_success_handler);this.deleteHandler(this._sasl_failure_handler);this._sasl_success_handler=this._addSysHandler(this._sasl_success_cb.bind(this),null,"success",null,null);this._sasl_failure_handler=this._addSysHandler(this._sasl_failure_cb.bind(this),null,"failure",null,null);this.send($build("response",{xmlns:Strophe.NS.SASL}).tree());return false},_auth1_cb:function(elem){var iq=$iq({type:"set",id:"_auth_2"}).c("query",{xmlns:Strophe.NS.AUTH}).c("username",{}).t(Strophe.getNodeFromJid(this.jid)).up().c("password").t(this.pass);if(!Strophe.getResourceFromJid(this.jid)){this.jid=Strophe.getBareJidFromJid(this.jid)+"/strophe"}iq.up().c("resource",{}).t(Strophe.getResourceFromJid(this.jid));this._addSysHandler(this._auth2_cb.bind(this),null,null,null,"_auth_2");this.send(iq.tree());return false},_sasl_success_cb:function(elem){Strophe.info("SASL authentication succeeded.");this.deleteHandler(this._sasl_failure_handler);this._sasl_failure_handler=null;if(this._sasl_challenge_handler){this.deleteHandler(this._sasl_challenge_handler);this._sasl_challenge_handler=null}this._addSysHandler(this._sasl_auth1_cb.bind(this),null,"stream:features",null,null);this._sendRestart();return false},_sasl_auth1_cb:function(elem){var i,child;for(i=0;i<elem.childNodes.length;i++){child=elem.childNodes[i];if(child.nodeName=="bind"){this.do_bind=true}if(child.nodeName=="session"){this.do_session=true}}if(!this.do_bind){this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}else{this._addSysHandler(this._sasl_bind_cb.bind(this),null,null,null,"_bind_auth_2");var resource=Strophe.getResourceFromJid(this.jid);if(resource){this.send($iq({type:"set",id:"_bind_auth_2"}).c("bind",{xmlns:Strophe.NS.BIND}).c("resource",{}).t(resource).tree())}else{this.send($iq({type:"set",id:"_bind_auth_2"}).c("bind",{xmlns:Strophe.NS.BIND}).tree())}}return false},_sasl_bind_cb:function(elem){if(elem.getAttribute("type")=="error"){Strophe.info("SASL binding failed.");this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}var bind=elem.getElementsByTagName("bind");var jidNode;if(bind.length>0){jidNode=bind[0].getElementsByTagName("jid");if(jidNode.length>0){this.jid=Strophe.getText(jidNode[0]);if(this.do_session){this._addSysHandler(this._sasl_session_cb.bind(this),null,null,null,"_session_auth_2");this.send($iq({type:"set",id:"_session_auth_2"}).c("session",{xmlns:Strophe.NS.SESSION}).tree())}else{this.authenticated=true;this._changeConnectStatus(Strophe.Status.CONNECTED,null)}}}else{Strophe.info("SASL binding failed.");this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}},_sasl_session_cb:function(elem){if(elem.getAttribute("type")=="result"){this.authenticated=true;this._changeConnectStatus(Strophe.Status.CONNECTED,null)}else{if(elem.getAttribute("type")=="error"){Strophe.info("Session creation failed.");this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false}}return false},_sasl_failure_cb:function(elem){if(this._sasl_success_handler){this.deleteHandler(this._sasl_success_handler);this._sasl_success_handler=null}if(this._sasl_challenge_handler){this.deleteHandler(this._sasl_challenge_handler);this._sasl_challenge_handler=null}this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);return false},_auth2_cb:function(elem){if(elem.getAttribute("type")=="result"){this.authenticated=true;this._changeConnectStatus(Strophe.Status.CONNECTED,null)}else{if(elem.getAttribute("type")=="error"){this._changeConnectStatus(Strophe.Status.AUTHFAIL,null);this.disconnect()}}return false},_addSysTimedHandler:function(period,handler){var thand=new Strophe.TimedHandler(period,handler);thand.user=false;this.addTimeds.push(thand);return thand},_addSysHandler:function(handler,ns,name,type,id){var hand=new Strophe.Handler(handler,ns,name,type,id);hand.user=false;this.addHandlers.push(hand);return hand},_onDisconnectTimeout:function(){Strophe.info("_onDisconnectTimeout was called");var req;while(this._requests.length>0){req=this._requests.pop();req.abort=true;req.xhr.abort();req.xhr.onreadystatechange=function(){}}this._doDisconnect();return false},_onIdle:function(){var i,thand,since,newList;while(this.removeTimeds.length>0){thand=this.removeTimeds.pop();i=this.timedHandlers.indexOf(thand);if(i>=0){this.timedHandlers.splice(i,1)}}while(this.addTimeds.length>0){this.timedHandlers.push(this.addTimeds.pop())}var now=new Date().getTime();newList=[];for(i=0;i<this.timedHandlers.length;i++){thand=this.timedHandlers[i];if(this.authenticated||!thand.user){since=thand.lastCalled+thand.period;if(since-now<=0){if(thand.run()){newList.push(thand)}}else{newList.push(thand)}}}this.timedHandlers=newList;var body,time_elapsed;if(this.authenticated&&this._requests.length===0&&this._data.length===0&&!this.disconnecting){Strophe.info("no requests during idle cycle, sending blank request");this._data.push(null)}if(this._requests.length<2&&this._data.length>0&&!this.paused){body=this._buildBody();for(i=0;i<this._data.length;i++){if(this._data[i]!==null){if(this._data[i]==="restart"){body.attrs({to:this.domain,"xml:lang":"en","xmpp:restart":"true","xmlns:xmpp":Strophe.NS.BOSH})}else{body.cnode(this._data[i]).up()}}}delete this._data;this._data=[];this._requests.push(new Strophe.Request(body.tree(),this._onRequestStateChange.bind(this).prependArg(this._dataRecv.bind(this)),body.tree().getAttribute("rid")));this._processRequest(this._requests.length-1)}if(this._requests.length>0){time_elapsed=this._requests[0].age();if(this._requests[0].dead!==null){if(this._requests[0].timeDead()>Math.floor(Strophe.SECONDARY_TIMEOUT*this.wait)){this._throttledRequestHandler()}}if(time_elapsed>Math.floor(Strophe.TIMEOUT*this.wait)){Strophe.warn("Request "+this._requests[0].id+" timed out, over "+Math.floor(Strophe.TIMEOUT*this.wait)+" seconds since last activity");this._throttledRequestHandler()}}clearTimeout(this._idleTimeout);this._idleTimeout=setTimeout(this._onIdle.bind(this),100)}};if(callback){callback(Strophe,$build,$msg,$iq,$pres)}})(function(){window.Strophe=arguments[0];window.$build=arguments[1];window.$msg=arguments[2];window.$iq=arguments[3];window.$pres=arguments[4]});
\ No newline at end of file
diff --git a/views/default/js/strophe.muc.js b/views/default/js/strophe.muc.js
new file mode 100644 (file)
index 0000000..954ca87
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+Plugin to implement the MUC extension. http://xmpp.org/extensions/xep-0045.html
+*/
+/* jslint configuration: */
+/* global document, window, setTimeout, clearTimeout, console,
+    XMLHttpRequest, ActiveXObject,
+    Base64, MD5,
+    Strophe, $build, $msg, $iq, $pres 
+*/
+
+Strophe.addConnectionPlugin('muc', {
+    _connection: null,
+    // The plugin must have the init function
+    /***Function
+    Initialize the MUC plugin. Sets the correct connection object and
+    extends the namesace.
+    */
+    init: function(conn) {
+        this._connection = conn;
+        /* extend name space 
+         *  NS.MUC - XMPP Multi-user chat namespace
+         *              from XEP 45.  
+         *
+         */
+        Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC+"#owner");
+        Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC+"#admin");
+    },
+    /***Function
+    Join a multi-user chat room
+    Parameters:
+    (String) room - The multi-user chat room to join.
+    (String) nick - The nickname to use in the chat room. Optional
+    (Function) msg_handler_cb - The function call to handle messages from the
+    specified chat room.
+    (Function) pres_handler_cb - The function call back to handle presence
+    in the chat room.
+    (String) password - The optional password to use. (password protected
+    rooms only)
+    */
+    join: function(room, nick, msg_handler_cb, pres_handler_cb, password) {
+        var room_nick = this.test_append_nick(room, nick);        
+        var msg = $pres({from: this._connection.jid,
+                         to: room_nick})
+            .c("x",{xmlns: Strophe.NS.MUC});
+        if (password)
+        {
+            var password_elem = Strophe.xmlElement("password", 
+                                                   [],
+                                                   password);
+            msg.cnode(password_elem);
+        }
+        if (msg_handler_cb)
+        {
+            this._connection.addHandler(function(stanza) {
+                var from = stanza.getAttribute('from');
+                var roomname = from.split("/");
+                // filter on room name
+                if (roomname.length > 1 && roomname[0] == room)
+                {
+                    return msg_handler_cb(stanza);
+                }
+                else
+                {
+                    return true;
+                }
+            },
+                                        null,
+                                        "message",
+                                        null,
+                                        null,
+                                        null);
+        }
+        if (pres_handler_cb)
+        {
+            this._connection.addHandler(function(stanza) {
+                var xquery = stanza.getElementsByTagName("x");
+                if (xquery.length > 0)
+                {
+                    //Handle only MUC user protocol
+                    for (var i = 0; i < xquery.length; i++)
+                    {
+                        var xmlns = xquery[i].getAttribute("xmlns");
+                        
+                        if (xmlns && xmlns.match(Strophe.NS.MUC))
+                        {
+                            return pres_handler_cb(stanza);
+                        }
+                    }
+                }
+                return true;                
+            },
+                                        null,
+                                        "presence",
+                                        null,
+                                        null,
+                                        null);
+        }
+        this._connection.send(msg);
+    },
+    /***Function
+    Leave a multi-user chat room
+    Parameters:
+    (String) room - The multi-user chat room to leave.
+    (String) nick - The nick name used in the room.
+    (Function) handler_cb - Optional function to handle the successful leave.
+    Returns:
+    iqid - The unique id for the room leave.
+    */
+    leave: function(room, nick, handler_cb) {
+        var room_nick = this.test_append_nick(room, nick);        
+        var presenceid = this._connection.getUniqueId();
+        var presence = $pres({type: "unavailable",
+                              id: presenceid,
+                              from: this._connection.jid,
+                              to: room_nick})
+            .c("x",{xmlns: Strophe.NS.MUC});
+        this._connection.addHandler(handler_cb,
+                                    null,
+                                    "presence",
+                                    null,
+                                    presenceid,
+                                    null);
+        this._connection.send(presence);
+        return presenceid;
+    },
+    /***Function
+    Parameters:
+    (String) room - The multi-user chat room name.
+    (String) nick - The nick name used in the chat room.
+    (String) message - The message to send to the room.
+    Returns:
+    msgiq - the unique id used to send the message
+    */
+    message: function(room, nick, message) {
+        var room_nick = this.test_append_nick(room, nick);        
+        var msgid = this._connection.getUniqueId();
+        var msg = $msg({to: room_nick,
+                        from: this._connection.jid,
+                        type: "groupchat",
+                        id: msgid}).c("body",
+                                      {xmlns: Strophe.NS.CLIENT}).t(message);
+        msg.up().c("x", {xmlns: "jabber:x:event"}).c("composing");
+        this._connection.send(msg);
+        return msgid;
+    },
+    /***Function
+    Start a room configuration.
+    Parameters:
+    (String) room - The multi-user chat room name.
+    Returns:
+    id - the unique id used to send the configuration request
+    */
+    configure: function(room) {
+        //send iq to start room configuration
+        var config = $iq({to:room,
+                          type: "get"}).c("query",
+                                          {xmlns: Strophe.NS.MUC_OWNER});
+        var stanza = config.tree();
+        return this._connection.sendIQ(stanza,
+                               function(){},
+                               function(){});
+    },
+    /***Function
+    Cancel the room configuration
+    Parameters:
+    (String) room - The multi-user chat room name.
+    Returns:
+    id - the unique id used to cancel the configuration.
+    */
+    cancelConfigure: function(room) {
+        //send iq to start room configuration
+        var config = $iq({to: room,
+                          type: "set"})
+            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
+            .c("x", {xmlns: "jabber:x:data", type: "cancel"});
+        var stanza = config.tree();
+        return this._connection.sendIQ(stanza,
+                                       function(){},
+                                       function(){});
+    },
+    /***Function
+    Save a room configuration.
+    Parameters:
+    (String) room - The multi-user chat room name.
+    (Array) configarray - an array of form elements used to configure the room.
+    Returns:
+    id - the unique id used to save the configuration.
+    */
+    saveConfiguration: function(room, configarray) {
+        var config = $iq({to: room,
+                          type: "set"})
+            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
+            .c("x", {xmlns: "jabber:x:data", type: "submit"});
+        for (var i = 0; i >= configarray.length; i++) {
+            config.cnode(configarray[i]);
+        }
+        var stanza = config.tree();
+        return this._connection.sendIQ(stanza,
+                                       function(){},
+                                       function(){});        
+    },
+    /***Function
+    Parameters:
+    (String) room - The multi-user chat room name.
+    Returns:
+    id - the unique id used to create the chat room.
+    */
+    createInstantRoom: function(room) {
+        var roomiq = $iq({to: room,
+                          type: "set"})
+            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
+            .c("x", {xmlns: "jabber:x:data",
+                     type: "submit"});
+        return this._connection.sendIQ(roomiq.tree(),
+                                       function() {},
+                                       function() {});
+    },
+    /***
+     Set the topic of the chat room.
+     Parameters:
+     (String) room - The multi-user chat room name.
+     (String) topic - Topic message.
+     */
+    setTopic: function(room, topic) {
+        var msg = $msg({to: room,
+                        from: this._connection.jid,
+                        type: "groupchat"})
+            .c("subject", {xmlns: "jabber:client"}).t(topic);
+        this._connection.send(msg.tree());
+    },
+    /***Function
+    Changes the role and affiliation of a member of a MUC room.
+    The modification can only be done by a room moderator. An error will be
+    returned if the user doesn't have permission.
+    Parameters:
+    (String) room - The multi-user chat room name.
+    (String) nick - The nick name of the user to modify.
+    (String) role - The new role of the user.
+    (String) affiliation - The new affiliation of the user.
+    (String) reason - The reason for the change.
+    Returns:
+    iq - the id of the mode change request.
+    */
+    modifyUser: function(room, nick, role, affiliation, reason) {
+        var item_attrs = {nick: Strophe.escapeNode(nick)};
+        if (role !== null)
+        {
+            item_attrs.role = role;
+        }
+        if (affiliation !== null)
+        {
+            item_attrs.affiliation = affiliation;
+        }
+        var item = $build("item", item_attrs);
+        if (reason !== null)
+        {
+            item.cnode(Strophe.xmlElement("reason", reason));
+        }
+        var roomiq = $iq({to: room,
+                          type: "set"})
+            .c("query", {xmlns: Strophe.NS.MUC_OWNER}).cnode(item.tree());
+        return this._connection.sendIQ(roomiq.tree(),
+                                       function() {},
+                                       function() {});
+    },
+    /***Function
+    Change the current users nick name.
+    Parameters:
+    (String) room - The multi-user chat room name.
+    (String) user - The new nick name.
+    */
+    changeNick: function(room, user) {
+        var room_nick = this.test_append_nick(room, user);
+        var presence = $pres({from: this._connection.jid,
+                              to: room_nick})
+            .c("x",{xmlns: Strophe.NS.MUC});
+        this._connection.send(presence.tree());
+    },
+    /***Function
+    List all chat room available on a server.
+    Parameters:
+    (String) server - name of chat server.
+    (String) handle_cb - Function to call for room list return.
+    */
+    listRooms: function(server, handle_cb) {
+        var iq = $iq({to: server,
+                      from: this._connection.jid,
+                      type: "get"})
+            .c("query",{xmlns: Strophe.NS.DISCO_ITEMS});        
+        this._connection.sendIQ(iq, handle_cb, function(){});        
+    },
+    test_append_nick: function(room, nick) {
+        var room_nick = room;
+        if (nick) 
+        {
+            room_nick += "/" + Strophe.escapeNode(nick); 
+        }
+        return room_nick;
+    }
+});
\ No newline at end of file
diff --git a/views/default/js/strophe.muc.js.php b/views/default/js/strophe.muc.js.php
new file mode 100644 (file)
index 0000000..e10750d
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+Plugin to implement the MUC extension. http://xmpp.org/extensions/xep-0045.html
+*/
+/* jslint configuration: */
+/* global document, window, setTimeout, clearTimeout, console,
+    XMLHttpRequest, ActiveXObject,
+    Base64, MD5,
+    Strophe, $build, $msg, $iq, $pres 
+*/
+
+Strophe.addConnectionPlugin('muc', {
+    _connection: null,
+    // The plugin must have the init function
+    /***Function
+    Initialize the MUC plugin. Sets the correct connection object and
+    extends the namesace.
+    */
+    init: function(conn) {
+        this._connection = conn;
+        /* extend name space 
+         *  NS.MUC - XMPP Multi-user chat namespace
+         *              from XEP 45.  
+         *
+         */
+        Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC+"#owner");
+        Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC+"#admin");
+    },
+    /***Function
+    Join a multi-user chat room
+    Parameters:
+    (String) room - The multi-user chat room to join.
+    (String) nick - The nickname to use in the chat room. Optional
+    (Function) msg_handler_cb - The function call to handle messages from the
+    specified chat room.
+    (Function) pres_handler_cb - The function call back to handle presence
+    in the chat room.
+    (String) password - The optional password to use. (password protected
+    rooms only)
+    */
+    join: function(room, nick, msg_handler_cb, pres_handler_cb, password) {
+        var room_nick = this.test_append_nick(room, nick);        
+        var msg = $pres({from: this._connection.jid,
+                         to: room_nick})
+            .c("x",{xmlns: Strophe.NS.MUC});
+        if (password)
+        {
+            var password_elem = Strophe.xmlElement("password", 
+                                                   [],
+                                                   password);
+            msg.cnode(password_elem);
+        }
+        if (msg_handler_cb)
+        {
+            this._connection.addHandler(function(stanza) {
+                var from = stanza.getAttribute('from');
+                var roomname = from.split("/");
+                // filter on room name
+                if (roomname.length > 1 && roomname[0] == room)
+                {
+                    return msg_handler_cb(stanza);
+                }
+                else
+                {
+                    return true;
+                }
+            },
+                                        null,
+                                        "message",
+                                        null,
+                                        null,
+                                        null);
+        }
+        if (pres_handler_cb)
+        {
+            this._connection.addHandler(function(stanza) {
+                var xquery = stanza.getElementsByTagName("x");
+                if (xquery.length > 0)
+                {
+                    //Handle only MUC user protocol
+                    for (var i = 0; i < xquery.length; i++)
+                    {
+                        var xmlns = xquery[i].getAttribute("xmlns");
+                        
+                        if (xmlns && xmlns.match(Strophe.NS.MUC))
+                        {
+                            return pres_handler_cb(stanza);
+                        }
+                    }
+                }
+                return true;                
+            },
+                                        null,
+                                        "presence",
+                                        null,
+                                        null,
+                                        null);
+        }
+        this._connection.send(msg);
+    },
+    /***Function
+    Leave a multi-user chat room
+    Parameters:
+    (String) room - The multi-user chat room to leave.
+    (String) nick - The nick name used in the room.
+    (Function) handler_cb - Optional function to handle the successful leave.
+    Returns:
+    iqid - The unique id for the room leave.
+    */
+    leave: function(room, nick, handler_cb) {
+        var room_nick = this.test_append_nick(room, nick);        
+        var presenceid = this._connection.getUniqueId();
+        var presence = $pres({type: "unavailable",
+                              id: presenceid,
+                              from: this._connection.jid,
+                              to: room_nick})
+            .c("x",{xmlns: Strophe.NS.MUC});
+        this._connection.addHandler(handler_cb,
+                                    null,
+                                    "presence",
+                                    null,
+                                    presenceid,
+                                    null);
+        this._connection.send(presence);
+        return presenceid;
+    },
+    /***Function
+    Parameters:
+    (String) room - The multi-user chat room name.
+    (String) nick - The nick name used in the chat room.
+    (String) message - The message to send to the room.
+    Returns:
+    msgiq - the unique id used to send the message
+    */
+    message: function(room, nick, message) {
+        var room_nick = this.test_append_nick(room, nick);        
+        var msgid = this._connection.getUniqueId();
+        var msg = $msg({to: room_nick,
+                        from: this._connection.jid,
+                        type: "groupchat",
+                        id: msgid}).c("body",
+                                      {xmlns: Strophe.NS.CLIENT}).t(message);
+        msg.up().c("x", {xmlns: "jabber:x:event"}).c("composing");
+        this._connection.send(msg);
+        return msgid;
+    },
+    /***Function
+    Start a room configuration.
+    Parameters:
+    (String) room - The multi-user chat room name.
+    Returns:
+    id - the unique id used to send the configuration request
+    */
+    configure: function(room) {
+        //send iq to start room configuration
+        var config = $iq({to:room,
+                          type: "get"}).c("query",
+                                          {xmlns: Strophe.NS.MUC_OWNER});
+        var stanza = config.tree();
+        return this._connection.sendIQ(stanza,
+                               function(){},
+                               function(){});
+    },
+    /***Function
+    Cancel the room configuration
+    Parameters:
+    (String) room - The multi-user chat room name.
+    Returns:
+    id - the unique id used to cancel the configuration.
+    */
+    cancelConfigure: function(room) {
+        //send iq to start room configuration
+        var config = $iq({to: room,
+                          type: "set"})
+            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
+            .c("x", {xmlns: "jabber:x:data", type: "cancel"});
+        var stanza = config.tree();
+        return this._connection.sendIQ(stanza,
+                                       function(){},
+                                       function(){});
+    },
+    /***Function
+    Save a room configuration.
+    Parameters:
+    (String) room - The multi-user chat room name.
+    (Array) configarray - an array of form elements used to configure the room.
+    Returns:
+    id - the unique id used to save the configuration.
+    */
+    saveConfiguration: function(room, configarray) {
+        var config = $iq({to: room,
+                          type: "set"})
+            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
+            .c("x", {xmlns: "jabber:x:data", type: "submit"});
+        for (var i = 0; i >= configarray.length; i++) {
+            config.cnode(configarray[i]);
+        }
+        var stanza = config.tree();
+        return this._connection.sendIQ(stanza,
+                                       function(){},
+                                       function(){});        
+    },
+    /***Function
+    Parameters:
+    (String) room - The multi-user chat room name.
+    Returns:
+    id - the unique id used to create the chat room.
+    */
+    createInstantRoom: function(room) {
+        var roomiq = $iq({to: room,
+                          type: "set"})
+            .c("query", {xmlns: Strophe.NS.MUC_OWNER})
+            .c("x", {xmlns: "jabber:x:data",
+                     type: "submit"});
+        return this._connection.sendIQ(roomiq.tree(),
+                                       function() {},
+                                       function() {});
+    },
+    /***
+     Set the topic of the chat room.
+     Parameters:
+     (String) room - The multi-user chat room name.
+     (String) topic - Topic message.
+     */
+    setTopic: function(room, topic) {
+        var msg = $msg({to: room,
+                        from: this._connection.jid,
+                        type: "groupchat"})
+            .c("subject", {xmlns: "jabber:client"}).t(topic);
+        this._connection.send(msg.tree());
+    },
+    /***Function
+    Changes the role and affiliation of a member of a MUC room.
+    The modification can only be done by a room moderator. An error will be
+    returned if the user doesn't have permission.
+    Parameters:
+    (String) room - The multi-user chat room name.
+    (String) nick - The nick name of the user to modify.
+    (String) role - The new role of the user.
+    (String) affiliation - The new affiliation of the user.
+    (String) reason - The reason for the change.
+    Returns:
+    iq - the id of the mode change request.
+    */
+    modifyUser: function(room, nick, role, affiliation, reason) {
+        var item_attrs = {nick: Strophe.escapeNode(nick)};
+        if (role !== null)
+        {
+            item_attrs.role = role;
+        }
+        if (affiliation !== null)
+        {
+            item_attrs.affiliation = affiliation;
+        }
+        var item = $build("item", item_attrs);
+        if (reason !== null)
+        {
+            item.cnode(Strophe.xmlElement("reason", reason));
+        }
+        var roomiq = $iq({to: room,
+                          type: "set"})
+            .c("query", {xmlns: Strophe.NS.MUC_OWNER}).cnode(item.tree());
+        return this._connection.sendIQ(roomiq.tree(),
+                                       function() {},
+                                       function() {});
+    },
+    /***Function
+    Change the current users nick name.
+    Parameters:
+    (String) room - The multi-user chat room name.
+    (String) user - The new nick name.
+    */
+    changeNick: function(room, user) {
+        var room_nick = this.test_append_nick(room, user);
+        var presence = $pres({from: this._connection.jid,
+                              to: room_nick})
+            .c("x",{xmlns: Strophe.NS.MUC});
+        this._connection.send(presence.tree());
+    },
+    /***Function
+    List all chat room available on a server.
+    Parameters:
+    (String) server - name of chat server.
+    (String) handle_cb - Function to call for room list return.
+    */
+    listRooms: function(server, handle_cb) {
+        var iq = $iq({to: server,
+                      from: this._connection.jid,
+                      type: "get"})
+            .c("query",{xmlns: Strophe.NS.DISCO_ITEMS});        
+        this._connection.sendIQ(iq, handle_cb, function(){});        
+    },
+    test_append_nick: function(room, nick) {
+        var room_nick = room;
+        if (nick) 
+        {
+            room_nick += "/" + Strophe.escapeNode(nick); 
+        }
+        return room_nick;
+    }
+});
diff --git a/views/default/settings/beechat/edit.php b/views/default/settings/beechat/edit.php
new file mode 100755 (executable)
index 0000000..8f82834
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/**
+ *     Barter Plugin
+ *     @package Barters
+ **/
+       $domain = get_plugin_setting("domain", "beechat");
+       $group_domain = get_plugin_setting("groupdomain", "beechat");
+       $xmlrpc_ip = get_plugin_setting("xmlrpcip", "beechat");
+       $dbname = get_plugin_setting("dbname", "beechat");
+       $dbhost = get_plugin_setting("dbhost", "beechat");
+       $dbuser = get_plugin_setting("dbuser", "beechat");
+       $dbpassword = get_plugin_setting("dbpassword", "beechat");
+?>
+<p>
+       <?php echo elgg_echo('beechat:domain'); ?>
+       <?php echo elgg_view('input/text', array('internalname' => 'params[domain]','value' => $domain)); ?>
+       <!--<?php echo elgg_echo('beechat:groupdomain'); ?>
+       <?php echo elgg_view('input/text', array('internalname' => 'params[groupdomain]','value' => $group_domain)); ?>-->
+       <?php echo elgg_echo('beechat:xmlrpcip'); ?>
+       <?php echo elgg_view('input/text', array('internalname' => 'params[xmlrpcip]','value' => $xmlrpc_ip)); ?>
+       <?php echo elgg_echo('beechat:dbname'); ?>
+       <?php echo elgg_view('input/text', array('internalname' => 'params[dbname]','value' => $dbname)); ?>
+       <?php echo elgg_echo('beechat:dbhost'); ?>
+       <?php echo elgg_view('input/text', array('internalname' => 'params[dbhost]','value' => $dbhost)); ?>
+       <?php echo elgg_echo('beechat:dbuser'); ?>
+       <?php echo elgg_view('input/text', array('internalname' => 'params[dbuser]','value' => $dbuser)); ?>
+       <?php echo elgg_echo('beechat:dbpassword'); ?>
+       <?php echo elgg_view('input/password', array('internalname' => 'params[dbpassword]','value' => $dbpassword)); ?>
+
+</p>
+