An alternative to UBB.threads
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Inga 🏳‍🌈 011afb4818 added readme 8 months ago
Builder Project options changed 12 years ago
FLocal.Common Fixed a critical XSS vulnerability 12 years ago
FLocal.IISHandler System.Diagnostics.Stopwatch is used instead of DateTime 11 years ago
FLocal.Migration.Console Fixed some bugs with import of discussion threads? 12 years ago
FLocal.Migration.Gateway UsersImporter up-to-date 13 years ago
FLocal.Patcher.Common Mentions dataobject implemented 12 years ago
FLocal.Patcher.IISHandler Completed integrating Patcher with FLocal; some PostgresDBTraits features are not implemented yet 13 years ago
MySQLConnector LoadIdsByConditions now accepts ColumnSpec idSpec as an argument 12 years ago
Patcher Patcher compatibility with postgres improved ('timestamp with time zone' data type support) 12 years ago
Patcher.Web DBIsOutdatedException implemented 13 years ago
Resources/FLocal C:/Program Files (x86)/Git/Replies/ URLs renamed to /Mentions/ 12 years ago
TexCompiler Projects and libraries renamed 13 years ago
ThirdParty PJonDeveloment.BBCode readme modified 12 years ago
Web.Core Post.mentionedUsersIds optimized 12 years ago
Web.IISUploadHandler Projects and libraries renamed 13 years ago
.gitignore .gitignore improved 12 years ago
FLocal.sln Project options changed 12 years ago
LICENSE.TXT Licenses added 12 years ago added readme 8 months ago
build-all.bat build-all.bat UI improved 12 years ago
build-debug.bat Build procedure improved 13 years ago
build-release.bat Build procedure improved 13 years ago
export-info.bat Fixed a critical bug with patcher logs on a production server 13 years ago



This is a fully functional alternative to UBB.threads, complete with capability of migration from UBB.threads.

First working release implemented in summer 2010, with occasional additional features added from time to time over the next two years.


It is highly performant, compared to UBB.threads: on a mid-range rental server in 2010 (dual-core Nehalem CPU, 8GB RAM, 32-bit PostgreSQL, 7200 RPM HDD) with over 10 million posts in the database, it handles 1000 simple requests per second with ease, with response time under DateTime's 16ms precision.

In addition to most features of stock UBB.threads, it also supports advanced features that were implemented by into their custom UBB.threads codebase:

  • Layers (normal, offtopic, garbage), with every post having a layer, with moderators being able to limit max layer for every user's posts by moderating actions, and visibility of layers configurable by every user on per-board basis;
  • Moderation "strikes" (one notice in a specific board is worth one point; one warning, three points; notices and warnings have expiration dates; total weight of over 9 or 27 points limits max layer for posts of that user in that board);
  • Threads can be locked (so that nobody except administrators can post in them);
  • Default UI of (heavily patched over UBB.threads default);
  • "Light" UI for extremely low-traffic surfing (minimal HTML, almost no JS, no automatic display of uploaded files);
  • Non-standard colors for usernames of some users (by request);
  • Themes and smileys from;
  • New users registration is only allowed from configurable allowlist of specific subnets;
  • etc

and some additional features never implemented by

  • Ability to list public uploaded files in order (only for logged-in users);
  • Ability for users to retroactively limit the visibility of all their posts to logged-in users or to nobody at all;
  • Hotlinking for uploaded images is blocked; they can only be viewed when embedded in local posts;
  • "Modern" UI in Metro-style (resembling Zune UI);
  • RSS (as yet another UI variant);
  • Raw XML (as yet another UI variant), for programmatic access by custom user-created applications, kind of like an API;
  • Private messages are grouped in threads by user;
  • Instead of "Zone" board (where thread author is a thread moderator), there are "Zone" subboards per user;
  • LaTeX support in posts;
  • Typographic improvements (e.g. double minus is replaced by mdash);
  • Threads are never "archived" (because, as opposed to, there are no performance reasons to do so), even unpinned threads with last posts over two months old can still be replied to (but old posts feature a slowpoke icon for actions, so that it's clear that they're old);
  • Last read post in thread is always tracked (as opposed to UBB.threads always marking any thread not visited for over seven days as fully read);
  • A page listing all posts replying to or mentioning any specific user (as opposed to listing only posts replying to that user);
  • A page listing all threads by a specific user;
  • Machichara similar to the ones featured on japanese cell phones;
  • Coexistence of imported posts with the new posts; regular importing of new posts from UBB.threads instance without conflicts with the posts originally created on the new software (imported posts always get lower IDs regardless of their date, so they're always displayed below);
  • Multi-language support (at the moment, only Russian and English are supported);
  • etc.

Technical details

This is mostly a C# 3.5 application, running in IIS 7.5 as a managed IIS module. Only one instance is running at a time, which allows to do aggressive caching of DB entries (especially considering that there is no 64-bit PostgreSQL on Windows, so PostgreSQL is limited to 2GB RAM).

It is currently running on Windows Server 2008 R2 Web Edition x64 with PostgreSQL 8.4, on a Hetzner box with 8GB RAM and 320GB 7200RPM HDD.

This is written completely from scratch; the only third-party libraries used are .NET Framework 3.5, Npgsql to connect to PostgreSQL, NConsoler for convenient CLI UI of importing tool, lightly modifiedBBCode parser by PJonDevelopment as a base library for BBCode (I implemented support for specific tags), and .NET Framework stock XSLT processing library.

This project is 25k LOC of C# code, and 15k LOC of XSLT files (for all supported designs).

Technical solutions

Key highlights:


Implemented via pluggable XSLT template sets in Resources/FLocal/templates.

At the moment, only four template sets are implemented:

  • Classic: the default one from, supporting all its themes;
  • Lite: inspired by the lite UI from, but even more efficient traffic-wise;
  • Modern: created from scratch, inspired by look of Metro UIs (such as the one in Zune), with tiles and stuff;
  • RSS: created from scratch, allows subscribing to basically any page (board, thread, posts of a specific user, mentions of a specific user, you name it);
  • Not technically a template set: raw XML, unprocessed by XSLT, for programmatic usage by third-party clients (e.g. can be used to implement a smartphone app).


I implemented my own ORM here, with the following features:

  • (SQL) DB-agnostic, all postgres-specific quirks are implemented in a separate PostgresDBTraits.cs;

  • Agressive caching of all entries fetched from DB; since only one instance of the application is supposed to be running at a time, and only on one server, we can assume that the data in DB is never changed unless application changed it, so we can safely cache everything, and only invalidate specific entries when we ourselves update them. This also means that for every entry in db fetched to the application, only one unique object exists in RAM.

    Implementation is in Registry.cs; example of usage is in Post.cs.

  • Bundling of all DB changes into one complex changeset (supporting incrementing values or referring to the newly inserted rows), executed in one go without any additional business logic slowing it down, ensuring quick transactions and reducing the possibility of conflicts. Implementation is in ChangeSet.cs; example of usage is in Thread.cs:getNewPostChanges for a new reply.

    Additionally, changeset executor reorders changes to conform to the ideal table locking order, and if that's not possible, locks the required tables early, ensuring that there will be no deadlocks.

DB patching

There is a separate service intended to keep DB schema up-to-date and to install the latest patches only once, and to revert them if needed: Updater.cs.

Example of usage: Patch_00002_mentions.xml.


All builds are packaged as MSI installer files; it is enough to run a new MSI file on the server to update to a new version that will automatically handle all new requests.