lwb5-in-2025/misc/forums-branch.patch

11689 lines
379 KiB
Diff
Raw Normal View History

2016-01-10 11:01:49 +01:00
diff -Naur beta5//scripts/config.inc forums//scripts/config.inc
--- beta5//scripts/config.inc 2011-02-05 10:09:57.904335002 +0100
+++ forums//scripts/config.inc 2011-03-12 15:47:09.431300051 +0100
@@ -39,7 +39,7 @@
"widgetURL" => "http://www.legacyworlds.com/downloads/LegacyWorlds-Dashboard-latest.zip",
// Version numbers to make us feel good
- "v_engine" => "0.85a",
+ "v_engine" => "0.86",
"v_game" => "Beta 5",
"v_rev" => "2218",
diff -Naur beta5//scripts/game/beta5/actions/getForums.inc forums//scripts/game/beta5/actions/getForums.inc
--- beta5//scripts/game/beta5/actions/getForums.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/beta5/actions/getForums.inc 2011-02-05 10:10:03.244335002 +0100
@@ -0,0 +1,84 @@
+<?
+
+/** This action returns the structure of the forums a player has access to.
+ *
+ * \parameter $player The player identifier for whom to get the forums' structure
+ *
+ * \returns null on error or a fl_container instance that contains the forums' structure.
+ */
+
+class beta5_getForums {
+
+ private static $names = array(
+ 'G' => array(
+ 'en' => array('General forums', "LegacyWorlds' public forums"),
+ 'fr' => array('Forums généraux', "Les forums publics de LegacyWorlds")
+ ),
+ 'U' => array(
+ 'en' => array('Player forums', "Forums belonging to other LegacyWorlds players"),
+ 'fr' => array('Forums des joueurs', "Forums appartenant à d'autres joueurs de LegacyWorlds")
+ )
+ );
+
+ public function __construct($game) {
+ $this->game = $game;
+ $this->db = $this->game->getDBAccess();
+
+ // Load the forums' access libraries
+ $this->gForums = $this->game->getLib('main/gforums');
+ $this->uForums = $this->game->getLib('main/uforums');
+ $this->aForums = $this->game->getLib('beta5/aforums');
+
+ // Load the container class
+ loader::needClasses('main/forums', 'fl_container');
+ }
+
+ public function run( $player ) {
+ // Get the player's user ID
+ $q = $this->db->query("SELECT userid FROM player WHERE id = $1", (int) $player);
+ if (!( $q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($user) = dbFetchArray($q);
+
+ // Get the language string for the user
+ // FIXME: that thing would not work inside anything *but* a web session
+ $lang = getLanguage();
+
+ // Get the list of general, user-specific and alliance forums
+ $gForums = $this->gForums->call('getStructure', $user);
+ $aForums = $this->aForums->call('getStructure', $user);
+ $uForums = $this->uForums->call('getStructure', $user);
+
+ // Generate the container for the whole thing
+ $forums = new fl_container('/', '', '');
+
+ // Generate the container for general forums
+ $gContainer = new fl_container('G', self::$names['G'][$lang][0], self::$names['G'][$lang][1]);
+ foreach ($gForums as $gc) {
+ $gContainer->addCategory($gc);
+ }
+ $forums->addCategory($gContainer);
+
+ // Add the alliance forums
+ if (count($aForums) == 1) {
+ $forums->addCategory($aForums[0]);
+ }
+
+ // Add the player's own forums
+ $forums->addCategory(array_shift($uForums));
+
+ // Add the other players' forums
+ if (count($uForums)) {
+ $uContainer = new fl_container('U', self::$names['U'][$lang][0], self::$names['U'][$lang][1]);
+ foreach ($uForums as $uc) {
+ $uContainer->addCategory($uc);
+ }
+ $forums->addCategory($uContainer);
+ }
+
+ return $forums;
+ }
+}
+
+?>
diff -Naur beta5//scripts/game/beta5/actions.inc forums//scripts/game/beta5/actions.inc
--- beta5//scripts/game/beta5/actions.inc 2011-02-05 10:09:57.784335002 +0100
+++ forums//scripts/game/beta5/actions.inc 2011-03-12 14:56:24.591300053 +0100
@@ -29,6 +29,10 @@
var $fleetDepartures = array();
var $ePower = array();
+ var $index = array(
+ 'getForums'
+ );
+
function actions_beta5($game) {
$this->game = $game;
diff -Naur beta5//scripts/game/beta5/aforums/library.inc forums//scripts/game/beta5/aforums/library.inc
--- beta5//scripts/game/beta5/aforums/library.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/beta5/aforums/library.inc 2011-02-05 10:10:03.334335002 +0100
@@ -0,0 +1,256 @@
+<?php
+
+/** Beta 5 alliance forums management library */
+
+class beta5_aforums_library {
+
+ private static $allianceAdmins = array();
+ private static $rAccess = array();
+
+ var $index = array( );
+
+ public function __construct($lib) {
+ $this->lib = $lib;
+ $this->game = $this->lib->game;
+ $this->version = $this->game->version;
+ $this->db = $this->game->db;
+
+ $this->fLib = $this->game->getLib('main/forums');
+ loader::needClasses('main/forums', array('fl_category', 'fl_forum'));
+
+ $this->getPlayerQ = $this->db->prepare(
+ "SELECT id FROM player WHERE userid = $1 AND (quit IS NULL OR quit > UNIX_TIMESTAMP(NOW()))",
+ array("user"));
+ $this->getAllianceCatQ = $this->db->prepare(
+ "SELECT a.f_category FROM player p, alliance a "
+ . "WHERE a.id = p.alliance AND p.alliance IS NOT NULL AND p.a_status='IN ' AND p.id = $1",
+ array("player") );
+ $this->getAllianceQ = $this->db->prepare(
+ "SELECT a.tag, a.name FROM alliance a WHERE a.f_category = $1",
+ array("category") );
+ $this->getCatForumsQ = $this->db->prepare(
+ "SELECT id FROM forums.t_forum WHERE category = $1 ORDER BY f_order", array("category") );
+ $this->getForumPrivQ = $this->db->prepare(
+ "SELECT * FROM get_aforums_privs( $1, $2 )", array("player", "forum") );
+ $this->getForumQ = $this->db->prepare(
+ "SELECT * FROM alliance_forum WHERE forum = $1", array("forum") );
+ $this->getForumRanksQ = $this->db->prepare(
+ "SELECT rank, is_mod FROM al_rank_forum WHERE forum = $1", array("forum") );
+ $this->getRankNameQ = $this->db->prepare(
+ "SELECT CASE name IS NULL WHEN TRUE THEN '-' ELSE name END FROM alliance_grade "
+ . "WHERE id = $1",
+ array("rank") );
+ }
+
+ public function getStructure( $user ) {
+ $cats = array();
+
+ $q = $this->getPlayerQ->execute($user);
+ if ($q && dbCount($q) == 1) {
+ list($player) = dbFetchArray($q);
+
+ $q = $this->getAllianceCatQ->execute($player);
+ if ($q && dbCount($q)) {
+ list($catId) = dbFetchArray($q);
+ $cat = $this->fLib->call('getCategory', $catId, $user);
+ if (! is_null($cat)) {
+ array_push($cats, $cat);
+ }
+ }
+ }
+
+ return $cats;
+ }
+
+ public function getCategory( $catId , $user ) {
+ $q = $this->getAllianceQ->execute($catId);
+ if (! ($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($tag, $name) = dbFetchArray($q);
+
+ $title = "[$tag] $name";
+ $description = "These are the forums for the alliance you are a member of, $name.";
+
+ $cat = new fl_category( $this->game, $user, $catId, $title, $description );
+
+ $q = $this->getCatForumsQ->execute($catId);
+ while ($r = dbFetchArray($q)) {
+ $forum = $this->fLib->call('getForum', $r[0], $user);
+ if ($forum->canView() && ($forum->isAdmin() || ! $forum->isDeleted())) {
+ $cat->addForum( $forum );
+ }
+ }
+
+ return $cat;
+ }
+
+
+ public function getForum( $forumId, $user ) {
+ $q = $this->getPlayerQ->execute($user);
+ if (!($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($player) = dbFetchArray($q);
+
+ $q = $this->getForumPrivQ->execute($player, $forumId);
+ if (! ($q && dbCount($q) == 1)) {
+ return null;
+ }
+ $privs = dbFetchHash($q);
+
+ try {
+ $forum = new fl_forum( $this->game, $forumId, $user );
+ } catch (Exception $e) {
+ return null;
+ }
+
+ $forum->setAdmin( $privs['is_admin'] == 't' );
+ $forum->setMod( $privs['is_mod'] == 't' );
+ $forum->setCreateTopic( $privs['can_create'] == 't' );
+ $forum->setCreatePoll( $privs['can_poll'] == 't' );
+ $forum->setPost( $privs['can_post'] == 't' );
+ $forum->setView( $privs['can_view'] == 't' );
+
+ return $forum;
+ }
+
+ public function getAdmins($forum) {
+ $q = $this->getForumQ->execute($forum);
+ if (!($q && dbCount($q) == 1)) {
+ return null;
+ }
+ $r = dbFetchHash($q);
+ $alliance = $r['alliance'];
+
+ if (! is_null(self::$allianceAdmins[$alliance])) {
+ return self::$allianceAdmins[$alliance];
+ }
+
+ if (is_null($this->alliance)) {
+ $this->alliance = $this->game->getLib('beta5/alliance');
+ }
+
+ $l = array_keys($this->alliance->call('getRanks', $alliance));
+ $admin = array();
+ foreach ($l as $rId) {
+ $pr = $this->alliance->call('getRankPrivileges', $rId);
+ if (! $pr['forum_admin']) {
+ continue;
+ }
+ array_push($admin, $rId);
+ }
+
+ return (self::$allianceAdmins[$alliance] = $admin);
+ }
+
+ public function getModerators($forum) {
+ $rl = $this->getRankAccess($forum);
+ $rv = array();
+ foreach ($rl as $rId => $isMod) {
+ if ($isMod) {
+ array_push($rv, $rId);
+ }
+ }
+ return $rv;
+ }
+
+ public function getUsers($forum) {
+ $rl = $this->getRankAccess($forum);
+ $rv = array();
+ foreach ($rl as $rId => $isMod) {
+ if (! $isMod) {
+ array_push($rv, $rId);
+ }
+ }
+ return $rv;
+ }
+
+
+ private function getRankAccess($forum) {
+ if (! is_null(self::$rAccess[$forum])) {
+ return self::$rAccess[$forum];
+ }
+
+ $rv = array();
+ $q = $this->getForumRanksQ->execute($forum);
+
+ if ($q && dbCount($q)) {
+ while ($r = dbFetchHash($q)) {
+ $rv[$r['rank']] = ($r['is_mod'] == 't');
+ }
+ }
+
+ return (self::$rAccess[$forum] = $rv);
+ }
+
+
+ public function aclIdToName($id) {
+ $q = $this->getRankNameQ->execute($id);
+ if (!($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($rv) = dbFetchArray($q);
+ return $rv;
+ }
+
+
+
+ public function getUserPrivileges($forum) {
+ $q = $this->getForumQ->execute($forum);
+ if (!($q && dbCount($q) == 1)) {
+ return null;
+ }
+ $r = dbFetchHash($q);
+ return $r['access_mode'];
+ }
+
+
+ public function create($player, $user, $alliance, $order, $name, $description, $accessMode) {
+ $q = $this->db->query("SELECT create_alliance_forum($1, $2, $3, $4, $5, $6)",
+ $player, $alliance, $order, $name, $description, $accessMode);
+ if (!($q && dbCount($q))) {
+ return -6;
+ }
+ list($rv) = dbFetchArray($q);
+
+ if ($rv > 0) {
+ $forum = $this->fLib->call('getForum', $rv, $user);
+ if (is_null($forum)) {
+ return -6;
+ }
+ $forum->getCategory()->insertNewForum($forum);
+ $rv = $forum;
+ } else {
+ $rv = -$rv;
+ }
+
+ return $rv;
+ }
+
+ public function modifyForum($forum, $player, $name, $description, $accessMode) {
+ $this->db->query("SELECT modify_alliance_forum($1,$2,$3,$4,$5)",
+ $player, $forum, $name, $description, $accessMode);
+ if (!($q && dbCount($q))) {
+ return -5;
+ }
+ list($rv) = dbFetchArray($q);
+ return $rv;
+ }
+
+ public function clearForumACL($forum) {
+ $this->db->query("DELETE FROM al_rank_forum WHERE forum = $1", $forum);
+ }
+
+ public function addForumModerator( $forum, $id ) {
+ $this->db->query("INSERT INTO al_rank_forum (rank, forum, is_mod) VALUES ($1, $2, TRUE)",
+ $id, $forum);
+ }
+
+ public function addForumUser( $forum, $id ) {
+ $this->db->query("INSERT INTO al_rank_forum (rank, forum, is_mod) VALUES ($1, $2, FALSE)",
+ $id, $forum);
+ }
+}
+
+?>
diff -Naur beta5//scripts/game/beta5/forums/topic/library.inc forums//scripts/game/beta5/forums/topic/library.inc
--- beta5//scripts/game/beta5/forums/topic/library.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/beta5/forums/topic/library.inc 2011-02-05 10:10:03.334335002 +0100
@@ -0,0 +1,330 @@
+<?
+
+class beta5_forums_topic_library {
+
+ private $pHandler;
+ private $lib;
+ private $game;
+ private $topic = null;
+ private $deleted = false;
+
+ public function __construct($lib) {
+ $this->lib = $lib;
+ $this->game = $this->lib->game;
+ }
+
+ public function initialize($pageHandler) {
+ $this->pHandler = $pageHandler;
+ }
+
+ public function forumCommand($player, $commandArgs) {
+
+ // Read the arguments
+ if (strstr($commandArgs, "#") !== FALSE) {
+ list( $topicIdS, $hexId ) = explode('#', $commandArgs);
+ if (strlen($hexId) != 32 || preg_match('/[^A-Z0-9]/i', $hexId)) {
+ $hexId = md5(uniqid(rand()));
+ }
+
+ $topicId = (int) $topicIdS;
+ $data = $this->pHandler->getSessionData('topic_' . $hexId);
+ if (is_null($data) || $topicId != $data['topic']) {
+ $hexId = md5(uniqid(rand()));
+ $firstTime = true;
+ } else {
+ $firstTime = false;
+ }
+ } else {
+ $topicId = (int) $commandArgs;
+ $hexId = md5(uniqid(rand()));
+ $firstTime = true;
+ }
+
+ // Get the player's user ID
+ $pinf = $this->game->getLib('beta5/player')->call('get', $player);
+ $user = $pinf['uid'];
+
+ if ($firstTime) {
+ $this->game->action('getForums', $player);
+ $data = $this->initTopicData($user, $topicId);
+ $this->makeDataString($data, $hexId);
+ } else {
+ $this->updateTopicData($topicId, $data);
+ }
+ $this->pHandler->setSessionData('topic_' . $hexId, $data);
+ $this->data = $data;
+
+ if ($data['exists']) {
+ $rv = array("V#F#{$data['forum']}", "vTopic", "$topicId#$hexId");
+ } else {
+ $rv = array("", "vTopic", "$topicId#$hexId");
+ }
+ return $rv;
+ }
+
+
+ /* This method initialises the stored session data for the specified topic ID.
+ */
+ private function initTopicData($user, $topicId) {
+ $data = array(
+ "viewTime" => time(),
+ "topic" => $topicId,
+ "user" => $user
+ );
+
+ // Check whether the topic actually exists
+ $topic = $this->game->getLib('main/forums')->call('getTopic', $topicId, $user);
+ if (is_null($topic)) {
+ $data['exists'] = false;
+ return $data;
+ }
+
+ // Check whether the topic is available
+ $forum = $this->forum = $topic->getForum();
+ if (is_null($forum) || ! $forum->canView()) {
+ $data['exists'] = false;
+ return $data;
+ }
+
+ // The topic exists
+ $data['exists'] = true;
+ $data['forum'] = $forum->getId();
+ $data['title'] = $topic->getTitle();
+
+ // Has it been deleted?
+ if ($topic->isDeleted()) {
+ $data['deleted'] = true;
+ $data['deletedAt'] = $topic->getDeletionTime();
+ $data['deletedBy'] = $topic->getDeletionMod();
+ return $data;
+ }
+
+ // Get additional data
+ $users = array();
+ $data['lastChange'] = $topic->getLastChange();
+ $data['lastRead'] = $topic->getLastRead();
+ $data['isLocked'] = $topic->isLocked();
+ $data['isMod'] = $forum->isMod();
+ $data['canPost'] = $forum->canPost();
+
+ // Get the topic's posts
+ $data['postOrder'] = array();
+
+ // -> linear, newest first
+ $list = $topic->getPostList(false, false);
+ $data['postOrder']['ln'] = array();
+ foreach ($list as $p) {
+ array_push($data['postOrder']['ln'], $p->getId());
+ }
+
+ // -> linear, oldest first
+ $list = $topic->getPostList(false, true);
+ $data['postOrder']['lo'] = array();
+ foreach ($list as $p) {
+ array_push($data['postOrder']['lo'], $p->getId());
+ }
+
+ // -> threaded, newest first
+ $list = $topic->getPostList(true, false);
+ $data['postOrder']['tn'] = array();
+ foreach ($list as $p) {
+ array_push($data['postOrder']['tn'], $p->getId());
+ }
+
+ // -> threaded, oldest first
+ $list = $topic->getPostList(true, true);
+ $data['postOrder']['to'] = array();
+ foreach ($list as $p) {
+ array_push($data['postOrder']['to'], $p->getId());
+ }
+
+ // -> post data
+ $data['posts'] = array();
+ foreach ($list as $p) {
+ // post_id # depth # author_id # posted_at # is_unread # lc_time # lc_author
+ // post_title
+ $pStr = $p->getId() . "#" . $p->getDepth() . "#" . $p->getPostedBy()
+ . "#" . $p->getPostedAt() . "#" . ($p->isUnread() ? 1 : 0)
+ . "#" . $p->getLastChange() . "#" . $p->getLastChangeAuthor()
+ . "\n" . utf8entities($p->getTitle());
+ array_push($data['posts'], $pStr);
+ if (!in_array($p->getPostedBy(), $users)) {
+ array_push($users, $p->getPostedBy());
+ }
+ if (!(is_null($p->getLastChangeAuthor()) || in_array($p->getLastChangeAuthor(), $users))) {
+ array_push($users, $p->getLastChangeAuthor());
+ }
+ }
+
+ // Get poll data
+ $poll = $topic->getPoll();
+ $data['hasPoll'] = ! is_null($poll);
+ if ($data['hasPoll']) {
+ // FIXME: get poll data
+ }
+
+ // Get user names
+ $data['users'] = $this->dumpNames($users);
+
+ return $data;
+ }
+
+ private function dumpNames($ids) {
+ $accLib = $this->game->getLib('main/account');
+
+ $output = array();
+ array_push($output, count($ids));
+ foreach ($ids as $id) {
+ array_push($output, "$id#" . utf8entities($accLib->call('getUserName', $id)));
+ }
+ return $output;
+ }
+
+ /* This method generates the data string to be sent the first time a topic
+ * page is loaded.
+ */
+ private function makeDataString(&$data, $hexId) {
+ $result = array(
+ "{$data['topic']}#$hexId"
+ );
+ if ($data['exists']) {
+ // Fetch the path to the topic
+ $parents = array();
+ $obj = $this->forum;
+ do {
+ array_push($parents, array(
+ $obj->getId(), utf8entities($obj->getTitle())
+ ));
+ $obj = $obj->getParent();
+ } while (! is_null($obj));
+
+ if ($data['deleted']) {
+ // If the topic has been deleted
+ array_push($result, "DELETED#{$data['deletedAt']}#" . count($parents));
+ array_push($result, utf8entities($data['title']));
+ // FIXME: fetch moderator's name
+// array_push($result, $this->game->getLib('
+
+ // Dump the path
+ foreach (array_reverse($parents) as $p) {
+ array_push($result, join('#', $p));
+ }
+
+ } else {
+ // If the topic is available
+ array_push($result, "TOPIC#" . count($parents));
+ array_push($result, utf8entities($data['title']));
+ array_push($result, "{$data['user']}#" . ($data['isMod'] ? 1 : 0)
+ . "#" . ($data['canPost'] ? 1 : 0) . "#" . ($data['hasPoll'] ? 1 : 0));
+
+ // Dump the path
+ foreach (array_reverse($parents) as $p) {
+ array_push($result, join('#', $p));
+ }
+
+ // Post orders
+ array_push($result, join('#', $data['postOrder']['ln']));
+ array_push($result, join('#', $data['postOrder']['lo']));
+ array_push($result, join('#', $data['postOrder']['tn']));
+ array_push($result, join('#', $data['postOrder']['to']));
+
+ // Posts
+ foreach ($data['posts'] as $post) {
+ array_push($result, $post);
+ }
+
+ // Users
+ foreach ($data['users'] as $user) {
+ array_push($result, $user);
+ }
+
+ // Get the viewing options
+ array_push($result, join('#', $this->getOptions($data['topic'])));
+ }
+ } else {
+ array_push($result, "MEH");
+ }
+
+ $data['initString'] = join("\n", $result);
+ }
+
+ /** This method checks for updates on the topic */
+ private function updateTopicData($topicId, &$data) {
+ $this->topic = $topic = $this->game->getLib('main/forums')->call('getTopic', $topicId, $user);
+ if (is_null($topic)) {
+ $data['stillExists'] = false;
+ return $data;
+ }
+
+ // Check whether the topic is available
+ $forum = $this->forum = $topic->getForum();
+ if (is_null($forum) || ! $forum->canView()) {
+ $data['stillExists'] = false;
+ return $data;
+ }
+
+ // The topic exists
+ $data['stillExists'] = true;
+
+ // Has it been deleted?
+ if ($topic->isDeleted()) {
+ $data['nowDeleted'] = true;
+ $data['deletedAt'] = $topic->getDeletionTime();
+ $data['deletedBy'] = $topic->getDeletionMod();
+ return $data;
+ }
+
+ // Topic hasn't been deleted, check for updates
+ $data['lastChange'] = $topic->getLastChange();
+ }
+
+ public function getData() {
+ if (is_null($this->data['updateString'])) {
+ return $this->data['initString'];
+ }
+ }
+
+
+ private function getOptions( $id ) {
+ if (! is_null($this->forum)) {
+ $isMod = $this->forum->isMod();
+ } else {
+ $isMod = false;
+ }
+
+ // perPage = posts / page, default 50, possible values 25 50 75 100
+ $perPage = prefs::get("main/T#PP#$id", prefs::get("main/T#PP", 50));
+ // vDeleted = view deleted posts, default "no"
+ $vDeleted = $isMod ? prefs::get("main/T#VD#$id", prefs::get("main/T#VD", 0)) : 0;
+ // threaded = enable threaded mode, default "yes"
+ $threaded = prefs::get("main/T#TV#$id", prefs::get("main/T#TV", 1));
+ // order = show oldest posts first, default "no"
+ $order = prefs::get("main/T#PO#$id", prefs::get("main/T#PO", 0));
+ // openPosts = posts open by default, default 1, possible values 0: none, 1: new only, 2: all
+ $openPosts = prefs::get("main/T#OP#$id", prefs::get("main/T#OP", 1));
+
+ return array($perPage, $vDeleted, $threaded, $order, $openPosts);
+ }
+
+
+ public function getPostContents($postId) {
+ $postId = (int) $postId;
+ if (! ($this->data['exists'] && $this->data['stillExists'])) {
+ return "-#$postId";
+ }
+
+ $post = $this->topic->getPostById($postId);
+ if (is_null($post)) {
+ return "-#$postId";
+ }
+
+ $contents = $this->game->getLib('main/forums')->call('substitute',
+ $post->getContents($this->data['viewTime']),
+ $post->codeEnabled($this->data['viewTime'])
+ );
+
+ return "+#$postId\n$contents";
+ }
+}
+
+?>
diff -Naur beta5//scripts/game/beta5/forums/view/library.inc forums//scripts/game/beta5/forums/view/library.inc
--- beta5//scripts/game/beta5/forums/view/library.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/beta5/forums/view/library.inc 2011-02-05 10:10:03.334335002 +0100
@@ -0,0 +1,405 @@
+<?
+
+class beta5_forums_view_library {
+
+ private $pHandler;
+ private $lib;
+ private $game;
+ private $fStructure;
+ private $displayObject;
+
+ public function __construct($lib) {
+ $this->lib = $lib;
+ $this->game = $this->lib->game;
+ }
+
+ public function initialize($pageHandler) {
+ $this->pHandler = $pageHandler;
+ }
+
+ public function forumCommand($player, $commandArgs) {
+ // Examine the arguments
+ $args = explode('#', $commandArgs);
+ if (count($args) != 2 || ! in_array($args[0], array('F', 'C'))) {
+ $args = array('C', '/');
+ }
+
+ // Try to find the requested object
+ $this->fStructure = $this->game->action('getForums', $player);
+ if ($args[0] == 'C') {
+ $this->displayObject = $this->fStructure->findCategory($args[1]);
+ } else {
+ $this->displayObject = $this->fStructure->findForum($args[1]);
+ if (! is_null($this->displayObject) && (
+ ($this->displayObject->isDeleted() && ! $this->displayObject->isAdmin())
+ || ! $this->displayObject->canView()) ) {
+ $this->displayObject = null;
+ }
+ }
+ if (is_null($this->displayObject)) {
+ $this->displayObject = $this->fStructure;
+ $args = array('C', '/');
+ }
+
+ $view = join('#', $args);
+ return array("V#$view", $args[0] == 'C' ? 'vCat' : 'vForum', $view);
+ }
+
+ public function getData($oldMD5 = null) {
+ if (is_null($this->displayObject)) {
+ $r = null;
+ } else {
+ if ($this->displayObject instanceof fl_forum) {
+ $r = $this->getForumData();
+ } else {
+ $r = $this->getCategoryData();
+ }
+ $md5 = md5(serialize($r));
+ if ($md5 != $oldMD5) {
+ array_unshift($r, $md5);
+ $r = join("\n", $r);
+ } else {
+ $r = '-';
+ }
+ }
+ return $r;
+ }
+
+ public function categoryRead($category) {
+ if (is_null($this->displayObject)) {
+ return;
+ }
+
+ $cat = $this->displayObject->findCategory((int) $category);
+ if (is_null($cat) || ! ($cat instanceof fl_category)) {
+ return;
+ }
+ $cat->markRead();
+ }
+
+ public function forumRead() {
+ if (is_null($this->displayObject) || ! $this->displayObject instanceof fl_forum ) {
+ return;
+ }
+
+ $this->displayObject->markRead();
+ }
+
+ public function restoreTopics($topicList) {
+ if (is_null($this->displayObject) || ! $this->displayObject instanceof fl_forum
+ || ! $this->displayObject->isMod() ) {
+ return;
+ }
+
+ foreach ($topicList as $topicId) {
+ $topic = $this->displayObject->findTopic($topicId);
+ if (! is_null($topic) && $topic->isInForum($this->displayObject)) {
+ $topic->restore();
+ }
+ }
+ $this->displayObject->refresh();
+ }
+
+ public function deleteTopics($topicList) {
+ if (is_null($this->displayObject) || ! $this->displayObject instanceof fl_forum
+ || ! $this->displayObject->isMod() ) {
+ return;
+ }
+
+ foreach ($topicList as $topicId) {
+ $topic = $this->displayObject->findTopic($topicId);
+ if (!is_null($topic) && $topic->isInForum($this->displayObject)) {
+ $topic->delete();
+ }
+ }
+ $this->displayObject->refresh();
+ }
+
+ public function changeTopicsLevel($topicList, $change) {
+ $change = (int) $change;
+ if (is_null($this->displayObject) || ! $this->displayObject instanceof fl_forum
+ || ! $this->displayObject->isMod() || $change != -1 && $change != 1 ) {
+ return;
+ }
+
+ foreach ($topicList as $topicId) {
+ $topic = $this->displayObject->findTopic($topicId);
+ if (!is_null($topic) && $topic->isInForum($this->displayObject)) {
+ $topic->setStickyLevel($topic->getStickyLevel() + $change);
+ }
+ }
+ $this->displayObject->refresh();
+ }
+
+ public function setTopicsLevel($topicList, $level) {
+ $level = (int) $level;
+ if (is_null($this->displayObject) || ! $this->displayObject instanceof fl_forum
+ || ! $this->displayObject->isMod() || $level < 0 || $level > 10) {
+ return;
+ }
+
+ foreach ($topicList as $topicId) {
+ $topic = $this->displayObject->findTopic($topicId);
+ if (!is_null($topic) && $topic->isInForum($this->displayObject)) {
+ $topic->setStickyLevel($level);
+ }
+ }
+ $this->displayObject->refresh();
+ }
+
+ public function setTopicsLock($topicList, $lock) {
+ if (is_null($this->displayObject) || ! $this->displayObject instanceof fl_forum
+ || ! $this->displayObject->isMod()) {
+ return;
+ }
+
+ foreach ($topicList as $topicId) {
+ $topic = $this->displayObject->findTopic($topicId);
+ if (!is_null($topic) && $topic->isInForum($this->displayObject)) {
+ $topic->setLock($lock);
+ }
+ }
+ }
+
+ public function moveTopics($topicList, $destId) {
+ if (is_null($this->displayObject) || ! $this->displayObject instanceof fl_forum
+ || ! $this->displayObject->isMod() || $destId == $this->displayObject->getId()) {
+ return;
+ }
+
+ $destination = $this->fStructure->findForum((int) $destId);
+ if (is_null($destination) || ! $destination->isMod()) {
+ return;
+ }
+
+ foreach ($topicList as $topicId) {
+ $topic = $this->displayObject->findTopic($topicId);
+ if (! is_null($topic) && $topic->isInForum($this->displayObject)) {
+ $topic->moveTo($destination);
+ }
+ }
+ $this->displayObject->refresh();
+ $destination->refresh();
+ }
+
+
+ private function dumpNames(&$output, $ids) {
+ $accLib = $this->game->getLib('main/account');
+
+ array_push($output, count($ids));
+ foreach ($ids as $id) {
+ array_push($output, "$id#" . utf8entities($accLib->call('getUserName', $id)));
+ }
+ }
+
+ private function getCategoryData() {
+ $output = array(
+ "C#" . $this->displayObject->getId()
+ );
+ $namesNeeded = array();
+
+ $this->dumpCategory( &$output, &$namesNeeded, $this->displayObject );
+ $this->dumpNames( &$output, $namesNeeded );
+
+ return $output;
+ }
+
+ private function dumpCategory( &$output, &$namesNeeded, $object ) {
+ if ( $object instanceof fl_container ) {
+ $contents = $object->getCategories();
+ $type = 'C';
+ } else {
+ $contents = array();
+ foreach ($object->getForums() as $forum) {
+ if ($forum->canView() && ($forum->isAdmin() || ! $forum->isDeleted())) {
+ array_push($contents, $forum);
+ }
+ }
+ $type = 'F';
+ }
+
+ $fullDesc = explode("\n", $object->getDescription());
+ $hasUnread = ($object->getUnread() > 0) ? 1 : 0;
+ array_push( $output, $object->getId() . "#$type#$hasUnread#"
+ . count($contents) . "#" . count($fullDesc) );
+ if ($type == 'F') {
+ array_push( $output, $object->getTypeName(getLanguage()) ); // FIXME getLanguage() ...
+ }
+ array_push( $output, utf8entities($object->getTitle()) );
+ foreach ($fullDesc as $dLine ) {
+ array_push( $output, utf8entities($dLine) );
+ }
+
+ if ( $object instanceof fl_container ) {
+ foreach ($contents as $cat) {
+ $this->dumpCategory( &$output, &$namesNeeded, $cat );
+ }
+ } else {
+ foreach ($contents as $forum) {
+ $this->dumpCatForum( &$output, &$namesNeeded, $forum );
+ }
+ }
+ }
+
+ private function dumpCatForum( &$output, &$namesNeeded, $forum ) {
+ $fullDesc = explode("\n", $forum->getDescription());
+
+ $deleted = $forum->isDeleted() ? '1' : '0';
+ $deletedAt = $forum->deletedAt();
+ $deletedBy = $forum->deletedBy();
+ if (! (is_null($deletedBy) || in_array($deletedBy, $namesNeeded))) {
+ array_push($namesNeeded, $deletedBy);
+ }
+
+ $topics = $forum->getTopics();
+ $posts = is_null($lp = $forum->getLastPost()) ? 0 : $forum->getPosts();
+ $unread = ($forum->getUnread() > 0 ? 1 : 0);
+
+ array_push( $output, $forum->getId() . "#" . count($fullDesc)
+ . "#$deleted#$deletedAt#$deletedBy#$topics#$posts#$unread" );
+
+ if ($posts != 0 && !is_null($lp)) {
+ $moment = $lp->getLastChange();
+ $author = $lp->getLastChangeAuthor();
+ if (! in_array($author, $namesNeeded) ) {
+ array_push($namesNeeded, $author);
+ }
+ array_push( $output, "$author#$moment" );
+ }
+
+ array_push( $output, utf8entities($forum->getTitle()) );
+ foreach ($fullDesc as $dLine ) {
+ array_push( $output, utf8entities($dLine) );
+ }
+ }
+
+ private function getForumData() {
+ $output = array(
+ "F#" . $this->displayObject->getId()
+ );
+ $namesNeeded = array();
+ $fob = $this->displayObject;
+ $id = $fob->getId();
+
+ $perPage = prefs::get("main/F#PP#$id", prefs::get("main/F#PP", 10));
+ $vDeleted = $fob->isMod() ? prefs::get("main/F#VD#$id", prefs::get("main/F#VD", 0)) : 0;
+
+ $rTopics = $fob->getTopicList();
+ $topics = array();
+ foreach ($rTopics as $topic) {
+ if ( ! ($topic->isInForum($fob) || !is_null($topic->getForum()) && $topic->getForum()->canView())
+ || ($topic->isDeleted() && ! $vDeleted) ) {
+ continue;
+ }
+ array_push($topics, $topic);
+ }
+
+ $nTopics = count($topics);
+ $hasUnread = ($fob->getUnread() > 0) ? 1 : 0;
+ $isMod = $fob->isMod() ? 1 : 0;
+ $canPost = $fob->canCreateTopic() ? 1 : 0;
+ $fDesc = explode("\n", $fob->getDescription());
+ $admins = $fob->getAdministrators(true);
+ $mods = $fob->getModerators(true);
+ $users = $fob->getUsers(true);
+
+ if ($fob->isMod()) {
+ $fMoveTo = array();
+ $list = $this->fStructure->findModForums();
+ foreach ($list as $forum) {
+ $fId = $forum->getId();
+ if ($fId == $id) {
+ continue;
+ }
+ $fName = array($forum->getParent()->getTitle(), $forum->getTitle());
+ array_push($fMoveTo, "$fId#" . utf8entities(join(' > ', $fName)));
+ }
+ }
+
+ $parents = array();
+ $obj = $fob->getParent();
+ do {
+ array_push($parents, array(
+ $obj->getId(), utf8entities($obj->getTitle())
+ ));
+ $obj = $obj->getParent();
+ } while (! is_null($obj));
+
+ array_push($output, "$id#$nTopics#$hasUnread#$isMod#$canPost#$perPage#$vDeleted#" . count($fDesc)
+ . "#" . count($parents) . "#" . count($admins) . "#" . count($mods)
+ . "#" . count($users) . ($isMod ? ("#" . count($fMoveTo)) : ""));
+ array_push($output, utf8entities($fob->getTitle()));
+
+ // Dump description
+ foreach ($fDesc as $dLine) {
+ array_push($output, utf8entities($dLine));
+ }
+ // Parent categories
+ foreach (array_reverse($parents) as $p) {
+ array_push($output, join('#', $p));
+ }
+ // Administrators
+ foreach ($admins as $name) {
+ array_push($output, utf8entities($name));
+ }
+ // Moderators
+ foreach ($mods as $name) {
+ array_push($output, utf8entities($name));
+ }
+ // Users
+ foreach ($users as $name) {
+ array_push($output, utf8entities($name));
+ }
+ // List of forums one can move a topic to
+ if ($isMod) {
+ foreach ($fMoveTo as $l) {
+ array_push($output, $l);
+ }
+ }
+
+ foreach ($topics as $topic) {
+ if ($topic->isDeleted() && ! $vDeleted) {
+ continue;
+ }
+
+ $tid = $topic->getId();
+ $movedTo = $topic->isInForum($fob) ? '' : $topic->getForum()->getId();
+ $unread = ($topic->getLastRead() < $topic->getLastChange()) ? 1 : 0;
+ $sticky = $topic->getStickyLevel();
+ $tReplies = $topic->getPosts() - 1;
+
+ $fpTime = $topic->getPosted();
+ $fpAuth = $topic->getAuthor();
+ if (! (is_null($fpAuth) || in_array($fpAuth, $namesNeeded))) {
+ array_push($namesNeeded, $fpAuth);
+ }
+ $lcTime = $topic->getLastChange();
+ $lcAuth = $topic->getLastChangeAuthor();
+ if (! (is_null($lcAuth) || in_array($lcAuth, $namesNeeded))) {
+ array_push($namesNeeded, $lcAuth);
+ }
+
+ $isLocked = $topic->isLocked() ? 1 : 0;
+ $hasPoll = is_null($topic->getPoll()) ? 0 : 1;
+
+ $isDeleted = $topic->isDeleted() ? 1 : 0;
+ $deletedAt = $topic->getDeletionTime();
+ $deletedBy = $topic->getDeletionMod();
+ if (! (is_null($deletedBy) || in_array($deletedBy, $namesNeeded))) {
+ array_push($namesNeeded, $deletedBy);
+ }
+
+ array_push($output, "$tid#$movedTo#$unread#$sticky#$tReplies#$fpTime#$fpAuth#$lcTime#$lcAuth"
+ . "#$isLocked#$hasPoll#$isDeleted#$deletedAt#$deletedBy");
+ array_push($output, utf8entities($topic->getTitle()));
+ if ($movedTo != '') {
+ array_push($output, utf8entities($topic->getForum()->getTitle()));
+ }
+ }
+
+ $this->dumpNames( &$output, $namesNeeded );
+ return $output;
+ }
+}
+
+?>
diff -Naur beta5//scripts/game/main/forums/fl_category.inc forums//scripts/game/main/forums/fl_category.inc
--- beta5//scripts/game/main/forums/fl_category.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/main/forums/fl_category.inc 2011-02-05 10:10:03.434335002 +0100
@@ -0,0 +1,270 @@
+<?php
+
+/* Category management class */
+
+class fl_category {
+
+ private static $getLibQuery = null;
+ private static $getNameQuery = null;
+
+ private $game;
+ private $mainLib = null;
+ private $hdlLib = null;
+
+ private $parent = null;
+ private $user;
+ private $id;
+ private $title;
+ private $description;
+
+ private $forums = array();
+ private $oForums = array();
+ private $unread = null;
+ private $topics = null;
+ private $posts = null;
+
+ public function __construct( $game, $user, $id, $title, $description = null ) {
+ self::initQueries();
+
+ $this->game = $game;
+ $this->db = $this->game->getDBAccess();
+
+ $this->user = $user;
+ $this->id = $id;
+ $this->title = $title;
+ $this->description = $description;
+ }
+
+ private static function initQueries() {
+ if (!is_null(self::$getLibQuery)) {
+ return;
+ }
+
+ $db = config::getMainInterface()->getDBAccess();
+ self::$getLibQuery = $db->prepare(
+ "SELECT t.id AS id,t.lib_path AS path "
+ . "FROM forums.category_type t, forums.category c "
+ . "WHERE c.id = $1 AND t.id = c.acl_lib",
+ array("id") );
+ self::$getNameQuery = $db->prepare(
+ "SELECT name FROM forums.cat_type_text "
+ . "WHERE id = $1 AND lang = $2",
+ array("id", "lang") );
+ }
+
+ public function findCategory( $catId ) {
+ if ($this->getId() == $catId) {
+ return $this;
+ }
+ return null;
+ }
+
+
+ // ----------------------------------------------------------------------
+ // READING CATEGORY PROPERTIES
+ // ----------------------------------------------------------------------
+
+ public function getId() {
+ return $this->id;
+ }
+
+ public function getTitle() {
+ return $this->title;
+ }
+
+ public function getDescription() {
+ return $this->description;
+ }
+
+ public function getLibrary() {
+ if (is_null($this->hdlLib)) {
+ $q = self::$getLibQuery->execute(array("id" => $this->id));
+ if (! ($q && dbCount($q) == 1)) {
+ return null;
+ }
+
+ $r = dbFetchHash($q);
+ $r['library'] = $this->game->getLib($r['path']);
+ $r['text'] = array();
+ $this->hdlLib = $r;
+ }
+ return $this->hdlLib['library'];
+ }
+
+ public function getTypeName($lang) {
+ if (is_null($this->hdlLib)) {
+ if (is_null($this->getLibrary())) {
+ return null;
+ }
+ }
+
+ if (! isset($this->hdlLib['text'][$lang]) ) {
+ $q = self::$getNameQuery->execute(array(
+ "id" => $this->hdlLib['id'],
+ "lang" => $lang
+ ));
+ if (! ($q || dbCount($q) == 1)) {
+ return null;
+ }
+ list($this->hdlLib['text'][$lang]) = dbFetchArray($q);
+ }
+
+ return $this->hdlLib['text'][$lang];
+ }
+
+ public function getUnread( ) {
+ if (!is_null($this->unread)) {
+ return $this->unread;
+ }
+
+ $total = 0;
+ foreach ($this->forums as $f) {
+ if ( $f->canView() && ! $f->isDeleted() ) {
+ $total += $f->getUnread();
+ }
+ }
+ return ($this->unread = $total);
+ }
+
+ public function getTopics( ) {
+ if (!is_null($this->topics)) {
+ return $this->topics;
+ }
+
+ $total = 0;
+ foreach ($this->forums as $f) {
+ if ( $f->canView() && ! $f->isDeleted() ) {
+ $total += $f->getTopics();
+ }
+ }
+ return ($this->topics = $total);
+ }
+
+ public function getPosts( ) {
+ if (!is_null($this->posts)) {
+ return $this->posts;
+ }
+
+ $total = 0;
+ foreach ($this->forums as $f) {
+ if ( $f->canView() && ! $f->isDeleted() ) {
+ $total += $f->getPosts();
+ }
+ }
+ return ($this->posts = $total);
+ }
+
+ public function setParent( $category ) {
+ $this->parent = $category;
+ }
+
+ public function getParent() {
+ return $this->parent;
+ }
+
+
+ // ----------------------------------------------------------------------
+ // FORUM ACCESS
+ // ----------------------------------------------------------------------
+
+ public function getForums() {
+ return $this->oForums;
+ }
+
+ public function findModForums() {
+ $r = array();
+ foreach ($this->oForums as $f) {
+ if ($f->isMod()) {
+ array_push($r, $f);
+ }
+ }
+ return $r;
+ }
+
+ public function addForum( $forum ) {
+ if (is_null($forum)) {
+ return;
+ }
+ $this->forums[(string) $forum->getId()] = $forum;
+ array_push($this->oForums, $forum);
+ $forum->setParent($this);
+ }
+
+ public function insertNewForum($forum) {
+ if (isset($this->forums[$id])) {
+ return;
+ }
+
+ $this->forums[$forum->getId()] = $forum;
+ $forum->setParent($this);
+ $order = array();
+ for ($i = 0; $i < count($this->oForums); $i ++) {
+ if ($i == $forum->getOrder()) {
+ array_push($order, $forum);
+ }
+ if ($i >= $forum->getOrder()) {
+ $this->oForums[$i]->increaseOrder();
+ }
+ array_push($order, $this->oForums[$i]);
+ }
+ if ($i == $forum->getOrder()) {
+ array_push($order, $forum);
+ }
+ $this->oForums = $order;
+ }
+
+ public function findForum( $id ) {
+ return isset($this->forums[$id]) ? $this->forums[$id] : null;
+ }
+
+ public function moveForum( $id, $moveUp ) {
+ if (!isset($this->forums[$id])) {
+ return false;
+ }
+
+ $qs = "SELECT forums.move_" . ($moveUp ? 'up' : 'down') . '($1)';
+ $q = $this->db->query($qs, $id);
+ if (! ($q && dbCount($q))) {
+ return false;
+ }
+ list($rc) = dbFetchArray($q);
+
+ if ($rc == 't') {
+ $n = count($this->oForums);
+ for ($i = 0; $i < $n; $i ++) {
+ if ($this->oForums[$i]->getId() == $id) {
+ if ($moveUp) {
+ $rv = $this->oForums[$i - 1];
+ $this->oForums[$i - 1] = $this->oForums[$i];
+ $this->oForums[$i] = $rv;
+ } else {
+ $rv = $this->oForums[$i + 1];
+ $this->oForums[$i + 1] = $this->oForums[$i];
+ $this->oForums[$i] = $rv;
+ }
+ break;
+ }
+ }
+ } else {
+ $rv = false;
+ }
+
+ return $rv;
+ }
+
+ public function markRead() {
+ foreach ($this->oForums as $forum) {
+ $forum->markRead();
+ }
+ }
+
+ public function refresh() {
+ $this->unread = $this->topics = $this->posts = null;
+ if ($this->parent) {
+ $this->parent->refresh();
+ }
+ }
+}
+
+
+?>
diff -Naur beta5//scripts/game/main/forums/fl_container.inc forums//scripts/game/main/forums/fl_container.inc
--- beta5//scripts/game/main/forums/fl_container.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/main/forums/fl_container.inc 2011-02-05 10:10:03.434335002 +0100
@@ -0,0 +1,116 @@
+<?php
+
+/* Class that represents a pseudo-category that contains sub-categories */
+
+class fl_container {
+
+ private $categories = array();
+ private $parent = null;
+ private $id;
+ private $title;
+ private $description;
+
+ private $topics = null;
+ private $unread = null;
+
+ public function __construct( $id, $title, $description ) {
+ $this->id = $id;
+ $this->title = $title;
+ $this->description = $description;
+ }
+
+ public function addCategory( $category ) {
+ if (! is_null($category)) {
+ array_push($this->categories, $category);
+ $category->setParent( $this );
+ }
+ }
+
+ public function setParent( $category ) {
+ $this->parent = $category;
+ }
+
+ public function getParent() {
+ return $this->parent;
+ }
+
+ public function getCategories() {
+ return $this->categories;
+ }
+
+ public function getId() {
+ return $this->id;
+ }
+
+ public function getTitle() {
+ return $this->title;
+ }
+
+ public function getDescription() {
+ return $this->description;
+ }
+
+ public function getUnread( ) {
+ if (!is_null($this->unread)) {
+ return $this->unread;
+ }
+
+ $total = 0;
+ foreach ($this->categories as $c) {
+ $total += $c->getUnread();
+ }
+ return ($this->unread = $total);
+ }
+
+ public function getTopics( ) {
+ if (!is_null($this->topics)) {
+ return $this->topics;
+ }
+
+ $total = 0;
+ foreach ($this->categories as $c) {
+ $total += $c->getTopics();
+ }
+ return ($this->topics = $total);
+ }
+
+ public function findCategory( $catId ) {
+ if ($this->getId() == $catId) {
+ return $this;
+ }
+ foreach ($this->categories as $cat) {
+ $x = $cat->findCategory( $catId );
+ if (! is_null($x)) {
+ return $x;
+ }
+ }
+ return null;
+ }
+
+ public function findForum( $fId ) {
+ foreach ($this->categories as $cat) {
+ $x = $cat->findForum( $fId );
+ if (! is_null($x)) {
+ return $x;
+ }
+ }
+ return null;
+ }
+
+ public function findModForums() {
+ $r = array();
+ foreach ($this->categories as $cat) {
+ $r = array_merge($r, $cat->findModForums());
+ }
+ return $r;
+ }
+
+ public function refresh() {
+ $this->unread = $this->topics = null;
+ if ($this->parent) {
+ $this->parent->refresh();
+ }
+ }
+}
+
+?>
diff -Naur beta5//scripts/game/main/forums/fl_forum.inc forums//scripts/game/main/forums/fl_forum.inc
--- beta5//scripts/game/main/forums/fl_forum.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/main/forums/fl_forum.inc 2011-02-05 10:10:03.434335002 +0100
@@ -0,0 +1,533 @@
+<?php
+
+/* Forum handling class */
+
+class fl_forum {
+
+ private static $queries = null;
+
+ private $game;
+ private $db;
+ private $mainLib = null;
+ private $parent = null;
+
+ private $user;
+ private $record;
+ private $privs;
+
+ private $unread = null;
+ private $topicList = null;
+
+ private $acl = array(
+ "admins" => array(),
+ "mods" => array(),
+ "users" => array()
+ );
+
+ public function __construct($game, $id, $user) {
+ self::initQueries();
+
+ $this->game = $game;
+ $this->db = $this->game->getDBAccess();
+ $this->user = $user;
+
+ $q = self::$queries['getInfo']->execute($id);
+ if (! ($q && dbCount($q) == 1)) {
+ throw new Exception("Unable to read forum record");
+ }
+ $this->record = dbFetchHash($q);
+
+ $this->privs = array(
+ 'adm' => false,
+ 'mod' => false,
+ 'ntop' => false,
+ 'poll' => false,
+ 'post' => false,
+ 'view' => false
+ );
+ }
+
+
+ private static function initQueries() {
+ if (is_array(self::$queries)) {
+ return;
+ }
+
+ $db = config::getMainInterface()->getDBAccess();
+
+ self::$queries['getInfo'] = $db->prepare(
+ "SELECT * FROM forums.forum WHERE id = $1",
+ array("id") );
+ self::$queries['getRead'] = $db->prepare(
+ "SELECT forums.get_read_topics( $1 , $2 )",
+ array("forum", "user") );
+ self::$queries['getCurrentSig'] = $db->prepare(
+ "SELECT id FROM forums.get_signature( $1, UNIX_TIMESTAMP(NOW()) )",
+ array("user") );
+ self::$queries['createTopic'] = $db->prepare(
+ "SELECT forums.create_topic($1, $2, $3, $4, $5, $6, $7, $8)",
+ array("forum", "user", "sticky", "title", "contents", "code", "smileys", "sig") );
+ self::$queries['killTopic'] = $db->prepare(
+ "DELETE FROM forums.t_topic WHERE id = $1",
+ array("topic") );
+ self::$queries['getTopics'] = $db->prepare(
+ "SELECT * FROM forums.topic WHERE forum = $1 OR moved_from = $1",
+ array("forum") );
+ }
+
+
+ // ----------------------------------------------------------------------
+ // READING FORUM PROPERTIES
+ // ----------------------------------------------------------------------
+
+ public function getId() {
+ return $this->record['id'];
+ }
+
+ public function getCategory() {
+ if (is_null($this->mainLib)) {
+ $this->mainLib = $this->game->getLib('main/forums');
+ }
+ return $this->mainLib->call('getCategory', $this->record['category'], $this->user);
+ }
+
+ public function getOrder() {
+ return $this->record['f_order'];
+ }
+
+ public function getTitle() {
+ return $this->record['title'];
+ }
+
+ public function getDescription() {
+ return $this->record['description'];
+ }
+
+ public function isDeleted() {
+ return !is_null($this->record['deleted']);
+ }
+
+ public function deletedAt() {
+ return $this->isDeleted() ? $this->record['deleted'] : null;
+ }
+
+ public function deletedBy() {
+ return $this->isDeleted() ? $this->record['deleted_by'] : null;
+ }
+
+ public function getTopics() {
+ return $this->record['topics'];
+ }
+
+ public function getPosts() {
+ return $this->record['posts'];
+ }
+
+ public function getUnread() {
+ if (is_null($this->unread)) {
+ $q = self::$queries['getRead']->execute($this->record['id'], $this->user);
+ if (! ($q && dbCount($q) == 1)) {
+ return 0;
+ }
+ list($r) = dbFetchArray($q);
+ $this->unread = $this->record['topics'] - $r;
+ }
+ return $this->unread;
+ }
+
+ public function isAdmin() {
+ return $this->privs['adm'];
+ }
+
+ public function isMod() {
+ return $this->privs['mod'];
+ }
+
+ public function canCreateTopic() {
+ return $this->privs['ntop'];
+ }
+
+ public function canCreatePoll() {
+ return $this->privs['poll'];
+ }
+
+ public function canPost() {
+ return $this->privs['post'];
+ }
+
+ public function canView() {
+ return $this->privs['view'];
+ }
+
+ public function getLastPost() {
+ $q = $this->db->query("SELECT * FROM forums.get_last_post($1)", $this->record['id']);
+ if (! ($q && dbCount($q))) {
+ return null;
+ }
+
+ if (! $this->mainLib) {
+ $this->mainLib = $this->game->getLib('main/forums');
+ }
+ return $this->mainLib->call('getPost', dbFetchHash($q), $this->user);
+ }
+
+ public function setParent( $category ) {
+ $this->parent = $category;
+ }
+
+ public function getParent() {
+ return $this->parent;
+ }
+
+
+ // ----------------------------------------------------------------------
+ // FORUM'S ACCESS LIST
+ // ----------------------------------------------------------------------
+
+ private function getAcl($type, $libFunc, $iWantNames) {
+ // Check if we read that already
+ $aKey = $iWantNames ? 'names' : 'ids';
+ if (array_key_exists($aKey, $this->acl[$type])) {
+ return $this->acl[$type][$aKey];
+ }
+
+ // Get the library and extract the ACL IDs
+ $catLib = $this->getCategory()->getLibrary();
+ if (! array_key_exists('ids', $this->acl[$type])) {
+ $this->acl[$type]['ids'] = $catLib->call($libFunc, $this->record['id']);
+ }
+
+ // If we were requesting the IDs, leave
+ if ($aKey == 'ids') {
+ return $this->acl[$type]['ids'];
+ }
+
+ // If the IDs list is null, names are null as well
+ if (is_null($this->acl[$type]['ids'])) {
+ $this->acl[$type]['names'] = null;
+ return $this->acl[$type]['names'];
+ }
+
+ // Convert the identifiers to names and return
+ $this->acl[$type]['names'] = array();
+ foreach ($this->acl[$type]['ids'] as $id) {
+ $this->acl[$type]['names'][$id] = $catLib->call('aclIdToName', $id);
+ }
+ return $this->acl[$type]['names'];
+ }
+
+ public function getAdministrators($iWantNames = false) {
+ return $this->getAcl("admins", "getAdmins", $iWantNames);
+ }
+
+ public function getModerators($iWantNames = false) {
+ return $this->getAcl("mods", "getModerators", $iWantNames);
+ }
+
+ public function getUsers($iWantNames = false) {
+ return $this->getAcl("users", "getUsers", $iWantNames);
+ }
+
+ public function clearACL() {
+ $this->getCategory()->getLibrary()->call('clearForumACL', $this->record['id']);
+ $this->acl = array(
+ 'users' => array(),
+ 'mods' => array(),
+ 'admins' => array()
+ );
+ }
+
+ public function addModerator($id) {
+ $this->getCategory()->getLibrary()->call('addForumModerator', $this->record['id'], $id);
+ $this->acl['mods'] = array();
+ }
+
+ public function addUser($id) {
+ $this->getCategory()->getLibrary()->call('addForumUser', $this->record['id'], $id);
+ $this->acl['users'] = array();
+ }
+
+
+ // ----------------------------------------------------------------------
+ // SETTING FORUM PROPERTIES
+ // ----------------------------------------------------------------------
+
+ public function setAdmin($value) {
+ $this->privs['adm'] = $value;
+ }
+
+ public function setMod($value) {
+ $this->privs['mod'] = $value;
+ }
+
+ public function setCreateTopic($value) {
+ $this->privs['ntop'] = $value;
+ }
+
+ public function setCreatePoll($value) {
+ $this->privs['poll'] = $value;
+ }
+
+ public function setPost($value) {
+ $this->privs['post'] = $value;
+ }
+
+ public function setView($value) {
+ $this->privs['view'] = $value;
+ }
+
+ public function increaseOrder() {
+ $this->record['f_order'] ++;
+ }
+
+
+ // ----------------------------------------------------------------------
+ // INTERNAL METHODS FOR CHECKS AND FORMATTING
+ // ----------------------------------------------------------------------
+
+ private function checkPostContents($title, $contents) {
+ if (strlen($title) < 2) {
+ $e = 1;
+ } elseif (strlen($title) > 100) {
+ $e = 2;
+ } elseif (strlen($contents) < 3) {
+ $e = 3;
+ } else {
+ $e = 0;
+ }
+ return $e;
+ }
+
+
+ private function reformatContents($contents) {
+ // Max. line breaks
+ $maxNL = 500;
+ // Max. characters without break
+ $maxNC = 100;
+
+ $ot = $contents;
+ $nt = "";
+ $nl = 0;
+
+ while ($ot != '' && $nl < $maxNL) {
+ $p = strpos($ot, '\n');
+ if ($p !== false && $p < $maxNC) {
+ $nt .= substr($ot, 0, $p+1);
+ $ot = substr($ot, $p+1);
+ } else if (strlen($ot) < $maxNC) {
+ $nt .= $ot;
+ $ot = "";
+ } else {
+ $s = substr($ot, 0, $maxNC);
+ $p = strrpos($s, ' ');
+ $ot = substr($ot, $maxNC);
+ $nt .= $s;
+ if ($p === false) {
+ $nt .= "\n";
+ }
+ }
+ $nl ++;
+ }
+
+ if ($nl >= $maxNL) {
+ return null;
+ }
+ return $nt;
+ }
+
+
+
+ // ----------------------------------------------------------------------
+ // OPERATIONS
+ // ----------------------------------------------------------------------
+
+ /* This method creates a new topic in the forum. It returns the
+ * corresponding fl_topic instance or a numeric error code.
+ *
+ * Error codes:
+ * -1 - Permission denied (topic creation)
+ * -2 - Permission denied (poll creation)
+ * -3 - Title too short
+ * -4 - Title too long
+ * -5 - Contents too short
+ * -6 - Contents too long
+ * -7 - Permission denied (sticky)
+ * -8 - Database access error
+ * -9 - Poll title too short
+ * -10 - Poll title too long
+ * -11 - Not enough poll options
+ * -12 - Too many poll options
+ */
+ public function createTopic(
+ $title, $contents, $stickyLevel,
+ $enableCode, $enableSmileys, $enableSignature,
+ $poll = null
+ ) {
+ // Check posting privileges
+ if ( ! $this->canCreateTopic() ) {
+ return -1;
+ }
+ if ( ! (is_null($poll) || $this->canCreatePoll()) ) {
+ return -2;
+ }
+
+ // Check the title and contents
+ $title = trim($title);
+ $contents = trim($contents);
+ $pc = $this->checkPostContents($title, $contents);
+ if ($pc) {
+ return - $pc - 2;
+ }
+
+ // Reformat the post's contents
+ $contents = $this->reformatContents($contents);
+ if (is_null($contents)) {
+ return -6;
+ }
+
+ // Check the sticky level
+ $stickyLevel = (int) $stickyLevel;
+ if ( $stickyLevel < 0 || $stickyLevel > 10 || ($stickyLevel > 0 && ! $this->isMod()) ) {
+ return -7;
+ }
+
+ // Check the poll's contents
+ if (! is_null($poll)) {
+ $pc = $poll->checkData();
+ if ($pc != 0) {
+ return - $pc - 8;
+ }
+ }
+
+ // Get the user's current signature if needed
+ if ($enableSignature) {
+ $q = self::$queries['getCurrentSig']->execute($this->user);
+ if ( ! ($q && dbCount($q)) ) {
+ return -8;
+ }
+
+ list($sig) = dbFetchArray($q);
+ } else {
+ $sig = null;
+ }
+
+ // Add the topic
+ $q = self::$queries['createTopic']->execute(array(
+ "forum" => $this->record['id'],
+ "user" => $this->user,
+ "sticky" => $stickyLevel,
+ "title" => $title,
+ "contents" => $contents,
+ "code" => dbBool($enableCode),
+ "smileys" => dbBool($enableSmileys),
+ "sig" => $sig
+ ));
+ if (! ($q && dbCount($q)) ) {
+ return -8;
+ }
+ list($tid) = dbFetchArray($q);
+ if (is_null($tid)) {
+ return -8;
+ }
+
+ // Insert poll if needed
+ if (! (is_null($poll) || $poll->insertIntoDB( $this->game, $this->user, $tid ) ) ) {
+ self::$queries['killTopic']->execute($tid);
+ return -8;
+ }
+
+ if (! $this->mainLib) {
+ $this->mainLib = $this->game->getLib('main/forums');
+ }
+ $topic = $this->mainLib->call('getTopic', $tid, $this->user);
+
+ $this->refresh();
+ return $topic;
+ }
+
+
+ public function getTopicList() {
+ if (is_null($this->topicList)) {
+ $q = self::$queries['getTopics']->execute($this->record['id']);
+ if (! $q) {
+ return null;
+ }
+
+ if (is_null($this->mainLib)) {
+ $this->mainLib = $this->game->getLib('main/forums');
+ }
+ $this->topicList = array();
+ while ($r = dbFetchHash($q)) {
+ $t = $this->mainLib->call('getTopic', $r, $this->user);
+ $this->topicList[$t->getId()] = $t;
+ }
+ }
+
+ return $this->topicList;
+ }
+
+ public function findTopic( $id ) {
+ if (is_null($this->topicList)) {
+ $this->getTopicList();
+ }
+ return array_key_exists($id, $this->topicList) ? $this->topicList[$id] : null;
+ }
+
+ /* Deletes the forum */
+ function delete() {
+ if ($this->isDeleted()) {
+ return;
+ }
+
+ $this->db->query("SELECT forums.delete_forum($1, $2)", $this->record['id'], $this->user);
+
+ $q = self::$queries['getInfo']->execute($this->record['id']);
+ if ($q && dbCount($q) == 1) {
+ $this->record = dbFetchHash($q);
+ }
+ }
+
+ /* Restore the forum */
+ function restore() {
+ if (!$this->isDeleted()) {
+ return;
+ }
+
+ $this->db->query("SELECT forums.restore_forum($1)", $this->record['id']);
+
+ $q = self::$queries['getInfo']->execute($this->record['id']);
+ if ($q && dbCount($q) == 1) {
+ $this->record = dbFetchHash($q);
+ }
+ }
+
+ /* Moves the forum either up or down */
+ function move($moveUp) {
+ $rv = $this->getCategory()->moveForum($this->record['id'], $moveUp);
+ if ($rv !== false) {
+ $this->record['f_order'] += ($moveUp ? -1 : 1);
+ $rv->record['f_order'] += ($moveUp ? 1 : -1);
+ }
+ }
+
+ /* Mark all topics as read */
+ function markRead() {
+ $this->db->query("SELECT forums.mark_forum_read($1, $2)", $this->record['id'], $this->user);
+ }
+
+ /* Forces the object to be re-read from the DB */
+ function refresh() {
+ $q = self::$queries['getInfo']->execute($this->record['id']);
+ if (! ($q && dbCount($q) == 1)) {
+ return;
+ }
+ $this->record = dbFetchHash($q);
+ $this->unread = $this->topics = $this->topicList = null;
+
+ if ($this->parent) {
+ $this->parent->refresh();
+ }
+ }
+}
+
+?>
diff -Naur beta5//scripts/game/main/forums/fl_poll.inc forums//scripts/game/main/forums/fl_poll.inc
--- beta5//scripts/game/main/forums/fl_poll.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/main/forums/fl_poll.inc 2011-02-05 10:10:03.434335002 +0100
@@ -0,0 +1,373 @@
+<?php
+
+
+/* Forum poll management class */
+
+class fl_poll {
+
+ private $user;
+ private $game;
+ private $db;
+
+ private $fromDB;
+ private $nbVotesQ;
+ private $checked;
+
+ private $record;
+ private $options = array();
+
+ public function __construct() {
+ $args = func_get_args();
+
+ if (count($args) == 1) {
+ // Manual initialisation
+ $this->fromDB = false;
+ $this->checked = false;
+ $this->record = array(
+ 'title' => preg_replace('/\s+/', ' ', trim($args[0]))
+ );
+ } else {
+ // Load from database
+ $this->fromDB = true;
+ $this->checked = true;
+ $this->game = $args[0];
+ $this->db = $this->game->getDBAccess();
+ $this->mainLib = $this->game->getLib('main/forums');
+ $this->user = $args[1];
+ $id = $args[2];
+
+ // Fetch the poll's data
+ $q = $this->db->query("SELECT * FROM forums.poll WHERE topic = $1 FOR UPDATE", $id);
+ if (! ($q && dbCount($q) == 1)) {
+ throw new Exception("No poll found for topic #$id");
+ }
+ $this->record = dbFetchHash($q);
+
+ // Fetch the poll options
+ $q = $this->db->query("SELECT * FROM forums.poll_option "
+ . "WHERE poll = $1 ORDER BY po_order "
+ . "FOR UPDATE", $id);
+ if (! ($q && dbCount($q) > 1)) {
+ throw new Exception("Poll options not found for topic #$id");
+ }
+ while ($r = dbFetchHash($q)) {
+ array_push($this->options, $r);
+ }
+
+ $this->prepareNbVotesQuery();
+ }
+ }
+
+
+ private function prepareNbVotesQuery() {
+ $this->nbVotesQ = $this->db->prepare(
+ "SELECT COUNT(*) FROM forums.poll_vote WHERE vote = $1", array("option") );
+ }
+
+
+ // ----------------------------------------------------------------------
+ // READING POLL PROPERTIES
+ // ----------------------------------------------------------------------
+
+ public function getTopic() {
+ if (! $this->fromDB) {
+ return null;
+ }
+ return $this->mainLib->call('getTopic', $this->record['topic'] );
+ }
+
+ public function getTitle() {
+ return $this->record['title'];
+ }
+
+ public function isClosed() {
+ return $this->fromDB && ($this->record['closed'] == 't');
+ }
+
+ public function isDeleted() {
+ return $this->fromDB && !is_null($this->record['deleted']);
+ }
+
+ public function getDeletionTime() {
+ return $this->fromDB ? $this->record['deleted'] : null;
+ }
+
+ public function getDeletionMod() {
+ return $this->fromDB ? $this->record['deleted_by'] : null;
+ }
+
+
+ // ----------------------------------------------------------------------
+ // POLL CREATION
+ // ----------------------------------------------------------------------
+
+ /* Checks the poll's data before inserting it in the database.
+ * Returns null if the poll is already inside the database, 0 if the poll
+ * is ok, or one of the following error codes:
+ * 1 - Title too short
+ * 2 - Title too long
+ * 3 - Not enough options
+ * 4 - Too many options
+ */
+ public function checkData() {
+ if ($this->fromDB || $this->checked) {
+ return null;
+ }
+
+ $l = strlen($this->record['title']);
+ if ($l < 3) {
+ return 1;
+ } elseif ($l > 64) {
+ return 2;
+ }
+
+ $c = count($this->options);
+ if ($c < 2) {
+ return 3;
+ } elseif ($c > 20) {
+ return 4;
+ }
+
+ $this->checked = true;
+ return 0;
+ }
+
+ /* Insert the poll's data into the database. */
+ public function insertIntoDB($game, $user, $topicId) {
+ if ($this->fromDB || ! $this->checked) {
+ return false;
+ }
+ $db = $game->getDBAccess();
+
+ // Insert the poll
+ $q = $db->query("SELECT * FROM forums.create_poll($1, $2)", $topicId, $this->record['title']);
+ if (! ($q && dbCount($q) == 1)) {
+ return false;
+ }
+
+ $rec = dbFetchHash($q);
+ if (is_null($rec['topic'])) {
+ return false;
+ }
+
+ // Insert the options
+ $pollQuery = $db->prepare("SELECT * FROM forums.create_option($1, $2, $3)",
+ array("poll", "order", "title") );
+ try {
+ $nOpts = array();
+ for ($i = 0; $i < count($this->options); $i ++) {
+ $q = $pollQuery->execute(array(
+ "poll" => $topicId,
+ "order" => $i,
+ "title" => $this->options[$i]['title']
+ ));
+ if (! ($q && dbCount($q) == 1)) {
+ throw new Exception('abort');
+ }
+
+ $orec = dbFetchHash($q);
+ if (is_null($orec['id'])) {
+ throw new Exception('abort');
+ }
+
+ array_push($nOpts, $orec);
+ }
+ $pollQuery->destroy();
+ } catch (Exception $e) {
+ $pollQuery->destroy();
+ $db->query("DELETE FROM forums.poll WHERE topic = $1", $topicId);
+ return false;
+ }
+
+ // Finalize
+ $this->record = $rec;
+ $this->options = $nOpts;
+ $this->game = $game;
+ $this->db = $db;
+ $this->user = $user;
+ $this->mainLib = $this->game->getLib('main/forums');
+ $this->prepareNbVotesQuery();
+ $this->fromDB = true;
+ return true;
+ }
+
+
+ // ----------------------------------------------------------------------
+ // OPTIONS
+ // ----------------------------------------------------------------------
+
+ /* Adds a new option at the end of the list.
+ * Returns 0 on success or one of the following error codes:
+ * -1 - Title too short
+ * -2 - Title too long
+ * -3 - Too many options
+ * -4 - Database error
+ * -5 - Adding options after the poll has been checked is not permitted
+ */
+ public function appendOption($title) {
+ $title = preg_replace('/\s+/', ' ', trim($title));
+ $l = strlen($title);
+ if ($l < 2) {
+ return -1;
+ } elseif ($l > 64) {
+ return -2;
+ }
+
+ if ($this->fromDB) {
+ $c = count($this->options);
+ if ($c == 20) {
+ return -3;
+ }
+
+ $q = $this->db->query("SELECT * FROM forums.create_option($1, $2, $3)",
+ $this->record['topic'], $c, $title);
+ if (! ($q && dbCount($q) == 1)) {
+ return -4;
+ }
+ array_push($this->options, dbFetchHash($q));
+ } else if (!$this->checked) {
+ array_push($this->options, array(
+ 'title' => $title
+ ));
+ } else {
+ return -5;
+ }
+ return 0;
+ }
+
+ /* Removes the poll option with the specified index. */
+ public function removeOption( $order ) {
+ $order = (int) $order;
+ if ($order < 0 || $order >= count($this->options)) {
+ return false;
+ }
+
+ if ($this->fromDB) {
+ $q = $this->db->query("SELECT forums.delete_option( $1, $2 )", $this->record['topic'], $order);
+ if (! ($q && dbCount($q) == 1)) {
+ return false;
+ }
+ list($ok) = dbFetchArray($q);
+ if ($ok != 't') {
+ return false;
+ }
+
+ for ($i = $order + 1; $i < count($this->options); $i ++) {
+ $this->options[$i]['po_order'] --;
+ }
+ }
+ array_splice($this->options, $order, 1);
+ return true;
+ }
+
+ /* Get the options */
+ public function getOptions() {
+ $opts = $this->options;
+ if (! $this->fromDB) {
+ for ($i = 0; $i < count($opts); $i++) {
+ $opts[$i]['po_order'] = $i;
+ }
+ }
+ return $opts;
+ }
+
+ /* Move an option up in the list of options */
+ public function moveUp( $order ) {
+ if ($order <= 0 || $order >= count($this->options)) {
+ return false;
+ }
+
+ if ($this->fromDB) {
+ $q = $this->db->query("SELECT forums.move_opt_up( $1, $2 )", $this->record['topic'], $order);
+ if (! ($q && dbCount($q) == 1)) {
+ return false;
+ }
+ list($ok) = dbFetchArray($q);
+ if ($ok != 't') {
+ return false;
+ }
+
+ $this->options[$order]['po_order'] --;
+ $this->options[$order - 1]['po_order'] ++;
+ }
+
+ $tmp = $this->options[$order];
+ $this->options[$order] = $this->options[$order - 1];
+ $this->options[$order - 1] = $tmp;
+ return true;
+ }
+
+ /* Move an option down in the list of options */
+ public function moveDown( $order ) {
+ if ($order < 0 || $order >= count($this->options) - 1) {
+ return false;
+ }
+
+ if ($this->fromDB) {
+ $q = $this->db->query("SELECT forums.move_opt_down($1,$2)", $this->record['topic'], $order);
+ if (! ($q && dbCount($q) == 1)) {
+ return false;
+ }
+ list($ok) = dbFetchArray($q);
+ if ($ok != 't') {
+ return false;
+ }
+
+ $this->options[$order]['po_order'] ++;
+ $this->options[$order + 1]['po_order'] --;
+ }
+
+ $tmp = $this->options[$order];
+ $this->options[$order] = $this->options[$order + 1];
+ $this->options[$order + 1] = $tmp;
+ return true;
+ }
+
+ /* Vote */
+ public function setVote( $order ) {
+ if (! $this->fromDB || $order < 0 || $order >= count($this->options)) {
+ return false;
+ }
+
+ $q = $this->db->query("SELECT forums.set_vote($1,$2,$3)", $this->user, $this->record['topic'],
+ $this->options[$order]['id']);
+ if (! $q) {
+ return false;
+ }
+ return true;
+ }
+
+ /* Returns the order of the option the user is voting for */
+ public function getVote() {
+ if (! $this->fromDB) {
+ return null;
+ }
+
+ $q = $this->db->query("SELECT o.po_order FROM forums.poll_option o, forums.poll_vote v "
+ . " WHERE o.id = v.vote AND o.poll = $1 AND v.account = $2",
+ $this->record['topic'], $this->user);
+ if (!($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($order) = dbFetchArray($q);
+ return $order;
+ }
+
+ /* Returns the amount of votes for an option */
+ public function getNbVotes( $order ) {
+ if (! $this->fromDB || $order < 0 || $order >= count($this->options)) {
+ return 0;
+ }
+
+ $q = $this->nbVotesQ->execute($this->options[$order]['id']);
+ if (!($q && dbCount($q) == 1)) {
+ return 0;
+ }
+
+ list($votes) = dbFetchArray($q);
+ return $votes;
+ }
+}
+
+
+?>
diff -Naur beta5//scripts/game/main/forums/fl_post.inc forums//scripts/game/main/forums/fl_post.inc
--- beta5//scripts/game/main/forums/fl_post.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/main/forums/fl_post.inc 2011-02-05 10:10:03.434335002 +0100
@@ -0,0 +1,219 @@
+<?php
+
+
+class fl_post {
+
+ private static $getQ = null;
+ private static $historyQ = null;
+ private static $repliesQ = null;
+
+ private $game;
+ private $mainLib;
+ private $db;
+ private $user;
+
+ private $record;
+ private $history = null;
+ private $replies = null;
+
+
+ public function __construct($game, $user, $data) {
+ self::initQueries();
+
+ $this->game = $game;
+ $this->user = $user;
+ $this->db = $this->game->getDBAccess();
+ $this->mainLib = $this->game->getLib('main/forums');
+
+ if (is_array($data)) {
+ $this->record = $data;
+ } else {
+ $data = (int) $data;
+ $row = self::$getQ->execute($data);
+ if (! ($row && dbCount($row) == 1)) {
+ throw new Exception("Post #$data not found");
+ }
+ $this->record = dbFetchHash($row);
+ }
+ }
+
+
+ static private function initQueries() {
+ if (! is_null(self::$getQ)) {
+ return;
+ }
+
+ $db = config::getMainInterface()->getDBAccess();
+ self::$getQ = $db->prepare( "SELECT * FROM forums.post WHERE id = $1", array("id") );
+ self::$historyQ = $db->prepare( "SELECT * FROM forums.post_text WHERE post = $1 ORDER BY moment",
+ array( "post" ));
+ self::$repliesQ = $db->prepare( "SELECT id FROM forums.post WHERE reply_to = $1 ORDER BY post_moment",
+ array( "post" ));
+ }
+
+
+ // ----------------------------------------------------------------------
+ // READING POST PROPERTIES
+ // ----------------------------------------------------------------------
+
+ public function getId() {
+ return $this->record['id'];
+ }
+
+
+ public function getForum() {
+ return $this->mainLib->call('getForum', $this->record['forum'], $this->user);
+ }
+
+ public function getTopic() {
+ return $this->mainLib->call('getTopic', $this->record['topic'], $this->user);
+ }
+
+
+ public function getParent() {
+ return is_null($this->record['reply_to']) ? null
+ : $this->mainLib->call('getPost', $this->record['reply_to'], $this->user);
+ }
+
+ public function getDepth() {
+ return $this->record['depth'];
+ }
+
+
+ public function getPostedAt() {
+ return $this->record['post_moment'];
+ }
+
+ public function getPostedBy() {
+ return $this->record['author'];
+ }
+
+ public function getLastChange() {
+ return $this->record['last_change'];
+ }
+
+ public function getLastChangeAuthor() {
+ return $this->record['last_author'];
+ }
+
+ public function isUnread() {
+ $topic = $this->getTopic();
+ if (is_null($topic)) {
+ return false;
+ }
+
+ return $topic->getLastRead() < $this->record['last_change'];
+ }
+
+
+ public function isDeleted() {
+ return ! is_null($this->record['deleted']);
+ }
+
+ public function getDeletionTime() {
+ return $this->record['deleted'];
+ }
+
+ public function getDeletionMod() {
+ return $this->record['deleted_by'];
+ }
+
+
+ public function getTitle() {
+ return $this->record['title'];
+ }
+
+ public function getContents($time = null) {
+ if (is_null($time)) {
+ $v = $this->record['contents'];
+ } else {
+ $hist = $this->getFullHistory();
+ $v = '';
+ foreach ($hist as $he) {
+ if ($he['moment'] > $time) {
+ break;
+ }
+ $v = $he['contents'];
+ }
+ }
+ return $v;
+ }
+
+ public function codeEnabled($time = null) {
+ if (is_null($time)) {
+ $v = $this->record['enable_code'];
+ } else {
+ $hist = $this->getFullHistory();
+ $v = false;
+ foreach ($hist as $he) {
+ if ($he['moment'] > $time) {
+ break;
+ }
+ $v = $he['enable_code'];
+ }
+ }
+ return ($v == 't');
+ }
+
+ public function smileysEnabled($time = null) {
+ if (is_null($time)) {
+ $v = $this->record['enable_smileys'];
+ } else {
+ $hist = $this->getFullHistory();
+ $v = false;
+ foreach ($hist as $he) {
+ if ($he['moment'] > $time) {
+ break;
+ }
+ $v = $he['enable_smileys'];
+ }
+ }
+ return ($v == 't');
+ }
+
+
+ public function getSignature() {
+ throw new Exception("FIXME: getSignature() is not implemented");
+ }
+
+ /* This function returns a post's full history */
+ public function getFullHistory() {
+ if (is_null( $this->history )) {
+ $result = self::$historyQ->execute($this->record['id']);
+ if (! ($result && dbCount($result))) {
+ return null;
+ }
+ $history = array();
+ while ($row = dbFetchHash($result)) {
+ array_push($history, $row);
+ }
+ $this->history = $history;
+ }
+ return $this->history;
+ }
+
+ /* This function returns the replies to a post */
+ public function getReplies() {
+ if (is_null( $this->replies )) {
+ $result = self::$repliesQ->execute($this->record['id']);
+ if (! $result) {
+ return null;
+ }
+ $this->replies = array();
+ while ($row = dbFetchArray($result)) {
+ $reply = $this->mainLib->call('getPost', $row[0], $this->user);
+ if (! is_null($reply)) {
+ array_push($this->replies, $reply);
+ }
+ }
+ }
+ return $this->replies;
+ }
+
+ /* This function deletes a post if it is not the top-level post */
+ public function delete() {
+ }
+}
+
+
+?>
diff -Naur beta5//scripts/game/main/forums/fl_topic.inc forums//scripts/game/main/forums/fl_topic.inc
--- beta5//scripts/game/main/forums/fl_topic.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/main/forums/fl_topic.inc 2011-02-05 10:10:03.434335002 +0100
@@ -0,0 +1,339 @@
+<?php
+
+/* Topic handling class */
+
+class fl_topic {
+
+ private static $getQuery = null;
+ private static $restoreQuery = null;
+ private static $deleteQuery = null;
+ private static $stickyLevelQuery = null;
+ private static $setLockQuery = null;
+ private static $moveQuery = null;
+ private static $postsQuery = null;
+
+ private $game;
+ private $db;
+ private $mainLib = null;
+
+ private $user;
+ private $record;
+ private $lastRead = null;
+ private $allPosts = null;
+
+ public function __construct($game, $user, $data) {
+ self::initQueries();
+
+ $this->game = $game;
+ $this->db = $this->game->getDBAccess();
+ $this->user = $user;
+
+ if (is_array($data)) {
+ $this->record = $data;
+ } else {
+ $data = (int) $data;
+ $q = self::$getQuery->execute($data);
+ if (! ($q && dbCount($q) == 1)) {
+ throw new Exception("Topic #$data not found");
+ }
+ $this->record = dbFetchHash($q);
+ }
+ }
+
+ static private function initQueries() {
+ if (is_null(self::$getQuery)) {
+ $db = config::getMainInterface()->getDBAccess();
+ self::$getQuery = $db->prepare(
+ "SELECT * FROM forums.topic WHERE id = $1",
+ array("id") );
+ self::$restoreQuery = $db->prepare( "SELECT forums.restore_post( $1 )", array("id") );
+ self::$deleteQuery = $db->prepare( "SELECT forums.delete_post( $1 , $2 )",
+ array("id", "user") );
+ self::$stickyLevelQuery = $db->prepare( "UPDATE forums.t_topic SET sticky_level = $2 "
+ . "WHERE id = $1", array("id", "level") );
+ self::$setLockQuery = $db->prepare( "UPDATE forums.t_topic SET locked = $2 WHERE id = $1",
+ array("id", "locked") );
+ self::$moveQuery = $db->prepare( "SELECT forums.move_topic( $1, $2, $3)",
+ array("topic", "destination", "user") );
+ self::$postsQuery = $db->prepare( "SELECT * FROM forums.post WHERE topic = $1",
+ array("topic") );
+ }
+ }
+
+
+ // ----------------------------------------------------------------------
+ // READING TOPIC PROPERTIES
+ // ----------------------------------------------------------------------
+
+ public function getId() {
+ return $this->record['id'];
+ }
+
+ public function getForum() {
+ if (is_null($this->mainLib)) {
+ $this->mainLib = $this->game->getLib('main/forums');
+ }
+ return $this->mainLib->call('getForum', $this->record['forum'], $this->user);
+ }
+
+ public function getMovedFrom() {
+ if (is_null($this->record['moved_from'])) {
+ return null;
+ }
+
+ if (is_null($this->mainLib)) {
+ $this->mainLib = $this->game->getLib('main/forums');
+ }
+ return $this->mainLib->call('getForum', $this->record['moved_from'], $this->user);
+ }
+
+ public function isInForum($forum) {
+ return ($forum->getId() == $this->record['forum']);
+ }
+
+ public function getPoll() {
+ if (is_null($this->mainLib)) {
+ $this->mainLib = $this->game->getLib('main/forums');
+ }
+ return $this->mainLib->call('getPoll', $this->record['id'], $this->user);
+ }
+
+ public function getStickyLevel() {
+ return $this->record['sticky_level'];
+ }
+
+ public function getTitle() {
+ return $this->record['title'];
+ }
+
+ public function getPosted() {
+ return $this->record['fp_moment'];
+ }
+
+ public function getAuthor() {
+ return $this->record['fp_author'];
+ }
+
+ public function getLastChange() {
+ return $this->record['lc_moment'];
+ }
+
+ public function getLastChangeAuthor() {
+ return $this->record['lc_author'];
+ }
+
+ public function isDeleted() {
+ return ! is_null($this->record['deleted']);
+ }
+
+ public function getDeletionTime() {
+ return $this->record['deleted'];
+ }
+
+ public function getDeletionMod() {
+ return $this->record['deleted_by'];
+ }
+
+ public function isLocked() {
+ return ($this->record['locked'] == 't');
+ }
+
+ public function getLastRead() {
+ if (is_null($this->lastRead)) {
+ $q = $this->db->query("SELECT read_at FROM forums.topic_read WHERE topic = $1 AND read_by = $2",
+ $this->record['id'], $this->user);
+ if (!($q && dbCount($q) == 1)) {
+ return 0;
+ }
+
+ list($this->lastRead) = dbFetchArray($q);
+ }
+
+ return $this->lastRead;
+ }
+
+
+ // ----------------------------------------------------------------------
+ // MANAGEMENT FUNCTIONS
+ // ----------------------------------------------------------------------
+
+ public function restore() {
+ if (! $this->isDeleted() ) {
+ return;
+ }
+ self::$restoreQuery->execute( $this->record['first_post'] );
+ $q = self::$getQuery->execute( $this->record['id'] );
+ if (! ($q && dbCount($q))) {
+ return;
+ }
+ $this->record = dbFetchHash($q);
+ }
+
+ public function delete() {
+ if ($this->isDeleted() ) {
+ return;
+ }
+ self::$deleteQuery->execute( $this->record['first_post'], $this->user );
+ $q = self::$getQuery->execute( $this->record['id'] );
+ if (! ($q && dbCount($q))) {
+ return;
+ }
+ $this->record = dbFetchHash($q);
+ }
+
+ public function setStickyLevel( $level ) {
+ if ($this->isDeleted() ) {
+ return;
+ }
+ if ($level < 0 || $level > 10) {
+ return;
+ }
+ self::$stickyLevelQuery->execute( $this->record['id'], $level );
+ $this->record['sticky_level'] = $level;
+ }
+
+ public function setLock( $locked ) {
+ if ($this->isDeleted() ) {
+ return;
+ }
+ self::$setLockQuery->execute( $this->record['id'], dbBool($locked) );
+ $this->record['locked'] = $locked ? 't' : 'f';
+ }
+
+ public function moveTo( $forum ) {
+ if ($this->isDeleted() ) {
+ return;
+ }
+ self::$moveQuery->execute($this->record['id'], $forum->getId(), $this->user);
+ $q = self::$getQuery->execute( $this->record['id'] );
+ if (! ($q && dbCount($q))) {
+ return;
+ }
+ $this->record = dbFetchHash($q);
+ }
+
+
+ // ----------------------------------------------------------------------
+ // ACCESSING THE POSTS
+ // ----------------------------------------------------------------------
+
+ public function getPosts() {
+ return $this->record['posts'];
+ }
+
+ public function getFirstPost() {
+ if (is_null($this->mainLib)) {
+ $this->mainLib = $this->game->getLib('main/forums');
+ }
+ return $this->mainLib->call('getPost', $this->record['first_post'], $this->user);
+ }
+
+ private function loadPosts() {
+ if (is_null($this->allPosts)) {
+ $q = self::$postsQuery->execute($this->record['id']);
+ if (! ($q && dbCount($q))) {
+ return null;
+ }
+
+ $this->allPosts = array();
+ while ($r = dbFetchHash($q)) {
+ $this->allPosts[$r['id']] = $this->mainLib->call('getPost', $r, $this->user);
+ }
+ }
+ }
+
+ public function getPostList($isThreaded, $oldFirst) {
+ $this->loadPosts();
+
+ if ($isThreaded) {
+ $result = $this->threadedSort($this->getFirstPost()->getReplies(), $oldFirst);
+ if (count($result)) {
+ array_shift($result);
+ }
+ array_unshift($result, $this->getFirstPost());
+ } else {
+ // If we are not in threaded mode, generate the list
+ // of reverse post <=> time associations and sort it
+ // in the appropriate direction
+ $timeList = array();
+ $result = array();
+
+ foreach ($this->allPosts as $id => $p) {
+ $time = (int) $p->getPostedAt();
+ if (! is_array($timeList[$time])) {
+ $timeList[$time] = array();
+ }
+ array_push($timeList[$time], $p);
+ }
+
+ $times = array_keys($timeList);
+ if ($oldFirst) {
+ sort($times);
+ } else {
+ rsort($times);
+ }
+
+ foreach ($times as $t) {
+ foreach ($timeList[$t] as $p) {
+ array_push($result, $p);
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ private function threadedSort($posts, $oldFirst) {
+ if (! count($posts)) {
+ return array();
+ }
+
+ $timeList = array();
+ $replyList = array();
+
+ foreach ($posts as $post) {
+ $postReplies = $this->threadedSort($post->getReplies(), $oldFirst);
+
+ if (count($postReplies)) {
+ $time = array_shift($postReplies);
+ $replyList[$post->getId()] = $postReplies;
+ } else {
+ $time = $post->getPostedAt();
+ $replyList[$post->getId()] = array();
+ }
+
+ $time = (int) $time;
+ if (! is_array($timeList[$time])) {
+ $timeList[$time] = array();
+ }
+ array_push($timeList[$time], $post);
+ }
+
+ $times = array_keys($timeList);
+ if ($oldFirst) {
+ sort($times);
+ } else {
+ rsort($times);
+ }
+
+ $result = array($times[0]);
+ foreach ($times as $t) {
+ foreach ($timeList[$t] as $p) {
+ array_push($result, $p);
+ foreach ($replyList[$p->getId()] as $r) {
+ array_push($result, $r);
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ public function getPostById($id) {
+ $this->loadPosts();
+ return array_key_exists($id, $this->allPosts) ? $this->allPosts[$id] : null;
+ }
+}
+
+
+?>
diff -Naur beta5//scripts/game/main/forums/library/substitute.inc forums//scripts/game/main/forums/library/substitute.inc
--- beta5//scripts/game/main/forums/library/substitute.inc 2011-02-05 10:09:57.844335002 +0100
+++ forums//scripts/game/main/forums/library/substitute.inc 2011-02-05 10:10:03.424335002 +0100
@@ -1,59 +1,73 @@
<?php
class main_forums_substitute {
- var $code = null;
- var $smiley = null;
+ private static $code = array(
+ array(
+ "re" => '\[b\](.*?)\[\/b\]',
+ "rt" => '<b>$1</b>'
+ ), array(
+ "re" => '\[u\](.*?)\[\/u\]',
+ "rt" => '<u>$1</u>'
+ ), array(
+ "re" => '\[i\](.*?)\[\/i\]',
+ "rt" => '<i>$1</i>'
+ ), array(
+ "re" => '\[sep(arator)?\]',
+ "rt" => '<hr/>'
+ ), array(
+ "re" => '\[item\](.*?)\[\/item\]',
+ "rt" => '<ul style="margin: 0px"><li>$1</li></ul>'
+ ), array(
+ "re" => '\[quote\](.*?)\[\/quote\]',
+ "rt" => '<blockquote style="margin: 10px 5px; padding: 5px; border: 1px solid #5F5F5F; background-color: #2F2F2F">$1</blockquote>',
+ "rep" => true
+ ), array(
+ "re" => '\[quote=([^\]]+)\](.*?)\[\/quote\]',
+ "rt" => '<blockquote style="margin: 10px 5px; padding: 5px; border: 1px solid #5F5F5F; background-color: #2F2F2F"><b>$1</b> said:<br/>$2</blockquote>',
+ "rep" => true
+ ), array(
+ "re" => '\[link=(http[^\]]+)\](.+?)\[\/link\]',
+ "rt" => '<a href="$1" target="_blank">$2</a>'
+ ), array(
+ "re" => '\[code\](.*?)\[\/code\]',
+ "rt" => '<pre>$1</pre>'
+ )
+ );
function main_forums_substitute($lib) {
$this->lib = $lib;
$this->db = $this->lib->game->db;
}
- function run($text, $ec, $es) {
+ function run($text, $ec) {
$src = array('/\\n/','/\\r/'); $dst = array("<br/>",'');
+ $rsSrc = array(); $rsDst = array();
$text = utf8entities($text, ENT_NOQUOTES);
- $ec = ($ec == 't');
- $es = ($es == 't');
if ($ec) {
- if (is_array($this->code)) {
- foreach ($this->code as $s => $d) {
- array_push($src, '/'.$s.'/i');
- array_push($dst, $d);
- }
- } else {
- $this->codes = array();
- $q = $this->db->query("SELECT * FROM f_code");
- while ($r = dbFetchArray($q)) {
- $this->code[$r[0]] = $r[1];
- array_push($src, '/'.$r[0].'/i');
- array_push($dst, $r[1]);
+ foreach (self::$code as $c) {
+ if ($c['rep']) {
+ array_push($rsSrc, "/{$c['re']}/i");
+ array_push($rsDst, $c['rt']);
+ } else {
+ array_push($src, "/{$c['re']}/i");
+ array_push($dst, $c['rt']);
}
}
}
- if ($es) {
- if (is_array($this->smiley)) {
- foreach ($this->smiley as $s => $d) {
- array_push($src, '/'.$s.'/i');
- array_push($dst, $d);
- }
- } else {
- $this->smiley = array();
- $q = $this->db->query("SELECT * FROM f_smiley");
- while ($r = dbFetchArray($q)) {
- $fn = getStatic("main/pics/smiles/icon_".$r[1].".gif");
- if (is_null($fn)) {
- continue;
- }
- $code = "<img src='$fn' alt='[S]' />";
- $this->smiley[$r[0]] = $code;
- array_push($src, '/'.$r[0].'/i');
- array_push($dst, $code);
+
+ if (count($rsSrc)) {
+ $i = 0;
+ foreach ($rsSrc as $re) {
+ while (preg_match($re, $text)) {
+ $text = preg_replace($re, $rsDst[$i], $text);
}
+ $i ++;
}
}
- return preg_replace($src, $dst, $text);
+ $rv = preg_replace($src, $dst, $text);
+ return $rv;
}
}
diff -Naur beta5//scripts/game/main/forums/library.inc forums//scripts/game/main/forums/library.inc
--- beta5//scripts/game/main/forums/library.inc 2011-02-05 10:09:57.844335002 +0100
+++ forums//scripts/game/main/forums/library.inc 2011-02-05 10:10:03.434335002 +0100
@@ -1,71 +1,152 @@
<?php
class main_forums_library {
- var $index = array(
- 'deletePost',
- 'deleteTopic',
- 'edit',
- 'get',
- 'getAdministrator',
- 'getCategories',
- 'getCategory',
- 'getForums',
- 'getModerator',
- 'getPost',
- 'getPosts',
- 'getTopic',
- 'getTopics',
- 'move',
- 'newTopic',
- 'reply',
- 'signature',
- 'substitute',
- 'updateLast',
+ private $libraries = array();
+ private $categories = array();
+ private $forums = array();
+ private $topics = array();
+ private $polls = array();
+ private $posts = array();
+
+ private $getForumLib;
+ private $getCategoryLib;
+
+ public $index = array(
+ 'substitute'
);
- function main_forums_library($lib) {
+ public function __construct($lib) {
$this->lib = $lib;
- $this->db = $this->lib->game->db;
- }
+ $this->game = $this->lib->game;
+ $this->db = $this->game->getDBAccess();
- function getVersionCategory($ver) {
- $q = $this->db->query("SELECT id,description FROM f_category WHERE title='!$ver!'");
- return dbFetchHash($q);
- }
+ $this->getForumLib = $this->db->prepare(
+ "SELECT l.lib_path FROM forums.t_forum f, forums.category c, forums.category_type l "
+ . "WHERE f.id = $1 AND c.id = f.category AND l.id = c.acl_lib",
+ array("id") );
+ $this->getCategoryLib = $this->db->prepare(
+ "SELECT l.lib_path FROM forums.category c, forums.category_type l "
+ . "WHERE l.id = c.acl_lib AND c.id = $1",
+ array("id") );
+ }
+
+ public function getCategory($id, $user) {
+ $idx = "$id;$user";
+
+ if (! isset($this->categories[$idx])) {
+ $q = $this->getCategoryLib->execute(array("id" => $id));
+ if (! ($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($lib) = dbFetchArray($q);
+
+ if (! isset($this->libraries[$lib]) ) {
+ $this->libraries[$lib] = $this->game->getLib($lib);
+ }
+ $cat = $this->libraries[$lib]->call('getCategory', $id, $user);
+
+ if (is_null($cat)) {
+ return null;
+ }
+ $this->categories[$idx] = $cat;
+ }
- function isRead($topic, $player) {
- $q = $this->db->query("SELECT * FROM f_read WHERE topic=$topic AND reader=$player");
- return $q && dbCount($q);
+ return $this->categories[$idx];
}
- function markRead($topic, $player) {
- if ($this->isRead($topic,$player)) {
- return false;
+ public function getForum($id, $user) {
+ $idx = "$id;$user";
+
+ if (! isset($this->forums[$idx])) {
+ $q = $this->getForumLib->execute(array("id" => $id));
+ if (! ($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($lib) = dbFetchArray($q);
+
+ if (! isset($this->libraries[$lib]) ) {
+ $this->libraries[$lib] = $this->game->getLib($lib);
+ }
+ $f = $this->libraries[$lib]->call('getForum', $id, $user);
+
+ if (is_null($f)) {
+ return null;
+ }
+ $this->forums[$idx] = $f;
}
- $this->db->query("DELETE FROM f_read WHERE topic=$topic AND reader=$player");
- $this->db->query("INSERT INTO f_read(topic,reader)VALUES($topic,$player)");
- return true;
+
+ return $this->forums[$idx];
}
- function markUnread($topic, $player) {
- $this->db->query("DELETE FROM f_read WHERE topic=$topic AND reader<>$player");
+ public function getTopic($data, $user) {
+ if (is_array($data)) {
+ $id = $data['id'];
+ } else {
+ $id = $data;
+ }
+ $idx = "$id;$user";
+
+ if (! isset($this->topics[$idx])) {
+ loader::needClasses('main/forums', 'fl_topic');
+ try {
+ $topic = new fl_topic($this->game, $user, $data);
+ } catch (Exception $e) {
+ logText("main/forums::getTopic: failed to fetch topic #$id (user #$user)", LOG_WARNING);
+ return null;
+ }
+ $this->topics[$idx] = $topic;
+ }
+
+ return $this->topics[$idx];
}
- // Get the amount of unread topics in a forum
- function getRead($fid, $uid) {
- $q = $this->db->query("SELECT COUNT(*) FROM f_read r,f_topic t WHERE t.id=r.topic AND t.forum=$fid AND r.reader=$uid AND t.deleted IS NULL");
- list($nr) = dbFetchArray($q);
- return $nr;
+ public function getPoll($id, $user) {
+ $idx = "$id;$user";
+
+ if (! isset($this->polls[$idx])) {
+ loader::needClasses('main/forums', 'fl_poll');
+ try {
+ $poll = new fl_poll($this->game, $user, $id);
+ } catch (Exception $e) {
+ return null;
+ }
+ $this->polls[$idx] = $poll;
+ }
+
+ return $this->polls[$idx];
}
- function switchSticky($forum, $topic) {
- $this->db->query("UPDATE f_topic SET sticky=NOT sticky WHERE id=$topic AND forum=$forum AND deleted IS NULL");
+ public function getPost($data, $user) {
+ if (is_array($data)) {
+ $id = $data['id'];
+ } else {
+ $id = $data;
+ }
+ $idx = "$id;$user";
+
+ if (! isset($this->posts[$idx])) {
+ loader::needClasses('main/forums', 'fl_post');
+ try {
+ $post = new fl_post($this->game, $user, $data);
+ } catch (Exception $e) {
+ logText("main/forums::getPost: failed to fetch post #$id (user #$user)", LOG_WARN);
+ return null;
+ }
+ $this->posts[$idx] = $post;
+ }
+
+ return $this->posts[$idx];
}
- function markForumRead($fid, $uid) {
- $q = $this->db->query("SELECT id FROM f_topic WHERE forum=$fid AND deleted IS NULL");
- while ($r = dbFetchArray($q)) {
- $this->markRead($r[0], $uid);
+ public function setOptions($pid, $forum, $perPage, $viewDeleted) {
+ if ($forum == -1) {
+ prefs::remove('main/F#PP#%');
+ prefs::remove('main/F#VD#%');
+ prefs::set('main/F#PP', $perPage);
+ prefs::set('main/F#VD', $viewDeleted ? 1 : 0);
+ } else {
+ prefs::set("main/F#PP#$forum", $perPage);
+ prefs::set("main/F#VD#$forum", $viewDeleted ? 1 : 0);
}
}
}
diff -Naur beta5//scripts/game/main/gforums/library.inc forums//scripts/game/main/gforums/library.inc
--- beta5//scripts/game/main/gforums/library.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/main/gforums/library.inc 2011-02-05 10:10:03.384335002 +0100
@@ -0,0 +1,165 @@
+<?php
+
+/* General forums management library */
+
+class main_gforums_library {
+
+ var $index = array( );
+
+ function __construct($lib) {
+ $this->lib = $lib;
+ $this->game = $this->lib->game;
+ $this->version = $this->game->version;
+ $this->db = $this->game->db;
+
+ $this->fLib = $this->game->getLib('main/forums');
+ loader::needClasses('main/forums', array('fl_category', 'fl_forum'));
+
+ $this->getCatQuery = $this->db->prepare(
+ "SELECT t_string,t_is_game FROM main.gf_category WHERE category = $1", array("id") );
+ $this->getCatForumsQuery = $this->db->prepare(
+ "SELECT id FROM forums.t_forum WHERE category = $1 ORDER BY f_order", array("category") );
+ $this->getForumPrivQuery = $this->db->prepare(
+ "SELECT * FROM main.get_gforums_privs( $1, $2 )", array("user", "forum") );
+ $this->getUserNameQ = $this->db->prepare( "SELECT name FROM account WHERE id = $1", array("user") );
+ }
+
+ function getStructure( $user ) {
+ $cats = array();
+
+ $q = $this->db->query("SELECT * FROM main.get_gf_categories($1, $2)",
+ $this->version->id, $this->game->name);
+ while ($r = dbFetchArray($q)) {
+ $cat = $this->fLib->call('getCategory', $r[0], $user);
+ if (! is_null($cat)) {
+ array_push($cats, $cat);
+ }
+ }
+
+ return $cats;
+ }
+
+ function getCategory( $catId , $user ) {
+ $q = $this->getCatQuery->execute($catId);
+ if (! ($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($str, $ig) = dbFetchArray($q);
+
+ if (is_null($str)) {
+ $title = 'Legacy Worlds forums';
+ $description = 'These forums are common to all versions of Legacy Worlds after Beta 5.';
+ } else if ($ig == 'f') {
+ $txt = config::$config->versions[$str]->text;
+ $title = "Legacy Worlds {$txt}";
+ $description = "These forums are common to all games using the Legacy Worlds "
+ . "{$txt} base code.";
+ } else {
+ $txt = config::$config->games[$str]->text;
+ $title = $txt;
+ $description = "These are the forums for the {$txt} game.";
+ }
+
+ $cat = new fl_category( $this->game, $user, $catId, $title, $description );
+
+ $q = $this->getCatForumsQuery->execute($catId);
+ while ($r = dbFetchArray($q)) {
+ $forum = $this->fLib->call('getForum', $r[0], $user);
+ if ($forum->canView() && ($forum->isAdmin() || ! $forum->isDeleted())) {
+ $cat->addForum( $forum );
+ }
+ }
+
+ return $cat;
+ }
+
+
+ function getForum( $forumId, $user ) {
+ $q = $this->getForumPrivQuery->execute($user, $forumId);
+ if (! ($q && dbCount($q) == 1)) {
+ return null;
+ }
+ $privs = dbFetchHash($q);
+
+ try {
+ $forum = new fl_forum( $this->game, $forumId, $user );
+ } catch (Exception $e) {
+ return null;
+ }
+
+ $forum->setAdmin( $privs['is_admin'] == 't' );
+ $forum->setMod( $privs['is_mod'] == 't' );
+ $forum->setCreateTopic( $privs['can_create'] == 't' );
+ $forum->setCreatePoll( $privs['can_poll'] == 't' );
+ $forum->setPost( $privs['can_post'] == 't' );
+ $forum->setView( $privs['can_view'] == 't' );
+
+ return $forum;
+ }
+
+
+ public function getAdmins($forum) {
+ $q = $this->db->query("SELECT category FROM forums.t_forum WHERE id = $1", $forum);
+ if (! ($q && dbCount($q) == 1)) {
+ return array();
+ }
+ list($cat) = dbFetchArray($q);
+
+ $admins = array();
+
+ $q = $this->db->query("SELECT account FROM gf_admin WHERE category = $1 OR category IS NULL", $cat);
+ if (!$q) {
+ return $admins;
+ }
+ while ($r = dbFetchArray($q)) {
+ array_push($admins, $r[0]);
+ }
+ return $admins;
+ }
+
+
+ public function getModerators($forum) {
+ $q = $this->db->query("SELECT category FROM forums.t_forum WHERE id = $1", $forum);
+ if (! ($q && dbCount($q) == 1)) {
+ return array();
+ }
+ list($cat) = dbFetchArray($q);
+
+ $mods = array();
+
+ $q = $this->db->query("SELECT account FROM gf_cat_moderator "
+ . "WHERE category = $1 OR category IS NULL", $cat);
+ if (!$q) {
+ return $mods;
+ }
+ while ($r = dbFetchArray($q)) {
+ array_push($mods, $r[0]);
+ }
+
+ $q = $this->db->query("SELECT account FROM gf_forum_moderator WHERE forum = $1", $forum);
+ if (!$q) {
+ while ($r = dbFetchArray($q)) {
+ array_push($mods, $r[0]);
+ }
+ }
+
+ return $mods;
+ }
+
+
+ public function getUsers($forum) {
+ return array();
+ }
+
+
+ public function aclIdToName($id) {
+ $q = $this->getUserNameQ->execute($id);
+ if (!($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($rv) = dbFetchArray($q);
+ return $rv;
+ }
+}
+
+?>
diff -Naur beta5//scripts/game/main/uforums/library.inc forums//scripts/game/main/uforums/library.inc
--- beta5//scripts/game/main/uforums/library.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/game/main/uforums/library.inc 2011-02-05 10:10:03.374335002 +0100
@@ -0,0 +1,193 @@
+<?php
+
+/** User forums management library
+ *
+ * This library handles permissions for user forums.
+ */
+
+class main_uforums_library {
+
+ var $index = array( );
+
+ function __construct($lib) {
+ $this->lib = $lib;
+ $this->game = $this->lib->game;
+ $this->db = $this->game->getDBAccess();
+
+ $this->account = $this->game->getLib('main/account');
+ $this->fLib = $this->game->getLib('main/forums');
+ loader::needClasses('main/forums', array('fl_category', 'fl_forum'));
+
+ $this->getOwnCatQ = $this->db->prepare(
+ "SELECT main.uf_get_category($1)", array("user") );
+ $this->getOtherCatsQ = $this->db->prepare(
+ "SELECT DISTINCT category FROM forums.t_forum WHERE id IN ("
+ . "SELECT forum FROM main.uf_subscription WHERE account = $1)",
+ array("user") );
+ $this->getCatOwnerQ = $this->db->prepare(
+ "SELECT account FROM main.user_category WHERE category = $1", array("category") );
+ $this->getOwnForumsQ = $this->db->prepare(
+ "SELECT id FROM forums.t_forum WHERE category = $1 ORDER BY f_order", array("category") );
+ $this->getOtherForumsQ = $this->db->prepare(
+ "SELECT id FROM forums.t_forum"
+ . " WHERE category = $1 "
+ . " AND id IN (SELECT forum FROM main.uf_subscription WHERE account = $2)"
+ . " ORDER BY f_order",
+ array("category", "user") );
+ $this->getForumPrivQ = $this->db->prepare(
+ "SELECT main.uf_get_user_access( $2, $1 )", array("forum", "user") );
+ $this->getUserNameQ = $this->db->prepare( "SELECT name FROM account WHERE id = $1", array("user") );
+ }
+
+ function getStructure( $user ) {
+ $cats = array();
+
+ $q = $this->getOwnCatQ->execute($user);
+ if ( $q && dbCount($q) == 1) {
+ list($id) = dbFetchArray($q);
+ $cat = $this->fLib->call('getCategory', $id, $user);
+ if (! is_null($cat)) {
+ array_push($cats, $cat);
+ }
+ }
+
+ $q = $this->getOtherCatsQ->execute($user);
+ while ($r = dbFetchArray($q)) {
+ $cat = $this->fLib->call('getCategory', $r[0], $user);
+ if (! is_null($cat)) {
+ array_push($cats, $cat);
+ }
+ }
+
+ return $cats;
+ }
+
+ function getCategory( $id, $user ) {
+ $q = $this->getCatOwnerQ->execute($id);
+ if (! ($q && dbCount($q) == 1) ) {
+ return null;
+ }
+ list($account) = dbFetchArray($q);
+
+ if ($account == $user) {
+ $title = "My forums";
+ $description = "These are your own forums; do with them as you please.";
+ } else {
+ $uname = $this->account->call('getUserName', $account);
+ $title = "$uname's forums";
+ $description = "These are the personnal forums of player $uname.";
+ }
+
+ $cat = new fl_category( $this->game, $user, $id, $title, $description );
+
+ if ($account == $user) {
+ $q = $this->getOwnForumsQ->execute($id);
+ if (! $q ) {
+ return null;
+ }
+ } else {
+ $q = $this->getOtherForumsQ->execute($id, $user);
+ if (! ($q && dbCount($q) ) ) {
+ return null;
+ }
+ }
+ while ($r = dbFetchArray($q)) {
+ $forum = $this->fLib->call('getForum', $r[0], $user);
+ if ($forum->canView() && ($forum->isAdmin() || ! $forum->isDeleted())) {
+ $cat->addForum( $forum );
+ }
+ }
+
+ return $cat;
+ }
+
+ function getForum( $forumId, $user) {
+ $q = $this->getForumPrivQ->execute($forumId, $user);
+ if (! ($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($accessMode) = dbFetchArray($q);
+ if (is_null($accessMode)) {
+ return null;
+ }
+
+ try {
+ $forum = new fl_forum( $this->game, $forumId, $user );
+ } catch (Exception $e) {
+ return null;
+ }
+
+ $forum->setAdmin( $accessMode == 'A' );
+ $forum->setMod( in_array($accessMode, array('M', 'A')) );
+ $forum->setCreatePoll( in_array($accessMode, array('L', 'M', 'A')) );
+ $forum->setCreateTopic( in_array($accessMode, array('T', 'L', 'M', 'A')) );
+ $forum->setPost( $accessMode != 'R' );
+ $forum->setView( true );
+
+ return $forum;
+ }
+
+
+ public function getAdmins($forum) {
+ $q = $this->db->query("SELECT uc.account FROM user_category uc, forums.t_forum f "
+ . "WHERE f.id = $1 AND uc.category = f.category", $forum);
+ if (!($q && dbCount($q) == 1)) {
+ return array();
+ }
+ list($admin) = dbFetchArray($q);
+
+ return array($admin);
+ }
+
+
+ public function getModerators($forum) {
+ $q = $this->db->query("SELECT account FROM uf_subscription WHERE access_mode = 'M' AND forum = $1",
+ $forum);
+ if (!$q) {
+ return array();
+ }
+ $mods = array();
+ while ($r = dbFetchArray($q)) {
+ array_push($mods, $r[0]);
+ }
+
+ return $mods;
+ }
+
+
+ public function getUsers($forum) {
+ $q = $this->db->query("SELECT uf_get_access_mode($1)", $forum);
+ if (!($q && dbCount($q))) {
+ return array();
+ }
+ list($mode) = dbFetchArray($q);
+ if ($mode == 'P') {
+ return array();
+ }
+
+ $q = $this->db->query("SELECT account FROM uf_subscription WHERE access_mode <> 'M' AND forum = $1",
+ $forum);
+ if (!$q) {
+ return array();
+ }
+ $users = array();
+ while ($r = dbFetchArray($q)) {
+ array_push($users, $r[0]);
+ }
+
+ return $users;
+ }
+
+
+ public function aclIdToName($id) {
+ $q = $this->getUserNameQ->execute($id);
+ if (!($q && dbCount($q) == 1)) {
+ return null;
+ }
+ list($rv) = dbFetchArray($q);
+ return $rv;
+ }
+}
+
+
+?>
diff -Naur beta5//scripts/lib/classloader.inc forums//scripts/lib/classloader.inc
--- beta5//scripts/lib/classloader.inc 2011-02-05 10:09:57.434335002 +0100
+++ forums//scripts/lib/classloader.inc 2011-03-12 14:56:22.471300053 +0100
@@ -20,6 +20,17 @@
array_push(loader::$loadedClasses, $className);
}
+
+ static function needClasses($basePath, $classes) {
+ $path = config::$main['scriptdir'] . "/game/$basePath/";
+ if (!is_array($classes)) {
+ $classes = array($classes);
+ }
+
+ foreach ($classes as $cn) {
+ self::load($path . $cn . ".inc", $cn);
+ }
+ }
}
?>
diff -Naur beta5//scripts/lib/config.inc forums//scripts/lib/config.inc
--- beta5//scripts/lib/config.inc 2011-02-05 10:09:57.434335002 +0100
+++ forums//scripts/lib/config.inc 2011-03-12 14:56:24.031300053 +0100
@@ -123,6 +123,10 @@
static function getParam($name) {
return config::$config->games['main']->params[$name];
}
+
+ static function getMainInterface() {
+ return config::$config->games['main'];
+ }
}
config::load();
diff -Naur beta5//scripts/lib/db_accessor.inc forums//scripts/lib/db_accessor.inc
--- beta5//scripts/lib/db_accessor.inc 2011-02-05 10:09:57.434335002 +0100
+++ forums//scripts/lib/db_accessor.inc 2011-03-12 15:30:19.021300053 +0100
@@ -32,9 +32,15 @@
$this->db->disableExceptions();
}
- public function query($q) {
+ public function query() {
$this->setNamespace();
- return $this->db->query($q);
+ $args = func_get_args();
+ return call_user_func_array(array($this->db, "query"), $args);
+ }
+
+ public function prepare($q, $params) {
+ $this->setNamespace();
+ return db_query::getQuery($this, $q, $params);
}
public function begin() {
@@ -45,6 +51,14 @@
return $this->db->end($rb);
}
+ public function getNamespace() {
+ return $this->namespace;
+ }
+
+ public function getDatabase() {
+ return $this->db;
+ }
+
public function needsReset() {
return $this->db->needsReset();
}
diff -Naur beta5//scripts/lib/db_connection.inc forums//scripts/lib/db_connection.inc
--- beta5//scripts/lib/db_connection.inc 2011-02-05 10:09:57.434335002 +0100
+++ forums//scripts/lib/db_connection.inc 2011-03-12 15:39:08.891300050 +0100
@@ -229,17 +229,22 @@
return true;
}
- public function query($query) {
- if (!$this->inTrans) {
- $this->fail("query executed outside of transaction", $query);
- return null;
+ public function query() {
+ if (func_num_args() == 1) {
+ $query = func_get_arg(0);
+ if (!$this->checkQuery($query)) {
+ return null;
+ }
+ $r = @pg_query($this->conn, $query);
+ } else {
+ $args = func_get_args();
+ $query = array_shift($args);
+ if (!$this->checkQuery($query)) {
+ return null;
+ }
+ $r = call_user_func("pg_query_params", $query, $args);
}
- $this->queries ++;
- if ($this->trace) {
- l::trace("EXECUTE: $query");
- }
- $r = @pg_query($this->conn, $query);
if (!$r) {
$cStat = pg_connection_status($this->conn);
$error = pg_last_error($this->conn);
@@ -264,48 +269,23 @@
}
} elseif (preg_match('/^\s*insert\s+into ("?\w+"?)/i', $query, $match)) {
pg_free_result($r);
-
- $tn = $match[1];
- if ($tn{0} == '"') {
- $tn = str_replace('"', '', $tn);
- } else {
- $tn = strtolower($tn);
- }
-
- $r2 = @pg_query("SELECT last_inserted('$tn')");
- if ($r2) {
- $rv = pg_fetch_row($r2);
- if (is_null($rv[0])) {
- $r = true;
- } else {
- $r = $rv[0];
- }
- pg_free_result($r2);
- } elseif (preg_match('/deadlock/i', $error)) {
- l::error("SQL: deadlock detected");
- if ($this->useExceptions) {
- throw new db_deadlock_exception($error);
- }
- $this->error = true;
- return;
- } else {
- $cStat = pg_connection_status($this->conn);
- $error = pg_last_error($this->conn);
- if ($cStat == PGSQL_CONNECTION_BAD) {
- l::notice("SQL: connection is gone while fetching last ID");
- $this->__needsReset = true;
- if ($this->useExceptions) {
- throw new db_srv_exception($error);
- }
- } else {
- $this->fail("failed to fetch last ID: $error", "SELECT last_inserted('$tn')");
- }
- $r = null;
- }
+ $r = $this->getLastInserted($match[1]);
}
return $r;
}
+ private function checkQuery($query) {
+ if (!$this->inTrans) {
+ $this->fail("SQL: query executed outside of transaction", $query);
+ return false;
+ }
+ if ($this->trace) {
+ l::trace("EXECUTE: $query");
+ }
+ $this->queries ++;
+ return true;
+ }
+
public function getGameAccess($prefix) {
if (is_null($this->accessors[$prefix])) {
$this->accessors[$prefix] = new db_accessor($this, $prefix);
@@ -313,6 +293,50 @@
return $this->accessors[$prefix];
}
+ public function getConnection() {
+ return $this->conn;
+ }
+
+ private function getLastInserted($tn) {
+ if ($tn{0} == '"') {
+ $tn = str_replace('"', '', $tn);
+ } else {
+ $tn = strtolower($tn);
+ }
+
+ $r2 = @pg_query("SELECT last_inserted('$tn')");
+ if ($r2) {
+ $rv = pg_fetch_row($r2);
+ if (is_null($rv[0])) {
+ $r = true;
+ } else {
+ $r = $rv[0];
+ }
+ pg_free_result($r2);
+ } elseif (preg_match('/deadlock/i', $error)) {
+ l::error("SQL: deadlock detected");
+ if ($this->useExceptions) {
+ throw new db_deadlock_exception($error);
+ }
+ $this->error = true;
+ $r = null;
+ } else {
+ $cStat = pg_connection_status($this->conn);
+ $error = pg_last_error($this->conn);
+ if ($cStat == PGSQL_CONNECTION_BAD) {
+ l::notice("SQL: connection is gone while fetching last ID");
+ $this->__needsReset = true;
+ if ($this->useExceptions) {
+ throw new db_srv_exception($error);
+ }
+ } else {
+ $this->fail("failed to fetch last ID: $error", "SELECT last_inserted('$tn')");
+ }
+ $r = null;
+ }
+ return $r;
+ }
+
public function needsReset() {
return $this->__needsReset;
}
diff -Naur beta5//scripts/lib/db_query.inc forums//scripts/lib/db_query.inc
--- beta5//scripts/lib/db_query.inc 1970-01-01 01:00:00.000000000 +0100
+++ forums//scripts/lib/db_query.inc 2011-02-05 10:10:03.074335002 +0100
@@ -0,0 +1,132 @@
+<?php
+
+class db_query {
+
+ private static $queries = array();
+
+ private $counter = 1;
+ private $table = null;
+ private $name;
+ private $accessor;
+ private $database;
+ private $connection;
+ private $query;
+ private $parameters;
+ private $resource;
+
+ private function __construct($name, $accessor, $query, $pNames) {
+ $this->accessor = $accessor;
+ $this->query = $query;
+ $this->parameters = $pNames;
+ $this->name = $name;
+
+ $this->database = $this->accessor->getDatabase();
+ $this->connection = $this->database->getConnection();
+
+ $this->accessor->useNamespace();
+ $r = @pg_prepare($this->connection, $this->name, $query);
+
+ if (! $r) {
+ $this->accessor->getDatabase()->fail(
+ "SQL: Could not prepare query: " . pg_last_error($this->connection),
+ $this->query );
+ throw new Exception('failed');
+ }
+
+ if (preg_match('/^\s*insert\s+into ("?\w+"?)/i', $this->query, $match)) {
+ $this->table = $match[1];
+ }
+ }
+
+
+ public function execute() {
+ if ($this->counter == 0) {
+ $this->database->fail(
+ "SQL: tried to execute de-allocated query",
+ $this->query );
+ return null;
+ }
+ if (!$this->database->checkQuery($this->query)) {
+ return null;
+ }
+
+ $args = func_get_args();
+ if (count($args) == 1 && is_array($args[0])) {
+ $params = $args[0];
+ $p = array();
+ for ($i = 0; $i < count($this->parameters); $i ++) {
+ if (!array_key_exists($this->parameters[$i], $params)) {
+ $this->database->fail(
+ "SQL: missing parameter '{$this->parameters[$i]}' for prepared query",
+ $this->query );
+ return null;
+ }
+ $p[$i] = $params[$this->parameters[$i]];
+ }
+ } elseif (count($args) == count($this->parameters)) {
+ $p = $args;
+ } else {
+ $this->database->fail( "SQL: invalid parameters for prepared query", $this->query );
+ return null;
+ }
+
+ $this->accessor->useNamespace();
+ $r = @pg_execute($this->connection, $this->name, $p);
+
+ if (! $r) {
+ $this->database->fail(
+ "SQL: could not execute prepared query: " . pg_last_error($this->connection),
+ $this->query );
+ return null;
+ }
+
+ if (!is_null($this->table)) {
+ pg_free_result($r);
+ $r = $this->database->getLastInserted($this->table);
+ }
+
+ return $r;
+ }
+
+ public function destroy($force = false) {
+ if ($this->counter == 0) {
+ return;
+ }
+
+ if ($force) {
+ $this->counter = 0;
+ } else {
+ $this->counter --;
+ }
+
+ if ($this->counter == 0) {
+ $this->accessor->useNamespace();
+ $r = $this->database->query("DEALLOCATE {$this->name}");
+ self::$queries[$this->name] = null;
+ }
+ }
+
+
+ public static function getQuery($accessor, $query, $pNames) {
+ $data = array(
+ "n" => $accessor->getNamespace(),
+ "q" => $query,
+ "p" => $pNames
+ );
+ $name = "q_" . strtolower(md5(serialize($data)));
+
+ if (is_null(self::$queries[$name])) {
+ try {
+ self::$queries[$name] = new db_query($name, $accessor, $query, $pNames);
+ } catch (Exception $e) {
+ return null;
+ }
+ } else {
+ self::$queries[$name]->counter ++;
+ }
+ return self::$queries[$name];
+ }
+
+}
+
+?>
diff -Naur beta5//scripts/lib/library.inc forums//scripts/lib/library.inc
--- beta5//scripts/lib/library.inc 2011-02-05 10:09:57.434335002 +0100
+++ forums//scripts/lib/library.inc 2011-03-12 14:56:22.481300053 +0100
@@ -66,10 +66,28 @@
$fcn = $this->loadClass($this->functions[$function][1]);
$this->functions[$function][2] = new $fcn($this);
}
- $rv = call_user_func_array(array($this->functions[$function][2], 'run'), $args);
+ try {
+ $rv = call_user_func_array(array($this->functions[$function][2], 'run'), $args);
+ } catch (Exception $e) {
+ fatalError(32, array(
+ "Function call '{$this->name}::$function' on game '{$this->game->name}' "
+ . "failed with exception:",
+ $e->getMessage()
+ ));
+ }
} else {
// Call the function instance's method
- $rv = call_user_func_array(array($this->mainClass, $this->functions[$function][1]), $args);
+ try {
+ $rv = call_user_func_array(
+ array($this->mainClass, $this->functions[$function][1]), $args
+ );
+ } catch (Exception $e) {
+ fatalError(32, array(
+ "Function call '{$this->name}::$function' on game '{$this->game->name}' "
+ . "failed with exception:",
+ $e->getMessage()
+ ));
+ }
}
return $rv;
diff -Naur beta5//scripts/lib/prefs.inc forums//scripts/lib/prefs.inc
--- beta5//scripts/lib/prefs.inc 2011-02-05 10:09:57.434335002 +0100
+++ forums//scripts/lib/prefs.inc 2011-02-05 10:10:03.074335002 +0100
@@ -107,6 +107,19 @@
return $v;
}
+ static function remove($path) {
+ list($version, $name) = explode('/', $path);
+ $qs = "DELETE FROM user_preferences WHERE account={$_SESSION['userid']} AND version = '$version' AND id";
+ if (strstr($name, '%') === FALSE) {
+ $q = dbQuery("$qs = '$name'");
+ } else {
+ $q = dbQuery("$qs LIKE '$name'");
+ }
+ prefs::$prefs = null;
+ prefs::load();
+
+ }
+
}
?>
diff -Naur beta5//scripts/site/beta5/handlers/alliance.inc forums//scripts/site/beta5/handlers/alliance.inc
--- beta5//scripts/site/beta5/handlers/alliance.inc 2011-02-05 10:09:57.204335002 +0100
+++ forums//scripts/site/beta5/handlers/alliance.inc 2011-03-12 15:16:23.151300053 +0100
@@ -18,8 +18,8 @@
// Pending requests
"getPending", "acceptRequests", "rejectRequests",
// Forums
- "getForums", "newForum", "changeForum", "delForum",
- "moveForum", "getForumAcl",
+ "getForums", "newForum", "changeForum",
+ "delForum", "restoreForum", "moveForum",
// Ranks
"getRanks", "newRank", "changeRank", "delRank"
),
@@ -802,190 +802,316 @@
// ALLIANCE FORUMS MANAGEMENT
//-------------------------------------------
- function doGetForums($aid) {
- $afl = gameAction('getAllianceForums', $aid);
- $s = "";
- foreach ($afl as $id => $afd)
- {
- if ($s != "")
- $s .= "\n";
- $s .= "$id#" . $afd['order'] . "#" . ($afd['user_post'] ? 1 : 0) . "#" . $afd['title'];
- if ($afd['description'] != '')
- {
- $dll = split("\n", $afd['description']);
- foreach ($dll as $dl)
- $s .= "\n+#$dl";
+ private function forumsGetLibraries() {
+ // Get the libraries
+ $this->player = input::$game->getLib('beta5/player');
+ $this->alliance = input::$game->getLib('beta5/alliance');
+ $this->forums = input::$game->getLib('main/forums');
+ $this->aForums = input::$game->getLib('beta5/aforums');
+ }
+
+ private function doGetForums($aid, $uid) {
+ $out = array();
+ $players = array();
+
+ // Get the category and output the amount of forums
+ $cat = array_shift($this->aForums->call('getStructure', $uid));
+ array_push($out, count($cat->getForums()));
+ $admin = null;
+
+ foreach ($cat->getForums() as $forum) {
+ // Get general information regarding the forum
+ $fid = $forum->getId();
+ $userPrivs = $this->aForums->call('getUserPrivileges', $fid);
+ $topics = $forum->getTopics();
+ $name = $forum->getTitle();
+
+ // Get information about the forum's deletion
+ $deleted = $forum->isDeleted() ? '1' : '0';
+ $deletedAt = $forum->deletedAt();
+ $deletedBy = $forum->deletedBy();
+ if (! (is_null($deletedBy) || in_array($deletedBy, $players))) {
+ array_push($players, $deletedBy);
+ }
+
+ // Output general information
+ array_push($out, "$fid#$deleted#$deletedBy#$deletedAt#$userPrivs#$topics#$name");
+
+ // Get the rank-specific access privileges for that forum
+ array_push($out, join('#', $forum->getUsers()));
+ array_push($out, join('#', $forum->getModerators()));
+ $admins = $forum->getAdministrators();
+
+ // Get the description
+ $description = $forum->getDescription();
+ if (is_null($description) || $description == '') {
+ array_push($out, "0");
+ } else {
+ $dList = explode("\n", $description);
+ array_push($out, count($dList));
+ foreach ($dList as $dLine) {
+ array_push($out, $dLine);
+ }
}
}
- return $s;
+
+ // Get the rank names
+ $ranks = $this->alliance->call('getRanks', $aid);
+ array_push($out, count($ranks));
+ foreach ($ranks as $rId => $rName) {
+ array_push($out, "$rId#" . utf8entities($rName));
+ }
+
+ // List the ranks having administrator privileges
+ if (is_null($admins)) {
+ $admins = array();
+ foreach ($ranks as $rId => $rName) {
+ $rkp = $this->alliance->call('getRankPrivileges', $rId);
+ if ($rkp['forum_admin']) {
+ array_push($admins, $rId);
+ }
+ }
+ }
+ array_push($out, join('#', $admins));
+
+ // Get the player names (for forums that have been deleted)
+ array_push($out, count($players));
+ foreach ($players as $pid) {
+ array_push($out, "$pid#" . utf8entities($this->player->call('getName', $pid, true)));
+ }
+
+ return join("\n", $out);
}
- function getForums() {
+ public function getForums() {
$pid = $_SESSION[game::sessName()]['player'];
- $p = gameAction('getPlayerInfo', $pid);
+ $this->forumsGetLibraries();
+
+ // Check if the player's in an alliance
+ $p = $this->player->call('get', $pid);
if (is_null($p['aid'])) {
return "ERR#0";
}
+
+ // Check if the player is a forums administrator
$aid = $p['aid'];
- $pr = gameAction('getAlliancePrivileges', $pid);
+ $pr = $this->alliance->call('getPrivileges', $pid);
if (!$pr['forum_admin']) {
return "ERR#4";
}
- $_SESSION[game::sessName()]['alliance_page'] = 'FAdmin';
- return $this->doGetForums($aid);
+ $_SESSION[game::sessName()]['alliance_page'] = 'FAdmin';
+ return $this->doGetForums($aid, $p['uid']);
}
- function newForum($name, $userPost, $after, $description, $acl) {
- if (gameAction('isOnVacation', $_SESSION[game::sessName()]['player'])) {
- return "ERR#200";
+ private function setForumPrivileges( $forum, $alliance, $acl ) {
+ $rl = $this->alliance->call('getRanks', $alliance);
+ $acla = explode('#', $acl);
+ $forum->clearACL();
+
+ foreach ($acla as $as) {
+ list($rank, $level) = explode('!', $as);
+ $level --;
+ if (is_null($rl[$rank]) || ($level != 0 && $level != 1)) {
+ continue;
+ }
+
+ if ($level) {
+ $forum->addModerator($rank);
+ } else {
+ $forum->addUser($rank);
+ }
}
+ }
+
+ public function newForum($name, $accessMode, $after, $description, $acl) {
+ $this->forumsGetLibraries();
$pid = $_SESSION[game::sessName()]['player'];
- $p = gameAction('getPlayerInfo', $pid);
- if (is_null($p['aid']))
- return "ERR#0";
- $aid = $p['aid'];
- $pr = gameAction('getAlliancePrivileges', $pid);
- if (!$pr['forum_admin'])
- return "ERR#4";
+ $p = $this->player->call('get', $pid);
- $afl = gameAction('getAllianceForums', $aid);
- if (count($afl) >= 30) {
- return "ERR#5";
+ if (is_null($p['aid'])) {
+ return "ERR#0\n0";
}
- $name = preg_replace('/\s+/', ' ', trim($name));
- if ($name == "" || strlen($name) < 4)
- return "ERR#1";
- foreach ($afl as $fid => $fd)
- if ($fd['title'] == $name)
- return "ERR#2";
-
- if ($after != "-1" && is_null($afl[$after]))
- return "ERR#6";
-
- $description = trim($description);
- gameAction('newAllianceForum', $aid, $name, ($userPost == 1), $after, $description);
-
- $afl = gameAction('getAllianceForums', $aid);
- $mId = false;
- foreach ($afl as $fid => $fd)
- if ($fd['title'] == $name)
- {
- $mId = $fid;
- break;
+ if ($this->player->call('isOnVacation', $pid)) {
+ $err = 200;
+ } else {
+ $name = preg_replace('/\s+/', ' ', trim($name));
+ $description = trim($description);
+ $cat = array_shift($this->aForums->call('getStructure', $p['uid']));
+ $after = (int) $after;
+
+ if ($name == "" || strlen($name) < 4) {
+ $err = 1;
+ } elseif ($after != -1 && is_null($cat->findForum($after))) {
+ $err = 6;
+ } else {
+ if ($after == -1) {
+ $order = 0;
+ } else {
+ $order = $cat->findForum($after)->getOrder() + 1;
+ }
+
+ $rv = $this->aForums->call('create',
+ $pid, $p['uid'], $p['aid'], $order,
+ $name, $description, $accessMode
+ );
+ if (is_object($rv)) {
+ $this->setForumPrivileges( $rv, $p['aid'], $acl );
+ $err = null;
+ } else {
+ logText("Alliance forum creation returned $rv");
+ switch ($rv) :
+ case 1: $err = 0; break;
+ case 2: $err = 4; break;
+ case 3: $err = 5; break;
+ case 4: $err = 2; break;
+ default: $err = 7; break;
+ endswitch;
+ }
}
- if (!$mId) {
- return "ERR#7";
}
- $rl = gameAction('getAllianceRanks', $aid);
- $fread = $fmod = array();
- $acla = explode('#', $acl);
- foreach ($acla as $as)
- {
- list($rank,$level) = explode('!', $as);
- $level --;
- if (is_null($rl[$rank]) || ($level != 0 && $level != 1))
- continue;
- if ($level)
- array_push($fmod, $rank);
- else
- array_push($fread, $rank);
+ $out = $this->doGetForums($p['aid'], $p['uid']);
+ if (!is_null($err)) {
+ $out = "ERR#$err\n$out";
}
- gameAction('setForumAccess', $mId, $fread, $fmod);
-
- return $this->doGetForums($aid);
+ return $out;
}
- function changeForum($id, $name, $userPost, $description, $acl) {
- if (gameAction('isOnVacation', $_SESSION[game::sessName()]['player'])) {
- return "ERR#200";
- }
-
+ public function changeForum($id, $name, $accessMode, $description, $acl) {
+ $this->forumsGetLibraries();
$pid = $_SESSION[game::sessName()]['player'];
- $p = gameAction('getPlayerInfo', $pid);
- if (is_null($p['aid']))
- return "ERR#0";
- $aid = $p['aid'];
- $pr = gameAction('getAlliancePrivileges', $pid);
- if (!$pr['forum_admin'])
- return "ERR#1";
-
- $afl = gameAction('getAllianceForums', $aid);
- if (is_null($afl[$id]))
- return "ERR#3";
+ $p = $this->player->call('get', $pid);
- $name = preg_replace('/\s+/', ' ', trim($name));
- if ($name == "" || strlen($name) < 4)
- return "ERR#1";
- foreach ($afl as $fid => $fd)
- if ($fid != $id && $fd['name'] == $name)
- return "ERR#2";
-
- $description = trim($description);
- gameAction('modifyAllianceForum', $id, $name, ($userPost == 1), $description);
+ if (is_null($p['aid'])) {
+ return "ERR#0\n0";
+ }
- $rl = gameAction('getAllianceRanks', $aid);
- $fread = $fmod = array();
- $acla = explode('#', $acl);
- foreach ($acla as $as)
- {
- list($rank,$level) = explode('!', $as);
- $level --;
- if (is_null($rl[$rank]) || ($level != 0 && $level != 1))
- continue;
- if ($level)
- array_push($fmod, $rank);
- else
- array_push($fread, $rank);
+ if ($this->player->call('isOnVacation', $pid)) {
+ $err = 200;
+ } else {
+ $id = (int) $id;
+ $name = preg_replace('/\s+/', ' ', trim($name));
+ $description = trim($description);
+
+ $rv = $this->aForums->call('modifyForum', $id, $pid, $name, $description, $accessMode);
+ if ($rv > 0) {
+ switch ($rv) :
+ case -1: $err = 7; break;
+ case -2: $err = 0; break;
+ case -3: $err = 4; break;
+ case -4: $err = 8; break;
+ case -5: $err = 7; break;
+ endswitch;
+ } else {
+ $err = null;
+ $this->setForumPrivileges( $this->forums->call('getForum', $id, $p['uid']),
+ $p['aid'], $acl );
+ }
}
- gameAction('setForumAccess', $id, $fread, $fmod);
- return $this->doGetForums($aid);
+ $out = $this->doGetForums($p['aid'], $p['uid']);
+ if (!is_null($err)) {
+ $out = "ERR#$err\n$out";
+ }
+ return $out;
}
function delForum($id) {
- if (gameAction('isOnVacation', $_SESSION[game::sessName()]['player'])) {
- return "ERR#200";
+ $this->forumsGetLibraries();
+ $pid = $_SESSION[game::sessName()]['player'];
+ $p = $this->player->call('get', $pid);
+
+ if (is_null($p['aid'])) {
+ $err = 0;
+ $out = "0";
+ } else {
+ if ($this->player->call('isOnVacation', $pid)) {
+ $err = 200;
+ } else {
+ $f = $this->forums->call('getForum', (int) $id, $p['uid']);
+ if (is_null($f) || $f->isDeleted()) {
+ $err = 8;
+ } elseif (! $f->isAdmin()) {
+ $err = 4;
+ } else {
+ $f->delete();
+ $err = null;
+ }
+ }
+ $out = $this->doGetForums($p['aid'], $p['uid']);
}
+ if (!is_null($err)) {
+ $out = "ERR#$err\n$out";
+ }
+ return $out;
+ }
+
+ function restoreForum($id) {
+ $this->forumsGetLibraries();
$pid = $_SESSION[game::sessName()]['player'];
- $p = gameAction('getPlayerInfo', $pid);
- if (is_null($p['aid']))
- return "ERR#0";
- $aid = $p['aid'];
- $pr = gameAction('getAlliancePrivileges', $pid);
- if (!$pr['forum_admin'])
- return "ERR#1";
+ $p = $this->player->call('get', $pid);
- $afl = gameAction('getAllianceForums', $aid);
- if (is_null($afl[$id])) {
- return "ERR#8";
+ if (is_null($p['aid'])) {
+ $err = 0;
+ $out = "0";
+ } else {
+ if ($this->player->call('isOnVacation', $pid)) {
+ $err = 200;
+ } else {
+ $f = $this->forums->call('getForum', (int) $id, $p['uid']);
+ if (is_null($f)) {
+ $err = 9;
+ } elseif (! $f->isAdmin()) {
+ $err = 4;
+ } elseif (! $f->isDeleted()) {
+ $err = 9;
+ } else {
+ $f->restore();
+ $err = null;
+ }
+ }
+ $out = $this->doGetForums($p['aid'], $p['uid']);
}
- gameAction('deleteAllianceForum', $id);
- return $this->doGetForums($aid);
- }
- function moveForum($id, $up) {
- if (gameAction('isOnVacation', $_SESSION[game::sessName()]['player'])) {
- return "ERR#200";
+ if (!is_null($err)) {
+ $out = "ERR#$err\n$out";
}
+ return $out;
+ }
+ function moveForum($id, $up) {
+ $this->forumsGetLibraries();
$pid = $_SESSION[game::sessName()]['player'];
- $p = gameAction('getPlayerInfo', $pid);
- if (is_null($p['aid']))
- return "ERR#0";
- $aid = $p['aid'];
- $pr = gameAction('getAlliancePrivileges', $pid);
- if (!$pr['forum_admin'])
- return "ERR#1";
+ $p = $this->player->call('get', $pid);
+
+ if (is_null($p['aid'])) {
+ $err = 0;
+ $out = "0";
+ } else {
+ if ($this->player->call('isOnVacation', $pid)) {
+ $err = 200;
+ } else {
+ $f = $this->forums->call('getForum', (int) $id, $p['uid']);
+ if (is_null($f) || $f->isDeleted()) {
+ $err = 8;
+ } elseif (! $f->isAdmin()) {
+ $err = 4;
+ } else {
+ $f->move($up == '1');
+ $err = null;
+ }
+ }
+ $out = $this->doGetForums($p['aid'], $p['uid']);
+ }
- $afl = gameAction('getAllianceForums', $aid);
- if (!is_null($afl[$id]))
- gameAction('moveAllianceForum', $id, ($up == "1"));
- return $this->doGetForums($aid);
+ if (!is_null($err)) {
+ $out = "ERR#$err\n$out";
+ }
+ return $out;
}
function getForumAcl($id) {
diff -Naur beta5//scripts/site/beta5/handlers/comms.inc forums//scripts/site/beta5/handlers/comms.inc
--- beta5//scripts/site/beta5/handlers/comms.inc 2011-02-05 10:09:57.204335002 +0100
+++ forums//scripts/site/beta5/handlers/comms.inc 2011-03-12 15:21:17.911300054 +0100
@@ -8,6 +8,50 @@
'init' => "makeCommsTooltips();\ninitPage();"
);
+ /** This method dumps containers, categories and forums to the output data.
+ * The dump's format is the following:
+ *
+ * type # id # nElements # topics # unread
+ * name
+ *
+ * With:
+ * "type" being either "C" for categories and containers or "F" for forums
+ * "id" being the object's identifier
+ * "nElements" is the number of sub-elements the object contains
+ * "topics" and "unread" are the amount of topics and unread topics
+ * "name" is the object's title
+ *
+ * \parameter $result a reference to the output data
+ * \parameter $container the object to be dumped
+ */
+ private function dumpForums( &$result, $container ) {
+ $res = array();
+
+ if ( $container instanceof fl_forum ) {
+ array_push($res, 'F');
+ $contents = array();
+ } else {
+ array_push($res, 'C');
+ if ( $container instanceof fl_category ) {
+ $contents = $container->getForums();
+ } else {
+ $contents = $container->getCategories();
+ }
+ }
+
+ array_push( $res, $container->getId() );
+ array_push( $res, count($contents) );
+ array_push( $res, $container->getTopics() );
+ array_push( $res, $container->getUnread() );
+
+ array_push( $result, join('#', $res) );
+ array_push( $result, utf8entities($container->getTitle()));
+
+ foreach ($contents as $c) {
+ $this->dumpForums( &$result, $c );
+ }
+ }
+
public function getCommsData() {
// Get the data
$data = $this->game->action('getCommsOverview', $_SESSION[game::sessName()]['player']);
@@ -16,33 +60,20 @@
$result = array();
array_push($result, count($data['folders']['CUS']) . "#" . count($data['forums']['general'])
. "#" . count($data['forums']['alliance']));
-
- // Messages in default folders
- $dFld = array('IN', 'INT', 'OUT');
- foreach ($dFld as $f) {
- array_push($result, join('#', $data['folders'][$f]));
- }
-
- // Custom folders
foreach ($data['folders']['CUS'] as $id => $folder) {
$folder[2] = utf8entities($folder[2]);
array_unshift($folder, $id);
array_push($result, join('#', $folder));
}
+
// Forums
- foreach ($data['forums']['general'] as $cat) {
- array_push($result, "{$cat['id']}#{$cat['type']}#" . count($cat['forums'])
- . "#" . utf8entities($cat['title']));
-
- foreach ($cat['forums'] as $f) {
- $f[3] = utf8entities($f[3]);
- array_push($result, join('#', $f));
- }
- }
- foreach ($data['forums']['alliance'] as $f) {
- $f[3] = utf8entities($f[3]);
- array_push($result, join('#', $f));
+ $forums = gameAction('getForums', $pid);
+ if (is_null($forums)) {
+ array_push($result, "C#/#0#0#0");
+ array_push($result, "");
+ } else {
+ $this->dumpForums( &$result, $forums );
}
return join("\n", $result);
diff -Naur beta5//scripts/site/beta5/handlers/diplomacy.inc forums//scripts/site/beta5/handlers/diplomacy.inc
--- beta5//scripts/site/beta5/handlers/diplomacy.inc 2011-02-05 10:09:57.204335002 +0100
+++ forums//scripts/site/beta5/handlers/diplomacy.inc 2011-02-05 10:10:02.884335002 +0100
@@ -1,7 +1,12 @@
<?php
-class page_handler
-{
+class page_handler {
+
+ private $rkLib;
+ private $player;
+ private $alliance;
+ private $aForums;
+
var $needsAuth = true;
var $ajax = array(
'func' => array('getInformation'),
@@ -9,9 +14,6 @@
);
function getAllianceRanking($tag) {
- if (! $this->rkLib) {
- $this->rkLib = input::$game->getLib('main/rankings');
- }
$rt = $this->rkLib->call('getType', "a_general");
$r = $this->rkLib->call('get', $rt, $tag);
if (!$r) {
@@ -20,27 +22,33 @@
return $r;
}
- function getInformation()
- {
+ function getInformation() {
$out = array();
$pid = $_SESSION[game::sessName()]['player'];
- $pinf = gameAction('getPlayerInfo', $pid);
- if (!is_null($pinf['arid']))
- {
- $ainf = gameAction('getAllianceInfo', $pinf['arid']);
+
+ // Get the libraries
+ $this->rkLib = input::$game->getLib('main/rankings');
+ $this->player = input::$game->getLib('beta5/player');
+ $this->alliance = input::$game->getLib('beta5/alliance');
+
+ $pinf = $this->player->call('get', $pid);
+
+ // Player has requested to join an alliance
+ if (!is_null($pinf['arid'])) {
+ $ainf = $this->alliance->call('get', $pinf['arid']);
$s = "1#" . $ainf['nplanets'] . '#' . $ainf['avgx'] . '#' . $ainf['avgy'];
list($points,$ranking) = $this->getAllianceRanking($ainf['tag']);
$s .= "#$ranking#$points";
array_push($out, $s);
array_push($out, utf8entities($pinf['alliance_req']));
array_push($out, utf8entities($pinf['aname']));
- $alinf = gameAction('getPlayerName', $ainf['leader']);
+ $alinf = $this->player->call('getName', $ainf['leader']);
array_push($out, utf8entities($alinf));
- }
- elseif (!is_null($pinf['aid']))
- {
- $ainf = gameAction('getAllianceInfo', $pinf['aid']);
- $pr = gameAction('getAlliancePrivileges', $pid);
+
+ // Player is a member of an alliance
+ } elseif (!is_null($pinf['aid'])) {
+ $ainf = $this->alliance->call('get', $pinf['aid']);
+ $pr = $this->alliance->call('getPrivileges', $pid);
$s = "2#" . $ainf['nplanets'] . '#' . $ainf['avgx'] . '#' . $ainf['avgy'];
list($points,$ranking) = $this->getAllianceRanking($ainf['tag']);
@@ -49,31 +57,36 @@
array_push($out, $s);
array_push($out, utf8entities($pinf['alliance']));
array_push($out, utf8entities($pinf['aname']));
- if (!$pr['is_leader'])
- {
- array_push($out, utf8entities(gameAction('getPlayerName', $ainf['leader'])));
- if (is_null($pinf['a_grade']))
+
+ // Get the player's rank if he isn't the leader
+ if (!$pr['is_leader']) {
+ array_push($out, utf8entities($this->player->call('getName', $ainf['leader'])));
+ if (is_null($pinf['a_grade'])) {
array_push($out, "-");
- else
- {
- $rkl = gameAction('getAllianceRanks', $pinf['aid']);
+ } else {
+ $rkl = $this->alliance->call('getRanks', $pinf['aid']);
array_push($out, $rkl[$pinf['a_grade']]);
}
}
- $fl = gameAction('getAllianceForumsComplete', $pinf['aid']);
- foreach ($fl as $fd)
- {
- $fid = $fd['id'];
- if (!(in_array($fid, $pr['f_read']) || in_array($fid, $pr['f_mod'])))
+ // Get the list of alliance forums
+ $aForums = input::$game->getLib('beta5/aforums');
+ $cat = array_shift($aForums->call('getStructure', $pinf['uid']));
+ foreach ($cat->getForums() as $forum) {
+ if ($forum->isDeleted()) {
continue;
- $tot = $fd['topics'];
- $unread = $tot - gameAction('getReadTopics', $fid, $pid);
- array_push($out, "$fid#$tot#$unread#".utf8entities($fd['title']));
+ }
+ $fid = $forum->getId();
+ $tot = $forum->getTopics();
+ $unread = $forum->getUnread();
+ $name = utf8entities($forum->getTitle());
+ array_push($out, "$fid#$tot#$unread#$name");
}
- }
- else
+
+ // Player is not a member of any alliance and has not requested to join one
+ } else {
array_push($out, "0");
+ }
$pm = gameAction('getAllMessages', $pid, 'IN');
$pmn = gameAction('getNewMessages', $pid, 'IN');
diff -Naur beta5//scripts/site/beta5/handlers/forums.inc forums//scripts/site/beta5/handlers/forums.inc
--- beta5//scripts/site/beta5/handlers/forums.inc 2011-02-05 10:09:57.204335002 +0100
+++ forums//scripts/site/beta5/handlers/forums.inc 2011-03-12 14:56:16.341300049 +0100
@@ -1,9 +1,7 @@
<?php
-class page_handler
-{
- var $needsAuth = true;
-
+class page_handler {
+/*
function getForum($ctype, $fid, &$cats)
{
$forum = null;
@@ -850,8 +848,9 @@
$gfl[$fid] = $ctype;
}
- $txt = '%' . preg_replace('/\*/', '%', addslashes($_SESSION[game::sessName()]['forumsearch']['text'])) . '%';
- $pg = $_SESSION[game::sessName()]['forumsearch']['page'];
+*/
+// $txt = '%' . preg_replace('/\*/', '%', addslashes($_SESSION[game::sessName()]['forumsearch']['text'])) . '%';
+/* $pg = $_SESSION[game::sessName()]['forumsearch']['page'];
$mpp = $_SESSION[game::sessName()]['forumsearch']['perpage'];
$c = $_SESSION[game::sessName()]['forumsearch']['whole'];
$sfs = array('moment','title');
@@ -915,7 +914,10 @@
$fl[$cat['type'] . "#" . $f['id']] = array($f['title'],$cat['id'],$cat['title']);
}
- $txt = '%' . preg_replace('/\*/', '%', addslashes($_SESSION[game::sessName()]['forumsearch']['text'])) . '%';
+*/
+// $txt = '%' . preg_replace('/\*/', '%', addslashes($_SESSION[game::sessName()]['forumsearch']['text'])) . '%';
+
+/*
$pg = $_SESSION[game::sessName()]['forumsearch']['page'];
$mpp = $_SESSION[game::sessName()]['forumsearch']['perpage'];
$c = $_SESSION[game::sessName()]['forumsearch']['whole'];
@@ -1067,6 +1069,474 @@
}
$this->output = "forums";
}
+*/
+ /* Timeout in seconds for the forums' session data */
+ const SESSION_TIMEOUT = 60;
+
+ /* AJAX engine data */
+ public $needsAuth = true;
+ public $ajax = array(
+ "init" => "main = new ForumsLayout();",
+ "func" => array(
+ // Menu functions
+ "showMenu", "hideMenu", "getMenu",
+ "menuOpen", "menuClose",
+ // Category / forum view functions
+ "getView", "categoryRead", "forumOptions", "forumRead",
+ "restoreTopics", "deleteTopics", "changeTopicsLevel",
+ "setTopicsLevel", "setTopicsLock", "moveTopics",
+ // Topic view functions
+ "getTopic", "loadPostContents"
+ ));
+
+ /* Method that loads the required libraries */
+ private function loadLibraries() {
+ $this->player = input::$game->getLib('beta5/player');
+
+ $this->forums = input::$game->getLib('main/forums');
+ $this->gForums = input::$game->getLib('main/gforums');
+ $this->uForums = input::$game->getLib('main/uforums');
+ $this->aForums = input::$game->getLib('beta5/aforums');
+ }
+
+
+/***********************************************************************************************************************/
+/** SESSION CODE *******************************************************************************************************/
+/***********************************************************************************************************************/
+
+ /* This method reads the menu's status from the session */
+ private function getMenuSession() {
+ if (! array_key_exists( 'forums_menu', $_SESSION[game::sessName()] )) {
+ $_SESSION[game::sessName()]['forums_menu'] = array();
+ }
+ return $_SESSION[game::sessName()]['forums_menu'];
+ }
+
+ /* This method stores the menu's status */
+ private function storeMenuSession( $value ) {
+ $_SESSION[game::sessName()]['forums_menu'] = $value;
+ }
+
+ /* This method initialises the main forums session and removes old data */
+ private function initMainSession() {
+
+ if (is_null( $_SESSION[game::sessName()]['forums_data'] )) {
+ $_SESSION[game::sessName()]['forums_data'] = array();
+ return;
+ }
+
+ // Clean up old data
+ $now = time();
+ $nSession = array();
+ foreach ($_SESSION[game::sessName()]['forums_data'] as $key => $data) {
+ if (!is_array( $data )) {
+ continue;
+ }
+ if ($data['ts'] - $now < self::SESSION_TIMEOUT) {
+ $nSession[$key] = $data;
+ }
+ }
+ $_SESSION[game::sessName()]['forums_data'] = $nSession;
+ }
+
+ /* This method is used by specific handlers to read from the session */
+ public function getSessionData($key) {
+ $this->initMainSession();
+ if (is_array($_SESSION[game::sessName()]['forums_data'][$key])
+ && array_key_exists( 'data', $_SESSION[game::sessName()]['forums_data'][$key])) {
+ $_SESSION[game::sessName()]['forums_data'][$key]['ts'] = time();
+ return $_SESSION[game::sessName()]['forums_data'][$key]['data'];
+ }
+ return null;
+ }
+
+ /* This method is used by specific handlers to write into the session */
+ public function setSessionData($key, $data) {
+ $this->initMainSession();
+ $_SESSION[game::sessName()]['forums_data'][$key] = array(
+ "ts" => time(),
+ "data" => $data
+ );
+ }
+
+
+/***********************************************************************************************************************/
+/** MENU HANDLER *******************************************************************************************************/
+/***********************************************************************************************************************/
+
+ /* Returns a boolean indicating whether the menu should be displayed */
+ private function getMenuVisibility() {
+ if (! array_key_exists( 'display_forums_menu', $_SESSION[game::sessName()] )) {
+ $_SESSION[game::sessName()]['display_forums_menu'] = true;
+ }
+ return $_SESSION[game::sessName()]['display_forums_menu'];
+ }
+
+ /* Sets the value for the menu's visibility */
+ private function setMenuVisibility( $value ) {
+ $_SESSION[game::sessName()]['display_forums_menu'] = (boolean) $value;
+ }
+
+ /* This method generates the output for a menu entry */
+ private function makeMenuEntry( &$output, $command, $isLeaf, $isOpen,
+ $displayType, $text, $id = '', $unread = 0 ) {
+
+ // The first line indicates the type of menu entry, as well as the display type,
+ // amount of unread topics and, if the entry is a submenu, whether it's open or not
+ $txt = $isLeaf ? "L" : "N";
+ $txt .= "#$displayType#$unread";
+ if (! $isLeaf) {
+ $txt .= "#" . ($isOpen ? "1" : "0") . "#$id";
+ }
+ array_push( $output, $txt );
+
+ // The two next lines contain the command and text / command ID
+ array_push( $output, $command );
+ array_push( $output, $text );
+ }
+
+ /* This method outputs the "separator" indicator */
+ private function makeMenuSeparator( &$output ) {
+ array_push( $output, "S" );
+ }
+
+ /* This method outputs the "end of menu" indicator */
+ private function makeEndOfMenu( &$output ) {
+ array_push( $output, "E" );
+ }
+
+ /* This method generates the menu's data */
+ private function dumpMenu( &$output, $structure ) {
+
+ // Handle the root of the tree
+ if ($structure instanceof fl_container && $structure->getId() == '/') {
+ // This is the root node
+ $this->makeMenuEntry( &$output, "V#C#/", false, true, "C", "overview", '/' );
+
+ // Add "Latest messages" entry
+ $this->makeMenuEntry( &$output, "L#C#/", true, false, "C", "latest" );
+ // Add the "Search forums" entry
+ $this->makeMenuEntry( &$output, "SF", true, false, "C", "search" );
+
+ // Add the moderation tools submenu
+ // FIXME
+
+ // Add the submenus
+ $this->makeMenuSeparator( &$output );
+ foreach ($structure->getCategories() as $cat) {
+ $this->dumpMenu( &$output, $cat, $menuData );
+ }
+
+ $this->makeEndOfMenu( &$output );
+ return;
+ }
+
+ // Handle containers
+ if ($structure instanceof fl_container) {
+ $id = $structure->getId();
+ $menuData = $this->getMenuSession();
+
+ // Create the node
+ $this->makeMenuEntry( &$output, "V#C#$id", false, $menuData[$id],
+ "T", $structure->getTitle(), $id, $structure->getUnread());
+
+ // Return if the menu's closed
+ if (! $menuData[$id]) {
+ return;
+ }
+
+ // Add "Latest messages" entry
+ $this->makeMenuEntry( &$output, "L#C#$id", true, false, "C", "latest" );
+
+ // Special stuff to be added here
+ // FIXME
+
+ // Add the submenus
+ $catList = $structure->getCategories();
+ if (count($catList)) {
+ $this->makeMenuSeparator( &$output );
+ foreach ($catList as $cat) {
+ $this->dumpMenu( &$output, $cat, $menuData );
+ }
+ }
+
+ $this->makeEndOfMenu( &$output );
+ return;
+ }
+
+ // Standard categories
+ if ($structure instanceof fl_category) {
+ $id = $structure->getId();
+ $menuData = $this->getMenuSession();
+
+ // Create the node
+ $this->makeMenuEntry( &$output, "V#C#$id", false, $menuData[$id],
+ "T", $structure->getTitle(), $id, $structure->getUnread());
+
+ // Return if the menu's closed
+ if (! $menuData[$id]) {
+ return;
+ }
+
+ // Add "Latest messages" entry
+ $this->makeMenuEntry( &$output, "L#C#$id", true, false, "C", "latest" );
+
+ // Special stuff to be added here
+ // FIXME
+
+ // Add the forums
+ $fList = $structure->getForums();
+ if (count($fList)) {
+ $this->makeMenuSeparator( &$output );
+ foreach ($fList as $f) {
+ if ( ! $f->canView() || $f->isDeleted() ) {
+ continue;
+ }
+ $this->makeMenuEntry( &$output, "V#F#" . $f->getId(),
+ true, false, "T", $f->getTitle(), '', $f->getUnread() );
+ }
+ }
+
+ $this->makeEndOfMenu( &$output );
+ return;
+ }
+ }
+
+ /* AJAX method that shows the menu */
+ public function showMenu() {
+ $this->setMenuVisibility(true);
+ return $this->getMenu();
+ }
+
+ /* AJAX method that hides the menu */
+ public function hideMenu() {
+ $this->setMenuVisibility(false);
+ }
+
+ /* AJAX method that returns the forums' menu */
+ public function getMenu($previousMD5 = null) {
+ $pid = $_SESSION[game::sessName()]['player'];
+ $this->loadLibraries();
+
+ // Get the forums' structure
+ $structure = input::$game->action('getForums', $pid);
+
+ // Dump the whole thing
+ $result = array();
+ $this->dumpMenu( &$result, $structure );
+
+ // Check the MD5 sum
+ $md5 = md5(serialize($result));
+ if ($md5 !== $previousMD5) {
+ array_unshift($result, $md5);
+ return join("\n", $result);
+ }
+
+ return "-";
+ }
+
+ /* AJAX method that opens a path in the menu */
+ public function menuOpen($toID) {
+ $intID = (int) $toID;
+ if ( in_array($toID, array('G', 'U', 'MT')) || (string) $intID == $toID ) {
+ if ( (string) $intID == $toID ) {
+ $toID = (string) $intID;
+ }
+ $menuData = $this->getMenuSession();
+ $menuData[$toID] = true;
+ $this->storeMenuSession($menuData);
+ }
+
+ return $this->getMenu();
+ }
+
+ /* AJAX method that closes a path in the menu */
+ public function menuClose($toID) {
+ $intID = (int) $toID;
+ if ( in_array($toID, array('G', 'U', 'MT')) || (string) $intID == $toID ) {
+ if ( (string) $intID == $toID ) {
+ $toID = (string) $intID;
+ }
+ $menuData = $this->getMenuSession();
+ $menuData[$toID] = false;
+ $this->storeMenuSession($menuData);
+ }
+
+ return $this->getMenu();
+ }
+
+
+/***********************************************************************************************************************/
+/** CATEGORY / FORUM VIEW **********************************************************************************************/
+/***********************************************************************************************************************/
+
+ /* AJAX method used to refresh a view page */
+ public function getView($whichView, $md5) {
+ $handler = input::$game->getLib('beta5/forums/view');
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler->call('forumCommand', $pid, $whichView);
+ return $handler->call('getData', $md5);
+ }
+
+ /* AJAX method that marks all of a category's forums as read */
+ public function categoryRead($category, $whichView) {
+ $handler = input::$game->getLib('beta5/forums/view');
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler->call('forumCommand', $pid, $whichView);
+ $handler->call('categoryRead', $category);
+ return $handler->call('getData', $md5);
+ }
+
+ /* AJAX method that set forums options */
+ public function forumOptions($forum, $toAll, $perPage, $viewDeleted, $md5) {
+ $forum = (int) $forum;
+ $toAll = ($toAll == '1');
+ $perPage = ($perPage > 0 && $perPage % 10 == 0 && $perPage / 10 < 6) ? (int)$perPage : 20;
+ $viewDeleted = $viewDeleted;
+ $pid = $_SESSION[game::sessName()]['player'];
+
+ $this->loadLibraries();
+ $this->forums->call('setOptions', $pid, $toAll ? -1 : $forum, $perPage, $viewDeleted);
+
+ $handler = input::$game->getLib('beta5/forums/view');
+ $handler->call('forumCommand', $pid, "F#$forum");
+ return $handler->call('getData', $md5);
+ }
+
+ /* AJAX method that set forums options */
+ public function forumRead($forum) {
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler = input::$game->getLib('beta5/forums/view');
+ $handler->call('forumCommand', $pid, "F#$forum");
+ $handler->call('forumRead');
+ return $handler->call('getData');
+ }
+
+ /* AJAX method that restores a set of topics */
+ public function restoreTopics($forum, $topics) {
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler = input::$game->getLib('beta5/forums/view');
+ $handler->call('forumCommand', $pid, "F#$forum");
+ $handler->call('restoreTopics', explode('#', $topics));
+ return $handler->call('getData');
+ }
+
+ /* AJAX method that deletes a set of topics */
+ public function deleteTopics($forum, $topics) {
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler = input::$game->getLib('beta5/forums/view');
+ $handler->call('forumCommand', $pid, "F#$forum");
+ $handler->call('deleteTopics', explode('#', $topics));
+ return $handler->call('getData');
+ }
+
+ /* AJAX method that changes the sticky level for a set of topics */
+ public function changeTopicsLevel($forum, $topics, $change) {
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler = input::$game->getLib('beta5/forums/view');
+ $handler->call('forumCommand', $pid, "F#$forum");
+ $handler->call('changeTopicsLevel', explode('#', $topics), $change);
+ return $handler->call('getData');
+ }
+
+ /* AJAX method that sets the sticky level for a set of topics */
+ public function setTopicsLevel($forum, $topics, $level) {
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler = input::$game->getLib('beta5/forums/view');
+ $handler->call('forumCommand', $pid, "F#$forum");
+ $handler->call('setTopicsLevel', explode('#', $topics), $level);
+ return $handler->call('getData');
+ }
+
+ /* AJAX method that sets the lock for a set of topics */
+ public function setTopicsLock($forum, $topics, $lock) {
+ $lock = ($lock == '1');
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler = input::$game->getLib('beta5/forums/view');
+ $handler->call('forumCommand', $pid, "F#$forum");
+ $handler->call('setTopicsLock', explode('#', $topics), $lock);
+ return $handler->call('getData');
+ }
+
+ /* AJAX method that moves a set of topics to another forum */
+ public function moveTopics($forum, $topics, $destination) {
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler = input::$game->getLib('beta5/forums/view');
+ $handler->call('forumCommand', $pid, "F#$forum");
+ $handler->call('moveTopics', explode('#', $topics), $destination);
+ return $handler->call('getData');
+ }
+
+
+/***********************************************************************************************************************/
+/** TOPIC VIEW *********************************************************************************************************/
+/***********************************************************************************************************************/
+
+ /* AJAX method that returns a post's contents */
+ public function loadPostContents($topic, $md5, $postId) {
+ $pid = $_SESSION[game::sessName()]['player'];
+ $handler = input::$game->getLib('beta5/forums/topic');
+ $handler->call('initialize', $this);
+ $handler->call('forumCommand', $pid, "$topic#$md5");
+ return $handler->call('getPostContents', $postId);
+ }
+
+
+/***********************************************************************************************************************/
+/** PAGE HANDLER *******************************************************************************************************/
+/***********************************************************************************************************************/
+
+ /* The main page handler */
+ public function handle($input) {
+
+ // Get the command
+ $cmd = $input['cmd'];
+ if ($cmd == 'o' || $cmd == '') {
+ $cmd = 'V#C#/';
+ }
+
+ // Check the command
+ if ($cmd == 'SF') {
+ // Search forums
+ $args = array(); // FIXME
+ } elseif ($cmd == 'xx') {
+ // FIXME: other 'simple' commands
+ } else {
+ $rCmd = $cmd{0};
+ $args = substr($cmd, 2);
+ if ($rCmd == 'V') {
+ // View command
+ $handler = input::$game->getLib('beta5/forums/view');
+ } elseif ($rCmd == 'T') {
+ // View topic command
+ $handler = input::$game->getLib('beta5/forums/topic');
+ }
+ }
+
+ // Execute the command
+ $handler->call('initialize', $this);
+ list($mCurrent, $pageType, $pageData) = $handler->call( 'forumCommand',
+ $_SESSION[game::sessName()]['player'], $args );
+
+ $this->data = array(
+ "needData" => input::$IE,
+ "showMenu" => $this->getMenuVisibility(),
+ "menuCurrent" => $mCurrent,
+ "pageType" => $pageType
+ );
+ if (input::$IE) {
+ $this->data['menuContents'] = '';
+ $this->data['pageData'] = $pageData;
+ } else {
+ if ($this->data['showMenu']) {
+ $this->data['menuContents'] = $this->getMenu();
+ }
+ $this->data['pageData'] = $handler->call('getData');
+ }
+
+ $this->output = "forums";
+ }
+
}
?>
diff -Naur beta5//scripts/site/beta5/output/comms.en.inc forums//scripts/site/beta5/output/comms.en.inc
--- beta5//scripts/site/beta5/output/comms.en.inc 2011-02-05 10:09:57.294335002 +0100
+++ forums//scripts/site/beta5/output/comms.en.inc 2011-03-12 14:56:19.761300052 +0100
@@ -15,9 +15,7 @@
</p>
</td><td style="width:45%">
<h1>Forums</h1>
- <h2>General forums</h2>
- <p id="gforums"></p>
- <div id="aforums"></div>
+ <div id="forums"></div>
</td><td>
<a href="manual?p=communications_page">Help</a>
</td>
diff -Naur beta5//scripts/site/beta5/output/forums.en.inc forums//scripts/site/beta5/output/forums.en.inc
--- beta5//scripts/site/beta5/output/forums.en.inc 2011-02-05 10:09:57.294335002 +0100
+++ forums//scripts/site/beta5/output/forums.en.inc 2011-02-05 10:10:02.974335002 +0100
@@ -1,5 +1,6 @@
<?
+/*
function drawForumsMenu($mode,$fList)
{
?>
@@ -68,5 +69,19 @@
$sp = $args['sp'];
$args = $args['d'];
include("forums/en/$sp.inc");
+*/
?>
+<div style="display: none; visibility: hidden;">
+ <div id="f-params"><?=$args['showMenu'] ? 1 : 0?>#<?=$args['needData'] ? 1 : 0?>#<?=$args['pageType']?></div>
+ <div id="f-menu-current"><?=$args['menuCurrent']?></div>
+<?php
+if (! $args['needData']) {
+?>
+ <div id="f-menu-init"><?=$args['menuContents']?></div>
+ <div id="f-page-init"><?=$args['pageData']?></div>
+<?php
+}
+?>
+</div>
+<div id="f-contents">&nbsp;</div>
diff -Naur beta5//scripts/ticks.php forums//scripts/ticks.php
--- beta5//scripts/ticks.php 2011-02-05 10:09:57.904335002 +0100
+++ forums//scripts/ticks.php 2011-03-12 15:13:57.671300053 +0100
@@ -20,8 +20,8 @@
$__loader = array(
'log', 'classloader',
'version', 'game', 'tick', 'config',
- 'db_connection', 'db_accessor', 'db_copy', 'db',
- 'pcheck', 'library', 'tick_manager',
+ 'db_connection', 'db_accessor', 'db_copy' , 'db_query',
+ 'db', 'pcheck' , 'library', 'tick_manager',
);
require_once("loader.inc");
diff -Naur beta5//site/index.php forums//site/index.php
--- beta5//site/index.php 2011-02-05 10:09:57.164335002 +0100
+++ forums//site/index.php 2011-02-05 10:10:02.844335002 +0100
@@ -4,8 +4,8 @@
$__loader = array(
'log', 'classloader',
'version', 'game', 'tick', 'config',
- 'db_connection', 'db_accessor', 'db',
- 'library', 'actions', 'data_tree',
+ 'db_connection', 'db_accessor', 'db_query',
+ 'db', 'library', 'actions', 'data_tree',
'input', 'ajax', 'handler', 'engine',
'resource', 'tracking', 'session',
'account', 'prefs', 'output'
diff -Naur beta5//site/static/beta5/js/pg_alliance-en.js forums//site/static/beta5/js/pg_alliance-en.js
--- beta5//site/static/beta5/js/pg_alliance-en.js 2011-02-05 10:09:56.434335002 +0100
+++ forums//site/static/beta5/js/pg_alliance-en.js 2011-03-12 15:12:38.321300050 +0100
@@ -1037,54 +1037,105 @@
// FORUMS ADMINISTRATION PAGE
//--------------------------------------------------
-function drawForumList()
-{
+function drawForumList() {
var str = '<table cellspacing="0" cellpadding="0">';
str += '<tr><td class="div2" id="fattl"><h1>Alliance Forums</h1><td id="crforum">&nbsp;</td></tr>';
str += '<tr><td colspan="2" id="falist">&nbsp;</td></tr></table>';
document.getElementById('alpmain').innerHTML = str;
- if (faForums.length < 30)
- drawCreateForumLink();
- if (faForums.length == 0)
+
+ if (faForums.length < 30) {
+ document.getElementById('crforum').innerHTML = '<a href="#" ' + alltt[120]
+ + ' onClick="createForum();return false">Create a forum</a>';
+ }
+
+ if (faForums.length == 0) {
drawTextNoForums();
- else
+ } else {
drawRealForumList();
+ }
}
-function drawCreateForumLink()
-{
- var str = '<a href="#" ' + alltt[120] + ' onClick="createForum();return false">';
- str += 'Create a forum</a>';
- document.getElementById('crforum').innerHTML = str;
-}
-
-function drawTextNoForums()
-{
+function drawTextNoForums() {
document.getElementById('falist').innerHTML = '<p>No forums have been defined for the alliance.</p>';
}
-function drawRealForumList()
-{
- var i, str = '<table class="list" cellspacing="0" cellpadding="0" id="fatbl">';
+function drawRealForumList() {
+ var i, str = '<table class="list" cellspacing="0" cellpadding="0" id="fatbl">';
+
+ var getFRankText = function (id) {
+ var r = faRanks['r' + id];
+ return r == '-' ? '<i>Default member</i>' : r;
+ }
+
+ str += '<tr><th class="faname">Name &amp; description</th><th class="fauserpost">User access mode</th></tr>';
+ for (i = 0; i < faForums.length; i++) {
+ str += '<tr><td class="faname"><b><u>'
+ + faForums[i].name.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
+ + '</u></b> (';
+ if (faForums[i].isDeleted) {
+ str += 'deleted by <b>' + faPlayers['p' + faForums[i].deletedBy] + '</b> at <b>'
+ + formatDate(faForums[i].deletedAt) + '</b> - <a href="#" onClick="restoreForum('
+ + faForums[i].id + ');return false">Restore</a>';
+ } else {
+ str += '<a ' + alltt[130] + ' href="#" onClick="editForum(' + faForums[i].id
+ + ');return false">Edit</a> - ';
+ if (i > 0) {
+ str += '<a ' + alltt[131] + ' href="#" onClick="moveForum(' + faForums[i].id
+ + ',true);return false">Move up</a> - ';
+ }
+ if (i < faForums.length - 1) {
+ str += '<a ' + alltt[132] + ' href="#" onClick="moveForum(' + faForums[i].id
+ + ',false);return false">Move down</a> - ';
+ }
+ str += '<a ' + alltt[133] + ' href="#" onClick="deleteForum(' + faForums[i].id
+ + ');return false">Delete</a>';
+ }
+ str += ")";
+
+ if (faForums[i].description != '' || faForums[i].users.length || faForums[i].mods.length) {
+
+ var nbr = false;
+ str += '<br/><p>';
+
+ if (faForums[i].description != '') {
+ str += faForums[i].description.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g,"<br/>");
+ nbr = true;
+ }
+
+ if (faForums[i].users.length) {
+ str += (nbr ? '<br/>' : '') + '<b>Users:</b> ';
+ for (var ri in faForums[i].users) {
+ str += (ri > 0 ? ' - ' : '') + getFRankText(faForums[i].users[ri]);
+ }
+ nbr = true;
+ }
+
+ if (faForums[i].mods.length) {
+ str += (nbr ? '<br/>' : '') + '<b>Moderators:</b> ';
+ for (var ri in faForums[i].mods) {
+ str += (ri > 0 ? ' - ' : '') + getFRankText(faForums[i].mods[ri]);
+ }
+ nbr = true;
+ }
+
+ str += '</p>';
+ }
- str += '<tr><th class="faname">Name &amp; description</th><th class="fauserpost">New threads</th></tr>';
- for (i=0;i<faForums.length;i++)
- {
- str += '<tr>';
- str += '<td class="faname"><b><u>' + faForums[i].name.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</u></b> (';
- str += '<a ' + alltt[130] + ' href="#" onClick="editForum(' + faForums[i].id + ');return false">Edit</a> - ';
- if (i > 0)
- str += '<a ' + alltt[131] + ' href="#" onClick="moveForum(' + faForums[i].id + ',true);return false">Move up</a> - ';
- if (i < faForums.length - 1)
- str += '<a ' + alltt[132] + ' href="#" onClick="moveForum(' + faForums[i].id + ',false);return false">Move down</a> - ';
- str += '<a ' + alltt[133] + ' href="#" onClick="deleteForum(' + faForums[i].id + ');return false">Delete</a>)';
- if (faForums[i].description != '')
- str += '<br/><p>' + faForums[i].description.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g,"<br/>") + '</p>';
str += '</td><td class="fauserpost">';
- if (faForums[i].userPost)
- str += 'Everyone';
- else
- str += 'Moderators only';
+ switch (faForums[i].accessMode) {
+ case 'L':
+ str += 'Full access';
+ break;
+ case 'T':
+ str += 'No polls';
+ break;
+ case 'P':
+ str += 'Replies only';
+ break;
+ case 'M':
+ str += 'Read only';
+ break;
+ }
str += '</td></tr>';
}
@@ -1092,85 +1143,96 @@
document.getElementById('falist').innerHTML = str;
}
-function cheatAlert()
-{
- alert('Possible cheating detected.');
-}
-
-function confirmDeleteForum(name)
-{
- var str = 'You are about to delete the following forum:\n' + name + '\n';
- str += 'The forum\'s topics will be lost and you will not be able to recover them.\nPlease confirm.';
+function confirmDeleteForum(forum) {
+ var str = 'You are about to delete the following forum:\n ' + forum.name + '\n';
+ if (forum.topics > 0) {
+ str += 'The forum contains '
+ + (forum.topics > 1 ? (formatNumber(forum.topics.toString()) + ' topics') : 'a single topic')
+ + '.\n';
+ }
+ str += 'Please confirm.';
return confirm(str);
}
-function alertMaximumFCount()
-{
+function alertMaximumFCount() {
alert('The alliance has reached its maximum possible count of forums.\nYou will be taken back to the list.');
}
-function drawForumEditor()
-{
+function drawForumEditor() {
document.getElementById('falist').innerHTML = '&nbsp;';
var str;
- if (faEditing.id)
- {
+ if (faEditing.id) {
f = forumById(faEditing.id);
str = "'" + f.name.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;') + "' forum";
- }
- else
+ } else {
str = "Create a forum";
+ }
document.getElementById('fattl').innerHTML = '<h1>' + str + '</h1>';
- str = '<table cellspacing="0" cellpadding="0" id="feditor">';
- str += '<tr><th class="edheader">Forum name:</th><td><input ' + alltt[140] + ' type="text" name="fedit" id="fname" size="48" maxlength="64" value="';
- str += faEditing.name.replace(/"/g, '&quot;') + '" onKeyUp="faEditing.name=value.replace(/&lt;/g, \'<\').replace(/&gt;/g, \'>\').replace(/&amp;/g, \'&\');';
- str += 'updateFEditor()" onChange="faEditing.name=value;updateFEditor()" />';
+ str = '<table cellspacing="0" cellpadding="0" id="feditor">'
+ + '<tr><th class="edheader">Forum name:</th><td><input ' + alltt[140]
+ + ' type="text" name="fedit" id="fname" size="48" maxlength="64"'
+ + ' onKeyUp="faEditing.name=value;updateFEditor()" onChange="faEditing.name=value;updateFEditor()" />'
+ + '</td></tr>'
+ + '<tr><th class="edheader">User access mode:</th><td>';
+
+ var aModes = {
+ M: 'Read only',
+ P: 'Replies only',
+ T: 'Topic creation',
+ L: 'Complete access'
+ };
+ for (var i in aModes) {
+ str += '<input type="radio" name="fam" id="f-am-' + i + '" value="' + i
+ + '" onClick="faEditing.accessMode=value;updateFEditor()"'
+ + (faEditing.accessMode == i ? ' checked="checked"' : '')
+ + ' /><label for="f-am-' + i + '">' + aModes[i] + '</label> ';
+ }
str += '</td></tr>';
- str += '<tr><th class="edheader">New threads:</th><td>';
- str += '<label><input ' + alltt[141] + ' type="radio" name="nt" value="1" onClick="faEditing.userPost=true;updateFEditor()" ';
- if (faEditing.userPost)
- str += 'checked="checked" ';
- str += '/> Everyone</label> <label><input ' + alltt[142] + ' type="radio" name="nt" value="0" onClick="faEditing.userPost=false;updateFEditor()" ';
- if (!faEditing.userPost)
- str += 'checked="checked" ';
- str += '/> Moderators only</label></td></tr>';
- if (!faEditing.id)
- str += '<tr><th class="edheader">Initial position:</th><td ' + alltt[143] + ' id="faeipos">&nbsp;</td></tr>';
- str += '<tr><th class="edheader">Description:</th><td><textarea ' + alltt[144] + ' name="fdesc" onKeyUp="faEditing.description=';
- str += 'value.replace(/&lt;/g, \'<\').replace(/&gt;/g, \'>\').replace(/&amp;/g, \'&\');updateFEditor()"';
- str += ' onChange="faEditing.description=value;updateFEditor()"';
- str += ' rows="10" cols="48">' + faEditing.description.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</textarea></td></tr>';
- str += '<td id="febut" colspan="2"><input type="button" name="feok" value="Ok" id="feok" onClick="forumEditOk();return false" ' + alltt[145] + ' />';
- str += '&nbsp;<input type="button" name="feccl" value="Cancel" onClick="forumEditCancel();return false" ' + alltt[146] + ' /></td></tr>';
- str += '<tr><td colspan="2"><h3>Forum access</h3></td></tr>';
- str += '<tr><td colspan="2" id="faeaccess"><p>(Loading access list data ...)</p></td></tr>';
- str += '</table>';
+ if (!faEditing.id) {
+ str += '<tr><th class="edheader">Initial position:</th><td '
+ + alltt[143] + ' id="faeipos">&nbsp;</td></tr>';
+ }
+
+ str += '<tr><th class="edheader">Description:</th><td><textarea ' + alltt[144]
+ + ' name="fdesc" id="fdesc" onKeyUp="faEditing.description=value;updateFEditor()"'
+ + ' onChange="faEditing.description=value;updateFEditor()"'
+ + ' rows="10" cols="48"></textarea></td></tr>'
+ + '<tr><td id="febut" colspan="2"><input type="button" name="feok" value="Ok" id="feok" '
+ + 'onClick="forumEditOk();return false" ' + alltt[145] + ' />'
+ + '&nbsp;<input type="button" name="feccl" value="Cancel" onClick="forumEditCancel();return false" '
+ + alltt[146] + ' /></td></tr>'
+ + '<tr><td colspan="2"><h3>Forum access</h3></td></tr>'
+ + '<tr><td colspan="2" id="faeaccess">&nbsp;</td></tr>'
+ + '</table>';
document.getElementById('falist').innerHTML = str;
+
+ document.getElementById('fname').value = faEditing.name;
+ document.getElementById('fdesc').value = faEditing.description;
document.getElementById('feok').disabled = true;
- if (!faEditing.id)
+ if (!faEditing.id) {
updateFPosSelector();
+ }
+ drawFAccessManager();
}
-function updateFPosSelector()
-{
- var i, str = '<select name="fanewpos" onChange="faNewPos=this.options[this.selectedIndex].value">';
- str += '<option value="-1">At the beginning</option>';
- for (i=0;i<faForums.length;i++)
- {
+function updateFPosSelector() {
+ var i, str = '<select name="fanewpos" onChange="faNewPos=this.options[this.selectedIndex].value">'
+ + '<option value="-1">At the beginning</option>';
+ for (i = 0; i < faForums.length; i ++) {
str += '<option value="' + faForums[i].id + '"';
- if (faNewPos == faForums[i].id)
+ if (faNewPos == faForums[i].id) {
str += ' selected="selected"';
+ }
str += '>After ' + faForums[i].name + '</option>';
}
str += '</select>';
document.getElementById('faeipos').innerHTML = str;
}
-function drawFAccessManager()
-{
+function drawFAccessManager() {
var lnp = new Array(), lmd = new Array(), lrd = new Array(), ml, i, sc=0;
for (i=0;i<faAccess.length;i++)
{
@@ -1268,6 +1330,8 @@
case 6: str += 'Probable bug: the forum to insert after wasn\'t transmitted.'; break;
case 7: str += 'A server error has occured.'; break;
case 8: str += 'This forum has already been deleted.'; break;
+ case 9: str += 'This forum has been cleansed and can no longer be recovered.'; break;
+ case 10: str += 'This forum has already been restored.'; break;
case 200: str += "You can\'t modify an alliance\'s forums while in vacation mode."; break;
default: str += 'An unknown error has happened.'; break;
}
diff -Naur beta5//site/static/beta5/js/pg_alliance.js forums//site/static/beta5/js/pg_alliance.js
--- beta5//site/static/beta5/js/pg_alliance.js 2011-02-05 10:09:56.434335002 +0100
+++ forums//site/static/beta5/js/pg_alliance.js 2011-03-12 14:56:07.421300050 +0100
@@ -80,6 +80,9 @@
var faOriACL;
var faNewPos;
var faAccess;
+var faRanks;
+var faAdmins;
+var faPlayers;
var raRanks = new Array();
var raForums;
@@ -1239,11 +1242,9 @@
// Forums administation
-function switchToFAdminPage()
-{
+function switchToFAdminPage() {
clearUpdate();
- if (alPrivileges[5] != 1)
- {
+ if (alPrivileges[5] != 1) {
switchToMainPage();
return;
}
@@ -1255,36 +1256,97 @@
x_getForums(forumsReceived);
}
-function AllianceForum(id,order,userPost,name,description)
-{
- this.id = id;
- this.order = order;
- this.userPost = userPost;
- this.name = name;
- this.description = description;
+function AllianceForum() {
+ this.id = null;
+ this.accessMode = 'T';
+ this.isDeleted = false;
+ this.deletedAt = null;
+ this.deletedBy = null;
+ this.name = '';
+ this.description = '';
+ this.topics = 0;
+ this.users = new Array();
+ this.mods = new Array();
+
+ this.parse = function (lines) {
+ var line = lines.shift().split('#');
+
+ // General information
+ this.id = line.shift();
+ this.isDeleted = (line.shift() == '1');
+ this.deletedBy = line.shift();
+ this.deletedAt = line.shift();
+ this.accessMode = line.shift();
+ this.topics = parseInt(line.shift(), 10);
+ this.name = line.join('#');
+
+ // Users
+ line = lines.shift();
+ if (line != '') {
+ this.users = line.split('#');
+ }
+
+ // Moderators
+ line = lines.shift();
+ if (line != '') {
+ this.mods = line.split('#');
+ }
+
+ // Description
+ var dLines = parseInt(lines.shift(), 10);
+ for (var i = 0; i < dLines; i ++) {
+ this.description += (i > 0 ? "\n" : "") + lines.shift();
+ }
+
+ return this;
+ };
+
+ this.copyFrom = function (ori) {
+ this.id = ori.id;
+ this.isDeleted = ori.isDeleted;
+ this.deletedBy = ori.deletedBy;
+ this.deletedAt = ori.deletedAt;
+ this.accessMode = ori.accessMode;
+ this.topics = ori.topics;
+ this.name = ori.name;
+ this.description = ori.description
+
+ // Users
+ for (var i in ori.users) {
+ this.users.push(ori.users[i]);
+ }
+
+ // Moderators
+ for (var i in ori.mods) {
+ this.mods.push(ori.users[i]);
+ }
+
+ return this;
+ };
}
-function ForumACL(id,priv,name)
-{
+
+function ForumACL(id, priv, name) {
this.id = id;
this.priv = priv;
this.name = name;
this.selected = false;
}
+
function forumsReceived(data) {
if (amPage != 'FAdmin') {
return;
}
- faForums = new Array();
if (data.indexOf("ERR#") == 0) {
- alertForum(parseInt((data.split('#'))[1], 10));
- puTimer = setTimeout('x_getForums(forumsReceived)', 180000);
- return;
- } else if (data != "") {
- parseForumList(data);
+ var lines = data.split('\n');
+ var el = lines.shift();
+ data = lines.join('\n');
+
+ alertForum(parseInt((el.split('#'))[1], 10));
}
+ parseForumList(data);
if (!faEditing) {
drawForumList();
@@ -1292,15 +1354,19 @@
alertMaximumFCount();
forumEditCancel();
} else if (!faEditing.id) {
- if (faNewPos != -1 && !forumById(faNewPos))
+ if (faNewPos != -1 && !forumById(faNewPos)) {
faNewPos = -1;
+ }
updateFPosSelector();
} else if (faEditing.id) {
- var f = forumById(faEditing.id);
- if (!f) {
+ var f = forumById(faEditing.id);
+ if (!f || f.isDeleted) {
alertForumDeleted();
forumEditCancel();
- } else if (faOriginal.name != f.name || faOriginal.userPost != f.userPost || faOriginal.description != f.description) {
+ } else if (faOriginal.name != f.name
+ || faOriginal.accessMode != f.accessMode
+ || faOriginal.description != f.description) {
+
alertForumChanged();
updateFEditor();
} else {
@@ -1310,111 +1376,119 @@
puTimer = setTimeout('x_getForums(forumsReceived)', 180000);
}
-function parseForumList(data)
-{
- var dl = data.split('\n');
- var st = 0, i = 0, cf = 0;
- var a;
- while (i<dl.length)
- {
- if (st == 0)
- {
- a = dl[i].split('#');
- faForums[cf] = new AllianceForum(a.shift(),a.shift(),(a.shift()=="1"),a.join('#'),'');
- st = 1;
- i ++;
- }
- else if (st == 1)
- {
- if (dl[i].indexOf('+#') == 0)
- {
- a = dl[i].split('#');
- a.shift();
- a = a.join('#');
- if (faForums[cf].description != '')
- faForums[cf].description += '\n';
- faForums[cf].description += a;
- i++;
- }
- else
- {
- cf++;
- st = 0;
- }
- }
+function parseForumList(data) {
+ var lines = data.split('\n');
+ var fCount = parseInt(lines.shift(), 10);
+ var i;
+
+ faForums = new Array();
+ for (i = 0; i < fCount; i ++) {
+ faForums.push( new AllianceForum().parse(lines) );
+ }
+
+ var rCount = parseInt(lines.shift(), 10);
+ faRanks = { };
+ for (i = 0; i < rCount; i ++) {
+ var rLine = lines.shift().split('#');
+ faRanks['r' + rLine.shift()] = rLine.join('#');
}
- faForums.sort(new Function('a','b','return (a.order > b.order ? 1 : -1)'));
+ i = lines.shift();
+ faAdmins = (i == '') ? (new Array()) : i.split('#');
+
+ var pCount = parseInt(lines.shift(), 10);
+ faPlayers = { };
+ for (i = 0; i < pCount; i ++) {
+ var rLine = lines.shift().split('#');
+ faPlayers['p' + rLine.shift()] = rLine.join('#');
+ }
}
-function moveForum(id,up)
-{
+
+function moveForum(id, up) {
x_moveForum(id, up ? 1 : 0, forumsReceived);
}
-function forumById(id)
-{
- var i;
- for (i=0;i<faForums.length&&faForums[i].id!=id;i++)
- ;
- return (i==faForums.length) ? false : faForums[i];
+function forumById(id) {
+ var i;
+ for (i = 0 ; i < faForums.length && faForums[i].id != id; i ++) ;
+ return (i==faForums.length) ? false : faForums[i];
}
-function deleteForum(id)
-{
- var f = forumById(id);
- if (!(f && confirmDeleteForum(f.name)))
+function deleteForum(id) {
+ var f = forumById(id);
+ if (!(f && confirmDeleteForum(f))) {
return;
+ }
x_delForum(id, forumsReceived);
}
-function createForum()
-{
- faEditing = new AllianceForum(false,false,true,'','');
- if (faForums.length)
+function restoreForum(id) {
+ var f = forumById(id);
+ if (!f) {
+ return;
+ }
+ x_restoreForum(id, forumsReceived);
+}
+
+function createForum() {
+ faEditing = new AllianceForum();
+ if (faForums.length) {
faNewPos = faForums[faForums.length - 1].id;
- else
+ } else {
faNewPos = -1;
+ }
displayForumEditor();
}
-function editForum(id)
-{
- var f = forumById(id);
- if (!f)
+function editForum(id) {
+ var f = forumById(id);
+ if (!f) {
return;
- faEditing = new AllianceForum(id,f.order,f.userPost,f.name,f.description);
- faOriginal = new AllianceForum(id,f.order,f.userPost,f.name,f.description);
+ }
+ faEditing = new AllianceForum().copyFrom(f);
+ faOriginal = f;
displayForumEditor();
}
-function displayForumEditor()
-{
+function displayForumEditor() {
document.getElementById('crforum').innerHTML = '';
+ computeForumACL();
drawForumEditor();
- x_getForumAcl(faEditing.id ? faEditing.id : '', forumAclReceived);
}
-function forumAclReceived(data)
-{
+function computeForumACL() {
+ var feUsers, feMods, feAdmins;
+ feUsers = '#' + faEditing.users.join('##') + '#';
+ feMods = '#' + faEditing.mods.join('##') + '#';
+ feAdmins = '#' + faAdmins.join('##') + '#';
+
faAccess = new Array();
- if (data != "")
- {
- var i, l = data.split('\n');
- for (i=0;i<l.length;i++)
- {
- var a = l[i].split('#');
- faAccess.push(new ForumACL(a.shift(), a.shift(), a.join('#')));
+ for (var i in faRanks) {
+ var rId = i.substr(1, i.length - 1);
+ var rn = faRanks[i];
+ var pr;
+
+ if (feUsers.indexOf('#' + rId + '#') != -1) {
+ pr = 1;
+ } else if (feMods.indexOf('#' + rId + '#') != -1) {
+ pr = 2;
+ } else if (feAdmins.indexOf('#' + rId + '#') != -1) {
+ pr = 3;
+ } else {
+ pr = 0;
}
- faAccess.sort(new Function('a','b','return a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1'));
+ faAccess.push(new ForumACL(rId, pr, rn));
}
- if (faEditing.id)
+ faAccess.sort(new Function('a','b','return a.name.toLowerCase() > b.name.toLowerCase() ? 1 : -1'));
+
+ if (faEditing.id) {
faOriACL = makeForumACLString();
- drawFAccessManager();
- updateFEditor();
+ }
}
+
function setFAccessLevel(level)
{
var i,cc=0;
@@ -1432,33 +1506,36 @@
}
}
-function updateFEditor()
-{
- var ok, i;
+function updateFEditor() {
+ var ok, i;
ok = (faEditing.name.length >= 4);
- if (faEditing.id)
+ if (faEditing.id) {
ok = ok && (
faEditing.name != faOriginal.name || faEditing.description != faOriginal.description
- || faEditing.userPost != faOriginal.userPost || faOriACL != makeForumACLString()
+ || faEditing.accessMode != faOriginal.accessMode || faOriACL != makeForumACLString()
);
+ }
document.getElementById('feok').disabled = !ok;
}
-function makeForumACLString()
-{
- var a = new Array(), i;
- for (i=0;i<faAccess.length;i++)
- if (faAccess[i].priv != 3 && faAccess[i].priv != 0)
+function makeForumACLString() {
+ var a = new Array(), i;
+ for (i = 0; i < faAccess.length; i ++) {
+ if (faAccess[i].priv != 3 && faAccess[i].priv != 0) {
a.push(faAccess[i].id + '!' + faAccess[i].priv);
- return a.join('#');
+ }
+ }
+ return a.join('#');
}
-function forumEditOk()
-{
- if (faEditing.id)
- x_changeForum(faEditing.id, faEditing.name, faEditing.userPost ? 1 : 0, faEditing.description, makeForumACLString(), forumEditCallback);
- else
- x_newForum(faEditing.name, faEditing.userPost ? 1 : 0, faNewPos, faEditing.description, makeForumACLString(), forumEditCallback);
+function forumEditOk() {
+ if (faEditing.id) {
+ x_changeForum( faEditing.id, faEditing.name, faEditing.accessMode, faEditing.description,
+ makeForumACLString(), forumEditCallback );
+ } else {
+ x_newForum( faEditing.name, faEditing.accessMode, faNewPos, faEditing.description,
+ makeForumACLString(), forumEditCallback );
+ }
}
function forumEditCancel()
diff -Naur beta5//site/static/beta5/js/pg_comms-en.js forums//site/static/beta5/js/pg_comms-en.js
--- beta5//site/static/beta5/js/pg_comms-en.js 2011-02-05 10:09:56.434335002 +0100
+++ forums//site/static/beta5/js/pg_comms-en.js 2011-02-05 10:10:02.214335002 +0100
@@ -28,13 +28,15 @@
return str;
}
-function makeTopicsText(tot, n)
-{
- if (tot == 0)
- return "empty forum";
- var str = '<b>' + formatNumber(tot) + '</b> topic' + (tot > 1 ? 's' : '');
- if (n == 0)
- return str;
- str += ' (<b>' + formatNumber(n) + '</b> unread)';
- return str;
+function makeTopicsText(tot, n) {
+ if (tot == 0) {
+ return "empty forum";
+ }
+
+ var str = '<b>' + formatNumber(tot.toString()) + '</b> topic' + (tot > 1 ? 's' : '');
+ if (n == 0) {
+ return str;
+ }
+ str += ' (<b>' + formatNumber(n.toString()) + '</b> unread)';
+ return str;
}
diff -Naur beta5//site/static/beta5/js/pg_comms.js forums//site/static/beta5/js/pg_comms.js
--- beta5//site/static/beta5/js/pg_comms.js 2011-02-05 10:09:56.434335002 +0100
+++ forums//site/static/beta5/js/pg_comms.js 2011-03-12 15:09:43.961300049 +0100
@@ -12,20 +12,40 @@
this.name = name;
}
-function Category(id, type, name)
-{
- this.id = id;
- this.type = type;
- this.name = name;
- this.forums = new Array();
-}
-function Forum(id, nTopics, nUnread, name)
-{
- this.id = id;
- this.nTopics = nTopics;
- this.nUnread = nUnread;
- this.name = name;
+
+function ForumsEntity(inputData) {
+ var iLine = inputData.shift().split('#');
+ var nElements;
+
+ this.type = iLine.shift();
+ this.id = iLine.shift();
+ nElements = parseInt(iLine.shift(), 10);
+ this.topics = parseInt(iLine.shift(), 10);
+ this.unread = parseInt(iLine.shift(), 10);
+ this.name = inputData.shift();
+ this.contents = new Array();
+ this.output = function (depth) {
+ var str = '';
+
+ if (this.id != '/') {
+ for (var i = 0; i < depth; i++) {
+ str += '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
+ }
+ str += '<a href="forums?cmd=V%23' + this.type + '%23' + this.id + '">' + this.name + '</a>: '
+ + makeTopicsText(this.topics, this.unread);
+ }
+
+ for (var i = 0; i < this.contents.length; i ++) {
+ str += '<br/>' + this.contents[i].output(depth + 1);
+ }
+
+ return str;
+ };
+
+ for (var i = 0; i < nElements; i ++) {
+ this.contents.push( new ForumsEntity(inputData) );
+ }
}
@@ -35,110 +55,55 @@
}
-function commsDataReceived(data)
-{
- var i, l = data.split('\n');
- var a = l.shift().split('#');
- var nCustom = parseInt(a[0],10), nGenCats = parseInt(a[1],10), nAForums = parseInt(a[2],10);
+function commsDataReceived(data) {
+ var i, a, nCustom;
+ var l = data.split('\n');
// Default folders
dFolders = new Array();
- for (i=0;i<3;i++)
- {
+ for (i=0;i<3;i++) {
a = l.shift().split('#');
dFolders.push(new Folder('', a[0], a[1], ''));
}
// Custom folders
+ nCustom = parseInt(l.shift(), 10);
cFolders = new Array();
- for (i=0;i<nCustom;i++)
- {
+ for (i=0;i<nCustom;i++) {
a = l.shift().split('#');
cFolders.push(new Folder(a.shift(), a.shift(), a.shift(), a.join('#')));
}
// General categories & forums
- genForums = new Array();
- for (i=0;i<nGenCats;i++)
- {
- a = l.shift().split('#');
-
- var j,c,id,tp,nForums;
- id = a.shift(); tp = a.shift();
- nForums = parseInt(a.shift(), 10);
- c = new Category(id, tp, a.join('#'));
-
- for (j=0;j<nForums;j++)
- {
- a = l.shift().split('#');
- c.forums.push(new Forum(a.shift(),a.shift(),a.shift(),a.join('#')));
- }
-
- genForums.push(c);
- }
-
- // Alliance forums
- aForums = new Array();
- for (i=0;i<nAForums;i++)
- {
- a = l.shift().split('#');
- aForums.push(new Forum(a.shift(),a.shift(),a.shift(),a.join('#')));
- }
+ forums = new ForumsEntity(l);
drawCommsPage();
setTimeout('x_getCommsData(commsDataReceived)', 30000);
}
-function drawCommsPage()
-{
- var i, j, a;
+function drawCommsPage() {
+ var i, j, a;
// Default folders
- for (i=0;i<3;i++)
+ for (i=0;i<3;i++) {
document.getElementById('msg' + i).innerHTML = makeMessagesText(dFolders[i].tMsg, dFolders[i].nMsg);
+ }
// Custom folders
- if (cFolders.length == 0)
+ if (cFolders.length == 0) {
document.getElementById('cflist').innerHTML = noCustomFolders;
- else
- {
+ } else {
a = new Array();
- for (i=0;i<cFolders.length;i++)
- {
- var s = '<a href="message?a=f&f=C&cf=' + cFolders[i].id;
- s += '" ' + comtt[0] + ' >' + cFolders[i].name + '</a>: ' + makeMessagesText(cFolders[i].tMsg, cFolders[i].nMsg);
+ for (i=0;i<cFolders.length;i++) {
+ var s = '<a href="message?a=f&f=C&cf=' + cFolders[i].id;
+ s += '" ' + comtt[0] + ' >' + cFolders[i].name + '</a>: '
+ + makeMessagesText(cFolders[i].tMsg, cFolders[i].nMsg);
a.push(s);
}
document.getElementById('cflist').innerHTML = a.join('<br/>') + '<br/>';
}
- // General forums
- a = new Array();
- for (i=0;i<genForums.length;i++)
- {with(genForums[i]){
- var s = '<a href="forums?cmd=C%23G%23' + id + '" ' + comtt[1] + ' >' + name + '</a>';
- for (j=0;j<forums.length;j++)
- {
- s += '<br/>&nbsp;&nbsp;-&nbsp;<a href="forums?cmd=F%23' + type + '%23' + forums[j].id + '" ' + comtt[2] + ' >' + forums[j].name + '</a>: ';
- s += makeTopicsText(forums[j].nTopics, forums[j].nUnread);
- }
- a.push(s);
- }}
- document.getElementById('gforums').innerHTML = a.join('<br/><br/>');
-
- // Alliance forums
- if (aForums.length == 0)
- document.getElementById('aforums').innerHTML = '&nbsp;';
- else
- {
- a = new Array();
- for (j=0;j<aForums.length;j++)
- {
- s = '&nbsp;&nbsp;-&nbsp;<a href="forums?cmd=F%23A%23' + aForums[j].id + '" ' + comtt[3] + ' >' + aForums[j].name + '</a>: ';
- s += makeTopicsText(aForums[j].nTopics, aForums[j].nUnread);
- a.push(s);
- }
- document.getElementById('aforums').innerHTML = '<h2>' + allianceForums + '</h2><p>' + a.join('<br/>') + '</p>';
- }
+ // Forums
+ document.getElementById('forums').innerHTML = '<p>' + forums.output(-1) + '</p>';
}
diff -Naur beta5//site/static/beta5/js/pg_forums-en.js forums//site/static/beta5/js/pg_forums-en.js
--- beta5//site/static/beta5/js/pg_forums-en.js 2011-02-05 10:09:56.434335002 +0100
+++ forums//site/static/beta5/js/pg_forums-en.js 2011-02-05 10:10:02.214335002 +0100
@@ -1,53 +1,98 @@
-function confirmDelete()
-{
- var i = countSelected();
- if (i == 0)
- {
- alert('Please select the topic(s) you want to delete.');
- return false;
- }
- return confirm('Please confirm you want to delete ' + (i > 1 ? ('these ' + i + ' topics') : 'this topic') + '.');
-}
-
-function confirmSticky()
-{
- var i = countSelected();
- if (i == 0)
- {
- alert('Please select the topic(s) you want to switch to/from sticky.');
- return false;
- }
- return confirm('Please confirm you want to switch ' + (i > 1 ? ('these ' + i + ' topics') : 'this topic') + ' to/from sticky.');
-}
-
-function confirmMove()
-{
- var i = countSelected();
- if (i == 0)
- {
- alert('Please select the topic(s) you want to move.');
- return false;
- }
-
- var e = document.getElementById('mdest');
- if (e.options[e.selectedIndex].value == '')
- {
- alert('Please select the forum to which the topic'+(i>1?'s':'')+' must be moved.');
- return false;
- }
-
- return confirm(
- 'Please confirm you want to move the selected topic' + (i>1?'s':'') + '\nto the "'
- + e.options[e.selectedIndex].text + '" forum.'
- );
-}
-
-function confirmDTopic()
-{
- return confirm('Deleting this post will delete the whole topic. Please confirm.');
-}
-
-function confirmDPost()
-{
- return confirm('Please confirm you want to delete this post.');
-}
+/* Text for menu commands */
+MenuItem.commandText = {
+ overview: "Overview",
+ latest: "Latest messages",
+ search: "Search forums"
+};
+
+/* Overview pseudo-category title & description */
+CategoryView.ovTitle = "Forums overview";
+CategoryView.ovDescription = "This page gives you a global view of all of the forums you have access to.";
+
+/* Text for layout-level commands */
+ForumsLayout.menuText = ['S','h','o','w','&nbsp;','m','e','n','u'];
+ForumsLayout.hideMenu = "Hide";
+ForumsLayout.menuTitle = "Forums";
+
+/* Text for the category view */
+CategoryView.empty = 'There are no forums in this category.';
+CategoryView.headers = {
+ name: 'Forum name',
+ topics: 'Topics',
+ posts: 'Posts',
+ lastPost: 'Last modification'
+};
+CategoryView.forumIcon = {
+ read: "This forums's topics have been read",
+ unread: "Some topics in this forum haven't been read"
+};
+CategoryView.deletedAt = "Forum deleted at ";
+CategoryView.by = " by ";
+CategoryView.noPosts = 'Empty forum';
+CategoryView.markRead = 'Mark forums as read';
+
+/* Text for the forum view */
+ForumView.markRead = 'Mark topics as read';
+ForumView.adminsHdr = 'Administrators';
+ForumView.modsHdr = 'Moderators';
+ForumView.usersHdr = 'Users';
+ForumView.empty = 'There are no topics in this forum.';
+ForumView.details = ' More details ... ';
+ForumView.showDetails = 'Show details';
+ForumView.hideDetails = 'Hide details';
+ForumView.displayOptions = 'Display options';
+ForumView.newTopic = 'New topic';
+ForumView.modTools = 'Moderation tools';
+ForumView.previousPage = 'Previous page';
+ForumView.nextPage = 'Next page';
+ForumView.pageSelHdr = 'Jump to page ';
+ForumView.headers = {
+ topic: 'Topic',
+ replies: 'Replies',
+ fPost: 'First post',
+ lPost: 'Last update'
+};
+ForumView.movedTo = 'Moved to ';
+ForumView.applyTo = 'Apply to ';
+ForumView.thisForum = 'this forum';
+ForumView.allForums = 'all forums';
+ForumView.perPage = 'Topics / page:';
+ForumView.ok = 'Ok';
+ForumView.cancel = 'Cancel';
+ForumView.displayDeleted = 'Display deleted topics:';
+ForumView.deletedAt = 'Topic deleted at ';
+ForumView.hideModTools = 'Hide moderation tools';
+ForumView.pleaseSelect = 'Please select at least one topic.';
+ForumView.deletedTopics = 'Deleted topics: ';
+ForumView.restoreTopics = 'restore';
+ForumView.selectedTopics = 'Selected topics: ';
+ForumView.deleteTopics = 'delete';
+ForumView.stickyLevel = 'sticky level: ';
+ForumView.decreaseStickyLevel = 'decrease';
+ForumView.increaseStickyLevel = 'increase';
+ForumView.setTo = 'set to ';
+ForumView.normalPost = 'not sticky';
+ForumView.lock = 'lock';
+ForumView.unlock = 'unlock';
+ForumView.moveTo = 'Move topics to ';
+
+
+/* Topic view: topic not found */
+TopicView.notFound = {
+ title: "Topic not found",
+ text: "The topic you were looking for is unavailable, either because it doesn't exist anymore or "
+ + "because you don't have access to the forum it is in."
+};
+/* Topic view: deleted topic */
+TopicView.deleted = {
+ header: "This topic was deleted at ",
+ by: " by "
+};
+/* Topic view: show / hide post contents */
+TopicView.close = "Hide post contents";
+TopicView.open = "Show post contents";
+/* Topic view, misc text */
+TopicView.posted = "Posted ";
+TopicView.loading = "Loading, please wait ...";
+TopicView.loadError = "An error occurred while loading this post :-(";
+TopicView.edited = "Edited at ";
diff -Naur beta5//site/static/beta5/js/pg_forums.js forums//site/static/beta5/js/pg_forums.js
--- beta5//site/static/beta5/js/pg_forums.js 2011-02-05 10:09:56.434335002 +0100
+++ forums//site/static/beta5/js/pg_forums.js 2011-02-05 10:10:02.204335002 +0100
@@ -1,10 +1,1607 @@
-function countSelected()
-{
- var n = 0, i = 0, e;
- while (e = document.getElementById('msel' + i))
- {
- n += e.checked ? 1 : 0;
- i++;
+var pageContents;
+var useGIFs;
+
+
+MenuItem = function (lines) {
+
+ // Parse the data
+ var fields = lines.shift().split('#');
+
+ this.isNode = (fields.shift() == 'N');
+ this.isCommand = (fields.shift() == 'C');
+ this.unread = parseInt(fields.shift(), 10);
+ this.isOpen = this.isNode ? (fields.shift() == '1') : false;
+ this.id = this.isNode ? fields.shift() : null;
+ this.cmdLink = lines.shift();
+ this.text = lines.shift();
+ this.entries = (this.isNode && this.isOpen) ? (new Array()) : null;
+
+ if (this.isCommand) {
+ this.text = MenuItem.commandText[this.text];
}
- return n;
-}
+
+ // Add menu entries
+ while (this.isNode && this.isOpen && lines[0] != 'E') {
+ if (lines[0] == 'S') {
+ // Separators
+ this.entries.push(null);
+ lines.shift();
+ } else {
+ // Entries
+ this.entries.push(new MenuItem(lines));
+ }
+ }
+ if (this.isNode && this.isOpen) {
+ lines.shift();
+ }
+
+ this.draw = function (output, depth) {
+ var rd = (typeof depth == 'undefined') ? -1 : depth;
+
+ var cst = ' style="margin: 0px; padding: 0px; border-width: 0px; vertical-align: middle"';
+ var tst = ' style="width: 100%; margin: 0px; padding: 0px; border-width: 0px"';
+ var smallCell = '<td style="width: 16px; margin: 0px; padding: 0px; border-width: 0px">';
+ var str = '<tr><td' + cst + '><table' + tst + '><tr>';
+
+ if (depth > 0) {
+ for (var i = 0; i < depth; i ++) {
+ str += smallCell + '&nbsp;</td>';
+ }
+ }
+
+ // 'Open'/'Close' command for submenus or empty cell
+ str += smallCell;
+ if (depth > -1 && this.isNode) {
+ if (this.isOpen) {
+ str += '<a href="#" onClick="main.menuClose(\'' + this.id + '\'); return false">-</a>';
+ } else {
+ str += '<a href="#" onClick="main.menuOpen(\'' + this.id + '\'); return false">+</a>';
+ }
+ } else {
+ str += '&nbsp;';
+ }
+ str += '</td>';
+
+ // Menu entry's text
+ str += '<td' + cst + '><a href="?cmd=' + this.cmdLink.replace(/#/g, '%23')
+ + '" style="text-decoration:none;font-style: normal">'
+ + (MenuItem.current == this.cmdLink ? '<em><u>' : '')
+ + ((this.unread > 0 && ! (this.isNode && this.isOpen)) ? '<b>' : '')
+ + this.text
+ + ((this.unread > 0 && ! (this.isNode && this.isOpen)) ? (' (' + this.unread + ')</b>') : '')
+ + (MenuItem.current == this.cmdLink ? '</u></em>' : '')
+ + '</a></td></tr></table></td></tr>';
+
+ // Output this line
+ output.push(str);
+
+ // Submenus
+ var sepPrev = false;
+ for (var i in this.entries) {
+ var e = this.entries[i];
+ if (e) {
+ if (e.isNode && e.isOpen && !sepPrev) {
+ output.push('<tr><td' + cst + '>&nbsp;</td></tr>');
+ }
+ e.draw(output, rd + 1);
+ if (e.isNode && e.isOpen) {
+ output.push('<tr><td' + cst + '>&nbsp;</td></tr>');
+ sepPrev = true;
+ } else {
+ sepPrev = false;
+ }
+ } else if (!sepPrev) {
+ output.push('<tr><td' + cst + '>&nbsp;</td></tr>');
+ sepPrev = true;
+ }
+ }
+ };
+};
+
+
+function parseNames( lines ) {
+ var line, cnt;
+ var res = { };
+
+ cnt = parseInt( lines.shift(), 10 );
+ for (var i = 0; i < cnt; i ++) {
+ line = lines.shift().split('#');
+ res[line[0]] = line[1];
+ }
+
+ return res;
+};
+
+
+TopicView = function () {
+
+ var me = this;
+ var tst = ' style="width: 100%; margin: 0px; padding: 0px; border-width: 0px"';
+ var cst = ' style="margin: 0px; padding: 0px; border-width: 0px; vertical-align: middle';
+
+ var pageUpdater = null;
+ var pageMD5 = null;
+ var topicId = null;
+ var locked = false;
+ var parents = [];
+ var posts = [];
+ var pOrder = {
+ ln: null,
+ lo: null,
+ tn: null,
+ to: null
+ };
+ var opts = {
+ perPage: 50,
+ vDeleted: false,
+ threaded: false,
+ order: false,
+ openPosts: 1
+ };
+ var title;
+ var topicStatus;
+ var currentUser;
+ var isMod;
+ var canPost;
+ var hasPoll;
+ var users;
+ var nPages;
+ var cPage;
+ var queue;
+
+ var parseInitialContents, displayNotFound, displayDeleted, displayTopicLayout, drawPageChanger,
+ displayPage, initLoaderQueue, loadPost, postLoaded;
+
+ parseInitialContents = function (data) {
+ var line = data.shift();
+
+ if (line == 'MEH') {
+ displayNotFound();
+ return false;
+ }
+
+ if (line.indexOf('DELETED#') == 0) {
+ var deletedAt, nParents;
+ line = line.split('#');
+ deletedAt = line[1];
+ nParents = parseInt(line[2], 10);
+ displayDeleted(data, deletedAt, nParents);
+ return false;
+ }
+
+ line = line.split('#');
+ var nParents = parseInt(line[1], 10);
+
+ title = data.shift();
+ line = data.shift().split('#');
+ currentUser = line.shift();
+ isMod = (line.shift() == 1);
+ canPost = (line.shift() == 1);
+ hasPoll = (line.shift() == 1);
+
+ for (var i = 0; i < nParents; i ++) {
+ line = data.shift().split('#');
+ parents.push({
+ id: line.shift(),
+ name: line.join('')
+ });
+ }
+
+ pOrder.ln = data.shift().split('#');
+ pOrder.lo = data.shift().split('#');
+ pOrder.tn = data.shift().split('#');
+ pOrder.to = data.shift().split('#');
+
+ for (var i = 0; i < pOrder.ln.length; i ++) {
+ var p = { };
+ line = data.shift().split('#');
+ p.id = line.shift();
+ p.depth = parseInt(line.shift(), 10);
+ p.author = line.shift();
+ p.postedAt = line.shift();
+ p.unread = (line.shift() == 1);
+ p.lcTime = line.shift();
+ p.lcAuthor = line.shift();
+ p.title = data.shift();
+ p.loading = false;
+ posts[p.id] = p;
+ }
+
+ users = parseNames( data );
+
+ line = data.shift().split('#');
+ opts.perPage = parseInt(line.shift(), 10);
+ opts.vDeleted = (line.shift() == 1);
+ opts.threaded = (line.shift() == 1);
+ opts.order = (line.shift() == 1);
+ opts.openPosts = parseInt(line.shift(), 10);
+
+ for (var i in posts) {
+ switch (opts.openPosts) {
+ case 0: posts[i].open = false;
+ break;
+ case 1: posts[i].open = posts[i].unread;
+ break;
+ case 2: posts[i].open = true;
+ break;
+ }
+ }
+
+ initLoaderQueue();
+
+ var m = pOrder.ln.length % opts.perPage;
+ nPages = (pOrder.ln.length - m) / opts.perPage + (m ? 1 : 0);
+ cPage = 0;
+ displayTopicLayout();
+ };
+
+ displayNotFound = function () {
+ document.getElementById('f-page').innerHTML = '<h1>' + TopicView.notFound.title + '</h1><p>'
+ + TopicView.notFound.text + '</p>';
+ };
+
+ displayDeleted = function (data, deletedAt, nParents) {
+ var str = '<div style="padding: 0px 0px 5px 5px">'
+ + '<h1 style="padding: 0px">' + data.shift() + '</h1>';
+ for (var i = 0; i < nParents; i ++) {
+ var l = data.shift().split('#');
+ var pid = l.shift();
+
+ str += (i > 0 ? ' &gt; ' : '') + '<a href="?cmd=V%23' + (i == nParents - 1 ? 'F' : 'C')
+ + '%23' + pid + '">' + (pid == '/' ? ForumsLayout.menuTitle : l.join('')) + '</a>';
+ }
+ str += '</div><p>' + TopicView.deleted.header + '<b>' + formatDate(deletedAt)
+ + '</b>' + TopicView.deleted.by + '<b>'
+ + 'some guy (FIXME)' + '</b>.</p>';
+ document.getElementById('f-page').innerHTML = str;
+ };
+
+ displayTopicLayout = function () {
+ var str = '<div style="padding: 0px 0px 0px 5px"><h1 style="padding: 0px">'
+ + title + '</h1>';
+ for (var i in parents) {
+ str += (i > 0 ? ' &gt; ' : '') + '<a href="?cmd=V%23' + (i == parents.length - 1 ? 'F' : 'C')
+ + '%23' + parents[i].id + '">'
+ + (parents[i].id == '/' ? ForumsLayout.menuTitle : parents[i].name) + '</a>';
+ }
+
+ str += '<table style="width: 100%; margin: 10px 0px 0px 0px; padding: 0px; border-width: 0px"><tr>';
+ str += drawPageChanger();
+
+ // FIXME: display tools
+
+ if (hasPoll) {
+ // FIXME: display poll
+ }
+
+ str += '<tr><td colspan="3"' + cst + '" id="topics-display">&nbsp;</td></tr>';
+ str += drawPageChanger();
+ str += '</table>';
+
+ document.getElementById('f-page').innerHTML = str;
+ displayPage();
+ };
+
+ drawPageChanger = function () {
+ if (nPages > 1) {
+ var st = 'border-width: 0px; margin: 0px; vertical-align: middle; ';
+ var str = '<tr><td style="' + st + 'padding: 5px 0px 0px 0px; text-align:left; width: 33%">'
+ + (cPage > 0 ? '<a href="#" onClick="pageContents.prevPage(); return false">' : '')
+ + '&lt;-- ' + ForumView.previousPage + (cPage > 0 ? '</a>' : '')
+ + '</td><td style="' + st + 'padding: 5px 0px 0px 0px; text-align:center">'
+ + '<form style="' + st + 'padding: 0px; ">' + ForumView.pageSelHdr
+ + '<select onChange="pageContents.jumpToPage(options[selectedIndex].value)">';
+ for (var i = 0; i < nPages; i ++) {
+ str += '<option ' + (i == cPage ? 'selected="selected" ' : '') + 'value="'
+ + i + '">' + (i + 1) + '</option>';
+ }
+ str += '</select></form></td><td style="' + st
+ + '; padding: 5px 0px 0px 0px; text-align: right; width: 33%">'
+ + ((cPage<nPages-1) ? '<a href="#" onClick="pageContents.nextPage(); return false">' : '')
+ + ForumView.nextPage + '--&gt;' + ((cPage<nPages-1) ? '</a>' : '') + '</td></tr>';
+ return str;
+ }
+ return '';
+ };
+
+ displayPage = function () {
+ var low = cPage * opts.perPage;
+ var high = Math.min(low + opts.perPage, pOrder.ln.length);
+ var str = '\n\n<table' + tst + '>';
+ var order;
+
+ if (opts.threaded) {
+ order = opts.order ? pOrder.to : pOrder.tn;
+ } else {
+ order = opts.order ? pOrder.lo : pOrder.ln;
+ }
+
+ for (var i = low; i < high; i ++) {
+ var post = posts[order[i]];
+ str += '\n<tr><td' + cst + '"><table' + tst + '><tr>';
+ if (opts.threaded && post.depth > 0) {
+ var sz = post.depth * 10;
+ str += '<td style="width: ' + sz + 'px; padding: 0px; margin: 0px">&nbsp;</td>';
+ }
+ str += '<td style="padding: 0px; margin: 0px" id="tp-post-' + post.id
+ + '">&nbsp</td></tr></table></td></tr>';
+ }
+ document.getElementById('topics-display').innerHTML = str + '\n</table>';
+
+ displayPosts();
+ };
+
+ displayPosts = function () {
+ for (var i in posts) {
+ var post = posts[i];
+ var el = document.getElementById("tp-post-" + post.id);
+ if (el) {
+ el.innerHTML = displayPost(post);
+ }
+ }
+ };
+
+ displayPost = function (post) {
+ var color = post.unread ? '#FFFFFF' : '#5F5F5F';
+ var margin = post.open ? (post.depth == 0 ? '0px 0px 10px 0px' : '10px 0px') : '0px';
+ var onClick = ' onClick="pageContents.togglePost(' + post.id + ')"';
+ var str = '<table style="width: 100%; margin: ' + margin + '; padding: 0px;border-collapse: '
+ + 'collapse; border: 1px solid ' + color + '"><tr><td rowspan="2" style="'
+ + 'width: 32px; border: 1px solid ' + color + '; padding: 0px;'
+ + 'vertical-align: middle"' + onClick + '><img src="' + staticurl
+ + '/beta5/pics/post_' + (post.open ? 'o' : 'c') + (post.unread ? 'n' : 'o')
+ + '.gif" alt="' + (post.open ? TopicView.close : TopicView.open) + '" /></td>'
+ + '<th style="padding: 1px; text-align: left; border: 1px solid ' + color + '"' + onClick + '>'
+ + post.title + '</th></tr><tr><td style="padding: 1px; border: 1px solid ' + color + '"'
+ + onClick + '>' + TopicView.posted + '<b>' + formatDate(post.postedAt) + '</b>'
+ + CategoryView.by + '<b>' + users[post.author] + '</b></td></tr>';
+
+ if (post.open) {
+ str += '<tr><td style="padding: 10px 5px; border: 1px solid ' + color + '" colspan="2"'
+ + ' id="post-contents-' + post.id + '">'
+ + (post.loaded ? post.contents :
+ ('<p style="padding: 0px 5px"><i>' + TopicView.loading + '</i></p>'))
+ + '</td></tr>';
+ if (post.lcTime != post.postedAt) {
+ str += '<tr><td style="padding: 1px 5px; border: 1px solid ' + color
+ + '; text-align: right" colspan="2"><i>' + TopicView.edited
+ + formatDate(post.lcTime) + CategoryView.by + '<b>'
+ + users[post.lcAuthor] + '</b></i></td></tr>';
+ }
+ }
+
+ return str + '</tr></table>';
+ };
+
+ initLoaderQueue = function () {
+ var order;
+
+ if (opts.threaded) {
+ order = opts.order ? pOrder.to : pOrder.tn;
+ } else {
+ order = opts.order ? pOrder.lo : pOrder.ln;
+ }
+
+ var openPosts = [], fpPosts = [], rest = [];
+ for (var i in order) {
+ var post = posts[order[i]];
+ if (post.open) {
+ openPosts.push(post);
+ } else if (i < opts.perPage) {
+ fpPosts.push(post);
+ } else {
+ rest.push(post);
+ }
+ }
+
+ queue = openPosts.concat(fpPosts.concat(rest));
+ loadPost();
+ };
+
+ postLoaded = function (data) {
+ if (queue.length == 0) {
+ return;
+ }
+
+ if (data.indexOf('-#') == 0) {
+ data = data.split('#');
+ if (queue[0].id != data[1]) {
+ loadPost();
+ return;
+ }
+ queue[0].loading = false;
+ queue[0].contents = '<p style="padding: 10px"><i>' + TopicView.loadError + '</i></p>';
+ } else {
+ data = data.split('\n');
+ var l = data.shift().split('#');
+ if (queue[0].id != l[1]) {
+ loadPost();
+ return;
+ }
+ queue[0].loading = false;
+ queue[0].contents = data.join('\n');
+ }
+ queue[0].loaded = true;
+
+ var el = document.getElementById("tp-post-" + queue[0].id);
+ if (el) {
+ el.innerHTML = displayPost(queue[0]);
+ }
+
+ queue.shift();
+ loadPost();
+ };
+
+ loadPost = function () {
+ if (queue.length == 0 || queue[0].loading) {
+ return;
+ }
+
+ queue[0].loading = true;
+ x_loadPostContents(topicId, pageMD5, queue[0].id, function (data) {
+ postLoaded(data);
+ });
+ };
+
+ this.parse = function (data) {
+ if (data.indexOf('\n') == -1) {
+ // IE, first update
+ data = data.split('#');
+ topicId = data.shift();
+ pageMD5 = data.shift();
+ this.update();
+ return;
+ }
+
+ data = data.split('\n');
+ var l = data.shift().split('#');
+ topicId = l.shift();
+ pageMD5 = l.shift();
+ if (parseInitialContents(data)) {
+ pageUpdater = window.setTimeout("pageContents.update()", 10000);
+ }
+ locked = false;
+ };
+
+ this.update = function () {
+ if (locked) {
+ return;
+ }
+ pageUpdater = null;
+ locked = true;
+ x_getTopic(topicId, pageMD5, function (data) { pageContents.parse(data); });
+ };
+
+ this.togglePost = function (postId) {
+ var post = posts[postId];
+ post.open = ! post.open;
+ var el = document.getElementById("tp-post-" + post.id);
+ if (el) {
+ el.innerHTML = displayPost(post);
+ }
+ };
+
+ this.setFieldValues = function () { };
+};
+
+
+ForumView = function () {
+ var me = this;
+
+ var pageUpdater = null;
+ var locked = false;
+ var pageMD5 = null;
+ var viewId = null;
+ var players = [];
+
+ var nPages = 0;
+ var cPage = -1;
+ var perPage = 10;
+
+ var topics = [];
+ var isMod = false;
+ var canPost = false;
+ var vDeleted = false;
+ var unread = false;
+ var admins = null;
+ var mods = null;
+ var users = null;
+ var hasMoveTargets = false;
+ var moveTargets = {};
+ var description = '';
+ var title = '';
+ var parents = null;
+
+ var showDetails = false;
+ var showModTools = false;
+ var modSelAll = false;
+ var showOptions = false;
+ var options = { };
+ var modTools = { };
+ var selTopicsStr = '';
+
+ var mainParser, parseTopic, displayContents, drawControls, drawModTools, setFieldValues, getSelectedTopics;
+
+ mainParser = function (lines) {
+ var line = lines.shift().split('#');
+ var nt, ndl, npe, na, nm, nu, nmt;
+
+ forumId = line.shift();
+ nt = parseInt(line.shift(), 10);
+ unread = (line.shift() == '1');
+ isMod = (line.shift() == '1');
+ canPost = (line.shift() == '1');
+ perPage = parseInt(line.shift(), 10);
+ vDeleted = (line.shift() == '1');
+ ndl = parseInt(line.shift(), 10);
+ npe = parseInt(line.shift(), 10);
+ na = parseInt(line.shift(), 10);
+ nm = parseInt(line.shift(), 10);
+ nu = parseInt(line.shift(), 10);
+ nmt = isMod ? parseInt(line.shift(), 10) : 0;
+ hasMoveTargets = (nmt > 0);
+ title = lines.shift();
+
+ var dc = new Array();
+ for (var i = 0; i < ndl; i ++) {
+ dc.push(lines.shift());
+ }
+ description = dc.join('<br/>');
+
+ parents = new Array();
+ for (var i = 0; i < npe; i ++) {
+ line = lines.shift().split('#');
+ parents.push({
+ id: line.shift(),
+ name: line.join('#')
+ });
+ }
+
+ admins = new Array();
+ for (var i = 0; i < na; i ++) {
+ admins.push(lines.shift());
+ }
+ mods = new Array();
+ for (var i = 0; i < nm; i ++) {
+ mods.push(lines.shift());
+ }
+ users = new Array();
+ for (var i = 0; i < nu; i ++) {
+ users.push(lines.shift());
+ }
+
+ moveTargets = {};
+ for (var i = 0; i < nmt; i ++) {
+ line = lines.shift().split('#');
+ var ln = line.shift();
+ moveTargets[ln] = line.join('#');
+ }
+
+ selTopicsStr = '';
+ for (var i in topics) {
+ if (topics[i].selected) {
+ selTopicsStr += '#' + topics[i].id + '#';
+ }
+ }
+
+ topics = new Array();
+ for (var i = 0; i < nt; i ++) {
+ topics.push(parseTopic(lines));
+ }
+
+ if (nt == 0) {
+ cPage = -1;
+ } else {
+ nPages = Math.ceil(nt / perPage);
+ if (cPage < 0) {
+ cPage = 0;
+ } else if (cPage >= nPages) {
+ cPage = nPages - 1;
+ }
+ }
+ };
+
+ parseTopic = function (lines) {
+ var topic = { };
+ var line = lines.shift().split('#');
+
+ topic.id = line.shift();
+ topic.movedTo = line.shift();
+ topic.unread = (line.shift() == '1');
+ topic.sticky = parseInt(line.shift(), 10);
+ topic.nReplies = line.shift();
+ topic.fpTime = line.shift();
+ topic.fpAuthor = line.shift();
+ topic.lcTime = line.shift();
+ topic.lcAuthor = line.shift();
+ topic.isLocked = (line.shift() == '1');
+ topic.hasPoll = (line.shift() == '1');
+ topic.isDeleted = (line.shift() == '1');
+ topic.deletedAt = line.shift();
+ topic.deletedBy = line.shift();
+ topic.title = lines.shift();
+ topic.mToForum = (topic.movedTo == '') ? null : lines.shift();
+ topic.selected = (selTopicsStr.indexOf( '#' + topic.id + '#') != -1);
+
+ return topic;
+ };
+
+ getSelectedTopics = function (deleted) {
+ var rv = new Array();
+ for (var i = cPage * perPage; i < topics.length && i < (cPage + 1) * perPage; i ++) {
+ if (topics[i].movedTo == '' && topics[i].selected && topics[i].isDeleted == deleted) {
+ rv.push(topics[i].id);
+ }
+ }
+ return rv;
+ };
+
+ drawControls = function () {
+ // Main controls
+ var str = '<tr><td style="padding: 10px 0px; border-width: 0px">'
+ + '<table style="width: 100%; padding: 0px 10px; border-width: 0px; margin: 0px">'
+ + '<tr><td style="padding: 0px; border-width: 0px; margin: 0px; text-align:center" colspan="3">'
+ + '<div id="f-std-ctrl" style="width: 100%; text-align: center'
+ + ((showModTools || showOptions) ? '; display: none' : '') + '">'
+ + '<a href="#" onClick="pageContents.displayOptions();return false">'
+ + ForumView.displayOptions + '</a>';
+
+ if (canPost) {
+ str += ' - <a href="?cmd=C%23' + forumId + '">' + ForumView.newTopic + '</a>';
+ }
+ if (isMod) {
+ str += ' - <a href="#" onClick="pageContents.displayModTools();return false">'
+ + ForumView.modTools + '</a>';
+ }
+
+ // Display options
+ str += '</div><fieldset id="f-options" style="margin: 0px; padding:0px'
+ + (showOptions ? '; display: block' : '; display: none') + '">'
+ + '<legend>' + ForumView.displayOptions + '</legend><form style="padding: 0px; margin: 0px">'
+ + '<table style="width: 100%"><tr><td style="padding: 0px 5px; margin: 0px; '
+ + 'width: 33%; text-align: right">' + ForumView.applyTo
+ + '</td><td style="padding: 0px; margin: 0px; text-align:left">'
+ +' <input type="radio" name="f-apply-to" '
+ + 'value="0" id="f-apply-to-this" onClick="pageContents.setOption(\'toAll\', 0)" />'
+ + '<label for="f-apply-to-this">' + ForumView.thisForum
+ + '</label> <input type="radio" name="f-apply-to" value="1" id="f-apply-to-all" '
+ + 'onClick="pageContents.setOption(\'toAll\', 1)" />'
+ + '<label for="f-apply-to-all">' + ForumView.allForums + '</label></td>'
+ + '<td style="width: 33%; padding: 0px 5px; margin: 0px; text-align:right">'
+ + '<a href="#" onClick="pageContents.optionsOk(); return false">' + ForumView.ok
+ + '</a></td></tr><tr><td style="width: 33%; padding: 0px 5px; margin: 0px; text-align:right">'
+ + ForumView.perPage + '</td><td style="padding: 0px; margin: 0px; text-align:left">'
+ + '<select id="f-per-page" '
+ + 'onChange="pageContents.setOption(\'pp\', options[selectedIndex].value)">';
+ for (var i = 10; i < 60; i += 10) {
+ str += '<option value="' + i + '">' + i + '</option>';
+ }
+ str += '</select></td><td style="width: 33%; padding: 0px 5px; margin: 0px; text-align:right">'
+ + '<a href="#" onClick="pageContents.optionsCancel(); return false">' + ForumView.cancel
+ + '</a></td></tr>';
+ if (isMod) {
+ str += '<tr><td style="padding: 0px 5px; margin: 0px; text-align: right"><label for="f-disp-del">'
+ + ForumView.displayDeleted + '</label></td><td style="padding: 0px; margin: 0px; '
+ + 'text-align:left" colspan="2"><input type="checkbox" name="f-disp-del"'
+ + ' id="f-disp-del" value="1" onClick="pageContents.setOption(\'dd\', checked ? 1 : 0)" '
+ + '/></td></tr>';
+ }
+ str += '</table></form></fieldset>';
+
+ // Moderation tools
+ if (isMod) {
+ str += '<fieldset id="f-mod-tools" style="margin: 0px; padding: 5px 0px; text-align: center'
+ + (showModTools ? '; display: block' : '; display: none') + '">'
+ + '<legend>' + ForumView.modTools + '</legend>'
+ + '<form style="padding: 0px; margin: 0px" id="f-mod-tools-contents">'
+ + '</form></fieldset>';
+ }
+ str += '</td></tr>';
+
+ // Page control
+ if (topics.length && nPages > 1) {
+ var st = 'border-width: 0px; margin: 0px; vertical-align: middle; ';
+ str += '<tr><td style="' + st + 'padding: 5px 0px 0px 0px; text-align:left; width: 33%">'
+ + (cPage > 0 ? '<a href="#" onClick="pageContents.prevPage(); return false">' : '')
+ + '&lt;-- ' + ForumView.previousPage + (cPage > 0 ? '</a>' : '')
+ + '</td><td style="' + st + 'padding: 5px 0px 0px 0px; text-align:center">'
+ + '<form style="' + st + 'padding: 0px; ">' + ForumView.pageSelHdr
+ + '<select onChange="pageContents.jumpToPage(options[selectedIndex].value)">';
+ for (var i = 0; i < nPages; i ++) {
+ str += '<option ' + (i == cPage ? 'selected="selected" ' : '') + 'value="'
+ + i + '">' + (i + 1) + '</option>';
+ }
+ str += '</select></form></td><td style="' + st
+ + '; padding: 5px 0px 0px 0px; text-align: right; width: 33%">'
+ + ((cPage<nPages-1) ? '<a href="#" onClick="pageContents.nextPage(); return false">' : '')
+ + ForumView.nextPage + '--&gt;' + ((cPage<nPages-1) ? '</a>' : '') + '</td></tr>';
+ }
+
+ str += '</table>';
+ return str;
+ };
+
+ displayContents = function () {
+ // Draw the header
+ var str = '<div style="padding: 0px 0px 0px 5px">';
+ var hasDetails = (description != '' || admins.length || mods.length || users.length);
+ if (unread || hasDetails) {
+ // "Mark as read" link
+ str += '<div style="float: right; text-align: right">';
+ if (hasDetails) {
+ str += '<a href="#" onClick="pageContents.toggleDetails();'
+ + 'return false" id="f-toggle-details">'
+ + (showDetails ? ForumView.hideDetails : ForumView.showDetails)
+ + '</a>' + (unread ? ' - ' : '');
+ }
+ if (unread) {
+ str += '<a href="#" onClick="pageContents.markRead(); return false">'
+ + ForumView.markRead + '</a>';
+ }
+ str += '</div>';
+ }
+ // Title and parent categories
+ str += '<h1 style="padding: 0px">' + title + '</h1>';
+ for (var i in parents) {
+ str += (i > 0 ? ' &gt; ' : '') + '<a href="?cmd=V%23C%23' + parents[i].id + '">'
+ + (parents[i].id == '/' ? ForumsLayout.menuTitle : parents[i].name)
+ + '</a>';
+ }
+ str += '</div>';
+ // Details (description & ACL)
+ if (hasDetails) {
+ var needsBR = false;
+ str += '<fieldset id="f-details" style="margin: 20px 20px'
+ + (showDetails ? '' : '; display: none')
+ + '"><legend>' + ForumView.details + '</legend>';
+
+ if (description != '') {
+ str += description;
+ needsBR = true;
+ }
+
+ if (admins.length) {
+ str += (needsBR ? '<br/>' : '') + '<b>' + ForumView.adminsHdr + '</b>: '
+ + admins.join(' - ');
+ needsBR = true;
+ }
+
+ if (mods.length) {
+ str += (needsBR ? '<br/>' : '') + '<b>' + ForumView.modsHdr + '</b>: '
+ + mods.join(' - ');
+ needsBR = true;
+ }
+
+ if (users.length) {
+ str += (needsBR ? '<br/>' : '') + '<b>' + ForumView.usersHdr + '</b>: '
+ + users.join(' - ');
+ }
+
+ str += '</fieldset>';
+ }
+ str += '<table style="width: 100%; margin: 20px 0px; padding: 0px; border-style:none">';
+
+ str += drawControls();
+ if (topics.length) {
+ // Topics list
+ str += '<tr><td style="padding: 0px; margin: 0px"><form style="padding:0px;margin:0px;'
+ + 'width:100%"><table style="width: 100%; padding: 0px; margin: 0px; border-collapse: '
+ + 'collapse"><tr><td style="width: 20px;text-align:center;vertical-align:middle">'
+ + '<input type="checkbox" id="mt-sel-all" name="mt-sel-all" value="1" '
+ + (modSelAll ? 'checked="checked" ' : '') + (showModTools ? '' : 'style="display: none"')
+ + ' onClick="pageContents.toggleSelAll(); return true" />'
+ + '</td><td style="width: 32px">&nbsp;</td>'
+ + '<th style="text-align: left; padding: 0px 0px 0px 5px">' + ForumView.headers.topic
+ + '</th><th style="width: 8%">' + ForumView.headers.replies
+ + '</th><th style="width: 25%">' + ForumView.headers.fPost
+ + '</th><th style="width: 25%">' + ForumView.headers.lPost + '</th></tr>';
+
+ for (var i = cPage * perPage; i < topics.length && i < (cPage + 1) * perPage; i ++) {
+ str += '\n<tr style="border-width: 1px 0px; border-style: solid; border-color: white"'
+ + '><td style="width: 20px; text-align: center; padding: 0px; vertical-align:'
+ + 'middle"><input type="checkbox" id="mt-sel-' + topics[i].id + '" value="1"'
+ + (topics[i].selected ? ' checked="checked"' : '')
+ + (showModTools ? '' : ' style="display: none"')
+ + ' onClick="pageContents.toggleTopic(' + i + '); return true" />'
+ + '</td><td style="width: 32px; text-align: center; padding: 0px">'
+ + '<img src="' + staticurl + '/beta5/pics/topic_s' + topics[i].sticky
+ + '_' + (topics[i].unread ? 'un' : '') + 'read.gif" style="border-width: 0px" />'
+ + '</td><td style="padding: 0px 0px 0px 5px">'
+ + ((topics[i].isLocked || topics[i].hasPoll) ? '<div style="float: right">' : '')
+ + (topics[i].isLocked ? ('<img src="' + staticurl + '/beta5/pics/topic_locked.'
+ + (useGIFs ? 'gif' : 'png')
+ + '" style="border-width: 0px; float: left" />') : '')
+ + (topics[i].hasPoll ? ('<img src="' + staticurl + '/beta5/pics/topic_poll.'
+ + (useGIFs ? 'gif' : 'png') + '" style="border-width: 0px" />') : '')
+ + ((topics[i].isLocked || topics[i].hasPoll) ? '</div>' : '') + '<div>'
+ + (topics[i].isDeleted ? '' : ('<a href="?cmd=T%23' + topics[i].id + '">'))
+ + topics[i].title + (topics[i].isDeleted ? '' : '</a>')
+ + (topics[i].movedTo != '' ? ('<br/>&nbsp;-&gt;&nbsp;' + ForumView.movedTo
+ + '<a href="?cmd=V%23F%23' + topics[i].movedTo + '">'
+ + topics[i].mToForum + '</a>') : '')
+ + '</div></td>';
+ if (topics[i].isDeleted) {
+ str += '<td colspan="3" style="text-align: center; vertical-align: middle">'
+ + ForumView.deletedAt + formatDate(topics[i].deletedAt) + CategoryView.by
+ + '<b>' + players[topics[i].deletedBy] + '</b></td>';
+ } else {
+ str += '<td style="text-align:center; vertical-align: middle">'
+ + formatNumber(topics[i].nReplies) + '</td>'
+ + '<td style="text-align:center;padding: 0px 2px;vertical-align:middle">'
+ + formatDate(topics[i].fpTime) + CategoryView.by + '<b>'
+ + players[topics[i].fpAuthor] + '</b></td>'
+ + '<td style="text-align:center;padding: 0px 2px;vertical-align:middle">'
+ + formatDate(topics[i].lcTime) + CategoryView.by + '<b>'
+ + players[topics[i].lcAuthor] + '</b></td>';
+ }
+ str += '</tr>';
+ }
+
+ str += '</table>';
+ } else {
+ str += '<tr><td style="padding: 0px; height: 48px; border-style: solid; border-color: white; '
+ + 'border-width: 1px 0px; text-align: center; vertical-align: middle">'
+ + ForumView.empty + '</td></tr>';
+ }
+ str += '</table>';
+
+ document.getElementById('f-page').innerHTML = str;
+ setFieldValues();
+ };
+
+ hideOptions = function () {
+ var e = document.getElementById('f-options');
+ if (!e) {
+ return;
+ }
+ showOptions = false;
+ e.style.display = 'none';
+ document.getElementById('f-std-ctrl').style.display = 'block';
+ };
+
+ drawModTools = function () {
+ var cnt = 0, sel = 0, dSel = 0, nSel = 0, hasLocked = false, hasUnlocked = false,
+ minStL = 11, maxStL = -1;
+ if (cPage != -1) {
+ for (var i = cPage * perPage; i < topics.length && i < (cPage + 1) * perPage; i ++) {
+ if (topics[i].movedTo != '') {
+ continue;
+ }
+ document.getElementById('mt-sel-' + topics[i].id).checked = topics[i].selected;
+ if (topics[i].selected) {
+ if (topics[i].isDeleted) {
+ dSel ++;
+ } else {
+ nSel ++;
+ hasLocked = hasLocked || topics[i].isLocked;
+ hasUnlocked = hasUnlocked || ! topics[i].isLocked;
+ }
+ minStL = (minStL > topics[i].sticky) ? topics[i].sticky : minStL;
+ maxStL = (maxStL < topics[i].sticky) ? topics[i].sticky : maxStL;
+ sel ++;
+ }
+ cnt ++;
+ }
+ document.getElementById('mt-sel-all').checked = modSelAll = (sel == cnt);
+ }
+
+ var str = '<a href="#" onClick="pageContents.hideModTools(); return false">' + ForumView.hideModTools
+ + '</a><br/>';
+ if (!(dSel || nSel)) {
+ str += '<br/>' + ForumView.pleaseSelect;
+ } else {
+ if (nSel) {
+ str += '<br/>' + ForumView.selectedTopics
+ + '<a href="#" onClick="pageContents.deleteSelected(); return false">'
+ + ForumView.deleteTopics + '</a> - ' + ForumView.stickyLevel;
+
+ // Sticky level management
+ if (maxStL < 10) {
+ str += '<a href="#" onClick="pageContents.increaseSticky(); return false">'
+ + ForumView.increaseStickyLevel + '</a> / ';
+ }
+ if (minStL > 0) {
+ str += '<a href="#" onClick="pageContents.decreaseSticky(); return false">'
+ + ForumView.decreaseStickyLevel + '</a> / ';
+ }
+
+ str += ForumView.setTo + '<select id="mt-set-level" onChange="pageContents.setSticky('
+ + 'options[selectedIndex].value)"><option value="">-------</option>'
+
+ var stText = [ForumView.normalPost, 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII',
+ 'IX', 'X'];
+ for (var i = 0; i < 11; i ++) {
+ str += '<option value="' + i + '">' + stText[i] + '</option>';
+ }
+ str += '</select>';
+
+ // Lock / Unlock
+ if (hasLocked) {
+ str += ' - <a href="#" onClick="pageContents.unlockTopics(); return false">'
+ + ForumView.unlock + '</a>';
+ }
+ if (hasUnlocked) {
+ str += ' - <a href="#" onClick="pageContents.lockTopics(); return false">'
+ + ForumView.lock + '</a>';
+ }
+
+ // Move to
+ if (hasMoveTargets) {
+ str += '<br/>' + ForumView.moveTo + '<select id="mt-move-to" onChange="'
+ + 'pageContents.moveTo(options[selectedIndex].value)">'
+ + '<option value="">-------</option>';
+ for (var i in moveTargets) {
+ str += '<option value="' + i + '">' + moveTargets[i] + '</option>';
+ }
+ str += '</select>';
+ }
+ }
+ if (dSel) {
+ str += '<br/>' + ForumView.deletedTopics
+ + '<a href="#" onClick="pageContents.restoreSelected(); return false">'
+ + ForumView.restoreTopics + '</a>';
+ }
+ }
+
+ document.getElementById('f-mod-tools-contents').innerHTML = str;
+ };
+
+ setFieldValues = function () {
+ var e = document.getElementById('f-options');
+ if (!e) {
+ return;
+ }
+
+ // Options block
+ document.getElementById('f-apply-to-this').checked = (options.toAll == 0);
+ document.getElementById('f-apply-to-all').checked = (options.toAll == 1);
+ document.getElementById('f-per-page').selectedIndex = (options.pp / 10) - 1;
+
+ // Moderation tools
+ if (! isMod) {
+ return;
+ }
+ document.getElementById('f-disp-del').checked = (options.dd == 1);
+
+ if (cPage != -1) {
+ for (var i = cPage * perPage; i < topics.length && i < (cPage + 1) * perPage; i ++) {
+ document.getElementById('mt-sel-' + topics[i].id).style.display =
+ ((showModTools && topics[i].movedTo == '') ? 'block' : 'none');
+ }
+ document.getElementById('mt-sel-all').style.display = (showModTools ? 'block' : 'none');
+ }
+
+ drawModTools();
+ };
+
+ // Page update: parser & updater
+ this.parse = function (data) {
+ if (data != '-') {
+ if (data.indexOf('\n') == -1) {
+ // IE, first update
+ viewId = data;
+ this.update();
+ return;
+ }
+
+ var lines = data.split('\n');
+ pageMD5 = lines.shift();
+ viewId = lines.shift();
+
+ mainParser(lines);
+ players = parseNames(lines);
+
+ displayContents();
+ }
+
+ pageUpdater = window.setTimeout("pageContents.update()", 10000);
+ locked = false;
+ };
+ this.update = function () {
+ if (locked) {
+ return;
+ }
+ pageUpdater = null;
+ locked = true;
+ x_getView(viewId, pageMD5, function (data) { pageContents.parse(data); });
+ };
+ this.setFieldValues = function () { setFieldValues(); };
+
+ // Displaying details
+ this.toggleDetails = function () {
+ var e = document.getElementById('f-details');
+ if (!e) {
+ return;
+ }
+ showDetails = ! showDetails;
+ document.getElementById('f-toggle-details').innerHTML
+ = (showDetails ? ForumView.hideDetails : ForumView.showDetails)
+ e.style.display = showDetails ? 'block' : 'none';
+ };
+
+ // "Display options" box management
+ this.displayOptions = function () {
+ var e = document.getElementById('f-options');
+ if (!e) {
+ return;
+ }
+ options = {
+ toAll: 0,
+ pp: perPage,
+ dd: (isMod && vDeleted) ? 1 : 0
+ };
+ setFieldValues();
+ showOptions = true;
+ e.style.display = 'block';
+ document.getElementById('f-std-ctrl').style.display = 'none';
+ };
+ this.optionsOk = function () {
+ hideOptions();
+ if (locked) {
+ window.setTimeout("pageContents.optionsOk()", 250);
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+ x_forumOptions(forumId, options.toAll, options.pp, options.dd, pageMD5, function (data) {
+ pageContents.parse(data); });
+ };
+ this.optionsCancel = function () { hideOptions(); };
+ this.setOption = function (name, value) { options[name] = value; };
+
+ // Moderation tools
+ this.displayModTools = function () {
+ var e = document.getElementById('f-mod-tools');
+ if (!e) {
+ return;
+ }
+ showModTools = true;
+ setFieldValues();
+ e.style.display = 'block';
+ document.getElementById('f-std-ctrl').style.display = 'none';
+ };
+ this.hideModTools = function () {
+ var e = document.getElementById('f-mod-tools');
+ if (!e) {
+ return;
+ }
+ showModTools = false;
+ setFieldValues();
+ e.style.display = 'none';
+ document.getElementById('f-std-ctrl').style.display = 'block';
+ };
+ this.toggleTopic = function (index) {
+ topics[index].selected = !topics[index].selected;
+ drawModTools();
+ };
+ this.toggleSelAll = function () {
+ modSelAll = !modSelAll;
+ for (var i = cPage * perPage; i < topics.length && i < (cPage + 1) * perPage; i ++) {
+ if (topics[i].movedTo != '') {
+ continue;
+ }
+ topics[i].selected = modSelAll;
+ }
+ drawModTools();
+ };
+ this.restoreSelected = function () {
+ if (locked) {
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+
+ var tlist = getSelectedTopics(true);
+ x_restoreTopics(forumId, tlist.join('#'), function (data) { pageContents.parse(data); });
+ };
+ this.deleteSelected = function () {
+ if (locked) {
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+
+ var tlist = getSelectedTopics(false);
+ x_deleteTopics(forumId, tlist.join('#'), function (data) { pageContents.parse(data); });
+ };
+ this.increaseSticky = function () {
+ if (locked) {
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+
+ var tlist = getSelectedTopics(false);
+ x_changeTopicsLevel(forumId, tlist.join('#'), 1, function (data) { pageContents.parse(data); });
+ };
+ this.decreaseSticky = function () {
+ if (locked) {
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+
+ var tlist = getSelectedTopics(false);
+ x_changeTopicsLevel(forumId, tlist.join('#'), -1, function (data) { pageContents.parse(data); });
+ };
+ this.setSticky = function (value) {
+ var e = document.getElementById('mt-set-level');
+ if (e) { e.disabled = true; }
+ e = document.getElementById('mt-set-level'); if (e) { e.disabled = true; }
+ e = document.getElementById('mt-move-to'); if (e) { e.disabled = true; }
+
+ if (locked) {
+ window.setTimeout("pageContents.setSticky(" + value + ")", 250);
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+
+ var tlist = getSelectedTopics(false);
+ x_setTopicsLevel(forumId, tlist.join('#'), value, function (data) { pageContents.parse(data); });
+ };
+ this.lockTopics = function () {
+ if (locked) {
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+
+ var tlist = getSelectedTopics(false);
+ x_setTopicsLock(forumId, tlist.join('#'), 1, function (data) { pageContents.parse(data); });
+ };
+ this.unlockTopics = function () {
+ if (locked) {
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+
+ var tlist = getSelectedTopics(false);
+ x_setTopicsLock(forumId, tlist.join('#'), 0, function (data) { pageContents.parse(data); });
+ };
+ this.moveTo = function (dest) {
+ e = document.getElementById('mt-set-level'); if (e) { e.disabled = true; }
+ e = document.getElementById('mt-move-to'); if (e) { e.disabled = true; }
+
+ if (locked) {
+ window.setTimeout("pageContents.moveTo(" + dest + ")", 250);
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+
+ var tlist = getSelectedTopics(false);
+ x_moveTopics(forumId, tlist.join('#'), dest, function (data) { pageContents.parse(data); });
+ };
+
+ // Page management
+ this.nextPage = function () { this.jumpToPage(cPage + 1); };
+ this.prevPage = function () { this.jumpToPage(cPage - 1); };
+ this.jumpToPage = function (value) {
+ cPage = parseInt(value, 10);
+ displayContents();
+ };
+
+ // Mark topics as read
+ this.markRead = function () {
+ if (locked) {
+ window.setTimeout("pageContents.markRead()", 250);
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+ x_forumRead(forumId, function (data) { pageContents.parse(data); });
+ };
+};
+
+
+CategoryView = function () {
+
+ var me = this;
+ var tst = ' style="width: 100%; margin: 0px; padding: 0px; border-width: 0px"';
+ var cst = ' style="margin: 0px; padding: 0px; border-width: 0px; vertical-align: middle"';
+
+ var pageUpdater = null;
+ var pageMD5 = null;
+ var viewId = null;
+ var contents = null;
+ var locked = false;
+ var players = [];
+
+ var parseContents, parseForum, displayContents, displayForums;
+
+ parseContents = function (lines) {
+ var line = lines.shift().split('#');
+ var obj = {};
+ var cc, dc;
+
+ obj.id = line.shift();
+ obj.isCategory = (line.shift() == 'F');
+ obj.hasUnread = (line.shift() == '1');
+ cc = parseInt(line.shift(), 10);
+ dc = parseInt(line.shift(), 10);
+
+ if (obj.isCategory) {
+ obj.typeName = lines.shift();
+ }
+ obj.title = lines.shift();
+
+ var da = new Array();
+ for (var i = 0; i < dc; i ++) {
+ da.push(lines.shift());
+ }
+ obj.description = da.join('<br/>');
+
+ if (obj.id == '/') {
+ obj.title = CategoryView.ovTitle;
+ obj.description = CategoryView.ovDescription;
+ }
+
+ obj.contents = new Array();
+ for (var i = 0; i < cc; i ++) {
+ obj.contents.push( obj.isCategory ? parseForum(lines) : parseContents(lines) );
+ }
+
+ return obj;
+ };
+ parseForum = function (lines) {
+ var line = lines.shift().split('#');
+ var obj = { };
+ var dc;
+
+ obj.id = line.shift();
+ dc = parseInt(line.shift(), 10);
+ obj.isDeleted = (line.shift() == '1');
+ obj.deletedAt = line.shift();
+ obj.deletedBy = line.shift();
+ obj.topics = line.shift();
+ obj.posts = line.shift();
+ obj.isUnread = (line.shift() == '1');
+
+ if (parseInt(obj.posts, 10) > 0) {
+ line = lines.shift().split('#');
+ obj.lastAuthor = line.shift();
+ obj.lastTimestamp = line.shift();
+ }
+
+ obj.title = lines.shift();
+ var desc = new Array();
+ for (var i = 0; i < dc; i ++) {
+ desc.push(lines.shift());
+ }
+ obj.description = desc.join('<br/>');
+
+ return obj;
+ };
+ displayContents = function (obj, depth) {
+ var d = (typeof depth == 'undefined') ? 0 : depth;
+ var mw = d * 8;
+ var htag = 'h' + (d + 1);
+
+ var str = '<table style="width: 100%; margin: 5px 0px 2px 0px; padding: 0px; border-width: 0px"><tr>';
+ if (d > 0) {
+ str += '<td style="width: ' + mw + 'px; margin: 0px; padding: 0px; border-width: 0px;">'
+ + '&nbsp;</td>';
+ }
+
+ var rText = '';
+ if (obj.isCategory) {
+ rText = '<div style="float: right; text-align: right">' + obj.typeName;
+ if (obj.hasUnread) {
+ rText += '<br/><a href="#" onClick="pageContents.markRead(\''
+ + obj.id + '\'); return false">' + CategoryView.markRead + '</a>';
+ }
+ rText += '</div>';
+ }
+
+ str += '<td' + cst + '>' + rText + '<div><' + htag + '>' + obj.title + '</' + htag + '>'
+ + (obj.description != '' ? ('<p>' + obj.description + '</p>') : '')
+ + '</div></td></tr></table>';
+
+ if (! obj.isCategory) {
+ for (var i in obj.contents) {
+ str += displayContents(obj.contents[i], d + 1);
+ }
+ } else {
+ str += displayForums(obj);
+ }
+
+ return str;
+ };
+ displayForums = function (obj) {
+ if (obj.contents.length == 0) {
+ return '<p>' + CategoryView.empty + '</p>';
+ }
+
+ var str = '<table style="border-collapse: collapse; width: 100%; margin: 0px 0px 20px 0px; padding: 0px; '
+ + 'border-style: none; border-color: white; border-width: 0px"><tr>'
+ + '<td style="width: 32px">&nbsp;</td><th style="text-align: left">'
+ + CategoryView.headers.name + '</th><th style="width: 10%">' + CategoryView.headers.topics
+ + '</th><th style="width: 10%">' + CategoryView.headers.posts
+ + '</th><th style="width: 25%">' + CategoryView.headers.lastPost
+ + '</th></tr>';
+
+ for (var i in obj.contents) {
+ var forum = obj.contents[i];
+ str += '<tr><td style="height: 32px"><img src="' + staticurl
+ + '/beta5/pics/forum_' + (forum.isUnread ? 'un' : '') + 'read.'
+ + (useGIFs ? 'gif' : 'png') + '" alt="'
+ + CategoryView.forumIcon[forum.isUnread ? 'unread' : 'read']
+ + '" style="border-style:none;border-width: 0px" /></td>'
+ + '<td style="vertical-align: middle; padding: 1px 0px 2px 0px"><a href="?cmd=V%23F%23'
+ + forum.id + '">' + forum.title + '</a>'
+ + (forum.description != '' ? ('<br/>' + forum.description) : '') + '</td>';
+ if (forum.isDeleted) {
+ str += '<td style="vertical-align: middle; text-align: center" colspan="3">'
+ + CategoryView.deletedAt + '<b>' + formatDate(forum.deletedAt) + '</b>'
+ + CategoryView.by + '<b>' + players[forum.deletedBy] + '</b></td>';
+ } else {
+ str += '<td style="vertical-align: middle; text-align: center">'
+ + formatNumber(forum.topics)
+ + '</td><td style="vertical-align: middle; text-align: center">'
+ + formatNumber(forum.posts)
+ + '</td><td style="vertical-align: middle; text-align: center">';
+ if (forum.posts != 0) {
+ str += formatDate(forum.lastTimestamp) + '<br/>' + CategoryView.by
+ + '<b>' + players[forum.lastAuthor] + '</b>';
+ } else {
+ str += CategoryView.noPosts;
+ }
+ str += '</td>';
+ }
+ str += '</tr>';
+ }
+
+ str += '</table>';
+ return str;
+ };
+
+ this.parse = function (data) {
+ if (data != '-') {
+ if (data.indexOf('\n') == -1) {
+ // IE, first update
+ viewId = data;
+ this.update();
+ return;
+ }
+
+ var lines = data.split('\n');
+ pageMD5 = lines.shift();
+ viewId = lines.shift();
+
+ contents = parseContents(lines);
+ players = parseNames(lines);
+
+ document.getElementById('f-page').innerHTML = displayContents(contents);
+ }
+
+ pageUpdater = window.setTimeout("pageContents.update()", 10000);
+ locked = false;
+ };
+
+ this.update = function () {
+ if (locked) {
+ return;
+ }
+ pageUpdater = null;
+ locked = true;
+ x_getView(viewId, pageMD5, function (data) { pageContents.parse(data); });
+ };
+
+ this.markRead = function (id) {
+ if (locked) {
+ window.setTimeout("pageContents.markRead('" + id + "')", 250);
+ return;
+ }
+ locked = true;
+ if (pageUpdater) {
+ window.clearTimeout(pageUpdater);
+ pageUpdater = null;
+ }
+ x_categoryRead(id, viewId, function (data) { pageContents.parse(data); });
+ };
+
+ this.setFieldValues = function () { };
+};
+
+
+
+ForumsLayout = function () {
+
+ var init = document.getElementById('f-params').innerHTML.split('#');
+ var me = this;
+
+ // Read the page's parameters
+ var menuVisible = (init.shift() == '1');
+ var needData = (init.shift() == '1');
+ var pageType = init.shift();
+
+ // Read the current menu entry
+ MenuItem.current = document.getElementById('f-menu-current').innerHTML;
+
+ // Initialize other private variables here
+ var menuMD5 = '';
+ var menuTree = null;
+ var menuUpdater = null;
+ var menuFDisabled = false;
+ var page = null;
+
+ // Initialize private methods here
+ var parseMenuData, drawLayout, drawMenu;
+ parseMenuData = function(data) {
+ menuUpdater = null;
+ if (! menuVisible) {
+ menuFDisabled = false;
+ return;
+ }
+
+ var lines = data.split('\n');
+ var line = lines.shift();
+
+ if (line != '-') {
+ menuMD5 = line;
+ menuTree = new MenuItem(lines);
+ drawMenu();
+ }
+ menuFDisabled = false;
+ menuUpdater = window.setTimeout("main.updateMenu()", 5000);
+ };
+ drawMenu = function () {
+ if (! menuTree) {
+ menuVisible = false;
+ drawLayout();
+ return;
+ }
+
+ var tst = ' style="width: 100%; margin: 0px; padding: 0px; border-width: 0px"';
+ var cst = ' style="margin: 0px; padding: 0px; border-width: 0px; vertical-align: middle"';
+ var str = '<table' + tst + '><tr><td' + tst + '><table' + tst + '><tr><td ' + cst
+ + '<h1>' + ForumsLayout.menuTitle + '</h1></td><td' + cst + '><a href="#" onClick="'
+ + 'main.hideMenu();return false">' + ForumsLayout.hideMenu
+ + '</a></td></tr></table></td></tr>' + '<tr><td' + tst + '>&nbsp;</td></tr>';
+
+ var x = new Array();
+ menuTree.draw(x);
+
+ str += x.join('') + '</table>';
+ document.getElementById('f-menu').innerHTML = str;
+ };
+ drawLayout = function () {
+ var mContents;
+ if (document.getElementById('f-page')) {
+ mContents = document.getElementById('f-page').innerHTML;
+ } else {
+ mContents = '&nbsp;';
+ }
+
+ var mainMargin;
+ var str = '<div id="f-menu" style="float: left; margin: 0px 5px; padding: 1px 10px 20px 5px; '
+ + 'border-color: white; border-style: solid; border-width: 0px 1px 0px 0px';
+ if (menuVisible) {
+ str += '; width: 300px"><i>(loading menu)</i>';
+ mainMargin = 326;
+ } else {
+ str += ';text-align:center; width: 16px"><a href="#" onClick="main.showMenu();return false">'
+ + ForumsLayout.menuText.join('<br/>') + '</a>';
+ mainMargin = 42;
+ }
+ str += '</div><div id="f-page" style="margin: 1px 5px 10px ' + mainMargin + 'px">&nbsp;</div>';
+ document.getElementById('f-contents').innerHTML = str;
+ document.getElementById('f-page').innerHTML = mContents;
+ if (mContents != '&nbsp;') {
+ pageContents.setFieldValues();
+ }
+ };
+
+ // Public methods
+ this.updateMenu = function() {
+ menuFDisabled = true;
+ x_getMenu(menuMD5, parseMenuData);
+ };
+ this.hideMenu = function() {
+ if (menuFDisabled || !menuVisible) {
+ if (menuFDisabled) {
+ window.setTimeout("main.hideMenu()", 250);
+ }
+ return;
+ }
+ if (menuUpdater) {
+ window.clearTimeout(menuUpdater);
+ }
+ menuUpdater = menuMD5 = menuTree = null;
+ menuVisible = false;
+ x_hideMenu(function () {});
+ drawLayout();
+ };
+ this.showMenu = function() {
+ if (menuFDisabled || menuVisible) {
+ if (menuFDisabled) {
+ window.setTimeout("main.showMenu()", 250);
+ }
+ return;
+ }
+ menuFDisabled = true;
+ menuVisible = true;
+ drawLayout();
+ x_showMenu(parseMenuData);
+ };
+ this.menuOpen = function(id) {
+ if (menuFDisabled || !menuVisible) {
+ if (menuFDisabled) {
+ window.setTimeout("main.menuOpen('" + id + "')", 250);
+ }
+ return;
+ }
+ menuFDisabled = true;
+ if (menuUpdater) {
+ window.clearTimeout(menuUpdater);
+ menuUpdater = null;
+ }
+ x_menuOpen(id, parseMenuData);
+ };
+ this.menuClose = function(id) {
+ if (menuFDisabled || !menuVisible) {
+ if (menuFDisabled) {
+ window.setTimeout("main.menuClose('" + id + "')", 250);
+ }
+ return;
+ }
+ menuFDisabled = true;
+ if (menuUpdater) {
+ window.clearTimeout(menuUpdater);
+ menuUpdater = null;
+ }
+ x_menuClose(id, parseMenuData);
+ };
+
+ useGIFs = needData;
+ pageContents = new ForumsLayout.pages[pageType];
+ drawLayout();
+ if (needData) {
+ if (menuVisible) {
+ x_getMenu(parseMenuData);
+ }
+ } else {
+ if (menuVisible) {
+ parseMenuData(document.getElementById('f-menu-init').innerHTML);
+ }
+ }
+ pageContents.parse(document.getElementById('f-page-init').innerHTML);
+};
+
+ForumsLayout.pages = {
+ vCat: CategoryView,
+ vForum: ForumView,
+ vTopic: TopicView
+};
diff -Naur beta5//site/static/beta5/js/pg_overview-en.js forums//site/static/beta5/js/pg_overview-en.js
--- beta5//site/static/beta5/js/pg_overview-en.js 2011-02-05 10:09:56.434335002 +0100
+++ forums//site/static/beta5/js/pg_overview-en.js 2011-03-12 15:10:45.561300049 +0100
@@ -84,26 +84,7 @@
str += '<h2>Fleets</h2><p>Total fleet power: <b>'+formatNumber(flOverview[0])+'</b></p>';
str += '<h2>Money</h2><p>Daily Profit: <b>&euro;'+formatNumber(moOverview[2])+'</b></p></td>';
- str += '<td colspan="2"><h2>Forums</h2><p>';
- var i,j,k,a=new Array();
- for (i=0;i<genForums.length;i++)
- {with(genForums[i]){
- k = 0;
- for (j=0;j<forums.length;j++)
- k += parseInt(forums[j].nUnread,10);
- j = (k==0? "no unread topics" : (k + ' unread topic' + (k>1 ? 's' : '')));
- a.push('<a href="forums?cmd=C%23G%23'+id+'" ' + ovett[4] + ' >'+name+'</a>: ' + j);
- }}
-
- if (aForums.length)
- {
- k = 0;
- for (j=0;j<aForums.length;j++)
- k += parseInt(aForums[j].nUnread,10);
- j = (k==0? "no unread topics" : (k + ' unread topic' + (k>1 ? 's' : '')));
- a.push('<a href="forums?cmd=C%23A%23'+allianceId+'" ' + ovett[5] + ' >Alliance forums</a>: ' + j);
- }
- str += a.join('<br/>') + '</p>';
+ str += '<td colspan="2"><h2>Forums</h2><p>' + forums.output(-1, false) + '</p>';
str += '<h2>Planets</h2><p><b>'+formatNumber(unOverview[0])+'</b> planets</p>';
str += '<h2>Next ticks</h2><p id="ticks"> </p>';
@@ -188,30 +169,7 @@
str += 'Daily Profit: <b>&euro;'+formatNumber(moOverview[2])+'</b><br/>';
str += '<a href="money" ' + ovett[15] + ' >More details...</a></p></td>';
- str += '<td colspan="2"><h2>Forums</h2><p>';
- var j,a=new Array(),s;
- for (i=0;i<genForums.length;i++)
- {with(genForums[i]){
- s = '<b>' + name + '</b> (<a href="forums?cmd=C%23G%23'+id+'" ' + ovett[16] + '>view</a>)';
- for (j=0;j<forums.length;j++)
- {
- s += '<br/>&nbsp;&nbsp;-&nbsp;<a href="forums?cmd=F%23' + type + '%23' + forums[j].id + '" ' + ovett[17] + '>' + forums[j].name + '</a>: ';
- s += makeTopicsText(forums[j].nTopics, forums[j].nUnread);
- }
- a.push(s);
- }}
-
- if (aForums.length)
- {
- s = '<b>Alliance Forums</b> (<a href="forums?cmd=C%23A%23'+allianceId+'" ' + ovett[18] + ' >view</a>)';
- for (j=0;j<aForums.length;j++)
- {
- s += '<br/>&nbsp;&nbsp;-&nbsp;<a href="forums?cmd=F%23A%23' + aForums[j].id + '" ' + ovett[17] + ' >' + aForums[j].name + '</a>: ';
- s += makeTopicsText(aForums[j].nTopics, aForums[j].nUnread);
- }
- a.push(s);
- }
- str += a.join('<br/><br/>') + '</p>';
+ str += '<td colspan="2"><h2>Forums</h2><p>' + forums.output(-1, true) + '</p>';
str += '<h2>Universe</h2><p><b>'+formatNumber(unOverview[0])+'</b> planets';// (<b>';
str += /*formatNumber(unOverview[2]) + '</b> at the same prot. level)*/'<br/><b>';
@@ -240,6 +198,40 @@
}
+function __forumsOutput(depth, complete) {
+ var str = '';
+
+ if (this.id != '/') {
+ for (var i = 0; i < depth; i++) {
+ str += '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
+ }
+ str += '<a href="forums?cmd=V%23' + this.type + '%23' + this.id + '">' + this.name + '</a>: ';
+ if (complete) {
+ str += '<b>' + this.topics + '</b> topic' + (this.unread > 1 ? 's' : '');
+ if (this.unread > 0) {
+ str += ' (<b>' + this.unread + '</b> unread)';
+ }
+ } else {
+ if (this.unread == 0) {
+ str += 'no unread topics';
+ } else {
+ str += '<b>' + this.unread + '</b> unread topic' + (this.unread > 1 ? 's' : '');
+ }
+ }
+ }
+
+ for (var i = 0; i < this.contents.length; i ++) {
+ if (this.contents[i].type == 'F' && ! complete) {
+ continue;
+ }
+
+ str += '<br/>' + this.contents[i].output(depth + 1, complete);
+ }
+
+ return str;
+}
+
+
function confirmBreakProtection() {
return confirm('You are about to break away from Peacekeeper protection.\n'
+ 'Anyone will be able to attack your planets afterwards.\n'
diff -Naur beta5//site/static/beta5/js/pg_overview.js forums//site/static/beta5/js/pg_overview.js
--- beta5//site/static/beta5/js/pg_overview.js 2011-02-05 10:09:56.434335002 +0100
+++ forums//site/static/beta5/js/pg_overview.js 2011-03-12 15:08:00.801300049 +0100
@@ -1,5 +1,5 @@
var dFolders, cFolders;
-var genForums, aForums, allianceId;
+var forums;
var plOverview, flOverview, moOverview, nResearch;
var unOverview,stDiff,ticks,tUpdate,rankings;
var complete, protection, updateTimer;
@@ -110,24 +110,25 @@
this.name = name;
}
-function Category(id, type, name)
-{
- this.id = id;
- this.type = type;
- this.name = name;
- this.forums = new Array();
-}
+function ForumsEntity(inputData) {
+ var iLine = inputData.shift().split('#');
+ var nElements;
+
+ this.type = iLine.shift();
+ this.id = iLine.shift();
+ nElements = parseInt(iLine.shift(), 10);
+ this.topics = parseInt(iLine.shift(), 10);
+ this.unread = parseInt(iLine.shift(), 10);
+ this.name = inputData.shift();
+ this.contents = new Array();
+ this.output = __forumsOutput;
-function Forum(id, nTopics, nUnread, name)
-{
- this.id = id;
- this.nTopics = nTopics;
- this.nUnread = nUnread;
- this.name = name;
+ for (var i = 0; i < nElements; i ++) {
+ this.contents.push( new ForumsEntity(inputData) );
+ }
}
-
function initPage() {
overviewReceived(document.getElementById('init-data').value);
}
@@ -140,55 +141,26 @@
}
-function parseComms(l)
-{
- var i, a = l.shift().split('#');
- var nCustom = parseInt(a[0],10), nGenCats = parseInt(a[1],10), nAForums = parseInt(a[2],10);
- allianceId = a[3];
+function parseComms(l) {
+ var i, a, nCustom;
// Default folders
dFolders = new Array();
- for (i=0;i<3;i++)
- {
+ for (i=0;i<3;i++) {
a = l.shift().split('#');
dFolders.push(new Folder('', a[0], a[1], ''));
}
// Custom folders
+ nCustom = parseInt(l.shift(), 10);
cFolders = new Array();
- for (i=0;i<nCustom;i++)
- {
+ for (i=0;i<nCustom;i++) {
a = l.shift().split('#');
cFolders.push(new Folder(a.shift(), a.shift(), a.shift(), a.join('#')));
}
// General categories & forums
- genForums = new Array();
- for (i=0;i<nGenCats;i++)
- {
- a = l.shift().split('#');
-
- var j,c,id,tp,nForums;
- id = a.shift(); tp = a.shift();
- nForums = parseInt(a.shift(), 10);
- c = new Category(id, tp, a.join('#'));
-
- for (j=0;j<nForums;j++)
- {
- a = l.shift().split('#');
- c.forums.push(new Forum(a.shift(),a.shift(),a.shift(),a.join('#')));
- }
-
- genForums.push(c);
- }
-
- // Alliance forums
- aForums = new Array();
- for (i=0;i<nAForums;i++)
- {
- a = l.shift().split('#');
- aForums.push(new Forum(a.shift(),a.shift(),a.shift(),a.join('#')));
- }
+ forums = new ForumsEntity(l);
}
diff -Naur beta5//site/static/beta5/pics/forum_read.gif forums//site/static/beta5/pics/forum_read.gif
--- beta5//site/static/beta5/pics/forum_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/forum_read.gif 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,5 @@
+GIF89a <00>I<00><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>&9"-<2D>3><3E>>=<3D><:8867<36>3=$<24>>?=;9741*'# 9<>&<26>0<13>
+6<>!$'3,<2C>81223<32><33>3458@<40><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,>#0<>9FEEDCCBA@<40><><EFBFBD> 19J<><4A>%<25><16><14>t<EFBFBD>R<EFBFBD>B(<04><><EFBFBD><EFBFBD>B<EFBFBD> (H<><48>@<40>S<EFBFBD>X<EFBFBD><58><11> .^<5E><><EFBFBD><EFBFBD><EFBFBD> 9<16><>I]<5D>!9<><39><EFBFBD> <<3C>a<02>5Ej<18>0B<30>$H<><18>'H<1D>d"R<>F<11><11>Ŋ!8d<38>Hd<><64>/.<2E>#<23>
+<2B>0X<30>сF$X<>E<EFBFBD>&N<>@<40>"<22>
+MkJ<6B>L<EFBFBD><4C>eD<65>;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/forum_read.png forums//site/static/beta5/pics/forum_read.png
--- beta5//site/static/beta5/pics/forum_read.png 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/forum_read.png 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,3 @@
+<2B>PNG
+
+ IHDR szz<7A>bKGD<00><00><00><><EFBFBD><EFBFBD><EFBFBD> pHYs  <00><>tIME<07>  0)No޸<03>IDATX<54><58><EFBFBD><EFBFBD>k$E<18><EFBFBD>U<EFBFBD>]<5D><15><><EFBFBD><EFBFBD>fr]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"ě<><C49B>G,( ^<5E><>]<5D>y<EFBFBD><79>%<13>E<<3C>E<+<1E> <01><><EFBFBD><EFBFBD><EFBFBD>$ fe<66><65>d<EFBFBD><64><1F><><EFBFBD>!<21>Nd<4E><15><>KW<4B><57>T=<3D><><EFBFBD><U<03>q<1D>rXӊ<58>n<EFBFBD>nY<6E> <0B><><EFBFBD>h4<68>0 <0C>o<EFBFBD>ۿw<DBBF>]<5D><>~MJX<><58>?<3F>m)%J)<29>RH)q<1C><>!ĽV<C4BD><56>ݴ<EFBFBD><EFBFBD><E4B4A2><EFBFBD><EFBFBD>Z<EFBFBD><5A><EFBFBD>$<24><><EFBFBD><04>G<EFBFBD>[RʗVWW? <0B><><EFBFBD><EFBFBD>Ƙs<C698><73>,)<29><12><>,<2C>,<2C>!<21><00><>x<><78>DQ<44><51><EFBFBD><EFBFBD>(<0E>5<EFBFBD><35>}<7D> <0A>˲&<26>TYEQ<45><51>)EQ<45><51>9EQ`<60><><EFBFBD>lz@ <0A><> <20>cz<63>^<5E><>z<EFBFBD>.U<><55>8::boo<6F><<3C>Ͻm<CFBD>e<EFBFBD><16><>J)<1A><06>7s <0B>0|,<2C>@A<18><>iz<04>oZ<6F><5A><EFBFBD><EFBFBD>bP<62>߲<EFBFBD>s-8[<5B>, !<21><>Z<EFBFBD>.#<23>TA<10><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Bw<><77><EFBFBD>e<><65><EFBFBD>x<0E>?᳙U0<55>y<EFBFBD><79><EFBFBD><<1C><>N<7F><4E>N<><4E><EFBFBD><EFBFBD>666<36><36>Z<EFBFBD>E<>U<EFBFBD><55>s<EFBFBD><73><EFBFBD>^ZZ<5A>iccß<63><C39F>{<7B>q<EFBFBD><71>b<EFBFBD>+<2B>(<28>.^<5E>b<><62>j}~<0E>Y^^<5E><13>1<EFBFBD><31><EFBFBD>x<EFBFBD><78>1p[)<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>܄xƘ'ƕ<02>1<EFBFBD>yNY<4E><59><EFBFBD>@><00><>m<EFBFBD><6D>DZ<44><5A>`~<7E>B)<29><><EFBFBD><EFBFBD>T<1F><><EFBFBD>4M)<29><><EFBFBD>(<28>`&I<><49><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)% 6 <20>$1<><31><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>>P<14><>ͫ<EFBFBD><CDAB><EFBFBD><EFBFBD>7o<37>3<EFBFBD><33><EFBFBD><07><>8FJ<46>ֺ|<7C><>џc<D19F><63>ٶ<EFBFBD>_nܸٶ=<3D><>e <20>0<EFBFBD>ΕH<08><>t<EFBFBD>7<EFBFBD><37>,<2C><><EFBFBD><EFBFBD><EFBFBD>ӓ<EFBFBD><D393>{<7B>1<EFBFBD>0<EFBFBD>ի<EFBFBD><D5AB><EFBFBD>i-<2D><>IB@<40><><EFBFBD>#<23><1C>ܧ0<>F<EFBFBD>K'<27><><EFBFBD>RJ<52><4A><EFBFBD><EFBFBD>ֺ\__<5F>$<24><><EFBFBD>β,<1C>Ak<41><6B>8<EFBFBD><38>Zc<5A><63><EFBFBD><EFBFBD><EFBFBD>3s`ss<73><73>(<28>nGQD<51>$<24><>y<EFBFBD>_v<5F><76>f<EFBFBD><66><EFBFBD><EFBFBD>u]<5D><>¶mc<6D>6B<36>s<EFBFBD><73>^J<> <0A>;3<00><>^]YYy=<3D>cvvvH<76>4<03>r]<5D><>n<EFBFBD><6E><EFBFBD>}<7D> <09>W<EFBFBD>j[><3E>J<EFBFBD><17><><EFBFBD><EFBFBD>Y<EFBFBD><59><EFBFBD>`@<40>e<EFBFBD><65><1A><>0$<24>2<0E>8<07>y<EFBFBD>h4b4M<><4D><EFBFBD><EFBFBD>֭[<5B>xo9<6F><39><`vww1Ơ<31>&<26>"j<>Z6<0E><>ߟh<DF9F>bV_<56>J<EFBFBD>qB<><42><EFBFBD><EFBFBD><EFBFBD>|<7C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0E> <><7F><EFBFBD>6<EFBFBD>R<EFBFBD><52><EFBFBD>p<EFBFBD><70><EFBFBD><EFBFBD>q<EFBFBD><71><EFBFBD>~0<><`۶<><DBB6><EFBFBD><EFBFBD>^<5E><07><><EFBFBD><EFBFBD>[<5B><1E><11><<3C> <0F><><EFBFBD><EFBFBD><03><>?j<>g}ͶIEND<4E>B`<60>
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/forum_unread.gif forums//site/static/beta5/pics/forum_unread.gif
--- beta5//site/static/beta5/pics/forum_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/forum_unread.gif 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,3 @@
+GIF89a <00><><00><><10><><12><><16><><16><><17><><1A><><1E><><1D><><1E><> <20><>"<22><>"<22><>#<23><>'<27><>*<2A><>2<EFBFBD><32>*<2A><>+<2B><>3<EFBFBD><33>+<2B><>5<EFBFBD><35>6<EFBFBD><36>/<2F><>8<EFBFBD><38>0<EFBFBD><30>4<EFBFBD><34>:<3A><>4<EFBFBD><34>5<EFBFBD><35>><3E><>7<EFBFBD><37>?<3F><>=<3D><>8<EFBFBD><38>><3E><>;<3B><>B<EFBFBD><42><<3C><>=<3D><>><3E><>E<EFBFBD><45>A<EFBFBD><41>B<EFBFBD><42>H<EFBFBD><48>B<EFBFBD><42>C<EFBFBD><43>D<EFBFBD><44>L<EFBFBD><4C>E<EFBFBD><45>G<EFBFBD><47>F<EFBFBD><46>H<EFBFBD><48>I<EFBFBD><49>O<EFBFBD><4F>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>O<EFBFBD><4F>P<EFBFBD><50>R<EFBFBD><52>U<EFBFBD><55>U<EFBFBD><55>V<EFBFBD><56>}<7D><>X<EFBFBD><58>X<EFBFBD><58>W<EFBFBD><57>X<EFBFBD><58>Y<EFBFBD><59>Z<EFBFBD>҃<EFBFBD>Ն<EFBFBD><D586>]<5D><>^<5E>ս<EFBFBD><D5BD>u<EFBFBD><75>^<5E><>`<60>Շ<EFBFBD><D587><EFBFBD><7F>`<60><>n<EFBFBD>׍<EFBFBD>؈<EFBFBD><D888>d<EFBFBD>ג<EFBFBD><D792>g<EFBFBD>ؚ<EFBFBD><D89A>e<EFBFBD>ח<EFBFBD><D797>e<EFBFBD>ם<EFBFBD>ע<EFBFBD><D7A2>l<EFBFBD><6C><EFBFBD><EFBFBD>ڤ<EFBFBD><DAA4>j<EFBFBD>چ<EFBFBD>ب<EFBFBD>ۧ<EFBFBD>ح<EFBFBD><D8AD>k<EFBFBD>ز<EFBFBD><D8B2>l<EFBFBD><6C>n<EFBFBD><6E>o<EFBFBD><6F>p<EFBFBD>ڸ<EFBFBD>݂<EFBFBD><DD82>u<EFBFBD>߽<EFBFBD><DFBD>q<EFBFBD>܁<EFBFBD><DC81>x<EFBFBD>݄<EFBFBD><DD84>t<EFBFBD>߇<EFBFBD>݂<EFBFBD><DD82>y<EFBFBD><79><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD>߅<EFBFBD><DF85><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>|<7C><>|<7C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>~<7E><><EFBFBD><EFBFBD>ߕ<EFBFBD><DF95><EFBFBD><EFBFBD>ߘ<EFBFBD><DF98><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߝ<EFBFBD><DF9D><EFBFBD><EFBFBD>ߠ<EFBFBD>ߥ<EFBFBD><DFA5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ߨ<EFBFBD><DFA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#J<>x<10>WI<57>T<>+<18>^<5E>n<EFBFBD><6E>5<EFBFBD>T(L<>*H<>+<2B><13><><EFBFBD>񪵪Ӥ=g<>0<19><03>B%<<3C><>"<22>N<EFBFBD>#Bd<42><64>A<>dZXJGn<04><><13>РC<D0A0>5z<04><>(cӪ]˶-Am<>A<EFBFBD>#<10>4hΚ1S<31> <0C>1_<31>^<5E>Z<EFBFBD><5A>O+ S`ʤ<>)R<>2X<32><08>qj!D|HH<48> )Ll<4C>0<EFBFBD><01>@1|Sǔ<17><><EFBFBD>ȡ<EFBFBD>Ǐ F<>.i┊<69><E2948A><EFBFBD><EFBFBD><1B>Pd <20>,Z<><5A>a#"M<><4D>Q<EFBFBD><51>@<40>h=<3D>$V<><56><EFBFBD>g͖\%+<2B>KV<4B>H<EFBFBD>F@<40>g<EFBFBD><11><>,<01>3'<27><>"9h<39>0q<30><71><EFBFBD>!l<><6C><02>Q<EFBFBD>
+(<28><><EFBFBD>T@<40>t CQ<43><51><EFBFBD>@a<>`<60>RT<52><54>\<5C>A<EFBFBD>k(܉(<28><><EFBFBD><EFBFBD> ;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/forum_unread.png forums//site/static/beta5/pics/forum_unread.png
--- beta5//site/static/beta5/pics/forum_unread.png 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/forum_unread.png 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,8 @@
+<2B>PNG
+
+ IHDR szz<7A>bKGD<00><00><00><><EFBFBD><EFBFBD><EFBFBD> pHYs  <00><>tIME<07>  0*<2A>f<EFBFBD>IDATX<54><58><EFBFBD><EFBFBD>kU<14>?w~<7E><>lv7<76><37>ش<EFBFBD><D8B4>m<EFBFBD>4mQ<6D>}4hѪ<68><D1AA><EFBFBD>G+jAD<><0F><>`)>E}<7D>C}<7D><><EFBFBD><17>Z<EFBFBD><5A>XmK<6D>j<EFBFBD>ִI!M7;;sg<73>w<><77><EFBFBD><EFBFBD>M_TȁÝ9̜<39><CC9C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>mؿl<D8BF>SPM1<4D>aM<61><>$<24><><EFBFBD><EFBFBD>#<23>_QSX<53><58>p<><70>~[<5B><14> <09><><EFBFBD>̓<EFBFBD><CD83><EFBFBD>g1_a<5F>Ůc<C5AE>v<EFBFBD><76><EFBFBD>+Wz<57><7A>_z<5F><7A>N<EFBFBD><4E>,qq<71>C<EFBFBD>5l<35> <09><><EFBFBD><05><08>H<>D<EFBFBD>J@<40><>$<24> <09>R<EFBFBD><52>%<25>E`0{<7B> <00>^<5E><>*8&Ȉ<><C888>[r<14>]<5D>E Hc<48>I<EFBFBD>#<23>Ch.<2E>lA<6C>A<><41>j<EFBFBD><6A><EFBFBD>
+0<><1D><><11><>4<EFBFBD>p<>{&M<>f<EFBFBD><66><EFBFBD>x<05>?@<40><>V<EFBFBD><56><EFBFBD><10>hR<><52>'<27><><EFBFBD>Q<EFBFBD><51><01><>?<3F><><EFBFBD>2<EFBFBD>V<00><07><><EFBFBD>
+=}<7D><>6<18><>c<EFBFBD><63><01><>F<1B>8<EFBFBD>-O<>#<23><>W<EFBFBD><57><EFBFBD>t6<7F>T薜<54>)%'?==<><7F><EFBFBD>i<EFBFBD><16> <18><><EFBFBD><EFBFBD><06><><15><>>n<13><><15><>m<EFBFBD>X'<27> <20><><EFBFBD><EFBFBD><11><><EFBFBD><EFBFBD><1C>!<21><>1I<31>rJ<72>}<7D><>:<3A>O<EFBFBD><4F>W<EFBFBD><57><<10>Na<08>l<EFBFBD>ps`<60><><EFBFBD><EFBFBD>v<EFBFBD><76><14>3#v|<7C><>",<2C>b<><62>C <0C>A<EFBFBD>kZ<6B><5A>1<EFBFBD> nn<6E>g<EFBFBD>~<7E><>6<EFBFBD>w<EFBFBD>R_<52><5F>@<40> "<1D>!*M<><4D><EFBFBD><EFBFBD><EFBFBD>n<00>T <<17>Eh<45>,<2C>x%<25>W@s<><73><0E>
+!\<5C>8ӄ$<24>T<EFBFBD>j<EFBFBD>6<EFBFBD>\<5C>@<40>ӧ<><D3A7>X=<3D><><EFBFBD>`1<>]<5D>4s<>z2<7A>h<EFBFBD>'<12><>֍<EFBFBD>$<24>":>j<><6A>jUAw<41>W<19>
+F<19>i<><69><03><>t!6<>K<EFBFBD><4B>C<05> <09> <09><><EFBFBD><EFBFBD>̱uz<75>SK<53><4B>/<2F>*B<><42>GkGX^(<28><>_<EFBFBD><5F><EFBFBD>l4/f:P<>du<64>4<EFBFBD><34><EFBFBD><08>)I<>-<2D><>7<><37>cg۹^<00>NE<4E>fuˆ<><CB86><EFBFBD>|O*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Q<1D>ΰ<EFBFBD><CEB0>A<EFBFBD><41>[<5B><>n~,;<12>'<27><>k@}`<60><>8|<7C><>* <0C>$A<>8<EFBFBD><38>RM1Lm<4C>Qr<51>{<7B>[@0 0l<30>,00-<2D><05><><EFBFBD><EFBFBD>rf<72>w<EFBFBD>/ <>y<EFBFBD>|<7C>;<3B><>q<16>_<><17><><EFBFBD><EFBFBD><17>G<EFBFBD><47>*<2A>y<EFBFBD><79>e<EFBFBD>))CMO<19><><EFBFBD>^<5E>0<EFBFBD>ԭ<0E><>_-<2D>Lh<4C><68><07>(U!<21><0E><>4E<34>DS/<2F>u;<1B>jd:<3A><>q!PYo<59><12>Шb<D0A8>;<3B>eFu|x{<7B><>[P<>QO<51><4F>H=Y<>jW
+T6z<01>{<7B>Z<EFBFBD><5A><EFBFBD><11>~<7E>(<28>7<EFBFBD>rC;d<>.fps<70>nD<6E>'aiw<69><77><EFBFBD>6<EFBFBD><36>v<>(m<10>b<EFBFBD><62><EFBFBD><>ց<EFBFBD><D681>;<3B><><EFBFBD>Z@<01><> .<00><1B><1B><><EFBFBD><EFBFBD><1D><><EFBFBD><06>IEND<4E>B`<60>
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/post_cn.gif forums//site/static/beta5/pics/post_cn.gif
--- beta5//site/static/beta5/pics/post_cn.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/post_cn.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,9 @@
+GIF89a <00><>"$), -!0$3%8*:,;-<.>.?/?0@1A2C4E4F5G6G7H8I9J9L:K:M;N<O=P>Q?R@S@TAUBUBVCWDXEYFZG[H\H^I]I_J^J`K_KaL`LbMfKcNdOePfQjOgQiRhRlQiSnRkToSpSrUsVnX pYuXr[vYs\t]w^{]v^ y` ~`|c<03>a{b<0E>h<15>j <EFBFBD>l<02>j<03>k<0F>m<04>l<10>n<05>m<11>n<13>o <09>o<14>p<15>q <0C>r<0E>q<17>t<11>s<1A>u<12>v<13>v<1D>w<15>w<1E>x<16>y <20>z<18>{<1A>|<1B>|$<24>}<1C>~<1D><1E>'<27><><1F><>(<28><>!<21><>)<29><>"<22><>*<2A><>#<23><>+<2B><>$<24><>,<2C><>-<2D><>.<2E><>.<2E><>5<EFBFBD><35>/<2F><>0<EFBFBD><30>1<EFBFBD><31>2<EFBFBD><32>2<EFBFBD><32>3<EFBFBD><33>3<EFBFBD><33>4<EFBFBD><34>4<EFBFBD><34>5<EFBFBD><35><<3C><>6<EFBFBD><36>7<EFBFBD><37>8<EFBFBD><38>9<EFBFBD><39>:<3A><>A<EFBFBD><41>B<EFBFBD><42>C<EFBFBD><43>D<EFBFBD><44>E<EFBFBD><45>F<EFBFBD><46>G<EFBFBD><47>H<EFBFBD><48>I<EFBFBD><49>J<EFBFBD><4A>K<EFBFBD><4B>Q<EFBFBD><51>W<EFBFBD><57>R<EFBFBD><52>X<EFBFBD><58>S<EFBFBD><53>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>X<EFBFBD><58>_<EFBFBD><5F>`<60><>a<EFBFBD><61>b<EFBFBD><62>h«cìd¬jĭeíkŮfįlŰmƱnDzoɳp̷{лѼ<7F>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD>‹<EFBFBD>Ì<EFBFBD>č<EFBFBD>Ŕ<EFBFBD>Ȗ<EFBFBD>ɗ<EFBFBD>ʘ<EFBFBD>˙<EFBFBD>̚<EFBFBD>͛<EFBFBD>͡<EFBFBD>΢<EFBFBD>ϣ<EFBFBD>Х<EFBFBD>Ҧ<EFBFBD>Ԯ<EFBFBD><D4AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>C<EFBFBD>Y"J<><4A><EFBFBD>!<21>,W<><57><EFBFBD><EFBFBD><EFBFBD>8 ф<>h1K@<40><05><><EFBFBD><EFBFBD>9rڨS<><53><EFBFBD>;<3B><19>i<08>;y<><79><EFBFBD><EFBFBD>F<EFBFBD><46><EFBFBD>
+<2B><><EFBFBD><EFBFBD>t#C<><43>81<02><><EFBFBD>6e<36><1E>"g<12>E<EFBFBD>-<2D><> <09>K<>p<EFBFBD>CG<43>Q<EFBFBD>Y<EFBFBD>h<EFBFBD>K<EFBFBD>R4b<34><62><EFBFBD>DO?w^<5E><><EFBFBD><EFBFBD>'N<>4%<25><><EFBFBD>@ ;j<00>"<22><>;E<>B<EFBFBD>ʔgQ<67>@M<>A<>?~ <0C><>pL<70>)<29>
+e
+*R<><=)<00><> ><3E><18> <08>K4<4B><34><EFBFBD>J<EFBFBD>
+UnS<6E>:5R<35>`<60><><EFBFBD><EFBFBD><EFBFBD><y<>g<EFBFBD>)<05><><EFBFBD><EFBFBD><EFBFBD>ʔ<EFBFBD>4d<34>ȡÆd?r<>H<EFBFBD>D<EFBFBD>q9^
+v<><15><>NpA!<21><><EFBFBD> 6<EFBFBD><EFBFBD>:<3A>`<60>B<>w<EFBFBD>-<2D><14>@0A<1B>B 4<><34>X 9<><39>^AR<41><12>,<2C><>b<><01>%<25><><EFBFBD>
+;ư<> p<16>ْD d0<64><30>t(B *<2A>@B<>'<27>@C~<7E><><EFBFBD>fW䢆8 <20><>8<>4xHB4`<60>SH8<16><>R^*<2A>pB<70>*<2A>A !t<>a,<2C><>+tE#<23><><EFBFBD><EFBFBD>,<2C><><EFBFBD>
++<2B><> L<>!Tq<54>$<24>4R<34>r<0E>E0<45>0s<30>1<EFBFBD>L/<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\1I%<25>,<2C>H<1F>d<> <20>,<2C>L2<4C><32>2J80A<1B>Q<EFBFBD>\cRFU<>I<EFBFBD><49>,#L/Z8<5A>A<03>^<5E> (sI2<49><1C><15>+̨z .O<08>@<40>c<EFBFBD>ҙ'<27>Tr<07> iq<69>1<EFBFBD><31><EFBFBD>F<04><><EFBFBD>(<28><><EFBFBD><EFBFBD>%t\<5C>Я<EFBFBD><D0AF><EFBFBD><EFBFBD>*<2A>qJ,<2C>xF<78><1A>><3E>E#<23><><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD>$ ;l<>@VhaFZ<46>|<7C><>+<2B>l<EFBFBD><6C>;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/post_co.gif forums//site/static/beta5/pics/post_co.gif
--- beta5//site/static/beta5/pics/post_co.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/post_co.gif 2011-02-05 10:10:02.714335002 +0100
@@ -0,0 +1,6 @@
+GIF89a <00><>...666:::===>>>???@@@BBBDDDEEEHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmppprrrssstttuuuvvvwwwxxxzzz|||}}}~~~<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\<5C><><EFBFBD>Ç <1B> b<>H<EFBFBD>"D<><04><>#bA@<40>T<EFBFBD>Be<42><65>(O<>0QR<51>GG<47><<3C><05>+ULBy<42>d  /<17><><EFBFBD><EFBFBD>K.[hB<01>d
+<2B>&L<> <09><><EFBFBD><EFBFBD>1b„<01><>˓%`,<2C>"<05>J%S<13>`b<>L<EFBFBD>2dƀI<C680>BD 2<><32>5(B!hԤ<19>ƌ<18><>XA<58>I<EFBFBD><49>*<2A><>8ȣ<38><C8A3>6<EFBFBD>٬Qs<51>@<40>&<16><><EFBFBD><EFBFBD>l<EFBFBD>"T<02><13>u8o<38>0A<00><><EFBFBD>-^<5E><><EFBFBD>TI<0F>Q<EFBFBD>>G<><47>118<>B /j4<6A><34><EFBFBD>I<EFBFBD><49>X<EFBFBD>hW<68>ĉ<EFBFBD>'O<><4F><EFBFBD><EFBFBD>0<EFBFBD>D<EFBFBD>,Z<><5A><EFBFBD>d
+<2B>&i<07>Ȳ'<0F> H<>pA<70><41>$<24>֜
+Ɛ<>OA[<5B>Q<EFBFBD> 0<>@X<><1F><10> <09><><EFBFBD><EFBFBD> <EFBFBD>)H\<5C><>
+0<><30>~`<60><> <20>0 $<24>`c 6Tj#zF T<><54><EFBFBD>X<>A<1F>B"4<><34>VLaĂ`<60>!A `<60><>t<>A<EFBFBD><1E><><EFBFBD>_<><5F><EFBFBD>WP1eAZ<41>!D<06>Y@<04>)<29>l<>e8\<5C>Ua<><10><><EFBFBD>x<<3C><><EFBFBD>3<>`<60>`<60>AZt<5A>E<15>}t<>"<22>R<> <20><02>c<> <20>_<>Յ<16>M<EFBFBD>&<12>4<EFBFBD><34>"<22>RH nаbh<><68>h<><11>Y<>PU<18>8<EFBFBD><08><><EFBFBD><11> 4<>=<3D><>F<1A>zq<7A><71><EFBFBD><EFBFBD><01>#<23>$R<>0`<60><16><>mp+<2B><13><12><><1C>*bW2<57><32>o<>G<>eD<65>C<<3C><><08>|<7C><><EFBFBD>H<>q<03><>D<EFBFBD><44>!a!<21><>u<><75>op!<04>j QiR4]<5D><14>=<04>G4<47>l<EFBFBD>G;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/post_on.gif forums//site/static/beta5/pics/post_on.gif
--- beta5//site/static/beta5/pics/post_on.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/post_on.gif 2011-02-05 10:10:02.684335002 +0100
@@ -0,0 +1,11 @@
+GIF89a <00><>))& ( , 2%5(7)9+:,;-<.>.?/?0@1A2C4E4F5G6G7H8I9J9L:M;N<O=Q?R@TATAUBVCWDXE\CYFZG[H\H^I_J`KaLbMcNgLdOcO ePfQjOhRlQnRoSlUpSqTlVrUsVpYqZqZ xZwZv]t]w^{]v^ u^w_
+za~`{b{b}d}d<11>f~ef<13>i <0C>l<02>j<03>m<04>k<05>n<05>n<13>o <09>p
+<2B>q <0C>q<16>r<0E>s<0F>r<19>t<11>t<1B>u<12>u<1C>v<13>w<15>w<1E>x<16>y<17>y <20>z<18>{<1A>|<1B>|$<24>}<1C>~<1D>,<2C>},<2C>~&<26><1E>'<27><><1F><>!<21><>)<29><>"<22><>*<2A><>#<23><>+<2B><>$<24><>,<2C><>-<2D><>-<2D><>.<2E><>/<2F><>0<EFBFBD><30>0<EFBFBD><30>1<EFBFBD><31>1<EFBFBD><31>2<EFBFBD><32>2<EFBFBD><32>9<EFBFBD><39>3<EFBFBD><33>3<EFBFBD><33>:<3A><>4<EFBFBD><34>4<EFBFBD><34>;<3B><>5<EFBFBD><35>5<EFBFBD><35><<3C><>6<EFBFBD><36>6<EFBFBD><36>=<3D><>7<EFBFBD><37>7<EFBFBD><37>><3E><>8<EFBFBD><38>?<3F><>9<EFBFBD><39>@<40><>@<40><>:<3A><>A<EFBFBD><41>G<EFBFBD><47>B<EFBFBD><42>C<EFBFBD><43>D<EFBFBD><44>E<EFBFBD><45>F<EFBFBD><46>G<EFBFBD><47>H<EFBFBD><48>I<EFBFBD><49>J<EFBFBD><4A>P<EFBFBD><50>K<EFBFBD><4B>Q<EFBFBD><51>L<EFBFBD><4C>R<EFBFBD><52>S<EFBFBD><53>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>Y<EFBFBD><59>_<EFBFBD><5F>`<60><>f<EFBFBD><66>a<EFBFBD><61>b«cìd¬jįlŰmƱnDzoʴq˵r̶s̷{ι}Ϻ~<7E>č<EFBFBD>Ŕ<EFBFBD>̚<EFBFBD>̠<EFBFBD>͡<EFBFBD>ϣ<EFBFBD>Х<EFBFBD>Ҧ<EFBFBD>ӧ<EFBFBD>Ԯ<EFBFBD><D4AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\<5C><10>Ç r)c<> 1<18>d<EFBFBD><12> 1p<02><><EFBFBD><EFBFBD>d9p<39><70><EFBFBD>±#<23>4<EFBFBD><10>$D =z<><7A>i<EFBFBD>FL˅W<CB85>T<EFBFBD>$)R<>Du<44>H(<28><>:mҀ<6D><D280><EFBFBD>J P<><50>f<EFBFBD>T<EFBFBD>Ƃ<1F><00>sRN<1B> <09><>1e<31><65>(R<>ڼX𠮍B<F0A0AE8D><00><><13> U<>g><3E>JE<4A>Ԟ<11>><3E><><EFBFBD><EFBFBD>ȱ'<27>d9<64><05><>X<EFBFBD>\ifcƒ(<08>t<EFBFBD><74>͓*<2A><><EFBFBD>"<22>V<EFBFBD>X<EFBFBD>a<EFBFBD>A@!<21> <16>H<EFBFBD>d<EFBFBD>P=y<><79><EFBFBD>bPϭ[<5B><>עǀ<><C780>6$<24><>)Q<>@zPz<50>x<EFBFBD><78><EFBFBD>]<5D>x<EFBFBD><78>
+<2B><>Bt<1D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> @}<7D><>A;<3B><>#a<><61><EFBFBD><EFBFBD>3<EFBFBD> lPB L<>J)<29><><EFBFBD>4E<34>@[D"<22>0<EFBFBD>(<28>2<>q@<04>P<EFBFBD><16>,2<>
+)<00>Fy<>A\}<7D>c
+B@ `<60><> -<2D> <20> M<><4D> 2<<3C>[T<>(<28>(<28>A2<>WB #<23><><EFBFBD> I@a 0<><30><18><>YA<59>(<00>P<10><>X<EFBFBD><58>:<3A> <19><>U<EFBFBD>_<EFBFBD><18><>@<40>ApB<>-<2D>0<EFBFBD><<3C>P<EFBFBD><15>(B<>b<18><><32><C688><12><><EFBFBD>%<25>5<>[ <20><>#<23><><EFBFBD><EFBFBD>A[<5B><>L<EFBFBD><4C> @A
+<1D>p”1<C294><31>bt<62><74>$x<>I<1B>8S<38>P<><50>
+X<>iD<19><>2
+'<27>R<>AX<41>"<22>4<EFBFBD>X*k &<26><>C C<>a<EFBFBD>+<2B><>҉%j<>6<EFBFBD><15>H<03>1<EFBFBD>R<EFBFBD><52> 0<00><>+<2B><><EFBFBD>J)<29><>!,<2C><>Bs,<14>P<1A><>R<EFBFBD>*<2A><>q<EFBFBD>BV<42><56> 3<><33>I<EFBFBD>t<><74><EFBFBD>-<2D><><EFBFBD>
+Vt<56><74>l䒌0z<30><01>-<2D><>r"b<>l2<6C>bD<12>#<23><><EFBFBD><EFBFBD><1B>L<EFBFBD>WTA<54><41>H'<27><>@;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/post_oo.gif forums//site/static/beta5/pics/post_oo.gif
--- beta5//site/static/beta5/pics/post_oo.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/post_oo.gif 2011-02-05 10:10:02.684335002 +0100
@@ -0,0 +1,7 @@
+GIF89a <00><>---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\<5C>P<EFBFBD>Ç&|H<><48>2cĄ<63>Q"A)T޼q<DEBC>f<EFBFBD><66>41<><31>(Q
+<2B>9r<39><72>qC<71><43><EFBFBD>3e2^<5E><><EFBFBD><EFBFBD>;v<><76><EFBFBD>$Ȗ5hR<68><52>³<EFBFBD><C2B3>=z<><7A><EFBFBD>C<EFBFBD><43><EFBFBD> Vpa<70><06>E1[<5B><1E>R<EFBFBD><52>?}<7D><><EFBFBD>R<EFBFBD>C<1E><><EFBFBD><EFBFBD>*b?Z$HP<48>@<>xh<78><68><03>J<><4A>i<EFBFBD><69>̘0yJ1D<31>P<EFBFBD>B<EFBFBD><42>$pqXĈ&t<>,<2C><><EFBFBD>K<EFBFBD>R<14>N<EFBFBD><4E><10>0D<30>(aʝ:<3A><><EFBFBD>Y<>G<> _<>E<EFBFBD> <0C>(RL<52>s<EFBFBD><73>L6i.<2E>V$I<12>H<EFBFBD><1F>aP<61>D<EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD>c4ez7<7A>D<EFBFBD><44>*U<><55>i<EFBFBD>C /<2F><00><>&ʓ0l$<24>[$<24>T<EFBFBD><54> |p<><0E><><EFBFBD> 1<><31> kA ?<3F><>To<54>dbx<00>8<><38><EFBFBD> 1<>P<EFBFBD>cA<63><41><EFBFBD> N@<40><>%<>p<EFBFBD> <1F>@<40> =<01><>70a<30>D<>0%<25><>I$ <20> "<22><><EFBFBD>
+(<28>pC:<3A><>ÖD<C396>!<21>l<><6C>G&Z\<5C> 5<>0<EFBFBD> 2<>p<EFBFBD><<3C><><EFBFBD>Fh<01>y<EFBFBD>I<EFBFBD><49>'\<5C>Y)<<3C>&;<3B><>Ip<49><70>ι<>g*<2A><><EFBFBD> <0B><><EFBFBD> <0B><16><>a<><61>uı<75>X<EFBFBD><58>
+<2B><><03>5<10><><12>c<00><>Z<EFBFBD><5A>&Y<><59>2<EFBFBD>f<><66>C<EFBFBD>I<EFBFBD><49><EFBFBD>~<7E><>d<EFBFBD><14><>*J$`<10><1E>F"<22>Hzp<7A><70><14><> (\X<><58>
+D4<44>F#<23> bmZ<>zl<1A><><EFBFBD>ID<><44><1C><<3C>"<22>b<><62>Rp<52>
+&u<><75>%<25>@<40>o<1B><><04><> {$<24><>Wl<57>?;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_locked.gif forums//site/static/beta5/pics/topic_locked.gif
--- beta5//site/static/beta5/pics/topic_locked.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_locked.gif 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,5 @@
+GIF89a <00>
+
+
+  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#J<><08>ԫV<D4AB>(<1A>$<24><><y<>t5<74>(p7~<7E><>mK<6D><0F> <20><><EFBFBD><EFBFBD>K<EFBFBD>hѧj<D1A7>filT<0E>'<27><><EFBFBD><EFBFBD><EFBFBD>C<EFBFBD>R<EFBFBD>es<08>9<EFBFBD><39>EJ<45>|y)<29><>$<24><><EFBFBD><EFBFBD><EFBFBD>RS6DQs<51><73><EFBFBD>2<EFBFBD>)<29><>5<EFBFBD>׬]<5D><><EFBFBD><EFBFBD>%<25><>'F;<3B>S<EFBFBD><53><EFBFBD>߿<EFBFBD><DFBF>a<EFBFBD>H)۷È<><7F><EFBFBD><10>BЪI<D0AA>L9<4C>/Ux <20>A欳g<E6ACB3><67>t<EFBFBD>2<EFBFBD><06>`<60>R<EFBFBD>&F<><46>,W<>D<EFBFBD><44>G<>/`<60>|<7C>҅<EFBFBD>,W<>R}<7D><><EFBFBD><EFBFBD><EFBFBD>_<EFBFBD>v<EFBFBD><76>E+<2B>+V<>N<EFBFBD><4E>4<06>]<5D>v<EFBFBD><76>5+<16>T<EFBFBD>H5<48><35>T<EFBFBD>a<EFBFBD>N<EFBFBD>L<EFBFBD><12><>ӦL<D3A6>*I<>KD+_<>x<EFBFBD>҅ <0B>-[h<>EO<>&<26><><EFBFBD> &;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_locked.png forums//site/static/beta5/pics/topic_locked.png
--- beta5//site/static/beta5/pics/topic_locked.png 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_locked.png 2011-02-05 10:10:02.684335002 +0100
@@ -0,0 +1,6 @@
+<2B>PNG
+
+ IHDR <00>s<EFBFBD>bKGD<00><><EFBFBD>̿ pHYs  <00><>tIME<07> 
+m<>)X<01>IDATH<54><48><EFBFBD>=hQ<10>{^<5E><>%<25>$<10>=J!H
+ E1<>,R<>[Y<><59>D<EFBFBD>F<EFBFBD><46>hP<><14><><EFBFBD>B<EFBFBD>@<40>4)<29>tz"\<5C>xz1<7A><31><EFBFBD>swo?޳09<30><39><EFBFBD><EFBFBD>Ke<4B>y<EFBFBD>¾<EFBFBD><C2BE><EFBFBD>7<EFBFBD>v<><76><EFBFBD><EFBFBD><EFBFBD><EFBFBD>]C;u`ZZ<>K鱹x<E9B1B9><78><EFBFBD><01><><EFBFBD>{<7B><>%iK[~<7E><><EFBFBD><EFBFBD>OO<0E>ۣڜ<19><<3C><><1E><><EFBFBD>Fg<46>{<7B>h0<68>]<5D>[<5B>ش
+<10>?<3F><><EFBFBD><1B>Z<EFBFBD><5A><EFBFBD>܉<EFBFBD>a&N<>\`<60><><EFBFBD><66><DFAD><EFBFBD><EFBFBD>w<EFBFBD>Z<EFBFBD>8G<38>.<2E>Y/ <0B><>2<EFBFBD>Hm<48>M<EFBFBD><00>D/E>,<2C>x<EFBFBD><78>),,<14>?<3F><><EFBFBD><7F><01><00><><elBj<42>R<15>T<16>C<EFBFBD><43>G@(<28><><EFBFBD><EFBFBD>"&<26>WF'D<><44>S<EFBFBD>L~<7E><>?pe<70><65><EFBFBD><16><>0X<30>dN/> <09>4<EFBFBD><34>S<><53> jx<6A>L9%<25><18><>,?>n<<3C>:Cퟀ<43><ED9F80>,<2C>MW<4D>-<2D><><EFBFBD><EFBFBD>U<EFBFBD><55><0F>X<EFBFBD>.X<><58><EFBFBD>f% <0B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:&V<><56> <09><><EFBFBD>H<EFBFBD>ǘxDT<44><54><EFBFBD><00><> Hjx<6A><08>f<EFBFBD><66>A<>D<03><><EFBFBD> <11><08>6 <09>$<24><><EFBFBD><EFBFBD><EFBFBD><EC91A2><EFBFBD>)<12>[<5B>n`;ž1r<31>EXᗻ<58>E<12><>͗<EFBFBD>tC<74>lt<6C>]{<7B>׌H<D78C><48>n zZ<7A><5A>G<7F>q<EFBFBD><71><EFBFBD>o<EFBFBD><6F><EFBFBD>j<0E><>IEND<4E>B`<60>
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_poll.gif forums//site/static/beta5/pics/topic_poll.gif
--- beta5//site/static/beta5/pics/topic_poll.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_poll.gif 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,9 @@
+GIF89a <00>m
+
+
+  !!!###$$$&&&---///111222666777888;;;<<<===>>>@@@AAABBBCCCEEEFFFGGGHHHIIIJJJLLLMMMNNNPPPRRRSSSTTTUUUWWWYYY]]]___```aaabbbcccdddeeekkklllmmmnnnooorrrssswwwzzz<7A><7A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
+ <0C><><16><>;NM?/<1A><>Ilh[D <09><>HjfYB<59><42>GidWA<19><><17><><EFBFBD><EFBFBD>ŏ'PSOK(<08><><EFBFBD>Đ
+-ejd_- J<>ΐ *agb],<2C><><EFBFBD>ۏA^f]+<2B><><EFBFBD><EFBFBD>
+ pP <0C>q<EFBFBD><71>=[AD<41>#B<><42><02>߼<EFBFBD><DFBC>\xQ<78><51><EFBFBD><1E>̰<EFBFBD> #"8<><38><> /6P<>E<EFBFBD>7$<24><>"<22>$:F4m<34><6D><EFBFBD><EFBFBD><EFBFBD>?EAo<41><6F> S<1E><><EFBFBD>PrܡcB<63>*4P`<60>挖!<21>fRX<11>F<EFBFBD><46>P^$<24>`dL*3>2
+<2B>@8p`"<03>)<29><><EFBFBD>A<EFBFBD><41><01>+V<1C><><EFBFBD> 8<>p<EFBFBD><70><EFBFBD>˘3k6;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_poll.png forums//site/static/beta5/pics/topic_poll.png
--- beta5//site/static/beta5/pics/topic_poll.png 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_poll.png 2011-02-05 10:10:02.684335002 +0100
@@ -0,0 +1,7 @@
+<2B>PNG
+
+ IHDR szz<7A>bKGD<00><00><00><><EFBFBD><EFBFBD><EFBFBD> pHYs  <00><>tIME<07>  s( <09>IDATX<54><58><EFBFBD>Ok$U<14><EFBFBD>uuWu<57>PiB4 H<><48><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!!<21>,EA<>0<><30><EFBFBD><02><> <0C>r<EFBFBD><72><EFBFBD><EFBFBD><EFBFBD>E<EFBFBD> ѕ&n<> Ջ<><D58B><EFBFBD><EFBFBD><EFBFBD><EFBFBD>zﺘ<7A>&<26><>L'<27>a\<5C><><EFBFBD>n<EFBFBD><6E><EFBFBD>{<7B><><EFBFBD>^<5E><1D><><EFBFBD>!<21><0E>j<EFBFBD><6A><EFBFBD><EFBFBD>z<EFBFBD>T*<2A><>"<22><18><18>1<EFBFBD>o<EFBFBD>܏<EFBFBD>^<5E>{U<>wK <0B><>0<EFBFBD><0F><>c<11><02>9<EFBFBD><39><EFBFBD>k<><6B>EQ<45>i<EFBFBD>f<EFBFBD>K<EFBFBD><4B>:s<><73>GD<16>0|<7C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>\^^<5E><>lR<6C><52><EFBFBD>^<5E><>V<EFBFBD><56><EFBFBD><0E><>?<3F><>o<EFBFBD><6F><EFBFBD>W<EFBFBD>(<28><><EFBFBD>_<EFBFBD><5F>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD>;;;lll<6C><6C><EFBFBD>b|&"<22>\<5C>knIJU<4A>(
+)<29>k<>8<EFBFBD>P<><50><03><>GQ<47><51><EFBFBD>oc<>"<22>"RXk <06><> Uu<55>=eY<65><59><EFBFBD><EFBFBD><03>L&<26><>XZ<58>V5<08><>"<22><08><19><><EFBFBD>uqq<71><71><EFBFBD>ި<EFBFBD>^J <20>"<1A>F=<3D><><EFBFBD>KKK<4B>ooo<6F><6F> <20>2<EFBFBD>8<EFBFBD><38><EFBFBD><EFBFBD><EFBFBD>n<EFBFBD><6E><00><>1<EFBFBD>O<00><>}<7D>s<1F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><1A>z<EFBFBD>4M<34><4D><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"2<><32><EFBFBD>u{<7B><><EFBFBD>Q<EFBFBD>`0<><30>*<2A>Z<EFBFBD>,<2C>(
<1C>,<2C>&<26><> f
+w<><77>e<EFBFBD>7y<37><79>wvv<76><76><EFBFBD><1E>v<1B><><EFBFBD>}<7D>:[{A<><02>A<><41><EFBFBD>|/"ov:<1D><><EFBFBD><EFBFBD><<3C><><EFBFBD>-<2D>s<EFBFBD>D<EFBFBD>i <09>߆a<DF86><61><EFBFBD><EFBFBD>BX<42><58><18>5<EFBFBD><35><EFBFBD>$I<><49><EFBFBD>*<2A><><EFBFBD>2o۵Z<DBB5><5A>f<EFBFBD><66><EFBFBD><EFBFBD>k<EFBFBD><6B>k-<2D><><EFBFBD><EFBFBD><EFBFBD>}VVV<56>T*<2A><><EFBFBD><02>Hc<01><>N<EFBFBD><4E><EFBFBD>}F<><46> <09>%쨛M <0C><>CD&<26><>j<EFBFBD><6A>: ^<1F><>d<EFBFBD>V<EFBFBD>y<>VD&<26>c?c<>V<EFBFBD><56>w<00><>Q<EFBFBD>V<EFBFBD><56><EFBFBD>y<EFBFBD><79>Xq]<02><><EFBFBD>@<40><><EFBFBD>(<28><>`c<1F>eI<65>$ <0C><><EFBFBD><EFBFBD>G<EFBFBD><47><EFBFBD>q<EFBFBD>`0 M<>qLT<4C>ި<EFBFBD><DEA8>i |
+<><3E><><EFBFBD><EFBFBD><EFBFBD>s<ϛH<>k-<07><>m<EFBFBD><6D><EFBFBD>9<EFBFBD><39><EFBFBD>)<29>~k-<2D>n<EFBFBD>N<EFBFBD>CY<43>5U}<04><0E>2<EFBFBD><32><EFBFBD> <09>1<EFBFBD><0F><>*sss<73>*eYr<59>R<EFBFBD>1<EFBFBD>4MI<4D><49>7৻<37><E0A7BB>;<3B><><EFBFBD>?<3F>|<7C>r<EFBFBD><72><EFBFBD>IEND<4E>B`<60>
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s0_read.gif forums//site/static/beta5/pics/topic_s0_read.gif
--- beta5//site/static/beta5/pics/topic_s0_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s0_read.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,4 @@
+GIF89a <00>x'''(((***---000111222555666777<<<>>>???CCCDDDGGGIIIJJJKKKLLLMMMNNNRRRSSSTTTUUUWWW^^^```bbbcccdddfffkkklllmmmnnnqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>/=CB?:73-,)('$!
+<07>1SUQLJGCD850+)&$<11> <0C><>7SOOJHE>><3E>,,<2C> <14> <09>3XWV<57>UUSSMMKKDDAA<841<34>-<12>7vuupsp<73>tq޼<71><17> <EFBFBD>7kά!<21><><EFBFBD> C9<43>ܩs<DCA9>NE<4E><12>X<EFBFBD><58>oN<6F>8n<38><6E>Aa<41>ƓQ<><51>XG<0E>6rƜ<72><C69C><EFBFBD>&F<>-ᄔ<>F<EFBFBD><46>6m<36><6D><EFBFBD>F <0A>5><3E>E9<45>N<EFBFBD>7r<37><72><64>!K3<4B><33>#<23> 9hֈ<68>b<EFBFBD>֬<><D6AC><EFBFBD>i<EFBFBD>R<EFBFBD>3<>f<EFBFBD>|!q5<71>ĭ]<5D><>[<5B><>٥i׶}w<><77>v+^<5E>s<EFBFBD><73>3eΜ!3&<26><11>k<EFBFBD><6B>xP<1B>iҠ1C<31> <0C>-t <0B><><EFBFBD>r<EFBFBD><72>6<02><><EFBFBD>[f 0ZFb<><62>9oԴL7͚ڦO<DAA6>&<26><02><>|<7C>ܴA<DCB4>!2fƈs<><73>eC<65>%<25> <0C><> <1B>q)<29><><EFBFBD><EFBFBD> jC*<2A>=}#<23><><EFBFBD><EFBFBD>`(<28><><EFBFBD><EFBFBD>K<EFBFBD><4B>Y`V
+TP<01>P8<50>DHa<>D<00>C;<3B><>Åꀁ!h<><68> 6<><36>$"`@ <20><><04><>Ɍ4<C98C>h<EFBFBD><68>8<EFBFBD><38>H ;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s0_unread.gif forums//site/static/beta5/pics/topic_s0_unread.gif
--- beta5//site/static/beta5/pics/topic_s0_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s0_unread.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,2 @@
+GIF89a <00>v'#($*&-(0+1,2-506172<6>8?9C<!D="G@#IB$JC%KD%LE&NF'RJ)SK)TL*UM*WO+^U/`W0bY1cZ1d[2f\3ka5lb6mc6nd7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-;A@=851+*'&%" <06>/QSOJHEAB63.)'$"<10> <0B><>5QMMHFC<<<3C>**<2A><13> <08>1VUT<55>SSQQKKIIBB??:62/<2F>+<11>5tssnqn<71>roڴ<6F><DAB4>f<EFBFBD><66>6iʤs<> C7<43>ԙS<D499>NE<4E><12>X<EFBFBD><58>/Μ7l<37><6C>1a<31>ƓQ<><51>8<07><>5p”<70><C294><EFBFBD>&F<><><DD84>F<EFBFBD><46>6m<36>̹<06><>4><3E>EGΜ6p<36><70>T<EFBFBD>p<EFBFBD>!K3<4B>{<03><>8f҈<66>b<EFBFBD>֬<><D6AC><EFBFBD>Y<EFBFBD> 2<>d<EFBFBD>tq5<71>ĭ]<5D><>[<5B><>٥i׶}w<><77>t+^<5E>s-<2D>2cʔ<13>K<10>k<EFBFBD><6B>x<10><1A>gΘ!#F<><46>,t <0B><><EFBFBD>2<EFBFBD><32>5<02><><EFBFBD>;&<26>/XBR<>r<EFBFBD>8mд<<03>L<EFBFBD>ڦO<DAA6>&<26><02><>|<7C>ج1<D8AC><06>1d€<64>R<EFBFBD><52>eC<65>%<25> <0C>u<EFBFBD><1A>q)<29><><EFBFBD>E jC(<28>=m#]<5D><><EFBFBD>^({<7B><>eK<65><4B>W`V<> RH<52>N0<4E><30>FAB<><42><EFBFBD>9<><39>Å<16>`<60>!`<60><>$P <10><><00>bɌ4<C98C>h<EFBFBD><68>8<EFBFBD><38>H ;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s10_read.gif forums//site/static/beta5/pics/topic_s10_read.gif
--- beta5//site/static/beta5/pics/topic_s10_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s10_read.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,12 @@
+GIF89a <00><>
+
+
+ '''(((***---000111222555666777<<<===>>>???CCCDDDGGGIIIJJJKKKLLLNNNOOOPPPQQQRRRSSSTTTUUUVVVWWW^^^```bbbcccdddfffjjjkkklllmmmnnnpppqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A><>d<EFBFBD>'I<><08><><03> 2\<5C>H<EFBFBD><48>Ç 4X<34><00> <20>2h<32>t<EFBFBD>re
+<2B>#D~<7E><>QC<51>
+#<lؐ<6C>B˂<01>K<>&Mp<4D><70>ѳ<EFBFBD>
+%<<3C>԰<EFBFBD><D4B0><04>B֨IC <EFBFBD>2e<EFBFBD>x<EFBFBD>…
+<2B>(Q<><02>.<06>0Z<30><5A>P"C}*T<><54><EFBFBD>A<EFBFBD>
+<05>Hϟ:5 "i<>hQ#F<>)S^<5E><><EFBFBD><EFBFBD>D<EFBFBD>B<><42><EFBFBD><EFBFBD>"<22>SoV<6F><08>"D<>!<21>c#<23><>ۚ1<DB9A>64 <20><06><>n<EFBFBD><02><12>N<00><>=<08><>@<40><><0E><>@@<40>Fn <20><>h<EFBFBD>lA<6C>g<EFBFBD> 2<><32>Y0<><30> D~ɯ#<23> <20><>4P<00>b<EFBFBD>k@<40><><EFBFBD><EFBFBD>u<>0^y<><79><00><><EFBFBD>{<7B><>}<07>w*0<><EFBFBD>8`<60><06><>Ȉ$<24><>"W<><57>G}<7D><><EFBFBD>n<><10>m{<7B>q@r <06><><EFBFBD>|衇nXP<0F><>FS B<><00>0<EFBFBD>y<>aG1<18>k<>(<28>H!<21><><EFBFBD><EFBFBD><EFBFBD><04><><EFBFBD>H*I<><0E><><EFBFBD>_<> <0C><> <20><><EFBFBD>y<>aGu<>h<10><><EFBFBD>6<EFBFBD>{<7B>"<22><>2<EFBFBD><32>eo$iP|-BX<42><58><EFBFBD>8<EFBFBD>2<>Qs@
+)6t<>g<>AF_p<5F>9WXaP0<50><30>I,<2C>k<EFBFBD>I<EFBFBD>` &<26><><EFBFBD><EFBFBD>`@<40><><<3C> ,<2C>,
+8<> Hd<48><64><EFBFBD>f<EFBFBD>-B;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s10_unread.gif forums//site/static/beta5/pics/topic_s10_unread.gif
--- beta5//site/static/beta5/pics/topic_s10_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s10_unread.gif 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,12 @@
+GIF89a <00><>
+ 
+  
+  '#($*&-(0+1,2-506172<6=7>8?9C<!D="G@#IB$JC%KD%LE&NF'OG'PH(QI(RJ)SK)TL*UM*VN+WO+^U/`W0bY1cZ1d[2f\3j`5ka5lb6mc6nd7pe8qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>M<EFBFBD><4D>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>Z<EFBFBD><5A>[<5B><>[<5B><>]<5D><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>m<EFBFBD><6D>n<EFBFBD><6E>o<EFBFBD><6F>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A><>d<EFBFBD>'I<><08><><03> 2\<5C>H<EFBFBD><48>Ç 4X<34><00> <20>2h<32>t<EFBFBD>re
+<2B>#D~<7E><>QC<51>
+#<lؐ<6C>B˂<01>K<>&Mp<4D><70>ѳ<EFBFBD>
+%<<3C>԰<EFBFBD><D4B0><04>B֨IC <EFBFBD>2e<EFBFBD>x<EFBFBD>…
+<2B>(Q<><02>.<06>0Z<30><5A>P"C}*T<><54><EFBFBD>A<EFBFBD>
+<05>Hϟ:5 "i<>hQ#F<>)S^<5E><><EFBFBD><EFBFBD>D<EFBFBD>B<><42><EFBFBD><EFBFBD>"<22>SoV<6F><08>"D<>!<21>c#<23><>ۚ1<DB9A>64 <20><06><>n<EFBFBD><02><12>N<00><>=<08><>@<40><><0E><>@@<40>Fn <20><>h<EFBFBD>lA<6C>g<EFBFBD> 2<><32>Y0<><30> D~ɯ#<23> <20><>4P<00>b<EFBFBD>k@<40><><EFBFBD><EFBFBD>u<>0^y<><79><00><><EFBFBD>{<7B><>}<07>w*0<><EFBFBD>8`<60><06><>Ȉ$<24><>"W<><57>G}<7D><><EFBFBD>n<><10>m{<7B>q@r <06><><EFBFBD>|衇nXP<0F><>FS B<><00>0<EFBFBD>y<>aG1<18>k<>(<28>H!<21><><EFBFBD><EFBFBD><EFBFBD><04><><EFBFBD>H*I<><0E><><EFBFBD>_<> <0C><> <20><><EFBFBD>y<>aGu<>h<10><><EFBFBD>6<EFBFBD>{<7B>"<22><>2<EFBFBD><32>eo$iP|-BX<42><58><EFBFBD>8<EFBFBD>2<>Qs@
+)6t<>g<>AF_p<5F>9WXaP0<50><30>I,<2C>k<EFBFBD>I<EFBFBD>` &<26><><EFBFBD><EFBFBD>`@<40><><<3C> ,<2C>,
+8<> Hd<48><64><EFBFBD>f<EFBFBD>-B;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s1_read.gif forums//site/static/beta5/pics/topic_s1_read.gif
--- beta5//site/static/beta5/pics/topic_s1_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s1_read.gif 2011-02-05 10:10:02.684335002 +0100
@@ -0,0 +1,3 @@
+GIF89a <00>w'''(((***---000111222555666777<<<>>>???CCCDDDGGGIIIJJJKKKLLLNNNRRRSSSTTTUUUWWW^^^```bbbcccdddfffkkklllmmmnnnqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.<BA>962,+('&# 
+<07>0RTPKIFBC74/*(%#<11> <0C><>6RNNIGD==<3D>++<2B><14> <09>2WVU<56>TTRRLLJJCC@@;730<33>,<12>6uttoro<72><6F><EFBFBD>q<EFBFBD><71>6oܨ1<DCA8>f /% <0C><>c<EFBFBD><63><EFBFBD>:)R<><52><EFBFBD><EFBFBD>>9tഉS愡SnTI$<24>8o<38><6F>c"<22>ʛ1<>|32N<1A><>h<EFBFBD>L @E<>0٤Y<D9A4>(<28><><1A>ʙC<CA99>M:2<><$a(T<>EC<45>i<EFBFBD>&<26>5h<35>p-<2D><>k<EFBFBD>8<EFBFBD>qؼL<D8BC><4C>L2^Ft<46>j',<2C><>eϦ]K<>-Էq<D4B7>ֽ<EFBFBD>א<EFBFBD>:<3A>#K<><4B>V<EFBFBD>2f̌FK<08>7<EFBFBD>U|St<53>V4hΔ3<><33><16><>Z<EFBFBD>l)nQ7Z<37><5A>%#<23>˗," <0C>`IgN7i^<5E><><EFBFBD>F <EFBFBD>֮aR<><52><EFBFBD>>~m؜Y<D89C><59>̘2b<32>|1<>ų!<21>u,<2C>f<EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD><14><><EFBFBD>ɾ&<26><>/<2F>}<7D>E\<5C>G<16>r<>S<<11>M(<28><>FQ<>?<3F><><EFBFBD>9<><39>a<EFBFBD>9\`<60>d0<64><30> 8<><38><EFBFBD>P<> <20><01>(<28>H<><48><EFBFBD><<3C><>#"<22>;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s1_unread.gif forums//site/static/beta5/pics/topic_s1_unread.gif
--- beta5//site/static/beta5/pics/topic_s1_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s1_unread.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,3 @@
+GIF89a <00>w'#($*&-(0+1,2-506172<6>8?9C<!D="G@#IB$JC%KD%LE&NF'RJ)SK)TL*UM*WO+^U/`W0bY1cZ1d[2f\3ka5lb6mc6nd7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.<BA>962,+('&# 
+<07>0RTPKIFBC74/*(%#<11> <0C><>6RNNIGD==<3D>++<2B><14> <09>2WVU<56>TTRRLLJJCC@@;730<33>,<12>6uttoro<72><6F><EFBFBD>q<EFBFBD><71>6oܨ1<DCA8>f /% <0C><>c<EFBFBD><63><EFBFBD>:)R<><52><EFBFBD><EFBFBD>>9tഉS愡SnTI$<24>8o<38><6F>c"<22>ʛ1<>|32N<1A><>h<EFBFBD>L @E<>0٤Y<D9A4>(<28><><1A>ʙC<CA99>M:2<><$a(T<>EC<45>i<EFBFBD>&<26>5h<35>p-<2D><>k<EFBFBD>8<EFBFBD>qؼL<D8BC><4C>L2^Ft<46>j',<2C><>eϦ]K<>-Էq<D4B7>ֽ<EFBFBD>א<EFBFBD>:<3A>#K<><4B>V<EFBFBD>2f̌FK<08>7<EFBFBD>U|St<53>V4hΔ3<><33><16><>Z<EFBFBD>l)nQ7Z<37><5A>%#<23>˗," <0C>`IgN7i^<5E><><EFBFBD>F <EFBFBD>֮aR<><52><EFBFBD>>~m؜Y<D89C><59>̘2b<32>|1<>ų!<21>u,<2C>f<EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD><14><><EFBFBD>ɾ&<26><>/<2F>}<7D>E\<5C>G<16>r<>S<<11>M(<28><>FQ<>?<3F><><EFBFBD>9<><39>a<EFBFBD>9\`<60>d0<64><30> 8<><38><EFBFBD>P<> <20><01>(<28>H<><48><EFBFBD><<3C><>#"<22>;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s2_read.gif forums//site/static/beta5/pics/topic_s2_read.gif
--- beta5//site/static/beta5/pics/topic_s2_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s2_read.gif 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,7 @@
+GIF89a <00>w'''(((***---000111222555666777<<<>>>???CCCDDDGGGIIIJJJKKKLLLNNNRRRSSSTTTUUUWWW^^^```bbbcccdddfffkkklllmmmnnnqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.<BA>962,+('&# 
+<07>0RTPKIFBC74/*(%#<11> <0C><>6RNNIGD==<3D>++<2B><14> <09>2WVU<56>TTRRLLJJCC@@;730<33>,<12>6uttoro<72><6F><EFBFBD>q<EFBFBD><71>6oܨ1<DCA8>f /% <0C><>c<EFBFBD><63><EFBFBD>:)R<><52><EFBFBD><EFBFBD>>9tഉS愡SnTI$<24>8o<38><6F>c"<22>ʛ1<>|32N<1A><>h<EFBFBD><68>Q a<>I<EFBFBD>F PdC<EFBFBD>=J<>M:2<><$a(FԢ<46><D4A2><EFBFBD>i<EFBFBD>&<26>5h<35>p-<2D>uh<75>}<7D>EټL<D9BC><4C>L2^Ft<46>
+ ,<2C><>eϦ]K<>-ηt<CEB7>έ{7<>!u"K<>,<2C><>X3d̘#<06><><10>o<EFBFBD><6F>
+<2B>jQ4<51>ϔ3<><33><16><>Z<EFBFBD>l)'<27><><EFBFBD>f<EFBFBD><66><11><>K<11>V<EFBFBD><56>3'<27><>4/<2F><>E<EFBFBD>fwkװ <09><><EFBFBD>o<1F>6lάQxfL1a<31><61><EFBFBD><EFBFBD>ِl<D990>:<07>e<EFBFBD><65><EFBFBD>]<5D>ax{<7B><><EFBFBD>P
+~U<>`_<><5F><EFBFBD><17>_x<5F><17>͇h<><68>0<EFBFBD>OD<4F>DJ q<>E1<><<3C><>C;t<>a<18>AL`b,<2C>"0<02>8@1
+0<><00><><EFBFBD><EFBFBD><EFBFBD><<3C><>H ;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s2_unread.gif forums//site/static/beta5/pics/topic_s2_unread.gif
--- beta5//site/static/beta5/pics/topic_s2_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s2_unread.gif 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,7 @@
+GIF89a <00>w'#($*&-(0+1,2-506172<6>8?9C<!D="G@#IB$JC%KD%LE&NF'RJ)SK)TL*UM*WO+^U/`W0bY1cZ1d[2f\3ka5lb6mc6nd7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.<BA>962,+('&# 
+<07>0RTPKIFBC74/*(%#<11> <0C><>6RNNIGD==<3D>++<2B><14> <09>2WVU<56>TTRRLLJJCC@@;730<33>,<12>6uttoro<72><6F><EFBFBD>q<EFBFBD><71>6oܨ1<DCA8>f /% <0C><>c<EFBFBD><63><EFBFBD>:)R<><52><EFBFBD><EFBFBD>>9tഉS愡SnTI$<24>8o<38><6F>c"<22>ʛ1<>|32N<1A><>h<EFBFBD><68>Q a<>I<EFBFBD>F PdC<EFBFBD>=J<>M:2<><$a(FԢ<46><D4A2><EFBFBD>i<EFBFBD>&<26>5h<35>p-<2D>uh<75>}<7D>EټL<D9BC><4C>L2^Ft<46>
+ ,<2C><>eϦ]K<>-ηt<CEB7>έ{7<>!u"K<>,<2C><>X3d̘#<06><><10>o<EFBFBD><6F>
+<2B>jQ4<51>ϔ3<><33><16><>Z<EFBFBD>l)'<27><><EFBFBD>f<EFBFBD><66><11><>K<11>V<EFBFBD><56>3'<27><>4/<2F><>E<EFBFBD>fwkװ <09><><EFBFBD>o<1F>6lάQxfL1a<31><61><EFBFBD><EFBFBD>ِl<D990>:<07>e<EFBFBD><65><EFBFBD>]<5D>ax{<7B><><EFBFBD>P
+~U<>`_<><5F><EFBFBD><17>_x<5F><17>͇h<><68>0<EFBFBD>OD<4F>DJ q<>E1<><<3C><>C;t<>a<18>AL`b,<2C>"0<02>8@1
+0<><00><><EFBFBD><EFBFBD><EFBFBD><<3C><>H ;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s3_read.gif forums//site/static/beta5/pics/topic_s3_read.gif
--- beta5//site/static/beta5/pics/topic_s3_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s3_read.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,3 @@
+GIF89a <00>w'''(((***---000111222555666777<<<>>>???CCCDDDGGGIIIJJJKKKLLLNNNRRRSSSTTTUUUWWW^^^```bbbcccdddfffkkklllmmmnnnqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.<BA>962,+('&# 
+<07>0RTPKIFBC74/*(%#<11> <0C><>6RNNIGD==<3D>++<2B><14> <09>2WVU<56>TTRRLLJJCC@@;730<33>,<12>6uttoro<72><6F><EFBFBD>q<EFBFBD><71>6oܨ1<DCA8>f /% <0C><>c<EFBFBD><63><EFBFBD>:)R<><52><EFBFBD><EFBFBD>>9tഉS愡SnTI$<24>8o<38><6F>c"<22>ʛ1<>|32N<1A><>h<EFBFBD><00>"ъDa<44>I<EFBFBD>F PdC<EFBFBD><EFBFBD>!*gNR:2<><$a(FT<46>B]<>^<5E><16>z<EFBFBD><7A>T<00>q<EFBFBD>$M<><4D>L2^Ft<46><74>V,<00>fѪ%<25>V<EFBFBD>ۤr<DBA4>ҵ<EFBFBD>Wo!u"K<>Ct_R6Dɘ13F -! <0C><>I9웱k<EC9BB1><6B>9Sf̘/Zjq<6A>b<>nR<03>KF̗/YDZ<><5A>Μ8nҼDc<17><>ޯa<DEAF><1E>B#<23>}<7D>ڰ9<DAB0>F<EFBFBD><46>1eĄ<65>b<EFBFBD> hC<68>)<29>H<><48><1A>w;<3B><><EFBFBD>eKlC)<29><>!<21>}<7D><><EFBFBD>_t<5F><74>]pQ_}X<>V<EFBFBD> SL<53>DO4<4F>GQDC<><43>:<3A><>Ç<1E>p<EFBFBD>!d<><64>(6<><36>,"`@ <20><>0<> Ɏ<<3C><>;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s3_unread.gif forums//site/static/beta5/pics/topic_s3_unread.gif
--- beta5//site/static/beta5/pics/topic_s3_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s3_unread.gif 2011-02-05 10:10:02.684335002 +0100
@@ -0,0 +1,3 @@
+GIF89a <00>w'#($*&-(0+1,2-506172<6>8?9C<!D="G@#IB$JC%KD%LE&NF'RJ)SK)TL*UM*WO+^U/`W0bY1cZ1d[2f\3ka5lb6mc6nd7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+, <07><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.<BA>962,+('&# 
+<07>0RTPKIFBC74/*(%#<11> <0C><>6RNNIGD==<3D>++<2B><14> <09>2WVU<56>TTRRLLJJCC@@;730<33>,<12>6uttoro<72><6F><EFBFBD>q<EFBFBD><71>6oܨ1<DCA8>f /% <0C><>c<EFBFBD><63><EFBFBD>:)R<><52><EFBFBD><EFBFBD>>9tഉS愡SnTI$<24>8o<38><6F>c"<22>ʛ1<>|32N<1A><>h<EFBFBD><00>"ъDa<44>I<EFBFBD>F PdC<EFBFBD><EFBFBD>!*gNR:2<><$a(FT<46>B]<>^<5E><16>z<EFBFBD><7A>T<00>q<EFBFBD>$M<><4D>L2^Ft<46><74>V,<00>fѪ%<25>V<EFBFBD>ۤr<DBA4>ҵ<EFBFBD>Wo!u"K<>Ct_R6Dɘ13F -! <0C><>I9웱k<EC9BB1><6B>9Sf̘/Zjq<6A>b<>nR<03>KF̗/YDZ<><5A>Μ8nҼDc<17><>ޯa<DEAF><1E>B#<23>}<7D>ڰ9<DAB0>F<EFBFBD><46>1eĄ<65>b<EFBFBD> hC<68>)<29>H<><48><1A>w;<3B><><EFBFBD>eKlC)<29><>!<21>}<7D><><EFBFBD>_t<5F><74>]pQ_}X<>V<EFBFBD> SL<53>DO4<4F>GQDC<><43>:<3A><>Ç<1E>p<EFBFBD>!d<><64>(6<><36>,"`@ <20><>0<> Ɏ<<3C><>;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s4_read.gif forums//site/static/beta5/pics/topic_s4_read.gif
--- beta5//site/static/beta5/pics/topic_s4_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s4_read.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,5 @@
+GIF89a <00><> '''(((***+++,,,---000111222555666777999;;;<<<>>>???CCCDDDFFFGGGIIIJJJKKKLLLNNNRRRSSSTTTUUUWWW^^^```bbbcccdddfffkkklllmmmnnnqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A>a<EFBFBD>I$C<><43><EFBFBD>A#<06>,R<> 1<><31><EFBFBD> 2P<32><50><EFBFBD><EFBFBD>/`<60>\<5C>"<22>ɓ >r̈ႅ<CC88>:hА<68>B˂@<40>h<EFBFBD>Re
+<2B>#GpҠ<70><13> !:<3A>̠<EFBFBD><CCA0><03><Ȍ C /^<5E>`<60>b<EFBFBD>ɓ%K<>顣n<E9A1A3> <06> $<24><0F>>}<03><><EFBFBD><EFBFBD><EFBFBD>=}<7D>ࡃ'<27>6.
+!DH<10>A<EFBFBD>)S<16><><EFBFBD>^@<40><><EFBFBD><EFBFBD>3<07><><1F>SoV-<08><>?}<7D><><EFBFBD><EFBFBD>"<22><>ۚ1<DB9A><31>3<EFBFBD><33><1D>}<7D><00>Y*<03><00><>;y<>G:<3A>8#<0E>y<1E><>0<EFBFBD><30>:<3A>4<06><>3g4u<34><75>g3<67>`<60><><EFBFBD>)G<00><>O<12>q<EFBFBD>s<><73> <0B><>G<EFBFBD>d<><04>G|<7C><>G<EFBFBD>}<7D><>G<EFBFBD> F<02>! <20>"X<> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><07> 4(t<><01>g<>`<60> <0A><>@_|4AL<>Q<EFBFBD>q<><71><EFBFBD>&d<>m<EFBFBD><10><>z<><7A>m(m<>a<EFBFBD>
+<06><><EFBFBD> <20><><EFBFBD><EFBFBD><1D><>A<EFBFBD>xl<78><6C><EFBFBD>M4<>f|<7C><><EFBFBD><7A>bu<62>1o<>A9<1A>$e<> <EFBFBD><07>yX<><58>op<6F>L$_<><10>g4؆<>m<EFBFBD><6D><EFBFBD><1A>NZ<4E><5A><05><><EFBFBD>[t<>E<VP1<50>QD<51><44>FA<>E<><45><EFBFBD> t<>"p`lL<><4C> ,p<>D{@<01>p<>e<><65><EFBFBD><EFBFBD>v<EFBFBD>P@;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s4_unread.gif forums//site/static/beta5/pics/topic_s4_unread.gif
--- beta5//site/static/beta5/pics/topic_s4_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s4_unread.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,6 @@
+GIF89a <00><> 
+'#($*&+',(-(0+1,2-50617293;5<6>8?9C<!D="F?#G@#IB$JC%KD%LE&NF'RJ)SK)TL*UM*WO+^U/`W0bY1cZ1d[2f\3ka5lb6mc6nd7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>yB<79>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>M<EFBFBD><4D>N<EFBFBD><4E>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>_ñaɶdλgнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>o<EFBFBD><6F>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A>a<EFBFBD>I$C<><43><EFBFBD>A#<06>,R<> 1<><31><EFBFBD> 2P<32><50><EFBFBD><EFBFBD>/`<60>\<5C>"<22>ɓ >r̈ႅ<CC88>:hА<68>B˂@<40>h<EFBFBD>Re
+<2B>#GpҠ<70><13> !:<3A>̠<EFBFBD><CCA0><03><Ȍ C /^<5E>`<60>b<EFBFBD>ɓ%K<>顣n<E9A1A3> <06> $<24><0F>>}<03><><EFBFBD><EFBFBD><EFBFBD>=}<7D>ࡃ'<27>6.
+!DH<10>A<EFBFBD>)S<16><><EFBFBD>^@<40><><EFBFBD><EFBFBD>3<07><><1F>SoV-<08><>?}<7D><><EFBFBD><EFBFBD>"<22><>ۚ1<DB9A><31>3<EFBFBD><33><1D>}<7D><00>Y*<03><00><>;y<>G:<3A>8#<0E>y<1E><>0<EFBFBD><30>:<3A>4<06><>3g4u<34><75>g3<67>`<60><><EFBFBD>)G<00><>O<12>q<EFBFBD>s<><73> <0B><>G<EFBFBD>d<><04>G|<7C><>G<EFBFBD>}<7D><>G<EFBFBD> F<02>! <20>"X<> <EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><07> 4(t<><01>g<>`<60> <0A><>@_|4AL<>Q<EFBFBD>q<><71><EFBFBD>&d<>m<EFBFBD><10><>z<><7A>m(m<>a<EFBFBD>
+<06><><EFBFBD> <20><><EFBFBD><EFBFBD><1D><>A<EFBFBD>xl<78><6C><EFBFBD>M4<>f|<7C><><EFBFBD><7A>bu<62>1o<>A9<1A>$e<> <EFBFBD><07>yX<><58>op<6F>L$_<><10>g4؆<>m<EFBFBD><6D><EFBFBD><1A>NZ<4E><5A><05><><EFBFBD>[t<>E<VP1<50>QD<51><44>FA<>E<><45><EFBFBD> t<>"p`lL<><4C> ,p<>D{@<01>p<>e<><65><EFBFBD><EFBFBD>v<EFBFBD>P@;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s5_read.gif forums//site/static/beta5/pics/topic_s5_read.gif
--- beta5//site/static/beta5/pics/topic_s5_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s5_read.gif 2011-02-05 10:10:02.684335002 +0100
@@ -0,0 +1,5 @@
+GIF89a <00><> '''(((***+++,,,---000111222555666777999:::<<<>>>???CCCDDDFFFGGGIIIJJJKKKLLLNNNRRRSSSTTTUUUWWW^^^```bbbcccdddfffkkklllmmmnnnqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A>a<EFBFBD> $C<><43><EFBFBD>A#<06>,R<> 1<><31><EFBFBD> 2P<32><50><EFBFBD><EFBFBD><EFBFBD>._<>X<EFBFBD><12><><EFBFBD> >r̈ႅ<CC88>:hА<68>B˂@<40>d<EFBFBD>BEʓ#GpҠ<70><13> !:<3A>̠<EFBFBD><CCA0><03>C<>˗.]<5D>\<5C>%J<>顣n<E9A1A3> <06>
+<14><>>}<01>ٳ<EFBFBD>o<EFBFBD><|<7C>ܙsN<>5.
+4(<28> A<>)S<0E><><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD>#<07><><1F>SoVt ?|<7C><>y<EFBFBD>"<22><>ۚ1<DB9A><31><1D>}<7D><1E><16>V$<24><><EFBFBD><0E>;<3B><><0E>`<04>?"<00><>H6<48><36>- <0C><><18><06><>:<3A><> @<06>:w<><77> _p<5F><70><00>Z@<40>k;v<>!Gk<> <20>p<EFBFBD>@<06>`z<><07>|<7C>dnp@<08><>X<>A7b<><62>(f<00>h<><68>q<>1o<>a<EFBFBD>
+$޶We<57>@uI<>p<><70><EFBFBD>d<>m<EFBFBD><6D>A<EFBFBD>z<04>Q<EFBFBD><03><>l<><6C><EFBFBD>A4<41> ~<7E>a<EFBFBD>kuX<>Vyd<79>͠_{<7B><>Gt<><74>p<><70><EFBFBD>ƍ-I<>n<EFBFBD><6E><EFBFBD>H<>W<>q<06><06><>W <20>͉<EFBFBD><CD89><03>A#k<><6B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>cA0x<30><78>\h<>ESH6P8<50><38>F1D<11><>:<06> <20>[<5B><14> <1C><><01>P<00>`<60>D<EFBFBD>Vk<56><6B><EFBFBD>";
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s5_unread.gif forums//site/static/beta5/pics/topic_s5_unread.gif
--- beta5//site/static/beta5/pics/topic_s5_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s5_unread.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,6 @@
+GIF89a <00><> 
+'#($*&+',(-(0+1,2-50617293:4<6>8?9C<!D="F?#G@#IB$JC%KD%LE&NF'RJ)SK)TL*UM*WO+^U/`W0bY1cZ1d[2f\3ka5lb6mc6nd7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>yB<79>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>N<EFBFBD><4E>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>k<EFBFBD><6B>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>o<EFBFBD><6F>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A>a<EFBFBD> $C<><43><EFBFBD>A#<06>,R<> 1<><31><EFBFBD> 2P<32><50><EFBFBD><EFBFBD><EFBFBD>._<>X<EFBFBD><12><><EFBFBD> >r̈ႅ<CC88>:hА<68>B˂@<40>d<EFBFBD>BEʓ#GpҠ<70><13> !:<3A>̠<EFBFBD><CCA0><03>C<>˗.]<5D>\<5C>%J<>顣n<E9A1A3> <06>
+<14><>>}<01>ٳ<EFBFBD>o<EFBFBD><|<7C>ܙsN<>5.
+4(<28> A<>)S<0E><><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD>#<07><><1F>SoVt ?|<7C><>y<EFBFBD>"<22><>ۚ1<DB9A><31><1D>}<7D><1E><16>V$<24><><EFBFBD><0E>;<3B><><0E>`<04>?"<00><>H6<48><36>- <0C><><18><06><>:<3A><> @<06>:w<><77> _p<5F><70><00>Z@<40>k;v<>!Gk<> <20>p<EFBFBD>@<06>`z<><07>|<7C>dnp@<08><>X<>A7b<><62>(f<00>h<><68>q<>1o<>a<EFBFBD>
+$޶We<57>@uI<>p<><70><EFBFBD>d<>m<EFBFBD><6D>A<EFBFBD>z<04>Q<EFBFBD><03><>l<><6C><EFBFBD>A4<41> ~<7E>a<EFBFBD>kuX<>Vyd<79>͠_{<7B><>Gt<><74>p<><70><EFBFBD>ƍ-I<>n<EFBFBD><6E><EFBFBD>H<>W<>q<06><06><>W <20>͉<EFBFBD><CD89><03>A#k<><6B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>cA0x<30><78>\h<>ESH6P8<50><38>F1D<11><>:<06> <20>[<5B><14> <1C><><01>P<00>`<60>D<EFBFBD>Vk<56><6B><EFBFBD>";
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s6_read.gif forums//site/static/beta5/pics/topic_s6_read.gif
--- beta5//site/static/beta5/pics/topic_s6_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s6_read.gif 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,8 @@
+GIF89a <00><> '''(((***+++,,,---...000111222555666777999;;;<<<>>>???CCCDDDFFFGGGHHHIIIJJJKKKLLLNNNRRRSSSTTTUUUVVVWWW^^^```bbbcccdddfffkkklllmmmnnnqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*ԑ䉓%F<><46><EFBFBD>q<EFBFBD><71> /X<>8a<38> 4T<34><54><EFBFBD>`0b<30>d<EFBFBD>B<EFBFBD> "Axؠ<11>E
+!>p<><70><EFBFBD>B˂C<CB82>p<EFBFBD>r<EFBFBD>J%Jp޸<70>sE
+#><3E><><EFBFBD><EFBFBD><04>CV<43>0`<60>h<EFBFBD><68>
+<2B>&M<>ң.<2E><06>4<>O ?}<05><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=~<7E>䩓GΝ61 )ThP!B<>)S<1E><><EFBFBD><EFBFBD>@<40><><EFBFBD>Dg<44>A!<21>SoV=<08> @~<7E><00>##<23><>ۚ1<DB9A><31>3<1E><06><>F`<60><>- 6=y<>#<23><><03> <09>%<00><18>|<7C>l=<3D>a<EFBFBD><18>q[ <EFBFBD>z
+<2B> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>F|A<><41>%<00>R
+<2B> <09><><EFBFBD>x<>A<EFBFBD>m<>0nH<00>A!<00><><1F><10>|yԷ<79>mr@<08>F<EFBFBD>x`<60><06>@Ȋ,<2C><> <00>A<EFBFBD><15>Q<EFBFBD>q<><71>F <><14>0<><1E>1gr<><72>
+<16><>m<EFBFBD><6D><EFBFBD>t<>Q$s<><11>n<><6E><EFBFBD>A7<41>6<EFBFBD> <20><><EFBFBD><EFBFBD>kwxGZ*<2A>d<EFBFBD>٠_{<7B><><EFBFBD>v衘r<>n<><6E>Ǝ=I<>n<EFBFBD><6E><11><1E>#[<5B><><06><06><><EFBFBD> <20>ݩ<EFBFBD><DDA9><07><><EFBFBD>m<><6D><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>cA3<41>F_t<5F>;VTA<54>R@<40>DIa<12><>j<EFBFBD><06>@ k<>$<24>@ <1C><><01>P<00>`<60>D<EFBFBD>f<EFBFBD><66><EFBFBD><EFBFBD>";
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s6_unread.gif forums//site/static/beta5/pics/topic_s6_unread.gif
--- beta5//site/static/beta5/pics/topic_s6_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s6_unread.gif 2011-02-05 10:10:02.694335002 +0100
@@ -0,0 +1,9 @@
+GIF89a <00><> 
+'#($*&+',(-(.)0+1,2-50617293;5<6>8?9C<!D="F?#G@#HA$IB$JC%KD%LE&NF'RJ)SK)TL*UM*VN+WO+^U/`W0bY1cZ1d[2f\3ka5lb6mc6nd7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>yB<79>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>o<EFBFBD><6F>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*ԑ䉓%F<><46><EFBFBD>q<EFBFBD><71> /X<>8a<38> 4T<34><54><EFBFBD>`0b<30>d<EFBFBD>B<EFBFBD> "Axؠ<11>E
+!>p<><70><EFBFBD>B˂C<CB82>p<EFBFBD>r<EFBFBD>J%Jp޸<70>sE
+#><3E><><EFBFBD><EFBFBD><04>CV<43>0`<60>h<EFBFBD><68>
+<2B>&M<>ң.<2E><06>4<>O ?}<05><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>=~<7E>䩓GΝ61 )ThP!B<>)S<1E><><EFBFBD><EFBFBD>@<40><><EFBFBD>Dg<44>A!<21>SoV=<08> @~<7E><00>##<23><>ۚ1<DB9A><31>3<1E><06><>F`<60><>- 6=y<>#<23><><03> <09>%<00><18>|<7C>l=<3D>a<EFBFBD><18>q[ <EFBFBD>z
+<2B> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>F|A<><41>%<00>R
+<2B> <09><><EFBFBD>x<>A<EFBFBD>m<>0nH<00>A!<00><><1F><10>|yԷ<79>mr@<08>F<EFBFBD>x`<60><06>@Ȋ,<2C><> <00>A<EFBFBD><15>Q<EFBFBD>q<><71>F <><14>0<><1E>1gr<><72>
+<16><>m<EFBFBD><6D><EFBFBD>t<>Q$s<><11>n<><6E><EFBFBD>A7<41>6<EFBFBD> <20><><EFBFBD><EFBFBD>kwxGZ*<2A>d<EFBFBD>٠_{<7B><><EFBFBD>v衘r<>n<><6E>Ǝ=I<>n<EFBFBD><6E><11><1E>#[<5B><><06><06><><EFBFBD> <20>ݩ<EFBFBD><DDA9><07><><EFBFBD>m<><6D><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>cA3<41>F_t<5F>;VTA<54>R@<40>DIa<12><>j<EFBFBD><06>@ k<>$<24>@ <1C><><01>P<00>`<60>D<EFBFBD>f<EFBFBD><66><EFBFBD><EFBFBD>";
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s7_read.gif forums//site/static/beta5/pics/topic_s7_read.gif
--- beta5//site/static/beta5/pics/topic_s7_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s7_read.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,4 @@
+GIF89a <00><> '''(((***+++,,,---...000111222555666777999<<<>>>???CCCDDDGGGHHHIIIJJJKKKLLLNNNRRRSSSTTTUUUVVVWWW^^^```bbbcccdddfffkkklllmmmnnnqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A>q<EFBFBD> <09>$D<><44><EFBFBD>QCF -T<>(A<><41><EFBFBD> 0P<30><50><EFBFBD><EFBFBD><EFBFBD>._<>X<EFBFBD><12><>!?tА<74><D090><EFBFBD> :hА<68>B˂A<CB82>d<EFBFBD>BE<42>$Hp֨<70>3<EFBFBD> !:<3A>Ġ<EFBFBD><04>C<>˗.]<5D>\<5C><52>%K<>񱣮<> <06>
+<14><>>}<01>ٳ<EFBFBD>o<EFBFBD><|<7C>ܙsN<>5/ 4(<28> A<>)S<0E><><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD>#'<27>A <20>SoVt ?|<7C><>y#<23><>ۚ1<DB9A><31><1D><>F<00>f, <00>5s;x<>G<>:<12>G<00><><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD>y<EFBFBD><79> <20><>h <0C>3<08>g1׃<31><D783><EFBFBD><EFBFBD>k<EFBFBD><<3C>Z(<28><<01><04>5r<><11>-<2D><><EFBFBD>d0<1C><>|<7C>p<><1D>9<EFBFBD> F<02>Q`<60> .<2E>`A8<08><><EFBFBD><00><1C>v<EFBFBD>q0<07>m<><6D><EFBFBD>A8<41>& sP|<7C>au<>e<>H<EFBFBD> <EFBFBD><EFBFBD><EFBFBD>u<>Ass<73><73><EFBFBD>l<>A <06><>Z <20><><EFBFBD><EFBFBD><1D>Ց`w<><77>ƒL:9 <0A><><EFBFBD>_z<5F>A<1E><><01>o<><6F><EFBFBD>k<>h<10><><EFBFBD>6~<7E><>G<EFBFBD>
+<2B><><06>k<EFBFBD>ѤA3<41>ay<61>1G<31>q<EFBFBD><71>#k<><6B>F<EFBFBD><46><EFBFBD><EFBFBD>cA1x<31><78>@\h<>ESHP8<50><38>GA<><11><>J<06> <20>$[<5B>4<>@ <1C><><01>P<00>`<60>D<EFBFBD>v<EFBFBD><76><EFBFBD><EFBFBD>";
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s7_unread.gif forums//site/static/beta5/pics/topic_s7_unread.gif
--- beta5//site/static/beta5/pics/topic_s7_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s7_unread.gif 2011-02-05 10:10:02.684335002 +0100
@@ -0,0 +1,5 @@
+GIF89a <00><> 
+'#($*&+',(-(.)0+1,2-50617293<6>8?9C<!D="G@#HA$IB$JC%KD%LE&NF'RJ)SK)TL*UM*VN+WO+^U/`W0bY1cZ1d[2f\3ka5lb6mc6nd7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>yB<79>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>n<EFBFBD><6E>o<EFBFBD><6F>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A>q<EFBFBD> <09>$D<><44><EFBFBD>QCF -T<>(A<><41><EFBFBD> 0P<30><50><EFBFBD><EFBFBD><EFBFBD>._<>X<EFBFBD><12><>!?tА<74><D090><EFBFBD> :hА<68>B˂A<CB82>d<EFBFBD>BE<42>$Hp֨<70>3<EFBFBD> !:<3A>Ġ<EFBFBD><04>C<>˗.]<5D>\<5C><52>%K<>񱣮<> <06>
+<14><>>}<01>ٳ<EFBFBD>o<EFBFBD><|<7C>ܙsN<>5/ 4(<28> A<>)S<0E><><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD>#'<27>A <20>SoVt ?|<7C><>y#<23><>ۚ1<DB9A><31><1D><>F<00>f, <00>5s;x<>G<>:<12>G<00><><EFBFBD><EFBFBD>?<3F><><EFBFBD><EFBFBD>y<EFBFBD><79> <20><>h <0C>3<08>g1׃<31><D783><EFBFBD><EFBFBD>k<EFBFBD><<3C>Z(<28><<01><04>5r<><11>-<2D><><EFBFBD>d0<1C><>|<7C>p<><1D>9<EFBFBD> F<02>Q`<60> .<2E>`A8<08><><EFBFBD><00><1C>v<EFBFBD>q0<07>m<><6D><EFBFBD>A8<41>& sP|<7C>au<>e<>H<EFBFBD> <EFBFBD><EFBFBD><EFBFBD>u<>Ass<73><73><EFBFBD>l<>A <06><>Z <20><><EFBFBD><EFBFBD><1D>Ց`w<><77>ƒL:9 <0A><><EFBFBD>_z<5F>A<1E><><01>o<><6F><EFBFBD>k<>h<10><><EFBFBD>6~<7E><>G<EFBFBD>
+<2B><><06>k<EFBFBD>ѤA3<41>ay<61>1G<31>q<EFBFBD><71>#k<><6B>F<EFBFBD><46><EFBFBD><EFBFBD>cA1x<31><78>@\h<>ESHP8<50><38>GA<><11><>J<06> <20>$[<5B>4<>@ <1C><><01>P<00>`<60>D<EFBFBD>v<EFBFBD><76><EFBFBD><EFBFBD>";
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s8_read.gif forums//site/static/beta5/pics/topic_s8_read.gif
--- beta5//site/static/beta5/pics/topic_s8_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s8_read.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,7 @@
+GIF89a <00><> '''(((***+++,,,---...000111222555666777999<<<>>>???CCCDDDGGGHHHIIIJJJKKKLLLNNNRRRSSSTTTUUUVVVWWW^^^```bbbcccdddfffkkklllmmmnnnqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A>q<EFBFBD>I%D<><44><EFBFBD>QCF -T<>(A<><41><EFBFBD> 0P<30><50><EFBFBD><EFBFBD>/`<60>\<5C>"<22><>!?tА<74><D090><EFBFBD> :hА<68>B˂A<CB82>h<EFBFBD>Re
+$Hp֨<70>3<EFBFBD> !:<3A>Ġ<EFBFBD><04>=ƈ C /^<5E>`<60>b<EFBFBD><62>&L<>񱣮<> <06> $<24><0F>>}<03><><EFBFBD><EFBFBD><EFBFBD>=}<7D>ࡃ'<27>6/ !DH<10>A<EFBFBD>)S<16><><EFBFBD>^@<40><><EFBFBD><EFBFBD>3'<27>A <20>SoV-<08><>?}<7D><><EFBFBD>#<23><>ۚ1<DB9A><31>3<EFBFBD><33><1D>B <20><>,<00>2s<32><73><EFBFBD><EFBFBD><01><>P$4<><00>c9@<40><><EFBFBD> <0B><>؅A<1E><><18><>P<EFBFBD><00>x<1D>s<xؘ/<2F><><EFBFBD>QP<><50>}<00><><EFBFBD>r<><72><EFBFBD>y<EFBFBD>@<06>`@@y <20><>~G<01><11>sd<73><07>
+<02><><EFBFBD><06><00><1D>8^<5E>z0'<1D><><EFBFBD><EFBFBD>+ĨY<14> Ee}D<>sv<73><76>\m<><6D>`A7h<37><04>Ȋ<><C88A><EFBFBD><EFBFBD><EFBFBD>r0<72>Fe<>`P <EFBFBD> <12>|<7C><><EFBFBD>s<>ar<>Ae<41>WD<>f|<7C><><EFBFBD><7A>bu<62>1o<>AD<1A>%e<> ֡y<><79>`<1C><><EFBFBD>gXi<58> | B<18>y<EFBFBD>A<07>mp<6D><70>Mj<4D>
+*E<14>_l<5F><6C>YXA<58>RD<11>KqDD<18>l<EFBFBD>D<EFBFBD>`
+"<22><><EFBFBD><EFBFBD>X0<58><30>4<><34>
+<18><>xk<78>Hd<48><64>覫.B;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s8_unread.gif forums//site/static/beta5/pics/topic_s8_unread.gif
--- beta5//site/static/beta5/pics/topic_s8_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s8_unread.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,8 @@
+GIF89a <00><> 
+'#($*&+',(-(.)0+1,2-50617293<6>8?9C<!D="G@#HA$IB$JC%KD%LE&NF'RJ)SK)TL*UM*VN+WO+^U/`W0bY1cZ1d[2f\3ka5lb6mc6nd7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>yB<79>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>o<EFBFBD><6F>p<EFBFBD><70>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A>q<EFBFBD>I%D<><44><EFBFBD>QCF -T<>(A<><41><EFBFBD> 0P<30><50><EFBFBD><EFBFBD>/`<60>\<5C>"<22><>!?tА<74><D090><EFBFBD> :hА<68>B˂A<CB82>h<EFBFBD>Re
+$Hp֨<70>3<EFBFBD> !:<3A>Ġ<EFBFBD><04>=ƈ C /^<5E>`<60>b<EFBFBD><62>&L<>񱣮<> <06> $<24><0F>>}<03><><EFBFBD><EFBFBD><EFBFBD>=}<7D>ࡃ'<27>6/ !DH<10>A<EFBFBD>)S<16><><EFBFBD>^@<40><><EFBFBD><EFBFBD>3'<27>A <20>SoV-<08><>?}<7D><><EFBFBD>#<23><>ۚ1<DB9A><31>3<EFBFBD><33><1D>B <20><>,<00>2s<32><73><EFBFBD><EFBFBD><01><>P$4<><00>c9@<40><><EFBFBD> <0B><>؅A<1E><><18><>P<EFBFBD><00>x<1D>s<xؘ/<2F><><EFBFBD>QP<><50>}<00><><EFBFBD>r<><72><EFBFBD>y<EFBFBD>@<06>`@@y <20><>~G<01><11>sd<73><07>
+<02><><EFBFBD><06><00><1D>8^<5E>z0'<1D><><EFBFBD><EFBFBD>+ĨY<14> Ee}D<>sv<73><76>\m<><6D>`A7h<37><04>Ȋ<><C88A><EFBFBD><EFBFBD><EFBFBD>r0<72>Fe<>`P <EFBFBD> <12>|<7C><><EFBFBD>s<>ar<>Ae<41>WD<>f|<7C><><EFBFBD><7A>bu<62>1o<>AD<1A>%e<> ֡y<><79>`<1C><><EFBFBD>gXi<58> | B<18>y<EFBFBD>A<07>mp<6D><70>Mj<4D>
+*E<14>_l<5F><6C>YXA<58>RD<11>KqDD<18>l<EFBFBD>D<EFBFBD>`
+"<22><><EFBFBD><EFBFBD>X0<58><30>4<><34>
+<18><>xk<78>Hd<48><64>覫.B;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s9_read.gif forums//site/static/beta5/pics/topic_s9_read.gif
--- beta5//site/static/beta5/pics/topic_s9_read.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s9_read.gif 2011-02-05 10:10:02.684335002 +0100
@@ -0,0 +1,10 @@
+GIF89a <00><>
+
+
+ '''(((***---000111222555666777;;;<<<===>>>???CCCDDDGGGIIIJJJKKKLLLNNNPPPQQQRRRSSSTTTUUUWWW^^^___```bbbcccdddfffkkklllmmmnnnoooqqqrrrtttzzz}}}<7F><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A><>d<EFBFBD>'H<>١ㆍ1\<5C>@q<> 6\<5C><00><>2g<32>t<EFBFBD>re
+#C|<7C><>A#Ɗ#>p<><70><EFBFBD>B˂<01>%K&Lp<4C><70>ѳ<EFBFBD>
+%><3E><><EFBFBD><EFBFBD><EFBFBD><04>AԤAC<41><43>2d<32>x<EFBFBD>…
+(P<><11><><EFBFBD><EFBFBD><06>0Z<30><5A>P"C}*T<><54><EFBFBD>A<EFBFBD>
+<05>Hϟ:4 i<>hQ#F<>)S^<5E><><EFBFBD><EFBFBD>D<EFBFBD>B<>džA"<22>SoV<6F><08>"D<>!<21>S#<23><>ۚ1<DB9A>64 <20><06><><00><> J*'r<02><> @<40>G:<3A>x<EFBFBD><02>(<28>3<00>ق<1E><>0<08>:<3A>2,<10><00> "?<3F><><EFBFBD>_<><5F>m<EFBFBD><6D><19>@ ߀<><DF80><EFBFBD>u<>@<40>y<EFBFBD><79>qm<08>^|<7C><>w<EFBFBD>}<7D>]f)@<02>h`A=0"∌<10><00>0H@<40>Gz<>q<EFBFBD>/<18><>m%<02><10> n`<60>|衇n|H<0F>-B"#E!<21>5{<7B>a<EFBFBD>m<>`<60><0E>-<2D>"<22><00><><02>H<>G"<22><>@9h<39><68>^|2<><1F>(<28><>|䁇}<7D>A<EFBFBD>AL<41>W<EFBFBD>`"<22><>ƈ<><C688>u<EFBFBD><75><EFBFBD>A8<41><38>av
+<2B><><EFBFBD>v<EFBFBD>hGt<>i<>k<EFBFBD>X<EFBFBD> f<EFBFBD><11>a|<7C><>:Y\a<>T<<3C><>I <20>Į<EFBFBD>"A<>A,<2C>`<60><07>b<EFBFBD>A<05>F<EFBFBD><46> 4<><34><EFBFBD> (<28><> , ѵ<>f<EFBFBD><66><EFBFBD>;
\ No newline at end of file
diff -Naur beta5//site/static/beta5/pics/topic_s9_unread.gif forums//site/static/beta5/pics/topic_s9_unread.gif
--- beta5//site/static/beta5/pics/topic_s9_unread.gif 1970-01-01 01:00:00.000000000 +0100
+++ forums//site/static/beta5/pics/topic_s9_unread.gif 2011-02-05 10:10:02.704335002 +0100
@@ -0,0 +1,10 @@
+GIF89a <00><>
+ 
+  
+  '#($*&-(0+1,2-506172;5<6=7>8?9C<!D="G@#IB$JC%KD%LE&NF'PH(QI(RJ)SK)TL*UM*WO+^U/_V/`W0bY1cZ1d[2f\3ka5lb6mc6nd7oe7qf8rg9ti:zo=}q>s?<3F>t@<40>vA<76>wA<77>xB<78>zC<7A>{D<>|D<>}E<>~E<><45>F<EFBFBD><46>G<EFBFBD><47>G<EFBFBD><47>H<EFBFBD><48>H<EFBFBD><48>I<EFBFBD><49>I<EFBFBD><49>J<EFBFBD><4A>J<EFBFBD><4A>K<EFBFBD><4B>K<EFBFBD><4B>L<EFBFBD><4C>M<EFBFBD><4D>N<EFBFBD><4E>N<EFBFBD><4E>O<EFBFBD><4F>O<EFBFBD><4F>P<EFBFBD><50>P<EFBFBD><50>Q<EFBFBD><51>R<EFBFBD><52>S<EFBFBD><53>T<EFBFBD><54>U<EFBFBD><55>V<EFBFBD><56>W<EFBFBD><57>W<EFBFBD><57>X<EFBFBD><58>X<EFBFBD><58>Y<EFBFBD><59>Y<EFBFBD><59>Z<EFBFBD><5A>[<5B><>[<5B><>\<5C><>_ñaɶdнh<D0BD><68>i<EFBFBD><69>j<EFBFBD><6A>k<EFBFBD><6B>l<EFBFBD><6C>l<EFBFBD><6C>m<EFBFBD><6D>m<EFBFBD><6D>n<EFBFBD><6E>p<EFBFBD><70>p<EFBFBD><70>q<EFBFBD><71>q<EFBFBD><71>r<EFBFBD><72>s<EFBFBD><73>t<EFBFBD><74>t<EFBFBD><74>u<EFBFBD><75>u<EFBFBD><75>v<EFBFBD><76>v<EFBFBD><76>w<EFBFBD><77>w<EFBFBD><77>x<EFBFBD><78>x<EFBFBD><78>y<EFBFBD><79>y<EFBFBD><79>z<EFBFBD><7A>z<EFBFBD><7A>{<7B><>{<7B><>|<7C><>|<7C><>}<7D><>}<7D><>~<7E><><EFBFBD><7F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>!<21>
+<00>, <08><00> H<><48><EFBFBD><EFBFBD>*\Ȱ<>Ç#*<2A><>d<EFBFBD>'H<>١ㆍ1\<5C>@q<> 6\<5C><00><>2g<32>t<EFBFBD>re
+#C|<7C><>A#Ɗ#>p<><70><EFBFBD>B˂<01>%K&Lp<4C><70>ѳ<EFBFBD>
+%><3E><><EFBFBD><EFBFBD><EFBFBD><04>AԤAC<41><43>2d<32>x<EFBFBD>…
+(P<><11><><EFBFBD><EFBFBD><06>0Z<30><5A>P"C}*T<><54><EFBFBD>A<EFBFBD>
+<05>Hϟ:4 i<>hQ#F<>)S^<5E><><EFBFBD><EFBFBD>D<EFBFBD>B<>džA"<22>SoV<6F><08>"D<>!<21>S#<23><>ۚ1<DB9A>64 <20><06><><00><> J*'r<02><> @<40>G:<3A>x<EFBFBD><02>(<28>3<00>ق<1E><>0<08>:<3A>2,<10><00> "?<3F><><EFBFBD>_<><5F>m<EFBFBD><6D><19>@ ߀<><DF80><EFBFBD>u<>@<40>y<EFBFBD><79>qm<08>^|<7C><>w<EFBFBD>}<7D>]f)@<02>h`A=0"∌<10><00>0H@<40>Gz<>q<EFBFBD>/<18><>m%<02><10> n`<60>|衇n|H<0F>-B"#E!<21>5{<7B>a<EFBFBD>m<>`<60><0E>-<2D>"<22><00><><02>H<>G"<22><>@9h<39><68>^|2<><1F>(<28><>|䁇}<7D>A<EFBFBD>AL<41>W<EFBFBD>`"<22><>ƈ<><C688>u<EFBFBD><75><EFBFBD>A8<41><38>av
+<2B><><EFBFBD>v<EFBFBD>hGt<>i<>k<EFBFBD>X<EFBFBD> f<EFBFBD><11>a|<7C><>:Y\a<>T<<3C><>I <20>Į<EFBFBD>"A<>A,<2C>`<60><07>b<EFBFBD>A<05>F<EFBFBD><46> 4<><34><EFBFBD> (<28><> , ѵ<>f<EFBFBD><66><EFBFBD>;
\ No newline at end of file
diff -Naur beta5//sql/13-main-forums.sql forums//sql/13-main-forums.sql
--- beta5//sql/13-main-forums.sql 2011-02-05 10:09:56.244335002 +0100
+++ forums//sql/13-main-forums.sql 1970-01-01 01:00:00.000000000 +0100
@@ -1,149 +0,0 @@
--- LegacyWorlds Beta 5
--- PostgreSQL database scripts
---
--- 13-main-forums.sql
---
--- Tables for the forums
---
--- Copyright(C) 2004-2007, DeepClone Development
--- --------------------------------------------------------
-
-
-
--- Connect to the database
-\c legacyworlds legacyworlds_admin
-
-
-
---
--- Forum categories
---
-CREATE TABLE main.f_category (
- id SERIAL NOT NULL PRIMARY KEY,
- corder INT NOT NULL UNIQUE CHECK(corder >= 0),
- title VARCHAR(64) NOT NULL UNIQUE,
- description TEXT
-);
-
-GRANT SELECT,INSERT ON TABLE main.f_category TO legacyworlds;
-GRANT SELECT,UPDATE ON main.f_category_id_seq TO legacyworlds;
-
-
---
--- Forums
---
-CREATE TABLE main.f_forum (
- id SERIAL NOT NULL PRIMARY KEY,
- category INT NOT NULL REFERENCES main.f_category (id) ON DELETE CASCADE,
- forder INT NOT NULL DEFAULT 0 CHECK(forder >= 0),
- title VARCHAR(64) NOT NULL,
- description TEXT,
- topics INT NOT NULL CHECK(topics >= 0),
- posts INT NOT NULL CHECK(posts >= 0),
- last_post BIGINT NULL,
- user_post BOOLEAN NOT NULL DEFAULT TRUE,
- admin_only BOOLEAN NOT NULL DEFAULT FALSE
-);
-
-CREATE UNIQUE INDEX forum_unique ON main.f_forum (category, forder);
-CREATE INDEX forum_last_post ON main.f_forum (last_post);
-
-GRANT SELECT,UPDATE,INSERT ON TABLE main.f_forum TO legacyworlds;
-GRANT SELECT,UPDATE ON main.f_forum_id_seq TO legacyworlds;
-
-
---
--- Topics
---
-CREATE TABLE main.f_topic (
- id BIGSERIAL NOT NULL PRIMARY KEY,
- forum INT NOT NULL REFERENCES main.f_forum (id) ON DELETE CASCADE,
- first_post BIGINT NOT NULL,
- last_post BIGINT NULL,
- sticky BOOLEAN NOT NULL DEFAULT FALSE,
- deleted INT NULL
-);
-
-CREATE INDEX topic_forum ON main.f_topic (forum);
-CREATE INDEX topic_fpost ON main.f_topic (first_post);
-CREATE INDEX topic_lpost ON main.f_topic (last_post);
-
-GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE main.f_topic TO legacyworlds;
-GRANT SELECT,UPDATE ON main.f_topic_id_seq TO legacyworlds;
-
-
---
--- Posts
---
-CREATE TABLE main.f_post (
- id BIGSERIAL PRIMARY KEY,
- forum INT NOT NULL REFERENCES main.f_forum (id) ON DELETE CASCADE,
- topic BIGINT NULL REFERENCES main.f_topic (id) ON DELETE CASCADE,
- author BIGINT NOT NULL REFERENCES main.account (id),
- reply_to BIGINT NULL REFERENCES main.f_post (id) ON DELETE SET NULL,
- moment INT NOT NULL DEFAULT INT4(EXTRACT(EPOCH FROM NOW())),
- title VARCHAR(100) NOT NULL,
- contents TEXT NOT NULL,
- enable_code BOOLEAN NOT NULL DEFAULT TRUE,
- enable_smileys BOOLEAN NOT NULL DEFAULT TRUE,
- edited INT NULL,
- edited_by BIGINT NULL REFERENCES main.account (id),
- deleted INT NULL
-);
-
-CREATE INDEX post_forum ON main.f_post (forum);
-CREATE INDEX post_topic ON main.f_post (topic);
-CREATE INDEX post_author ON main.f_post (author);
-CREATE INDEX post_editor ON main.f_post (edited_by);
-CREATE INDEX post_reply ON main.f_post (reply_to);
-
-ALTER TABLE main.f_forum ADD FOREIGN KEY (last_post) REFERENCES main.f_post (id) ON DELETE SET NULL;
-ALTER TABLE main.f_topic ADD FOREIGN KEY (first_post) REFERENCES main.f_post (id) ON DELETE CASCADE;
-ALTER TABLE main.f_topic ADD FOREIGN KEY (last_post) REFERENCES main.f_post (id) ON DELETE SET NULL;
-
-GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE main.f_post TO legacyworlds;
-GRANT SELECT,UPDATE ON main.f_post_id_seq TO legacyworlds;
-
-
---
--- Read topics
---
-CREATE TABLE main.f_read (
- reader BIGINT NOT NULL REFERENCES main.account (id),
- topic BIGINT NOT NULL REFERENCES main.f_topic (id) ON DELETE CASCADE,
- PRIMARY KEY (reader, topic)
-);
-
-GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE main.f_read TO legacyworlds;
-
-
---
--- Smileys and forum codes
---
-CREATE TABLE main.f_smiley (
- smiley VARCHAR(20) NOT NULL PRIMARY KEY,
- file VARCHAR(20) NOT NULL
-);
-CREATE TABLE main.f_code (
- p_reg_exp VARCHAR(40) NOT NULL PRIMARY KEY,
- replacement VARCHAR(80) NOT NULL
-);
-GRANT SELECT ON main.f_smiley TO legacyworlds;
-GRANT SELECT ON main.f_code TO legacyworlds;
-
-
---
--- Admins, mods, losers
--- Not everything is useful in the current version so meh.
---
-CREATE TABLE main.f_admin (
- "user" BIGINT NOT NULL REFERENCES main.account (id) PRIMARY KEY,
- category INT NULL REFERENCES main.f_category (id) ON DELETE CASCADE
-);
-GRANT SELECT,INSERT,UPDATE,DELETE ON main.f_admin TO legacyworlds;
-
-CREATE TABLE main.f_moderator (
- "user" BIGINT NOT NULL REFERENCES main.account (id) PRIMARY KEY,
- forum INT NULL REFERENCES main.f_forum (id) ON DELETE CASCADE
-);
-GRANT SELECT,INSERT,UPDATE,DELETE ON main.f_moderator TO legacyworlds;
diff -Naur beta5//sql/14-main-forums.sql forums//sql/14-main-forums.sql
--- beta5//sql/14-main-forums.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/14-main-forums.sql 2011-02-05 10:10:01.774335002 +0100
@@ -0,0 +1,227 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- 14-main-forums.sql
+--
+-- Execute the generic forums installation script,
+-- then add tables for the general forums
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+
+-- Install the generic forums
+\i forums/FORUMS.sql
+
+
+--
+-- Create category type for general forums
+--
+SELECT forums.add_category_type( 'main/gforums', 'en', 'General forums' );
+-- SELECT forums.add_category_type( 'main/gforums', 'fr', 'Forums généraux ' );
+
+
+
+--
+-- The general forums' categories
+--
+CREATE TABLE main.gf_category (
+ category BIGINT PRIMARY KEY REFERENCES forums.category (id) ON DELETE CASCADE,
+ t_string VARCHAR(15) NULL,
+ t_is_game BOOLEAN NULL,
+ UNIQUE(t_string, t_is_game)
+);
+
+GRANT SELECT,INSERT,DELETE ON main.gf_category TO legacyworlds;
+
+
+
+--
+-- The general forums' access list
+--
+-- Access type:
+-- - MO: moderator- (and admin-) only access, not visible to most users
+-- - MP: moderator- (and admin-) only posting, standard users can't create new topics
+-- - UP: users can view the forum and create topics, but can't create polls; this is the default
+-- - UL: users can view the forum, create topics and create polls
+--
+CREATE TABLE main.gf_forum (
+ forum BIGINT PRIMARY KEY REFERENCES forums.t_forum (id) ON DELETE CASCADE,
+ access_type CHAR(2) NOT NULL DEFAULT 'UP' CHECK( access_type IN ('MO', 'MP', 'UP', 'UL') )
+);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON main.gf_forum TO legacyworlds;
+
+-- Trigger function & definition for main.gf_forum
+CREATE OR REPLACE FUNCTION main.trgf_gf_forum_check () RETURNS TRIGGER AS $$
+BEGIN
+ PERFORM g.category FROM main.gf_category g, forums.forum f
+ WHERE f.id = NEW.forum AND g.category = f.category;
+ IF NOT FOUND THEN
+ RAISE EXCEPTION 'Forum #% is not a general forum', NEW.forum;
+ END IF;
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+CREATE TRIGGER trg_gf_forum_check BEFORE INSERT OR UPDATE ON main.gf_forum
+ FOR EACH ROW EXECUTE PROCEDURE main.trgf_gf_forum_check();
+
+
+--
+-- Bans on the general forums
+--
+CREATE TABLE main.gf_ban (
+ account BIGINT PRIMARY KEY REFERENCES main.account (id) ON DELETE CASCADE,
+ until INT NOT NULL
+);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON main.gf_ban TO legacyworlds;
+
+
+
+--
+-- General forums administrators
+--
+-- List of people who can create, remove or modify general forums.
+-- An admin is either a general admin (all GF categories) or the admin for a specific category
+--
+CREATE TABLE main.gf_admin (
+ account BIGINT NOT NULL REFERENCES main.account (id) ON DELETE CASCADE,
+ category BIGINT NULL REFERENCES main.gf_category (category) ON DELETE CASCADE,
+ UNIQUE( account, category )
+);
+
+GRANT SELECT,INSERT,DELETE ON main.gf_admin TO legacyworlds;
+
+-- Trigger function & definition that makes sure that you're either a general admin or a category-specific admin,
+-- not both.
+CREATE OR REPLACE FUNCTION main.trgf_gf_admin_check () RETURNS TRIGGER AS $$
+BEGIN
+ IF NEW.category IS NULL THEN
+ PERFORM * FROM main.gf_admin WHERE account = NEW.account AND category IS NOT NULL;
+ IF FOUND THEN
+ RAISE EXCEPTION 'User #% is already a cat-specific admin', NEW.account;
+ END IF;
+ DELETE FROM main.gf_cat_moderator WHERE account = NEW.account;
+ DELETE FROM main.gf_forum_moderator WHERE account = NEW.account;
+ ELSE
+ PERFORM * FROM main.gf_category WHERE category = NEW.category;
+ IF NOT FOUND THEN
+ RAISE EXCEPTION 'Category #% is not a general category', NEW.category;
+ END IF;
+ PERFORM * FROM main.gf_admin WHERE account = NEW.account AND category IS NULL;
+ IF FOUND THEN
+ RAISE EXCEPTION 'User #% is already a general admin', NEW.account;
+ END IF;
+ DELETE FROM main.gf_cat_moderator WHERE account = NEW.account AND category = NEW.category;
+ DELETE FROM main.gf_forum_moderator WHERE account = NEW.account AND forum IN (
+ SELECT id FROM forums.forum WHERE category = NEW.category
+ );
+ END IF;
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+CREATE TRIGGER trg_gf_admin_check BEFORE INSERT ON main.gf_admin
+ FOR EACH ROW EXECUTE PROCEDURE main.trgf_gf_admin_check();
+
+
+
+
+--
+-- General forums moderators, by category
+--
+-- List of people who can moderate whole categories of the general forums.
+-- These people should not already be listed in the admin list for the category.
+--
+CREATE TABLE main.gf_cat_moderator (
+ account BIGINT NOT NULL REFERENCES main.account (id) ON DELETE CASCADE,
+ category BIGINT NULL REFERENCES main.gf_category (category) ON DELETE CASCADE,
+ UNIQUE( account, category )
+);
+
+GRANT SELECT,INSERT,DELETE ON main.gf_cat_moderator TO legacyworlds;
+
+-- Trigger function & definition that makes sure that you're either a general mod or a category-specific mod,
+-- and that you're not an admin.
+CREATE OR REPLACE FUNCTION main.trgf_gf_cmod_check () RETURNS TRIGGER AS $$
+BEGIN
+ IF NEW.category IS NULL THEN
+ PERFORM * FROM main.gf_cat_moderator WHERE account = NEW.account AND category IS NOT NULL;
+ IF FOUND THEN
+ RAISE EXCEPTION 'User #% is already a cat-specific moderator', NEW.account;
+ END IF;
+ PERFORM * FROM main.gf_admin WHERE account = NEW.account AND category IS NULL;
+ IF FOUND THEN
+ RAISE EXCEPTION 'User #% is already a general administrator', NEW.account;
+ END IF;
+ DELETE FROM main.gf_forum_moderator WHERE account = NEW.account;
+ ELSE
+ PERFORM * FROM main.gf_category WHERE category = NEW.category;
+ IF NOT FOUND THEN
+ RAISE EXCEPTION 'Category #% is not a general category', NEW.category;
+ END IF;
+ PERFORM * FROM main.gf_cat_moderator WHERE account = NEW.account AND category IS NULL;
+ IF FOUND THEN
+ RAISE EXCEPTION 'User #% is already a general moderator', NEW.account;
+ END IF;
+ PERFORM * FROM main.gf_admin
+ WHERE account = NEW.account
+ AND (category = NEW.category OR category IS NULL);
+ IF FOUND THEN
+ RAISE EXCEPTION 'User #% is already an administrator for category', NEW.account;
+ END IF;
+ DELETE FROM main.gf_forum_moderator WHERE account = NEW.account AND forum IN (
+ SELECT id FROM forums.forum WHERE category = NEW.category
+ );
+ END IF;
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+CREATE TRIGGER trg_gf_cmod_check BEFORE INSERT ON main.gf_cat_moderator
+ FOR EACH ROW EXECUTE PROCEDURE main.trgf_gf_cmod_check();
+
+
+
+
+--
+-- General forums moderators, by forum
+--
+-- List of people who can moderate specific forums.
+--
+CREATE TABLE main.gf_forum_moderator (
+ account BIGINT NOT NULL REFERENCES main.account (id) ON DELETE CASCADE,
+ forum BIGINT NOT NULL REFERENCES forums.t_forum (id) ON DELETE CASCADE,
+ UNIQUE( account, forum )
+ -- FIXME: add constraint to make sure that if someone's a mod for the forum's category or an admin
+ -- for the category in question, that someone can't be added as a forum-specific moderator
+);
+
+GRANT SELECT,INSERT,DELETE ON main.gf_forum_moderator TO legacyworlds;
+
+-- Trigger function & definition that makes sure that you're not a forums' category mod or admin.
+CREATE OR REPLACE FUNCTION main.trgf_gf_fmod_check() RETURNS TRIGGER AS $$
+DECLARE
+ cid BIGINT;
+BEGIN
+ SELECT INTO cid g.category FROM main.gf_category g, forums.forum f
+ WHERE f.id = NEW.forum AND g.category = f.category;
+ IF NOT FOUND THEN
+ RAISE EXCEPTION 'Forum #% is not a general forum', NEW.forum;
+ END IF;
+
+ PERFORM * FROM main.gf_cat_moderator WHERE account = NEW.account AND (category IS NULL OR category = cid);
+ IF FOUND THEN
+ RAISE EXCEPTION 'User #% is already a moderator for forum #%', NEW.account, NEW.forum;
+ END IF;
+
+ PERFORM * FROM main.gf_admin WHERE account = NEW.account AND (category IS NULL OR category = cid);
+ IF FOUND THEN
+ RAISE EXCEPTION 'User #% is already an administrator for forum #%', NEW.account, NEW.forum;
+ END IF;
+
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+CREATE TRIGGER trg_gf_fmod_check BEFORE INSERT ON main.gf_forum_moderator
+ FOR EACH ROW EXECUTE PROCEDURE main.trgf_gf_fmod_check();
diff -Naur beta5//sql/15-main-gf-functions.sql forums//sql/15-main-gf-functions.sql
--- beta5//sql/15-main-gf-functions.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/15-main-gf-functions.sql 2011-02-05 10:10:01.774335002 +0100
@@ -0,0 +1,205 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- 15-main-gf-functions.sql
+--
+-- Creates the general forums access functions
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+
+--
+-- main.init_general_forums()
+--
+-- This function initialises the general forums by creating
+-- a category for the main GF category.
+
+CREATE OR REPLACE FUNCTION main.init_general_forums() RETURNS BIGINT AS $$
+DECLARE
+ cid BIGINT;
+BEGIN
+ SELECT INTO cid * FROM main.gf_category WHERE t_string IS NULL;
+ IF FOUND THEN
+ RETURN cid;
+ END IF;
+
+ SELECT INTO cid forums.make_category( 'main/gforums' );
+ INSERT INTO main.gf_category (category, t_string, t_is_game )
+ VALUES (cid, NULL, NULL);
+
+ RETURN cid;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- main.init_version_forums( version )
+--
+-- This function initialises the general forums category
+-- for a specific version of LW
+
+CREATE OR REPLACE FUNCTION main.init_version_forums( v TEXT ) RETURNS BIGINT AS $$
+DECLARE
+ cid BIGINT;
+BEGIN
+ SELECT INTO cid * FROM main.gf_category WHERE t_string = v AND NOT t_is_game;
+ IF FOUND THEN
+ RETURN cid;
+ END IF;
+
+ SELECT INTO cid forums.make_category( 'main/gforums' );
+ INSERT INTO main.gf_category (category, t_string, t_is_game )
+ VALUES (cid, v, FALSE);
+
+ RETURN cid;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- main.init_game_forums( game )
+--
+-- This function initialises the general forums category
+-- for a specific LW game
+
+CREATE OR REPLACE FUNCTION main.init_game_forums( g TEXT ) RETURNS BIGINT AS $$
+DECLARE
+ cid BIGINT;
+BEGIN
+ SELECT INTO cid * FROM main.gf_category WHERE t_string = g AND t_is_game;
+ IF FOUND THEN
+ RETURN cid;
+ END IF;
+
+ SELECT INTO cid forums.make_category( 'main/gforums' );
+ INSERT INTO main.gf_category (category, t_string, t_is_game )
+ VALUES (cid, g, TRUE);
+
+ RETURN cid;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- main.get_gf_categories( version , game )
+--
+-- Returns the list of all available general forum categories for a version and game
+
+CREATE OR REPLACE FUNCTION main.get_gf_categories( ver TEXT, game TEXT ) RETURNS SETOF BIGINT AS $$
+ SELECT category FROM main.gf_category
+ WHERE t_string IS NULL
+ OR (t_string = $1 AND NOT t_is_game)
+ OR (t_string = $2 AND t_is_game)
+ ORDER BY category;
+$$ LANGUAGE SQL;
+
+
+--
+-- main.get_gf_list( version , game )
+--
+-- Returns the list of all available general forums for a version and game
+
+CREATE OR REPLACE FUNCTION main.get_gf_list( ver TEXT, game TEXT ) RETURNS SETOF BIGINT AS $$
+ SELECT id FROM forums.t_forum
+ WHERE category IN ( SELECT * FROM main.get_gf_categories( $1, $2 ) )
+ ORDER BY category, f_order;
+$$ LANGUAGE SQL;
+
+
+--
+-- main.get_gforums_privs( user , forum )
+--
+-- Returns the set of privileges an user has over a specific general forum
+
+CREATE OR REPLACE FUNCTION main.get_gforums_privs( aid BIGINT, fid BIGINT, OUT can_view BOOLEAN, OUT can_post BOOLEAN, OUT can_create BOOLEAN, OUT can_poll BOOLEAN, OUT is_mod BOOLEAN, OUT is_admin BOOLEAN) AS $$
+DECLARE
+ cid BIGINT;
+ r TEXT;
+BEGIN
+ -- Get the category's ID
+ SELECT INTO cid category FROM forums.t_forum WHERE id = fid;
+ IF NOT FOUND THEN
+ is_admin := FALSE;
+ is_mod := FALSE;
+ can_view := FALSE;
+ can_post := FALSE;
+ can_create := FALSE;
+ can_poll := FALSE;
+ RETURN;
+ END IF;
+
+ -- Check if this is a general category
+ PERFORM * FROM main.gf_category WHERE category = cid;
+ IF NOT FOUND THEN
+ RETURN;
+ END IF;
+
+ -- Fetch category admin details
+ PERFORM * FROM main.gf_admin WHERE (category IS NULL OR category = cid) AND account = aid;
+ IF FOUND THEN
+ can_view := TRUE;
+ can_post := TRUE;
+ can_create := TRUE;
+ can_poll := TRUE;
+ is_mod := TRUE;
+ is_admin := TRUE;
+ RETURN;
+ END IF;
+ is_admin := FALSE;
+
+ -- Fetch category mod details
+ PERFORM * FROM main.gf_cat_moderator WHERE (category IS NULL OR category = cid) AND account = aid;
+ IF FOUND THEN
+ can_view := TRUE;
+ can_post := TRUE;
+ can_create := TRUE;
+ can_poll := TRUE;
+ is_mod := TRUE;
+ RETURN;
+ END IF;
+
+ -- Fetch forum mod details
+ PERFORM * FROM main.gf_forum_moderator WHERE forum = fid AND account = aid;
+ IF FOUND THEN
+ can_view := TRUE;
+ can_post := TRUE;
+ can_create := TRUE;
+ can_poll := TRUE;
+ is_mod := TRUE;
+ RETURN;
+ END IF;
+ is_mod := false;
+
+ -- Check forum access
+ SELECT INTO r access_type FROM main.gf_forum WHERE forum = fid;
+ IF NOT FOUND THEN
+ r := 'UP';
+ END IF;
+
+ -- Check for mod-only forum
+ IF r = 'MO' THEN
+ can_view := FALSE;
+ can_post := FALSE;
+ can_create := FALSE;
+ can_poll := FALSE;
+ RETURN;
+ END IF;
+ can_view := TRUE;
+
+ -- Check for bans
+ PERFORM * FROM main.gf_ban WHERE account = aid;
+ IF FOUND THEN
+ can_post := FALSE;
+ can_create := FALSE;
+ can_poll := FALSE;
+ RETURN;
+ END IF;
+
+ -- Set can_post, can_create and can_poll depending on the access type
+ can_post := TRUE;
+ can_create := (r = 'UP' OR r = 'UL');
+ can_poll := (r = 'UL');
+END;
+$$ LANGUAGE plpgsql;
diff -Naur beta5//sql/15-main-uforums.sql forums//sql/15-main-uforums.sql
--- beta5//sql/15-main-uforums.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/15-main-uforums.sql 2011-02-05 10:10:01.774335002 +0100
@@ -0,0 +1,332 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- 15-main-uforums.sql
+--
+-- Add tables and functions to manage the user forums
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+--
+-- Access types for forums:
+-- - 'P': public
+-- - 'W': password
+-- - 'I': invite-only
+--
+-- User access flag:
+-- - 'M': moderator
+-- - 'L': can start topics, post and create polls
+-- - 'T': can start topics and post
+-- - 'P': can post
+-- - 'R': can read
+
+
+--
+-- Create category type
+--
+SELECT forums.add_category_type( 'main/uforums', 'en', 'User forums' );
+
+
+--
+-- main.uf_get_access_mode( forum )
+--
+-- Returns the access mode for a specific user forum
+
+CREATE OR REPLACE FUNCTION main.uf_get_access_mode( fid BIGINT ) RETURNS TEXT AS $$
+DECLARE
+ cid BIGINT;
+ am TEXT;
+BEGIN
+ -- Check if the forum exists and is an user forum; if it is, get the access mode
+ SELECT INTO am access_mode FROM main.user_forum WHERE forum = fid;
+ IF NOT FOUND THEN
+ RETURN NULL;
+ END IF;
+
+ IF am IS NULL THEN
+ -- Forum uses defaults, get its category
+ SELECT INTO cid category FROM forums.t_forum WHERE id = fid;
+ SELECT INTO am default_access FROM main.user_category;
+ END IF;
+
+ RETURN am;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- main.uf_get_user_access( user, forum )
+--
+-- Returns the user access mode for a specific user and forum combination
+
+CREATE OR REPLACE FUNCTION main.uf_get_user_access( aid BIGINT, fid BIGINT ) RETURNS TEXT AS $$
+DECLARE
+ fua TEXT;
+ r RECORD;
+BEGIN
+ -- Read the category's data
+ SELECT INTO r c.account AS fo, c.user_access AS am FROM main.user_category c, forums.t_forum f
+ WHERE c.category = f.category AND f.id = fid;
+
+ -- Try reading the subscription value
+ SELECT INTO fua access_mode FROM main.uf_subscription WHERE account = aid;
+ IF NOT FOUND THEN
+ -- No subscription - check if we're the owner
+ IF r.fo = aid THEN
+ RETURN 'A';
+ END IF;
+ RETURN NULL;
+ END IF;
+
+ -- We got a subscription value
+ IF fua IS NOT NULL THEN
+ RETURN fua;
+ END IF;
+
+ -- Check if the forum exists and get its default user access
+ SELECT INTO fua user_access FROM main.user_forum WHERE forum = fid;
+ IF NOT FOUND THEN
+ RETURN NULL;
+ END IF;
+
+ -- If we had a default user access mode, return it
+ IF fua IS NOT NULL THEN
+ RETURN fua;
+ END IF;
+
+ -- Return the category's default access mode
+ RETURN r.am;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- main.uf_get_category( user )
+--
+-- Gets the ID of the user's forums category. If it doesn't exist, create it.
+
+CREATE OR REPLACE FUNCTION main.uf_get_category( aid BIGINT ) RETURNS BIGINT AS $$
+DECLARE
+ cid BIGINT;
+BEGIN
+ SELECT INTO cid category FROM main.user_category WHERE account = aid;
+ IF NOT FOUND THEN
+ cid := forums.make_category( 'main/uforums' );
+ INSERT INTO main.user_category (category, account) VALUES (cid, aid);
+ END IF;
+ RETURN cid;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- main.uf_create_forum( user, forum_order, forum_title, forum_description, user_access, access_mode, password )
+--
+-- Creates an user forum.
+-- Return values:
+-- any positive value: identifier of the new forum
+-- -1: the user has 20 forums already
+-- -2: invalid access modes
+-- -3: a forum with the same name already exists
+-- -4: failure in the generic forums code
+
+CREATE OR REPLACE FUNCTION main.uf_create_forum( aid BIGINT, fo INT, ttl TEXT, dsc TEXT, ua TEXT, am TEXT, pass TEXT) RETURNS BIGINT AS $$
+DECLARE
+ cid BIGINT;
+ fid BIGINT;
+ n INT;
+ cam TEXT;
+BEGIN
+ -- Get the user's category and check if it's possible to create the user's new forum
+ cid := main.uf_get_category( aid );
+ SELECT INTO n COUNT(*) FROM forums.t_forum WHERE category = cid AND deleted IS NULL;
+ IF n = 20 THEN
+ RETURN -1;
+ END IF;
+
+ -- Check the access mode
+ SELECT INTO cam default_access FROM main.user_category WHERE category = cid;
+ IF (am = 'W' AND pass IS NULL) OR (am IS NULL AND cam = 'W' AND pass IS NULL) THEN
+ RETURN -2;
+ END IF;
+
+ -- Check the forum's title
+ PERFORM * FROM forums.t_forum WHERE category = cid AND title = ttl;
+ IF FOUND THEN
+ RETURN -3;
+ END IF;
+
+ -- Create the forum
+ fid := forums.make_forum( cid, fo, ttl, dsc );
+ IF fid IS NULL THEN
+ RETURN -4;
+ END IF;
+ IF (am = 'W' OR (am IS NULL AND cam = 'W')) THEN
+ INSERT INTO main.user_forum (forum, access_mode, password, user_access) VALUES ( fid, am, pass, ua );
+ ELSE
+ INSERT INTO main.user_forum (forum, access_mode, user_access) VALUES ( fid, am, ua );
+ END IF;
+
+ RETURN fid;
+END;
+$$ LANGUAGE plpgsql;
+
+
+
+
+--
+-- Category / user mapping
+--
+-- If the account gets disabled (QUIT, INAC), we need to mark the forums for deletion.
+-- If the account gets re-enabled (STD), we need to restore the forums.
+-- If the account gets kicked, we need to delete the forums immediately.
+
+CREATE TABLE main.user_category (
+ account BIGINT PRIMARY KEY REFERENCES main.account (id) ON DELETE CASCADE,
+ category BIGINT NOT NULL UNIQUE REFERENCES forums.category (id) ON DELETE CASCADE,
+ default_access CHAR(1) NOT NULL DEFAULT 'I' CHECK( default_access IN ('P', 'I') ),
+ user_access CHAR(1) NOT NULL DEFAULT 'T' CHECK( user_access IN ('M', 'L', 'T', 'P', 'R') )
+);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON main.user_category TO legacyworlds;
+
+-- Trigger function & definition for the account table that allows handling the users' categories.
+CREATE OR REPLACE FUNCTION main.trgf_account_user_forums() RETURNS TRIGGER AS $$
+DECLARE
+ cid BIGINT;
+BEGIN
+ -- No status change, proceed
+ IF NEW.status = OLD.status THEN
+ RETURN NEW;
+ END IF;
+
+ -- Get the user's category
+ SELECT INTO cid category FROM main.user_category WHERE account = NEW.id;
+ IF NOT FOUND THEN
+ RETURN NEW;
+ END IF;
+
+ -- Check the new status
+ IF NEW.status = 'INAC' OR NEW.status = 'QUIT' THEN
+ PERFORM forums.delete_forums( cid, NEW.id );
+ ELSIF NEW.status = 'STD' THEN
+ PERFORM forums.restore_forums( cid );
+ ELSIF NEW.status = 'KICKED' THEN
+ DELETE FROM forums.category WHERE id = cid;
+ END IF;
+
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+CREATE TRIGGER trg_account_user_forums BEFORE UPDATE ON main.account
+ FOR EACH ROW EXECUTE PROCEDURE main.trgf_account_user_forums();
+
+
+
+--
+-- User forums
+--
+
+CREATE TABLE main.user_forum (
+ forum BIGINT PRIMARY KEY REFERENCES forums.t_forum (id) ON DELETE CASCADE,
+ access_mode CHAR(1) DEFAULT NULL CHECK( access_mode IS NULL
+ OR access_mode IN ('P', 'W', 'I') ),
+ password VARCHAR(64) DEFAULT NULL,
+ user_access CHAR(1) DEFAULT NULL CHECK( user_access IS NULL
+ OR user_access IN ('M', 'L', 'T', 'P', 'R') ),
+ CHECK( (main.uf_get_access_mode(forum) = 'W' AND password IS NOT NULL)
+ OR (main.uf_get_access_mode(forum) <> 'W' AND password IS NULL) )
+);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON main.user_forum TO legacyworlds;
+
+
+--
+-- Subscriptions
+--
+-- An user can't subscribe to one of his own forums.
+--
+
+CREATE TABLE main.uf_subscription (
+ forum BIGINT NOT NULL REFERENCES main.user_forum (forum) ON DELETE CASCADE,
+ account BIGINT NOT NULL REFERENCES main.account (id) ON DELETE CASCADE,
+ access_mode CHAR(1) DEFAULT NULL CHECK( access_mode IS NULL
+ OR access_mode IN ('M', 'L', 'T', 'P', 'R') ),
+ PRIMARY KEY( forum, account )
+);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON main.uf_subscription TO legacyworlds;
+
+-- Trigger function & definition
+CREATE OR REPLACE FUNCTION main.trgf_uf_subscription_check() RETURNS TRIGGER AS $$
+DECLARE
+ fo BIGINT;
+BEGIN
+ IF TG_OP = 'INSERT' THEN
+ SELECT INTO fo account FROM main.user_category c, forums.t_forum f
+ WHERE c.category = f.category AND f.id = NEW.forum;
+ IF FOUND AND fo = NEW.account THEN
+ RETURN NULL;
+ END IF;
+ ELSIF TG_OP = 'UPDATE' THEN
+ NEW.forum = OLD.forum;
+ NEW.account = OLD.account;
+ END IF;
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+CREATE TRIGGER trg_uf_subscription_check BEFORE INSERT OR UPDATE ON main.uf_subscription
+ FOR EACH ROW EXECUTE PROCEDURE main.trgf_uf_subscription_check();
+
+
+--
+-- Invites
+--
+-- An user can only be invited to an invite-only user forum.
+-- An user can be invited if he's not already a subscriber to the forum.
+-- An user can't be invited to one of his own forums.
+--
+
+CREATE TABLE main.uf_invite (
+ forum BIGINT NOT NULL REFERENCES main.user_forum (forum) ON DELETE CASCADE,
+ account BIGINT NOT NULL REFERENCES main.account (id) ON DELETE CASCADE,
+ sent_on INT NOT NULL DEFAULT UNIX_TIMESTAMP( NOW() ),
+ PRIMARY KEY( forum, account )
+);
+
+GRANT SELECT,INSERT,DELETE ON main.uf_invite TO legacyworlds;
+
+-- Trigger function & definition
+CREATE OR REPLACE FUNCTION main.trgf_uf_invite_check() RETURNS TRIGGER AS $$
+DECLARE
+ m TEXT;
+ fo BIGINT;
+BEGIN
+ -- Check the forum's access mode
+ m := main.uf_get_access_mode( NEW.forum );
+ IF m IS NULL OR m <> 'I' THEN
+ RETURN NULL;
+ END IF;
+ -- Check for a subscription by the user
+ PERFORM * FROM main.uf_subscription WHERE forum = NEW.forum AND account = NEW.account;
+ IF FOUND THEN
+ RETURN NULL;
+ END IF;
+ -- Check for an existing invite for the user
+ PERFORM * FROM main.uf_invite WHERE forum = NEW.forum AND account = NEW.account;
+ IF FOUND THEN
+ RETURN NULL;
+ END IF;
+ -- Check if the user is actually the forum's owner
+ SELECT INTO fo account FROM main.user_category c, forums.t_forum f
+ WHERE c.category = f.category AND f.id = NEW.forum;
+ IF FOUND AND fo = NEW.account THEN
+ RETURN NULL;
+ END IF;
+ RETURN NEW;
+END;
+$$ LANGUAGE plpgsql;
+CREATE TRIGGER trg_uf_invite_check BEFORE INSERT ON main.uf_invite
+ FOR EACH ROW EXECUTE PROCEDURE main.trgf_uf_invite_check();
diff -Naur beta5//sql/18-main-functions.sql forums//sql/18-main-functions.sql
--- beta5//sql/18-main-functions.sql 2011-02-05 10:09:56.244335002 +0100
+++ forums//sql/18-main-functions.sql 2011-02-05 10:10:01.774335002 +0100
@@ -27,8 +27,13 @@
--
-- Function that registers a game
--
-CREATE OR REPLACE FUNCTION main.register_game (version TEXT, game_name TEXT) RETURNS VOID AS $$
+CREATE OR REPLACE FUNCTION main.register_game (ver TEXT, gn TEXT) RETURNS VOID AS $$
+BEGIN
INSERT INTO main.ranking_game (ranking, game)
- SELECT id, $2 FROM main.ranking_def
- WHERE version = $1;
-$$ LANGUAGE SQL;
+ SELECT id, gn FROM main.ranking_def
+ WHERE version = ver;
+ PERFORM main.init_general_forums();
+ PERFORM main.init_version_forums( ver );
+ PERFORM main.init_game_forums( gn );
+END;
+$$ LANGUAGE plpgsql;
diff -Naur beta5//sql/19-main-values.sql forums//sql/19-main-values.sql
--- beta5//sql/19-main-values.sql 2011-02-05 10:09:56.244335002 +0100
+++ forums//sql/19-main-values.sql 2011-03-12 15:05:03.511300054 +0100
@@ -77,49 +77,6 @@
\.
-COPY main.f_smiley FROM STDIN;
-:-?\\) smile
-[:;]-?p razz
-:-?D lol
-[:;]-&gt; biggrin
-;-?\\) wink
-;-?D mrgreen
-:-?\\( sad
-:evil: evil
-:smile: smile
-:happy: smile
-:wink: wink
-:sad: sad
-:unhappy: sad
-:'\\( cry
-:cry: cry
-:crying: cry
-:grin: biggrin
-:lol: lol
-:tongue: razz
-:rofl: mrgreen
-[:;]-?\\| neutral
-:neutral: neutral
-\.
-
-
-COPY main.f_code FROM STDIN;
-\\[b\\](.*?)\\[\\/b\\] <b>$1</b>
-\\[u\\](.*?)\\[\\/u\\] <u>$1</u>
-\\[i\\](.*?)\\[\\/i\\] <i>$1</i>
-\\[sep(arator)?\\] <hr/>
-\\[item\\](.*?)\\[\\/item\\] <ul><li>$1</li></ul>
-\\[quote\\](.*?)\\[\\/quote\\] <blockquote class="quote">$1</blockquote>
-\\[quote=([^\\]]+)\\](.*?)\\[\\/quote\\] <blockquote class="quote"><b>$1</b> said:<br/>$2</blockquote>
-\\[link=(http[^\\]]+)\\](.+?)\\[\\/link\\] <a href="$1" target="_blank">$2</a>
-\\[code\\](.*?)\\[\\/code\\] <pre>$1</pre>
-<\\/li><\\/ul>\\s*(<br\\/>\\s*)*<ul><li> </li><li>
-\\[manual\\](.*?)\\[\\/manual\\] <a href="manual" target="_blank">$1</a>
-\\[manual=(\\w+)(#\\w+)?\\](.*?)\\[\\/manual\\] <a href="manual?p=$1$2" target="_blank">$3</a>
-\\[topic=(\\d+)\\](.*?)\\[\\/topic\\] <a href="forums?cmd=T%23G%23$1" target="_blank">$2</a>
-\.
-
-
-- Connect to the database in USER mode
\c legacyworlds legacyworlds
diff -Naur beta5//sql/beta5/00-beta5.sql forums//sql/beta5/00-beta5.sql
--- beta5//sql/beta5/00-beta5.sql 2011-02-05 10:09:56.184335002 +0100
+++ forums//sql/beta5/00-beta5.sql 2011-02-05 10:10:01.744335002 +0100
@@ -44,3 +44,6 @@
'for a long term estimate of the bets players'' accomplishments.');
SELECT add_ranking_description('beta5', 'p_idr', 'en', 'Inflicted Damage Ranking',
'This ranking represents the amount of damage a player has inflicted on other players'' fleets.');
+
+
+SELECT forums.add_category_type( 'beta5/aforums', 'en', 'Alliance forums' );
diff -Naur beta5//sql/beta5/structure/01-alliance.sql forums//sql/beta5/structure/01-alliance.sql
--- beta5//sql/beta5/structure/01-alliance.sql 2011-02-05 10:09:56.174335002 +0100
+++ forums//sql/beta5/structure/01-alliance.sql 2011-03-12 14:59:24.651300052 +0100
@@ -20,12 +20,15 @@
successor BIGINT REFERENCES player (id),
democracy BOOLEAN NOT NULL DEFAULT FALSE,
default_grade BIGINT NOT NULL,
+ f_category BIGINT NOT NULL DEFAULT forums.make_category('beta5/forums')
+ REFERENCES forums.category (id),
enable_tt CHAR(1) NOT NULL DEFAULT 'N' CHECK(enable_tt IN ('N', 'S', 'R'))
);
CREATE INDEX alliance_leader ON alliance (leader);
CREATE INDEX alliance_successor ON alliance (successor);
CREATE INDEX alliance_def_grade ON alliance (default_grade);
+CREATE INDEX alliance_f_category ON alliance (f_category);
GRANT SELECT,INSERT,UPDATE,DELETE ON alliance TO legacyworlds;
GRANT SELECT,UPDATE ON alliance_id_seq TO legacyworlds;
diff -Naur beta5//sql/beta5/structure/02-alliance-forums.sql forums//sql/beta5/structure/02-alliance-forums.sql
--- beta5//sql/beta5/structure/02-alliance-forums.sql 2011-02-05 10:09:56.174335002 +0100
+++ forums//sql/beta5/structure/02-alliance-forums.sql 2011-03-12 15:02:40.271300051 +0100
@@ -10,91 +10,268 @@
-- --------------------------------------------------------
-CREATE TABLE af_forum (
- id SERIAL PRIMARY KEY,
- alliance INT NOT NULL REFERENCES alliance(id) ON DELETE CASCADE,
- forder INT NOT NULL CHECK(forder >= 0),
- title VARCHAR(64) NOT NULL,
- description TEXT,
- topics INT NOT NULL DEFAULT 0 CHECK(topics >= 0),
- posts INT NOT NULL DEFAULT 0 CHECK(posts >= 0),
- last_post BIGINT,
- user_post BOOLEAN NOT NULL DEFAULT TRUE,
- UNIQUE(alliance, forder),
- UNIQUE(alliance, title)
-);
-
-CREATE INDEX af_forum_last_post ON af_forum (last_post);
-
-GRANT SELECT,INSERT,UPDATE,DELETE ON af_forum TO legacyworlds;
-GRANT SELECT,UPDATE ON af_forum_id_seq TO legacyworlds;
-
-
-
-CREATE TABLE af_topic (
- id BIGSERIAL NOT NULL PRIMARY KEY,
- forum INT NOT NULL REFERENCES af_forum (id) ON DELETE CASCADE,
- first_post BIGINT NOT NULL,
- last_post BIGINT,
- sticky BOOLEAN NOT NULL DEFAULT FALSE
-);
+--
+-- Access types for alliance forums
+--
+-- - M: only mods can post, create topics and polls
+-- - P: only mods can create topics and polls, users can post
+-- - T: only mods can create polls, users can create topics and post
+-- - L: users can create polls or topics and post
+--
-CREATE INDEX af_topic_forum ON af_topic (forum);
-CREATE INDEX af_topic_first_post ON af_topic (first_post);
-CREATE INDEX af_topic_last_post ON af_topic (last_post);
-
-GRANT SELECT,INSERT,UPDATE,DELETE ON af_topic TO legacyworlds;
-GRANT SELECT,UPDATE ON af_topic_id_seq TO legacyworlds;
+--
+-- Alliance forums
+--
-CREATE TABLE af_post (
- id BIGSERIAL NOT NULL PRIMARY KEY,
- forum INT NOT NULL REFERENCES af_forum (id) ON DELETE CASCADE,
- topic BIGINT REFERENCES af_topic (id) ON DELETE CASCADE,
- author BIGINT NOT NULL REFERENCES player (id),
- reply_to BIGINT REFERENCES af_post (id) ON DELETE NO ACTION,
- moment INT NOT NULL DEFAULT INT4(EXTRACT(EPOCH FROM NOW())),
- title VARCHAR(100) NOT NULL,
- contents TEXT NOT NULL,
- enable_code BOOLEAN NOT NULL DEFAULT TRUE,
- enable_smileys BOOLEAN NOT NULL DEFAULT TRUE,
- edited INT,
- edited_by BIGINT REFERENCES player(id)
+CREATE TABLE alliance_forum (
+ forum BIGINT PRIMARY KEY REFERENCES forums.t_forum (id) ON DELETE CASCADE,
+ alliance INT NOT NULL REFERENCES alliance(id) ON DELETE CASCADE,
+ access_mode CHAR(1) NOT NULL DEFAULT('T') CHECK( access_mode IN ('M', 'P', 'T', 'L') ),
+ UNIQUE( alliance, forum )
);
-CREATE INDEX af_post_forum ON af_post (forum);
-CREATE INDEX af_post_topic ON af_post (topic);
-CREATE INDEX af_post_author ON af_post (author);
-CREATE INDEX af_post_reply_to ON af_post (reply_to);
-CREATE INDEX af_post_edited_by ON af_post (edited_by);
-
-ALTER TABLE af_forum ADD FOREIGN KEY (last_post) REFERENCES af_post (id) ON DELETE SET NULL;
-ALTER TABLE af_topic ADD FOREIGN KEY (first_post) REFERENCES af_post (id) ON DELETE CASCADE;
-ALTER TABLE af_topic ADD FOREIGN KEY (last_post) REFERENCES af_post (id) ON DELETE SET NULL;
+GRANT SELECT, INSERT, UPDATE ON alliance_forum TO legacyworlds;
-GRANT SELECT,INSERT,UPDATE,DELETE ON af_post TO legacyworlds;
-GRANT SELECT,UPDATE ON af_post_id_seq TO legacyworlds;
+--
+-- Alliance ranks / forum access
+--
-CREATE TABLE af_read (
- reader BIGINT NOT NULL REFERENCES player (id),
- topic BIGINT NOT NULL REFERENCES af_topic (id) ON DELETE CASCADE,
- PRIMARY KEY (reader, topic)
+CREATE TABLE al_rank_forum (
+ rank BIGINT NOT NULL REFERENCES alliance_grade (id) ON DELETE CASCADE,
+ forum INT NOT NULL REFERENCES alliance_forum (forum) ON DELETE CASCADE,
+ is_mod BOOLEAN NOT NULL DEFAULT FALSE,
+ PRIMARY KEY ( rank, forum )
);
-CREATE INDEX af_read_topic ON af_read (topic);
-GRANT SELECT,INSERT,DELETE ON af_read TO legacyworlds;
-
+CREATE INDEX al_rank_forum_forum ON al_rank_forum (forum);
+GRANT SELECT,INSERT,DELETE,UPDATE ON al_rank_forum TO legacyworlds;
-CREATE TABLE algr_forums (
- grade BIGINT NOT NULL REFERENCES alliance_grade (id) ON DELETE CASCADE,
- forum INT NOT NULL REFERENCES af_forum (id) ON DELETE CASCADE,
- is_mod BOOLEAN NOT NULL DEFAULT FALSE,
- PRIMARY KEY (grade, forum)
-);
-
-CREATE INDEX algr_forums_forum ON algr_forums (forum);
-GRANT SELECT,INSERT,DELETE,UPDATE ON algr_forums TO legacyworlds;
+--
+-- create_alliance_forum( player, alliance, order, title, description, access_mode )
+--
+-- Creates a new forum in an alliance. Return values:
+-- any positive value: identifier of the new forum
+-- -1: alliance not found
+-- -2: the player doesn't have the necessary privileges to create the forum
+-- -3: the alliance already has 30 forums
+-- -4: a forum with the same title already exists
+-- -5: invalid access mode
+-- -6: failure to create the generic forum
+
+CREATE OR REPLACE FUNCTION create_alliance_forum( pid BIGINT, aid BIGINT, fo INT, ttl TEXT, dsc TEXT, am TEXT) RETURNS BIGINT AS $$
+DECLARE
+ arec RECORD;
+ prec RECORD;
+ rid BIGINT;
+ rrec RECORD;
+ nf BIGINT;
+BEGIN
+ -- Check the access mode
+ IF am NOT IN ('M','P','T','L') THEN
+ RETURN -5;
+ END IF;
+
+ -- Get the alliance's record
+ SELECT INTO arec default_grade, f_category, leader FROM alliance WHERE id = aid;
+ IF NOT FOUND THEN
+ RETURN -1;
+ END IF;
+
+ -- Get the player's record
+ SELECT INTO prec alliance, a_grade FROM player WHERE id = pid AND (quit IS NULL OR quit > UNIX_TIMESTAMP(NOW()))
+ AND alliance = aid AND a_status = 'IN ';
+ IF NOT FOUND THEN
+ RETURN -2;
+ END IF;
+
+ -- Get the player's rank
+ rid := CASE prec.a_grade IS NULL
+ WHEN TRUE THEN arec.default_grade
+ ELSE prec.a_grade
+ END;
+ SELECT INTO rrec forum_admin FROM alliance_grade WHERE id = rid;
+ IF NOT FOUND THEN
+ RETURN -2;
+ END IF;
+
+ -- Check if the player has access
+ IF NOT (pid = arec.leader OR rrec.forum_admin) THEN
+ RETURN -2;
+ END IF;
+
+ -- Check the amount of forums the alliance has
+ SELECT INTO nf COUNT(*) FROM alliance_forum WHERE alliance = aid;
+ IF nf >= 30 THEN
+ RETURN -3;
+ END IF;
+
+ -- Check the forum's title
+ PERFORM * FROM forums.t_forum WHERE category = arec.f_category AND title = ttl;
+ IF FOUND THEN
+ RETURN -4;
+ END IF;
+
+ -- Create the forum
+ nf := forums.make_forum( arec.f_category, fo, ttl, dsc );
+ IF nf IS NULL THEN
+ RETURN -6;
+ END IF;
+ INSERT INTO alliance_forum (forum, alliance, access_mode) VALUES (nf, aid, am);
+ RETURN nf;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- modify_alliance_forum( player, forum, title, description, access_mode )
+--
+-- This function tries to modify an existing alliance forum. Return values:
+-- 0 success
+-- -1 invalid access mode
+-- -2 the player is not in the alliance
+-- -3 the player is not a forum administrator for the alliance
+-- -4 forum not found
+
+CREATE OR REPLACE FUNCTION modify_alliance_forum( pid BIGINT, fid BIGINT, ttl TEXT, dsc TEXT, am TEXT ) RETURNS INT AS $$
+DECLARE
+ prec RECORD;
+ arec RECORD;
+ rid BIGINT;
+BEGIN
+ -- Check the access mode
+ IF am NOT IN ('M','P','T','L') THEN
+ RETURN -1;
+ END IF;
+
+ -- Get the player's alliance and rank
+ SELECT INTO prec alliance, a_grade FROM player WHERE id = pid AND (quit IS NULL OR quit > UNIX_TIMESTAMP(NOW()))
+ AND alliance IS NOT NULL AND a_status = 'IN ';
+ IF NOT FOUND THEN
+ RETURN -2;
+ END IF;
+
+ -- Check the player's privileges
+ SELECT INTO arec default_grade, leader FROM alliance WHERE id = prec.alliance;
+ IF (arec.leader <> pid) THEN
+ rid := CASE prec.a_grade IS NULL
+ WHEN TRUE THEN arec.default_grade
+ ELSE prec.a_grade
+ END;
+ PERFORM id FROM alliance_grade WHERE id = rid AND forum_admin;
+ IF NOT FOUND THEN
+ RETURN -3;
+ END IF;
+ END IF;
+
+ -- Make sure the forum exists and hasn't been deleted
+ PERFORM f.id,af.alliance FROM forums.t_forum f, alliance_forum af
+ WHERE af.alliance = prec.alliance AND f.id = af.forum AND f.deleted IS NULL;
+ IF NOT FOUND THEN
+ RETURN -4;
+ END IF;
+
+ -- Update both the forum and the access table
+ UPDATE forums.t_forum SET title = ttl, description = dsc WHERE id = fid;
+ UPDATE alliance_forum SET access_mode = am WHERE forum = fid;
+ RETURN 0;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- get_aforums_privs( player, forum )
+--
+-- Returns the set of privileges a player has over a specific alliance forum
+
+CREATE OR REPLACE FUNCTION get_aforums_privs( pid BIGINT, fid BIGINT, OUT can_view BOOLEAN, OUT can_post BOOLEAN, OUT can_create BOOLEAN, OUT can_poll BOOLEAN, OUT is_mod BOOLEAN, OUT is_admin BOOLEAN) AS $$
+DECLARE
+ cid BIGINT;
+ rid BIGINT;
+ arec RECORD;
+ b BOOLEAN;
+BEGIN
+ -- Initialise all privileges to FALSE
+ is_admin := FALSE;
+ is_mod := FALSE;
+ can_view := FALSE;
+ can_post := FALSE;
+ can_create := FALSE;
+ can_poll := FALSE;
+
+ -- Checks whether it's an alliance forum and get the associated data
+ SELECT INTO arec a.id, a.leader, a.default_grade, af.access_mode
+ FROM alliance a, alliance_forum af
+ WHERE af.forum = fid AND a.id = af.alliance;
+ IF NOT FOUND THEN
+ RETURN;
+ END IF;
+
+ -- If the player is the leader, set all privileges to TRUE and return
+ IF arec.leader = pid THEN
+ is_admin := TRUE;
+ is_mod := TRUE;
+ can_view := TRUE;
+ can_post := TRUE;
+ can_create := TRUE;
+ can_poll := TRUE;
+ RETURN;
+ END IF;
+
+ -- Checks whether the player is an actual member of the alliance and get his rank
+ SELECT INTO rid a_grade FROM player
+ WHERE id = pid AND (quit IS NULL OR quit > UNIX_TIMESTAMP(NOW()))
+ AND alliance = arec.id AND a_status = 'IN ';
+ IF NOT FOUND THEN
+ RETURN;
+ ELSIF rid IS NULL THEN
+ rid := arec.default_grade;
+ END IF;
+
+ -- Checks whether the player is a forums admin for the alliance
+ SELECT INTO b forum_admin FROM alliance_grade WHERE id = rid;
+ IF NOT FOUND THEN
+ RETURN;
+ ELSIF b THEN
+ is_admin := TRUE;
+ is_mod := TRUE;
+ can_view := TRUE;
+ can_post := TRUE;
+ can_create := TRUE;
+ can_poll := TRUE;
+ RETURN;
+ END IF;
+
+ -- Get the access level for this forum/rank combination
+ SELECT INTO b is_mod FROM al_rank_forum WHERE rank = rid AND forum = fid;
+ IF NOT FOUND THEN
+ RETURN;
+ ELSIF b THEN
+ is_mod := TRUE;
+ can_view := TRUE;
+ can_post := TRUE;
+ can_create := TRUE;
+ can_poll := TRUE;
+ END IF;
+
+ -- We can view; can we post?
+ can_view := TRUE;
+ IF arec.access_mode = 'M' THEN
+ RETURN;
+ END IF;
+
+ -- We can post; can we create topics?
+ can_post := TRUE;
+ IF arec.access_mode = 'P' THEN
+ RETURN;
+ END IF;
+
+ -- We can create topics; can we create polls?
+ can_create := TRUE;
+ can_poll := (arec.access_mode = 'L');
+END;
+$$ LANGUAGE plpgsql;
diff -Naur beta5//sql/forums/00-schema.sql forums//sql/forums/00-schema.sql
--- beta5//sql/forums/00-schema.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/forums/00-schema.sql 2011-02-05 10:10:01.764335002 +0100
@@ -0,0 +1,18 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- forums/00-schema.sql
+--
+-- Initialises the schema for the forums
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+-- Connect to the database
+\c legacyworlds legacyworlds_admin
+
+-- Create the forums schema
+CREATE SCHEMA forums;
+GRANT USAGE ON SCHEMA forums TO legacyworlds;
+
diff -Naur beta5//sql/forums/01-forums.sql forums//sql/forums/01-forums.sql
--- beta5//sql/forums/01-forums.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/forums/01-forums.sql 2011-02-05 10:10:01.764335002 +0100
@@ -0,0 +1,77 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- forums/01-forums.sql
+--
+-- Categories, forums, topics and posts
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+
+--
+-- Create the table of forum category types
+--
+CREATE TABLE forums.category_type (
+ id SERIAL PRIMARY KEY,
+ lib_path VARCHAR(24) NOT NULL UNIQUE
+);
+
+GRANT SELECT ON forums.category_type TO legacyworlds;
+SELECT register_serial_table('forums', 'category_type');
+
+
+
+--
+-- Create the table of translations for category types
+--
+CREATE TABLE forums.cat_type_text (
+ id INT NOT NULL REFERENCES forums.category_type (id) ON DELETE CASCADE,
+ lang VARCHAR(4) NOT NULL REFERENCES main.lang (txt) ON DELETE CASCADE,
+ name VARCHAR(32) NOT NULL,
+ PRIMARY KEY( id, lang )
+);
+
+CREATE INDEX i_forums_cat_type_lang ON forums.cat_type_text (lang);
+
+GRANT SELECT ON forums.cat_type_text TO legacyworlds;
+
+
+--
+-- Create the category table to store forum groups
+--
+CREATE TABLE forums.category (
+ id BIGSERIAL PRIMARY KEY,
+ acl_lib INT NOT NULL REFERENCES forums.category_type (id) ON DELETE CASCADE
+);
+
+CREATE INDEX i_forums_category_acl_lib ON forums.category (acl_lib);
+
+GRANT SELECT,INSERT,DELETE ON forums.category TO legacyworlds;
+GRANT SELECT,UPDATE ON forums.category_id_seq TO legacyworlds;
+
+SELECT register_serial_table('forums', 'category');
+
+
+--
+-- Create the forums table
+--
+CREATE TABLE forums.t_forum (
+ id BIGSERIAL PRIMARY KEY,
+ category BIGINT NOT NULL REFERENCES forums.category (id) ON DELETE CASCADE,
+ f_order INT NOT NULL CHECK( f_order >= 0 ),
+ title VARCHAR(64) NOT NULL,
+ description TEXT,
+ deleted INT NULL,
+ deleted_by BIGINT NULL REFERENCES main.account (id) ON DELETE SET NULL,
+ UNIQUE( category, f_order ),
+ UNIQUE( category, title )
+);
+
+CREATE INDEX i_forum_deleted_by ON forums.t_forum (deleted_by);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON forums.t_forum TO legacyworlds;
+GRANT SELECT,UPDATE ON forums.t_forum_id_seq TO legacyworlds;
+
+SELECT register_serial_table('forums', 't_forum');
diff -Naur beta5//sql/forums/01-signatures.sql forums//sql/forums/01-signatures.sql
--- beta5//sql/forums/01-signatures.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/forums/01-signatures.sql 2011-02-05 10:10:01.764335002 +0100
@@ -0,0 +1,31 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- forums/01-signatures.sql
+--
+-- Signature storage table
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+--
+-- Create the signature storage table
+--
+CREATE TABLE forums.signature (
+ id BIGSERIAL PRIMARY KEY,
+ account BIGINT NOT NULL REFERENCES main.account(id) ON DELETE CASCADE,
+ sig_set INT NOT NULL DEFAULT UNIX_TIMESTAMP(NOW()),
+ sig_unset INT,
+ signature TEXT NOT NULL,
+ enable_code BOOLEAN NOT NULL,
+ enable_smileys BOOLEAN NOT NULL,
+ CHECK( sig_unset IS NULL OR sig_set < sig_unset )
+);
+
+CREATE UNIQUE INDEX i_forums_signature ON forums.signature (account, sig_set);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON forums.signature TO legacyworlds;
+GRANT SELECT,UPDATE ON forums.signature_id_seq TO legacyworlds;
+
+SELECT register_serial_table('forums', 'signature');
diff -Naur beta5//sql/forums/02-topics.sql forums//sql/forums/02-topics.sql
--- beta5//sql/forums/02-topics.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/forums/02-topics.sql 2011-02-05 10:10:01.764335002 +0100
@@ -0,0 +1,92 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- forums/02-topics.sql
+--
+-- Topics, posts and post texts
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+--
+-- Create the topics table
+--
+CREATE TABLE forums.t_topic (
+ id BIGSERIAL PRIMARY KEY,
+ forum BIGINT NOT NULL REFERENCES forums.t_forum (id) ON DELETE CASCADE,
+ sticky_level INT2 NOT NULL DEFAULT 0 CHECK( sticky_level >= 0 AND sticky_level <= 10 ),
+ moved_from BIGINT NULL REFERENCES forums.t_forum (id) ON DELETE SET NULL,
+ deleted INT NULL,
+ deleted_by BIGINT NULL REFERENCES main.account (id) ON DELETE CASCADE,
+ locked BOOLEAN NOT NULL DEFAULT FALSE
+);
+
+CREATE INDEX i_topic_forum ON forums.t_topic (forum);
+CREATE INDEX i_topic_moved_from ON forums.t_topic (moved_from);
+CREATE INDEX i_topic_deleted_by ON forums.t_topic (deleted_by);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON forums.t_topic TO legacyworlds;
+GRANT SELECT,UPDATE ON forums.t_topic_id_seq TO legacyworlds;
+
+SELECT register_serial_table('forums', 't_topic');
+
+
+--
+-- Create the post table
+--
+
+CREATE TABLE forums.t_post (
+ id BIGSERIAL PRIMARY KEY,
+ topic BIGINT NOT NULL REFERENCES forums.t_topic (id) ON DELETE CASCADE,
+ depth INT NOT NULL DEFAULT 0,
+ reply_to BIGINT REFERENCES forums.t_post (id),
+ signature BIGINT REFERENCES forums.signature (id) ON DELETE SET NULL,
+ deleted INT,
+ deleted_by BIGINT REFERENCES main.account (id) ON DELETE CASCADE
+);
+
+CREATE INDEX i_post_topic ON forums.t_post (topic);
+CREATE INDEX i_post_reply_to ON forums.t_post (reply_to);
+CREATE INDEX i_post_signature ON forums.t_post (signature);
+CREATE INDEX i_deleted_by ON forums.t_post (deleted_by);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON forums.t_post TO legacyworlds;
+GRANT SELECT,UPDATE ON forums.t_post_id_seq TO legacyworlds;
+
+SELECT register_serial_table('forums', 't_post');
+
+
+--
+-- Create the table to store post texts
+--
+
+CREATE TABLE forums.post_text (
+ post BIGINT NOT NULL REFERENCES forums.t_post (id) ON DELETE CASCADE,
+ moment INT NOT NULL DEFAULT UNIX_TIMESTAMP(NOW()),
+ author BIGINT NOT NULL REFERENCES main.account (id) ON DELETE CASCADE,
+ title VARCHAR(100) NOT NULL,
+ contents TEXT NOT NULL,
+ enable_code BOOLEAN NOT NULL,
+ enable_smileys BOOLEAN NOT NULL,
+ PRIMARY KEY( post, moment )
+);
+
+CREATE INDEX i_post_text_author ON forums.post_text (author);
+
+GRANT SELECT,INSERT,DELETE ON forums.post_text TO legacyworlds;
+
+
+--
+-- Create a table that stores the last time an user read some topic
+--
+CREATE TABLE forums.topic_read (
+ topic BIGINT NOT NULL REFERENCES forums.t_topic (id) ON DELETE CASCADE,
+ read_by BIGINT NOT NULL REFERENCES main.account (id) ON DELETE CASCADE,
+ read_at INT NOT NULL DEFAULT UNIX_TIMESTAMP(NOW()),
+ PRIMARY KEY( topic, read_by )
+);
+
+CREATE INDEX i_topic_read_by ON forums.topic_read (read_by);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON forums.topic_read TO legacyworlds;
diff -Naur beta5//sql/forums/03-polls.sql forums//sql/forums/03-polls.sql
--- beta5//sql/forums/03-polls.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/forums/03-polls.sql 2011-02-05 10:10:01.764335002 +0100
@@ -0,0 +1,55 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- forums/03-polls.sql
+--
+-- Forum polls, poll options and votes
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+--
+-- Create the polls table
+--
+CREATE TABLE forums.poll (
+ topic BIGINT PRIMARY KEY REFERENCES forums.t_topic (id) ON DELETE CASCADE,
+ title VARCHAR(64) NOT NULL,
+ closed BOOLEAN NOT NULL DEFAULT FALSE,
+ deleted INT NULL,
+ deleted_by BIGINT NULL REFERENCES main.account(id) ON DELETE SET NULL
+);
+
+CREATE INDEX i_poll_deleted_by ON forums.poll (deleted_by);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON forums.poll TO legacyworlds;
+
+
+--
+-- Table for a poll's options
+--
+CREATE TABLE forums.poll_option (
+ id BIGSERIAL PRIMARY KEY,
+ poll BIGINT NOT NULL REFERENCES forums.t_topic (id) ON DELETE CASCADE,
+ po_order INT NOT NULL CHECK( po_order >= 0 ),
+ title VARCHAR(64) NOT NULL,
+ UNIQUE( poll, po_order ),
+ UNIQUE( poll, title )
+);
+
+GRANT SELECT,INSERT,UPDATE,DELETE ON forums.poll_option TO legacyworlds;
+GRANT SELECT,UPDATE ON forums.poll_option_id_seq TO legacyworlds;
+
+SELECT register_serial_table('forums', 'poll_option');
+
+
+--
+-- Table for a poll's votes
+--
+CREATE TABLE forums.poll_vote (
+ vote BIGINT NOT NULL REFERENCES forums.poll_option (id) ON DELETE CASCADE,
+ account BIGINT NOT NULL REFERENCES main.account (id) ON DELETE CASCADE,
+ PRIMARY KEY( vote, account )
+);
+
+GRANT SELECT,INSERT,DELETE ON forums.poll_vote TO legacyworlds;
diff -Naur beta5//sql/forums/10-views.sql forums//sql/forums/10-views.sql
--- beta5//sql/forums/10-views.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/forums/10-views.sql 2011-02-05 10:10:01.764335002 +0100
@@ -0,0 +1,73 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- forums/10-views.sql
+--
+-- Defines a few views corresponding to some common
+-- queries
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+--
+-- View for individual posts
+--
+
+CREATE VIEW forums.post
+ AS SELECT p.id AS id, t.forum AS forum, p.topic AS topic, t1.author AS author,
+ p.reply_to AS reply_to, p.signature AS signature, p.deleted AS deleted,
+ p.deleted_by AS deleted_by, p.depth AS depth, t1.moment AS post_moment,
+ t2.moment AS last_change, t2.author AS last_author,
+ t2.contents AS contents, t2.title AS title,
+ t2.enable_code AS enable_code, t2.enable_smileys AS enable_smileys
+ FROM forums.t_post p, forums.t_topic t, forums.post_text t1, forums.post_text t2
+ WHERE t1.post = p.id AND t1.moment = (SELECT MIN(moment) FROM forums.post_text WHERE post = p.id)
+ AND t2.post = p.id AND t2.moment = (SELECT MAX(moment) FROM forums.post_text WHERE post = p.id)
+ AND t.id = p.topic;
+
+GRANT SELECT ON forums.post TO legacyworlds;
+
+
+--
+-- View for forum topics
+--
+
+CREATE VIEW forums.topic_fp_lp
+ AS SELECT t.id, t.forum, MIN(p.post_moment) AS fp_moment,
+ MAX(p.last_change) AS lc_moment, COUNT(p.*) AS posts
+ FROM forums.t_topic t
+ LEFT JOIN forums.post p ON (p.topic = t.id AND (
+ (t.deleted IS NULL AND p.deleted IS NULL)
+ OR (t.deleted IS NOT NULL AND p.deleted = t.deleted) ))
+ GROUP BY t.id, t.forum, t.deleted;
+
+
+CREATE VIEW forums.topic
+ AS SELECT t.*, tt.posts AS posts,
+ fp.title, fp.id AS first_post, fp.author AS fp_author, fp.post_moment AS fp_moment,
+ lp.author AS lc_author, lp.last_change AS lc_moment
+ FROM forums.t_topic t
+ LEFT JOIN forums.topic_fp_lp tt ON (t.id = tt.id)
+ LEFT JOIN forums.post fp ON (fp.topic = t.id AND fp.post_moment = tt.fp_moment)
+ LEFT JOIN forums.post lp ON (lp.topic = t.id AND lp.last_change = tt.lc_moment)
+ ORDER BY sticky_level DESC, lc_moment DESC;
+
+GRANT SELECT ON forums.topic TO legacyworlds;
+
+
+--
+-- View for forums
+--
+
+CREATE VIEW forums.forum
+ AS SELECT f.id AS id, f.category AS category, f.f_order AS f_order,
+ f.title AS title, f.description AS description,
+ f.deleted AS deleted, f.deleted_by AS deleted_by,
+ (SELECT COUNT(*) FROM forums.t_topic WHERE forum = f.id AND deleted IS NULL) AS topics,
+ (SELECT COUNT(*) FROM forums.post WHERE forum = f.id AND deleted IS NULL) AS posts
+ FROM forums.t_forum f
+ ORDER BY category, f_order;
+
+GRANT SELECT ON forums.forum TO legacyworlds;
+
diff -Naur beta5//sql/forums/11-access-functions.sql forums//sql/forums/11-access-functions.sql
--- beta5//sql/forums/11-access-functions.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/forums/11-access-functions.sql 2011-02-05 10:10:01.764335002 +0100
@@ -0,0 +1,869 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- forums/11-access-functions.sql
+--
+-- Functions to access the forums and topics
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+-- --------------------------------------------------------
+-- LIST OF ALL REQUIRED FUNCTIONS
+-- --------------------------------------------------------
+--
+-- Functions listed with a '*' have been implemented.
+-- Functions listed with a '!' need modifications.
+--
+--
+-- GENERAL CLEAN-UP
+--
+-- forum_cleanup() *
+-- Causes a general clean-up by deleting old stuff
+-- that had been marked for deletion earlier.
+--
+--
+-- SIGNATURE MANAGEMENT
+--
+-- set_signature( account, set_all, new_signature, enable_code, enable_smileys ) *
+-- Sets a new signature for the account
+--
+-- get_signature( account, timestamp ) *
+-- Returns the complete data for the account's
+-- signature at the specified timestamp.
+--
+--
+-- CATEGORIES AND FORUMS MANAGEMENT
+--
+-- add_category_type( library_path , language , description ) *
+-- Creates a category type with the specified library as
+-- its handler if it doesn't exist, then add the description.
+--
+-- make_category( access_library ) *
+-- Creates a category and returns its ID
+--
+-- make_forum( category, f_order, title, description ) *
+-- Creates a forum and returns its ID
+--
+-- move_up( forum ) *
+-- Moves a forum up in the list of forums in a category
+--
+-- move_down( forum ) *
+-- Moves a forum down in the list of forums in a category
+--
+-- delete_forum( forum , administrator ) *
+-- Delete a forum and its contents
+--
+-- restore_forum( forum ) *
+-- Restores a deleted forum to its previous state
+--
+-- delete_forums( category, administrator )
+-- Deletes all forums in a category
+--
+-- restore_forums( category )
+-- Restore all forums in a category
+--
+-- get_last_post( forum ) *
+-- Returns the data from the last post in the specified forum
+--
+-- get_read_topics( forum , user ) *
+-- Returns the amount of topics an user has read since they
+-- were last updated
+--
+-- mark_forum_read( forum, read_by ) *
+-- Marks all of a forum's topics as read by some user
+--
+--
+-- TOPICS AND POSTS MANAGEMENT
+--
+-- mark_topic_read( topic, read_by ) *
+-- Marks a topic as read by some user
+--
+-- create_topic( forum, author, sticky_level, title, contents, enable_code, enable_smileys, sig ) *
+-- Creates a new topic in a forum and returns its
+-- ID
+--
+-- move_topic( topic, forum, user ) *
+-- Moves a topic from a forum to another
+--
+-- add_reply( reply_to, author, title, contents, enable_code, enable_smileys, signature ) *
+-- Posts a reply to a post
+--
+-- edit_post( post, author, contents, enable_code, enable_smileys, change_signature, signature ) *
+-- Modifies a post
+--
+-- delete_post( post, moderator ) *
+-- Marks a post as deleted; delete the topic if the
+-- post is the topic's "main" post
+--
+-- restore_post( post ) *
+-- Restores a deleted post or, if that post was the
+-- first of a topic, restore the whole topic
+--
+--
+-- FORUM POLLS
+--
+-- create_poll( topic, title ) *
+-- Adds a new poll to the database and returns the
+-- new row
+--
+-- create_option( poll, order, title ) *
+-- Adds a poll option at the specified order and
+-- returns the new row
+--
+-- delete_option( poll, order ) *
+-- Removes a poll option
+--
+-- move_opt_up( poll, order ) *
+-- Moves a poll option up in the list and returns a
+-- boolean to indicate success or failure
+--
+-- move_opt_down( poll, order ) *
+-- Moves a poll option down in the list and returns a
+-- boolean to indicate success or failure
+--
+-- set_vote( user, poll, option) *
+-- Sets the vote on a forum poll
+--
+
+
+
+
+-- --------------------------------------------------------
+-- GENERAL CLEAN-UP
+-- --------------------------------------------------------
+
+--
+-- forum_cleanup()
+--
+-- Causes a general clean-up by deleting old stuff that had been marked for deletion earlier.
+
+CREATE OR REPLACE FUNCTION forums.forum_cleanup() RETURNS VOID AS $$
+DECLARE
+ crec RECORD;
+ frec RECORD;
+ fod INT;
+ nts INT;
+BEGIN
+ -- Start by locking the tables
+ LOCK TABLE forums.category, forums.t_forum, forums.t_topic, forums.t_post IN ACCESS EXCLUSIVE MODE;
+
+ -- Now get the categories containing forums to be deleted
+ nts := UNIX_TIMESTAMP( NOW() ) - 28 * 24 * 3600;
+ FOR crec IN SELECT DISTINCT category FROM forums.t_forum
+ WHERE deleted IS NOT NULL AND deleted <= nts
+ LOOP
+ -- For each category, go through the list of forums
+ fod := 0;
+ FOR frec IN SELECT id,deleted FROM forums.t_forum WHERE category = crec.category
+ LOOP
+ -- This forum is to be deleted; remove it
+ IF (frec.deleted IS NOT NULL AND frec.deleted <= nts) THEN
+ DELETE FROM forums.t_forum WHERE id = frec.id;
+ fod := fod + 1;
+
+ -- This forum is not to be deleted, however its order must be fixed
+ ELSIF (fod > 1) THEN
+ UPDATE forums.t_forum SET f_order = f_order - fod WHERE id = frec.id;
+ END IF;
+ END LOOP;
+ END LOOP;
+
+ -- Delete topics and posts that were not part of forums to be deleted
+ DELETE FROM forums.t_topic WHERE deleted IS NOT NULL AND deleted <= nts;
+ DELETE FROM forums.t_post WHERE deleted IS NOT NULL AND deleted <= nts;
+END;
+$$ LANGUAGE plpgsql;
+
+
+
+
+-- --------------------------------------------------------
+-- SIGNATURE MANAGEMENT
+-- --------------------------------------------------------
+
+--
+-- forums.set_signature( account, set_all, new_signature, enable_code, enable_smileys )
+--
+-- Sets a new signature for the account
+
+CREATE OR REPLACE FUNCTION forums.set_signature ( a BIGINT, s BOOLEAN, t TEXT, ec BOOLEAN, es BOOLEAN ) RETURNS VOID AS $$
+DECLARE
+ sid BIGINT;
+BEGIN
+ -- Mark the previous signature as "ended"
+ UPDATE forums.signature
+ SET sig_unset = UNIX_TIMESTAMP(NOW()) - 1
+ WHERE account = a AND sig_unset IS NULL;
+
+ -- If there *is* a new signature, insert it
+ IF NOT(t IS NULL OR t = '') THEN
+ INSERT INTO forums.signature (account, signature, enable_code, enable_smileys)
+ VALUES ( a, t, ec, es );
+ sid := last_inserted('signature');
+ ELSE
+ sid := NULL;
+ END IF;
+
+ -- Change all of the posts' signatures to the new one and delete
+ -- the old signatures if needed.
+ IF s THEN
+ UPDATE forums.t_post
+ SET signature = sid
+ WHERE author = a;
+ IF sid IS NOT NULL THEN
+ DELETE FROM forums.signature
+ WHERE account = a AND id <> sid;
+ ELSE
+ DELETE FROM forums.signature
+ WHERE account = a;
+ END IF;
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.get_signature( account, timestamp )
+--
+-- Returns the complete data for the account's signature at the specified timestamp.
+
+CREATE OR REPLACE FUNCTION forums.get_signature ( a BIGINT, ts INT ) RETURNS forums.signature AS $$
+ SELECT * FROM forums.signature
+ WHERE account = $1 AND sig_set <= $2
+ AND (sig_unset IS NULL OR sig_unset >= $2);
+$$ LANGUAGE SQL;
+
+
+
+
+-- --------------------------------------------------------
+-- FORUMS AND CATEGORIES MANAGEMENT
+-- --------------------------------------------------------
+
+--
+-- forums.add_category_type( library_path , language , description )
+--
+-- Creates a category type with the specified library as its handler if it doesn't exist, then add the description.
+
+CREATE OR REPLACE FUNCTION forums.add_category_type ( lp TEXT, lg TEXT, dsc TEXT ) RETURNS VOID AS $$
+DECLARE
+ ct INT;
+BEGIN
+ SELECT INTO ct id FROM forums.category_type WHERE lib_path = lp;
+ IF NOT FOUND THEN
+ INSERT INTO forums.category_type (lib_path) VALUES (lp);
+ ct := last_inserted( 'category_type' );
+ END IF;
+
+ INSERT INTO forums.cat_type_text (id, lang, name) VALUES (ct, lg, dsc);
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.make_category( access_library )
+--
+-- Creates a category and returns its ID
+
+CREATE OR REPLACE FUNCTION forums.make_category ( al TEXT ) RETURNS BIGINT AS $$
+DECLARE
+ ct INT;
+BEGIN
+ SELECT INTO ct id FROM forums.category_type WHERE lib_path = al;
+ IF NOT FOUND THEN
+ RETURN NULL;
+ END IF;
+
+ INSERT INTO forums.category (acl_lib) VALUES ( ct );
+ RETURN last_inserted( 'category' );
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.make_forum( category, f_order, title, description )
+--
+-- Creates a forum and returns its ID
+
+CREATE OR REPLACE FUNCTION forums.make_forum( cid BIGINT, fo INT, tt TEXT, dsc TEXT )
+ RETURNS BIGINT AS $$
+DECLARE
+ rec RECORD;
+ fid BIGINT;
+ rfo INT;
+BEGIN
+ IF fo IS NULL THEN
+ SELECT INTO rfo MAX(f_order) + 1 FROM forums.t_forum WHERE category = cid;
+ ELSE
+ rfo := fo;
+ FOR rec IN SELECT id FROM forums.t_forum
+ WHERE category = cid AND f_order >= rfo
+ ORDER BY f_order DESC
+ FOR UPDATE
+ LOOP
+ UPDATE forums.t_forum SET f_order = f_order + 1 WHERE id = rec.id;
+ END LOOP;
+ END IF;
+
+ INSERT INTO forums.t_forum (category, f_order, title, description)
+ VALUES (cid, rfo, tt, dsc);
+ fid := last_inserted( 't_forum' );
+ RETURN fid;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.move_up( forum )
+--
+-- Moves a forum up in the list of forums in a category
+
+CREATE OR REPLACE FUNCTION forums.move_up ( fid BIGINT ) RETURNS BOOLEAN AS $$
+DECLARE
+ cid BIGINT;
+ fo INT;
+ mfo INT;
+BEGIN
+ SELECT INTO fo COUNT(*) FROM forums.t_forum WHERE id = fid;
+ IF fo = 0 THEN
+ RETURN FALSE;
+ END IF;
+ SELECT INTO cid category FROM forums.t_forum WHERE id = fid;
+
+ PERFORM * FROM forums.t_forum WHERE category = cid FOR UPDATE;
+ SELECT INTO fo f_order FROM forums.t_forum WHERE id = fid;
+ IF fo = 0 THEN
+ RETURN FALSE;
+ END IF;
+
+ SELECT INTO mfo MAX(f_order) + 1 FROM forums.t_forum
+ WHERE category = (SELECT category FROM forums.t_forum WHERE id = fid);
+
+ UPDATE forums.t_forum SET f_order = mfo WHERE id = fid;
+ UPDATE forums.t_forum SET f_order = fo WHERE category = cid AND f_order = fo - 1;
+ UPDATE forums.t_forum SET f_order = fo - 1 WHERE id = fid;
+
+ RETURN TRUE;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.move_down( forum )
+--
+-- Moves a forum down in the list of forums in a category
+
+CREATE OR REPLACE FUNCTION forums.move_down ( fid BIGINT ) RETURNS BOOLEAN AS $$
+DECLARE
+ cid BIGINT;
+ fo INT;
+ mfo INT;
+BEGIN
+ SELECT INTO fo COUNT(*) FROM forums.t_forum WHERE id = fid;
+ IF fo = 0 THEN
+ RETURN FALSE;
+ END IF;
+ SELECT INTO cid category FROM forums.t_forum WHERE id = fid;
+
+ PERFORM * FROM forums.t_forum WHERE category = cid FOR UPDATE;
+ SELECT INTO fo f_order FROM forums.t_forum WHERE id = fid;
+ SELECT INTO mfo MAX(f_order) FROM forums.t_forum
+ WHERE category = (SELECT category FROM forums.t_forum WHERE id = fid);
+ IF fo = mfo THEN
+ RETURN FALSE;
+ END IF;
+
+ UPDATE forums.t_forum SET f_order = mfo + 1 WHERE id = fid;
+ UPDATE forums.t_forum SET f_order = fo WHERE category = cid AND f_order = fo + 1;
+ UPDATE forums.t_forum SET f_order = fo + 1 WHERE id = fid;
+
+ RETURN TRUE;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.delete_forum( forum , administrator )
+--
+-- Delete a forum and its contents
+
+CREATE OR REPLACE FUNCTION forums.delete_forum( fid BIGINT, aid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ cts INT;
+BEGIN
+ -- Check if the forum exists and hasn't been deleted
+ PERFORM * FROM forums.t_forum WHERE id = fid AND deleted IS NULL;
+ IF NOT FOUND THEN
+ RETURN;
+ END IF;
+
+ -- Marks the forum and its contents as deleted
+ cts := UNIX_TIMESTAMP( NOW () );
+ UPDATE forums.t_forum SET deleted = cts, deleted_by = aid WHERE id = fid;
+ -- FIXME Argh! f_order! headache!
+ UPDATE forums.t_post SET deleted = cts, deleted_by = aid
+ WHERE topic IN (SELECT id FROM forums.t_topic WHERE forum = fid AND deleted IS NULL)
+ AND deleted IS NULL;
+ UPDATE forums.t_topic SET deleted = cts, deleted_by = aid
+ WHERE forum = fid AND deleted IS NULL;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.restore_forum( forum )
+--
+-- Restores a deleted forum to its previous state
+
+CREATE OR REPLACE FUNCTION forums.restore_forum( fid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ ts INT;
+BEGIN
+ SELECT INTO ts deleted FROM forums.t_forum
+ WHERE id = fid AND deleted IS NOT NULL;
+ IF NOT FOUND THEN
+ RETURN;
+ END IF;
+
+ -- Marks the forum and its contents as deleted
+ UPDATE forums.t_forum SET deleted = NULL, deleted_by = NULL WHERE id = fid;
+ -- FIXME Argh! f_order! headache!
+ UPDATE forums.t_post SET deleted = NULL, deleted_by = NULL
+ WHERE topic IN (SELECT id FROM forums.t_topic WHERE forum = fid AND deleted = ts)
+ AND deleted = ts;
+ UPDATE forums.t_topic SET deleted = NULL, deleted_by = NULL
+ WHERE forum = fid AND deleted = ts;
+END;
+$$ LANGUAGE plpgsql;
+
+--
+-- forums.delete_forums( category, administrator )
+--
+-- Deletes all forums in a category
+
+CREATE OR REPLACE FUNCTION forums.delete_forums( cid BIGINT, aid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ f RECORD;
+BEGIN
+ FOR f IN SELECT id FROM forums.t_forum WHERE category = cid AND deleted IS NULL
+ LOOP
+ PERFORM forums.delete_forum( f.id, aid );
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.restore_forums( category )
+--
+-- Restore all forums in a category
+
+CREATE OR REPLACE FUNCTION forums.restore_forums( cid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ f RECORD;
+BEGIN
+ FOR f IN SELECT id FROM forums.t_forum WHERE category = cid AND deleted IS NOT NULL
+ LOOP
+ PERFORM forums.restore_forum( f.id );
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.get_last_post( forum )
+--
+-- Returns the data from the last post in the specified forum
+
+CREATE OR REPLACE FUNCTION forums.get_last_post( fid BIGINT ) RETURNS forums.post AS $$
+ SELECT * FROM forums.post
+ WHERE forum = $1 AND deleted IS NULL
+ AND last_change = (SELECT MAX(last_change) FROM forums.post WHERE forum = $1 AND deleted IS NULL);
+$$ LANGUAGE SQL;
+
+
+--
+-- forums.get_read_topics( forum , user )
+--
+-- Returns the amount of topics an user has read since they were last updated
+
+CREATE OR REPLACE FUNCTION forums.get_read_topics( fid BIGINT, aid BIGINT ) RETURNS BIGINT AS $$
+ SELECT COUNT(DISTINCT p.topic)
+ FROM forums.post p
+ LEFT JOIN forums.topic_read r ON (p.topic = r.topic AND p.last_change <= r.read_at)
+ WHERE p.forum = $1 AND r.read_by = $2 AND p.deleted IS NULL;
+$$ LANGUAGE SQL;
+
+
+--
+-- forums.mark_forum_read( forum, read_by )
+--
+-- Marks all of a forum's topics as read by some user
+
+CREATE OR REPLACE FUNCTION forums.mark_forum_read( fid BIGINT, aid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ rec RECORD;
+BEGIN
+ FOR rec IN SELECT id FROM forums.t_topic WHERE deleted IS NULL AND forum = fid FOR UPDATE
+ LOOP
+ PERFORM forums.mark_topic_read( rec.id, aid );
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+
+
+-- --------------------------------------------------------
+-- TOPICS AND POSTS MANAGEMENT
+-- --------------------------------------------------------
+
+--
+-- forums.mark_topic_read( topic, read_by )
+--
+-- Marks a topic as read by some user
+
+CREATE OR REPLACE FUNCTION forums.mark_topic_read ( tid BIGINT, rid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ rr RECORD;
+BEGIN
+ SELECT INTO rr * FROM forums.topic_read WHERE topic = tid AND read_by = rid FOR UPDATE;
+ IF NOT FOUND THEN
+ INSERT INTO forums.topic_read (topic, read_by) VALUES (tid, rid);
+ ELSE
+ UPDATE forums.topic_read SET read_at = UNIX_TIMESTAMP(NOW())
+ WHERE topic = tid AND read_by = rid;
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
+
+
+
+--
+-- forums.create_topic( forum, author, sticky_level, title, contents, enable_code, enable_smileys, sig )
+--
+-- Creates a new topic in a forum and returns its ID
+
+CREATE OR REPLACE FUNCTION forums.create_topic(
+ fid BIGINT, aid BIGINT, sl INT,
+ ttl TEXT, c TEXT, ec BOOLEAN,
+ es BOOLEAN, sig BIGINT )
+ RETURNS BIGINT AS $$
+DECLARE
+ tid BIGINT;
+ pid BIGINT;
+BEGIN
+ INSERT INTO forums.t_topic (forum, sticky_level) VALUES (fid, sl);
+ SELECT INTO tid last_inserted('t_topic');
+
+ INSERT INTO forums.t_post (topic, signature) VALUES (tid, sig);
+ SELECT INTO pid last_inserted('t_post');
+
+ INSERT INTO forums.post_text (post, author, title, contents, enable_code, enable_smileys)
+ VALUES (pid, aid, ttl, c, ec, es);
+ INSERT INTO forums.topic_read (topic, read_by) VALUES (tid, aid);
+
+ RETURN tid;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.move_topic( topic, forum, user ) *
+--
+-- Moves a topic from a forum to another
+
+CREATE OR REPLACE FUNCTION forums.move_topic( tid BIGINT, did BIGINT, aid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ cfid BIGINT;
+BEGIN
+ SELECT INTO cfid forum FROM forums.t_topic WHERE id = tid;
+ IF NOT FOUND THEN
+ RETURN;
+ END IF;
+
+ UPDATE forums.t_topic SET moved_from = cfid, forum = did WHERE id = tid;
+ DELETE FROM forums.topic_read WHERE topic = tid;
+ PERFORM forums.mark_topic_read( tid, aid );
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.add_reply( reply_to, author, title, contents, enable_code, enable_smileys, signature )
+--
+-- Posts a reply to a post
+
+CREATE OR REPLACE FUNCTION forums.add_reply (
+ rid BIGINT, aid BIGINT, ttl TEXT,
+ c TEXT, ec BOOLEAN, es BOOLEAN,
+ sig BIGINT )
+ RETURNS BIGINT AS $$
+DECLARE
+ rr RECORD;
+ pid BIGINT;
+BEGIN
+ SELECT INTO rr * FROM forums.t_post WHERE id = rid AND deleted IS NULL;
+ IF NOT FOUND THEN
+ RETURN -1;
+ END IF;
+
+ INSERT INTO forums.t_post (topic, reply_to, signature, depth)
+ VALUES (rr.topic, rid, sig, rr.depth + 1);
+ SELECT INTO pid last_inserted('t_post');
+
+ INSERT INTO forums.post_text (post, author, title, contents, enable_code, enable_smileys)
+ VALUES (pid, aid, ttl, c, ec, es);
+
+ PERFORM forums.mark_topic_read( rr.topic, aid );
+
+ RETURN pid;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.edit_post( post, author, contents, enable_code, enable_smileys, change_signature, signature )
+--
+-- Modifies a post
+
+CREATE OR REPLACE FUNCTION forums.edit_post (
+ pid BIGINT, aid BIGINT, ttl TEXT,
+ c TEXT, ec BOOLEAN, es BOOLEAN,
+ chsig BOOLEAN, sig BIGINT )
+ RETURNS VOID AS $$
+DECLARE
+ tid BIGINT;
+BEGIN
+ PERFORM * FROM forums.t_post WHERE id = pid AND deleted IS NULL;
+ IF NOT FOUND THEN
+ RETURN;
+ END IF;
+
+ INSERT INTO forums.post_text (post, author, title, contents, enable_code, enable_smileys)
+ VALUES (pid, aid, ttl, c, ec, es);
+ IF chsig THEN
+ UPDATE forums.t_post SET signature = sig WHERE id = pid;
+ END IF;
+
+ SELECT INTO tid topic FROM forums.t_post WHERE id = pid;
+ PERFORM forums.mark_topic_read( tid, aid );
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.delete_post( post, moderator )
+--
+-- Marks a post as deleted; delete the topic if the post is the topic's "main" post
+
+CREATE OR REPLACE FUNCTION forums.delete_post ( pid BIGINT, mid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ ppid BIGINT;
+ cts INT;
+BEGIN
+ SELECT INTO ppid reply_to FROM forums.t_post WHERE id = pid AND deleted IS NULL;
+ IF NOT FOUND THEN
+ RETURN;
+ END IF;
+
+ cts := UNIX_TIMESTAMP(NOW());
+ IF ppid IS NULL THEN
+ -- Delete the topic
+ SELECT INTO ppid topic FROM forums.t_post WHERE id = pid;
+ UPDATE forums.t_topic SET deleted = cts, deleted_by = mid WHERE id = ppid;
+ UPDATE forums.poll SET deleted = cts, deleted_by = mid WHERE topic = ppid;
+ UPDATE forums.t_post SET deleted = cts, deleted_by = mid
+ WHERE topic = ppid AND deleted IS NULL;
+ ELSE
+ -- Delete the post and reparent replies;
+ UPDATE forums.t_post SET deleted = cts, deleted_by = mid WHERE id = pid;
+ UPDATE forums.t_post SET reply_to = ppid, depth = depth - 1 WHERE reply_to = pid;
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.restore_post( post )
+--
+-- Restores a deleted post or, if that post was the first of a topic, restore the whole topic
+
+CREATE OR REPLACE FUNCTION forums.restore_post ( pid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ r RECORD;
+BEGIN
+ SELECT INTO r reply_to, deleted, topic FROM forums.t_post
+ WHERE id = pid AND deleted IS NOT NULL;
+ IF NOT FOUND THEN
+ RETURN;
+ END IF;
+
+ IF r.reply_to IS NULL THEN
+ -- Restore the topic
+ UPDATE forums.t_post SET deleted = NULL, deleted_by = NULL
+ WHERE topic = r.topic AND deleted = r.deleted;
+ UPDATE forums.t_topic SET deleted = NULL, deleted_by = NULL
+ WHERE id = r.topic;
+ UPDATE forums.poll SET deleted = NULL, deleted_by = NULL
+ WHERE topic = r.topic AND deleted = r.deleted;
+ ELSE
+ -- Restore the post
+ UPDATE forums.t_post SET deleted = NULL, deleted_by = NULL
+ WHERE id = pid;
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
+
+
+
+
+-- --------------------------------------------------------
+-- FORUM POLLS
+-- --------------------------------------------------------
+
+--
+-- forums.create_poll( topic, title )
+--
+-- Adds a new poll to the database and returns the new row
+
+CREATE OR REPLACE FUNCTION forums.create_poll( t_id BIGINT, ttl TEXT ) RETURNS forums.poll AS $$
+DECLARE
+ rv forums.poll;
+BEGIN
+ INSERT INTO forums.poll (topic, title) VALUES (t_id, ttl);
+ SELECT INTO rv * FROM forums.poll WHERE topic = t_id;
+ RETURN rv;
+EXCEPTION WHEN unique_violation OR foreign_key_violation THEN
+ rv.topic := NULL;
+ rv.title := NULL;
+ RETURN rv;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.create_option( poll, order, title )
+--
+-- Adds a poll option at the specified order and returns the new row
+
+CREATE OR REPLACE FUNCTION forums.create_option( p_id BIGINT, oo INT, ttl TEXT ) RETURNS forums.poll_option AS $$
+DECLARE
+ rv forums.poll_option;
+ rec RECORD;
+ noid BIGINT;
+BEGIN
+ FOR rec IN SELECT * FROM forums.poll_option
+ WHERE poll = p_id AND po_order >= oo
+ ORDER BY po_order DESC
+ FOR UPDATE
+ LOOP
+ UPDATE forums.poll_option SET po_order = po_order + 1 WHERE id = rec.id;
+ END LOOP;
+
+ INSERT INTO forums.poll_option (poll, po_order, title) VALUES (p_id, oo, ttl);
+ SELECT INTO noid last_inserted('poll_option');
+
+ SELECT INTO rv * FROM forums.poll_option WHERE id = noid;
+ RETURN rv;
+
+EXCEPTION WHEN foreign_key_violation OR unique_violation THEN
+ rv.id := NULL;
+ rv.poll := NULL;
+ RETURN rv;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.delete_option( poll, order )
+--
+-- Removes a poll option
+
+CREATE OR REPLACE FUNCTION forums.delete_option( p_id BIGINT, oo INT ) RETURNS VOID AS $$
+DECLARE
+ rec RECORD;
+BEGIN
+ PERFORM * FROM forums.poll_option WHERE poll = p_id AND po_order > oo FOR UPDATE;
+ DELETE FROM forums.poll_option WHERE poll = p_id AND po_order = oo;
+ FOR rec IN SELECT id FROM forums.poll_option WHERE poll = p_id AND po_order > oo ORDER BY po_order ASC
+ LOOP
+ UPDATE forums.poll_option SET po_order = po_order - 1 WHERE id = rec.id;
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.move_opt_up( poll, order )
+--
+-- Moves a poll option up in the list and returns a boolean to indicate success or failure
+
+CREATE OR REPLACE FUNCTION forums.move_opt_up( p_id BIGINT, oo INT ) RETURNS BOOLEAN AS $$
+DECLARE
+ c BIGINT;
+BEGIN
+ IF oo = 0 THEN
+ RETURN FALSE;
+ END IF;
+
+ SELECT INTO c COUNT(*) FROM forums.poll_option WHERE poll = p_id;
+ IF NOT FOUND OR oo >= c THEN
+ RETURN FALSE;
+ END IF;
+
+ UPDATE forums.poll_option SET po_order = c WHERE poll = p_id AND po_order = oo - 1;
+ UPDATE forums.poll_option SET po_order = po_order - 1 WHERE poll = p_id AND po_order = oo;
+ UPDATE forums.poll_option SET po_order = oo WHERE poll = p_id AND po_order = c;
+ RETURN TRUE;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.move_opt_down( poll, order )
+--
+-- Moves a poll option down in the list and returns a boolean to indicate success or failure
+
+CREATE OR REPLACE FUNCTION forums.move_opt_down( p_id BIGINT, oo INT ) RETURNS BOOLEAN AS $$
+DECLARE
+ c BIGINT;
+BEGIN
+ SELECT INTO c COUNT(*) FROM forums.poll_option WHERE poll = p_id;
+ IF NOT FOUND OR oo >= c - 1 THEN
+ RETURN FALSE;
+ END IF;
+
+ UPDATE forums.poll_option SET po_order = c WHERE poll = p_id AND po_order = oo + 1;
+ UPDATE forums.poll_option SET po_order = po_order + 1 WHERE poll = p_id AND po_order = oo;
+ UPDATE forums.poll_option SET po_order = oo WHERE poll = p_id AND po_order = c;
+ RETURN TRUE;
+END;
+$$ LANGUAGE plpgsql;
+
+
+--
+-- forums.set_vote( user, poll, option )
+--
+-- Sets the vote on a forum poll
+
+CREATE OR REPLACE FUNCTION forums.set_vote( u_id BIGINT, p_id BIGINT, o_id BIGINT ) RETURNS VOID AS $$
+DECLARE
+ p BIGINT;
+BEGIN
+ -- Delete the previous vote
+ DELETE FROM forums.poll_vote
+ WHERE account = u_id
+ AND vote IN (SELECT id FROM forums.poll_option WHERE poll = p_id);
+
+ IF o_id IS NOT NULL THEN
+ -- Add the new vote if that is possible
+ SELECT INTO p poll FROM forums.poll_option WHERE id = o_id;
+ IF NOT FOUND OR p <> p_id THEN
+ RETURN;
+ END IF;
+ INSERT INTO forums.poll_vote (vote, account) VALUES (o_id, u_id);
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
diff -Naur beta5//sql/forums/FORUMS.sql forums//sql/forums/FORUMS.sql
--- beta5//sql/forums/FORUMS.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/forums/FORUMS.sql 2011-02-05 10:10:01.764335002 +0100
@@ -0,0 +1,19 @@
+-- LegacyWorlds Beta 5
+-- PostgreSQL database scripts
+--
+-- forums/FORUMS.sql
+--
+-- Install the forums' generic tables and code
+--
+-- Copyright(C) 2004-2007, DeepClone Development
+-- --------------------------------------------------------
+
+
+-- Execute the forums' installation scripts
+\i forums/00-schema.sql
+\i forums/01-forums.sql
+\i forums/01-signatures.sql
+\i forums/02-topics.sql
+\i forums/03-polls.sql
+\i forums/10-views.sql
+\i forums/11-access-functions.sql
diff -Naur beta5//sql/INSTALL.sql forums//sql/INSTALL.sql
--- beta5//sql/INSTALL.sql 2011-02-05 10:09:56.244335002 +0100
+++ forums//sql/INSTALL.sql 2011-03-12 15:03:56.721300053 +0100
@@ -10,16 +10,20 @@
\i 00-init.sql
\i 01-inheritance.sql
+
\i 10-main.sql
\i 11-main-enums.sql
\i 12-main-tables.sql
\i 13-main-donations.sql
-\i 13-main-forums.sql
+-- \i 13-main-forums.sql
\i 13-main-links.sql
\i 13-main-manual.sql
\i 13-main-proxy.sql
+\i 14-main-forums.sql
+\i 15-main-gf-functions.sql
\i 18-main-functions.sql
\i 19-main-values.sql
+
\i 25-ctf-maps.sql
\i 25-predefined-alliances.sql
\i 30-beta5.sql
diff -Naur beta5//sql/tools/destroy_alliance_forums.sql forums//sql/tools/destroy_alliance_forums.sql
--- beta5//sql/tools/destroy_alliance_forums.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/tools/destroy_alliance_forums.sql 2011-02-05 10:10:01.714335002 +0100
@@ -0,0 +1,11 @@
+ALTER TABLE alliance DROP COLUMN f_category;
+
+-- grep 'CREATE TABLE' beta5/structure/02-alliance-forums.sql | sed -e 's/CREATE/DROP/' -e 's/ ($/ CASCADE;/' >>tools/destroy_alliance_forums.sql
+-- grep 'CREATE OR REPLACE FUNCTION' beta5/structure/02-alliance-forums.sql | sed -e 's/CREATE OR REPLACE/DROP/' -e 's/).*$/) CASCADE;/' >> tools/destroy_alliance_forums.sql
+
+DROP TABLE alliance_forum CASCADE;
+DROP TABLE al_rank_forum CASCADE;
+
+DROP FUNCTION create_alliance_forum( pid BIGINT, aid BIGINT, fo INT, ttl TEXT, dsc TEXT, am TEXT) CASCADE;
+DROP FUNCTION modify_alliance_forum( pid BIGINT, fid BIGINT, ttl TEXT, dsc TEXT, am TEXT ) CASCADE;
+DROP FUNCTION get_aforums_privs( pid BIGINT, fid BIGINT, OUT can_view BOOLEAN, OUT can_post BOOLEAN, OUT can_create BOOLEAN, OUT can_poll BOOLEAN, OUT is_mod BOOLEAN, OUT is_admin BOOLEAN) CASCADE;
diff -Naur beta5//sql/tools/destroy_forums.sql forums//sql/tools/destroy_forums.sql
--- beta5//sql/tools/destroy_forums.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/tools/destroy_forums.sql 2011-02-05 10:10:01.714335002 +0100
@@ -0,0 +1,39 @@
+DROP SCHEMA forums CASCADE;
+
+SET search_path="b5",public;
+\i tools/destroy_alliance_forums.sql
+
+SET search_path="b5m0",public;
+\i tools/destroy_alliance_forums.sql
+
+SET search_path=public;
+-- grep 'CREATE TABLE' 1[45]*.sql | awk -F: '{print $2}' | sed -e 's/CREATE/DROP/' -e 's/ ($/ CASCADE;/' >>tools/destroy_forums.sql
+-- grep 'CREATE OR REPLACE FUNCTION' 1[45]*.sql | awk -F: '{print $2}' | sed -e 's/CREATE OR REPLACE/DROP/' -e 's/).*$/) CASCADE;/' >> tools/destroy_forums.sql
+
+DROP TABLE main.gf_category CASCADE;
+DROP TABLE main.gf_forum CASCADE;
+DROP TABLE main.gf_ban CASCADE;
+DROP TABLE main.gf_admin CASCADE;
+DROP TABLE main.gf_cat_moderator CASCADE;
+DROP TABLE main.gf_forum_moderator CASCADE;
+DROP TABLE main.user_category CASCADE;
+DROP TABLE main.user_forum CASCADE;
+DROP TABLE main.uf_subscription CASCADE;
+DROP TABLE main.uf_invite CASCADE;
+DROP FUNCTION main.trgf_gf_forum_check () CASCADE;
+DROP FUNCTION main.trgf_gf_admin_check () CASCADE;
+DROP FUNCTION main.trgf_gf_cmod_check () CASCADE;
+DROP FUNCTION main.trgf_gf_fmod_check() CASCADE;
+DROP FUNCTION main.init_general_forums() CASCADE;
+DROP FUNCTION main.init_version_forums( v TEXT ) CASCADE;
+DROP FUNCTION main.init_game_forums( g TEXT ) CASCADE;
+DROP FUNCTION main.get_gf_categories( ver TEXT, game TEXT ) CASCADE;
+DROP FUNCTION main.get_gf_list( ver TEXT, game TEXT ) CASCADE;
+DROP FUNCTION main.get_gforums_privs( aid BIGINT, fid BIGINT, OUT can_view BOOLEAN, OUT can_post BOOLEAN, OUT can_create BOOLEAN, OUT can_poll BOOLEAN, OUT is_mod BOOLEAN, OUT is_admin BOOLEAN) CASCADE;
+DROP FUNCTION main.uf_get_access_mode( fid BIGINT ) CASCADE;
+DROP FUNCTION main.uf_get_user_access( aid BIGINT, fid BIGINT ) CASCADE;
+DROP FUNCTION main.uf_get_category( aid BIGINT ) CASCADE;
+DROP FUNCTION main.uf_create_forum( aid BIGINT, fo INT, ttl TEXT, dsc TEXT, ua TEXT, am TEXT, pass TEXT) CASCADE;
+DROP FUNCTION main.trgf_account_user_forums() CASCADE;
+DROP FUNCTION main.trgf_uf_subscription_check() CASCADE;
+DROP FUNCTION main.trgf_uf_invite_check() CASCADE;
diff -Naur beta5//sql/tools/make_alliance_forums.sql forums//sql/tools/make_alliance_forums.sql
--- beta5//sql/tools/make_alliance_forums.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/tools/make_alliance_forums.sql 2011-02-05 10:10:01.714335002 +0100
@@ -0,0 +1,115 @@
+ALTER TABLE alliance ADD COLUMN f_category BIGINT NOT NULL DEFAULT forums.make_category('beta5/aforums') REFERENCES forums.category (id);
+CREATE INDEX alliance_f_category ON alliance (f_category);
+\i beta5/structure/02-alliance-forums.sql
+
+
+
+CREATE OR REPLACE FUNCTION get_player_uid( pid BIGINT ) RETURNS BIGINT AS $$
+DECLARE
+ i BIGINT;
+BEGIN
+ SELECT INTO i userid FROM player WHERE id = pid;
+ RETURN i;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION upgrade_alf_replies(opid BIGINT, npid BIGINT) RETURNS VOID AS $$
+DECLARE
+ rep RECORD;
+ nrid BIGINT;
+BEGIN
+ -- For each reply
+ FOR rep IN SELECT * FROM af_post WHERE reply_to = opid
+ LOOP
+ -- Post the reply
+ SELECT INTO nrid forums.add_reply( npid, get_player_uid(rep.author), rep.title, rep.contents,
+ rep.enable_code, rep.enable_smileys, NULL );
+ UPDATE forums.post_text SET moment = rep.moment WHERE post = nrid;
+
+ -- Check for edited post
+ IF rep.edited IS NOT NULL THEN
+ INSERT INTO forums.post_text (post, moment, author, title, contents, enable_code, enable_smileys)
+ VALUES (nrid, rep.edited, get_player_uid(rep.edited_by), rep.title, rep.contents,
+ rep.enable_code, rep.enable_smileys);
+ END IF;
+
+ -- Handle replies
+ PERFORM upgrade_alf_replies( rep.id, nrid );
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION upgrade_alf_contents(ofid INT, nfid BIGINT) RETURNS VOID AS $$
+DECLARE
+ top RECORD;
+ fpost RECORD;
+ ntid BIGINT;
+ fpid BIGINT;
+BEGIN
+ RAISE NOTICE 'Importing alliance forum #% (as #%)', ofid, nfid;
+
+ -- For each topic
+ FOR top IN SELECT * FROM af_topic WHERE forum = ofid
+ LOOP
+ -- Create it
+ SELECT INTO fpost * FROM af_post WHERE id = top.first_post;
+ SELECT INTO ntid forums.create_topic(
+ nfid, get_player_uid(fpost.author), CASE top.sticky WHEN true THEN 10 ELSE 0 END,
+ fpost.title, fpost.contents, fpost.enable_code, fpost.enable_smileys, NULL
+ );
+
+ -- Get the first post and fix its timestamp
+ SELECT INTO fpid id FROM forums.t_post WHERE topic = ntid;
+ UPDATE forums.post_text SET moment = fpost.moment WHERE post = fpid;
+
+ -- Add an entry if it has been edited
+ IF fpost.edited IS NOT NULL THEN
+ INSERT INTO forums.post_text (post, moment, author, title, contents, enable_code, enable_smileys)
+ VALUES (fpid, fpost.edited, get_player_uid(fpost.edited_by), fpost.title, fpost.contents,
+ fpost.enable_code, fpost.enable_smileys);
+ END IF;
+
+ PERFORM upgrade_alf_replies( fpost.id, fpid );
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+
+CREATE OR REPLACE FUNCTION upgrade_alliance( aid INT, cid BIGINT ) RETURNS VOID AS $$
+DECLARE
+ af RECORD;
+ arf RECORD;
+ nfid BIGINT;
+BEGIN
+ FOR af IN SELECT * FROM af_forum WHERE alliance = aid
+ LOOP
+ SELECT INTO nfid forums.make_forum( cid, af.forder, af.title, af.description );
+ INSERT INTO alliance_forum VALUES ( nfid, aid, CASE af.user_post WHEN TRUE THEN 'T' ELSE 'P' END);
+ FOR arf IN SELECT * FROM algr_forums WHERE forum = af.id
+ LOOP
+ INSERT INTO al_rank_forum VALUES (arf.grade, nfid, arf.is_mod);
+ END LOOP;
+ PERFORM upgrade_alf_contents( af.id, nfid );
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+
+CREATE OR REPLACE FUNCTION upgrade_alliance_forums() RETURNS VOID AS $$
+DECLARE
+ al RECORD;
+BEGIN
+ FOR al IN SELECT * FROM alliance
+ LOOP
+ RAISE NOTICE 'Upgrading forums for alliance #% [%]', al.id, al.tag;
+ PERFORM upgrade_alliance( al.id, al.f_category );
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+SELECT upgrade_alliance_forums();
+
+DROP FUNCTION upgrade_alliance_forums() ;
+DROP FUNCTION upgrade_alliance( INT, BIGINT ) ;
+DROP FUNCTION upgrade_alf_contents( INT, BIGINT) ;
+DROP FUNCTION get_player_uid( BIGINT ) ;
diff -Naur beta5//sql/tools/make_forums.sql forums//sql/tools/make_forums.sql
--- beta5//sql/tools/make_forums.sql 1970-01-01 01:00:00.000000000 +0100
+++ forums//sql/tools/make_forums.sql 2011-02-05 10:10:01.714335002 +0100
@@ -0,0 +1,168 @@
+\i 14-main-forums.sql
+\i 15-main-gf-functions.sql
+\i 15-main-uforums.sql
+
+SELECT forums.add_category_type( 'beta5/aforums', 'en', 'Alliance forums' );
+
+
+CREATE OR REPLACE FUNCTION upgrade_gen_replies(opid BIGINT, npid BIGINT) RETURNS VOID AS $$
+DECLARE
+ rep RECORD;
+ nrid BIGINT;
+BEGIN
+ -- For each reply
+ FOR rep IN SELECT * FROM main.f_post WHERE reply_to = opid AND deleted IS NULL
+ LOOP
+ -- Post the reply
+ SELECT INTO nrid forums.add_reply( npid, rep.author, rep.title, rep.contents,
+ rep.enable_code, rep.enable_smileys, NULL );
+ UPDATE forums.post_text SET moment = rep.moment WHERE post = nrid;
+
+ -- Check for edited post
+ IF rep.edited IS NOT NULL THEN
+ INSERT INTO forums.post_text (post, moment, author, title, contents, enable_code, enable_smileys)
+ VALUES (nrid, rep.edited, rep.edited_by, rep.title, rep.contents,
+ rep.enable_code, rep.enable_smileys);
+ END IF;
+
+ -- Handle replies
+ PERFORM upgrade_gen_replies( rep.id, nrid );
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION upgrade_gen_forum(ofid INT, nfid BIGINT) RETURNS VOID AS $$
+DECLARE
+ top RECORD;
+ fpost RECORD;
+ ntid BIGINT;
+ fpid BIGINT;
+BEGIN
+ RAISE NOTICE 'Importing general forum #% (as #%)', ofid, nfid;
+
+ -- For each topic
+ FOR top IN SELECT * FROM main.f_topic WHERE forum = ofid AND deleted IS NULL
+ LOOP
+ -- Create it
+ SELECT INTO fpost * FROM main.f_post WHERE id = top.first_post;
+ SELECT INTO ntid forums.create_topic(
+ nfid, fpost.author, CASE top.sticky WHEN true THEN 10 ELSE 0 END,
+ fpost.title, fpost.contents, fpost.enable_code, fpost.enable_smileys, NULL
+ );
+
+ -- Get the first post and fix its timestamp
+ SELECT INTO fpid id FROM forums.t_post WHERE topic = ntid;
+ UPDATE forums.post_text SET moment = fpost.moment WHERE post = fpid;
+
+ -- Add an entry if it has been edited
+ IF fpost.edited IS NOT NULL THEN
+ INSERT INTO forums.post_text (post, moment, author, title, contents, enable_code, enable_smileys)
+ VALUES (fpid, fpost.edited, fpost.edited_by, fpost.title, fpost.contents,
+ fpost.enable_code, fpost.enable_smileys);
+ END IF;
+
+ PERFORM upgrade_gen_replies( fpost.id, fpid );
+ END LOOP;
+END;
+$$ LANGUAGE plpgsql;
+
+
+CREATE OR REPLACE FUNCTION upgrade_forums() RETURNS VOID AS $$
+DECLARE
+ mcid BIGINT;
+ cid_v BIGINT;
+ cid_b5 BIGINT;
+ cid_m5 BIGINT;
+ fid BIGINT;
+BEGIN
+ -- Main forums
+ SELECT INTO mcid main.init_general_forums();
+ -- Announcements
+ SELECT INTO fid forums.make_forum( mcid, 0, 'Announcements',
+ 'Updates on the game''s progress, new versions, etc...');
+ INSERT INTO main.gf_forum VALUES ( fid, 'MP' );
+ PERFORM upgrade_gen_forum( 1, fid );
+ -- The Pub
+ SELECT INTO fid forums.make_forum( mcid, 1, 'The Pub', 'Discuss whatever''s on your mind in here.');
+ INSERT INTO main.gf_forum VALUES ( fid, 'UL' );
+ PERFORM upgrade_gen_forum( 3, fid );
+ -- M&A
+ SELECT INTO fid forums.make_forum( mcid, 2, 'Malcontents and Anarchists',
+ 'Forum in which public executions take place.');
+ INSERT INTO main.gf_forum VALUES ( fid, 'MP' );
+ PERFORM upgrade_gen_forum( 4, fid );
+ -- Admin policies
+ SELECT INTO fid forums.make_forum( mcid, 3, '[ADMIN] Main moderators/admins board',
+ 'Forum only available to Legacy Worlds administrators and moderators.');
+ INSERT INTO main.gf_forum VALUES ( fid, 'MO' );
+ PERFORM upgrade_gen_forum( 12, fid );
+
+
+ -- Beta 5 *version* forums
+ SELECT INTO cid_v main.init_version_forums('beta5');
+ -- New / Improved features
+ SELECT INTO fid forums.make_forum( cid_v, 0, 'New / Improved features',
+ 'Your ideas about how to improve the game and our response to these ideas.' );
+ PERFORM upgrade_gen_forum( 2, fid);
+ -- Bugs and Problems
+ SELECT INTO fid forums.make_forum( cid_v, 1, 'Bugs and Problems',
+ 'Whine about what you think is wrong with Beta 5 in this forum.' );
+ PERFORM upgrade_gen_forum( 7, fid);
+ -- Help
+ SELECT INTO fid forums.make_forum( cid_v, 2, 'Help', 'Ask the staff and other players for advice.' );
+ PERFORM upgrade_gen_forum( 8, fid);
+
+
+ -- Beta 5 *game* forums
+ SELECT INTO cid_b5 main.init_game_forums('beta5');
+ -- General Discussion
+ SELECT INTO fid forums.make_forum( cid_b5, 0, 'General Discussion',
+ 'Discuss what''s going on in the Beta 5 universe.' );
+ PERFORM upgrade_gen_forum( 5, fid );
+ -- Alliance Recruitment
+ SELECT INTO fid forums.make_forum( cid_b5, 1, 'Alliance Recruitment',
+ 'Advertise for your alliance and recruit new members through this forum.' );
+ PERFORM upgrade_gen_forum( 6, fid );
+ -- Marketplace Advertisement
+ SELECT INTO fid forums.make_forum( cid_b5, 2, 'Marketplace Advertisement',
+ 'Advertise for items you''ve put on sale in the marketplace or technologies you''re willing to provide through diplomacy.' );
+ PERFORM upgrade_gen_forum( 9, fid );
+
+
+ -- Beta 5 *match* forums
+ SELECT INTO cid_m5 main.init_game_forums('b5match');
+ -- General Discussion
+ SELECT INTO fid forums.make_forum( cid_m5, 0, 'General Discussion',
+ 'Discuss what''s going on in the Beta 5 match.' );
+ PERFORM upgrade_gen_forum( 11, fid );
+ -- Alliance Recruitment
+ SELECT INTO fid forums.make_forum( cid_m5, 1, 'Alliance Recruitment',
+ 'Advertise for your alliance and recruit new members through this forum.' );
+ -- Marketplace Advertisement
+ SELECT INTO fid forums.make_forum( cid_m5, 2, 'Marketplace Advertisement',
+ 'Advertise for items you''ve put on sale in the marketplace or technologies you''re willing to provide through diplomacy.' );
+
+
+ -- Add admins and mods
+ INSERT INTO main.gf_admin (account) VALUES (1);
+ INSERT INTO main.gf_admin (account) VALUES (2);
+ INSERT INTO main.gf_admin (account) VALUES (3);
+ INSERT INTO main.gf_admin (account) VALUES (4);
+ INSERT INTO main.gf_cat_moderator (account) VALUES (7);
+ INSERT INTO main.gf_cat_moderator (account) VALUES (8);
+END;
+$$ LANGUAGE plpgsql;
+
+SELECT upgrade_forums();
+
+DROP FUNCTION upgrade_forums() ;
+DROP FUNCTION upgrade_gen_forum(ofid INT, nfid BIGINT) ;
+DROP FUNCTION upgrade_gen_replies(BIGINT, BIGINT) ;
+
+SET search_path=b5,main,public;
+\i tools/make_alliance_forums.sql
+SET search_path=b5m0,main,public;
+\i tools/make_alliance_forums.sql
+SET search_path=public;
+
+VACUUM ANALYZE;