// Code generated by Gosora's Router Generator. DO NOT EDIT.
/* This file was automatically generated by the software. Please don't edit it as your changes may be overwritten at any moment. */
package main

import (
	"log"
	"strings"
	//"bytes"
	"strconv"
	"compress/gzip"
	"sync"
	"sync/atomic"
	"errors"
	"os"
	"net/http"
	"time"

	c "github.com/Azareal/Gosora/common"
	co "github.com/Azareal/Gosora/common/counters"
	"github.com/Azareal/Gosora/uutils"
	"github.com/Azareal/Gosora/routes"
	"github.com/Azareal/Gosora/routes/panel"
)

var ErrNoRoute = errors.New("That route doesn't exist.")
// TODO: What about the /uploads/ route? x.x
var RouteMap = map[string]interface{}{ 
	"routes.Error": routes.Error,
	"routes.Overview": routes.Overview,
	"routes.CustomPage": routes.CustomPage,
	"routes.ForumList": routes.ForumList,
	"routes.ViewForum": routes.ViewForum,
	"routes.ChangeTheme": routes.ChangeTheme,
	"routes.ShowAttachment": routes.ShowAttachment,
	"common.RouteWebsockets": c.RouteWebsockets,
	"routeAPIPhrases": routeAPIPhrases,
	"routes.APIMe": routes.APIMe,
	"routeJSAntispam": routeJSAntispam,
	"routeAPI": routeAPI,
	"routes.ReportSubmit": routes.ReportSubmit,
	"routes.TopicListMostViewed": routes.TopicListMostViewed,
	"routes.CreateTopic": routes.CreateTopic,
	"routes.TopicList": routes.TopicList,
	"panel.Forums": panel.Forums,
	"panel.ForumsCreateSubmit": panel.ForumsCreateSubmit,
	"panel.ForumsDelete": panel.ForumsDelete,
	"panel.ForumsDeleteSubmit": panel.ForumsDeleteSubmit,
	"panel.ForumsOrderSubmit": panel.ForumsOrderSubmit,
	"panel.ForumsEdit": panel.ForumsEdit,
	"panel.ForumsEditSubmit": panel.ForumsEditSubmit,
	"panel.ForumsEditPermsSubmit": panel.ForumsEditPermsSubmit,
	"panel.ForumsEditPermsAdvance": panel.ForumsEditPermsAdvance,
	"panel.ForumsEditPermsAdvanceSubmit": panel.ForumsEditPermsAdvanceSubmit,
	"panel.Settings": panel.Settings,
	"panel.SettingEdit": panel.SettingEdit,
	"panel.SettingEditSubmit": panel.SettingEditSubmit,
	"panel.WordFilters": panel.WordFilters,
	"panel.WordFiltersCreateSubmit": panel.WordFiltersCreateSubmit,
	"panel.WordFiltersEdit": panel.WordFiltersEdit,
	"panel.WordFiltersEditSubmit": panel.WordFiltersEditSubmit,
	"panel.WordFiltersDeleteSubmit": panel.WordFiltersDeleteSubmit,
	"panel.Pages": panel.Pages,
	"panel.PagesCreateSubmit": panel.PagesCreateSubmit,
	"panel.PagesEdit": panel.PagesEdit,
	"panel.PagesEditSubmit": panel.PagesEditSubmit,
	"panel.PagesDeleteSubmit": panel.PagesDeleteSubmit,
	"panel.Themes": panel.Themes,
	"panel.ThemesSetDefault": panel.ThemesSetDefault,
	"panel.ThemesMenus": panel.ThemesMenus,
	"panel.ThemesMenusEdit": panel.ThemesMenusEdit,
	"panel.ThemesMenuItemEdit": panel.ThemesMenuItemEdit,
	"panel.ThemesMenuItemEditSubmit": panel.ThemesMenuItemEditSubmit,
	"panel.ThemesMenuItemCreateSubmit": panel.ThemesMenuItemCreateSubmit,
	"panel.ThemesMenuItemDeleteSubmit": panel.ThemesMenuItemDeleteSubmit,
	"panel.ThemesMenuItemOrderSubmit": panel.ThemesMenuItemOrderSubmit,
	"panel.ThemesWidgets": panel.ThemesWidgets,
	"panel.ThemesWidgetsEditSubmit": panel.ThemesWidgetsEditSubmit,
	"panel.ThemesWidgetsCreateSubmit": panel.ThemesWidgetsCreateSubmit,
	"panel.ThemesWidgetsDeleteSubmit": panel.ThemesWidgetsDeleteSubmit,
	"panel.Plugins": panel.Plugins,
	"panel.PluginsActivate": panel.PluginsActivate,
	"panel.PluginsDeactivate": panel.PluginsDeactivate,
	"panel.PluginsInstall": panel.PluginsInstall,
	"panel.Users": panel.Users,
	"panel.UsersEdit": panel.UsersEdit,
	"panel.UsersEditSubmit": panel.UsersEditSubmit,
	"panel.UsersAvatarSubmit": panel.UsersAvatarSubmit,
	"panel.UsersAvatarRemoveSubmit": panel.UsersAvatarRemoveSubmit,
	"panel.AnalyticsViews": panel.AnalyticsViews,
	"panel.AnalyticsRoutes": panel.AnalyticsRoutes,
	"panel.AnalyticsRoutesPerf": panel.AnalyticsRoutesPerf,
	"panel.AnalyticsAgents": panel.AnalyticsAgents,
	"panel.AnalyticsSystems": panel.AnalyticsSystems,
	"panel.AnalyticsLanguages": panel.AnalyticsLanguages,
	"panel.AnalyticsReferrers": panel.AnalyticsReferrers,
	"panel.AnalyticsRouteViews": panel.AnalyticsRouteViews,
	"panel.AnalyticsAgentViews": panel.AnalyticsAgentViews,
	"panel.AnalyticsForumViews": panel.AnalyticsForumViews,
	"panel.AnalyticsSystemViews": panel.AnalyticsSystemViews,
	"panel.AnalyticsLanguageViews": panel.AnalyticsLanguageViews,
	"panel.AnalyticsReferrerViews": panel.AnalyticsReferrerViews,
	"panel.AnalyticsPosts": panel.AnalyticsPosts,
	"panel.AnalyticsMemory": panel.AnalyticsMemory,
	"panel.AnalyticsActiveMemory": panel.AnalyticsActiveMemory,
	"panel.AnalyticsTopics": panel.AnalyticsTopics,
	"panel.AnalyticsForums": panel.AnalyticsForums,
	"panel.AnalyticsPerf": panel.AnalyticsPerf,
	"panel.Groups": panel.Groups,
	"panel.GroupsEdit": panel.GroupsEdit,
	"panel.GroupsEditPromotions": panel.GroupsEditPromotions,
	"panel.GroupsPromotionsCreateSubmit": panel.GroupsPromotionsCreateSubmit,
	"panel.GroupsPromotionsDeleteSubmit": panel.GroupsPromotionsDeleteSubmit,
	"panel.GroupsEditPerms": panel.GroupsEditPerms,
	"panel.GroupsEditSubmit": panel.GroupsEditSubmit,
	"panel.GroupsEditPermsSubmit": panel.GroupsEditPermsSubmit,
	"panel.GroupsCreateSubmit": panel.GroupsCreateSubmit,
	"panel.Backups": panel.Backups,
	"panel.LogsRegs": panel.LogsRegs,
	"panel.LogsMod": panel.LogsMod,
	"panel.LogsAdmin": panel.LogsAdmin,
	"panel.Debug": panel.Debug,
	"panel.Dashboard": panel.Dashboard,
	"routes.AccountEdit": routes.AccountEdit,
	"routes.AccountEditPassword": routes.AccountEditPassword,
	"routes.AccountEditPasswordSubmit": routes.AccountEditPasswordSubmit,
	"routes.AccountEditAvatarSubmit": routes.AccountEditAvatarSubmit,
	"routes.AccountEditRevokeAvatarSubmit": routes.AccountEditRevokeAvatarSubmit,
	"routes.AccountEditUsernameSubmit": routes.AccountEditUsernameSubmit,
	"routes.AccountEditPrivacy": routes.AccountEditPrivacy,
	"routes.AccountEditPrivacySubmit": routes.AccountEditPrivacySubmit,
	"routes.AccountEditMFA": routes.AccountEditMFA,
	"routes.AccountEditMFASetup": routes.AccountEditMFASetup,
	"routes.AccountEditMFASetupSubmit": routes.AccountEditMFASetupSubmit,
	"routes.AccountEditMFADisableSubmit": routes.AccountEditMFADisableSubmit,
	"routes.AccountEditEmail": routes.AccountEditEmail,
	"routes.AccountEditEmailTokenSubmit": routes.AccountEditEmailTokenSubmit,
	"routes.AccountLogins": routes.AccountLogins,
	"routes.AccountBlocked": routes.AccountBlocked,
	"routes.LevelList": routes.LevelList,
	"routes.Convos": routes.Convos,
	"routes.ConvosCreate": routes.ConvosCreate,
	"routes.Convo": routes.Convo,
	"routes.ConvosCreateSubmit": routes.ConvosCreateSubmit,
	"routes.ConvosCreateReplySubmit": routes.ConvosCreateReplySubmit,
	"routes.ConvosDeleteReplySubmit": routes.ConvosDeleteReplySubmit,
	"routes.ConvosEditReplySubmit": routes.ConvosEditReplySubmit,
	"routes.RelationsBlockCreate": routes.RelationsBlockCreate,
	"routes.RelationsBlockCreateSubmit": routes.RelationsBlockCreateSubmit,
	"routes.RelationsBlockRemove": routes.RelationsBlockRemove,
	"routes.RelationsBlockRemoveSubmit": routes.RelationsBlockRemoveSubmit,
	"routes.ViewProfile": routes.ViewProfile,
	"routes.BanUserSubmit": routes.BanUserSubmit,
	"routes.UnbanUser": routes.UnbanUser,
	"routes.ActivateUser": routes.ActivateUser,
	"routes.IPSearch": routes.IPSearch,
	"routes.DeletePostsSubmit": routes.DeletePostsSubmit,
	"routes.CreateTopicSubmit": routes.CreateTopicSubmit,
	"routes.EditTopicSubmit": routes.EditTopicSubmit,
	"routes.DeleteTopicSubmit": routes.DeleteTopicSubmit,
	"routes.StickTopicSubmit": routes.StickTopicSubmit,
	"routes.UnstickTopicSubmit": routes.UnstickTopicSubmit,
	"routes.LockTopicSubmit": routes.LockTopicSubmit,
	"routes.UnlockTopicSubmit": routes.UnlockTopicSubmit,
	"routes.MoveTopicSubmit": routes.MoveTopicSubmit,
	"routes.LikeTopicSubmit": routes.LikeTopicSubmit,
	"routes.UnlikeTopicSubmit": routes.UnlikeTopicSubmit,
	"routes.AddAttachToTopicSubmit": routes.AddAttachToTopicSubmit,
	"routes.RemoveAttachFromTopicSubmit": routes.RemoveAttachFromTopicSubmit,
	"routes.ViewTopic": routes.ViewTopic,
	"routes.CreateReplySubmit": routes.CreateReplySubmit,
	"routes.ReplyEditSubmit": routes.ReplyEditSubmit,
	"routes.ReplyDeleteSubmit": routes.ReplyDeleteSubmit,
	"routes.ReplyLikeSubmit": routes.ReplyLikeSubmit,
	"routes.ReplyUnlikeSubmit": routes.ReplyUnlikeSubmit,
	"routes.AddAttachToReplySubmit": routes.AddAttachToReplySubmit,
	"routes.RemoveAttachFromReplySubmit": routes.RemoveAttachFromReplySubmit,
	"routes.ProfileReplyCreateSubmit": routes.ProfileReplyCreateSubmit,
	"routes.ProfileReplyEditSubmit": routes.ProfileReplyEditSubmit,
	"routes.ProfileReplyDeleteSubmit": routes.ProfileReplyDeleteSubmit,
	"routes.PollVote": routes.PollVote,
	"routes.PollResults": routes.PollResults,
	"routes.AccountLogin": routes.AccountLogin,
	"routes.AccountRegister": routes.AccountRegister,
	"routes.AccountLogout": routes.AccountLogout,
	"routes.AccountLoginSubmit": routes.AccountLoginSubmit,
	"routes.AccountLoginMFAVerify": routes.AccountLoginMFAVerify,
	"routes.AccountLoginMFAVerifySubmit": routes.AccountLoginMFAVerifySubmit,
	"routes.AccountRegisterSubmit": routes.AccountRegisterSubmit,
	"routes.AccountPasswordReset": routes.AccountPasswordReset,
	"routes.AccountPasswordResetSubmit": routes.AccountPasswordResetSubmit,
	"routes.AccountPasswordResetToken": routes.AccountPasswordResetToken,
	"routes.AccountPasswordResetTokenSubmit": routes.AccountPasswordResetTokenSubmit,
	"routes.DynamicRoute": routes.DynamicRoute,
	"routes.UploadedFile": routes.UploadedFile,
	"routes.StaticFile": routes.StaticFile,
	"routes.RobotsTxt": routes.RobotsTxt,
	"routes.SitemapXml": routes.SitemapXml,
	"routes.OpenSearchXml": routes.OpenSearchXml,
	"routes.Favicon": routes.Favicon,
	"routes.BadRoute": routes.BadRoute,
	"routes.HTTPSRedirect": routes.HTTPSRedirect,
}

