Browse Source

basic framework done

Rafał Pitoń 9 years ago
parent
commit
4eee5d0f01

+ 6 - 4
misago/frontend/gulpfile.js

@@ -172,22 +172,22 @@ gulp.task('cleantest', function(cb) {
 
 gulp.task('collecttestjs', ['cleantest', 'collectjs'], function() {
   return gulp.src('dist/js/**/*')
-    .pipe(gulp.dest('test/dist/js'));
+    .pipe(gulp.dest('test/dist/misago/js'));
 });
 
 gulp.task('collecttestcss', ['cleantest', 'collectcss'], function() {
   return gulp.src('dist/css/**/*')
-    .pipe(gulp.dest('test/dist/css'));
+    .pipe(gulp.dest('test/dist/misago/css'));
 });
 
 gulp.task('collecttestfonts', ['cleantest', 'copyfonts'], function() {
   return gulp.src('dist/fonts/**/*')
-    .pipe(gulp.dest('test/dist/fonts'));
+    .pipe(gulp.dest('test/dist/misago/fonts'));
 });
 
 gulp.task('collecttestimg', ['cleantest', 'copyimg'], function() {
   return gulp.src('dist/img/**/*')
-    .pipe(gulp.dest('test/dist/img'));
+    .pipe(gulp.dest('test/dist/misago/img'));
 });
 
 gulp.task('collecttestslibs', ['cleantest'], function() {
@@ -238,6 +238,8 @@ gulp.task('test', ['starttestserver'], function() {
     'collecttests',
     'collecttestjs',
     'collecttestcss',
+    'collecttestfonts',
+    'collecttestimg',
     'collecttestsutils',
     'collecttestslibs'
   ]);

+ 1 - 1
misago/frontend/misago/app.js

@@ -46,7 +46,7 @@
     this.init = function(setup) {
       this.setup = {
         fixture: ns.get(setup, 'fixture', null),
-        inTest: ns.get(setup, 'inTest', false),
+        test: ns.get(setup, 'test', false),
         api: ns.get(setup, 'api', '/api/')
       };
 

+ 1 - 1
misago/frontend/misago/models/ban.js

@@ -13,7 +13,7 @@
   var deserializeBan = function(data) {
     data.expires_on = Misago.deserializeDatetime(data.expires_on);
 
-    return new Misago.Ban(data);
+    return data;
   };
 
   Misago.addService('ban-model', function(_) {

+ 1 - 0
misago/frontend/misago/models/legal-page.js

@@ -4,6 +4,7 @@
   var LegalPage = function(data) {
     this.title = data.title;
     this.body = data.body;
+    this.link = data.link;
   };
 
   Misago.addService('legal-page-model', function(_) {

+ 6 - 2
misago/frontend/misago/routes/error-pages.js

@@ -69,11 +69,15 @@
     },
     error: null,
     view: function() {
+      if (this.error === "Permission denied") {
+        this.error = gettext("You don't have permission to access this page.");
+      }
+
       return errorPage({
         code: 403,
         icon: 'remove_circle_outline',
         message: gettext("This page is not available."),
-        help: this.error || gettext("You don't have permission to access this page.")
+        help: this.error
       });
     }
   });
@@ -112,7 +116,7 @@
     },
     view: function() {
       return errorPage({
-        code: 500,
+        code: 0,
         icon: 'sync_problem',
         message: gettext("Could not connect to application."),
         help: gettext("This may be caused by problems with your connection or application server. Please check your internet connection and refresh page if problem persists.")

+ 10 - 6
misago/frontend/misago/routes/legal.js

@@ -28,14 +28,18 @@
         ondata: function(page, component, _) {
           m.startComputation();
 
-          page.title = page.title || defaultTitle;
-          this.page = page;
-          this.isReady = true;
+          if (page.link) {
+            window.location = page.link;
+          } else {
+            page.title = page.title || defaultTitle;
+            this.page = page;
+            this.isReady = true;
 
-          m.endComputation();
+            m.endComputation();
 
-          if (component.isActive) {
-            _.title.set(this.page.title);
+            if (component.isActive) {
+              _.title.set(this.page.title);
+            }
           }
         }
       },

+ 1 - 1
misago/frontend/misago/services/forum-layout.js

@@ -11,7 +11,7 @@
 
     destroy: function(_) {
       if (_.setup.fixture) {
-        m.mount(_.setup.fixture, null);
+        m.mount(document.getElementById(_.setup.fixture), null);
       }
     }
   }, {before: 'start-routing'});

+ 5 - 1
misago/frontend/misago/services/router.js

@@ -33,7 +33,11 @@
       populatePatterns(urlconf);
       this.fixture = fixture;
 
-      m.route.mode = 'pathname';
+      if (_.setup.test) {
+        m.route.mode = 'search';
+      } else {
+        m.route.mode = 'pathname';
+      }
       m.route(fixture, '/', this.urls);
     };
 

+ 3 - 0
misago/frontend/misago/urls.js

@@ -15,5 +15,8 @@
     Misago.PrivacyPolicyRoute,
     'privacy_policy');
 
+  // Catch-all 404 not found route
+  urls.url('/:rest...', Misago.Error404Route, 'not_found');
+
   Misago.urls = urls;
 } (Misago.prototype, Misago.prototype.UrlConf));

+ 10 - 0
misago/frontend/package.json

@@ -16,13 +16,23 @@
       "Misago",
       "m",
       "moment",
+
+      "initTestMisago",
       "getMisagoService",
+      "click",
+      "then",
+      "onElement",
+
+      "getElement",
+      "getElementText",
+
       "gettext",
       "ngettext",
       "gettext_noop",
       "pgettext",
       "npgettext",
       "interpolate",
+
       "console",
       "document",
       "window",

+ 4 - 3
misago/frontend/test/index.html

@@ -4,17 +4,18 @@
   <meta charset="utf-8">
   <title>Misago QUnit</title>
   <link rel="stylesheet" href="//code.jquery.com/qunit/qunit-1.18.0.css">
-  <link rel="stylesheet" href="/dist/css/misago.css">
+  <link rel="stylesheet" href="/dist/misago/css/misago.css">
   <base href="/">
 </head>
 <body>
   <div id="qunit"></div>
   <div id="qunit-fixture"></div>
+  <div id="misago-fixture"></div>
   <script src="//code.jquery.com/qunit/qunit-1.18.0.js"></script>
-  <script src="/dist/js/vendor.js"></script>
+  <script src="/dist/misago/js/vendor.js"></script>
   <script src="/dist/libs.js"></script>
   <script src="/dist/utils.js"></script>
-  <script src="/dist/js/misago.js"></script>
+  <script src="/dist/misago/js/misago.js"></script>
   <script src="/dist/tests.js"></script>
 </body>
 </html>

+ 141 - 0
misago/frontend/test/tests/acceptance/error-pages.js

@@ -0,0 +1,141 @@
+(function () {
+  'use strict';
+
+  var app = null;
+
+  QUnit.acceptance("Error Pages", {
+    beforeEach: function() {
+      app = initTestMisago();
+    },
+    afterEach: function() {
+      app.destroy();
+    }
+  });
+
+  QUnit.test("Error banned", function(assert) {
+    $.mockjax({
+      url: '/test-api/legal-pages/terms-of-service/',
+      status: 403,
+      responseText: {
+        'detail': 'You are banned!',
+        'ban': {
+          'expires_on': null,
+          'message': {
+            'plain': 'This is test ban.',
+            'html': '<p>This is test ban.</p>'
+          }
+        }
+      }
+    });
+
+    var done = assert.async();
+
+    click('.footer-nav li:first-child a');
+    onElement('.error-page.error-banned-page .error-message', function() {
+      assert.ok(true, "Permission denied error page was displayed.");
+      assert.equal(
+        getElementText('.page .error-message .lead'),
+        "This is test ban.",
+        "Banned page displayed ban message.");
+      done();
+    });
+  });
+
+  QUnit.test("Error 403 with message", function(assert) {
+    $.mockjax({
+      url: '/test-api/legal-pages/terms-of-service/',
+      status: 403,
+      responseText: {
+        'detail': "I can't let you do this Dave."
+      }
+    });
+
+    var done = assert.async();
+
+    click('.footer-nav li:first-child a');
+    onElement('.error-page.error-403-page .error-message', function() {
+      assert.ok(true, "Permission denied error page was displayed.");
+      assert.equal(
+        getElementText('.page .error-message .help'),
+        "I can't let you do this Dave.",
+        "Permission denied error page used backend message.");
+      done();
+    });
+  });
+
+  QUnit.test("Error 403 without message", function(assert) {
+    $.mockjax({
+      url: '/test-api/legal-pages/terms-of-service/',
+      status: 403,
+      responseText: {
+        'detail': 'Permission denied'
+      }
+    });
+
+    var done = assert.async();
+
+    click('.footer-nav li:first-child a');
+    onElement('.error-page.error-403-page .error-message', function() {
+      assert.ok(true, "Permission denied error page was displayed.");
+      assert.equal(
+        getElementText('.page .error-message .help'),
+        "You don't have permission to access this page.",
+        "Permission denied error page used default message.");
+      done();
+    });
+  });
+
+  QUnit.test("Error 404", function(assert) {
+    $.mockjax({
+      url: '/test-api/legal-pages/terms-of-service/',
+      status: 404
+    });
+
+    var done = assert.async();
+
+    click('.footer-nav li:first-child a');
+    onElement('.error-page.error-404-page', function() {
+      assert.ok(true, "Not found error page was displayed.");
+      done();
+    });
+  });
+
+  QUnit.test("Error 404 on invalid url", function(assert) {
+    var done = assert.async();
+    m.route('/some-invalid-url-is-her!');
+    onElement('.error-page.error-404-page', function() {
+      assert.ok(true, "Not found error page was displayed.");
+      done();
+    });
+  });
+
+  QUnit.test("Error 500", function(assert) {
+    $.mockjax({
+      url: '/test-api/legal-pages/terms-of-service/',
+      status: 500
+    });
+
+    var done = assert.async();
+
+    click('.footer-nav li:first-child a');
+    onElement('.error-page.error-500-page', function() {
+      assert.ok(true, "Backend error page was displayed.");
+      done();
+    });
+  });
+
+  QUnit.test("Error 0", function(assert) {
+    $.mockjax({
+      url: '/test-api/legal-pages/terms-of-service/',
+      isTimeout: true
+    });
+
+    var done = assert.async();
+
+    click('.footer-nav li:first-child a');
+    onElement('.error-page.error-0-page', function() {
+      assert.ok(true, "Timeout error page was displayed.");
+      done();
+    });
+  });
+}());

+ 156 - 0
misago/frontend/test/tests/acceptance/legal-pages.js

@@ -0,0 +1,156 @@
+(function () {
+  'use strict';
+
+  var app = null;
+
+  QUnit.acceptance("Legal Pages", {
+    beforeEach: function() {
+      app = initTestMisago();
+    },
+    afterEach: function() {
+      app.destroy();
+    }
+  });
+
+  QUnit.test('privacy policy link', function(assert) {
+    var doneHidden = assert.async();
+    var doneVisible = assert.async();
+
+    app.settings.terms_of_service = false;
+    app.settings.privacy_policy = false;
+
+    m.redraw();
+
+    onElement('.forum-footer', function() {
+      assert.equal(
+        getElementText('.footer-nav'), "",
+        "Privacy policy link is hidden in footer.");
+      doneHidden();
+
+      app.settings.privacy_policy = true;
+
+      m.redraw();
+
+      onElement('.footer-nav a', function() {
+        assert.equal(
+          getElementText('.footer-nav a'), "Test Privacy Policy",
+          "Privacy policy link is displayed in footer.");
+        doneVisible();
+      });
+    });
+  });
+
+  QUnit.test('terms of service link', function(assert) {
+    var doneHidden = assert.async();
+    var doneVisible = assert.async();
+
+    app.settings.privacy_policy = false;
+    app.settings.terms_of_service = false;
+
+    m.redraw();
+
+    onElement('.forum-footer', function() {
+      assert.equal(
+        getElementText('.footer-nav'), "",
+        "Terms link is hidden in footer.");
+      doneHidden();
+
+      app.settings.terms_of_service = true;
+
+      m.redraw();
+
+      onElement('.footer-nav a', function() {
+        assert.equal(
+          getElementText('.footer-nav a'), "Test Terms",
+          "Terms link is displayed in footer.");
+        doneVisible();
+      });
+    });
+  });
+
+  QUnit.test('legals pages disabled', function(assert) {
+    app.settings.privacy_policy = null;
+    app.settings.terms_of_service = null;
+
+    $.mockjax({
+      url: '/test-api/legal-pages/privacy-policy/',
+      status: 404,
+      responseText: {'detail': 'Not found'}
+    });
+    $.mockjax({
+      url: '/test-api/legal-pages/terms-of-service/',
+      status: 404,
+      responseText: {'detail': 'Not found'}
+    });
+
+    var donePrivacyPolicy = assert.async();
+    var doneTermsOfService = assert.async();
+
+    assert.ok(!getElement('.footer-nav a').length,
+      "footer nav has no legal pages links");
+
+    m.route('/privacy-policy/');
+    onElement('.error-page.error-404-page', function() {
+      assert.ok(true, "Unset privacy policy returned 404 page.");
+      donePrivacyPolicy();
+    });
+
+    m.route('/terms-of-service/');
+    onElement('.error-page.error-404-page', function() {
+      assert.ok(true, "Unset terms of service returned 404 page.");
+      doneTermsOfService();
+    });
+  });
+
+  QUnit.test('privacy policy page', function(assert) {
+    $.mockjax({
+      url: '/test-api/legal-pages/privacy-policy/',
+      status: 200,
+      responseText: {
+        'id': 'privacy-policy',
+        'link': '',
+        'title': 'Backend Policy',
+        'body': '<p>Lorem ipsum dolor met sit amet elit.</p>'
+      }
+    });
+
+    var done = assert.async();
+
+    m.route('/privacy-policy/');
+    onElement('.legal-page', function() {
+      assert.equal(
+        getElementText('.page-header h1'), 'Backend Policy',
+        "Privacy Policy page has been rendered.");
+      assert.equal(
+        getElementText('.container p'), 'Lorem ipsum dolor met sit amet elit.',
+        "Privacy Policy body has been rendered.");
+      done();
+    });
+  });
+
+  QUnit.test('terms of service page', function(assert) {
+    $.mockjax({
+      url: '/test-api/legal-pages/terms-of-service/',
+      status: 200,
+      responseText: {
+        'id': 'terms-of-service',
+        'link': '',
+        'title': 'Backend Terms',
+        'body': '<p>Lorem ipsum dolor met sit amet elit.</p>'
+      }
+    });
+
+    var done = assert.async();
+
+    m.route('/terms-of-service/');
+    onElement('.legal-page', function() {
+      assert.equal(
+        getElementText('.page-header h1'), 'Backend Terms',
+        "Terms of Service page has been rendered.");
+      assert.equal(
+        getElementText('.container p'), 'Lorem ipsum dolor met sit amet elit.',
+        "Terms of Service body has been rendered.");
+      done();
+    });
+  });
+}());

+ 19 - 0
misago/frontend/test/tests/acceptance/tests-utils.js

@@ -0,0 +1,19 @@
+(function () {
+  'use strict';
+
+  QUnit.module("Acceptance Tests Utils");
+
+  QUnit.test("create and destroy Misago app", function(assert) {
+    var done = assert.async();
+    var app = initTestMisago();
+
+    assert.equal($('#router-fixture').length, 1, "#router-fixture created");
+
+    app.destroy();
+
+    window.setTimeout(function() {
+      assert.equal($('#router-fixture').length, 0, "#router-fixture removed");
+      done();
+    }, 100);
+  });
+}());

+ 90 - 0
misago/frontend/test/utils/async-utils.js

@@ -0,0 +1,90 @@
+(function () {
+  'use strict';
+
+  var deferred = m.deferred();
+  window._promise = deferred.promise;
+  window.setTimeout(function() {
+    deferred.resolve();
+  }, 50);
+
+  var getElement = function(selector) {
+    var deferred = m.deferred();
+
+    var _getElement = function() {
+      window.setTimeout(function() {
+        var $element = $('#misago-fixture ' + selector);
+        if ($element.length >= 1) {
+          deferred.resolve($element);
+        } else {
+          _getElement();
+        }
+      }, 50);
+    };
+
+    _getElement();
+
+    return deferred.promise;
+  };
+
+  var queueAction = function(action) {
+    window._promise.then(function() {
+      window._promise = action();
+    });
+  };
+
+  window.click = function(selector) {
+    queueAction(function() {
+      var deferred = m.deferred();
+      getElement(selector).then(function(element) {
+        window.setTimeout(function() {
+          element.trigger('click');
+          window.setTimeout(function() {
+            deferred.resolve();
+          }, 50);
+        }, 50);
+      });
+      return deferred.promise;
+    });
+  };
+
+  window.then = function(callback, timeout) {
+    queueAction(function() {
+      var deferred = m.deferred();
+      window.setTimeout(function() {
+        callback();
+        deferred.resolve();
+      }, timeout || 80);
+      return deferred.promise;
+    });
+  };
+
+  window.onElement = function(selector, callback) {
+    queueAction(function() {
+      var deferred = m.deferred();
+      getElement(selector).then(function(element) {
+        window.setTimeout(function() {
+          callback(element);
+          deferred.resolve();
+        }, 50);
+      });
+      return deferred.promise;
+    });
+  };
+
+  window.onCleanUp = function(callback) {
+    var waitForFixtureCleanUp = function() {
+      window.setTimeout(function() {
+        var content = $.trim($('#misago-fixture').html());
+        if (!content) {
+          window.setTimeout(function() {
+            callback();
+          }, 250);
+        } else {
+          waitForFixtureCleanUp();
+        }
+      }, 50);
+    };
+
+    waitForFixtureCleanUp();
+  };
+}());

+ 100 - 0
misago/frontend/test/utils/misago-factory.js

@@ -0,0 +1,100 @@
+(function () {
+  'use strict';
+
+  window.initTestMisago = function() {
+    var misago = new Misago();
+
+    misago.context = {
+      "CSRF_COOKIE_NAME": "csrftoken",
+
+      "STATIC_URL": "/dist/",
+      "MEDIA_URL": "/media/",
+
+      "SETTINGS": {
+        "LOGIN_URL": "/login/",
+        "LOGIN_API_URL": "auth",
+        "LOGIN_REDIRECT_URL": "/",
+        "LOGOUT_URL": "/logout/",
+
+        "thread_title_length_min": 5,
+        "account_activation": "none",
+        "recaptcha_site_key": "",
+        "password_length_min": 5,
+        "forum_branding_text": "isago",
+        "username_length_max": 14,
+        "signature_length_max": 256,
+        "username_length_min": 3,
+        "forum_footnote": "",
+        "forum_index_title": "Misago Preview",
+        "captcha_type": "no",
+        "forum_branding_display": true,
+        "forum_name": "Misago",
+        "avatar_upload_limit": 750,
+        "thread_title_length_max": 90,
+
+        "privacy_policy": true,
+        "privacy_policy_title": "Test Privacy Policy",
+        "privacy_policy_link": "",
+
+        "terms_of_service": true,
+        "terms_of_service_title": "Test Terms",
+        "terms_of_service_link": ""
+      },
+
+      "isAuthenticated": false,
+      "user": {
+        "id": null,
+        "acl": {
+          "can_delete_users_newer_than": 0,
+          "can_see_users_name_history": 0,
+          "can_moderate_avatars": 0,
+          "can_be_warned": 1,
+          "can_see_reports": [],
+          "can_follow_users": 0,
+          "can_see_users_emails": 0,
+          "can_see_users_online_list": 0,
+          "can_moderate_signatures": 0,
+          "can_start_private_threads": 0,
+          "name_changes_allowed": 0,
+          "can_add_everyone_to_private_threads": 0,
+          "_acl_version": 6,
+          "can_rename_users": 0,
+          "can_browse_users_list": 1,
+          "allow_signature_links": 0,
+          "visible_forums": [3, 4, 5],
+          "can_warn_users": 0,
+          "can_report_private_threads": 0,
+          "can_search_users": 1,
+          "can_use_private_threads": 0,
+          "can_be_blocked": 1,
+          "can_review_moderated_content": [],
+          "can_delete_users_with_less_posts_than": 0,
+          "can_moderate_private_threads": 0,
+          "can_see_ban_details": 0,
+          "can_delete_warnings": 0,
+          "can_see_users_ips": 0,
+          "allow_signature_blocks": 0,
+          "can_ban_users": 0,
+          "max_ban_length": 2,
+          "can_have_signature": 0,
+          "allow_signature_images": 0,
+          "can_see_hidden_users": 0,
+          "max_private_thread_participants": 3,
+          "can_cancel_warnings": 0,
+          "name_changes_expire": 0,
+          "can_lift_bans": 0,
+          "max_lifted_ban_length": 2,
+          "can_see_other_users_warnings": 0
+        }
+      }
+    };
+
+    misago.init({
+      test: true,
+      fixture: 'misago-fixture',
+      api: '/test-api/'
+    });
+
+    return misago;
+  };
+}());

+ 25 - 0
misago/frontend/test/utils/mock-window.js

@@ -0,0 +1,25 @@
+// Mithril.js window mock factory
+// jshint ignore: start
+(function (global) {
+  'use strict';
+
+  window.mock = function() {
+    var window = {}
+    window.document = global.document;
+    window.scrollTo = function() {};
+    window.cancelAnimationFrame = global.cancelAnimationFrame;
+    window.requestAnimationFrame = global.requestAnimationFrame;
+    window.XMLHttpRequest = global.XMLHttpRequest;
+    window.location = {search: "", pathname: "", hash: ""};
+    window.history = {};
+    window.history.$$length = 0;
+    window.history.pushState = function(data, title, url) {
+      window.history.$$length++
+      window.location.pathname = window.location.search = window.location.hash = url
+    };
+    window.history.replaceState = function(data, title, url) {
+      window.location.pathname = window.location.search = window.location.hash = url
+    };
+    return window;
+  };
+}(window));

+ 28 - 0
misago/frontend/test/utils/qunit-boilerplate.js

@@ -0,0 +1,28 @@
+(function () {
+  'use strict';
+
+  // Boilerplate QUnit acceptance test
+  QUnit.acceptance = function(name, conf) {
+    var title = document.title;
+
+    var wrappedBeforeEach = conf.beforeEach;
+    conf.beforeEach = function() {
+      m.deps(window.mock());
+      wrappedBeforeEach();
+    };
+
+    var wrappedAfterEach = conf.afterEach;
+    conf.afterEach = function(assert) {
+      var cleaned = assert.async();
+      wrappedAfterEach();
+      document.title = title;
+      $.mockjax.clear();
+
+      window.onCleanUp(function() {
+        cleaned();
+      });
+    };
+
+    QUnit.module('Acceptance: ' + name, conf);
+  };
+}());

+ 11 - 0
misago/frontend/test/utils/selectors.js

@@ -0,0 +1,11 @@
+(function () {
+  'use strict';
+
+  window.getElement = function(selector) {
+    return $('#misago-fixture ' + selector);
+  };
+
+  window.getElementText = function(selector) {
+    return $.trim(getElement(selector).text());
+  };
+}());

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

@@ -1,2 +1,2 @@
-!function(){"use strict";window.Misago=function(){var t=Object.getPrototypeOf(this),e=this;this.context={SETTINGS:{}},this._initServices=function(r){var n=new t.OrderedList(r).order(!1);n.forEach(function(t){var r=null;r=void 0!==t.item.factory?t.item.factory:t.item;var n=r(e);n&&(e[t.key]=n)})},this._destroyServices=function(r){var n=new t.OrderedList(r).order();n.reverse(),n.forEach(function(t){void 0!==t.destroy&&t.destroy(e)})},this.setup=!1,this.init=function(e){this.setup={fixture:t.get(e,"fixture",null),inTest:t.get(e,"inTest",!1),api:t.get(e,"api","/api/")},this._initServices(t._services)},this.destroy=function(){this._destroyServices(t._services)}};var t=window.Misago.prototype;t._services=[],t.addService=function(e,r,n){t._services.push({key:e,item:r,after:t.get(n,"after"),before:t.get(n,"before")})}}(),function(t){"use strict";t.has=function(t,e){return t?t.hasOwnProperty(e):!1},t.get=function(e,r,n){return t.has(e,r)?e[r]:void 0!==n?n:void 0},t.pop=function(e,r,n){var i=t.get(e,r,n);return t.has(e,r)&&(e[r]=null),i}}(Misago.prototype),function(t){"use strict";t.OrderedList=function(e){this.isOrdered=!1,this._items=e||[],this.add=function(e,r,n){this._items.push({key:e,item:r,after:t.get(n,"after"),before:t.get(n,"before")})},this.get=function(t,e){for(var r=0;r<this._items.length;r++)if(this._items[r].key===t)return this._items[r].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===i.indexOf(t.key)&&(t.after?(e=i.indexOf(t.after),-1!==e&&(e+=1)):t.before&&(e=i.indexOf(t.before)),-1!==e&&(n.splice(e,0,t),i.splice(e,0,t.key)))}var r=[];t.forEach(function(t){r.push(t.key)});var n=[],i=[];t.forEach(function(t){t.after||t.before||(n.push(t),i.push(t.key))}),t.forEach(function(t){"_end"===t.before&&(n.push(t),i.push(t.key))});for(var o=200;o>0&&r.length!==i.length;)o-=1,t.forEach(e);return n}}}(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.UrlConfInvalidComponentError=function(t){this.message="route's "+t+" component should be an array or object",this.toString=function(){return this.message}},t.UrlConf=function(){var e=this;this._patterns=[],this.patterns=function(){return this._patterns};var r=function(t,e){return(t+e).replace("//","/")},n=function(t,n){for(var i=0;i<n.length;i++)e.url(r(t,n[i].pattern),n[i].component,n[i].name)};this.url=function(e,r,i){if("object"!=typeof r)throw new t.UrlConfInvalidComponentError(i);""===e&&(e="/"),r instanceof t.UrlConf?n(e,r.patterns()):this._patterns.push({pattern:e,component:r,name:i})}}}(Misago.prototype),function(t){"use strict";t.loadingPage=function(e){return m(".page.page-loading",e.component(t.Loader))}}(Misago.prototype),function(t){"use strict";var e=function(e){if(-1!==document.cookie.indexOf(e)){var r=new RegExp(e+"=([^;]*)"),n=t.get(document.cookie.match(r),0);return n.split("=")[1]}return null},r=function(r){this.csrfToken=e(r.context.CSRF_COOKIE_NAME);var n={};this.ajax=function(e,r,i,o){var s=m.deferred(),a={url:r,method:e,headers:{"X-CSRFToken":this.csrfToken},data:i|{},dataType:"json",success:function(i){"GET"===e&&t.pop(n,r),s.resolve(i)},error:function(i){"GET"===e&&t.pop(n,r);var o=i.responseJSON||{};o.status=i.status,o.statusText=i.statusText,s.reject(o)}};return o?void 0:($.ajax(a),s.promise)},this.get=function(e){var i=t.pop(r.context,e);if(i){var o=m.deferred();return o.resolve(i),o.promise}return void 0!==n[e]?n[e]:(n[e]=this.ajax("GET",e),n[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 r(t)})}(Misago.prototype),function(t){"use strict";var e=function(t){if("object"==typeof t){var e=[];for(var r in t)if(t.hasOwnProperty(r)){var n=encodeURIComponent(r),i=encodeURIComponent(t[r]);e.push(n+"="+i)}return"?"+e.join("&")}return t+"/"},r=function(t,n){this.url=n.url||t.setup.api,this.url+=n.path?n.path+"/":n.related?n.related+"/":n.model+"s/",n.filters&&(this.url+=e(n.filters)),!n.url&&n.filters&&(n.model&&(this.related=function(e,i){return new r(t,{url:this.url,relation:n.model,related:e,filters:i})}),this.endpoint=function(e,n){return new r(t,{url:this.url,path:e,filters:n})}),this.get=function(){var e=null;return n.related?e=n.relation+":"+n.related:n.model&&(e=n.model),t.ajax.get(this.url).then(function(r){return e?r.results?(r.results.map(function(r){return t.models["new"](e,r)}),r):t.models["new"](e,r):r})},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)}},n=function(t){this.model=function(e,n){return new r(t,{model:e,filters:n})},this.endpoint=function(e,n){return new r(t,{path:e,filters:n})}};t.addService("api",function(t){return new n(t)})}(Misago.prototype),function(t){"use strict";t.addService("component-factory",function(t){t.component=function(){for(var e=[],r=0;r<arguments.length;r+=1)e.push(arguments[r]);return e.push(t),m.component.apply(void 0,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";t.addService("forum-layout",{factory:function(e){e.setup.fixture&&m.mount(document.getElementById(e.setup.fixture),e.component(t.ForumLayout))},destroy:function(t){t.setup.fixture&&m.mount(t.setup.fixture,null)}},{before:"start-routing"})}(Misago.prototype),function(t){"use strict";var e=function(){this.classes={},this.deserializers={},this.relations={},this.add=function(t,e){if(e["class"]&&(this.classes[t]=e["class"]),e.deserialize&&(this.deserializers[t]=e.deserialize),e.relations)for(var r in e.relations)e.relations.hasOwnProperty(r)&&(this.relations[t+":"+r]=e.relations[r])},this["new"]=function(t,e){return this.classes[t]?new this.classes[t](e):e},this.deserialize=function(t,e){return this.relations[t]&&(t=this.relations[t]),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.route=function(r){r.isActive=!0;var n=r.controller||e;if(r.controller=function(){r.isActive=!0;var t=n.apply(r,arguments)||{},i=t.onunload||e;return t.onunload=function(){i.apply(r,arguments),r.isActive=!1},t},r.vm&&r.vm.init){var i=r.vm.init;r.vm.init=function(){var t=arguments,e=i.apply(r.vm,t);e&&e.then(function(){if(r.isActive&&r.vm.ondata){for(var e=[],n=0;n<arguments.length;n++)e.push(arguments[n]);for(var i=0;i<t.length;i++)e.push(t[i]);r.vm.ondata.apply(r.vm,e)}},function(t){r.isActive&&r.container.router.errorPage(t)})},r.loading||(r.loading=function(){var e=this.container;return m(".page.page-loading",e.component(t.Loader))});var o=r.view;r.view=function(){return r.vm.isReady?o.apply(r,arguments):r.loading.apply(r,arguments)}}return r}}(Misago.prototype),function(t){"use strict";var e=function(e){var r=this;this.baseUrl=$("base").attr("href");var n=t.get(e.context,"STATIC_URL","/"),i=t.get(e.context,"MEDIA_URL","/");this.urls={},this.reverses={};var o=function(t){return t.container=e,t},s=function(t){t.patterns().forEach(function(t){var e=r.baseUrl+t.pattern;e=e.replace("//","/"),r.urls[e]=o(t.component),r.reverses[t.name]=e})};this.startRouting=function(t,e){s(t),this.fixture=e,m.route.mode="pathname",m.route(e,"/",this.urls)},this.url=function(t){return this.reverses[t]},this.delegateElement=null,this.delegateName="click.misago-router",this.cleanUrl=function(t){if(t){var e="/"===t.substr(0,1)&&"//"!==t.substr(0,2);if(!e){var r=window.location;if("//"!==t.substr(0,2)){var o=t.substr(0,r.protocol.length+2);if(o!==r.protocol+"//")return;t=t.substr(r.protocol.length+2)}else t=t.substr(2);if(t.substr(0,r.host.length)!==r.host)return;t=t.substr(r.host.length)}if(t.substr(0,this.baseUrl.length)===this.baseUrl&&t.substr(0,n.length)!==n&&t.substr(0,i.length)!==i){var s="/user-avatar/";if(t.substr(0,s.length)!==s)return t}}},this.delegateClicks=function(t){this.delegateElement=t,$(this.delegateElement).on(this.delegateName,"a",function(t){var e=r.cleanUrl(t.target.href);e&&(e!=m.route()&&m.route(e),t.preventDefault())})},this.destroy=function(){$(this.delegateElement).off(this.delegateName)};var a=function(t){return function(e){return t+e}};this.staticUrl=a(n),this.mediaUrl=a(i),this.error403=function(r){var n=null;r.ban?(n=o(t.ErrorBannedRoute),n.error={message:r.detail,ban:e.models.deserialize("ban",r.ban)}):(n=o(t.Error403Route),n.error=r.detail),m.mount(this.fixture,n)},this.error404=function(){m.mount(this.fixture,o(t.Error404Route))},this.error500=function(){m.mount(this.fixture,o(t.Error500Route))},this.error0=function(){m.mount(this.fixture,o(t.Error0Route))},this.errorPage=function(t){0===t.status&&this.error0(),500===t.status&&this.error500(),404===t.status&&this.error404(),403===t.status&&this.error403(t)}};t.addService("router",function(t){return new e(t)}),t.addService("start-routing",function(e){e.router.startRouting(t.urls,document.getElementById("router-fixture")),e.router.delegateClicks(document.getElementById(e.setup.fixture))},{before:"_end"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=this;this._intervals={};var r=function(t){e._intervals[t]&&(window.clearTimeout(e._intervals[t]),e._intervals[t]=null)};this.run=function(n,i,o){this._intervals[i]=window.setTimeout(function(){r(i);var s=n(t);s!==!1&&e.run(n,i,o)},o)},this.runOnce=function(e,n,i){this._intervals[n]=window.setTimeout(function(){r(n),e(t)},i)},this.stop=function(t){for(var e in this._intervals)t&&t!==e||r(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("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 r=e.title;if("undefined"!=typeof e.page&&e.page>1){var n=interpolate(gettext("page %(page)s"),{page:e.page},!0);r+=" ("+n+")"}"undefined"!=typeof e.parent&&(r+=" | "+e.parent),document.title=r+" | "+t}};t.addService("page-title",function(t){t.title=new e(t.settings.forum_name)})}(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},r=function(e){return e.expires_on=t.deserializeDatetime(e.expires_on),new t.Ban(e)};t.addService("ban-model",function(t){t.models.add("ban",{"class":e,deserialize:r})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){this.title=t.title,this.body=t.body};t.addService("legal-page-model",function(t){t.models.add("legal-page",{"class":e})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=[m("p.lead",t.message)];return t.help&&e.push(m("p.help",t.help)),m(".page.error-page.error-"+t.code+"-page",m(".container",m(".error-panel",[m(".error-icon",m("span.material-icon",t.icon)),m(".error-message",e)])))};t.ErrorBannedRoute=t.route({controller:function(){this.container.title.set(gettext("You are banned"))},error:null,view:function(){var t=[];t.push(this.error.ban.message.html?m(".lead",m.trust(this.error.ban.message.html)):m("p.lead",this.error.message));var e=null;return e=this.error.ban.expires_on?this.error.ban.expires_on.isAfter(moment())?interpolate(gettext("This ban expires %(expires_on)s."),{expires_on:this.error.ban.expires_on.fromNow()},!0):gettext("This ban has expired."):gettext("This ban is permanent."),t.push(m("p",e)),m(".page.error-page.error-banned-page",m(".container",m(".error-panel",[m(".error-icon",m("span.material-icon","highlight_off")),m(".error-message",t)])))}}),t.Error403Route=t.route({controller:function(){this.container.title.set(gettext("Page not available"))},error:null,view:function(){return e({code:403,icon:"remove_circle_outline",message:gettext("This page is not available."),help:this.error||gettext("You don't have permission to access this page.")})}}),t.Error404Route=t.route({controller:function(){this.container.title.set(gettext("Page not found"))},view:function(){return e({code:404,icon:"info_outline",message:gettext("Requested page could not be found."),help:gettext("The link you followed was incorrect or the page has been moved or deleted.")})}}),t.Error500Route=t.route({controller:function(){this.container.title.set(gettext("Application error occured"))},view:function(){return e({code:500,icon:"error_outline",message:gettext("Requested page could not be displayed due to an error."),help:gettext("Please try again later or contact site staff if error persists.")})}}),t.Error0Route=t.route({controller:function(){this.container.title.set(gettext("Lost connection with application"))},view:function(){return e({code:500,icon:"sync_problem",message:gettext("Could not connect to application."),help:gettext("This may be caused by problems with your connection or application server. Please check your internet connection and refresh page if problem persists.")})}})}(Misago.prototype),function(t){"use strict";t.IndexRoute=t.route({controller:function(){var t=this.container;document.title=t.settings.forum_index_title||t.settings.forum_name;var e=m.prop(0);return{count:e,increment:function(){console.log("increment()"),e(e()+1)}}},view:function(t){return m(".container",[m("h1",["Count: ",m("strong",t.count())]),m("p","Clicky click button to increase count!."),m("p",m("button.btn.btn-primary",{onclick:t.increment},"Clicky clicky!"))])}})}(Misago.prototype),function(t){"use strict";var e=function(e,r){var n=e.replace(/_/g,"-");return t.route({controller:function(){var r=this.container;t.get(r.settings,e+"_link")?window.location=t.get(r.settings,e+"_link"):this.vm.init(this,r)},vm:{page:null,isReady:!1,init:function(t,e){return this.isReady?void e.title.set(this.title):(e.title.set(),e.api.model("legal-page",n))},ondata:function(t,e,n){m.startComputation(),t.title=t.title||r,this.page=t,this.isReady=!0,m.endComputation(),e.isActive&&n.title.set(this.page.title)}},view:function(){var e=this.container;return m(".page.legal-page."+n+"-page",[e.component(t.PageHeader,{title:this.vm.page.title}),m(".container",e.component(t.Markup,this.vm.page.body))])}})};t.TermsOfServiceRoute=e("terms_of_service",gettext("Terms of service")),t.PrivacyPolicyRoute=e("privacy_policy",gettext("Privacy policy"))}(Misago.prototype),function(t){"use strict";var e=function(e,r,n){var i=t.get(e.settings,r+"_link");return!i&&t.get(e.settings,r)&&(i=e.router.url(r)),i?m("li",m("a",{href:i},t.get(e.settings,r+"_title",n))):null};t.FooterNav={isVisible:function(t){return-1!==[!!t.forum_footnote,!!t.terms_of_service,!!t.terms_of_service_link,!!t.privacy_policy,!!t.privacy_policy_link].indexOf(!0)},view:function(t,r){var n=[];return r.settings.forum_footnote&&n.push(m("li.forum-footnote",m.trust(r.settings.forum_footnote))),n.push(e(r,"terms_of_service",gettext("Terms of service"))),n.push(e(r,"privacy_policy",gettext("Privacy policy"))),m("ul.list-inline.footer-nav",n)}}}(Misago.prototype),function(t){"use strict";t.ForumFooter={view:function(e,r){var n=null;return t.FooterNav.isVisible(r.settings)&&(n=r.component(t.FooterNav)),m("footer.forum-footer",[m(".container",m(".footer-content",[n,r.component(t.FooterMisagoBranding)]))])}}}(Misago.prototype),function(t){"use strict";t.FooterMisagoBranding={view:function(){return m("a.misago-branding[href=http://misago-project.org]",["powered by ",m("strong","misago")])}}}(Misago.prototype),function(t){"use strict";t.BrandFull={view:function(t,e,r){var n=[m("img",{src:r.router.staticUrl("misago/img/site-logo.png"),alt:r.settings.forum_name})];return e&&n.push(e),m("a.navbar-brand",{href:r.router.url("index")},n)}}}(Misago.prototype),function(t){"use strict";t.ForumNavbar={view:function(e,r){var n=[];r.settings.forum_branding_display&&n.push(r.component(t.BrandFull,r.settings.forum_branding_text)),n.push(m("ul.nav.navbar-nav",[m("li",m("a",{config:m.route,href:r.router.url("index")},"Index"))]));var i=".navbar.navbar-default.navbar-static-top";return m("nav"+i+'[role="navigation"]',[m(".container.navbar-full.hidden-xs.hidden-sm",n)])}}}(Misago.prototype),function(t){"use strict";var e=function(t,e,r){r.retain=!0};t.ForumLayout={view:function(r,n){return[n.component(t.ForumNavbar),m("#router-fixture",{config:e}),n.component(t.ForumFooter)]}}}(Misago.prototype),function(t){"use strict";t.Loader={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.LoadingPage={view:function(e,r){return m(".page.loading-page",r.component(t.Loader))}}}(Misago.prototype),function(t){"use strict";var e=function(t,e,r){r.retain=!0};t.Markup={view:function(t,r){return m("article.misago-markup",{config:e},m.trust(r))}}}(Misago.prototype),function(t){"use strict";t.PageHeader={view:function(t,e){return m(".page-header",m(".container",[m("h1",e.title)]))}}}(Misago.prototype),function(t,e){"use strict";var r=new e;r.url("/",t.IndexRoute,"index"),r.url("/terms-of-service/",t.TermsOfServiceRoute,"terms_of_service"),r.url("/privacy-policy/",t.PrivacyPolicyRoute,"privacy_policy"),t.urls=r}(Misago.prototype,Misago.prototype.UrlConf);
+!function(){"use strict";window.Misago=function(){var t=Object.getPrototypeOf(this),e=this;this.context={SETTINGS:{}},this._initServices=function(r){var n=new t.OrderedList(r).order(!1);n.forEach(function(t){var r=null;r=void 0!==t.item.factory?t.item.factory:t.item;var n=r(e);n&&(e[t.key]=n)})},this._destroyServices=function(r){var n=new t.OrderedList(r).order();n.reverse(),n.forEach(function(t){void 0!==t.destroy&&t.destroy(e)})},this.setup=!1,this.init=function(e){this.setup={fixture:t.get(e,"fixture",null),test:t.get(e,"test",!1),api:t.get(e,"api","/api/")},this._initServices(t._services)},this.destroy=function(){this._destroyServices(t._services)}};var t=window.Misago.prototype;t._services=[],t.addService=function(e,r,n){t._services.push({key:e,item:r,after:t.get(n,"after"),before:t.get(n,"before")})}}(),function(t){"use strict";t.has=function(t,e){return t?t.hasOwnProperty(e):!1},t.get=function(e,r,n){return t.has(e,r)?e[r]:void 0!==n?n:void 0},t.pop=function(e,r,n){var i=t.get(e,r,n);return t.has(e,r)&&(e[r]=null),i}}(Misago.prototype),function(t){"use strict";t.OrderedList=function(e){this.isOrdered=!1,this._items=e||[],this.add=function(e,r,n){this._items.push({key:e,item:r,after:t.get(n,"after"),before:t.get(n,"before")})},this.get=function(t,e){for(var r=0;r<this._items.length;r++)if(this._items[r].key===t)return this._items[r].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===i.indexOf(t.key)&&(t.after?(e=i.indexOf(t.after),-1!==e&&(e+=1)):t.before&&(e=i.indexOf(t.before)),-1!==e&&(n.splice(e,0,t),i.splice(e,0,t.key)))}var r=[];t.forEach(function(t){r.push(t.key)});var n=[],i=[];t.forEach(function(t){t.after||t.before||(n.push(t),i.push(t.key))}),t.forEach(function(t){"_end"===t.before&&(n.push(t),i.push(t.key))});for(var o=200;o>0&&r.length!==i.length;)o-=1,t.forEach(e);return n}}}(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.UrlConfInvalidComponentError=function(t){this.message="route's "+t+" component should be an array or object",this.toString=function(){return this.message}},t.UrlConf=function(){var e=this;this._patterns=[],this.patterns=function(){return this._patterns};var r=function(t,e){return(t+e).replace("//","/")},n=function(t,n){for(var i=0;i<n.length;i++)e.url(r(t,n[i].pattern),n[i].component,n[i].name)};this.url=function(e,r,i){if("object"!=typeof r)throw new t.UrlConfInvalidComponentError(i);""===e&&(e="/"),r instanceof t.UrlConf?n(e,r.patterns()):this._patterns.push({pattern:e,component:r,name:i})}}}(Misago.prototype),function(t){"use strict";t.loadingPage=function(e){return m(".page.page-loading",e.component(t.Loader))}}(Misago.prototype),function(t){"use strict";var e=function(e){if(-1!==document.cookie.indexOf(e)){var r=new RegExp(e+"=([^;]*)"),n=t.get(document.cookie.match(r),0);return n.split("=")[1]}return null},r=function(r){this.csrfToken=e(r.context.CSRF_COOKIE_NAME);var n={};this.ajax=function(e,r,i,o){var s=m.deferred(),a={url:r,method:e,headers:{"X-CSRFToken":this.csrfToken},data:i|{},dataType:"json",success:function(i){"GET"===e&&t.pop(n,r),s.resolve(i)},error:function(i){"GET"===e&&t.pop(n,r);var o=i.responseJSON||{};o.status=i.status,o.statusText=i.statusText,s.reject(o)}};return o?void 0:($.ajax(a),s.promise)},this.get=function(e){var i=t.pop(r.context,e);if(i){var o=m.deferred();return o.resolve(i),o.promise}return void 0!==n[e]?n[e]:(n[e]=this.ajax("GET",e),n[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 r(t)})}(Misago.prototype),function(t){"use strict";var e=function(t){if("object"==typeof t){var e=[];for(var r in t)if(t.hasOwnProperty(r)){var n=encodeURIComponent(r),i=encodeURIComponent(t[r]);e.push(n+"="+i)}return"?"+e.join("&")}return t+"/"},r=function(t,n){this.url=n.url||t.setup.api,this.url+=n.path?n.path+"/":n.related?n.related+"/":n.model+"s/",n.filters&&(this.url+=e(n.filters)),!n.url&&n.filters&&(n.model&&(this.related=function(e,i){return new r(t,{url:this.url,relation:n.model,related:e,filters:i})}),this.endpoint=function(e,n){return new r(t,{url:this.url,path:e,filters:n})}),this.get=function(){var e=null;return n.related?e=n.relation+":"+n.related:n.model&&(e=n.model),t.ajax.get(this.url).then(function(r){return e?r.results?(r.results.map(function(r){return t.models["new"](e,r)}),r):t.models["new"](e,r):r})},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)}},n=function(t){this.model=function(e,n){return new r(t,{model:e,filters:n})},this.endpoint=function(e,n){return new r(t,{path:e,filters:n})}};t.addService("api",function(t){return new n(t)})}(Misago.prototype),function(t){"use strict";t.addService("component-factory",function(t){t.component=function(){for(var e=[],r=0;r<arguments.length;r+=1)e.push(arguments[r]);return e.push(t),m.component.apply(void 0,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";t.addService("forum-layout",{factory:function(e){e.setup.fixture&&m.mount(document.getElementById(e.setup.fixture),e.component(t.ForumLayout))},destroy:function(t){t.setup.fixture&&m.mount(document.getElementById(t.setup.fixture),null)}},{before:"start-routing"})}(Misago.prototype),function(t){"use strict";var e=function(){this.classes={},this.deserializers={},this.relations={},this.add=function(t,e){if(e["class"]&&(this.classes[t]=e["class"]),e.deserialize&&(this.deserializers[t]=e.deserialize),e.relations)for(var r in e.relations)e.relations.hasOwnProperty(r)&&(this.relations[t+":"+r]=e.relations[r])},this["new"]=function(t,e){return this.classes[t]?new this.classes[t](e):e},this.deserialize=function(t,e){return this.relations[t]&&(t=this.relations[t]),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.route=function(r){r.isActive=!0;var n=r.controller||e;if(r.controller=function(){r.isActive=!0;var t=n.apply(r,arguments)||{},i=t.onunload||e;return t.onunload=function(){i.apply(r,arguments),r.isActive=!1},t},r.vm&&r.vm.init){var i=r.vm.init;r.vm.init=function(){var t=arguments,e=i.apply(r.vm,t);e&&e.then(function(){if(r.isActive&&r.vm.ondata){for(var e=[],n=0;n<arguments.length;n++)e.push(arguments[n]);for(var i=0;i<t.length;i++)e.push(t[i]);r.vm.ondata.apply(r.vm,e)}},function(t){r.isActive&&r.container.router.errorPage(t)})},r.loading||(r.loading=function(){var e=this.container;return m(".page.page-loading",e.component(t.Loader))});var o=r.view;r.view=function(){return r.vm.isReady?o.apply(r,arguments):r.loading.apply(r,arguments)}}return r}}(Misago.prototype),function(t){"use strict";var e=function(e){var r=this;this.baseUrl=$("base").attr("href");var n=t.get(e.context,"STATIC_URL","/"),i=t.get(e.context,"MEDIA_URL","/");this.urls={},this.reverses={};var o=function(t){return t.container=e,t},s=function(t){t.patterns().forEach(function(t){var e=r.baseUrl+t.pattern;e=e.replace("//","/"),r.urls[e]=o(t.component),r.reverses[t.name]=e})};this.startRouting=function(t,r){s(t),this.fixture=r,m.route.mode=e.setup.test?"search":"pathname",m.route(r,"/",this.urls)},this.url=function(t){return this.reverses[t]},this.delegateElement=null,this.delegateName="click.misago-router",this.cleanUrl=function(t){if(t){var e="/"===t.substr(0,1)&&"//"!==t.substr(0,2);if(!e){var r=window.location;if("//"!==t.substr(0,2)){var o=t.substr(0,r.protocol.length+2);if(o!==r.protocol+"//")return;t=t.substr(r.protocol.length+2)}else t=t.substr(2);if(t.substr(0,r.host.length)!==r.host)return;t=t.substr(r.host.length)}if(t.substr(0,this.baseUrl.length)===this.baseUrl&&t.substr(0,n.length)!==n&&t.substr(0,i.length)!==i){var s="/user-avatar/";if(t.substr(0,s.length)!==s)return t}}},this.delegateClicks=function(t){this.delegateElement=t,$(this.delegateElement).on(this.delegateName,"a",function(t){var e=r.cleanUrl(t.target.href);e&&(e!=m.route()&&m.route(e),t.preventDefault())})},this.destroy=function(){$(this.delegateElement).off(this.delegateName)};var a=function(t){return function(e){return t+e}};this.staticUrl=a(n),this.mediaUrl=a(i),this.error403=function(r){var n=null;r.ban?(n=o(t.ErrorBannedRoute),n.error={message:r.detail,ban:e.models.deserialize("ban",r.ban)}):(n=o(t.Error403Route),n.error=r.detail),m.mount(this.fixture,n)},this.error404=function(){m.mount(this.fixture,o(t.Error404Route))},this.error500=function(){m.mount(this.fixture,o(t.Error500Route))},this.error0=function(){m.mount(this.fixture,o(t.Error0Route))},this.errorPage=function(t){0===t.status&&this.error0(),500===t.status&&this.error500(),404===t.status&&this.error404(),403===t.status&&this.error403(t)}};t.addService("router",function(t){return new e(t)}),t.addService("start-routing",function(e){e.router.startRouting(t.urls,document.getElementById("router-fixture")),e.router.delegateClicks(document.getElementById(e.setup.fixture))},{before:"_end"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=this;this._intervals={};var r=function(t){e._intervals[t]&&(window.clearTimeout(e._intervals[t]),e._intervals[t]=null)};this.run=function(n,i,o){this._intervals[i]=window.setTimeout(function(){r(i);var s=n(t);s!==!1&&e.run(n,i,o)},o)},this.runOnce=function(e,n,i){this._intervals[n]=window.setTimeout(function(){r(n),e(t)},i)},this.stop=function(t){for(var e in this._intervals)t&&t!==e||r(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("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 r=e.title;if("undefined"!=typeof e.page&&e.page>1){var n=interpolate(gettext("page %(page)s"),{page:e.page},!0);r+=" ("+n+")"}"undefined"!=typeof e.parent&&(r+=" | "+e.parent),document.title=r+" | "+t}};t.addService("page-title",function(t){t.title=new e(t.settings.forum_name)})}(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},r=function(e){return e.expires_on=t.deserializeDatetime(e.expires_on),e};t.addService("ban-model",function(t){t.models.add("ban",{"class":e,deserialize:r})},{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("legal-page-model",function(t){t.models.add("legal-page",{"class":e})},{after:"models"})}(Misago.prototype),function(t){"use strict";var e=function(t){var e=[m("p.lead",t.message)];return t.help&&e.push(m("p.help",t.help)),m(".page.error-page.error-"+t.code+"-page",m(".container",m(".error-panel",[m(".error-icon",m("span.material-icon",t.icon)),m(".error-message",e)])))};t.ErrorBannedRoute=t.route({controller:function(){this.container.title.set(gettext("You are banned"))},error:null,view:function(){var t=[];t.push(this.error.ban.message.html?m(".lead",m.trust(this.error.ban.message.html)):m("p.lead",this.error.message));var e=null;return e=this.error.ban.expires_on?this.error.ban.expires_on.isAfter(moment())?interpolate(gettext("This ban expires %(expires_on)s."),{expires_on:this.error.ban.expires_on.fromNow()},!0):gettext("This ban has expired."):gettext("This ban is permanent."),t.push(m("p",e)),m(".page.error-page.error-banned-page",m(".container",m(".error-panel",[m(".error-icon",m("span.material-icon","highlight_off")),m(".error-message",t)])))}}),t.Error403Route=t.route({controller:function(){this.container.title.set(gettext("Page not available"))},error:null,view:function(){return"Permission denied"===this.error&&(this.error=gettext("You don't have permission to access this page.")),e({code:403,icon:"remove_circle_outline",message:gettext("This page is not available."),help:this.error})}}),t.Error404Route=t.route({controller:function(){this.container.title.set(gettext("Page not found"))},view:function(){return e({code:404,icon:"info_outline",message:gettext("Requested page could not be found."),help:gettext("The link you followed was incorrect or the page has been moved or deleted.")})}}),t.Error500Route=t.route({controller:function(){this.container.title.set(gettext("Application error occured"))},view:function(){return e({code:500,icon:"error_outline",message:gettext("Requested page could not be displayed due to an error."),help:gettext("Please try again later or contact site staff if error persists.")})}}),t.Error0Route=t.route({controller:function(){this.container.title.set(gettext("Lost connection with application"))},view:function(){return e({code:0,icon:"sync_problem",message:gettext("Could not connect to application."),help:gettext("This may be caused by problems with your connection or application server. Please check your internet connection and refresh page if problem persists.")})}})}(Misago.prototype),function(t){"use strict";t.IndexRoute=t.route({controller:function(){var t=this.container;document.title=t.settings.forum_index_title||t.settings.forum_name;var e=m.prop(0);return{count:e,increment:function(){console.log("increment()"),e(e()+1)}}},view:function(t){return m(".container",[m("h1",["Count: ",m("strong",t.count())]),m("p","Clicky click button to increase count!."),m("p",m("button.btn.btn-primary",{onclick:t.increment},"Clicky clicky!"))])}})}(Misago.prototype),function(t){"use strict";var e=function(e,r){var n=e.replace(/_/g,"-");return t.route({controller:function(){var r=this.container;t.get(r.settings,e+"_link")?window.location=t.get(r.settings,e+"_link"):this.vm.init(this,r)},vm:{page:null,isReady:!1,init:function(t,e){return this.isReady?void e.title.set(this.title):(e.title.set(),e.api.model("legal-page",n))},ondata:function(t,e,n){m.startComputation(),t.link?window.location=t.link:(t.title=t.title||r,this.page=t,this.isReady=!0,m.endComputation(),e.isActive&&n.title.set(this.page.title))}},view:function(){var e=this.container;return m(".page.legal-page."+n+"-page",[e.component(t.PageHeader,{title:this.vm.page.title}),m(".container",e.component(t.Markup,this.vm.page.body))])}})};t.TermsOfServiceRoute=e("terms_of_service",gettext("Terms of service")),t.PrivacyPolicyRoute=e("privacy_policy",gettext("Privacy policy"))}(Misago.prototype),function(t){"use strict";var e=function(e,r,n){var i=t.get(e.settings,r+"_link");return!i&&t.get(e.settings,r)&&(i=e.router.url(r)),i?m("li",m("a",{href:i},t.get(e.settings,r+"_title",n))):null};t.FooterNav={isVisible:function(t){return-1!==[!!t.forum_footnote,!!t.terms_of_service,!!t.terms_of_service_link,!!t.privacy_policy,!!t.privacy_policy_link].indexOf(!0)},view:function(t,r){var n=[];return r.settings.forum_footnote&&n.push(m("li.forum-footnote",m.trust(r.settings.forum_footnote))),n.push(e(r,"terms_of_service",gettext("Terms of service"))),n.push(e(r,"privacy_policy",gettext("Privacy policy"))),m("ul.list-inline.footer-nav",n)}}}(Misago.prototype),function(t){"use strict";t.ForumFooter={view:function(e,r){var n=null;return t.FooterNav.isVisible(r.settings)&&(n=r.component(t.FooterNav)),m("footer.forum-footer",[m(".container",m(".footer-content",[n,r.component(t.FooterMisagoBranding)]))])}}}(Misago.prototype),function(t){"use strict";t.FooterMisagoBranding={view:function(){return m("a.misago-branding[href=http://misago-project.org]",["powered by ",m("strong","misago")])}}}(Misago.prototype),function(t){"use strict";t.BrandFull={view:function(t,e,r){var n=[m("img",{src:r.router.staticUrl("misago/img/site-logo.png"),alt:r.settings.forum_name})];return e&&n.push(e),m("a.navbar-brand",{href:r.router.url("index")},n)}}}(Misago.prototype),function(t){"use strict";t.ForumNavbar={view:function(e,r){var n=[];r.settings.forum_branding_display&&n.push(r.component(t.BrandFull,r.settings.forum_branding_text)),n.push(m("ul.nav.navbar-nav",[m("li",m("a",{config:m.route,href:r.router.url("index")},"Index"))]));var i=".navbar.navbar-default.navbar-static-top";return m("nav"+i+'[role="navigation"]',[m(".container.navbar-full.hidden-xs.hidden-sm",n)])}}}(Misago.prototype),function(t){"use strict";var e=function(t,e,r){r.retain=!0};t.ForumLayout={view:function(r,n){return[n.component(t.ForumNavbar),m("#router-fixture",{config:e}),n.component(t.ForumFooter)]}}}(Misago.prototype),function(t){"use strict";t.Loader={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.LoadingPage={view:function(e,r){return m(".page.loading-page",r.component(t.Loader))}}}(Misago.prototype),function(t){"use strict";var e=function(t,e,r){r.retain=!0};t.Markup={view:function(t,r){return m("article.misago-markup",{config:e},m.trust(r))}}}(Misago.prototype),function(t){"use strict";t.PageHeader={view:function(t,e){return m(".page-header",m(".container",[m("h1",e.title)]))}}}(Misago.prototype),function(t,e){"use strict";var r=new e;r.url("/",t.IndexRoute,"index"),r.url("/terms-of-service/",t.TermsOfServiceRoute,"terms_of_service"),r.url("/privacy-policy/",t.PrivacyPolicyRoute,"privacy_policy"),r.url("/:rest...",t.Error404Route,"not_found"),t.urls=r}(Misago.prototype,Misago.prototype.UrlConf);
 //# 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","context","SETTINGS","_initServices","services","orderedServices","OrderedList","order","forEach","item","factory","undefined","serviceInstance","key","_destroyServices","reverse","destroy","setup","init","fixture","get","inTest","api","_services","proto","prototype","addService","name","push","after","before","has","obj","hasOwnProperty","value","pop","returnValue","items","isOrdered","_items","add","i","length","values","values_only","_order","unordered","insertItem","insertAt","ordering","indexOf","ordered","splice","index","iterations","serializeDatetime","serialized","format","deserializeDatetime","deserialized","moment","startsWith","string","beginning","endsWith","tail","UrlConfInvalidComponentError","message","toString","UrlConf","_patterns","patterns","prefixPattern","prefix","pattern","replace","include","url","component","loadingPage","_","m","Loader","getCsrfToken","cookie_name","document","cookie","cookieRegex","RegExp","match","split","Ajax","csrfToken","CSRF_COOKIE_NAME","runningGets","ajax","method","data","progress","promise","deferred","ajax_settings","headers","X-CSRFToken","dataType","success","resolve","error","jqXHR","rejection","responseJSON","status","statusText","reject","$","preloaded","post","patch","put","filtersUrl","filters","encodedKey","encodeURIComponent","encodedValue","join","Query","call","path","related","model","relation","endpoint","then","results","map","models","Api","argumentsArray","arguments","apply","settings","mount","getElementById","ForumLayout","Models","classes","deserializers","relations","kwargs","deserialize","json","locale","attr","noop","route","isActive","__controller","controller","__onunload","onunload","vm","__init","initArgs","ondata","finalArgs","f","container","router","errorPage","loading","__view","view","isReady","Router","baseUrl","staticUrl","mediaUrl","urls","reverses","routedComponent","populatePatterns","urlconf","finalPattern","startRouting","mode","delegateElement","delegateName","cleanUrl","isRelative","substr","location","protocol","host","avatarsUrl","delegateClicks","element","on","e","target","href","preventDefault","off","prefixUrl","error403","ban","ErrorBannedRoute","detail","Error403Route","error404","Error404Route","error500","Error500Route","error0","Error0Route","RunLoop","_intervals","stopInterval","clearTimeout","run","callable","delay","setTimeout","result","runOnce","stop","loop","runloop","ticks","prop","startComputation","endComputation","PageTitle","forum_name","set","title","_set_complex","completeTitle","page","page_label","interpolate","gettext","parent","Ban","html","plain","expires_on","deserializeBan","class","LegalPage","body","error_message","help","code","icon","trust","expirationMessage","isAfter","fromNow","IndexRoute","forum_index_title","count","increment","console","log","ctrl","onclick","legalPageFactory","typeName","defaultTitle","dashedTypeName","PageHeader","Markup","TermsOfServiceRoute","PrivacyPolicyRoute","legalLink","legalType","FooterNav","isVisible","forum_footnote","terms_of_service","terms_of_service_link","privacy_policy","privacy_policy_link","ForumFooter","nav","FooterMisagoBranding","BrandFull","branding","children","src","alt","ForumNavbar","desktopNavbar","forum_branding_display","forum_branding_text","config","navbarStyle","persistent","el","isInit","retain","LoadingPage","setupMarkup","content","options"],"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    // Context data\n    this.context = {\n      // Empty settings\n      SETTINGS: {}\n    };\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    // App init/destory\n    this.setup = false;\n    this.init = function(setup) {\n      this.setup = {\n        fixture: ns.get(setup, 'fixture', null),\n        inTest: ns.get(setup, 'inTest', false),\n        api: ns.get(setup, 'api', '/api/')\n      };\n\n      this._initServices(ns._services);\n    };\n\n    this.destroy = function() {\n      this._destroyServices(ns._services);\n    };\n  };\n\n\n  // Services registry\n  var proto = window.Misago.prototype;\n  proto._services = [];\n\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\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  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        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  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.UrlConfInvalidComponentError = function(name) {\n    this.message = \"route's \" + name + \" component \" +\n                   \"should be an array or object\";\n\n    this.toString = function() {\n      return this.message;\n    };\n  };\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 (typeof component !== 'object') {\n        throw new Misago.UrlConfInvalidComponentError(name);\n      }\n\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,\n          name: name\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(Misago.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.csrfToken = getCsrfToken(_.context.CSRF_COOKIE_NAME);\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 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.url && call.filters) {\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\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\n  Misago.addService('api', function(_) {\n    return new Api(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('component-factory', function(_) {\n    // Component factory\n    _.component = function() {\n      var argumentsArray = [];\n      for (var i = 0; i < arguments.length; i += 1) {\n        argumentsArray.push(arguments[i]);\n      }\n\n      argumentsArray.push(_);\n      return m.component.apply(undefined, argumentsArray);\n    };\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  Misago.addService('forum-layout', {\n    factory: function(_) {\n      if (_.setup.fixture) {\n        m.mount(document.getElementById(_.setup.fixture),\n                _.component(Misago.ForumLayout));\n      }\n    },\n\n    destroy: function(_) {\n      if (_.setup.fixture) {\n        m.mount(_.setup.fixture, null);\n      }\n    }\n  }, {before: 'start-routing'});\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Models = function() {\n    this.classes = {};\n    this.deserializers = {};\n    this.relations = {};\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      if (kwargs.relations) {\n        for (var key in kwargs.relations) {\n          if (kwargs.relations.hasOwnProperty(key)) {\n            this.relations[name + ':' + key] = kwargs.relations[key];\n          }\n        }\n      }\n    };\n\n    this.new = function(name, data) {\n      if (this.classes[name]) {\n        return new this.classes[name](data);\n      } else {\n        return data;\n      }\n    };\n\n    this.deserialize = function(name, json) {\n      if (this.relations[name]) {\n        name = this.relations[name];\n      }\n\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 noop = function() {};\n\n  Misago.route = function(component) {\n    /*\n      Boilerplate for Misago top-level components\n    */\n\n    // Component state\n    component.isActive = true;\n\n    // Wrap controller to store lifecycle methods\n    var __controller = component.controller || noop;\n    component.controller = function() {\n      component.isActive = true;\n\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    };\n\n    // Add state callbacks to View-Model\n    if (component.vm && component.vm.init) {\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              component.container.router.errorPage(error);\n            }\n          });\n        }\n      };\n\n      // setup default loading view\n      if (!component.loading) {\n        component.loading = function () {\n          var _ = this.container;\n          return m('.page.page-loading',\n            _.component(Misago.Loader)\n          );\n        };\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\n    return component;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Router = function(_) {\n    var self = this;\n    this.baseUrl = $('base').attr('href');\n\n    var staticUrl = Misago.get(_.context, 'STATIC_URL', '/');\n    var mediaUrl = Misago.get(_.context, 'MEDIA_URL', '/');\n\n    // Routing\n    this.urls = {};\n    this.reverses = {};\n\n    var routedComponent = function(component) {\n      component.container = _;\n      return component;\n    };\n\n    var populatePatterns = function(urlconf) {\n      urlconf.patterns().forEach(function(url) {\n        // set service container on component\n\n        var finalPattern = self.baseUrl + url.pattern;\n        finalPattern = finalPattern.replace('//', '/');\n\n        self.urls[finalPattern] = routedComponent(url.component);\n        self.reverses[url.name] = finalPattern;\n      });\n    };\n\n    this.startRouting = function(urlconf, fixture) {\n      populatePatterns(urlconf);\n      this.fixture = fixture;\n\n      m.route.mode = 'pathname';\n      m.route(fixture, '/', this.urls);\n    };\n\n    this.url = function(name) {\n      return this.reverses[name];\n    };\n\n    // Delegate clicks\n    this.delegateElement = null;\n    this.delegateName = 'click.misago-router';\n\n    this.cleanUrl = function(url) {\n      if (!url) { return; }\n\n      // Is link relative?\n      var isRelative = url.substr(0, 1) === '/' && url.substr(0, 2) !== '//';\n\n      // If link contains host, validate to see if its outgoing\n      if (!isRelative) {\n        var location = window.location;\n\n        // If protocol matches current one, strip it from string\n        // otherwhise stop handler\n        if (url.substr(0, 2) !== '//') {\n          var protocol = url.substr(0, location.protocol.length + 2);\n          if (protocol !== location.protocol + '//') { return; }\n          url = url.substr(location.protocol.length + 2);\n        } else {\n          url = url.substr(2);\n        }\n\n        // Host checks out?\n        if (url.substr(0, location.host.length) !== location.host) { return; }\n        url = url.substr(location.host.length);\n      }\n\n      // Is link within Ember app?\n      if (url.substr(0, this.baseUrl.length) !== this.baseUrl) { return; }\n\n      // Is link to media/static/avatar server?\n      if (url.substr(0, staticUrl.length) === staticUrl) { return; }\n\n      if (url.substr(0, mediaUrl.length) === mediaUrl) { return; }\n\n      var avatarsUrl = '/user-avatar/';\n      if (url.substr(0, avatarsUrl.length) === avatarsUrl) { return; }\n\n      return url;\n    };\n\n    this.delegateClicks = function(element) {\n      this.delegateElement = element;\n      $(this.delegateElement).on(this.delegateName, 'a', function(e) {\n        var cleanUrl = self.cleanUrl(e.target.href);\n        if (cleanUrl) {\n          if (cleanUrl != m.route()) {\n            m.route(cleanUrl);\n          }\n          e.preventDefault();\n        }\n      });\n    };\n\n    this.destroy = function() {\n      $(this.delegateElement).off(this.delegateName);\n    };\n\n    // Media/Static url\n    var prefixUrl = function(prefix) {\n      return function(url) {\n        return prefix + url;\n      };\n    };\n\n    this.staticUrl = prefixUrl(staticUrl);\n    this.mediaUrl = prefixUrl(mediaUrl);\n\n    // Errors\n    this.error403 = function(error) {\n      var component = null;\n      if (error.ban) {\n        component = routedComponent(Misago.ErrorBannedRoute);\n        component.error = {\n          message: error.detail,\n          ban: _.models.deserialize('ban', error.ban)\n        };\n      } else {\n        component = routedComponent(Misago.Error403Route);\n        component.error = error.detail;\n      }\n\n      m.mount(this.fixture, component);\n    };\n\n    this.error404 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error404Route));\n    };\n\n    this.error500 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error500Route));\n    };\n\n    this.error0 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error0Route));\n    };\n\n    this.errorPage = function(error) {\n      if (error.status === 0) {\n        this.error0();\n      }\n\n      if (error.status === 500) {\n        this.error500();\n      }\n\n      if (error.status === 404) {\n        this.error404();\n      }\n\n      if (error.status === 403) {\n        this.error403(error);\n      }\n    };\n  };\n\n  Misago.addService('router', function(_) {\n    return new Router(_);\n  });\n\n  Misago.addService('start-routing', function(_) {\n    _.router.startRouting(\n      Misago.urls, document.getElementById('router-fixture'));\n    _.router.delegateClicks(document.getElementById(_.setup.fixture));\n  }, {before: '_end'});\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\n    destroy: function(_) {\n      _.runloop.stop();\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 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 new Misago.Ban(data);\n  };\n\n  Misago.addService('ban-model', function(_) {\n    _.models.add('ban', {\n      class: Ban,\n      deserialize: deserializeBan\n    });\n  }, {after: 'models'});\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  };\n\n  Misago.addService('legal-page-model', function(_) {\n    _.models.add('legal-page', {\n      class: LegalPage\n    });\n  }, {after: 'models'});\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var errorPage = function(error) {\n    var error_message = [\n      m('p.lead', error.message)\n    ];\n\n    if (error.help) {\n      error_message.push(m('p.help', error.help));\n    }\n\n    return m('.page.error-page.error-' + error.code + '-page',\n      m('.container',\n        m('.error-panel', [\n          m('.error-icon',\n            m('span.material-icon', error.icon)\n          ),\n          m('.error-message', error_message)\n        ])\n      )\n    );\n  };\n\n  Misago.ErrorBannedRoute = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('You are banned'));\n    },\n    error: null,\n    view: function() {\n      var error_message = [];\n      if (this.error.ban.message.html) {\n        error_message.push(m('.lead', m.trust(this.error.ban.message.html)));\n      } else {\n        error_message.push(m('p.lead', this.error.message));\n      }\n\n      var expirationMessage = null;\n      if (this.error.ban.expires_on) {\n        if (this.error.ban.expires_on.isAfter(moment())) {\n          expirationMessage = interpolate(\n            gettext('This ban expires %(expires_on)s.'),\n            { 'expires_on': this.error.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.error-page.error-banned-page',\n        m('.container',\n          m('.error-panel', [\n            m('.error-icon',\n              m('span.material-icon', 'highlight_off')\n            ),\n            m('.error-message', error_message)\n          ])\n        )\n      );\n    }\n  });\n\n  Misago.Error403Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Page not available'));\n    },\n    error: null,\n    view: function() {\n      return errorPage({\n        code: 403,\n        icon: 'remove_circle_outline',\n        message: gettext(\"This page is not available.\"),\n        help: this.error || gettext(\"You don't have permission to access this page.\")\n      });\n    }\n  });\n\n  Misago.Error404Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Page not found'));\n    },\n    view: function() {\n      return errorPage({\n        code: 404,\n        icon: 'info_outline',\n        message: gettext(\"Requested page could not be found.\"),\n        help: gettext(\"The link you followed was incorrect or the page has been moved or deleted.\")\n      });\n    }\n  });\n\n  Misago.Error500Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Application error occured'));\n    },\n    view: function() {\n      return errorPage({\n        code: 500,\n        icon: 'error_outline',\n        message: gettext(\"Requested page could not be displayed due to an error.\"),\n        help: gettext(\"Please try again later or contact site staff if error persists.\")\n      });\n    }\n  });\n\n  Misago.Error0Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Lost connection with application'));\n    },\n    view: function() {\n      return errorPage({\n        code: 500,\n        icon: 'sync_problem',\n        message: gettext(\"Could not connect to application.\"),\n        help: gettext(\"This may be caused by problems with your connection or application server. Please check your internet connection and refresh page if problem persists.\")\n      });\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.IndexRoute = Misago.route({\n    controller: function() {\n      var _ = this.container;\n      document.title = _.settings.forum_index_title || _.settings.forum_name;\n\n      var count = m.prop(0);\n\n      return {\n        count: count,\n        increment: function() {\n          console.log('increment()');\n          count(count() + 1);\n        }\n      };\n    },\n    view: function(ctrl) {\n      return m('.container', [\n        m('h1', [\n          'Count: ', m('strong', ctrl.count())\n        ]),\n        m('p', 'Clicky click button to increase count!.'),\n        m('p',\n          m('button.btn.btn-primary', {onclick: ctrl.increment},\n            'Clicky clicky!'\n          )\n        )\n      ]);\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var legalPageFactory = function(typeName, defaultTitle) {\n    var dashedTypeName = typeName.replace(/_/g, '-');\n\n    return Misago.route({\n      controller: function() {\n        var _ = this.container;\n\n        if (Misago.get(_.settings, typeName + '_link')) {\n          window.location = Misago.get(_.settings, typeName + '_link');\n        } else {\n          this.vm.init(this, _);\n        }\n      },\n      vm: {\n        page: null,\n        isReady: false,\n        init: function(component, _) {\n          if (this.isReady) {\n            _.title.set(this.title);\n          } else {\n            _.title.set();\n            return _.api.model('legal-page', dashedTypeName);\n          }\n        },\n        ondata: function(page, component, _) {\n          m.startComputation();\n\n          page.title = page.title || defaultTitle;\n          this.page = page;\n          this.isReady = true;\n\n          m.endComputation();\n\n          if (component.isActive) {\n            _.title.set(this.page.title);\n          }\n        }\n      },\n      view: function() {\n        var _ = this.container;\n\n        return m('.page.legal-page.' + dashedTypeName + '-page', [\n          _.component(Misago.PageHeader, {title: this.vm.page.title}),\n          m('.container',\n            _.component(Misago.Markup, this.vm.page.body)\n          )\n        ]);\n      }\n    });\n  };\n\n  Misago.TermsOfServiceRoute = legalPageFactory(\n    'terms_of_service', gettext('Terms of service'));\n  Misago.PrivacyPolicyRoute = legalPageFactory(\n    'privacy_policy', gettext('Privacy policy'));\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var legalLink = function(_, legalType, defaultTitle) {\n    var url = Misago.get(_.settings, legalType + '_link');\n    if (!url && Misago.get(_.settings, legalType)) {\n      url = _.router.url(legalType);\n    }\n\n    if (url) {\n      return m('li',\n        m('a', {href: url},\n          Misago.get(_.settings, legalType + '_title', defaultTitle)\n        )\n      );\n    } else {\n      return null;\n    }\n  };\n\n  Misago.FooterNav = {\n    isVisible: function(settings) {\n      return [\n        !!settings.forum_footnote,\n        !!settings.terms_of_service,\n        !!settings.terms_of_service_link,\n        !!settings.privacy_policy,\n        !!settings.privacy_policy_link\n      ].indexOf(true) !== -1;\n    },\n    view: function(ctrl, _) {\n      var items = [];\n\n      if (_.settings.forum_footnote) {\n        items.push(m('li.forum-footnote', m.trust(_.settings.forum_footnote)));\n      }\n\n      items.push(\n        legalLink(_, 'terms_of_service', gettext('Terms of service')));\n      items.push(\n        legalLink(_, 'privacy_policy', gettext('Privacy policy')));\n\n      return m('ul.list-inline.footer-nav', items);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.ForumFooter = {\n    view: function(ctrl, _) {\n      var nav = null;\n      if (Misago.FooterNav.isVisible(_.settings)) {\n        nav = _.component(Misago.FooterNav);\n      }\n\n      return m('footer.forum-footer', [\n        m('.container',\n          m('.footer-content', [\n            nav,\n            _.component(Misago.FooterMisagoBranding)\n          ])\n        )\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.FooterMisagoBranding = {\n    view: function() {\n      return m('a.misago-branding[href=http://misago-project.org]', [\n        \"powered by \", m('strong', \"misago\")\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.BrandFull = {\n    view: function(ctrl, branding, _) {\n      var children = [\n        m('img', {\n          src: _.router.staticUrl('misago/img/site-logo.png'),\n          alt: _.settings.forum_name\n        })\n      ];\n\n      if (branding) {\n        children.push(branding);\n      }\n\n      return m('a.navbar-brand', {href: _.router.url('index')}, children);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.ForumNavbar = {\n    view: function(ctrl, _) {\n      var desktopNavbar = [];\n\n      if (_.settings.forum_branding_display) {\n        desktopNavbar.push(\n          _.component(Misago.BrandFull, _.settings.forum_branding_text));\n      }\n\n      desktopNavbar.push(m('ul.nav.navbar-nav', [\n        m('li',\n          m(\"a\", {config: m.route, href: _.router.url('index')}, 'Index')\n        )\n      ]));\n\n      var navbarStyle = '.navbar.navbar-default.navbar-static-top';\n\n      return m('nav' + navbarStyle + '[role=\"navigation\"]', [\n        m('.container.navbar-full.hidden-xs.hidden-sm', desktopNavbar)\n      ]);\n    }\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  Misago.ForumLayout = {\n    view: function(ctrl, _) {\n      return [\n        _.component(Misago.ForumNavbar),\n        m('#router-fixture', {config: persistent}),\n        _.component(Misago.ForumFooter)\n      ];\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.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.LoadingPage = {\n    view: function(ctrl, _) {\n      return m('.page.loading-page',\n        _.component(Misago.Loader)\n      );\n    }\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var setupMarkup = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  Misago.Markup = {\n    view: function(ctrl, content) {\n      return m('article.misago-markup', {config: setupMarkup},\n        m.trust(content)\n      );\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.PageHeader = {\n    view: function(ctrl, options) {\n      return m('.page-header',\n        m('.container', [\n          m('h1', options.title),\n        ])\n      );\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago, UrlConf) {\n  'use strict';\n\n  var urls = new UrlConf();\n  urls.url('/', Misago.IndexRoute, 'index');\n\n  // Legal pages\n  urls.url(\n    '/terms-of-service/',\n    Misago.TermsOfServiceRoute,\n    'terms_of_service');\n\n  urls.url(\n    '/privacy-policy/',\n    Misago.PrivacyPolicyRoute,\n    'privacy_policy');\n\n  Misago.urls = urls;\n} (Misago.prototype, Misago.prototype.UrlConf));\n"],"sourceRoot":"/source/"}
+{"version":3,"sources":["misago.js"],"names":["window","Misago","ns","Object","getPrototypeOf","this","self","context","SETTINGS","_initServices","services","orderedServices","OrderedList","order","forEach","item","factory","undefined","serviceInstance","key","_destroyServices","reverse","destroy","setup","init","fixture","get","test","api","_services","proto","prototype","addService","name","push","after","before","has","obj","hasOwnProperty","value","pop","returnValue","items","isOrdered","_items","add","i","length","values","values_only","_order","unordered","insertItem","insertAt","ordering","indexOf","ordered","splice","index","iterations","serializeDatetime","serialized","format","deserializeDatetime","deserialized","moment","startsWith","string","beginning","endsWith","tail","UrlConfInvalidComponentError","message","toString","UrlConf","_patterns","patterns","prefixPattern","prefix","pattern","replace","include","url","component","loadingPage","_","m","Loader","getCsrfToken","cookie_name","document","cookie","cookieRegex","RegExp","match","split","Ajax","csrfToken","CSRF_COOKIE_NAME","runningGets","ajax","method","data","progress","promise","deferred","ajax_settings","headers","X-CSRFToken","dataType","success","resolve","error","jqXHR","rejection","responseJSON","status","statusText","reject","$","preloaded","post","patch","put","filtersUrl","filters","encodedKey","encodeURIComponent","encodedValue","join","Query","call","path","related","model","relation","endpoint","then","results","map","models","Api","argumentsArray","arguments","apply","settings","mount","getElementById","ForumLayout","Models","classes","deserializers","relations","kwargs","deserialize","json","locale","attr","noop","route","isActive","__controller","controller","__onunload","onunload","vm","__init","initArgs","ondata","finalArgs","f","container","router","errorPage","loading","__view","view","isReady","Router","baseUrl","staticUrl","mediaUrl","urls","reverses","routedComponent","populatePatterns","urlconf","finalPattern","startRouting","mode","delegateElement","delegateName","cleanUrl","isRelative","substr","location","protocol","host","avatarsUrl","delegateClicks","element","on","e","target","href","preventDefault","off","prefixUrl","error403","ban","ErrorBannedRoute","detail","Error403Route","error404","Error404Route","error500","Error500Route","error0","Error0Route","RunLoop","_intervals","stopInterval","clearTimeout","run","callable","delay","setTimeout","result","runOnce","stop","loop","runloop","ticks","prop","startComputation","endComputation","PageTitle","forum_name","set","title","_set_complex","completeTitle","page","page_label","interpolate","gettext","parent","Ban","html","plain","expires_on","deserializeBan","class","LegalPage","body","link","error_message","help","code","icon","trust","expirationMessage","isAfter","fromNow","IndexRoute","forum_index_title","count","increment","console","log","ctrl","onclick","legalPageFactory","typeName","defaultTitle","dashedTypeName","PageHeader","Markup","TermsOfServiceRoute","PrivacyPolicyRoute","legalLink","legalType","FooterNav","isVisible","forum_footnote","terms_of_service","terms_of_service_link","privacy_policy","privacy_policy_link","ForumFooter","nav","FooterMisagoBranding","BrandFull","branding","children","src","alt","ForumNavbar","desktopNavbar","forum_branding_display","forum_branding_text","config","navbarStyle","persistent","el","isInit","retain","LoadingPage","setupMarkup","content","options"],"mappings":"CAEC,WACC,YAEAA,QAAOC,OAAS,WACd,GAAIC,GAAKC,OAAOC,eAAeC,MAC3BC,EAAOD,IAGXA,MAAKE,SAEHC,aAIFH,KAAKI,cAAgB,SAASC,GAC5B,GAAIC,GAAkB,GAAIT,GAAGU,YAAYF,GAAUG,OAAM,EACzDF,GAAgBG,QAAQ,SAAUC,GAChC,GAAIC,GAAU,IAEZA,GADwBC,SAAtBF,EAAKA,KAAKC,QACFD,EAAKA,KAAKC,QAEVD,EAAKA,IAGjB,IAAIG,GAAkBF,EAAQV,EAC1BY,KACFZ,EAAKS,EAAKI,KAAOD,MAKvBb,KAAKe,iBAAmB,SAASV,GAC/B,GAAIC,GAAkB,GAAIT,GAAGU,YAAYF,GAAUG,OACnDF,GAAgBU,UAChBV,EAAgBG,QAAQ,SAAUC,GACXE,SAAjBF,EAAKO,SACPP,EAAKO,QAAQhB,MAMnBD,KAAKkB,OAAQ,EACblB,KAAKmB,KAAO,SAASD,GACnBlB,KAAKkB,OACHE,QAASvB,EAAGwB,IAAIH,EAAO,UAAW,MAClCI,KAAMzB,EAAGwB,IAAIH,EAAO,QAAQ,GAC5BK,IAAK1B,EAAGwB,IAAIH,EAAO,MAAO,UAG5BlB,KAAKI,cAAcP,EAAG2B,YAGxBxB,KAAKiB,QAAU,WACbjB,KAAKe,iBAAiBlB,EAAG2B,YAM7B,IAAIC,GAAQ9B,OAAOC,OAAO8B,SAC1BD,GAAMD,aAENC,EAAME,WAAa,SAASC,EAAMjB,EAASH,GACzCiB,EAAMD,UAAUK,MACdf,IAAKc,EACLlB,KAAMC,EACNmB,MAAOL,EAAMJ,IAAIb,EAAO,SACxBuB,OAAQN,EAAMJ,IAAIb,EAAO,gBAK9B,SAAUZ,GACT,YAEAA,GAAOoC,IAAM,SAASC,EAAKnB,GACzB,MAAImB,GACKA,EAAIC,eAAepB,IAEnB,GAIXlB,EAAOyB,IAAM,SAASY,EAAKnB,EAAKqB,GAC9B,MAAIvC,GAAOoC,IAAIC,EAAKnB,GACXmB,EAAInB,GACQF,SAAVuB,EACFA,EAEAvB,QAIXhB,EAAOwC,IAAM,SAASH,EAAKnB,EAAKqB,GAC9B,GAAIE,GAAczC,EAAOyB,IAAIY,EAAKnB,EAAKqB,EAIvC,OAHIvC,GAAOoC,IAAIC,EAAKnB,KAClBmB,EAAInB,GAAO,MAENuB,IAETzC,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOW,YAAc,SAAS+B,GAC5BtC,KAAKuC,WAAY,EACjBvC,KAAKwC,OAASF,MAEdtC,KAAKyC,IAAM,SAAS3B,EAAKJ,EAAMF,GAC7BR,KAAKwC,OAAOX,MACVf,IAAKA,EACLJ,KAAMA,EACNoB,MAAOlC,EAAOyB,IAAIb,EAAO,SACzBuB,OAAQnC,EAAOyB,IAAIb,EAAO,aAI9BR,KAAKqB,IAAM,SAASP,EAAKqB,GACvB,IAAK,GAAIO,GAAI,EAAGA,EAAI1C,KAAKwC,OAAOG,OAAQD,IACtC,GAAI1C,KAAKwC,OAAOE,GAAG5B,MAAQA,EACzB,MAAOd,MAAKwC,OAAOE,GAAGhC,IAI1B,OAAOyB,IAGTnC,KAAKgC,IAAM,SAASlB,GAClB,MAAyBF,UAAlBZ,KAAKqB,IAAIP,IAGlBd,KAAK4C,OAAS,WAEZ,IAAK,GADDA,MACKF,EAAI,EAAGA,EAAI1C,KAAKwC,OAAOG,OAAQD,IACtCE,EAAOf,KAAK7B,KAAKwC,OAAOE,GAAGhC,KAE7B,OAAOkC,IAGT5C,KAAKQ,MAAQ,SAASqC,GAMpB,MALK7C,MAAKuC,YACRvC,KAAKwC,OAASxC,KAAK8C,OAAO9C,KAAKwC,QAC/BxC,KAAKuC,WAAY,GAGfM,GAAsC,mBAAhBA,GACjB7C,KAAK4C,SAEL5C,KAAKwC,QAIhBxC,KAAK8C,OAAS,SAASC,GAgCrB,QAASC,GAAWtC,GAClB,GAAIuC,GAAW,EACoB,MAA/BC,EAASC,QAAQzC,EAAKI,OACpBJ,EAAKoB,OACPmB,EAAWC,EAASC,QAAQzC,EAAKoB,OAChB,KAAbmB,IACFA,GAAY,IAELvC,EAAKqB,SACdkB,EAAWC,EAASC,QAAQzC,EAAKqB,SAGlB,KAAbkB,IACFG,EAAQC,OAAOJ,EAAU,EAAGvC,GAC5BwC,EAASG,OAAOJ,EAAU,EAAGvC,EAAKI,OA5CxC,GAAIwC,KACJP,GAAUtC,QAAQ,SAAUC,GAC1B4C,EAAMzB,KAAKnB,EAAKI,MAIlB,IAAIsC,MACAF,IAIJH,GAAUtC,QAAQ,SAAUC,GACrBA,EAAKoB,OAAUpB,EAAKqB,SACvBqB,EAAQvB,KAAKnB,GACbwC,EAASrB,KAAKnB,EAAKI,QAMvBiC,EAAUtC,QAAQ,SAAUC,GACN,SAAhBA,EAAKqB,SACPqB,EAAQvB,KAAKnB,GACbwC,EAASrB,KAAKnB,EAAKI,OA2BvB,KADA,GAAIyC,GAAa,IACVA,EAAa,GAAKD,EAAMX,SAAWO,EAASP,QACjDY,GAAc,EACdR,EAAUtC,QAAQuC,EAGpB,OAAOI,MAGVxD,OAAO8B,WAET,SAAU9B,GACTA,EAAO4D,kBAAoB,SAASC,GAClC,MAAOA,GAAaA,EAAWC,SAAW,MAG5C9D,EAAO+D,oBAAsB,SAASC,GACpC,MAAOA,GAAeC,OAAOD,GAAgB,OAE/ChE,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOkE,WAAa,SAASC,EAAQC,GACnC,MAAqC,KAA9BD,EAAOZ,QAAQa,IAGxBpE,EAAOqE,SAAW,SAASF,EAAQG,GACjC,MAA6D,KAAtDH,EAAOZ,QAAQe,EAAMH,EAAOpB,OAASuB,EAAKvB,UAEnD/C,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOuE,6BAA+B,SAASvC,GAC7C5B,KAAKoE,QAAU,WAAaxC,EAAO,0CAGnC5B,KAAKqE,SAAW,WACd,MAAOrE,MAAKoE,UAIhBxE,EAAO0E,QAAU,WACf,GAAIrE,GAAOD,IACXA,MAAKuE,aAELvE,KAAKwE,SAAW,WACd,MAAOxE,MAAKuE,UAGd,IAAIE,GAAgB,SAASC,EAAQC,GACnC,OAAQD,EAASC,GAASC,QAAQ,KAAM,MAGtCC,EAAU,SAASH,EAAQF,GAC7B,IAAK,GAAI9B,GAAI,EAAGA,EAAI8B,EAAS7B,OAAQD,IACnCzC,EAAK6E,IAAIL,EAAcC,EAAQF,EAAS9B,GAAGiC,SAClCH,EAAS9B,GAAGqC,UACZP,EAAS9B,GAAGd,MAIzB5B,MAAK8E,IAAM,SAASH,EAASI,EAAWnD,GACtC,GAAyB,gBAAdmD,GACT,KAAM,IAAInF,GAAOuE,6BAA6BvC,EAGhC,MAAZ+C,IACFA,EAAU,KAGRI,YAAqBnF,GAAO0E,QAC9BO,EAAQF,EAASI,EAAUP,YAE3BxE,KAAKuE,UAAU1C,MACb8C,QAASA,EACTI,UAAWA,EACXnD,KAAMA,OAKdhC,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOoF,YAAc,SAASC,GAC5B,MAAOC,GAAE,qBACPD,EAAEF,UAAUnF,EAAOuF,WAGvBvF,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAIwF,GAAe,SAASC,GAC1B,GAA6C,KAAzCC,SAASC,OAAOpC,QAAQkC,GAAqB,CAC/C,GAAIG,GAAc,GAAIC,QAAOJ,EAAc,YACvCE,EAAS3F,EAAOyB,IAAIiE,SAASC,OAAOG,MAAMF,GAAc,EAC5D,OAAOD,GAAOI,MAAM,KAAK,GAEzB,MAAO,OAIPC,EAAO,SAASX,GAClBjF,KAAK6F,UAAYT,EAAaH,EAAE/E,QAAQ4F,iBAMxC,IAAIC,KAEJ/F,MAAKgG,KAAO,SAASC,EAAQnB,EAAKoB,EAAMC,GACtC,GAAIC,GAAUlB,EAAEmB,WAEZC,GACFxB,IAAKA,EACLmB,OAAQA,EACRM,SACEC,cAAexG,KAAK6F,WAGtBK,KAAMA,KACNO,SAAU,OAEVC,QAAS,SAASR,GACD,QAAXD,GACFrG,EAAOwC,IAAI2D,EAAajB,GAE1BsB,EAAQO,QAAQT,IAElBU,MAAO,SAASC,GACC,QAAXZ,GACFrG,EAAOwC,IAAI2D,EAAajB,EAG1B,IAAIgC,GAAYD,EAAME,gBAEtBD,GAAUE,OAASH,EAAMG,OACzBF,EAAUG,WAAaJ,EAAMI,WAE7Bb,EAAQc,OAAOJ,IAInB,OAAIX,GAAJ,QAIAgB,EAAEnB,KAAKM,GACAF,EAAQA,UAGjBpG,KAAKqB,IAAM,SAASyD,GAClB,GAAIsC,GAAYxH,EAAOwC,IAAI6C,EAAE/E,QAAS4E,EACtC,IAAIsC,EAAW,CACb,GAAIf,GAAWnB,EAAEmB,UAEjB,OADAA,GAASM,QAAQS,GACVf,EAASD,QACX,MAAyBxF,UAArBmF,EAAYjB,GACdiB,EAAYjB,IAEnBiB,EAAYjB,GAAO9E,KAAKgG,KAAK,MAAOlB,GAC7BiB,EAAYjB,KAIvB9E,KAAKqH,KAAO,SAASvC,EAAKoB,GACxB,MAAOlG,MAAKgG,KAAK,OAAQlB,EAAKoB,IAGhClG,KAAKsH,MAAQ,SAASxC,EAAKoB,GACzB,MAAOlG,MAAKgG,KAAK,QAASlB,EAAKoB,IAGjClG,KAAKuH,IAAM,SAASzC,EAAKoB,GACvB,MAAOlG,MAAKgG,KAAK,MAAOlB,EAAKoB,IAG/BlG,KAAAA,UAAc,SAAS8E,GACrB,MAAO9E,MAAKgG,KAAK,SAAUlB,IAI/BlF,GAAO+B,WAAW,OAAQ,SAASsD,GACjC,MAAO,IAAIW,GAAKX,MAElBrF,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAI4H,GAAa,SAASC,GACxB,GAAuB,gBAAZA,GAAsB,CAC/B,GAAI7E,KACJ,KAAK,GAAI9B,KAAO2G,GACd,GAAIA,EAAQvF,eAAepB,GAAM,CAC/B,GAAI4G,GAAaC,mBAAmB7G,GAChC8G,EAAeD,mBAAmBF,EAAQ3G,GAC9C8B,GAAOf,KAAK6F,EAAa,IAAME,GAGnC,MAAO,IAAMhF,EAAOiF,KAAK,KAEzB,MAAOJ,GAAU,KAIjBK,EAAQ,SAAS7C,EAAG8C,GACtB/H,KAAK8E,IAAMiD,EAAKjD,KAAOG,EAAE/D,MAAMK,IAG7BvB,KAAK8E,KADHiD,EAAKC,KACKD,EAAKC,KAAO,IACfD,EAAKE,QACFF,EAAKE,QAAU,IAEfF,EAAKG,MAAQ,KAGvBH,EAAKN,UACPzH,KAAK8E,KAAO0C,EAAWO,EAAKN,WAGzBM,EAAKjD,KAAOiD,EAAKN,UAChBM,EAAKG,QACPlI,KAAKiI,QAAU,SAASC,EAAOT,GAC7B,MAAO,IAAIK,GAAM7C,GACfH,IAAK9E,KAAK8E,IACVqD,SAAUJ,EAAKG,MACfD,QAASC,EACTT,QAASA,MAKfzH,KAAKoI,SAAW,SAASJ,EAAMP,GAC7B,MAAO,IAAIK,GAAM7C,GACfH,IAAK9E,KAAK8E,IACVkD,KAAMA,EACNP,QAASA,MAKfzH,KAAKqB,IAAM,WACT,GAAI6G,GAAQ,IAOZ,OANIH,GAAKE,QACPC,EAAQH,EAAKI,SAAW,IAAMJ,EAAKE,QAC1BF,EAAKG,QACdA,EAAQH,EAAKG,OAGRjD,EAAEe,KAAK3E,IAAIrB,KAAK8E,KAAKuD,KAAK,SAASnC,GACxC,MAAIgC,GACEhC,EAAKoC,SACPpC,EAAKoC,QAAQC,IAAI,SAAS7H,GACxB,MAAOuE,GAAEuD,OAAFvD,OAAaiD,EAAOxH,KAEtBwF,GAEAjB,EAAEuD,OAAFvD,OAAaiD,EAAOhC,GAGtBA,KAKblG,KAAKqH,KAAO,SAASnB,GACnB,MAAOjB,GAAEe,KAAKqB,KAAKrH,KAAK8E,IAAKoB,IAG/BlG,KAAKsH,MAAQ,SAASpB,GACpB,MAAOjB,GAAEe,KAAKsB,MAAMtH,KAAK8E,IAAKoB,IAGhClG,KAAKuH,IAAM,SAASrB,GAClB,MAAOjB,GAAEe,KAAKuB,IAAIvH,KAAK8E,IAAKoB,IAG9BlG,KAAAA,UAAc,WACZ,MAAOiF,GAAEe,KAAFf,UAAcjF,KAAK8E,MAI5B9E,KAAKqI,KAAO,SAAS1B,EAASO,GAC5B,MAAOlH,MAAKqB,MAAMgH,KAAK1B,EAASO,KAIhCuB,EAAM,SAASxD,GACjBjF,KAAKkI,MAAQ,SAASA,EAAOT,GAC3B,MAAO,IAAIK,GAAM7C,GACfiD,MAAOA,EACPT,QAASA,KAIbzH,KAAKoI,SAAW,SAASJ,EAAMP,GAC7B,MAAO,IAAIK,GAAM7C,GACf+C,KAAMA,EACNP,QAASA,KAKf7H,GAAO+B,WAAW,MAAO,SAASsD,GAChC,MAAO,IAAIwD,GAAIxD,MAEjBrF,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAO+B,WAAW,oBAAqB,SAASsD,GAE9CA,EAAEF,UAAY,WAEZ,IAAK,GADD2D,MACKhG,EAAI,EAAGA,EAAIiG,UAAUhG,OAAQD,GAAK,EACzCgG,EAAe7G,KAAK8G,UAAUjG,GAIhC,OADAgG,GAAe7G,KAAKoD,GACbC,EAAEH,UAAU6D,MAAMhI,OAAW8H,OAGxC9I,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAO+B,WAAW,OAAQ,SAASsD,GACjCA,EAAE4D,SAAWjJ,EAAOyB,IAAI4D,EAAE/E,QAAS,kBAErCN,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAO+B,WAAW,gBAChBhB,QAAS,SAASsE,GACZA,EAAE/D,MAAME,SACV8D,EAAE4D,MAAMxD,SAASyD,eAAe9D,EAAE/D,MAAME,SAChC6D,EAAEF,UAAUnF,EAAOoJ,eAI/B/H,QAAS,SAASgE,GACZA,EAAE/D,MAAME,SACV8D,EAAE4D,MAAMxD,SAASyD,eAAe9D,EAAE/D,MAAME,SAAU,SAGpDW,OAAQ,mBACZnC,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAIqJ,GAAS,WACXjJ,KAAKkJ,WACLlJ,KAAKmJ,iBACLnJ,KAAKoJ,aAELpJ,KAAKyC,IAAM,SAASb,EAAMyH,GASxB,GARIA,EAAAA,WACFrJ,KAAKkJ,QAAQtH,GAAQyH,EAAAA,UAGnBA,EAAOC,cACTtJ,KAAKmJ,cAAcvH,GAAQyH,EAAOC,aAGhCD,EAAOD,UACT,IAAK,GAAItI,KAAOuI,GAAOD,UACjBC,EAAOD,UAAUlH,eAAepB,KAClCd,KAAKoJ,UAAUxH,EAAO,IAAMd,GAAOuI,EAAOD,UAAUtI,KAM5Dd,KAAAA,OAAW,SAAS4B,EAAMsE,GACxB,MAAIlG,MAAKkJ,QAAQtH,GACR,GAAI5B,MAAKkJ,QAAQtH,GAAMsE,GAEvBA,GAIXlG,KAAKsJ,YAAc,SAAS1H,EAAM2H,GAKhC,MAJIvJ,MAAKoJ,UAAUxH,KACjBA,EAAO5B,KAAKoJ,UAAUxH,IAGpB5B,KAAKmJ,cAAcvH,GACd5B,KAAAA,OAAS4B,EAAM5B,KAAKmJ,cAAcvH,GAAM2H,EAAMvJ,OAE9CA,KAAAA,OAAS4B,EAAM2H,IAK5B3J,GAAO+B,WAAW,SAAU,WAC1B,MAAO,IAAIsH,MAEbrJ,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAO+B,WAAW,sBAAuB,WACvCkC,OAAO2F,OAAOrC,EAAE,QAAQsC,KAAK,YAE/B7J,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAI8J,GAAO,YAEX9J,GAAO+J,MAAQ,SAAS5E,GAMtBA,EAAU6E,UAAW,CAGrB,IAAIC,GAAe9E,EAAU+E,YAAcJ,CAiB3C,IAhBA3E,EAAU+E,WAAa,WACrB/E,EAAU6E,UAAW,CAErB,IAAIE,GAAaD,EAAajB,MAAM7D,EAAW4D,eAG3CoB,EAAaD,EAAWE,UAAYN,CAMxC,OALAI,GAAWE,SAAW,WACpBD,EAAWnB,MAAM7D,EAAW4D,WAC5B5D,EAAU6E,UAAW,GAGhBE,GAIL/E,EAAUkF,IAAMlF,EAAUkF,GAAG9I,KAAM,CAErC,GAAI+I,GAASnF,EAAUkF,GAAG9I,IAC1B4D,GAAUkF,GAAG9I,KAAO,WAClB,GAAIgJ,GAAWxB,UACXvC,EAAU8D,EAAOtB,MAAM7D,EAAUkF,GAAIE,EAErC/D,IACFA,EAAQiC,KAAK,WACX,GAAItD,EAAU6E,UAAY7E,EAAUkF,GAAGG,OAAQ,CAE7C,IAAK,GADDC,MACK3H,EAAI,EAAGA,EAAIiG,UAAUhG,OAAQD,IACpC2H,EAAUxI,KAAK8G,UAAUjG,GAE3B,KAAK,GAAI4H,GAAI,EAAGA,EAAIH,EAASxH,OAAQ2H,IACnCD,EAAUxI,KAAKsI,EAASG,GAG1BvF,GAAUkF,GAAGG,OAAOxB,MAAM7D,EAAUkF,GAAII,KAEzC,SAASzD,GACN7B,EAAU6E,UACZ7E,EAAUwF,UAAUC,OAAOC,UAAU7D,MAOxC7B,EAAU2F,UACb3F,EAAU2F,QAAU,WAClB,GAAIzF,GAAIjF,KAAKuK,SACb,OAAOrF,GAAE,qBACPD,EAAEF,UAAUnF,EAAOuF,UAKzB,IAAIwF,GAAS5F,EAAU6F,IACvB7F,GAAU6F,KAAO,WACf,MAAI7F,GAAUkF,GAAGY,QACRF,EAAO/B,MAAM7D,EAAW4D,WAExB5D,EAAU2F,QAAQ9B,MAAM7D,EAAW4D,YAKhD,MAAO5D,KAETnF,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAIkL,GAAS,SAAS7F,GACpB,GAAIhF,GAAOD,IACXA,MAAK+K,QAAU5D,EAAE,QAAQsC,KAAK,OAE9B,IAAIuB,GAAYpL,EAAOyB,IAAI4D,EAAE/E,QAAS,aAAc,KAChD+K,EAAWrL,EAAOyB,IAAI4D,EAAE/E,QAAS,YAAa,IAGlDF,MAAKkL,QACLlL,KAAKmL,WAEL,IAAIC,GAAkB,SAASrG,GAE7B,MADAA,GAAUwF,UAAYtF,EACfF,GAGLsG,EAAmB,SAASC,GAC9BA,EAAQ9G,WAAW/D,QAAQ,SAASqE,GAGlC,GAAIyG,GAAetL,EAAK8K,QAAUjG,EAAIH,OACtC4G,GAAeA,EAAa3G,QAAQ,KAAM,KAE1C3E,EAAKiL,KAAKK,GAAgBH,EAAgBtG,EAAIC,WAC9C9E,EAAKkL,SAASrG,EAAIlD,MAAQ2J,IAI9BvL,MAAKwL,aAAe,SAASF,EAASlK,GACpCiK,EAAiBC,GACjBtL,KAAKoB,QAAUA,EAGb8D,EAAEyE,MAAM8B,KADNxG,EAAE/D,MAAMI,KACK,SAEA,WAEjB4D,EAAEyE,MAAMvI,EAAS,IAAKpB,KAAKkL,OAG7BlL,KAAK8E,IAAM,SAASlD,GAClB,MAAO5B,MAAKmL,SAASvJ,IAIvB5B,KAAK0L,gBAAkB,KACvB1L,KAAK2L,aAAe,sBAEpB3L,KAAK4L,SAAW,SAAS9G,GACvB,GAAKA,EAAL,CAGA,GAAI+G,GAAkC,MAArB/G,EAAIgH,OAAO,EAAG,IAAmC,OAArBhH,EAAIgH,OAAO,EAAG,EAG3D,KAAKD,EAAY,CACf,GAAIE,GAAWpM,OAAOoM,QAItB,IAAyB,OAArBjH,EAAIgH,OAAO,EAAG,GAAa,CAC7B,GAAIE,GAAWlH,EAAIgH,OAAO,EAAGC,EAASC,SAASrJ,OAAS,EACxD,IAAIqJ,IAAaD,EAASC,SAAW,KAAQ,MAC7ClH,GAAMA,EAAIgH,OAAOC,EAASC,SAASrJ,OAAS,OAE5CmC,GAAMA,EAAIgH,OAAO,EAInB,IAAIhH,EAAIgH,OAAO,EAAGC,EAASE,KAAKtJ,UAAYoJ,EAASE,KAAQ,MAC7DnH,GAAMA,EAAIgH,OAAOC,EAASE,KAAKtJ,QAIjC,GAAImC,EAAIgH,OAAO,EAAG9L,KAAK+K,QAAQpI,UAAY3C,KAAK+K,SAG5CjG,EAAIgH,OAAO,EAAGd,EAAUrI,UAAYqI,GAEpClG,EAAIgH,OAAO,EAAGb,EAAStI,UAAYsI,EAAvC,CAEA,GAAIiB,GAAa,eACjB,IAAIpH,EAAIgH,OAAO,EAAGI,EAAWvJ,UAAYuJ,EAEzC,MAAOpH,MAGT9E,KAAKmM,eAAiB,SAASC,GAC7BpM,KAAK0L,gBAAkBU,EACvBjF,EAAEnH,KAAK0L,iBAAiBW,GAAGrM,KAAK2L,aAAc,IAAK,SAASW,GAC1D,GAAIV,GAAW3L,EAAK2L,SAASU,EAAEC,OAAOC,KAClCZ,KACEA,GAAY1G,EAAEyE,SAChBzE,EAAEyE,MAAMiC,GAEVU,EAAEG,qBAKRzM,KAAKiB,QAAU,WACbkG,EAAEnH,KAAK0L,iBAAiBgB,IAAI1M,KAAK2L,cAInC,IAAIgB,GAAY,SAASjI,GACvB,MAAO,UAASI,GACd,MAAOJ,GAASI,GAIpB9E,MAAKgL,UAAY2B,EAAU3B,GAC3BhL,KAAKiL,SAAW0B,EAAU1B,GAG1BjL,KAAK4M,SAAW,SAAShG,GACvB,GAAI7B,GAAY,IACZ6B,GAAMiG,KACR9H,EAAYqG,EAAgBxL,EAAOkN,kBACnC/H,EAAU6B,OACRxC,QAASwC,EAAMmG,OACfF,IAAK5H,EAAEuD,OAAOc,YAAY,MAAO1C,EAAMiG,QAGzC9H,EAAYqG,EAAgBxL,EAAOoN,eACnCjI,EAAU6B,MAAQA,EAAMmG,QAG1B7H,EAAE4D,MAAM9I,KAAKoB,QAAS2D,IAGxB/E,KAAKiN,SAAW,WACd/H,EAAE4D,MAAM9I,KAAKoB,QAASgK,EAAgBxL,EAAOsN,iBAG/ClN,KAAKmN,SAAW,WACdjI,EAAE4D,MAAM9I,KAAKoB,QAASgK,EAAgBxL,EAAOwN,iBAG/CpN,KAAKqN,OAAS,WACZnI,EAAE4D,MAAM9I,KAAKoB,QAASgK,EAAgBxL,EAAO0N,eAG/CtN,KAAKyK,UAAY,SAAS7D,GACH,IAAjBA,EAAMI,QACRhH,KAAKqN,SAGc,MAAjBzG,EAAMI,QACRhH,KAAKmN,WAGc,MAAjBvG,EAAMI,QACRhH,KAAKiN,WAGc,MAAjBrG,EAAMI,QACRhH,KAAK4M,SAAShG,IAKpBhH,GAAO+B,WAAW,SAAU,SAASsD,GACnC,MAAO,IAAI6F,GAAO7F,KAGpBrF,EAAO+B,WAAW,gBAAiB,SAASsD,GAC1CA,EAAEuF,OAAOgB,aACP5L,EAAOsL,KAAM5F,SAASyD,eAAe,mBACvC9D,EAAEuF,OAAO2B,eAAe7G,SAASyD,eAAe9D,EAAE/D,MAAME,YACtDW,OAAQ,UACZnC,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAI2N,GAAU,SAAStI,GACrB,GAAIhF,GAAOD,IAEXA,MAAKwN,aAEL,IAAIC,GAAe,SAAS7L,GACtB3B,EAAKuN,WAAW5L,KAClBjC,OAAO+N,aAAazN,EAAKuN,WAAW5L,IACpC3B,EAAKuN,WAAW5L,GAAQ,MAI5B5B,MAAK2N,IAAM,SAASC,EAAUhM,EAAMiM,GAClC7N,KAAKwN,WAAW5L,GAAQjC,OAAOmO,WAAW,WACxCL,EAAa7L,EACb,IAAImM,GAASH,EAAS3I,EAClB8I,MAAW,GACb9N,EAAK0N,IAAIC,EAAUhM,EAAMiM,IAE1BA,IAGL7N,KAAKgO,QAAU,SAASJ,EAAUhM,EAAMiM,GACtC7N,KAAKwN,WAAW5L,GAAQjC,OAAOmO,WAAW,WACxCL,EAAa7L,GACbgM,EAAS3I,IACR4I,IAGL7N,KAAKiO,KAAO,SAASrM,GACnB,IAAK,GAAIsM,KAAQlO,MAAKwN,WACf5L,GAAQA,IAASsM,GACpBT,EAAaS,IAMrBtO,GAAO+B,WAAW,WAChBhB,QAAS,SAASsE,GAChB,MAAO,IAAIsI,GAAQtI,IAGrBhE,QAAS,SAASgE,GAChBA,EAAEkJ,QAAQF,WAGdrO,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAO+B,WAAW,aAAc,SAASsD,GACvC,GAAImJ,GAAQlJ,EAAEmJ,MAEdpJ,GAAEkJ,QAAQR,IAAI,WACZzI,EAAEoJ,mBAEFF,EAAMA,IAAU,GAEhBlJ,EAAEqJ,kBACD,OAAQ,QAEb3O,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAI4O,GAAY,SAASC,GACvBzO,KAAK0O,IAAM,SAASC,GACdA,EACF3O,KAAK4O,aAAaD,GAElBrJ,SAASqJ,MAAQF,GAIrBzO,KAAK4O,aAAe,SAASD,GACN,gBAAVA,KACTA,GAASA,MAAOA,GAGlB,IAAIE,GAAgBF,EAAMA,KAE1B,IAA0B,mBAAfA,GAAMG,MAAwBH,EAAMG,KAAO,EAAG,CACvD,GAAIC,GAAaC,YACfC,QAAQ,kBAAoBH,KAAKH,EAAMG,OAAQ,EACjDD,IAAiB,KAAOE,EAAa,IAGX,mBAAjBJ,GAAMO,SACfL,GAAiB,MAAQF,EAAMO,QAGjC5J,SAASqJ,MAAQE,EAAgB,MAAQJ,GAI7C7O,GAAO+B,WAAW,aAAc,SAASsD,GACvCA,EAAE0J,MAAQ,GAAIH,GAAUvJ,EAAE4D,SAAS4F,eAErC7O,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAIuP,GAAM,SAASjJ,GACjBlG,KAAKoE,SACHgL,KAAMlJ,EAAK9B,QAAQgL,KACnBC,MAAOnJ,EAAK9B,QAAQiL,OAGtBrP,KAAKsP,WAAapJ,EAAKoJ,YAGrBC,EAAiB,SAASrJ,GAG5B,MAFAA,GAAKoJ,WAAa1P,EAAO+D,oBAAoBuC,EAAKoJ,YAE3CpJ,EAGTtG,GAAO+B,WAAW,YAAa,SAASsD,GACtCA,EAAEuD,OAAO/F,IAAI,OACX+M,QAAOL,EACP7F,YAAaiG,MAEbzN,MAAO,YACVlC,OAAO8B,WAET,SAAU9B,GACT,YAEA,IAAI6P,GAAY,SAASvJ,GACvBlG,KAAK2O,MAAQzI,EAAKyI,MAClB3O,KAAK0P,KAAOxJ,EAAKwJ,KACjB1P,KAAK2P,KAAOzJ,EAAKyJ,KAGnB/P,GAAO+B,WAAW,mBAAoB,SAASsD,GAC7CA,EAAEuD,OAAO/F,IAAI,cACX+M,QAAOC,MAEP3N,MAAO,YACVlC,OAAO8B,WAET,SAAU9B,GACT,YAEA,IAAI6K,GAAY,SAAS7D,GACvB,GAAIgJ,IACF1K,EAAE,SAAU0B,EAAMxC,SAOpB,OAJIwC,GAAMiJ,MACRD,EAAc/N,KAAKqD,EAAE,SAAU0B,EAAMiJ,OAGhC3K,EAAE,0BAA4B0B,EAAMkJ,KAAO,QAChD5K,EAAE,aACAA,EAAE,gBACAA,EAAE,cACAA,EAAE,qBAAsB0B,EAAMmJ,OAEhC7K,EAAE,iBAAkB0K,OAM5BhQ,GAAOkN,iBAAmBlN,EAAO+J,OAC/BG,WAAY,WACV9J,KAAKuK,UAAUoE,MAAMD,IAAIO,QAAQ,oBAEnCrI,MAAO,KACPgE,KAAM,WACJ,GAAIgF,KAEFA,GAAc/N,KADZ7B,KAAK4G,MAAMiG,IAAIzI,QAAQgL,KACNlK,EAAE,QAASA,EAAE8K,MAAMhQ,KAAK4G,MAAMiG,IAAIzI,QAAQgL,OAE1ClK,EAAE,SAAUlF,KAAK4G,MAAMxC,SAG5C,IAAI6L,GAAoB,IAexB,OAZIA,GAFAjQ,KAAK4G,MAAMiG,IAAIyC,WACbtP,KAAK4G,MAAMiG,IAAIyC,WAAWY,QAAQrM,UAChBmL,YAClBC,QAAQ,qCACNK,WAActP,KAAK4G,MAAMiG,IAAIyC,WAAWa,YAC1C,GAEkBlB,QAAQ,yBAGVA,QAAQ,0BAE9BW,EAAc/N,KAAKqD,EAAE,IAAK+K,IAEnB/K,EAAE,qCACPA,EAAE,aACAA,EAAE,gBACAA,EAAE,cACAA,EAAE,qBAAsB,kBAE1BA,EAAE,iBAAkB0K,UAO9BhQ,EAAOoN,cAAgBpN,EAAO+J,OAC5BG,WAAY,WACV9J,KAAKuK,UAAUoE,MAAMD,IAAIO,QAAQ,wBAEnCrI,MAAO,KACPgE,KAAM,WAKJ,MAJmB,sBAAf5K,KAAK4G,QACP5G,KAAK4G,MAAQqI,QAAQ,mDAGhBxE,GACLqF,KAAM,IACNC,KAAM,wBACN3L,QAAS6K,QAAQ,+BACjBY,KAAM7P,KAAK4G,WAKjBhH,EAAOsN,cAAgBtN,EAAO+J,OAC5BG,WAAY,WACV9J,KAAKuK,UAAUoE,MAAMD,IAAIO,QAAQ,oBAEnCrE,KAAM,WACJ,MAAOH,IACLqF,KAAM,IACNC,KAAM,eACN3L,QAAS6K,QAAQ,sCACjBY,KAAMZ,QAAQ,mFAKpBrP,EAAOwN,cAAgBxN,EAAO+J,OAC5BG,WAAY,WACV9J,KAAKuK,UAAUoE,MAAMD,IAAIO,QAAQ,+BAEnCrE,KAAM,WACJ,MAAOH,IACLqF,KAAM,IACNC,KAAM,gBACN3L,QAAS6K,QAAQ,0DACjBY,KAAMZ,QAAQ,wEAKpBrP,EAAO0N,YAAc1N,EAAO+J,OAC1BG,WAAY,WACV9J,KAAKuK,UAAUoE,MAAMD,IAAIO,QAAQ,sCAEnCrE,KAAM,WACJ,MAAOH,IACLqF,KAAM,EACNC,KAAM,eACN3L,QAAS6K,QAAQ,qCACjBY,KAAMZ,QAAQ,gKAIpBrP,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOwQ,WAAaxQ,EAAO+J,OACzBG,WAAY,WACV,GAAI7E,GAAIjF,KAAKuK,SACbjF,UAASqJ,MAAQ1J,EAAE4D,SAASwH,mBAAqBpL,EAAE4D,SAAS4F,UAE5D,IAAI6B,GAAQpL,EAAEmJ,KAAK,EAEnB,QACEiC,MAAOA,EACPC,UAAW,WACTC,QAAQC,IAAI,eACZH,EAAMA,IAAU,MAItB1F,KAAM,SAAS8F,GACb,MAAOxL,GAAE,cACPA,EAAE,MACA,UAAWA,EAAE,SAAUwL,EAAKJ,WAE9BpL,EAAE,IAAK,2CACPA,EAAE,IACAA,EAAE,0BAA2ByL,QAASD,EAAKH,WACzC,yBAMV3Q,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAIgR,GAAmB,SAASC,EAAUC,GACxC,GAAIC,GAAiBF,EAASjM,QAAQ,KAAM,IAE5C,OAAOhF,GAAO+J,OACZG,WAAY,WACV,GAAI7E,GAAIjF,KAAKuK,SAET3K,GAAOyB,IAAI4D,EAAE4D,SAAUgI,EAAW,SACpClR,OAAOoM,SAAWnM,EAAOyB,IAAI4D,EAAE4D,SAAUgI,EAAW,SAEpD7Q,KAAKiK,GAAG9I,KAAKnB,KAAMiF,IAGvBgF,IACE6E,KAAM,KACNjE,SAAS,EACT1J,KAAM,SAAS4D,EAAWE,GACxB,MAAIjF,MAAK6K,YACP5F,GAAE0J,MAAMD,IAAI1O,KAAK2O,QAEjB1J,EAAE0J,MAAMD,MACDzJ,EAAE1D,IAAI2G,MAAM,aAAc6I,KAGrC3G,OAAQ,SAAS0E,EAAM/J,EAAWE,GAChCC,EAAEoJ,mBAEEQ,EAAKa,KACPhQ,OAAOoM,SAAW+C,EAAKa,MAEvBb,EAAKH,MAAQG,EAAKH,OAASmC,EAC3B9Q,KAAK8O,KAAOA,EACZ9O,KAAK6K,SAAU,EAEf3F,EAAEqJ,iBAEExJ,EAAU6E,UACZ3E,EAAE0J,MAAMD,IAAI1O,KAAK8O,KAAKH,UAK9B/D,KAAM,WACJ,GAAI3F,GAAIjF,KAAKuK,SAEb,OAAOrF,GAAE,oBAAsB6L,EAAiB,SAC9C9L,EAAEF,UAAUnF,EAAOoR,YAAarC,MAAO3O,KAAKiK,GAAG6E,KAAKH,QACpDzJ,EAAE,aACAD,EAAEF,UAAUnF,EAAOqR,OAAQjR,KAAKiK,GAAG6E,KAAKY,YAOlD9P,GAAOsR,oBAAsBN,EAC3B,mBAAoB3B,QAAQ,qBAC9BrP,EAAOuR,mBAAqBP,EAC1B,iBAAkB3B,QAAQ,oBAC5BrP,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAIwR,GAAY,SAASnM,EAAGoM,EAAWP,GACrC,GAAIhM,GAAMlF,EAAOyB,IAAI4D,EAAE4D,SAAUwI,EAAY,QAK7C,QAJKvM,GAAOlF,EAAOyB,IAAI4D,EAAE4D,SAAUwI,KACjCvM,EAAMG,EAAEuF,OAAO1F,IAAIuM,IAGjBvM,EACKI,EAAE,KACPA,EAAE,KAAMsH,KAAM1H,GACZlF,EAAOyB,IAAI4D,EAAE4D,SAAUwI,EAAY,SAAUP,KAI1C,KAIXlR,GAAO0R,WACLC,UAAW,SAAS1I,GAClB,MAMoB,QALhBA,EAAS2I,iBACT3I,EAAS4I,mBACT5I,EAAS6I,wBACT7I,EAAS8I,iBACT9I,EAAS+I,qBACXzO,SAAQ,IAEZyH,KAAM,SAAS8F,EAAMzL,GACnB,GAAI3C,KAWJ,OATI2C,GAAE4D,SAAS2I,gBACblP,EAAMT,KAAKqD,EAAE,oBAAqBA,EAAE8K,MAAM/K,EAAE4D,SAAS2I,kBAGvDlP,EAAMT,KACJuP,EAAUnM,EAAG,mBAAoBgK,QAAQ,sBAC3C3M,EAAMT,KACJuP,EAAUnM,EAAG,iBAAkBgK,QAAQ,oBAElC/J,EAAE,4BAA6B5C,MAG1C1C,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOiS,aACLjH,KAAM,SAAS8F,EAAMzL,GACnB,GAAI6M,GAAM,IAKV,OAJIlS,GAAO0R,UAAUC,UAAUtM,EAAE4D,YAC/BiJ,EAAM7M,EAAEF,UAAUnF,EAAO0R,YAGpBpM,EAAE,uBACPA,EAAE,aACAA,EAAE,mBACA4M,EACA7M,EAAEF,UAAUnF,EAAOmS,8BAM7BnS,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOmS,sBACLnH,KAAM,WACJ,MAAO1F,GAAE,qDACP,cAAeA,EAAE,SAAU,eAIjCtF,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOoS,WACLpH,KAAM,SAAS8F,EAAMuB,EAAUhN,GAC7B,GAAIiN,IACFhN,EAAE,OACAiN,IAAKlN,EAAEuF,OAAOQ,UAAU,4BACxBoH,IAAKnN,EAAE4D,SAAS4F,aAQpB,OAJIwD,IACFC,EAASrQ,KAAKoQ,GAGT/M,EAAE,kBAAmBsH,KAAMvH,EAAEuF,OAAO1F,IAAI,UAAWoN,MAG9DtS,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOyS,aACLzH,KAAM,SAAS8F,EAAMzL,GACnB,GAAIqN,KAEArN,GAAE4D,SAAS0J,wBACbD,EAAczQ,KACZoD,EAAEF,UAAUnF,EAAOoS,UAAW/M,EAAE4D,SAAS2J,sBAG7CF,EAAczQ,KAAKqD,EAAE,qBACnBA,EAAE,KACAA,EAAE,KAAMuN,OAAQvN,EAAEyE,MAAO6C,KAAMvH,EAAEuF,OAAO1F,IAAI,UAAW,YAI3D,IAAI4N,GAAc,0CAElB,OAAOxN,GAAE,MAAQwN,EAAc,uBAC7BxN,EAAE,6CAA8CoN,QAItD1S,OAAO8B,WAER,SAAU9B,GACT,YAEA,IAAI+S,GAAa,SAASC,EAAIC,EAAQ3S,GACpCA,EAAQ4S,QAAS,EAGnBlT,GAAOoJ,aACL4B,KAAM,SAAS8F,EAAMzL,GACnB,OACEA,EAAEF,UAAUnF,EAAOyS,aACnBnN,EAAE,mBAAoBuN,OAAQE,IAC9B1N,EAAEF,UAAUnF,EAAOiS,iBAIzBjS,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOuF,QACLyF,KAAM,WACJ,MAAO1F,GAAE,2BACPA,EAAE,qBACFA,EAAE,qBACFA,EAAE,qBACFA,EAAE,yBAKRtF,EAAOmT,aACLnI,KAAM,SAAS8F,EAAMzL,GACnB,MAAOC,GAAE,qBACPD,EAAEF,UAAUnF,EAAOuF,YAIxBvF,OAAO8B,WAET,SAAU9B,GACT,YAEA,IAAIoT,GAAc,SAASJ,EAAIC,EAAQ3S,GACrCA,EAAQ4S,QAAS,EAGnBlT,GAAOqR,QACLrG,KAAM,SAAS8F,EAAMuC,GACnB,MAAO/N,GAAE,yBAA0BuN,OAAQO,GACzC9N,EAAE8K,MAAMiD,OAIdrT,OAAO8B,WAER,SAAU9B,GACT,YAEAA,GAAOoR,YACLpG,KAAM,SAAS8F,EAAMwC,GACnB,MAAOhO,GAAE,eACPA,EAAE,cACAA,EAAE,KAAMgO,EAAQvE,aAKxB/O,OAAO8B,WAER,SAAU9B,EAAQ0E,GACjB,YAEA,IAAI4G,GAAO,GAAI5G,EACf4G,GAAKpG,IAAI,IAAKlF,EAAOwQ,WAAY,SAGjClF,EAAKpG,IACH,qBACAlF,EAAOsR,oBACP,oBAEFhG,EAAKpG,IACH,mBACAlF,EAAOuR,mBACP,kBAGFjG,EAAKpG,IAAI,YAAalF,EAAOsN,cAAe,aAE5CtN,EAAOsL,KAAOA,GACbtL,OAAO8B,UAAW9B,OAAO8B,UAAU4C","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    // Context data\n    this.context = {\n      // Empty settings\n      SETTINGS: {}\n    };\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    // App init/destory\n    this.setup = false;\n    this.init = function(setup) {\n      this.setup = {\n        fixture: ns.get(setup, 'fixture', null),\n        test: ns.get(setup, 'test', false),\n        api: ns.get(setup, 'api', '/api/')\n      };\n\n      this._initServices(ns._services);\n    };\n\n    this.destroy = function() {\n      this._destroyServices(ns._services);\n    };\n  };\n\n\n  // Services registry\n  var proto = window.Misago.prototype;\n  proto._services = [];\n\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\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  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        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  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.UrlConfInvalidComponentError = function(name) {\n    this.message = \"route's \" + name + \" component \" +\n                   \"should be an array or object\";\n\n    this.toString = function() {\n      return this.message;\n    };\n  };\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 (typeof component !== 'object') {\n        throw new Misago.UrlConfInvalidComponentError(name);\n      }\n\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,\n          name: name\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(Misago.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.csrfToken = getCsrfToken(_.context.CSRF_COOKIE_NAME);\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 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.url && call.filters) {\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\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\n  Misago.addService('api', function(_) {\n    return new Api(_);\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.addService('component-factory', function(_) {\n    // Component factory\n    _.component = function() {\n      var argumentsArray = [];\n      for (var i = 0; i < arguments.length; i += 1) {\n        argumentsArray.push(arguments[i]);\n      }\n\n      argumentsArray.push(_);\n      return m.component.apply(undefined, argumentsArray);\n    };\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  Misago.addService('forum-layout', {\n    factory: function(_) {\n      if (_.setup.fixture) {\n        m.mount(document.getElementById(_.setup.fixture),\n                _.component(Misago.ForumLayout));\n      }\n    },\n\n    destroy: function(_) {\n      if (_.setup.fixture) {\n        m.mount(document.getElementById(_.setup.fixture), null);\n      }\n    }\n  }, {before: 'start-routing'});\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Models = function() {\n    this.classes = {};\n    this.deserializers = {};\n    this.relations = {};\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      if (kwargs.relations) {\n        for (var key in kwargs.relations) {\n          if (kwargs.relations.hasOwnProperty(key)) {\n            this.relations[name + ':' + key] = kwargs.relations[key];\n          }\n        }\n      }\n    };\n\n    this.new = function(name, data) {\n      if (this.classes[name]) {\n        return new this.classes[name](data);\n      } else {\n        return data;\n      }\n    };\n\n    this.deserialize = function(name, json) {\n      if (this.relations[name]) {\n        name = this.relations[name];\n      }\n\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 noop = function() {};\n\n  Misago.route = function(component) {\n    /*\n      Boilerplate for Misago top-level components\n    */\n\n    // Component state\n    component.isActive = true;\n\n    // Wrap controller to store lifecycle methods\n    var __controller = component.controller || noop;\n    component.controller = function() {\n      component.isActive = true;\n\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    };\n\n    // Add state callbacks to View-Model\n    if (component.vm && component.vm.init) {\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              component.container.router.errorPage(error);\n            }\n          });\n        }\n      };\n\n      // setup default loading view\n      if (!component.loading) {\n        component.loading = function () {\n          var _ = this.container;\n          return m('.page.page-loading',\n            _.component(Misago.Loader)\n          );\n        };\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\n    return component;\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var Router = function(_) {\n    var self = this;\n    this.baseUrl = $('base').attr('href');\n\n    var staticUrl = Misago.get(_.context, 'STATIC_URL', '/');\n    var mediaUrl = Misago.get(_.context, 'MEDIA_URL', '/');\n\n    // Routing\n    this.urls = {};\n    this.reverses = {};\n\n    var routedComponent = function(component) {\n      component.container = _;\n      return component;\n    };\n\n    var populatePatterns = function(urlconf) {\n      urlconf.patterns().forEach(function(url) {\n        // set service container on component\n\n        var finalPattern = self.baseUrl + url.pattern;\n        finalPattern = finalPattern.replace('//', '/');\n\n        self.urls[finalPattern] = routedComponent(url.component);\n        self.reverses[url.name] = finalPattern;\n      });\n    };\n\n    this.startRouting = function(urlconf, fixture) {\n      populatePatterns(urlconf);\n      this.fixture = fixture;\n\n      if (_.setup.test) {\n        m.route.mode = 'search';\n      } else {\n        m.route.mode = 'pathname';\n      }\n      m.route(fixture, '/', this.urls);\n    };\n\n    this.url = function(name) {\n      return this.reverses[name];\n    };\n\n    // Delegate clicks\n    this.delegateElement = null;\n    this.delegateName = 'click.misago-router';\n\n    this.cleanUrl = function(url) {\n      if (!url) { return; }\n\n      // Is link relative?\n      var isRelative = url.substr(0, 1) === '/' && url.substr(0, 2) !== '//';\n\n      // If link contains host, validate to see if its outgoing\n      if (!isRelative) {\n        var location = window.location;\n\n        // If protocol matches current one, strip it from string\n        // otherwhise stop handler\n        if (url.substr(0, 2) !== '//') {\n          var protocol = url.substr(0, location.protocol.length + 2);\n          if (protocol !== location.protocol + '//') { return; }\n          url = url.substr(location.protocol.length + 2);\n        } else {\n          url = url.substr(2);\n        }\n\n        // Host checks out?\n        if (url.substr(0, location.host.length) !== location.host) { return; }\n        url = url.substr(location.host.length);\n      }\n\n      // Is link within Ember app?\n      if (url.substr(0, this.baseUrl.length) !== this.baseUrl) { return; }\n\n      // Is link to media/static/avatar server?\n      if (url.substr(0, staticUrl.length) === staticUrl) { return; }\n\n      if (url.substr(0, mediaUrl.length) === mediaUrl) { return; }\n\n      var avatarsUrl = '/user-avatar/';\n      if (url.substr(0, avatarsUrl.length) === avatarsUrl) { return; }\n\n      return url;\n    };\n\n    this.delegateClicks = function(element) {\n      this.delegateElement = element;\n      $(this.delegateElement).on(this.delegateName, 'a', function(e) {\n        var cleanUrl = self.cleanUrl(e.target.href);\n        if (cleanUrl) {\n          if (cleanUrl != m.route()) {\n            m.route(cleanUrl);\n          }\n          e.preventDefault();\n        }\n      });\n    };\n\n    this.destroy = function() {\n      $(this.delegateElement).off(this.delegateName);\n    };\n\n    // Media/Static url\n    var prefixUrl = function(prefix) {\n      return function(url) {\n        return prefix + url;\n      };\n    };\n\n    this.staticUrl = prefixUrl(staticUrl);\n    this.mediaUrl = prefixUrl(mediaUrl);\n\n    // Errors\n    this.error403 = function(error) {\n      var component = null;\n      if (error.ban) {\n        component = routedComponent(Misago.ErrorBannedRoute);\n        component.error = {\n          message: error.detail,\n          ban: _.models.deserialize('ban', error.ban)\n        };\n      } else {\n        component = routedComponent(Misago.Error403Route);\n        component.error = error.detail;\n      }\n\n      m.mount(this.fixture, component);\n    };\n\n    this.error404 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error404Route));\n    };\n\n    this.error500 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error500Route));\n    };\n\n    this.error0 = function() {\n      m.mount(this.fixture, routedComponent(Misago.Error0Route));\n    };\n\n    this.errorPage = function(error) {\n      if (error.status === 0) {\n        this.error0();\n      }\n\n      if (error.status === 500) {\n        this.error500();\n      }\n\n      if (error.status === 404) {\n        this.error404();\n      }\n\n      if (error.status === 403) {\n        this.error403(error);\n      }\n    };\n  };\n\n  Misago.addService('router', function(_) {\n    return new Router(_);\n  });\n\n  Misago.addService('start-routing', function(_) {\n    _.router.startRouting(\n      Misago.urls, document.getElementById('router-fixture'));\n    _.router.delegateClicks(document.getElementById(_.setup.fixture));\n  }, {before: '_end'});\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\n    destroy: function(_) {\n      _.runloop.stop();\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 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('ban-model', function(_) {\n    _.models.add('ban', {\n      class: Ban,\n      deserialize: deserializeBan\n    });\n  }, {after: 'models'});\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('legal-page-model', function(_) {\n    _.models.add('legal-page', {\n      class: LegalPage\n    });\n  }, {after: 'models'});\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var errorPage = function(error) {\n    var error_message = [\n      m('p.lead', error.message)\n    ];\n\n    if (error.help) {\n      error_message.push(m('p.help', error.help));\n    }\n\n    return m('.page.error-page.error-' + error.code + '-page',\n      m('.container',\n        m('.error-panel', [\n          m('.error-icon',\n            m('span.material-icon', error.icon)\n          ),\n          m('.error-message', error_message)\n        ])\n      )\n    );\n  };\n\n  Misago.ErrorBannedRoute = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('You are banned'));\n    },\n    error: null,\n    view: function() {\n      var error_message = [];\n      if (this.error.ban.message.html) {\n        error_message.push(m('.lead', m.trust(this.error.ban.message.html)));\n      } else {\n        error_message.push(m('p.lead', this.error.message));\n      }\n\n      var expirationMessage = null;\n      if (this.error.ban.expires_on) {\n        if (this.error.ban.expires_on.isAfter(moment())) {\n          expirationMessage = interpolate(\n            gettext('This ban expires %(expires_on)s.'),\n            { 'expires_on': this.error.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.error-page.error-banned-page',\n        m('.container',\n          m('.error-panel', [\n            m('.error-icon',\n              m('span.material-icon', 'highlight_off')\n            ),\n            m('.error-message', error_message)\n          ])\n        )\n      );\n    }\n  });\n\n  Misago.Error403Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Page not available'));\n    },\n    error: null,\n    view: function() {\n      if (this.error === \"Permission denied\") {\n        this.error = gettext(\"You don't have permission to access this page.\");\n      }\n\n      return errorPage({\n        code: 403,\n        icon: 'remove_circle_outline',\n        message: gettext(\"This page is not available.\"),\n        help: this.error\n      });\n    }\n  });\n\n  Misago.Error404Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Page not found'));\n    },\n    view: function() {\n      return errorPage({\n        code: 404,\n        icon: 'info_outline',\n        message: gettext(\"Requested page could not be found.\"),\n        help: gettext(\"The link you followed was incorrect or the page has been moved or deleted.\")\n      });\n    }\n  });\n\n  Misago.Error500Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Application error occured'));\n    },\n    view: function() {\n      return errorPage({\n        code: 500,\n        icon: 'error_outline',\n        message: gettext(\"Requested page could not be displayed due to an error.\"),\n        help: gettext(\"Please try again later or contact site staff if error persists.\")\n      });\n    }\n  });\n\n  Misago.Error0Route = Misago.route({\n    controller: function() {\n      this.container.title.set(gettext('Lost connection with application'));\n    },\n    view: function() {\n      return errorPage({\n        code: 0,\n        icon: 'sync_problem',\n        message: gettext(\"Could not connect to application.\"),\n        help: gettext(\"This may be caused by problems with your connection or application server. Please check your internet connection and refresh page if problem persists.\")\n      });\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.IndexRoute = Misago.route({\n    controller: function() {\n      var _ = this.container;\n      document.title = _.settings.forum_index_title || _.settings.forum_name;\n\n      var count = m.prop(0);\n\n      return {\n        count: count,\n        increment: function() {\n          console.log('increment()');\n          count(count() + 1);\n        }\n      };\n    },\n    view: function(ctrl) {\n      return m('.container', [\n        m('h1', [\n          'Count: ', m('strong', ctrl.count())\n        ]),\n        m('p', 'Clicky click button to increase count!.'),\n        m('p',\n          m('button.btn.btn-primary', {onclick: ctrl.increment},\n            'Clicky clicky!'\n          )\n        )\n      ]);\n    }\n  });\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var legalPageFactory = function(typeName, defaultTitle) {\n    var dashedTypeName = typeName.replace(/_/g, '-');\n\n    return Misago.route({\n      controller: function() {\n        var _ = this.container;\n\n        if (Misago.get(_.settings, typeName + '_link')) {\n          window.location = Misago.get(_.settings, typeName + '_link');\n        } else {\n          this.vm.init(this, _);\n        }\n      },\n      vm: {\n        page: null,\n        isReady: false,\n        init: function(component, _) {\n          if (this.isReady) {\n            _.title.set(this.title);\n          } else {\n            _.title.set();\n            return _.api.model('legal-page', dashedTypeName);\n          }\n        },\n        ondata: function(page, component, _) {\n          m.startComputation();\n\n          if (page.link) {\n            window.location = page.link;\n          } else {\n            page.title = page.title || defaultTitle;\n            this.page = page;\n            this.isReady = true;\n\n            m.endComputation();\n\n            if (component.isActive) {\n              _.title.set(this.page.title);\n            }\n          }\n        }\n      },\n      view: function() {\n        var _ = this.container;\n\n        return m('.page.legal-page.' + dashedTypeName + '-page', [\n          _.component(Misago.PageHeader, {title: this.vm.page.title}),\n          m('.container',\n            _.component(Misago.Markup, this.vm.page.body)\n          )\n        ]);\n      }\n    });\n  };\n\n  Misago.TermsOfServiceRoute = legalPageFactory(\n    'terms_of_service', gettext('Terms of service'));\n  Misago.PrivacyPolicyRoute = legalPageFactory(\n    'privacy_policy', gettext('Privacy policy'));\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var legalLink = function(_, legalType, defaultTitle) {\n    var url = Misago.get(_.settings, legalType + '_link');\n    if (!url && Misago.get(_.settings, legalType)) {\n      url = _.router.url(legalType);\n    }\n\n    if (url) {\n      return m('li',\n        m('a', {href: url},\n          Misago.get(_.settings, legalType + '_title', defaultTitle)\n        )\n      );\n    } else {\n      return null;\n    }\n  };\n\n  Misago.FooterNav = {\n    isVisible: function(settings) {\n      return [\n        !!settings.forum_footnote,\n        !!settings.terms_of_service,\n        !!settings.terms_of_service_link,\n        !!settings.privacy_policy,\n        !!settings.privacy_policy_link\n      ].indexOf(true) !== -1;\n    },\n    view: function(ctrl, _) {\n      var items = [];\n\n      if (_.settings.forum_footnote) {\n        items.push(m('li.forum-footnote', m.trust(_.settings.forum_footnote)));\n      }\n\n      items.push(\n        legalLink(_, 'terms_of_service', gettext('Terms of service')));\n      items.push(\n        legalLink(_, 'privacy_policy', gettext('Privacy policy')));\n\n      return m('ul.list-inline.footer-nav', items);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.ForumFooter = {\n    view: function(ctrl, _) {\n      var nav = null;\n      if (Misago.FooterNav.isVisible(_.settings)) {\n        nav = _.component(Misago.FooterNav);\n      }\n\n      return m('footer.forum-footer', [\n        m('.container',\n          m('.footer-content', [\n            nav,\n            _.component(Misago.FooterMisagoBranding)\n          ])\n        )\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.FooterMisagoBranding = {\n    view: function() {\n      return m('a.misago-branding[href=http://misago-project.org]', [\n        \"powered by \", m('strong', \"misago\")\n      ]);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.BrandFull = {\n    view: function(ctrl, branding, _) {\n      var children = [\n        m('img', {\n          src: _.router.staticUrl('misago/img/site-logo.png'),\n          alt: _.settings.forum_name\n        })\n      ];\n\n      if (branding) {\n        children.push(branding);\n      }\n\n      return m('a.navbar-brand', {href: _.router.url('index')}, children);\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.ForumNavbar = {\n    view: function(ctrl, _) {\n      var desktopNavbar = [];\n\n      if (_.settings.forum_branding_display) {\n        desktopNavbar.push(\n          _.component(Misago.BrandFull, _.settings.forum_branding_text));\n      }\n\n      desktopNavbar.push(m('ul.nav.navbar-nav', [\n        m('li',\n          m(\"a\", {config: m.route, href: _.router.url('index')}, 'Index')\n        )\n      ]));\n\n      var navbarStyle = '.navbar.navbar-default.navbar-static-top';\n\n      return m('nav' + navbarStyle + '[role=\"navigation\"]', [\n        m('.container.navbar-full.hidden-xs.hidden-sm', desktopNavbar)\n      ]);\n    }\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  Misago.ForumLayout = {\n    view: function(ctrl, _) {\n      return [\n        _.component(Misago.ForumNavbar),\n        m('#router-fixture', {config: persistent}),\n        _.component(Misago.ForumFooter)\n      ];\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.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.LoadingPage = {\n    view: function(ctrl, _) {\n      return m('.page.loading-page',\n        _.component(Misago.Loader)\n      );\n    }\n  };\n} (Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  var setupMarkup = function(el, isInit, context) {\n    context.retain = true;\n  };\n\n  Misago.Markup = {\n    view: function(ctrl, content) {\n      return m('article.misago-markup', {config: setupMarkup},\n        m.trust(content)\n      );\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago) {\n  'use strict';\n\n  Misago.PageHeader = {\n    view: function(ctrl, options) {\n      return m('.page-header',\n        m('.container', [\n          m('h1', options.title),\n        ])\n      );\n    }\n  };\n}(Misago.prototype));\n\n(function (Misago, UrlConf) {\n  'use strict';\n\n  var urls = new UrlConf();\n  urls.url('/', Misago.IndexRoute, 'index');\n\n  // Legal pages\n  urls.url(\n    '/terms-of-service/',\n    Misago.TermsOfServiceRoute,\n    'terms_of_service');\n\n  urls.url(\n    '/privacy-policy/',\n    Misago.PrivacyPolicyRoute,\n    'privacy_policy');\n\n  // Catch-all 404 not found route\n  urls.url('/:rest...', Misago.Error404Route, 'not_found');\n\n  Misago.urls = urls;\n} (Misago.prototype, Misago.prototype.UrlConf));\n"],"sourceRoot":"/source/"}