Index: common/db/score.php
===================================================================
--- common/db/score.php	(revision 1164)
+++ common/db/score.php	(working copy)
@@ -372,9 +372,7 @@ function score_get_rankings($rounds, $tasks, $start = 0, $count = 999999,
     // Get the total score for all rounds
     $query = "
         SELECT ".(count($rounds) > 1 ? "SUM(score) AS score" : "score").",
-                user_id, ia_user.username AS user_name,
-                ia_user.full_name AS user_full,
-                ia_user.rating_cache AS user_rating
+                user_id AS id, ia_user.*
         FROM ia_score_user_round
         LEFT JOIN ia_user ON ia_user.id = ia_score_user_round.user_id
         WHERE".implode('AND', $where)."
@@ -389,7 +387,7 @@ function score_get_rankings($rounds, $tasks, $start = 0, $count = 999999,
 
     $users = array();
     foreach ($rankings as $ranking) {
-        array_push($users, $ranking['user_id']);
+        array_push($users, $ranking['id']);
     }
 
     // Further queries concern only the users that are in this rankings page
@@ -440,7 +438,7 @@ function score_get_rankings($rounds, $tasks, $start = 0, $count = 999999,
 
     //create all entries
     for ($i = 0; $i < count($rankings); $i++) {
-        $user_id = $rankings[$i]['user_id'];
+        $user_id = $rankings[$i]['id'];
 
         //task columns
         if ($detail_task == true) {
@@ -450,7 +448,7 @@ function score_get_rankings($rounds, $tasks, $start = 0, $count = 999999,
                 } else {
                     $score = 0;
                 }
-                $rankings[$i][$task_id] = $score;
+                $rankings[$i]['task_scores_' . $task_id] = $score;
             }
         }
 
@@ -462,7 +460,7 @@ function score_get_rankings($rounds, $tasks, $start = 0, $count = 999999,
                 } else {
                     $score = 0;
                 }
-                $rankings[$i][$round_id] = $score;
+                $rankings[$i]['round_scores_' . $round_id] = $score;
             }
         }
 
Index: common/db/textblock.php
===================================================================
--- common/db/textblock.php	(revision 1164)
+++ common/db/textblock.php	(working copy)
@@ -117,9 +117,11 @@ function textblock_complex_query($options)
         $field_list .= ", `text`";
     }
 