// ! NEVER RELY ON THESE REMAINING THE SAME BETWEEN COMMITS
var routeMapEnum = map[string]int{ 
	"routes.Error": 0,
	"routes.Overview": 1,
	"routes.CustomPage": 2,
	"routes.ForumList": 3,
	"routes.ViewForum": 4,
	"routes.ChangeTheme": 5,
	"routes.ShowAttachment": 6,
	"common.RouteWebsockets": 7,
	"routeAPIPhrases": 8,
	"routes.APIMe": 9,
	"routeJSAntispam": 10,
	"routeAPI": 11,
	"routes.ReportSubmit": 12,
	"routes.TopicListMostViewed": 13,
	"routes.CreateTopic": 14,
	"routes.TopicList": 15,
	"panel.Forums": 16,
	"panel.ForumsCreateSubmit": 17,
	"panel.ForumsDelete": 18,
	"panel.ForumsDeleteSubmit": 19,
	"panel.ForumsOrderSubmit": 20,
	"panel.ForumsEdit": 21,
	"panel.ForumsEditSubmit": 22,
	"panel.ForumsEditPermsSubmit": 23,
	"panel.ForumsEditPermsAdvance": 24,
	"panel.ForumsEditPermsAdvanceSubmit": 25,
	"panel.Settings": 26,
	"panel.SettingEdit": 27,
	"panel.SettingEditSubmit": 28,
	"panel.WordFilters": 29,
	"panel.WordFiltersCreateSubmit": 30,
	"panel.WordFiltersEdit": 31,
	"panel.WordFiltersEditSubmit": 32,
	"panel.WordFiltersDeleteSubmit": 33,
	"panel.Pages": 34,
	"panel.PagesCreateSubmit": 35,
	"panel.PagesEdit": 36,
	"panel.PagesEditSubmit": 37,
	"panel.PagesDeleteSubmit": 38,
	"panel.Themes": 39,
	"panel.ThemesSetDefault": 40,
	"panel.ThemesMenus": 41,
	"panel.ThemesMenusEdit": 42,
	"panel.ThemesMenuItemEdit": 43,
	"panel.ThemesMenuItemEditSubmit": 44,
	"panel.ThemesMenuItemCreateSubmit": 45,
	"panel.ThemesMenuItemDeleteSubmit": 46,
	"panel.ThemesMenuItemOrderSubmit": 47,
	"panel.ThemesWidgets": 48,
	"panel.ThemesWidgetsEditSubmit": 49,
	"panel.ThemesWidgetsCreateSubmit": 50,
	"panel.ThemesWidgetsDeleteSubmit": 51,
	"panel.Plugins": 52,
	"panel.PluginsActivate": 53,
	"panel.PluginsDeactivate": 54,
	"panel.PluginsInstall": 55,
	"panel.Users": 56,
	"panel.UsersEdit": 57,
	"panel.UsersEditSubmit": 58,
	"panel.UsersAvatarSubmit": 59,
	"panel.UsersAvatarRemoveSubmit": 60,
	"panel.AnalyticsViews": 61,
	"panel.AnalyticsRoutes": 62,
	"panel.AnalyticsRoutesPerf": 63,
	"panel.AnalyticsAgents": 64,
	"panel.AnalyticsSystems": 65,
	"panel.AnalyticsLanguages": 66,
	"panel.AnalyticsReferrers": 67,
	"panel.AnalyticsRouteViews": 68,
	"panel.AnalyticsAgentViews": 69,
	"panel.AnalyticsForumViews": 70,
	"panel.AnalyticsSystemViews": 71,
	"panel.AnalyticsLanguageViews": 72,
	"panel.AnalyticsReferrerViews": 73,
	"panel.AnalyticsPosts": 74,
	"panel.AnalyticsMemory": 75,
	"panel.AnalyticsActiveMemory": 76,
	"panel.AnalyticsTopics": 77,
	"panel.AnalyticsForums": 78,
	"panel.AnalyticsPerf": 79,
	"panel.Groups": 80,
	"panel.GroupsEdit": 81,
	"panel.GroupsEditPromotions": 82,
	"panel.GroupsPromotionsCreateSubmit": 83,
	"panel.GroupsPromotionsDeleteSubmit": 84,
	"panel.GroupsEditPerms": 85,
	"panel.GroupsEditSubmit": 86,
	"panel.GroupsEditPermsSubmit": 87,
	"panel.GroupsCreateSubmit": 88,
	"panel.Backups": 89,
	"panel.LogsRegs": 90,
	"panel.LogsMod": 91,
	"panel.LogsAdmin": 92,
	"panel.Debug": 93,
	"panel.Dashboard": 94,
	"routes.AccountEdit": 95,
	"routes.AccountEditPassword": 96,
	"routes.AccountEditPasswordSubmit": 97,
	"routes.AccountEditAvatarSubmit": 98,
	"routes.AccountEditRevokeAvatarSubmit": 99,
	"routes.AccountEditUsernameSubmit": 100,
	"routes.AccountEditPrivacy": 101,
	"routes.AccountEditPrivacySubmit": 102,
	"routes.AccountEditMFA": 103,
	"routes.AccountEditMFASetup": 104,
	"routes.AccountEditMFASetupSubmit": 105,
	"routes.AccountEditMFADisableSubmit": 106,
	"routes.AccountEditEmail": 107,
	"routes.AccountEditEmailTokenSubmit": 108,
	"routes.AccountLogins": 109,
	"routes.AccountBlocked": 110,
	"routes.LevelList": 111,
	"routes.Convos": 112,
	"routes.ConvosCreate": 113,
	"routes.Convo": 114,
	"routes.ConvosCreateSubmit": 115,
	"routes.ConvosCreateReplySubmit": 116,
	"routes.ConvosDeleteReplySubmit": 117,
	"routes.ConvosEditReplySubmit": 118,
	"routes.RelationsBlockCreate": 119,
	"routes.RelationsBlockCreateSubmit": 120,
	"routes.RelationsBlockRemove": 121,
	"routes.RelationsBlockRemoveSubmit": 122,
	"routes.ViewProfile": 123,
	"routes.BanUserSubmit": 124,
	"routes.UnbanUser": 125,
	"routes.ActivateUser": 126,
	"routes.IPSearch": 127,
	"routes.DeletePostsSubmit": 128,
	"routes.CreateTopicSubmit": 129,
	"routes.EditTopicSubmit": 130,
	"routes.DeleteTopicSubmit": 131,
	"routes.StickTopicSubmit": 132,
	"routes.UnstickTopicSubmit": 133,
	"routes.LockTopicSubmit": 134,
	"routes.UnlockTopicSubmit": 135,
	"routes.MoveTopicSubmit": 136,
	"routes.LikeTopicSubmit": 137,
	"routes.UnlikeTopicSubmit": 138,
	"routes.AddAttachToTopicSubmit": 139,
	"routes.RemoveAttachFromTopicSubmit": 140,
	"routes.ViewTopic": 141,
	"routes.CreateReplySubmit": 142,
	"routes.ReplyEditSubmit": 143,
	"routes.ReplyDeleteSubmit": 144,
	"routes.ReplyLikeSubmit": 145,
	"routes.ReplyUnlikeSubmit": 146,
	"routes.AddAttachToReplySubmit": 147,
	"routes.RemoveAttachFromReplySubmit": 148,
	"routes.ProfileReplyCreateSubmit": 149,
	"routes.ProfileReplyEditSubmit": 150,
	"routes.ProfileReplyDeleteSubmit": 151,
	"routes.PollVote": 152,
	"routes.PollResults": 153,
	"routes.AccountLogin": 154,
	"routes.AccountRegister": 155,
	"routes.AccountLogout": 156,
	"routes.AccountLoginSubmit": 157,
	"routes.AccountLoginMFAVerify": 158,
	"routes.AccountLoginMFAVerifySubmit": 159,
	"routes.AccountRegisterSubmit": 160,
	"routes.AccountPasswordReset": 161,
	"routes.AccountPasswordResetSubmit": 162,
	"routes.AccountPasswordResetToken": 163,
	"routes.AccountPasswordResetTokenSubmit": 164,
	"routes.DynamicRoute": 165,
	"routes.UploadedFile": 166,
	"routes.StaticFile": 167,
	"routes.RobotsTxt": 168,
	"routes.SitemapXml": 169,
	"routes.OpenSearchXml": 170,
	"routes.Favicon": 171,
	"routes.BadRoute": 172,
	"routes.HTTPSRedirect": 173,
}
var reverseRouteMapEnum = map[int]string{ 
	0: "routes.Error",
	1: "routes.Overview",
	2: "routes.CustomPage",
	3: "routes.ForumList",
	4: "routes.ViewForum",
	5: "routes.ChangeTheme",
	6: "routes.ShowAttachment",
	7: "common.RouteWebsockets",
	8: "routeAPIPhrases",
	9: "routes.APIMe",
	10: "routeJSAntispam",
	11: "routeAPI",
	12: "routes.ReportSubmit",
	13: "routes.TopicListMostViewed",
	14: "routes.CreateTopic",
	15: "routes.TopicList",
	16: "panel.Forums",
	17: "panel.ForumsCreateSubmit",
	18: "panel.ForumsDelete",
	19: "panel.ForumsDeleteSubmit",
	20: "panel.ForumsOrderSubmit",
	21: "panel.ForumsEdit",
	22: "panel.ForumsEditSubmit",
	23: "panel.ForumsEditPermsSubmit",
	24: "panel.ForumsEditPermsAdvance",
	25: "panel.ForumsEditPermsAdvanceSubmit",
	26: "panel.Settings",
	27: "panel.SettingEdit",
	28: "panel.SettingEditSubmit",
	29: "panel.WordFilters",
	30: "panel.WordFiltersCreateSubmit",
	31: "panel.WordFiltersEdit",
	32: "panel.WordFiltersEditSubmit",
	33: "panel.WordFiltersDeleteSubmit",
	34: "panel.Pages",
	35: "panel.PagesCreateSubmit",
	36: "panel.PagesEdit",
	37: "panel.PagesEditSubmit",
	38: "panel.PagesDeleteSubmit",
	39: "panel.Themes",
	40: "panel.ThemesSetDefault",
	41: "panel.ThemesMenus",
	42: "panel.ThemesMenusEdit",
	43: "panel.ThemesMenuItemEdit",
	44: "panel.ThemesMenuItemEditSubmit",
	45: "panel.ThemesMenuItemCreateSubmit",
	46: "panel.ThemesMenuItemDeleteSubmit",
	47: "panel.ThemesMenuItemOrderSubmit",
	48: "panel.ThemesWidgets",
	49: "panel.ThemesWidgetsEditSubmit",
	50: "panel.ThemesWidgetsCreateSubmit",
	51: "panel.ThemesWidgetsDeleteSubmit",
	52: "panel.Plugins",
	53: "panel.PluginsActivate",
	54: "panel.PluginsDeactivate",
	55: "panel.PluginsInstall",
	56: "panel.Users",
	57: "panel.UsersEdit",
	58: "panel.UsersEditSubmit",
	59: "panel.UsersAvatarSubmit",
	60: "panel.UsersAvatarRemoveSubmit",
	61: "panel.AnalyticsViews",
	62: "panel.AnalyticsRoutes",
	63: "panel.AnalyticsRoutesPerf",
	64: "panel.AnalyticsAgents",
	65: "panel.AnalyticsSystems",
	66: "panel.AnalyticsLanguages",
	67: "panel.AnalyticsReferrers",
	68: "panel.AnalyticsRouteViews",
	69: "panel.AnalyticsAgentViews",
	70: "panel.AnalyticsForumViews",
	71: "panel.AnalyticsSystemViews",
	72: "panel.AnalyticsLanguageViews",
	73: "panel.AnalyticsReferrerViews",
	74: "panel.AnalyticsPosts",
	75: "panel.AnalyticsMemory",
	76: "panel.AnalyticsActiveMemory",
	77: "panel.AnalyticsTopics",
	78: "panel.AnalyticsForums",
	79: "panel.AnalyticsPerf",
	80: "panel.Groups",
	81: "panel.GroupsEdit",
	82: "panel.GroupsEditPromotions",
	83: "panel.GroupsPromotionsCreateSubmit",
	84: "panel.GroupsPromotionsDeleteSubmit",
	85: "panel.GroupsEditPerms",
	86: "panel.GroupsEditSubmit",
	87: "panel.GroupsEditPermsSubmit",
	88: "panel.GroupsCreateSubmit",
	89: "panel.Backups",
	90: "panel.LogsRegs",
	91: "panel.LogsMod",
	92: "panel.LogsAdmin",
	93: "panel.Debug",
	94: "panel.Dashboard",
	95: "routes.AccountEdit",
	96: "routes.AccountEditPassword",
	97: "routes.AccountEditPasswordSubmit",
	98: "routes.AccountEditAvatarSubmit",
	99: "routes.AccountEditRevokeAvatarSubmit",
	100: "routes.AccountEditUsernameSubmit",
	101: "routes.AccountEditPrivacy",
	102: "routes.AccountEditPrivacySubmit",
	103: "routes.AccountEditMFA",
	104: "routes.AccountEditMFASetup",
	105: "routes.AccountEditMFASetupSubmit",
	106: "routes.AccountEditMFADisableSubmit",
	107: "routes.AccountEditEmail",
	108: "routes.AccountEditEmailTokenSubmit",
	109: "routes.AccountLogins",
	110: "routes.AccountBlocked",
	111: "routes.LevelList",
	112: "routes.Convos",
	113: "routes.ConvosCreate",
	114: "routes.Convo",
	115: "routes.ConvosCreateSubmit",
	116: "routes.ConvosCreateReplySubmit",
	117: "routes.ConvosDeleteReplySubmit",
	118: "routes.ConvosEditReplySubmit",
	119: "routes.RelationsBlockCreate",
	120: "routes.RelationsBlockCreateSubmit",
	121: "routes.RelationsBlockRemove",
	122: "routes.RelationsBlockRemoveSubmit",
	123: "routes.ViewProfile",
	124: "routes.BanUserSubmit",
	125: "routes.UnbanUser",
	126: "routes.ActivateUser",
	127: "routes.IPSearch",
	128: "routes.DeletePostsSubmit",
	129: "routes.CreateTopicSubmit",
	130: "routes.EditTopicSubmit",
	131: "routes.DeleteTopicSubmit",
	132: "routes.StickTopicSubmit",
	133: "routes.UnstickTopicSubmit",
	134: "routes.LockTopicSubmit",
	135: "routes.UnlockTopicSubmit",
	136: "routes.MoveTopicSubmit",
	137: "routes.LikeTopicSubmit",
	138: "routes.UnlikeTopicSubmit",
	139: "routes.AddAttachToTopicSubmit",
	140: "routes.RemoveAttachFromTopicSubmit",
	141: "routes.ViewTopic",
	142: "routes.CreateReplySubmit",
	143: "routes.ReplyEditSubmit",
	144: "routes.ReplyDeleteSubmit",
	145: "routes.ReplyLikeSubmit",
	146: "routes.ReplyUnlikeSubmit",
	147: "routes.AddAttachToReplySubmit",
	148: "routes.RemoveAttachFromReplySubmit",
	149: "routes.ProfileReplyCreateSubmit",
	150: "routes.ProfileReplyEditSubmit",
	151: "routes.ProfileReplyDeleteSubmit",
	152: "routes.PollVote",
	153: "routes.PollResults",
	154: "routes.AccountLogin",
	155: "routes.AccountRegister",
	156: "routes.AccountLogout",
	157: "routes.AccountLoginSubmit",
	158: "routes.AccountLoginMFAVerify",
	159: "routes.AccountLoginMFAVerifySubmit",
	160: "routes.AccountRegisterSubmit",
	161: "routes.AccountPasswordReset",
	162: "routes.AccountPasswordResetSubmit",
	163: "routes.AccountPasswordResetToken",
	164: "routes.AccountPasswordResetTokenSubmit",
	165: "routes.DynamicRoute",
	166: "routes.UploadedFile",
	167: "routes.StaticFile",
	168: "routes.RobotsTxt",
	169: "routes.SitemapXml",
	170: "routes.OpenSearchXml",
	171: "routes.Favicon",
	172: "routes.BadRoute",
	173: "routes.HTTPSRedirect",
}
var osMapEnum = map[string]int{ 
	"unknown": 0,
	"windows": 1,
	"linux": 2,
	"mac": 3,
	"android": 4,
	"iphone": 5,
}
var reverseOSMapEnum = map[int]string{ 
	0: "unknown",
	1: "windows",
	2: "linux",
	3: "mac",
	4: "android",
	5: "iphone",
}
var agentMapEnum = map[string]int{ 
	"unknown": 0,
	"firefox": 1,
	"chrome": 2,
	"opera": 3,
	"safari": 4,
	"edge": 5,
	"internetexplorer": 6,
	"trident": 7,
	"androidchrome": 8,
	"mobilesafari": 9,
	"samsung": 10,
	"ucbrowser": 11,
	"googlebot": 12,
	"yandex": 13,
	"bing": 14,
	"slurp": 15,
	"exabot": 16,
	"mojeek": 17,
	"cliqz": 18,
	"datenbank": 19,
	"baidu": 20,
	"sogou": 21,
	"toutiao": 22,
	"haosou": 23,
	"duckduckgo": 24,
	"seznambot": 25,
	"discord": 26,
	"twitter": 27,
	"facebook": 28,
	"cloudflare": 29,
	"archive_org": 30,
	"uptimebot": 31,
	"slackbot": 32,
	"apple": 33,
	"discourse": 34,
	"mattermost": 35,
	"alexa": 36,
	"lynx": 37,
	"blank": 38,
	"malformed": 39,
	"suspicious": 40,
	"semrush": 41,
	"dotbot": 42,
	"ahrefs": 43,
	"proximic": 44,
	"majestic": 45,
	"blexbot": 46,
	"aspiegel": 47,
	"mail_ru": 48,
	"ccbot": 49,
	"zgrab": 50,
	"curl": 51,
	"python": 52,
	"go": 53,
}
var reverseAgentMapEnum = map[int]string{ 
	0: "unknown",
	1: "firefox",
	2: "chrome",
	3: "opera",
	4: "safari",
	5: "edge",
	6: "internetexplorer",
	7: "trident",
	8: "androidchrome",
	9: "mobilesafari",
	10: "samsung",
	11: "ucbrowser",
	12: "googlebot",
	13: "yandex",
	14: "bing",
	15: "slurp",
	16: "exabot",
	17: "mojeek",
	18: "cliqz",
	19: "datenbank",
	20: "baidu",
	21: "sogou",
	22: "toutiao",
	23: "haosou",
	24: "duckduckgo",
	25: "seznambot",
	26: "discord",
	27: "twitter",
	28: "facebook",
	29: "cloudflare",
	30: "archive_org",
	31: "uptimebot",
	32: "slackbot",
	33: "apple",
	34: "discourse",
	35: "mattermost",
	36: "alexa",
	37: "lynx",
	38: "blank",
	39: "malformed",
	40: "suspicious",
	41: "semrush",
	42: "dotbot",
	43: "ahrefs",
	44: "proximic",
	45: "majestic",
	46: "blexbot",
	47: "aspiegel",
	48: "mail_ru",
	49: "ccbot",
	50: "zgrab",
	51: "curl",
	52: "python",
	53: "go",
}
var markToAgent = map[string]string{ 
	"OPR": "opera",
	"Chrome": "chrome",
	"Firefox": "firefox",
	"Safari": "safari",
	"MSIE": "internetexplorer",
	"Trident": "trident",
	"Edge": "edge",
	"Lynx": "lynx",
	"SamsungBrowser": "samsung",
	"UCBrowser": "ucbrowser",
	"Google": "googlebot",
	"Googlebot": "googlebot",
	"yandex": "yandex",
	"DuckDuckBot": "duckduckgo",
	"DuckDuckGo": "duckduckgo",
	"Baiduspider": "baidu",
	"Sogou": "sogou",
	"ToutiaoSpider": "toutiao",
	"360Spider": "haosou",
	"bingbot": "bing",
	"BingPreview": "bing",
	"msnbot": "bing",
	"Slurp": "slurp",
	"Exabot": "exabot",
	"MojeekBot": "mojeek",
	"Cliqzbot": "cliqz",
	"netEstate": "datenbank",
	"SeznamBot": "seznambot",
	"CloudFlare": "cloudflare",
	"archive": "archive_org",
	"Uptimebot": "uptimebot",
	"Slackbot": "slackbot",
	"Slack": "slackbot",
	"Discordbot": "discord",
	"Twitterbot": "twitter",
	"facebookexternalhit": "facebook",
	"Facebot": "facebook",
	"Applebot": "apple",
	"Discourse": "discourse",
	"mattermost": "mattermost",
	"ia_archiver": "alexa",
	"SemrushBot": "semrush",
	"DotBot": "dotbot",
	"AhrefsBot": "ahrefs",
	"proximic": "proximic",
	"MJ12bot": "majestic",
	"BLEXBot": "blexbot",
	"AspiegelBot": "aspiegel",
	"RU_Bot": "mail_ru",
	"CCBot": "ccbot",
	"zgrab": "zgrab",
	"curl": "curl",
	"python": "python",
	"Go": "go",
}
var markToID = map[string]int{ 
	"OPR": 3,
	"Chrome": 2,
	"Firefox": 1,
	"Safari": 4,
	"MSIE": 6,
	"Trident": 7,
	"Edge": 5,
	"Lynx": 37,
	"SamsungBrowser": 10,
	"UCBrowser": 11,
	"Google": 12,
	"Googlebot": 12,
	"yandex": 13,
	"DuckDuckBot": 24,
	"DuckDuckGo": 24,
	"Baiduspider": 20,
	"Sogou": 21,
	"ToutiaoSpider": 22,
	"360Spider": 23,
	"bingbot": 14,
	"BingPreview": 14,
	"msnbot": 14,
	"Slurp": 15,
	"Exabot": 16,
	"MojeekBot": 17,
	"Cliqzbot": 18,
	"netEstate": 19,
	"SeznamBot": 25,
	"CloudFlare": 29,
	"archive": 30,
	"Uptimebot": 31,
	"Slackbot": 32,
	"Slack": 32,
	"Discordbot": 26,
	"Twitterbot": 27,
	"facebookexternalhit": 28,
	"Facebot": 28,
	"Applebot": 33,
	"Discourse": 34,
	"mattermost": 35,
	"ia_archiver": 36,
	"SemrushBot": 41,
	"DotBot": 42,
	"AhrefsBot": 43,
	"proximic": 44,
	"MJ12bot": 45,
	"BLEXBot": 46,
	"AspiegelBot": 47,
	"RU_Bot": 48,
	"CCBot": 49,
	"zgrab": 50,
	"curl": 51,
	"python": 52,
	"Go": 53,
}
/*var agentRank = map[string]int{
	"opera":9,
	"chrome":8,
	"safari":1,
}*/

