Browse Source

activation reverted to js and html process instead of 100% js process

Rafał Pitoń 9 years ago
parent
commit
a097f9fa32
52 changed files with 720 additions and 374 deletions
  1. 11 5
      misago/core/errorpages.py
  2. 11 7
      misago/core/exceptionhandler.py
  3. 9 0
      misago/core/exceptions.py
  4. 5 1
      misago/core/forms.py
  5. 1 0
      misago/core/testproject/urls.py
  6. 8 0
      misago/core/testproject/views.py
  7. 6 0
      misago/core/tests/test_errorpages.py
  8. 15 0
      misago/core/tests/test_exceptionhandlers.py
  9. 39 0
      misago/frontend/misago/components/ban-expiration-message.js
  10. 0 0
      misago/frontend/misago/components/ban-expires-message.js
  11. 3 16
      misago/frontend/misago/components/banned-page.js
  12. 100 0
      misago/frontend/misago/components/forms/request-activation-link-form.js
  13. 0 34
      misago/frontend/misago/components/forms/request-link-form.js
  14. 0 0
      misago/frontend/misago/components/loader.js
  15. 1 1
      misago/frontend/misago/components/navbar/compact/guest-nav.js
  16. 1 1
      misago/frontend/misago/components/navbar/compact/user-nav.js
  17. 1 6
      misago/frontend/misago/forms/request-link.js
  18. 1 1
      misago/frontend/misago/mounts/alert.js
  19. 1 1
      misago/frontend/misago/mounts/auth-changed-message.js
  20. 2 2
      misago/frontend/misago/mounts/user-menu.js
  21. 1 1
      misago/frontend/misago/services/modal-controller.js
  22. 11 0
      misago/frontend/misago/services/mount-page.js
  23. 7 6
      misago/frontend/misago/services/show-banned-page.js
  24. 1 0
      misago/frontend/misago/style/misago.less
  25. 24 0
      misago/frontend/misago/style/misago/footer.less
  26. 32 0
      misago/frontend/misago/style/misago/forms.less
  27. 0 5
      misago/frontend/misago/style/misago/material-icons.less
  28. 1 1
      misago/static/misago/css/misago.css
  29. 2 2
      misago/static/misago/js/misago.js
  30. 1 1
      misago/static/misago/js/misago.js.map
  31. 25 0
      misago/templates/misago/activation/done.html
  32. 30 0
      misago/templates/misago/activation/error.html
  33. 55 0
      misago/templates/misago/activation/request.html
  34. 25 0
      misago/templates/misago/activation/stopped.html
  35. 4 4
      misago/templates/misago/base.html
  36. 1 1
      misago/templates/misago/errorpages/403.html
  37. 1 1
      misago/templates/misago/errorpages/404.html
  38. 1 1
      misago/templates/misago/errorpages/405.html
  39. 37 0
      misago/templates/misago/errorpages/banned.html
  40. 1 1
      misago/templates/misago/errorpages/csrf_failure.html
  41. 1 1
      misago/templates/misago/errorpages/csrf_failure_authenticated.html
  42. 7 5
      misago/templates/misago/footer.html
  43. 3 3
      misago/templates/misago/navbar.html
  44. 33 75
      misago/users/api/auth.py
  45. 3 3
      misago/users/decorators.py
  46. 2 17
      misago/users/forms/auth.py
  47. 10 0
      misago/users/models/ban.py
  48. 78 19
      misago/users/tests/test_activation_views.py
  49. 29 139
      misago/users/tests/test_auth_api.py
  50. 2 2
      misago/users/urls/__init__.py
  51. 1 2
      misago/users/urls/api.py
  52. 76 9
      misago/users/views/activation.py

+ 11 - 5
misago/core/errorpages.py

@@ -12,11 +12,17 @@ def _ajax_error(code=406, message=None):
 
 
 @admin_error_page
 @admin_error_page
 def _error_page(request, code, message=None):
 def _error_page(request, code, message=None):
-    response = render(request,
-                      'misago/errorpages/%s.html' % code,
-                      {'message': message})
-    response.status_code = code
-    return response
+    return render(request, 'misago/errorpages/%s.html' % code, {
+            'message': message
+        }, status=code)
+
+
+def banned(request, ban):
+    request.frontend_context['ban'] = ban
+
+    return render(request, 'misago/errorpages/banned.html', {
+            'ban': ban
+        }, status=403)
 
 
 
 
 def permission_denied(request, message=None):
 def permission_denied(request, message=None):

+ 11 - 7
misago/core/exceptionhandler.py

@@ -6,10 +6,11 @@ from django.utils.translation import gettext as _
 from rest_framework.views import exception_handler as rest_exception_handler
 from rest_framework.views import exception_handler as rest_exception_handler
 
 
 from misago.core import errorpages
 from misago.core import errorpages
-from misago.core.exceptions import AjaxError, ExplicitFirstPage, OutdatedSlug
+from misago.core.exceptions import (
+    AjaxError, Banned, ExplicitFirstPage, OutdatedSlug)
 
 
 
 
-HANDLED_EXCEPTIONS = (AjaxError, ExplicitFirstPage, Http404,
+HANDLED_EXCEPTIONS = (AjaxError, Banned, ExplicitFirstPage, Http404,
                       OutdatedSlug, PermissionDenied)
                       OutdatedSlug, PermissionDenied)
 
 
 
 
@@ -22,6 +23,10 @@ def handle_ajax_error(request, exception):
     return JsonResponse(json, status=exception.code)
     return JsonResponse(json, status=exception.code)
 
 
 
 
+def handle_banned_exception(request, exception):
+    return errorpages.banned(request, exception.ban)
+
+
 def handle_explicit_first_page_exception(request, exception):
 def handle_explicit_first_page_exception(request, exception):
     matched_url = request.resolver_match.url_name
     matched_url = request.resolver_match.url_name
     if request.resolver_match.namespace:
     if request.resolver_match.namespace:
@@ -61,6 +66,7 @@ def handle_permission_denied_exception(request, exception):
 
 
 EXCEPTION_HANDLERS = (
 EXCEPTION_HANDLERS = (
     (AjaxError, handle_ajax_error),
     (AjaxError, handle_ajax_error),
+    (Banned, handle_banned_exception),
     (Http404, handle_http404_exception),
     (Http404, handle_http404_exception),
     (ExplicitFirstPage, handle_explicit_first_page_exception),
     (ExplicitFirstPage, handle_explicit_first_page_exception),
     (OutdatedSlug, handle_outdated_slug_exception),
     (OutdatedSlug, handle_outdated_slug_exception),
@@ -85,13 +91,11 @@ def handle_misago_exception(request, exception):
 def handle_api_exception(exception, context):
 def handle_api_exception(exception, context):
     response = rest_exception_handler(exception, context)
     response = rest_exception_handler(exception, context)
     if response:
     if response:
-        if isinstance(exception, PermissionDenied):
+        if isinstance(exception, Banned):
+            response.data['ban'] = exception.ban
+        elif isinstance(exception, PermissionDenied):
             try:
             try:
                 response.data['detail'] = exception.args[0]
                 response.data['detail'] = exception.args[0]
-                try:
-                    response.data.update(exception.args[1])
-                except IndexError:
-                    pass
             except IndexError:
             except IndexError:
                 pass
                 pass
         return response
         return response

+ 9 - 0
misago/core/exceptions.py

@@ -1,3 +1,6 @@
+from django.core.exceptions import PermissionDenied
+
+
 class AjaxError(Exception):
 class AjaxError(Exception):
     """You've tried to do something over AJAX but misago blurped"""
     """You've tried to do something over AJAX but misago blurped"""
     def __init__(self, message=None, code=406):
     def __init__(self, message=None, code=406):
@@ -5,6 +8,12 @@ class AjaxError(Exception):
         self.code = code
         self.code = code
 
 
 
 
+class Banned(PermissionDenied):
+    def __init__(self, ban=None):
+        if ban:
+            self.ban = ban.get_serialized_message()
+
+
 class ExplicitFirstPage(Exception):
 class ExplicitFirstPage(Exception):
     """The url that was used to reach view contained explicit first page"""
     """The url that was used to reach view contained explicit first page"""
     pass
     pass

+ 5 - 1
misago/core/forms.py

@@ -39,7 +39,11 @@ def YesNoSwitch(**kwargs):
 
 
 class IsoDateTimeField(DateTimeField):
 class IsoDateTimeField(DateTimeField):
     input_formats = ['iso8601']
     input_formats = ['iso8601']
-    iso8601_formats = ("%Y-%m-%dT%H:%M:%S+00:00", "%Y-%m-%dT%H:%M:%S.%f+00:00")
+    iso8601_formats = (
+        "%Y-%m-%dT%H:%M:%S",
+        "%Y-%m-%dT%H:%M:%S+00:00",
+        "%Y-%m-%dT%H:%M:%S.%f",
+        "%Y-%m-%dT%H:%M:%S.%f+00:00")
 
 
     def prepare_value(self, value):
     def prepare_value(self, value):
         try:
         try:

+ 1 - 0
misago/core/testproject/urls.py

@@ -11,6 +11,7 @@ urlpatterns += patterns('misago.core.testproject.views',
     url(r'^forum/test-pagination/$', 'test_pagination', name='test_pagination'),
     url(r'^forum/test-pagination/$', 'test_pagination', name='test_pagination'),
     url(r'^forum/test-pagination/(?P<page>[1-9][0-9]*)/$', 'test_pagination', name='test_pagination'),
     url(r'^forum/test-pagination/(?P<page>[1-9][0-9]*)/$', 'test_pagination', name='test_pagination'),
     url(r'^forum/test-valid-slug/(?P<model_slug>[a-z0-9\-]+)-(?P<model_id>\d+)/$', 'validate_slug_view', name='validate_slug_view'),
     url(r'^forum/test-valid-slug/(?P<model_slug>[a-z0-9\-]+)-(?P<model_id>\d+)/$', 'validate_slug_view', name='validate_slug_view'),
+    url(r'^forum/test-banned/$', 'raise_misago_banned', name='raise_misago_banned'),
     url(r'^forum/test-403/$', 'raise_misago_403', name='raise_misago_403'),
     url(r'^forum/test-403/$', 'raise_misago_403', name='raise_misago_403'),
     url(r'^forum/test-404/$', 'raise_misago_404', name='raise_misago_404'),
     url(r'^forum/test-404/$', 'raise_misago_404', name='raise_misago_404'),
     url(r'^forum/test-405/$', 'raise_misago_405', name='raise_misago_405'),
     url(r'^forum/test-405/$', 'raise_misago_405', name='raise_misago_405'),

+ 8 - 0
misago/core/testproject/views.py

@@ -4,10 +4,13 @@ from django.http import Http404, HttpResponse
 
 
 from misago.core import errorpages, mail
 from misago.core import errorpages, mail
 from misago.core.decorators import require_POST
 from misago.core.decorators import require_POST
+from misago.core.exceptions import Banned
 from misago.core.shortcuts import paginate, validate_slug
 from misago.core.shortcuts import paginate, validate_slug
 from misago.core.testproject.models import Model
 from misago.core.testproject.models import Model
 from misago.core.views import home_redirect
 from misago.core.views import home_redirect
 
 
+from misago.users.models import Ban
+
 
 
 def test_mail_user(request):
 def test_mail_user(request):
     User = get_user_model()
     User = get_user_model()
@@ -44,6 +47,11 @@ def validate_slug_view(request, model_id, model_slug):
     return HttpResponse("Allright!")
     return HttpResponse("Allright!")
 
 
 
 
+def raise_misago_banned(request):
+    ban = Ban(user_message="Banned for test!")
+    raise Banned(ban)
+
+
 def raise_misago_403(request):
 def raise_misago_403(request):
     raise PermissionDenied('Misago 403')
     raise PermissionDenied('Misago 403')
 
 

+ 6 - 0
misago/core/tests/test_errorpages.py

@@ -21,6 +21,12 @@ class CSRFErrorViewTests(TestCase):
 class ErrorPageViewsTests(TestCase):
 class ErrorPageViewsTests(TestCase):
     urls = 'misago.core.testproject.urls'
     urls = 'misago.core.testproject.urls'
 
 
+    def test_banned_returns_403(self):
+        """banned error page has no show-stoppers"""
+        response = self.client.get(reverse('raise_misago_banned'))
+        self.assertEqual(response.status_code, 403)
+        self.assertIn("<p>Banned for test!</p>", response.content)
+
     def test_permission_denied_returns_403(self):
     def test_permission_denied_returns_403(self):
         """permission_denied error page has no show-stoppers"""
         """permission_denied error page has no show-stoppers"""
         response = self.client.get(reverse('raise_misago_403'))
         response = self.client.get(reverse('raise_misago_403'))

+ 15 - 0
misago/core/tests/test_exceptionhandlers.py

@@ -3,7 +3,10 @@ from django.core.exceptions import PermissionDenied
 from django.http import Http404
 from django.http import Http404
 from django.test import TestCase
 from django.test import TestCase
 
 
+from misago.users.models import Ban
+
 from misago.core import exceptionhandler
 from misago.core import exceptionhandler
+from misago.core.exceptions import Banned
 
 
 
 
 INVALID_EXCEPTIONS = (
 INVALID_EXCEPTIONS = (
@@ -51,6 +54,18 @@ class GetExceptionHandlerTests(TestCase):
 
 
 
 
 class HandleAPIExceptionTests(TestCase):
 class HandleAPIExceptionTests(TestCase):
+    def test_banned(self):
+        """banned exception is correctly handled"""
+        ban = Ban(user_message="This is test ban!")
+
+        response = exceptionhandler.handle_api_exception(
+            Banned(ban), None)
+
+        self.assertEqual(response.status_code, 403)
+        self.assertEqual(
+            response.data['ban']['message']['html'],
+            "<p>This is test ban!</p>")
+
     def test_permission_denied(self):
     def test_permission_denied(self):
         """permission denied exception is correctly handled"""
         """permission denied exception is correctly handled"""
         response = exceptionhandler.handle_api_exception(
         response = exceptionhandler.handle_api_exception(

+ 39 - 0
misago/frontend/misago/components/ban-expiration-message.js

@@ -0,0 +1,39 @@
+(function (Misago) {
+  'use strict';
+
+  var banExpirationMessage = {
+    controller: function(ban, container) {
+      var _ = container || ban;
+
+      if (container) {
+        return ban;
+      } else {
+        return _.models.deserialize('ban', _.context.ban);
+      }
+    },
+    view: function(ban) {
+      var expirationMessage = null;
+      if (ban.expires_on) {
+        if (ban.expires_on.isAfter(moment())) {
+          expirationMessage = interpolate(
+            gettext('This ban expires %(expires_on)s.'),
+            {'expires_on': ban.expires_on.fromNow()},
+            true);
+        } else {
+          expirationMessage = gettext('This ban has expired.');
+        }
+      } else {
+        expirationMessage = gettext('This ban is permanent.');
+      }
+
+      return m('p', expirationMessage);
+    }
+  };
+
+  Misago.addService('component:ban-expiration-message', function(_) {
+    _.component('ban-expiration-message', banExpirationMessage);
+  },
+  {
+    after: 'components'
+  });
+}(Misago.prototype));

+ 0 - 0
misago/frontend/misago/components/ban-expires-message.js


+ 3 - 16
misago/frontend/misago/components/banned-page.js

@@ -2,29 +2,16 @@
   'use strict';
   'use strict';
 
 
   var bannedPage = {
   var bannedPage = {
-    view: function(ctrl, ban) {
+    view: function(ctrl, ban, _) {
       var error_message = [];
       var error_message = [];
 
 
       if (ban.message.html) {
       if (ban.message.html) {
         error_message.push(m('.lead', m.trust(ban.message.html)));
         error_message.push(m('.lead', m.trust(ban.message.html)));
       } else {
       } else {
-        error_message.push(m('p.lead', gettext('You are banned.')));
+        error_message.push(m('p.lead', ban.message.plain));
       }
       }
 
 
-      var expirationMessage = null;
-      if (ban.expires_on) {
-        if (ban.expires_on.isAfter(moment())) {
-          expirationMessage = interpolate(
-            gettext('This ban expires %(expires_on)s.'),
-            {'expires_on': ban.expires_on.fromNow()},
-            true);
-        } else {
-          expirationMessage = gettext('This ban has expired.');
-        }
-      } else {
-        expirationMessage = gettext('This ban is permanent.');
-      }
-      error_message.push(m('p', expirationMessage));
+      error_message.push(_.component('ban-expiration-message', ban));
 
 
       return m('.page.page-error.page-error-banned',
       return m('.page.page-error.page-error-banned',
         m('.container',
         m('.container',

+ 100 - 0
misago/frontend/misago/components/forms/request-activation-link-form.js

@@ -0,0 +1,100 @@
+(function (Misago) {
+  'use strict';
+
+  var style = '.well.well-form.well-form-request-activation-link';
+
+  var ViewModel = function(api) {
+    this.api = api;
+    this.user = null;
+
+    this.success = function(user) {
+      this.user = user;
+    };
+
+    this.error = function(rejection, _) {
+      if (rejection.code === 'already_active') {
+        _.alert.info(rejection.detail);
+        _.modal('sign-in');
+      } else if (rejection.code === 'inactive_admin') {
+        _.alert.info(rejection.detail);
+      } else {
+        _.alert.error(rejection.detail);
+      }
+    };
+
+    this.reset = function() {
+      this.user = null;
+    };
+  };
+
+  var form = {
+    controller: function(_) {
+      var vm = new ViewModel(_.context.SEND_ACTIVATION_API_URL);
+
+      return {
+        vm: vm,
+        form: _.form('request-link', vm)
+      };
+    },
+    view: function(ctrl, _) {
+      if (ctrl.vm.user) {
+        return this.done(ctrl.vm, ctrl.form, _);
+      } else {
+        return this.form(ctrl.form, _);
+      }
+    },
+    done: function(vm, form, _) {
+      var message = gettext("Activation link sent to %(email)s.");
+
+      return m(style + '.well-done',
+        m('.done-message', [
+          m('.message-icon',
+            m('span.material-icon', 'check')
+          ),
+          m('.message-body',
+            m('p',
+              interpolate(message, {
+                email: vm.user.email
+              }, true)
+            )
+          ),
+          _.component('button', {
+            class: '.btn-default.btn-block',
+            submit: false,
+            label: gettext("Request another link"),
+            onclick: form.reset.bind(form)
+          })
+
+        ])
+      );
+    },
+    form: function(form, _) {
+      return m(style,
+        m('form', {onsubmit: form.submit}, [
+          m('.form-group',
+            m('.control-input',
+              Misago.input({
+                disabled: form.isBusy,
+                value: form.email,
+                placeholder: gettext("Your e-mail address")
+              })
+            )
+          ),
+          _.component('button', {
+            class: '.btn-primary.btn-block',
+            submit: true,
+            loading: form.isBusy,
+            label: gettext("Send link")
+          })
+        ])
+      );
+    }
+  };
+
+  Misago.addService('component:request-link-form', function(_) {
+    _.component('request-activation-link-form', form);
+  },
+  {
+    after: 'components'
+  });
+}(Misago.prototype));

+ 0 - 34
misago/frontend/misago/components/forms/request-link-form.js

@@ -1,34 +0,0 @@
-(function (Misago) {
-  'use strict';
-
-  var form = {
-    view: function(ctrl, form, _) {
-      return m('.well.well-form',
-        m('form', {onsubmit: form.submit}, [
-          m('.form-group',
-            m('.control-input',
-              Misago.input({
-                disabled: form.isBusy,
-                value: form.email,
-                placeholder: gettext("Your e-mail address")
-              })
-            )
-          ),
-          _.component('button', {
-            class: '.btn-primary.btn-block',
-            submit: true,
-            loading: form.isBusy,
-            label: gettext("Send link")
-          })
-        ])
-      );
-    }
-  };
-
-  Misago.addService('component:request-link-form', function(_) {
-    _.component('request-link-form', form);
-  },
-  {
-    after: 'components'
-  });
-}(Misago.prototype));

+ 0 - 0
misago/frontend/misago/components/loaders.js → misago/frontend/misago/components/loader.js


+ 1 - 1
misago/frontend/misago/components/navbar/compact/guest-nav.js

@@ -5,7 +5,7 @@
     controller: function(_) {
     controller: function(_) {
       return {
       return {
         openUserMenu: function() {
         openUserMenu: function() {
-          _.dropdown.toggle('misago-navbar-dropdown', 'navbar:dropdown:guest');
+          _.dropdown.toggle('navbar-dropdown', 'navbar:dropdown:guest');
         }
         }
       };
       };
     },
     },

+ 1 - 1
misago/frontend/misago/components/navbar/compact/user-nav.js

@@ -5,7 +5,7 @@
     controller: function(_) {
     controller: function(_) {
       return {
       return {
         openUserMenu: function() {
         openUserMenu: function() {
-          _.dropdown.toggle('misago-navbar-dropdown', 'navbar:dropdown:user');
+          _.dropdown.toggle('navbar-dropdown', 'navbar:dropdown:user');
           return false;
           return false;
         }
         }
       };
       };

+ 1 - 6
misago/frontend/misago/forms/request-link.js

@@ -22,7 +22,7 @@
     };
     };
 
 
     this.submit = function() {
     this.submit = function() {
-      _.api.endpoint('auth').endpoint(vm.endpoint).post({
+      _.ajax.post(vm.api, {
         email: self.email()
         email: self.email()
       }).then(function(user) {
       }).then(function(user) {
         self.success(user);
         self.success(user);
@@ -38,11 +38,6 @@
     this.error = function(rejection) {
     this.error = function(rejection) {
       if (rejection.status === 400) {
       if (rejection.status === 400) {
           vm.error(rejection, _);
           vm.error(rejection, _);
-      } else if (rejection.status === 403 && rejection.ban) {
-        _.router.error403({
-          message: '',
-          ban: rejection.ban
-        });
       } else {
       } else {
         _.api.alert(rejection);
         _.api.alert(rejection);
       }
       }

+ 1 - 1
misago/frontend/misago/mounts/alert.js

@@ -1,7 +1,7 @@
 (function (Misago) {
 (function (Misago) {
   'use strict';
   'use strict';
 
 
-  var mount = document.getElementById('misago-alert-mount');
+  var mount = document.getElementById('alert-mount');
 
 
   Misago.addService('mount:alert', {
   Misago.addService('mount:alert', {
     factory: function(_) {
     factory: function(_) {

+ 1 - 1
misago/frontend/misago/mounts/auth-changed-message.js

@@ -1,7 +1,7 @@
 (function (Misago) {
 (function (Misago) {
   'use strict';
   'use strict';
 
 
-  var mount = document.getElementById('misago-auth-changed-message-mount');
+  var mount = document.getElementById('auth-changed-message-mount');
 
 
   Misago.addService('mount:auth-changed-message', {
   Misago.addService('mount:auth-changed-message', {
     factory: function(_) {
     factory: function(_) {

+ 2 - 2
misago/frontend/misago/mounts/user-menu.js

@@ -1,8 +1,8 @@
 (function (Misago) {
 (function (Misago) {
   'use strict';
   'use strict';
 
 
-  var mountDesktop = document.getElementById('misago-user-menu-mount');
-  var mountCompact = document.getElementById('misago-user-menu-compact-mount');
+  var mountDesktop = document.getElementById('user-menu-mount');
+  var mountCompact = document.getElementById('user-menu-compact-mount');
 
 
   Misago.addService('mount:user-menu', {
   Misago.addService('mount:user-menu', {
     factory: function(_) {
     factory: function(_) {

+ 1 - 1
misago/frontend/misago/services/modal-controller.js

@@ -4,7 +4,7 @@
   var Modal = function() {
   var Modal = function() {
     var self = this;
     var self = this;
 
 
-    var element = document.getElementById('misago-modal');
+    var element = document.getElementById('modal-mount');
 
 
     this.destroy = function() {
     this.destroy = function() {
       $(element).off();
       $(element).off();

+ 11 - 0
misago/frontend/misago/services/mount-page.js

@@ -0,0 +1,11 @@
+(function (Misago) {
+  'use strict';
+
+  var mount = document.getElementById('page-mount');
+
+  Misago.addService('mount-page', function(_) {
+    _.mountPage = function(component) {
+      m.mount(mount, component);
+    };
+  });
+}(Misago.prototype));

+ 7 - 6
misago/frontend/misago/services/show-banned-page.js

@@ -1,16 +1,17 @@
 (function (Misago) {
 (function (Misago) {
   'use strict';
   'use strict';
 
 
-  var mount = document.getElementById('misago-page-mount');
-
   Misago.addService('show-banned-page', function(_) {
   Misago.addService('show-banned-page', function(_) {
-    _.showBannedPage = function(ban) {
+    _.showBannedPage = function(ban, changeState) {
       var component = _.component(
       var component = _.component(
         'banned-page', _.models.deserialize('ban', ban));
         'banned-page', _.models.deserialize('ban', ban));
 
 
-      _.title.set(gettext('You are banned'));
-      window.history.pushState({}, "", _.context.BANNED_URL);
-      m.mount(mount, component);
+      if (typeof changeState === 'undefined' || !changeState) {
+        _.title.set(gettext('You are banned'));
+        window.history.pushState({}, "", _.context.BANNED_URL);
+      }
+
+      _.mountPage(component);
     };
     };
   });
   });
 }(Misago.prototype));
 }(Misago.prototype));

+ 1 - 0
misago/frontend/misago/style/misago.less

@@ -64,6 +64,7 @@
 @import "misago/forms.less";
 @import "misago/forms.less";
 @import "misago/buttons.less";
 @import "misago/buttons.less";
 @import "misago/dropdowns.less";
 @import "misago/dropdowns.less";
+@import "misago/footer.less";
 
 
 // Pages
 // Pages
 @import "misago/message-pages.less";
 @import "misago/message-pages.less";

+ 24 - 0
misago/frontend/misago/style/misago/footer.less

@@ -0,0 +1,24 @@
+//
+// Forum Footer style
+// --------------------------------------------------
+
+
+// Superbasic spacing and layout for easy overriding
+.misago-footer {
+  margin-top: @line-height-computed * 1.5;
+  margin-bottom: @line-height-computed * 2.5;
+
+  .footer-content {
+    border-top: 1px solid @page-header-border-color;
+    padding-top: @line-height-computed * 1.5;
+  }
+}
+
+
+// Position "enable JS!" message's icon
+.misago-footer .noscript-message .material-icon {
+  position: relative;
+  bottom: 1px;
+
+  font-size: @font-size-large;
+}

+ 32 - 0
misago/frontend/misago/style/misago/forms.less

@@ -10,3 +10,35 @@
   font-size: @line-height-base;
   font-size: @line-height-base;
   line-height: @line-height-base;
   line-height: @line-height-base;
 }
 }
+
+
+// Well done
+.well.well-form.well-done {
+  font-size: @font-size-large;
+  text-align: center;
+
+  .message-icon {
+    margin-bottom: @line-height-computed / 2;
+
+    font-size: @font-size-large * 5;
+    line-height: @font-size-large * 5;
+  }
+
+  .message-body {
+    margin-bottom: @line-height-computed / 3;
+  }
+}
+
+
+// Noscript well
+.well.well-form.well-noscript {
+  font-size: @font-size-large;
+  text-align: center;
+
+  .message-icon {
+    margin-bottom: @line-height-computed / 2;
+
+    font-size: @font-size-large * 5;
+    line-height: @font-size-large * 5;
+  }
+}

+ 0 - 5
misago/frontend/misago/style/misago/material-icons.less

@@ -3,11 +3,6 @@
 // --------------------------------------------------
 // --------------------------------------------------
 
 
 
 
-/*
-Just a note about using Material Icons
-*/
-
-
 @font-face {
 @font-face {
   font-family: 'Material Icons';
   font-family: 'Material Icons';
   font-style: normal;
   font-style: normal;

+ 1 - 1
misago/static/misago/css/misago.css

@@ -1 +1 @@
-/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */.btn,.caret,img{vertical-align:middle}hr,img{border:0}body,figure{margin:0}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.pre-scrollable{max-height:340px}.img-thumbnail,.table,label{max-width:100%}.alerts,a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;font-size:10px;-webkit-tap-highlight-color:transparent}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}b,optgroup,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}svg:not(:root){overflow:hidden}hr{box-sizing:content-box;height:0}pre,textarea{overflow:auto}code,kbd,pre,samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{blockquote,img,pre,tr{page-break-inside:avoid}*,:after,:before{background:0 0!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999}thead{display:table-header-group}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}.btn,.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-warning.active,.btn-warning:active,.btn.active,.btn:active,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.form-control,.navbar-toggle,.open>.dropdown-toggle.btn-danger,.open>.dropdown-toggle.btn-default,.open>.dropdown-toggle.btn-info,.open>.dropdown-toggle.btn-primary,.open>.dropdown-toggle.btn-warning{background-image:none}.img-thumbnail,body{background-color:#fff}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}dt,kbd kbd,label{font-weight:700}address,blockquote .small,blockquote footer,blockquote small,dd,dt,pre{line-height:1.42857143}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{background-color:#fcf8e3;padding:.2em}.list-inline,.list-unstyled{padding-left:0;list-style:none}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}pre code,table{background-color:transparent}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}dl,ol,ul{margin-top:0}ol,ul{margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-inline{margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-bottom:20px}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}code,kbd{padding:2px 4px;font-size:90%}caption,th{text-align:left}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}.container,.container-fluid{margin-right:auto;margin-left:auto}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-radius:0}.container,.container-fluid{padding-left:15px;padding-right:15px}.pre-scrollable{overflow-y:scroll}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.row{margin-left:-15px;margin-right:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}caption{padding-top:8px;padding-bottom:8px;color:#777}.table{width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover,.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset,legend{padding:0;border:0}fieldset{margin:0;min-width:0}legend{display:block;width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px}.media-object.img-thumbnail,.nav>li>a>img{max-width:none}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}.form-control,output{font-size:14px;line-height:1.42857143;color:#555;display:block}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}output{padding-top:7px}.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .form-control-feedback,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px\9}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0;min-height:34px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.form-group-sm .form-control,.input-sm{padding:5px 10px;border-radius:3px;font-size:12px}.input-sm{height:30px;line-height:1.5}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;line-height:1.5}.form-group-lg .form-control,.input-lg{border-radius:6px;padding:10px 16px;font-size:18px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;line-height:1.3333333}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;line-height:1.3333333}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.collapsing,.dropdown,.dropup{position:relative}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.btn,.dropdown-header,.nav-tabs>li>a{line-height:1.42857143}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .form-control-feedback,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .form-control-feedback,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-control-static,.form-inline .form-group{display:inline-block}.form-inline .control-label,.form-inline .form-group{margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.btn-block,input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;touch-action:manipulation;cursor:pointer;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.btn.active,.btn:active,.dropdown-toggle:focus,.modal,.modal-content,.navbar-toggle:focus,.open>a{outline:0}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary.active,.btn-primary:active,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success.active,.btn-success:active,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info.active,.btn-info:active,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger.active,.btn-danger:active,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#337ab7;font-weight:400;border-radius:0}.alert .alert-link,.close{font-weight:700}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-sm,.btn-xs{font-size:12px;line-height:1.5;border-radius:3px}.btn-sm{padding:5px 10px}.btn-xs{padding:1px 5px}.btn-block{display:block}.btn-block+.btn-block{margin-top:5px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{height:0;overflow:hidden;-webkit-transition-property:height,visibility;transition-property:height,visibility;-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu-right,.dropdown-menu.pull-right{left:auto;right:0}.nav>li,.nav>li>a,.open>.dropdown-menu{display:block}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#337ab7}.dropdown-header,.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.nav>li.disabled>a{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.nav>li,.nav>li>a,.navbar{position:relative}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.nav-justified>.dropdown .dropdown-menu,.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li>a{padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px;margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-justified>li,.nav-stacked>li{float:none}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{min-height:50px;border:1px solid transparent}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar{border-radius:4px}.navbar-header{float:left}.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-left:0;padding-right:0}}.modal,.modal-open,.progress{overflow:hidden}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}.navbar-static-top{z-index:1000;border-width:0 0 1px}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}.progress-bar-striped,.progress-striped .progress-bar,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}@media (min-width:768px){.navbar-toggle{display:none}.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:8px -15px}@media (min-width:768px){.navbar-form .form-control-static,.navbar-form .form-group{display:inline-block}.navbar-form .control-label,.navbar-form .form-group{margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:4px 4px 0 0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.modal,.modal-backdrop{top:0;right:0;bottom:0;left:0}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-striped .progress-bar-info,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal{display:none;position:fixed;z-index:1050;-webkit-overflow-scrolling:touch}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.alerts,.auth-changed-message{transition:top 300ms ease;width:100%}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box}.modal-backdrop{position:fixed;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.43px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.row:after,.row:before{content:" ";display:table}.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.hidden,.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.material-icon,.user-dropdown .dropdown-header strong{font-weight:400}.affix{position:fixed}@-ms-viewport{width:device-width}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}.visible-xs-block{display:block!important}.visible-xs-inline{display:inline!important}.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}.visible-sm-block{display:block!important}.visible-sm-inline{display:inline!important}.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}.visible-md-block{display:block!important}.visible-md-inline{display:inline!important}.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}.visible-lg-block{display:block!important}.visible-lg-inline{display:inline!important}.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}.hidden-print{display:none!important}}.alerts p,.loader-compact>div,.navbar .navbar-full .navbar-brand>*{display:inline-block}.auth-changed-message{position:fixed;top:0;left:0;z-index:1070}.auth-changed-message>div{position:absolute;bottom:0;width:100%;background-color:#eee;padding:20px 0}.auth-changed-message.show>div{top:0;bottom:auto}.auth-changed-message p{padding:10px 0;color:#222;font-size:18px}@media screen and (max-width:991px){.auth-changed-message{text-align:center}.auth-changed-message .btn{padding:10px 16px;font-size:18px}}.alerts{position:fixed;top:-100%;z-index:1060;text-align:center;font-size:18px}.alerts.in{top:0;transition:top 200ms ease}.alerts p{border-radius:0 0 4px 4px;margin:0;pointer-events:all}.loader.sk-folding-cube{margin:80px auto;width:80px;height:80px;position:relative;-webkit-transform:rotateZ(45deg);transform:rotateZ(45deg)}.loader.sk-folding-cube .sk-cube{float:left;width:50%;height:50%;position:relative;-webkit-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1)}.loader.sk-folding-cube .sk-cube:before{content:'';position:absolute;top:0;left:0;width:100%;height:100%;background-color:#777;-webkit-animation:sk-foldCubeAngle 2.4s infinite linear both;animation:sk-foldCubeAngle 2.4s infinite linear both;-webkit-transform-origin:100% 100%;-ms-transform-origin:100% 100%;transform-origin:100% 100%}.loader.sk-folding-cube .sk-cube2{-webkit-transform:scale(1.1) rotateZ(90deg);transform:scale(1.1) rotateZ(90deg)}.loader.sk-folding-cube .sk-cube3{-webkit-transform:scale(1.1) rotateZ(180deg);transform:scale(1.1) rotateZ(180deg)}.loader.sk-folding-cube .sk-cube4{-webkit-transform:scale(1.1) rotateZ(270deg);transform:scale(1.1) rotateZ(270deg)}.loader.sk-folding-cube .sk-cube2:before{-webkit-animation-delay:.3s;animation-delay:.3s}.loader.sk-folding-cube .sk-cube3:before{-webkit-animation-delay:.6s;animation-delay:.6s}.loader.sk-folding-cube .sk-cube4:before{-webkit-animation-delay:.9s;animation-delay:.9s}@-webkit-keyframes sk-foldCubeAngle{0%,10%{-webkit-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-webkit-transform:perspective(140px) rotateX(0);transform:perspective(140px) rotateX(0);opacity:1}100%,90%{-webkit-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}@keyframes sk-foldCubeAngle{0%,10%{-webkit-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-webkit-transform:perspective(140px) rotateX(0);transform:perspective(140px) rotateX(0);opacity:1}100%,90%{-webkit-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}.loader-compact{margin:0 auto;width:50px;text-align:center}.loader-compact>div{width:10px;height:10px;background-color:#333;border-radius:100%;-webkit-animation:sk-bouncedelay 1.4s infinite ease-in-out both;animation:sk-bouncedelay 1.4s infinite ease-in-out both}.loader-compact .bounce1{-webkit-animation-delay:-.32s;animation-delay:-.32s}.loader-compact .bounce2{margin:0 4px;-webkit-animation-delay:-.16s;animation-delay:-.16s}@-webkit-keyframes sk-bouncedelay{0%,100%,80%{-webkit-transform:scale(.5)}40%{-webkit-transform:scale(1)}}@keyframes sk-bouncedelay{0%,100%,80%{-webkit-transform:scale(.5);transform:scale(.5)}40%{-webkit-transform:scale(1);transform:scale(1)}}.page-loading .lead{margin-top:-40px;margin-bottom:80px;color:#777;text-align:center}.navbar{margin-bottom:0}.navbar .navbar-full .navbar-brand img{height:16px}.navbar .navbar-full .nav-guest,.navbar .navbar-full .nav-user{float:right}.navbar .navbar-full .nav-user .dropdown-toggle{padding:8px}.navbar .navbar-full .nav-user .dropdown-toggle img{width:34px;height:34px}.navbar ul.navbar-compact-nav{margin:0;display:table;width:100%}.navbar ul.navbar-compact-nav>li{display:table-cell}.navbar ul.navbar-compact-nav>li>a,.navbar ul.navbar-compact-nav>li>button{background:0 0;border:none;margin:0;padding-top:10px;padding-bottom:10px;width:100%;color:#777;text-align:center}.navbar ul.navbar-compact-nav>li>a:focus,.navbar ul.navbar-compact-nav>li>a:hover,.navbar ul.navbar-compact-nav>li>button:focus,.navbar ul.navbar-compact-nav>li>button:hover{color:#333;background-color:transparent}.navbar ul.navbar-compact-nav>li>a>img,.navbar ul.navbar-compact-nav>li>button>img{width:24px;height:24px}.navbar ul.navbar-compact-nav>li>button{padding-top:10px;padding-bottom:10px}.navbar ul.navbar-compact-nav>li>a>.material-icon{font-size:24px;line-height:24px}@media (max-width:767px){.navbar.navbar-misago{min-height:auto}}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(../fonts/MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular'),url(../fonts/MaterialIcons-Regular.woff2) format('woff2'),url(../fonts/MaterialIcons-Regular.woff) format('woff'),url(../fonts/MaterialIcons-Regular.ttf) format('truetype')}.material-icon{font-family:'Material Icons';font-style:normal;display:inline-block;width:1em;height:1em;line-height:1;text-align:center;text-transform:none;letter-spacing:normal;vertical-align:middle;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}@media screen and (max-width:991px){.modal-message{text-align:center}.modal-message .message-icon{margin:30px}.modal-message .message-icon .material-icon{font-size:160px}}@media screen and (min-width:992px){.modal-message .message-icon{float:left}.modal-message .message-icon .material-icon{font-size:80px}.modal-message .message-body{margin-left:100px}}@media screen and (max-width:991px){.modal-register .modal-footer{text-align:center}.modal-register .modal-footer a{display:block}.modal-register .modal-footer .btn{display:block;float:none;margin-top:10px;width:100%}}.material-icon.form-control-feedback{top:6px;right:24px;font-size:1.42857143;line-height:1.42857143}.btn.btn-loading,.btn.btn-loading:active,.btn.btn-loading:focus,.btn.btn-loading:hover,.btn.btn-loading:link,.btn.btn-loading:visited{color:transparent}.btn.btn-loading .loader-compact,.btn.btn-loading:active .loader-compact,.btn.btn-loading:focus .loader-compact,.btn.btn-loading:hover .loader-compact,.btn.btn-loading:link .loader-compact,.btn.btn-loading:visited .loader-compact{margin-top:-20px;height:20px;position:relative;top:0}.btn.btn-loading.btn-default .loader-compact>div{background-color:#333}.btn.btn-loading.btn-danger .loader-compact>div,.btn.btn-loading.btn-info .loader-compact>div,.btn.btn-loading.btn-primary .loader-compact>div,.btn.btn-loading.btn-success .loader-compact>div,.btn.btn-loading.btn-warning .loader-compact>div{background-color:#fff}.dropdown-menu>li>.btn-link,.dropdown-menu>li>a{display:block;border:none;clear:both;float:none;padding:4px 20px;width:100%;color:#333;font-weight:400;line-height:1.42857143;text-align:left;white-space:nowrap}.dropdown-menu>li>.btn-link:focus,.dropdown-menu>li>.btn-link:hover,.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#f5f5f5;color:#262626;text-decoration:none}.dropdown-menu>li>.btn-link .material-icon,.dropdown-menu>li>a .material-icon{margin:-2px 7px -2px 0;position:relative;bottom:1px;font-size:18px}.dropdown-menu .dropdown-footer{padding:6px 20px}.mobile-dropdown{position:static;margin:0}.mobile-dropdown.open>.dropdown-menu{border:none;border-radius:0;-webkit-box-shadow:none;box-shadow:none;display:block;margin:0;width:100%;position:static}.user-dropdown .guest-preview{text-align:center}.user-dropdown .guest-preview .row{margin:0}.navbar .user-dropdown{width:240px}.user-dropdown .dropdown-header{padding:6px 20px;font-size:18px}@media screen and (max-width:991px){.page-error,.page-message{text-align:center}.page-error .message-icon,.page-message .message-icon{margin:30px}.page-error .message-icon .material-icon,.page-message .message-icon .material-icon{font-size:160px}}@media screen and (min-width:992px){.page-error .message-panel,.page-message .message-panel{margin:60px auto;max-width:779.35px;overflow:auto}.page-error .message-icon,.page-message .message-icon{float:left}.page-error .message-icon .material-icon,.page-message .message-icon .material-icon{font-size:80px}.page-error .message-body,.page-message .message-body{margin-left:100px}}
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */.btn,.caret,img{vertical-align:middle}hr,img{border:0}body,figure{margin:0}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.pre-scrollable{max-height:340px}.img-thumbnail,.table,label{max-width:100%}.alerts,a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;font-size:10px;-webkit-tap-highlight-color:transparent}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}b,optgroup,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}svg:not(:root){overflow:hidden}hr{box-sizing:content-box;height:0}pre,textarea{overflow:auto}code,kbd,pre,samp{font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{blockquote,img,pre,tr{page-break-inside:avoid}*,:after,:before{background:0 0!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999}thead{display:table-header-group}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}.btn,.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-warning.active,.btn-warning:active,.btn.active,.btn:active,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.form-control,.navbar-toggle,.open>.dropdown-toggle.btn-danger,.open>.dropdown-toggle.btn-default,.open>.dropdown-toggle.btn-info,.open>.dropdown-toggle.btn-primary,.open>.dropdown-toggle.btn-warning{background-image:none}.img-thumbnail,body{background-color:#fff}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;text-decoration:underline}a:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.42857143;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}dt,kbd kbd,label{font-weight:700}address,blockquote .small,blockquote footer,blockquote small,dd,dt,pre{line-height:1.42857143}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{background-color:#fcf8e3;padding:.2em}.list-inline,.list-unstyled{padding-left:0;list-style:none}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}pre code,table{background-color:transparent}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}dl,ol,ul{margin-top:0}ol,ul{margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-inline{margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-bottom:20px}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}code,kbd{padding:2px 4px;font-size:90%}caption,th{text-align:left}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}.container,.container-fluid{margin-right:auto;margin-left:auto}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;border-radius:0}.container,.container-fluid{padding-left:15px;padding-right:15px}.pre-scrollable{overflow-y:scroll}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.row{margin-left:-15px;margin-right:-15px}.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}caption{padding-top:8px;padding-bottom:8px;color:#777}.table{width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover,.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset,legend{padding:0;border:0}fieldset{margin:0;min-width:0}legend{display:block;width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px}.media-object.img-thumbnail,.nav>li>a>img{max-width:none}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}.form-control,output{font-size:14px;line-height:1.42857143;color:#555;display:block}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=checkbox]:focus,input[type=radio]:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}output{padding-top:7px}.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .form-control-feedback,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-inline label{color:#3c763d}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px\9}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio label,fieldset[disabled] .radio-inline,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0;min-height:34px}.form-control-static.input-lg,.form-control-static.input-sm{padding-left:0;padding-right:0}.form-group-sm .form-control,.input-sm{padding:5px 10px;border-radius:3px;font-size:12px}.input-sm{height:30px;line-height:1.5}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;line-height:1.5}.form-group-lg .form-control,.input-lg{border-radius:6px;padding:10px 16px;font-size:18px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;line-height:1.3333333}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;line-height:1.3333333}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.collapsing,.dropdown,.dropup{position:relative}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.btn,.dropdown-header,.nav-tabs>li>a{line-height:1.42857143}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .form-control-feedback,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-error .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .form-control-feedback,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-control-static,.form-inline .form-group{display:inline-block}.form-inline .control-label,.form-inline .form-group{margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.btn-block,input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}.form-horizontal .form-group-lg .control-label{padding-top:14.33px;font-size:18px}.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;touch-action:manipulation;cursor:pointer;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:dotted thin;outline:-webkit-focus-ring-color auto 5px;outline-offset:-2px}.btn.active,.btn:active,.dropdown-toggle:focus,.modal,.modal-content,.navbar-toggle:focus,.open>a{outline:0}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.btn-default:hover,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary.active,.btn-primary:active,.btn-primary:hover,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success.active,.btn-success:active,.btn-success:hover,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info.active,.btn-info:active,.btn-info:hover,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.btn-warning:hover,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger.active,.btn-danger:active,.btn-danger:hover,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#337ab7;font-weight:400;border-radius:0}.alert .alert-link,.close{font-weight:700}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-sm,.btn-xs{font-size:12px;line-height:1.5;border-radius:3px}.btn-sm{padding:5px 10px}.btn-xs{padding:1px 5px}.btn-block{display:block}.btn-block+.btn-block{margin-top:5px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{height:0;overflow:hidden;-webkit-transition-property:height,visibility;transition-property:height,visibility;-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu-right,.dropdown-menu.pull-right{left:auto;right:0}.nav>li,.nav>li>a,.open>.dropdown-menu{display:block}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#337ab7}.dropdown-header,.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover,.nav>li.disabled>a{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.nav>li,.nav>li>a,.navbar{position:relative}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.nav-justified>.dropdown .dropdown-menu,.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li>a{padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px;margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0;border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-justified>li,.nav-stacked>li{float:none}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{min-height:50px;border:1px solid transparent}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar{border-radius:4px}.navbar-header{float:left}.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-left:0;padding-right:0}}.modal,.modal-open,.progress{overflow:hidden}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}.navbar-static-top{z-index:1000;border-width:0 0 1px}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}.progress-bar-striped,.progress-striped .progress-bar,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}@media (min-width:768px){.navbar-toggle{display:none}.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin:8px -15px}@media (min-width:768px){.navbar-form .form-control-static,.navbar-form .form-group{display:inline-block}.navbar-form .control-label,.navbar-form .form-group{margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-radius:4px 4px 0 0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.modal,.modal-backdrop{top:0;right:0;bottom:0;left:0}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#337ab7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-striped .progress-bar-info,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal{display:none;position:fixed;z-index:1050;-webkit-overflow-scrolling:touch}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.alerts,.auth-changed-message{transition:top 300ms ease;width:100%}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box}.modal-backdrop{position:fixed;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.43px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.row:after,.row:before{content:" ";display:table}.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.row:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.hidden,.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.material-icon,.user-dropdown .dropdown-header strong{font-weight:400}.affix{position:fixed}@-ms-viewport{width:device-width}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}.visible-xs-block{display:block!important}.visible-xs-inline{display:inline!important}.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}.visible-sm-block{display:block!important}.visible-sm-inline{display:inline!important}.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}.visible-md-block{display:block!important}.visible-md-inline{display:inline!important}.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}.visible-lg-block{display:block!important}.visible-lg-inline{display:inline!important}.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}.hidden-print{display:none!important}}.alerts p,.loader-compact>div,.navbar .navbar-full .navbar-brand>*{display:inline-block}.auth-changed-message{position:fixed;top:0;left:0;z-index:1070}.auth-changed-message>div{position:absolute;bottom:0;width:100%;background-color:#eee;padding:20px 0}.auth-changed-message.show>div{top:0;bottom:auto}.auth-changed-message p{padding:10px 0;color:#222;font-size:18px}@media screen and (max-width:991px){.auth-changed-message{text-align:center}.auth-changed-message .btn{padding:10px 16px;font-size:18px}}.alerts{position:fixed;top:-100%;z-index:1060;text-align:center;font-size:18px}.alerts.in{top:0;transition:top 200ms ease}.alerts p{border-radius:0 0 4px 4px;margin:0;pointer-events:all}.loader.sk-folding-cube{margin:80px auto;width:80px;height:80px;position:relative;-webkit-transform:rotateZ(45deg);transform:rotateZ(45deg)}.loader.sk-folding-cube .sk-cube{float:left;width:50%;height:50%;position:relative;-webkit-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1)}.loader.sk-folding-cube .sk-cube:before{content:'';position:absolute;top:0;left:0;width:100%;height:100%;background-color:#777;-webkit-animation:sk-foldCubeAngle 2.4s infinite linear both;animation:sk-foldCubeAngle 2.4s infinite linear both;-webkit-transform-origin:100% 100%;-ms-transform-origin:100% 100%;transform-origin:100% 100%}.loader.sk-folding-cube .sk-cube2{-webkit-transform:scale(1.1) rotateZ(90deg);transform:scale(1.1) rotateZ(90deg)}.loader.sk-folding-cube .sk-cube3{-webkit-transform:scale(1.1) rotateZ(180deg);transform:scale(1.1) rotateZ(180deg)}.loader.sk-folding-cube .sk-cube4{-webkit-transform:scale(1.1) rotateZ(270deg);transform:scale(1.1) rotateZ(270deg)}.loader.sk-folding-cube .sk-cube2:before{-webkit-animation-delay:.3s;animation-delay:.3s}.loader.sk-folding-cube .sk-cube3:before{-webkit-animation-delay:.6s;animation-delay:.6s}.loader.sk-folding-cube .sk-cube4:before{-webkit-animation-delay:.9s;animation-delay:.9s}@-webkit-keyframes sk-foldCubeAngle{0%,10%{-webkit-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-webkit-transform:perspective(140px) rotateX(0);transform:perspective(140px) rotateX(0);opacity:1}100%,90%{-webkit-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}@keyframes sk-foldCubeAngle{0%,10%{-webkit-transform:perspective(140px) rotateX(-180deg);transform:perspective(140px) rotateX(-180deg);opacity:0}25%,75%{-webkit-transform:perspective(140px) rotateX(0);transform:perspective(140px) rotateX(0);opacity:1}100%,90%{-webkit-transform:perspective(140px) rotateY(180deg);transform:perspective(140px) rotateY(180deg);opacity:0}}.loader-compact{margin:0 auto;width:50px;text-align:center}.loader-compact>div{width:10px;height:10px;background-color:#333;border-radius:100%;-webkit-animation:sk-bouncedelay 1.4s infinite ease-in-out both;animation:sk-bouncedelay 1.4s infinite ease-in-out both}.loader-compact .bounce1{-webkit-animation-delay:-.32s;animation-delay:-.32s}.loader-compact .bounce2{margin:0 4px;-webkit-animation-delay:-.16s;animation-delay:-.16s}@-webkit-keyframes sk-bouncedelay{0%,100%,80%{-webkit-transform:scale(.5)}40%{-webkit-transform:scale(1)}}@keyframes sk-bouncedelay{0%,100%,80%{-webkit-transform:scale(.5);transform:scale(.5)}40%{-webkit-transform:scale(1);transform:scale(1)}}.page-loading .lead{margin-top:-40px;margin-bottom:80px;color:#777;text-align:center}.navbar{margin-bottom:0}.navbar .navbar-full .navbar-brand img{height:16px}.navbar .navbar-full .nav-guest,.navbar .navbar-full .nav-user{float:right}.navbar .navbar-full .nav-user .dropdown-toggle{padding:8px}.navbar .navbar-full .nav-user .dropdown-toggle img{width:34px;height:34px}.navbar ul.navbar-compact-nav{margin:0;display:table;width:100%}.navbar ul.navbar-compact-nav>li{display:table-cell}.navbar ul.navbar-compact-nav>li>a,.navbar ul.navbar-compact-nav>li>button{background:0 0;border:none;margin:0;padding-top:10px;padding-bottom:10px;width:100%;color:#777;text-align:center}.navbar ul.navbar-compact-nav>li>a:focus,.navbar ul.navbar-compact-nav>li>a:hover,.navbar ul.navbar-compact-nav>li>button:focus,.navbar ul.navbar-compact-nav>li>button:hover{color:#333;background-color:transparent}.navbar ul.navbar-compact-nav>li>a>img,.navbar ul.navbar-compact-nav>li>button>img{width:24px;height:24px}.navbar ul.navbar-compact-nav>li>button{padding-top:10px;padding-bottom:10px}.navbar ul.navbar-compact-nav>li>a>.material-icon{font-size:24px;line-height:24px}@media (max-width:767px){.navbar.navbar-misago{min-height:auto}}@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(../fonts/MaterialIcons-Regular.eot);src:local('Material Icons'),local('MaterialIcons-Regular'),url(../fonts/MaterialIcons-Regular.woff2) format('woff2'),url(../fonts/MaterialIcons-Regular.woff) format('woff'),url(../fonts/MaterialIcons-Regular.ttf) format('truetype')}.material-icon{font-family:'Material Icons';font-style:normal;display:inline-block;width:1em;height:1em;line-height:1;text-align:center;text-transform:none;letter-spacing:normal;vertical-align:middle;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}@media screen and (max-width:991px){.modal-message{text-align:center}.modal-message .message-icon{margin:30px}.modal-message .message-icon .material-icon{font-size:160px}}@media screen and (min-width:992px){.modal-message .message-icon{float:left}.modal-message .message-icon .material-icon{font-size:80px}.modal-message .message-body{margin-left:100px}}@media screen and (max-width:991px){.modal-register .modal-footer{text-align:center}.modal-register .modal-footer a{display:block}.modal-register .modal-footer .btn{display:block;float:none;margin-top:10px;width:100%}}.material-icon.form-control-feedback{top:6px;right:24px;font-size:1.42857143;line-height:1.42857143}.well.well-form.well-done{font-size:18px;text-align:center}.well.well-form.well-done .message-icon{margin-bottom:10px;font-size:90px;line-height:90px}.well.well-form.well-done .message-body{margin-bottom:6.67px}.well.well-form.well-noscript{font-size:18px;text-align:center}.well.well-form.well-noscript .message-icon{margin-bottom:10px;font-size:90px;line-height:90px}.btn.btn-loading,.btn.btn-loading:active,.btn.btn-loading:focus,.btn.btn-loading:hover,.btn.btn-loading:link,.btn.btn-loading:visited{color:transparent}.btn.btn-loading .loader-compact,.btn.btn-loading:active .loader-compact,.btn.btn-loading:focus .loader-compact,.btn.btn-loading:hover .loader-compact,.btn.btn-loading:link .loader-compact,.btn.btn-loading:visited .loader-compact{margin-top:-20px;height:20px;position:relative;top:0}.btn.btn-loading.btn-default .loader-compact>div{background-color:#333}.btn.btn-loading.btn-danger .loader-compact>div,.btn.btn-loading.btn-info .loader-compact>div,.btn.btn-loading.btn-primary .loader-compact>div,.btn.btn-loading.btn-success .loader-compact>div,.btn.btn-loading.btn-warning .loader-compact>div{background-color:#fff}.dropdown-menu>li>.btn-link,.dropdown-menu>li>a{display:block;border:none;clear:both;float:none;padding:4px 20px;width:100%;color:#333;font-weight:400;line-height:1.42857143;text-align:left;white-space:nowrap}.dropdown-menu>li>.btn-link:focus,.dropdown-menu>li>.btn-link:hover,.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#f5f5f5;color:#262626;text-decoration:none}.dropdown-menu>li>.btn-link .material-icon,.dropdown-menu>li>a .material-icon{margin:-2px 7px -2px 0;position:relative;bottom:1px;font-size:18px}.dropdown-menu .dropdown-footer{padding:6px 20px}.mobile-dropdown{position:static;margin:0}.mobile-dropdown.open>.dropdown-menu{border:none;border-radius:0;-webkit-box-shadow:none;box-shadow:none;display:block;margin:0;width:100%;position:static}.user-dropdown .guest-preview{text-align:center}.user-dropdown .guest-preview .row{margin:0}.navbar .user-dropdown{width:240px}.user-dropdown .dropdown-header{padding:6px 20px;font-size:18px}.misago-footer{margin-top:30px;margin-bottom:50px}.misago-footer .footer-content{border-top:1px solid #eee;padding-top:30px}.misago-footer .noscript-message .material-icon{position:relative;bottom:1px;font-size:18px}@media screen and (max-width:991px){.page-error,.page-message{text-align:center}.page-error .message-icon,.page-message .message-icon{margin:30px}.page-error .message-icon .material-icon,.page-message .message-icon .material-icon{font-size:160px}}@media screen and (min-width:992px){.page-error .message-panel,.page-message .message-panel{margin:60px auto;max-width:779.35px;overflow:auto}.page-error .message-icon,.page-message .message-icon{float:left}.page-error .message-icon .material-icon,.page-message .message-icon .material-icon{font-size:80px}.page-error .message-body,.page-message .message-body{margin-left:100px}}

+ 2 - 2
misago/static/misago/js/misago.js

@@ -1,3 +1,3 @@
-!function(){"use strict";window.Misago=function(){var t=Object.getPrototypeOf(this),e=this;this._initServices=function(n){var o=new t.OrderedList(n).order(!1);o.forEach(function(t){var n=null;n=void 0!==t.item.factory?t.item.factory:t.item;var o=n(e);o&&(e[t.key]=o)})},this._destroyServices=function(n){var o=new t.OrderedList(n).order();o.reverse(),o.forEach(function(t){void 0!==t.destroy&&t.destroy(e)})},this.context={SETTINGS:{}},this.setup=!1,this.init=function(e,n){this.setup={test:t.get(e,"test",!1),api:t.get(e,"api","/api/")},n&&(this.context=n),this._initServices(t._services)},this.destroy=function(){this._destroyServices(t._services)}};var t=window.Misago.prototype;t._services=[],t.addService=function(e,n,o){t._services.push({key:e,item:n,after:t.get(o,"after"),before:t.get(o,"before")})},t.PermissionDenied=function(t){this.detail=t,this.status=403,this.toString=function(){return this.detail||"Permission denied"}}}(),function(t){"use strict";t.has=function(t,e){return t?t.hasOwnProperty(e):!1},t.get=function(e,n,o){return t.has(e,n)?e[n]:void 0!==o?o:void 0},t.pop=function(e,n,o){var r=t.get(e,n,o);return t.has(e,n)&&(e[n]=null),r}}(Misago.prototype),function(t){"use strict";function e(t,e,n){n.retain=!0}t.input=function(t){var n={disabled:t.disabled||!1,config:t.config||e};t.placeholder&&(n.placeholder=t.placeholder),t.autocomplete===!1&&(n.autocomplete="off");var o="input";return t.id&&(o+="#"+t.id,n.key="field-"+t.id),o+=".form-control"+(t["class"]||""),o+='[type="'+(t.type||"text")+'"]',t.value&&(n.value=t.value(),n.oninput=m.withAttr("value",t.value)),m(o,n)}}(Misago.prototype),function(t){"use strict";var e=function(){};t.stateHooks=function(t,n,o){if(t._hasLifecycleHooks)return t;t._hasLifecycleHooks=!0,t.isActive=!0;var r=o.bind(t),i=t.controller||e;if(t.controller=function(){try{t.isActive=!0;var n=i.apply(t,arguments)||{},o=n.onunload||e;return n.onunload=function(){o.apply(t,arguments),t.isActive=!1},n}catch(a){r(a)}},t.vm&&t.vm.init){if(!t.loading){var a=n.bind(t);t.loading=a}var s=t.view;t.view=function(){return t.vm.isReady?s.apply(t,arguments):t.loading.apply(t,arguments)};var u=t.vm.init;t.vm.init=function(){var e=arguments,n=u.apply(t.vm,e);n&&n.then(function(){if(t.isActive&&t.vm.ondata){for(var n=[],o=0;o<arguments.length;o++)n.push(arguments[o]);for(var r=0;r<e.length;r++)n.push(e[r]);t.vm.ondata.apply(t.vm,n)}},function(e){t.isActive&&r(e)})}}return t}}(Misago.prototype),function(t){"use strict";t.OrderedList=function(e){this.isOrdered=!1,this._items=e||[],this.add=function(e,n,o){this._items.push({key:e,item:n,after:t.get(o,"after"),before:t.get(o,"before")})},this.get=function(t,e){for(var n=0;n<this._items.length;n++)if(this._items[n].key===t)return this._items[n].item;return e},this.has=function(t){return void 0!==this.get(t)},this.values=function(){for(var t=[],e=0;e<this._items.length;e++)t.push(this._items[e].item);return t},this.order=function(t){return this.isOrdered||(this._items=this._order(this._items),this.isOrdered=!0),t||"undefined"==typeof t?this.values():this._items},this._order=function(t){function e(t){var e=-1;-1===r.indexOf(t.key)&&(t.after?(e=r.indexOf(t.after),-1!==e&&(e+=1)):t.before&&(e=r.indexOf(t.before)),-1!==e&&(o.splice(e,0,t),r.splice(e,0,t.key)))}var n=[];t.forEach(function(t){n.push(t.key)});var o=[],r=[];t.forEach(function(t){t.after||t.before||(o.push(t),r.push(t.key))}),t.forEach(function(t){"_end"===t.before&&(o.push(t),r.push(t.key))});for(var i=200;i>0&&n.length!==r.length;)i-=1,t.forEach(e);return o}}}(Misago.prototype),function(t){"use strict";t.Page=function(e,n){var o=this;this.name=e,this.isFinalized=!1,this._sections=[];var r=function(){if(!o.isFinalized){o.isFinalized=!0;var e=[];o._sections.forEach(function(t){(!t.visibleIf||t.visibleIf(n))&&e.push(t)}),o._sections=new t.OrderedList(e).order(!0)}};this.addSection=function(t){if(this.isFinalized)throw this.name+" page was initialized already and no longer accepts new sections";this._sections.push({key:t.link,item:t,after:t.after,before:t.before})},this.getSections=function(){return r(),this._sections},this.getDefaultLink=function(){return r(),this._sections[0].link}}}(Misago.prototype),function(t){t.serializeDatetime=function(t){return t?t.format():null},t.deserializeDatetime=function(t){return t?moment(t):null}}(Misago.prototype),function(t){"use strict";t.startsWith=function(t,e){return 0===t.indexOf(e)},t.endsWith=function(t,e){return-1!==t.indexOf(e,t.length-e.length)}}(Misago.prototype),function(t){"use strict";t.UrlConf=function(){var e=this;this._patterns=[],this.patterns=function(){return this._patterns};var n=function(t,e){return(t+e).replace("//","/")},o=function(t,o){for(var r=0;r<o.length;r++)e.url(n(t,o[r].pattern),o[r].component,o[r].name)};this.url=function(e,n,r){""===e&&(e="/"),n instanceof t.UrlConf?o(e,n.patterns()):this._patterns.push({pattern:e,component:n.replace(/_/g,"-"),name:r||n})}}}(Misago.prototype),function(t){"use strict";t.loadingPage=function(t){return m(".page.page-loading",t.component("loader"))}}(Misago.prototype),function(t){"use strict";var e=function(e){if(-1!==document.cookie.indexOf(e)){var n=new RegExp(e+"=([^;]*)"),o=t.get(document.cookie.match(n),0);return o.split("=")[1]}return null},n=function(n){this.refreshCsrfToken=function(){this.csrfToken=e(n.context.CSRF_COOKIE_NAME)},this.refreshCsrfToken();var o={};this.ajax=function(e,n,r,i){var a=m.deferred(),s={url:n,method:e,headers:{"X-CSRFToken":this.csrfToken},data:r||{},dataType:"json",success:function(r){"GET"===e&&t.pop(o,n),a.resolve(r)},error:function(r){"GET"===e&&t.pop(o,n);var i=r.responseJSON||{};i.status=r.status,i.statusText=r.statusText,a.reject(i)}};return i?void 0:($.ajax(s),a.promise)},this.get=function(e){var r=t.pop(n.context,e);if(r){var i=m.deferred();return i.resolve(r),i.promise}return void 0!==o[e]?o[e]:(o[e]=this.ajax("GET",e),o[e])},this.post=function(t,e){return this.ajax("POST",t,e)},this.patch=function(t,e){return this.ajax("PATCH",t,e)},this.put=function(t,e){return this.ajax("PUT",t,e)},this["delete"]=function(t){return this.ajax("DELETE",t)}};t.addService("ajax",function(t){return new n(t)})}(Misago.prototype),function(t){"use strict";var e=5e3,n=70,o=9e3,r=300,i=function(t){var i=this;this.type="",this.message=null,this.isVisible=!1;var a=function(r,a){i.type=r,i.message=a,i.isVisible=!0;var s=e;s+=a.length*n,s>o&&(s=o),t.runloop.runOnce(function(){m.startComputation(),i.isVisible=!1,m.endComputation()},"flash-message-hide",s)},s=function(e,n){t.runloop.stop("flash-message-hide"),t.runloop.stop("flash-message-show"),i.isVisible?(i.isVisible=!1,t.runloop.runOnce(function(){m.startComputation(),a(e,n),m.endComputation()},"flash-message-show",r)):a(e,n)};this.info=function(t){s("info",t)},this.success=function(t){s("success",t)},this.warning=function(t){s("warning",t)},this.error=function(t){s("error",t)}};t.addService("alert",{factory:function(t){return new i(t)}})}(Misago.prototype),function(t){"use strict";var e=function(t){if("object"==typeof t){var e=[];for(var n in t)if(t.hasOwnProperty(n)){var o=encodeURIComponent(n),r=encodeURIComponent(t[n]);e.push(o+"="+r)}return"?"+e.join("&")}return t+"/"},n=function(t,o){this.url=o.url||t.setup.api,this.url+=o.path?o.path+"/":o.related?o.related+"/":o.model+"s/",o.filters&&(this.url+=e(o.filters)),o.model&&(this.related=function(e,r){return new n(t,{url:this.url,relation:o.model,related:e,filters:r})}),this.endpoint=function(e,o){return new n(t,{url:this.url,path:e,filters:o})},this.get=function(){var e=null;return o.related?e=o.relation+":"+o.related:o.model&&(e=o.model),t.ajax.get(this.url).then(function(n){return e?n.results?(n.results.map(function(n){return t.models["new"](e,n)}),n):t.models["new"](e,n):n})},this.post=function(e){return t.ajax.post(this.url,e)},this.patch=function(e){return t.ajax.patch(this.url,e)},this.put=function(e){return t.ajax.put(this.url,e)},this["delete"]=function(){return t.ajax["delete"](this.url)},this.then=function(t,e){return this.get().then(t,e)}},o=function(t){this.model=function(e,o){return new n(t,{model:e,filters:o})},this.endpoint=function(e,o){return new n(t,{path:e,filters:o})},this.alert=function(e){var n=gettext("Unknown error has occured.");0===e.status&&(n=gettext("Lost connection with application.")),403===e.status&&(n=e.detail,"Permission denied"===n&&(n=gettext("You don't have permission to perform this action."))),404===e.status&&(n=gettext("Action link is invalid.")),t.alert.error(n)}};t.addService("api",function(t){return new o(t)})}(Misago.prototype),function(t){"use strict";var e=function(e){var n=this;e.user=e.models.deserialize("user",e.context.user),this.isDesynced=!1,this.newUser=null;var o=function(t){n.isDesynced||(m.startComputation(),n.isDesynced=!0,t&&(n.newUser=e.localstore.get("auth-user")),m.endComputation())},r=function(t){n.isDesynced||(m.startComputation(),e.user.id!==t.id?(n.isDesynced=!0,n.newUser=t):t&&(e.user=$.extend(e.user,t)),m.endComputation())},i=function(){e.localstore.set("auth-user",e.user),e.localstore.set("auth-is-authenticated",e.user.isAuthenticated),e.localstore.watch("auth-is-authenticated",o),e.localstore.watch("auth-user",r)};i(),this.denyAuthenticated=function(n){if(e.user.isAuthenticated)throw new t.PermissionDenied(n||gettext("This page is not available to signed in users."))},this.denyAnonymous=function(n){if(e.user.isAnonymous)throw new t.PermissionDenied(n||gettext("This page is not available to guests."))}};t.addService("auth",function(t){return new e(t)},{after:"model:user"})}(Misago.prototype),function(t){"use strict";var e=function(){var t=m.deferred();t.resolve(),this.load=function(){return t.promise},this.value=function(){return null}},n=function(t){var e=this;this.loading=!1,this.question=null,this.value=m.prop("");var n=m.deferred();this.load=function(){return this.value(""),this.question||this.loading||(this.loading=!0,t.api.endpoint("captcha-question").get().then(function(t){e.question=t,n.resolve()},function(){t.api.alert(gettext("Failed to load CAPTCHA.")),n.reject()}).then(function(){e.loading=!0})),n.promise},this.component=function(e){return t.component("form-group",{label:this.question.question,labelClass:e.labelClass||null,controlClass:e.controlClass||null,control:t.input({value:t.validate(e.form,"captcha"),id:"id_captcha",disabled:e.form.isBusy}),validation:e.form.errors,validationKey:"captcha",helpText:this.question.help_text})},this.validator=function(){return[]}},o=function(t){this.included=!1,this.question=null;var e=m.deferred(),n=function(e){"undefined"!=typeof grecaptcha?e.resolve():t.runloop.runOnce(function(){n(e)},"loading-grecaptcha",150)};this.load=function(){return"undefined"!=typeof grecaptcha&&grecaptcha.reset(),this.included||(t.include("https://www.google.com/recaptcha/api.js",!0),this.included=!0),n(e),e.promise};var o=function(e,n,o){o.retain=!0,n||grecaptcha.render("recaptcha",{sitekey:t.settings.recaptcha_site_key})};this.component=function(e){var n=m("#recaptcha",{config:o});return t.component("form-group",{label:gettext("Security test"),labelClass:e.labelClass||null,controlClass:e.controlClass||null,control:n,validation:e.form.errors,validationKey:"captcha"})},this.value=function(){return"undefined"!=typeof grecaptcha?grecaptcha.getResponse():""},this.clean=function(t){t.errors.captcha=this.value()?!0:[gettext("This field is required.")]},this.validator=function(){return[]}},r=function(t){var r={no:e,qa:n,re:o},i=new r[t.settings.captcha_type](t);this.value=i.value,this.load=function(){return i.load()},this.component=function(t){return i.component?i.component(t):null},this.validator=function(){return i.validator?i.validator():null},this.clean=function(t){i.clean?i.clean(t):t.errors.captcha=!0}};t.addService("captcha",function(t){return new r(t)},{after:"include"})}(Misago.prototype),function(t){"use strict";var e=function(t,e){if(this._components[t]){if(arguments.length>1){for(var n=[this._components[t]],o=1;o<arguments.length;o+=1)n.push(arguments[o]);return n.push(this),m.component.apply(void 0,n)}return m.component(this._components[t],this)}if(!e)throw'"'+t+"\" component is not registered and can't be created";this._components[t]=e};t.addService("components",function(t){t._components={},t.component=e})}(Misago.prototype),function(t){"use strict";t.addService("conf",function(e){e.settings=t.get(e.context,"SETTINGS",{})})}(Misago.prototype),function(t){"use strict";var e=function(t){var e={};this.toggle=function(n,o){var r=document.getElementById(n);r.hasChildNodes()&&e[n]===o?(e[n]=null,m.mount(r,null),$(r).removeClass("open")):(console.log(r.hasChildNodes()),e[n]=o,m.mount(r,t.component(o)),$(r).addClass("open"))},this.destroy=function(){var t=null;for(var n in e)e.hasOwnProperty(n)&&(t=document.getElementById(n),t&&t.hasChildNodes()&&m.mount(t,null))}};t.addService("dropdown",{factory:function(t){return new e(t)},destroy:function(t){t.dropdown.destroy()}},{before:"components"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=t.submit,n=t.success,o=t.error;return t.isBusy=!1,t.errors=null,t.submit=function(){return t.isBusy?!1:(t.clean?t.clean()&&(t.isBusy=!0,e.apply(t)):t.isBusy=!0,!1)},t.success=function(){m.startComputation(),n.apply(t,arguments),t.isBusy=!1,m.endComputation()},t.error=function(){m.startComputation(),o.apply(t,arguments),t.isBusy=!1,m.endComputation()},t.hasErrors=function(){if(null===t.errors)return!1;for(var e in t.validation)if(t.validation.hasOwnProperty(e)&&t.errors[e]!==!0)return!0;return!1},t},n=function(t,n){return this._forms[t]?e(n?new this._forms[t](n,this):new this._forms[t](this)):void(this._forms[t]=n)};t.addService("forms",function(t){t._forms={},t.form=n})}(Misago.prototype),function(t){"use strict";var e=function(t,e){e||(t=this.context.STATIC_URL+t),$.ajax({url:t,cache:!0,dataType:"script"})};t.addService("include",function(t){t.include=e},{after:"conf"})}(Misago.prototype),function(t){"use strict";var e=function(e){e.baseUrl=$("base").attr("href");var n=t.get(e.context,"STATIC_URL","/"),o=t.get(e.context,"MEDIA_URL","/"),r=function(t){return function(e){return t+e}};e.staticUrl=r(n),e.mediaUrl=r(o)};t.addService("links",function(t){e(t)})}(Misago.prototype),function(t){"use strict";var e=function(){var t=window.localStorage,e="_misago_",n=[],o=function(t){var e=JSON.parse(t.newValue);$.each(n,function(n,o){o.keyName===t.key&&t.oldValue!==t.newValue&&o.callback(e)})};window.addEventListener("storage",o);var r=function(t){return e+t};this.set=function(e,n){t.setItem(r(e),JSON.stringify(n))},this.get=function(e){var n=t.getItem(r(e));return n?JSON.parse(n):null},this.watch=function(t,e){n.push({keyName:r(t),callback:e})},this.destroy=function(){this.watchers=[]}};t.addService("localstore",{factory:function(){return new e},destroy:function(t){t.localstore.destroy()}})}(Misago.prototype),function(t){"use strict";var e=function(){var t=this,e=document.getElementById("misago-modal");this.destroy=function(){$(e).off(),$("body").removeClass("modal-open"),$(".modal-backdrop").remove()};var n=$(e).modal({show:!1});this.open=!1,n.on("hidden.bs.modal",function(){t.open&&(m.mount(e,null),this.open=!1)}),this.show=function(t){this.open=!0,m.mount(e,t),n.modal("show")},this.hide=function(){n.modal("hide")}};t.addService("_modal",{factory:function(){return new e},destroy:function(t){t._modal.destroy()}},{before:"mount:page-component"})}(Misago.prototype),function(t){"use strict";var e=function(t,e){if(this._modals[t]){for(var n=[this._modals[t]],o=1;o<arguments.length;o+=1)n.push(arguments[o]);n.push(this),this._modal.show(m.component.apply(m,n))}else t?this._modals[t]=e:this._modal.hide()};t.addService("modals",function(t){t._modals={},t.modal=e},{after:"_modal"})}(Misago.prototype),function(t){"use strict";var e=function(){this.classes={},this.deserializers={},this.add=function(t,e){e["class"]&&(this.classes[t]=e["class"]),e.deserialize&&(this.deserializers[t]=e.deserialize)},this["new"]=function(t,e){return this.classes[t]?(e.id=e.id?String(e.id):null,new this.classes[t](e)):e},this.deserialize=function(t,e){return this.deserializers[t]?this["new"](t,this.deserializers[t](e,this)):this["new"](t,e)}};t.addService("models",function(){return new e})}(Misago.prototype),function(t){"use strict";t.addService("set-momentjs-locale",function(){moment.locale($("html").attr("lang"))})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=this;this._intervals={};var n=function(t){e._intervals[t]&&(window.clearTimeout(e._intervals[t]),e._intervals[t]=null)};this.run=function(o,r,i){this._intervals[r]=window.setTimeout(function(){n(r);var a=o(t);a!==!1&&e.run(o,r,i)},i)},this.runOnce=function(e,o,r){this._intervals[o]=window.setTimeout(function(){n(o),e(t)},r)},this.stop=function(t){for(var e in this._intervals)t&&t!==e||n(e)}};t.addService("runloop",{factory:function(t){return new e(t)},destroy:function(t){t.runloop.stop()}})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("misago-page-mount");t.addService("show-banned-page",function(t){t.showBannedPage=function(n){var o=t.component("banned-page",t.models.deserialize("ban",n));t.title.set(gettext("You are banned")),window.history.pushState({},"",t.context.BANNED_URL),m.mount(e,o)}})}(Misago.prototype),function(t){"use strict";t.addService("start-tick",function(t){var e=m.prop();t.runloop.run(function(){m.startComputation(),e(e()+1),m.endComputation()},"tick",6e4)})}(Misago.prototype),function(t){"use strict";var e=function(t){this.set=function(e){e?this._set_complex(e):document.title=t},this._set_complex=function(e){"string"==typeof e&&(e={title:e});var n=e.title;if("undefined"!=typeof e.page&&e.page>1){var o=interpolate(gettext("page %(page)s"),{page:e.page},!0);n+=" ("+o+")"}"undefined"!=typeof e.parent&&(n+=" | "+e.parent),document.title=n+" | "+t}};t.addService("page-title",function(t){t.title=new e(t.settings.forum_name)})}(Misago.prototype),function(t){"use strict";var e=/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i,n=new RegExp("^[0-9a-z]+$","i");t.validators={required:function(){return function(t){return 0===$.trim(t).length?gettext("This field is required."):void 0}},email:function(t){return function(n){return e.test(n)?void 0:t||gettext("Enter a valid email address.")}},minLength:function(t,e){return function(n){var o="",r=$.trim(n).length;return t>r?(o=e?e(t,r):ngettext("Ensure this value has at least %(limit_value)s character (it has %(show_value)s).","Ensure this value has at least %(limit_value)s characters (it has %(show_value)s).",t),interpolate(o,{limit_value:t,show_value:r},!0)):void 0}},maxLength:function(t,e){return function(n){var o="",r=$.trim(n).length;return r>t?(o=e?e(t,r):ngettext("Ensure this value has at most %(limit_value)s character (it has %(show_value)s).","Ensure this value has at most %(limit_value)s characters (it has %(show_value)s).",t),interpolate(o,{limit_value:t,show_value:r},!0)):void 0}},usernameMinLength:function(t){var e=function(t){return ngettext("Username must be at least %(limit_value)s character long.","Username must be at least %(limit_value)s characters long.",t)};return this.minLength(t.username_length_min,e)},usernameMaxLength:function(t){var e=function(t){return ngettext("Username cannot be longer than %(limit_value)s character.","Username cannot be longer than %(limit_value)s characters.",t)};return this.maxLength(t.username_length_max,e)},usernameContent:function(){return function(t){return n.test($.trim(t))?void 0:gettext("Username can only contain latin alphabet letters and digits.")}},passwordMinLength:function(t){var e=function(t){return ngettext("Valid password must be at least %(limit_value)s character long.","Valid password must be at least %(limit_value)s characters long.",t)};return this.minLength(t.password_length_min,e)}};var o=function(e,n){var o=t.validators.required()(e),r=[];if(o)return[o];for(var i in n)o=n[i](e),o&&r.push(o);return r.length?r:!0},r=function(t){var e={},n=null,r=!0;for(var i in t.validation)t.validation.hasOwnProperty(i)&&(n=t[i](),e[i]=o(t[i](),t.validation[i]),e[i]!==!0&&(r=!1));return t.errors=e,r},i=function(t,e){return e?function(n){var r=null;return"undefined"!=typeof n?(r=o(n,t.validation[e]),r&&(t.errors||(t.errors={}),t.errors[e]=r),t[e](n),t[e](n)):t[e]()}:r(t)};t.addService("validate",{factory:function(){return i}})}(Misago.prototype),function(t){"use strict";var e=function(t){this.included=!1,this.scorePassword=function(t,e){return zxcvbn(t,e).score},this.include=function(){t.include("misago/js/zxcvbn.js"),this.included=!0};var e=function(n){"undefined"!=typeof zxcvbn?n.resolve():t.runloop.runOnce(function(){e(n)},"loading-zxcvbn",150)},n=m.deferred();this.load=function(){return this.included||this.include(),e(n),n.promise}};t.addService("zxcvbn",function(t){return new e(t)},{after:"include"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.message={html:t.message.html,plain:t.message.plain},this.expires_on=t.expires_on},n=function(e){return e.expires_on=t.deserializeDatetime(e.expires_on),e};t.addService("model:ban",function(t){t.models.add("ban",{"class":e,deserialize:n})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.title=t.title,this.body=t.body,this.link=t.link};t.addService("model:legal-page",function(t){t.models.add("legal-page",{"class":e})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.id=t.id,this.name=t.name,this.slug=t.slug,this.description=t.description,this.title=t.title,this.css_class=t.css_class,this.is_tab=t.is_tab};t.addService("model:rank",function(t){t.models.add("rank",{"class":e})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.id=t.id,this.isAuthenticated=!!this.id,this.isAnonymous=!this.isAuthenticated,this.username=t.username,this.slug=t.slug,this.email=t.email,this.full_title=t.full_title,this.rank=t.rank,this.avatar_hash=t.avatar_hash,this.acl=t.acl,this.absolute_url=t.absolute_url},n=function(e,n){return e.joined_on&&(e.joined_on=t.deserializeDatetime(e.joined_on)),e.rank&&(e.rank=n.deserialize("rank",e.rank)),e};t.addService("model:user",function(t){t.models.add("user",{"class":e,deserialize:n})},{after:"model:rank"})}(Misago.prototype),function(t){"use strict";var e={view:function(e,n,o){return m(".well.well-form",m("form",{onsubmit:n.submit},[m(".form-group",m(".control-input",t.input({disabled:n.isBusy,value:n.email,placeholder:gettext("Your e-mail address")}))),o.component("button",{"class":".btn-primary.btn-block",submit:!0,loading:n.isBusy,label:gettext("Send link")})]))}};t.addService("component:request-link-form",function(t){t.component("request-link-form",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(t,e){return m(".modal-header",[m('button.close[type="button"]',{"data-dismiss":"modal","aria-label":gettext("Close")},m("span",{"aria-hidden":"true"},m.trust("&times;"))),m("h4#misago-modal-label.modal-title",e)])}};t.addService("component:modal:header",function(t){t.component("modal:header",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=function(t,e,n){n.retain=!0},n=function(){document.location.reload()},o={controller:function(t,e){"active"===t.activation&&e.runloop.runOnce(n,"refresh-after-registration",1e4)},view:function(t,n,o){var r=null;return r="active"===n.activation?this.active(n):this.inactive(n),m('.modal-dialog.modal-message.modal-register[role="document"]',{config:e},m(".modal-content",[o.component("modal:header",gettext("Registration complete")),m(".modal-body",r)]))},active:function(t){var e=gettext("%(username)s, your account has been created and you were signed in.");return[m(".message-icon",m("span.material-icon","check")),m(".message-body",[m("p.lead",interpolate(e,{username:t.username},!0)),m("p",gettext("The page will refresh automatically in 10 seconds.")),m("p",m('button[type="button"].btn.btn-default',{onclick:n},gettext("Refresh page")))])]},inactive:function(t){var e=null,n=null;return"user"===t.activation?(e=gettext("%(username)s, your account has been created but you need to activate it before you will be able to sign in."),n=gettext("We have sent an e-mail to %(email)s with link that you have to click to activate your account.")):"admin"===t.activation&&(e=gettext("%(username)s, your account has been created but board administrator will have to activate it before you will be able to sign in."),n=gettext("We will send an e-mail to %(email)s when this takes place.")),[m(".message-icon",m("span.material-icon","info_outline")),m(".message-body",[m("p.lead",interpolate(e,{username:t.username},!0)),m("p",interpolate(n,{email:t.email},!0))])]}};t.addService("modal:register-complete",function(t){t.modal("register-complete",o)},{after:"modals"})}(Misago.prototype),function(t){"use strict";var e=function(t,e,n){n.retain=!0},n={controller:function(t){return{form:t.form("register")}},view:function(t,n){var o=n.captcha.component({form:t.form,labelClass:".col-md-4",controlClass:".col-md-8"}),r=null;return n.context.TERMS_OF_SERVICE_URL&&(r=m("a",{href:n.context.TERMS_OF_SERVICE_URL},m.trust(interpolate(gettext("By registering you agree to site's %(terms)s."),{terms:"<strong>"+gettext("terms and conditions")+"</strong>"},!0)))),m('.modal-dialog.modal-form.modal-register[role="document"]',{config:e},m(".modal-content",[n.component("modal:header",gettext("Register")),m("form.form-horizontal",{onsubmit:t.form.submit},[m('input[type="text"]',{name:"_username",style:"display: none"}),m('input[type="password"]',{name:"_password",style:"display: none"}),m(".modal-body",[n.component("form-group",{label:gettext("Username"),labelClass:".col-md-4",controlClass:".col-md-8",control:n.input({value:n.validate(t.form,"username"),id:"id_username",disabled:t.form.isBusy}),validation:t.form.errors,validationKey:"username"}),n.component("form-group",{label:gettext("E-mail"),labelClass:".col-md-4",controlClass:".col-md-8",control:n.input({value:n.validate(t.form,"email"),id:"id_email",disabled:t.form.isBusy}),validation:t.form.errors,validationKey:"email"}),n.component("form-group",{label:gettext("Password"),labelClass:".col-md-4",controlClass:".col-md-8",control:n.input({value:n.validate(t.form,"password"),type:"password",id:"id_password",disabled:t.form.isBusy}),validation:t.form.errors,validationKey:"password",helpText:n.component("password-strength",{inputs:[t.form.username(),t.form.email()],password:t.form.password()})}),o]),m(".modal-footer",[r,n.component("button",{"class":".btn-primary",submit:!0,loading:t.form.isBusy,label:gettext("Register account")})])])]))}};t.addService("modal:register",function(t){t.modal("register",n)},{after:"modals"})}(Misago.prototype),function(t){"use strict";function e(t,e,n){n.retain=!0}var n={controller:function(t){return{form:t.form("sign-in")}},view:function(n,o){var r=null;return n.form.showActivation&&(r=m("a.btn.btn-block.btn-success",{href:o.context.REQUEST_ACTIVATION_URL},gettext("Activate account"))),m('.modal-dialog.modal-sm.modal-signin[role="document"]',{config:e},m(".modal-content",[o.component("modal:header",gettext("Sign in")),m("form",{onsubmit:n.form.submit},[m(".modal-body",[m(".form-group",m(".control-input",t.input({disabled:n.form.isBusy,value:n.form.username,placeholder:gettext("Username or e-mail")}))),m(".form-group",m(".control-input",t.input({type:"password",disabled:n.form.isBusy,value:n.form.password,placeholder:gettext("Password")})))]),m(".modal-footer",[r,o.component("button",{"class":".btn-primary.btn-block",submit:!0,loading:n.form.isBusy,label:gettext("Sign in")}),m("a.btn.btn-block.btn-default",{href:o.context.FORGOTTEN_PASSWORD_URL},gettext("Forgot password?"))])])]))}};t.addService("modal:sign-in",function(t){t.modal("sign-in",n)},{after:"modals"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{showSignIn:function(){t.modal("sign-in")}}},view:function(t,e){return m('ul.dropdown-menu.user-dropdown.dropdown-menu-right[role="menu"]',m("li.guest-preview",[m("h4",gettext("You are browsing as guest.")),m("p",gettext("Sign in or register to start and participate in discussions.")),m(".row",[m(".col-xs-6",e.component("button",{"class":".btn.btn-default.btn-block",onclick:t.showSignIn,disabled:t.isBusy,label:gettext("Sign in")})),m(".col-xs-6",e.component("navbar:register-button",".btn.btn-primary.btn-block"))])]))}};t.addService("component:navbar:dropdown:guest",function(t){t.component("navbar:dropdown:guest",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={style:".nav.navbar-nav.navbar-compact-nav.hidden-md.hidden-lg",controller:function(t,e){return{openUserMenu:function(){return e.user.isAuthenticated?e.dropdown.toggle("navbar-dropdown","navbar:dropdown:user"):e.dropdown.toggle("navbar-dropdown","navbar:dropdown:guest"),!1}}},userMenu:function(t,e){return e.user.isAuthenticated?{element:e.component("user-avatar",e.user,64),config:{onclick:t.openUserMenu,url:"/not-yet/","data-misago-routed":"false"}}:{element:e.component("user-avatar",null,64),config:{onclick:t.openUserMenu,href:"#","data-misago-routed":"false"}}},mobileNav:function(t,e,n){var o=[{element:m("img",{src:n.router.staticUrl("misago/img/site-icon.png"),alt:n.settings.forum_name}),url:n.router.url("index")}];return e.forEach(function(t){t.url!==o[0].url&&o.push(t)}),o.push(this.userMenu(t,n)),o},view:function(t,e,n){var o=this.mobileNav(t,e,n);return m("ul"+this.style+".with-"+o.length+"-items",o.map(function(t){return m("li",m("a",t.config||{href:t.url},t.element||m("span.material-icon",{title:t.label},t.icon)))}))}};t.addService("component:navbar:mobile",function(t){t.component("navbar:mobile",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t,e){return{isBusy:!1,showRegister:function(){if("closed"===e.settings.account_activation)e.alert.info(gettext("New registrations are currently disabled."));else{m.startComputation(),this.isBusy=!0,m.endComputation();var t=this;m.sync([e.zxcvbn.load(),e.captcha.load()]).then(function(){e.modal("register")},function(){e.alert.error(gettext("Registation is not available now due to an error."))}).then(function(){m.startComputation(),t.isBusy=!1,m.endComputation()})}}}},view:function(t,e,n){return n.component("button",{"class":e,onclick:t.showRegister.bind(t),loading:t.isBusy,label:gettext("Register")})}};t.addService("component:navbar:register-button",function(t){t.component("navbar:register-button",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={"class":".dropdown-menu.user-dropdown.dropdown-menu-right",controller:function(){return{logout:function(){var t=confirm(gettext("Are you sure you want to sign out?"));t&&$("#hidden-logout-form").submit()}}},view:function(t,e){return m("ul"+this["class"]+'[role="menu"]',[m("li.dropdown-header",m("strong",e.user.username)),m("li.divider"),m("li",m("a",{href:e.user.absolute_url},[m("span.material-icon","account_circle"),gettext("See your profile")])),m("li",m("a",{href:e.context.USERCP_URL},[m("span.material-icon","done_all"),gettext("Change options")])),m("li",m('button.btn-link[type="button"]',[m("span.material-icon","face"),gettext("Change avatar")])),m("li.divider"),m("li.dropdown-footer",m("button.btn.btn-default.btn-block",{onclick:t.logout},gettext("Logout")))])}};t.addService("component:navbar:dropdown:user",function(t){t.component("navbar:dropdown:user",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{openUserMenu:function(){t.dropdown.toggle("misago-navbar-dropdown","navbar:dropdown:guest")}}},view:function(t,e){return m("button",{type:"button",onclick:t.openUserMenu},e.component("user-avatar",null,64))}};t.addService("component:navbar:compact:guest-nav",function(t){t.component("navbar:compact:guest-nav",e)},{after:"components"
-})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{openUserMenu:function(){return t.dropdown.toggle("misago-navbar-dropdown","navbar:dropdown:user"),!1}}},view:function(t,e){var n={onclick:t.openUserMenu,href:e.user.absolute_url};return m("a",n,e.component("user-avatar",e.user,64))}};t.addService("component:navbar:compact:user-nav",function(t){t.component("navbar:compact:user-nav",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{showSignIn:function(){t.modal("sign-in")}}},view:function(t,e){return m("div.nav.nav-guest",[e.component("button",{"class":".navbar-btn.btn-default",onclick:t.showSignIn,disabled:t.isBusy,label:gettext("Sign in")}),e.component("navbar:register-button",".navbar-btn.btn-primary")])}};t.addService("component:navbar:desktop:guest-nav",function(t){t.component("navbar:desktop:guest-nav",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{dropdownToggle:{href:t.user.absolute_url,"data-toggle":"dropdown","data-misago-routed":"false","aria-haspopup":"true","aria-expanded":"false"}}},view:function(t,e){return m("ul.nav.navbar-nav.nav-user",[m("li.dropdown",[m('a.dropdown-toggle[role="button"]',t.dropdownToggle,e.component("user-avatar",e.user,64)),e.component("navbar:dropdown:user")])])}};t.addService("component:navbar:desktop:user-nav",function(t){t.component("navbar:desktop:user-nav",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";function e(t,e,n){n.retain=!0}var n={classes:{info:"alert-info",success:"alert-success",warning:"alert-warning",error:"alert-danger"},view:function(t,n){var o={config:e,"class":n.alert.isVisible?"in":"out"};return m(".alerts",o,m("p.alert",{"class":this.classes[n.alert.type]},n.alert.message))}};t.addService("component:alert",function(t){t.component("alert",n)},{after:"components"})}(Misago.prototype),function(t){"use strict";function e(t,e,n){n.retain=!0}var n={refresh:function(){window.location.reload()},view:function(t,n){var o="",r={config:e,"class":n.auth.isDesynced?"show":null};return n.auth.isDesynced&&(n.auth.newUser&&n.auth.newUser.isAuthenticated?(o=gettext("You have signed in as %(username)s. Please refresh this page before continuing."),o=interpolate(o,{username:n.auth.newUser.username},!0)):(o=gettext("%(username)s, you have been signed out. Please refresh this page before continuing."),o=interpolate(o,{username:n.user.username},!0))),m(".auth-changed-message",r,m("",m(".container",[m("p",o),m("p",[m('button.btn.btn-default[type="button"]',{onclick:this.refresh},gettext("Reload page")),m("span.hidden-xs.hidden-sm.text-muted",gettext("or press F5 key."))])])))}};t.addService("component:auth-changed-message",function(t){t.component("auth-changed-message",n)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(t,e){var n=[];n.push(e.message.html?m(".lead",m.trust(e.message.html)):m("p.lead",gettext("You are banned.")));var o=null;return o=e.expires_on?e.expires_on.isAfter(moment())?interpolate(gettext("This ban expires %(expires_on)s."),{expires_on:e.expires_on.fromNow()},!0):gettext("This ban has expired."):gettext("This ban is permanent."),n.push(m("p",o)),m(".page.page-error.page-error-banned",m(".container",m(".message-panel",[m(".message-icon",m("span.material-icon","highlight_off")),m(".message-body",n)])))}};t.addService("component:banned-page",function(t){t.component("banned-page",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(t,e){var n={disabled:e.disabled||e.loading||!1,config:e.config||null,loading:e.loading||!1,type:e.submit?"submit":"button",onclick:e.onclick||null},o='button[type="'+n.type+'"].btn';n.loading&&(o+=".btn-loading"),e.id&&(o+="#"+e.id),o+=e["class"]||"";var r=e.label;return n.loading&&(r=[r,m(".loader-compact",[m(".bounce1"),m(".bounce2"),m(".bounce3")])]),m(o,n,r)}};t.addService("component:button",function(t){t.component("button",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=["text","password","email"],n={view:function(t,n){var o=".form-group",r=null,i=null,a=n.control.attrs.type,s=n.control.attrs.id,u=s+"_feedback",c=null,l=null,d=n.validationKey&&null!==n.validation;return n.control.attrs["aria-describedby"]="",d&&n.validation[n.validationKey]&&(l=e.indexOf(a)>=0,n.control.attrs["aria-describedby"]=u,n.validation[n.validationKey]===!0?(o+=".has-success",c=[m("span.material-icon.form-control-feedback",{"aria-hidden":"true"},"check"),m("span.sr-only#"+u,gettext("(success)"))]):(o+=".has-error",r=n.validation[n.validationKey],c=[m("span.material-icon.form-control-feedback",{"aria-hidden":"true"},"clear"),m("span.sr-only#"+u,gettext("(error)"))])),n.helpText&&(i="string"==typeof n.helpText||n.helpText instanceof String?m("p.help-block",n.helpText):n.helpText),m(o,[m("label.control-label"+(n.labelClass||""),{"for":n.labelFor||s},n.label+":"),m(n.controlClass||"",[n.control,l?c:null,r?m(".help-block.errors",r.map(function(t){return m("p",t)})):null,i])])}};t.addService("component:form-group",function(t){t.component("form-group",n)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(){return m(".loader.sk-folding-cube",[m(".sk-cube1.sk-cube"),m(".sk-cube2.sk-cube"),m(".sk-cube4.sk-cube"),m(".sk-cube3.sk-cube")])}};t.addService("component:loader",function(t){t.component("loader",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=function(t,e,n){n.retain=!0},n={view:function(t,n){return m("article.misago-markup",{config:e},m.trust(n))}};t.addService("component:markup",function(t){t.component("markup",n)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(t,e){return m(".page-header",m(".container",[m("h1",e.title)]))}};t.addService("component:header",function(t){t.component("header",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=function(t,e,n){n.retain=!0},n=["progress-bar-danger","progress-bar-warning","progress-bar-warning","progress-bar-primary","progress-bar-success"],o=[gettext("Entered password is very weak."),gettext("Entered password is weak."),gettext("Entered password is average."),gettext("Entered password is strong."),gettext("Entered password is very strong.")],r={view:function(t,r,i){var a=i.zxcvbn.scorePassword(r.password,r.inputs),s={config:e,"class":n[a],style:"width: "+(20+20*a)+"%",role:"progressbar","aria-valuenow":a,"aria-valuemin":"0","aria-valuemax":"4"};return m(".help-block.password-strength",{key:"password-strength"},[m(".progress",m(".progress-bar",s,m("span.sr-only",o[a]))),m("p.text-small",o[a])])}};t.addService("component:password-strength",function(t){t.component("password-strength",r)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={defaultSize:100,src:function(t,e,n){var o=n.baseUrl+"user-avatar/";return o+=t&&t.id?t.avatar_hash+"/"+e+"/"+t.id+".png":e+".png"},view:function(t,e,n,o){var r=n||this.defaultSize;return m("img",{alt:e&&e.username?e.username:gettext("Unregistered"),width:r,height:r,src:this.src(e,r,o)})}};t.addService("component:user-avatar",function(t){t.component("user-avatar",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=function(e){var n=this;this.username=null,this.password=m.prop(""),this.validation={password:[t.validators.passwordMinLength(e.settings)]},this.clean=function(){return e.validate(this)?!0:(e.alert.error($.trim(this.password()).length?this.errors.password:gettext("Enter new password.")),!1)},this.submit=function(){var t=e.api.endpoint("auth").endpoint("change-password");t=t.endpoint(m.route.param("user_id")),t=t.endpoint(m.route.param("token")),t.post({password:n.password()}).then(function(t){n.success(t)},function(t){n.error(t)})},this.success=function(t){this.username=t.username},this.error=function(t){403===t.status&&t.ban?e.router.error403({message:"",ban:t.ban}):400===t.status?e.alert.error(t.detail):e.api.alert(t)}};t.addService("form:change-password",function(t){t.form("change-password",e)},{after:"forms"})}(Misago.prototype),function(t){"use strict";var e=function(e){var n=this;this.showActivation=!1,this.username=m.prop(""),this.email=m.prop(""),this.password=m.prop(""),this.captcha=e.captcha.value,this.errors=null,this.validation={username:[t.validators.usernameContent(),t.validators.usernameMinLength(e.settings),t.validators.usernameMaxLength(e.settings)],email:[t.validators.email()],password:[t.validators.passwordMinLength(e.settings)],captcha:e.captcha.validator()},this.clean=function(){return null===this.errors&&e.validate(this),e.captcha.clean(this),this.hasErrors()?(e.alert.error(gettext("Form contains errors.")),!1):!0},this.submit=function(){e.api.model("user").post({username:this.username(),email:this.email(),password:this.password(),captcha:this.captcha()}).then(this.success,this.error)},this.success=function(t){e.modal("register-complete",t)},this.error=function(t){400===t.status?(e.alert.error(gettext("Form contains errors.")),$.extend(n.errors,t)):e.api.alert(t)}};t.addService("form:register",function(t){t.form("register",e)},{after:"forms"})}(Misago.prototype),function(t){"use strict";var e=function(e,n){var o=this;this.email=m.prop(""),this.validation={email:[t.validators.email()]},this.clean=function(){return n.validate(this)?!0:(n.alert.error(gettext("Enter a valid email address.")),!1)},this.submit=function(){n.api.endpoint("auth").endpoint(e.endpoint).post({email:o.email()}).then(function(t){o.success(t)},function(t){o.error(t)})},this.success=function(t){e.success(t)},this.error=function(t){400===t.status?e.error(t,n):403===t.status&&t.ban?n.router.error403({message:"",ban:t.ban}):n.api.alert(t)},this.reset=function(){this.email(""),e.reset()}};t.addService("form:request-link",function(t){t.form("request-link",e)},{after:"forms"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=this;this.showActivation=!1,this.username=m.prop(""),this.password=m.prop(""),this.validation={username:[],password:[]},this.clean=function(){return t.validate(this)?!0:(t.alert.error(gettext("Fill out both fields.")),!1)},this.submit=function(){t.api.endpoint("auth").post({username:e.username(),password:e.password()}).then(function(){e.success()},function(t){e.error(t)})},this.success=function(){t.modal();var e=$("#hidden-login-form");t.ajax.refreshCsrfToken(),e.find('input[type="hidden"]').val(t.ajax.csrfToken),e.find('input[name="redirect_to"]').val(m.route()),e.find('input[name="username"]').val(this.username()),e.find('input[name="password"]').val(this.password()),e.submit()},this.error=function(n){400===n.status?"inactive_admin"===n.code?t.alert.info(n.detail):"inactive_user"===n.code?(t.alert.info(n.detail),e.showActivation=!0):"banned"===n.code?(t.showBannedPage(n.detail),t.modal()):t.alert.error(n.detail):t.api.alert(n)}};t.addService("form:sign-in",function(t){t.form("sign-in",e)},{after:"forms"})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("misago-alert-mount");t.addService("mount:alert",{factory:function(t){m.mount(e,t.component("alert"))},destroy:function(){m.mount(e,null)}},{before:"mount:page-component"})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("misago-auth-changed-message-mount");t.addService("mount:auth-changed-message",{factory:function(t){m.mount(e,t.component("auth-changed-message"))},destroy:function(){m.mount(e,null)}},{before:"mount:page-component"})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("page-component");t.addService("mount:page-component",{factory:function(t){e&&m.mount(e,t.component(e.dataset.componentName))},destroy:function(){e&&m.mount(e,null)}},{before:"_end"})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("misago-user-menu-mount"),n=document.getElementById("misago-user-menu-compact-mount");t.addService("mount:user-menu",{factory:function(t){t.user.isAuthenticated?(m.mount(e,t.component("navbar:desktop:user-nav")),m.mount(n,t.component("navbar:compact:user-nav"))):(m.mount(e,t.component("navbar:desktop:guest-nav")),m.mount(n,t.component("navbar:compact:guest-nav")))},destroy:function(){m.mount(e,null),m.mount(n,null)}},{before:"mount:page-component"})}(Misago.prototype);
+!function(){"use strict";window.Misago=function(){var t=Object.getPrototypeOf(this),e=this;this._initServices=function(n){var o=new t.OrderedList(n).order(!1);o.forEach(function(t){var n=null;n=void 0!==t.item.factory?t.item.factory:t.item;var o=n(e);o&&(e[t.key]=o)})},this._destroyServices=function(n){var o=new t.OrderedList(n).order();o.reverse(),o.forEach(function(t){void 0!==t.destroy&&t.destroy(e)})},this.context={SETTINGS:{}},this.setup=!1,this.init=function(e,n){this.setup={test:t.get(e,"test",!1),api:t.get(e,"api","/api/")},n&&(this.context=n),this._initServices(t._services)},this.destroy=function(){this._destroyServices(t._services)}};var t=window.Misago.prototype;t._services=[],t.addService=function(e,n,o){t._services.push({key:e,item:n,after:t.get(o,"after"),before:t.get(o,"before")})},t.PermissionDenied=function(t){this.detail=t,this.status=403,this.toString=function(){return this.detail||"Permission denied"}}}(),function(t){"use strict";t.has=function(t,e){return t?t.hasOwnProperty(e):!1},t.get=function(e,n,o){return t.has(e,n)?e[n]:void 0!==o?o:void 0},t.pop=function(e,n,o){var r=t.get(e,n,o);return t.has(e,n)&&(e[n]=null),r}}(Misago.prototype),function(t){"use strict";function e(t,e,n){n.retain=!0}t.input=function(t){var n={disabled:t.disabled||!1,config:t.config||e};t.placeholder&&(n.placeholder=t.placeholder),t.autocomplete===!1&&(n.autocomplete="off");var o="input";return t.id&&(o+="#"+t.id,n.key="field-"+t.id),o+=".form-control"+(t["class"]||""),o+='[type="'+(t.type||"text")+'"]',t.value&&(n.value=t.value(),n.oninput=m.withAttr("value",t.value)),m(o,n)}}(Misago.prototype),function(t){"use strict";var e=function(){};t.stateHooks=function(t,n,o){if(t._hasLifecycleHooks)return t;t._hasLifecycleHooks=!0,t.isActive=!0;var r=o.bind(t),i=t.controller||e;if(t.controller=function(){try{t.isActive=!0;var n=i.apply(t,arguments)||{},o=n.onunload||e;return n.onunload=function(){o.apply(t,arguments),t.isActive=!1},n}catch(a){r(a)}},t.vm&&t.vm.init){if(!t.loading){var a=n.bind(t);t.loading=a}var s=t.view;t.view=function(){return t.vm.isReady?s.apply(t,arguments):t.loading.apply(t,arguments)};var u=t.vm.init;t.vm.init=function(){var e=arguments,n=u.apply(t.vm,e);n&&n.then(function(){if(t.isActive&&t.vm.ondata){for(var n=[],o=0;o<arguments.length;o++)n.push(arguments[o]);for(var r=0;r<e.length;r++)n.push(e[r]);t.vm.ondata.apply(t.vm,n)}},function(e){t.isActive&&r(e)})}}return t}}(Misago.prototype),function(t){"use strict";t.OrderedList=function(e){this.isOrdered=!1,this._items=e||[],this.add=function(e,n,o){this._items.push({key:e,item:n,after:t.get(o,"after"),before:t.get(o,"before")})},this.get=function(t,e){for(var n=0;n<this._items.length;n++)if(this._items[n].key===t)return this._items[n].item;return e},this.has=function(t){return void 0!==this.get(t)},this.values=function(){for(var t=[],e=0;e<this._items.length;e++)t.push(this._items[e].item);return t},this.order=function(t){return this.isOrdered||(this._items=this._order(this._items),this.isOrdered=!0),t||"undefined"==typeof t?this.values():this._items},this._order=function(t){function e(t){var e=-1;-1===r.indexOf(t.key)&&(t.after?(e=r.indexOf(t.after),-1!==e&&(e+=1)):t.before&&(e=r.indexOf(t.before)),-1!==e&&(o.splice(e,0,t),r.splice(e,0,t.key)))}var n=[];t.forEach(function(t){n.push(t.key)});var o=[],r=[];t.forEach(function(t){t.after||t.before||(o.push(t),r.push(t.key))}),t.forEach(function(t){"_end"===t.before&&(o.push(t),r.push(t.key))});for(var i=200;i>0&&n.length!==r.length;)i-=1,t.forEach(e);return o}}}(Misago.prototype),function(t){"use strict";t.Page=function(e,n){var o=this;this.name=e,this.isFinalized=!1,this._sections=[];var r=function(){if(!o.isFinalized){o.isFinalized=!0;var e=[];o._sections.forEach(function(t){(!t.visibleIf||t.visibleIf(n))&&e.push(t)}),o._sections=new t.OrderedList(e).order(!0)}};this.addSection=function(t){if(this.isFinalized)throw this.name+" page was initialized already and no longer accepts new sections";this._sections.push({key:t.link,item:t,after:t.after,before:t.before})},this.getSections=function(){return r(),this._sections},this.getDefaultLink=function(){return r(),this._sections[0].link}}}(Misago.prototype),function(t){t.serializeDatetime=function(t){return t?t.format():null},t.deserializeDatetime=function(t){return t?moment(t):null}}(Misago.prototype),function(t){"use strict";t.startsWith=function(t,e){return 0===t.indexOf(e)},t.endsWith=function(t,e){return-1!==t.indexOf(e,t.length-e.length)}}(Misago.prototype),function(t){"use strict";t.UrlConf=function(){var e=this;this._patterns=[],this.patterns=function(){return this._patterns};var n=function(t,e){return(t+e).replace("//","/")},o=function(t,o){for(var r=0;r<o.length;r++)e.url(n(t,o[r].pattern),o[r].component,o[r].name)};this.url=function(e,n,r){""===e&&(e="/"),n instanceof t.UrlConf?o(e,n.patterns()):this._patterns.push({pattern:e,component:n.replace(/_/g,"-"),name:r||n})}}}(Misago.prototype),function(t){"use strict";t.loadingPage=function(t){return m(".page.page-loading",t.component("loader"))}}(Misago.prototype),function(t){"use strict";var e=function(e){if(-1!==document.cookie.indexOf(e)){var n=new RegExp(e+"=([^;]*)"),o=t.get(document.cookie.match(n),0);return o.split("=")[1]}return null},n=function(n){this.refreshCsrfToken=function(){this.csrfToken=e(n.context.CSRF_COOKIE_NAME)},this.refreshCsrfToken();var o={};this.ajax=function(e,n,r,i){var a=m.deferred(),s={url:n,method:e,headers:{"X-CSRFToken":this.csrfToken},data:r||{},dataType:"json",success:function(r){"GET"===e&&t.pop(o,n),a.resolve(r)},error:function(r){"GET"===e&&t.pop(o,n);var i=r.responseJSON||{};i.status=r.status,i.statusText=r.statusText,a.reject(i)}};return i?void 0:($.ajax(s),a.promise)},this.get=function(e){var r=t.pop(n.context,e);if(r){var i=m.deferred();return i.resolve(r),i.promise}return void 0!==o[e]?o[e]:(o[e]=this.ajax("GET",e),o[e])},this.post=function(t,e){return this.ajax("POST",t,e)},this.patch=function(t,e){return this.ajax("PATCH",t,e)},this.put=function(t,e){return this.ajax("PUT",t,e)},this["delete"]=function(t){return this.ajax("DELETE",t)}};t.addService("ajax",function(t){return new n(t)})}(Misago.prototype),function(t){"use strict";var e=5e3,n=70,o=9e3,r=300,i=function(t){var i=this;this.type="",this.message=null,this.isVisible=!1;var a=function(r,a){i.type=r,i.message=a,i.isVisible=!0;var s=e;s+=a.length*n,s>o&&(s=o),t.runloop.runOnce(function(){m.startComputation(),i.isVisible=!1,m.endComputation()},"flash-message-hide",s)},s=function(e,n){t.runloop.stop("flash-message-hide"),t.runloop.stop("flash-message-show"),i.isVisible?(i.isVisible=!1,t.runloop.runOnce(function(){m.startComputation(),a(e,n),m.endComputation()},"flash-message-show",r)):a(e,n)};this.info=function(t){s("info",t)},this.success=function(t){s("success",t)},this.warning=function(t){s("warning",t)},this.error=function(t){s("error",t)}};t.addService("alert",{factory:function(t){return new i(t)}})}(Misago.prototype),function(t){"use strict";var e=function(t){if("object"==typeof t){var e=[];for(var n in t)if(t.hasOwnProperty(n)){var o=encodeURIComponent(n),r=encodeURIComponent(t[n]);e.push(o+"="+r)}return"?"+e.join("&")}return t+"/"},n=function(t,o){this.url=o.url||t.setup.api,this.url+=o.path?o.path+"/":o.related?o.related+"/":o.model+"s/",o.filters&&(this.url+=e(o.filters)),o.model&&(this.related=function(e,r){return new n(t,{url:this.url,relation:o.model,related:e,filters:r})}),this.endpoint=function(e,o){return new n(t,{url:this.url,path:e,filters:o})},this.get=function(){var e=null;return o.related?e=o.relation+":"+o.related:o.model&&(e=o.model),t.ajax.get(this.url).then(function(n){return e?n.results?(n.results.map(function(n){return t.models["new"](e,n)}),n):t.models["new"](e,n):n})},this.post=function(e){return t.ajax.post(this.url,e)},this.patch=function(e){return t.ajax.patch(this.url,e)},this.put=function(e){return t.ajax.put(this.url,e)},this["delete"]=function(){return t.ajax["delete"](this.url)},this.then=function(t,e){return this.get().then(t,e)}},o=function(t){this.model=function(e,o){return new n(t,{model:e,filters:o})},this.endpoint=function(e,o){return new n(t,{path:e,filters:o})},this.alert=function(e){var n=gettext("Unknown error has occured.");0===e.status&&(n=gettext("Lost connection with application.")),403===e.status&&(n=e.detail,"Permission denied"===n&&(n=gettext("You don't have permission to perform this action."))),404===e.status&&(n=gettext("Action link is invalid.")),t.alert.error(n)}};t.addService("api",function(t){return new o(t)})}(Misago.prototype),function(t){"use strict";var e=function(e){var n=this;e.user=e.models.deserialize("user",e.context.user),this.isDesynced=!1,this.newUser=null;var o=function(t){n.isDesynced||(m.startComputation(),n.isDesynced=!0,t&&(n.newUser=e.localstore.get("auth-user")),m.endComputation())},r=function(t){n.isDesynced||(m.startComputation(),e.user.id!==t.id?(n.isDesynced=!0,n.newUser=t):t&&(e.user=$.extend(e.user,t)),m.endComputation())},i=function(){e.localstore.set("auth-user",e.user),e.localstore.set("auth-is-authenticated",e.user.isAuthenticated),e.localstore.watch("auth-is-authenticated",o),e.localstore.watch("auth-user",r)};i(),this.denyAuthenticated=function(n){if(e.user.isAuthenticated)throw new t.PermissionDenied(n||gettext("This page is not available to signed in users."))},this.denyAnonymous=function(n){if(e.user.isAnonymous)throw new t.PermissionDenied(n||gettext("This page is not available to guests."))}};t.addService("auth",function(t){return new e(t)},{after:"model:user"})}(Misago.prototype),function(t){"use strict";var e=function(){var t=m.deferred();t.resolve(),this.load=function(){return t.promise},this.value=function(){return null}},n=function(t){var e=this;this.loading=!1,this.question=null,this.value=m.prop("");var n=m.deferred();this.load=function(){return this.value(""),this.question||this.loading||(this.loading=!0,t.api.endpoint("captcha-question").get().then(function(t){e.question=t,n.resolve()},function(){t.api.alert(gettext("Failed to load CAPTCHA.")),n.reject()}).then(function(){e.loading=!0})),n.promise},this.component=function(e){return t.component("form-group",{label:this.question.question,labelClass:e.labelClass||null,controlClass:e.controlClass||null,control:t.input({value:t.validate(e.form,"captcha"),id:"id_captcha",disabled:e.form.isBusy}),validation:e.form.errors,validationKey:"captcha",helpText:this.question.help_text})},this.validator=function(){return[]}},o=function(t){this.included=!1,this.question=null;var e=m.deferred(),n=function(e){"undefined"!=typeof grecaptcha?e.resolve():t.runloop.runOnce(function(){n(e)},"loading-grecaptcha",150)};this.load=function(){return"undefined"!=typeof grecaptcha&&grecaptcha.reset(),this.included||(t.include("https://www.google.com/recaptcha/api.js",!0),this.included=!0),n(e),e.promise};var o=function(e,n,o){o.retain=!0,n||grecaptcha.render("recaptcha",{sitekey:t.settings.recaptcha_site_key})};this.component=function(e){var n=m("#recaptcha",{config:o});return t.component("form-group",{label:gettext("Security test"),labelClass:e.labelClass||null,controlClass:e.controlClass||null,control:n,validation:e.form.errors,validationKey:"captcha"})},this.value=function(){return"undefined"!=typeof grecaptcha?grecaptcha.getResponse():""},this.clean=function(t){t.errors.captcha=this.value()?!0:[gettext("This field is required.")]},this.validator=function(){return[]}},r=function(t){var r={no:e,qa:n,re:o},i=new r[t.settings.captcha_type](t);this.value=i.value,this.load=function(){return i.load()},this.component=function(t){return i.component?i.component(t):null},this.validator=function(){return i.validator?i.validator():null},this.clean=function(t){i.clean?i.clean(t):t.errors.captcha=!0}};t.addService("captcha",function(t){return new r(t)},{after:"include"})}(Misago.prototype),function(t){"use strict";var e=function(t,e){if(this._components[t]){if(arguments.length>1){for(var n=[this._components[t]],o=1;o<arguments.length;o+=1)n.push(arguments[o]);return n.push(this),m.component.apply(void 0,n)}return m.component(this._components[t],this)}if(!e)throw'"'+t+"\" component is not registered and can't be created";this._components[t]=e};t.addService("components",function(t){t._components={},t.component=e})}(Misago.prototype),function(t){"use strict";t.addService("conf",function(e){e.settings=t.get(e.context,"SETTINGS",{})})}(Misago.prototype),function(t){"use strict";var e=function(t){var e={};this.toggle=function(n,o){var r=document.getElementById(n);r.hasChildNodes()&&e[n]===o?(e[n]=null,m.mount(r,null),$(r).removeClass("open")):(console.log(r.hasChildNodes()),e[n]=o,m.mount(r,t.component(o)),$(r).addClass("open"))},this.destroy=function(){var t=null;for(var n in e)e.hasOwnProperty(n)&&(t=document.getElementById(n),t&&t.hasChildNodes()&&m.mount(t,null))}};t.addService("dropdown",{factory:function(t){return new e(t)},destroy:function(t){t.dropdown.destroy()}},{before:"components"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=t.submit,n=t.success,o=t.error;return t.isBusy=!1,t.errors=null,t.submit=function(){return t.isBusy?!1:(t.clean?t.clean()&&(t.isBusy=!0,e.apply(t)):t.isBusy=!0,!1)},t.success=function(){m.startComputation(),n.apply(t,arguments),t.isBusy=!1,m.endComputation()},t.error=function(){m.startComputation(),o.apply(t,arguments),t.isBusy=!1,m.endComputation()},t.hasErrors=function(){if(null===t.errors)return!1;for(var e in t.validation)if(t.validation.hasOwnProperty(e)&&t.errors[e]!==!0)return!0;return!1},t},n=function(t,n){return this._forms[t]?e(n?new this._forms[t](n,this):new this._forms[t](this)):void(this._forms[t]=n)};t.addService("forms",function(t){t._forms={},t.form=n})}(Misago.prototype),function(t){"use strict";var e=function(t,e){e||(t=this.context.STATIC_URL+t),$.ajax({url:t,cache:!0,dataType:"script"})};t.addService("include",function(t){t.include=e},{after:"conf"})}(Misago.prototype),function(t){"use strict";var e=function(e){e.baseUrl=$("base").attr("href");var n=t.get(e.context,"STATIC_URL","/"),o=t.get(e.context,"MEDIA_URL","/"),r=function(t){return function(e){return t+e}};e.staticUrl=r(n),e.mediaUrl=r(o)};t.addService("links",function(t){e(t)})}(Misago.prototype),function(t){"use strict";var e=function(){var t=window.localStorage,e="_misago_",n=[],o=function(t){var e=JSON.parse(t.newValue);$.each(n,function(n,o){o.keyName===t.key&&t.oldValue!==t.newValue&&o.callback(e)})};window.addEventListener("storage",o);var r=function(t){return e+t};this.set=function(e,n){t.setItem(r(e),JSON.stringify(n))},this.get=function(e){var n=t.getItem(r(e));return n?JSON.parse(n):null},this.watch=function(t,e){n.push({keyName:r(t),callback:e})},this.destroy=function(){this.watchers=[]}};t.addService("localstore",{factory:function(){return new e},destroy:function(t){t.localstore.destroy()}})}(Misago.prototype),function(t){"use strict";var e=function(){var t=this,e=document.getElementById("modal-mount");this.destroy=function(){$(e).off(),$("body").removeClass("modal-open"),$(".modal-backdrop").remove()};var n=$(e).modal({show:!1});this.open=!1,n.on("hidden.bs.modal",function(){t.open&&(m.mount(e,null),this.open=!1)}),this.show=function(t){this.open=!0,m.mount(e,t),n.modal("show")},this.hide=function(){n.modal("hide")}};t.addService("_modal",{factory:function(){return new e},destroy:function(t){t._modal.destroy()}},{before:"mount:page-component"})}(Misago.prototype),function(t){"use strict";var e=function(t,e){if(this._modals[t]){for(var n=[this._modals[t]],o=1;o<arguments.length;o+=1)n.push(arguments[o]);n.push(this),this._modal.show(m.component.apply(m,n))}else t?this._modals[t]=e:this._modal.hide()};t.addService("modals",function(t){t._modals={},t.modal=e},{after:"_modal"})}(Misago.prototype),function(t){"use strict";var e=function(){this.classes={},this.deserializers={},this.add=function(t,e){e["class"]&&(this.classes[t]=e["class"]),e.deserialize&&(this.deserializers[t]=e.deserialize)},this["new"]=function(t,e){return this.classes[t]?(e.id=e.id?String(e.id):null,new this.classes[t](e)):e},this.deserialize=function(t,e){return this.deserializers[t]?this["new"](t,this.deserializers[t](e,this)):this["new"](t,e)}};t.addService("models",function(){return new e})}(Misago.prototype),function(t){"use strict";t.addService("set-momentjs-locale",function(){moment.locale($("html").attr("lang"))})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("page-mount");t.addService("mount-page",function(t){t.mountPage=function(t){m.mount(e,t)}})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=this;this._intervals={};var n=function(t){e._intervals[t]&&(window.clearTimeout(e._intervals[t]),e._intervals[t]=null)};this.run=function(o,r,i){this._intervals[r]=window.setTimeout(function(){n(r);var a=o(t);a!==!1&&e.run(o,r,i)},i)},this.runOnce=function(e,o,r){this._intervals[o]=window.setTimeout(function(){n(o),e(t)},r)},this.stop=function(t){for(var e in this._intervals)t&&t!==e||n(e)}};t.addService("runloop",{factory:function(t){return new e(t)},destroy:function(t){t.runloop.stop()}})}(Misago.prototype),function(t){"use strict";t.addService("show-banned-page",function(t){t.showBannedPage=function(e,n){var o=t.component("banned-page",t.models.deserialize("ban",e));"undefined"!=typeof n&&n||(t.title.set(gettext("You are banned")),window.history.pushState({},"",t.context.BANNED_URL)),t.mountPage(o)}})}(Misago.prototype),function(t){"use strict";t.addService("start-tick",function(t){var e=m.prop();t.runloop.run(function(){m.startComputation(),e(e()+1),m.endComputation()},"tick",6e4)})}(Misago.prototype),function(t){"use strict";var e=function(t){this.set=function(e){e?this._set_complex(e):document.title=t},this._set_complex=function(e){"string"==typeof e&&(e={title:e});var n=e.title;if("undefined"!=typeof e.page&&e.page>1){var o=interpolate(gettext("page %(page)s"),{page:e.page},!0);n+=" ("+o+")"}"undefined"!=typeof e.parent&&(n+=" | "+e.parent),document.title=n+" | "+t}};t.addService("page-title",function(t){t.title=new e(t.settings.forum_name)})}(Misago.prototype),function(t){"use strict";var e=/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i,n=new RegExp("^[0-9a-z]+$","i");t.validators={required:function(){return function(t){return 0===$.trim(t).length?gettext("This field is required."):void 0}},email:function(t){return function(n){return e.test(n)?void 0:t||gettext("Enter a valid email address.")}},minLength:function(t,e){return function(n){var o="",r=$.trim(n).length;return t>r?(o=e?e(t,r):ngettext("Ensure this value has at least %(limit_value)s character (it has %(show_value)s).","Ensure this value has at least %(limit_value)s characters (it has %(show_value)s).",t),interpolate(o,{limit_value:t,show_value:r},!0)):void 0}},maxLength:function(t,e){return function(n){var o="",r=$.trim(n).length;return r>t?(o=e?e(t,r):ngettext("Ensure this value has at most %(limit_value)s character (it has %(show_value)s).","Ensure this value has at most %(limit_value)s characters (it has %(show_value)s).",t),interpolate(o,{limit_value:t,show_value:r},!0)):void 0}},usernameMinLength:function(t){var e=function(t){return ngettext("Username must be at least %(limit_value)s character long.","Username must be at least %(limit_value)s characters long.",t)};return this.minLength(t.username_length_min,e)},usernameMaxLength:function(t){var e=function(t){return ngettext("Username cannot be longer than %(limit_value)s character.","Username cannot be longer than %(limit_value)s characters.",t)};return this.maxLength(t.username_length_max,e)},usernameContent:function(){return function(t){return n.test($.trim(t))?void 0:gettext("Username can only contain latin alphabet letters and digits.")}},passwordMinLength:function(t){var e=function(t){return ngettext("Valid password must be at least %(limit_value)s character long.","Valid password must be at least %(limit_value)s characters long.",t)};return this.minLength(t.password_length_min,e)}};var o=function(e,n){var o=t.validators.required()(e),r=[];if(o)return[o];for(var i in n)o=n[i](e),o&&r.push(o);return r.length?r:!0},r=function(t){var e={},n=null,r=!0;for(var i in t.validation)t.validation.hasOwnProperty(i)&&(n=t[i](),e[i]=o(t[i](),t.validation[i]),e[i]!==!0&&(r=!1));return t.errors=e,r},i=function(t,e){return e?function(n){var r=null;return"undefined"!=typeof n?(r=o(n,t.validation[e]),r&&(t.errors||(t.errors={}),t.errors[e]=r),t[e](n),t[e](n)):t[e]()}:r(t)};t.addService("validate",{factory:function(){return i}})}(Misago.prototype),function(t){"use strict";var e=function(t){this.included=!1,this.scorePassword=function(t,e){return zxcvbn(t,e).score},this.include=function(){t.include("misago/js/zxcvbn.js"),this.included=!0};var e=function(n){"undefined"!=typeof zxcvbn?n.resolve():t.runloop.runOnce(function(){e(n)},"loading-zxcvbn",150)},n=m.deferred();this.load=function(){return this.included||this.include(),e(n),n.promise}};t.addService("zxcvbn",function(t){return new e(t)},{after:"include"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.message={html:t.message.html,plain:t.message.plain},this.expires_on=t.expires_on},n=function(e){return e.expires_on=t.deserializeDatetime(e.expires_on),e};t.addService("model:ban",function(t){t.models.add("ban",{"class":e,deserialize:n})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.title=t.title,this.body=t.body,this.link=t.link};t.addService("model:legal-page",function(t){t.models.add("legal-page",{"class":e})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.id=t.id,this.name=t.name,this.slug=t.slug,this.description=t.description,this.title=t.title,this.css_class=t.css_class,this.is_tab=t.is_tab};t.addService("model:rank",function(t){t.models.add("rank",{"class":e})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.id=t.id,this.isAuthenticated=!!this.id,this.isAnonymous=!this.isAuthenticated,this.username=t.username,this.slug=t.slug,this.email=t.email,this.full_title=t.full_title,this.rank=t.rank,this.avatar_hash=t.avatar_hash,this.acl=t.acl,this.absolute_url=t.absolute_url},n=function(e,n){return e.joined_on&&(e.joined_on=t.deserializeDatetime(e.joined_on)),e.rank&&(e.rank=n.deserialize("rank",e.rank)),e};t.addService("model:user",function(t){t.models.add("user",{"class":e,deserialize:n})},{after:"model:rank"})}(Misago.prototype),function(t){"use strict";var e=".well.well-form.well-form-request-activation-link",n=function(t){this.api=t,this.user=null,this.success=function(t){this.user=t},this.error=function(t,e){"already_active"===t.code?(e.alert.info(t.detail),e.modal("sign-in")):"inactive_admin"===t.code?e.alert.info(t.detail):e.alert.error(t.detail)},this.reset=function(){this.user=null}},o={controller:function(t){var e=new n(t.context.SEND_ACTIVATION_API_URL);return{vm:e,form:t.form("request-link",e)}},view:function(t,e){return t.vm.user?this.done(t.vm,t.form,e):this.form(t.form,e)},done:function(t,n,o){var r=gettext("Activation link sent to %(email)s.");return m(e+".well-done",m(".done-message",[m(".message-icon",m("span.material-icon","check")),m(".message-body",m("p",interpolate(r,{email:t.user.email},!0))),o.component("button",{"class":".btn-default.btn-block",submit:!1,label:gettext("Request another link"),onclick:n.reset.bind(n)})]))},form:function(n,o){return m(e,m("form",{onsubmit:n.submit},[m(".form-group",m(".control-input",t.input({disabled:n.isBusy,value:n.email,placeholder:gettext("Your e-mail address")}))),o.component("button",{"class":".btn-primary.btn-block",submit:!0,loading:n.isBusy,label:gettext("Send link")})]))}};t.addService("component:request-link-form",function(t){t.component("request-activation-link-form",o)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(t,e){return m(".modal-header",[m('button.close[type="button"]',{"data-dismiss":"modal","aria-label":gettext("Close")},m("span",{"aria-hidden":"true"},m.trust("&times;"))),m("h4#misago-modal-label.modal-title",e)])}};t.addService("component:modal:header",function(t){t.component("modal:header",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=function(t,e,n){n.retain=!0},n=function(){document.location.reload()},o={controller:function(t,e){"active"===t.activation&&e.runloop.runOnce(n,"refresh-after-registration",1e4)},view:function(t,n,o){var r=null;return r="active"===n.activation?this.active(n):this.inactive(n),m('.modal-dialog.modal-message.modal-register[role="document"]',{config:e},m(".modal-content",[o.component("modal:header",gettext("Registration complete")),m(".modal-body",r)]))},active:function(t){var e=gettext("%(username)s, your account has been created and you were signed in.");return[m(".message-icon",m("span.material-icon","check")),m(".message-body",[m("p.lead",interpolate(e,{username:t.username},!0)),m("p",gettext("The page will refresh automatically in 10 seconds.")),m("p",m('button[type="button"].btn.btn-default',{onclick:n},gettext("Refresh page")))])]},inactive:function(t){var e=null,n=null;return"user"===t.activation?(e=gettext("%(username)s, your account has been created but you need to activate it before you will be able to sign in."),n=gettext("We have sent an e-mail to %(email)s with link that you have to click to activate your account.")):"admin"===t.activation&&(e=gettext("%(username)s, your account has been created but board administrator will have to activate it before you will be able to sign in."),n=gettext("We will send an e-mail to %(email)s when this takes place.")),[m(".message-icon",m("span.material-icon","info_outline")),m(".message-body",[m("p.lead",interpolate(e,{username:t.username},!0)),m("p",interpolate(n,{email:t.email},!0))])]}};t.addService("modal:register-complete",function(t){t.modal("register-complete",o)},{after:"modals"})}(Misago.prototype),function(t){"use strict";var e=function(t,e,n){n.retain=!0},n={controller:function(t){return{form:t.form("register")}},view:function(t,n){var o=n.captcha.component({form:t.form,labelClass:".col-md-4",controlClass:".col-md-8"}),r=null;return n.context.TERMS_OF_SERVICE_URL&&(r=m("a",{href:n.context.TERMS_OF_SERVICE_URL},m.trust(interpolate(gettext("By registering you agree to site's %(terms)s."),{terms:"<strong>"+gettext("terms and conditions")+"</strong>"},!0)))),m('.modal-dialog.modal-form.modal-register[role="document"]',{config:e},m(".modal-content",[n.component("modal:header",gettext("Register")),m("form.form-horizontal",{onsubmit:t.form.submit},[m('input[type="text"]',{name:"_username",style:"display: none"}),m('input[type="password"]',{name:"_password",style:"display: none"}),m(".modal-body",[n.component("form-group",{label:gettext("Username"),labelClass:".col-md-4",controlClass:".col-md-8",control:n.input({value:n.validate(t.form,"username"),id:"id_username",disabled:t.form.isBusy}),validation:t.form.errors,validationKey:"username"}),n.component("form-group",{label:gettext("E-mail"),labelClass:".col-md-4",controlClass:".col-md-8",control:n.input({value:n.validate(t.form,"email"),id:"id_email",disabled:t.form.isBusy}),validation:t.form.errors,validationKey:"email"}),n.component("form-group",{label:gettext("Password"),labelClass:".col-md-4",controlClass:".col-md-8",control:n.input({value:n.validate(t.form,"password"),type:"password",id:"id_password",disabled:t.form.isBusy}),validation:t.form.errors,validationKey:"password",helpText:n.component("password-strength",{inputs:[t.form.username(),t.form.email()],password:t.form.password()})}),o]),m(".modal-footer",[r,n.component("button",{"class":".btn-primary",submit:!0,loading:t.form.isBusy,label:gettext("Register account")})])])]))}};t.addService("modal:register",function(t){t.modal("register",n)},{after:"modals"})}(Misago.prototype),function(t){"use strict";function e(t,e,n){n.retain=!0}var n={controller:function(t){return{form:t.form("sign-in")}},view:function(n,o){var r=null;return n.form.showActivation&&(r=m("a.btn.btn-block.btn-success",{href:o.context.REQUEST_ACTIVATION_URL},gettext("Activate account"))),m('.modal-dialog.modal-sm.modal-signin[role="document"]',{config:e},m(".modal-content",[o.component("modal:header",gettext("Sign in")),m("form",{onsubmit:n.form.submit},[m(".modal-body",[m(".form-group",m(".control-input",t.input({disabled:n.form.isBusy,value:n.form.username,placeholder:gettext("Username or e-mail")}))),m(".form-group",m(".control-input",t.input({type:"password",disabled:n.form.isBusy,value:n.form.password,placeholder:gettext("Password")})))]),m(".modal-footer",[r,o.component("button",{"class":".btn-primary.btn-block",submit:!0,loading:n.form.isBusy,label:gettext("Sign in")}),m("a.btn.btn-block.btn-default",{href:o.context.FORGOTTEN_PASSWORD_URL},gettext("Forgot password?"))])])]))}};t.addService("modal:sign-in",function(t){t.modal("sign-in",n)},{after:"modals"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{showSignIn:function(){t.modal("sign-in")}}},view:function(t,e){return m('ul.dropdown-menu.user-dropdown.dropdown-menu-right[role="menu"]',m("li.guest-preview",[m("h4",gettext("You are browsing as guest.")),m("p",gettext("Sign in or register to start and participate in discussions.")),m(".row",[m(".col-xs-6",e.component("button",{"class":".btn.btn-default.btn-block",onclick:t.showSignIn,disabled:t.isBusy,label:gettext("Sign in")})),m(".col-xs-6",e.component("navbar:register-button",".btn.btn-primary.btn-block"))])]))}};t.addService("component:navbar:dropdown:guest",function(t){t.component("navbar:dropdown:guest",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={style:".nav.navbar-nav.navbar-compact-nav.hidden-md.hidden-lg",controller:function(t,e){return{openUserMenu:function(){return e.user.isAuthenticated?e.dropdown.toggle("navbar-dropdown","navbar:dropdown:user"):e.dropdown.toggle("navbar-dropdown","navbar:dropdown:guest"),!1}}},userMenu:function(t,e){return e.user.isAuthenticated?{element:e.component("user-avatar",e.user,64),config:{onclick:t.openUserMenu,url:"/not-yet/","data-misago-routed":"false"}}:{element:e.component("user-avatar",null,64),config:{onclick:t.openUserMenu,href:"#","data-misago-routed":"false"}}},mobileNav:function(t,e,n){var o=[{element:m("img",{src:n.router.staticUrl("misago/img/site-icon.png"),alt:n.settings.forum_name}),url:n.router.url("index")}];return e.forEach(function(t){t.url!==o[0].url&&o.push(t)}),o.push(this.userMenu(t,n)),o},view:function(t,e,n){var o=this.mobileNav(t,e,n);return m("ul"+this.style+".with-"+o.length+"-items",o.map(function(t){return m("li",m("a",t.config||{href:t.url},t.element||m("span.material-icon",{title:t.label},t.icon)))}))}};t.addService("component:navbar:mobile",function(t){t.component("navbar:mobile",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t,e){return{isBusy:!1,showRegister:function(){if("closed"===e.settings.account_activation)e.alert.info(gettext("New registrations are currently disabled."));else{m.startComputation(),this.isBusy=!0,m.endComputation();var t=this;m.sync([e.zxcvbn.load(),e.captcha.load()]).then(function(){e.modal("register")},function(){e.alert.error(gettext("Registation is not available now due to an error."))}).then(function(){m.startComputation(),t.isBusy=!1,m.endComputation()})}}}},view:function(t,e,n){return n.component("button",{"class":e,onclick:t.showRegister.bind(t),loading:t.isBusy,label:gettext("Register")})}};t.addService("component:navbar:register-button",function(t){t.component("navbar:register-button",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={"class":".dropdown-menu.user-dropdown.dropdown-menu-right",controller:function(){return{logout:function(){var t=confirm(gettext("Are you sure you want to sign out?"));t&&$("#hidden-logout-form").submit()}}},view:function(t,e){return m("ul"+this["class"]+'[role="menu"]',[m("li.dropdown-header",m("strong",e.user.username)),m("li.divider"),m("li",m("a",{
+href:e.user.absolute_url},[m("span.material-icon","account_circle"),gettext("See your profile")])),m("li",m("a",{href:e.context.USERCP_URL},[m("span.material-icon","done_all"),gettext("Change options")])),m("li",m('button.btn-link[type="button"]',[m("span.material-icon","face"),gettext("Change avatar")])),m("li.divider"),m("li.dropdown-footer",m("button.btn.btn-default.btn-block",{onclick:t.logout},gettext("Logout")))])}};t.addService("component:navbar:dropdown:user",function(t){t.component("navbar:dropdown:user",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{openUserMenu:function(){t.dropdown.toggle("navbar-dropdown","navbar:dropdown:guest")}}},view:function(t,e){return m("button",{type:"button",onclick:t.openUserMenu},e.component("user-avatar",null,64))}};t.addService("component:navbar:compact:guest-nav",function(t){t.component("navbar:compact:guest-nav",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{openUserMenu:function(){return t.dropdown.toggle("navbar-dropdown","navbar:dropdown:user"),!1}}},view:function(t,e){var n={onclick:t.openUserMenu,href:e.user.absolute_url};return m("a",n,e.component("user-avatar",e.user,64))}};t.addService("component:navbar:compact:user-nav",function(t){t.component("navbar:compact:user-nav",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{showSignIn:function(){t.modal("sign-in")}}},view:function(t,e){return m("div.nav.nav-guest",[e.component("button",{"class":".navbar-btn.btn-default",onclick:t.showSignIn,disabled:t.isBusy,label:gettext("Sign in")}),e.component("navbar:register-button",".navbar-btn.btn-primary")])}};t.addService("component:navbar:desktop:guest-nav",function(t){t.component("navbar:desktop:guest-nav",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t){return{dropdownToggle:{href:t.user.absolute_url,"data-toggle":"dropdown","data-misago-routed":"false","aria-haspopup":"true","aria-expanded":"false"}}},view:function(t,e){return m("ul.nav.navbar-nav.nav-user",[m("li.dropdown",[m('a.dropdown-toggle[role="button"]',t.dropdownToggle,e.component("user-avatar",e.user,64)),e.component("navbar:dropdown:user")])])}};t.addService("component:navbar:desktop:user-nav",function(t){t.component("navbar:desktop:user-nav",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";function e(t,e,n){n.retain=!0}var n={classes:{info:"alert-info",success:"alert-success",warning:"alert-warning",error:"alert-danger"},view:function(t,n){var o={config:e,"class":n.alert.isVisible?"in":"out"};return m(".alerts",o,m("p.alert",{"class":this.classes[n.alert.type]},n.alert.message))}};t.addService("component:alert",function(t){t.component("alert",n)},{after:"components"})}(Misago.prototype),function(t){"use strict";function e(t,e,n){n.retain=!0}var n={refresh:function(){window.location.reload()},view:function(t,n){var o="",r={config:e,"class":n.auth.isDesynced?"show":null};return n.auth.isDesynced&&(n.auth.newUser&&n.auth.newUser.isAuthenticated?(o=gettext("You have signed in as %(username)s. Please refresh this page before continuing."),o=interpolate(o,{username:n.auth.newUser.username},!0)):(o=gettext("%(username)s, you have been signed out. Please refresh this page before continuing."),o=interpolate(o,{username:n.user.username},!0))),m(".auth-changed-message",r,m("",m(".container",[m("p",o),m("p",[m('button.btn.btn-default[type="button"]',{onclick:this.refresh},gettext("Reload page")),m("span.hidden-xs.hidden-sm.text-muted",gettext("or press F5 key."))])])))}};t.addService("component:auth-changed-message",function(t){t.component("auth-changed-message",n)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={controller:function(t,e){var n=e||t;return e?t:n.models.deserialize("ban",n.context.ban)},view:function(t){var e=null;return e=t.expires_on?t.expires_on.isAfter(moment())?interpolate(gettext("This ban expires %(expires_on)s."),{expires_on:t.expires_on.fromNow()},!0):gettext("This ban has expired."):gettext("This ban is permanent."),m("p",e)}};t.addService("component:ban-expiration-message",function(t){t.component("ban-expiration-message",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(t,e,n){var o=[];return o.push(e.message.html?m(".lead",m.trust(e.message.html)):m("p.lead",e.message.plain)),o.push(n.component("ban-expiration-message",e)),m(".page.page-error.page-error-banned",m(".container",m(".message-panel",[m(".message-icon",m("span.material-icon","highlight_off")),m(".message-body",o)])))}};t.addService("component:banned-page",function(t){t.component("banned-page",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(t,e){var n={disabled:e.disabled||e.loading||!1,config:e.config||null,loading:e.loading||!1,type:e.submit?"submit":"button",onclick:e.onclick||null},o='button[type="'+n.type+'"].btn';n.loading&&(o+=".btn-loading"),e.id&&(o+="#"+e.id),o+=e["class"]||"";var r=e.label;return n.loading&&(r=[r,m(".loader-compact",[m(".bounce1"),m(".bounce2"),m(".bounce3")])]),m(o,n,r)}};t.addService("component:button",function(t){t.component("button",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=["text","password","email"],n={view:function(t,n){var o=".form-group",r=null,i=null,a=n.control.attrs.type,s=n.control.attrs.id,u=s+"_feedback",c=null,l=null,d=n.validationKey&&null!==n.validation;return n.control.attrs["aria-describedby"]="",d&&n.validation[n.validationKey]&&(l=e.indexOf(a)>=0,n.control.attrs["aria-describedby"]=u,n.validation[n.validationKey]===!0?(o+=".has-success",c=[m("span.material-icon.form-control-feedback",{"aria-hidden":"true"},"check"),m("span.sr-only#"+u,gettext("(success)"))]):(o+=".has-error",r=n.validation[n.validationKey],c=[m("span.material-icon.form-control-feedback",{"aria-hidden":"true"},"clear"),m("span.sr-only#"+u,gettext("(error)"))])),n.helpText&&(i="string"==typeof n.helpText||n.helpText instanceof String?m("p.help-block",n.helpText):n.helpText),m(o,[m("label.control-label"+(n.labelClass||""),{"for":n.labelFor||s},n.label+":"),m(n.controlClass||"",[n.control,l?c:null,r?m(".help-block.errors",r.map(function(t){return m("p",t)})):null,i])])}};t.addService("component:form-group",function(t){t.component("form-group",n)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(){return m(".loader.sk-folding-cube",[m(".sk-cube1.sk-cube"),m(".sk-cube2.sk-cube"),m(".sk-cube4.sk-cube"),m(".sk-cube3.sk-cube")])}};t.addService("component:loader",function(t){t.component("loader",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=function(t,e,n){n.retain=!0},n={view:function(t,n){return m("article.misago-markup",{config:e},m.trust(n))}};t.addService("component:markup",function(t){t.component("markup",n)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={view:function(t,e){return m(".page-header",m(".container",[m("h1",e.title)]))}};t.addService("component:header",function(t){t.component("header",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=function(t,e,n){n.retain=!0},n=["progress-bar-danger","progress-bar-warning","progress-bar-warning","progress-bar-primary","progress-bar-success"],o=[gettext("Entered password is very weak."),gettext("Entered password is weak."),gettext("Entered password is average."),gettext("Entered password is strong."),gettext("Entered password is very strong.")],r={view:function(t,r,i){var a=i.zxcvbn.scorePassword(r.password,r.inputs),s={config:e,"class":n[a],style:"width: "+(20+20*a)+"%",role:"progressbar","aria-valuenow":a,"aria-valuemin":"0","aria-valuemax":"4"};return m(".help-block.password-strength",{key:"password-strength"},[m(".progress",m(".progress-bar",s,m("span.sr-only",o[a]))),m("p.text-small",o[a])])}};t.addService("component:password-strength",function(t){t.component("password-strength",r)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e={defaultSize:100,src:function(t,e,n){var o=n.baseUrl+"user-avatar/";return o+=t&&t.id?t.avatar_hash+"/"+e+"/"+t.id+".png":e+".png"},view:function(t,e,n,o){var r=n||this.defaultSize;return m("img",{alt:e&&e.username?e.username:gettext("Unregistered"),width:r,height:r,src:this.src(e,r,o)})}};t.addService("component:user-avatar",function(t){t.component("user-avatar",e)},{after:"components"})}(Misago.prototype),function(t){"use strict";var e=function(e){var n=this;this.username=null,this.password=m.prop(""),this.validation={password:[t.validators.passwordMinLength(e.settings)]},this.clean=function(){return e.validate(this)?!0:(e.alert.error($.trim(this.password()).length?this.errors.password:gettext("Enter new password.")),!1)},this.submit=function(){var t=e.api.endpoint("auth").endpoint("change-password");t=t.endpoint(m.route.param("user_id")),t=t.endpoint(m.route.param("token")),t.post({password:n.password()}).then(function(t){n.success(t)},function(t){n.error(t)})},this.success=function(t){this.username=t.username},this.error=function(t){403===t.status&&t.ban?e.router.error403({message:"",ban:t.ban}):400===t.status?e.alert.error(t.detail):e.api.alert(t)}};t.addService("form:change-password",function(t){t.form("change-password",e)},{after:"forms"})}(Misago.prototype),function(t){"use strict";var e=function(e){var n=this;this.showActivation=!1,this.username=m.prop(""),this.email=m.prop(""),this.password=m.prop(""),this.captcha=e.captcha.value,this.errors=null,this.validation={username:[t.validators.usernameContent(),t.validators.usernameMinLength(e.settings),t.validators.usernameMaxLength(e.settings)],email:[t.validators.email()],password:[t.validators.passwordMinLength(e.settings)],captcha:e.captcha.validator()},this.clean=function(){return null===this.errors&&e.validate(this),e.captcha.clean(this),this.hasErrors()?(e.alert.error(gettext("Form contains errors.")),!1):!0},this.submit=function(){e.api.model("user").post({username:this.username(),email:this.email(),password:this.password(),captcha:this.captcha()}).then(this.success,this.error)},this.success=function(t){e.modal("register-complete",t)},this.error=function(t){400===t.status?(e.alert.error(gettext("Form contains errors.")),$.extend(n.errors,t)):e.api.alert(t)}};t.addService("form:register",function(t){t.form("register",e)},{after:"forms"})}(Misago.prototype),function(t){"use strict";var e=function(e,n){var o=this;this.email=m.prop(""),this.validation={email:[t.validators.email()]},this.clean=function(){return n.validate(this)?!0:(n.alert.error(gettext("Enter a valid email address.")),!1)},this.submit=function(){n.ajax.post(e.api,{email:o.email()}).then(function(t){o.success(t)},function(t){o.error(t)})},this.success=function(t){e.success(t)},this.error=function(t){400===t.status?e.error(t,n):n.api.alert(t)},this.reset=function(){this.email(""),e.reset()}};t.addService("form:request-link",function(t){t.form("request-link",e)},{after:"forms"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=this;this.showActivation=!1,this.username=m.prop(""),this.password=m.prop(""),this.validation={username:[],password:[]},this.clean=function(){return t.validate(this)?!0:(t.alert.error(gettext("Fill out both fields.")),!1)},this.submit=function(){t.api.endpoint("auth").post({username:e.username(),password:e.password()}).then(function(){e.success()},function(t){e.error(t)})},this.success=function(){t.modal();var e=$("#hidden-login-form");t.ajax.refreshCsrfToken(),e.find('input[type="hidden"]').val(t.ajax.csrfToken),e.find('input[name="redirect_to"]').val(m.route()),e.find('input[name="username"]').val(this.username()),e.find('input[name="password"]').val(this.password()),e.submit()},this.error=function(n){400===n.status?"inactive_admin"===n.code?t.alert.info(n.detail):"inactive_user"===n.code?(t.alert.info(n.detail),e.showActivation=!0):"banned"===n.code?(t.showBannedPage(n.detail),t.modal()):t.alert.error(n.detail):t.api.alert(n)}};t.addService("form:sign-in",function(t){t.form("sign-in",e)},{after:"forms"})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("alert-mount");t.addService("mount:alert",{factory:function(t){m.mount(e,t.component("alert"))},destroy:function(){m.mount(e,null)}},{before:"mount:page-component"})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("auth-changed-message-mount");t.addService("mount:auth-changed-message",{factory:function(t){m.mount(e,t.component("auth-changed-message"))},destroy:function(){m.mount(e,null)}},{before:"mount:page-component"})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("page-component");t.addService("mount:page-component",{factory:function(t){e&&m.mount(e,t.component(e.dataset.componentName))},destroy:function(){e&&m.mount(e,null)}},{before:"_end"})}(Misago.prototype),function(t){"use strict";var e=document.getElementById("user-menu-mount"),n=document.getElementById("user-menu-compact-mount");t.addService("mount:user-menu",{factory:function(t){t.user.isAuthenticated?(m.mount(e,t.component("navbar:desktop:user-nav")),m.mount(n,t.component("navbar:compact:user-nav"))):(m.mount(e,t.component("navbar:desktop:guest-nav")),m.mount(n,t.component("navbar:compact:guest-nav")))},destroy:function(){m.mount(e,null),m.mount(n,null)}},{before:"mount:page-component"})}(Misago.prototype);
 //# sourceMappingURL=/misago.js.map
 //# sourceMappingURL=/misago.js.map

+ 1 - 1
misago/static/misago/js/misago.js.map

@@ -1 +1 @@
-{"version":3,"sources":["misago.js"],"names":["window","Misago","ns","Object","getPrototypeOf","this","self","_initServices","services","orderedServices","OrderedList","order","forEach","item","factory","undefined","serviceInstance","key","_destroyServices","reverse","destroy","context","SETTINGS","setup","init","test","get","api","_services","proto","prototype","addService","name","push","after","before","PermissionDenied","message","detail","status","toString","has","obj","hasOwnProperty","value","pop","returnValue","persistent","el","isInit","retain","input","kwargs","options","disabled","config","placeholder","autocomplete","element","id","type","oninput","m","withAttr","noop","stateHooks","component","loadingState","errorState","_hasLifecycleHooks","isActive","errorHandler","bind","_controller","controller","apply","arguments","_onunload","onunload","e","vm","loading","loadingHandler","_view","view","isReady","_init","initArgs","promise","then","ondata","finalArgs","i","length","f","error","items","isOrdered","_items","add","values","values_only","_order","unordered","insertItem","insertAt","ordering","indexOf","ordered","splice","index","iterations","Page","_","isFinalized","_sections","finalize","visible","visibleIf","addSection","section","link","getSections","getDefaultLink","serializeDatetime","serialized","format","deserializeDatetime","deserialized","moment","startsWith","string","beginning","endsWith","tail","UrlConf","_patterns","patterns","prefixPattern","prefix","pattern","replace","include","url","loadingPage","getCsrfToken","cookie_name","document","cookie","cookieRegex","RegExp","match","split","Ajax","refreshCsrfToken","csrfToken","CSRF_COOKIE_NAME","runningGets","ajax","method","data","progress","deferred","ajax_settings","headers","X-CSRFToken","dataType","success","resolve","jqXHR","rejection","responseJSON","statusText","reject","$","preloaded","post","patch","put","ALERT_BASE_DISPLAY_TIME","ALERT_LENGTH_FACTOR","ALERT_MAX_DISPLAY_TIME","ALERT_HIDE_ANIMATION_LENGTH","Alert","isVisible","show","displayTime","runloop","runOnce","startComputation","endComputation","set","stop","info","warning","filtersUrl","filters","encodedKey","encodeURIComponent","encodedValue","join","Query","call","path","related","model","relation","endpoint","results","map","models","Api","alert","gettext","Auth","user","deserialize","isDesynced","newUser","handleAuthChange","isAuthenticated","localstore","handleUserChange","extend","syncSession","watch","denyAuthenticated","denyAnonymous","isAnonymous","NoCaptcha","load","QACaptcha","question","prop","label","labelClass","controlClass","control","validate","form","isBusy","validation","errors","validationKey","helpText","help_text","validator","ReCaptcha","included","wait","grecaptcha","reset","controlConfig","render","sitekey","settings","recaptcha_site_key","getResponse","clean","captcha","Captcha","types","no","qa","re","captcha_type","_components","argumentsArray","Dropdown","slots","toggle","elementId","getElementById","hasChildNodes","mount","removeClass","console","log","addClass","dropdown","boilerplate","_submit","submit","_success","_error","hasErrors","constructor","_forms","script","remote","STATIC_URL","cache","setLinks","baseUrl","attr","staticUrl","mediaUrl","prefixUrl","LocalStore","storage","localStorage","watchers","handleStorageEvent","newValueJson","JSON","parse","newValue","each","watcher","keyName","oldValue","callback","addEventListener","prefixKey","setItem","stringify","itemString","getItem","Modal","off","remove","modal","open","on","hide","_modal","_modals","Models","classes","deserializers","String","json","locale","RunLoop","_intervals","stopInterval","clearTimeout","run","callable","delay","setTimeout","result","loop","showBannedPage","ban","title","history","pushState","BANNED_URL","ticks","PageTitle","forum_name","_set_complex","completeTitle","page","page_label","interpolate","parent","EMAIL","USERNAME","validators","required","trim","email","minLength","limit_value","returnMessage","ngettext","show_value","maxLength","usernameMinLength","username_length_min","usernameMaxLength","username_length_max","usernameContent","passwordMinLength","password_length_min","validateField","validateForm","isValid","Zxcvbn","scorePassword","password","inputs","zxcvbn","score","Ban","html","plain","expires_on","deserializeBan","class","LegalPage","body","Rank","slug","description","css_class","is_tab","User","username","full_title","rank","avatar_hash","acl","absolute_url","deserializeUser","joined_on","ctrl","onsubmit","header","data-dismiss","aria-label","aria-hidden","trust","refresh","location","reload","registerComplete","activation","messageHtml","active","inactive","lead","onclick","help","register","footnote","TERMS_OF_SERVICE_URL","href","terms","style","signin","activateButton","showActivation","REQUEST_ACTIVATION_URL","FORGOTTEN_PASSWORD_URL","showSignIn","navbar","links","openUserMenu","userMenu","data-misago-routed","mobileNav","mobileLinks","src","router","alt","icon","button","showRegister","account_activation","sync","logout","decision","confirm","USERCP_URL","nav","dropdownToggle","data-toggle","aria-haspopup","aria-expanded","authChanged","auth","bannedPage","error_message","expirationMessage","isAfter","fromNow","textFields","formGroup","groupClass","controlType","attrs","controlId","feedbackId","feedbackIcon","showFeedbackIcon","isValidated","for","labelFor","loader","markup","content","styles","labels","passwordStrength","role","aria-valuenow","aria-valuemin","aria-valuemax","avatar","defaultSize","size","finalSize","width","height","ChangePassword","route","param","error403","Register","RequestLink","SignIn","$form","find","val","code","dataset","componentName","mountDesktop","mountCompact"],"mappings":"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","file":"misago.js","sourcesContent":["/* global -Misago */\n/* exported Misago */\n(function () {\n  'use strict';\n\n  window.Misago = function() {\n    var ns = Object.getPrototypeOf(this);\n    var self = this;\n\n    // Services init/destroy\n    this._initServices = function(services) {\n      var orderedServices = new ns.OrderedList(services).order(false);\n      orderedServices.forEach(function (item) {\n        var factory = null;\n        if (item.item.factory !== undefined) {\n          factory = item.item.factory;\n        } else {\n          factory = item.item;\n        }\n\n        var serviceInstance = factory(self);\n        if (serviceInstance) {\n          self[item.key] = serviceInstance;\n        }\n      });\n    };\n\n    this._destroyServices = function(services) {\n      var orderedServices = new ns.OrderedList(services).order();\n      orderedServices.reverse();\n      orderedServices.forEach(function (item) {\n        if (item.destroy !== undefined) {\n          item.destroy(self);\n        }\n      });\n    };\n\n    // Context data\n    this.context = {\n      // Empty settings\n      SETTINGS: {}\n    };\n\n    // App init/destory\n    this.setup = false;\n    this.init = function(setup, context) {\n      this.setup = {\n        test: ns.get(setup, 'test', false),\n        api: ns.get(setup, 'api', '/api/')\n      };\n\n      if (context) {\n        this.context = context;\n      }\n\n      this._initServices(ns._services);\n    };\n\n    this.destroy = function() {\n      this._destroyServices(ns._services);\n    };\n  };\n\n  // Services\n  var proto = window.Misago.prototype;\n\n  proto._services = [];\n  proto.addService = function(name, factory, order) {\n    proto._services.push({\n      key: name,\n      item: factory,\n      after: proto.get(order, 'after'),\n      before: proto.get(order, 'before')\n    });\n  };\n\n  // Exceptions\n  proto.PermissionDenied = function(message) {\n    this.detail = message;\n    this.status = 403;\n\n    this.toString = function() {\n      return this.detail || 'Permission denied';\n    };\n  };\n}());\n\n(function (Misago) {\n  'use strict';\n\n  Misago.has = function(obj, key) {\n    if (obj) {\n      return obj.hasOwnProperty(key);\n    } else {\n      return false;\n    }\n  };\n\n  Misago.get = function(obj, key, value) {\n    if (Misago.has(obj, key)) {\n      return obj[key];\n    } else if (value !== undefined) {\n      return value;\n    } else {\n      return undefined;\n    }\n  };\n\n  Misago.pop = function(obj, key, value) {\n    var returnValue = Misago.get(obj, key, value);\n    if (Misago.has(obj, key)) {\n      obj[key] = null;\n    }\n    return returnValue;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  function persistent(el, isInit, context) {\n    context.retain = true;\n  }\n\n  Misago.input = function(kwargs) {\n    var options = {\n      disabled: kwargs.disabled || false,\n      config: kwargs.config || persistent\n    };\n\n    if (kwargs.placeholder) {\n      options.placeholder = kwargs.placeholder;\n    }\n\n    if (kwargs.autocomplete === false) {\n      options.autocomplete = 'off';\n    }\n\n    var element = 'input';\n\n    if (kwargs.id) {\n      element += '#' + kwargs.id;\n      options.key = 'field-' + kwargs.id;\n    }\n\n    element += '.form-control' + (kwargs.class || '');\n    element += '[type=\"' + (kwargs.type || 'text') + '\"]';\n\n    if (kwargs.value) {\n      options.value = kwargs.value();\n      options.oninput = m.withAttr('value', kwargs.value);\n    }\n\n    return m(element, options);\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var noop = function() {};\n\n  Misago.stateHooks = function(component, loadingState, errorState) {\n    /*\n      Boilerplate for Misago components with lifecycles\n    */\n\n    // Component boilerplated (this may happen in tests)\n    if (component._hasLifecycleHooks) {\n      return component;\n    }\n    component._hasLifecycleHooks = true;\n\n    // Component active state\n    component.isActive = true;\n\n    var errorHandler = errorState.bind(component);\n\n    // Wrap controller to store lifecycle methods\n    var _controller = component.controller || noop;\n    component.controller = function() {\n      try {\n        component.isActive = true;\n        var controller = _controller.apply(component, arguments) || {};\n\n        // wrap onunload for lifestate\n        var _onunload = controller.onunload || noop;\n        controller.onunload = function() {\n          _onunload.apply(component, arguments);\n          component.isActive = false;\n        };\n\n        return controller;\n      } catch (e) {\n        errorHandler(e);\n      }\n    };\n\n    // Add state callbacks to View-Model\n    if (component.vm && component.vm.init) {\n      // setup default loading view\n      if (!component.loading) {\n        var loadingHandler = loadingState.bind(component);\n        component.loading = loadingHandler;\n      }\n\n      var _view = component.view;\n      component.view = function() {\n        if (component.vm.isReady) {\n          return _view.apply(component, arguments);\n        } else {\n          return component.loading.apply(component, arguments);\n        }\n      };\n\n      // wrap vm.init in promise handler\n      var _init = component.vm.init;\n      component.vm.init = function() {\n        var initArgs = arguments;\n        var promise = _init.apply(component.vm, initArgs);\n\n        if (promise) {\n          promise.then(function() {\n            if (component.isActive && component.vm.ondata) {\n              var finalArgs = [];\n              for (var i = 0; i < arguments.length; i++) {\n                finalArgs.push(arguments[i]);\n              }\n              for (var f = 0; f < initArgs.length; f++) {\n                finalArgs.push(initArgs[f]);\n              }\n\n              component.vm.ondata.apply(component.vm, finalArgs);\n            }\n          }, function(error) {\n            if (component.isActive) {\n              errorHandler(error);\n            }\n          });\n        }\n      };\n    }\n\n    return component;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.OrderedList = function(items) {\n    this.isOrdered = false;\n    this._items = items || [];\n\n    this.add = function(key, item, order) {\n      this._items.push({\n        key: key,\n        item: item,\n\n        after: Misago.get(order, 'after'),\n        before: Misago.get(order, 'before')\n      });\n    };\n\n    this.get = function(key, value) {\n      for (var i = 0; i < this._items.length; i++) {\n        if (this._items[i].key === key) {\n          return this._items[i].item;\n        }\n      }\n\n      return value;\n    };\n\n    this.has = function(key) {\n      return this.get(key) !== undefined;\n    };\n\n    this.values = function() {\n      var values = [];\n      for (var i = 0; i < this._items.length; i++) {\n        values.push(this._items[i].item);\n      }\n      return values;\n    };\n\n    this.order = function(values_only) {\n      if (!this.isOrdered) {\n        this._items = this._order(this._items);\n        this.isOrdered = true;\n      }\n\n      if (values_only || typeof values_only === 'undefined') {\n        return this.values();\n      } else {\n        return this._items;\n      }\n    };\n\n    this._order = function(unordered) {\n      // Index of unordered items\n      var index = [];\n      unordered.forEach(function (item) {\n        index.push(item.key);\n      });\n\n      // Ordered items\n      var ordered = [];\n      var ordering = [];\n\n      // First pass: register items that\n      // don't specify their order\n      unordered.forEach(function (item) {\n        if (!item.after && !item.before) {\n          ordered.push(item);\n          ordering.push(item.key);\n        }\n      });\n\n      // Second pass: register items that\n      // specify their before to \"_end\"\n      unordered.forEach(function (item) {\n        if (item.before === \"_end\") {\n          ordered.push(item);\n          ordering.push(item.key);\n        }\n      });\n\n      // Third pass: keep iterating items\n      // until we hit iterations limit or finish\n      // ordering list\n      function insertItem(item) {\n        var insertAt = -1;\n        if (ordering.indexOf(item.key) === -1) {\n          if (item.after) {\n            insertAt = ordering.indexOf(item.after);\n            if (insertAt !== -1) {\n              insertAt += 1;\n            }\n          } else if (item.before) {\n            insertAt = ordering.indexOf(item.before);\n          }\n\n          if (insertAt !== -1) {\n            ordered.splice(insertAt, 0, item);\n            ordering.splice(insertAt, 0, item.key);\n          }\n        }\n      }\n\n      var iterations = 200;\n      while (iterations > 0 && index.length !== ordering.length) {\n        iterations -= 1;\n        unordered.forEach(insertItem);\n      }\n\n      return ordered;\n    };\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.Page = function(name, _) {\n    var self = this;\n\n    this.name = name;\n    this.isFinalized = false;\n    this._sections = [];\n\n    var finalize = function() {\n      if (!self.isFinalized) {\n        self.isFinalized = true;\n\n        var visible = [];\n        self._sections.forEach(function (item) {\n          if (!item.visibleIf || item.visibleIf(_)) {\n            visible.push(item);\n          }\n        });\n        self._sections = new Misago.OrderedList(visible).order(true);\n      }\n    };\n\n    this.addSection = function(section) {\n      if (this.isFinalized) {\n        throw (this.name + \" page was initialized already and no longer accepts new sections\");\n      }\n\n      this._sections.push({\n        key: section.link,\n        item: section,\n\n        after: section.after,\n        before: section.before\n      });\n    };\n\n    this.getSections = function() {\n      finalize();\n      return this._sections;\n    };\n\n    this.getDefaultLink = function() {\n      finalize();\n      return this._sections[0].link;\n    };\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  Misago.serializeDatetime = function(serialized) {\n    return serialized ? serialized.format() : null;\n  };\n\n  Misago.deserializeDatetime = function(deserialized) {\n    return deserialized ? moment(deserialized) : null;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.startsWith = function(string, beginning) {\n    return string.indexOf(beginning) === 0;\n  };\n\n  Misago.endsWith = function(string, tail) {\n    return string.indexOf(tail, string.length - tail.length) !== -1;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.UrlConf = function() {\n    var self = this;\n    this._patterns = [];\n\n    this.patterns = function() {\n      return this._patterns;\n    };\n\n    var prefixPattern = function(prefix, pattern) {\n      return (prefix + pattern).replace('//', '/');\n    };\n\n    var include = function(prefix, patterns) {\n      for (var i = 0; i < patterns.length; i ++) {\n        self.url(prefixPattern(prefix, patterns[i].pattern),\n                 patterns[i].component,\n                 patterns[i].name);\n      }\n    };\n\n    this.url = function(pattern, component, name) {\n      if (pattern === '') {\n        pattern = '/';\n      }\n\n      if (component instanceof Misago.UrlConf) {\n        include(pattern, component.patterns());\n      } else {\n        this._patterns.push({\n          pattern: pattern,\n          component: component.replace(/_/g, '-'),\n          name: name || component\n        });\n      }\n    };\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.loadingPage = function(_) {\n    return m('.page.page-loading',\n      _.component('loader')\n    );\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var getCsrfToken = function(cookie_name) {\n    if (document.cookie.indexOf(cookie_name) !== -1) {\n      var cookieRegex = new RegExp(cookie_name + '\\=([^;]*)');\n      var cookie = Misago.get(document.cookie.match(cookieRegex), 0);\n      return cookie.split('=')[1];\n    } else {\n      return null;\n    }\n  };\n\n  var Ajax = function(_) {\n    this.refreshCsrfToken = function() {\n      this.csrfToken = getCsrfToken(_.context.CSRF_COOKIE_NAME);\n    };\n    this.refreshCsrfToken();\n\n    /*\n      List of GETs underway\n      We are limiting number of GETs to API to 1 per url\n    */\n    var runningGets = {};\n\n    this.ajax = function(method, url, data, progress) {\n      var promise = m.deferred();\n\n      var ajax_settings = {\n        url: url,\n        method: method,\n        headers: {\n          'X-CSRFToken': this.csrfToken\n        },\n\n        data: data || {},\n        dataType: 'json',\n\n        success: function(data) {\n          if (method === 'GET') {\n            Misago.pop(runningGets, url);\n          }\n          promise.resolve(data);\n        },\n        error: function(jqXHR) {\n          if (method === 'GET') {\n            Misago.pop(runningGets, url);\n          }\n\n          var rejection = jqXHR.responseJSON || {};\n\n          rejection.status = jqXHR.status;\n          rejection.statusText = jqXHR.statusText;\n\n          promise.reject(rejection);\n        }\n      };\n\n      if (progress) {\n        return; // not implemented... yet!\n      }\n\n      $.ajax(ajax_settings);\n      return promise.promise;\n    };\n\n    this.get = function(url) {\n      var preloaded = Misago.pop(_.context, url);\n      if (preloaded) {\n        var deferred = m.deferred();\n        deferred.resolve(preloaded);\n        return deferred.promise;\n      } else if (runningGets[url] !== undefined) {\n        return runningGets[url];\n      } else {\n        runningGets[url] = this.ajax('GET', url);\n        return runningGets[url];\n      }\n    };\n\n    this.post = function(url, data) {\n      return this.ajax('POST', url, data);\n    };\n\n    this.patch = function(url, data) {\n      return this.ajax('PATCH', url, data);\n    };\n\n    this.put = function(url, data) {\n      return this.ajax('PUT', url, data);\n    };\n\n    this.delete = function(url) {\n      return this.ajax('DELETE', url);\n    };\n  };\n\n  Misago.addService('ajax', function(_) {\n    return new Ajax(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var ALERT_BASE_DISPLAY_TIME = 5 * 1000;\n  var ALERT_LENGTH_FACTOR = 70;\n  var ALERT_MAX_DISPLAY_TIME = 9 * 1000;\n  var ALERT_HIDE_ANIMATION_LENGTH = 300;\n\n  var Alert = function(_) {\n    var self = this;\n\n    this.type = '';\n    this.message = null;\n    this.isVisible = false;\n\n    var show = function(type, message) {\n      self.type = type;\n      self.message = message;\n      self.isVisible = true;\n\n      var displayTime = ALERT_BASE_DISPLAY_TIME;\n      displayTime += message.length * ALERT_LENGTH_FACTOR;\n      if (displayTime > ALERT_MAX_DISPLAY_TIME) {\n        displayTime = ALERT_MAX_DISPLAY_TIME;\n      }\n\n      _.runloop.runOnce(function () {\n        m.startComputation();\n        self.isVisible = false;\n        m.endComputation();\n      }, 'flash-message-hide', displayTime);\n    };\n\n    var set = function(type, message) {\n      _.runloop.stop('flash-message-hide');\n      _.runloop.stop('flash-message-show');\n\n      if (self.isVisible) {\n        self.isVisible = false;\n        _.runloop.runOnce(function () {\n          m.startComputation();\n          show(type, message);\n          m.endComputation();\n        }, 'flash-message-show', ALERT_HIDE_ANIMATION_LENGTH);\n      } else {\n        show(type, message);\n      }\n    };\n\n    this.info = function(message) {\n      set('info', message);\n    };\n\n    this.success = function(message) {\n      set('success', message);\n    };\n\n    this.warning = function(message) {\n      set('warning', message);\n    };\n\n    this.error = function(message) {\n      set('error', message);\n    };\n  };\n\n  Misago.addService('alert', {\n    factory: function(_) {\n      return new Alert(_);\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var filtersUrl = function(filters) {\n    if (typeof filters === 'object') {\n      var values = [];\n      for (var key in filters) {\n        if (filters.hasOwnProperty(key)) {\n          var encodedKey = encodeURIComponent(key);\n          var encodedValue = encodeURIComponent(filters[key]);\n          values.push(encodedKey + '=' + encodedValue);\n        }\n      }\n      return '?' + values.join('&');\n    } else {\n      return filters + '/';\n    }\n  };\n\n  var Query = function(_, call) {\n    this.url = call.url || _.setup.api;\n\n    if (call.path) {\n      this.url += call.path + '/';\n    } else if (call.related) {\n      this.url += call.related + '/';\n    } else {\n      this.url += call.model + 's' + '/';\n    }\n\n    if (call.filters) {\n      this.url += filtersUrl(call.filters);\n    }\n\n    if (call.model) {\n      this.related = function(model, filters) {\n        return new Query(_, {\n          url: this.url,\n          relation: call.model,\n          related: model,\n          filters: filters,\n        });\n      };\n    }\n\n    this.endpoint = function(path, filters) {\n      return new Query(_, {\n        url: this.url,\n        path: path,\n        filters: filters\n      });\n    };\n\n    this.get = function() {\n      var model = null;\n      if (call.related) {\n        model = call.relation + ':' + call.related;\n      } else if (call.model) {\n        model = call.model;\n      }\n\n      return _.ajax.get(this.url).then(function(data) {\n        if (model) {\n          if (data.results) {\n            data.results.map(function(item) {\n              return _.models.new(model, item);\n            });\n            return data;\n          } else {\n            return _.models.new(model, data);\n          }\n        } else {\n          return data;\n        }\n      });\n    };\n\n    this.post = function(data) {\n      return _.ajax.post(this.url, data);\n    };\n\n    this.patch = function(data) {\n      return _.ajax.patch(this.url, data);\n    };\n\n    this.put = function(data) {\n      return _.ajax.put(this.url, data);\n    };\n\n    this.delete = function() {\n      return _.ajax.delete(this.url);\n    };\n\n    // shortcut for get()\n    this.then = function(resolve, reject) {\n      return this.get().then(resolve, reject);\n    };\n  };\n\n  var Api = function(_) {\n    this.model = function(model, filters) {\n      return new Query(_, {\n        model: model,\n        filters: filters,\n      });\n    };\n\n    this.endpoint = function(path, filters) {\n      return new Query(_, {\n        path: path,\n        filters: filters\n      });\n    };\n\n    this.alert = function(rejection) {\n      // Shorthand for API errors\n      var message = gettext(\"Unknown error has occured.\");\n\n      if (rejection.status === 0) {\n        message = gettext(\"Lost connection with application.\");\n      }\n\n      if (rejection.status === 403) {\n        message = rejection.detail;\n        if (message === \"Permission denied\") {\n          message = gettext(\n            \"You don't have permission to perform this action.\");\n        }\n      }\n\n      if (rejection.status === 404) {\n        message = gettext(\"Action link is invalid.\");\n      }\n\n      _.alert.error(message);\n    };\n  };\n\n  Misago.addService('api', function(_) {\n    return new Api(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Auth = function(_) {\n    var self = this;\n\n    _.user = _.models.deserialize('user', _.context.user);\n\n    // Auth state synchronization across tabs\n    this.isDesynced = false; // becomes true if auth state between tabs differs\n    this.newUser = null; // becomes user obj to which we want to sync\n\n    var handleAuthChange = function(isAuthenticated) {\n      if (!self.isDesynced) {\n        m.startComputation();\n\n        // display annoying \"you were desynced\" message\n        self.isDesynced = true;\n\n        if (isAuthenticated) {\n          self.newUser = _.localstore.get('auth-user');\n        }\n\n        m.endComputation();\n      }\n    };\n\n    var handleUserChange = function(newUser) {\n      if (!self.isDesynced) {\n        m.startComputation();\n\n        if (_.user.id !== newUser.id) {\n          self.isDesynced = true;\n          self.newUser = newUser;\n        } else if (newUser) {\n          _.user = $.extend(_.user, newUser);\n        }\n\n        m.endComputation();\n      }\n    };\n\n    var syncSession = function() {\n      _.localstore.set('auth-user', _.user);\n      _.localstore.set('auth-is-authenticated', _.user.isAuthenticated);\n\n      _.localstore.watch('auth-is-authenticated', handleAuthChange);\n      _.localstore.watch('auth-user', handleUserChange);\n    };\n\n    syncSession();\n\n    // Access controls\n    this.denyAuthenticated = function(message) {\n      if (_.user.isAuthenticated) {\n        throw new Misago.PermissionDenied(\n          message || gettext(\"This page is not available to signed in users.\"));\n      }\n    };\n\n    this.denyAnonymous = function(message) {\n      if (_.user.isAnonymous) {\n        throw new Misago.PermissionDenied(\n          message || gettext(\"This page is not available to guests.\"));\n      }\n    };\n  };\n\n  Misago.addService('auth',\n  function(_) {\n    return new Auth(_);\n  },\n  {\n    after: 'model:user'\n  });\n}(Misago.prototype));\n\n/* global grecaptcha */\n(function (Misago) {\n  'use strict';\n\n  var NoCaptcha = function() {\n    var deferred = m.deferred();\n    deferred.resolve();\n\n    this.load = function() {\n      return deferred.promise;\n    };\n\n    this.value = function() {\n      return null;\n    };\n  };\n\n  var QACaptcha = function(_) {\n    var self = this;\n\n    this.loading = false;\n    this.question = null;\n    this.value = m.prop('');\n\n    var deferred = m.deferred();\n    this.load = function() {\n      this.value('');\n\n      if (!this.question && !this.loading) {\n        this.loading = true;\n\n        _.api.endpoint('captcha-question').get().then(function(question) {\n          self.question = question;\n          deferred.resolve();\n        }, function() {\n          _.api.alert(gettext('Failed to load CAPTCHA.'));\n          deferred.reject();\n        }).then(function() {\n          self.loading = true;\n        });\n      }\n\n      return deferred.promise;\n    };\n\n    this.component = function(kwargs) {\n      return _.component('form-group', {\n        label: this.question.question,\n        labelClass: kwargs.labelClass || null,\n        controlClass: kwargs.controlClass || null,\n        control: _.input({\n          value: _.validate(kwargs.form, 'captcha'),\n          id: 'id_captcha',\n          disabled: kwargs.form.isBusy\n        }),\n        validation: kwargs.form.errors,\n        validationKey: 'captcha',\n        helpText: this.question.help_text\n      });\n    };\n\n    this.validator = function() {\n      return [];\n    };\n  };\n\n  var ReCaptcha = function(_) {\n    this.included = false;\n    this.question = null;\n\n    var deferred = m.deferred();\n\n    var wait = function(promise) {\n      if (typeof grecaptcha !== \"undefined\") {\n        promise.resolve();\n      } else {\n        _.runloop.runOnce(function() {\n          wait(promise);\n        }, 'loading-grecaptcha', 150);\n      }\n    };\n\n    this.load = function() {\n      if (typeof grecaptcha !== \"undefined\") {\n        grecaptcha.reset();\n      }\n\n      if (!this.included) {\n        _.include('https://www.google.com/recaptcha/api.js', true);\n        this.included = true;\n      }\n\n      wait(deferred);\n\n      return deferred.promise;\n    };\n\n    var controlConfig = function(el, isInit, context) {\n      context.retain = true;\n\n      if (!isInit) {\n        grecaptcha.render('recaptcha', {\n          'sitekey': _.settings.recaptcha_site_key\n        });\n      }\n    };\n\n    this.component = function(kwargs) {\n      var control = m('#recaptcha', {\n        config: controlConfig\n      });\n\n      return _.component('form-group', {\n        label: gettext(\"Security test\"),\n        labelClass: kwargs.labelClass || null,\n        controlClass: kwargs.controlClass || null,\n        control: control,\n        validation: kwargs.form.errors,\n        validationKey: 'captcha'\n      });\n    };\n\n    this.value = function() {\n      if (typeof grecaptcha !== \"undefined\") {\n        return grecaptcha.getResponse();\n      } else {\n        return '';\n      }\n    };\n\n    this.clean = function(form) {\n      if (!this.value()) {\n        form.errors.captcha = [\n          gettext('This field is required.')\n        ];\n      } else {\n        form.errors.captcha = true;\n      }\n    };\n\n    this.validator = function() {\n      return [];\n    };\n  };\n\n  var Captcha = function(_) {\n    var types = {\n      'no': NoCaptcha,\n      'qa': QACaptcha,\n      're': ReCaptcha\n    };\n\n    var captcha = new types[_.settings.captcha_type](_);\n\n    this.value = captcha.value;\n\n    this.load = function() {\n      return captcha.load();\n    };\n\n    this.component = function(kwargs) {\n      if (captcha.component) {\n        return captcha.component(kwargs);\n      } else {\n        return null;\n      }\n    };\n\n    this.validator = function() {\n      if (captcha.validator) {\n        return captcha.validator();\n      } else {\n        return null;\n      }\n    };\n\n    this.clean = function(form) {\n      if (captcha.clean) {\n        captcha.clean(form);\n      } else {\n        form.errors.captcha = true;\n      }\n    };\n  };\n\n  Misago.addService('captcha', function(_) {\n    return new Captcha(_);\n  },\n  {\n    after: 'include'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var component = function(name, component) {\n    if (this._components[name]) {\n      if (arguments.length > 1) {\n        var argumentsArray = [this._components[name]];\n        for (var i = 1; i < arguments.length; i += 1) {\n          argumentsArray.push(arguments[i]);\n        }\n        argumentsArray.push(this);\n        return m.component.apply(undefined, argumentsArray);\n      } else {\n        return m.component(this._components[name], this);\n      }\n    } else if (component) {\n      this._components[name] = component;\n    } else {\n      throw '\"' + name + '\" component is not registered and can\\'t be created';\n    }\n  };\n\n  Misago.addService('components', function(_) {\n    _._components = {};\n    _.component = component;\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('conf', function(_) {\n    _.settings = Misago.get(_.context, 'SETTINGS', {});\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Dropdown = function(_) {\n    var slots = {};\n\n    this.toggle = function(elementId, component) {\n      var element = document.getElementById(elementId);\n\n      if (element.hasChildNodes() && slots[elementId] === component) {\n        slots[elementId] = null;\n        m.mount(element, null);\n        $(element).removeClass('open');\n      } else {\n        console.log(element.hasChildNodes());\n        slots[elementId] = component;\n        m.mount(element, _.component(component));\n        $(element).addClass('open');\n      }\n    };\n\n    this.destroy = function() {\n      var element = null;\n\n      for (var elementId in slots) {\n        if (slots.hasOwnProperty(elementId)) {\n          element = document.getElementById(elementId);\n          if (element && element.hasChildNodes()) {\n            m.mount(element, null);\n          }\n        }\n      }\n    };\n  };\n\n  Misago.addService('dropdown', {\n    factory: function(_) {\n      return new Dropdown(_);\n    },\n    destroy: function(_) {\n      _.dropdown.destroy();\n    }\n  },\n  {\n    before: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var boilerplate = function(form) {\n    var _submit = form.submit;\n    var _success = form.success;\n    var _error = form.error;\n\n    form.isBusy = false;\n\n    form.errors = null;\n\n    form.submit = function() {\n      if (form.isBusy) {\n        return false;\n      }\n\n      if (form.clean) {\n        if (form.clean()) {\n          form.isBusy = true;\n          _submit.apply(form);\n        }\n      } else {\n        form.isBusy = true;\n      }\n      return false;\n    };\n\n    form.success = function() {\n      m.startComputation();\n\n      _success.apply(form, arguments);\n      form.isBusy = false;\n\n      m.endComputation();\n    };\n\n    form.error = function() {\n      m.startComputation();\n\n      _error.apply(form, arguments);\n      form.isBusy = false;\n\n      m.endComputation();\n    };\n\n    form.hasErrors = function() {\n      if (form.errors === null) {\n        return false;\n      }\n\n      for (var key in form.validation) {\n        if (form.validation.hasOwnProperty(key)) {\n          if (form.errors[key] !== true) {\n            return true;\n          }\n        }\n      }\n\n      return false;\n    };\n\n    return form;\n  };\n\n  var form = function(name, constructor) {\n    if (this._forms[name]) {\n      if (constructor) {\n        return boilerplate(new this._forms[name](constructor, this));\n      } else {\n        return boilerplate(new this._forms[name](this));\n      }\n    } else {\n      this._forms[name] = constructor;\n    }\n  };\n\n  Misago.addService('forms', function(_) {\n    _._forms = {};\n    _.form = form;\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var include = function(script, remote) {\n    if (!remote) {\n      script = this.context.STATIC_URL + script;\n    }\n\n    $.ajax({\n      url: script,\n      cache: true,\n      dataType: 'script'\n    });\n  };\n\n  Misago.addService('include', function(_) {\n    _.include = include;\n  },\n  {\n    after: 'conf'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var setLinks = function(_) {\n    _.baseUrl = $('base').attr('href');\n\n    var staticUrl = Misago.get(_.context, 'STATIC_URL', '/');\n    var mediaUrl = Misago.get(_.context, 'MEDIA_URL', '/');\n\n    // Media/Static urls\n    var prefixUrl = function(prefix) {\n      return function(url) {\n        return prefix + url;\n      };\n    };\n\n    _.staticUrl = prefixUrl(staticUrl);\n    _.mediaUrl = prefixUrl(mediaUrl);\n  };\n\n  Misago.addService('links', function(_) {\n    setLinks(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var LocalStore = function() {\n    var storage = window.localStorage;\n    var prefix = '_misago_';\n    var watchers = [];\n\n    var handleStorageEvent = function(e) {\n      var newValueJson = JSON.parse(e.newValue);\n      $.each(watchers, function(i, watcher) {\n        if (watcher.keyName === e.key && e.oldValue !== e.newValue) {\n          watcher.callback(newValueJson);\n        }\n      });\n    };\n\n    window.addEventListener('storage', handleStorageEvent);\n\n    var prefixKey = function(keyName) {\n      return prefix + keyName;\n    };\n\n    this.set = function(keyName, value) {\n      storage.setItem(prefixKey(keyName), JSON.stringify(value));\n    };\n\n    this.get = function(keyName) {\n      var itemString = storage.getItem(prefixKey(keyName));\n      if (itemString) {\n        return JSON.parse(itemString);\n      } else {\n        return null;\n      }\n    };\n\n    this.watch = function(keyName, callback) {\n      watchers.push({keyName: prefixKey(keyName), callback: callback});\n    };\n\n    this.destroy = function() {\n      this.watchers = [];\n    };\n  };\n\n  Misago.addService('localstore', {\n    factory: function() {\n      return new LocalStore();\n    },\n    destroy: function(_) {\n      _.localstore.destroy();\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Modal = function() {\n    var self = this;\n\n    var element = document.getElementById('misago-modal');\n\n    this.destroy = function() {\n      $(element).off();\n      $('body').removeClass('modal-open');\n      $('.modal-backdrop').remove();\n    };\n\n    // Open/close modal\n    var modal = $(element).modal({show: false});\n    this.open = false;\n\n    modal.on('hidden.bs.modal', function () {\n      if (self.open) {\n        m.mount(element, null);\n        this.open = false;\n      }\n    });\n\n    this.show = function(component) {\n      this.open = true;\n      m.mount(element, component);\n      modal.modal('show');\n    };\n\n    this.hide = function() {\n      modal.modal('hide');\n    };\n  };\n\n  Misago.addService('_modal', {\n    factory: function() {\n      return new Modal();\n    },\n    destroy: function(_) {\n      _._modal.destroy();\n    }\n  },\n  {\n    before: 'mount:page-component'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var modal = function(name, component) {\n    if (this._modals[name]) {\n      var argumentsArray = [this._modals[name]];\n      for (var i = 1; i < arguments.length; i += 1) {\n        argumentsArray.push(arguments[i]);\n      }\n      argumentsArray.push(this);\n      this._modal.show(m.component.apply(m, argumentsArray));\n    } else if (name) {\n      this._modals[name] = component;\n    } else {\n      this._modal.hide();\n    }\n  };\n\n  Misago.addService('modals', function(_) {\n    _._modals = {};\n    _.modal = modal;\n  },\n  {\n    after: '_modal'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Models = function() {\n    this.classes = {};\n    this.deserializers = {};\n\n    this.add = function(name, kwargs) {\n      if (kwargs.class) {\n        this.classes[name] = kwargs.class;\n      }\n\n      if (kwargs.deserialize) {\n        this.deserializers[name] = kwargs.deserialize;\n      }\n    };\n\n    this.new = function(name, data) {\n      if (this.classes[name]) {\n        // Coerce ID to string\n        // This is done to avoid type comparisions gotchas\n        // later into app\n        data.id = data.id ? String(data.id) : null;\n\n        return new this.classes[name](data);\n      } else {\n        return data;\n      }\n    };\n\n    this.deserialize = function(name, json) {\n      if (this.deserializers[name]) {\n        return this.new(name, this.deserializers[name](json, this));\n      } else {\n        return this.new(name, json);\n      }\n    };\n  };\n\n  Misago.addService('models', function() {\n    return new Models();\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('set-momentjs-locale', function() {\n    moment.locale($('html').attr('lang'));\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var RunLoop = function(_) {\n    var self = this;\n\n    this._intervals = {};\n\n    var stopInterval = function(name) {\n      if (self._intervals[name]) {\n        window.clearTimeout(self._intervals[name]);\n        self._intervals[name] = null;\n      }\n    };\n\n    this.run = function(callable, name, delay) {\n      this._intervals[name] = window.setTimeout(function() {\n        stopInterval(name);\n        var result = callable(_);\n        if (result !== false) {\n          self.run(callable, name, delay);\n        }\n      }, delay);\n    };\n\n    this.runOnce = function(callable, name, delay) {\n      this._intervals[name] = window.setTimeout(function() {\n        stopInterval(name);\n        callable(_);\n      }, delay);\n    };\n\n    this.stop = function(name) {\n      for (var loop in this._intervals) {\n        if (!name || name === loop) {\n          stopInterval(loop);\n        }\n      }\n    };\n  };\n\n  Misago.addService('runloop', {\n    factory: function(_) {\n      return new RunLoop(_);\n    },\n    destroy: function(_) {\n      _.runloop.stop();\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mount = document.getElementById('misago-page-mount');\n\n  Misago.addService('show-banned-page', function(_) {\n    _.showBannedPage = function(ban) {\n      var component = _.component(\n        'banned-page', _.models.deserialize('ban', ban));\n\n      _.title.set(gettext('You are banned'));\n      window.history.pushState({}, \"\", _.context.BANNED_URL);\n      m.mount(mount, component);\n    };\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('start-tick', function(_) {\n    var ticks = m.prop();\n\n    _.runloop.run(function() {\n      m.startComputation();\n      // just tick once a minute so stuff gets rerendered\n      ticks(ticks() + 1);\n      // syncing dynamic timestamps, etc ect\n      m.endComputation();\n    }, 'tick', 60000);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var PageTitle = function(forum_name) {\n    this.set = function(title) {\n      if (title) {\n        this._set_complex(title);\n      } else {\n        document.title = forum_name;\n      }\n    };\n\n    this._set_complex = function(title) {\n      if (typeof title === 'string') {\n        title = {title: title};\n      }\n\n      var completeTitle = title.title;\n\n      if (typeof title.page !== 'undefined' && title.page > 1) {\n        var page_label = interpolate(\n          gettext('page %(page)s'), { page:title.page }, true);\n        completeTitle += ' (' + page_label + ')';\n      }\n\n      if (typeof title.parent !== 'undefined') {\n        completeTitle += ' | ' + title.parent;\n      }\n\n      document.title = completeTitle + ' | ' + forum_name;\n    };\n  };\n\n  Misago.addService('page-title', function(_) {\n    _.title = new PageTitle(_.settings.forum_name);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var EMAIL = /^(([^<>()[\\]\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@(([^<>()[\\]\\.,;:\\s@\\\"]+\\.)+[^<>()[\\]\\.,;:\\s@\\\"]{2,})$/i;\n  var USERNAME = new RegExp('^[0-9a-z]+$', 'i');\n\n  // Validators namespace\n  Misago.validators = {\n    required: function() {\n      return function(value) {\n        if ($.trim(value).length === 0) {\n          return gettext(\"This field is required.\");\n        }\n      };\n    },\n    email: function(message) {\n      return function(value) {\n        if (!EMAIL.test(value)) {\n          return message || gettext(\"Enter a valid email address.\");\n        }\n      };\n    },\n    minLength: function(limit_value, message) {\n      return function(value) {\n        var returnMessage = '';\n        var length = $.trim(value).length;\n\n        if (length < limit_value) {\n          if (message) {\n            returnMessage = message(limit_value, length);\n          } else {\n            returnMessage = ngettext(\n              \"Ensure this value has at least %(limit_value)s character (it has %(show_value)s).\",\n              \"Ensure this value has at least %(limit_value)s characters (it has %(show_value)s).\",\n              limit_value);\n          }\n          return interpolate(returnMessage, {\n            limit_value: limit_value,\n            show_value: length\n          }, true);\n        }\n      };\n    },\n    maxLength: function(limit_value, message) {\n      return function(value) {\n        var returnMessage = '';\n        var length = $.trim(value).length;\n\n        if (length > limit_value) {\n          if (message) {\n            returnMessage = message(limit_value, length);\n          } else {\n            returnMessage = ngettext(\n              \"Ensure this value has at most %(limit_value)s character (it has %(show_value)s).\",\n              \"Ensure this value has at most %(limit_value)s characters (it has %(show_value)s).\",\n              limit_value);\n          }\n          return interpolate(returnMessage, {\n            limit_value: limit_value,\n            show_value: length\n          }, true);\n        }\n      };\n    },\n    usernameMinLength: function(settings) {\n      var message = function(limit_value) {\n        return ngettext(\n          \"Username must be at least %(limit_value)s character long.\",\n          \"Username must be at least %(limit_value)s characters long.\",\n          limit_value);\n      };\n      return this.minLength(settings.username_length_min, message);\n    },\n    usernameMaxLength: function(settings) {\n      var message = function(limit_value) {\n        return ngettext(\n          \"Username cannot be longer than %(limit_value)s character.\",\n          \"Username cannot be longer than %(limit_value)s characters.\",\n          limit_value);\n      };\n      return this.maxLength(settings.username_length_max, message);\n    },\n    usernameContent: function() {\n      return function(value) {\n        if (!USERNAME.test($.trim(value))) {\n          return gettext(\"Username can only contain latin alphabet letters and digits.\");\n        }\n      };\n    },\n    passwordMinLength: function(settings) {\n      var message = function(limit_value) {\n        return ngettext(\n          \"Valid password must be at least %(limit_value)s character long.\",\n          \"Valid password must be at least %(limit_value)s characters long.\",\n          limit_value);\n      };\n      return this.minLength(settings.password_length_min, message);\n    }\n  };\n\n  var validateField = function(value, validators) {\n    var result = Misago.validators.required()(value);\n    var errors = [];\n\n    if (result) {\n      return [result];\n    } else {\n      for (var i in validators) {\n        result = validators[i](value);\n\n        if (result) {\n          errors.push(result);\n        }\n      }\n    }\n\n    return errors.length ? errors : true;\n  };\n\n  var validateForm = function(form) {\n    var errors = {};\n    var value = null;\n\n    var isValid = true;\n\n    for (var key in form.validation) {\n      if (form.validation.hasOwnProperty(key)) {\n        value = form[key]();\n        errors[key] = validateField(form[key](), form.validation[key]);\n        if (errors[key] !== true) {\n          isValid = false;\n        }\n      }\n    }\n\n    form.errors = errors;\n    return isValid;\n  };\n\n  var validate = function(form, name) {\n    if (name) {\n      return function(value) {\n        var errors = null;\n        if (typeof value !== 'undefined') {\n          errors = validateField(value, form.validation[name]);\n          if (errors) {\n            if (!form.errors) {\n              form.errors = {};\n            }\n            form.errors[name] = errors;\n          }\n          form[name](value);\n          return form[name](value);\n        } else {\n          return form[name]();\n        }\n      };\n    } else {\n      return validateForm(form);\n    }\n  };\n\n  Misago.addService('validate', {\n    factory: function() {\n      return validate;\n    }\n  });\n}(Misago.prototype));\n\n/* global zxcvbn */\n(function (Misago) {\n  'use strict';\n\n  var Zxcvbn = function(_) {\n    this.included = false;\n\n    this.scorePassword = function(password, inputs) {\n      // 0-4 score, the more the stronger password\n      return zxcvbn(password, inputs).score;\n    };\n\n    // loading\n    this.include = function() {\n      _.include('misago/js/zxcvbn.js');\n      this.included = true;\n    };\n\n    var wait = function(promise) {\n      if (typeof zxcvbn !== \"undefined\") {\n        promise.resolve();\n      } else {\n        _.runloop.runOnce(function() {\n          wait(promise);\n        }, 'loading-zxcvbn', 150);\n      }\n    };\n\n    var deferred = m.deferred();\n    this.load = function() {\n      if (!this.included) {\n        this.include();\n      }\n      wait(deferred);\n      return deferred.promise;\n    };\n  };\n\n  Misago.addService('zxcvbn', function(_) {\n    return new Zxcvbn(_);\n  },\n  {\n    after: 'include'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Ban = function(data) {\n    this.message = {\n      html: data.message.html,\n      plain: data.message.plain,\n    };\n\n    this.expires_on = data.expires_on;\n  };\n\n  var deserializeBan = function(data) {\n    data.expires_on = Misago.deserializeDatetime(data.expires_on);\n\n    return data;\n  };\n\n  Misago.addService('model:ban', function(_) {\n    _.models.add('ban', {\n      class: Ban,\n      deserialize: deserializeBan\n    });\n  },\n  {\n    after: 'models'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var LegalPage = function(data) {\n    this.title = data.title;\n    this.body = data.body;\n    this.link = data.link;\n  };\n\n  Misago.addService('model:legal-page', function(_) {\n    _.models.add('legal-page', {\n      class: LegalPage\n    });\n  },\n  {\n    after: 'models'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Rank = function(data) {\n    this.id = data.id;\n\n    this.name = data.name;\n    this.slug = data.slug;\n\n    this.description = data.description;\n\n    this.title = data.title;\n    this.css_class = data.css_class;\n\n    this.is_tab = data.is_tab;\n  };\n\n  Misago.addService('model:rank', function(_) {\n    _.models.add('rank', {\n      class: Rank\n    });\n  },\n  {\n    after: 'models'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var User = function(data) {\n    this.id = data.id;\n\n    this.isAuthenticated = !!this.id;\n    this.isAnonymous = !this.isAuthenticated;\n\n    this.username = data.username;\n    this.slug = data.slug;\n\n    this.email = data.email;\n\n    this.full_title = data.full_title;\n    this.rank = data.rank;\n\n    this.avatar_hash = data.avatar_hash;\n\n    this.acl = data.acl;\n\n    this.absolute_url = data.absolute_url;\n  };\n\n  var deserializeUser = function(data, models) {\n    if (data.joined_on) {\n      data.joined_on = Misago.deserializeDatetime(data.joined_on);\n    }\n\n    if (data.rank) {\n      data.rank = models.deserialize('rank', data.rank);\n    }\n\n    return data;\n  };\n\n  Misago.addService('model:user', function(_) {\n    _.models.add('user', {\n      class: User,\n      deserialize: deserializeUser\n    });\n  },\n  {\n    after: 'model:rank'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var form = {\n    view: function(ctrl, form, _) {\n      return m('.well.well-form',\n        m('form', {onsubmit: form.submit}, [\n          m('.form-group',\n            m('.control-input',\n              Misago.input({\n                disabled: form.isBusy,\n                value: form.email,\n                placeholder: gettext(\"Your e-mail address\")\n              })\n            )\n          ),\n          _.component('button', {\n            class: '.btn-primary.btn-block',\n            submit: true,\n            loading: form.isBusy,\n            label: gettext(\"Send link\")\n          })\n        ])\n      );\n    }\n  };\n\n  Misago.addService('component:request-link-form', function(_) {\n    _.component('request-link-form', form);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var header = {\n    view: function(ctrl, title) {\n      return m('.modal-header', [\n        m('button.close[type=\"button\"]',\n          {'data-dismiss': 'modal', 'aria-label': gettext('Close')},\n          m('span', {'aria-hidden': 'true'}, m.trust('&times;'))\n        ),\n        m('h4#misago-modal-label.modal-title', title)\n      ]);\n    }\n  };\n\n  Misago.addService('component:modal:header', function(_) {\n    _.component('modal:header', header);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  var refresh = function() {\n    document.location.reload();\n  };\n\n  var registerComplete = {\n    controller: function(message, _) {\n      if (message.activation === 'active') {\n        _.runloop.runOnce(\n          refresh, 'refresh-after-registration', 10000);\n      }\n    },\n    view: function(ctrl, message, _) {\n      var messageHtml = null;\n\n      if (message.activation === 'active') {\n        messageHtml = this.active(message);\n      } else {\n        messageHtml = this.inactive(message);\n      }\n\n      return m('.modal-dialog.modal-message.modal-register[role=\"document\"]',\n        {config: persistent},\n        m('.modal-content', [\n          _.component('modal:header', gettext('Registration complete')),\n          m('.modal-body',\n            messageHtml\n          )\n        ])\n      );\n    },\n    active: function(message) {\n      var lead = gettext(\"%(username)s, your account has been created and you were signed in.\");\n      return [\n        m('.message-icon',\n          m('span.material-icon', 'check')\n        ),\n        m('.message-body', [\n          m('p.lead',\n            interpolate(lead, {'username': message.username}, true)\n          ),\n          m('p',\n            gettext('The page will refresh automatically in 10 seconds.')\n          ),\n          m('p',\n            m('button[type=\"button\"].btn.btn-default', {onclick: refresh},\n              gettext('Refresh page')\n            )\n          )\n        ])\n      ];\n    },\n    inactive: function(message) {\n      var lead = null;\n      var help = null;\n\n      if (message.activation === 'user') {\n        lead = gettext(\"%(username)s, your account has been created but you need to activate it before you will be able to sign in.\");\n        help = gettext(\"We have sent an e-mail to %(email)s with link that you have to click to activate your account.\");\n      } else if (message.activation === 'admin') {\n        lead = gettext(\"%(username)s, your account has been created but board administrator will have to activate it before you will be able to sign in.\");\n        help = gettext(\"We will send an e-mail to %(email)s when this takes place.\");\n      }\n\n      return [\n        m('.message-icon',\n          m('span.material-icon', 'info_outline')\n        ),\n        m('.message-body', [\n          m('p.lead',\n            interpolate(lead, {'username': message.username}, true)\n          ),\n          m('p',\n            interpolate(help, {'email': message.email}, true)\n          )\n        ])\n      ];\n    }\n  };\n\n  Misago.addService('modal:register-complete', function(_) {\n    _.modal('register-complete', registerComplete);\n  },\n  {\n    after: 'modals'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  var register = {\n    controller: function(_) {\n      return {\n        form: _.form('register')\n      };\n    },\n    view: function(ctrl, _) {\n      var captcha = _.captcha.component({\n        form: ctrl.form,\n\n        labelClass: '.col-md-4',\n        controlClass: '.col-md-8'\n      });\n\n      var footnote = null;\n\n      if (_.context.TERMS_OF_SERVICE_URL) {\n        footnote = m('a', {href: _.context.TERMS_OF_SERVICE_URL},\n          m.trust(interpolate(gettext(\"By registering you agree to site's %(terms)s.\"), {\n            terms: '<strong>' + gettext(\"terms and conditions\") + '</strong>'\n          }, true))\n        );\n      }\n\n      return m('.modal-dialog.modal-form.modal-register[role=\"document\"]',\n        {config: persistent},\n        m('.modal-content', [\n          _.component('modal:header', gettext('Register')),\n          m('form.form-horizontal',\n          {\n            onsubmit: ctrl.form.submit\n          },\n          [\n            m('input[type=\"text\"]', {\n              name:'_username',\n              style: 'display: none'\n            }),\n            m('input[type=\"password\"]', {\n              name:'_password',\n              style: 'display: none'\n            }),\n            m('.modal-body', [\n              _.component('form-group', {\n                label: gettext(\"Username\"),\n                labelClass: '.col-md-4',\n                controlClass: '.col-md-8',\n                control: _.input({\n                  value: _.validate(ctrl.form, 'username'),\n                  id: 'id_username',\n                  disabled: ctrl.form.isBusy\n                }),\n                validation: ctrl.form.errors,\n                validationKey: 'username'\n              }),\n              _.component('form-group', {\n                label: gettext(\"E-mail\"),\n                labelClass: '.col-md-4',\n                controlClass: '.col-md-8',\n                control: _.input({\n                  value: _.validate(ctrl.form, 'email'),\n                  id: 'id_email',\n                  disabled: ctrl.form.isBusy\n                }),\n                validation: ctrl.form.errors,\n                validationKey: 'email'\n              }),\n              _.component('form-group', {\n                label: gettext(\"Password\"),\n                labelClass: '.col-md-4',\n                controlClass: '.col-md-8',\n                control: _.input({\n                  value: _.validate(ctrl.form, 'password'),\n                  type: 'password',\n                  id: 'id_password',\n                  disabled: ctrl.form.isBusy\n                }),\n                validation: ctrl.form.errors,\n                validationKey: 'password',\n                helpText: _.component('password-strength', {\n                  inputs: [\n                    ctrl.form.username(),\n                    ctrl.form.email()\n                  ],\n                  password: ctrl.form.password()\n                })\n              }),\n              captcha\n            ]),\n            m('.modal-footer', [\n              footnote,\n              _.component('button', {\n                class: '.btn-primary',\n                submit: true,\n                loading: ctrl.form.isBusy,\n                label: gettext(\"Register account\")\n              })\n            ])\n          ])\n        ])\n      );\n    }\n  };\n\n  Misago.addService('modal:register', function(_) {\n    _.modal('register', register);\n  },\n  {\n    after: 'modals'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  function persistent(el, isInit, context) {\n    context.retain = true;\n  }\n\n  var signin = {\n    controller: function(_) {\n      return {\n        form: _.form('sign-in')\n      };\n    },\n    view: function(ctrl, _) {\n      var activateButton = null;\n\n      if (ctrl.form.showActivation) {\n        activateButton = m('a.btn.btn-block.btn-success',\n          {href: _.context.REQUEST_ACTIVATION_URL},\n          gettext(\"Activate account\")\n        );\n      }\n\n      return m('.modal-dialog.modal-sm.modal-signin[role=\"document\"]',\n        {config: persistent},\n        m('.modal-content', [\n          _.component('modal:header', gettext(\"Sign in\")),\n          m('form', {onsubmit: ctrl.form.submit}, [\n            m('.modal-body', [\n              m('.form-group',\n                m('.control-input',\n                  Misago.input({\n                    disabled: ctrl.form.isBusy,\n                    value: ctrl.form.username,\n                    placeholder: gettext(\"Username or e-mail\")\n                  })\n                )\n              ),\n              m('.form-group',\n                m('.control-input',\n                  Misago.input({\n                    type: 'password',\n                    disabled: ctrl.form.isBusy,\n                    value: ctrl.form.password,\n                    placeholder: gettext(\"Password\")\n                  })\n                )\n              )\n            ]),\n            m('.modal-footer', [\n              activateButton,\n              _.component('button', {\n                class: '.btn-primary.btn-block',\n                submit: true,\n                loading: ctrl.form.isBusy,\n                label: gettext(\"Sign in\")\n              }),\n              m('a.btn.btn-block.btn-default',\n                {href: _.context.FORGOTTEN_PASSWORD_URL},\n                gettext(\"Forgot password?\")\n              )\n            ])\n          ])\n        ])\n      );\n    }\n  };\n\n  Misago.addService('modal:sign-in', function(_) {\n    _.modal('sign-in', signin);\n  },\n  {\n    after: 'modals'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var dropdown = {\n    controller: function(_) {\n      return {\n        showSignIn: function() {\n          _.modal('sign-in');\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('ul.dropdown-menu.user-dropdown.dropdown-menu-right[role=\"menu\"]',\n        m('li.guest-preview', [\n          m('h4',\n            gettext(\"You are browsing as guest.\")\n          ),\n          m('p',\n            gettext('Sign in or register to start and participate in discussions.')\n          ),\n          m('.row', [\n            m('.col-xs-6',\n              _.component('button', {\n                class: '.btn.btn-default.btn-block',\n                onclick: ctrl.showSignIn,\n                disabled: ctrl.isBusy,\n                label: gettext('Sign in')\n              })\n            ),\n            m('.col-xs-6',\n              _.component(\n                'navbar:register-button', '.btn.btn-primary.btn-block')\n            )\n          ])\n        ])\n      );\n    }\n  };\n\n  Misago.addService('component:navbar:dropdown:guest', function(_) {\n    _.component('navbar:dropdown:guest', dropdown);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var navbar = {\n    style: '.nav.navbar-nav.navbar-compact-nav.hidden-md.hidden-lg',\n    controller: function(links, _) {\n      return {\n        openUserMenu: function() {\n          if (_.user.isAuthenticated) {\n            _.dropdown.toggle('navbar-dropdown', 'navbar:dropdown:user');\n          } else {\n            _.dropdown.toggle('navbar-dropdown', 'navbar:dropdown:guest');\n          }\n\n          return false;\n        }\n      };\n    },\n    userMenu: function(ctrl, _) {\n      if (_.user.isAuthenticated) {\n        return {\n          element: _.component('user-avatar', _.user, 64),\n          config: {\n            onclick: ctrl.openUserMenu,\n            url: '/not-yet/',\n\n            'data-misago-routed': 'false'\n          }\n        };\n      } else {\n        return {\n          element: _.component('user-avatar', null, 64),\n          config: {\n            onclick: ctrl.openUserMenu,\n            href: '#',\n\n            'data-misago-routed': 'false'\n          }\n        };\n      }\n    },\n    mobileNav: function(ctrl, links, _) {\n      var mobileLinks = [\n        {\n          element: m('img', {\n            src: _.router.staticUrl('misago/img/site-icon.png'),\n            alt: _.settings.forum_name\n          }),\n          url: _.router.url('index')\n        }\n      ];\n\n      links.forEach(function(link) {\n        if (link.url !== mobileLinks[0].url) {\n          mobileLinks.push(link);\n        }\n      });\n\n      mobileLinks.push(this.userMenu(ctrl, _));\n\n      return mobileLinks;\n    },\n    view: function(ctrl, links, _) {\n      var mobileLinks = this.mobileNav(ctrl, links, _);\n\n      return m('ul' + this.style + '.with-' + mobileLinks.length + '-items',\n        mobileLinks.map(function(link) {\n          return m('li',\n            m('a', link.config || {href: link.url},\n              link.element || m('span.material-icon', {title:link.label},\n                link.icon\n              )\n            )\n          );\n        })\n      );\n    }\n  };\n\n  Misago.addService('component:navbar:mobile', function(_) {\n    _.component('navbar:mobile', navbar);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var button = {\n    controller: function(style, _) {\n      return {\n        isBusy: false,\n\n        showRegister: function() {\n          if (_.settings.account_activation === 'closed') {\n            _.alert.info(gettext(\"New registrations are currently disabled.\"));\n          } else {\n            m.startComputation();\n            this.isBusy = true;\n            m.endComputation();\n\n            var self = this;\n            m.sync([\n              _.zxcvbn.load(),\n              _.captcha.load()\n            ]).then(function() {\n              _.modal('register');\n            }, function() {\n              _.alert.error(gettext('Registation is not available now due to an error.'));\n            }).then(function() {\n              m.startComputation();\n              self.isBusy = false;\n              m.endComputation();\n            });\n          }\n        }\n      };\n    },\n    view: function(ctrl, style, _) {\n      return _.component('button', {\n        class: style,\n        onclick: ctrl.showRegister.bind(ctrl),\n        loading: ctrl.isBusy,\n        label: gettext('Register')\n      });\n    }\n  };\n\n  Misago.addService('component:navbar:register-button', function(_) {\n    _.component('navbar:register-button', button);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var dropdown = {\n    class: '.dropdown-menu.user-dropdown.dropdown-menu-right',\n\n    controller: function() {\n      return {\n        logout: function() {\n          var decision = confirm(gettext(\"Are you sure you want to sign out?\"));\n          if (decision) {\n            $('#hidden-logout-form').submit();\n          }\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('ul' + this.class + '[role=\"menu\"]', [\n        m('li.dropdown-header',\n          m('strong',\n            _.user.username\n          )\n        ),\n        m('li.divider'),\n        m('li',\n          m('a', {href: _.user.absolute_url}, [\n            m('span.material-icon',\n              'account_circle'\n            ),\n            gettext(\"See your profile\")\n          ])\n        ),\n        m('li',\n          m('a', {href: _.context.USERCP_URL}, [\n            m('span.material-icon',\n              'done_all'\n            ),\n            gettext(\"Change options\")\n          ])\n        ),\n        m('li',\n          m('button.btn-link[type=\"button\"]', [\n            m('span.material-icon',\n              'face'\n            ),\n            gettext(\"Change avatar\")\n          ])\n        ),\n        m('li.divider'),\n        m('li.dropdown-footer',\n          m('button.btn.btn-default.btn-block', {onclick: ctrl.logout},\n            gettext(\"Logout\")\n          )\n        )\n      ]);\n    }\n  };\n\n  Misago.addService('component:navbar:dropdown:user', function(_) {\n    _.component('navbar:dropdown:user', dropdown);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var nav = {\n    controller: function(_) {\n      return {\n        openUserMenu: function() {\n          _.dropdown.toggle('misago-navbar-dropdown', 'navbar:dropdown:guest');\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('button', {type: 'button', onclick: ctrl.openUserMenu},\n        _.component('user-avatar', null, 64)\n      );\n    }\n  };\n\n  Misago.addService('component:navbar:compact:guest-nav', function(_) {\n    _.component('navbar:compact:guest-nav', nav);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var nav = {\n    controller: function(_) {\n      return {\n        openUserMenu: function() {\n          _.dropdown.toggle('misago-navbar-dropdown', 'navbar:dropdown:user');\n          return false;\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      var config = {\n        onclick: ctrl.openUserMenu,\n        href: _.user.absolute_url\n      };\n\n      return m('a', config,\n        _.component('user-avatar', _.user, 64)\n      );\n    }\n  };\n\n  Misago.addService('component:navbar:compact:user-nav', function(_) {\n    _.component('navbar:compact:user-nav', nav);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var nav = {\n    controller: function(_) {\n      return {\n        showSignIn: function() {\n          _.modal('sign-in');\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('div.nav.nav-guest', [\n        _.component('button', {\n          class: '.navbar-btn.btn-default',\n          onclick: ctrl.showSignIn,\n          disabled: ctrl.isBusy,\n          label: gettext('Sign in')\n        }),\n        _.component('navbar:register-button', '.navbar-btn.btn-primary')\n      ]);\n    }\n  };\n\n  Misago.addService('component:navbar:desktop:guest-nav', function(_) {\n    _.component('navbar:desktop:guest-nav', nav);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var nav = {\n    controller: function(_) {\n      return {\n        dropdownToggle: {\n          href: _.user.absolute_url,\n\n          'data-toggle': 'dropdown',\n          'data-misago-routed': 'false',\n\n          'aria-haspopup': 'true',\n          'aria-expanded': 'false'\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('ul.nav.navbar-nav.nav-user', [\n        m('li.dropdown', [\n          m('a.dropdown-toggle[role=\"button\"]', ctrl.dropdownToggle,\n            _.component('user-avatar', _.user, 64)\n          ),\n          _.component('navbar:dropdown:user')\n        ])\n      ]);\n    }\n  };\n\n  Misago.addService('component:navbar:desktop:user-nav', function(_) {\n    _.component('navbar:desktop:user-nav', nav);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  function persistent(el, isInit, context) {\n    context.retain = true;\n  }\n\n  var alert = {\n    classes: {\n      'info': 'alert-info',\n      'success': 'alert-success',\n      'warning': 'alert-warning',\n      'error': 'alert-danger'\n    },\n    view: function(ctrl, _) {\n      var config = {\n        config: persistent,\n        class: _.alert.isVisible ? 'in' : 'out'\n      };\n\n      return m('.alerts', config,\n        m('p.alert', {class: this.classes[_.alert.type]},\n          _.alert.message\n        )\n      );\n    }\n  };\n\n  Misago.addService('component:alert', function(_) {\n    _.component('alert', alert);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  function persistent(el, isInit, context) {\n    context.retain = true;\n  }\n\n  var authChanged = {\n    refresh: function() {\n      window.location.reload();\n    },\n    view: function(ctrl, _) {\n      var message = '';\n\n      var options = {\n        config: persistent,\n        class: (_.auth.isDesynced ? 'show' : null)\n      };\n\n      if (_.auth.isDesynced) {\n        if (_.auth.newUser && _.auth.newUser.isAuthenticated) {\n          message = gettext(\"You have signed in as %(username)s. Please refresh this page before continuing.\");\n          message = interpolate(message, {username: _.auth.newUser.username}, true);\n        } else {\n          message = gettext(\"%(username)s, you have been signed out. Please refresh this page before continuing.\");\n          message = interpolate(message, {username: _.user.username}, true);\n        }\n      }\n\n      return m('.auth-changed-message', options,\n        m('',\n          m('.container', [\n            m('p',\n              message\n            ),\n            m('p', [\n              m('button.btn.btn-default[type=\"button\"]', {onclick: this.refresh},\n                gettext(\"Reload page\")\n              ),\n              m('span.hidden-xs.hidden-sm.text-muted',\n                gettext(\"or press F5 key.\")\n              )\n            ])\n          ])\n        )\n      );\n    }\n  };\n\n  Misago.addService('component:auth-changed-message', function(_) {\n    _.component('auth-changed-message', authChanged);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var bannedPage = {\n    view: function(ctrl, ban) {\n      var error_message = [];\n\n      if (ban.message.html) {\n        error_message.push(m('.lead', m.trust(ban.message.html)));\n      } else {\n        error_message.push(m('p.lead', gettext('You are banned.')));\n      }\n\n      var expirationMessage = null;\n      if (ban.expires_on) {\n        if (ban.expires_on.isAfter(moment())) {\n          expirationMessage = interpolate(\n            gettext('This ban expires %(expires_on)s.'),\n            {'expires_on': ban.expires_on.fromNow()},\n            true);\n        } else {\n          expirationMessage = gettext('This ban has expired.');\n        }\n      } else {\n        expirationMessage = gettext('This ban is permanent.');\n      }\n      error_message.push(m('p', expirationMessage));\n\n      return m('.page.page-error.page-error-banned',\n        m('.container',\n          m('.message-panel', [\n            m('.message-icon',\n              m('span.material-icon', 'highlight_off')\n            ),\n            m('.message-body', error_message)\n          ])\n        )\n      );\n    }\n  };\n\n  Misago.addService('component:banned-page', function(_) {\n    _.component('banned-page', bannedPage);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var button = {\n    view: function(ctrl, kwargs) {\n      var options = {\n        disabled: kwargs.disabled || kwargs.loading || false,\n        config: kwargs.config || null,\n        loading: kwargs.loading || false,\n        type: kwargs.submit ? 'submit' : 'button',\n        onclick: kwargs.onclick || null\n      };\n\n      var element = 'button[type=\"' + options.type + '\"].btn';\n      if (options.loading) {\n        element += '.btn-loading';\n      }\n\n      if (kwargs.id) {\n        element += '#' + kwargs.id;\n      }\n\n      element += (kwargs.class || '');\n\n      var label = kwargs.label;\n      if (options.loading) {\n        label = [\n          label,\n          m('.loader-compact', [\n            m('.bounce1'),\n            m('.bounce2'),\n            m('.bounce3')\n          ])\n        ];\n      }\n\n      return m(element, options, label);\n    },\n  };\n\n  Misago.addService('component:button', function(_) {\n    _.component('button', button);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var textFields = ['text', 'password', 'email'];\n\n  var formGroup = {\n    view: function(ctrl, kwargs) {\n      var groupClass = '.form-group';\n      var errors = null;\n      var helpText = null;\n\n      var controlType = kwargs.control.attrs.type;\n      var controlId = kwargs.control.attrs.id;\n\n      var feedbackId = controlId + '_feedback';\n      var feedbackIcon = null;\n      var showFeedbackIcon = null;\n\n      var isValidated = kwargs.validationKey && kwargs.validation !== null;\n\n      kwargs.control.attrs['aria-describedby'] = '';\n\n      if (isValidated && kwargs.validation[kwargs.validationKey]) {\n        showFeedbackIcon = textFields.indexOf(controlType) >= 0;\n        kwargs.control.attrs['aria-describedby'] = feedbackId;\n\n        if (kwargs.validation[kwargs.validationKey] === true) {\n          groupClass += '.has-success';\n          feedbackIcon = [\n            m('span.material-icon.form-control-feedback',\n              {\n                'aria-hidden': 'true'\n              },\n              'check'\n            ),\n            m('span.sr-only#' + feedbackId, gettext(\"(success)\"))\n          ];\n        } else {\n          groupClass += '.has-error';\n          errors = kwargs.validation[kwargs.validationKey];\n          feedbackIcon = [\n            m('span.material-icon.form-control-feedback',\n              {\n                'aria-hidden': 'true'\n              },\n              'clear'\n            ),\n            m('span.sr-only#' + feedbackId, gettext(\"(error)\"))\n          ];\n        }\n      }\n\n      if (kwargs.helpText) {\n        if (typeof kwargs.helpText === 'string' ||\n            kwargs.helpText instanceof String) {\n          helpText = m('p.help-block', kwargs.helpText);\n        } else {\n          helpText = kwargs.helpText;\n        }\n      }\n\n      return m(groupClass, [\n        m('label.control-label' + (kwargs.labelClass || ''),\n          {\n            for: kwargs.labelFor || controlId\n          },\n          kwargs.label + ':'\n        ),\n        m(kwargs.controlClass || '', [\n          kwargs.control,\n          showFeedbackIcon ? feedbackIcon : null,\n          errors ? m('.help-block.errors', errors.map(function(item) {\n            return m('p', item);\n          })) : null,\n          helpText\n        ])\n      ]);\n    },\n  };\n\n  Misago.addService('component:form-group', function(_) {\n    _.component('form-group', formGroup);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var loader = {\n    view: function() {\n      return m('.loader.sk-folding-cube', [\n        m('.sk-cube1.sk-cube'),\n        m('.sk-cube2.sk-cube'),\n        m('.sk-cube4.sk-cube'),\n        m('.sk-cube3.sk-cube')\n      ]);\n    }\n  };\n\n  Misago.addService('component:loader', function(_) {\n    _.component('loader', loader);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  var markup = {\n    view: function(ctrl, content) {\n      return m('article.misago-markup', {config: persistent},\n        m.trust(content)\n      );\n    }\n  };\n\n  Misago.addService('component:markup', function(_) {\n    _.component('markup', markup);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var header = {\n    view: function(ctrl, options) {\n      return m('.page-header',\n        m('.container', [\n          m('h1', options.title),\n        ])\n      );\n    }\n  };\n\n  Misago.addService('component:header', function(_) {\n    _.component('header', header);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  var styles = [\n    'progress-bar-danger',\n    'progress-bar-warning',\n    'progress-bar-warning',\n    'progress-bar-primary',\n    'progress-bar-success'\n  ];\n\n  var labels = [\n    gettext('Entered password is very weak.'),\n    gettext('Entered password is weak.'),\n    gettext('Entered password is average.'),\n    gettext('Entered password is strong.'),\n    gettext('Entered password is very strong.')\n  ];\n\n  var passwordStrength = {\n    view: function(ctrl, kwargs, _) {\n      var score = _.zxcvbn.scorePassword(kwargs.password, kwargs.inputs);\n      var options = {\n        config: persistent,\n        class: styles[score],\n        style: \"width: \" + (20 + (20 * score)) + '%',\n        'role': \"progressbar\",\n        'aria-valuenow': score,\n        'aria-valuemin': \"0\",\n        'aria-valuemax': \"4\"\n      };\n\n      return m('.help-block.password-strength', {key: 'password-strength'}, [\n        m('.progress',\n          m('.progress-bar', options,\n            m('span.sr-only', labels[score])\n          )\n        ),\n        m('p.text-small', labels[score])\n      ]);\n    },\n  };\n\n  Misago.addService('component:password-strength', function(_) {\n    _.component('password-strength', passwordStrength);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var avatar = {\n    defaultSize: 100,\n\n    src: function(user, size, _) {\n      var src = _.baseUrl + 'user-avatar/';\n\n      if (user && user.id) {\n        // just avatar hash, size and user id\n        src += user.avatar_hash + '/' + size + '/' + user.id + '.png';\n      } else {\n        // just append avatar size to file to produce no-avatar placeholder\n        src += size + '.png';\n      }\n\n      return src;\n    },\n    view: function(ctrl, user, size, _) {\n      var finalSize = size || this.defaultSize;\n      return m('img', {\n        alt: user && user.username ? user.username : gettext(\"Unregistered\"),\n        width: finalSize,\n        height: finalSize,\n        src: this.src(user, finalSize, _)\n      });\n    }\n  };\n\n  Misago.addService('component:user-avatar', function(_) {\n    _.component('user-avatar', avatar);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var ChangePassword = function(_) {\n    var self = this;\n\n    this.username = null;\n    this.password = m.prop('');\n\n    this.validation = {\n      'password': [\n        Misago.validators.passwordMinLength(_.settings)\n      ]\n    };\n\n    this.clean = function() {\n      if (!_.validate(this)) {\n        if ($.trim(this.password()).length) {\n          _.alert.error(this.errors.password);\n        } else {\n          _.alert.error(gettext(\"Enter new password.\"));\n        }\n        return false;\n      } else {\n        return true;\n      }\n    };\n\n    this.submit = function() {\n      var endpoint = _.api.endpoint('auth').endpoint('change-password');\n      endpoint = endpoint.endpoint(m.route.param('user_id'));\n      endpoint = endpoint.endpoint(m.route.param('token'));\n\n      endpoint.post({\n        password: self.password()\n      }).then(function(user) {\n        self.success(user);\n      }, function(error) {\n        self.error(error);\n      });\n    };\n\n    this.success = function(user) {\n      this.username = user.username;\n    };\n\n    this.error = function(rejection) {\n      if (rejection.status === 403 && rejection.ban) {\n        _.router.error403({\n          message: '',\n          ban: rejection.ban\n        });\n      } else if (rejection.status === 400) {\n        _.alert.error(rejection.detail);\n      } else {\n        _.api.alert(rejection);\n      }\n    };\n  };\n\n  Misago.addService('form:change-password', function(_) {\n    _.form('change-password', ChangePassword);\n  },\n  {\n    after: 'forms'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Register = function(_) {\n    var self = this;\n\n    this.showActivation = false;\n\n    this.username = m.prop('');\n    this.email = m.prop('');\n    this.password = m.prop('');\n\n    this.captcha = _.captcha.value;\n\n    this.errors = null;\n\n    this.validation = {\n      'username': [\n        Misago.validators.usernameContent(),\n        Misago.validators.usernameMinLength(_.settings),\n        Misago.validators.usernameMaxLength(_.settings)\n      ],\n      'email': [\n        Misago.validators.email()\n      ],\n      'password': [\n        Misago.validators.passwordMinLength(_.settings)\n      ],\n      'captcha': _.captcha.validator()\n    };\n\n    this.clean = function() {\n      if (this.errors === null) {\n        _.validate(this);\n      }\n\n      _.captcha.clean(this);\n\n      if (this.hasErrors()) {\n        _.alert.error(gettext(\"Form contains errors.\"));\n        return false;\n      } else {\n        return true;\n      }\n    };\n\n    this.submit = function() {\n      _.api.model('user').post({\n        username: this.username(),\n        email: this.email(),\n        password: this.password(),\n        captcha: this.captcha()\n      }).then(this.success, this.error);\n    };\n\n    this.success = function(data) {\n      _.modal('register-complete', data);\n    };\n\n    this.error = function(rejection) {\n      if (rejection.status === 400) {\n        _.alert.error(gettext(\"Form contains errors.\"));\n        $.extend(self.errors, rejection);\n      } else {\n        _.api.alert(rejection);\n      }\n    };\n  };\n\n  Misago.addService('form:register', function(_) {\n    _.form('register', Register);\n  },\n  {\n    after: 'forms'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var RequestLink = function(vm, _) {\n    var self = this;\n\n    this.email = m.prop('');\n\n    this.validation = {\n      'email': [\n        Misago.validators.email()\n      ]\n    };\n\n    this.clean = function() {\n      if (!_.validate(this)) {\n        _.alert.error(gettext(\"Enter a valid email address.\"));\n        return false;\n      } else {\n        return true;\n      }\n    };\n\n    this.submit = function() {\n      _.api.endpoint('auth').endpoint(vm.endpoint).post({\n        email: self.email()\n      }).then(function(user) {\n        self.success(user);\n      }, function(error) {\n        self.error(error);\n      });\n    };\n\n    this.success = function(user) {\n      vm.success(user);\n    };\n\n    this.error = function(rejection) {\n      if (rejection.status === 400) {\n          vm.error(rejection, _);\n      } else if (rejection.status === 403 && rejection.ban) {\n        _.router.error403({\n          message: '',\n          ban: rejection.ban\n        });\n      } else {\n        _.api.alert(rejection);\n      }\n    };\n\n    this.reset = function() {\n      this.email('');\n      vm.reset();\n    };\n  };\n\n  Misago.addService('form:request-link', function(_) {\n    _.form('request-link', RequestLink);\n  },\n  {\n    after: 'forms'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var SignIn = function(_) {\n    var self = this;\n\n    this.showActivation = false;\n\n    this.username = m.prop('');\n    this.password = m.prop('');\n\n    this.validation = {\n      'username': [],\n      'password': []\n    };\n\n    this.clean = function() {\n      if (!_.validate(this)) {\n        _.alert.error(gettext(\"Fill out both fields.\"));\n        return false;\n      } else {\n        return true;\n      }\n    };\n\n    this.submit = function() {\n      _.api.endpoint('auth').post({\n        username: self.username(),\n        password: self.password()\n      }).then(function() {\n        self.success();\n      }, function(error) {\n        self.error(error);\n      });\n    };\n\n    this.success = function() {\n      _.modal();\n\n      var $form = $('#hidden-login-form');\n\n      // refresh CSRF token because api call to /auth/ changed it\n      _.ajax.refreshCsrfToken();\n\n      // fill out form with user credentials and submit it, this will tell\n      // misago to redirect user back to right page, and will trigger browser's\n      // key ring feature\n      $form.find('input[type=\"hidden\"]').val(_.ajax.csrfToken);\n      $form.find('input[name=\"redirect_to\"]').val(m.route());\n      $form.find('input[name=\"username\"]').val(this.username());\n      $form.find('input[name=\"password\"]').val(this.password());\n      $form.submit();\n    };\n\n    this.error = function(rejection) {\n      if (rejection.status === 400) {\n        if (rejection.code === 'inactive_admin') {\n          _.alert.info(rejection.detail);\n        } else if (rejection.code === 'inactive_user') {\n          _.alert.info(rejection.detail);\n          self.showActivation = true;\n        } else if (rejection.code === 'banned') {\n          _.showBannedPage(rejection.detail);\n          _.modal();\n        } else {\n          _.alert.error(rejection.detail);\n        }\n      } else {\n        _.api.alert(rejection);\n      }\n    };\n  };\n\n  Misago.addService('form:sign-in', function(_) {\n    _.form('sign-in', SignIn);\n  },\n  {\n    after: 'forms'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mount = document.getElementById('misago-alert-mount');\n\n  Misago.addService('mount:alert', {\n    factory: function(_) {\n      m.mount(mount, _.component('alert'));\n    },\n    destroy: function() {\n      m.mount(mount, null);\n    }\n  },\n  {\n    before: 'mount:page-component'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mount = document.getElementById('misago-auth-changed-message-mount');\n\n  Misago.addService('mount:auth-changed-message', {\n    factory: function(_) {\n      m.mount(mount, _.component('auth-changed-message'));\n    },\n    destroy: function() {\n      m.mount(mount, null);\n    }\n  },\n  {\n    before: 'mount:page-component'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mount = document.getElementById('page-component');\n\n  Misago.addService('mount:page-component', {\n    factory: function(_) {\n      if (mount) {\n        m.mount(mount, _.component(mount.dataset.componentName));\n      }\n    },\n    destroy: function() {\n      if (mount) {\n        m.mount(mount, null);\n      }\n    }\n  },\n  {\n    before: '_end'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mountDesktop = document.getElementById('misago-user-menu-mount');\n  var mountCompact = document.getElementById('misago-user-menu-compact-mount');\n\n  Misago.addService('mount:user-menu', {\n    factory: function(_) {\n      if (_.user.isAuthenticated) {\n        m.mount(mountDesktop, _.component('navbar:desktop:user-nav'));\n        m.mount(mountCompact, _.component('navbar:compact:user-nav'));\n      } else {\n        m.mount(mountDesktop, _.component('navbar:desktop:guest-nav'));\n        m.mount(mountCompact, _.component('navbar:compact:guest-nav'));\n      }\n    },\n    destroy: function() {\n      m.mount(mountDesktop, null);\n      m.mount(mountCompact, null);\n    }\n  },\n  {\n    before: 'mount:page-component'\n  });\n}(Misago.prototype));\n"],"sourceRoot":"/source/"}
+{"version":3,"sources":["misago.js"],"names":["window","Misago","ns","Object","getPrototypeOf","this","self","_initServices","services","orderedServices","OrderedList","order","forEach","item","factory","undefined","serviceInstance","key","_destroyServices","reverse","destroy","context","SETTINGS","setup","init","test","get","api","_services","proto","prototype","addService","name","push","after","before","PermissionDenied","message","detail","status","toString","has","obj","hasOwnProperty","value","pop","returnValue","persistent","el","isInit","retain","input","kwargs","options","disabled","config","placeholder","autocomplete","element","id","type","oninput","m","withAttr","noop","stateHooks","component","loadingState","errorState","_hasLifecycleHooks","isActive","errorHandler","bind","_controller","controller","apply","arguments","_onunload","onunload","e","vm","loading","loadingHandler","_view","view","isReady","_init","initArgs","promise","then","ondata","finalArgs","i","length","f","error","items","isOrdered","_items","add","values","values_only","_order","unordered","insertItem","insertAt","ordering","indexOf","ordered","splice","index","iterations","Page","_","isFinalized","_sections","finalize","visible","visibleIf","addSection","section","link","getSections","getDefaultLink","serializeDatetime","serialized","format","deserializeDatetime","deserialized","moment","startsWith","string","beginning","endsWith","tail","UrlConf","_patterns","patterns","prefixPattern","prefix","pattern","replace","include","url","loadingPage","getCsrfToken","cookie_name","document","cookie","cookieRegex","RegExp","match","split","Ajax","refreshCsrfToken","csrfToken","CSRF_COOKIE_NAME","runningGets","ajax","method","data","progress","deferred","ajax_settings","headers","X-CSRFToken","dataType","success","resolve","jqXHR","rejection","responseJSON","statusText","reject","$","preloaded","post","patch","put","ALERT_BASE_DISPLAY_TIME","ALERT_LENGTH_FACTOR","ALERT_MAX_DISPLAY_TIME","ALERT_HIDE_ANIMATION_LENGTH","Alert","isVisible","show","displayTime","runloop","runOnce","startComputation","endComputation","set","stop","info","warning","filtersUrl","filters","encodedKey","encodeURIComponent","encodedValue","join","Query","call","path","related","model","relation","endpoint","results","map","models","Api","alert","gettext","Auth","user","deserialize","isDesynced","newUser","handleAuthChange","isAuthenticated","localstore","handleUserChange","extend","syncSession","watch","denyAuthenticated","denyAnonymous","isAnonymous","NoCaptcha","load","QACaptcha","question","prop","label","labelClass","controlClass","control","validate","form","isBusy","validation","errors","validationKey","helpText","help_text","validator","ReCaptcha","included","wait","grecaptcha","reset","controlConfig","render","sitekey","settings","recaptcha_site_key","getResponse","clean","captcha","Captcha","types","no","qa","re","captcha_type","_components","argumentsArray","Dropdown","slots","toggle","elementId","getElementById","hasChildNodes","mount","removeClass","console","log","addClass","dropdown","boilerplate","_submit","submit","_success","_error","hasErrors","constructor","_forms","script","remote","STATIC_URL","cache","setLinks","baseUrl","attr","staticUrl","mediaUrl","prefixUrl","LocalStore","storage","localStorage","watchers","handleStorageEvent","newValueJson","JSON","parse","newValue","each","watcher","keyName","oldValue","callback","addEventListener","prefixKey","setItem","stringify","itemString","getItem","Modal","off","remove","modal","open","on","hide","_modal","_modals","Models","classes","deserializers","String","json","locale","mountPage","RunLoop","_intervals","stopInterval","clearTimeout","run","callable","delay","setTimeout","result","loop","showBannedPage","ban","changeState","title","history","pushState","BANNED_URL","ticks","PageTitle","forum_name","_set_complex","completeTitle","page","page_label","interpolate","parent","EMAIL","USERNAME","validators","required","trim","email","minLength","limit_value","returnMessage","ngettext","show_value","maxLength","usernameMinLength","username_length_min","usernameMaxLength","username_length_max","usernameContent","passwordMinLength","password_length_min","validateField","validateForm","isValid","Zxcvbn","scorePassword","password","inputs","zxcvbn","score","Ban","html","plain","expires_on","deserializeBan","class","LegalPage","body","Rank","slug","description","css_class","is_tab","User","username","full_title","rank","avatar_hash","acl","absolute_url","deserializeUser","joined_on","style","ViewModel","code","SEND_ACTIVATION_API_URL","ctrl","done","onclick","onsubmit","header","data-dismiss","aria-label","aria-hidden","trust","refresh","location","reload","registerComplete","activation","messageHtml","active","inactive","lead","help","register","footnote","TERMS_OF_SERVICE_URL","href","terms","signin","activateButton","showActivation","REQUEST_ACTIVATION_URL","FORGOTTEN_PASSWORD_URL","showSignIn","navbar","links","openUserMenu","userMenu","data-misago-routed","mobileNav","mobileLinks","src","router","alt","icon","button","showRegister","account_activation","sync","logout","decision","confirm","USERCP_URL","nav","dropdownToggle","data-toggle","aria-haspopup","aria-expanded","authChanged","auth","banExpirationMessage","container","expirationMessage","isAfter","fromNow","bannedPage","error_message","textFields","formGroup","groupClass","controlType","attrs","controlId","feedbackId","feedbackIcon","showFeedbackIcon","isValidated","for","labelFor","loader","markup","content","styles","labels","passwordStrength","role","aria-valuenow","aria-valuemin","aria-valuemax","avatar","defaultSize","size","finalSize","width","height","ChangePassword","route","param","error403","Register","RequestLink","SignIn","$form","find","val","dataset","componentName","mountDesktop","mountCompact"],"mappings":"CAEC,WACC,YAEAA,QAAOC,OAAS,WACd,GAAIC,GAAKC,OAAOC,eAAeC,MAC3BC,EAAOD,IAGXA,MAAKE,cAAgB,SAASC,GAC5B,GAAIC,GAAkB,GAAIP,GAAGQ,YAAYF,GAAUG,OAAM,EACzDF,GAAgBG,QAAQ,SAAUC,GAChC,GAAIC,GAAU,IAEZA,GADwBC,SAAtBF,EAAKA,KAAKC,QACFD,EAAKA,KAAKC,QAEVD,EAAKA,IAGjB,IAAIG,GAAkBF,EAAQR,EAC1BU,KACFV,EAAKO,EAAKI,KAAOD,MAKvBX,KAAKa,iBAAmB,SAASV,GAC/B,GAAIC,GAAkB,GAAIP,GAAGQ,YAAYF,GAAUG,OACnDF,GAAgBU,UAChBV,EAAgBG,QAAQ,SAAUC,GACXE,SAAjBF,EAAKO,SACPP,EAAKO,QAAQd,MAMnBD,KAAKgB,SAEHC,aAIFjB,KAAKkB,OAAQ,EACblB,KAAKmB,KAAO,SAASD,EAAOF,GAC1BhB,KAAKkB,OACHE,KAAMvB,EAAGwB,IAAIH,EAAO,QAAQ,GAC5BI,IAAKzB,EAAGwB,IAAIH,EAAO,MAAO,UAGxBF,IACFhB,KAAKgB,QAAUA,GAGjBhB,KAAKE,cAAcL,EAAG0B,YAGxBvB,KAAKe,QAAU,WACbf,KAAKa,iBAAiBhB,EAAG0B,YAK7B,IAAIC,GAAQ7B,OAAOC,OAAO6B,SAE1BD,GAAMD,aACNC,EAAME,WAAa,SAASC,EAAMlB,EAASH,GACzCkB,EAAMD,UAAUK,MACdhB,IAAKe,EACLnB,KAAMC,EACNoB,MAAOL,EAAMH,IAAIf,EAAO,SACxBwB,OAAQN,EAAMH,IAAIf,EAAO,aAK7BkB,EAAMO,iBAAmB,SAASC,GAChChC,KAAKiC,OAASD,EACdhC,KAAKkC,OAAS,IAEdlC,KAAKmC,SAAW,WACd,MAAOnC,MAAKiC,QAAU,yBAK3B,SAAUrC,GACT,YAEAA,GAAOwC,IAAM,SAASC,EAAKzB,GACzB,MAAIyB,GACKA,EAAIC,eAAe1B,IAEnB,GAIXhB,EAAOyB,IAAM,SAASgB,EAAKzB,EAAK2B,GAC9B,MAAI3C,GAAOwC,IAAIC,EAAKzB,GACXyB,EAAIzB,GACQF,SAAV6B,EACFA,EAEA7B,QAIXd,EAAO4C,IAAM,SAASH,EAAKzB,EAAK2B,GAC9B,GAAIE,GAAc7C,EAAOyB,IAAIgB,EAAKzB,EAAK2B,EAIvC,OAHI3C,GAAOwC,IAAIC,EAAKzB,KAClByB,EAAIzB,GAAO,MAEN6B,IAET7C,OAAO6B,WAER,SAAU7B,GACT,YAEA,SAAS8C,GAAWC,EAAIC,EAAQ5B,GAC9BA,EAAQ6B,QAAS,EAGnBjD,EAAOkD,MAAQ,SAASC,GACtB,GAAIC,IACFC,SAAUF,EAAOE,WAAY,EAC7BC,OAAQH,EAAOG,QAAUR,EAGvBK,GAAOI,cACTH,EAAQG,YAAcJ,EAAOI,aAG3BJ,EAAOK,gBAAiB,IAC1BJ,EAAQI,aAAe,MAGzB,IAAIC,GAAU,OAed,OAbIN,GAAOO,KACTD,GAAW,IAAMN,EAAOO,GACxBN,EAAQpC,IAAM,SAAWmC,EAAOO,IAGlCD,GAAW,iBAAmBN,EAAAA,UAAgB,IAC9CM,GAAW,WAAaN,EAAOQ,MAAQ,QAAU,KAE7CR,EAAOR,QACTS,EAAQT,MAAQQ,EAAOR,QACvBS,EAAQQ,QAAUC,EAAEC,SAAS,QAASX,EAAOR,QAGxCkB,EAAEJ,EAASL,KAEpBpD,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI+D,GAAO,YAEX/D,GAAOgE,WAAa,SAASC,EAAWC,EAAcC,GAMpD,GAAIF,EAAUG,mBACZ,MAAOH,EAETA,GAAUG,oBAAqB,EAG/BH,EAAUI,UAAW,CAErB,IAAIC,GAAeH,EAAWI,KAAKN,GAG/BO,EAAcP,EAAUQ,YAAcV,CAoB1C,IAnBAE,EAAUQ,WAAa,WACrB,IACER,EAAUI,UAAW,CACrB,IAAII,GAAaD,EAAYE,MAAMT,EAAWU,eAG1CC,EAAYH,EAAWI,UAAYd,CAMvC,OALAU,GAAWI,SAAW,WACpBD,EAAUF,MAAMT,EAAWU,WAC3BV,EAAUI,UAAW,GAGhBI,EACP,MAAOK,GACPR,EAAaQ,KAKbb,EAAUc,IAAMd,EAAUc,GAAGxD,KAAM,CAErC,IAAK0C,EAAUe,QAAS,CACtB,GAAIC,GAAiBf,EAAaK,KAAKN,EACvCA,GAAUe,QAAUC,EAGtB,GAAIC,GAAQjB,EAAUkB,IACtBlB,GAAUkB,KAAO,WACf,MAAIlB,GAAUc,GAAGK,QACRF,EAAMR,MAAMT,EAAWU,WAEvBV,EAAUe,QAAQN,MAAMT,EAAWU,WAK9C,IAAIU,GAAQpB,EAAUc,GAAGxD,IACzB0C,GAAUc,GAAGxD,KAAO,WAClB,GAAI+D,GAAWX,UACXY,EAAUF,EAAMX,MAAMT,EAAUc,GAAIO,EAEpCC,IACFA,EAAQC,KAAK,WACX,GAAIvB,EAAUI,UAAYJ,EAAUc,GAAGU,OAAQ,CAE7C,IAAK,GADDC,MACKC,EAAI,EAAGA,EAAIhB,UAAUiB,OAAQD,IACpCD,EAAU1D,KAAK2C,UAAUgB,GAE3B,KAAK,GAAIE,GAAI,EAAGA,EAAIP,EAASM,OAAQC,IACnCH,EAAU1D,KAAKsD,EAASO,GAG1B5B,GAAUc,GAAGU,OAAOf,MAAMT,EAAUc,GAAIW,KAEzC,SAASI,GACN7B,EAAUI,UACZC,EAAawB,MAOvB,MAAO7B,KAETjE,OAAO6B,WAER,SAAU7B,GACT,YAEAA,GAAOS,YAAc,SAASsF,GAC5B3F,KAAK4F,WAAY,EACjB5F,KAAK6F,OAASF,MAEd3F,KAAK8F,IAAM,SAASlF,EAAKJ,EAAMF,GAC7BN,KAAK6F,OAAOjE,MACVhB,IAAKA,EACLJ,KAAMA,EAENqB,MAAOjC,EAAOyB,IAAIf,EAAO,SACzBwB,OAAQlC,EAAOyB,IAAIf,EAAO,aAI9BN,KAAKqB,IAAM,SAAST,EAAK2B,GACvB,IAAK,GAAIgD,GAAI,EAAGA,EAAIvF,KAAK6F,OAAOL,OAAQD,IACtC,GAAIvF,KAAK6F,OAAON,GAAG3E,MAAQA,EACzB,MAAOZ,MAAK6F,OAAON,GAAG/E,IAI1B,OAAO+B,IAGTvC,KAAKoC,IAAM,SAASxB,GAClB,MAAyBF,UAAlBV,KAAKqB,IAAIT,IAGlBZ,KAAK+F,OAAS,WAEZ,IAAK,GADDA,MACKR,EAAI,EAAGA,EAAIvF,KAAK6F,OAAOL,OAAQD,IACtCQ,EAAOnE,KAAK5B,KAAK6F,OAAON,GAAG/E,KAE7B,OAAOuF,IAGT/F,KAAKM,MAAQ,SAAS0F,GAMpB,MALKhG,MAAK4F,YACR5F,KAAK6F,OAAS7F,KAAKiG,OAAOjG,KAAK6F,QAC/B7F,KAAK4F,WAAY,GAGfI,GAAsC,mBAAhBA,GACjBhG,KAAK+F,SAEL/F,KAAK6F,QAIhB7F,KAAKiG,OAAS,SAASC,GAgCrB,QAASC,GAAW3F,GAClB,GAAI4F,GAAW,EACoB,MAA/BC,EAASC,QAAQ9F,EAAKI,OACpBJ,EAAKqB,OACPuE,EAAWC,EAASC,QAAQ9F,EAAKqB,OAChB,KAAbuE,IACFA,GAAY,IAEL5F,EAAKsB,SACdsE,EAAWC,EAASC,QAAQ9F,EAAKsB,SAGlB,KAAbsE,IACFG,EAAQC,OAAOJ,EAAU,EAAG5F,GAC5B6F,EAASG,OAAOJ,EAAU,EAAG5F,EAAKI,OA5CxC,GAAI6F,KACJP,GAAU3F,QAAQ,SAAUC,GAC1BiG,EAAM7E,KAAKpB,EAAKI,MAIlB,IAAI2F,MACAF,IAIJH,GAAU3F,QAAQ,SAAUC,GACrBA,EAAKqB,OAAUrB,EAAKsB,SACvByE,EAAQ3E,KAAKpB,GACb6F,EAASzE,KAAKpB,EAAKI,QAMvBsF,EAAU3F,QAAQ,SAAUC,GACN,SAAhBA,EAAKsB,SACPyE,EAAQ3E,KAAKpB,GACb6F,EAASzE,KAAKpB,EAAKI,OA2BvB,KADA,GAAI8F,GAAa,IACVA,EAAa,GAAKD,EAAMjB,SAAWa,EAASb,QACjDkB,GAAc,EACdR,EAAU3F,QAAQ4F,EAGpB,OAAOI,MAGV3G,OAAO6B,WAET,SAAU7B,GACT,YAEAA,GAAO+G,KAAO,SAAShF,EAAMiF,GAC3B,GAAI3G,GAAOD,IAEXA,MAAK2B,KAAOA,EACZ3B,KAAK6G,aAAc,EACnB7G,KAAK8G,YAEL,IAAIC,GAAW,WACb,IAAK9G,EAAK4G,YAAa,CACrB5G,EAAK4G,aAAc,CAEnB,IAAIG,KACJ/G,GAAK6G,UAAUvG,QAAQ,SAAUC,KAC1BA,EAAKyG,WAAazG,EAAKyG,UAAUL,KACpCI,EAAQpF,KAAKpB,KAGjBP,EAAK6G,UAAY,GAAIlH,GAAOS,YAAY2G,GAAS1G,OAAM,IAI3DN,MAAKkH,WAAa,SAASC,GACzB,GAAInH,KAAK6G,YACP,KAAO7G,MAAK2B,KAAO,kEAGrB3B,MAAK8G,UAAUlF,MACbhB,IAAKuG,EAAQC,KACb5G,KAAM2G,EAENtF,MAAOsF,EAAQtF,MACfC,OAAQqF,EAAQrF,UAIpB9B,KAAKqH,YAAc,WAEjB,MADAN,KACO/G,KAAK8G,WAGd9G,KAAKsH,eAAiB,WAEpB,MADAP,KACO/G,KAAK8G,UAAU,GAAGM,QAG7BxH,OAAO6B,WAER,SAAU7B,GACTA,EAAO2H,kBAAoB,SAASC,GAClC,MAAOA,GAAaA,EAAWC,SAAW,MAG5C7H,EAAO8H,oBAAsB,SAASC,GACpC,MAAOA,GAAeC,OAAOD,GAAgB,OAE/C/H,OAAO6B,WAER,SAAU7B,GACT,YAEAA,GAAOiI,WAAa,SAASC,EAAQC,GACnC,MAAqC,KAA9BD,EAAOxB,QAAQyB,IAGxBnI,EAAOoI,SAAW,SAASF,EAAQG,GACjC,MAA6D,KAAtDH,EAAOxB,QAAQ2B,EAAMH,EAAOtC,OAASyC,EAAKzC,UAEnD5F,OAAO6B,WAER,SAAU7B,GACT,YAEAA,GAAOsI,QAAU,WACf,GAAIjI,GAAOD,IACXA,MAAKmI,aAELnI,KAAKoI,SAAW,WACd,MAAOpI,MAAKmI,UAGd,IAAIE,GAAgB,SAASC,EAAQC,GACnC,OAAQD,EAASC,GAASC,QAAQ,KAAM,MAGtCC,EAAU,SAASH,EAAQF,GAC7B,IAAK,GAAI7C,GAAI,EAAGA,EAAI6C,EAAS5C,OAAQD,IACnCtF,EAAKyI,IAAIL,EAAcC,EAAQF,EAAS7C,GAAGgD,SAClCH,EAAS7C,GAAG1B,UACZuE,EAAS7C,GAAG5D,MAIzB3B,MAAK0I,IAAM,SAASH,EAAS1E,EAAWlC,GACtB,KAAZ4G,IACFA,EAAU,KAGR1E,YAAqBjE,GAAOsI,QAC9BO,EAAQF,EAAS1E,EAAUuE,YAE3BpI,KAAKmI,UAAUvG,MACb2G,QAASA,EACT1E,UAAWA,EAAU2E,QAAQ,KAAM,KACnC7G,KAAMA,GAAQkC,OAKtBjE,OAAO6B,WAER,SAAU7B,GACT,YAEAA,GAAO+I,YAAc,SAAS/B,GAC5B,MAAOnD,GAAE,qBACPmD,EAAE/C,UAAU,aAGhBjE,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIgJ,GAAe,SAASC,GAC1B,GAA6C,KAAzCC,SAASC,OAAOzC,QAAQuC,GAAqB,CAC/C,GAAIG,GAAc,GAAIC,QAAOJ,EAAc,YACvCE,EAASnJ,EAAOyB,IAAIyH,SAASC,OAAOG,MAAMF,GAAc,EAC5D,OAAOD,GAAOI,MAAM,KAAK,GAEzB,MAAO,OAIPC,EAAO,SAASxC,GAClB5G,KAAKqJ,iBAAmB,WACtBrJ,KAAKsJ,UAAYV,EAAahC,EAAE5F,QAAQuI,mBAE1CvJ,KAAKqJ,kBAML,IAAIG,KAEJxJ,MAAKyJ,KAAO,SAASC,EAAQhB,EAAKiB,EAAMC,GACtC,GAAIzE,GAAU1B,EAAEoG,WAEZC,GACFpB,IAAKA,EACLgB,OAAQA,EACRK,SACEC,cAAehK,KAAKsJ,WAGtBK,KAAMA,MACNM,SAAU,OAEVC,QAAS,SAASP,GACD,QAAXD,GACF9J,EAAO4C,IAAIgH,EAAad,GAE1BvD,EAAQgF,QAAQR,IAElBjE,MAAO,SAAS0E,GACC,QAAXV,GACF9J,EAAO4C,IAAIgH,EAAad,EAG1B,IAAI2B,GAAYD,EAAME,gBAEtBD,GAAUnI,OAASkI,EAAMlI,OACzBmI,EAAUE,WAAaH,EAAMG,WAE7BpF,EAAQqF,OAAOH,IAInB,OAAIT,GAAJ,QAIAa,EAAEhB,KAAKK,GACA3E,EAAQA,UAGjBnF,KAAKqB,IAAM,SAASqH,GAClB,GAAIgC,GAAY9K,EAAO4C,IAAIoE,EAAE5F,QAAS0H,EACtC,IAAIgC,EAAW,CACb,GAAIb,GAAWpG,EAAEoG,UAEjB,OADAA,GAASM,QAAQO,GACVb,EAAS1E,QACX,MAAyBzE,UAArB8I,EAAYd,GACdc,EAAYd,IAEnBc,EAAYd,GAAO1I,KAAKyJ,KAAK,MAAOf,GAC7Bc,EAAYd,KAIvB1I,KAAK2K,KAAO,SAASjC,EAAKiB,GACxB,MAAO3J,MAAKyJ,KAAK,OAAQf,EAAKiB,IAGhC3J,KAAK4K,MAAQ,SAASlC,EAAKiB,GACzB,MAAO3J,MAAKyJ,KAAK,QAASf,EAAKiB,IAGjC3J,KAAK6K,IAAM,SAASnC,EAAKiB,GACvB,MAAO3J,MAAKyJ,KAAK,MAAOf,EAAKiB,IAG/B3J,KAAAA,UAAc,SAAS0I,GACrB,MAAO1I,MAAKyJ,KAAK,SAAUf,IAI/B9I,GAAO8B,WAAW,OAAQ,SAASkF,GACjC,MAAO,IAAIwC,GAAKxC,MAElBhH,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIkL,GAA0B,IAC1BC,EAAsB,GACtBC,EAAyB,IACzBC,EAA8B,IAE9BC,EAAQ,SAAStE,GACnB,GAAI3G,GAAOD,IAEXA,MAAKuD,KAAO,GACZvD,KAAKgC,QAAU,KACfhC,KAAKmL,WAAY,CAEjB,IAAIC,GAAO,SAAS7H,EAAMvB,GACxB/B,EAAKsD,KAAOA,EACZtD,EAAK+B,QAAUA,EACf/B,EAAKkL,WAAY,CAEjB,IAAIE,GAAcP,CAClBO,IAAerJ,EAAQwD,OAASuF,EAC5BM,EAAcL,IAChBK,EAAcL,GAGhBpE,EAAE0E,QAAQC,QAAQ,WAChB9H,EAAE+H,mBACFvL,EAAKkL,WAAY,EACjB1H,EAAEgI,kBACD,qBAAsBJ,IAGvBK,EAAM,SAASnI,EAAMvB,GACvB4E,EAAE0E,QAAQK,KAAK,sBACf/E,EAAE0E,QAAQK,KAAK,sBAEX1L,EAAKkL,WACPlL,EAAKkL,WAAY,EACjBvE,EAAE0E,QAAQC,QAAQ,WAChB9H,EAAE+H,mBACFJ,EAAK7H,EAAMvB,GACXyB,EAAEgI,kBACD,qBAAsBR,IAEzBG,EAAK7H,EAAMvB,GAIfhC,MAAK4L,KAAO,SAAS5J,GACnB0J,EAAI,OAAQ1J,IAGdhC,KAAKkK,QAAU,SAASlI,GACtB0J,EAAI,UAAW1J,IAGjBhC,KAAK6L,QAAU,SAAS7J,GACtB0J,EAAI,UAAW1J,IAGjBhC,KAAK0F,MAAQ,SAAS1D,GACpB0J,EAAI,QAAS1J,IAIjBpC,GAAO8B,WAAW,SAChBjB,QAAS,SAASmG,GAChB,MAAO,IAAIsE,GAAMtE,OAGrBhH,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIkM,GAAa,SAASC,GACxB,GAAuB,gBAAZA,GAAsB,CAC/B,GAAIhG,KACJ,KAAK,GAAInF,KAAOmL,GACd,GAAIA,EAAQzJ,eAAe1B,GAAM,CAC/B,GAAIoL,GAAaC,mBAAmBrL,GAChCsL,EAAeD,mBAAmBF,EAAQnL,GAC9CmF,GAAOnE,KAAKoK,EAAa,IAAME,GAGnC,MAAO,IAAMnG,EAAOoG,KAAK,KAEzB,MAAOJ,GAAU,KAIjBK,EAAQ,SAASxF,EAAGyF,GACtBrM,KAAK0I,IAAM2D,EAAK3D,KAAO9B,EAAE1F,MAAMI,IAG7BtB,KAAK0I,KADH2D,EAAKC,KACKD,EAAKC,KAAO,IACfD,EAAKE,QACFF,EAAKE,QAAU,IAEfF,EAAKG,MAAQ,KAGvBH,EAAKN,UACP/L,KAAK0I,KAAOoD,EAAWO,EAAKN,UAG1BM,EAAKG,QACPxM,KAAKuM,QAAU,SAASC,EAAOT,GAC7B,MAAO,IAAIK,GAAMxF,GACf8B,IAAK1I,KAAK0I,IACV+D,SAAUJ,EAAKG,MACfD,QAASC,EACTT,QAASA,MAKf/L,KAAK0M,SAAW,SAASJ,EAAMP,GAC7B,MAAO,IAAIK,GAAMxF,GACf8B,IAAK1I,KAAK0I,IACV4D,KAAMA,EACNP,QAASA,KAIb/L,KAAKqB,IAAM,WACT,GAAImL,GAAQ,IAOZ,OANIH,GAAKE,QACPC,EAAQH,EAAKI,SAAW,IAAMJ,EAAKE,QAC1BF,EAAKG,QACdA,EAAQH,EAAKG,OAGR5F,EAAE6C,KAAKpI,IAAIrB,KAAK0I,KAAKtD,KAAK,SAASuE,GACxC,MAAI6C,GACE7C,EAAKgD,SACPhD,EAAKgD,QAAQC,IAAI,SAASpM,GACxB,MAAOoG,GAAEiG,OAAFjG,OAAa4F,EAAOhM,KAEtBmJ,GAEA/C,EAAEiG,OAAFjG,OAAa4F,EAAO7C,GAGtBA,KAKb3J,KAAK2K,KAAO,SAAShB,GACnB,MAAO/C,GAAE6C,KAAKkB,KAAK3K,KAAK0I,IAAKiB,IAG/B3J,KAAK4K,MAAQ,SAASjB,GACpB,MAAO/C,GAAE6C,KAAKmB,MAAM5K,KAAK0I,IAAKiB,IAGhC3J,KAAK6K,IAAM,SAASlB,GAClB,MAAO/C,GAAE6C,KAAKoB,IAAI7K,KAAK0I,IAAKiB,IAG9B3J,KAAAA,UAAc,WACZ,MAAO4G,GAAE6C,KAAF7C,UAAc5G,KAAK0I,MAI5B1I,KAAKoF,KAAO,SAAS+E,EAASK,GAC5B,MAAOxK,MAAKqB,MAAM+D,KAAK+E,EAASK,KAIhCsC,EAAM,SAASlG,GACjB5G,KAAKwM,MAAQ,SAASA,EAAOT,GAC3B,MAAO,IAAIK,GAAMxF,GACf4F,MAAOA,EACPT,QAASA,KAIb/L,KAAK0M,SAAW,SAASJ,EAAMP,GAC7B,MAAO,IAAIK,GAAMxF,GACf0F,KAAMA,EACNP,QAASA,KAIb/L,KAAK+M,MAAQ,SAAS1C,GAEpB,GAAIrI,GAAUgL,QAAQ,6BAEG,KAArB3C,EAAUnI,SACZF,EAAUgL,QAAQ,sCAGK,MAArB3C,EAAUnI,SACZF,EAAUqI,EAAUpI,OACJ,sBAAZD,IACFA,EAAUgL,QACR,uDAImB,MAArB3C,EAAUnI,SACZF,EAAUgL,QAAQ,4BAGpBpG,EAAEmG,MAAMrH,MAAM1D,IAIlBpC,GAAO8B,WAAW,MAAO,SAASkF,GAChC,MAAO,IAAIkG,GAAIlG,MAEjBhH,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIqN,GAAO,SAASrG,GAClB,GAAI3G,GAAOD,IAEX4G,GAAEsG,KAAOtG,EAAEiG,OAAOM,YAAY,OAAQvG,EAAE5F,QAAQkM,MAGhDlN,KAAKoN,YAAa,EAClBpN,KAAKqN,QAAU,IAEf,IAAIC,GAAmB,SAASC,GACzBtN,EAAKmN,aACR3J,EAAE+H,mBAGFvL,EAAKmN,YAAa,EAEdG,IACFtN,EAAKoN,QAAUzG,EAAE4G,WAAWnM,IAAI,cAGlCoC,EAAEgI,mBAIFgC,EAAmB,SAASJ,GACzBpN,EAAKmN,aACR3J,EAAE+H,mBAEE5E,EAAEsG,KAAK5J,KAAO+J,EAAQ/J,IACxBrD,EAAKmN,YAAa,EAClBnN,EAAKoN,QAAUA,GACNA,IACTzG,EAAEsG,KAAOzC,EAAEiD,OAAO9G,EAAEsG,KAAMG,IAG5B5J,EAAEgI,mBAIFkC,EAAc,WAChB/G,EAAE4G,WAAW9B,IAAI,YAAa9E,EAAEsG,MAChCtG,EAAE4G,WAAW9B,IAAI,wBAAyB9E,EAAEsG,KAAKK,iBAEjD3G,EAAE4G,WAAWI,MAAM,wBAAyBN,GAC5C1G,EAAE4G,WAAWI,MAAM,YAAaH,GAGlCE,KAGA3N,KAAK6N,kBAAoB,SAAS7L,GAChC,GAAI4E,EAAEsG,KAAKK,gBACT,KAAM,IAAI3N,GAAOmC,iBACfC,GAAWgL,QAAQ,oDAIzBhN,KAAK8N,cAAgB,SAAS9L,GAC5B,GAAI4E,EAAEsG,KAAKa,YACT,KAAM,IAAInO,GAAOmC,iBACfC,GAAWgL,QAAQ,2CAK3BpN,GAAO8B,WAAW,OAClB,SAASkF,GACP,MAAO,IAAIqG,GAAKrG,KAGhB/E,MAAO,gBAETjC,OAAO6B,WAGR,SAAU7B,GACT,YAEA,IAAIoO,GAAY,WACd,GAAInE,GAAWpG,EAAEoG,UACjBA,GAASM,UAETnK,KAAKiO,KAAO,WACV,MAAOpE,GAAS1E,SAGlBnF,KAAKuC,MAAQ,WACX,MAAO,QAIP2L,EAAY,SAAStH,GACvB,GAAI3G,GAAOD,IAEXA,MAAK4E,SAAU,EACf5E,KAAKmO,SAAW,KAChBnO,KAAKuC,MAAQkB,EAAE2K,KAAK,GAEpB,IAAIvE,GAAWpG,EAAEoG,UACjB7J,MAAKiO,KAAO,WAiBV,MAhBAjO,MAAKuC,MAAM,IAENvC,KAAKmO,UAAanO,KAAK4E,UAC1B5E,KAAK4E,SAAU,EAEfgC,EAAEtF,IAAIoL,SAAS,oBAAoBrL,MAAM+D,KAAK,SAAS+I,GACrDlO,EAAKkO,SAAWA,EAChBtE,EAASM,WACR,WACDvD,EAAEtF,IAAIyL,MAAMC,QAAQ,4BACpBnD,EAASW,WACRpF,KAAK,WACNnF,EAAK2E,SAAU,KAIZiF,EAAS1E,SAGlBnF,KAAK6D,UAAY,SAASd,GACxB,MAAO6D,GAAE/C,UAAU,cACjBwK,MAAOrO,KAAKmO,SAASA,SACrBG,WAAYvL,EAAOuL,YAAc,KACjCC,aAAcxL,EAAOwL,cAAgB,KACrCC,QAAS5H,EAAE9D,OACTP,MAAOqE,EAAE6H,SAAS1L,EAAO2L,KAAM,WAC/BpL,GAAI,aACJL,SAAUF,EAAO2L,KAAKC,SAExBC,WAAY7L,EAAO2L,KAAKG,OACxBC,cAAe,UACfC,SAAU/O,KAAKmO,SAASa,aAI5BhP,KAAKiP,UAAY,WACf,WAIAC,EAAY,SAAStI,GACvB5G,KAAKmP,UAAW,EAChBnP,KAAKmO,SAAW,IAEhB,IAAItE,GAAWpG,EAAEoG,WAEbuF,EAAO,SAASjK,GACQ,mBAAfkK,YACTlK,EAAQgF,UAERvD,EAAE0E,QAAQC,QAAQ,WAChB6D,EAAKjK,IACJ,qBAAsB,KAI7BnF,MAAKiO,KAAO,WAYV,MAX0B,mBAAfoB,aACTA,WAAWC,QAGRtP,KAAKmP,WACRvI,EAAE6B,QAAQ,2CAA2C,GACrDzI,KAAKmP,UAAW,GAGlBC,EAAKvF,GAEEA,EAAS1E,QAGlB,IAAIoK,GAAgB,SAAS5M,EAAIC,EAAQ5B,GACvCA,EAAQ6B,QAAS,EAEZD,GACHyM,WAAWG,OAAO,aAChBC,QAAW7I,EAAE8I,SAASC,qBAK5B3P,MAAK6D,UAAY,SAASd,GACxB,GAAIyL,GAAU/K,EAAE,cACdP,OAAQqM,GAGV,OAAO3I,GAAE/C,UAAU,cACjBwK,MAAOrB,QAAQ,iBACfsB,WAAYvL,EAAOuL,YAAc,KACjCC,aAAcxL,EAAOwL,cAAgB,KACrCC,QAASA,EACTI,WAAY7L,EAAO2L,KAAKG,OACxBC,cAAe,aAInB9O,KAAKuC,MAAQ,WACX,MAA0B,mBAAf8M,YACFA,WAAWO,cAEX,IAIX5P,KAAK6P,MAAQ,SAASnB,GAMlBA,EAAKG,OAAOiB,QALT9P,KAAKuC,SAKc,GAHpByK,QAAQ,6BAOdhN,KAAKiP,UAAY,WACf,WAIAc,EAAU,SAASnJ,GACrB,GAAIoJ,IACFC,GAAMjC,EACNkC,GAAMhC,EACNiC,GAAMjB,GAGJY,EAAU,GAAIE,GAAMpJ,EAAE8I,SAASU,cAAcxJ,EAEjD5G,MAAKuC,MAAQuN,EAAQvN,MAErBvC,KAAKiO,KAAO,WACV,MAAO6B,GAAQ7B,QAGjBjO,KAAK6D,UAAY,SAASd,GACxB,MAAI+M,GAAQjM,UACHiM,EAAQjM,UAAUd,GAElB,MAIX/C,KAAKiP,UAAY,WACf,MAAIa,GAAQb,UACHa,EAAQb,YAER,MAIXjP,KAAK6P,MAAQ,SAASnB,GAChBoB,EAAQD,MACVC,EAAQD,MAAMnB,GAEdA,EAAKG,OAAOiB,SAAU,GAK5BlQ,GAAO8B,WAAW,UAAW,SAASkF,GACpC,MAAO,IAAImJ,GAAQnJ,KAGnB/E,MAAO,aAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIiE,GAAY,SAASlC,EAAMkC,GAC7B,GAAI7D,KAAKqQ,YAAY1O,GAAO,CAC1B,GAAI4C,UAAUiB,OAAS,EAAG,CAExB,IAAK,GADD8K,IAAkBtQ,KAAKqQ,YAAY1O,IAC9B4D,EAAI,EAAGA,EAAIhB,UAAUiB,OAAQD,GAAK,EACzC+K,EAAe1O,KAAK2C,UAAUgB,GAGhC,OADA+K,GAAe1O,KAAK5B,MACbyD,EAAEI,UAAUS,MAAM5D,OAAW4P,GAEpC,MAAO7M,GAAEI,UAAU7D,KAAKqQ,YAAY1O,GAAO3B,MAExC,IAAI6D,EAGT,KAAM,IAAMlC,EAAO,qDAFnB3B,MAAKqQ,YAAY1O,GAAQkC,EAM7BjE,GAAO8B,WAAW,aAAc,SAASkF,GACvCA,EAAEyJ,eACFzJ,EAAE/C,UAAYA,KAEhBjE,OAAO6B,WAER,SAAU7B,GACT,YAEAA,GAAO8B,WAAW,OAAQ,SAASkF,GACjCA,EAAE8I,SAAW9P,EAAOyB,IAAIuF,EAAE5F,QAAS,kBAErCpB,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI2Q,GAAW,SAAS3J,GACtB,GAAI4J,KAEJxQ,MAAKyQ,OAAS,SAASC,EAAW7M,GAChC,GAAIR,GAAUyF,SAAS6H,eAAeD,EAElCrN,GAAQuN,iBAAmBJ,EAAME,KAAe7M,GAClD2M,EAAME,GAAa,KACnBjN,EAAEoN,MAAMxN,EAAS,MACjBoH,EAAEpH,GAASyN,YAAY,UAEvBC,QAAQC,IAAI3N,EAAQuN,iBACpBJ,EAAME,GAAa7M,EACnBJ,EAAEoN,MAAMxN,EAASuD,EAAE/C,UAAUA,IAC7B4G,EAAEpH,GAAS4N,SAAS,UAIxBjR,KAAKe,QAAU,WACb,GAAIsC,GAAU,IAEd,KAAK,GAAIqN,KAAaF,GAChBA,EAAMlO,eAAeoO,KACvBrN,EAAUyF,SAAS6H,eAAeD,GAC9BrN,GAAWA,EAAQuN,iBACrBnN,EAAEoN,MAAMxN,EAAS,QAO3BzD,GAAO8B,WAAW,YAChBjB,QAAS,SAASmG,GAChB,MAAO,IAAI2J,GAAS3J,IAEtB7F,QAAS,SAAS6F,GAChBA,EAAEsK,SAASnQ,aAIbe,OAAQ,gBAEVlC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIuR,GAAc,SAASzC,GACzB,GAAI0C,GAAU1C,EAAK2C,OACfC,EAAW5C,EAAKxE,QAChBqH,EAAS7C,EAAKhJ,KAwDlB,OAtDAgJ,GAAKC,QAAS,EAEdD,EAAKG,OAAS,KAEdH,EAAK2C,OAAS,WACZ,MAAI3C,GAAKC,QACA,GAGLD,EAAKmB,MACHnB,EAAKmB,UACPnB,EAAKC,QAAS,EACdyC,EAAQ9M,MAAMoK,IAGhBA,EAAKC,QAAS,GAET,IAGTD,EAAKxE,QAAU,WACbzG,EAAE+H,mBAEF8F,EAAShN,MAAMoK,EAAMnK,WACrBmK,EAAKC,QAAS,EAEdlL,EAAEgI,kBAGJiD,EAAKhJ,MAAQ,WACXjC,EAAE+H,mBAEF+F,EAAOjN,MAAMoK,EAAMnK,WACnBmK,EAAKC,QAAS,EAEdlL,EAAEgI,kBAGJiD,EAAK8C,UAAY,WACf,GAAoB,OAAhB9C,EAAKG,OACP,OAAO,CAGT,KAAK,GAAIjO,KAAO8N,GAAKE,WACnB,GAAIF,EAAKE,WAAWtM,eAAe1B,IAC7B8N,EAAKG,OAAOjO,MAAS,EACvB,OAAO,CAKb,QAAO,GAGF8N,GAGLA,EAAO,SAAS/M,EAAM8P,GACxB,MAAIzR,MAAK0R,OAAO/P,GAELwP,EADLM,EACiB,GAAIzR,MAAK0R,OAAO/P,GAAM8P,EAAazR,MAEnC,GAAIA,MAAK0R,OAAO/P,GAAM3B,YAG3CA,KAAK0R,OAAO/P,GAAQ8P,GAIxB7R,GAAO8B,WAAW,QAAS,SAASkF,GAClCA,EAAE8K,UACF9K,EAAE8H,KAAOA,KAEX9O,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI6I,GAAU,SAASkJ,EAAQC,GACxBA,IACHD,EAAS3R,KAAKgB,QAAQ6Q,WAAaF,GAGrClH,EAAEhB,MACAf,IAAKiJ,EACLG,OAAO,EACP7H,SAAU,WAIdrK,GAAO8B,WAAW,UAAW,SAASkF,GACpCA,EAAE6B,QAAUA,IAGZ5G,MAAO,UAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAImS,GAAW,SAASnL,GACtBA,EAAEoL,QAAUvH,EAAE,QAAQwH,KAAK,OAE3B,IAAIC,GAAYtS,EAAOyB,IAAIuF,EAAE5F,QAAS,aAAc,KAChDmR,EAAWvS,EAAOyB,IAAIuF,EAAE5F,QAAS,YAAa,KAG9CoR,EAAY,SAAS9J,GACvB,MAAO,UAASI,GACd,MAAOJ,GAASI,GAIpB9B,GAAEsL,UAAYE,EAAUF,GACxBtL,EAAEuL,SAAWC,EAAUD,GAGzBvS,GAAO8B,WAAW,QAAS,SAASkF,GAClCmL,EAASnL,MAEXhH,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIyS,GAAa,WACf,GAAIC,GAAU3S,OAAO4S,aACjBjK,EAAS,WACTkK,KAEAC,EAAqB,SAAS/N,GAChC,GAAIgO,GAAeC,KAAKC,MAAMlO,EAAEmO,SAChCpI,GAAEqI,KAAKN,EAAU,SAASjN,EAAGwN,GACvBA,EAAQC,UAAYtO,EAAE9D,KAAO8D,EAAEuO,WAAavO,EAAEmO,UAChDE,EAAQG,SAASR,KAKvB/S,QAAOwT,iBAAiB,UAAWV,EAEnC,IAAIW,GAAY,SAASJ,GACvB,MAAO1K,GAAS0K,EAGlBhT,MAAK0L,IAAM,SAASsH,EAASzQ,GAC3B+P,EAAQe,QAAQD,EAAUJ,GAAUL,KAAKW,UAAU/Q,KAGrDvC,KAAKqB,IAAM,SAAS2R,GAClB,GAAIO,GAAajB,EAAQkB,QAAQJ,EAAUJ,GAC3C,OAAIO,GACKZ,KAAKC,MAAMW,GAEX,MAIXvT,KAAK4N,MAAQ,SAASoF,EAASE,GAC7BV,EAAS5Q,MAAMoR,QAASI,EAAUJ,GAAUE,SAAUA,KAGxDlT,KAAKe,QAAU,WACbf,KAAKwS,aAIT5S,GAAO8B,WAAW,cAChBjB,QAAS,WACP,MAAO,IAAI4R,IAEbtR,QAAS,SAAS6F,GAChBA,EAAE4G,WAAWzM,cAGjBnB,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI6T,GAAQ,WACV,GAAIxT,GAAOD,KAEPqD,EAAUyF,SAAS6H,eAAe,cAEtC3Q,MAAKe,QAAU,WACb0J,EAAEpH,GAASqQ,MACXjJ,EAAE,QAAQqG,YAAY,cACtBrG,EAAE,mBAAmBkJ,SAIvB,IAAIC,GAAQnJ,EAAEpH,GAASuQ,OAAOxI,MAAM,GACpCpL,MAAK6T,MAAO,EAEZD,EAAME,GAAG,kBAAmB,WACtB7T,EAAK4T,OACPpQ,EAAEoN,MAAMxN,EAAS,MACjBrD,KAAK6T,MAAO,KAIhB7T,KAAKoL,KAAO,SAASvH,GACnB7D,KAAK6T,MAAO,EACZpQ,EAAEoN,MAAMxN,EAASQ,GACjB+P,EAAMA,MAAM,SAGd5T,KAAK+T,KAAO,WACVH,EAAMA,MAAM,SAIhBhU,GAAO8B,WAAW,UAChBjB,QAAS,WACP,MAAO,IAAIgT,IAEb1S,QAAS,SAAS6F,GAChBA,EAAEoN,OAAOjT,aAIXe,OAAQ,0BAEVlC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIgU,GAAQ,SAASjS,EAAMkC,GACzB,GAAI7D,KAAKiU,QAAQtS,GAAO,CAEtB,IAAK,GADD2O,IAAkBtQ,KAAKiU,QAAQtS,IAC1B4D,EAAI,EAAGA,EAAIhB,UAAUiB,OAAQD,GAAK,EACzC+K,EAAe1O,KAAK2C,UAAUgB,GAEhC+K,GAAe1O,KAAK5B,MACpBA,KAAKgU,OAAO5I,KAAK3H,EAAEI,UAAUS,MAAMb,EAAG6M,QAC7B3O,GACT3B,KAAKiU,QAAQtS,GAAQkC,EAErB7D,KAAKgU,OAAOD,OAIhBnU,GAAO8B,WAAW,SAAU,SAASkF,GACnCA,EAAEqN,WACFrN,EAAEgN,MAAQA,IAGV/R,MAAO,YAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIsU,GAAS,WACXlU,KAAKmU,WACLnU,KAAKoU,iBAELpU,KAAK8F,IAAM,SAASnE,EAAMoB,GACpBA,EAAAA,WACF/C,KAAKmU,QAAQxS,GAAQoB,EAAAA,UAGnBA,EAAOoK,cACTnN,KAAKoU,cAAczS,GAAQoB,EAAOoK,cAItCnN,KAAAA,OAAW,SAAS2B,EAAMgI,GACxB,MAAI3J,MAAKmU,QAAQxS,IAIfgI,EAAKrG,GAAKqG,EAAKrG,GAAK+Q,OAAO1K,EAAKrG,IAAM,KAE/B,GAAItD,MAAKmU,QAAQxS,GAAMgI,IAEvBA,GAIX3J,KAAKmN,YAAc,SAASxL,EAAM2S,GAChC,MAAItU,MAAKoU,cAAczS,GACd3B,KAAAA,OAAS2B,EAAM3B,KAAKoU,cAAczS,GAAM2S,EAAMtU,OAE9CA,KAAAA,OAAS2B,EAAM2S,IAK5B1U,GAAO8B,WAAW,SAAU,WAC1B,MAAO,IAAIwS,MAEbtU,OAAO6B,WAER,SAAU7B,GACT,YAEAA,GAAO8B,WAAW,sBAAuB,WACvCkG,OAAO2M,OAAO9J,EAAE,QAAQwH,KAAK,YAE/BrS,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIiR,GAAQ/H,SAAS6H,eAAe,aAEpC/Q,GAAO8B,WAAW,aAAc,SAASkF,GACvCA,EAAE4N,UAAY,SAAS3Q,GACrBJ,EAAEoN,MAAMA,EAAOhN,OAGnBjE,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI6U,GAAU,SAAS7N,GACrB,GAAI3G,GAAOD,IAEXA,MAAK0U,aAEL,IAAIC,GAAe,SAAShT,GACtB1B,EAAKyU,WAAW/S,KAClBhC,OAAOiV,aAAa3U,EAAKyU,WAAW/S,IACpC1B,EAAKyU,WAAW/S,GAAQ,MAI5B3B,MAAK6U,IAAM,SAASC,EAAUnT,EAAMoT,GAClC/U,KAAK0U,WAAW/S,GAAQhC,OAAOqV,WAAW,WACxCL,EAAahT,EACb,IAAIsT,GAASH,EAASlO,EAClBqO,MAAW,GACbhV,EAAK4U,IAAIC,EAAUnT,EAAMoT,IAE1BA,IAGL/U,KAAKuL,QAAU,SAASuJ,EAAUnT,EAAMoT,GACtC/U,KAAK0U,WAAW/S,GAAQhC,OAAOqV,WAAW,WACxCL,EAAahT,GACbmT,EAASlO,IACRmO,IAGL/U,KAAK2L,KAAO,SAAShK,GACnB,IAAK,GAAIuT,KAAQlV,MAAK0U,WACf/S,GAAQA,IAASuT,GACpBP,EAAaO,IAMrBtV,GAAO8B,WAAW,WAChBjB,QAAS,SAASmG,GAChB,MAAO,IAAI6N,GAAQ7N,IAErB7F,QAAS,SAAS6F,GAChBA,EAAE0E,QAAQK,WAGd/L,OAAO6B,WAER,SAAU7B,GACT,YAEAA,GAAO8B,WAAW,mBAAoB,SAASkF,GAC7CA,EAAEuO,eAAiB,SAASC,EAAKC,GAC/B,GAAIxR,GAAY+C,EAAE/C,UAChB,cAAe+C,EAAEiG,OAAOM,YAAY,MAAOiI,GAElB,oBAAhBC,IAAgCA,IACzCzO,EAAE0O,MAAM5J,IAAIsB,QAAQ,mBACpBrN,OAAO4V,QAAQC,aAAc,GAAI5O,EAAE5F,QAAQyU,aAG7C7O,EAAE4N,UAAU3Q,OAGhBjE,OAAO6B,WAER,SAAU7B,GACT,YAEAA,GAAO8B,WAAW,aAAc,SAASkF,GACvC,GAAI8O,GAAQjS,EAAE2K,MAEdxH,GAAE0E,QAAQuJ,IAAI,WACZpR,EAAE+H,mBAEFkK,EAAMA,IAAU,GAEhBjS,EAAEgI,kBACD,OAAQ,QAEb7L,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI+V,GAAY,SAASC,GACvB5V,KAAK0L,IAAM,SAAS4J,GACdA,EACFtV,KAAK6V,aAAaP,GAElBxM,SAASwM,MAAQM,GAIrB5V,KAAK6V,aAAe,SAASP,GACN,gBAAVA,KACTA,GAASA,MAAOA,GAGlB,IAAIQ,GAAgBR,EAAMA,KAE1B,IAA0B,mBAAfA,GAAMS,MAAwBT,EAAMS,KAAO,EAAG,CACvD,GAAIC,GAAaC,YACfjJ,QAAQ,kBAAoB+I,KAAKT,EAAMS,OAAQ,EACjDD,IAAiB,KAAOE,EAAa,IAGX,mBAAjBV,GAAMY,SACfJ,GAAiB,MAAQR,EAAMY,QAGjCpN,SAASwM,MAAQQ,EAAgB,MAAQF,GAI7ChW,GAAO8B,WAAW,aAAc,SAASkF,GACvCA,EAAE0O,MAAQ,GAAIK,GAAU/O,EAAE8I,SAASkG,eAErChW,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIuW,GAAQ,uHACRC,EAAW,GAAInN,QAAO,cAAe,IAGzCrJ,GAAOyW,YACLC,SAAU,WACR,MAAO,UAAS/T,GACd,MAA6B,KAAzBkI,EAAE8L,KAAKhU,GAAOiD,OACTwH,QAAQ,2BADjB,SAKJwJ,MAAO,SAASxU,GACd,MAAO,UAASO,GACd,MAAK4T,GAAM/U,KAAKmB,GAAhB,OACSP,GAAWgL,QAAQ,kCAIhCyJ,UAAW,SAASC,EAAa1U,GAC/B,MAAO,UAASO,GACd,GAAIoU,GAAgB,GAChBnR,EAASiF,EAAE8L,KAAKhU,GAAOiD,MAE3B,OAAakR,GAATlR,GAEAmR,EADE3U,EACcA,EAAQ0U,EAAalR,GAErBoR,SACd,oFACA,qFACAF,GAEGT,YAAYU,GACjBD,YAAaA,EACbG,WAAYrR,IACX,IAZL,SAgBJsR,UAAW,SAASJ,EAAa1U,GAC/B,MAAO,UAASO,GACd,GAAIoU,GAAgB,GAChBnR,EAASiF,EAAE8L,KAAKhU,GAAOiD,MAE3B,OAAIA,GAASkR,GAETC,EADE3U,EACcA,EAAQ0U,EAAalR,GAErBoR,SACd,mFACA,oFACAF,GAEGT,YAAYU,GACjBD,YAAaA,EACbG,WAAYrR,IACX,IAZL,SAgBJuR,kBAAmB,SAASrH,GAC1B,GAAI1N,GAAU,SAAS0U,GACrB,MAAOE,UACL,4DACA,6DACAF,GAEJ,OAAO1W,MAAKyW,UAAU/G,EAASsH,oBAAqBhV,IAEtDiV,kBAAmB,SAASvH,GAC1B,GAAI1N,GAAU,SAAS0U,GACrB,MAAOE,UACL,4DACA,6DACAF,GAEJ,OAAO1W,MAAK8W,UAAUpH,EAASwH,oBAAqBlV,IAEtDmV,gBAAiB,WACf,MAAO,UAAS5U,GACd,MAAK6T,GAAShV,KAAKqJ,EAAE8L,KAAKhU,IAA1B,OACSyK,QAAQ,kEAIrBoK,kBAAmB,SAAS1H,GAC1B,GAAI1N,GAAU,SAAS0U,GACrB,MAAOE,UACL,kEACA,mEACAF,GAEJ,OAAO1W,MAAKyW,UAAU/G,EAAS2H,oBAAqBrV,IAIxD,IAAIsV,GAAgB,SAAS/U,EAAO8T,GAClC,GAAIpB,GAASrV,EAAOyW,WAAWC,WAAW/T,GACtCsM,IAEJ,IAAIoG,EACF,OAAQA,EAER,KAAK,GAAI1P,KAAK8Q,GACZpB,EAASoB,EAAW9Q,GAAGhD,GAEnB0S,GACFpG,EAAOjN,KAAKqT,EAKlB,OAAOpG,GAAOrJ,OAASqJ,GAAS,GAG9B0I,EAAe,SAAS7I,GAC1B,GAAIG,MACAtM,EAAQ,KAERiV,GAAU,CAEd,KAAK,GAAI5W,KAAO8N,GAAKE,WACfF,EAAKE,WAAWtM,eAAe1B,KACjC2B,EAAQmM,EAAK9N,KACbiO,EAAOjO,GAAO0W,EAAc5I,EAAK9N,KAAQ8N,EAAKE,WAAWhO,IACrDiO,EAAOjO,MAAS,IAClB4W,GAAU,GAMhB,OADA9I,GAAKG,OAASA,EACP2I,GAGL/I,EAAW,SAASC,EAAM/M,GAC5B,MAAIA,GACK,SAASY,GACd,GAAIsM,GAAS,IACb,OAAqB,mBAAVtM,IACTsM,EAASyI,EAAc/U,EAAOmM,EAAKE,WAAWjN,IAC1CkN,IACGH,EAAKG,SACRH,EAAKG,WAEPH,EAAKG,OAAOlN,GAAQkN,GAEtBH,EAAK/M,GAAMY,GACJmM,EAAK/M,GAAMY,IAEXmM,EAAK/M,MAIT4V,EAAa7I,GAIxB9O,GAAO8B,WAAW,YAChBjB,QAAS,WACP,MAAOgO,OAGX7O,OAAO6B,WAGR,SAAU7B,GACT,YAEA,IAAI6X,GAAS,SAAS7Q,GACpB5G,KAAKmP,UAAW,EAEhBnP,KAAK0X,cAAgB,SAASC,EAAUC,GAEtC,MAAOC,QAAOF,EAAUC,GAAQE,OAIlC9X,KAAKyI,QAAU,WACb7B,EAAE6B,QAAQ,uBACVzI,KAAKmP,UAAW,EAGlB,IAAIC,GAAO,SAASjK,GACI,mBAAX0S,QACT1S,EAAQgF,UAERvD,EAAE0E,QAAQC,QAAQ,WAChB6D,EAAKjK,IACJ,iBAAkB,MAIrB0E,EAAWpG,EAAEoG,UACjB7J,MAAKiO,KAAO,WAKV,MAJKjO,MAAKmP,UACRnP,KAAKyI,UAEP2G,EAAKvF,GACEA,EAAS1E,SAIpBvF,GAAO8B,WAAW,SAAU,SAASkF,GACnC,MAAO,IAAI6Q,GAAO7Q,KAGlB/E,MAAO,aAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAImY,GAAM,SAASpO,GACjB3J,KAAKgC,SACHgW,KAAMrO,EAAK3H,QAAQgW,KACnBC,MAAOtO,EAAK3H,QAAQiW,OAGtBjY,KAAKkY,WAAavO,EAAKuO,YAGrBC,EAAiB,SAASxO,GAG5B,MAFAA,GAAKuO,WAAatY,EAAO8H,oBAAoBiC,EAAKuO,YAE3CvO,EAGT/J,GAAO8B,WAAW,YAAa,SAASkF,GACtCA,EAAEiG,OAAO/G,IAAI,OACXsS,QAAOL,EACP5K,YAAagL,MAIftW,MAAO,YAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAIyY,GAAY,SAAS1O,GACvB3J,KAAKsV,MAAQ3L,EAAK2L,MAClBtV,KAAKsY,KAAO3O,EAAK2O,KACjBtY,KAAKoH,KAAOuC,EAAKvC,KAGnBxH,GAAO8B,WAAW,mBAAoB,SAASkF,GAC7CA,EAAEiG,OAAO/G,IAAI,cACXsS,QAAOC,MAITxW,MAAO,YAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAI2Y,GAAO,SAAS5O,GAClB3J,KAAKsD,GAAKqG,EAAKrG,GAEftD,KAAK2B,KAAOgI,EAAKhI,KACjB3B,KAAKwY,KAAO7O,EAAK6O,KAEjBxY,KAAKyY,YAAc9O,EAAK8O,YAExBzY,KAAKsV,MAAQ3L,EAAK2L,MAClBtV,KAAK0Y,UAAY/O,EAAK+O,UAEtB1Y,KAAK2Y,OAAShP,EAAKgP,OAGrB/Y,GAAO8B,WAAW,aAAc,SAASkF,GACvCA,EAAEiG,OAAO/G,IAAI,QACXsS,QAAOG,MAIT1W,MAAO,YAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAIgZ,GAAO,SAASjP,GAClB3J,KAAKsD,GAAKqG,EAAKrG,GAEftD,KAAKuN,kBAAoBvN,KAAKsD,GAC9BtD,KAAK+N,aAAe/N,KAAKuN,gBAEzBvN,KAAK6Y,SAAWlP,EAAKkP,SACrB7Y,KAAKwY,KAAO7O,EAAK6O,KAEjBxY,KAAKwW,MAAQ7M,EAAK6M,MAElBxW,KAAK8Y,WAAanP,EAAKmP,WACvB9Y,KAAK+Y,KAAOpP,EAAKoP,KAEjB/Y,KAAKgZ,YAAcrP,EAAKqP,YAExBhZ,KAAKiZ,IAAMtP,EAAKsP,IAEhBjZ,KAAKkZ,aAAevP,EAAKuP,cAGvBC,EAAkB,SAASxP,EAAMkD,GASnC,MARIlD,GAAKyP,YACPzP,EAAKyP,UAAYxZ,EAAO8H,oBAAoBiC,EAAKyP,YAG/CzP,EAAKoP,OACPpP,EAAKoP,KAAOlM,EAAOM,YAAY,OAAQxD,EAAKoP,OAGvCpP,EAGT/J,GAAO8B,WAAW,aAAc,SAASkF,GACvCA,EAAEiG,OAAO/G,IAAI,QACXsS,QAAOQ,EACPzL,YAAagM,MAIftX,MAAO,gBAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAIyZ,GAAQ,oDAERC,EAAY,SAAShY,GACvBtB,KAAKsB,IAAMA,EACXtB,KAAKkN,KAAO,KAEZlN,KAAKkK,QAAU,SAASgD,GACtBlN,KAAKkN,KAAOA,GAGdlN,KAAK0F,MAAQ,SAAS2E,EAAWzD,GACR,mBAAnByD,EAAUkP,MACZ3S,EAAEmG,MAAMnB,KAAKvB,EAAUpI,QACvB2E,EAAEgN,MAAM,YACoB,mBAAnBvJ,EAAUkP,KACnB3S,EAAEmG,MAAMnB,KAAKvB,EAAUpI,QAEvB2E,EAAEmG,MAAMrH,MAAM2E,EAAUpI,SAI5BjC,KAAKsP,MAAQ,WACXtP,KAAKkN,KAAO,OAIZwB,GACFrK,WAAY,SAASuC,GACnB,GAAIjC,GAAK,GAAI2U,GAAU1S,EAAE5F,QAAQwY,wBAEjC,QACE7U,GAAIA,EACJ+J,KAAM9H,EAAE8H,KAAK,eAAgB/J,KAGjCI,KAAM,SAAS0U,EAAM7S,GACnB,MAAI6S,GAAK9U,GAAGuI,KACHlN,KAAK0Z,KAAKD,EAAK9U,GAAI8U,EAAK/K,KAAM9H,GAE9B5G,KAAK0O,KAAK+K,EAAK/K,KAAM9H,IAGhC8S,KAAM,SAAS/U,EAAI+J,EAAM9H,GACvB,GAAI5E,GAAUgL,QAAQ,qCAEtB,OAAOvJ,GAAE4V,EAAQ,aACf5V,EAAE,iBACAA,EAAE,gBACAA,EAAE,qBAAsB,UAE1BA,EAAE,gBACAA,EAAE,IACAwS,YAAYjU,GACVwU,MAAO7R,EAAGuI,KAAKsJ,QACd,KAGP5P,EAAE/C,UAAU,UACVuU,QAAO,yBACP/G,QAAQ,EACRhD,MAAOrB,QAAQ,wBACf2M,QAASjL,EAAKY,MAAMnL,KAAKuK,SAMjCA,KAAM,SAASA,EAAM9H,GACnB,MAAOnD,GAAE4V,EACP5V,EAAE,QAASmW,SAAUlL,EAAK2C,SACxB5N,EAAE,cACAA,EAAE,iBACA7D,EAAOkD,OACLG,SAAUyL,EAAKC,OACfpM,MAAOmM,EAAK8H,MACZrT,YAAa6J,QAAQ,2BAI3BpG,EAAE/C,UAAU,UACVuU,QAAO,yBACP/G,QAAQ,EACRzM,QAAS8J,EAAKC,OACdN,MAAOrB,QAAQ,mBAOzBpN,GAAO8B,WAAW,8BAA+B,SAASkF,GACxDA,EAAE/C,UAAU,+BAAgC6K,KAG5C7M,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIia,IACF9U,KAAM,SAAS0U,EAAMnE,GACnB,MAAO7R,GAAE,iBACPA,EAAE,+BACCqW,eAAgB,QAASC,aAAc/M,QAAQ,UAChDvJ,EAAE,QAASuW,cAAe,QAASvW,EAAEwW,MAAM,aAE7CxW,EAAE,oCAAqC6R,MAK7C1V,GAAO8B,WAAW,yBAA0B,SAASkF,GACnDA,EAAE/C,UAAU,eAAgBgW,KAG5BhY,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI8C,GAAa,SAASC,EAAIC,EAAQ5B,GACpCA,EAAQ6B,QAAS,GAGfqX,EAAU,WACZpR,SAASqR,SAASC,UAGhBC,GACFhW,WAAY,SAASrC,EAAS4E,GACD,WAAvB5E,EAAQsY,YACV1T,EAAE0E,QAAQC,QACR2O,EAAS,6BAA8B,MAG7CnV,KAAM,SAAS0U,EAAMzX,EAAS4E,GAC5B,GAAI2T,GAAc,IAQlB,OALEA,GADyB,WAAvBvY,EAAQsY,WACIta,KAAKwa,OAAOxY,GAEZhC,KAAKya,SAASzY,GAGvByB,EAAE,+DACNP,OAAQR,GACTe,EAAE,kBACAmD,EAAE/C,UAAU,eAAgBmJ,QAAQ,0BACpCvJ,EAAE,cACA8W,OAKRC,OAAQ,SAASxY,GACf,GAAI0Y,GAAO1N,QAAQ,sEACnB,QACEvJ,EAAE,gBACAA,EAAE,qBAAsB,UAE1BA,EAAE,iBACAA,EAAE,SACAwS,YAAYyE,GAAO7B,SAAY7W,EAAQ6W,WAAW,IAEpDpV,EAAE,IACAuJ,QAAQ,uDAEVvJ,EAAE,IACAA,EAAE,yCAA0CkW,QAASO,GACnDlN,QAAQ,sBAMlByN,SAAU,SAASzY,GACjB,GAAI0Y,GAAO,KACPC,EAAO,IAUX,OAR2B,SAAvB3Y,EAAQsY,YACVI,EAAO1N,QAAQ,+GACf2N,EAAO3N,QAAQ,mGACiB,UAAvBhL,EAAQsY,aACjBI,EAAO1N,QAAQ,oIACf2N,EAAO3N,QAAQ,gEAIfvJ,EAAE,gBACAA,EAAE,qBAAsB,iBAE1BA,EAAE,iBACAA,EAAE,SACAwS,YAAYyE,GAAO7B,SAAY7W,EAAQ6W,WAAW,IAEpDpV,EAAE,IACAwS,YAAY0E,GAAOnE,MAASxU,EAAQwU,QAAQ,QAOtD5W,GAAO8B,WAAW,0BAA2B,SAASkF,GACpDA,EAAEgN,MAAM,oBAAqByG,KAG7BxY,MAAO,YAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI8C,GAAa,SAASC,EAAIC,EAAQ5B,GACpCA,EAAQ6B,QAAS,GAGf+X,GACFvW,WAAY,SAASuC,GACnB,OACE8H,KAAM9H,EAAE8H,KAAK,cAGjB3J,KAAM,SAAS0U,EAAM7S,GACnB,GAAIkJ,GAAUlJ,EAAEkJ,QAAQjM,WACtB6K,KAAM+K,EAAK/K,KAEXJ,WAAY,YACZC,aAAc,cAGZsM,EAAW,IAUf,OARIjU,GAAE5F,QAAQ8Z,uBACZD,EAAWpX,EAAE,KAAMsX,KAAMnU,EAAE5F,QAAQ8Z,sBACjCrX,EAAEwW,MAAMhE,YAAYjJ,QAAQ,kDAC1BgO,MAAO,WAAahO,QAAQ,wBAA0B,cACrD,MAIAvJ,EAAE,4DACNP,OAAQR,GACTe,EAAE,kBACAmD,EAAE/C,UAAU,eAAgBmJ,QAAQ,aACpCvJ,EAAE,wBAEAmW,SAAUH,EAAK/K,KAAK2C,SAGpB5N,EAAE,sBACA9B,KAAK,YACL0X,MAAO,kBAET5V,EAAE,0BACA9B,KAAK,YACL0X,MAAO,kBAET5V,EAAE,eACAmD,EAAE/C,UAAU,cACVwK,MAAOrB,QAAQ,YACfsB,WAAY,YACZC,aAAc,YACdC,QAAS5H,EAAE9D,OACTP,MAAOqE,EAAE6H,SAASgL,EAAK/K,KAAM,YAC7BpL,GAAI,cACJL,SAAUwW,EAAK/K,KAAKC,SAEtBC,WAAY6K,EAAK/K,KAAKG,OACtBC,cAAe,aAEjBlI,EAAE/C,UAAU,cACVwK,MAAOrB,QAAQ,UACfsB,WAAY,YACZC,aAAc,YACdC,QAAS5H,EAAE9D,OACTP,MAAOqE,EAAE6H,SAASgL,EAAK/K,KAAM,SAC7BpL,GAAI,WACJL,SAAUwW,EAAK/K,KAAKC,SAEtBC,WAAY6K,EAAK/K,KAAKG,OACtBC,cAAe,UAEjBlI,EAAE/C,UAAU,cACVwK,MAAOrB,QAAQ,YACfsB,WAAY,YACZC,aAAc,YACdC,QAAS5H,EAAE9D,OACTP,MAAOqE,EAAE6H,SAASgL,EAAK/K,KAAM,YAC7BnL,KAAM,WACND,GAAI,cACJL,SAAUwW,EAAK/K,KAAKC,SAEtBC,WAAY6K,EAAK/K,KAAKG,OACtBC,cAAe,WACfC,SAAUnI,EAAE/C,UAAU,qBACpB+T,QACE6B,EAAK/K,KAAKmK,WACVY,EAAK/K,KAAK8H,SAEZmB,SAAU8B,EAAK/K,KAAKiJ,eAGxB7H,IAEFrM,EAAE,iBACAoX,EACAjU,EAAE/C,UAAU,UACVuU,QAAO,eACP/G,QAAQ,EACRzM,QAAS6U,EAAK/K,KAAKC,OACnBN,MAAOrB,QAAQ,8BAS7BpN,GAAO8B,WAAW,iBAAkB,SAASkF,GAC3CA,EAAEgN,MAAM,WAAYgH,KAGpB/Y,MAAO,YAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,SAAS8C,GAAWC,EAAIC,EAAQ5B,GAC9BA,EAAQ6B,QAAS,EAGnB,GAAIoY,IACF5W,WAAY,SAASuC,GACnB,OACE8H,KAAM9H,EAAE8H,KAAK,aAGjB3J,KAAM,SAAS0U,EAAM7S,GACnB,GAAIsU,GAAiB,IASrB,OAPIzB,GAAK/K,KAAKyM,iBACZD,EAAiBzX,EAAE,+BAChBsX,KAAMnU,EAAE5F,QAAQoa,wBACjBpO,QAAQ,sBAILvJ,EAAE,wDACNP,OAAQR,GACTe,EAAE,kBACAmD,EAAE/C,UAAU,eAAgBmJ,QAAQ,YACpCvJ,EAAE,QAASmW,SAAUH,EAAK/K,KAAK2C,SAC7B5N,EAAE,eACAA,EAAE,cACAA,EAAE,iBACA7D,EAAOkD,OACLG,SAAUwW,EAAK/K,KAAKC,OACpBpM,MAAOkX,EAAK/K,KAAKmK,SACjB1V,YAAa6J,QAAQ,0BAI3BvJ,EAAE,cACAA,EAAE,iBACA7D,EAAOkD,OACLS,KAAM,WACNN,SAAUwW,EAAK/K,KAAKC,OACpBpM,MAAOkX,EAAK/K,KAAKiJ,SACjBxU,YAAa6J,QAAQ,kBAK7BvJ,EAAE,iBACAyX,EACAtU,EAAE/C,UAAU,UACVuU,QAAO,yBACP/G,QAAQ,EACRzM,QAAS6U,EAAK/K,KAAKC,OACnBN,MAAOrB,QAAQ,aAEjBvJ,EAAE,+BACCsX,KAAMnU,EAAE5F,QAAQqa,wBACjBrO,QAAQ,6BAStBpN,GAAO8B,WAAW,gBAAiB,SAASkF,GAC1CA,EAAEgN,MAAM,UAAWqH,KAGnBpZ,MAAO,YAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIsR,IACF7M,WAAY,SAASuC,GACnB,OACE0U,WAAY,WACV1U,EAAEgN,MAAM,cAId7O,KAAM,SAAS0U,EAAM7S,GACnB,MAAOnD,GAAE,kEACPA,EAAE,oBACAA,EAAE,KACAuJ,QAAQ,+BAEVvJ,EAAE,IACAuJ,QAAQ,iEAEVvJ,EAAE,QACAA,EAAE,YACAmD,EAAE/C,UAAU,UACVuU,QAAO,6BACPuB,QAASF,EAAK6B,WACdrY,SAAUwW,EAAK9K,OACfN,MAAOrB,QAAQ,cAGnBvJ,EAAE,YACAmD,EAAE/C,UACA,yBAA0B,qCAQxCjE,GAAO8B,WAAW,kCAAmC,SAASkF,GAC5DA,EAAE/C,UAAU,wBAAyBqN,KAGrCrP,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI2b,IACFlC,MAAO,yDACPhV,WAAY,SAASmX,EAAO5U,GAC1B,OACE6U,aAAc,WAOZ,MANI7U,GAAEsG,KAAKK,gBACT3G,EAAEsK,SAAST,OAAO,kBAAmB,wBAErC7J,EAAEsK,SAAST,OAAO,kBAAmB,0BAGhC,KAIbiL,SAAU,SAASjC,EAAM7S,GACvB,MAAIA,GAAEsG,KAAKK,iBAEPlK,QAASuD,EAAE/C,UAAU,cAAe+C,EAAEsG,KAAM,IAC5ChK,QACEyW,QAASF,EAAKgC,aACd/S,IAAK,YAELiT,qBAAsB,WAKxBtY,QAASuD,EAAE/C,UAAU,cAAe,KAAM,IAC1CX,QACEyW,QAASF,EAAKgC,aACdV,KAAM,IAENY,qBAAsB,WAK9BC,UAAW,SAASnC,EAAM+B,EAAO5U,GAC/B,GAAIiV,KAEAxY,QAASI,EAAE,OACTqY,IAAKlV,EAAEmV,OAAO7J,UAAU,4BACxB8J,IAAKpV,EAAE8I,SAASkG,aAElBlN,IAAK9B,EAAEmV,OAAOrT,IAAI,UAYtB,OARA8S,GAAMjb,QAAQ,SAAS6G,GACjBA,EAAKsB,MAAQmT,EAAY,GAAGnT,KAC9BmT,EAAYja,KAAKwF,KAIrByU,EAAYja,KAAK5B,KAAK0b,SAASjC,EAAM7S,IAE9BiV,GAET9W,KAAM,SAAS0U,EAAM+B,EAAO5U,GAC1B,GAAIiV,GAAc7b,KAAK4b,UAAUnC,EAAM+B,EAAO5U,EAE9C,OAAOnD,GAAE,KAAOzD,KAAKqZ,MAAQ,SAAWwC,EAAYrW,OAAS,SAC3DqW,EAAYjP,IAAI,SAASxF,GACvB,MAAO3D,GAAE,KACPA,EAAE,IAAK2D,EAAKlE,SAAW6X,KAAM3T,EAAKsB,KAChCtB,EAAK/D,SAAWI,EAAE,sBAAuB6R,MAAMlO,EAAKiH,OAClDjH,EAAK6U,YASnBrc,GAAO8B,WAAW,0BAA2B,SAASkF,GACpDA,EAAE/C,UAAU,gBAAiB0X,KAG7B1Z,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIsc,IACF7X,WAAY,SAASgV,EAAOzS,GAC1B,OACE+H,QAAQ,EAERwN,aAAc,WACZ,GAAsC,WAAlCvV,EAAE8I,SAAS0M,mBACbxV,EAAEmG,MAAMnB,KAAKoB,QAAQ,kDAChB,CACLvJ,EAAE+H,mBACFxL,KAAK2O,QAAS,EACdlL,EAAEgI,gBAEF,IAAIxL,GAAOD,IACXyD,GAAE4Y,MACAzV,EAAEiR,OAAO5J,OACTrH,EAAEkJ,QAAQ7B,SACT7I,KAAK,WACNwB,EAAEgN,MAAM,aACP,WACDhN,EAAEmG,MAAMrH,MAAMsH,QAAQ,wDACrB5H,KAAK,WACN3B,EAAE+H,mBACFvL,EAAK0O,QAAS,EACdlL,EAAEgI,uBAMZ1G,KAAM,SAAS0U,EAAMJ,EAAOzS,GAC1B,MAAOA,GAAE/C,UAAU,UACjBuU,QAAOiB,EACPM,QAASF,EAAK0C,aAAahY,KAAKsV,GAChC7U,QAAS6U,EAAK9K,OACdN,MAAOrB,QAAQ,eAKrBpN,GAAO8B,WAAW,mCAAoC,SAASkF,GAC7DA,EAAE/C,UAAU,yBAA0BqY,KAGtCra,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIsR,IACFkH,QAAO,mDAEP/T,WAAY,WACV,OACEiY,OAAQ,WACN,GAAIC,GAAWC,QAAQxP,QAAQ,sCAC3BuP,IACF9R,EAAE,uBAAuB4G,YAKjCtM,KAAM,SAAS0U,EAAM7S,GACnB,MAAOnD,GAAE,KAAOzD,KAAAA,SAAa,iBAC3ByD,EAAE,qBACAA,EAAE,SACAmD,EAAEsG,KAAK2L,WAGXpV,EAAE,cACFA,EAAE,KACAA,EAAE;AAAMsX,KAAMnU,EAAEsG,KAAKgM,eACnBzV,EAAE,qBACA,kBAEFuJ,QAAQ,uBAGZvJ,EAAE,KACAA,EAAE,KAAMsX,KAAMnU,EAAE5F,QAAQyb,aACtBhZ,EAAE,qBACA,YAEFuJ,QAAQ,qBAGZvJ,EAAE,KACAA,EAAE,kCACAA,EAAE,qBACA,QAEFuJ,QAAQ,oBAGZvJ,EAAE,cACFA,EAAE,qBACAA,EAAE,oCAAqCkW,QAASF,EAAK6C,QACnDtP,QAAQ,eAOlBpN,GAAO8B,WAAW,iCAAkC,SAASkF,GAC3DA,EAAE/C,UAAU,uBAAwBqN,KAGpCrP,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI8c,IACFrY,WAAY,SAASuC,GACnB,OACE6U,aAAc,WACZ7U,EAAEsK,SAAST,OAAO,kBAAmB,4BAI3C1L,KAAM,SAAS0U,EAAM7S,GACnB,MAAOnD,GAAE,UAAWF,KAAM,SAAUoW,QAASF,EAAKgC,cAChD7U,EAAE/C,UAAU,cAAe,KAAM,MAKvCjE,GAAO8B,WAAW,qCAAsC,SAASkF,GAC/DA,EAAE/C,UAAU,2BAA4B6Y,KAGxC7a,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI8c,IACFrY,WAAY,SAASuC,GACnB,OACE6U,aAAc,WAEZ,MADA7U,GAAEsK,SAAST,OAAO,kBAAmB,yBAC9B,KAIb1L,KAAM,SAAS0U,EAAM7S,GACnB,GAAI1D,IACFyW,QAASF,EAAKgC,aACdV,KAAMnU,EAAEsG,KAAKgM,aAGf,OAAOzV,GAAE,IAAKP,EACZ0D,EAAE/C,UAAU,cAAe+C,EAAEsG,KAAM,MAKzCtN,GAAO8B,WAAW,oCAAqC,SAASkF,GAC9DA,EAAE/C,UAAU,0BAA2B6Y,KAGvC7a,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI8c,IACFrY,WAAY,SAASuC,GACnB,OACE0U,WAAY,WACV1U,EAAEgN,MAAM,cAId7O,KAAM,SAAS0U,EAAM7S,GACnB,MAAOnD,GAAE,qBACPmD,EAAE/C,UAAU,UACVuU,QAAO,0BACPuB,QAASF,EAAK6B,WACdrY,SAAUwW,EAAK9K,OACfN,MAAOrB,QAAQ,aAEjBpG,EAAE/C,UAAU,yBAA0B,8BAK5CjE,GAAO8B,WAAW,qCAAsC,SAASkF,GAC/DA,EAAE/C,UAAU,2BAA4B6Y,KAGxC7a,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI8c,IACFrY,WAAY,SAASuC,GACnB,OACE+V,gBACE5B,KAAMnU,EAAEsG,KAAKgM,aAEb0D,cAAe,WACfjB,qBAAsB,QAEtBkB,gBAAiB,OACjBC,gBAAiB,WAIvB/X,KAAM,SAAS0U,EAAM7S,GACnB,MAAOnD,GAAE,8BACPA,EAAE,eACAA,EAAE,mCAAoCgW,EAAKkD,eACzC/V,EAAE/C,UAAU,cAAe+C,EAAEsG,KAAM,KAErCtG,EAAE/C,UAAU,6BAMpBjE,GAAO8B,WAAW,oCAAqC,SAASkF,GAC9DA,EAAE/C,UAAU,0BAA2B6Y,KAGvC7a,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,SAAS8C,GAAWC,EAAIC,EAAQ5B,GAC9BA,EAAQ6B,QAAS,EAGnB,GAAIkK,IACFoH,SACEvI,KAAQ,aACR1B,QAAW,gBACX2B,QAAW,gBACXnG,MAAS,gBAEXX,KAAM,SAAS0U,EAAM7S,GACnB,GAAI1D,IACFA,OAAQR,EACR0V,QAAOxR,EAAEmG,MAAM5B,UAAY,KAAO,MAGpC,OAAO1H,GAAE,UAAWP,EAClBO,EAAE,WAAY2U,QAAOpY,KAAKmU,QAAQvN,EAAEmG,MAAMxJ,OACxCqD,EAAEmG,MAAM/K,WAMhBpC,GAAO8B,WAAW,kBAAmB,SAASkF,GAC5CA,EAAE/C,UAAU,QAASkJ,KAGrBlL,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,SAAS8C,GAAWC,EAAIC,EAAQ5B,GAC9BA,EAAQ6B,QAAS,EAGnB,GAAIka,IACF7C,QAAS,WACPva,OAAOwa,SAASC,UAElBrV,KAAM,SAAS0U,EAAM7S,GACnB,GAAI5E,GAAU,GAEVgB,GACFE,OAAQR,EACR0V,QAAQxR,EAAEoW,KAAK5P,WAAa,OAAS,KAavC,OAVIxG,GAAEoW,KAAK5P,aACLxG,EAAEoW,KAAK3P,SAAWzG,EAAEoW,KAAK3P,QAAQE,iBACnCvL,EAAUgL,QAAQ,mFAClBhL,EAAUiU,YAAYjU,GAAU6W,SAAUjS,EAAEoW,KAAK3P,QAAQwL,WAAW,KAEpE7W,EAAUgL,QAAQ,uFAClBhL,EAAUiU,YAAYjU,GAAU6W,SAAUjS,EAAEsG,KAAK2L,WAAW,KAIzDpV,EAAE,wBAAyBT,EAChCS,EAAE,GACAA,EAAE,cACAA,EAAE,IACAzB,GAEFyB,EAAE,KACAA,EAAE,yCAA0CkW,QAAS3Z,KAAKka,SACxDlN,QAAQ,gBAEVvJ,EAAE,sCACAuJ,QAAQ,4BAStBpN,GAAO8B,WAAW,iCAAkC,SAASkF,GAC3DA,EAAE/C,UAAU,uBAAwBkZ,KAGpClb,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIqd,IACF5Y,WAAY,SAAS+Q,EAAK8H,GACxB,GAAItW,GAAIsW,GAAa9H,CAErB,OAAI8H,GACK9H,EAEAxO,EAAEiG,OAAOM,YAAY,MAAOvG,EAAE5F,QAAQoU,MAGjDrQ,KAAM,SAASqQ,GACb,GAAI+H,GAAoB,IAcxB,OAXIA,GAFA/H,EAAI8C,WACF9C,EAAI8C,WAAWkF,QAAQxV,UACLqO,YAClBjJ,QAAQ,qCACPkL,WAAc9C,EAAI8C,WAAWmF,YAC9B,GAEkBrQ,QAAQ,yBAGVA,QAAQ,0BAGvBvJ,EAAE,IAAK0Z,IAIlBvd,GAAO8B,WAAW,mCAAoC,SAASkF,GAC7DA,EAAE/C,UAAU,yBAA0BoZ,KAGtCpb,MAAO,gBAETjC,OAAO6B,WAGR,SAAU7B,GACT,YAEA,IAAI0d,IACFvY,KAAM,SAAS0U,EAAMrE,EAAKxO,GACxB,GAAI2W,KAUJ,OAPEA,GAAc3b,KADZwT,EAAIpT,QAAQgW,KACKvU,EAAE,QAASA,EAAEwW,MAAM7E,EAAIpT,QAAQgW,OAE/BvU,EAAE,SAAU2R,EAAIpT,QAAQiW,QAG7CsF,EAAc3b,KAAKgF,EAAE/C,UAAU,yBAA0BuR,IAElD3R,EAAE,qCACPA,EAAE,aACAA,EAAE,kBACAA,EAAE,gBACAA,EAAE,qBAAsB,kBAE1BA,EAAE,gBAAiB8Z,QAO7B3d,GAAO8B,WAAW,wBAAyB,SAASkF,GAClDA,EAAE/C,UAAU,cAAeyZ,KAG3Bzb,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIsc,IACFnX,KAAM,SAAS0U,EAAM1W,GACnB,GAAIC,IACFC,SAAUF,EAAOE,UAAYF,EAAO6B,UAAW,EAC/C1B,OAAQH,EAAOG,QAAU,KACzB0B,QAAS7B,EAAO6B,UAAW,EAC3BrB,KAAMR,EAAOsO,OAAS,SAAW,SACjCsI,QAAS5W,EAAO4W,SAAW,MAGzBtW,EAAU,gBAAkBL,EAAQO,KAAO,QAC3CP,GAAQ4B,UACVvB,GAAW,gBAGTN,EAAOO,KACTD,GAAW,IAAMN,EAAOO,IAG1BD,GAAYN,EAAAA,UAAgB,EAE5B,IAAIsL,GAAQtL,EAAOsL,KAYnB,OAXIrL,GAAQ4B,UACVyJ,GACEA,EACA5K,EAAE,mBACAA,EAAE,YACFA,EAAE,YACFA,EAAE,gBAKDA,EAAEJ,EAASL,EAASqL,IAI/BzO,GAAO8B,WAAW,mBAAoB,SAASkF,GAC7CA,EAAE/C,UAAU,SAAUqY,KAGtBra,MAAO,gBAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAI4d,IAAc,OAAQ,WAAY,SAElCC,GACF1Y,KAAM,SAAS0U,EAAM1W,GACnB,GAAI2a,GAAa,cACb7O,EAAS,KACTE,EAAW,KAEX4O,EAAc5a,EAAOyL,QAAQoP,MAAMra,KACnCsa,EAAY9a,EAAOyL,QAAQoP,MAAMta,GAEjCwa,EAAaD,EAAY,YACzBE,EAAe,KACfC,EAAmB,KAEnBC,EAAclb,EAAO+L,eAAuC,OAAtB/L,EAAO6L,UA2CjD,OAzCA7L,GAAOyL,QAAQoP,MAAM,oBAAsB,GAEvCK,GAAelb,EAAO6L,WAAW7L,EAAO+L,iBAC1CkP,EAAmBR,EAAWlX,QAAQqX,IAAgB,EACtD5a,EAAOyL,QAAQoP,MAAM,oBAAsBE,EAEvC/a,EAAO6L,WAAW7L,EAAO+L,kBAAmB,GAC9C4O,GAAc,eACdK,GACEta,EAAE,4CAEEuW,cAAe,QAEjB,SAEFvW,EAAE,gBAAkBqa,EAAY9Q,QAAQ,iBAG1C0Q,GAAc,aACd7O,EAAS9L,EAAO6L,WAAW7L,EAAO+L,eAClCiP,GACEta,EAAE,4CAEEuW,cAAe,QAEjB,SAEFvW,EAAE,gBAAkBqa,EAAY9Q,QAAQ,eAK1CjK,EAAOgM,WAGPA,EAF6B,gBAApBhM,GAAOgM,UACdhM,EAAOgM,mBAAoBsF,QAClB5Q,EAAE,eAAgBV,EAAOgM,UAEzBhM,EAAOgM,UAIftL,EAAEia,GACPja,EAAE,uBAAyBV,EAAOuL,YAAc,KAE5C4P,MAAKnb,EAAOob,UAAYN,GAE1B9a,EAAOsL,MAAQ,KAEjB5K,EAAEV,EAAOwL,cAAgB,IACvBxL,EAAOyL,QACPwP,EAAmBD,EAAe,KAClClP,EAASpL,EAAE,qBAAsBoL,EAAOjC,IAAI,SAASpM,GACnD,MAAOiD,GAAE,IAAKjD,MACV,KACNuO,OAMRnP,GAAO8B,WAAW,uBAAwB,SAASkF,GACjDA,EAAE/C,UAAU,aAAc4Z,KAG1B5b,MAAO,gBAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAIwe,IACFrZ,KAAM,WACJ,MAAOtB,GAAE,2BACPA,EAAE,qBACFA,EAAE,qBACFA,EAAE,qBACFA,EAAE,wBAKR7D,GAAO8B,WAAW,mBAAoB,SAASkF,GAC7CA,EAAE/C,UAAU,SAAUua,KAGtBvc,MAAO,gBAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAI8C,GAAa,SAASC,EAAIC,EAAQ5B,GACpCA,EAAQ6B,QAAS,GAGfwb,GACFtZ,KAAM,SAAS0U,EAAM6E,GACnB,MAAO7a,GAAE,yBAA0BP,OAAQR,GACzCe,EAAEwW,MAAMqE,KAKd1e,GAAO8B,WAAW,mBAAoB,SAASkF,GAC7CA,EAAE/C,UAAU,SAAUwa,KAGtBxc,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIia,IACF9U,KAAM,SAAS0U,EAAMzW,GACnB,MAAOS,GAAE,eACPA,EAAE,cACAA,EAAE,KAAMT,EAAQsS,WAMxB1V,GAAO8B,WAAW,mBAAoB,SAASkF,GAC7CA,EAAE/C,UAAU,SAAUgW,KAGtBhY,MAAO,gBAETjC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAI8C,GAAa,SAASC,EAAIC,EAAQ5B,GACpCA,EAAQ6B,QAAS,GAGf0b,GACF,sBACA,uBACA,uBACA,uBACA,wBAGEC,GACFxR,QAAQ,kCACRA,QAAQ,6BACRA,QAAQ,gCACRA,QAAQ,+BACRA,QAAQ,qCAGNyR,GACF1Z,KAAM,SAAS0U,EAAM1W,EAAQ6D,GAC3B,GAAIkR,GAAQlR,EAAEiR,OAAOH,cAAc3U,EAAO4U,SAAU5U,EAAO6U,QACvD5U,GACFE,OAAQR,EACR0V,QAAOmG,EAAOzG,GACduB,MAAO,WAAa,GAAM,GAAKvB,GAAU,IACzC4G,KAAQ,cACRC,gBAAiB7G,EACjB8G,gBAAiB,IACjBC,gBAAiB,IAGnB,OAAOpb,GAAE,iCAAkC7C,IAAK,sBAC9C6C,EAAE,YACAA,EAAE,gBAAiBT,EACjBS,EAAE,eAAgB+a,EAAO1G,MAG7BrU,EAAE,eAAgB+a,EAAO1G,OAK/BlY,GAAO8B,WAAW,8BAA+B,SAASkF,GACxDA,EAAE/C,UAAU,oBAAqB4a,KAGjC5c,MAAO,gBAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAIkf,IACFC,YAAa,IAEbjD,IAAK,SAAS5O,EAAM8R,EAAMpY,GACxB,GAAIkV,GAAMlV,EAAEoL,QAAU,cAUtB,OANE8J,IAFE5O,GAAQA,EAAK5J,GAER4J,EAAK8L,YAAc,IAAMgG,EAAO,IAAM9R,EAAK5J,GAAK,OAGhD0b,EAAO,QAKlBja,KAAM,SAAS0U,EAAMvM,EAAM8R,EAAMpY,GAC/B,GAAIqY,GAAYD,GAAQhf,KAAK+e,WAC7B,OAAOtb,GAAE,OACPuY,IAAK9O,GAAQA,EAAK2L,SAAW3L,EAAK2L,SAAW7L,QAAQ,gBACrDkS,MAAOD,EACPE,OAAQF,EACRnD,IAAK9b,KAAK8b,IAAI5O,EAAM+R,EAAWrY,MAKrChH,GAAO8B,WAAW,wBAAyB,SAASkF,GAClDA,EAAE/C,UAAU,cAAeib,KAG3Bjd,MAAO,gBAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAIwf,GAAiB,SAASxY,GAC5B,GAAI3G,GAAOD,IAEXA,MAAK6Y,SAAW,KAChB7Y,KAAK2X,SAAWlU,EAAE2K,KAAK,IAEvBpO,KAAK4O,YACH+I,UACE/X,EAAOyW,WAAWe,kBAAkBxQ,EAAE8I,YAI1C1P,KAAK6P,MAAQ,WACX,MAAKjJ,GAAE6H,SAASzO,OAQP,GANL4G,EAAEmG,MAAMrH,MADN+E,EAAE8L,KAAKvW,KAAK2X,YAAYnS,OACZxF,KAAK6O,OAAO8I,SAEZ3K,QAAQ,yBAEjB,IAMXhN,KAAKqR,OAAS,WACZ,GAAI3E,GAAW9F,EAAEtF,IAAIoL,SAAS,QAAQA,SAAS,kBAC/CA,GAAWA,EAASA,SAASjJ,EAAE4b,MAAMC,MAAM,YAC3C5S,EAAWA,EAASA,SAASjJ,EAAE4b,MAAMC,MAAM,UAE3C5S,EAAS/B,MACPgN,SAAU1X,EAAK0X,aACdvS,KAAK,SAAS8H,GACfjN,EAAKiK,QAAQgD,IACZ,SAASxH,GACVzF,EAAKyF,MAAMA,MAIf1F,KAAKkK,QAAU,SAASgD,GACtBlN,KAAK6Y,SAAW3L,EAAK2L,UAGvB7Y,KAAK0F,MAAQ,SAAS2E,GACK,MAArBA,EAAUnI,QAAkBmI,EAAU+K,IACxCxO,EAAEmV,OAAOwD,UACPvd,QAAS,GACToT,IAAK/K,EAAU+K,MAEa,MAArB/K,EAAUnI,OACnB0E,EAAEmG,MAAMrH,MAAM2E,EAAUpI,QAExB2E,EAAEtF,IAAIyL,MAAM1C,IAKlBzK,GAAO8B,WAAW,uBAAwB,SAASkF,GACjDA,EAAE8H,KAAK,kBAAmB0Q,KAG1Bvd,MAAO,WAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAI4f,GAAW,SAAS5Y,GACtB,GAAI3G,GAAOD,IAEXA,MAAKmb,gBAAiB,EAEtBnb,KAAK6Y,SAAWpV,EAAE2K,KAAK,IACvBpO,KAAKwW,MAAQ/S,EAAE2K,KAAK,IACpBpO,KAAK2X,SAAWlU,EAAE2K,KAAK,IAEvBpO,KAAK8P,QAAUlJ,EAAEkJ,QAAQvN,MAEzBvC,KAAK6O,OAAS,KAEd7O,KAAK4O,YACHiK,UACEjZ,EAAOyW,WAAWc,kBAClBvX,EAAOyW,WAAWU,kBAAkBnQ,EAAE8I,UACtC9P,EAAOyW,WAAWY,kBAAkBrQ,EAAE8I,WAExC8G,OACE5W,EAAOyW,WAAWG,SAEpBmB,UACE/X,EAAOyW,WAAWe,kBAAkBxQ,EAAE8I,WAExCI,QAAWlJ,EAAEkJ,QAAQb,aAGvBjP,KAAK6P,MAAQ,WAOX,MANoB,QAAhB7P,KAAK6O,QACPjI,EAAE6H,SAASzO,MAGb4G,EAAEkJ,QAAQD,MAAM7P,MAEZA,KAAKwR,aACP5K,EAAEmG,MAAMrH,MAAMsH,QAAQ,2BACf,IAEA,GAIXhN,KAAKqR,OAAS,WACZzK,EAAEtF,IAAIkL,MAAM,QAAQ7B,MAClBkO,SAAU7Y,KAAK6Y,WACfrC,MAAOxW,KAAKwW,QACZmB,SAAU3X,KAAK2X,WACf7H,QAAS9P,KAAK8P,YACb1K,KAAKpF,KAAKkK,QAASlK,KAAK0F,QAG7B1F,KAAKkK,QAAU,SAASP,GACtB/C,EAAEgN,MAAM,oBAAqBjK,IAG/B3J,KAAK0F,MAAQ,SAAS2E,GACK,MAArBA,EAAUnI,QACZ0E,EAAEmG,MAAMrH,MAAMsH,QAAQ,0BACtBvC,EAAEiD,OAAOzN,EAAK4O,OAAQxE,IAEtBzD,EAAEtF,IAAIyL,MAAM1C,IAKlBzK,GAAO8B,WAAW,gBAAiB,SAASkF,GAC1CA,EAAE8H,KAAK,WAAY8Q,KAGnB3d,MAAO,WAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAI6f,GAAc,SAAS9a,EAAIiC,GAC7B,GAAI3G,GAAOD,IAEXA,MAAKwW,MAAQ/S,EAAE2K,KAAK,IAEpBpO,KAAK4O,YACH4H,OACE5W,EAAOyW,WAAWG,UAItBxW,KAAK6P,MAAQ,WACX,MAAKjJ,GAAE6H,SAASzO,OAIP,GAHP4G,EAAEmG,MAAMrH,MAAMsH,QAAQ,kCACf,IAMXhN,KAAKqR,OAAS,WACZzK,EAAE6C,KAAKkB,KAAKhG,EAAGrD,KACbkV,MAAOvW,EAAKuW,UACXpR,KAAK,SAAS8H,GACfjN,EAAKiK,QAAQgD,IACZ,SAASxH,GACVzF,EAAKyF,MAAMA,MAIf1F,KAAKkK,QAAU,SAASgD,GACtBvI,EAAGuF,QAAQgD,IAGblN,KAAK0F,MAAQ,SAAS2E,GACK,MAArBA,EAAUnI,OACVyC,EAAGe,MAAM2E,EAAWzD,GAEtBA,EAAEtF,IAAIyL,MAAM1C,IAIhBrK,KAAKsP,MAAQ,WACXtP,KAAKwW,MAAM,IACX7R,EAAG2K,SAIP1P,GAAO8B,WAAW,oBAAqB,SAASkF,GAC9CA,EAAE8H,KAAK,eAAgB+Q,KAGvB5d,MAAO,WAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAI8f,GAAS,SAAS9Y,GACpB,GAAI3G,GAAOD,IAEXA,MAAKmb,gBAAiB,EAEtBnb,KAAK6Y,SAAWpV,EAAE2K,KAAK,IACvBpO,KAAK2X,SAAWlU,EAAE2K,KAAK,IAEvBpO,KAAK4O,YACHiK,YACAlB,aAGF3X,KAAK6P,MAAQ,WACX,MAAKjJ,GAAE6H,SAASzO,OAIP,GAHP4G,EAAEmG,MAAMrH,MAAMsH,QAAQ,2BACf,IAMXhN,KAAKqR,OAAS,WACZzK,EAAEtF,IAAIoL,SAAS,QAAQ/B,MACrBkO,SAAU5Y,EAAK4Y,WACflB,SAAU1X,EAAK0X,aACdvS,KAAK,WACNnF,EAAKiK,WACJ,SAASxE,GACVzF,EAAKyF,MAAMA,MAIf1F,KAAKkK,QAAU,WACbtD,EAAEgN,OAEF,IAAI+L,GAAQlV,EAAE,qBAGd7D,GAAE6C,KAAKJ,mBAKPsW,EAAMC,KAAK,wBAAwBC,IAAIjZ,EAAE6C,KAAKH,WAC9CqW,EAAMC,KAAK,6BAA6BC,IAAIpc,EAAE4b,SAC9CM,EAAMC,KAAK,0BAA0BC,IAAI7f,KAAK6Y,YAC9C8G,EAAMC,KAAK,0BAA0BC,IAAI7f,KAAK2X,YAC9CgI,EAAMtO,UAGRrR,KAAK0F,MAAQ,SAAS2E,GACK,MAArBA,EAAUnI,OACW,mBAAnBmI,EAAUkP,KACZ3S,EAAEmG,MAAMnB,KAAKvB,EAAUpI,QACK,kBAAnBoI,EAAUkP,MACnB3S,EAAEmG,MAAMnB,KAAKvB,EAAUpI,QACvBhC,EAAKkb,gBAAiB,GACM,WAAnB9Q,EAAUkP,MACnB3S,EAAEuO,eAAe9K,EAAUpI,QAC3B2E,EAAEgN,SAEFhN,EAAEmG,MAAMrH,MAAM2E,EAAUpI,QAG1B2E,EAAEtF,IAAIyL,MAAM1C,IAKlBzK,GAAO8B,WAAW,eAAgB,SAASkF,GACzCA,EAAE8H,KAAK,UAAWgR,KAGlB7d,MAAO,WAERjC,OAAO6B,WAET,SAAU7B,GACT,YAEA,IAAIiR,GAAQ/H,SAAS6H,eAAe,cAEpC/Q,GAAO8B,WAAW,eAChBjB,QAAS,SAASmG,GAChBnD,EAAEoN,MAAMA,EAAOjK,EAAE/C,UAAU,WAE7B9C,QAAS,WACP0C,EAAEoN,MAAMA,EAAO,SAIjB/O,OAAQ,0BAEVlC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIiR,GAAQ/H,SAAS6H,eAAe,6BAEpC/Q,GAAO8B,WAAW,8BAChBjB,QAAS,SAASmG,GAChBnD,EAAEoN,MAAMA,EAAOjK,EAAE/C,UAAU,0BAE7B9C,QAAS,WACP0C,EAAEoN,MAAMA,EAAO,SAIjB/O,OAAQ,0BAEVlC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIiR,GAAQ/H,SAAS6H,eAAe,iBAEpC/Q,GAAO8B,WAAW,wBAChBjB,QAAS,SAASmG,GACZiK,GACFpN,EAAEoN,MAAMA,EAAOjK,EAAE/C,UAAUgN,EAAMiP,QAAQC,iBAG7Chf,QAAS,WACH8P,GACFpN,EAAEoN,MAAMA,EAAO,SAKnB/O,OAAQ,UAEVlC,OAAO6B,WAER,SAAU7B,GACT,YAEA,IAAIogB,GAAelX,SAAS6H,eAAe,mBACvCsP,EAAenX,SAAS6H,eAAe,0BAE3C/Q,GAAO8B,WAAW,mBAChBjB,QAAS,SAASmG,GACZA,EAAEsG,KAAKK,iBACT9J,EAAEoN,MAAMmP,EAAcpZ,EAAE/C,UAAU,4BAClCJ,EAAEoN,MAAMoP,EAAcrZ,EAAE/C,UAAU,8BAElCJ,EAAEoN,MAAMmP,EAAcpZ,EAAE/C,UAAU,6BAClCJ,EAAEoN,MAAMoP,EAAcrZ,EAAE/C,UAAU,+BAGtC9C,QAAS,WACP0C,EAAEoN,MAAMmP,EAAc,MACtBvc,EAAEoN,MAAMoP,EAAc,SAIxBne,OAAQ,0BAEVlC,OAAO6B","file":"misago.js","sourcesContent":["/* global -Misago */\n/* exported Misago */\n(function () {\n  'use strict';\n\n  window.Misago = function() {\n    var ns = Object.getPrototypeOf(this);\n    var self = this;\n\n    // Services init/destroy\n    this._initServices = function(services) {\n      var orderedServices = new ns.OrderedList(services).order(false);\n      orderedServices.forEach(function (item) {\n        var factory = null;\n        if (item.item.factory !== undefined) {\n          factory = item.item.factory;\n        } else {\n          factory = item.item;\n        }\n\n        var serviceInstance = factory(self);\n        if (serviceInstance) {\n          self[item.key] = serviceInstance;\n        }\n      });\n    };\n\n    this._destroyServices = function(services) {\n      var orderedServices = new ns.OrderedList(services).order();\n      orderedServices.reverse();\n      orderedServices.forEach(function (item) {\n        if (item.destroy !== undefined) {\n          item.destroy(self);\n        }\n      });\n    };\n\n    // Context data\n    this.context = {\n      // Empty settings\n      SETTINGS: {}\n    };\n\n    // App init/destory\n    this.setup = false;\n    this.init = function(setup, context) {\n      this.setup = {\n        test: ns.get(setup, 'test', false),\n        api: ns.get(setup, 'api', '/api/')\n      };\n\n      if (context) {\n        this.context = context;\n      }\n\n      this._initServices(ns._services);\n    };\n\n    this.destroy = function() {\n      this._destroyServices(ns._services);\n    };\n  };\n\n  // Services\n  var proto = window.Misago.prototype;\n\n  proto._services = [];\n  proto.addService = function(name, factory, order) {\n    proto._services.push({\n      key: name,\n      item: factory,\n      after: proto.get(order, 'after'),\n      before: proto.get(order, 'before')\n    });\n  };\n\n  // Exceptions\n  proto.PermissionDenied = function(message) {\n    this.detail = message;\n    this.status = 403;\n\n    this.toString = function() {\n      return this.detail || 'Permission denied';\n    };\n  };\n}());\n\n(function (Misago) {\n  'use strict';\n\n  Misago.has = function(obj, key) {\n    if (obj) {\n      return obj.hasOwnProperty(key);\n    } else {\n      return false;\n    }\n  };\n\n  Misago.get = function(obj, key, value) {\n    if (Misago.has(obj, key)) {\n      return obj[key];\n    } else if (value !== undefined) {\n      return value;\n    } else {\n      return undefined;\n    }\n  };\n\n  Misago.pop = function(obj, key, value) {\n    var returnValue = Misago.get(obj, key, value);\n    if (Misago.has(obj, key)) {\n      obj[key] = null;\n    }\n    return returnValue;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  function persistent(el, isInit, context) {\n    context.retain = true;\n  }\n\n  Misago.input = function(kwargs) {\n    var options = {\n      disabled: kwargs.disabled || false,\n      config: kwargs.config || persistent\n    };\n\n    if (kwargs.placeholder) {\n      options.placeholder = kwargs.placeholder;\n    }\n\n    if (kwargs.autocomplete === false) {\n      options.autocomplete = 'off';\n    }\n\n    var element = 'input';\n\n    if (kwargs.id) {\n      element += '#' + kwargs.id;\n      options.key = 'field-' + kwargs.id;\n    }\n\n    element += '.form-control' + (kwargs.class || '');\n    element += '[type=\"' + (kwargs.type || 'text') + '\"]';\n\n    if (kwargs.value) {\n      options.value = kwargs.value();\n      options.oninput = m.withAttr('value', kwargs.value);\n    }\n\n    return m(element, options);\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var noop = function() {};\n\n  Misago.stateHooks = function(component, loadingState, errorState) {\n    /*\n      Boilerplate for Misago components with lifecycles\n    */\n\n    // Component boilerplated (this may happen in tests)\n    if (component._hasLifecycleHooks) {\n      return component;\n    }\n    component._hasLifecycleHooks = true;\n\n    // Component active state\n    component.isActive = true;\n\n    var errorHandler = errorState.bind(component);\n\n    // Wrap controller to store lifecycle methods\n    var _controller = component.controller || noop;\n    component.controller = function() {\n      try {\n        component.isActive = true;\n        var controller = _controller.apply(component, arguments) || {};\n\n        // wrap onunload for lifestate\n        var _onunload = controller.onunload || noop;\n        controller.onunload = function() {\n          _onunload.apply(component, arguments);\n          component.isActive = false;\n        };\n\n        return controller;\n      } catch (e) {\n        errorHandler(e);\n      }\n    };\n\n    // Add state callbacks to View-Model\n    if (component.vm && component.vm.init) {\n      // setup default loading view\n      if (!component.loading) {\n        var loadingHandler = loadingState.bind(component);\n        component.loading = loadingHandler;\n      }\n\n      var _view = component.view;\n      component.view = function() {\n        if (component.vm.isReady) {\n          return _view.apply(component, arguments);\n        } else {\n          return component.loading.apply(component, arguments);\n        }\n      };\n\n      // wrap vm.init in promise handler\n      var _init = component.vm.init;\n      component.vm.init = function() {\n        var initArgs = arguments;\n        var promise = _init.apply(component.vm, initArgs);\n\n        if (promise) {\n          promise.then(function() {\n            if (component.isActive && component.vm.ondata) {\n              var finalArgs = [];\n              for (var i = 0; i < arguments.length; i++) {\n                finalArgs.push(arguments[i]);\n              }\n              for (var f = 0; f < initArgs.length; f++) {\n                finalArgs.push(initArgs[f]);\n              }\n\n              component.vm.ondata.apply(component.vm, finalArgs);\n            }\n          }, function(error) {\n            if (component.isActive) {\n              errorHandler(error);\n            }\n          });\n        }\n      };\n    }\n\n    return component;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.OrderedList = function(items) {\n    this.isOrdered = false;\n    this._items = items || [];\n\n    this.add = function(key, item, order) {\n      this._items.push({\n        key: key,\n        item: item,\n\n        after: Misago.get(order, 'after'),\n        before: Misago.get(order, 'before')\n      });\n    };\n\n    this.get = function(key, value) {\n      for (var i = 0; i < this._items.length; i++) {\n        if (this._items[i].key === key) {\n          return this._items[i].item;\n        }\n      }\n\n      return value;\n    };\n\n    this.has = function(key) {\n      return this.get(key) !== undefined;\n    };\n\n    this.values = function() {\n      var values = [];\n      for (var i = 0; i < this._items.length; i++) {\n        values.push(this._items[i].item);\n      }\n      return values;\n    };\n\n    this.order = function(values_only) {\n      if (!this.isOrdered) {\n        this._items = this._order(this._items);\n        this.isOrdered = true;\n      }\n\n      if (values_only || typeof values_only === 'undefined') {\n        return this.values();\n      } else {\n        return this._items;\n      }\n    };\n\n    this._order = function(unordered) {\n      // Index of unordered items\n      var index = [];\n      unordered.forEach(function (item) {\n        index.push(item.key);\n      });\n\n      // Ordered items\n      var ordered = [];\n      var ordering = [];\n\n      // First pass: register items that\n      // don't specify their order\n      unordered.forEach(function (item) {\n        if (!item.after && !item.before) {\n          ordered.push(item);\n          ordering.push(item.key);\n        }\n      });\n\n      // Second pass: register items that\n      // specify their before to \"_end\"\n      unordered.forEach(function (item) {\n        if (item.before === \"_end\") {\n          ordered.push(item);\n          ordering.push(item.key);\n        }\n      });\n\n      // Third pass: keep iterating items\n      // until we hit iterations limit or finish\n      // ordering list\n      function insertItem(item) {\n        var insertAt = -1;\n        if (ordering.indexOf(item.key) === -1) {\n          if (item.after) {\n            insertAt = ordering.indexOf(item.after);\n            if (insertAt !== -1) {\n              insertAt += 1;\n            }\n          } else if (item.before) {\n            insertAt = ordering.indexOf(item.before);\n          }\n\n          if (insertAt !== -1) {\n            ordered.splice(insertAt, 0, item);\n            ordering.splice(insertAt, 0, item.key);\n          }\n        }\n      }\n\n      var iterations = 200;\n      while (iterations > 0 && index.length !== ordering.length) {\n        iterations -= 1;\n        unordered.forEach(insertItem);\n      }\n\n      return ordered;\n    };\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.Page = function(name, _) {\n    var self = this;\n\n    this.name = name;\n    this.isFinalized = false;\n    this._sections = [];\n\n    var finalize = function() {\n      if (!self.isFinalized) {\n        self.isFinalized = true;\n\n        var visible = [];\n        self._sections.forEach(function (item) {\n          if (!item.visibleIf || item.visibleIf(_)) {\n            visible.push(item);\n          }\n        });\n        self._sections = new Misago.OrderedList(visible).order(true);\n      }\n    };\n\n    this.addSection = function(section) {\n      if (this.isFinalized) {\n        throw (this.name + \" page was initialized already and no longer accepts new sections\");\n      }\n\n      this._sections.push({\n        key: section.link,\n        item: section,\n\n        after: section.after,\n        before: section.before\n      });\n    };\n\n    this.getSections = function() {\n      finalize();\n      return this._sections;\n    };\n\n    this.getDefaultLink = function() {\n      finalize();\n      return this._sections[0].link;\n    };\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  Misago.serializeDatetime = function(serialized) {\n    return serialized ? serialized.format() : null;\n  };\n\n  Misago.deserializeDatetime = function(deserialized) {\n    return deserialized ? moment(deserialized) : null;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.startsWith = function(string, beginning) {\n    return string.indexOf(beginning) === 0;\n  };\n\n  Misago.endsWith = function(string, tail) {\n    return string.indexOf(tail, string.length - tail.length) !== -1;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.UrlConf = function() {\n    var self = this;\n    this._patterns = [];\n\n    this.patterns = function() {\n      return this._patterns;\n    };\n\n    var prefixPattern = function(prefix, pattern) {\n      return (prefix + pattern).replace('//', '/');\n    };\n\n    var include = function(prefix, patterns) {\n      for (var i = 0; i < patterns.length; i ++) {\n        self.url(prefixPattern(prefix, patterns[i].pattern),\n                 patterns[i].component,\n                 patterns[i].name);\n      }\n    };\n\n    this.url = function(pattern, component, name) {\n      if (pattern === '') {\n        pattern = '/';\n      }\n\n      if (component instanceof Misago.UrlConf) {\n        include(pattern, component.patterns());\n      } else {\n        this._patterns.push({\n          pattern: pattern,\n          component: component.replace(/_/g, '-'),\n          name: name || component\n        });\n      }\n    };\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.loadingPage = function(_) {\n    return m('.page.page-loading',\n      _.component('loader')\n    );\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var getCsrfToken = function(cookie_name) {\n    if (document.cookie.indexOf(cookie_name) !== -1) {\n      var cookieRegex = new RegExp(cookie_name + '\\=([^;]*)');\n      var cookie = Misago.get(document.cookie.match(cookieRegex), 0);\n      return cookie.split('=')[1];\n    } else {\n      return null;\n    }\n  };\n\n  var Ajax = function(_) {\n    this.refreshCsrfToken = function() {\n      this.csrfToken = getCsrfToken(_.context.CSRF_COOKIE_NAME);\n    };\n    this.refreshCsrfToken();\n\n    /*\n      List of GETs underway\n      We are limiting number of GETs to API to 1 per url\n    */\n    var runningGets = {};\n\n    this.ajax = function(method, url, data, progress) {\n      var promise = m.deferred();\n\n      var ajax_settings = {\n        url: url,\n        method: method,\n        headers: {\n          'X-CSRFToken': this.csrfToken\n        },\n\n        data: data || {},\n        dataType: 'json',\n\n        success: function(data) {\n          if (method === 'GET') {\n            Misago.pop(runningGets, url);\n          }\n          promise.resolve(data);\n        },\n        error: function(jqXHR) {\n          if (method === 'GET') {\n            Misago.pop(runningGets, url);\n          }\n\n          var rejection = jqXHR.responseJSON || {};\n\n          rejection.status = jqXHR.status;\n          rejection.statusText = jqXHR.statusText;\n\n          promise.reject(rejection);\n        }\n      };\n\n      if (progress) {\n        return; // not implemented... yet!\n      }\n\n      $.ajax(ajax_settings);\n      return promise.promise;\n    };\n\n    this.get = function(url) {\n      var preloaded = Misago.pop(_.context, url);\n      if (preloaded) {\n        var deferred = m.deferred();\n        deferred.resolve(preloaded);\n        return deferred.promise;\n      } else if (runningGets[url] !== undefined) {\n        return runningGets[url];\n      } else {\n        runningGets[url] = this.ajax('GET', url);\n        return runningGets[url];\n      }\n    };\n\n    this.post = function(url, data) {\n      return this.ajax('POST', url, data);\n    };\n\n    this.patch = function(url, data) {\n      return this.ajax('PATCH', url, data);\n    };\n\n    this.put = function(url, data) {\n      return this.ajax('PUT', url, data);\n    };\n\n    this.delete = function(url) {\n      return this.ajax('DELETE', url);\n    };\n  };\n\n  Misago.addService('ajax', function(_) {\n    return new Ajax(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var ALERT_BASE_DISPLAY_TIME = 5 * 1000;\n  var ALERT_LENGTH_FACTOR = 70;\n  var ALERT_MAX_DISPLAY_TIME = 9 * 1000;\n  var ALERT_HIDE_ANIMATION_LENGTH = 300;\n\n  var Alert = function(_) {\n    var self = this;\n\n    this.type = '';\n    this.message = null;\n    this.isVisible = false;\n\n    var show = function(type, message) {\n      self.type = type;\n      self.message = message;\n      self.isVisible = true;\n\n      var displayTime = ALERT_BASE_DISPLAY_TIME;\n      displayTime += message.length * ALERT_LENGTH_FACTOR;\n      if (displayTime > ALERT_MAX_DISPLAY_TIME) {\n        displayTime = ALERT_MAX_DISPLAY_TIME;\n      }\n\n      _.runloop.runOnce(function () {\n        m.startComputation();\n        self.isVisible = false;\n        m.endComputation();\n      }, 'flash-message-hide', displayTime);\n    };\n\n    var set = function(type, message) {\n      _.runloop.stop('flash-message-hide');\n      _.runloop.stop('flash-message-show');\n\n      if (self.isVisible) {\n        self.isVisible = false;\n        _.runloop.runOnce(function () {\n          m.startComputation();\n          show(type, message);\n          m.endComputation();\n        }, 'flash-message-show', ALERT_HIDE_ANIMATION_LENGTH);\n      } else {\n        show(type, message);\n      }\n    };\n\n    this.info = function(message) {\n      set('info', message);\n    };\n\n    this.success = function(message) {\n      set('success', message);\n    };\n\n    this.warning = function(message) {\n      set('warning', message);\n    };\n\n    this.error = function(message) {\n      set('error', message);\n    };\n  };\n\n  Misago.addService('alert', {\n    factory: function(_) {\n      return new Alert(_);\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var filtersUrl = function(filters) {\n    if (typeof filters === 'object') {\n      var values = [];\n      for (var key in filters) {\n        if (filters.hasOwnProperty(key)) {\n          var encodedKey = encodeURIComponent(key);\n          var encodedValue = encodeURIComponent(filters[key]);\n          values.push(encodedKey + '=' + encodedValue);\n        }\n      }\n      return '?' + values.join('&');\n    } else {\n      return filters + '/';\n    }\n  };\n\n  var Query = function(_, call) {\n    this.url = call.url || _.setup.api;\n\n    if (call.path) {\n      this.url += call.path + '/';\n    } else if (call.related) {\n      this.url += call.related + '/';\n    } else {\n      this.url += call.model + 's' + '/';\n    }\n\n    if (call.filters) {\n      this.url += filtersUrl(call.filters);\n    }\n\n    if (call.model) {\n      this.related = function(model, filters) {\n        return new Query(_, {\n          url: this.url,\n          relation: call.model,\n          related: model,\n          filters: filters,\n        });\n      };\n    }\n\n    this.endpoint = function(path, filters) {\n      return new Query(_, {\n        url: this.url,\n        path: path,\n        filters: filters\n      });\n    };\n\n    this.get = function() {\n      var model = null;\n      if (call.related) {\n        model = call.relation + ':' + call.related;\n      } else if (call.model) {\n        model = call.model;\n      }\n\n      return _.ajax.get(this.url).then(function(data) {\n        if (model) {\n          if (data.results) {\n            data.results.map(function(item) {\n              return _.models.new(model, item);\n            });\n            return data;\n          } else {\n            return _.models.new(model, data);\n          }\n        } else {\n          return data;\n        }\n      });\n    };\n\n    this.post = function(data) {\n      return _.ajax.post(this.url, data);\n    };\n\n    this.patch = function(data) {\n      return _.ajax.patch(this.url, data);\n    };\n\n    this.put = function(data) {\n      return _.ajax.put(this.url, data);\n    };\n\n    this.delete = function() {\n      return _.ajax.delete(this.url);\n    };\n\n    // shortcut for get()\n    this.then = function(resolve, reject) {\n      return this.get().then(resolve, reject);\n    };\n  };\n\n  var Api = function(_) {\n    this.model = function(model, filters) {\n      return new Query(_, {\n        model: model,\n        filters: filters,\n      });\n    };\n\n    this.endpoint = function(path, filters) {\n      return new Query(_, {\n        path: path,\n        filters: filters\n      });\n    };\n\n    this.alert = function(rejection) {\n      // Shorthand for API errors\n      var message = gettext(\"Unknown error has occured.\");\n\n      if (rejection.status === 0) {\n        message = gettext(\"Lost connection with application.\");\n      }\n\n      if (rejection.status === 403) {\n        message = rejection.detail;\n        if (message === \"Permission denied\") {\n          message = gettext(\n            \"You don't have permission to perform this action.\");\n        }\n      }\n\n      if (rejection.status === 404) {\n        message = gettext(\"Action link is invalid.\");\n      }\n\n      _.alert.error(message);\n    };\n  };\n\n  Misago.addService('api', function(_) {\n    return new Api(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Auth = function(_) {\n    var self = this;\n\n    _.user = _.models.deserialize('user', _.context.user);\n\n    // Auth state synchronization across tabs\n    this.isDesynced = false; // becomes true if auth state between tabs differs\n    this.newUser = null; // becomes user obj to which we want to sync\n\n    var handleAuthChange = function(isAuthenticated) {\n      if (!self.isDesynced) {\n        m.startComputation();\n\n        // display annoying \"you were desynced\" message\n        self.isDesynced = true;\n\n        if (isAuthenticated) {\n          self.newUser = _.localstore.get('auth-user');\n        }\n\n        m.endComputation();\n      }\n    };\n\n    var handleUserChange = function(newUser) {\n      if (!self.isDesynced) {\n        m.startComputation();\n\n        if (_.user.id !== newUser.id) {\n          self.isDesynced = true;\n          self.newUser = newUser;\n        } else if (newUser) {\n          _.user = $.extend(_.user, newUser);\n        }\n\n        m.endComputation();\n      }\n    };\n\n    var syncSession = function() {\n      _.localstore.set('auth-user', _.user);\n      _.localstore.set('auth-is-authenticated', _.user.isAuthenticated);\n\n      _.localstore.watch('auth-is-authenticated', handleAuthChange);\n      _.localstore.watch('auth-user', handleUserChange);\n    };\n\n    syncSession();\n\n    // Access controls\n    this.denyAuthenticated = function(message) {\n      if (_.user.isAuthenticated) {\n        throw new Misago.PermissionDenied(\n          message || gettext(\"This page is not available to signed in users.\"));\n      }\n    };\n\n    this.denyAnonymous = function(message) {\n      if (_.user.isAnonymous) {\n        throw new Misago.PermissionDenied(\n          message || gettext(\"This page is not available to guests.\"));\n      }\n    };\n  };\n\n  Misago.addService('auth',\n  function(_) {\n    return new Auth(_);\n  },\n  {\n    after: 'model:user'\n  });\n}(Misago.prototype));\n\n/* global grecaptcha */\n(function (Misago) {\n  'use strict';\n\n  var NoCaptcha = function() {\n    var deferred = m.deferred();\n    deferred.resolve();\n\n    this.load = function() {\n      return deferred.promise;\n    };\n\n    this.value = function() {\n      return null;\n    };\n  };\n\n  var QACaptcha = function(_) {\n    var self = this;\n\n    this.loading = false;\n    this.question = null;\n    this.value = m.prop('');\n\n    var deferred = m.deferred();\n    this.load = function() {\n      this.value('');\n\n      if (!this.question && !this.loading) {\n        this.loading = true;\n\n        _.api.endpoint('captcha-question').get().then(function(question) {\n          self.question = question;\n          deferred.resolve();\n        }, function() {\n          _.api.alert(gettext('Failed to load CAPTCHA.'));\n          deferred.reject();\n        }).then(function() {\n          self.loading = true;\n        });\n      }\n\n      return deferred.promise;\n    };\n\n    this.component = function(kwargs) {\n      return _.component('form-group', {\n        label: this.question.question,\n        labelClass: kwargs.labelClass || null,\n        controlClass: kwargs.controlClass || null,\n        control: _.input({\n          value: _.validate(kwargs.form, 'captcha'),\n          id: 'id_captcha',\n          disabled: kwargs.form.isBusy\n        }),\n        validation: kwargs.form.errors,\n        validationKey: 'captcha',\n        helpText: this.question.help_text\n      });\n    };\n\n    this.validator = function() {\n      return [];\n    };\n  };\n\n  var ReCaptcha = function(_) {\n    this.included = false;\n    this.question = null;\n\n    var deferred = m.deferred();\n\n    var wait = function(promise) {\n      if (typeof grecaptcha !== \"undefined\") {\n        promise.resolve();\n      } else {\n        _.runloop.runOnce(function() {\n          wait(promise);\n        }, 'loading-grecaptcha', 150);\n      }\n    };\n\n    this.load = function() {\n      if (typeof grecaptcha !== \"undefined\") {\n        grecaptcha.reset();\n      }\n\n      if (!this.included) {\n        _.include('https://www.google.com/recaptcha/api.js', true);\n        this.included = true;\n      }\n\n      wait(deferred);\n\n      return deferred.promise;\n    };\n\n    var controlConfig = function(el, isInit, context) {\n      context.retain = true;\n\n      if (!isInit) {\n        grecaptcha.render('recaptcha', {\n          'sitekey': _.settings.recaptcha_site_key\n        });\n      }\n    };\n\n    this.component = function(kwargs) {\n      var control = m('#recaptcha', {\n        config: controlConfig\n      });\n\n      return _.component('form-group', {\n        label: gettext(\"Security test\"),\n        labelClass: kwargs.labelClass || null,\n        controlClass: kwargs.controlClass || null,\n        control: control,\n        validation: kwargs.form.errors,\n        validationKey: 'captcha'\n      });\n    };\n\n    this.value = function() {\n      if (typeof grecaptcha !== \"undefined\") {\n        return grecaptcha.getResponse();\n      } else {\n        return '';\n      }\n    };\n\n    this.clean = function(form) {\n      if (!this.value()) {\n        form.errors.captcha = [\n          gettext('This field is required.')\n        ];\n      } else {\n        form.errors.captcha = true;\n      }\n    };\n\n    this.validator = function() {\n      return [];\n    };\n  };\n\n  var Captcha = function(_) {\n    var types = {\n      'no': NoCaptcha,\n      'qa': QACaptcha,\n      're': ReCaptcha\n    };\n\n    var captcha = new types[_.settings.captcha_type](_);\n\n    this.value = captcha.value;\n\n    this.load = function() {\n      return captcha.load();\n    };\n\n    this.component = function(kwargs) {\n      if (captcha.component) {\n        return captcha.component(kwargs);\n      } else {\n        return null;\n      }\n    };\n\n    this.validator = function() {\n      if (captcha.validator) {\n        return captcha.validator();\n      } else {\n        return null;\n      }\n    };\n\n    this.clean = function(form) {\n      if (captcha.clean) {\n        captcha.clean(form);\n      } else {\n        form.errors.captcha = true;\n      }\n    };\n  };\n\n  Misago.addService('captcha', function(_) {\n    return new Captcha(_);\n  },\n  {\n    after: 'include'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var component = function(name, component) {\n    if (this._components[name]) {\n      if (arguments.length > 1) {\n        var argumentsArray = [this._components[name]];\n        for (var i = 1; i < arguments.length; i += 1) {\n          argumentsArray.push(arguments[i]);\n        }\n        argumentsArray.push(this);\n        return m.component.apply(undefined, argumentsArray);\n      } else {\n        return m.component(this._components[name], this);\n      }\n    } else if (component) {\n      this._components[name] = component;\n    } else {\n      throw '\"' + name + '\" component is not registered and can\\'t be created';\n    }\n  };\n\n  Misago.addService('components', function(_) {\n    _._components = {};\n    _.component = component;\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('conf', function(_) {\n    _.settings = Misago.get(_.context, 'SETTINGS', {});\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Dropdown = function(_) {\n    var slots = {};\n\n    this.toggle = function(elementId, component) {\n      var element = document.getElementById(elementId);\n\n      if (element.hasChildNodes() && slots[elementId] === component) {\n        slots[elementId] = null;\n        m.mount(element, null);\n        $(element).removeClass('open');\n      } else {\n        console.log(element.hasChildNodes());\n        slots[elementId] = component;\n        m.mount(element, _.component(component));\n        $(element).addClass('open');\n      }\n    };\n\n    this.destroy = function() {\n      var element = null;\n\n      for (var elementId in slots) {\n        if (slots.hasOwnProperty(elementId)) {\n          element = document.getElementById(elementId);\n          if (element && element.hasChildNodes()) {\n            m.mount(element, null);\n          }\n        }\n      }\n    };\n  };\n\n  Misago.addService('dropdown', {\n    factory: function(_) {\n      return new Dropdown(_);\n    },\n    destroy: function(_) {\n      _.dropdown.destroy();\n    }\n  },\n  {\n    before: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var boilerplate = function(form) {\n    var _submit = form.submit;\n    var _success = form.success;\n    var _error = form.error;\n\n    form.isBusy = false;\n\n    form.errors = null;\n\n    form.submit = function() {\n      if (form.isBusy) {\n        return false;\n      }\n\n      if (form.clean) {\n        if (form.clean()) {\n          form.isBusy = true;\n          _submit.apply(form);\n        }\n      } else {\n        form.isBusy = true;\n      }\n      return false;\n    };\n\n    form.success = function() {\n      m.startComputation();\n\n      _success.apply(form, arguments);\n      form.isBusy = false;\n\n      m.endComputation();\n    };\n\n    form.error = function() {\n      m.startComputation();\n\n      _error.apply(form, arguments);\n      form.isBusy = false;\n\n      m.endComputation();\n    };\n\n    form.hasErrors = function() {\n      if (form.errors === null) {\n        return false;\n      }\n\n      for (var key in form.validation) {\n        if (form.validation.hasOwnProperty(key)) {\n          if (form.errors[key] !== true) {\n            return true;\n          }\n        }\n      }\n\n      return false;\n    };\n\n    return form;\n  };\n\n  var form = function(name, constructor) {\n    if (this._forms[name]) {\n      if (constructor) {\n        return boilerplate(new this._forms[name](constructor, this));\n      } else {\n        return boilerplate(new this._forms[name](this));\n      }\n    } else {\n      this._forms[name] = constructor;\n    }\n  };\n\n  Misago.addService('forms', function(_) {\n    _._forms = {};\n    _.form = form;\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var include = function(script, remote) {\n    if (!remote) {\n      script = this.context.STATIC_URL + script;\n    }\n\n    $.ajax({\n      url: script,\n      cache: true,\n      dataType: 'script'\n    });\n  };\n\n  Misago.addService('include', function(_) {\n    _.include = include;\n  },\n  {\n    after: 'conf'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var setLinks = function(_) {\n    _.baseUrl = $('base').attr('href');\n\n    var staticUrl = Misago.get(_.context, 'STATIC_URL', '/');\n    var mediaUrl = Misago.get(_.context, 'MEDIA_URL', '/');\n\n    // Media/Static urls\n    var prefixUrl = function(prefix) {\n      return function(url) {\n        return prefix + url;\n      };\n    };\n\n    _.staticUrl = prefixUrl(staticUrl);\n    _.mediaUrl = prefixUrl(mediaUrl);\n  };\n\n  Misago.addService('links', function(_) {\n    setLinks(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var LocalStore = function() {\n    var storage = window.localStorage;\n    var prefix = '_misago_';\n    var watchers = [];\n\n    var handleStorageEvent = function(e) {\n      var newValueJson = JSON.parse(e.newValue);\n      $.each(watchers, function(i, watcher) {\n        if (watcher.keyName === e.key && e.oldValue !== e.newValue) {\n          watcher.callback(newValueJson);\n        }\n      });\n    };\n\n    window.addEventListener('storage', handleStorageEvent);\n\n    var prefixKey = function(keyName) {\n      return prefix + keyName;\n    };\n\n    this.set = function(keyName, value) {\n      storage.setItem(prefixKey(keyName), JSON.stringify(value));\n    };\n\n    this.get = function(keyName) {\n      var itemString = storage.getItem(prefixKey(keyName));\n      if (itemString) {\n        return JSON.parse(itemString);\n      } else {\n        return null;\n      }\n    };\n\n    this.watch = function(keyName, callback) {\n      watchers.push({keyName: prefixKey(keyName), callback: callback});\n    };\n\n    this.destroy = function() {\n      this.watchers = [];\n    };\n  };\n\n  Misago.addService('localstore', {\n    factory: function() {\n      return new LocalStore();\n    },\n    destroy: function(_) {\n      _.localstore.destroy();\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Modal = function() {\n    var self = this;\n\n    var element = document.getElementById('modal-mount');\n\n    this.destroy = function() {\n      $(element).off();\n      $('body').removeClass('modal-open');\n      $('.modal-backdrop').remove();\n    };\n\n    // Open/close modal\n    var modal = $(element).modal({show: false});\n    this.open = false;\n\n    modal.on('hidden.bs.modal', function () {\n      if (self.open) {\n        m.mount(element, null);\n        this.open = false;\n      }\n    });\n\n    this.show = function(component) {\n      this.open = true;\n      m.mount(element, component);\n      modal.modal('show');\n    };\n\n    this.hide = function() {\n      modal.modal('hide');\n    };\n  };\n\n  Misago.addService('_modal', {\n    factory: function() {\n      return new Modal();\n    },\n    destroy: function(_) {\n      _._modal.destroy();\n    }\n  },\n  {\n    before: 'mount:page-component'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var modal = function(name, component) {\n    if (this._modals[name]) {\n      var argumentsArray = [this._modals[name]];\n      for (var i = 1; i < arguments.length; i += 1) {\n        argumentsArray.push(arguments[i]);\n      }\n      argumentsArray.push(this);\n      this._modal.show(m.component.apply(m, argumentsArray));\n    } else if (name) {\n      this._modals[name] = component;\n    } else {\n      this._modal.hide();\n    }\n  };\n\n  Misago.addService('modals', function(_) {\n    _._modals = {};\n    _.modal = modal;\n  },\n  {\n    after: '_modal'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Models = function() {\n    this.classes = {};\n    this.deserializers = {};\n\n    this.add = function(name, kwargs) {\n      if (kwargs.class) {\n        this.classes[name] = kwargs.class;\n      }\n\n      if (kwargs.deserialize) {\n        this.deserializers[name] = kwargs.deserialize;\n      }\n    };\n\n    this.new = function(name, data) {\n      if (this.classes[name]) {\n        // Coerce ID to string\n        // This is done to avoid type comparisions gotchas\n        // later into app\n        data.id = data.id ? String(data.id) : null;\n\n        return new this.classes[name](data);\n      } else {\n        return data;\n      }\n    };\n\n    this.deserialize = function(name, json) {\n      if (this.deserializers[name]) {\n        return this.new(name, this.deserializers[name](json, this));\n      } else {\n        return this.new(name, json);\n      }\n    };\n  };\n\n  Misago.addService('models', function() {\n    return new Models();\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('set-momentjs-locale', function() {\n    moment.locale($('html').attr('lang'));\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mount = document.getElementById('page-mount');\n\n  Misago.addService('mount-page', function(_) {\n    _.mountPage = function(component) {\n      m.mount(mount, component);\n    };\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var RunLoop = function(_) {\n    var self = this;\n\n    this._intervals = {};\n\n    var stopInterval = function(name) {\n      if (self._intervals[name]) {\n        window.clearTimeout(self._intervals[name]);\n        self._intervals[name] = null;\n      }\n    };\n\n    this.run = function(callable, name, delay) {\n      this._intervals[name] = window.setTimeout(function() {\n        stopInterval(name);\n        var result = callable(_);\n        if (result !== false) {\n          self.run(callable, name, delay);\n        }\n      }, delay);\n    };\n\n    this.runOnce = function(callable, name, delay) {\n      this._intervals[name] = window.setTimeout(function() {\n        stopInterval(name);\n        callable(_);\n      }, delay);\n    };\n\n    this.stop = function(name) {\n      for (var loop in this._intervals) {\n        if (!name || name === loop) {\n          stopInterval(loop);\n        }\n      }\n    };\n  };\n\n  Misago.addService('runloop', {\n    factory: function(_) {\n      return new RunLoop(_);\n    },\n    destroy: function(_) {\n      _.runloop.stop();\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('show-banned-page', function(_) {\n    _.showBannedPage = function(ban, changeState) {\n      var component = _.component(\n        'banned-page', _.models.deserialize('ban', ban));\n\n      if (typeof changeState === 'undefined' || !changeState) {\n        _.title.set(gettext('You are banned'));\n        window.history.pushState({}, \"\", _.context.BANNED_URL);\n      }\n\n      _.mountPage(component);\n    };\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('start-tick', function(_) {\n    var ticks = m.prop();\n\n    _.runloop.run(function() {\n      m.startComputation();\n      // just tick once a minute so stuff gets rerendered\n      ticks(ticks() + 1);\n      // syncing dynamic timestamps, etc ect\n      m.endComputation();\n    }, 'tick', 60000);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var PageTitle = function(forum_name) {\n    this.set = function(title) {\n      if (title) {\n        this._set_complex(title);\n      } else {\n        document.title = forum_name;\n      }\n    };\n\n    this._set_complex = function(title) {\n      if (typeof title === 'string') {\n        title = {title: title};\n      }\n\n      var completeTitle = title.title;\n\n      if (typeof title.page !== 'undefined' && title.page > 1) {\n        var page_label = interpolate(\n          gettext('page %(page)s'), { page:title.page }, true);\n        completeTitle += ' (' + page_label + ')';\n      }\n\n      if (typeof title.parent !== 'undefined') {\n        completeTitle += ' | ' + title.parent;\n      }\n\n      document.title = completeTitle + ' | ' + forum_name;\n    };\n  };\n\n  Misago.addService('page-title', function(_) {\n    _.title = new PageTitle(_.settings.forum_name);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var EMAIL = /^(([^<>()[\\]\\.,;:\\s@\\\"]+(\\.[^<>()[\\]\\.,;:\\s@\\\"]+)*)|(\\\".+\\\"))@(([^<>()[\\]\\.,;:\\s@\\\"]+\\.)+[^<>()[\\]\\.,;:\\s@\\\"]{2,})$/i;\n  var USERNAME = new RegExp('^[0-9a-z]+$', 'i');\n\n  // Validators namespace\n  Misago.validators = {\n    required: function() {\n      return function(value) {\n        if ($.trim(value).length === 0) {\n          return gettext(\"This field is required.\");\n        }\n      };\n    },\n    email: function(message) {\n      return function(value) {\n        if (!EMAIL.test(value)) {\n          return message || gettext(\"Enter a valid email address.\");\n        }\n      };\n    },\n    minLength: function(limit_value, message) {\n      return function(value) {\n        var returnMessage = '';\n        var length = $.trim(value).length;\n\n        if (length < limit_value) {\n          if (message) {\n            returnMessage = message(limit_value, length);\n          } else {\n            returnMessage = ngettext(\n              \"Ensure this value has at least %(limit_value)s character (it has %(show_value)s).\",\n              \"Ensure this value has at least %(limit_value)s characters (it has %(show_value)s).\",\n              limit_value);\n          }\n          return interpolate(returnMessage, {\n            limit_value: limit_value,\n            show_value: length\n          }, true);\n        }\n      };\n    },\n    maxLength: function(limit_value, message) {\n      return function(value) {\n        var returnMessage = '';\n        var length = $.trim(value).length;\n\n        if (length > limit_value) {\n          if (message) {\n            returnMessage = message(limit_value, length);\n          } else {\n            returnMessage = ngettext(\n              \"Ensure this value has at most %(limit_value)s character (it has %(show_value)s).\",\n              \"Ensure this value has at most %(limit_value)s characters (it has %(show_value)s).\",\n              limit_value);\n          }\n          return interpolate(returnMessage, {\n            limit_value: limit_value,\n            show_value: length\n          }, true);\n        }\n      };\n    },\n    usernameMinLength: function(settings) {\n      var message = function(limit_value) {\n        return ngettext(\n          \"Username must be at least %(limit_value)s character long.\",\n          \"Username must be at least %(limit_value)s characters long.\",\n          limit_value);\n      };\n      return this.minLength(settings.username_length_min, message);\n    },\n    usernameMaxLength: function(settings) {\n      var message = function(limit_value) {\n        return ngettext(\n          \"Username cannot be longer than %(limit_value)s character.\",\n          \"Username cannot be longer than %(limit_value)s characters.\",\n          limit_value);\n      };\n      return this.maxLength(settings.username_length_max, message);\n    },\n    usernameContent: function() {\n      return function(value) {\n        if (!USERNAME.test($.trim(value))) {\n          return gettext(\"Username can only contain latin alphabet letters and digits.\");\n        }\n      };\n    },\n    passwordMinLength: function(settings) {\n      var message = function(limit_value) {\n        return ngettext(\n          \"Valid password must be at least %(limit_value)s character long.\",\n          \"Valid password must be at least %(limit_value)s characters long.\",\n          limit_value);\n      };\n      return this.minLength(settings.password_length_min, message);\n    }\n  };\n\n  var validateField = function(value, validators) {\n    var result = Misago.validators.required()(value);\n    var errors = [];\n\n    if (result) {\n      return [result];\n    } else {\n      for (var i in validators) {\n        result = validators[i](value);\n\n        if (result) {\n          errors.push(result);\n        }\n      }\n    }\n\n    return errors.length ? errors : true;\n  };\n\n  var validateForm = function(form) {\n    var errors = {};\n    var value = null;\n\n    var isValid = true;\n\n    for (var key in form.validation) {\n      if (form.validation.hasOwnProperty(key)) {\n        value = form[key]();\n        errors[key] = validateField(form[key](), form.validation[key]);\n        if (errors[key] !== true) {\n          isValid = false;\n        }\n      }\n    }\n\n    form.errors = errors;\n    return isValid;\n  };\n\n  var validate = function(form, name) {\n    if (name) {\n      return function(value) {\n        var errors = null;\n        if (typeof value !== 'undefined') {\n          errors = validateField(value, form.validation[name]);\n          if (errors) {\n            if (!form.errors) {\n              form.errors = {};\n            }\n            form.errors[name] = errors;\n          }\n          form[name](value);\n          return form[name](value);\n        } else {\n          return form[name]();\n        }\n      };\n    } else {\n      return validateForm(form);\n    }\n  };\n\n  Misago.addService('validate', {\n    factory: function() {\n      return validate;\n    }\n  });\n}(Misago.prototype));\n\n/* global zxcvbn */\n(function (Misago) {\n  'use strict';\n\n  var Zxcvbn = function(_) {\n    this.included = false;\n\n    this.scorePassword = function(password, inputs) {\n      // 0-4 score, the more the stronger password\n      return zxcvbn(password, inputs).score;\n    };\n\n    // loading\n    this.include = function() {\n      _.include('misago/js/zxcvbn.js');\n      this.included = true;\n    };\n\n    var wait = function(promise) {\n      if (typeof zxcvbn !== \"undefined\") {\n        promise.resolve();\n      } else {\n        _.runloop.runOnce(function() {\n          wait(promise);\n        }, 'loading-zxcvbn', 150);\n      }\n    };\n\n    var deferred = m.deferred();\n    this.load = function() {\n      if (!this.included) {\n        this.include();\n      }\n      wait(deferred);\n      return deferred.promise;\n    };\n  };\n\n  Misago.addService('zxcvbn', function(_) {\n    return new Zxcvbn(_);\n  },\n  {\n    after: 'include'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Ban = function(data) {\n    this.message = {\n      html: data.message.html,\n      plain: data.message.plain,\n    };\n\n    this.expires_on = data.expires_on;\n  };\n\n  var deserializeBan = function(data) {\n    data.expires_on = Misago.deserializeDatetime(data.expires_on);\n\n    return data;\n  };\n\n  Misago.addService('model:ban', function(_) {\n    _.models.add('ban', {\n      class: Ban,\n      deserialize: deserializeBan\n    });\n  },\n  {\n    after: 'models'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var LegalPage = function(data) {\n    this.title = data.title;\n    this.body = data.body;\n    this.link = data.link;\n  };\n\n  Misago.addService('model:legal-page', function(_) {\n    _.models.add('legal-page', {\n      class: LegalPage\n    });\n  },\n  {\n    after: 'models'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Rank = function(data) {\n    this.id = data.id;\n\n    this.name = data.name;\n    this.slug = data.slug;\n\n    this.description = data.description;\n\n    this.title = data.title;\n    this.css_class = data.css_class;\n\n    this.is_tab = data.is_tab;\n  };\n\n  Misago.addService('model:rank', function(_) {\n    _.models.add('rank', {\n      class: Rank\n    });\n  },\n  {\n    after: 'models'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var User = function(data) {\n    this.id = data.id;\n\n    this.isAuthenticated = !!this.id;\n    this.isAnonymous = !this.isAuthenticated;\n\n    this.username = data.username;\n    this.slug = data.slug;\n\n    this.email = data.email;\n\n    this.full_title = data.full_title;\n    this.rank = data.rank;\n\n    this.avatar_hash = data.avatar_hash;\n\n    this.acl = data.acl;\n\n    this.absolute_url = data.absolute_url;\n  };\n\n  var deserializeUser = function(data, models) {\n    if (data.joined_on) {\n      data.joined_on = Misago.deserializeDatetime(data.joined_on);\n    }\n\n    if (data.rank) {\n      data.rank = models.deserialize('rank', data.rank);\n    }\n\n    return data;\n  };\n\n  Misago.addService('model:user', function(_) {\n    _.models.add('user', {\n      class: User,\n      deserialize: deserializeUser\n    });\n  },\n  {\n    after: 'model:rank'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var style = '.well.well-form.well-form-request-activation-link';\n\n  var ViewModel = function(api) {\n    this.api = api;\n    this.user = null;\n\n    this.success = function(user) {\n      this.user = user;\n    };\n\n    this.error = function(rejection, _) {\n      if (rejection.code === 'already_active') {\n        _.alert.info(rejection.detail);\n        _.modal('sign-in');\n      } else if (rejection.code === 'inactive_admin') {\n        _.alert.info(rejection.detail);\n      } else {\n        _.alert.error(rejection.detail);\n      }\n    };\n\n    this.reset = function() {\n      this.user = null;\n    };\n  };\n\n  var form = {\n    controller: function(_) {\n      var vm = new ViewModel(_.context.SEND_ACTIVATION_API_URL);\n\n      return {\n        vm: vm,\n        form: _.form('request-link', vm)\n      };\n    },\n    view: function(ctrl, _) {\n      if (ctrl.vm.user) {\n        return this.done(ctrl.vm, ctrl.form, _);\n      } else {\n        return this.form(ctrl.form, _);\n      }\n    },\n    done: function(vm, form, _) {\n      var message = gettext(\"Activation link sent to %(email)s.\");\n\n      return m(style + '.well-done',\n        m('.done-message', [\n          m('.message-icon',\n            m('span.material-icon', 'check')\n          ),\n          m('.message-body',\n            m('p',\n              interpolate(message, {\n                email: vm.user.email\n              }, true)\n            )\n          ),\n          _.component('button', {\n            class: '.btn-default.btn-block',\n            submit: false,\n            label: gettext(\"Request another link\"),\n            onclick: form.reset.bind(form)\n          })\n\n        ])\n      );\n    },\n    form: function(form, _) {\n      return m(style,\n        m('form', {onsubmit: form.submit}, [\n          m('.form-group',\n            m('.control-input',\n              Misago.input({\n                disabled: form.isBusy,\n                value: form.email,\n                placeholder: gettext(\"Your e-mail address\")\n              })\n            )\n          ),\n          _.component('button', {\n            class: '.btn-primary.btn-block',\n            submit: true,\n            loading: form.isBusy,\n            label: gettext(\"Send link\")\n          })\n        ])\n      );\n    }\n  };\n\n  Misago.addService('component:request-link-form', function(_) {\n    _.component('request-activation-link-form', form);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var header = {\n    view: function(ctrl, title) {\n      return m('.modal-header', [\n        m('button.close[type=\"button\"]',\n          {'data-dismiss': 'modal', 'aria-label': gettext('Close')},\n          m('span', {'aria-hidden': 'true'}, m.trust('&times;'))\n        ),\n        m('h4#misago-modal-label.modal-title', title)\n      ]);\n    }\n  };\n\n  Misago.addService('component:modal:header', function(_) {\n    _.component('modal:header', header);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  var refresh = function() {\n    document.location.reload();\n  };\n\n  var registerComplete = {\n    controller: function(message, _) {\n      if (message.activation === 'active') {\n        _.runloop.runOnce(\n          refresh, 'refresh-after-registration', 10000);\n      }\n    },\n    view: function(ctrl, message, _) {\n      var messageHtml = null;\n\n      if (message.activation === 'active') {\n        messageHtml = this.active(message);\n      } else {\n        messageHtml = this.inactive(message);\n      }\n\n      return m('.modal-dialog.modal-message.modal-register[role=\"document\"]',\n        {config: persistent},\n        m('.modal-content', [\n          _.component('modal:header', gettext('Registration complete')),\n          m('.modal-body',\n            messageHtml\n          )\n        ])\n      );\n    },\n    active: function(message) {\n      var lead = gettext(\"%(username)s, your account has been created and you were signed in.\");\n      return [\n        m('.message-icon',\n          m('span.material-icon', 'check')\n        ),\n        m('.message-body', [\n          m('p.lead',\n            interpolate(lead, {'username': message.username}, true)\n          ),\n          m('p',\n            gettext('The page will refresh automatically in 10 seconds.')\n          ),\n          m('p',\n            m('button[type=\"button\"].btn.btn-default', {onclick: refresh},\n              gettext('Refresh page')\n            )\n          )\n        ])\n      ];\n    },\n    inactive: function(message) {\n      var lead = null;\n      var help = null;\n\n      if (message.activation === 'user') {\n        lead = gettext(\"%(username)s, your account has been created but you need to activate it before you will be able to sign in.\");\n        help = gettext(\"We have sent an e-mail to %(email)s with link that you have to click to activate your account.\");\n      } else if (message.activation === 'admin') {\n        lead = gettext(\"%(username)s, your account has been created but board administrator will have to activate it before you will be able to sign in.\");\n        help = gettext(\"We will send an e-mail to %(email)s when this takes place.\");\n      }\n\n      return [\n        m('.message-icon',\n          m('span.material-icon', 'info_outline')\n        ),\n        m('.message-body', [\n          m('p.lead',\n            interpolate(lead, {'username': message.username}, true)\n          ),\n          m('p',\n            interpolate(help, {'email': message.email}, true)\n          )\n        ])\n      ];\n    }\n  };\n\n  Misago.addService('modal:register-complete', function(_) {\n    _.modal('register-complete', registerComplete);\n  },\n  {\n    after: 'modals'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  var register = {\n    controller: function(_) {\n      return {\n        form: _.form('register')\n      };\n    },\n    view: function(ctrl, _) {\n      var captcha = _.captcha.component({\n        form: ctrl.form,\n\n        labelClass: '.col-md-4',\n        controlClass: '.col-md-8'\n      });\n\n      var footnote = null;\n\n      if (_.context.TERMS_OF_SERVICE_URL) {\n        footnote = m('a', {href: _.context.TERMS_OF_SERVICE_URL},\n          m.trust(interpolate(gettext(\"By registering you agree to site's %(terms)s.\"), {\n            terms: '<strong>' + gettext(\"terms and conditions\") + '</strong>'\n          }, true))\n        );\n      }\n\n      return m('.modal-dialog.modal-form.modal-register[role=\"document\"]',\n        {config: persistent},\n        m('.modal-content', [\n          _.component('modal:header', gettext('Register')),\n          m('form.form-horizontal',\n          {\n            onsubmit: ctrl.form.submit\n          },\n          [\n            m('input[type=\"text\"]', {\n              name:'_username',\n              style: 'display: none'\n            }),\n            m('input[type=\"password\"]', {\n              name:'_password',\n              style: 'display: none'\n            }),\n            m('.modal-body', [\n              _.component('form-group', {\n                label: gettext(\"Username\"),\n                labelClass: '.col-md-4',\n                controlClass: '.col-md-8',\n                control: _.input({\n                  value: _.validate(ctrl.form, 'username'),\n                  id: 'id_username',\n                  disabled: ctrl.form.isBusy\n                }),\n                validation: ctrl.form.errors,\n                validationKey: 'username'\n              }),\n              _.component('form-group', {\n                label: gettext(\"E-mail\"),\n                labelClass: '.col-md-4',\n                controlClass: '.col-md-8',\n                control: _.input({\n                  value: _.validate(ctrl.form, 'email'),\n                  id: 'id_email',\n                  disabled: ctrl.form.isBusy\n                }),\n                validation: ctrl.form.errors,\n                validationKey: 'email'\n              }),\n              _.component('form-group', {\n                label: gettext(\"Password\"),\n                labelClass: '.col-md-4',\n                controlClass: '.col-md-8',\n                control: _.input({\n                  value: _.validate(ctrl.form, 'password'),\n                  type: 'password',\n                  id: 'id_password',\n                  disabled: ctrl.form.isBusy\n                }),\n                validation: ctrl.form.errors,\n                validationKey: 'password',\n                helpText: _.component('password-strength', {\n                  inputs: [\n                    ctrl.form.username(),\n                    ctrl.form.email()\n                  ],\n                  password: ctrl.form.password()\n                })\n              }),\n              captcha\n            ]),\n            m('.modal-footer', [\n              footnote,\n              _.component('button', {\n                class: '.btn-primary',\n                submit: true,\n                loading: ctrl.form.isBusy,\n                label: gettext(\"Register account\")\n              })\n            ])\n          ])\n        ])\n      );\n    }\n  };\n\n  Misago.addService('modal:register', function(_) {\n    _.modal('register', register);\n  },\n  {\n    after: 'modals'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  function persistent(el, isInit, context) {\n    context.retain = true;\n  }\n\n  var signin = {\n    controller: function(_) {\n      return {\n        form: _.form('sign-in')\n      };\n    },\n    view: function(ctrl, _) {\n      var activateButton = null;\n\n      if (ctrl.form.showActivation) {\n        activateButton = m('a.btn.btn-block.btn-success',\n          {href: _.context.REQUEST_ACTIVATION_URL},\n          gettext(\"Activate account\")\n        );\n      }\n\n      return m('.modal-dialog.modal-sm.modal-signin[role=\"document\"]',\n        {config: persistent},\n        m('.modal-content', [\n          _.component('modal:header', gettext(\"Sign in\")),\n          m('form', {onsubmit: ctrl.form.submit}, [\n            m('.modal-body', [\n              m('.form-group',\n                m('.control-input',\n                  Misago.input({\n                    disabled: ctrl.form.isBusy,\n                    value: ctrl.form.username,\n                    placeholder: gettext(\"Username or e-mail\")\n                  })\n                )\n              ),\n              m('.form-group',\n                m('.control-input',\n                  Misago.input({\n                    type: 'password',\n                    disabled: ctrl.form.isBusy,\n                    value: ctrl.form.password,\n                    placeholder: gettext(\"Password\")\n                  })\n                )\n              )\n            ]),\n            m('.modal-footer', [\n              activateButton,\n              _.component('button', {\n                class: '.btn-primary.btn-block',\n                submit: true,\n                loading: ctrl.form.isBusy,\n                label: gettext(\"Sign in\")\n              }),\n              m('a.btn.btn-block.btn-default',\n                {href: _.context.FORGOTTEN_PASSWORD_URL},\n                gettext(\"Forgot password?\")\n              )\n            ])\n          ])\n        ])\n      );\n    }\n  };\n\n  Misago.addService('modal:sign-in', function(_) {\n    _.modal('sign-in', signin);\n  },\n  {\n    after: 'modals'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var dropdown = {\n    controller: function(_) {\n      return {\n        showSignIn: function() {\n          _.modal('sign-in');\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('ul.dropdown-menu.user-dropdown.dropdown-menu-right[role=\"menu\"]',\n        m('li.guest-preview', [\n          m('h4',\n            gettext(\"You are browsing as guest.\")\n          ),\n          m('p',\n            gettext('Sign in or register to start and participate in discussions.')\n          ),\n          m('.row', [\n            m('.col-xs-6',\n              _.component('button', {\n                class: '.btn.btn-default.btn-block',\n                onclick: ctrl.showSignIn,\n                disabled: ctrl.isBusy,\n                label: gettext('Sign in')\n              })\n            ),\n            m('.col-xs-6',\n              _.component(\n                'navbar:register-button', '.btn.btn-primary.btn-block')\n            )\n          ])\n        ])\n      );\n    }\n  };\n\n  Misago.addService('component:navbar:dropdown:guest', function(_) {\n    _.component('navbar:dropdown:guest', dropdown);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var navbar = {\n    style: '.nav.navbar-nav.navbar-compact-nav.hidden-md.hidden-lg',\n    controller: function(links, _) {\n      return {\n        openUserMenu: function() {\n          if (_.user.isAuthenticated) {\n            _.dropdown.toggle('navbar-dropdown', 'navbar:dropdown:user');\n          } else {\n            _.dropdown.toggle('navbar-dropdown', 'navbar:dropdown:guest');\n          }\n\n          return false;\n        }\n      };\n    },\n    userMenu: function(ctrl, _) {\n      if (_.user.isAuthenticated) {\n        return {\n          element: _.component('user-avatar', _.user, 64),\n          config: {\n            onclick: ctrl.openUserMenu,\n            url: '/not-yet/',\n\n            'data-misago-routed': 'false'\n          }\n        };\n      } else {\n        return {\n          element: _.component('user-avatar', null, 64),\n          config: {\n            onclick: ctrl.openUserMenu,\n            href: '#',\n\n            'data-misago-routed': 'false'\n          }\n        };\n      }\n    },\n    mobileNav: function(ctrl, links, _) {\n      var mobileLinks = [\n        {\n          element: m('img', {\n            src: _.router.staticUrl('misago/img/site-icon.png'),\n            alt: _.settings.forum_name\n          }),\n          url: _.router.url('index')\n        }\n      ];\n\n      links.forEach(function(link) {\n        if (link.url !== mobileLinks[0].url) {\n          mobileLinks.push(link);\n        }\n      });\n\n      mobileLinks.push(this.userMenu(ctrl, _));\n\n      return mobileLinks;\n    },\n    view: function(ctrl, links, _) {\n      var mobileLinks = this.mobileNav(ctrl, links, _);\n\n      return m('ul' + this.style + '.with-' + mobileLinks.length + '-items',\n        mobileLinks.map(function(link) {\n          return m('li',\n            m('a', link.config || {href: link.url},\n              link.element || m('span.material-icon', {title:link.label},\n                link.icon\n              )\n            )\n          );\n        })\n      );\n    }\n  };\n\n  Misago.addService('component:navbar:mobile', function(_) {\n    _.component('navbar:mobile', navbar);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var button = {\n    controller: function(style, _) {\n      return {\n        isBusy: false,\n\n        showRegister: function() {\n          if (_.settings.account_activation === 'closed') {\n            _.alert.info(gettext(\"New registrations are currently disabled.\"));\n          } else {\n            m.startComputation();\n            this.isBusy = true;\n            m.endComputation();\n\n            var self = this;\n            m.sync([\n              _.zxcvbn.load(),\n              _.captcha.load()\n            ]).then(function() {\n              _.modal('register');\n            }, function() {\n              _.alert.error(gettext('Registation is not available now due to an error.'));\n            }).then(function() {\n              m.startComputation();\n              self.isBusy = false;\n              m.endComputation();\n            });\n          }\n        }\n      };\n    },\n    view: function(ctrl, style, _) {\n      return _.component('button', {\n        class: style,\n        onclick: ctrl.showRegister.bind(ctrl),\n        loading: ctrl.isBusy,\n        label: gettext('Register')\n      });\n    }\n  };\n\n  Misago.addService('component:navbar:register-button', function(_) {\n    _.component('navbar:register-button', button);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var dropdown = {\n    class: '.dropdown-menu.user-dropdown.dropdown-menu-right',\n\n    controller: function() {\n      return {\n        logout: function() {\n          var decision = confirm(gettext(\"Are you sure you want to sign out?\"));\n          if (decision) {\n            $('#hidden-logout-form').submit();\n          }\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('ul' + this.class + '[role=\"menu\"]', [\n        m('li.dropdown-header',\n          m('strong',\n            _.user.username\n          )\n        ),\n        m('li.divider'),\n        m('li',\n          m('a', {href: _.user.absolute_url}, [\n            m('span.material-icon',\n              'account_circle'\n            ),\n            gettext(\"See your profile\")\n          ])\n        ),\n        m('li',\n          m('a', {href: _.context.USERCP_URL}, [\n            m('span.material-icon',\n              'done_all'\n            ),\n            gettext(\"Change options\")\n          ])\n        ),\n        m('li',\n          m('button.btn-link[type=\"button\"]', [\n            m('span.material-icon',\n              'face'\n            ),\n            gettext(\"Change avatar\")\n          ])\n        ),\n        m('li.divider'),\n        m('li.dropdown-footer',\n          m('button.btn.btn-default.btn-block', {onclick: ctrl.logout},\n            gettext(\"Logout\")\n          )\n        )\n      ]);\n    }\n  };\n\n  Misago.addService('component:navbar:dropdown:user', function(_) {\n    _.component('navbar:dropdown:user', dropdown);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var nav = {\n    controller: function(_) {\n      return {\n        openUserMenu: function() {\n          _.dropdown.toggle('navbar-dropdown', 'navbar:dropdown:guest');\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('button', {type: 'button', onclick: ctrl.openUserMenu},\n        _.component('user-avatar', null, 64)\n      );\n    }\n  };\n\n  Misago.addService('component:navbar:compact:guest-nav', function(_) {\n    _.component('navbar:compact:guest-nav', nav);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var nav = {\n    controller: function(_) {\n      return {\n        openUserMenu: function() {\n          _.dropdown.toggle('navbar-dropdown', 'navbar:dropdown:user');\n          return false;\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      var config = {\n        onclick: ctrl.openUserMenu,\n        href: _.user.absolute_url\n      };\n\n      return m('a', config,\n        _.component('user-avatar', _.user, 64)\n      );\n    }\n  };\n\n  Misago.addService('component:navbar:compact:user-nav', function(_) {\n    _.component('navbar:compact:user-nav', nav);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var nav = {\n    controller: function(_) {\n      return {\n        showSignIn: function() {\n          _.modal('sign-in');\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('div.nav.nav-guest', [\n        _.component('button', {\n          class: '.navbar-btn.btn-default',\n          onclick: ctrl.showSignIn,\n          disabled: ctrl.isBusy,\n          label: gettext('Sign in')\n        }),\n        _.component('navbar:register-button', '.navbar-btn.btn-primary')\n      ]);\n    }\n  };\n\n  Misago.addService('component:navbar:desktop:guest-nav', function(_) {\n    _.component('navbar:desktop:guest-nav', nav);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var nav = {\n    controller: function(_) {\n      return {\n        dropdownToggle: {\n          href: _.user.absolute_url,\n\n          'data-toggle': 'dropdown',\n          'data-misago-routed': 'false',\n\n          'aria-haspopup': 'true',\n          'aria-expanded': 'false'\n        }\n      };\n    },\n    view: function(ctrl, _) {\n      return m('ul.nav.navbar-nav.nav-user', [\n        m('li.dropdown', [\n          m('a.dropdown-toggle[role=\"button\"]', ctrl.dropdownToggle,\n            _.component('user-avatar', _.user, 64)\n          ),\n          _.component('navbar:dropdown:user')\n        ])\n      ]);\n    }\n  };\n\n  Misago.addService('component:navbar:desktop:user-nav', function(_) {\n    _.component('navbar:desktop:user-nav', nav);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  function persistent(el, isInit, context) {\n    context.retain = true;\n  }\n\n  var alert = {\n    classes: {\n      'info': 'alert-info',\n      'success': 'alert-success',\n      'warning': 'alert-warning',\n      'error': 'alert-danger'\n    },\n    view: function(ctrl, _) {\n      var config = {\n        config: persistent,\n        class: _.alert.isVisible ? 'in' : 'out'\n      };\n\n      return m('.alerts', config,\n        m('p.alert', {class: this.classes[_.alert.type]},\n          _.alert.message\n        )\n      );\n    }\n  };\n\n  Misago.addService('component:alert', function(_) {\n    _.component('alert', alert);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  function persistent(el, isInit, context) {\n    context.retain = true;\n  }\n\n  var authChanged = {\n    refresh: function() {\n      window.location.reload();\n    },\n    view: function(ctrl, _) {\n      var message = '';\n\n      var options = {\n        config: persistent,\n        class: (_.auth.isDesynced ? 'show' : null)\n      };\n\n      if (_.auth.isDesynced) {\n        if (_.auth.newUser && _.auth.newUser.isAuthenticated) {\n          message = gettext(\"You have signed in as %(username)s. Please refresh this page before continuing.\");\n          message = interpolate(message, {username: _.auth.newUser.username}, true);\n        } else {\n          message = gettext(\"%(username)s, you have been signed out. Please refresh this page before continuing.\");\n          message = interpolate(message, {username: _.user.username}, true);\n        }\n      }\n\n      return m('.auth-changed-message', options,\n        m('',\n          m('.container', [\n            m('p',\n              message\n            ),\n            m('p', [\n              m('button.btn.btn-default[type=\"button\"]', {onclick: this.refresh},\n                gettext(\"Reload page\")\n              ),\n              m('span.hidden-xs.hidden-sm.text-muted',\n                gettext(\"or press F5 key.\")\n              )\n            ])\n          ])\n        )\n      );\n    }\n  };\n\n  Misago.addService('component:auth-changed-message', function(_) {\n    _.component('auth-changed-message', authChanged);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var banExpirationMessage = {\n    controller: function(ban, container) {\n      var _ = container || ban;\n\n      if (container) {\n        return ban;\n      } else {\n        return _.models.deserialize('ban', _.context.ban);\n      }\n    },\n    view: function(ban) {\n      var expirationMessage = null;\n      if (ban.expires_on) {\n        if (ban.expires_on.isAfter(moment())) {\n          expirationMessage = interpolate(\n            gettext('This ban expires %(expires_on)s.'),\n            {'expires_on': ban.expires_on.fromNow()},\n            true);\n        } else {\n          expirationMessage = gettext('This ban has expired.');\n        }\n      } else {\n        expirationMessage = gettext('This ban is permanent.');\n      }\n\n      return m('p', expirationMessage);\n    }\n  };\n\n  Misago.addService('component:ban-expiration-message', function(_) {\n    _.component('ban-expiration-message', banExpirationMessage);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n\n(function (Misago) {\n  'use strict';\n\n  var bannedPage = {\n    view: function(ctrl, ban, _) {\n      var error_message = [];\n\n      if (ban.message.html) {\n        error_message.push(m('.lead', m.trust(ban.message.html)));\n      } else {\n        error_message.push(m('p.lead', ban.message.plain));\n      }\n\n      error_message.push(_.component('ban-expiration-message', ban));\n\n      return m('.page.page-error.page-error-banned',\n        m('.container',\n          m('.message-panel', [\n            m('.message-icon',\n              m('span.material-icon', 'highlight_off')\n            ),\n            m('.message-body', error_message)\n          ])\n        )\n      );\n    }\n  };\n\n  Misago.addService('component:banned-page', function(_) {\n    _.component('banned-page', bannedPage);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var button = {\n    view: function(ctrl, kwargs) {\n      var options = {\n        disabled: kwargs.disabled || kwargs.loading || false,\n        config: kwargs.config || null,\n        loading: kwargs.loading || false,\n        type: kwargs.submit ? 'submit' : 'button',\n        onclick: kwargs.onclick || null\n      };\n\n      var element = 'button[type=\"' + options.type + '\"].btn';\n      if (options.loading) {\n        element += '.btn-loading';\n      }\n\n      if (kwargs.id) {\n        element += '#' + kwargs.id;\n      }\n\n      element += (kwargs.class || '');\n\n      var label = kwargs.label;\n      if (options.loading) {\n        label = [\n          label,\n          m('.loader-compact', [\n            m('.bounce1'),\n            m('.bounce2'),\n            m('.bounce3')\n          ])\n        ];\n      }\n\n      return m(element, options, label);\n    },\n  };\n\n  Misago.addService('component:button', function(_) {\n    _.component('button', button);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var textFields = ['text', 'password', 'email'];\n\n  var formGroup = {\n    view: function(ctrl, kwargs) {\n      var groupClass = '.form-group';\n      var errors = null;\n      var helpText = null;\n\n      var controlType = kwargs.control.attrs.type;\n      var controlId = kwargs.control.attrs.id;\n\n      var feedbackId = controlId + '_feedback';\n      var feedbackIcon = null;\n      var showFeedbackIcon = null;\n\n      var isValidated = kwargs.validationKey && kwargs.validation !== null;\n\n      kwargs.control.attrs['aria-describedby'] = '';\n\n      if (isValidated && kwargs.validation[kwargs.validationKey]) {\n        showFeedbackIcon = textFields.indexOf(controlType) >= 0;\n        kwargs.control.attrs['aria-describedby'] = feedbackId;\n\n        if (kwargs.validation[kwargs.validationKey] === true) {\n          groupClass += '.has-success';\n          feedbackIcon = [\n            m('span.material-icon.form-control-feedback',\n              {\n                'aria-hidden': 'true'\n              },\n              'check'\n            ),\n            m('span.sr-only#' + feedbackId, gettext(\"(success)\"))\n          ];\n        } else {\n          groupClass += '.has-error';\n          errors = kwargs.validation[kwargs.validationKey];\n          feedbackIcon = [\n            m('span.material-icon.form-control-feedback',\n              {\n                'aria-hidden': 'true'\n              },\n              'clear'\n            ),\n            m('span.sr-only#' + feedbackId, gettext(\"(error)\"))\n          ];\n        }\n      }\n\n      if (kwargs.helpText) {\n        if (typeof kwargs.helpText === 'string' ||\n            kwargs.helpText instanceof String) {\n          helpText = m('p.help-block', kwargs.helpText);\n        } else {\n          helpText = kwargs.helpText;\n        }\n      }\n\n      return m(groupClass, [\n        m('label.control-label' + (kwargs.labelClass || ''),\n          {\n            for: kwargs.labelFor || controlId\n          },\n          kwargs.label + ':'\n        ),\n        m(kwargs.controlClass || '', [\n          kwargs.control,\n          showFeedbackIcon ? feedbackIcon : null,\n          errors ? m('.help-block.errors', errors.map(function(item) {\n            return m('p', item);\n          })) : null,\n          helpText\n        ])\n      ]);\n    },\n  };\n\n  Misago.addService('component:form-group', function(_) {\n    _.component('form-group', formGroup);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var loader = {\n    view: function() {\n      return m('.loader.sk-folding-cube', [\n        m('.sk-cube1.sk-cube'),\n        m('.sk-cube2.sk-cube'),\n        m('.sk-cube4.sk-cube'),\n        m('.sk-cube3.sk-cube')\n      ]);\n    }\n  };\n\n  Misago.addService('component:loader', function(_) {\n    _.component('loader', loader);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  var markup = {\n    view: function(ctrl, content) {\n      return m('article.misago-markup', {config: persistent},\n        m.trust(content)\n      );\n    }\n  };\n\n  Misago.addService('component:markup', function(_) {\n    _.component('markup', markup);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var header = {\n    view: function(ctrl, options) {\n      return m('.page-header',\n        m('.container', [\n          m('h1', options.title),\n        ])\n      );\n    }\n  };\n\n  Misago.addService('component:header', function(_) {\n    _.component('header', header);\n  },\n  {\n    after: 'components'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var persistent = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  var styles = [\n    'progress-bar-danger',\n    'progress-bar-warning',\n    'progress-bar-warning',\n    'progress-bar-primary',\n    'progress-bar-success'\n  ];\n\n  var labels = [\n    gettext('Entered password is very weak.'),\n    gettext('Entered password is weak.'),\n    gettext('Entered password is average.'),\n    gettext('Entered password is strong.'),\n    gettext('Entered password is very strong.')\n  ];\n\n  var passwordStrength = {\n    view: function(ctrl, kwargs, _) {\n      var score = _.zxcvbn.scorePassword(kwargs.password, kwargs.inputs);\n      var options = {\n        config: persistent,\n        class: styles[score],\n        style: \"width: \" + (20 + (20 * score)) + '%',\n        'role': \"progressbar\",\n        'aria-valuenow': score,\n        'aria-valuemin': \"0\",\n        'aria-valuemax': \"4\"\n      };\n\n      return m('.help-block.password-strength', {key: 'password-strength'}, [\n        m('.progress',\n          m('.progress-bar', options,\n            m('span.sr-only', labels[score])\n          )\n        ),\n        m('p.text-small', labels[score])\n      ]);\n    },\n  };\n\n  Misago.addService('component:password-strength', function(_) {\n    _.component('password-strength', passwordStrength);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var avatar = {\n    defaultSize: 100,\n\n    src: function(user, size, _) {\n      var src = _.baseUrl + 'user-avatar/';\n\n      if (user && user.id) {\n        // just avatar hash, size and user id\n        src += user.avatar_hash + '/' + size + '/' + user.id + '.png';\n      } else {\n        // just append avatar size to file to produce no-avatar placeholder\n        src += size + '.png';\n      }\n\n      return src;\n    },\n    view: function(ctrl, user, size, _) {\n      var finalSize = size || this.defaultSize;\n      return m('img', {\n        alt: user && user.username ? user.username : gettext(\"Unregistered\"),\n        width: finalSize,\n        height: finalSize,\n        src: this.src(user, finalSize, _)\n      });\n    }\n  };\n\n  Misago.addService('component:user-avatar', function(_) {\n    _.component('user-avatar', avatar);\n  },\n  {\n    after: 'components'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var ChangePassword = function(_) {\n    var self = this;\n\n    this.username = null;\n    this.password = m.prop('');\n\n    this.validation = {\n      'password': [\n        Misago.validators.passwordMinLength(_.settings)\n      ]\n    };\n\n    this.clean = function() {\n      if (!_.validate(this)) {\n        if ($.trim(this.password()).length) {\n          _.alert.error(this.errors.password);\n        } else {\n          _.alert.error(gettext(\"Enter new password.\"));\n        }\n        return false;\n      } else {\n        return true;\n      }\n    };\n\n    this.submit = function() {\n      var endpoint = _.api.endpoint('auth').endpoint('change-password');\n      endpoint = endpoint.endpoint(m.route.param('user_id'));\n      endpoint = endpoint.endpoint(m.route.param('token'));\n\n      endpoint.post({\n        password: self.password()\n      }).then(function(user) {\n        self.success(user);\n      }, function(error) {\n        self.error(error);\n      });\n    };\n\n    this.success = function(user) {\n      this.username = user.username;\n    };\n\n    this.error = function(rejection) {\n      if (rejection.status === 403 && rejection.ban) {\n        _.router.error403({\n          message: '',\n          ban: rejection.ban\n        });\n      } else if (rejection.status === 400) {\n        _.alert.error(rejection.detail);\n      } else {\n        _.api.alert(rejection);\n      }\n    };\n  };\n\n  Misago.addService('form:change-password', function(_) {\n    _.form('change-password', ChangePassword);\n  },\n  {\n    after: 'forms'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Register = function(_) {\n    var self = this;\n\n    this.showActivation = false;\n\n    this.username = m.prop('');\n    this.email = m.prop('');\n    this.password = m.prop('');\n\n    this.captcha = _.captcha.value;\n\n    this.errors = null;\n\n    this.validation = {\n      'username': [\n        Misago.validators.usernameContent(),\n        Misago.validators.usernameMinLength(_.settings),\n        Misago.validators.usernameMaxLength(_.settings)\n      ],\n      'email': [\n        Misago.validators.email()\n      ],\n      'password': [\n        Misago.validators.passwordMinLength(_.settings)\n      ],\n      'captcha': _.captcha.validator()\n    };\n\n    this.clean = function() {\n      if (this.errors === null) {\n        _.validate(this);\n      }\n\n      _.captcha.clean(this);\n\n      if (this.hasErrors()) {\n        _.alert.error(gettext(\"Form contains errors.\"));\n        return false;\n      } else {\n        return true;\n      }\n    };\n\n    this.submit = function() {\n      _.api.model('user').post({\n        username: this.username(),\n        email: this.email(),\n        password: this.password(),\n        captcha: this.captcha()\n      }).then(this.success, this.error);\n    };\n\n    this.success = function(data) {\n      _.modal('register-complete', data);\n    };\n\n    this.error = function(rejection) {\n      if (rejection.status === 400) {\n        _.alert.error(gettext(\"Form contains errors.\"));\n        $.extend(self.errors, rejection);\n      } else {\n        _.api.alert(rejection);\n      }\n    };\n  };\n\n  Misago.addService('form:register', function(_) {\n    _.form('register', Register);\n  },\n  {\n    after: 'forms'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var RequestLink = function(vm, _) {\n    var self = this;\n\n    this.email = m.prop('');\n\n    this.validation = {\n      'email': [\n        Misago.validators.email()\n      ]\n    };\n\n    this.clean = function() {\n      if (!_.validate(this)) {\n        _.alert.error(gettext(\"Enter a valid email address.\"));\n        return false;\n      } else {\n        return true;\n      }\n    };\n\n    this.submit = function() {\n      _.ajax.post(vm.api, {\n        email: self.email()\n      }).then(function(user) {\n        self.success(user);\n      }, function(error) {\n        self.error(error);\n      });\n    };\n\n    this.success = function(user) {\n      vm.success(user);\n    };\n\n    this.error = function(rejection) {\n      if (rejection.status === 400) {\n          vm.error(rejection, _);\n      } else {\n        _.api.alert(rejection);\n      }\n    };\n\n    this.reset = function() {\n      this.email('');\n      vm.reset();\n    };\n  };\n\n  Misago.addService('form:request-link', function(_) {\n    _.form('request-link', RequestLink);\n  },\n  {\n    after: 'forms'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var SignIn = function(_) {\n    var self = this;\n\n    this.showActivation = false;\n\n    this.username = m.prop('');\n    this.password = m.prop('');\n\n    this.validation = {\n      'username': [],\n      'password': []\n    };\n\n    this.clean = function() {\n      if (!_.validate(this)) {\n        _.alert.error(gettext(\"Fill out both fields.\"));\n        return false;\n      } else {\n        return true;\n      }\n    };\n\n    this.submit = function() {\n      _.api.endpoint('auth').post({\n        username: self.username(),\n        password: self.password()\n      }).then(function() {\n        self.success();\n      }, function(error) {\n        self.error(error);\n      });\n    };\n\n    this.success = function() {\n      _.modal();\n\n      var $form = $('#hidden-login-form');\n\n      // refresh CSRF token because api call to /auth/ changed it\n      _.ajax.refreshCsrfToken();\n\n      // fill out form with user credentials and submit it, this will tell\n      // misago to redirect user back to right page, and will trigger browser's\n      // key ring feature\n      $form.find('input[type=\"hidden\"]').val(_.ajax.csrfToken);\n      $form.find('input[name=\"redirect_to\"]').val(m.route());\n      $form.find('input[name=\"username\"]').val(this.username());\n      $form.find('input[name=\"password\"]').val(this.password());\n      $form.submit();\n    };\n\n    this.error = function(rejection) {\n      if (rejection.status === 400) {\n        if (rejection.code === 'inactive_admin') {\n          _.alert.info(rejection.detail);\n        } else if (rejection.code === 'inactive_user') {\n          _.alert.info(rejection.detail);\n          self.showActivation = true;\n        } else if (rejection.code === 'banned') {\n          _.showBannedPage(rejection.detail);\n          _.modal();\n        } else {\n          _.alert.error(rejection.detail);\n        }\n      } else {\n        _.api.alert(rejection);\n      }\n    };\n  };\n\n  Misago.addService('form:sign-in', function(_) {\n    _.form('sign-in', SignIn);\n  },\n  {\n    after: 'forms'\n  });\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mount = document.getElementById('alert-mount');\n\n  Misago.addService('mount:alert', {\n    factory: function(_) {\n      m.mount(mount, _.component('alert'));\n    },\n    destroy: function() {\n      m.mount(mount, null);\n    }\n  },\n  {\n    before: 'mount:page-component'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mount = document.getElementById('auth-changed-message-mount');\n\n  Misago.addService('mount:auth-changed-message', {\n    factory: function(_) {\n      m.mount(mount, _.component('auth-changed-message'));\n    },\n    destroy: function() {\n      m.mount(mount, null);\n    }\n  },\n  {\n    before: 'mount:page-component'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mount = document.getElementById('page-component');\n\n  Misago.addService('mount:page-component', {\n    factory: function(_) {\n      if (mount) {\n        m.mount(mount, _.component(mount.dataset.componentName));\n      }\n    },\n    destroy: function() {\n      if (mount) {\n        m.mount(mount, null);\n      }\n    }\n  },\n  {\n    before: '_end'\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var mountDesktop = document.getElementById('user-menu-mount');\n  var mountCompact = document.getElementById('user-menu-compact-mount');\n\n  Misago.addService('mount:user-menu', {\n    factory: function(_) {\n      if (_.user.isAuthenticated) {\n        m.mount(mountDesktop, _.component('navbar:desktop:user-nav'));\n        m.mount(mountCompact, _.component('navbar:compact:user-nav'));\n      } else {\n        m.mount(mountDesktop, _.component('navbar:desktop:guest-nav'));\n        m.mount(mountCompact, _.component('navbar:compact:guest-nav'));\n      }\n    },\n    destroy: function() {\n      m.mount(mountDesktop, null);\n      m.mount(mountCompact, null);\n    }\n  },\n  {\n    before: 'mount:page-component'\n  });\n}(Misago.prototype));\n"],"sourceRoot":"/source/"}

+ 25 - 0
misago/templates/misago/activation/done.html

@@ -0,0 +1,25 @@
+{% extends "misago/base.html" %}
+{% load i18n %}
+
+
+{% block title %}{% trans "Account activated" %} | {{ block.super }}{% endblock %}
+
+
+{% block content %}
+<div class="page page-message page-message-success page-activation-done">
+  <div class="container">
+    <div class="message-panel">
+
+      <div class="message-icon">
+        <span class="material-icon">check</span>
+      </div>
+
+      <div class="message-body">
+        <p class="lead">{{ message }}</p>
+        <p>{% trans "You can now sign in to finish setting up your account and to participate in or start new discussions." %}</p>
+      </div>
+
+    </div>
+  </div>
+</div>
+{% endblock content %}

+ 30 - 0
misago/templates/misago/activation/error.html

@@ -0,0 +1,30 @@
+{% extends "misago/base.html" %}
+{% load i18n %}
+
+
+{% block title %}{% trans "Activation failed" %} | {{ block.super }}{% endblock %}
+
+
+{% block content %}
+<div class="page page-error page-activation-error">
+  <div class="container">
+    <div class="message-panel">
+
+      <div class="message-icon">
+        <span class="material-icon">info_outline</span>
+      </div>
+
+      <div class="message-body">
+        <p class="lead">{% trans "Account activation has failed." %}</p>
+        <p>{% trans "The link you followed was incorrect or the page has been moved or deleted." %}</p>
+        <p>
+          <a href="{% url 'misago:request_activation' %}">
+            Request another activation link.
+          </a>
+        </p>
+      </div>
+
+    </div>
+  </div>
+</div>
+{% endblock content %}

+ 55 - 0
misago/templates/misago/activation/request.html

@@ -0,0 +1,55 @@
+{% extends "misago/base.html" %}
+{% load i18n %}
+
+
+{% block title %}{% trans "Request activation link" %} | {{ block.super }}{% endblock %}
+
+
+{% block content %}
+<div class="page page-request-activation">
+  <div class="page-header">
+    <div class="container">
+      <h1>{% trans "Request activation link" %}</h1>
+    </div>
+  </div>
+
+  <div class="container">
+
+    <div class="row">
+      <div class="col-md-8">
+        <div class="side-form-copy">
+
+          <p class="lead">{% trans "Site administrator may impose requirement on newly regitered accounts to be activated before users will be able to sign in." %}</p>
+          <p>{% trans "Depending on time of registration, you will be able activate your account by clicking special activation link. This link will be valid only for your browser, for seven days or until your account is activated." %}</p>
+          <p>
+            {% blocktrans trimmed %}
+              To receive this link, enter your account's e-mail addres in form and press "Send link" button.
+            {% endblocktrans %}
+          </p>
+
+        </div>
+      </div>
+      <div id="page-component" class="col-md-4" data-component-name="request-activation-link-form">
+
+        <noscript>
+          <div class="well well-form well-noscript">
+            <div class="noscript-message">
+
+              <div class="message-icon">
+                <span class="material-icon">error_outline</span>
+              </div>
+
+              <div class="message-body">
+                <p>{% trans "To request new activation link please enable JavaScript." %}</p>
+              </div>
+
+            </div>
+          </div>
+        </noscript>
+
+      </div>
+    </div>
+
+  </div>
+</div>
+{% endblock content %}

+ 25 - 0
misago/templates/misago/activation/stopped.html

@@ -0,0 +1,25 @@
+{% extends "misago/base.html" %}
+{% load i18n %}
+
+
+{% block title %}{% trans "Activation failed" %} | {{ block.super }}{% endblock %}
+
+
+{% block content %}
+<div class="page page-message page-message-info">
+  <div class="container">
+    <div class="message-panel">
+
+      <div class="message-icon">
+        <span class="material-icon">info_outline</span>
+      </div>
+
+      <div class="message-body">
+        <p class="lead">{% trans "Your account can't be activated at this time." %}</p>
+        <p>{{ message }}</p>
+      </div>
+
+    </div>
+  </div>
+</div>
+{% endblock content %}

+ 4 - 4
misago/templates/misago/base.html

@@ -24,20 +24,20 @@
   </head>
   </head>
   <body>
   <body>
 
 
-    <div id="misago-auth-changed-message-mount"></div>
-    <div id="misago-alert-mount"></div>
+    <div id="auth-changed-message-mount"></div>
+    <div id="alert-mount"></div>
 
 
     {% include "misago/jumbotron.html" %}
     {% include "misago/jumbotron.html" %}
     {% include "misago/navbar.html" %}
     {% include "misago/navbar.html" %}
 
 
-    <div id="misago-page-mount">
+    <div id="page-mount">
       {% block content %}{% endblock content %}
       {% block content %}{% endblock content %}
     </div>
     </div>
 
 
     {% include "misago/footer.html" %}
     {% include "misago/footer.html" %}
     {% include "misago/auth.html" %}
     {% include "misago/auth.html" %}
 
 
-    <div class="modal fade" id="misago-modal" tabindex="-1" role="dialog" aria-labelledby="misago-modal-label"></div>
+    <div class="modal fade" id="modal-mount" tabindex="-1" role="dialog" aria-labelledby="misago-modal-label"></div>
 
 
     <script type="text/javascript" src="/django-i18n.js"></script>
     <script type="text/javascript" src="/django-i18n.js"></script>
     <script type="text/javascript" src="{% static 'misago/js/vendor.js' %}"></script>
     <script type="text/javascript" src="{% static 'misago/js/vendor.js' %}"></script>

+ 1 - 1
misago/templates/misago/errorpages/403.html

@@ -14,7 +14,7 @@
     <div class="message-panel">
     <div class="message-panel">
 
 
       <div class="message-icon">
       <div class="message-icon">
-        <i class="material-icon">remove_circle_outline</i>
+        <span class="material-icon">remove_circle_outline</span>
       </div>
       </div>
 
 
       <div class="message-body">
       <div class="message-body">

+ 1 - 1
misago/templates/misago/errorpages/404.html

@@ -14,7 +14,7 @@
     <div class="message-panel">
     <div class="message-panel">
 
 
       <div class="message-icon">
       <div class="message-icon">
-        <i class="material-icon">info_outline</i>
+        <span class="material-icon">info_outline</span>
       </div>
       </div>
 
 
       <div class="message-body">
       <div class="message-body">

+ 1 - 1
misago/templates/misago/errorpages/405.html

@@ -14,7 +14,7 @@
     <div class="message-panel">
     <div class="message-panel">
 
 
       <div class="message-icon">
       <div class="message-icon">
-        <i class="material-icon">remove_circle_outline</i>
+        <span class="material-icon">remove_circle_outline</span>
       </div>
       </div>
 
 
       <div class="message-body">
       <div class="message-body">

+ 37 - 0
misago/templates/misago/errorpages/banned.html

@@ -0,0 +1,37 @@
+{% extends "misago/base.html" %}
+{% load i18n %}
+
+
+{% block title %}{% trans "You are banned" %} | {{ block.super }}{% endblock %}
+
+
+{% block meta_description %}{% trans "You are banned from accessing this page." %}{% endblock meta_description %}
+
+
+{% block content %}
+<div class="page page-error page-error-403 page-error-banned">
+  <div class="container">
+    <div class="message-panel">
+
+      <div class="message-icon">
+        <span class="material-icon">highlight_off</span>
+      </div>
+
+      <div class="message-body">
+        {% if ban.message.html %}
+        <div class="lead">
+          {{ ban.message.html|safe }}
+        </div>
+        {% else %}
+        <p class="lead">
+          {{ ban.message.plain }}
+        </p>
+        {% endif %}
+
+        <div id="page-component" data-component-name="ban-expiration-message"></div>
+      </div>
+
+    </div>
+  </div>
+</div>
+{% endblock content %}

+ 1 - 1
misago/templates/misago/errorpages/csrf_failure.html

@@ -14,7 +14,7 @@
     <div class="message-panel">
     <div class="message-panel">
 
 
       <div class="message-icon">
       <div class="message-icon">
-        <i class="material-icon">remove_circle_outline</i>
+        <span class="material-icon">remove_circle_outline</span>
       </div>
       </div>
 
 
       <div class="message-body">
       <div class="message-body">

+ 1 - 1
misago/templates/misago/errorpages/csrf_failure_authenticated.html

@@ -11,7 +11,7 @@
     <div class="message-panel">
     <div class="message-panel">
 
 
       <div class="message-icon">
       <div class="message-icon">
-        <i class="material-icon">remove_circle_outline</i>
+        <span class="material-icon">remove_circle_outline</span>
       </div>
       </div>
 
 
       <div class="message-body">
       <div class="message-body">

+ 7 - 5
misago/templates/misago/footer.html

@@ -1,12 +1,14 @@
 {% load i18n %}
 {% load i18n %}
-<footer class="site-footer">
+<footer class="misago-footer">
   <div class="container">
   <div class="container">
     <div class="footer-content">
     <div class="footer-content">
 
 
-      <p class="site-noscript">
-        <i class="material-icon hidden-xs hidden-sm">info_outline</i>
-        {% trans "For complete experience please enable JavaScript." %}
-      </p>
+      <noscript>
+        <p class="noscript-message">
+          <i class="material-icon hidden-xs hidden-sm">info_outline</i>
+          {% trans "For complete experience please enable JavaScript." %}
+        </p>
+      </noscript>
 
 
       {% if misago_settings.terms_of_service or misago_settings.terms_of_service_link or misago_settings.privacy_policy or misago_settings.privacy_policy_link or misago_settings.forum_footnote %}
       {% if misago_settings.terms_of_service or misago_settings.terms_of_service_link or misago_settings.privacy_policy or misago_settings.privacy_policy_link or misago_settings.forum_footnote %}
         <ul class="list-inline footer-nav">
         <ul class="list-inline footer-nav">

+ 3 - 3
misago/templates/misago/navbar.html

@@ -34,7 +34,7 @@
       </li>
       </li>
     </ul>
     </ul>
 
 
-    <div id="misago-user-menu-mount"></div>
+    <div id="user-menu-mount"></div>
   </div><!-- /full navbar -->
   </div><!-- /full navbar -->
 
 
   <ul class="nav navbar-nav navbar-compact-nav hidden-md hidden-lg">
   <ul class="nav navbar-nav navbar-compact-nav hidden-md hidden-lg">
@@ -60,8 +60,8 @@
         <i class="material-icon">search</i>
         <i class="material-icon">search</i>
       </a>
       </a>
     </li>
     </li>
-    <li id="misago-user-menu-compact-mount"></li>
+    <li id="user-menu-compact-mount"></li>
   </ul>
   </ul>
   <!-- /compact navbar -->
   <!-- /compact navbar -->
 </nav>
 </nav>
-<div id="misago-navbar-dropdown" class="mobile-dropdown"></div>
+<div id="navbar-dropdown" class="mobile-dropdown"></div>

+ 33 - 75
misago/users/api/auth.py

@@ -10,8 +10,9 @@ from rest_framework.response import Response
 from misago.conf import settings
 from misago.conf import settings
 from misago.core.mail import mail_user
 from misago.core.mail import mail_user
 
 
-from misago.users.forms.auth import (AuthenticationForm, ResendActivationForm,
-                                     ResetPasswordForm)
+from misago.users.bans import get_user_ban
+from misago.users.forms.auth import (
+    AuthenticationForm, ResendActivationForm, ResetPasswordForm)
 from misago.users.rest_permissions import UnbannedAnonOnly, UnbannedOnly
 from misago.users.rest_permissions import UnbannedAnonOnly, UnbannedOnly
 from misago.users.serializers import (AuthenticatedUserSerializer,
 from misago.users.serializers import (AuthenticatedUserSerializer,
                                       AnonymousUserSerializer)
                                       AnonymousUserSerializer)
@@ -91,49 +92,6 @@ def send_activation(request):
 
 
 
 
 """
 """
-POST /auth/activate-account/ with CSRF token, user ID and activation token
-will activate account
-"""
-@api_view(['POST'])
-@permission_classes((UnbannedAnonOnly,))
-@csrf_protect
-def activate_account(request, user_id, token):
-    User = auth.get_user_model()
-
-    try:
-        user = User.objects.get(pk=user_id)
-    except User.DoesNotExist:
-        message = _("Activation link is invalid. Please try again.")
-        return Response({'detail': message}, status=status.HTTP_400_BAD_REQUEST)
-
-    if not is_activation_token_valid(user, token):
-        message = _("Activation link is invalid. Please try again.")
-        return Response({'detail': message},
-                        status=status.HTTP_400_BAD_REQUEST)
-
-    form = ResendActivationForm()
-    try:
-        form.confirm_user_not_banned(user)
-    except ValidationError:
-        message = _("Activation link has expired. Please request new one.")
-        return Response({'detail': message},
-                        status=status.HTTP_400_BAD_REQUEST)
-
-    try:
-        form.confirm_can_be_activated(user)
-    except ValidationError as e:
-        return Response({'detail': e.messages[0]},
-                        status=status.HTTP_400_BAD_REQUEST)
-
-    user.requires_activation = False
-    user.save(update_fields=['requires_activation'])
-
-    return Response({
-            'username': user.username
-        })
-
-
-"""
 POST /auth/send-password-form/ with CSRF token and email
 POST /auth/send-password-form/ with CSRF token and email
 will mail change password form link to requester
 will mail change password form link to requester
 """
 """
@@ -166,55 +124,55 @@ def send_password_form(request):
 
 
 
 
 """
 """
-GET /auth/change-password/user/token/ will validate change password link
 POST /auth/change-password/user/token/ with CSRF and new password
 POST /auth/change-password/user/token/ with CSRF and new password
 will change forgotten password
 will change forgotten password
 """
 """
-@api_view(['GET', 'POST'])
+class PasswordChangeFailed(Exception):
+    pass
+
+
+@api_view(['POST'])
 @permission_classes((UnbannedOnly,))
 @permission_classes((UnbannedOnly,))
 @csrf_protect
 @csrf_protect
 def change_forgotten_password(request, user_id, token):
 def change_forgotten_password(request, user_id, token):
     User = auth.get_user_model()
     User = auth.get_user_model()
-    invalid_message = _("Form link is invalid. Please try again.")
 
 
-    try:
-        user = User.objects.get(pk=user_id)
-        if request.user.is_authenticated() and request.user.id != user.id:
-            raise User.DoesNotExist()
-    except User.DoesNotExist:
-        return Response({'detail': invalid_message},
-                        status=status.HTTP_400_BAD_REQUEST)
-
-    if not is_password_change_token_valid(user, token):
-        return Response({'detail': invalid_message},
-                        status=status.HTTP_400_BAD_REQUEST)
+    invalid_message = _("Form link is invalid. Please try again.")
+    expired_message = _("Your link has expired. Please request new one.")
 
 
     try:
     try:
-        form = ResetPasswordForm()
-        form.confirm_allowed(user)
-    except ValidationError:
-        message = _("Your link has expired. Please request new one.")
-        return Response({'detail': message},
-                        status=status.HTTP_400_BAD_REQUEST)
+        try:
+            user = User.objects.get(pk=user_id)
+        except User.DoesNotExist:
+            raise PasswordChangeFailed(invalid_message)
 
 
-    if request.method == 'POST':
-        return process_forgotten_password_form(request, user)
-    else:
+        if request.user.is_authenticated() and request.user.id != user.id:
+            raise PasswordChangeFailed(invalid_message)
+        if not is_password_change_token_valid(user, token):
+            raise PasswordChangeFailed(invalid_message)
+        if get_user_ban(user):
+            raise PasswordChangeFailed(expired_message)
+
+        try:
+            form = ResetPasswordForm()
+            form.confirm_allowed(user)
+        except ValidationError:
+            raise PasswordChangeFailed(expired_message)
+    except PasswordChangeFailed as e:
         return Response({
         return Response({
-                'username': user.username,
-                'email': user.email
-            })
-
+                'detail': e.args[0]
+            }, status=status.HTTP_400_BAD_REQUEST)
 
 
-def process_forgotten_password_form(request, user):
     new_password = request.data.get('password', '').strip()
     new_password = request.data.get('password', '').strip()
     try:
     try:
         validate_password(new_password)
         validate_password(new_password)
         user.set_password(new_password)
         user.set_password(new_password)
         user.save()
         user.save()
     except ValidationError as e:
     except ValidationError as e:
-        return Response({'detail': e.messages[0]},
-                        status=status.HTTP_400_BAD_REQUEST)
+        return Response({
+                'detail': e.messages[0]
+            }, status=status.HTTP_400_BAD_REQUEST)
+
     return Response({
     return Response({
             'username': user.username
             'username': user.username
         })
         })

+ 3 - 3
misago/users/decorators.py

@@ -2,6 +2,8 @@ from django.core.exceptions import PermissionDenied
 from django.shortcuts import redirect
 from django.shortcuts import redirect
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
+from misago.core.exceptions import Banned
+
 from misago.users.bans import get_request_ip_ban
 from misago.users.bans import get_request_ip_ban
 
 
 
 
@@ -29,9 +31,7 @@ def deny_banned_ips(f):
     def decorator(request, *args, **kwargs):
     def decorator(request, *args, **kwargs):
         ban = get_request_ip_ban(request)
         ban = get_request_ip_ban(request)
         if ban:
         if ban:
-            raise PermissionDenied(
-                _("Your IP address is banned from performing this action."),
-                {'ban': ban.get_serialized_message()})
+            raise Banned(ban)
         else:
         else:
             return f(request, *args, **kwargs)
             return f(request, *args, **kwargs)
     return decorator
     return decorator

+ 2 - 17
misago/users/forms/auth.py

@@ -142,12 +142,11 @@ class GetUserForm(MisagoAuthMixin, forms.Form):
         return data
         return data
 
 
     def confirm_allowed(self, user):
     def confirm_allowed(self, user):
-        raise NotImplementedError("confirm_allowed method must be defined "
-                                  "by inheriting classes")
+        """override this method to include additional checks"""
 
 
 
 
 class ResendActivationForm(GetUserForm):
 class ResendActivationForm(GetUserForm):
-    def confirm_can_be_activated(self, user):
+    def confirm_allowed(self, user):
         username_format = {'user': user.username}
         username_format = {'user': user.username}
 
 
         if not user.requires_activation:
         if not user.requires_activation:
@@ -161,21 +160,7 @@ class ResendActivationForm(GetUserForm):
             raise forms.ValidationError(message % username_format,
             raise forms.ValidationError(message % username_format,
                                         code='inactive_admin')
                                         code='inactive_admin')
 
 
-    def confirm_allowed(self, user):
-        self.confirm_user_not_banned(user)
-        self.confirm_can_be_activated(user)
-
-
 
 
 class ResetPasswordForm(GetUserForm):
 class ResetPasswordForm(GetUserForm):
-    error_messages = {
-        'inactive_user': _("You have to activate your account before "
-                           "you will be able to request new password."),
-        'inactive_admin': _("Your account has to be activated by "
-                            "Administrator before you will be able to request "
-                            "new password."),
-    }
-
     def confirm_allowed(self, user):
     def confirm_allowed(self, user):
-        self.confirm_user_not_banned(user)
         self.confirm_user_active(user)
         self.confirm_user_active(user)

+ 10 - 0
misago/users/models/ban.py

@@ -135,6 +135,16 @@ class BanCache(models.Model):
         except IntegrityError:
         except IntegrityError:
             pass # first come is first serve with ban cache
             pass # first come is first serve with ban cache
 
 
+    def get_serialized_message(self):
+        from misago.users.serializers import BanMessageSerializer
+        temp_ban = Ban(
+            id=1,
+            check_type=BAN_USERNAME,
+            user_message=self.user_message,
+            staff_message=self.staff_message,
+            expires_on=self.expires_on)
+        return BanMessageSerializer(temp_ban).data
+
     @property
     @property
     def is_banned(self):
     def is_banned(self):
         return bool(self.ban)
         return bool(self.ban)

+ 78 - 19
misago/users/tests/test_activation_views.py

@@ -2,6 +2,7 @@ from django.contrib.auth import get_user_model
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.test import TestCase
 from django.test import TestCase
 
 
+from misago.users.models import Ban, BAN_USERNAME
 from misago.users.tokens import make_activation_token
 from misago.users.tokens import make_activation_token
 
 
 
 
@@ -11,34 +12,92 @@ class ActivationViewsTests(TestCase):
         response = self.client.get(reverse('misago:request_activation'))
         response = self.client.get(reverse('misago:request_activation'))
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
-    def test_activate_view_returns_200(self):
-        """
-        activate account view returns 200
+    def test_view_activate_banned(self):
+        """activate banned user shows error"""
+        User = get_user_model()
+        test_user = User.objects.create_user('Bob', 'bob@test.com', 'Pass.123',
+                                             requires_activation=1)
+        Ban.objects.create(check_type=BAN_USERNAME,
+                           banned_value='bob',
+                           user_message='Nope!')
+
+        activation_token = make_activation_token(test_user)
+
+        response = self.client.get(
+            reverse('misago:activate_by_token',
+                    kwargs={'user_id': test_user.pk,
+                            'token': activation_token}))
+        self.assertEqual(response.status_code, 403)
+        self.assertIn("<p>Nope!</p>", response.content)
+
+        test_user = User.objects.get(pk=test_user.pk)
+        self.assertEqual(test_user.requires_activation, 1)
+
+    def test_view_activate_invalid_token(self):
+        """activate with invalid token shows error"""
+        User = get_user_model()
+        test_user = User.objects.create_user('Bob', 'bob@test.com', 'Pass.123',
+                                             requires_activation=1)
+
+        activation_token = make_activation_token(test_user)
+
+        response = self.client.get(
+            reverse('misago:activate_by_token',
+                    kwargs={'user_id': test_user.pk,
+                            'token': activation_token + 'acd'}))
+        self.assertEqual(response.status_code, 400)
+
+        test_user = User.objects.get(pk=test_user.pk)
+        self.assertEqual(test_user.requires_activation, 1)
 
 
-        all views return 200 because real validation occurs via JS and API
-        """
+    def test_view_activate_active(self):
+        """activate active user shows error"""
         User = get_user_model()
         User = get_user_model()
         test_user = User.objects.create_user('Bob', 'bob@test.com', 'Pass.123')
         test_user = User.objects.create_user('Bob', 'bob@test.com', 'Pass.123')
 
 
+        activation_token = make_activation_token(test_user)
+
         response = self.client.get(
         response = self.client.get(
-            reverse('misago:activate_by_token', kwargs={
-                'user_id': test_user.id,
-                'token': make_activation_token(test_user)
-            }))
+            reverse('misago:activate_by_token',
+                    kwargs={'user_id': test_user.pk,
+                            'token': activation_token}))
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
-        # test invalid user
+        test_user = User.objects.get(pk=test_user.pk)
+        self.assertEqual(test_user.requires_activation, 0)
+
+    def test_view_activate_admin_activated(self):
+        """activate inactive user passess"""
+        User = get_user_model()
+        test_user = User.objects.create_user('Bob', 'bob@test.com', 'Pass.123',
+                                             requires_activation=2)
+
+        activation_token = make_activation_token(test_user)
+
         response = self.client.get(
         response = self.client.get(
-            reverse('misago:activate_by_token', kwargs={
-                'user_id': 7681,
-                'token': 'a7d8sa97d98sa798dsa'
-            }))
+            reverse('misago:activate_by_token',
+                    kwargs={'user_id': test_user.pk,
+                            'token': activation_token}))
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
+        self.assertIn("only by one of the administrators", response.content)
+
+        test_user = User.objects.get(pk=test_user.pk)
+        self.assertEqual(test_user.requires_activation, 2)
+
+    def test_view_activate_inactive(self):
+        """activate inactive user passess"""
+        User = get_user_model()
+        test_user = User.objects.create_user('Bob', 'bob@test.com', 'Pass.123',
+                                             requires_activation=1)
+
+        activation_token = make_activation_token(test_user)
 
 
-        # test invalid token
         response = self.client.get(
         response = self.client.get(
-            reverse('misago:activate_by_token', kwargs={
-                'user_id': test_user.id,
-                'token': 'asd79as87ds9a8d7sa'
-            }))
+            reverse('misago:activate_by_token',
+                    kwargs={'user_id': test_user.pk,
+                            'token': activation_token}))
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
+        self.assertIn("your account has been activated!", response.content)
+
+        test_user = User.objects.get(pk=test_user.pk)
+        self.assertEqual(test_user.requires_activation, 0)

+ 29 - 139
misago/users/tests/test_auth_api.py

@@ -133,6 +133,17 @@ class SendActivationAPITests(TestCase):
 
 
         self.assertIn('Activate Bob', mail.outbox[0].subject)
         self.assertIn('Activate Bob', mail.outbox[0].subject)
 
 
+    def test_submit_banned(self):
+        """request activation link api passes for banned users"""
+        Ban.objects.create(check_type=BAN_USERNAME,
+                           banned_value=self.user.username,
+                           user_message='Nope!')
+
+        response = self.client.post(self.link, data={'email': self.user.email})
+        self.assertEqual(response.status_code, 200)
+
+        self.assertIn('Activate Bob', mail.outbox[0].subject)
+
     def test_submit_empty(self):
     def test_submit_empty(self):
         """request activation link api errors for no body"""
         """request activation link api errors for no body"""
         response = self.client.post(self.link)
         response = self.client.post(self.link)
@@ -149,18 +160,6 @@ class SendActivationAPITests(TestCase):
 
 
         self.assertTrue(not mail.outbox)
         self.assertTrue(not mail.outbox)
 
 
-    def test_submit_banned(self):
-        """request activation link api errors for banned users"""
-        Ban.objects.create(check_type=BAN_USERNAME,
-                           banned_value=self.user.username,
-                           user_message='Nope!')
-
-        response = self.client.post(self.link, data={'email': self.user.email})
-        self.assertEqual(response.status_code, 400)
-        self.assertIn('Nope!', response.content)
-
-        self.assertTrue(not mail.outbox)
-
     def test_submit_active_user(self):
     def test_submit_active_user(self):
         """request activation link api errors for active user"""
         """request activation link api errors for active user"""
         self.user.requires_activation = 0
         self.user.requires_activation = 0
@@ -192,103 +191,26 @@ class SendActivationAPITests(TestCase):
         self.assertTrue(mail.outbox)
         self.assertTrue(mail.outbox)
 
 
 
 
-class ActivateAccountAPITests(TestCase):
+class SendPasswordFormAPITests(TestCase):
     def setUp(self):
     def setUp(self):
         User = get_user_model()
         User = get_user_model()
         self.user = User.objects.create_user('Bob', 'bob@test.com', 'Pass.123')
         self.user = User.objects.create_user('Bob', 'bob@test.com', 'Pass.123')
-        self.user.requires_activation = 1
-        self.user.save()
 
 
-        self.link = '/api/auth/activate-account/%s/%s/'
+        self.link = '/api/auth/send-password-form/'
 
 
     def test_submit_valid(self):
     def test_submit_valid(self):
-        """activate user api returns success and activates user"""
-        response = self.client.post(self.link % (
-                self.user.id,
-                make_activation_token(self.user)
-            ))
+        """request change password form link api sends reset link mail"""
+        response = self.client.post(self.link, data={'email': self.user.email})
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
-        self.assertIn(self.user.username, response.content)
-
-        user = get_user_model().objects.get(id=self.user.id)
-        self.assertFalse(user.requires_activation)
 
 
-    def test_submit_invalid_token(self):
-        """activate user api errors for invalid token"""
-        response = self.client.post(self.link % (
-                self.user.id,
-                'sadsadsadsdsassdsa'
-            ))
-        self.assertEqual(response.status_code, 400)
-        self.assertIn('Activation link is invalid.', response.content)
-
-    def test_submit_invalid_user(self):
-        """activate user api errors for invalid user"""
-        response = self.client.post(self.link % (
-                123,
-                'sadsadsadsdsassdsa'
-            ))
-        self.assertEqual(response.status_code, 400)
-        self.assertIn('Activation link is invalid.', response.content)
+        self.assertIn('Change Bob password', mail.outbox[0].subject)
 
 
     def test_submit_banned(self):
     def test_submit_banned(self):
-        """activate user api errors for banned user"""
+        """request change password form link api sends reset link mail"""
         Ban.objects.create(check_type=BAN_USERNAME,
         Ban.objects.create(check_type=BAN_USERNAME,
                            banned_value=self.user.username,
                            banned_value=self.user.username,
                            user_message='Nope!')
                            user_message='Nope!')
 
 
-        response = self.client.post(self.link % (
-                self.user.id,
-                make_activation_token(self.user)
-            ))
-        self.assertEqual(response.status_code, 400)
-        self.assertIn('Activation link has expired.', response.content)
-
-    def test_submit_active_user(self):
-        """validate link api errors for active user"""
-        self.user.requires_activation = 0
-        self.user.save()
-
-        response = self.client.post(self.link % (
-                self.user.id,
-                make_activation_token(self.user)
-            ))
-        self.assertEqual(response.status_code, 400)
-        self.assertIn('Bob, your account is already active.',
-                      response.content)
-
-    def test_submit_inactive_user(self):
-        """validate link api errors for inactive user"""
-        self.user.requires_activation = 1
-        self.user.save()
-
-        response = self.client.post(self.link % (
-                self.user.id,
-                make_activation_token(self.user)
-            ))
-        self.assertEqual(response.status_code, 200)
-
-        self.user.requires_activation = 2
-        self.user.save()
-
-        response = self.client.post(self.link % (
-                self.user.id,
-                make_activation_token(self.user)
-            ))
-        self.assertEqual(response.status_code, 400)
-        self.assertIn('Bob, only administrator may activate your account.',
-                      response.content)
-
-
-class SendPasswordFormAPITests(TestCase):
-    def setUp(self):
-        User = get_user_model()
-        self.user = User.objects.create_user('Bob', 'bob@test.com', 'Pass.123')
-
-        self.link = '/api/auth/send-password-form/'
-
-    def test_submit_valid(self):
-        """request change password form link api sends reset link mail"""
         response = self.client.post(self.link, data={'email': self.user.email})
         response = self.client.post(self.link, data={'email': self.user.email})
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
 
 
@@ -310,18 +232,6 @@ class SendPasswordFormAPITests(TestCase):
 
 
         self.assertTrue(not mail.outbox)
         self.assertTrue(not mail.outbox)
 
 
-    def test_submit_banned(self):
-        """request change password form link api errors for banned users"""
-        Ban.objects.create(check_type=BAN_USERNAME,
-                           banned_value=self.user.username,
-                           user_message='Nope!')
-
-        response = self.client.post(self.link, data={'email': self.user.email})
-        self.assertEqual(response.status_code, 400)
-        self.assertIn('Nope!', response.content)
-
-        self.assertTrue(not mail.outbox)
-
     def test_submit_inactive_user(self):
     def test_submit_inactive_user(self):
         """request change password form link api errors for inactive users"""
         """request change password form link api errors for inactive users"""
         self.user.requires_activation = 1
         self.user.requires_activation = 1
@@ -348,29 +258,20 @@ class ChangePasswordAPITests(TestCase):
 
 
         self.link = '/api/auth/change-password/%s/%s/'
         self.link = '/api/auth/change-password/%s/%s/'
 
 
-    def test_valid_link(self):
-        """get validates link"""
-        response = self.client.get(self.link % (
+    def test_submit_valid(self):
+        """submit change password form api errors for empty body"""
+        response = self.client.post(self.link % (
                 self.user.id,
                 self.user.id,
                 make_password_change_token(self.user)
                 make_password_change_token(self.user)
-            ))
-
+            ), data={'password': 'n3wp4ss!'})
         self.assertEqual(response.status_code, 200)
         self.assertEqual(response.status_code, 200)
-        self.assertIn(self.user.username, response.content)
 
 
-    def test_invalid_user_id_link(self):
-        """get errors on invalid user id link"""
-        response = self.client.get(self.link % (
-                123,
-                make_password_change_token(self.user)
-            ))
-
-        self.assertEqual(response.status_code, 400)
-        self.assertIn('Form link is invalid.', response.content)
+        user = get_user_model().objects.get(id=self.user.id)
+        self.assertTrue(user.check_password('n3wp4ss!'))
 
 
     def test_invalid_token_link(self):
     def test_invalid_token_link(self):
-        """get errors on invalid user id link"""
-        response = self.client.get(self.link % (
+        """request errors on invalid user id link"""
+        response = self.client.post(self.link % (
                 self.user.id,
                 self.user.id,
                 'asda7ad89sa7d9s789as'
                 'asda7ad89sa7d9s789as'
             ))
             ))
@@ -379,12 +280,12 @@ class ChangePasswordAPITests(TestCase):
         self.assertIn('Form link is invalid.', response.content)
         self.assertIn('Form link is invalid.', response.content)
 
 
     def test_banned_user_link(self):
     def test_banned_user_link(self):
-        """get errors because user is banned"""
+        """request errors because user is banned"""
         Ban.objects.create(check_type=BAN_USERNAME,
         Ban.objects.create(check_type=BAN_USERNAME,
                            banned_value=self.user.username,
                            banned_value=self.user.username,
                            user_message='Nope!')
                            user_message='Nope!')
 
 
-        response = self.client.get(self.link % (
+        response = self.client.post(self.link % (
                 self.user.id,
                 self.user.id,
                 make_password_change_token(self.user)
                 make_password_change_token(self.user)
             ))
             ))
@@ -396,7 +297,7 @@ class ChangePasswordAPITests(TestCase):
         self.user.requires_activation = 1
         self.user.requires_activation = 1
         self.user.save()
         self.user.save()
 
 
-        response = self.client.get(self.link % (
+        response = self.client.post(self.link % (
                 self.user.id,
                 self.user.id,
                 make_password_change_token(self.user)
                 make_password_change_token(self.user)
             ))
             ))
@@ -406,7 +307,7 @@ class ChangePasswordAPITests(TestCase):
         self.user.requires_activation = 2
         self.user.requires_activation = 2
         self.user.save()
         self.user.save()
 
 
-        response = self.client.get(self.link % (
+        response = self.client.post(self.link % (
                 self.user.id,
                 self.user.id,
                 make_password_change_token(self.user)
                 make_password_change_token(self.user)
             ))
             ))
@@ -421,14 +322,3 @@ class ChangePasswordAPITests(TestCase):
             ))
             ))
         self.assertEqual(response.status_code, 400)
         self.assertEqual(response.status_code, 400)
         self.assertIn('Valid password must', response.content)
         self.assertIn('Valid password must', response.content)
-
-    def test_submit_valid(self):
-        """submit change password form api errors for empty body"""
-        response = self.client.post(self.link % (
-                self.user.id,
-                make_password_change_token(self.user)
-            ), data={'password': 'n3wp4ss!'})
-        self.assertEqual(response.status_code, 200)
-
-        user = get_user_model().objects.get(id=self.user.id)
-        self.assertTrue(user.check_password('n3wp4ss!'))

+ 2 - 2
misago/users/urls/__init__.py

@@ -13,8 +13,8 @@ urlpatterns += patterns('misago.users.views.auth',
 
 
 
 
 urlpatterns += patterns('misago.users.views.activation',
 urlpatterns += patterns('misago.users.views.activation',
-    url(r'^activation/$', 'activation_noscript', name="request_activation"),
-    url(r'^activation/(?P<user_id>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'activation_noscript', name="activate_by_token"),
+    url(r'^request-activation/$', 'request_activation', name="request_activation"),
+    url(r'^activation/(?P<user_id>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'activate_by_token', name="activate_by_token"),
 )
 )
 
 
 
 

+ 1 - 2
misago/users/urls/api.py

@@ -7,8 +7,7 @@ from misago.users.api.usernamechanges import UsernameChangesViewSet
 
 
 urlpatterns = patterns('misago.users.api.auth',
 urlpatterns = patterns('misago.users.api.auth',
     url(r'^auth/$', 'gateway'),
     url(r'^auth/$', 'gateway'),
-    url(r'^auth/send-activation/$', 'send_activation'),
-    url(r'^auth/activate-account/(?P<user_id>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'activate_account'),
+    url(r'^auth/send-activation/$', 'send_activation', name='send_activation'),
     url(r'^auth/send-password-form/$', 'send_password_form'),
     url(r'^auth/send-password-form/$', 'send_password_form'),
     url(r'^auth/change-password/(?P<user_id>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'change_forgotten_password'),
     url(r'^auth/change-password/(?P<user_id>\d+)/(?P<token>[a-zA-Z0-9]+)/$', 'change_forgotten_password'),
 )
 )

+ 76 - 9
misago/users/views/activation.py

@@ -1,14 +1,81 @@
+from django.contrib.auth import get_user_model
+from django.core.urlresolvers import reverse
+from django.shortcuts import get_object_or_404, render
 from django.utils.translation import ugettext as _
 from django.utils.translation import ugettext as _
-from django.views.decorators.debug import sensitive_post_parameters
 
 
-from misago.users.decorators import deflect_authenticated, deflect_banned_ips
+from misago.conf import settings
+from misago.core.mail import mail_user
+from misago.core.exceptions import Banned
 
 
+from misago.users.bans import get_user_ban
+from misago.users.decorators import deny_authenticated, deny_banned_ips
+from misago.users.models import ACTIVATION_REQUIRED_NONE
+from misago.users.tokens import is_activation_token_valid
 
 
-@sensitive_post_parameters()
-@deflect_authenticated
-@deflect_banned_ips
-def activation_noscript(request, user_id=None, token=None):
-    return noscript(request, **{
-        'title': _("Activate your account"),
-        'message': _("To activate your account enable JavaScript."),
+
+def activation_view(f):
+    @deny_authenticated
+    @deny_banned_ips
+    def decorator(*args, **kwargs):
+        return f(*args, **kwargs)
+    return decorator
+
+
+@activation_view
+def request_activation(request):
+    request.frontend_context.update({
+        'SEND_ACTIVATION_API_URL': reverse('misago:api:send_activation')
     })
     })
+    return render(request, 'misago/activation/request.html')
+
+
+class ActivationStopped(Exception):
+    pass
+
+
+class ActivationError(Exception):
+    pass
+
+
+@activation_view
+def activate_by_token(request, user_id, token):
+    User = get_user_model()
+    inactive_user = get_object_or_404(User.objects, pk=user_id)
+
+    try:
+        if not inactive_user.requires_activation:
+            message = _("%(user)s, your account is already active.")
+            message = message % {'user': inactive_user.username}
+            raise ActivationStopped(message)
+        if inactive_user.requires_activation_by_admin:
+            message = _("%(user)s, your account can be activated "
+                        "only by one of the administrators.")
+            message = message % {'user': inactive_user.username}
+            raise ActivationStopped(message)
+
+        if not is_activation_token_valid(inactive_user, token):
+            message = _("%(user)s, your activation link is invalid. "
+                        "Try again or request new activation link.")
+            message = message % {'user': inactive_user.username}
+            raise ActivationError(message)
+
+        ban = get_user_ban(inactive_user)
+        if ban:
+            raise Banned(ban)
+    except ActivationStopped as e:
+        return render(request, 'misago/activation/stopped.html', {
+                'message': e.args[0],
+            })
+    except ActivationError as e:
+        return render(request, 'misago/activation/error.html', {
+                'message': e.args[0],
+            }, status=400)
+
+    inactive_user.requires_activation = ACTIVATION_REQUIRED_NONE
+    inactive_user.save(update_fields=['requires_activation'])
+
+    message = _("%(user)s, your account has been activated!")
+
+    return render(request, 'misago/activation/done.html', {
+            'message': message % {'user': inactive_user.username},
+        })