+    //FIXME: get username as username and full_name as full_mame, no conflicts here so why mess up?
     // Add a join for username.
     if (getattr($options, 'username', false) == true) {
-        $field_list .= ", `username` as `user_name`, `full_name` as `user_fullname`, rating_cache";
+        $field_list .= ", `username` as `user_name`, `full_name` as `user_fullname`, rating_cache"
+                . ", security_level, avatar_timestamp";
         $join = "LEFT JOIN ia_user ON `user_id` = `ia_user`.`id`";
     } else {
         $join = "";
@@ -234,11 +236,11 @@ function textblock_get_revision_count($name) {
     $name = normalize_page_name($name);
     log_assert(is_normal_page_name($name));
 
-    $query = sprintf("SELECT COUNT(*) AS `cnt` FROM ia_textblock_revision
+    $query = sprintf("SELECT COUNT(*) AS `count` FROM ia_textblock_revision
                       WHERE `name` = '%s'",
                     db_escape(strtolower($name)));
     $row = db_fetch($query);
-    return $row['cnt'] + 1;
+    return $row['count'] + 1;
 }
 
 // Grep through textblocks. This is mostly a hack needed for macro_grep.php
Index: common/db/user.php
===================================================================
--- common/db/user.php	(revision 1164)
+++ common/db/user.php	(working copy)
@@ -166,6 +166,7 @@ function user_create($user, $remote_ip_info=null)
 // Also updates SMF, which is good.
 function user_update($user)
 {
+    $user['avatar_timestamp'] = time();
     log_assert_valid(user_validate($user));
 
     // Update DB
Index: common/security.php
===================================================================
--- common/security.php	(revision 1164)
+++ common/security.php	(working copy)
@@ -131,11 +131,11 @@ function security_simplify_action($action) {
         case 'task-delete':
         case 'task-tag':
         case 'task-reeval':
-        case 'task-edit-ratings': 
+        case 'task-edit-ratings':
         case 'textblock-delete':
         case 'textblock-delete-revision':
         case 'round-tag':
-        case 'round-view-progress': 
+        case 'round-view-progress':
         case 'grader-overwrite':
         case 'grader-delete':
         case 'grader-rename':
@@ -181,6 +181,105 @@ function security_simplify_action($action) {
     }
 }
 
+/**
+ * Ask for the available actions on the object
+ * For use in XHP objects so they won't query the identity user
+ * FIXME: add all the other object types security queries
+ *
+ * @param  $user    array
+ * @param  $object  array
+ * @return array
+ */
+function security_actions_query($user, $object) {
+    log_assert(is_array($object),
+        '$object must be an array');
+
+    if (IA_LOG_SECURITY) {
+        $username = getattr($user, 'username', 'null');
+        $security_level = getattr($user, 'security_level', 'anonymus');
+        $object_name = getattr($object, 'name', $object);
+        log_print("SECURITY QUERY: ($username, $security_level, $object): "
+                . "(username, level, object)");
+    }
+
+    switch ($object['type']) {
+        case 'textblock':
+           $actions = security_actions_textblock($user, $object);
+           break;
+
+        default:
+            log_error('Invalid type of object: ' . $object['type']);
+    }
+
+    if (IA_LOG_SECURITY) {
+        if (count($actions) == 0) {
+            log_print("NO ACTIONS");
+        } else {
+            log_print_r($actions);
+        }
+    }
+
+    return $actions;
+}
+
+/**
+ * Checks what actions an user can perform on a given textblock
+ * For use in XHP object
+ *
+ * @param  $user       the user array containing all the necessary
+ *                     information about the user
+ * @param  $textblock
+ * @return array
+ */
+function security_actions_textblock($user, $textblock) {
+    $user_security_level = getattr($user, 'security_level', 'anonymus');
+    $textblock_security_level = getattr($textblock, 'security');
+
+    $view_actions = array('view', 'history', 'list-attach');
+    $sensitive_info = array('view-ip');
+    $reversible_actions = array('edit', 'restore', 'attach', 'create',
+            'change-topic', 'copy');
+    $admin_actions = array('move', 'delete', 'delete-revision',
+            'change-security', 'tag');
+
+    $actions = array();
+    if ($textblock_security_level == 'public') {
+        switch ($user_security_level) {
+            case 'admin':
+                $actions = array_merge($actions, $admin_actions);
+            case 'intern':
+            case 'helper':
+                $actions = array_merge($actions, $sensitive_info);
+            case 'normal':
+                $actions = array_merge($actions, $reversible_actions);
+            default:
+                $actions = array_merge($actions, $view_actions);
+                break;
+        }
+    } elseif ($textblock_security_level == 'protected') {
+        switch ($user_security_level) {
+            case 'admin':
+                $actions = array_merge($actions, $admin_actions,
+                        $reversible_actions);
+            case 'intern':
+            case 'helper':
+                $actions = array_merge($actions, $sensitive_info);
+            case 'normal':
+            default:
+                $actions = array_merge($actions, $view_actions);
+        }
+    } else {
+        if ($user_security_level == 'admin') {
+            $actions = array_merge($admin_actions, $sensitive_info,
+                    $reversible_actions, $view_actions);
+        } else {
+            $actions = array();
+        }
+    }
+
+    return $actions;
+}
+
 // Handles textblock security.
 function security_textblock($user, $action, $textblock) {
     require_once(IA_ROOT_DIR."common/textblock.php");
@@ -254,7 +353,7 @@ function security_textblock($user, $action, $textblock) {
             }
 
         case 'sensitive-info':
-            return ($usersec == 'admin' || $usersec == 'helper');
+            return ($usersec == 'admin' || $usersec == 'intern' || $usersec == 'helper');
 
         // Reversible modifications.
         case 'simple-rev-edit':
Index: common/textblock.php
===================================================================
--- common/textblock.php	(revision 1164)
+++ common/textblock.php	(working copy)
@@ -10,15 +10,15 @@ function hijack_title(&$text, $url, $title) {
     if (preg_match('/^\s*<h1>(.*)<\/h1>(.*)$/sxi', $text, $matches)) {
         $text = $matches[2];
         if (is_null($url)) {
-            return '<h1>'.$matches[1].'</h1>';
+            return <h1> {$matches[1]} </h1>;
         } else {
-            return '<h1>'.format_link($url, $matches[1], false).'</h1>';
+            return <h1> <ui:link href={$url}> {$matches[1]} </ui:link> </h1>;
         }
     } else {
         if (is_null($url)) {
-            return '<h1>'.html_escape($title).'</h1>';
+            return <h1> {$title} </h1>;
         } else {
-            return '<h1>'.format_link($url, $title).'</h1>';
+            return <h1> <ui:link href={$url}> {$title} </ui:link> </h1>;
         }
     }
 }
Index: common/user.php
===================================================================
--- common/user.php	(revision 1164)
+++ common/user.php	(working copy)
@@ -103,15 +103,25 @@ function user_validate($user) {
     } else if ($user['newsletter'] != '0' && $user['newsletter'] != '1') {
         $errors['newsletter'] = "Se accepta doar 0/1";
     }
-    
+
     return $errors;
 }
 
-function user_is_admin($user) {
+/**
+ * Checks if the user is an admin
+ * the second parameter is used to tell if it's just for formality( such as
+ * <ui:user:* /> tags which do not have any effect on the database
+ * @param  string  $user
+ * @param  bool    @validate
+ * @return bool
+ */
+function user_is_admin($user, $validate = true) {
     if (!$user) {
         return false;
     }
-    log_assert_valid(user_validate($user));
+    if ($validate == true) {
+        log_assert_valid(user_validate($user));
+    }
     return $user['security_level'] === 'admin';
 }
 
Index: scripts/add-avatar-timestamps
new file mode 100755
===================================================================
--- scripts/add-avatar-timestamps	(revision 0)
+++ scripts/add-avatar-timestamps	(working copy)
@@ -0,0 +1,18 @@
+#! /usr/bin/env php
+<?php
+
+require_once(dirname($argv[0]) . '/utilities.php');
+require_once(IA_ROOT_DIR . 'common/db/db.php');
+require_once(IA_ROOT_DIR . 'common/cache.php');
+
+db_connect();
+
+$result = db_query("SHOW COLUMNS FROM `ia_user` LIKE 'avatar_timestamp'");
+if (mysql_num_rows($result) == 0) {
+    $query = "ALTER TABLE `ia_user` ADD COLUMN avatar_timestamp INT";
+    db_query($query);
+}
+
+db_query("UPDATE `ia_user` SET `avatar_timestamp` = " . time());
+mem_cache_purge();
+?>
Index: smf/Themes/default/index.template.php
===================================================================
--- smf/Themes/default/index.template.php	(revision 1164)
+++ smf/Themes/default/index.template.php	(working copy)
@@ -29,7 +29,7 @@
 	http://www.simplemachines.org/
 */
 
-require_once(IA_ROOT_DIR.'www/views/sitewide.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ia/sitewide.php');
 
 // Initialize the template... mainly little settings.
 function template_init()
@@ -209,7 +209,7 @@ function template_main_above()
 </div>
 
 <?php*/
-	ia_template_header();
+	echo <ia:header user={identity_get_user()} />;
 
 	// Show the menu here, according to the menu sub template.
 	template_menu();
@@ -255,7 +255,7 @@ function template_main_below()
 		<span class="smalltext">', $txt['smf301'], $context['load_time'], $txt['smf302'], $context['load_queries'], $txt['smf302b'], '</span>';
 
 	// throw in infoarena footer
-	ia_template_footer();
+	echo <ia:footer />;
 
 	// This is an interesting bug in Internet Explorer AND Safari. Rather annoying, it makes overflows just not tall enough.
 	if (($context['browser']['is_ie'] && !$context['browser']['is_ie4']) || $context['browser']['is_mac_ie'] || $context['browser']['is_safari'] || $context['browser']['is_firefox'])
@@ -388,7 +388,10 @@ function template_menu() {
 	$smf_admin = $context['allow_admin'];
 
 	// display menu
-	ia_template_topnav($current_action, $smf_admin);
+	echo <ia:top-navbar
+		user={identity_get_user()} selected={$current_action}
+		user_pm_count={identity_is_anonymous() ? null :
+		               smf_get_pm_count(identity_get_username())} />;
 	if ($context['user']['is_logged']) {
 		echo '<div style="float: right; padding: 3pt">',
 			 '<a href="', $scripturl, '?action=search', '"><strong>Cauta in forum</strong></a> | ',
Index: smf/ia_comments.php
===================================================================
--- smf/ia_comments.php	(revision 1164)
+++ smf/ia_comments.php	(working copy)
@@ -20,6 +20,7 @@ if (is_null($max_comm)) {
 } else {
     ssi_commentThread($topic_id, $display, $begin_comm, (int)$max_comm);
 }
+
 echo '</div>';
 
 ?>
Index: www/controllers/attachment.php
===================================================================
--- www/controllers/attachment.php	(revision 1164)
+++ www/controllers/attachment.php	(working copy)
@@ -1,11 +1,12 @@
 <?php
 
-require_once(IA_ROOT_DIR."www/format/pager.php");
-require_once(IA_ROOT_DIR."common/db/textblock.php");
-require_once(IA_ROOT_DIR."common/db/attachment.php");
-require_once(IA_ROOT_DIR.'www/controllers/zip_attachment.php');
-require_once(IA_ROOT_DIR."common/external_libs/zipfile.php");
-require_once(IA_ROOT_DIR."common/avatar.php");
+require_once(IA_ROOT_DIR . 'www/format/pager.php');
+require_once(IA_ROOT_DIR . 'common/db/textblock.php');
+require_once(IA_ROOT_DIR . 'common/db/attachment.php');
+require_once(IA_ROOT_DIR . 'www/controllers/zip_attachment.php');
+require_once(IA_ROOT_DIR . 'common/external_libs/zipfile.php');
+require_once(IA_ROOT_DIR . 'common/avatar.php');
+require_once(IA_ROOT_DIR . 'common/db/user.php');
 
 // Try to get the textblock model for a certain page.
 // If it fails it will flash and redirect
@@ -328,6 +329,7 @@ function controller_attachment_delete($page_name, $file_name, $more_files = 0) {
     // Delete the resizedimages in case the page is an avatar
     $matches = get_page_user_name($page_name);
     if (is_avatar_attachment($file_name, $page_name)) {
+        user_update(identity_get_user());
         avatar_delete($matches[1]);
     }
     // We've got big balls.
Index: www/controllers/json.php
===================================================================
--- www/controllers/json.php	(revision 1164)
+++ www/controllers/json.php	(working copy)
@@ -39,7 +39,7 @@ function controller_json($suburl) {
             );
 
             // output JSON
-            execute_view_die('views/json.php', $view);
+            execute_view_die('views/json.php', $view, true);
 
         case 'task-get-rounds':
             // Return list of parent rounds for a task
@@ -57,7 +57,7 @@ function controller_json($suburl) {
             );
 
             // Output JSON
-            execute_view_die('views/json.php', $view);
+            execute_view_die('views/json.php', $view, true);
         default:
             die_http_error(400, 'Actiune invalida.');
     }
Index: www/controllers/login.php
===================================================================
--- www/controllers/login.php	(revision 1164)
+++ www/controllers/login.php	(working copy)
@@ -1,6 +1,7 @@
 <?php
 
-require_once(IA_ROOT_DIR . "common/db/user.php");
+require_once(IA_ROOT_DIR . 'common/db/user.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/textblock.php');
 
 function controller_login() {
     global $identity_user;
@@ -81,14 +82,31 @@ function controller_login() {
     // always reset password before displaying web form
     $data['password'] = '';
 
-    $view['page_name'] = "login";
-    $view['title'] = "Autentificare";
-    $view['form_values'] = $data;
-    $view['form_errors'] = array();
-    $view['topnav_select'] = 'login';
-    $view['no_sidebar_login'] = true;
+    $textblock = textblock_get_revision('template/login');
+    log_assert($textblock, "Pagina template/login lipseste");
+    $textblock['text'] = wiki_process_textblock($textblock);
 
-    execute_view_die('views/login.php', $view);
+    $login_form =
+      <x:frag>
+        <h1>
+          Autentificare
+        </h1>
+        <p>
+          Daca nu esti inregistrat deja, te poti
+          <ui:link href={url_register()}>
+            inregistra aici
+          </ui:link>
+          ; daca ti-ai uitat parola, o poti
+          <ui:link href={url_resetpass()}>
+            reseta aici
+          </ui:link>
+          .
+        </p>
+        <ia:login_form values={$data}/>
+        <ui:textblock textblock={$textblock} show_forum={false} />
+      </x:frag>;
+
+    execute_render_die($login_form, 'Autentificare', 'login', true);
 }
 
 ?>
Index: www/controllers/textblock.php
===================================================================
--- www/controllers/textblock.php	(revision 1164)
+++ www/controllers/textblock.php	(working copy)
@@ -1,13 +1,56 @@
 <?php
 
-require_once(IA_ROOT_DIR . "www/format/pager.php");
-require_once(IA_ROOT_DIR . "common/db/textblock.php");
-require_once(IA_ROOT_DIR . "common/textblock.php");
-require_once(IA_ROOT_DIR . "common/diff.php");
+require_once(IA_ROOT_DIR . 'www/format/pager.php');
+require_once(IA_ROOT_DIR . 'common/db/textblock.php');
+require_once(IA_ROOT_DIR . 'common/textblock.php');
+require_once(IA_ROOT_DIR . 'common/diff.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/textblock.php');
+function controller_textblock_render($page_name, $revision_number = null) {
+    $current_page = textblock_get_revision($page_name);
+
+    if ($current_page) {
+        $revision_count = textblock_get_revision_count($page_name);
+
+        if ($revision_number && $revision_number != $revision_count) {
+            if (!is_numeric($revision_number) || (int)$revision_number < 1) {
+                flash_error('Revizia "' . $revision_number . '" este invalida.');
+                redirect(url_textblock($page_name));
+            } else {
+                $reivison_number = (int)$revision_number;
+            }
 
+            identity_require("textblock-history", $current_page);
+            $page = textblock_get_revision($page_name, $revision_number);
+
+            if (!$page) {
+                flash_error('Revizia "' . $revision_number . '" nu exista.');
+                redirect(url_textblock($page_name));
+            }
+        } else {
+            identity_require('textblock-view', $current_page);
+            $page = $current_page;
+        }
+    } else {
+        // Missing page
+        flash_error("Nu exista pagina, dar poti sa o creezi ...");
+        redirect(url_textblock_edit($page_name));
+    }
+
+    log_assert_valid(textblock_validate($page));
+
+    $page['type'] = 'textblock';
+    $page['text'] = wiki_process_textblock($page);
+    $permitted_actions = identity_actions($page);
+
+    $textblock =
+      <ui:textblock textblock={$page} show_forum={true} revision={$revision_number}
+          revision_count={$revision_count} permitted_actions={$permitted_actions} />;
+
+    execute_render_die($textblock, $page['title']);
+}
 
-// View a plain textblock.
-// That textblock can be owned by something else.
+// DEPRECATED
+// FIXME: remove this once the newsletter is rewritten in XHP too
 function controller_textblock_view($page_name, $rev_num = null,
         $display_view = 'views/textblock_view.php') {
     global $identity_user;
Index: www/format/format.php
===================================================================
--- www/format/format.php	(revision 1164)
+++ www/format/format.php	(working copy)
@@ -104,6 +104,13 @@ function format_post_link($url, $content, $post_data = array(), $escape = true,
 // FIXME: Improve this logic.
 function format_highlight_access_key($string, $key) {
     if (($pos = stripos($string, $key)) !== false) {
+        require_once(IA_ROOT_DIR . 'www/xhp/base/init.php');
+        return
+            <x:frag>
+                {substr($string, 0, $pos)}
+                <span class="access-key">{$string[$pos]}</span>
+                {substr($string, $pos + 1)}
+            </x:frag>;
         return substr_replace($string,
                 '<span class="access-key">'.$string[$pos].'</span>', $pos, 1);
     } else {
Index: www/identity.php
===================================================================
--- www/identity.php	(revision 1164)
+++ www/identity.php	(working copy)
@@ -62,6 +62,17 @@ function identity_can($action, $object = null) {
     return security_query($identity_user, $action, $object);
 }
 
+/**
+ * Returns the actions the current user is allowed on an object
+ *
+ * @param  array  object
+ * @return array
+ */
+function identity_actions($object) {
+    global $identity_user;
+    return security_actions_query($identity_user, $object);
+}
+
 // Require login first.
 // It makes a lot of sense to separate this from security. No matter what
 // dumb little security.php might say, some things absolutely require login.
Index: www/index.php
===================================================================
--- www/index.php	(revision 1164)
+++ www/index.php	(working copy)
@@ -324,7 +324,7 @@ else if (IA_NEWSLETTER_TEXTBLOCK_PREFIX == $urlstart.'/'
 // general textblock view
 else if ($action == 'view') {
     require_once(IA_ROOT_DIR.'www/controllers/textblock.php');
-    controller_textblock_view($page, request('revision'));
+    controller_textblock_render($page, request('revision'));
 }
 
 // invalid URL
Index: www/macros/macro_gallery.php
===================================================================
--- www/macros/macro_gallery.php	(revision 1164)
+++ www/macros/macro_gallery.php	(working copy)
@@ -39,16 +39,19 @@ function macro_gallery($args) {
     $atts = attachment_get_all($page, $file, $options['first_entry'], $options['display_entries']);
 
     // display gallery
-    $buffer = '<div class="gallery"><div class="images">';
+    $gallery = <div class="images" />;
     foreach ($atts as $attach) {
         $thumbsrc = url_image_resize($attach['page'], $attach['name'], "130x80");
         $fullsrc = url_image_resize($attach['page'], $attach['name'], null);
-        $buffer .= "<a href=\"".html_escape($fullsrc)."\"><img src=\"".html_escape($thumbsrc)."\" alt=\"".html_escape($attach['page'])."\" /></a>";
+        $gallery -> appendChild(<ui:link href={$fullsrc}> <img src={$thumbsrc} alt={$attach['page']} /> </ui:link>);
     }
-    $buffer .= '</div>';
-    $buffer .= format_pager($options);
-    $buffer .= '</div>';
 
+    return
+      <div class="gallery">
+        {$gallery}
+        <ui:pager:page-number display_entries={$options['display_entries']} total_entries={$options['total_entries']}
+            first_entry={$options['first_entry']} show_count={true} />
+      </div>;
     return $buffer;
 }
 
Index: www/macros/macro_rankings.php
===================================================================
--- www/macros/macro_rankings.php	(revision 1164)
+++ www/macros/macro_rankings.php	(working copy)
@@ -1,9 +1,11 @@
 <?php
 
-require_once(IA_ROOT_DIR . "www/format/table.php");
-require_once(IA_ROOT_DIR . "www/format/pager.php");
-require_once(IA_ROOT_DIR . "www/format/format.php");
-require_once(IA_ROOT_DIR . "common/db/score.php");
+require_once(IA_ROOT_DIR . 'www/format/pager.php');
+require_once(IA_ROOT_DIR . 'www/format/format.php');
+require_once(IA_ROOT_DIR . 'common/db/score.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/user.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/table.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/pager.php');
 
 // Displays *interactive* rankings table summing up score points from a
 // pre-defined set of contest rounds.
@@ -40,8 +42,6 @@ function macro_rankings($args) {
 
     // Paginator options
     $options = pager_init_options($args);
-    $options['show_count'] = true;
-    $options['css_class'] = 'sortable';
 
     // Rounds parameters
     $roundstr = getattr($args, 'rounds', '');
@@ -63,20 +63,13 @@ function macro_rankings($args) {
 
     // Generating Table
 
-    $column_infos = array(
-        array(
-            'title' => 'Pozitie',
-            'key' => 'ranking',
-            'css_class' => 'number rank'
-        ),
-        array(
-            'title' => 'Nume',
-            'key' => 'user_full',
-            'rowform' => function($row) {
-                return format_user_normal($row['user_name'], $row['user_full'], $row['user_rating']);
-            },
-        ),
-    );
+    $header =
+      <x:frag>
+        <th class="number rank">
+          {'Pozitie'}
+        </th>
+        Nume
+      </x:frag>;
 
     $columns = array();
     $tasks = array();
@@ -87,63 +80,74 @@ function macro_rankings($args) {
             if ($detail_task == true) {
                 $new_tasks = round_get_tasks($round_id);
                 foreach ($new_tasks as $task) {
-                    array_push($columns, array(
-                        'name' => $task['id'],
-                        'type' => 'task',
-                        'title' => $task['title']
-                    ));
+                    $header -> appendChild(<th class="number score">
+                                          {$task['title']}
+                                        </th>);
+                    $columns[] = 'task_scores_' . $task['id'];
                     array_push($tasks, $task['id']);
                 }
             }
 
             if ($detail_round == true) {
-                array_push($columns, array(
-                    'name' => $round['round_id'],
-                    'type' => 'round',
-                    'title' => $round['round_name']
-                ));
+                $header -> appendChild(<th class="number score">
+                                      {$round['round_name']}
+                                    </th>);
+                $columns[] = 'round_scores_' . $round['round_id'];
             }
         }
     }
 
-    foreach ($columns as $column) {
-        array_push($column_infos, array(
-            'title' => $column['title'],
-            'key' => $column['name'],
-            'rowform' => function($row) use ($column) {
-                return round($row[$column['name']]);
-            },
-            'css_class' => 'number score'
-        ));
-    }
-
     $total = 'Scor';
     if ($detail_round == true || $detail_task == true) {
         $total = 'Total';
     }
-    array_push($column_infos, array(
-        'title' => $total,
-        'key' => 'score',
-        'rowform' => function($row) {
-            return round($row['score']);
-        },
-        'css_class' => 'number score'
-    ));
+    $header -> appendChild(<th class="number score">
+                             {$total}
+                           </th>);
+
+    $content = <x:frag />;
 
     $round_ids = array();
     foreach ($rounds as $round) {
         array_push($round_ids, $round['round_id']);
     }
     $rankings = score_get_rankings($round_ids, $tasks, $options['first_entry'], $options['display_entries'], $detail_task, $detail_round);
-
-    if (pager_needs_total_entries($options)) {
-        $options['total_entries'] = score_get_count(null, null, $round_ids);
+    foreach ($rankings as $user) {
+        $content -> appendChild(<x:frag>
+                                  <td class="number rank">
+                                    {$user['ranking']}
+                                  </td>
+                                  <ui:user:normal user={$user} />
+                                </x:frag>);
+        foreach ($columns as $column) {
+            $content -> appendChild(<td class="number score">
+                                      {(int)$user[$column]}
+                                    </td>);
+        }
+        $content -> appendChild(<td class="number score">
+                                {(int)$user['score']}
+                              </td>);
     }
 
+    $options['total_entries'] = score_get_count(null, null, $round_ids);
+
     if (0 >= count($rankings)) {
         return macro_message('Nici un rezultat inregistrat pentru aceasta runda.');
     } else {
-        return format_table($rankings, $column_infos, $options);
+        $pager =
+          <ui:pager:page-number first_entry={$options['first_entry']} display_entries={$options['display_entries']}
+            total_entries={$options['total_entries']} show_count={true} show_display_entries={true}
+            prefix="rankings_"/>;
+
+        return
+          <x:frag>
+            {$pager}
+            <ui:table sortable={true} cols={count($columns) + 3} >
+              {$header}
+              {$content}
+            </ui:table>
+            {$pager}
+          </x:frag>;
     }
 }
 
Index: www/macros/macro_remotebox.php
===================================================================
--- www/macros/macro_remotebox.php	(revision 1164)
+++ www/macros/macro_remotebox.php	(working copy)
@@ -17,13 +17,15 @@ function macro_remotebox($url, $bypass_security = false) {
         return macro_error('Expecting argument `url`');
     }
 
-    $buffer = '';
-    $buffer .= '<div id="remotebox">remote content</div>';
-    $buffer .= '<script type="text/javascript">RemoteBox_Url="';
-    $buffer .= html_escape($url);
-    $buffer .= '";</script>';
+    $remotebox =
+      <x:frag>
+        <div id="remotebox">remote content</div>
+        <script type="text/javascript">
+          {HTML('RemoteBox_Url="' . html_escape($url) . '"')}
+        </script>
+      </x:frag>;
 
-    return $buffer;
+    return $remotebox;
 }
 
 ?>
Index: www/macros/macro_smfcomments.php
===================================================================
--- www/macros/macro_smfcomments.php	(revision 1164)
+++ www/macros/macro_smfcomments.php	(working copy)
@@ -14,7 +14,7 @@ require_once(IA_ROOT_DIR.'www/macros/macro_remotebox.php');
 //      SmfComments( topic_id="400" display="show" )
 //      SmfComments( topic_id="400" display="hide" max_comm="5")
 function macro_smfcomments($args) {
-    $comments = '<div id="comentarii">';
+    $comments = <div id="comentarii" />;
 
     $topic_id = getattr($args, 'topic_id');
     $display = getattr($args, 'display');
@@ -43,9 +43,7 @@ function macro_smfcomments($args) {
         $url .= '&max_comm=' . $max_comm;
     }
 
-    $comments .= macro_remotebox($url, true);
-    $comments .= '</div>';
-
+    $comments -> appendChild(macro_remotebox($url, true));
     return $comments;
 }
 
Index: www/macros/macro_toprated.php
===================================================================
--- www/macros/macro_toprated.php	(revision 1164)
+++ www/macros/macro_toprated.php	(working copy)
@@ -2,10 +2,12 @@
 
 // FIXME: This should be marged with macro_rankings.php
 
-require_once(IA_ROOT_DIR . "www/format/table.php");
-require_once(IA_ROOT_DIR . "www/format/pager.php");
-require_once(IA_ROOT_DIR . "www/format/format.php");
-require_once(IA_ROOT_DIR . "common/db/score.php");
+require_once(IA_ROOT_DIR . 'www/format/table.php');
+require_once(IA_ROOT_DIR . 'www/format/pager.php');
+require_once(IA_ROOT_DIR . 'www/format/format.php');
+require_once(IA_ROOT_DIR . 'common/db/score.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/pager.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/table.php');
 
 // Displays *interactive* rankings table displaying user *ratings*.
 //
@@ -22,36 +24,48 @@ function macro_toprated($args) {
 
     $rankings = get_users_by_rating_range($options['first_entry'], $options['display_entries'], true);
 
-    $column_infos = array(
-        array(
-            'title' => 'Loc',
-            'key' => 'position',
-            'css_class' => 'number rank',
-        ),
-        array(
-            'title' => 'Nume',
-            'key' => 'full_name',
-            'rowform' => function($row) {
-                return format_user_normal($row['username'], $row['full_name'], $row['rating_cache']);
-            },
-        ),
-        array(
-            'title' => 'Rating',
-            'key' => 'rating_cache',
-            'rowform' => function($row) {
-                return rating_scale($row['rating_cache']);
-            },
-            'css_class' => 'number rating',
-        ),
-    );
-    if (pager_needs_total_entries($options)) {
-        $options['total_entries'] = get_users_by_rating_count();
+    $header =
+      <x:frag>
+        <th class="number rank">
+          Loc
+        </th>
+        Nume
+        <th class="number rating">
+          Rating
+        </th>
+      </x:frag>;
+
+    $content = <x:frag />;
+    foreach ($rankings as $user) {
+        $content -> appendChild(<x:frag>
+                                  <td class="number rank">
+                                    {(int)$user['position']}
+                                  </td>
+                                  <ui:user:normal user={$user} />
+                                  <td class="number rating">
+                                    {(int)rating_scale($user['rating_cache']) }
+                                  </td>
+                                </x:frag>);
     }
+    $options['total_entries'] = get_users_by_rating_count();
 
     if (0 >= count($rankings)) {
         return macro_message('Nici un utilizator cu rating.');
     } else {
-        return format_table($rankings, $column_infos, $options);
+        $pager =
+          <ui:pager:page-number first_entry={$options['first_entry']} display_entries={$options['display_entries']}
+              total_entries={$options['total_entries']} show_count={true} show_display_entries={true}
+              prefix="toprated_" />;
+
+        return
+          <x:frag>
+            {$pager}
+            <ui:table sortable={true} cols={3}>
+              {$header}
+              {$content}
+            </ui:table>
+            {$pager}
+          </x:frag>;
     }
 }
 
Index: www/macros/macro_user.php
===================================================================
--- www/macros/macro_user.php	(revision 1164)
+++ www/macros/macro_user.php	(working copy)
@@ -2,6 +2,7 @@
 
 require_once(IA_ROOT_DIR . 'www/format/format.php');
 require_once(IA_ROOT_DIR . 'common/db/user.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/user.php');
 
 // Display a link to an user.
 // Includes avatar, etc.
@@ -22,14 +23,11 @@ function macro_user($args) {
 
     $type = getattr($args, 'type', 'link');
     if ($type == 'link') {
-        return format_user_link($dbuser['username'], $dbuser['full_name'],
-                                $dbuser['rating_cache']);
+        return <ui:user:link user={$dbuser} />;
     } else if ($type == 'tiny') {
-        return format_user_tiny($dbuser['username'], $dbuser['full_name'],
-                                $dbuser['rating_cache']);
+        return <ui:user:tiny user={$dbuser} />;
     } else if ($type == 'normal') {
-        return format_user_normal($dbuser['username'], $dbuser['full_name'],
-                                  $dbuser['rating_cache']);
+        return <ui:user:normal user={$dbuser} />;
     } else {
         return macro_error("Unknown userlink type \"$type\"");
     }
Index: www/macros/macro_userimage.php
===================================================================
--- www/macros/macro_userimage.php	(revision 1164)
+++ www/macros/macro_userimage.php	(working copy)
@@ -1,18 +1,20 @@
 <?php
 
-require_once(IA_ROOT_DIR.'www/format/format.php');
-require_once(IA_ROOT_DIR.'common/common.php');
-
+require_once(IA_ROOT_DIR . 'www/format/format.php');
+require_once(IA_ROOT_DIR . 'common/common.php');
+require_once(IA_ROOT_DIR . 'common/db/user.php');
+require_once(IA_ROOT_DIR . 'www/url.php');
 /**
  * Returns a an image which links to it's location of a giver username
  * and size
  *
  * @param  array $args      An array containing the user for whom to get the
  *                          avatar as well as the size
- * @return string
+ *
+ * @return :ui:link
  */
 function macro_userimage($args) {
-    $user = $args['user'];
+    $username = $args['user'];
 
     $size_type = $args['size'];
 
@@ -20,6 +22,9 @@ function macro_userimage($args) {
         return macro_error("Unkown size type \"".$size_type."\".");
     }
 
-    return format_link(url_complex("avatar/full/".$user),
-        format_user_avatar($user, $size_type, false), false);
+    $user = user_get_by_username($username);
+    return
+      <ui:link href={url_user_avatar($user)}>
+        <ui:user:avatar user={$user} size={$size_type} />
+      </ui:link>;
 }
Index: www/macros/macros.php
===================================================================
--- www/macros/macros.php	(revision 1164)
+++ www/macros/macros.php	(working copy)
@@ -10,7 +10,13 @@ function get_macro_include_file($macro_name)
 // Format an error message as a html div.
 // Can be returned from macros.
 function macro_error($text, $raw_html = false) {
-    return '<div class="macroError">' . ($raw_html ? $text : html_escape($text)) . '</div>';
+    $error = <div class="macroError" />;
+    if ($raw_html) {
+        $error -> appendChild(<x:frag>HTML($text)</x:frag>);
+    } else {
+        $error -> appendChild(<x:frag> {$text} </x:frag>);
+    }
+    return $error;
 }
 
 // Format message as a html div.
Index: www/static/css/screen.css
===================================================================
--- www/static/css/screen.css	(revision 1164)
+++ www/static/css/screen.css	(working copy)
@@ -158,7 +158,7 @@ The basic layout of the homepage is as follows:
 #main {
     /*float:right;*/
     background: #fff url(../images/main_tile.jpg) repeat-x top;
-    padding: 15px;
+    padding: 8px 16px;
     margin-left: 191px;
     border-left: 1px solid #d0d0d0;
 }
@@ -452,19 +452,17 @@ The basic layout of the homepage is as follows:
 }
 
 /* Breadcrumbs */
-#breadcrumbs {
-    font-size:11px;
-    line-height:2;
-    margin: 0;
-    margin-top: -10px;
+.breadcrumbs {
+    font-size: 11px;
+    line-height: 2;
     border-bottom: 1px solid #f0f0f0;
 }
 
-#breadcrumbs a {
+.breadcrumbs a {
     font-style: italic;
 }
 
-#breadcrumbs .separator {
+.breadcrumbs .separator {
     color: silver;
 }
 
@@ -1266,7 +1264,6 @@ td.rating, th.rating {
     margin-left: 1.2em;
     text-align: left;
     color:#6A6A6B;
-
 }
 
 /* task enumeration */
Index: www/static/js/default.js
===================================================================
--- www/static/js/default.js	(revision 1164)
+++ www/static/js/default.js	(working copy)
@@ -5,10 +5,10 @@
 
 function Page_Init() {
     // fade away flash message
-    var flash = $('flash');
-    if (flash && !hasElementClass(flash, 'flashError')) {
+    var flash = $$('.flash');
+    if (flash[0] && !hasElementClass(flash[0], 'flashError')) {
         var callback = function() {
-            hideElement(flash);
+            hideElement(flash[0]);
         }
         setTimeout(callback, 13000);
     }
Index: www/url.php
===================================================================
--- www/url.php	(revision 1164)
+++ www/url.php	(working copy)
@@ -70,7 +70,25 @@ function url_from_args($args)
 // Here are the specific url functions you should use.
 // Names should should be more or less obvious.
 
-// First: textblocks(wiki pages).
+/**
+ * If we want to get the current page with no options
+ * @return string
+ */
+function url_no_options() {
+    return $_GET['page'];
+}
+
+/**
+ * In case we just want to add options to our current page(or modify them)
+ *
+ * @param  $options  array
+ * @return string
+ */
+function url_options_add($options = array()) {
+    return url_from_args(array_merge($_GET, $options));
+}
+
+// textblocks(wiki pages).
 
 function url_textblock($page_name) {
     return url_complex($page_name, array());
@@ -241,12 +259,13 @@ function url_user_stats($username) {
 /**
  * Returns an url to an user's avatar with a given size
  *
- * @param  string  $username
+ * @param  array   $user
  * @param  string  $size_type
  * @return string
  */
-function url_user_avatar($username, $size_type = "full") {
-    return url_complex("avatar/".$size_type."/".$username);
+function url_user_avatar($user, $size_type = "full") {
+    return url_complex("avatar/" . $size_type . "/" . $user['username'],
+            array('timestamp' => $user['avatar_timestamp']));
 }
 
 function url_unsubscribe($username, $key) {
Index: www/utilities.php
===================================================================
--- www/utilities.php	(revision 1164)
+++ www/utilities.php	(working copy)
@@ -1,6 +1,18 @@
 <?php
 
-require_once(IA_ROOT_DIR."www/url.php");
+require_once(IA_ROOT_DIR . 'www/url.php');
+
+require_once(IA_ROOT_DIR . 'www/xhp/base/init.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ia/base.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ia/sitewide.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ia/sidebar.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ia/calendar.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ia/google_search.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ia/user_count.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ia/server_time.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/breadcrumbs.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/flash_message.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ia/log.php');
 
 // Wrapper around htmlentities which defaults charset to UTF-8
 function html_escape($string, $quote_style = ENT_COMPAT, $charset = "UTF-8")
@@ -22,7 +34,7 @@ function xml_escape($string, $quote_style = ENT_COMPAT, $charset = "UTF-8")
         '&#226;','&#227;','&#228;','&#229;','&#230;','&#231;','&#232;','&#233;',
         '&#234;','&#235;','&#236;','&#237;','&#238;','&#239;','&#240;','&#241;',
         '&#242;','&#243;','&#244;','&#245;','&#246;','&#247;','&#248;','&#249;',
-        '&#250;','&#251;','&#252;','&#253;','&#254;','&#255;', '&#8221;', 
+        '&#250;','&#251;','&#252;','&#253;','&#254;','&#255;', '&#8221;',
         '&#8222;',
     );
     $html = array('&quot;','&amp;','&amp;','&lt;','&gt;','&nbsp;','&iexcl;',
@@ -152,7 +164,7 @@ function http_serve($disk_file_name, $http_file_name, $mime_type = null, $cache_
         }
     }
 
-    // HTTP headers.  
+    // HTTP headers.
     header("Content-Type: {$mime_type}");
     header("Content-Disposition: {$disposition}; filename="
            .urlencode($http_file_name).";");
@@ -193,62 +205,188 @@ function flash_error($message) {
     flash($message, 'flashError');
 }
 
-// Execute a view. Variables in $view are placed in the
-// local namespace as variables. This is the preffered
-// way of calling a template, because globals are not
-// easily accessible.
-function execute_view($view_file_name, $view) {
-    global $identity_user;
-
-    // retrieve recent page history
-    // some pages display it as navigation breadcrumbs
+/**
+ * Composes a XHP object that provides the page frame, containing the default
+ * header, footer, navigation bars, breadcrumbs and flash messages. The object
+ * expects a <ia:content> child containg the main page content to be appended
+ * before rendering.
+ *
+ * @param   string  $title
+ * @param   string  $top_navbar_selected
+ * @param   bool    $hide_sidebar_login_form
+ * @param   string  $charset
+ * @return  :ia:page
+ */
+function default_view_compose($title = null,
+                              $top_navbar_selected = "infoarena",
+                              $hide_sidebar_login_form = false,
+                              $charset = "UTF-8") {
+    // Retrieve recent page history to display as navigation breadcrumbs
     $recent_pages = getattr($_SESSION, '_ia_recent_pages', array());
 
-    // update recent page history
-    $query = url_from_args($_GET);
-    if (!preg_match('/\/(json|plot|changes)\//', $query) && !request_is_post()) {
-        $hashkey = strtolower($query);
-        $recent_pages[$hashkey] = array($query, getattr($view, 'title', $query)); 
+    // Update recent page history
+    $current_page = url_from_args($_GET);
+    if (!request_is_post() &&
+        !preg_match('/\/(json|plot|changes)\//', $current_page)) {
+        $current_page_key = strtolower($current_page);
+        $recent_pages[$current_page_key] =
+            array($current_page, is_null($title) ? $current_page : $title);
         if (5 < count($recent_pages)) {
             array_shift($recent_pages);
         }
         $_SESSION['_ia_recent_pages'] = $recent_pages;
+    } else {
+        $current_page_key = null;
+    }
+
+    // Display flash message if it exists.
+    if (isset($_SESSION['_ia_flash'])) {
+        $flash_message =
+          <ui:flash-message class={getattr($_SESSION, '_ia_flash_class')}>
+            {$_SESSION['_ia_flash']}
+          </ui:flash-message>;
+
+        // Clear flash message.
+        unset($_SESSION['_ia_flash']);
+        if (isset($_SESSION['_ia_flash_class'])) {
+            unset($_SESSION['_ia_flash_class']);
+        }
+    } else {
+        $flash_message = <x:frag />;
     }
 
-    // let view access recent_pages
-    $view['current_url_key'] = strtolower($query);
-    $view['recent_pages'] = $recent_pages;
+    // Add google custom search bar only if not in development mode
+    if (!IA_DEVELOPMENT_MODE) {
+        $google_search = <ia:google-search />;
+    } else {
+        $google_search = <x:frag />;
+    }
+    // Show the login form in the sidebar only if user is not authenticated.
+    // Get the user's unread personal message count if he is.
+    if (identity_is_anonymous()) {
+        $sidebar_login =
+          <ia:sidebar-login
+            show_login_form={!$hide_sidebar_login_form}/>;
+        $user = null;
+        $user_pm_count = null;
+    } else {
+        $sidebar_login = <x:frag />;
+        $user = identity_get_user();
+        $user_pm_count = smf_get_pm_count(identity_get_username());
+    }
+
+    // Compose and return the page.
+    return
+      <ia:page title={$title} user={$user} charset={$charset}>
+        <ia:header />
+        <ia:top-navbar selected={$top_navbar_selected}
+          user_pm_count={$user_pm_count} />
+
+        <ia:left-col>
+          <ia:left-navbar />
+          {$google_search}
+          <ia:calendar />
+          {$sidebar_login}
+          <ia:user-count />
+          <ia:server-time />
+          <ia:sidebar-ad />
+        </ia:left-col>
+
+        <ui:breadcrumbs entries={$recent_pages} current={$current_page_key} />
+        {$flash_message}
+
+        <ia:footer />
+      </ia:page>;
+}
+
+/*
+ * Renders the main page and then dies.
+ */
+
+function execute_render_die($content, $title = null,
+                            $top_navbar_selected = "infoarena",
+                            $hide_sidebar_login_form = false,
+                            $charset = "UTF-8") {
+    $ia_page = default_view_compose($title, $top_navbar_selected,
+                                    $hide_sidebar_login_form, $charset);
+
+    $ia_page -> appendChild(
+      <ia:content>
+        {$content}
+      </ia:content>);
 
-    // give access to request statistics
     if (IA_DEVELOPMENT_MODE) {
+        // Development mode: display current page's log in site footer
         global $execution_stats;
-        $view['execution_stats'] = $execution_stats;
+        log_execution_stats();
+        $buffer = $execution_stats['log_copy'];
+        $ia_page -> appendChild(
+          <ia:log>
+            {$buffer}
+          </ia:log>);
     }
 
-    // expand $view members into global scope
+    echo $ia_page;
+    session_write_close();
+    die();
+}
+/*
+ * DEPRECATED: Please use XHP based views.
+ *
+ * Execute as view and dies. Variables in $view are placed in the local
+ * namespace as variables. This is the preffered way of calling a template,
+ * because globals are not easily accessible.
+ *
+ * @param   string  $view_file_name
+ * @param   array   $view
+ */
+function execute_view_die($view_file_name, $view, $simple = false) {
+    require_once(IA_ROOT_DIR . 'www/views/utilities.php');
+    // Expand $view members into global scope
     $GLOBALS['view'] = $view;
-
     foreach ($view as $view_hash_key => $view_hash_value) {
         if ($view_hash_key == 'view_hash_key') continue;
         if ($view_hash_key == 'view_hash_value') continue;
         if ($view_hash_key == 'view_file_name') continue;
         if ($view_hash_key == 'view') continue;
-        //echo "added $view_hash_key = $view_hash_value into globals";
         $GLOBALS[$view_hash_key] = $view_hash_value;
         $$view_hash_key = $view_hash_value;
     }
 
-    // NOTE: no includes here, unless you want to get
-    // warnings about function redeclaration.
+    if ($simple == true) {
+        include($view_file_name);
+        session_write_close();
+        die();
+        return;
+    }
+
+    $_xhp_page = default_view_compose(
+        getattr($view, 'title'),
+        getattr($view, 'topnav_select', 'infoarena'),
+        getattr($view, 'no_sidebar_login', false),
+        getattr($view, 'charset', 'UTF-8'));
+
+    ob_start();
     include($view_file_name);
-}
+    $rendered = ob_get_clean();
+
+    $_xhp_page->appendChild(
+      <ia:content>
+        {HTML($rendered)}
+      </ia:content>);
 
-// Execute view and then die.
-function execute_view_die($view_file_name, $view) {
-    execute_view($view_file_name, $view);
     if (IA_DEVELOPMENT_MODE) {
+        // Development mode: display current page's log in site footer
+        global $execution_stats;
         log_execution_stats();
+        $buffer = $execution_stats['log_copy'];
+        $_xhp_page -> appendChild(
+          <ia:log>
+            {$buffer}
+          </ia:log>);
     }
+
+    echo $_xhp_page;
     session_write_close();
     die();
 }
Index: www/views/account.php
===================================================================
--- www/views/account.php	(revision 1164)
+++ www/views/account.php	(working copy)
@@ -91,7 +91,7 @@ if (array_key_exists('security_level', $form_values)) {
         <li>
             <?php
                 // display avatar
-                $avatar_url = url_user_avatar($user['username'], "big");
+                $avatar_url = url_user_avatar($user, "big");
                 echo '<img class="avatar" src="'.html_escape($avatar_url).'" alt="avatar"/>';
             ?>
         </li>
Index: www/views/blog_index.php
===================================================================
--- www/views/blog_index.php	(revision 1164)
+++ www/views/blog_index.php	(working copy)
@@ -40,6 +40,7 @@ foreach ($subpages as $subpage) {
     echo '&nbsp;<a href="'.url_textblock($subpage['name']).'#comentarii">Comentarii ('.$subpage['comment_count'].')</a>';
     echo '</p>';
 
+    // FIXME: Use better words for classes maybe?
     // Also display tags
     echo '<div class="strap">';
     echo '<strong>Categorii: </strong>';
Index: www/views/blog_view.php
===================================================================
--- www/views/blog_view.php	(revision 1164)
+++ www/views/blog_view.php	(working copy)
@@ -2,6 +2,7 @@
 
 require_once(IA_ROOT_DIR.'www/wiki/wiki.php');
 require_once(IA_ROOT_DIR.'www/macros/macro_smfcomments.php');
+require_once(IA_ROOT_DIR.'www/xhp/ia/blog.php');
 
 // site header
 include('header.php');
@@ -9,6 +10,7 @@ include('header.php');
 // wiki page header (actions)
 include('textblock_header.php');
 
+echo <ia:blog:post textblock={$textblock}/>;
 // blog sidebar
 echo '<div class="blog-sidebar">';
 wiki_include(IA_BLOG_SIDEBAR);
@@ -20,10 +22,15 @@ if (getattr($view, 'revision')) {
 }
 
 // blog content
-echo '<div class="wiki_text_block">';
 echo '<div class="blog">';
+echo '<div class="wiki_text_block">';
 $text = wiki_process_textblock($textblock);
-echo hijack_title($text, null, $textblock['title']);
+// FIXME:
+// Why do we need to hijack title to remove links? It's obvious the ones writing blog
+// posts won't put links there and even if that would happen this hijack would render
+// something like <h1> &lt;a href=.....
+
+//echo hijack_title($text, null, $textblock['title']);
 echo $text;
 echo '<div class="strap">';
 echo '<strong>Categorii: </strong>';
Index: www/views/footer.php
===================================================================
--- www/views/footer.php	(revision 1164)
+++ www/views/footer.php	(working copy)
@@ -1,12 +1 @@
 <?php
-require_once(IA_ROOT_DIR.'www/views/sitewide.php');
-?>
-</div>
-</div>
-</div>
-
-<?php ia_template_footer(); ?>
-
-</body>
-</html>
-
Index: www/views/form_login.php
deleted file mode 100644
===================================================================
--- www/views/form_login.php	(revision 1164)
+++ /dev/null	(working copy)
@@ -1,26 +0,0 @@
-<form action="<?= html_escape(url_login()) ?>" method="post" class="login">
-<fieldset>
-    <legend><img src="<?= html_escape(url_static('images/icons/login.png')) ?>" alt="!" /> Autentificare</legend>
-    <ul class="form">
-<?= view_form_field_li(array(
-        'name' => 'Cont de utilizator',
-        'type' => 'string',
-        'access_key' => 'c',
-), 'username') ?>
-<?= view_form_field_li(array(
-        'name' => 'Parola',
-        'type' => 'string',
-        'is_password' => true,
-        'access_key' => 'p',
-), 'password') ?>
-        <li>
-            <input type="checkbox" value="on" id="form_remember" name="remember" class="checkbox"<?= fval('remember') ? ' checked="checked"' : '' ?>/>
-            <label class="checkbox" for="form_remember">Pastreaza-ma autentificat 5 zile</label>
-        </li>
-        <li>
-            <input type="submit" value="Autentificare" id="form_submit" class="button important" />
-        </li>
-    </ul>
-</fieldset>
-</form>
-
Index: www/views/google_search.php
deleted file mode 100644
===================================================================
--- www/views/google_search.php	(revision 1164)
+++ /dev/null	(working copy)
@@ -1,12 +0,0 @@
-<!-- Google CSE Search Box Begins -->
-  <form id="searchbox_010130381492294265836:kw-fmmvpxco" action="http://infoarena.ro/search">
-  <fieldset>
-  <legend><img src="<?= html_escape(url_static('images/icons/search.png')) ?>" alt="!" /> Cautare</legend>
-    <input type="hidden" name="cx" value="010130381492294265836:kw-fmmvpxco" />
-    <input type="hidden" name="cof" value="FORID:9" />
-    <input name="q" type="text" size="22" />
-    <input type="submit" name="sa" value="Cauta" class="button important"/>
-  </fieldset>
-  </form>
-  <script type="text/javascript" src="http://www.google.com/coop/cse/brand?form=searchbox_010130381492294265836%3Akw-fmmvpxco"></script>
-<!-- Google CSE Search Box Ends -->
Index: www/views/header.php
===================================================================
--- www/views/header.php	(revision 1164)
+++ www/views/header.php	(working copy)
@@ -1,188 +1 @@
 <?php
-
-require_once(IA_ROOT_DIR.'www/views/sitewide.php');
-require_once(IA_ROOT_DIR.'www/views/utilities.php');
-require_once(IA_ROOT_DIR.'www/macros/macro_calendar.php');
-
-// Basic view checks.
-log_assert(is_array($view));
-log_assert(is_string($view['title']));
-
-// Check forms.
-if (isset($form_errors) || isset($form_values)) {
-    log_assert(is_array($view['form_errors']));
-    log_assert(is_array($view['form_values']));
-    foreach ($form_values as $k => $v) {
-        if (html_escape($k) != $k) {
-            log_error("Form field $k contains special html chars.");
-        }
-    }
-}
-
-header("Content-type: text/html; charset=utf-8");
-?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-<?php
-    // Hack to insert meta description and keywords for home page.
-    // Description should get us a better snippet for keywords that hit our
-    // home page. If this proves to be effective we should find a way to
-    // include meta descriptions for the most visited pages (can we do it with
-    // a macro?).
-    if (getattr($view, 'page_name') == "home") {
-?>
-    <meta name="Description" content="Concursuri de programare, Stiri si articole de informatica, Comunitate online. Arhiva de probleme, Evaluare 24/24, Forum, Resurse educationale, Pregatire pentru olimpiada." />
-    <meta name="keywords" content="Cocursuri, Informatica, Programare, Comunitate, Algoritmi, Articole, Evaluare, Pregatire" />
-    <meta name="verify-v1" content="j9UCDYvsDL2pLtkJDDkE4HnHVmXakgvz30vOyIJ+6cI=" />
-    <meta name="verify-v1" content="ac36ilLp6y4xp71sJgZEjFMgow6YCLkyQLrG/b2iT/Q=" />
-    <meta name="verify-v1" content="PQDTb5Advw297iADXVUYuxh0z+iQKfq1wtYWnfHCb1Y=" />
-    <meta name="verify-v1" content="GUKPcDm0TzwAR7r5xbagq576p/YWH9su/Ca4o8YlYBg=" /> <!--bogdan2412-->
-    <meta name="google-site-verification" content="T_HFYNIO3S70696yFC5rkbPn339gjnfVwMqYPmU866I" /> <!--devilkind-->
-<?php
-    }
-?>
-    <title><?= html_escape(getattr($view, 'title')) ?></title>
-
-    <link type="text/css" rel="stylesheet" href="<?= html_escape(url_static('css/sitewide.css')) ?>"/>
-    <link type="text/css" rel="stylesheet" href="<?= html_escape(url_static('css/iconize.css')) ?>"/>
-    <link type="text/css" rel="stylesheet" href="<?= html_escape(url_static('css/screen.css')) ?>"/>
-    <link type="text/css" rel="stylesheet" href="<?= html_escape(url_static('css/tabber.css')) ?>"/>
-    <link type="text/css" rel="stylesheet" href="<?= html_escape(url_static('css/sh/shCore.css')) ?>"/>
-    <link type="text/css" rel="stylesheet" href="<?= html_escape(url_static('css/sh/shThemeDefault.css')) ?>"/>
-    <link type="text/css" rel="stylesheet" href="<?= html_escape(url_static('css/print.css')) ?>" media="print" />
-    <link rel="icon" href="<?= IA_URL."favicon.ico" ?>" type="image/vnd.microsoft.icon" />
-    <script type="text/javascript" src="<?= html_escape(url_static('js/config.js.php')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/MochiKit.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/default.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/tabber-minimized.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/submit.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/remotebox.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/postdata.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/sh/shCore.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/sh/shBrushCpp.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/sh/shBrushDelphi.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/sh/shBrushJava.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/sh/shBrushPython.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/sh/shInit.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/tags.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/roundtimer.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/restoreparity.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/foreach.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/sorttable.js')) ?>"></script>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/tablednd.js')) ?>"></script>
-
-    <script type="text/javascript">Sh_Init("<?= html_escape(url_static('swf/clipboard.swf')) ?>")</script>
-
-<?php
-    if (request("action") == 'rating') {
-?>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/swfobject.js')) ?>"></script>
-<?php
-    }
-?>
-
-    <?= getattr($view, 'head') ?>
-</head>
-<body id="infoarena" <?= getattr($view, 'body_onload') ? ' onload="' . html_escape(getattr($view, 'body_onload')) . '"' : '' ?>>
-<div id="page">
-
-<?php
-if (!isset($topnav_select)) {
-    $topnav_select = 'infoarena';
-}
-ia_template_header();
-$smf_admin = ('admin' == getattr($identity_user, 'security_level'));
-ia_template_topnav($topnav_select, $smf_admin);
-?>
-
-<div id="content_small" class="clear">
-<div id="sidebar">
-    <ul id="nav" class="clear">
-        <li><a href="<?= html_escape(url_home()) ?>">Home</a></li>
-        <li><?= format_link_access(url_textblock('arhiva'), "Arhiva de probleme", 'a') ?></li>
-        <li><a href="<?= html_escape(url_textblock('arhiva-educationala')) ?>">Arhiva educatională</a></li>
-        <li><a href="<?= html_escape(url_textblock('concursuri')) ?>">Concursuri</a></li>
-        <li><a href="<?= html_escape(url_textblock('concursuri-virtuale')) ?>">Concursuri virtuale</a></li> 
-        <li><a href="<?= html_escape(url_textblock('clasament-rating')) ?>">Clasament</a></li>
-        <li><a href="<?= html_escape(url_textblock('articole')) ?>">Articole</a></li>
-        <li><a href="<?= html_escape(url_textblock('downloads')) ?>">Downloads</a></li>
-        <li><a href="<?= html_escape(url_textblock('links')) ?>">Links</a></li>
-        <li><a href="<?= html_escape(url_textblock('documentatie')) ?>">Documentaţie</a></li>
-        <li><a href="<?= html_escape(url_textblock('despre-infoarena')) ?>">Despre infoarena</a></li>
-        <li class="separator"><hr/></li>
-        <li><?= format_link_access(url_monitor(array('user' => identity_get_username())), "Monitorul de evaluare", 'm') ?></li>
-        <?php if (!identity_is_anonymous()) { ?>
-        <li><a href="<?= html_escape(url_submit()) ?>"><strong>Trimite soluţii</strong></a></li>
-        <li><?= format_link_access(url_account(), "Contul meu", 'c') ?></li>
-        <?php } ?>
-        </ul>
-
-    <?php if (!IA_DEVELOPMENT_MODE) { ?>
-    <div id="google-search">
-        <?php include(IA_ROOT_DIR.'www/views/google_search.php'); ?>
-    </div>
-    <?php } ?>
-
-    <div id="calendar">
-        <?= macro_calendar(array()) ?>
-    </div>
-
-    <?php if (identity_is_anonymous()) { ?>
-    <div id="login">
-        <?php if (!isset($no_sidebar_login)) include(IA_ROOT_DIR.'www/views/form_login.php') ?>
-        <p>
-        <?= format_link(url_register(), "Ma inregistrez!" ) ?><br/>
-        <?= format_link(url_resetpass(), "Mi-am uitat parola..." ) ?>
-        </p>
-    </div>
-    <?php } ?>
-    <p class="user-count"><?php echo user_count(); ?> membri inregistrati</p>
-    <div id="srv_time" class="user-count" align="center"></div>
-    <script type="text/javascript" src="<?= html_escape(url_static('js/time.js')) ?>"></script>
-    <script type="text/javascript">loadTime(<?= format_date(null, "%H, %M, %S");?>);</script>
-
-    <?php include(IA_ROOT_DIR.'www/views/sidebar_ad.php'); ?>
-</div>
-
-<div id="main">
-<?php
-
-// breadcrumbs with recent pages
-if (isset($recent_pages) && (1 < count($recent_pages))) {
-    $bstring = '';
-    foreach ($recent_pages as $rec_key => $rec_entry) {
-        list($rec_url, $rec_title) = $rec_entry;
-
-        $rec_title = html_escape($rec_title);
-
-        if ($bstring) {
-            $bstring .= ' <span class="separator">|</span> ';
-        }
-        if ($current_url_key == $rec_key) {
-            $bstring .= "<strong>{$rec_title}</strong>";
-        }
-        else {
-            $bstring .= "<a href=\"" . html_escape($rec_url) . "\">{$rec_title}</a>";
-        }
-    }
-    echo '<p id="breadcrumbs">Pagini recente &raquo; ' . $bstring . '</p>';
-}
-
-?>
-
-<?php
-    // display flash message
-    if (isset($_SESSION['_ia_flash'])) { ?>
-
-<div id="flash" class="flash <?= html_escape(getattr($_SESSION, '_ia_flash_class')) ?>"><?= html_escape($_SESSION['_ia_flash']) ?></div>
-
-<?php
-        // clear flash message
-        unset($_SESSION['_ia_flash']);
-        if (isset($_SESSION['_ia_flash_class'])) {
-            unset($_SESSION['_ia_flash_class']);
-        }
-    }
-?>
Index: www/views/login.php
===================================================================
--- www/views/login.php	(revision 1164)
+++ www/views/login.php	(working copy)
@@ -6,7 +6,7 @@
 <?= format_link(url_register(), "inregistra aici") ?>;
 daca ti-ai uitat parola, o poti <a href="<?= html_escape(url_resetpass()) ?>">reseta aici</a>.</p>
 
-<?php include(IA_ROOT_DIR.'www/views/form_login.php'); ?>
+<?php echo <ia:login_form />; ?>
 
 <?php wiki_include('template/login'); ?>
 
Index: www/views/projector.php
===================================================================
--- www/views/projector.php	(revision 1164)
+++ www/views/projector.php	(working copy)
@@ -1,6 +1,5 @@
 <?php
 
-require_once(IA_ROOT_DIR.'www/views/sitewide.php');
 require_once(IA_ROOT_DIR.'www/format/table.php');
 require_once(IA_ROOT_DIR.'www/format/format.php');
 require_once(IA_ROOT_DIR.'www/format/list.php');
Index: www/views/sidebar_ad.php
deleted file mode 100644
===================================================================
--- www/views/sidebar_ad.php	(revision 1164)
+++ /dev/null	(working copy)
@@ -1,10 +0,0 @@
-<div class="ad">
-<?php
-$sidebar = textblock_get_revision(IA_SIDEBAR_PAGE);
-if ($sidebar) {
-    echo '<div class="wiki_text_block">';
-    echo wiki_process_textblock($sidebar);
-    echo '</div>';
-}
-?>
-</div>
Index: www/views/sitewide.php
deleted file mode 100644
===================================================================
--- www/views/sitewide.php	(revision 1164)
+++ /dev/null	(working copy)
@@ -1,167 +0,0 @@
-<?php
-
-require_once(IA_ROOT_DIR."www/format/format.php");
-
-// site-wide templates (templates shared with SMF / search)
-//
-// This file may be included from different environments
-// (currently SMF and infoarena website) so it can use only
-// limited application logic.
-
-// display site header
-function ia_template_header() {
-    global $identity_user;
-?>
-<div id="header" class="clear">
-    <?php if (!identity_is_anonymous()) { $username = $identity_user['username']; ?>
-        <div id="userbox">
-        <?= format_link(url_user_profile($username, true), format_user_avatar($username, "normal", true), false) ?>
-            <div class="user">
-                <strong><?= html_escape($identity_user['full_name']) ?></strong><br/>
-                <?= format_user_ratingbadge($username, $identity_user['rating_cache']) ?>
-                <?= format_link_access(url_user_profile($username, true), $username, 'p') ?><br/>
-                <?= format_post_link(url_logout(), "logout", array(), true, array('class' => 'logout')) ?> |
-                <?= format_link_access(url_account(), 'contul meu', 'c') ?>
-            </div>
-        </div>
-    <?php } ?>
-    <?php if (IA_DEVELOPMENT_MODE) { ?>
-        <div id="dev_warning">
-            Bravely working in development mode&hellip;<br/>Keep it up!
-        </div>
-    <?php } ?>
-
-    <h1><?= format_link(url_home(), "infoarena informatica de performanta") ?></h1>
-</div>
-<?php
-}
-
-// display main navigation bar
-function ia_template_topnav($selected = 'infoarena', $smf_admin = false) {
-    global $identity_user;
-
-    $pre = array($selected => '<strong>');
-    $post = array($selected => '</strong>');
-?>
-<div id="topnav">
-<ul>
-    <li>
-        <?= getattr($pre, 'infoarena') ?>
-        <?= format_link(url_home(), 'info<em>arena</em>', false) ?>
-        <?= getattr($post, 'infoarena') ?>
-    </li>
-    <li>
-        <?= getattr($pre, 'blog') ?>
-        <?= format_link_access(url_blog(), "blog", 'b') ?>
-        <?= getattr($post, 'blog') ?>
-    </li>
-    <li>
-        <?= getattr($pre, 'forum') ?>
-        <?= format_link_access(url_forum(), "forum", 'f') ?>
-        <?= getattr($post, 'forum') ?>
-    </li>
-    <li>
-        <?= getattr($pre, 'calendar') ?>
-        <?= format_link(url_forum() . "?action=calendar", "calendar") ?>
-        <?= getattr($post, 'calendar') ?>
-    </li>
-<?php if (identity_is_anonymous()) { ?>
-    <li>
-        <?= getattr($pre, 'login')?>
-        <?= format_link(url_login(), "autentificare") ?>
-        <?= getattr($post, 'login') ?>
-    </li>
-    <li>
-        <?= getattr($pre, 'register')?>
-        <?= format_link(url_register(), "inregistrare") ?>
-        <?= getattr($post, 'register') ?>
-    </li>
-<?php } else { ?>
-    <li>
-        <?= getattr($pre, 'profile') ?>
-        <?= format_link_access(url_user_profile($identity_user['username']), 'profilul meu', 'p') ?>
-        <?= getattr($post, 'profile') ?></li>
-    <li>
-        <?= getattr($pre, 'pm') ?>
-	<?php
-        $new_pm_count = smf_get_pm_count($identity_user['username']);
-        if ($new_pm_count) { ?>
-            <?= format_link(url_forum() . "?action=pm", "<b>mesaje (".$new_pm_count.")</b>", false) ?>
-	<?php } else { ?>
-            <?= format_link(url_forum() . "?action=pm", "mesaje") ?>
-	<?php } ?>
-        <?= getattr($post, 'pm') ?>
-    </li>
-<?php if ($smf_admin) { ?>
-    <li>
-        <?= getattr($pre, 'smf_admin') ?>
-        <?= format_link(url_forum() . "?action=admin", "forum admin") ?>
-        <?= getattr($post, 'smf_admin') ?>
-    </li>
-<?php } ?>
-<?php } ?>
-</ul>
-</div>
-
-<?php
-}
-
-function ia_template_footer() {
-?>
-<div id="footer">
-    <ul class="clear">
-        <li class="copyright">&copy;&nbsp;2004-<?= date("Y") ?>&nbsp;<?= format_link(url_textblock('Asociatia-infoarena'), "Asociatia infoarena") ?></li>
-        <li class="separate"><?= format_link(url_home(), "Prima pagina") ?></li>
-        <li><?= format_link(url_textblock("despre-infoarena"), "Despre infoarena") ?></li>
-        <li><?= format_link(url_textblock("termeni-si-conditii"), "Termeni si conditii") ?></li>
-        <li><?= format_link(url_textblock("contact"), "Contact") ?></li>
-        <li class="top"><a href="#header">Sari la inceputul paginii &uarr;</a></li>
-    </ul>
-<?php if (!IA_DEVELOPMENT_MODE) { ?>
-    <p class="cc">
-    <!--Creative Commons License-->
-    <a class="badge" rel="license" href="http://creativecommons.org/licenses/by-nc/2.5/"><img alt="Creative Commons License" src="<?= url_static('images/CreativeCommonsBadge.png') ?>"/></a>
-    Cu exceptia cazurilor in care se specifica altfel, continutul site-ului infoarena<br/>este publicat sub licenta <a rel="license" href="http://creativecommons.org/licenses/by-nc/2.5/">Creative Commons Attribution-NonCommercial 2.5</a>.
-    <!--/Creative Commons License-->
-    <rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
-        <Work rdf:about="">
-            <license rdf:resource="http://creativecommons.org/licenses/by-nc/2.5/" />
-        </Work>
-        <License rdf:about="http://creativecommons.org/licenses/by-nc/2.5/">
-            <permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
-            <permits rdf:resource="http://web.resource.org/cc/Distribution"/>
-            <requires rdf:resource="http://web.resource.org/cc/Notice"/>
-            <requires rdf:resource="http://web.resource.org/cc/Attribution"/>
-            <prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/>
-            <permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
-        </License>
-    </rdf:RDF>
-    </p>
-<?php
-    }
-    else {
-        // Development mode: display current page's log in site footer
-        global $execution_stats;
-        log_execution_stats();
-        $buffer = $execution_stats['log_copy'];
-        echo '<textarea id="log" rows="50" cols="80">';
-        echo html_escape($buffer);
-        echo '</textarea>';
-    }
-?>
-</div>
-
-<?php if (!IA_DEVELOPMENT_MODE) { ?>
-    <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
-    </script>
-    <script type="text/javascript">
-    _uacct = "UA-113289-8";
-    _udn = "infoarena.ro";
-    urchinTracker();
-    </script>
-<?php } ?>
-
-<?php
-}
-
-?>
Index: www/views/textblock_header.php
===================================================================
--- www/views/textblock_header.php	(revision 1164)
+++ www/views/textblock_header.php	(working copy)
@@ -37,7 +37,7 @@ log_assert_valid(textblock_validate($textblock));
 </li>
 <?php } ?>
 <?php if (identity_can('textblock-attach', $textblock)) { ?>
-<li><?= format_link_access(url_attachment_new($textblock['name']), 'Ataşează', 'a') ?></li>
+<li><?= format_link_access(url_attachment_new($textblock['name']), 'Ataşează', 't') ?></li>
 <?php } ?>
 <?php if (identity_can('textblock-list-attach', $textblock)) { ?>
 <li><?= format_link_access(url_attachment_list($textblock['name']), 'Listează ataşamente', 'l') ?></li>
Index: www/views/textblock_view.php
===================================================================
--- www/views/textblock_view.php	(revision 1164)
+++ www/views/textblock_view.php	(working copy)
@@ -1,6 +1,7 @@
 <?php
 
 require_once(IA_ROOT_DIR.'www/wiki/wiki.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/textblock.php');
 
 // site header
 include('header.php');
@@ -16,14 +17,13 @@ if (getattr($view, 'revision')) {
 // textblock content
 echo '<div class="wiki_text_block">';
 echo wiki_process_textblock($textblock);
-echo '</div>';
 
 // page comments
 if (getattr($view, 'forum_topic')) {
     require_once(IA_ROOT_DIR.'www/macros/macro_smfcomments.php');
     echo macro_smfcomments(array('topic_id' => $view['forum_topic'], 'display' => 'hide'));
 }
-
+echo '</div>';
 // site footer
 include('footer.php');
 
Index: www/xhp/base/core.php
new file mode 100644
===================================================================
--- www/xhp/base/core.php	(revision 0)
+++ www/xhp/base/core.php	(working copy)
@@ -0,0 +1,779 @@
+<?php
+/*
+  +----------------------------------------------------------------------+
+  | XHP                                                                  |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2009 - 2010 Facebook, Inc. (http://www.facebook.com)          |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE.PHP, and is    |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt                                  |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+*/
+
+abstract class :x:base {
+  abstract public function __construct();
+  abstract public function appendChild($child);
+  abstract public function getAttribute($attr);
+  abstract public function setAttribute($attr, $val);
+  abstract public function categoryOf($cat);
+  abstract public function __toString();
+  abstract protected static function &__xhpAttributeDeclaration();
+  abstract protected function &__xhpCategoryDeclaration();
+  abstract protected function &__xhpChildrenDeclaration();
+
+  /**
+   * Enabling validation will give you stricter documents; you won't be able to
+   * do many things that violate the XHTML 1.0 Strict spec. It is recommend that
+   * you leave this on because otherwise things like the `children` keyword will
+   * do nothing. This validation comes at some CPU cost, however, so if you are
+   * running a high-traffic site you will probably want to disable this in
+   * production. You should still leave it on while developing new features,
+   * though.
+   */
+  public static $ENABLE_VALIDATION = true;
+
+  final protected static function renderChild($child) {
+    if ($child instanceof :x:base) {
+      return $child->__toString();
+    } else if ($child instanceof HTML) {
+      return $child->render();
+    } else if (is_array($child)) {
+      throw new XHPRenderArrayException('Can not render array!');
+    } else {
+      return htmlspecialchars((string)$child);
+    }
+  }
+
+  public static function element2class($element) {
+    return 'xhp_'.str_replace(array(':', '-'), array('__', '_'), $element);
+  }
+
+  public static function class2element($class) {
+    return str_replace(array('__', '_'), array(':', '-'), preg_replace('#^xhp_#i', '', $class));
+  }
+}
+
+abstract class :x:composable-element extends :x:base {
+  private
+    $attributes,
+    $children;
+
+  // Private constants indicating the declared types of attributes
+  const TYPE_STRING = 1;
+  const TYPE_BOOL   = 2;
+  const TYPE_NUMBER = 3;
+  const TYPE_ARRAY  = 4;
+  const TYPE_OBJECT = 5;
+  const TYPE_VAR    = 6;
+  const TYPE_ENUM   = 7;
+  const TYPE_FLOAT  = 8;
+
+  protected function init() {}
+
+  /**
+   * A new :x:composable-element is instantiated for every literal tag
+   * expression in the script.
+   *
+   * The following code:
+   * $foo = <foo attr="val">bar</foo>;
+   *
+   * will execute something like:
+   * $foo = new xhp_foo(array('attr' => 'val'), array('bar'));
+   *
+   * @param $attributes    map of attributes to values
+   * @param $children      list of children
+   */
+  final public function __construct($attributes, $children) {
+    if ($attributes) {
+      foreach ($attributes as $key => &$val) {
+        $this->validateAttributeValue($key, $val);
+      }
+      unset($val);
+    }
+    $this->attributes = $attributes;
+    $this->children = array();
+    foreach ($children as $child) {
+      $this->appendChild($child);
+    }
+    if (:x:base::$ENABLE_VALIDATION) {
+      // There is some cost to having defaulted unused arguments on a function
+      // so we leave these out and get them with func_get_args().
+      $args = func_get_args();
+      if (isset($args[2])) {
+        $this->source = "$args[2]:$args[3]";
+      } else {
+        $this->source =
+          'You have ENABLE_VALIDATION on, but debug information is not being ' .
+          'passed to XHP objects correctly. Ensure xhp.include_debug is on ' .
+          'in your PHP configuration. Without this option enabled, ' .
+          'validation errors will be painful to debug at best.';
+      }
+    }
+    $this->init();
+  }
+
+  /**
+   * Adds a child to the end of this node. If you give an array to this method
+   * then it will behave like a DocumentFragment.
+   *
+   * @param $child     single child or array of children
+   */
+  final public function appendChild($child) {
+    if (is_array($child)) {
+      foreach ($child as $c) {
+        $this->appendChild($c);
+      }
+    } else if ($child instanceof :x:frag) {
+      $this->children = array_merge($this->children, $child->children);
+    } else if ($child !== null) {
+      $this->children[] = $child;
+    }
+    return $this;
+  }
+
+  /**
+   * Fetches all direct children of this element that match a particular tag
+   * name (or all children if no tag is given)
+   *
+   * @param $tag_name   tag name (optional)
+   * @return array
+   */
+   final protected function getChildren($tag_name = null) {
+     if (!$tag_name) {
+       return $this->children;
+     }
+
+     $tag_name = :x:base::element2class($tag_name);
+     $ret = array();
+     foreach ($this->children as $child) {
+       if ($child instanceof $tag_name) {
+         $ret[] = $child;
+       }
+     }
+     return $ret;
+   }
+
+  /**
+   * Fetches an attribute from this elements attribute store. If $attr is not
+   * defined in the store, and $default is null an exception will be thrown. An
+   * exception will also be thrown if $attr is not supported -- see
+   * `supportedAttributes`
+   *
+   * @param $attr      attribute to fetch
+   * @return           value
+   */
+  final public function getAttribute($attr) {
+
+    // Return attribute if it's there, otherwise default or exception.
+    if (isset($this->attributes[$attr])) {
+      return $this->attributes[$attr];
+    }
+
+    // Get the declaration on miss
+    $decl = $this->__xhpAttributeDeclaration();
+
+    if (!isset($decl[$attr])) {
+      throw new XHPAttributeNotSupportedException($this, $attr);
+    } else if (!empty($decl[$attr][3])) {
+      throw new XHPAttributeRequiredException($this, $attr);
+    } else {
+      $decl = $this->__xhpAttributeDeclaration();
+      return $decl[$attr][2];
+    }
+  }
+
+  final protected function getAttributes() {
+    return $this->attributes;
+  }
+
+  /**
+   * Sets an attribute in this element's attribute store. An exception will be
+   * thrown if $attr is not supported -- see `supportedAttributes`.
+   *
+   * @param $attr      attribute to set
+   * @param $val       value
+   */
+  final public function setAttribute($attr, $val) {
+    $this->validateAttributeValue($attr, $val);
+    $this->attributes[$attr] = $val;
+    return $this;
+  }
+
+  final protected function __flushElementChildren() {
+
+    // Flush all :x:base elements to x:primitive's
+    $ln = count($this->children);
+    for ($ii = 0; $ii < $ln; ++$ii) {
+      $child = $this->children[$ii];
+      if ($child instanceof :x:element) {
+        do {
+          if (:x:base::$ENABLE_VALIDATION) {
+            $child->validateChildren();
+          }
+          $child = $child->render();
+        } while ($child instanceof :x:element);
+
+        if (!($child instanceof :x:primitive)) {
+          throw new XHPCoreRenderException($this->children[$ii], $child);
+        }
+
+        if ($child instanceof :x:frag) {
+          array_splice($this->children, $ii, 1, $child->children);
+          $ln = count($this->children);
+          --$ii;
+        } else {
+          $this->children[$ii] = $child;
+        }
+      }
+    }
+  }
+
+  /**
+   * Defined in elements by the `attribute` keyword. The declaration is simple.
+   * There is a keyed array, with each key being an attribute. Each value is
+   * an array with 4 elements. The first is the attribute type. The second is
+   * meta-data about the attribute. The third is a default value (null for
+   * none). And the fourth is whether or not this value is required.
+   *
+   * Attribute types are suggested by the TYPE_* constants.
+   */
+  protected static function &__xhpAttributeDeclaration() {
+    static $_ = array();
+    return $_;
+  }
+
+  /**
+   * Defined in elements by the `category` keyword. This is just a list of all
+   * categories an element belongs to. Each category is a key with value 1.
+   */
+  protected function &__xhpCategoryDeclaration() {
+    static $_ = array();
+    return $_;
+  }
+
+  /**
+   * Defined in elements by the `children` keyword. This returns a pattern of
+   * allowed children. The return value is potentially very complicated. The
+   * two simplest are 0 and 1 which mean no children and any children,
+   * respectively. Otherwise you're dealing with an array which is just the
+   * biggest mess you've ever seen.
+   */
+  protected function &__xhpChildrenDeclaration() {
+    static $_ = 1;
+    return $_;
+  }
+
+  /**
+   * Throws an exception if $val is not a valid value for the attribute $attr
+   * on this element.
+   */
+  final protected function validateAttributeValue($attr, &$val) {
+    $decl = $this->__xhpAttributeDeclaration();
+    if (!isset($decl[$attr])) {
+      throw new XHPAttributeNotSupportedException($this, $attr);
+    }
+    if ($val === null) {
+      return;
+    }
+    switch ($decl[$attr][0]) {
+      case self::TYPE_STRING:
+        $val = (string)$val;
+        return;
+
+      case self::TYPE_BOOL:
+        if (!is_bool($val)) {
+          if ($val === "false") {
+            $val = false;
+          } else {
+            $val = (bool)$val;
+          }
+        }
+        return;
+
+      case self::TYPE_NUMBER:
+        if (!is_int($val)) {
+          $val = (int)$val;
+        }
+        return;
+
+      case self::TYPE_FLOAT:
+        if (!is_numeric($val)) {
+          $val = (float)$val;
+        }
+        return;
+
+      case self::TYPE_ARRAY:
+        if (!is_array($val)) {
+          throw new XHPInvalidAttributeException($this, 'array', $attr, $val);
+        }
+        return;
+
+      case self::TYPE_OBJECT:
+        if (!($val instanceof $decl[$attr][1])) {
+          throw new XHPInvalidAttributeException(
+            $this, $decl[$attr][1], $attr, $val
+          );
+        }
+        return;
+
+      // case self::TYPE_VAR: `var` (any type)
+
+      case self::TYPE_ENUM:
+        foreach ($decl[$attr][1] as $enum) {
+          if ($enum === $val) {
+            return;
+          }
+        }
+        $enums = 'enum("' . implode('","', $decl[$attr][1]) . '")';
+        throw new XHPInvalidAttributeException($this, $enums, $attr, $val);
+    }
+  }
+
+  /**
+  * FIXME: IA Hack Does the same thing as the function above but it does not throw any exception
+  */
+  final public function hasAttribute($attribute, $value = null) {
+    try {
+      $this -> validateAttributeValue($attribute, $value);
+      return true;
+    } catch (Exception $exception) {
+      return false;
+    }
+}
+
+  /**
+   * Validates that this element's children match its children descriptor, and
+   * throws an exception if that's not the case.
+   */
+  final protected function validateChildren() {
+    $decl = $this->__xhpChildrenDeclaration();
+    if ($decl === 1) { // Any children allowed
+      return;
+    }
+    if ($decl === 0) { // No children allowed
+      if ($this->children) {
+        throw new XHPInvalidChildrenException($this, 0);
+      } else {
+        return;
+      }
+    }
+    $ii = 0;
+    if (!$this->validateChildrenExpression($decl, $ii) ||
+        $ii < count($this->children)) {
+      // Use of HTML() breaks the content model definition.
+      // Lesson: Don't use HTML().
+      if (isset($this->children[$ii]) && $this->children[$ii] instanceof HTML) {
+        return;
+      }
+      throw new XHPInvalidChildrenException($this, $ii);
+    }
+  }
+
+  final private function validateChildrenExpression($decl, &$index) {
+    switch ($decl[0]) {
+      case 0: // Exactly once -- :fb-thing
+        if ($this->validateChildrenRule($decl[1], $decl[2], $index)) {
+          return true;
+        }
+        return false;
+
+      case 1: // Zero or more times -- :fb-thing*
+        while ($this->validateChildrenRule($decl[1], $decl[2], $index));
+        return true;
+
+      case 2: // Zero or one times -- :fb-thing?
+        if ($this->validateChildrenRule($decl[1], $decl[2], $index));
+        return true;
+
+      case 3: // One or more times -- :fb-thing+
+        if (!$this->validateChildrenRule($decl[1], $decl[2], $index)) {
+          return false;
+        }
+        while ($this->validateChildrenRule($decl[1], $decl[2], $index));
+        return true;
+
+      case 4: // Specific order -- :fb-thing, :fb-other-thing
+        $oindex = $index;
+        if ($this->validateChildrenExpression($decl[1], $index) &&
+            $this->validateChildrenExpression($decl[2], $index)) {
+          return true;
+        }
+        $index = $oindex;
+        return false;
+
+      case 5: // Either or -- :fb-thing | :fb-other-thing
+        if ($this->validateChildrenExpression($decl[1], $index) ||
+            $this->validateChildrenExpression($decl[2], $index)) {
+          return true;
+        }
+        return false;
+    }
+  }
+
+  final private function validateChildrenRule($type, $rule, &$index) {
+    switch ($type) {
+      case 1: // any element -- any
+        if (isset($this->children[$index])) {
+          ++$index;
+          return true;
+        }
+        return false;
+
+      case 2: // pcdata -- pcdata
+        if (isset($this->children[$index]) &&
+            !($this->children[$index] instanceof :x:base)) {
+          ++$index;
+          return true;
+        }
+        return false;
+
+      case 3: // specific element -- :fb-thing
+        if (isset($this->children[$index]) &&
+            $this->children[$index] instanceof $rule) {
+          ++$index;
+          return true;
+        }
+        return false;
+
+      case 4: // element category -- %block
+        if (!isset($this->children[$index]) ||
+            !($this->children[$index] instanceof :x:base)) {
+          return false;
+        }
+        $categories = $this->children[$index]->__xhpCategoryDeclaration();
+        if (empty($categories[$rule])) {
+          return false;
+        }
+        ++$index;
+        return true;
+
+      case 5: // nested rule -- ((:fb-thing, :fb-other-thing)*, :fb:thing-footer)
+        return $this->validateChildrenExpression($rule, $index);
+    }
+  }
+
+  /**
+   * Returns the human-readable `children` declaration as seen in this class's
+   * source code.
+   */
+  final public function __getChildrenDeclaration() {
+    $decl = $this->__xhpChildrenDeclaration();
+    if ($decl === 1) {
+      return 'any';
+    }
+    if ($decl === 0) {
+      return 'empty';
+    }
+    return $this->renderChildrenDeclaration($decl);
+  }
+
+  final private function renderChildrenDeclaration($decl) {
+    switch ($decl[0]) {
+      case 0:
+        return $this->renderChildrenRule($decl[1], $decl[2]);
+
+      case 1:
+        return $this->renderChildrenRule($decl[1], $decl[2]) . '*';
+
+      case 2:
+        return $this->renderChildrenRule($decl[1], $decl[2]) . '?';
+
+      case 3:
+        return $this->renderChildrenRule($decl[1], $decl[2]) . '+';
+
+      case 4:
+        return $this->renderChildrenDeclaration($decl[1]) . ',' .
+          $this->renderChildrenDeclaration($decl[2]);
+
+      case 5:
+        return $this->renderChildrenDeclaration($decl[1]) . '|' .
+          $this->renderChildrenDeclaration($decl[2]);
+    }
+  }
+
+  final private function renderChildrenRule($type, $rule) {
+    switch ($type) {
+      case 1:
+        return 'any';
+
+      case 2:
+        return 'pcdata';
+
+      case 3:
+        return ':' . :x:base::class2element($rule);
+
+      case 4:
+        return '%' . $rule;
+
+      case 5:
+        return '(' . $this->renderChildrenDeclaration($rule) . ')';
+    }
+  }
+
+  /**
+   * Returns a description of the current children in this element. Maybe
+   * something like this:
+   * <div><span>foo</span>bar</div> ->
+   * :span[%inline],pcdata
+   */
+  final public function __getChildrenDescription() {
+    $desc = array();
+    foreach ($this->children as $child) {
+      if ($child instanceof :x:base) {
+        $tmp = ':' . :x:base::class2element(get_class($child));
+        if ($categories = $child->__xhpCategoryDeclaration()) {
+          $tmp .= '[%'. implode(',%', array_keys($categories)) . ']';
+        }
+        $desc[] = $tmp;
+      } else {
+        $desc[] = 'pcdata';
+      }
+    }
+    return implode(',', $desc);
+  }
+
+  final public function categoryOf($c) {
+    $categories = $this->__xhpCategoryDeclaration();
+    return isset($categories[$c]);
+  }
+}
+
+/**
+ * :x:primitive lays down the foundation for very low-level elements. You
+ * should directly :x:primitive only if you are creating a core element that
+ * needs to directly implement stringify(). All other elements should subclass
+ * from :x:element.
+ */
+abstract class :x:primitive extends :x:composable-element {
+  abstract protected function stringify();
+
+  /**
+   *  This isn't __toString() because throwing an exception out of __toString()
+   *  produces a useless, immediate fatal, and allowing XHP to seamlessly cast
+   *  into strings encourages bad practices, like this real snippet:
+   *
+   *    $links .= <a>...</a>;
+   *    $links .= <a>...</a>;
+   *    return HTML($links);
+   *
+   */
+  final public function __toString() {
+
+    // Validate our children
+    $this->__flushElementChildren();
+    if (:x:base::$ENABLE_VALIDATION) {
+      $this->validateChildren();
+    }
+
+    // Render to string
+    return $this->stringify();
+  }
+}
+
+/**
+ * :x:element defines an interface that all user-land elements should subclass
+ * from. The main difference between :x:element and :x:primitive is that
+ * subclasses of :x:element should implement `render()` instead of `stringify`.
+ * This is important because most elements should not be dealing with strings
+ * of markup.
+ */
+abstract class :x:element extends :x:composable-element {
+  final public function __toString() {
+    $that = $this;
+
+    if (:x:base::$ENABLE_VALIDATION) {
+      // Validate the current object
+      $that->validateChildren();
+
+      // And each intermediary object it returns
+      while (($that = $that->render()) instanceof :x:element) {
+        $that->validateChildren();
+      }
+
+      // render() must always return XHPPrimitives
+      if (!($that instanceof :x:composable-element)) {
+        throw new XHPCoreRenderException($this, $that);
+      }
+    } else {
+      // Skip the above checks when not validating
+      while (($that = $that->render()) instanceof :x:element);
+    }
+
+    return $that->__toString();
+  }
+}
+
+/**
+ * :x:composite is a special class which allows you to pass around a node that
+ * acts on another node, but any `appendChild()` calls will append to one of its
+ * children.
+ *
+ * This can be useful if you want to pass around an object that will later be
+ * wrapped on the inside.
+ *
+ * For instance, you can define an :x:composite like this:
+ * $parent = <div><p>{$anchor = <span />}</p></div>;
+ * $composite = new :x:composite($parent, $anchor);
+ *
+ * Then if another client wants to wrap the contents of your composite node,
+ * he would do so by:
+ * $composite->appendChild($anchor = <b />);
+ * $composite = new :x:composite($composite, $anchor);
+ *
+ * Note that we create another composite from the old one so that later down the
+ * line we can wrap again with another tag.
+ *
+ * IMPORTANT: I think this class is broken right now. If you want to use it you
+ * should try to fix it.
+ */
+class :x:composite extends :x:base {
+  private
+    $parent,
+    $anchor;
+
+  public function __construct(:x:base $parent, :x:base $anchor) {
+    $this->parent = $parent;
+    $this->anchor = $anchor;
+  }
+
+  public function appendChild($child) {
+    return $this->anchor->appendChild($child);
+  }
+
+  public function getAttribute($attr) {
+    return $this->parent->getAttribute($attr);
+  }
+
+  public function setAttribute($attr, $val) {
+    return $this->parent->setAttribute($attr, $val);
+  }
+
+  public function categoryOf($cat) {
+    return $this->parent->categoryOf($cat);
+  }
+
+  public function __toString() {
+    return $this->parent->__toString();
+  }
+
+  protected static function &__xhpAttributeDeclaration() {
+    return $this->parent->__xhpAttributeDeclaration();
+  }
+
+  protected function &__xhpCategoryDeclaration() {
+    return $this->parent->__xhpCategoryDeclaration();
+  }
+
+  protected function &__xhpChildrenDeclaration() {
+    return $this->parent->__xhpChildrenDeclaration();
+  }
+}
+
+/**
+ * An <x:frag /> is a transparent wrapper around any number of elements. When
+ * you render it just the children will be rendered. When you append it to an
+ * element the <x:frag /> will disappear and each child will be sequentially
+ * appended to the element.
+ */
+class :x:frag extends :x:primitive {
+  protected function stringify() {
+    $buf = '';
+    foreach ($this->getChildren() as $child) {
+      $buf .= :x:base::renderChild($child);
+    }
+    return $buf;
+  }
+}
+
+/**
+ * Exceptions are neat.
+ */
+class XHPException extends Exception {
+  protected static function getElementName($that) {
+    $name = get_class($that);
+    if (substr($name, 0, 4) !== 'xhp_') {
+      return $name;
+    } else {
+      return :x:base::class2element($name);
+    }
+  }
+}
+
+class XHPClassException extends XHPException {
+  public function __construct($that, $msg) {
+    parent::__construct(
+      'Exception in class `' . XHPException::getElementName($that) . "`\n\n".
+      "$that->source\n\n".
+      $msg
+    );
+  }
+}
+
+class XHPCoreRenderException extends XHPException {
+  public function __construct($that, $rend) {
+    parent::__construct(
+      ':x:element::render must reduce an object to an :x:primitive, but `'.
+      :x:base::class2element(get_class($that)).'` reduced into `'.gettype($rend)."`.\n\n".
+      $that->source
+    );
+  }
+}
+
+class XHPRenderArrayException extends XHPException {
+}
+
+class XHPAttributeNotSupportedException extends XHPException {
+  public function __construct($that, $attr) {
+    parent::__construct(
+      'Attribute `'.$attr.'` is not supported in class '.
+      '`'.XHPException::getElementName($that)."`.\n\n".
+      "$that->source\n\n".
+      'Please check for typos in your attribute. If you are creating a new '.
+      'attribute on this element please add your attribute to the '.
+      "`supportedAttributes` method.\n\n"
+    );
+  }
+}
+
+class XHPAttributeRequiredException extends XHPException {
+  public function __construct($that, $attr) {
+    parent::__construct(
+      'Required attribute `'.$attr.'` was not specified in element '.
+      '`'.XHPException::getElementName($that)."`.\n\n".
+      $that->source
+    );
+  }
+}
+
+class XHPInvalidAttributeException extends XHPException {
+  public function __construct($that, $type, $attr, $val) {
+    if (is_object($val)) {
+      $val_type = get_class($val);
+    } else {
+      $val_type = gettype($val);
+    }
+    parent::__construct(
+      "Invalid attribute `$attr` of type `$val_type` supplied to element `".
+      :x:base::class2element(get_class($that))."`, expected `$type`.\n\n".
+      $that->source
+    );
+  }
+}
+
+class XHPInvalidChildrenException extends XHPException {
+  public function __construct($that, $index) {
+    parent::__construct(
+      'Element `'.XHPException::getElementName($that).'` was rendered with '.
+      "invalid children.\n\n".
+      "$that->source\n\n".
+      "Verified $index children before failing.\n\n".
+      "Children expected:\n".$that->__getChildrenDeclaration()."\n\n".
+      "Children received:\n".$that->__getChildrenDescription()
+    );
+  }
+}
Index: www/xhp/base/html.php
new file mode 100644
===================================================================
--- www/xhp/base/html.php	(revision 0)
+++ www/xhp/base/html.php	(working copy)
@@ -0,0 +1,741 @@
+<?php
+/*
+  +----------------------------------------------------------------------+
+  | XHP                                                                  |
+  +----------------------------------------------------------------------+
+  | Copyright (c) 2009 - 2010 Facebook, Inc. (http://www.facebook.com)          |
+  +----------------------------------------------------------------------+
+  | This source file is subject to version 3.01 of the PHP license,      |
+  | that is bundled with this package in the file LICENSE.PHP, and is    |
+  | available through the world-wide-web at the following url:           |
+  | http://www.php.net/license/3_01.txt                                  |
+  | If you did not receive a copy of the PHP license and are unable to   |
+  | obtain it through the world-wide-web, please send a note to          |
+  | license@php.net so we can mail you a copy immediately.               |
+  +----------------------------------------------------------------------+
+*/
+
+/**
+ * This is the base library of HTML elements for use in XHP. This includes all
+ * non-deprecated tags and attributes. Elements in this file should stay as
+ * close to spec as possible. Facebook-specific extensions should go into their
+ * own elements.
+ */
+abstract class :xhp:html-element extends :x:primitive {
+
+  // TODO: Break these out into abstract elements so that elements that need
+  // them can steal the definition. Right now this is an overloaded list of
+  // attributes.
+  attribute
+    // HTML attributes
+    string accesskey, string class, string dir, string id, string lang,
+    string style, string tabindex, string title,
+
+    // Javascript events
+    string onabort, string onblur, string onchange, string onclick,
+    string ondblclick, string onerror, string onfocus, string onkeydown,
+    string onkeypress, string onkeyup, string onload, string onmousedown,
+    string onmousemove, string onmouseout, string onmouseover, string onmouseup,
+    string onreset, string onresize, string onselect, string onsubmit,
+    string onunload,
+
+    // IE only
+    string onmouseenter, string onmouseleave,
+
+    // Joe Hewitt!!
+    // TODO:
+    string selected, string otherButtonLabel, string otherButtonHref,
+    string otherButtonClass, string type, string replaceCaret,
+    string replaceChildren;
+
+
+  protected
+    $tagName;
+
+  public function requireUniqueId() {
+    // TODO: Implement something on AsyncRequest that returns the number of
+    //       requests sent so far so we can remove the microtime(true) thing.
+    if (!($id = $this->getAttribute('id'))) {
+      $this->setAttribute('id', $id = substr(md5(mt_rand(0, 100000)), 0, 10));
+    }
+    return $id;
+  }
+
+  protected final function renderBaseAttrs() {
+    $buf = '<'.$this->tagName;
+    foreach ($this->getAttributes() as $key => $val) {
+      if ($val !== null && $val !== false) {
+        $buf .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($val, true) . '"';
+      }
+    }
+    return $buf;
+  }
+
+  public function addClass($class) {
+    $class = trim($class);
+
+    $currentClasses = $this->getAttribute('class');
+    $has = strpos(' '.$currentClasses.' ', ' '.$class.' ') !== false;
+    if ($has) {
+      return $this;
+    }
+
+    $this->setAttribute('class', trim($currentClasses.' '.$class));
+    return $this;
+  }
+
+  protected function stringify() {
+    $buf = $this->renderBaseAttrs() . '>';
+    foreach ($this->getChildren() as $child) {
+      $buf .= :x:base::renderChild($child);
+    }
+    $buf .= '</'.$this->tagName.'>';
+    return $buf;
+  }
+}
+
+/**
+ * Subclasses of :xhp:html-singleton may not contain children. When rendered they
+ * will be in singleton (<img />, <br />) form.
+ */
+abstract class :xhp:html-singleton extends :xhp:html-element {
+  children empty;
+
+  protected function stringify() {
+    return $this->renderBaseAttrs() . ' />';
+  }
+}
+
+/**
+ * Subclasses of :xhp:pseudo-singleton may contain exactly zero or one
+ * children. When rendered they will be in full open\close form, no matter how
+ * many children there are.
+ */
+abstract class :xhp:pseudo-singleton extends :xhp:html-element {
+  children (pcdata)*;
+
+  protected function escape($txt) {
+    return htmlspecialchars($txt);
+  }
+
+  protected function stringify() {
+    $buf = $this->renderBaseAttrs() . '>';
+    if ($children = $this->getChildren()) {
+      $buf .= :x:base::renderChild($children[0]);
+    }
+    return $buf . '</'.$this->tagName.'>';
+  }
+}
+
+/**
+ * Below is a big wall of element definitions. These are the basic building
+ * blocks of XHP pages.
+ */
+class :a extends :xhp:html-element {
+  attribute
+    string href, string name, string rel, string target;
+  category %flow, %phrase, %interactive;
+  // transparent
+  // may not contain %interactive
+  children (pcdata | %flow)*;
+  protected $tagName = 'a';
+}
+
+class :abbr extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'abbr';
+}
+
+class :acronym extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'acronym';
+}
+
+class :address extends :xhp:html-element {
+  category %flow;
+  // may not contain h1-h6
+  children (pcdata | %flow)*;
+  protected $tagName = 'address';
+}
+
+class :area extends :xhp:html-singleton {
+  attribute string alt, string coords, string href, bool nohref, string target;
+  protected $tagName = 'area';
+}
+
+class :b extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'b';
+}
+
+class :base extends :xhp:html-singleton {
+  attribute string href, string target;
+  // also a member of "metadata", but is not listed here. see comments in :head
+  // for more information
+  protected $tagName = 'base';
+}
+
+class :big extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'big';
+}
+
+class :blockquote extends :xhp:html-element {
+  attribute string cite;
+  category %flow;
+  children (pcdata | %flow)*;
+  protected $tagName = 'blockquote';
+}
+
+class :body extends :xhp:html-element {
+  children (pcdata | %flow)*;
+  protected $tagName = 'body';
+}
+
+class :br extends :xhp:html-singleton {
+  category %flow, %phrase;
+  protected $tagName = 'br';
+}
+
+class :button extends :xhp:html-element {
+  attribute
+    bool disabled, string name, enum { "submit", "button", "reset" } type, string value;
+  category %flow, %phrase, %interactive;
+  // may not contain interactive
+  children (pcdata | %phrase)*;
+  protected $tagName = 'button';
+}
+
+class :caption extends :xhp:html-element {
+  // may not contain table
+  children (pcdata | %flow)*;
+  protected $tagName = 'caption';
+}
+
+class :cite extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'cite';
+}
+
+class :code extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'code';
+}
+
+class :col extends :xhp:html-singleton {
+  attribute
+    enum { "left", "right", "center", "justify", "char" } align, string char,
+    int charoff, int span,
+    enum { "top", "middle", "bottom", "baseline" } valign, string width;
+  protected $tagName = 'col';
+}
+
+class :colgroup extends :xhp:html-element {
+  attribute
+    enum { "left", "right", "center", "justify", "char" } align, string char,
+    int charoff, int span,
+    enum { "top", "middle", "bottom", "baseline" } valign, string width;
+  children (:col)*;
+  protected $tagName = 'colgroup';
+}
+
+class :dd extends :xhp:html-element {
+  children (pcdata | %flow)*;
+  protected $tagName = 'dd';
+}
+
+class :del extends :xhp:html-element {
+  attribute string cite, string datetime;
+  category %flow, %phrase;
+  // transparent
+  children (pcdata | %flow)*;
+  protected $tagName = 'del';
+}
+
+class :div extends :xhp:html-element {
+  category %flow;
+  children (pcdata | %flow)*;
+  protected $tagName = 'div';
+}
+
+class :dfn extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'dfn';
+}
+
+class :dl extends :xhp:html-element {
+  category %flow;
+  children (:dt+, :dd+)*;
+  protected $tagName = 'dl';
+}
+
+class :dt extends :xhp:html-element {
+  children (pcdata | %phrase)*;
+  protected $tagName = 'dt';
+}
+
+class :em extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'em';
+}
+
+class :fieldset extends :xhp:html-element {
+  category %flow;
+  children (:legend?, (pcdata | %flow)*);
+  protected $tagName = 'fieldset';
+}
+
+class :form extends :xhp:html-element {
+  attribute
+    string action, string accept, string accept-charset, string enctype,
+    enum { "get", "post" } method, string name, string target, bool ajaxify;
+  category %flow;
+  // may not contain form
+  children (pcdata | %flow)*;
+  protected $tagName = 'form';
+}
+
+class :frame extends :xhp:html-singleton {
+  attribute
+    bool frameborder, string longdesc, int marginheight, int marginwidth,
+    string name, bool noresize, enum { "yes", "no", "auto" } scrolling,
+    string src;
+  protected $tagName = 'frame';
+}
+
+class :frameset extends :xhp:html-element {
+  children (:frame | :frameset | :noframes)*;
+  protected $tagName = 'frameset';
+}
+
+class :h1 extends :xhp:html-element {
+  category %flow;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'h1';
+}
+
+class :h2 extends :xhp:html-element {
+  category %flow;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'h2';
+}
+
+class :h3 extends :xhp:html-element {
+  category %flow;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'h3';
+}
+
+class :h4 extends :xhp:html-element {
+  category %flow;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'h4';
+}
+
+class :h5 extends :xhp:html-element {
+  category %flow;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'h5';
+}
+
+class :h6 extends :xhp:html-element {
+  category %flow;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'h6';
+}
+
+class :head extends :xhp:html-element {
+  attribute string profile;
+  children (%metadata*, :title, %metadata*, :base?, %metadata*);
+  // Note: html/xhtml spec says that there should be exactly 1 <title />, and at
+  // most 1 <base />. These elements can occur in any order, and can be
+  // surrounded by any number of other elements (in %metadata). The problem
+  // here is that XHP's validation does not backtrack, so there's no way to
+  // accurately implement the spec. This is the closest we can get. The only
+  // difference between this and the spec is that in XHP the <title /> must
+  // appear before the <base />.
+  protected $tagName = 'head';
+}
+
+class :hr extends :xhp:html-singleton {
+  category %flow;
+  protected $tagName = 'hr';
+}
+
+class :html extends :xhp:html-element {
+  attribute string xmlns;
+  children (:head, :body);
+  protected $tagName = 'html';
+}
+
+class :i extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'i';
+}
+
+class :iframe extends :xhp:pseudo-singleton {
+  attribute
+    enum {"1", "0"} frameborder,
+    string height, string longdesc, int marginheight,
+    int marginwidth, string name, enum { "yes", "no", "auto" } scrolling,
+    string src, string width;
+  category %flow, %phrase, %interactive;
+  children empty;
+  protected $tagName = 'iframe';
+}
+
+class :img extends :xhp:html-singleton {
+  attribute
+    // Lite
+    string staticsrc,
+    // HTML
+    string alt, string src, string height, bool ismap, string longdesc,
+    string usemap, string width;
+  category %flow, %phrase;
+  protected $tagName = 'img';
+}
+
+class :input extends :xhp:html-singleton {
+  attribute
+    // Non-standard
+    enum { "on", "off" } autocomplete,
+    string placeholder,
+    // HTML
+    string accept, enum { "left", "right", "top", "middle", "bottom" } align,
+    string alt, bool checked, bool disabled, int maxlength, string name,
+    bool readonly, int size, string src,
+    enum {
+      "button", "checkbox", "file", "hidden", "image", "password", "radio",
+      "reset", "submit", "text"
+    } type,
+    string value;
+  category %flow, %phrase, %interactive;
+  protected $tagName = 'input';
+}
+
+class :ins extends :xhp:html-element {
+  attribute string cite, string datetime;
+  category %flow, %phrase;
+  // transparent
+  children (pcdata | %flow)*;
+  protected $tagName = 'ins';
+}
+
+class :kbd extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'kbd';
+}
+
+class :label extends :xhp:html-element {
+  attribute string for;
+  category %flow, %phrase, %interactive;
+  // may not contain label
+  children (pcdata | %phrase)*;
+  protected $tagName = 'label';
+}
+
+class :legend extends :xhp:html-element {
+  children (pcdata | %phrase)*;
+  protected $tagName = 'legend';
+}
+
+class :li extends :xhp:html-element {
+  children (pcdata | %flow)*;
+  protected $tagName = 'li';
+}
+
+class :link extends :xhp:html-singleton {
+  attribute
+    string charset, string href, string hreflang, string media, string rel,
+    string rev, string target, string type;
+  category %metadata;
+  protected $tagName = 'link';
+}
+
+class :map extends :xhp:html-element {
+  attribute string name;
+  category %flow, %phrase;
+  // transparent
+  children ((pcdata | %flow)+ | :area+);
+  protected $tagName = 'map';
+}
+
+class :meta extends :xhp:html-singleton {
+  attribute
+    string content @required,
+    enum {
+      "content-type", "content-style-type", "expires", "refresh", "set-cookie"
+    } http-equiv,
+    string http-equiv, string name, string scheme;
+  category %metadata;
+  protected $tagName = 'meta';
+}
+
+class :noframes extends :xhp:html-element {
+  children (%html-body);
+  protected $tagName = 'noframes';
+}
+
+class :noscript extends :xhp:html-element {
+  // transparent
+  category %flow, %phrase;
+  protected $tagName = 'noscript';
+}
+
+class :object extends :xhp:html-element {
+  attribute
+    enum { "left", "right", "top", "bottom" } align, string archive, int border,
+    string classid, string codebase, string codetype, string data, bool declare,
+    int height, int hspace, string name, string standby, string type,
+    string usemap, int vspace, int width;
+  category %flow, %phrase;
+  // transparent, after the params
+  children (:param*, (pcdata | %flow)*);
+  protected $tagName = 'object';
+}
+
+class :ol extends :xhp:html-element {
+  category %flow;
+  children (:li)*;
+  protected $tagName = 'ol';
+}
+
+class :optgroup extends :xhp:html-element {
+  attribute string label, bool disabled;
+  children (:option)*;
+  protected $tagName = 'optgroup';
+}
+
+class :option extends :xhp:pseudo-singleton {
+  attribute bool disabled, string label, bool selected, string value;
+  protected $tagName = 'option';
+}
+
+class :p extends :xhp:html-element {
+  category %flow;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'p';
+}
+
+class :param extends :xhp:pseudo-singleton {
+  attribute
+    string name, string type, string value,
+    enum { "data", "ref", "object" } valuetype;
+  protected $tagName = 'param';
+}
+
+class :pre extends :xhp:html-element {
+  category %flow;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'pre';
+}
+
+class :q extends :xhp:html-element {
+  attribute string cite;
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'q';
+}
+
+// deprecated
+class :s extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 's';
+}
+
+class :samp extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'samp';
+}
+
+class :script extends :xhp:pseudo-singleton {
+  attribute string charset, bool defer, string src, string type;
+  category %flow, %phrase, %metadata;
+  protected $tagName = 'script';
+}
+
+class :select extends :xhp:html-element {
+  attribute bool disabled, bool multiple, string name, int size;
+  category %flow, %phrase, %interactive;
+  children (:option | :optgroup)*;
+  protected $tagName = 'select';
+}
+
+class :small extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'small';
+}
+
+class :span extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'span';
+}
+
+class :strong extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'strong';
+}
+
+class :style extends :xhp:pseudo-singleton {
+  attribute
+    enum {
+      "screen", "tty", "tv", "projection", "handheld", "print", "braille",
+      "aural", "all"
+    } media, string type;
+  category %metadata;
+  protected $tagName = 'style';
+}
+
+class :sub extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase);
+  protected $tagName = 'sub';
+}
+
+class :sup extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase);
+  protected $tagName = 'sup';
+}
+
+class :table extends :xhp:html-element {
+  attribute
+    int border, int cellpadding, int cellspacing,
+    enum {
+      "void", "above", "below", "hsides", "lhs", "rhs", "vsides", "box",
+      "border"
+    } frame,
+    enum { "none", "groups", "rows", "cols", "all" } rules,
+    string summary, string width;
+  category %flow;
+  children (
+    :caption?, :colgroup*,
+    :thead?,
+    (
+      (:tfoot, (:tbody+ | :tr*)) |
+      ((:tbody+ | :tr*), :tfoot?)
+    )
+  );
+  protected $tagName = 'table';
+}
+
+class :tbody extends :xhp:html-element {
+  attribute
+    enum { "right", "left", "center", "justify", "char" } align, string char,
+    int charoff, enum { "top", "middle", "bottom", "baseline" } valign;
+  children (:tr)*;
+  protected $tagName = 'tbody';
+}
+
+
+class :td extends :xhp:html-element {
+  attribute
+    string abbr, enum { "left", "right", "center", "justify", "char" } align,
+    string axis, string char, int charoff, int colspan, string headers,
+    int rowspan, enum { "col", "colgroup", "row", "rowgroup" } scope,
+    enum { "top", "middle", "bottom", "baseline" } valign;
+  children (pcdata | %flow)*;
+  protected $tagName = 'td';
+}
+
+class :textarea extends :xhp:pseudo-singleton {
+  attribute int cols, int rows, bool disabled, string name, bool readonly;
+  category %flow, %phrase, %interactive;
+  protected $tagName = 'textarea';
+}
+
+class :tfoot extends :xhp:html-element {
+  attribute
+    enum { "left", "right", "center", "justify", "char" } align, string char,
+    int charoff, enum { "top", "middle", "bottom", "baseline" } valign;
+  children (:tr)*;
+  protected $tagName = 'tfoot';
+}
+
+class :th extends :xhp:html-element {
+  attribute
+    string abbr, enum { "left", "right", "center", "justify", "char" } align,
+    string axis, string char, int charoff, int colspan, int rowspan,
+    enum { "col", "colgroup", "row", "rowgroup" } scope,
+    enum { "top", "middle", "bottom", "baseline" } valign;
+  children (pcdata | %flow)*;
+  protected $tagName = 'th';
+}
+
+class :thead extends :xhp:html-element {
+  attribute
+    enum { "left", "right", "center", "justify", "char" } align, string char,
+    int charoff, enum { "top", "middle", "bottom", "baseline" } valign;
+  children (:tr)*;
+  protected $tagName = 'thead';
+}
+
+class :title extends :xhp:pseudo-singleton {
+  // also a member of "metadata", but is not listed here. see comments in :head
+  // for more information.
+  protected $tagName = 'title';
+}
+
+class :tr extends :xhp:html-element {
+  attribute
+    enum { "left", "right", "center", "justify", "char" } align, string char,
+    int charoff, enum { "top", "middle", "bottom", "baseline" } valign;
+  children (:th | :td)*;
+  protected $tagName = 'tr';
+}
+
+class :tt extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'tt';
+}
+
+// deprecated
+class :u extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'u';
+}
+
+class :ul extends :xhp:html-element {
+  category %flow;
+  children (:li)*;
+  protected $tagName = 'ul';
+}
+
+class :var extends :xhp:html-element {
+  category %flow, %phrase;
+  children (pcdata | %phrase)*;
+  protected $tagName = 'var';
+}
+
+/**
+ * Render an <html /> element with a DOCTYPE, great for dumping a page to a
+ * browser. Choose from a wide variety of flavors like XHTML 1.0 Strict, HTML
+ * 4.01 Transitional, and new and improved HTML 5!
+ *
+ * Note: Some flavors may not be available in your area.
+ */
+class :x:doctype extends :x:primitive {
+  children (:html);
+
+  protected function stringify() {
+    $children = $this->getChildren();
+    return '<!DOCTYPE html>' . (:x:base::renderChild($children[0]));
+  }
+}
Index: www/xhp/base/init.php
new file mode 100644
===================================================================
--- www/xhp/base/init.php	(revision 0)
+++ www/xhp/base/init.php	(working copy)
@@ -0,0 +1,20 @@
+<?php
+require_once 'core.php';
+require_once 'html.php';
+
+// Infoarena-only hack. The XHP codebase allows one to disable escaping of a
+// string by using something like HTML('...'), but that was not defined
+// anywhere. This makes it work, but is extremely limited.
+function HTML($str) {
+  return new HTML($str);
+}
+
+class HTML {
+  function __construct($str) {
+    $this->str = $str;
+  }
+
+  function render() {
+    return $this->str;
+  }
+}
Index: www/xhp/ia/base.php
new file mode 100644
===================================================================
--- www/xhp/ia/base.php	(revision 0)
+++ www/xhp/ia/base.php	(working copy)
@@ -0,0 +1,131 @@
+<?php
+// Contains the base ia:page XHP object that is used as a platform for
+// rendering all pages on the main website.
+
+require_once(IA_ROOT_DIR . 'www/xhp/ia/sitewide.php');
+
+class :ia:page extends :ui:element {
+    attribute
+        array user,
+        string title = "infoarena",
+        string charset = "UTF-8";
+    /*
+     * The ia:page XHP object can have meta, link and script children that are
+     * added to the <head> of the rendered page in addition to the default one.
+     *
+     * The website's header, top navigation bar, left column and footer are all
+     * optional and can be ommited. The main content of the website should be
+     * enclosed in a <ia:content> tag.
+     */
+    children ((:meta | :link | :script)*,
+              :ia:header?, :ia:top-navbar?, :ia:left-col?,
+              :ui:breadcrumbs?, :ui:flash-message?, :ia:footer?,
+              :ia:content, :ia:log?);
+
+    protected function render() {
+        $default_css = array(
+            'sitewide.css', 'screen.css',
+            'iconize.css', 'sh/shCore.css', 'sh/shThemeDefault.css',
+            <link type="text/css" rel="stylesheet"
+              href={url_static('css/print.css')} media="print" />,
+        );
+        // FIXME: infoarena's javascript is a horrible mess.
+        $default_js = array(
+            'config.js.php',
+            'MochiKit.js',
+            'default.js',
+            'submit.js',
+            'remotebox.js',
+            'postdata.js',
+            'sh/shCore.js',
+            'sh/shBrushCpp.js',
+            'sh/shBrushDelphi.js',
+            'sh/shBrushJava.js',
+            'sh/shBrushPython.js',
+            'sh/shInit.js',
+            'tags.js',
+            'roundtimer.js',
+            'restoreparity.js',
+            'foreach.js',
+            'sorttable.js',
+            'tablednd.js',
+            'wikiedit.js',
+            <script type="text/javascript">
+              {"Sh_Init('" . url_static('swf/clipboard.swf') . "')"}
+            </script>,
+        );
+
+        // Add the default CSS and JS files to the page's children.
+        foreach ($default_css as $css_element) {
+            if (is_string($css_element)) {
+                $this->appendChild(
+                  <link type="text/css" rel="stylesheet"
+                    href={url_static('css/' . $css_element)} />);
+            } else {
+                $this->appendChild($css_element);
+            }
+        }
+        foreach ($default_js as $js_element) {
+            if (is_string($js_element)) {
+                $this->appendChild(
+                  <script type="text/javascript"
+                    src={url_static('js/' . $js_element)} />);
+            } else {
+                $this->appendChild($js_element);
+            }
+        }
+
+        // Forward the user attribute down to the children that require it.
+        foreach ($this->getChildren() as $child) {
+            $this -> sendAttributes($child, 'user');
+        }
+
+        // Render the document
+        $content_type = 'text/html; charset=' . $this->getAttribute('charset');
+        $head =
+          <head>
+            <meta http-equiv="Content-Type" content={$content_type} />
+            {$this->getChildren('meta')}
+
+            <title>{$this->getAttribute('title')}</title>
+
+            {$this->getChildren('link')}
+            <link rel="icon" href={IA_URL . 'favicon.ico'}
+              type="image/vnd.microsoft.icon" />
+
+            {$this->getChildren('script')}
+          </head>;
+
+        $body =
+          <body id="infoarena">
+            <div id="page">
+              {$this->getChildren('ia:header')}
+              {$this->getChildren('ia:top-navbar')}
+              <div id="content_small" class="clear">
+                {$this->getChildren('ia:left-col')}
+                <div id="main">
+                  {$this->getChildren('ui:breadcrumbs')}
+                  {$this->getChildren('ui:flash-message')}
+                  {$this->getChildren('ia:content')}
+                </div>
+              </div>
+            </div>
+            {$this->getChildren('ia:footer')}
+            {$this -> getChildren('ia:log')}
+          </body>;
+
+        return
+          <x:doctype>
+            <html>
+              {$head}
+              {$body}
+            </html>
+          </x:doctype>;
+    }
+}
+
+class :ia:content extends :x:element {
+    protected function render() {
+        return <x:frag>{$this->getChildren()}</x:frag>;
+    }
+}
Index: www/xhp/ia/calendar.php
new file mode 100644
===================================================================
--- www/xhp/ia/calendar.php	(revision 0)
+++ www/xhp/ia/calendar.php	(working copy)
@@ -0,0 +1,15 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/macros/macro_calendar.php');
+
+class :ia:calendar extends :x:element {
+    children empty;
+
+    protected function render() {
+        // FIXME: This should not be done like this.
+        return
+          <div id="calendar">
+            {HTML(macro_calendar(array()))}
+          </div>;
+    }
+}
Index: www/xhp/ia/google_search.php
new file mode 100644
===================================================================
--- www/xhp/ia/google_search.php	(revision 0)
+++ www/xhp/ia/google_search.php	(working copy)
@@ -0,0 +1,21 @@
+<?php
+
+class :ia:google-search extends :x:element {
+    children empty;
+
+    protected function render() {
+        return
+          <div id="google-search">
+            <form id="searchbox_010130381492294265836:kw-fmmvpxco" action="http://infoarena.ro/search">
+              <fieldset>
+                <legend><img src={url_static('images/icons/search.png')} alt="!" /> Cautare</legend>
+                <input type="hidden" name="cx" value="010130381492294265836:kw-fmmvpxco" />
+                <input type="hidden" name="cof" value="FORID:9" />
+                <input name="q" type="text" size="22" />
+                <input type="submit" name="sa" value="Cauta" class="button important"/>
+              </fieldset>
+            </form>
+            <script type="text/javascript" src="http://www.google.com/coop/cse/brand?form=searchbox_010130381492294265836%3Akw-fmmvpxco"></script>
+          </div>;
+    }
+}
Index: www/xhp/ia/log.php
new file mode 100644
===================================================================
--- www/xhp/ia/log.php	(revision 0)
+++ www/xhp/ia/log.php	(working copy)
@@ -0,0 +1,13 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+
+class :ia:log extends :ui:element {
+
+    protected function render() {
+        return
+          <textarea id="log" rows="50" cols="80">
+            {$this -> getChildren()}
+          </textarea>;
+    }
+}
Index: www/xhp/ia/login_form.php
new file mode 100644
===================================================================
--- www/xhp/ia/login_form.php	(revision 0)
+++ www/xhp/ia/login_form.php	(working copy)
@@ -0,0 +1,38 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/form.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/list.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/button.php');
+require_once(IA_ROOT_DIR . 'www/views/utilities.php');
+
+class :ia:login-form extends :ui:form {
+
+    protected function render() {
+        $this -> setAttribute('action', url_login());
+        $this -> setAttribute('method', 'post');
+        $this -> setAttribute('class', 'login');
+        $this -> setAttribute('imageURL', url_static('images/icons/login.png'));
+        $this -> setAttribute('legend', ' Autentificare');
+
+        $this -> appendChild(
+          <x:frag>
+            <ui:form:input name="username" type="text" accesskey="c">
+              Cont de utilizator
+            </ui:form:input>
+
+            <ui:form:input name="password" type="password" accesskey="p">
+              Parola
+            </ui:form:input>
+
+            <ui:form:checkbox name="remember" class="checkbox" order="reversed">
+              Pastreaza-ma autentificat 5 zile
+            </ui:form:checkbox>
+
+            <ui:button type="submit" id="form_submit" important="true">
+              Autentificare
+            </ui:button>
+          </x:frag>);
+
+        return :ui:form::render();
+    }
+}
Index: www/xhp/ia/server_time.php
new file mode 100644
===================================================================
--- www/xhp/ia/server_time.php	(revision 0)
+++ www/xhp/ia/server_time.php	(working copy)
@@ -0,0 +1,14 @@
+<?php
+
+class :ia:server-time extends :x:element {
+    children empty;
+
+    protected function render() {
+        return
+          <x:frag>
+            <div id="srv_time" class="user-count"  />
+            <script type="text/javascript" src={url_static('js/time.js')} />
+            <script type="text/javascript">{'loadTime(' . format_date(null, "%H, %M, %S") . ');'}</script>
+           </x:frag>;
+    }
+}
Index: www/xhp/ia/sidebar.php
new file mode 100644
===================================================================
--- www/xhp/ia/sidebar.php	(revision 0)
+++ www/xhp/ia/sidebar.php	(working copy)
@@ -0,0 +1,144 @@
+<?php
+// Contains XHP objects for the site's left side bar.
+
+require_once(IA_ROOT_DIR . 'www/xhp/ia/login_form.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/list.php');
+require_once(IA_ROOT_DIR . 'www/wiki/wiki.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/textblock.php');
+
+class :ia:left-col extends :x:element {
+    attribute
+        array user;
+
+    protected function render() {
+        $user = $this->getAttribute('user');
+        foreach ($this->getChildren('ia:left-navbar') as $child) {
+            $child->setAttribute('user', $user);
+        }
+        return
+          <div id="sidebar">
+            {$this->getChildren()}
+          </div>;
+    }
+}
+
+class :ia:left-navbar extends :x:element {
+    attribute
+        array user;
+    children empty;
+
+    protected function render() {
+        $user = $this->getAttribute('user');
+        $list =
+          <ui:list id="nav" class="clear">
+            <ui:link href={url_home()}>
+              Home
+            </ui:link>
+
+            <ui:link href={url_textblock('arhiva')} accesskey="a">
+              Arhiva de probleme
+            </ui:link>
+            <ui:link href={url_textblock('arhiva-educationala')}>
+              Arhiva educatională
+            </ui:link>
+            <ui:link href={url_textblock('concursuri')}>
+              Concursuri
+            </ui:link>
+            <ui:link href={url_textblock('concursuri-virtuale')}>
+              Concursuri virtuale
+            </ui:link>
+            <ui:link href={url_textblock('clasament-rating')}>
+              Clasament
+            </ui:link>
+            <ui:link href={url_textblock('articole')}>
+              Articole
+            </ui:link>
+            <ui:link href={url_textblock('downloads')}>
+              Downloads
+            </ui:link>
+            <ui:link href={url_textblock('links')}>
+              Links
+            </ui:link>
+            <ui:link href={url_textblock('documentatie')}>
+              Documentaţie
+            </ui:link>
+            <ui:link href={url_textblock('despre-infoarena')}>
+              Despre infoarena
+            </ui:link>
+            <li class="separator">
+              <hr/>
+            </li>
+          </ui:list>;
+
+        if ($user) {
+            $list->appendChild(
+                <ui:link
+                  href={url_monitor(array('user' => $user['username']))}
+                  accesskey="m">
+                  Monitorul de evaluare
+                </ui:link>);
+            $list->appendChild(
+                <ui:link href={url_submit()}>
+                  <strong>Trimite soluţii</strong>
+                </ui:link>);
+            $list->appendChild(
+                <ui:link href={url_account()} accesskey="c">
+                  Contul meu
+                </ui:link>);
+        } else {
+            $list->appendChild(
+                <ui:link href={url_monitor()} accesskey="m">
+                  Monitorul de evaluare
+                </ui:link>);
+        }
+
+        return $list;
+    }
+}
+
+class :ia:sidebar-ad extends :x:element {
+    children empty;
+
+    protected function render() {
+        $sidebar = textblock_get_revision(IA_SIDEBAR_PAGE);
+        if (!$sidebar) {
+            return <x:frag />;
+        }
+
+        $sidebar['text'] = wiki_process_textblock($sidebar);
+
+        return
+          <ui:textblock class="ad" show_forum={false} textblock={$sidebar} />;
+    }
+}
+
+class :ia:sidebar-login extends :x:element {
+    attribute
+        bool show_login_form = true;
+    children empty;
+
+    protected function render() {
+        if ($this->getAttribute('show_login_form')) {
+            $form = <ia:login-form />;
+        } else {
+            $form = <x:frag />;
+        }
+
+        $extra =
+          <p>
+            <ui:link href={url_register()}>
+              Mă înregistrez!
+            </ui:link>
+            <br />
+            <ui:link href={url_resetpass()}>
+              Mi-am uitat parola...
+            </ui:link>
+          </p>;
+
+        return
+          <div id="login">
+            {$form}
+            {$extra}
+          </div>;
+    }
+}
Index: www/xhp/ia/sitewide.php
new file mode 100644
===================================================================
--- www/xhp/ia/sitewide.php	(revision 0)
+++ www/xhp/ia/sitewide.php	(working copy)
@@ -0,0 +1,210 @@
+<?php
+// Contains important XHP objects that are needed to render the website's
+// frame, such as the website header, footer and navigation bar.
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/link.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/list.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/user.php');
+
+class :ia:header:userbox extends :x:element {
+    attribute
+        array user      @required;
+    children empty;
+
+    protected function render() {
+        $user = $this->getAttribute('user');
+        $username = $user['username'];
+
+        return
+          <div id="userbox">
+            <ui:link:user user={$user}>
+              <ui:user:avatar size="normal"/>
+            </ui:link:user>
+            <div class="user">
+              <strong>
+                {$user['full_name']}
+              </strong>
+
+              <br />
+
+              <ui:user:rating-badge user={$user} />
+
+              <ui:link:user user={$user} accesskey="p">
+                {$username}
+              </ui:link:user>
+
+              <br />
+
+              <ui:link:post href={url_logout()} class="logout" post_data={array()} accesskey="l">
+                logout
+              </ui:link:post>
+              |
+              <ui:link href={url_account()} accesskey="c">contul meu</ui:link>
+            </div>
+          </div>;
+    }
+}
+
+class :ia:header extends :x:element {
+    attribute
+        array user;
+    children empty;
+
+    protected function render() {
+        $header = <div id="header" class="clear" />;
+
+        $user = $this->getAttribute('user');
+        if ($user) {
+            $header->appendChild(<ia:header:userbox user={$user} />);
+        }
+
+        if (IA_DEVELOPMENT_MODE) {
+            $header->appendChild(
+              <div id="dev_warning">
+                Bravely working in development mode&hellip;<br/>Keep it up!
+              </div>);
+        }
+
+        $header->appendChild(
+          <h1>
+            <ui:link href={url_home()}>
+              infoarena informatica de performanta
+            </ui:link>
+          </h1>);
+
+        return $header;
+    }
+}
+
+class :ia:top-navbar extends :x:element {
+    attribute
+        array user,
+        int user_pm_count = 0,
+        string selected = "infoarena";
+    children empty;
+
+    protected function render() {
+        $fields = array(
+          'infoarena' =>
+            <ui:link href={url_home()}>info<em>arena</em></ui:link>,
+          'blog' => <ui:link href={url_blog()} accesskey="b">blog</ui:link>,
+          'forum' => <ui:link href={url_forum()} accesskey="f">forum</ui:link>,
+          'calendar' =>
+            <ui:link href={url_forum() . '?action=calendar'}>
+              calendar
+            </ui:link>,
+        );
+
+        $user = $this->getAttribute('user');
+        if (!$user) {
+            $fields['login'] =
+              <ui:link href={url_login()}>autentificare</ui:link>;
+            $fields['register'] =
+              <ui:link href={url_login()}>inregistrare</ui:link>;
+        } else {
+            $fields['profile'] =
+              <ui:link href={url_user_profile($user['username'])}
+                accesskey="p">profilul meu</ui:link>;
+
+            $user_pm_count = $this->getAttribute('user_pm_count');
+            if ($user_pm_count) {
+                $pm_content = <strong>mesaje ({$user_pm_count})</strong>;
+            } else {
+                $pm_content = 'mesaje';
+            }
+            $fields['pm'] =
+              <ui:link href={url_forum() . '?action=pm'}>
+                {$pm_content}
+              </ui:link>;
+
+            if ($user['security_level'] === 'admin') {
+                $fields['smf_admin'] =
+                  <ui:link href={url_forum() . '?action=admin'}>
+                    forum admin
+                  </ui:link>;
+            }
+        }
+
+        $selected = $this->getAttribute('selected');
+        $list = <ul />;
+        foreach ($fields as $name => $content) {
+            if ($selected === $name) {
+                $content = <strong>{$content}</strong>;
+            }
+            $list->appendChild(<li>{$content}</li>);
+        }
+
+        return
+          <div id="topnav">
+            {$list}
+          </div>;
+    }
+}
+
+class :ia:footer extends :x:element {
+    children empty;
+
+    protected function render() {
+        $elem =
+          <div id="footer">
+            <ui:list class="clear">
+              <li class="copyright">&copy;&nbsp;2004-{date("Y")}&nbsp;
+                <ui:link href={url_textblock('Asociatia-infoarena')}>
+                  Asociatia infoarena
+                </ui:link>
+              </li>
+              <li class="separate">
+                <ui:link href={url_home()}>Prima pagina</ui:link>
+              </li>
+              <ui:link href={url_textblock('despre-infoarena')}>
+                Despre infoarena
+              </ui:link>
+              <ui:link href={url_textblock('termeni-si-conditii')}>
+                Termeni si conditii
+              </ui:link>
+              <ui:link href={url_textblock('contact')}>
+                Contact
+              </ui:link>
+              <li class="top">
+                <ui:link href="#header">
+                  Sari la inceputul paginii &uarr;
+                </ui:link>
+              </li>
+            </ui:list>
+          </div>;
+
+        if (!IA_DEVELOPMENT_MODE) {
+            $elem->appendChild(
+            <p class="cc">
+              {HTML('<!--Creative Commons License-->')}
+              <ui:link class="badge" rel="license" href="http://creativecommons.org/licenses/by-nc/2.5/"><img alt="Creative Commons License" src={url_static('images/CreativeCommonsBadge.png')} /></ui:link>
+              Cu exceptia cazurilor in care se specifica altfel, continutul site-ului infoarena<br/>este publicat sub licenta <ui:link rel="license" href="http://creativecommons.org/licenses/by-nc/2.5/">Creative Commons Attribution-NonCommercial 2.5</ui:link>.
+              {HTML('<!--/Creative Commons License-->
+                <rdf:RDF xmlns="http://web.resource.org/cc/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">
+                  <Work rdf:about="">
+                    <license rdf:resource="http://creativecommons.org/licenses/by-nc/2.5/" />
+                  </Work>
+                  <License rdf:about="http://creativecommons.org/licenses/by-nc/2.5/">
+                    <permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
+                    <permits rdf:resource="http://web.resource.org/cc/Distribution"/>
+                    <requires rdf:resource="http://web.resource.org/cc/Notice"/>
+                    <requires rdf:resource="http://web.resource.org/cc/Attribution"/>
+                    <prohibits rdf:resource="http://web.resource.org/cc/CommercialUse"/>
+                    <permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
+                  </License>
+                </rdf:RDF>')}
+            </p>);
+
+            $elem->appendChild(
+              <script src="http://www.google-analytics.com/urchin.js" type="text/javascript" />);
+            $elem->appendChild(
+              <script type="text/javascript">
+                _uacct = 'UA-113289-8';
+                _udn = 'infoarena.ro';
+                urchinTracker();
+              </script>);
+        }
+
+        return $elem;
+    }
+}
Index: www/xhp/ia/user_count.php
new file mode 100644
===================================================================
--- www/xhp/ia/user_count.php	(revision 0)
+++ www/xhp/ia/user_count.php	(working copy)
@@ -0,0 +1,12 @@
+<?php
+
+class :ia:user-count extends :x:element {
+    children empty;
+
+    protected function render() {
+        return
+          <p class="user-count">
+            {user_count()} membri înregistraţi
+          </p>;
+    }
+}
Index: www/xhp/ui/base.php
new file mode 100644
===================================================================
--- www/xhp/ui/base.php	(revision 0)
+++ www/xhp/ui/base.php	(working copy)
@@ -0,0 +1,28 @@
+<?php
+
+class :ui:element extends :x:element {
+    // TODO: facebook was doing cool stuff with CSS margin and padding in ui
+    // elements
+
+    final public function sendAttributes($destination, $attributes = null) {
+        if ($attributes == null) {
+            $attributes = array_keys($this -> getAttributes());
+        }
+
+        if (is_array($attributes)) {
+            foreach ($attributes as $attribute) {
+                $this -> sendAttributes($destination, $attribute);
+            }
+        } elseif ($this -> getAttribute($attributes) &&
+                  method_exists($destination, 'hasAttribute') &&
+                  $destination -> hasAttribute($attributes)) {
+
+                if ($attributes == 'class') {
+                    $destination -> addClass($this -> getAttribute('class'));
+                } else {
+                    $destination -> setAttribute($attributes,
+                        $this -> getAttribute($attributes));
+                }
+        }
+    }
+}
Index: www/xhp/ui/breadcrumbs.php
new file mode 100644
===================================================================
--- www/xhp/ui/breadcrumbs.php	(revision 0)
+++ www/xhp/ui/breadcrumbs.php	(working copy)
@@ -0,0 +1,42 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+
+class :ui:breadcrumbs extends :ui:element {
+    attribute
+        array entries,
+        string current,
+        string title = "Pagini recente";
+    children empty;
+
+    protected function render() {
+        $entries = $this->getAttribute('entries');
+        $current = $this->getAttribute('current');
+
+        if (count($entries) <= 1) {
+            return <x:frag />;
+        }
+
+        $elem =
+          <div class="breadcrumbs">
+            {$this->getAttribute('title')} &raquo;
+          </div>;
+        $first = true;
+        foreach ($entries as $key => $entry) {
+            list($url, $title) = $entry;
+
+            if (!$first) {
+                $elem->appendChild(<span class="separator"> | </span>);
+            } else {
+                $first = false;
+            }
+
+            if ($current == $key) {
+                $elem->appendChild(<strong>{$title}</strong>);
+            } else {
+                $elem->appendChild(<a href={$url}>{$title}</a>);
+            }
+        }
+        return $elem;
+    }
+}
Index: www/xhp/ui/button.php
new file mode 100644
===================================================================
--- www/xhp/ui/button.php	(revision 0)
+++ www/xhp/ui/button.php	(working copy)
@@ -0,0 +1,30 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+
+class :ui:button extends :ui:element {
+    attribute
+        :input,
+        enum { "submit", "button" } type = "button",
+        bool important = false;
+
+    protected function render() {
+        $tag = <input value={(string) <x:frag>
+                                        {$this -> getChildren()}
+                                      </x:frag>}
+                   type={$this -> getAttribute('type')}
+                   class="button" />;
+
+        if ($this -> getAttribute('important') == true) {
+            $tag -> addClass('important');
+        }
+
+        if ($this -> getAttribute('class')) {
+            $classes = explode(' ', $this -> getAttribute('class'));
+            foreach ($classes as $class) {
+                $tag -> addClass($class);
+            }
+        }
+        return $tag;
+    }
+}
Index: www/xhp/ui/flash_message.php
new file mode 100644
===================================================================
--- www/xhp/ui/flash_message.php	(revision 0)
+++ www/xhp/ui/flash_message.php	(working copy)
@@ -0,0 +1,13 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+
+class :ui:flash-message extends :ui:element {
+    attribute
+        :div;
+
+    protected function render() {
+        $message = <div class={'flash ' . $this -> getAttribute('class')}> {$this -> getChildren()} </div>;
+        return $message;
+    }
+}
Index: www/xhp/ui/form.php
new file mode 100644
===================================================================
--- www/xhp/ui/form.php	(revision 0)
+++ www/xhp/ui/form.php	(working copy)
@@ -0,0 +1,183 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+
+class :ui:form extends :ui:element {
+    attribute
+        :form,
+        string legend = "",
+        string imageURL = "",
+        array values,
+        array errors,
+        array descriptions,
+        enum { "list", "inline" } type = "list";
+
+    protected function render() {
+        $legend = $this -> getAttribute('legend');
+        $imageURL = $this -> getAttribute('imageURL');
+        $values = $this -> getAttribute('values');
+        $errors = $this -> getAttribute('errors');
+        $descriptions = $this -> getAttribute('descriptions');
+        $type = $this -> getAttribute('type');
+
+        foreach($this -> getChildren() as $child) {
+            if ($child instanceof :ui:form_field) {
+                $name = $child -> getAttribute('name');
+
+                if ($value = getattr($values, $name, '')) {
+                    $child -> setAttribute('value', $value);
+                }
+
+                if ($error = getattr($errors, $name, '')) {
+                    $child -> setAttribute('error', $error);
+                }
+
+                if ($description = getattr($descriptions, $name, '')) {
+                    $child -> setAttribute('description', $description);
+                }
+            }
+        }
+
+        if ($legend || $imageURL) {
+            $title = <legend />;
+            if ($imageURL) {
+                $title -> appendChild(<img src={$imageURL} alt="!" />);
+            }
+
+            if ($legend) {
+                $title -> appendChild(<x:frag>{$legend}</x:frag>);
+            }
+        } else {
+            $title = <x:frag />;
+        }
+
+        if ($type == 'list') {
+            $container =
+              <ui:list class="form">
+                {$this -> getChildren()}
+              </ui:list>;
+        } else {
+            $container =
+              <x:frag>
+                {$this -> getChildren()}
+              </x:frag>;
+        }
+
+        $form =
+          <form>
+            <fieldset>
+              {$title}
+              {$container}
+            </fieldset>
+          </form>;
+
+        $this -> sendAttributes($form);
+
+        return $form;
+    }
+}
+
+abstract class :ui:form_field extends :ui:element {
+    attribute
+        var editor,
+        bool label=true,
+        enum { "normal", "reversed" } order = "normal",
+        string accesskey,
+        string error,
+        string description;
+
+    protected function render() {
+        // Setting the label for the form field
+        if ($this -> getAttribute('label') == true && array_key_exists(0, $this -> getChildren())) {
+            $label =
+              <label for={'form_' . $this -> getAttribute('name')}
+                accesskey={$this -> getAttribute('accesskey')}>
+                <ui:highlight_accesskey accesskey ={$this -> getAttribute('accesskey')}>
+                  {$this -> getChildren()}
+                </ui:highlight_accesskey>
+              </label>;
+        } else {
+            $label = <x:frag />;
+        }
+
+        // Getting any extra errors
+        if ($this -> getAttribute('error')) {
+            $error =
+              <span class="fieldError">
+                {$this -> getAttribute('error')}
+              </span>;
+        } else {
+            $error = <x:frag />;
+        }
+
+        // Getting the editor
+        $editor = $this -> getAttribute('editor');
+
+        // Any extra description
+        if ($this -> getAttribute('description')) {
+            $description =
+              <span class = "fieldHelp">
+                {$this -> getAttribute('description')}
+              </span>;
+        } else {
+            $description = <x:frag />;
+        }
+
+        // Classes
+        $editor -> setAttribute('class', $this -> getAttribute('class'));
+        $this -> sendAttributes($label, 'class');
+
+        if ($this -> getAttribute('order') == "normal") {
+            return
+              <x:frag>
+                {$label}
+                {$error}
+                {$editor}
+                {$description}
+              </x:frag>;
+        }
+
+        return
+          <x:frag>
+            {$description}
+            {$editor}
+            {$error}
+            {$label}
+          </x:frag>;
+    }
+}
+
+class :ui:form:input extends :ui:form_field {
+    attribute
+        :input,
+        enum { "text", "password" } type = "text";
+
+    protected function render() {
+        $editor =
+          <input name={$this -> getAttribute('name')}
+              id={'form_' . $this -> getAttribute('name')}
+              value={$this -> getAttribute('value')}
+              type={$this -> getAttribute('type')} />;
+
+        $this -> setAttribute('editor', $editor);
+        return :ui:form_field::render();
+    }
+}
+
+class :ui:form:checkbox extends :ui:form_field {
+    attribute
+        :input;
+
+    protected function render() {
+        $editor =
+          <input name={$this -> getAttribute('name')}
+              id={'form_' . $this -> getAttribute('name')}
+              checked={$this -> getAttribute('value')}
+              type="checkbox" />;
+
+
+        $this -> sendAttributes($editor, 'checked');
+        $this -> setAttribute('editor', $editor);
+        return :ui:form_field::render();
+    }
+}
Index: www/xhp/ui/link.php
new file mode 100644
===================================================================
--- www/xhp/ui/link.php	(revision 0)
+++ www/xhp/ui/link.php	(working copy)
@@ -0,0 +1,123 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+require_once(IA_ROOT_DIR . 'www/JSON.php');
+
+class :ui:highlight_accesskey extends :ui:element {
+    attribute
+        string accesskey;
+
+    protected function render() {
+        $value = (string)(<x:frag>
+                            {$this -> getChildren()}
+                          </x:frag>);
+        $access_key = $this -> getAttribute('accesskey');
+        if (($pos = stripos($value, $access_key)) !== false) {
+            return
+              <x:frag>
+                {substr($value, 0, $pos)}
+                <span class="access-key">
+                  {$value[$pos]}
+                </span>
+                {substr($value, $pos + 1)}
+              </x:frag>;
+        } else {
+            return
+                <x:frag>
+                    {$value}
+                </x:frag>;
+        }
+    }
+}
+
+class :ui:link extends :ui:element {
+    attribute
+        bool highlight_accesskey = true,    // Whether or not to highlight the
+                                            // link's accesskey if specified.
+        string confirm_request = "",
+        :a;
+
+    protected function render() {
+        $elem = <a>{$this->getChildren()}</a>;
+        $confirm_request = $this -> getAttribute('confirm_request');
+        $accesskey = $this->getAttribute('accesskey');
+
+        if ($accesskey && $this->getAttribute('highlight_accesskey')) {
+            // This assumes that no HTML tags are present inside the link.
+            // If these are present, they will be escaped.
+            $elem = <a>
+                      <ui:highlight_accesskey accesskey={$this -> getAttribute('accesskey')}>
+                        {$this -> getChildren()}
+                      </ui:highlight_accesskey>
+                    </a>;
+        }
+
+        if ($confirm_request) {
+            $elem -> setAttribute('onclick', "return confirm ('" . $confirm_request . "')");
+        }
+        $this -> sendAttributes($elem);
+        return $elem;
+    }
+}
+
+class :ui:link:post extends :ui:link {
+    attribute
+        array post_data;
+
+    protected function render() {
+        $post_data = $this -> getAttribute('post_data');
+        $href = $this -> getAttribute('href');
+
+        $json = new Services_JSON();
+        $href = "javascript:PostData(" . str_replace('"', "'", $json -> encode($href)) . ", " . str_replace('"', "'", $json -> encode($post_data)) . ")";
+        $this -> setAttribute('href', $href);
+        return :ui:link::render();
+    }
+}
+
+class :ui:link:user extends :ui:link {
+    attribute
+        array user @required,
+        enum { "default", "rating", "stats" } page = "default";
+
+    protected function render() {
+        $user = $this -> getAttribute('user');
+        $page = $this -> getAttribute('page');
+        if ($page == "default") {
+            $href = url_user_profile($user['username'], true);
+        } else if ($page == "rating") {
+            $href = url_user_rating($user['username']);
+        } else if ($page == "stats") {
+            $href = url_user_stats($user['username']);
+        }
+        $this -> setAttribute('href', $href);
+
+        foreach ($this -> getChildren() as $child) {
+            $this -> sendAttributes($child, 'user');
+        }
+        return :ui:link::render();
+    }
+}
+
+class :ui:link:pager extends :ui:link {
+    attribute
+        int display_entries = 50,
+        int first_entry = 0,
+        string prefix = "";
+
+    protected function render() {
+        $prefix = $this -> getAttribute('prefix');
+
+        $options = array();
+        $options[$prefix . 'first_entry'] = $this -> getAttribute('first_entry');
+        $options[$prefix . 'display_entries'] = $this -> getAttribute('display_entries');
+
+        $this -> setAttribute('href', url_options_add($options));
+
+        if (count($this -> getChildren()) == 0) {
+            $page = ($this -> getAttribute('first_entry') / $this -> getAttribute('display_entries')) + 1;
+            $this -> appendChild(<x:frag> {$page} </x:frag>);
+        }
+        return :ui:link::render();
+    }
+}
Index: www/xhp/ui/list.php
new file mode 100644
===================================================================
--- www/xhp/ui/list.php	(revision 0)
+++ www/xhp/ui/list.php	(working copy)
@@ -0,0 +1,31 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+
+class :ui:list extends :ui:element {
+    attribute
+        :ul,
+        enum { "unordered", "ordered"} type = "unordered";
+
+    protected function render() {
+        if ($this -> getAttribute('type') == "unordered") {
+            $list = <ul />;
+        } else {
+            $list = <ol />;
+        }
+
+        $this -> sendAttributes($list);
+
+        foreach ($this -> getChildren() as $child) {
+            if ($child instanceof :li) {
+                $list -> appendChild($child);
+            } else {
+                $list -> appendChild(<li>
+                                   {$child}
+                                 </li>);
+            }
+        }
+        return $list;
+    }
+}
+?>
Index: www/xhp/ui/pager.php
new file mode 100644
===================================================================
--- www/xhp/ui/pager.php	(revision 0)
+++ www/xhp/ui/pager.php	(working copy)
@@ -0,0 +1,115 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/link.php');
+require_once(IA_ROOT_DIR . 'www/url.php');
+
+class :ui:pager extends :ui:element {
+    attribute
+        string prefix = "";
+}
+
+class :ui:pager:page-number extends :ui:pager {
+    attribute
+        int first_entry = 0,
+        int display_entries = 50,
+        int total_entries = 0,
+        int surround_pages = 5,
+        bool show_count = false,
+        bool show_display_entries = false;
+
+    protected function listPages($display_entries, $begin, $end) {
+        $list = <x:frag />;
+        for ($i = $begin; $i <= $end; ++$i) {
+            $child = <ui:link:pager first_entry={($i - 1) * $display_entries} display_entries={$display_entries} />;
+            $this -> sendAttributes($child, 'prefix');
+            $list -> appendChild($child);
+        }
+        return $list;
+    }
+
+    protected function render() {
+        $first_entry = $this -> getAttribute('first_entry');
+        $display_entries = $this -> getAttribute('display_entries');
+        $total_entries = $this -> getAttribute('total_entries');
+        $surround_pages = $this -> getAttribute('surround_pages');
+        $show_count = $this -> getAttributes('show_count');
+        $show_display_entries = $this -> getAttribute('show_display_entries');
+
+        // Setting the current page
+        $pager = <x:frag>
+                   Vezi pagina:
+                 </x:frag>;
+
+        $current_page = (int)($first_entry / $display_entries) + 1;
+        $total_pages = (int)(($total_entries - 1) / $display_entries) + 1;
+
+        // We could put a number instead of the "..."
+        if ($current_page <= 2 * $surround_pages + 1) {
+            $pager -> appendChild($this -> listPages($display_entries, 1, $current_page - 1));
+        } else {
+            $pager -> appendChild($this -> listPages($display_entries, 1, $surround_pages))
+                   -> appendChild(<x:frag> ... </x:frag>)
+                   -> appendChild($this -> listPages($display_entries, $current_page - $surround_pages, $current_page));
+        }
+
+        $pager -> appendChild(<span class="selected">
+                                <strong>
+                                  {$current_page}
+                                </strong>
+                              </span>);
+
+        if ($total_pages - $current_page <= 2 * $surround_pages) {
+            $pager -> appendChild($this -> listPages($display_entries, $current_page + 1, $total_pages));
+        } else {
+            $pager -> appendChild($this -> listPages($display_entries, $current_page + 1, $current_page + $surround_pages))
+                   -> appendChild(<x:frag> ... </x:frag>)
+                   -> appendChild($this -> listPages($display_entries, $total_pages - $surround_pages, $total_pages));
+        }
+
+        if ($show_count == true) {
+            $pager -> appendChild(<span class="count">
+                                    ({$total_entries} {$total_entries == 1 ? ' rezultat' : ' rezultate'})
+                                  </span>);
+        }
+
+        if ($show_display_entries == true) {
+            $display_entries_options = array(25, 50, 100, 250, $display_entries);
+            sort($display_entries_options);
+            $display_entries_options = array_unique($display_entries_options);
+
+            $first = true;
+            $options = <x:frag />;
+            foreach ($display_entries_options as $option) {
+                if ($first == false) {
+                   $options -> appendChild(<x:frag> | </x:frag>);
+                }
+                $first = false;
+
+                if ($option == $display_entries) {
+                    $option =
+                      <span class="selected">
+                        <strong>
+                          {$option}
+                        </strong>
+                      </span>;
+                } else {
+                    $option = <ui:link:pager display_entries={$option}>
+                                {$option}
+                              </ui:link:pager>;
+                    $this -> sendAttributes($option, array('first_entry', 'prefix'));
+                }
+
+                $options -> appendChild($option);
+            }
+
+            $pager -> appendChild(<span class="entries-per-page"> ({$options})</span>);
+        }
+        return
+          <div class="pager">
+            <div class="standard-pager">
+              {$pager}
+            </div>
+          </div>;
+    }
+}
Index: www/xhp/ui/revision-warning.php
new file mode 100644
===================================================================
--- www/xhp/ui/revision-warning.php	(revision 0)
+++ www/xhp/ui/revision-warning.php	(working copy)
@@ -0,0 +1,55 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+
+class :ui:revision-warning extends :ui:element {
+    attribute
+        int revision = 1,
+        int revision_count = 1,
+        string timestamp @required,
+        bool can_delete = false;
+
+    protected function render() {
+        $revision = $this -> getAttribute('revision');
+        $revision_count = $this -> getAttribute('revision_count');
+        $timestamp = $this -> getAttribute('timestamp');
+
+        $warning = <div class="warning" />;
+
+        if ($revision < $revision_count) {
+            $warning -> appendChild(<x:frag> Atenţie! Aceasta este o versiune veche a paginii </x:frag>);
+        } else {
+            $warning -> appendChild(<x:frag> Atenţie! Aceasta este ultima versiune a paginii </x:frag>);
+        }
+
+        $warning -> appendChild(<x:frag>
+                                  , scrisă la {$timestamp}
+                                  <br />
+                                </x:frag>);
+
+        if ($revision > 1) {
+            $warning -> appendChild(<ui:link href={url_textblock_revision(url_no_options(), $revision - 1)}>
+                                      Revizia anterioară
+                                    </ui:link>);
+        } else {
+            $warning -> appendChild(<x:frag> Revizia anterioară </x:frag>);
+        }
+
+
+        if ($revision < $revision_count) {
+            $warning -> appendChild(<ui:link href={url_textblock_revision(url_no_options(), $revision + 1)}>
+                                      Revizia următoare
+                                    </ui:link>);
+        } else {
+            $warning -> appendChild(<x:frag> Revizia următoare </x:frag>);
+        }
+
+
+        if ($this -> getAttribute('can_delete') == true) {
+            $warning -> appendChild(<ui:link:post href={url_textblock_delete_revision(url_no_options(), $revision)}>
+                                      Şterge
+                                    </ui:link:post>);
+        }
+    }
+}
+?>
Index: www/xhp/ui/table.php
new file mode 100644
===================================================================
--- www/xhp/ui/table.php	(revision 0)
+++ www/xhp/ui/table.php	(working copy)
@@ -0,0 +1,123 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+
+// If the cols attribute is missing the table will have 1 row with all the elements
+class :ui:table extends :ui:element {
+    attribute
+        :table,
+        bool header = true,
+        int cols = 0,
+        bool sortable = false;
+
+    // generates an array from all the elements
+    protected function list_elements($element) {
+        if (is_array($element)) {
+            $elements = array();
+            foreach ($element as $one) {
+                $elements = array_merge($elements, $this -> list_elements($one));
+            }
+            return $elements;
+        }
+
+        if ($element instanceof tr || $element instanceof thead || $element instanceof tbody) {
+            return $this -> list_elements($element -> getChildren());
+        }
+
+        return array($element);
+    }
+    protected function buildTable($list, $cols, $header = false, $parity = true) {
+        $rows = count($list) / $cols;
+        if (count($list) % $cols != 0) {
+            if ($header == true) {
+                $error = <th />;
+            } else {
+                $error = <td />;
+            }
+
+            $error -> setAttribute('colspan', $cols);
+            $error -> addClass('error');
+            $error -> appendChild(<x:frag> Elementele nu pot fi organizate intr-un tabel cu <strong> {$cols}
+                                      </strong> coloane.
+                                  </x:frag>);
+            return
+              <tr>
+                {$error}
+              </tr>;
+         }
+
+         $content = <x:frag />;
+
+         for ($i = 0; $i < $rows; ++$i) {
+             $row = <tr />;
+             if ($parity == true) {
+                if ($i % 2) {
+                    $row -> addClass('even');
+                } else {
+                    $row -> addClass('odd');
+                }
+             }
+
+             for ($j = 0; $j < $cols; ++$j) {
+                 if ($list[$i * $cols + $j] instanceof :td or $list[$i * $cols + $j] instanceof :th) {
+                     $row -> appendChild($list[$i * $cols + $j]);
+                 } elseif ($header == false) {
+                     $row -> appendChild(<td>
+                                           {$list[$i * $cols + $j] }
+                                        </td>);
+                 } else {
+                     $row -> appendChild(<th>
+                                           {$list[$i * $cols + $j] }
+                                         </th>);
+                 }
+             }
+             $content -> appendChild($row);
+         }
+
+         return $content;
+    }
+    protected function render() {
+        $cols = $this -> getAttribute('cols');
+        if ($cols == 0) {
+            $cols = count($this -> list_elements($this -> getChildren()));
+        }
+
+        $table = <table />;
+        $this -> sendAttributes($table);
+
+        // Making the table sortable
+        if ($this -> getAttribute('sortable') == true) {
+            $table -> addClass('sortable');
+        }
+        $children = $this -> getChildren();
+
+        $bodybegin = 0;
+        if ($this -> getAttribute('header') == true) {
+
+            if ($children[0] instanceof thead || $children[0] instanceof tr) {
+                $header = <thead>
+-                           {$this -> buildTable($children[0] -> list_elements, $cols, true, false)}
+                          </thead>;
+                $bodybegin = 1;
+            } else {
+                $header = <thead>
+                            {$this -> buildTable(array_slice($children, 0, $cols), $cols, true, false)}
+                          </thead>;
+                $bodybegin = $cols;
+            }
+        } else {
+            $header = <x:frag />;
+        }
+
+        $content = <tbody>
+                     {$this -> buildTable(array_slice($children, $bodybegin), $cols, false)}
+                   </tbody>;
+
+        // FIXME: add support for footer as it is for header
+        $footer = <tfoot />;
+
+        $table -> appendChild(array($header, $content, $footer));
+        return $table;
+    }
+}
+?>
Index: www/xhp/ui/textblock.php
new file mode 100644
===================================================================
--- www/xhp/ui/textblock.php	(revision 0)
+++ www/xhp/ui/textblock.php	(working copy)
@@ -0,0 +1,107 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/revision-warning.php');
+require_once(IA_ROOT_DIR . 'www/macros/macro_smfcomments.php');
+require_once(IA_ROOT_DIR . 'www/xhp/ui/link.php');
+
+class :ui:textblock extends :ui:element {
+    children empty;
+
+    attribute
+        :div,
+        array textblock @required,
+        bool show_forum = true,
+        int revision = 0,
+        int revision_count = 0,
+        array permitted_actions;
+
+    protected function render() {
+        $textblock = $this -> getAttribute('textblock');
+        $show_forum = $this -> getAttribute('show_forum');
+        $revision = $this -> getAttribute('revision');
+        $revision_count = $this -> getAttribute('revision_count');
+        $permitted_actions = $this -> getAttribute('permitted_actions');
+
+        $element = <x:frag />;
+
+        if (is_array($permitted_actions)) {
+            $element -> appendChild(<ui:textblock:actions textblock={$textblock}
+                                        permitted_actions={$permitted_actions} />);
+        }
+
+        // Show revision warning in case we show a revision
+        if ($revision != 0 && $revision_count != 0) {
+            $warning = <ui:revision-warning revision={$revision}
+                    revision_count={$revision}
+                    timestamp={$textblock['timestamp']} />;
+
+            if (in_array('delete-revision', $permitted_actions)) {
+                $warning -> setAttribute('can_delete', true);
+            }
+
+            $element -> appendChild($warning);
+        }
+
+        $div = <div class="wiki_text_block"> {HTML($textblock['text'])} </div>;
+        $this -> sendAttributes($div);
+
+        $element -> appendChild($div);
+
+        if ($show_forum == true && $textblock['forum_topic']) {
+            $element -> appendChild(macro_smfcommects(array('topic' => $textblock['forum_topic'],
+                                                            'display' => 'hide')));
+        }
+        return $element;
+    }
+}
+
+class :ui:textblock:actions extends :ui:element {
+    children empty;
+
+    attribute
+        array permitted_actions @required,
+        array textblock @required;
+
+    protected function render() {
+        $permitted_actions = $this -> getAttribute('permitted_actions');
+        $textblock = $this -> getAttribute('textblock');
+        $actions = <ui:list /> ;
+
+        log_print_r($permitted_actions);
+        if (in_array('edit', $permitted_actions)) {
+           $actions -> appendChild(<ui:link accesskey="e" href={url_textblock_edit($textblock['name'])}> Editează </ui:link>);
+        }
+
+        if (in_array('history', $permitted_actions)) {
+            $actions -> appendChild(<ui:link accesskey="i" href={url_textblock_history($textblock['name'])}> Istoria </ui:link>);
+        }
+
+        if (in_array('move', $permitted_actions)) {
+            $actions -> appendChild(<ui:link accesskey="u" href={url_textblock_move($textblock['name'])}> Mută </ui:link>);
+        }
+
+        if (in_array('copy', $permitted_actions)) {
+            $actions -> appendChild(<ui:link accesskey="c" href={url_textblock_copy($textblock['name'])}> Copiază </ui:link>);
+        }
+        if (in_array('delete', $permitted_actions)) {
+            $actions -> appendChild(<ui:link:post accesskey="r" href={url_textblock_delete($textblock['name'])}
+                                        confirm_request="Aceasta actiune este ireversibila! Doresti sa continui?">
+                                      Şterge
+                                    </ui:link:post>);
+        }
+        if (in_array('attach', $permitted_actions)) {
+            $actions -> appendChild(<ui:link accesskey="t" href={url_attachment_new($textblock['name'])}> Ataşează </ui:link>);
+        }
+
+        if (in_array('list-attach', $permitted_actions)) {
+            $actions -> appendChild(<ui:link accesskey="l" href={url_attachment_list($textblock['name'])}> Listează ataşamente </ui:link>);
+        }
+
+        if (count($actions -> getChildren()) == 0) {
+            return <x:frag />;
+        } else {
+            return <div id="wikiOps"> {$actions} </div>;
+        }
+    }
+}
Index: www/xhp/ui/user.php
new file mode 100644
===================================================================
--- www/xhp/ui/user.php	(revision 0)
+++ www/xhp/ui/user.php	(working copy)
@@ -0,0 +1,130 @@
+<?php
+
+require_once(IA_ROOT_DIR . 'www/xhp/ui/base.php');
+require_once(IA_ROOT_DIR . 'www/format/format.php');
+abstract class :ui:user extends :ui:element {
+    attribute
+        array user;
+}
+
+class :ui:user:avatar extends :ui:user {
+    attribute
+        enum { "tiny", "small", "normal", "forum", "big", "full" } size = "full";
+
+    protected function render() {
+        $user = $this -> getAttribute('user');
+        $avatar =
+          <img src={url_user_avatar($user, $this -> getAttribute('size'))}
+              alt={$user['username']} />;
+
+        return $avatar;
+    }
+}
+
+class :ui:user:rating-badge extends :ui:user {
+
+    protected function render() {
+        $user = $this -> getAttribute('user');
+        $is_admin = user_is_admin($user, false);
+        $rating = $user['rating_cache'];
+        $class = rating_group($rating, $is_admin);
+        $rating = rating_scale($rating);
+
+        if ($rating) {
+            $tag =
+              <ui:link:user page="rating" user={$user} class={'rating-badge-' . $class}
+                  title={'Rating ' . $user['username'] . ': ' . $rating}>
+                &bull;
+              </ui:link:user>;
+        } else {
+            $tag = <x:frag />;
+        }
+        return $tag;
+    }
+}
+
+class :ui:user:link extends :ui:user {
+    attribute
+        bool show_rating = true;
+
+    protected function render() {
+        $user = $this -> getAttribute('user');
+        $link =
+          <ui:link:user user={$user}>
+            {$user['full_name']}
+          </ui:link:user>;
+
+        if ($this -> getAttribute('show_rating') && !is_null($user['rating_cache'])) {
+            $link -> setAttribute('class', 'user_' . rating_group($user['rating_cache']));
+        }
+
+        if ($this -> getAttribute('show_rating')) {
+            $rating_badge = <ui:user:rating-badge user={$user} />;
+        } else {
+            $rating_badge = <x:frag />;
+        }
+
+        return
+          <x:frag>
+            {$rating_badge}
+            {$link}
+          </x:frag>;
+    }
+}
+class :ui:user:tiny extends :ui:user {
+
+    protected function render() {
+        $user = $this -> getAttribute('user');
+        $tag =
+          <x:frag>
+            <span class="tiny-user">
+              <ui:link:user user={$user}>
+                <ui:user:avatar size="tiny" />
+                {$user['full_name']}
+              </ui:link:user>
+
+              <ui:user:rating-badge user={$user}/>
+
+              <span class="username">
+                <ui:link:user user={$user}>
+                  {$user['username']}
+                </ui:link:user>
+              </span>
+
+            </span>
+          </x:frag>;
+
+       return $tag;
+    }
+}
+
+class :ui:user:normal extends :ui:user {
+
+    protected function render() {
+        $user = $this -> getAttribute('user');
+        $tag =
+          <x:frag>
+           <div class="normal-user">
+             <ui:link:user user={$user}>
+               <ui:user:avatar size="small" />
+             </ui:link:user>
+
+             <span class="fullname">
+               {$user['full_name']}
+             </span>
+
+             <br />
+
+             <ui:user:rating-badge user={$user}/>
+
+             <ui:link:user user={$user}>
+               <span class="username">
+                 {$user['username']}
+               </span>
+             </ui:link:user>
+           </div>
+         </x:frag>;
+       return $tag;
+    }
+}
+?>