// TODO: Stop spilling these into the package scope?
func init() {
	_ = time.Now()
	co.SetRouteMapEnum(routeMapEnum)
	co.SetReverseRouteMapEnum(reverseRouteMapEnum)
	co.SetAgentMapEnum(agentMapEnum)
	co.SetReverseAgentMapEnum(reverseAgentMapEnum)
	co.SetOSMapEnum(osMapEnum)
	co.SetReverseOSMapEnum(reverseOSMapEnum)
	c.Chrome = agentMapEnum["chrome"]
	c.Firefox = agentMapEnum["firefox"]
	ame := agentMapEnum
	c.SimpleBots = []int{
		ame["semrush"],
		ame["ahrefs"],
		ame["python"],
		ame["go"],
		ame["curl"],
	}
}

type WriterIntercept struct {
	http.ResponseWriter
}

func NewWriterIntercept(w http.ResponseWriter) *WriterIntercept {
	return &WriterIntercept{w}
}

var wiMaxAge = "max-age=" + strconv.Itoa(int(c.Day))
func (wi *WriterIntercept) WriteHeader(code int) {
	if code == 200 {
		h := wi.ResponseWriter.Header()
		h.Set("Cache-Control", wiMaxAge)
		h.Set("Vary", "Accept-Encoding")
	}
	wi.ResponseWriter.WriteHeader(code)
}

