This repository has been archived on 2024-07-18. You can view files and clone it, but cannot push or open issues or pull requests.
lwb5/misc/forums-branch.patch

11688 lines
379 KiB
Diff
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
<EFBFBD>˲&<26>TYEQ<45><51>)EQ<45><51>9EQ`<60><><EFBFBD>lz@
<EFBFBD><EFBFBD> <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<>
<EFBFBD>;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<EFBFBD>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<EFBFBD><EFBFBD>^AR<41><12>,<2C><>b<><01>%<25><><EFBFBD>
+;ư<>
p<16>ْD
d0<EFBFBD><EFBFBD>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
<EFBFBD>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<EFBFBD><EFBFBD><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<EFBFBD><EFBFBD><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>
<EFBFBD><EFBFBD>@_|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>
<EFBFBD><EFBFBD>@_|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
<EFBFBD><EFBFBD><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
<EFBFBD><EFBFBD><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;