// HTTPSRedirect is a connection handler which redirects all HTTP requests to HTTPS
type HTTPSRedirect struct {}

func (red *HTTPSRedirect) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	w.Header().Set("Connection", "close")
	co.RouteViewCounter.Bump(173)
	dest := "https://" + req.Host + req.URL.String()
	http.Redirect(w, req, dest, http.StatusTemporaryRedirect)
}

type GenRouter struct {
	UploadHandler func(http.ResponseWriter, *http.Request)
	extraRoutes map[string]func(http.ResponseWriter, *http.Request, *c.User) c.RouteError
	requestLogger *log.Logger
	
	sync.RWMutex
}

func NewGenRouter(uploads http.Handler) (*GenRouter, error) {
	f, err := os.OpenFile("./logs/reqs-"+strconv.FormatInt(c.StartTime.Unix(),10)+".log", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0755)
	if err != nil {
		return nil, err
	}

	return &GenRouter{
		UploadHandler: func(w http.ResponseWriter, req *http.Request) {
			writ := NewWriterIntercept(w)
			http.StripPrefix("/uploads/",uploads).ServeHTTP(writ,req)
		},
		extraRoutes: make(map[string]func(http.ResponseWriter, *http.Request, *c.User) c.RouteError),
		requestLogger: log.New(f, "", log.LstdFlags),
	}, nil
}

func (r *GenRouter) handleError(err c.RouteError, w http.ResponseWriter, req *http.Request, u *c.User) {
	if err.Handled() {
		return
	}
	if err.Type() == "system" {
		c.InternalErrorJSQ(err, w, req, err.JSON())
		return
	}
	c.LocalErrorJSQ(err.Error(), w, req, u, err.JSON())
}

func (r *GenRouter) Handle(_ string, _ http.Handler) {
}

func (r *GenRouter) HandleFunc(pattern string, h func(http.ResponseWriter, *http.Request, *c.User) c.RouteError) {
	r.Lock()
	defer r.Unlock()
	r.extraRoutes[pattern] = h
}

func (r *GenRouter) RemoveFunc(pattern string) error {
	r.Lock()
	defer r.Unlock()
	_, ok := r.extraRoutes[pattern]
	if !ok {
		return ErrNoRoute
	}
	delete(r.extraRoutes, pattern)
	return nil
}

// TODO: Use strings builder?
func (r *GenRouter) DumpRequest(req *http.Request, pre string) {
	var heads string
	for key, value := range req.Header {
		for _, vvalue := range value {
			heads += "Head " + c.SanitiseSingleLine(key) + ": " + c.SanitiseSingleLine(vvalue) + "\n"
		}
	}

	r.requestLogger.Print(pre + 
		"\nUA: " + c.SanitiseSingleLine(req.UserAgent()) + "\n" +
		"Method: " + c.SanitiseSingleLine(req.Method) + "\n" + heads + 
		"Host: " + c.SanitiseSingleLine(req.Host) + "\n" + 
		"URL.Path: " + c.SanitiseSingleLine(req.URL.Path) + "\n" + 
		"URL.RawQuery: " + c.SanitiseSingleLine(req.URL.RawQuery) + "\n" + 
		"Ref: " + c.SanitiseSingleLine(req.Referer()) + "\n" + 
		"IP: " + req.RemoteAddr + "\n")
}

func (r *GenRouter) SuspiciousRequest(req *http.Request, pre string) {
	if pre != "" {
		pre += "\n"
	}
	r.DumpRequest(req,pre+"Suspicious Request")
	co.AgentViewCounter.Bump(40)
}

func isLocalHost(h string) bool {
	return h=="localhost" || h=="127.0.0.1" || h=="::1"
}

// TODO: Pass the default path or config struct to the router rather than accessing it via a package global
// TODO: SetDefaultPath
// TODO: GetDefaultPath
func (r *GenRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	malformedRequest := func(typ int) {
		w.WriteHeader(200) // 400
		w.Write([]byte(""))
		r.DumpRequest(req,"Malformed Request T"+strconv.Itoa(typ))
		co.AgentViewCounter.Bump(39)
	}
	
	// Split the Host and Port string
	var shost, sport string
	if req.Host[0]=='[' {
		spl := strings.Split(req.Host,"]")
		if len(spl) > 2 {
			malformedRequest(0)
			return
		}
		shost = strings.TrimPrefix(spl[0],"[")
		sport = strings.TrimPrefix(spl[1],":")
	} else if strings.Contains(req.Host,":") {
		spl := strings.Split(req.Host,":")
		if len(spl) > 2 {
			malformedRequest(1)
			return
		}
		shost = spl[0]
		//if len(spl)==2 {
			sport = spl[1]
		//}
	} else {
		shost = req.Host
	}
	// TODO: Reject requests from non-local IPs, if the site host is set to localhost or a localhost IP
	if !c.Config.LoosePort && c.Site.PortInt != 80 && c.Site.PortInt != 443 && sport != c.Site.Port {
		malformedRequest(2)
		return
	}
	
	// Redirect www. and local IP requests to the right place
	if strings.HasPrefix(shost, "www.") || c.Site.LocalHost {
	if shost == "www." + c.Site.Host || (c.Site.LocalHost && shost != c.Site.Host && isLocalHost(shost)) {
		// TODO: Abstract the redirect logic?
		w.Header().Set("Connection", "close")
		var s string
		if c.Config.SslSchema {
			s = "s"
		}
		var p string
		if c.Site.PortInt != 80 && c.Site.PortInt != 443 {
			p = ":"+c.Site.Port
		}
		dest := "http"+s+"://" + c.Site.Host+p + req.URL.Path
		if len(req.URL.RawQuery) > 0 {
			dest += "?" + req.URL.RawQuery
		}
		http.Redirect(w, req, dest, http.StatusMovedPermanently)
		return
	}
	}

	// Deflect malformed requests
	if len(req.URL.Path) == 0 || req.URL.Path[0] != '/' || (!c.Config.LooseHost && shost != c.Site.Host) {
		malformedRequest(3)
		return
	}
	if c.Dev.FullReqLog {
		r.DumpRequest(req,"")
	}

	// TODO: Cover more suspicious strings and at a lower layer than this
	for _, ch := range req.URL.Path { //char
		if ch != '&' && !(ch > 44 && ch < 58) && ch != '=' && ch != '?' && !(ch > 64 && ch < 91) && ch != '\\' && ch != '_' && !(ch > 96 && ch < 123) {
			r.SuspiciousRequest(req,"Bad char '"+string(ch)+"' in path")
			break
		}
	}
	lp := strings.ToLower(req.URL.Path)
	// TODO: Flag any requests which has a dot with anything but a number after that
	// TODO: Use HasSuffix to avoid over-scanning?
	if strings.Contains(lp,"..")/* || strings.Contains(lp,"--")*/ || strings.Contains(lp,".php") || strings.Contains(lp,".asp") || strings.Contains(lp,".cgi") || strings.Contains(lp,".py") || strings.Contains(lp,".sql") || strings.Contains(lp,".action") {
		r.SuspiciousRequest(req,"Bad snippet in path")
	}

	// Indirect the default route onto a different one
	if req.URL.Path == "/" {
		req.URL.Path = c.Config.DefaultPath
	}
	//log.Print("URL.Path: ", req.URL.Path)
	prefix := req.URL.Path[0:strings.IndexByte(req.URL.Path[1:],'/') + 1]

	// TODO: Use the same hook table as downstream
	hTbl := c.GetHookTable()
	skip, ferr := hTbl.VhookSkippable("router_after_filters", w, req, prefix)
	if skip || ferr != nil {
		return
	}

	if prefix != "/ws" {
		h := w.Header()
		h.Set("X-Frame-Options", "deny")
		h.Set("X-XSS-Protection", "1; mode=block") // TODO: Remove when we add a CSP? CSP's are horrendously glitchy things, tread with caution before removing
		h.Set("X-Content-Type-Options", "nosniff")
		if c.Config.RefNoRef || !c.Config.SslSchema {
			h.Set("Referrer-Policy","no-referrer")
		} else {
			h.Set("Referrer-Policy","strict-origin")
		}
	}
	
	if c.Dev.SuperDebug {
		r.DumpRequest(req,"before routes.StaticFile")
	}
	// Increment the request counter
	if !c.Config.DisableAnalytics {
		co.GlobalViewCounter.Bump()
	}
	
	if prefix == "/s" { //old prefix: /static
		if !c.Config.DisableAnalytics {
			co.RouteViewCounter.Bump(167)
		}
		routes.StaticFile(w, req)
		return
	}
	// TODO: Handle JS routes
	if atomic.LoadInt32(&c.IsDBDown) == 1 {
		c.DatabaseError(w, req)
		return
	}
	if c.Dev.SuperDebug {
		r.requestLogger.Print("before PreRoute")
	}

	/*if c.Dev.QuicPort != 0 {
		w.Header().Set("Alt-Svc", "quic=\":"+strconv.Itoa(c.Dev.QuicPort)+"\"; ma=2592000; v=\"44,43,39\", h3-23=\":"+strconv.Itoa(c.Dev.QuicPort)+"\"; ma=3600, h3-24=\":"+strconv.Itoa(c.Dev.QuicPort)+"\"; ma=3600, h2=\":443\"; ma=3600")
	}*/

	// Track the user agents. Unfortunately, everyone pretends to be Mozilla, so this'll be a little less efficient than I would like.
	// TODO: Add a setting to disable this?
	// TODO: Use a more efficient detector instead of smashing every possible combination in
	var agent int
	if !c.Config.DisableAnalytics {
	
	ua := strings.TrimSpace(strings.Replace(strings.TrimPrefix(req.UserAgent(),"Mozilla/5.0 ")," Safari/537.36","",-1)) // Noise, no one's going to be running this and it would require some sort of agent ranking system to determine which identifier should be prioritised over another
	if ua == "" {
		co.AgentViewCounter.Bump(38)
		if c.Dev.DebugMode {
			var pre string
			for _, char := range req.UserAgent() {
				pre += strconv.Itoa(int(char)) + " "
			}
			r.DumpRequest(req,"Blank UA: " + pre)
		}
	} else {		
		// WIP UA Parser
		var items []string
		var buffer []byte
		var os int
		for _, it := range uutils.StringToBytes(ua) {
			if (it > 64 && it < 91) || (it > 96 && it < 123) || it == '_' {
				// TODO: Store an index and slice that instead?
				buffer = append(buffer, it)
			} else if it == ' ' || it == '(' || it == ')' || it == '-' || (it > 47 && it < 58) || it == ';' || it == ':' || it == '.' || it == '+' || it == '~' || it == '@' /*|| (it == ':' && bytes.Equal(buffer,[]byte("http")))*/ || it == ',' || it == '/' {
				if len(buffer) != 0 {
					if len(buffer) > 2 {
						// Use an unsafe zero copy conversion here just to use the switch, it's not safe for this string to escape from here, as it will get mutated, so do a regular string conversion in append
						switch(uutils.BytesToString(buffer)) {
						case "Windows":
							os = 1
						case "Linux":
							os = 2
						case "Mac":
							os = 3
						case "iPhone":
							os = 5
						case "Android":
							os = 4
						case "like","compatible":
							// Skip these words
						default:
							items = append(items, string(buffer))
						}
					}
					buffer = buffer[:0]
				}
			} else {
				// TODO: Test this
				items = items[:0]
				r.SuspiciousRequest(req,"Illegal char "+strconv.Itoa(int(it))+" in UA")
				r.requestLogger.Print("UA Buf: ", buffer)
				r.requestLogger.Print("UA Buf String: ", string(buffer))
				break
			}
		}

		// Iterate over this in reverse as the real UA tends to be on the right side
		for i := len(items) - 1; i >= 0; i-- {
			//fAgent, ok := markToAgent[items[i]]
			fAgent, ok := markToID[items[i]]
			if ok {
				agent = fAgent
				if agent != 4 {
					break
				}
			}
		}
		if c.Dev.SuperDebug {
			r.requestLogger.Print("parsed agent: ", agent)
			r.requestLogger.Print("os: ", os)
			r.requestLogger.Printf("items: %+v\n",items)
		}
		
		// Special handling
		switch(agent) {
		case 2:
			if os == 4 {
				agent = 8
			}
		case 4:
			if os == 5 {
				agent = 9
			}
		case 7:
			// Hack to support IE11, change this after we start logging versions
			if strings.Contains(ua,"rv:11") {
				agent = 6
			}
		case 50:
			r.SuspiciousRequest(req,"Vulnerability Scanner")
		}
		
		if agent == 0 {
			co.AgentViewCounter.Bump(0)
			if c.Dev.DebugMode {
				var pre string
				for _, char := range req.UserAgent() {
					pre += strconv.Itoa(int(char)) + " "
				}
				r.DumpRequest(req,"Blank UA: " + pre)
			} else {
				r.requestLogger.Print("unknown ua: ", c.SanitiseSingleLine(ua))
			}
		} else {
			//co.AgentViewCounter.Bump(agentMapEnum[agent])
			co.AgentViewCounter.Bump(agent)
		}
		co.OSViewCounter.Bump(os)
	}

	// TODO: Do we want to track missing language headers too? Maybe as it's own type, e.g. "noheader"?
	// TODO: Default to anything other than en, if anything else is present, to avoid over-representing it for multi-linguals?
	lang := req.Header.Get("Accept-Language")
	if lang != "" {
		// TODO: Reduce allocs here
		lLang := strings.Split(strings.TrimSpace(lang),"-")
		tLang := strings.Split(strings.Split(lLang[0],";")[0],",")
		c.DebugDetail("tLang:", tLang)
		var llLang string
		for _, seg := range tLang {
			if seg == "*" {
				continue
			}
			llLang = seg
			break
		}
		c.DebugDetail("llLang:", llLang)
		if !co.LangViewCounter.Bump(llLang) {
			r.DumpRequest(req,"Invalid ISO Code")
		}
	} else {
		co.LangViewCounter.Bump2(0)
	}

	if !c.Config.RefNoTrack {
		ref := req.Header.Get("Referer") // Check the 'referrer' header too? :P
		if ref != "" {
			// ? Optimise this a little?
			ref = strings.TrimPrefix(strings.TrimPrefix(ref,"http://"),"https://")
			ref = strings.Split(ref,"/")[0]
			portless := strings.Split(ref,":")[0]
			// TODO: Handle c.Site.Host in uppercase too?
			if portless != "localhost" && portless != "127.0.0.1" && portless != c.Site.Host {
				co.ReferrerTracker.Bump(ref)
			}
		}
	}

	}
	
	// Deal with the session stuff, etc.
	ucpy, ok := c.PreRoute(w, req)
	if !ok {
		return
	}
	user := &ucpy
	user.LastAgent = agent
	if c.Dev.SuperDebug {
		r.requestLogger.Print(
			"after PreRoute\n" +
			"routeMapEnum: ", routeMapEnum)
	}
	//log.Println("req: ", req)

	// Disable Gzip when SSL is disabled for security reasons?
	if prefix != "/ws" && strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") {
		h := w.Header()
		h.Set("Content-Encoding", "gzip")
		gzw := c.GzipResponseWriter{Writer: gzip.NewWriter(w), ResponseWriter: w}
		defer func() {
			//h := w.Header()
			if h.Get("Content-Encoding") == "gzip" && h.Get("X-I") == "" {
				//log.Print("push gzip close")
				gzw.Writer.(*gzip.Writer).Close()
			}
		}()
		w = gzw
	}

	skip, ferr = hTbl.VhookSkippable("router_pre_route", w, req, user, prefix)
	if skip || ferr != nil {
		r.handleError(ferr,w,req,user)
		return
	}
	var extraData string
	if req.URL.Path[len(req.URL.Path) - 1] != '/' {
		extraData = req.URL.Path[strings.LastIndexByte(req.URL.Path,'/') + 1:]
		req.URL.Path = req.URL.Path[:strings.LastIndexByte(req.URL.Path,'/') + 1]
	}
	ferr = r.routeSwitch(w, req, user, prefix, extraData)
	if ferr != nil {
		r.handleError(ferr,w,req,user)
		return
	}
	/*if !c.Config.DisableAnalytics {
		co.RouteViewCounter.Bump(id)
	}*/

	hTbl.VhookNoRet("router_end", w, req, user, prefix, extraData)
	//c.StoppedServer("Profile end")
}
	
func (r *GenRouter) routeSwitch(w http.ResponseWriter, req *http.Request, user *c.User, prefix, extraData string) /*(id int, orerr */c.RouteError/*)*/ {
	var err c.RouteError
	cn := uutils.Nanotime()
	switch(prefix) {
		case "/overview":
			h, err := c.UserCheckNano(w,req,user,cn)
			if err != nil {
				return err
			}
			err = routes.Overview(w,req,user,h)
			co.RouteViewCounter.Bump3(1, cn)
		case "/pages":
			h, err := c.UserCheckNano(w,req,user,cn)
			if err != nil {
				return err
			}
			err = routes.CustomPage(w,req,user,h,extraData)
			co.RouteViewCounter.Bump3(2, cn)
		case "/forums":
			h, err := c.UserCheckNano(w,req,user,cn)
			if err != nil {
				return err
			}
			err = routes.ForumList(w,req,user,h)
			co.RouteViewCounter.Bump3(3, cn)
		case "/forum":
			h, err := c.UserCheckNano(w,req,user,cn)
			if err != nil {
				return err
			}
			err = routes.ViewForum(w,req,user,h,extraData)
			co.RouteViewCounter.Bump3(4, cn)
		case "/theme":
				err = c.ParseForm(w,req,user)
				if err != nil {
					return err
				}
				
			err = routes.ChangeTheme(w,req,user)
			co.RouteViewCounter.Bump3(5, cn)
		case "/attachs":
				err = c.ParseForm(w,req,user)
				if err != nil {
					return err
				}
				
					gzw, ok := w.(c.GzipResponseWriter)
					if ok {
					w = gzw.ResponseWriter
					w.Header().Del("Content-Encoding")
					}
			err = routes.ShowAttachment(w,req,user,extraData)
			co.RouteViewCounter.Bump3(6, cn)
		case "/ws":
					req.URL.Path += extraData
			err = c.RouteWebsockets(w,req,user)
		case "/api":
			switch(req.URL.Path) {
				case "/api/phrases/":
					err = routeAPIPhrases(w,req,user)
					co.RouteViewCounter.Bump3(8, cn)
				case "/api/me/":
					err = routes.APIMe(w,req,user)
					co.RouteViewCounter.Bump3(9, cn)
				case "/api/watches/":
					err = routeJSAntispam(w,req,user)
					co.RouteViewCounter.Bump3(10, cn)
				default:
					err = routeAPI(w,req,user)
			co.RouteViewCounter.Bump3(11, cn)
			}
		case "/report":
			err = c.NoBanned(w,req,user)
			if err != nil {
				return err
			}
			
			switch(req.URL.Path) {
				case "/report/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ReportSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(12, cn)
			}
		case "/topics":
			switch(req.URL.Path) {
				case "/topics/most-viewed/":
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.TopicListMostViewed(w,req,user,h)
					co.RouteViewCounter.Bump3(13, cn)
				case "/topics/create/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.CreateTopic(w,req,user,h,extraData)
					co.RouteViewCounter.Bump3(14, cn)
				default:
					h, err := c.UserCheckNano(w,req,user,cn)
					if err != nil {
						return err
					}
					err = routes.TopicList(w,req,user, h)
			co.RouteViewCounter.Bump3(15, cn)
			}
		case "/panel":
			err = c.SuperModOnly(w,req,user)
			if err != nil {
				return err
			}
			
			switch(req.URL.Path) {
				case "/panel/forums/":
					err = panel.Forums(w,req,user)
					co.RouteViewCounter.Bump3(16, cn)
				case "/panel/forums/create/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ForumsCreateSubmit(w,req,user)
					co.RouteViewCounter.Bump3(17, cn)
				case "/panel/forums/delete/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ForumsDelete(w,req,user,extraData)
					co.RouteViewCounter.Bump3(18, cn)
				case "/panel/forums/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ForumsDeleteSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(19, cn)
				case "/panel/forums/order/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ForumsOrderSubmit(w,req,user)
					co.RouteViewCounter.Bump3(20, cn)
				case "/panel/forums/edit/":
					err = panel.ForumsEdit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(21, cn)
				case "/panel/forums/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ForumsEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(22, cn)
				case "/panel/forums/edit/perms/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ForumsEditPermsSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(23, cn)
				case "/panel/forums/edit/perms/":
					err = panel.ForumsEditPermsAdvance(w,req,user,extraData)
					co.RouteViewCounter.Bump3(24, cn)
				case "/panel/forums/edit/perms/adv/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ForumsEditPermsAdvanceSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(25, cn)
				case "/panel/settings/":
					err = panel.Settings(w,req,user)
					co.RouteViewCounter.Bump3(26, cn)
				case "/panel/settings/edit/":
					err = panel.SettingEdit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(27, cn)
				case "/panel/settings/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.SettingEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(28, cn)
				case "/panel/settings/word-filters/":
					err = panel.WordFilters(w,req,user)
					co.RouteViewCounter.Bump3(29, cn)
				case "/panel/settings/word-filters/create/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.WordFiltersCreateSubmit(w,req,user)
					co.RouteViewCounter.Bump3(30, cn)
				case "/panel/settings/word-filters/edit/":
					err = panel.WordFiltersEdit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(31, cn)
				case "/panel/settings/word-filters/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.WordFiltersEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(32, cn)
				case "/panel/settings/word-filters/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.WordFiltersDeleteSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(33, cn)
				case "/panel/pages/":
					err = c.AdminOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.Pages(w,req,user)
					co.RouteViewCounter.Bump3(34, cn)
				case "/panel/pages/create/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.AdminOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.PagesCreateSubmit(w,req,user)
					co.RouteViewCounter.Bump3(35, cn)
				case "/panel/pages/edit/":
					err = c.AdminOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.PagesEdit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(36, cn)
				case "/panel/pages/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.AdminOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.PagesEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(37, cn)
				case "/panel/pages/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.AdminOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.PagesDeleteSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(38, cn)
				case "/panel/themes/":
					err = panel.Themes(w,req,user)
					co.RouteViewCounter.Bump3(39, cn)
				case "/panel/themes/default/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ThemesSetDefault(w,req,user,extraData)
					co.RouteViewCounter.Bump3(40, cn)
				case "/panel/themes/menus/":
					err = panel.ThemesMenus(w,req,user)
					co.RouteViewCounter.Bump3(41, cn)
				case "/panel/themes/menus/edit/":
					err = panel.ThemesMenusEdit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(42, cn)
				case "/panel/themes/menus/item/edit/":
					err = panel.ThemesMenuItemEdit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(43, cn)
				case "/panel/themes/menus/item/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ThemesMenuItemEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(44, cn)
				case "/panel/themes/menus/item/create/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ThemesMenuItemCreateSubmit(w,req,user)
					co.RouteViewCounter.Bump3(45, cn)
				case "/panel/themes/menus/item/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ThemesMenuItemDeleteSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(46, cn)
				case "/panel/themes/menus/item/order/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ThemesMenuItemOrderSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(47, cn)
				case "/panel/themes/widgets/":
					err = panel.ThemesWidgets(w,req,user)
					co.RouteViewCounter.Bump3(48, cn)
				case "/panel/themes/widgets/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ThemesWidgetsEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(49, cn)
				case "/panel/themes/widgets/create/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ThemesWidgetsCreateSubmit(w,req,user)
					co.RouteViewCounter.Bump3(50, cn)
				case "/panel/themes/widgets/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.ThemesWidgetsDeleteSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(51, cn)
				case "/panel/plugins/":
					err = panel.Plugins(w,req,user)
					co.RouteViewCounter.Bump3(52, cn)
				case "/panel/plugins/activate/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.PluginsActivate(w,req,user,extraData)
					co.RouteViewCounter.Bump3(53, cn)
				case "/panel/plugins/deactivate/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.PluginsDeactivate(w,req,user,extraData)
					co.RouteViewCounter.Bump3(54, cn)
				case "/panel/plugins/install/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.PluginsInstall(w,req,user,extraData)
					co.RouteViewCounter.Bump3(55, cn)
				case "/panel/users/":
					err = panel.Users(w,req,user)
					co.RouteViewCounter.Bump3(56, cn)
				case "/panel/users/edit/":
					err = panel.UsersEdit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(57, cn)
				case "/panel/users/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.UsersEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(58, cn)
				case "/panel/users/avatar/submit/":
					err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize))
					if err != nil {
					return err
					}
					err = c.NoUploadSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.UsersAvatarSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(59, cn)
				case "/panel/users/avatar/remove/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.UsersAvatarRemoveSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(60, cn)
				case "/panel/analytics/views/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsViews(w,req,user)
					co.RouteViewCounter.Bump3(61, cn)
				case "/panel/analytics/routes/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsRoutes(w,req,user)
					co.RouteViewCounter.Bump3(62, cn)
				case "/panel/analytics/routes-perf/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsRoutesPerf(w,req,user)
					co.RouteViewCounter.Bump3(63, cn)
				case "/panel/analytics/agents/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsAgents(w,req,user)
					co.RouteViewCounter.Bump3(64, cn)
				case "/panel/analytics/systems/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsSystems(w,req,user)
					co.RouteViewCounter.Bump3(65, cn)
				case "/panel/analytics/langs/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsLanguages(w,req,user)
					co.RouteViewCounter.Bump3(66, cn)
				case "/panel/analytics/referrers/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsReferrers(w,req,user)
					co.RouteViewCounter.Bump3(67, cn)
				case "/panel/analytics/route/":
					err = panel.AnalyticsRouteViews(w,req,user,extraData)
					co.RouteViewCounter.Bump3(68, cn)
				case "/panel/analytics/agent/":
					err = panel.AnalyticsAgentViews(w,req,user,extraData)
					co.RouteViewCounter.Bump3(69, cn)
				case "/panel/analytics/forum/":
					err = panel.AnalyticsForumViews(w,req,user,extraData)
					co.RouteViewCounter.Bump3(70, cn)
				case "/panel/analytics/system/":
					err = panel.AnalyticsSystemViews(w,req,user,extraData)
					co.RouteViewCounter.Bump3(71, cn)
				case "/panel/analytics/lang/":
					err = panel.AnalyticsLanguageViews(w,req,user,extraData)
					co.RouteViewCounter.Bump3(72, cn)
				case "/panel/analytics/referrer/":
					err = panel.AnalyticsReferrerViews(w,req,user,extraData)
					co.RouteViewCounter.Bump3(73, cn)
				case "/panel/analytics/posts/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsPosts(w,req,user)
					co.RouteViewCounter.Bump3(74, cn)
				case "/panel/analytics/memory/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsMemory(w,req,user)
					co.RouteViewCounter.Bump3(75, cn)
				case "/panel/analytics/active-memory/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsActiveMemory(w,req,user)
					co.RouteViewCounter.Bump3(76, cn)
				case "/panel/analytics/topics/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsTopics(w,req,user)
					co.RouteViewCounter.Bump3(77, cn)
				case "/panel/analytics/forums/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsForums(w,req,user)
					co.RouteViewCounter.Bump3(78, cn)
				case "/panel/analytics/perf/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.AnalyticsPerf(w,req,user)
					co.RouteViewCounter.Bump3(79, cn)
				case "/panel/groups/":
					err = panel.Groups(w,req,user)
					co.RouteViewCounter.Bump3(80, cn)
				case "/panel/groups/edit/":
					err = panel.GroupsEdit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(81, cn)
				case "/panel/groups/edit/promotions/":
					err = panel.GroupsEditPromotions(w,req,user,extraData)
					co.RouteViewCounter.Bump3(82, cn)
				case "/panel/groups/promotions/create/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.GroupsPromotionsCreateSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(83, cn)
				case "/panel/groups/promotions/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.GroupsPromotionsDeleteSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(84, cn)
				case "/panel/groups/edit/perms/":
					err = panel.GroupsEditPerms(w,req,user,extraData)
					co.RouteViewCounter.Bump3(85, cn)
				case "/panel/groups/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.GroupsEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(86, cn)
				case "/panel/groups/edit/perms/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.GroupsEditPermsSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(87, cn)
				case "/panel/groups/create/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.GroupsCreateSubmit(w,req,user)
					co.RouteViewCounter.Bump3(88, cn)
				case "/panel/backups/":
					err = c.SuperAdminOnly(w,req,user)
					if err != nil {
						return err
					}
					
					gzw, ok := w.(c.GzipResponseWriter)
					if ok {
					w = gzw.ResponseWriter
					w.Header().Del("Content-Encoding")
					}
					err = panel.Backups(w,req,user,extraData)
					co.RouteViewCounter.Bump3(89, cn)
				case "/panel/logs/regs/":
					err = panel.LogsRegs(w,req,user)
					co.RouteViewCounter.Bump3(90, cn)
				case "/panel/logs/mod/":
					err = panel.LogsMod(w,req,user)
					co.RouteViewCounter.Bump3(91, cn)
				case "/panel/logs/admin/":
					err = panel.LogsAdmin(w,req,user)
					co.RouteViewCounter.Bump3(92, cn)
				case "/panel/debug/":
					err = c.AdminOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = panel.Debug(w,req,user)
					co.RouteViewCounter.Bump3(93, cn)
				default:
					err = panel.Dashboard(w,req,user)
			co.RouteViewCounter.Bump3(94, cn)
			}
		case "/user":
			switch(req.URL.Path) {
				case "/user/edit/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountEdit(w,req,user,h)
					co.RouteViewCounter.Bump3(95, cn)
				case "/user/edit/password/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountEditPassword(w,req,user,h)
					co.RouteViewCounter.Bump3(96, cn)
				case "/user/edit/password/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountEditPasswordSubmit(w,req,user)
					co.RouteViewCounter.Bump3(97, cn)
				case "/user/edit/avatar/submit/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize))
					if err != nil {
					return err
					}
					err = c.NoUploadSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountEditAvatarSubmit(w,req,user)
					co.RouteViewCounter.Bump3(98, cn)
				case "/user/edit/avatar/revoke/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountEditRevokeAvatarSubmit(w,req,user)
					co.RouteViewCounter.Bump3(99, cn)
				case "/user/edit/username/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountEditUsernameSubmit(w,req,user)
					co.RouteViewCounter.Bump3(100, cn)
				case "/user/edit/privacy/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountEditPrivacy(w,req,user,h)
					co.RouteViewCounter.Bump3(101, cn)
				case "/user/edit/privacy/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountEditPrivacySubmit(w,req,user)
					co.RouteViewCounter.Bump3(102, cn)
				case "/user/edit/mfa/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountEditMFA(w,req,user,h)
					co.RouteViewCounter.Bump3(103, cn)
				case "/user/edit/mfa/setup/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountEditMFASetup(w,req,user,h)
					co.RouteViewCounter.Bump3(104, cn)
				case "/user/edit/mfa/setup/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountEditMFASetupSubmit(w,req,user)
					co.RouteViewCounter.Bump3(105, cn)
				case "/user/edit/mfa/disable/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountEditMFADisableSubmit(w,req,user)
					co.RouteViewCounter.Bump3(106, cn)
				case "/user/edit/email/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountEditEmail(w,req,user,h)
					co.RouteViewCounter.Bump3(107, cn)
				case "/user/edit/token/":
					err = routes.AccountEditEmailTokenSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(108, cn)
				case "/user/edit/logins/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountLogins(w,req,user,h)
					co.RouteViewCounter.Bump3(109, cn)
				case "/user/edit/blocked/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountBlocked(w,req,user,h)
					co.RouteViewCounter.Bump3(110, cn)
				case "/user/levels/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.LevelList(w,req,user,h)
					co.RouteViewCounter.Bump3(111, cn)
				case "/user/convos/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.Convos(w,req,user,h)
					co.RouteViewCounter.Bump3(112, cn)
				case "/user/convos/create/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.ConvosCreate(w,req,user,h)
					co.RouteViewCounter.Bump3(113, cn)
				case "/user/convo/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.Convo(w,req,user,h,extraData)
					co.RouteViewCounter.Bump3(114, cn)
				case "/user/convos/create/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ConvosCreateSubmit(w,req,user)
					co.RouteViewCounter.Bump3(115, cn)
				case "/user/convo/create/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ConvosCreateReplySubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(116, cn)
				case "/user/convo/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ConvosDeleteReplySubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(117, cn)
				case "/user/convo/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ConvosEditReplySubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(118, cn)
				case "/user/block/create/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.RelationsBlockCreate(w,req,user,h,extraData)
					co.RouteViewCounter.Bump3(119, cn)
				case "/user/block/create/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.RelationsBlockCreateSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(120, cn)
				case "/user/block/remove/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.RelationsBlockRemove(w,req,user,h,extraData)
					co.RouteViewCounter.Bump3(121, cn)
				case "/user/block/remove/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.RelationsBlockRemoveSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(122, cn)
				default:
					req.URL.Path += extraData
					h, err := c.UserCheckNano(w,req,user,cn)
					if err != nil {
						return err
					}
					err = routes.ViewProfile(w,req,user, h)
			co.RouteViewCounter.Bump3(123, cn)
			}
		case "/users":
			switch(req.URL.Path) {
				case "/users/ban/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.BanUserSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(124, cn)
				case "/users/unban/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.UnbanUser(w,req,user,extraData)
					co.RouteViewCounter.Bump3(125, cn)
				case "/users/activate/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ActivateUser(w,req,user,extraData)
					co.RouteViewCounter.Bump3(126, cn)
				case "/users/ips/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.IPSearch(w,req,user,h)
					co.RouteViewCounter.Bump3(127, cn)
				case "/users/delete-posts/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.DeletePostsSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(128, cn)
			}
		case "/topic":
			switch(req.URL.Path) {
				case "/topic/create/submit/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize))
					if err != nil {
					return err
					}
					err = c.NoUploadSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.CreateTopicSubmit(w,req,user)
					co.RouteViewCounter.Bump3(129, cn)
				case "/topic/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.EditTopicSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(130, cn)
				case "/topic/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					req.URL.Path += extraData
					err = routes.DeleteTopicSubmit(w,req,user)
					co.RouteViewCounter.Bump3(131, cn)
				case "/topic/stick/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.StickTopicSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(132, cn)
				case "/topic/unstick/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.UnstickTopicSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(133, cn)
				case "/topic/lock/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					req.URL.Path += extraData
					err = routes.LockTopicSubmit(w,req,user)
					co.RouteViewCounter.Bump3(134, cn)
				case "/topic/unlock/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.UnlockTopicSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(135, cn)
				case "/topic/move/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.MoveTopicSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(136, cn)
				case "/topic/like/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.LikeTopicSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(137, cn)
				case "/topic/unlike/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.UnlikeTopicSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(138, cn)
				case "/topic/attach/add/submit/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize))
					if err != nil {
					return err
					}
					err = c.NoUploadSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AddAttachToTopicSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(139, cn)
				case "/topic/attach/remove/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.RemoveAttachFromTopicSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(140, cn)
				default:
					h, err := c.UserCheckNano(w,req,user,cn)
					if err != nil {
						return err
					}
					err = routes.ViewTopic(w,req,user, h, extraData)
			co.RouteViewCounter.Bump3(141, cn)
			}
		case "/reply":
			switch(req.URL.Path) {
				case "/reply/create/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize))
					if err != nil {
					return err
					}
					err = c.NoUploadSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.CreateReplySubmit(w,req,user)
					co.RouteViewCounter.Bump3(142, cn)
				case "/reply/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ReplyEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(143, cn)
				case "/reply/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ReplyDeleteSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(144, cn)
				case "/reply/like/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ReplyLikeSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(145, cn)
				case "/reply/unlike/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ReplyUnlikeSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(146, cn)
				case "/reply/attach/add/submit/":
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.HandleUploadRoute(w,req,user,int(c.Config.MaxRequestSize))
					if err != nil {
					return err
					}
					err = c.NoUploadSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AddAttachToReplySubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(147, cn)
				case "/reply/attach/remove/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.RemoveAttachFromReplySubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(148, cn)
			}
		case "/profile":
			switch(req.URL.Path) {
				case "/profile/reply/create/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ProfileReplyCreateSubmit(w,req,user)
					co.RouteViewCounter.Bump3(149, cn)
				case "/profile/reply/edit/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ProfileReplyEditSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(150, cn)
				case "/profile/reply/delete/submit/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.ProfileReplyDeleteSubmit(w,req,user,extraData)
					co.RouteViewCounter.Bump3(151, cn)
			}
		case "/poll":
			switch(req.URL.Path) {
				case "/poll/vote/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.PollVote(w,req,user,extraData)
					co.RouteViewCounter.Bump3(152, cn)
				case "/poll/results/":
					err = routes.PollResults(w,req,user,extraData)
					co.RouteViewCounter.Bump3(153, cn)
			}
		case "/accounts":
			switch(req.URL.Path) {
				case "/accounts/login/":
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountLogin(w,req,user,h)
					co.RouteViewCounter.Bump3(154, cn)
				case "/accounts/create/":
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountRegister(w,req,user,h)
					co.RouteViewCounter.Bump3(155, cn)
				case "/accounts/logout/":
					err = c.NoSessionMismatch(w,req,user)
					if err != nil {
						return err
					}
					
					err = c.MemberOnly(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountLogout(w,req,user)
					co.RouteViewCounter.Bump3(156, cn)
				case "/accounts/login/submit/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountLoginSubmit(w,req,user)
					co.RouteViewCounter.Bump3(157, cn)
				case "/accounts/mfa_verify/":
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountLoginMFAVerify(w,req,user,h)
					co.RouteViewCounter.Bump3(158, cn)
				case "/accounts/mfa_verify/submit/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountLoginMFAVerifySubmit(w,req,user)
					co.RouteViewCounter.Bump3(159, cn)
				case "/accounts/create/submit/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountRegisterSubmit(w,req,user)
					co.RouteViewCounter.Bump3(160, cn)
				case "/accounts/password-reset/":
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountPasswordReset(w,req,user,h)
					co.RouteViewCounter.Bump3(161, cn)
				case "/accounts/password-reset/submit/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountPasswordResetSubmit(w,req,user)
					co.RouteViewCounter.Bump3(162, cn)
				case "/accounts/password-reset/token/":
				h, err := c.UserCheckNano(w,req,user,cn)
				if err != nil {
					return err
				}
					err = routes.AccountPasswordResetToken(w,req,user,h)
					co.RouteViewCounter.Bump3(163, cn)
				case "/accounts/password-reset/token/submit/":
					err = c.ParseForm(w,req,user)
					if err != nil {
						return err
					}
					
					err = routes.AccountPasswordResetTokenSubmit(w,req,user)
					co.RouteViewCounter.Bump3(164, cn)
			}
		/*case "/sitemaps": // TODO: Count these views
			req.URL.Path += extraData
			err = sitemapSwitch(w,req)*/
		// ! Temporary fix for certain bots
		case "/static":
			w.Header().Set("Connection", "close")
			http.Redirect(w, req, "/s/"+extraData, http.StatusTemporaryRedirect)
		case "/uploads":
			if extraData == "" {
				co.RouteViewCounter.Bump3(166, cn)
				return c.NotFound(w,req,nil)
			}
			gzw, ok := w.(c.GzipResponseWriter)
			if ok {
				w = gzw.ResponseWriter
				h := w.Header()
				h.Del("Content-Encoding")
			}
			req.URL.Path += extraData
			// TODO: Find a way to propagate errors up from this?
			r.UploadHandler(w,req) // TODO: Count these views
			co.RouteViewCounter.Bump3(166, cn)
			return nil
		case "":
			// Stop the favicons, robots.txt file, etc. resolving to the topics list
			// TODO: Add support for favicons and robots.txt files
			switch(extraData) {
				case "robots.txt":
					co.RouteViewCounter.Bump3(168, cn)
					return routes.RobotsTxt(w,req)
				case "favicon.ico":
					gzw, ok := w.(c.GzipResponseWriter)
					if ok {
						w = gzw.ResponseWriter
						h := w.Header()
						h.Del("Content-Encoding")
					}
					req.URL.Path = "/s/favicon.ico"
					routes.StaticFile(w,req)
					co.RouteViewCounter.Bump3(171, cn)
					return nil
				case "opensearch.xml":
					co.RouteViewCounter.Bump3(170, cn)
					return routes.OpenSearchXml(w,req)
				/*case "sitemap.xml":
					co.RouteViewCounter.Bump3(169, cn)
					return routes.SitemapXml(w,req)*/
			}
			co.RouteViewCounter.Bump(0)
			return c.NotFound(w,req,nil)
		default:
			// A fallback for dynamic routes, e.g. ones declared by plugins
			r.RLock()
			h, ok := r.extraRoutes[req.URL.Path]
			r.RUnlock()
			req.URL.Path += extraData
			
			if ok {
				// TODO: Be more specific about *which* dynamic route it is
				co.RouteViewCounter.Bump(165)
				return h(w,req,user)
			}
			co.RouteViewCounter.Bump3(172, cn)

			lp := strings.ToLower(req.URL.Path)
			if strings.Contains(lp,"admin") || strings.Contains(lp,"sql") || strings.Contains(lp,"manage") || strings.Contains(lp,"//") || strings.Contains(lp,"\\\\") || strings.Contains(lp,"wp") || strings.Contains(lp,"wordpress") || strings.Contains(lp,"config") || strings.Contains(lp,"setup") || strings.Contains(lp,"install") || strings.Contains(lp,"update") || strings.Contains(lp,"php") || strings.Contains(lp,"pl") || strings.Contains(lp,"wget") || strings.Contains(lp,"wp-") || strings.Contains(lp,"include") || strings.Contains(lp,"vendor") || strings.Contains(lp,"bin") || strings.Contains(lp,"system") || strings.Contains(lp,"eval") || strings.Contains(lp,"config") {
				r.SuspiciousRequest(req,"Bad Route")
				return c.MicroNotFound(w,req)
			}
			r.DumpRequest(req,"Bad Route")
			return c.NotFound(w,req,nil)
	}
	return err
}