changeset 164:e9f0a4215e46

multi-sites handling (moved templates to "templates" sub-directory) + noscript styles handling.
author Goffi <goffi@goffi.org>
date Mon, 10 Sep 2018 08:53:33 +0200
parents 33f67228686a
children 9e8d9d754337
files sat_templates/default/app/app.html sat_templates/default/base/base.html sat_templates/default/blog/articles.html sat_templates/default/blog/atom.xml sat_templates/default/blog/discover.html sat_templates/default/blog/item.html sat_templates/default/blog/macros.html sat_templates/default/chat/chat.html sat_templates/default/chat/message.html sat_templates/default/chat/select.html sat_templates/default/components/avatar.html sat_templates/default/components/block.html sat_templates/default/components/common.html sat_templates/default/components/images.html sat_templates/default/error/401.html sat_templates/default/error/404.html sat_templates/default/error/base.html sat_templates/default/event/admin.html sat_templates/default/event/attendance.html sat_templates/default/event/counter.html sat_templates/default/event/create.html sat_templates/default/event/invitation.html sat_templates/default/event/overview.html sat_templates/default/file/discover.html sat_templates/default/file/overview.html sat_templates/default/forum/overview.html sat_templates/default/forum/view.html sat_templates/default/forum/view_topics.html sat_templates/default/input/field.html sat_templates/default/input/form.html sat_templates/default/input/navigation.html sat_templates/default/input/textbox.html sat_templates/default/input/xmlui.html sat_templates/default/invitation/welcome.html sat_templates/default/login/logged.html sat_templates/default/login/login.html sat_templates/default/login/register.html sat_templates/default/merge-request/create.html sat_templates/default/merge-request/discover.html sat_templates/default/merge-request/edit.html sat_templates/default/merge-request/item.html sat_templates/default/photo/album.html sat_templates/default/photo/discover.html sat_templates/default/session/disconnect.html sat_templates/default/static/app.css sat_templates/default/static/blog.css sat_templates/default/static/chat.css sat_templates/default/static/chat.js sat_templates/default/static/chat_select.css sat_templates/default/static/common.js sat_templates/default/static/event.css sat_templates/default/static/file.css sat_templates/default/static/fonts.css sat_templates/default/static/fonts/sat_base_font/README.txt sat_templates/default/static/fonts/sat_base_font/SIL Open Font License.txt sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff2 sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff2 sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff2 sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff2 sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff2 sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff2 sat_templates/default/static/forum.css sat_templates/default/static/highlight.css sat_templates/default/static/invitation.css sat_templates/default/static/login.css sat_templates/default/static/merge-request.css sat_templates/default/static/merge-request_item.css sat_templates/default/static/photo.css sat_templates/default/static/styles.css sat_templates/default/static/ticket.css sat_templates/default/static/websocket.js sat_templates/default/ticket/create.html sat_templates/default/ticket/discover.html sat_templates/default/ticket/edit.html sat_templates/default/ticket/item.html sat_templates/default/ticket/overview.html sat_templates/default/ticket/tickets.html sat_templates/templates/default/app/app.html sat_templates/templates/default/base/base.html sat_templates/templates/default/blog/articles.html sat_templates/templates/default/blog/atom.xml sat_templates/templates/default/blog/discover.html sat_templates/templates/default/blog/item.html sat_templates/templates/default/blog/macros.html sat_templates/templates/default/chat/chat.html sat_templates/templates/default/chat/message.html sat_templates/templates/default/chat/select.html sat_templates/templates/default/components/avatar.html sat_templates/templates/default/components/block.html sat_templates/templates/default/components/common.html sat_templates/templates/default/components/images.html sat_templates/templates/default/error/401.html sat_templates/templates/default/error/404.html sat_templates/templates/default/error/base.html sat_templates/templates/default/event/admin.html sat_templates/templates/default/event/attendance.html sat_templates/templates/default/event/counter.html sat_templates/templates/default/event/create.html sat_templates/templates/default/event/invitation.html sat_templates/templates/default/event/overview.html sat_templates/templates/default/file/discover.html sat_templates/templates/default/file/overview.html sat_templates/templates/default/forum/overview.html sat_templates/templates/default/forum/view.html sat_templates/templates/default/forum/view_topics.html sat_templates/templates/default/input/field.html sat_templates/templates/default/input/form.html sat_templates/templates/default/input/navigation.html sat_templates/templates/default/input/textbox.html sat_templates/templates/default/input/xmlui.html sat_templates/templates/default/invitation/welcome.html sat_templates/templates/default/login/logged.html sat_templates/templates/default/login/login.html sat_templates/templates/default/login/register.html sat_templates/templates/default/merge-request/create.html sat_templates/templates/default/merge-request/discover.html sat_templates/templates/default/merge-request/edit.html sat_templates/templates/default/merge-request/item.html sat_templates/templates/default/photo/album.html sat_templates/templates/default/photo/discover.html sat_templates/templates/default/session/disconnect.html sat_templates/templates/default/static/app.css sat_templates/templates/default/static/blog.css sat_templates/templates/default/static/chat.css sat_templates/templates/default/static/chat.js sat_templates/templates/default/static/chat_select.css sat_templates/templates/default/static/common.js sat_templates/templates/default/static/event.css sat_templates/templates/default/static/file.css sat_templates/templates/default/static/fonts.css sat_templates/templates/default/static/fonts/sat_base_font/README.txt sat_templates/templates/default/static/fonts/sat_base_font/SIL Open Font License.txt sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff2 sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff2 sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff2 sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff2 sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff2 sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff2 sat_templates/templates/default/static/forum.css sat_templates/templates/default/static/highlight.css sat_templates/templates/default/static/invitation.css sat_templates/templates/default/static/login.css sat_templates/templates/default/static/merge-request.css sat_templates/templates/default/static/merge-request_item.css sat_templates/templates/default/static/photo.css sat_templates/templates/default/static/styles.css sat_templates/templates/default/static/ticket.css sat_templates/templates/default/static/websocket.js sat_templates/templates/default/ticket/create.html sat_templates/templates/default/ticket/discover.html sat_templates/templates/default/ticket/edit.html sat_templates/templates/default/ticket/item.html sat_templates/templates/default/ticket/overview.html sat_templates/templates/default/ticket/tickets.html
diffstat 166 files changed, 4283 insertions(+), 4269 deletions(-) [+]
line wrap: on
line diff
--- a/sat_templates/default/app/app.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-{% extends 'base/base.html' %}
-{% block body %}
-<article id="web_app_box" class="box">
-    <p>
-        {% trans app_name=C.APP_NAME %}
-            The following link allows you to access {{app_name}} web application, which is a more feature rich way to use this software (but it is also a bit more heavy and complex to use).
-        {% endtrans %}
-    </p>
-    <p class="warning_text">
-        {% trans %}
-            Please note that current version of web application use legacy technologies and will be rewritten for next version of Salut à Toi (0.8). It does contain some bugs and it is under minimal maintenance.
-        {% endtrans %}
-    </p>
-    <p id="link_section">
-        <a href="/libervia.html">{% trans %}Click here to access the web application{% endtrans %}</a>.
-    </p>
-    <p>
-        {% trans %}
-            Next time you can go directly to the above URL.
-        {% endtrans %}
-    </p>
-</article>
-{% endblock body %}
--- a/sat_templates/default/base/base.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-{% set embedded = True %} {# embedded is set to avoid including base.html several times if a generic page is included (e.g. blog/articles.html) #}
-{% import 'components/common.html' as component with context %}
-{{ script.include('common', '') }} {# common.js is a common script, so it's useful to import it here #}
-<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="utf-8">
-    <meta name="viewport" content="width=device-width, initial-scale=1">
-
-    {% if norobots %}
-        <meta name="robots" content="noindex, nofollow">
-    {% endif %}
-
-    <title>{% block title %}{{C.APP_NAME}}{% endblock %}</title>
-
-    {% if css_content is defined %}
-        <style type="text/css">
-            {{css_content}}
-        </style>
-    {% else %}
-        {% for css_file in css_files %}
-            <link rel='stylesheet' type="text/css" href='{{root_path}}{{css_file}}'>
-        {% endfor %}
-    {% endif %}
-
-    {% if xmpp_uri is defined %}
-        <link rel="alternate" type="application/atom+xml" href="{{xmpp_uri}}" >
-    {% endif %}
-
-    {% if dynamic_style is defined %}
-    {# be extra careful about dynamic style, insure escaping if you use untrusted values ! #}
-        <style type="text/css">
-        {{dynamic_style}}
-        </style>
-    {% endif %}
-
-    {# JS handling #}
-    {% if websocket is defined %}
-        {{ script.include('websocket', '') }}
-    {% endif %}
-    {{ script.generate_scripts() }}
-    {% if websocket is defined %}
-        <script>var socket=new WSHandler("{{websocket.url}}", "{{websocket.token}}", {{websocket.debug}});</script>
-    {% endif %}
-
-    {% block favicon %}
-        <link rel="icon" href="{{media_path}}icons/apps/64/sat.png">
-    {% endblock favicon %}
-</head>
-<body>
-    {% if main_menu is defined %}
-        {% block main_menu %}
-            {{ component.menu(main_menu, class="main_menu") }}
-        {% endblock main_menu %}
-    {% endif %}
-
-    <main id='main_area'>
-        <header>
-            {% if confirm %}
-            {# confirmation message used when post data has been handled correctly #}
-                {% block confirm %}
-                    <div class="box post_confirm">
-                        {% block confirm_message %}
-                            {% trans %}Your data has been sent correctly.{% endtrans %}
-                        {% endblock confirm_message %}
-                    </div>
-                {% endblock confirm %}
-            {% endif %}
-
-        </header>
-
-        <div id="body">
-        {% block category_menu scoped %}
-            {% if category_menu is defined %}
-                {{ component.menu(category_menu, class="category_menu") }}
-            {% endif %}
-        {% endblock category_menu %}
-        {% block body %}
-        {% endblock body %}
-        </div>
-        <footer>{% block footer %}<span>{% trans app_name=C.APP_NAME %}Powered by {{app_name}}{% endtrans %}</span>{% endblock %}</footer>
-    </main>
-</body>
-</html>
--- a/sat_templates/default/blog/articles.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% set single = items|length == 1 %}
-{% set dates_format='relative' if single else 'short' %}
-{% import 'blog/macros.html' as blog with context %}
-{% import 'input/navigation.html' as navigation with context %}
-
-{%- block title scoped -%}
-    {%- if not embedded -%}
-        {%- if single -%}
-            {{- items[0].title|default(items[0].content, true)|truncate(60, True, '…') + ' - ' + C.APP_NAME -}}
-        {%- else -%}
-            {{C.APP_NAME}}
-            {# {{- super() -}}
-               FIXME: super() is failing if blog is embedded (i.e. base/base.html is not its direct parent)
-                      not sure what's the best way to avoid that, so just using C.APP_NAME for now #}
-        {%- endif -%}
-    {%- endif -%}
-{%- endblock title -%}
-
-{% block body %}
-{% if items %}
-    <div id="blog_items">
-        {{ blog.show_items(items, expanded=single) }}
-    </div>
-{% else %}
-    <p class="message--info">{% trans %}No articles found in this blog!{% endtrans %}</p>
-{% endif %}
-
-{{ navigation.prev_next(_("newer articles"), _("older articles")) }}
-{% endblock body %}
--- a/sat_templates/default/blog/atom.xml	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<feed xmlns='http://www.w3.org/2005/Atom'>
-    {% if title is defined %}
-        <title>{{title}}</title>
-    {% elif target_profile is defined %}
-        <title>{% trans name=target_profile%}{{name}}'s blog{% endtrans %}</title>
-    {% else %}
-        <title>{% trans app_name=C.APP_NAME%}{{app_name}} blog{% endtrans %}</title>
-    {% endif %}
-    <link href='{{request_uri}}' type='application/atom+xml' rel='self'/>
-    <link href='{{http_uri}}' type='text/html' rel='alternate'/>
-    <link href='{{xmpp_uri}}' type='application/atom+xml' rel='alternate'/>
-    <id>{{xmpp_uri}}</id>
-    <updated>{{updated|date_fmt('iso')}}</updated>
-    {% for item in items %}
-        <entry>
-            {% if item.title_xhtml %}
-                <title type='xhtml'>{{item.title_xhtml}}</title>
-            {% else %}
-                <title>{{item.title|default(item.content|truncate(80, True, '…'), True)}}</title>
-            {% endif %}
-            <link href='{{items_http_uri[item.id]}}' type='text/html' rel='alternate'/>
-            <link href='{{item.uri}}' type='application/atom+xml' rel='alternate'/>
-            <id>{{item.uri}}</id>
-            <updated>{{item.updated|date_fmt('iso')}}</updated>
-            <published>{{item.published|date_fmt('iso')}}</published>
-            <author>
-                <name>{{item.author}}</name>
-                <uri>xmpp:{{item.author_jid}}</uri>
-            </author>
-            {% for tag in item.tags %}
-                <category term="{{tag}}"/>
-            {% endfor %}
-            {% if item.content_xhtml %}
-                <content type='xhtml'>
-                    <div xmlns='http://www.w3.org/1999/xhtml'>
-                    {{item.content_xhtml}}
-                    </div>
-                </content>
-            {% else %}
-                <content type='text'>
-                    {{item.content_txt}}
-                </content>
-            {% endif %}
-        </entry>
-    {% endfor %}
-</feed>
--- a/sat_templates/default/blog/discover.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-{% extends 'base/base.html' %}
-{% import 'components/block.html' as block %}
-{% import 'components/images.html' as images with context %}
-{% import 'components/avatar.html' as avatar with context %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% block body %}
-{{ icon_defs('blog') }}
-<p class="instructions--head">
-    {% trans %}
-    Please select the blog you want to consult
-    {% endtrans %}
-</p>
-<div class="disco_blogs">
-    <ul class="grid grid--center">
-        {% for entity in disco_entities %}
-            <li class='grid__item grid__item--medium grid__item--selectable'>
-                <a href="{{entities_url[entity]}}" class="items_vert--centered">
-                    {{ avatar.avatar(entity, class="avatar--medium") }}
-                    <span>{{ identities[entity].nick|default(entity, true) }}</span>
-                </a>
-            </li>
-        {% endfor %}
-    </ul>
-</div>
-
-{% if disco_entities %}
-    <p class="instructions--alt">{% trans %}Or enter the jid of a blog writer{% endtrans %}</p>
-{% endif %}
-{% call form.form(class="form--single") %}
-    {{ field.text("jid", _("blog writer jid"), required=true)}}
-    {{ field.submit(_("Consult")) }}
-{% endcall %}
-{% endblock body %}
--- a/sat_templates/default/blog/item.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,98 +0,0 @@
-{# display a blog item which can be expanded/retracted by clicking on it
-
-    if the locale differs from item language, it will be totally reduced, and will need a click to be displayed
-
-    @variable item(data_object.BlogItem): item to display
-    @variable identities(data_object.Identities): identities which can be used to display info on item author
-    @variable dates_format(unicode): format of the date to use (see date_fmt filter)
-#}
-
-{% block item %}
-
-{% if item.language and locale and locale.language != item.language %}
-    {# we may display items in different language in a specific way #}
-    {% set other_lang = " other_lang" %}
-{% endif %}
-
-{% if expanded %}
-    {# FIXME: the style attribute is not nice, but due to the use of clicked_mh_fix. A cleaner way would be welcomed #}
-    <article id="{{item.id}}" class="init box{{other_lang}} clicked" style="max-height: none">
-{% else %}
-    <article id="{{item.id}}" class="init box{{other_lang}}" >
-{% endif %}
-
-    {# following message is displayed if item lang is different from page locale #}
-    {% if other_lang is defined %}
-        <div class="info"><p>{% trans language=locale.language_name %}This message is not in {{language}}, click to display anyway{% endtrans %}</p></div>
-    {% endif %}
-
-    {# we put a reduce button at the top #}
-    <div class="expand_box box_top" onclick="clicked_mh_fix('{{item.id}}')">
-        <p>
-            <span class='hide'>{% trans %}Click to reduce…{% endtrans %}</span>
-        </p>
-    </div>
-
-    <header>
-        {% block header %}
-        {# title and publication date link to a HTTP page if items_http_uri is set #}
-        {% set item_http_uri = items_http_uri.get(item.id) if items_http_uri is defined else none %}
-
-        <div class="title">
-            {% block blog_title scoped %}
-                {% set title = item.title_xhtml or item.title or '' %}
-                {% if item_http_uri %}
-                    <a href="{{item_http_uri}}">{{title}}</a>
-                {% else %}
-                    {{title}}
-                {% endif %}
-            {% endblock %}
-        </div>
-            {% block metadata scoped %}
-            <div class="metadata">
-            {% if identities is defined %}
-                <span class="author">{{identities[item.author_jid].nick | default(item.author)}}</span>
-            {% else %}
-                <span class="author">{{item.author}}</span>
-            {% endif %}
-            {% set published = item.published|date_fmt(fmt=dates_format) %}
-            {% if item_http_uri %}
-                <span class="blog_data"><a href="{{item_http_uri}}">{{published}}</a></span>
-            {% else %}
-                {{- published -}}
-            {% endif %}
-            </div>
-            {% if item.tags %}
-                <div class="labels">
-                    {% if tags_http_uri is defined %}
-                        {% for tag in item.tags %}
-                            <a href="{{tags_http_uri[tag]}}"><span>{{tag}}</span></a>
-                        {% endfor %}
-                    {% else %}
-                        {% for tag in item.tags %}
-                            <span>{{tag}}</span>
-                        {% endfor %}
-                    {% endif %}
-                </div>
-            {% endif %}
-            {% endblock metadata %}
-        {% endblock header %}
-    </header>
-
-    <div class="content{{' text' if not item.content_xhtml}}">
-        {% block content %}
-        {{- item.content_xhtml or item.content|urlize or '' -}}
-        {% endblock content %}
-    </div>
-
-    {# and the bottom button to expand/reduce the article #}
-    <div class="expand_box box_bottom" onclick="clicked_mh_fix('{{item.id}}')">
-        <p>
-            <span class='show'>{% trans %}Click to expand…{% endtrans %}</span>
-            <span class='hide'>{% trans %}Click to reduce…{% endtrans %}</span>
-        </p>
-    </div>
-
-</article>
-
-{% endblock item %}
--- a/sat_templates/default/blog/macros.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-{% import 'input/textbox.html' as textbox with context %}
-
-{% macro show_items(items, comments=False, expanded=false, dates_fmt=none) %}
-    {# show items and comments items if present after each item,
-        then post form if allow_commenting is set
-        @param items(BlogItems): items to show
-        @param comments(bool): True items are comments
-            if False, a div with "main_article" class will be added
-        @param expanded(bool): initial state of items
-    #}
-    {% if dates_format is undefined %}
-        {% set dates_format = dates_fmt or 'short' %}
-    {% endif %}
-    {% for item in items %}
-        {% if not comments %}<div class="main_article">{% endif %}
-            {% include 'blog/item.html' %}
-        {% if not comments %}</div>{% endif %}
-
-        {# we recursively display comments for all comments nodes (usually there's only one) #}
-        {% for comments_items in item.comments_items_list %}
-            <button class="comments_btn" onclick="clicked_mh_fix('{{'comments_panel'|next_gidx}}');clicked_cls(this)">
-                <span class='show'>{% trans %}show comments{% endtrans %}</span>
-                <span class='hide'>{% trans %}hide comments{% endtrans %}</span>
-                ({{comments_items|count}})
-            </button>
-            <div id="{{'comments_panel'|cur_gidx}}" class="comments_panel">
-                {% if allow_commenting %}
-                    <div class="comment_post">
-                        {{- textbox.comment(service=comments_items.service, node=comments_items.node) -}}
-                    </div>
-                {% endif %}
-
-                <div class="comments">
-                    {{show_items(comments_items, comments=True)}}
-                </div>
-            </div>
-
-        {% endfor %}
-
-    {% endfor %}
-{% endmacro %}
--- a/sat_templates/default/chat/chat.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-{{ script.include('chat') }}
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% block title %}{{ target_jid }} - {{ super() }}{% endblock %}
-{% block body %}
-<div class="chat_widget">
-    <div id="messages">
-    {% if subject is defined %}
-        <div id="subject">
-            {{- subject|urlize(nofollow=true,target='_blank') -}}
-        </div>
-    {% endif %}
-    {% for msg in messages %}
-        {% include 'chat/message.html' %}
-    {% endfor %}
-    </div>
-    <div class="message_box">
-        <textarea id="message_input" name="message" type="text" placeholder="{{_("enter your message")}}"></textarea>
-    </div>
-</div>
-{% endblock body %}
-
-{% block footer %}{% endblock footer %}
--- a/sat_templates/default/chat/message.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-{% import 'components/avatar.html' as avatar with context %}
-
-<p id="{{msg.id}}" class="msg_{{msg.type}} {{'own_msg' if msg.from_ == own_jid.full()}}">
-    {%- if msg.type != C.MESS_TYPE_INFO %}
-        {%- set author = identities[msg.from_].nick | default(msg.from_) -%}
-        {{ avatar.avatar(msg.from_, "avatar--float-left") }}
-        <span class="msg_header">
-            <span class="author">{{author}}</span>
-            <span class="date">{{msg.timestamp|date_fmt('auto_day')}}</span>
-        </span>
-    {% endif -%}
-    <span class="msg_body">
-        {{- msg.html or (msg.text|urlize(nofollow=true, target="_blank")) -}}
-    </span>
-</p>
--- a/sat_templates/default/chat/select.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% block body %}
-<p class="instructions--head">{% trans %}Please select the chat room you want to enter{% endtrans %}</p>
-<ul class="rooms_list">
-{% for room in rooms %}
-    <li><a href="{{room.url}}">{{room.name}}</a></li>
-{% endfor %}
-</ul>
-<p class="instructions--alt">{% trans %}Or enter a room address{% endtrans %}</p>
-{% call form.form(class="form--single") %}
-    {{ field.text("jid", _("Room address (JID)"), required=true)}}
-    {{ field.submit(_("Join")) }}
-{% endcall %}
-{% endblock body %}
--- a/sat_templates/default/components/avatar.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-{% macro avatar(jid, class) %}
-    {%- if identities is defined -%}
-        {%- if identities[jid].avatar_basename is defined %}
-            <img class="avatar {{class}}" src="{{cache_path}}{{identities[jid].avatar_basename}}">
-        {% else %}
-            <span class="avatar avatar--generated {{class}}"><span class="avatar__content">{{identities[jid].nick|first|upper}}</span></span>
-        {%- endif -%}
-    {%- endif -%}
-{% endmacro %}
--- a/sat_templates/default/components/block.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-{% macro separator(label, align='center') %}
-{# display a bloc separator
-    @param label(unicode): label to show
-    @param align(unicode): one of "left", "center", "right"
-#}
-    <div class="block_separator">
-        {% if align in ('center', 'right') %}
-            <div class="block_separator__line"></div>
-        {% endif %}
-        <div class="block_separator__label">
-            {{label}}
-        </div>
-        {% if align in ('center', 'left') %}
-            <div class="block_separator__line"></div>
-        {% endif %}
-    </div>
-{% endmacro %}
-
-{% macro disco_icon_grid(disco_entities, icon_name) %}
-{# display discovered entities in a grid
-    @param disco_entities: entities which mush have a name and url key or attribute
-    @param icon_name: name of a defined icon
-#}
-    <ul class="grid grid--center">
-        {% for disco_entity in disco_entities %}
-            <li class='grid__item grid__item--medium grid__item--selectable'>
-                <a href="{{disco_entity.url}}" class="items_vert--centered">
-                    {{ icon(icon_name, cls='icon--medium') }}
-                    <span>{{ disco_entity.name }}</span>
-                </a>
-            </li>
-        {% endfor %}
-    </ul>
-{% endmacro %}
--- a/sat_templates/default/components/common.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-{# menu labels, map from menu names to labels #}
-{% set ml = {
-    'login': _('Session') if profile else _('Log in'),
-    'blog': _('Blog'),
-    'forums': _('Forums'),
-    'merge-requests': _('Merge requests'),
-    'merge-request_new': _('Create new merge request'),
-    'tickets': _('Tickets'),
-    'tickets_list': _('List tickets'),
-    'ticket_new': _('Create new ticket'),
-    'chat': _('Chat'),
-    'files': _('Files sharing'),
-    'events': _('Events'),
-    'event_new': _('Create an event'),
-    'photos': _('Photos albums'),
-    'app': _('Application'),
-} %}
-
-{% macro menu(menus, class='') %}
-    <nav class="menu {{class}}">
-        <ul>
-        {% for name,url in menus %}
-            <li><a class="menu_item menu_item--{{name}}" {{ {'href': url}|xmlattr }}>{{ml[name]}}</a></li>
-        {% endfor %}
-        </ul>
-    </nav>
-{% endmacro %}
--- a/sat_templates/default/components/images.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-{% macro get_icon_client(ident) %}
-    {% if ident.client %}
-        {% if ident.client.pc %}
-            {{ icon('desktop', cls='file__icon') }}
-        {% elif ident.client.phone %}
-            {{ icon('mobile', cls='file__icon') }}
-        {% elif ident.client.web %}
-            {{ icon('globe', cls='file__icon') }}
-        {% elif ident.client.console %}
-            {{ icon('terminal', cls='file__icon') }}
-        {% else %}
-            {{ icon('desktop', cls='file__icon') }}
-        {% endif %}
-    {% endif %}
-{% endmacro %}
--- a/sat_templates/default/error/401.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-{% extends 'error/base.html' %}
-
-{% block body %}
-<h1>{% trans %}Unauthorized{% endtrans %}</h1>
-<p>{% trans %}Sorry, you are not allowed to access this page.{% endtrans %}</p>
-{% endblock body %}
--- a/sat_templates/default/error/404.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-{% extends 'error/base.html' %}
-
-{% block body %}
-<h1>{% trans %}Not Found{% endtrans %}</h1>
-<p>{% trans %}Sorry, we can't find the resource you are trying to access.{% endtrans %}</p>
-{% endblock body %}
--- a/sat_templates/default/error/base.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-{% extends 'base/base.html' %}
-
-{% block title %}{% trans %}Error {{error_code}}{% endtrans %}{% endblock %}
-{% block body %}
-{% trans %}An error occured while trying to access the resource.{% endtrans %}
-{% endblock body %}
-{% block footer %}{% endblock %}
--- a/sat_templates/default/event/admin.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-{% extends 'base/base.html' %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-{% import 'input/textbox.html' as textbox with context %}
-
-{% block body %}
-<div class='invitation_header box'>
-    <h1>{% trans name=event.name %}{{name}} administration{% endtrans %}</h1>
-    {% if event.image is defined %}
-        <p><img class='event__picture' src="{{event.image}}"></p>
-    {% endif %}
-    {% if event.description is defined %}
-        <p>{{event.description}}</p>
-    {% endif %}
-</div>
-
-{% include 'event/counter.html' %}
-
-{% if invitees %}
-    <div class="box">
-    <h3 class="title">{% trans %}invitees{% endtrans %}</h3>
-    <table class="table--main">
-    <tr>
-        <th>{% trans %}name{% endtrans %}</th>
-        <th>{% trans %}coming?{% endtrans %}</th>
-        <th>{% trans %}guests{% endtrans %}</th>
-    {% for name, data in invitees.iteritems() %}
-        <tr>
-            <td>{{name}}</td>
-            <td>{{data.attend|default('')}}</td>
-            {% if data.attend == 'no' %}
-                <td>&nbsp;</td>
-            {% else %}
-                <td>{{data.guests|default(0)}}</td>
-            {% endif %}
-        </tr>
-    {% endfor %}
-    <tr>
-        <td colspan=2 class="table__total">{% trans %}total expected{% endtrans %}</td>
-        <td class="table__total_value">{{invitees_guests|default('0')}}</td>
-    </tr>
-    </table>
-    </div>
-{% endif %}
-
-<div class="box">
-<h3 class="title">{% trans %}invite people{% endtrans %}</h3>
-{% call form.form(class="form--paper form__panel--vertical form__panel--center") %}
-    {{ textbox.head(event_service, event_node, 'event') }}
-    {{ field.meta('event_id', event_id) }}
-    {{ field.textarea("jids",
-                      _("enter here a list of jid (one per line) to invite"),
-                      class="form__field--medium") }}
-    {{ field.textarea("emails",
-                      _("enter here a list of emails addresses (one per line) to invite"),
-                      class="form__field--medium") }}
-    {{ field.submit(_("Invite people")) }}
-{% endcall %}
-</div>
-
-<div class="box">
-<h3 class="title">{% trans %}write a blog post{% endtrans %}</h3>
-{% call form.form(class="form--paper form__panel--vertical form__panel--center") %}
-    {{ textbox.head(service, node, 'blog') }}
-    {{ field.text("title",
-                  _("title"),
-                  class="form__field--big") }}
-    {{ field.textarea("body",
-                      _("body"),
-                      class="form__field--big") }}
-    {{ field.text("language",
-                  _("language"),
-                  class="form__field--tiny") }}
-    {{ field.checkbox("comments",
-                      _("allow comments"),
-                      checked=true) }}
-    {{ field.submit(_("send")) }}
-{% endcall %}
-</div>
-
-{% if items is defined %}
-    {% include 'blog/articles.html' %}
-{% endif %}
-
-{% endblock body %}
--- a/sat_templates/default/event/attendance.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-<div class="attendance box">
-    <p class="poll_instructions">{% trans %}Please indicate if you plan to attend the event:{% endtrans %}</p>
-    {% call form.form() %}
-        {{ field.meta("type", "attendance") }}
-        {{ field.meta("service", event.invitees_service) }}
-        {{ field.meta("node", event.invitees_node) }}
-        <div class="attending">
-            {{ field.choices("attend", (("yes", _("yes")), ("no", _("no")), ("maybe", _("maybe"))), checked=invitee.attend) }}
-        </div>
-        <div class="guests">
-            {{ field.int("guests", label=_("How many people will come (including you)?"), init=invitee.get("guests", 1)) }}
-        </div>
-        <div class="submit">
-            {{ field.submit() }}
-        </div>
-    {% endcall %}
-</div>
--- a/sat_templates/default/event/counter.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-{% if days_left is defined %}
-    {% if days_left > 0 %}
-        <div class="event__counter box">
-            {% trans %}
-                {{days_left}} day left
-            {% pluralize %}
-                {{days_left}} days left
-            {% endtrans %}
-        </div>
-    {% else %}
-        <div class="event__counter box">{% trans %}the event is finished{% endtrans %}</div>
-    {% endif %}
-
-{% endif %}
--- a/sat_templates/default/event/create.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-{# create a new event #}
-
-{% extends 'base/base.html' %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% block body %}
-<div class='instructions--head'>
-{% trans %}Create an event{% endtrans %}
-</div>
-<div class="box--hollow">
-{% call form.form(class="form--paper form__panel--vertical") %}
-    {{ field.text("name", _("name"), required=true) }}
-    {{ field.text("location", _("location"), required=true) }}
-    {{ field.textarea("body",
-                      _("description of the event"),
-                      required=true,
-                      class="form__field--medium") }}
-    {{ field.date("date", _("date of the event"), required=true) }}
-    {{ field.url("main_image", _("event image URL (https)"),
-                 title=_("you can enter here the URL to a JPEG or PNG image to use as representation of your event"),
-                 placeholder=_("JPEG or PNG image URL"),
-                 pattern='http.*(jpg|jpeg|png)') }}
-    {{ field.url("bg_image", _("background image URL (https)"),
-                 title=_("you can enter here the URL to a JPEG or PNG image to use repeating background"),
-                 placeholder=_("JPEG or PNG image URL"),
-                 pattern='http.*(jpg|jpeg|png)') }}
-    {{ field.submit(_("Create event")) }}
-{% endcall %}
-</div>
-{% endblock body %}
--- a/sat_templates/default/event/invitation.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-{% extends 'base/base.html' %}
-
-{% block body %}
-<div class='box box--paper'>
-    <h1>{% trans %}Welcome {{name}}{% endtrans %}</h1>
-    <p class='instructions'>{% trans %}You have been invited to participate to an event{% endtrans %}</p>
-    {% if event.image is defined %}
-        <p><img id='event_picture' src="{{event.image}}"></p>
-    {% endif %}
-</div>
-
-{% include 'event/counter.html' %}
-
-{% include 'event/attendance.html' %}
-
-{% if items is defined %}
-    {% include 'blog/articles.html' %}
-{% endif %}
-
-{% endblock body %}
--- a/sat_templates/default/event/overview.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-{# overview of current events
-
-    @variable item(xmlui_item): ticket to display
-    @variable comments(data_object.BlogItems): comments of the ticket
-    @variable comments_service(unicode): service for adding comments
-    @variable comments_node(unicode): node for adding comments
-#}
-
-{% set category_menu = [('event_new', url_event_new)] %}
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% block body %}
-<div class="box message--info">
-    <p>{% trans %}There is not events discovery yet, this will come in the future.{% endtrans %}</p>
-</div>
-{% if events is defined %}
-    <p class="message--note">
-        {% trans nb_events=events|length%}
-            You have currently {{nb_events}} event in your personal list
-        {% pluralize %}
-            You have currently {{nb_events}} events in your personal list
-        {% endtrans %}
-    </p>
-    <ul class="grid grid--center">
-        {% for event in events %}
-            <li class='grid__item grid__item--medium grid__item--selectable'>
-                <a href="{{event.url}}">
-                    {% if event.image %}
-                        <img class="img--small" src="{{event.image}}">
-                    {% endif %}
-                    <span><em>{{event.name}}</em></span>
-                </a>
-            </li>
-        {% endfor %}
-    </ul>
-{% endif %}
-{% endblock body %}
--- a/sat_templates/default/file/discover.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-{% extends 'base/base.html' %}
-{% import 'components/block.html' as block %}
-{% import 'components/images.html' as images with context %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% block body %}
-{{ icon_defs('server', 'desktop', 'mobile', 'globe', 'terminal') }}
-<p class="instructions--head">
-    {% trans %}
-    Please select the device you want to access
-    {% endtrans %}
-</p>
-<div class="disco_files">
-    {% if disco_service_entities %}
-        <div class="files__services">
-            {{ block.separator(_("services")) }}
-            <ul class="grid grid--center">
-                {% for entity,ident in disco_service_entities.iteritems() %}
-                    <li class='grid__item grid__item--medium grid__item--selectable'>
-                        <a href="{{entities_url[entity]}}">
-                            {{ icon('server', cls='file__icon') }}
-                            <span>
-                                {% if disco_service_entities|count == 1 %}
-                                    {% trans %}your server{% endtrans %}
-                                {% else %}
-                                    {{ ident.values()[0].values()[0][0] }}
-                                {% endif %}
-                            </span>
-                        </a>
-                    </li>
-                {% endfor %}
-            </ul>
-        </div>
-    {% endif %}
-    {% if disco_own_entities %}
-        <div class="files__own">
-            {{ block.separator(_("your devices")) }}
-            <ul class="grid grid--center">
-                {% for entity,ident in disco_own_entities.iteritems() %}
-                    <li class='grid__item grid__item--medium grid__item--selectable'>
-                        <a href="{{entities_url[entity]}}">
-                            {{images.get_icon_client(ident)}}
-                            <span>{{ ident.values()[0].values()[0][0] }}</span>
-                        </a>
-                    </li>
-                {% endfor %}
-            </ul>
-        </div>
-    {% endif %}
-    {% if disco_roster_entities %}
-        <div class="files__roster">
-            {{ block.separator(_("your contacts devices")) }}
-            <ul class="grid grid--center">
-                {% for entity,ident in disco_roster_entities.iteritems() %}
-                    <li class='grid__item grid__item--medium grid__item--selectable'>
-                        <a href="{{entities_url[entity]}}">
-                            {{images.get_icon_client(ident)}}
-                            <span>{{entity.userhost()}}</span>
-                        </a>
-                    </li>
-                {% endfor %}
-            </ul>
-        </div>
-    {% endif %}
-</div>
-
-<p class="instructions--alt">{% trans %}Or enter a full jid of a device{% endtrans %}</p>
-{% call form.form(class="form--single") %}
-    {{ field.text("jid", _("device full jid"), required=true)}}
-    {{ field.submit(_("Access")) }}
-{% endcall %}
-{% endblock body %}
--- a/sat_templates/default/file/overview.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-{% extends 'base/base.html' %}
-
-{% block body %}
-{{ icon_defs('level-up', 'doc','folder-open-empty', 'comment-empty') }}
-<ul id="files">
-    {% if parent_url is defined  %}
-        <li class="file">
-            <a href="{{ parent_url }}">
-                {{ icon('level-up', cls='file__icon') }}
-                {% trans %}parent dir{% endtrans %}
-            </a>
-        </li>
-    {% endif %}
-
-    {% for file in files_data %}
-        {% if file.type == C.FILE_TYPE_DIRECTORY %}
-            <li class="file file_{{file.type}}">
-                <a href="{{file.url}}">
-                    {{ icon('folder-open-empty', cls='file__icon') }}
-                    {{ file.name }}
-                </a>
-            </li>
-        {% else %}
-            <li class="file file_{{file.type}}">
-                <a href="{{file.url}}">
-                    {% if file.thumb_url is defined %}
-                        <img src="{{file.thumb_url}}" class="file__thumbnail" alt="{{file.name}}">
-                    {% else %}
-                        {{ icon('doc', cls='file__icon icon--soft') }}
-                    {% endif %}
-                    {{ file.name }}
-                </a>
-            </li>
-        {% endif %}
-    {% endfor %}
-</ul>
-{% if not files_data %}
-    <p class="message--info">{% trans %}No files are shared in this directory!{% endtrans %}</p>
-{% endif%}
-{% endblock body %}
--- a/sat_templates/default/forum/overview.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-{% extends 'base/base.html' %}
-
-{% macro generate_forums(forums_data, level=0) %}
-    {% set panel_type = "main" if level==0 else "sub" %}
-    <ul class="forum forum__panel_{{panel_type}}">
-    {% for forum in forums_data %}
-        <li class="forum forum__cat_{{panel_type}} forum__level_{{level}}">
-            {% if 'http_url' in forum %}
-                <a href="{{forum['http_url']}}" class="forum_active">
-            {% else %}
-                <a>
-            {% endif %}
-                <span class="forum_title">{{ forum.title }}</span>
-                {% if 'short-desc' in forum %}
-                    <p class="forum_short-desc">{{ forum['short-desc'] }}</p>
-                {% endif %}
-            </a>
-
-            {% if 'sub-forums' in forum %}
-                {{ generate_forums(forum['sub-forums'], level=level+1) }}
-            {% endif %}
-        </li>
-    {% endfor %}
-    </ul>
-{% endmacro %}
-
-{% block body %}
-{% if not forums %}
-    <p class="message--info">{% trans %}No forums found on this server!{% endtrans %}</p>
-{% else %}
-    <div class="forums">
-        {{ generate_forums(forums) }}
-    </div>
-{% endif %}
-{% endblock body %}
--- a/sat_templates/default/forum/view.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% set dates_format='relative' if single else 'short' %}
-{% import 'blog/macros.html' as blog with context %}
-{% import 'input/textbox.html' as textbox with context %}
-
-{% block body %}
-
-<div id="blog_items">
-    {{ blog.show_items(items, expanded=true) }}
-</div>
-<div class="forum_topic_answer">
-    {{- textbox.comment_or_login(service=service, node=node, placeholder=_("Enter your message here")) -}}
-</div>
-<nav class="prev_next_links">
-    <ul>
-        {% if newer_url is defined %}
-            <li class="newer_items">
-                <a href="{{newer_url}}">
-                    <img src="{{media_path}}icons/tango/actions/32/go-previous.png">
-                    {% trans %}newer messages{% endtrans %}
-                </a>
-            </li>
-        {% endif %}
-        {% if older_url is defined %}
-            <li class="older_items">
-                <a href="{{older_url}}">
-                    <img src="{{media_path}}icons/tango/actions/32/go-next.png">
-                    {% trans %}older messages{% endtrans %}
-                </a>
-            </li>
-        {% endif %}
-    </ul>
-</nav>
-{% endblock body %}
--- a/sat_templates/default/forum/view_topics.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% import 'input/field.html' as field with context%}
-{% import 'input/textbox.html' as textbox with context %}
-{% import 'input/navigation.html' as navigation with context %}
-{% import 'components/avatar.html' as avatar with context %}
-
-{% block body %}
-
-    {% if not topics %}
-        <div class="message--info">
-            {% trans %}There is not message yet in this forum.{% endtrans %}
-            {% if profile %}
-                {% trans %}You can start a topic of interest by filling this form.{% endtrans %}
-            {% else %}
-                {% trans %}You can login to create a new topic.{% endtrans %}
-            {% endif %}
-        </div>
-    {% endif %}
-    {% if profile %}
-        <div class="forum__topic_create">
-            {% call textbox.textbox(service, node, placeholder=_("Your message"), submit_label=_("Create topic"), type="new_topic") %}
-                {{ field.text("title", placeholder=_("Your topic (try to be short and explicit)"), required=True) }}
-            {% endcall %}
-        </div>
-    {% endif %}
-
-    <div class="forum__topics">
-        {% for topic in topics %}
-            <div>
-                <a href="{{topic.http_uri}}">
-                    {{ avatar.avatar(topic.author) }}
-                    {{topic.title}}
-                </a>
-            </div>
-        {% endfor %}
-    </div>
-
-    {{ navigation.prev_next(_("older topics"), _("newer topics")) }}
-{% endblock body %}
--- a/sat_templates/default/input/field.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-{# macros to create form fields #}
-
-{% macro field(type, name, label="", required=false) %}
-    {# generic field
-       "class" keyword can be used to add classes
-       additional kwargs will be passed as attributes #}
-    <span class="form_input {{kwargs.pop('class', '')}}">
-        {% set cur_id = name|next_gidx %}
-        {% if label %}
-            <label for="{{cur_id}}" {{'class="required"'|safe if required}}>{{label}}</label>
-        {% endif %}
-        <input id="{{cur_id}}" type="{{type}}" name="{{name}}" {{"required" if required}} {{kwargs|xmlattr}}>
-    </span>
-{% endmacro %}
-
-{% macro choices(name, choices_list, checked=none) %}
-    {% for choice, label in choices_list %}
-        <div class="form_input {{kwargs.pop('class', '')}}">
-            <input id="{{name|next_gidx}}" type="radio" name="{{name}}" value="{{choice}}"{{" checked" if checked==choice}}><label for="{{name|cur_gidx}}">{{label}}</label>
-        </div>
-    {% endfor %}
-{% endmacro %}
-
-{% macro int(name, label="", init=0) %}
-    {{ field("number", name=name, label=label, value=init, step=1, min=0, **kwargs) }}
-{% endmacro %}
-
-{% macro checkbox(name, label="", checked=false) %}
-    {% if checked %}
-        {{ field("checkbox", name=name, label=label, checked="checked", **kwargs) }}
-    {% else %}
-        {{ field("checkbox", name=name, label=label, **kwargs) }}
-    {% endif %}
-{% endmacro %}
-
-{% macro text(name, label="", placeholder="", required=false) %}
-    {{ field("text", name=name, label=label, required=required, placeholder=placeholder, **kwargs) }}
-{% endmacro %}
-
-{% macro password(name, label="", required=false) %}
-    {{ field("password", name=name, label=label, required=required, **kwargs) }}
-{% endmacro %}
-
-{% macro email(name, label="", required=false) %}
-    {{ field("email", name=name, label=label, required=required, **kwargs) }}
-{% endmacro %}
-
-{% macro date(name, label="", required=false) %}
-    {{ field("date", name=name, label=label, required=required, **kwargs) }}
-{% endmacro %}
-
-{% macro url(name, label="", required=false) %}
-    {{ field("url", name=name, label=label, required=required, **kwargs) }}
-{% endmacro %}
-
-{% macro file(name, label="", required=false) %}
-    {{ field("file", name=name, label=label, required=required, **kwargs) }}
-{% endmacro %}
-
-{% macro textarea(name, label="", rows=10, cols=50, placeholder='', required=false) %}
-    <div class="form_input {{kwargs.pop('class', '')}}">
-        {% set cur_id = name|next_gidx %}
-        {% if label %}
-            <label for="{{cur_id}}" {{'class="required"'|safe if required}}>{{label}}</label>
-        {% endif %}
-        <textarea id="{{cur_id}}" name="{{name}}" rows="{{rows}}" cols="{{cols}}" placeholder="{{placeholder}}" {{"required" if required}} class="{{kwargs.pop('class', '')}}"></textarea>
-    </div>
-{% endmacro %}
-
-{% macro meta(name, value) %}
-    <input type="hidden" name="{{name}}" value="{{value}}">
-{% endmacro %}
-
-{% macro submit(text=_("Send")) %}
-    <input class="form_submit button" type="submit" value="{{text}}" class="{{kwargs.pop('class', '')}}">
-{% endmacro %}
--- a/sat_templates/default/input/form.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-{% macro form(action='', class='') %}
-<form method="post" action="{{action}}" {{ {'class': class}|xmlattr }} {{kwargs|xmlattr}} >
-    {% if csrf_token is defined %}
-        <input type="hidden" name="csrf_token" value="{{csrf_token}}">
-    {% endif %}
-    {{ caller() }}
-</form>
-{% endmacro %}
--- a/sat_templates/default/input/navigation.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-{% macro prev_next(prev_label=_("newer"), next_label=_("older")) %}
-    <nav class="prev_next_links">
-        <ul>
-            {% if newer_url is defined %}
-                <li class="newer_items">
-                    <a href="{{newer_url}}">
-                        <img src="{{media_path}}icons/tango/actions/32/go-previous.png">
-                        {{prev_label}}
-                    </a>
-                </li>
-            {% endif %}
-            {% if older_url is defined %}
-                <li class="older_items">
-                    <a href="{{older_url}}">
-                        <img src="{{media_path}}icons/tango/actions/32/go-next.png">
-                        {{next_label}}
-                    </a>
-                </li>
-            {% endif %}
-        </ul>
-    </nav>
-{% endmacro %}
--- a/sat_templates/default/input/textbox.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% macro head(service, node, type="textbox") %}
-    {# include data needed to identify the node to use for commenting #}
-    <input type="hidden" name="type" value="{{type}}">
-    <input type="hidden" name="service" value="{{service}}">
-    <input type="hidden" name="node" value="{{node}}">
-{% endmacro %}
-
-{% macro submit(label=_("Send")) %}
-    <input type="submit" value="{{label}}">
-{% endmacro %}
-
-{% macro textbox(service, node, action='', placeholder='',
-                 submit_label=_("Send"), type="textbox",
-                 class='', ta_class='') %}
-    {# generic content area for comments/blog posts/etc.
-       Only a body by default, but new elements can be
-       added by using this macro with call #}
-    {% set extra_content = caller() if caller is defined else '' %}
-    {% call form.form(action=action, class="textbox " + class) %}
-        {{ head(service, node, type) }}
-        {{ extra_content }}
-        {{ field.textarea("body", placeholder=placeholder, required=True,
-                          class=ta_class) }}
-        {{ submit(label=submit_label) }}
-    {% endcall %}
-{% endmacro %}
-
-{% macro blog_text(service, node, action='', placeholder=_("Your comment")) %}
-    {{ textbox(service, node, action=action, placeholder=placeholder, type="comment") }}
-{% endmacro %}
-
-{% macro comment(service, node, action='', placeholder=_("Your comment"), class='box--medium') %}
-    {{ textbox(service, node, action=action, placeholder=placeholder, type="comment", class=class) }}
-{% endmacro %}
-
-{% macro comment_or_login(service, node, action='', placeholder=none) %}
-    {# show comment form a a message asking to log in
-       login is checked using profile #}
-    {% if profile %}
-        {% if placeholder is none %}
-            {{ comment(service, node, action) }}
-        {% else %}
-            {{ comment(service, node, action, placeholder=placeholder) }}
-        {% endif %}
-    {% else %}
-        <div class="log_request">
-        <p class="not_logged">{% trans %}You are not logged. You need to log in to comment.{% endtrans %}</p>
-        {% if login_url is defined %}
-            <p class="log_in_url">
-                {% trans link_start=('<a href="',login_url,'">')|join|safe, link_end='</a>'|safe %}
-                    To log in {{link_start}}follow this link{{link_end}}
-                {% endtrans %}
-            </p>
-        {% endif %}
-        </div>
-    {% endif %}
-{% endmacro %}
--- a/sat_templates/default/input/xmlui.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,237 +0,0 @@
-{% import 'input/field.html' as field %}
-
-{# generate methods #}
-
-{% macro generate_container(cont, config) %}
-    {% if cont.type == 'vertical' %}
-        {{ vertical_container(cont, config) }}
-    {% elif cont.type == 'pairs' %}
-        {{ pairs_container(cont, config) }}
-    {% elif cont.type == 'label' %}
-        {{ label_container(cont, config) }}
-    {% endif %}
-{% endmacro %}
-
-{% macro generate_widget(wid, config, id=none) %}
-    {% if wid.type == 'text' %}
-        {{ text_widget(wid, config, id=id) }}
-    {% elif wid.type == 'label' %}
-        {{ label_widget(wid, config) }}
-    {% elif wid.type == 'string' %}
-        {{ string_widget(wid, config, id=id) }}
-    {% elif wid.type == 'jid' %}
-        {# TODO: proper JID widget #}
-        {{ string_widget(wid, config, id=id) }}
-    {% elif wid.type == 'textbox' %}
-        {{ textbox_widget(wid, config, id=id) }}
-    {% elif wid.type == 'list' %}
-        {{ list_widget(wid, config, id=id) }}
-    {% endif %}
-{% endmacro %}
-
-{% macro generate_children(cont, config) %}
-    {% for child in cont.children %}
-        {% if child.category == 'container' %}
-            {{ generate_container(child, config) }}
-        {% else %}
-            {{ generate_widget(child, config) }}
-        {% endif %}
-    {% endfor %}
-
-{% endmacro %}
-
-{% macro generate(xmlui, form=true, filters=none, attributes=none) %}
-{# generate HTML from XMLUI
-    @param xmlui(template_xmlui.XMLUIPanel): xmlui to use
-    @param form(bool): if true will generate form elements
-    @param filters(dict,none): filters as expected by item_filter
-    @param attributes(dict,none): extra attributes to put on named widgets
-#}
-    {% set config = {'form':form, 'filters':filters or {}, 'attrs': attributes or {}} %}
-    {{ generate_container(xmlui.main_cont, config) }}
-{% endmacro %}
-
-{% macro generate_table(xmlui_items, fields, formatters, tr_class_fields, on_click) %}
-{# generate a HTML table from requested widgets names
-    @param xmlui_items(iterable[unicode]): list of xmlui to show (one per row)
-    @param fields(tuple[unicode,unicode]): fields to show (name, label)
-    @param formatters(dict): dictionary of templates to format values:
-        field_name => template
-        if no formatter is set (or None is used) for a field, it will be used unmodified.
-        current xmlui items will be set as "item" key
-    @param tr_class_fields(iterable[unicode]): name of fields to use as class
-        class will be "{name}_{value}" where name is field name, and value field value
-        all lowercase/stripped
-    @param on_click(data_objects.OnClick): thing to do when clicking on a row
-#}
-    {% if formatters is undefined %}
-        {% set formatters = {} %}
-    {% endif %}
-    {% if on_click is undefined %}
-        {% set on_click = {} %}
-    {% endif %}
-    <table>
-        <thead>
-            <tr>
-                {% for name,label in fields %}
-                    <th>{{ label }}</th>
-                {% endfor %}
-            </tr>
-        </thead>
-        <tbody>
-            {% for xmlui in xmlui_items %}
-                {% set link=on_click.formatUrl(item=xmlui.widget_value) if on_click.url else none %}
-                <tr {{ {'class': xmlui|xmlui_class(tr_class_fields)}|xmlattr }}>
-
-                    {% for name,label in fields %}
-                        <td {{ {'class': 'td_'+name}|xmlattr }}>
-                            {% for value in xmlui.widgets[name].values %}
-                                <a {{ {'href':link}|xmlattr }}>{{ value|adv_format(formatters.get(name),item=xmlui.widget_value) }}</a>
-                            {% endfor %}
-                        </td>
-                    {% endfor %}
-                </tr>
-            {% endfor %}
-        </tbody>
-    </table>
-{% endmacro %}
-
-
-
-
-{% macro generate_list(xmlui_items, fields, formatters, item_class_fields, on_click) %}
-{# generate a list of rendered XMLUI from requested widgets names
-    very similar to generate_table but generate a list instead of a tabme
-    @param xmlui_items(iterable[unicode]): list of xmlui to show
-    @param fields(tuple[unicode,unicode]): fields to show (name, label)
-    @param formatters(dict): dictionary of templates to format values:
-        field_name => template
-        if no formatter is set (or None is used) for a field, it will be used unmodified.
-        current xmlui items will be set as "item" key for the template
-    @param item_class_fields(iterable[unicode]): name of fields to use as class
-        class will be "{name}_{value}" where name is field name, and value field value
-        all lowercase/stripped
-    @param on_click(data_objects.OnClick): thing to do when clicking on a row
-#}
-    {% if formatters is undefined %}
-        {% set formatters = {} %}
-    {% endif %}
-    {% if on_click is undefined %}
-        {% set on_click = {} %}
-    {% endif %}
-    <ul class="xmlui_list">
-        {% for xmlui in xmlui_items %}
-            <li>
-            {% set link=on_click.formatUrl(item=xmlui.widget_value) if on_click.url else none %}
-                <a {{ {'class': xmlui|xmlui_class(item_class_fields),
-                        'href':link}|xmlattr }}>
-                    {% for name,label in fields %}
-                        <span {{ {'class': 'xmlui_field__'+name}|xmlattr }}>
-                            {% for label in xmlui.widgets.get(name, {}).labels %}
-                                <span>{{ label|adv_format(formatters.get(name),item=xmlui.widget_value) }}</span>
-                            {% endfor %}
-                        </span>
-                    {% endfor %}
-                </a>
-            </li>
-        {% endfor %}
-    </ul>
-{% endmacro %}
-
-
-
-
-
-{# containers #}
-
-{% macro vertical_container(cont, config) %}
-    <div class="xmlui_cont xmlui_cont_vertical">
-        {{ generate_children(cont, config) }}
-    </div>
-{% endmacro %}
-
-{% macro pairs_container(cont, config) %}
-    {# TODO: proper impelmentation (do the same as vertical container for now #}
-    <div class="xmlui_cont xmlui_cont_vertical">
-        {{ generate_children(cont, config) }}
-    </div>
-{% endmacro %}
-
-{% macro label_container(cont, config) %}
-    <div class="xmlui_cont xmlui_cont_vertical">
-        {% for child in cont.children %}
-            {% if loop.index is odd %}
-                {# label #}
-                {% if child.type == 'label' %}
-                    {% set for_ = ('wid_' + (child.for_name or child.name or '_noname'))|next_gidx %}
-                    {{ label_widget(child, config, for=for_) }}
-                {% endif %}
-            {% else %}
-                {# widget #}
-                {% set id = ('wid_' + (child.name or '_noname'))|cur_gidx %}
-                {{ generate_widget(child, config, id=id) }}
-            {% endif %}
-        {% endfor %}
-    </div>
-{% endmacro %}
-
-
-{# widgets #}
-
-{% macro text_widget(wid, config, id=none) %}
-    <p class="xmlui_widget xmlui_text" {{ {'id':id}|xmlattr }}>
-        {{- wid|item_filter(config.filters)|default('\u00A0',true) -}}
-    </p>
-{% endmacro%}
-
-{% macro label_widget(wid, config, for=none) %}
-    {% if config.form %}
-        <label class="xmlui_widget xmlui_label" {{ {'for':for}|xmlattr }}>
-            {{wid|item_filter(config.filters)}}
-        </label>
-    {% else %}
-        <span class="xmlui_widget xmlui_label" {{ {'id':none if not for else 'label_%s'|format(for)}|xmlattr }}>{{wid|item_filter(config.filters)}}</span>
-    {% endif %}
-{% endmacro%}
-
-{% macro string_widget(wid, config, id=none) %}
-    {% if config.form %}
-        <input class="xmlui_widget xmlui_string" type="text" {{ {'name':wid.name, 'id':id, 'value':wid|item_filter(config.filters)}|dict_ext(config.attrs, wid.name)|xmlattr }}>
-    {% else %}
-        <div class="xmlui_widget xmlui_string"  {{ {'id':id}|xmlattr }}>
-            {{- wid|item_filter(config.filters)|default('\u00A0',true) -}}
-        </div>
-    {% endif %}
-{% endmacro%}
-
-{% macro textbox_widget(wid, config, id=none) %}
-    {% if config.form %}
-        <textarea class="xmlui_widget xmlui_textbox" rows="10" cols="50" {{ {'name':wid.name, 'id':id}|dict_ext(config.attrs, wid.name)|xmlattr }}>
-            {{- wid|item_filter(config.filters) -}}
-        </textarea>
-    {% else %}
-        <p class="xmlui_widget xmlui_textbox" {{ {'id':id}|xmlattr }}>
-            {{- wid|item_filter(config.filters) -}}
-        </p>
-    {% endif %}
-{% endmacro%}
-
-{% macro list_widget(wid, config, id=none) %}
-    {% if config.form %}
-        <select class="xmlui_widget xmlui_list" {{ {'name':wid.name, 'id':id}|dict_ext(config.attrs, wid.name)|xmlattr }}>
-            {% for value,label in wid.options %}
-                <option {{ {'value':value}|xmlattr }} {{ 'selected' if value in wid.selected }}>
-                    {{- label -}}
-                </option>
-            {% endfor %}
-        </select>
-    {% else %}
-        <div class="xmlui_widget xmlui_list" {{ {'id':id}|xmlattr }}>
-            {% for value,label in wid.items %}
-                <span class="xmlui_list_item value_{{value|attr_escape}}">
-                    {{- label -}}
-                </span>
-            {% endfor %}
-        </div>
-    {% endif %}
-{% endmacro%}
--- a/sat_templates/default/invitation/welcome.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-{% extends 'base/base.html' %}
-
-{% block body %}
-<div class='invitation_header'>
-    <h1>{% trans %}Welcome {{name}}{% endtrans %}</h1>
-    <p class='instructions'>{% trans %}You have been invited to participate with the community, please choose an action below{% endtrans %}</p>
-</div>
-
-{% if include_url is defined %}
-<iframe id='include_main' src='{{include_url}}'></iframe>
-{% endif %}
-
-{% endblock body %}
--- a/sat_templates/default/login/logged.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-{% set post_confirm_message=_("You have been logged correctly") %}
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% block title %}{{C.APP_NAME}}{% endblock %}
-
-{% block confirm_message %}
-    {% trans %}You have been logged correctly{% endtrans %}
-{% endblock confirm_message %}
-
-{% block body %}
-<div id='logged'>
-    <div class='logged_box box'>
-        {% if guest_session %}
-            <p>{% trans %}You are logged as a guest{% endtrans %}</p>
-        {% else %}
-            <p>{% trans name='<span class="logged_profile">'|safe + profile + '</span>'|safe %}You are logged under the account {{name}} {% endtrans %}</p>
-        {% endif %}
-        <p>{% trans session_started='<span class="logged_time">'|safe + session_started|date_fmt('relative') + '</span>'|safe %}You logged {{session_started}}{% endtrans %}</p>
-    </div>
-    {% call form.form() %}
-        {{ field.meta('type', 'disconnect') }}
-        {{ field.submit(_("Disconnect")) }}
-    {% endcall %}
-</div>
-{% endblock body %}
--- a/sat_templates/default/login/login.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% block title %}{{C.APP_NAME}} login{% endblock %}
-
-{% block body %}
-<div id="login_container">
-<div id="login_box">
-    <div id="login_left">
-        <img src="{{media_path}}libervia/register_left.png">
-    </div>
-    <div id="login_right">
-        {% block login_right_top %}{% endblock %}
-        {% if login_error is defined %}
-            {# error messages displayed in case of failing attempt to login #}
-            <div id="login_error">
-                <p>
-                {% block login_error_message %}
-                {% if login_error == S_C.PROFILE_AUTH_ERROR %}
-                    {%- trans %}Your login and/or password is incorrect. Please try again.{% endtrans -%}
-                {% elif login_error == S_C.XMPP_AUTH_ERROR %}
-                    {%- trans %}Your XMPP account failed to connect. Did you enter the good password? If you have changed your XMPP password since your last connection on Libervia, please use another SàT frontend to update your profile.{% endtrans -%}
-                {% elif login_error == S_C.NO_REPLY %}
-                    {%- trans %}Did not received a reply (the timeout expired or the connection is broken).{% endtrans -%}
-                {% else %}
-                    {%- trans %}An unknown error occurred, please contact your service administrator.{% endtrans -%}
-                {% endif %}
-                {% endblock login_error_message %}
-                </p>
-            </div>
-        {% endif %}
-
-        <div id="login_form">
-            {% block login_form %}
-            {% call form.form() %}
-                {{ field.meta('type', 'login') }}
-                {{ field.text("login", _("Login"),
-                              required=true,
-                              value=login,
-                              )}}
-                {{ field.password("password", _("Password"), required=not empty_password_allowed) }}
-                {{ field.submit(_("Log in")) }}
-            {% endcall %}
-            {% endblock login_form %}
-        </div>
-        {% block login_right_bottom %}
-        {% if register_url is defined %}
-            <div id="create_account_link">
-                <p>
-                    <a href="{{register_url}}">{% trans %}No account yet? Create a new one!{% endtrans %}</a>
-                </p>
-            </div>
-        {% endif %}
-        {% endblock login_right_bottom %}
-    </div>
-</div>
-</div>
-{% endblock body %}
--- a/sat_templates/default/login/register.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-{% extends 'login/login.html' %}
-
-{% block title %}{{C.APP_NAME}} register new account{% endblock %}
-
-{% block login_error_message %}
-{% if login_error == S_C.ALREADY_EXISTS %}
-    {%- trans %}This login already exists, please choose another one.{% endtrans -%}
-{% elif login_error == S_C.INVALID_INPUT %}
-    {%- trans %}The data you entered are nod valid.{% endtrans -%}
-{% elif login_error == S_C.BAD_REQUEST %}
-    {%- trans %}Bad request, please contact your service administrator{% endtrans -%}
-{% else %}
-    {%- trans %}An unknown error occurred, please contact your service administrator.{% endtrans -%}
-{% endif %}
-{% endblock login_error_message %}
-
-{% block login_right_top %}
-{% if login_url is defined %}
-    <div id="login_link">
-        <a href="{{login_url}}">
-            {%- trans %}Go to login page{% endtrans -%}
-        </a>
-    </div>
-{% endif %}
-{% endblock login_right_top %}
-
-{% block login_form %}
-{% call form.form(class='register') %}
-    {{ field.meta('type', 'register') }}
-    {{ field.text("login", _("Login"),
-                  required=true,
-                  pattern=S_C.REG_LOGIN_RE,
-                  title=_("Login must be lower case, with only plain letters (a-z), numbers (0-9) or underscore(_)"),
-                  value=login,
-                  )}}
-    {{ field.email("email", _("Email"),
-                   required=true,
-                   value=email,
-                   )}}
-    {{ field.password("password", _("Password"),
-                      required=true,
-                      minlength=S_C.PASSWORD_MIN_LENGTH,
-                      value=password,
-                      )}}
-    {{ field.submit(_("Register new account")) }}
-{% endcall %}
-{% endblock login_form %}
-
-{% block login_right_bottom %}{% endblock %}
--- a/sat_templates/default/merge-request/create.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-{# creata a new ticket #}
-
-{% set category_menu = [('merge-requests', url_tickets_list)] %}
-{% extends 'base/base.html' %}
-{% block body %}
-<div class="box message--info">
-    <p>{% trans %}It is not yet possible to create a merge request from inside Libervia, please use <pre>jp merge-request set</pre> for now. Merge requests welcome ;){% endtrans %}</p>
-</div>
-{% endblock body %}
--- a/sat_templates/default/merge-request/discover.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-{% extends 'base/base.html' %}
-{% import 'components/block.html' as block with context %}
-{% import 'components/images.html' as images with context %}
-{% import 'components/avatar.html' as avatar with context %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% block body %}
-{{ icon_defs('merge') }}
-<p class="instructions--head">
-    {% trans %}
-    Please select a merge-requests handler
-    {% endtrans %}
-</p>
-{% if mr_handlers is defined %}
-    <div class="disco_tickets">
-        {{block.disco_icon_grid(mr_handlers, 'merge')}}
-    </div>
-{% endif %}
-
-{% call form.form(class="form--single") %}
-    {{ field.text("jid", _("handler jid"), required=true)}}
-    {{ field.submit(_("Access")) }}
-{% endcall %}
-{% endblock body %}
--- a/sat_templates/default/merge-request/edit.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-{# edit an existing ticket #}
-
-{% set category_menu = [('merge-requests', url_tickets_list),
-                        ('merge-request_new', url_tickets_new)] %}
-{% extends 'base/base.html' %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-{% import 'input/xmlui.html' as xmlui with context %}
-
-{% block body %}
-<div class='instructions'>
-    <p><span class="box">{% trans app_name=C.APP_NAME%}Note: to modify content of the merge request, you'll have to use command line (with jp){% endtrans %}</span></p>
-</div>
-<div class="create single ticket box">
-{% call form.form() %}
-    {{ xmlui.generate(new_ticket_xmlui,
-                      attributes = {'title': {'required': 'required',
-                                              'placeholder': _("Short description of your issue/request")},
-                                    'body': {'required': 'required',
-                                             'placeholder': _("Please describe your issue/request with as much details as possible")},
-                                    'labels': {'placeholder': _("You can enter one or several labels separated by commas")},
-                                    })}}
-    {{ field.submit(_("Modify ticket")) }}
-{% endcall %}
-</div>
-{% endblock body %}
--- a/sat_templates/default/merge-request/item.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-{# display a single ticket
-
-    @variable item(xmlui_item): ticket to display
-    @variable comments(data_object.BlogItems): comments of the ticket
-    @variable comments_service(unicode): service for adding comments
-    @variable comments_node(unicode): node for adding comments
-#}
-
-{% set category_menu = [('merge-requests', url_tickets_list),
-                        ('merge-request_new', url_tickets_new)] %}
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% import 'input/xmlui.html' as xmlui with context %}
-{% import 'blog/macros.html' as blog with context %}
-{% import 'input/textbox.html' as textbox with context %}
-
-{% block title %}{{item|adv_format('[{value.widget_value.id}] {value.widget_value.title}') }}{% endblock %}
-
-{% block confirm_message %}
-    {% trans %}Your comment has been sent{% endtrans %}
-{% endblock confirm_message %}
-
-{% block body %}
-{{ icon_defs('pencil') }}
-<div class="tab_container">
-    <div class="tab_header">
-        <ul>
-            <li class="tab_button clicked" onclick='toggle_clicked_class_sel(".tab_button,.tab_page")'>{% trans %}Description{% endtrans %}</li>
-            <li class="tab_button" onclick='toggle_clicked_class_sel(".tab_button,.tab_page")'>{% trans %}Patches{% endtrans %}</li>
-        </ul>
-    </div>
-    <div class="tab_page clicked" id="tab_description">
-        <div id="{{ item.widget_value['id'] }}" class="view single ticket box">
-            {% if url_ticket_edit is defined %}
-                <p class="box__tools">
-                    <a href="{{url_ticket_edit}}">
-                    {{ icon('pencil', cls='icon--small') }}
-                    edit
-                    </a>
-                </p>
-            {% endif %}
-            {{ xmlui.generate(item,
-                form=false,
-                filters={'created': {'filters': ['date_fmt'], 'filters_args':[{'fmt': 'short'}]},
-                         'updated': {'filters': ['date_fmt'], 'filters_args':[{'fmt': 'short'}]},
-                         'body': {'filters': ['urlize'], 'filters_args':[{'nofollow': True, 'rel': 'noopener noreferrer'}]}},
-                )}}
-        </div>
-        {% if comments is defined %}
-        <div id="blog_items">
-            {{ blog.show_items(comments|reverse, expanded=true) }}
-        </div>
-        {% endif %}
-        {% if comments_node is defined %}
-            <div class="comment_post">
-                {{- textbox.comment_or_login(service=comments_service, node=comments_node) -}}
-            </div>
-        {% endif %}
-    </div>
-    <div class="tab_page" id="tab_patches">
-        {% for patch in patches %}
-            <div class="patch">
-                <header class="box">
-                    <div class="author"><label>{% trans %}author:{% endtrans %} </label>{{patch.author}}</div>
-                    <p class="commit_msg">{{patch.commit_msg}}</p>
-                </header>
-                <div class="diff">
-                    {{- patch.diff|highlight('diff') -}}
-                </div>
-            </div>
-        {% endfor %}
-    </div>
-</div>
-{% endblock body %}
--- a/sat_templates/default/photo/album.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-{% extends 'base/base.html' %}
-{% import 'input/textbox.html' as textbox with context %}
-{% import 'blog/macros.html' as blog with context %}
-
-{% block body %}
-{{ icon_defs('comment-empty') }}
-<div class="album">
-    {% for file in files_data %}
-        {% if file.type == C.FILE_TYPE_FILE %}
-            <div class="album__item">
-                <div class="album__vignette">
-                    <img src="{{file.thumb_url}}" class="album__thumbnail" alt="{{file.name}}">
-                </div>
-                {% if file.comments_url is defined %}
-                    <span class='album__comments-bar' onclick="clicked_mh_fix('{{'comments_panel'|next_gidx}}')">
-                        {% trans %}comments{% endtrans %}
-                        {% if file.comments_count %}
-                            <span class='comments__count'>({{file.comments_count}})</span>
-                        {% endif %}
-                        {{ icon('comment-empty', cls='icon--small') }}
-                    </span>
-                    <div id='{{'comments_panel'|cur_gidx}}' class="panel-drawer">
-                        {{ blog.show_items(file.comments, expanded=true, dates_fmt='relative') }}
-                        <div class="comment_post">
-                            {{- textbox.comment_or_login(service=file.comments_service, node=file.comments_node) -}}
-                        </div>
-                    </div>
-                {% endif %}
-            </div>
-        {% endif %}
-    {% endfor %}
-</div>
-{% endblock body %}
--- a/sat_templates/default/photo/discover.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-{% extends 'base/base.html' %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% block body %}
-<p class="instructions--alt">{% trans %}Photo discovery is not implemented yet, however you can enter a jid below to find its albums{% endtrans %}</p>
-{% call form.form(class="form--single") %}
-    {{ field.text("jid", _("device full jid"), required=true)}}
-    {{ field.submit(_("Access")) }}
-{% endcall %}
-{% endblock body %}
--- a/sat_templates/default/session/disconnect.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-{% extends 'base/base.html' %}
-
-{% block body %}
-<p>{% trans %}You have been disconnected, have a nice day!{% endtrans %}</p>
-{% endblock body %}
--- a/sat_templates/default/static/app.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#body {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-}
-
-#web_app_box {
-    width: 80%;
-    padding: 2em;
-    text-align: justify;
-}
-
-#link_section {
-    font-weight: bold;
-    text-align: center;
-    font-size: 1.5rem;
-}
-
-article p:last-child {
-    text-align: center;
-}
--- a/sat_templates/default/static/blog.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,313 +0,0 @@
-/*** articles ***/
-
-article.box {
-    position: relative;
-    margin: 2% auto;
-    border-style: solid none none;
-    border-width: 1px;
-    padding: 2%;
-    min-height: 9em;
-    max-height: 20em;
-    overflow: hidden;
-    transition: max-height 0.5s;
-}
-
-article video {
-    max-width: 100%;
-    height: auto;
-}
-
-.main_article article.box:not(.clicked) {
-    border-bottom-right-radius: 0;
-    border-bottom-left-radius: 0;
-}
-
-/** header **/
-
-header a {
-    color: inherit;
-    text-decoration: inherit;
-}
-
-header .metadata {
-    text-align: right;
-}
-
-article .author {
-    font-weight: bold;
-}
-
-article .author::after {
-    content: ", ";
-}
-
-/*** labels ***/
-
-.labels {
-    text-align: right;
-    white-space: nowrap;
-}
-
-.labels a {
-    text-decoration: none;
-    color: inherit;
-}
-
-.labels span {
-    font-variant: small-caps;
-    font-size: 0.8rem;
-    background-color: #ddd;
-    border-radius: 0.4em;
-    padding: 0 0.5em;
-    transition: all 0.5s;
-}
-
-.labels a>span {
-    cursor: pointer;
-}
-
-.labels a>span:hover {
-    box-shadow: 0px 0px 6px 1px #000;
-}
-
-
-/** content **/
-
-article div.content {
-    text-align: justify;
-    font-size: 0.9em;
-}
-
-article div.content.text {
-    white-space: pre-wrap;
-}
-
-
-article img {
-    max-width: 100%;
-    margin: 0;
-}
-
-/** reduce/expand buttons **/
-
-.expand_box {
-    cursor: pointer;
-}
-
-.box_top {
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 100%;
-}
-
-.box_bottom {
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    width: 100%;
-}
-
-.expand_box.box_bottom::before {
-    /* we do a gradient to show that text can be expanded */
-    background-image: linear-gradient(to bottom,rgba(0,0,0,0),#ffffff);
-    display: block;
-    content: "";
-    width: 100%;
-    height: 4em;
-    border: none;
-}
-
-.expand_box p {
-    background-color: white;
-    margin: 0;
-    text-align: center;
-    font-weight: bold;
-    font-size: 0.8em;
-    border-style: solid none dotted none;
-    border-width: 1px 0 1px;
-    border-bottom-color: gray;
-}
-
-article .expand_box .hide {
-    /* when not clicked, we only display .show */
-    display: none;
-}
-
-article .expand_box.box_top {
-    /* top expand box only show a reduce button
-     * so it should be displayed only when article is .clicked */
-    display: none;
-}
-
-/** other language **/
-
-/* we hide everything just to display a message informing that
- * the item is in an other language, and asking to click
- * to display it */
-
-article.other_lang>div.info {
-    display: none;
-}
-
-article.other_lang.init>* {
-    display: none;
-}
-
-article.other_lang.init>div.info {
-    display: initial;
-}
-
-article.other_lang.init>div.expand_box.box_top {
-    /* as we need to have the message clickable, we cheat and use
-     * expand box on the whole surface but fully transparent */
-    display: initial;
-    height: 100%;
-    opacity: 0;
-}
-
-article.other_lang.init>div.info>p {
-    margin: 0;
-    padding: 0.2em;
-    text-align: center;
-    font-style: italic;
-}
-
-article.other_lang.init {
-    border: none;
-    border-radius: 0;
-    padding: 0;
-    min-height: 0;
-}
-
-/*** comments ***/
-
-button.comments_btn {
-    border: none;
-    font-weight: bold;
-    display: block;
-    margin: 0 10% 0 auto;
-    border-radius: 1em;
-    background:  #b8bcc4;
-    color: #4d4d4d;
-}
-
-button.comments_btn:active {
-    background: #4d4d4d;
-    color: #b8bcc4;
-}
-
-button.comments_btn.clicked span.show {
-    display: none;
-}
-
-button.comments_btn:not(.clicked) span.hide {
-    display: none;
-}
-
-.comments_panel {
-    max-height: 0;
-    opacity: 0;
-    transition: max-height 1s, opacity 2s;
-    overflow: hidden;
-}
-
-.comments_panel.clicked {
-    opacity: 1;
-}
-
-.comments article {
-    background-color: #9ca0a8;
-    border: none;
-    max-height: none;
-}
-
-.comment_post {
-    text-align: center;
-}
-
-.comment_post textarea {
-    border-style: solid;
-    border-width: 1px  0;
-    border-color: black;
-    max-width: 100%;
-}
-
-.comments_panel article .expand_box {
-    /* no expand box in comments */
-    display: none;
-}
-
-/*** media queries ***/
-
-@media (min-width: 500px) {
-    /*** general ***/
-
-    #main_area {
-        background-image: var(--bg-img);
-        background-repeat: no-repeat;
-        background-size: cover;
-    }
-
-    article.box {
-        width: 80%;
-        border-style: solid solid none solid;
-    }
-    .comments article.box {
-        width: 30rem;
-        margin: 2% auto;
-        border: none;
-    }
-    .comment_post textarea {
-        border-width: 1px;
-        border-radius: 1em;
-        border: solid 1px;
-        padding: 0.5em;
-    }
-
-    footer span {
-        background: rgba(200,200,200,0.6);
-        border-radius: 0.5em 0.5em 0 0;
-        padding: 0 0.5em;
-        margin-top: 1em;
-    }
-
-}
-
-/*** clicked ***/
-
-.main_article article.clicked {
-    border-bottom-style: solid;
-}
-
-.main_article article.clicked .expand_box.box_top {
-    display: initial;
-}
-
-.main_article article.clicked .expand_box {
-    opacity: 0;
-    transition: opacity 0.5s;
-}
-
-.main_article article.clicked .expand_box p {
-    background-color: transparent;
-    border: none;
-}
-
-.main_article article.clicked .expand_box:hover {
-    opacity: 1;
-    color: grey;
-}
-
-.main_article article.clicked .expand_box::before {
-    background-image: none;
-    display: none;
-}
-
-.main_article article.clicked .expand_box .hide {
-    display: inline;
-}
-
-.main_article article.clicked .expand_box .show {
-    display: none;
-}
--- a/sat_templates/default/static/chat.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-:root {
-  --message_input-height: 2rem;
-}
-
-#main_area {
-    overflow: hidden;
-}
-
-.chat_widget {
-	position: absolute;
-    height: 100%;
-    width: 100%;
-    box-sizing: border-box;
-    display: flex;
-    flex-direction: column;
-}
-
-#messages {
-    height: 100%;
-    min-height: 150px;
-    overflow: auto;
-    box-sizing: border-box;
-    resize: vertical;
-    transition: height 0.6s;
-}
-
-#subject {
-	padding: 1em;
-	text-align: center;
-	background: #eee;
-	font-style: italic;
-}
-
-#messages > p {
-    margin: 0;
-    padding: 0.5em 0 0 0.5em;
-}
-
-#messages .msg_body {
-    white-space: pre-wrap;
-}
-
-#message_input {
-    width: 100%;
-    height: 100%;
-    padding-top: 0.5rem;
-    margin: 0;
-    box-sizing: border-box;
-    resize: none;
-}
-
-.message_box {
-    flex: 1 1 calc(var(--message_input-height));
-    position: relative;
-    min-height: 1rem;
-    box-sizing: border-box;
-}
-
-
-#messages > p.msg_info {
-    white-space: pre-wrap;
-    font-family: monospace;
-    color: #049282;
-}
-
-.msg_header {
-	display: block;
-	font-size: 0.9em;
-}
-
-.author {
-    font-weight: bold;
-}
-
-.date {
-	color: #777;
-}
-
-@media (min-width: 800px) {
-    #messages > p {
-        padding-left: 1.5em;
-    }
-}
--- a/sat_templates/default/static/chat.js	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/* SàT Template: Chat page handling
- *
- * Copyright (C) 2017 Jérôme Poisson (goffi@goffi.org)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-var msgInput = document.getElementById('message_input');
-var messages = document.getElementById('messages');
-const messagesTransitionOri = messages.style.transition;
-
-msgInput.addEventListener('keypress', function(event) {
-    if (event.which == 13 && !event.shiftKey) {
-        if (messages.style.height !== '100%') {
-            messages.style.transition = messagesTransitionOri;
-            setTimeout(function() {
-                messages.style.transition = 'initial';
-                messages.scrollTop = messages.scrollHeight;
-            }, 1000);
-            messages.style.height = "100%";
-        }
-        if (!this.value.trim()) {
-            return;
-        }
-        socket.send({'type': 'msg',
-                     'body': this.value});
-        this.value = '';
-        event.preventDefault();
-    }}
-);
-
-var mutationCb = function(mutationsList) {
-    scrollPos = messages.scrollTop + messages.clientHeight;
-    if (messages.lastChild.offsetTop - scrollPos - 10 <= 0) {
-        // we auto scroll only if we are at the bottom of the page
-        // else the use is probably checking history
-        // Note thas this doesn't take margin into account,
-        // we suppose margin to be 0 for messages children
-        messages.scrollTop = messages.scrollHeight;
-    }
-};
-
-var observer = new MutationObserver(mutationCb);
-
-observer.observe(messages, { childList: true });
-// we want to start with scrolling at bottom
-messages.scrollTop = messages.scrollHeight;
-messages.style.transition = 'initial';
--- a/sat_templates/default/static/chat_select.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-#main_area {
-    overflow: auto;
-}
-
-.rooms_list {
-	list-style: none;
-    display: grid;
-    text-align: center;
-    padding: 0;
-}
-
-.rooms_list a {
-	text-decoration: none;
-	color: inherit;
-	font-variant: small-caps;
-	font-weight: bold;
-}
-
-.rooms_list li {
-    margin-top: 1em;
-}
-
-.rooms_list li:first-child {
-    margin-top: 0;
-}
-
-.rooms_list li:hover {
-    background-color: #efefef;
-}
-
-@media (min-width: 600px) {
-    .rooms_list {
-        grid-template-columns: 1fr 1fr 1fr;
-    }
-
-    .rooms_list li {
-        margin-top: 0;
-    }
-}
--- a/sat_templates/default/static/common.js	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-var __session_storage_available;
-var __local_storage_available;
-
-function storageAvailable(type) {
-    /* check if session or local storage is available
-     *
-     * @param type(string): "session" or "storage"
-     * @return (boolean): true if requested storage is available
-     */
-    console.assert(type == 'session' || type == 'storage', "bad storage type (%s)", type);
-    const var_name = '__' + type + '_storage_available';
-    var available = window[var_name];
-    if (available === undefined) {
-        // test method from https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
-        var storage = window[type + 'Storage'];
-        try {
-            x = '__storage_test__';
-            storage.setItem(x, x);
-            storage.removeItem(x);
-            available = true;
-        }
-        catch(e) {
-            available = e instanceof DOMException && (
-                    // everything except Firefox
-                    e.code === 22 ||
-                    // Firefox
-                    e.code === 1014 ||
-                    // test name field too, because code might not be present
-                    // everything except Firefox
-                    e.name === 'QuotaExceededError' ||
-                    // Firefox
-                    e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
-                // acknowledge QuotaExceededError only if there's something already stored
-                storage.length !== 0;
-        }
-
-        if (!available) {
-            console.warn("%s storage not available", type);
-        }
-        window[var_name] = available;
-    }
-
-    return available;
-}
-
-function toggle_clicked_class_tag(tag_name, class_name='clicked') {
-    for (let elt of document.getElementsByTagName(tag_name)) {
-        elt.classList.toggle(class_name);
-    }
-}
-
-function toggle_clicked_class_sel(selectors, class_name='clicked') {
-    for (let elt of document.querySelectorAll(selectors)) {
-        elt.classList.toggle(class_name);
-    }
-}
-
-function set_clicked_class_id(trigger_elem_id, target_elem_id=null, class_name='clicked') {
-    if (target_elem_id === null) { target_elem_id = trigger_elem_id; }
-    document.getElementById(trigger_elem_id).addEventListener(
-        "click",
-        function() {
-            document.getElementById(target_elem_id).classList.toggle(class_name);
-        }
-    );
-}
-
-function get_elt(arg) {
-    if (typeof arg === 'string') {
-        // we should have an id
-        return document.getElementById(arg);
-    }
-    else {
-        // we should have an element
-        return arg;
-    }
-}
-
-function clicked_cls(elt) {
-    /* toggle "clicked" class on each click, and remove "init" class if present */
-    // init
-    if (elt.classList.contains("init")) {
-        elt.classList.remove("init");
-    }
-
-    // clicked
-    elt.classList.toggle("clicked");
-}
-
-function clicked_mh_fix(arg) {
-    /* toggle clicked, and fix max-height on transitionend
-     *
-     * needed to workaround transition issue with max-height:none
-     * inspired from https://css-tricks.com/using-css-transitions-auto-dimensions,
-     * thanks to Brandon Smith
-     *
-     * @param arg: element to toggle (id as string, or element itself)
-     * */
-    elt = get_elt(arg);
-
-    if (!elt.classList.contains("clicked")) {
-        /* expand */
-        var fix_expand = function(event) {
-            elt.removeEventListener("transitionend", fix_expand, false);
-            if (elt.classList.contains("clicked")) {
-                /* if event is clicked quicker than transition time,
-                 * this callback can be called on reduce */
-                elt.style.maxHeight = "none";
-            }
-        };
-
-        elt.setAttribute('max_height_init', elt.clientHeight);
-        elt.addEventListener("transitionend", fix_expand, false);
-        clicked_cls(elt);
-        elt.style.maxHeight = elt.scrollHeight + 'px';
-    }
-    else {
-        /* reduce */
-        var transition_save = elt.style.transition;
-        elt.style.transition = '';
-        requestAnimationFrame(function() {
-            elt.style.maxHeight = elt.scrollHeight + 'px';
-            elt.style.transition = transition_save;
-
-            requestAnimationFrame(function() {
-                elt.style.maxHeight = elt.getAttribute('max_height_init') + 'px';
-                elt.removeAttribute('max_height_init');
-                elt.style.maxHeight = null;
-            });
-        });
-
-        clicked_cls(elt);
-    }
-}
--- a/sat_templates/default/static/event.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-@import 'blog.css'; /* needed as blog/articles.html is included */
-
-.invitation_header {
-    text-align: center;
-    font-variant: small-caps;
-    border: none;
-}
-
-.instructions {
-    font-style: italic;
-    margin: 0;
-}
-
-.event__picture {
-    max-width: 100%;
-    border-radius: 2em;
-}
-
-.event__counter {
-    font-weight: bold;
-    font-size: 1.3em;
-    text-align: center;
-    width: 15em;
-    margin: 1em auto;
-    border: 2px solid #aab6c4;
-    background-color: #f3e7e7;
-    color: #2f3943;
-}
-
-.attendance {
-    background-color: #9ca0a8;
-    padding: 0 0.3em;
-    max-width: 580px;
-    margin: 0 auto;
-    color: #3A3A3A;
-}
-
-.attending {
-    width: 6em;
-    margin: 0 auto;
-}
-
-.attending label {
-    /* display: inline; */
-    margin: 0.8em 0;
-}
-
-.guests label {
-    display: block;
-    margin: 1em 0;
-}
-
-.guests input {
-    width: 2.5em;
-    margin: 0 1em;
-}
-
-.poll_instructions {
-    font-weight: bold;
-    font-size: 0.9em;
-    font-size: 1.1em;
-    text-align: center;
-}
-
-.guests label{
-    text-align: center;
-    /* font-style: italic */
-}
-
-.guests input {
-    display: block;
-    margin: 0 auto;
-}
-
-.submit {
-    width: 15em;
-    margin: 0 auto;
-    padding: 1em 0;
-}
-
-.submit input {
-    width: 100%;
-}
-
-@media (min-width: 500px) {
-    .invitation_header {
-        width: 94%;
-        margin: 0 auto;
-        border: solid 1px;
-        border-color: #9ca0a8;
-    }
-}
--- a/sat_templates/default/static/file.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-#files {
-    list-style: none;
-    display: flex;
-    flex-wrap: wrap;
-}
-
-.file {
-    padding: 0 0 0.5em;
-    width: 100px;
-    text-overflow: ellipsis;
-    overflow: hidden;
-    text-align: center;
-    overflow-wrap: break-word;
-}
-
-.file:hover {
-    background: #ddd;
-    overflow: visible;
-}
-
-.file a {
-    text-decoration: none;
-    outline: none;
-}
-
-.file a:focus img {
-    outline: 3px solid #bbb;
-}
-
-.file__icon {
-    height: 3em;
-    display: block;
-    margin: 0 auto;
-}
-
-.file__thumbnail {
-    max-width: 300px;
-    height: 125px;
-    display: block;
-    margin: 0 auto;
-}
-
-
-@media (min-width: 500px) {
-    .file {
-        padding: 1em;
-        width: 170px;
-    }
-}
--- a/sat_templates/default/static/fonts.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/* generated from https://google-webfonts-helper.herokuapp.com */
-
-/* *** sat_base_font *** */
-
-/* sat_base_font-regular - latin-ext_latin */
-@font-face {
-  font-family: 'sat-base-font';
-  font-style: normal;
-  font-weight: 400;
-  src: local('sat-base-font'), local('sat-base-font-Regular'),
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
-}
-
-/* sat_base_font-italic - latin-ext_latin */
-@font-face {
-  font-family: 'sat-base-font';
-  font-style: italic;
-  font-weight: 400;
-  src: local('sat-base-font Italic'), local('sat-base-font-Italic'),
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
-}
-
-/* sat_base_font-700 - latin-ext_latin */
-@font-face {
-  font-family: 'sat-base-font';
-  font-style: normal;
-  font-weight: 700;
-  src: local('sat-base-font Bold'), local('sat-base-font-Bold'),
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
-}
-
-/* sat_base_font-900 - latin-ext_latin */
-@font-face {
-  font-family: 'sat-base-font';
-  font-style: normal;
-  font-weight: 900;
-  src: local('sat-base-font Black'), local('sat-base-font-Black'),
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
-}
-
-/* sat_base_font-700italic - latin-ext_latin */
-@font-face {
-  font-family: 'sat-base-font';
-  font-style: italic;
-  font-weight: 700;
-  src: local('sat-base-font Bold Italic'), local('sat-base-font-BoldItalic'),
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
-}
-
-/* sat_base_font-900italic - latin-ext_latin */
-@font-face {
-  font-family: 'sat-base-font';
-  font-style: italic;
-  font-weight: 900;
-  src: local('sat-base-font Black Italic'), local('sat-base-font-BlackItalic'),
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
-       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
-}
--- a/sat_templates/default/static/fonts/sat_base_font/README.txt	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-This font is based on the Alegreya font by Juan Pablo del Peral (juan@huertatipografica.com.ar), it has been modified to be compressed using https://google-webfonts-helper.herokuapp.com, and put here for being embedded in Salut à Toi templates, to avoid privacy issues with third party website download.
-
-As the name is a reserved name and the compression make the font a derivative, this font has been renamed to "sat_base_font", according to the recommandation read at http://scripts.sil.org/cms/scripts/page.php?item_id=OFL-FAQ_web#1db14da7
-
-Thanks to Juan Pable del Peral for his work!
-
-The license "SIL Open Font License, Version 1.1" only apply to this directory.
--- a/sat_templates/default/static/fonts/sat_base_font/SIL Open Font License.txt	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-Copyright (c) 2011, Juan Pablo del Peral (juan@huertatipografica.com.ar), 
-with Reserved Font Names "Alegreya" "Alegreya SC"
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
-
-"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
-
-5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
\ No newline at end of file
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff2 has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff2 has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff2 has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff2 has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff2 has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff has changed
Binary file sat_templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff2 has changed
--- a/sat_templates/default/static/forum.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-@import 'blog.css'; /* needed as blog/articles.html is included */
-
-.forums {
-    margin: 2em auto 0 auto;
-    width: 90%;
-}
-
-ul.forum {
-    list-style: none;
-}
-
-ul.forum__panel_sub {
-    box-sizing: border-box;
-    display: flex;
-    flex-flow: row wrap;
-    margin: 0 auto;
-}
-
-.forum__cat_sub {
-    margin: 0.5em 1em;
-    width: 25em;
-}
-
-.forum__cat_sub>a {
-    border: 0.7rem solid #ddd;
-    border-radius: 0.5em;
-    display: block;
-    padding: 1rem;
-    margin-bottom: 1rem;
-    text-decoration: none;
-    color: inherit;
-}
-
-a.forum_active:hover {
-    background-color: #43d2f6;
-}
-
-p.forum_short-desc {
-    color: #666;
-    margin: 0;
-    font-size: 0.8em;
-}
-
-.forum__topics {
-    margin-top: 3em;
-}
-
-.forum__topics>div {
-    box-sizing: border-box;
-    width: 80%;
-    margin: 0.5em auto;
-    padding: 0.2em 2em;
-    background: #eee;
-
-}
-
-.forum__topics>:hover {
-    background-color: #43d2f6;
-}
-
-.forum__topics img.avatar {
-    vertical-align: middle;
-    margin-right: 1em;
-}
-
-.forum__topics a {
-    display: block;
-    text-decoration: none;
-    color: inherit;
-}
-
-.textbox input {
-    width: 100%;
-    box-sizing: border-box;
-}
-
-@media (min-width: 500px) {
-    .textbox input {
-        min-width: 26em;
-        width: auto;
-    }
-}
--- a/sat_templates/default/static/highlight.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-/* This file as been generated from Pygments using
- * f.write(HtmlFormatter().get_style_defs('.highlight'))
- * where f was an open file.
- * It is used in Libervia for highlighting code or markup
- * If changes are needed, they should be done in a separate CSS file
- * so this one keep Pygments' defaults
- */
-.highlight .hll { background-color: #ffffcc }
-.highlight  { background: #f8f8f8; }
-.highlight .c { color: #408080; font-style: italic } /* Comment */
-.highlight .err { border: 1px solid #FF0000 } /* Error */
-.highlight .k { color: #008000; font-weight: bold } /* Keyword */
-.highlight .o { color: #666666 } /* Operator */
-.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
-.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
-.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
-.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
-.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
-.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
-.highlight .gd { color: #A00000 } /* Generic.Deleted */
-.highlight .ge { font-style: italic } /* Generic.Emph */
-.highlight .gr { color: #FF0000 } /* Generic.Error */
-.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
-.highlight .gi { color: #00A000 } /* Generic.Inserted */
-.highlight .go { color: #888888 } /* Generic.Output */
-.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
-.highlight .gs { font-weight: bold } /* Generic.Strong */
-.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.highlight .gt { color: #0044DD } /* Generic.Traceback */
-.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
-.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
-.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
-.highlight .kp { color: #008000 } /* Keyword.Pseudo */
-.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
-.highlight .kt { color: #B00040 } /* Keyword.Type */
-.highlight .m { color: #666666 } /* Literal.Number */
-.highlight .s { color: #BA2121 } /* Literal.String */
-.highlight .na { color: #7D9029 } /* Name.Attribute */
-.highlight .nb { color: #008000 } /* Name.Builtin */
-.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
-.highlight .no { color: #880000 } /* Name.Constant */
-.highlight .nd { color: #AA22FF } /* Name.Decorator */
-.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
-.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
-.highlight .nf { color: #0000FF } /* Name.Function */
-.highlight .nl { color: #A0A000 } /* Name.Label */
-.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
-.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
-.highlight .nv { color: #19177C } /* Name.Variable */
-.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
-.highlight .w { color: #bbbbbb } /* Text.Whitespace */
-.highlight .mb { color: #666666 } /* Literal.Number.Bin */
-.highlight .mf { color: #666666 } /* Literal.Number.Float */
-.highlight .mh { color: #666666 } /* Literal.Number.Hex */
-.highlight .mi { color: #666666 } /* Literal.Number.Integer */
-.highlight .mo { color: #666666 } /* Literal.Number.Oct */
-.highlight .sa { color: #BA2121 } /* Literal.String.Affix */
-.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
-.highlight .sc { color: #BA2121 } /* Literal.String.Char */
-.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
-.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
-.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
-.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
-.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
-.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
-.highlight .sx { color: #008000 } /* Literal.String.Other */
-.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
-.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
-.highlight .ss { color: #19177C } /* Literal.String.Symbol */
-.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
-.highlight .fm { color: #0000FF } /* Name.Function.Magic */
-.highlight .vc { color: #19177C } /* Name.Variable.Class */
-.highlight .vg { color: #19177C } /* Name.Variable.Global */
-.highlight .vi { color: #19177C } /* Name.Variable.Instance */
-.highlight .vm { color: #19177C } /* Name.Variable.Magic */
-.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
-
--- a/sat_templates/default/static/invitation.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-#body {
-    display: flex;
-    flex-direction: column;
-}
-
-.invitation_header {
-    flex: 1
-}
-
-.invitation_header h1,p {
-    text-align: center;
-}
-
-#include_main {
-    flex: 9
-}
-
-#include_main {
-    width: 100%;
-    margin: 0;
-    border: none;
-}
-
-footer {
-    /* footer should already be displayed in included page */
-    display: none;
-}
--- a/sat_templates/default/static/login.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-body {
-    background: #111;
-}
-
-footer {
-    color: #999;
-}
-
-#login_container {
-    display: flex;
-    height: 100%;
-    align-items: center;
-    justify-content: center;
-}
-
-#login_box {
-    display: flex;
-    background: #111;
-    color: #aaa;
-    width: 600px;
-    margin: auto;
-}
-
-#login_left {
-    display: none;
-}
-
-#login_right {
-    width: 100%;
-    position: relative;
-}
-
-#login_form {
-    margin-top: 60px;
-}
-
-#login_form label {
-    font-weight: bold;
-    display: block;
-    text-align: center;
-}
-
-#login_form input:not(.form_submit) {
-    display: block;
-    margin: 0 auto;
-    height: 25px;
-    line-height: 25px;
-    width: 200px;
-    text-indent: 11px;
-    background: #000;
-    color: #ccc;
-    border: 1px solid #555;
-    border-radius: 15px 15px 15px 15px;
-}
-
-#login_form input:not(.form_submit):focus {
-	box-shadow: 0 0 2px 2px #43d2f6;
-}
-
-#login_form input:hover {
-    background-color: #222;
-}
-
-#login_form input:focus {
-	border: 1px solid #999;
-	outline: none;
-}
-
-#login_box .form_input {
-    display: block;
-    margin-bottom: 1em;
-}
-
-#login_form .form_submit,
-#logged .form_submit {
-    /* FIXME: as above /media is not good.
-     * url should be replaced by real gradient */
-    color: #fff;
-    background: #222 url('/media/libervia/gradient.png') repeat-x;
-    font-weight: bold;
-    line-height: 1;
-    text-shadow: 0 -1px 1px rgba(0,0,0,0.25);
-    padding: 7px 10px 8px;
-    border: 0;
-    border-radius: 6px 6px 6px 6px;
-    cursor: pointer;
-    margin-top: 30px;
-}
-
-#login_error {
-    position: absolute;
-    margin: -90px 0 0;
-    width: 100%;
-    height: 150px;
-    overflow: auto;
-    font-size: 0.9em;
-	font-weight: bold;
-	color: lightcoral;
-	text-align: center;
-}
-
-#login_error p {
-    position: absolute;
-    bottom: 0;
-    margin-left: 46px;
-    margin-right: 46px;
-}
-
-#create_account_link {
-    width: 100%;
-    margin-top: 3em;
-}
-
-#login_link {
-    margin-top: 1em;
-}
-
-#create_account_link a,
-#login_link a {
-    text-decoration: none;
-    text-align: center;
-    font-size: 0.8em;
-    cursor: pointer;
-    color: #fff;
-    display: block;
-    text-shadow: 1px 1px 0px rgba(255, 255, 255, 0.2);
-}
-
-.logged_box {
-    margin: 3em;
-	padding: 1em;
-	text-align: center;
-	font-style: italic;
-}
-
-.logged_profile {
-    font-style: normal;
-    font-weight: bold;
-}
-
-#login_form form.register input[type=submit] {
-    margin-top: 0.5em;
-}
-
-@media (min-width: 600px) {
-    body {
-        background: transparent;
-    }
-
-    footer {
-        color: black;
-    }
-
-    #login_left {
-        display: inline;
-    }
-
-    #login_right {
-        /* FIXME: there is not way to correctly select images from
-         * media path at the moment */
-        background: url('/media/libervia/register_right.png');
-    }
-
-    #login_error {
-        width: auto;
-        max-height: 50px;
-        margin: 10px 46px 0;
-    }
-     
-    #login_error p {
-        position: static;
-        margin: 0;
-    }
-
-    #login_form label {
-        text-align: initial;
-        position: relative;
-        left: 50px;
-    }
-
-    #login_form label::after {
-        content: ':'
-    }
-
-    #login_form input:not(.form_submit) {
-        display: inline;
-        margin: 0;
-        position: relative;
-        left: 50px;
-    }
-
-    #create_account_link {
-        margin-top: 0;
-        bottom: 0;
-        position: absolute;
-    }
-}
--- a/sat_templates/default/static/merge-request.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-ticket.css
\ No newline at end of file
--- a/sat_templates/default/static/merge-request_item.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-@import 'highlight.css';
-
-.highlight {
-    overflow: auto;
-}
-
-.box {
-    border-radius: 0;
-    box-shadow: none;
-}
-
-.ticket {
-    max-width: none;
-}
-
-.xmlui_cont.xmlui_cont_vertical {
-    max-width: 780px;
-    margin: 0 auto;
-}
-
-.view #wid_body {
-    border: 1px solid silver;
-}
-
-#tab_patches {
-    overflow: auto;
-}
-
-#tab_patches header {
-    border-top: 1px solid silver;
-}
-
-#tab_patches header label {
-    font-weight: bold;
-}
-
-.commit_msg {
-    font-style: italic;
-    white-space: pre-wrap;
-}
-
-.diff {
-    white-space: pre;
-}
--- a/sat_templates/default/static/photo.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-@import 'blog.css'; /* needed for comments */
-
-.album {
-    display: flex;
-    flex-wrap: wrap;
-}
-
-.album__item {
-    width: 400px;
-	margin: 0 0.1em 2em 0.1em;
-}
-
-.album__vignette {
-    background-color: #444;
-    height: 300px;
-    position: relative;
-}
-
-.album__thumbnail {
-    height: 100%;
-    display: block;
-    margin: 0 auto;
-}
-
-.album__comments-bar {
-    display: block;
-    font-size: 0.8em;
-    color: black;
-    text-align: right;
-    cursor: pointer;
-}
-
-.album__comments-bar:hover {
-    background-color: #ddd;
-    font-weight: bold;
-}
-
-.comments__count {
-    font-weight: bold;
-}
-
-.panel-drawer {
-    max-height: 0;
-    opacity: 0;
-    transition: max-height 1s, opacity 2s;
-    overflow: hidden;
-}
-
-.panel-drawer.clicked {
-    opacity: 1;
-}
--- a/sat_templates/default/static/styles.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,747 +0,0 @@
-:root {
-  --select-bg-color: #ddd;
-  --size-medium: 3em;
-}
-
-
-html {
-    font-family: "sat-base-font";
-}
-
-body {
-    margin: 0;
-    padding: 0;
-    display: flex;
-    height: 100vh;
-    flex-direction: column;
-    box-sizing: border-box;
-}
-
-ul {
-    padding: 0;
-}
-
-#main_side_bar {
-
-}
-
-#main_area {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    box-sizing: border-box;
-}
-
-#body {
-    flex: 1;
-    position: relative;
-}
-
-footer {
-    text-align: center;
-    font-size: 0.7em;
-    font-weight: bold;
-}
-.title {
-    font-weight: bold;
-    text-align: center;
-}
-
-.post_confirm {
-    text-align: center;
-    background-color: lightgreen;
-    padding: 1em;
-    font-size: 1.2em;
-    font-weight: bold;
-    width: 60%;
-    margin: 1.5em auto;
-}
-
-/*** Generic ***/
-
-.button {
-    padding: 0.5em 1em;
-    background: #333;
-    color: #ccc;
-    border: 1px solid #555;
-    border-radius: 0.8em;
-    font-weight: bold;
-}
-
-
-.button:hover {
-    background-color: #bc0000;
-}
-
-.instructions--head {
-    font-size: 1.5em;
-    text-align: center;
-}
-
-.instructions--alt {
-    text-align: center;
-    font-style: italic;
-}
-
-.items_vert--centered {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-}
-
-/*** boxes ***/
-
-.box {
-    background-color: #edf2ff;
-    border-radius: 0;
-    border-color: silver;
-    margin: 0 auto;
-}
-
-.box--medium {
-    max-width: 50em;
-}
-
-.box--small {
-    max-width: 20em;
-}
-
-.box--hollow {
-    border-radius: 0;
-    border-style: solid;
-    border-color: silver;
-    border-width: 1px 0;
-    margin: 0;
-}
-
-.box--paper {
-    text-align: center;
-    font-variant: small-caps;
-    border: none;
-}
-
-.box--center {
-}
-
-.box__tools {
-    /* toolbar in a box */
-    margin: 0;
-    padding: 0;
-}
-
-.box__tools a {
-    text-decoration: none;
-    color: inherit;
-    padding: 0.2em;
-    border-radius: 0.4em;
-}
-
-.box__tools a:hover {
-    background-color: var(--select-bg-color);
-}
-
-
-/*** blocks ***/
-
-.block_separator {
-    font-size: 1.4em;
-    display: flex;
-}
-
-.block_separator__label {
-    display: inline-block;
-    margin: 0 0.2em;
-}
-
-.block_separator__line {
-    height: 1px;
-    background: #ccc;
-    flex: 1;
-    margin-top: 0.7em;
-}
-
-/*** lists ***/
-
-.list {
-    list-style: none;
-    display: flex;
-    flex-direction: column;
-}
-
-.list__item>a {
-    text-decoration: none;
-    color: inherit;
-}
-
-/*** grids ***/
-
-.grid {
-    display: flex;
-    flex-wrap: wrap;
-}
-
-ul.grid {
-    list-style: none;
-}
-
-.grid--center {
-    justify-content: center;
-}
-
-li.grid__item>a {
-    text-decoration: none;
-    color: inherit;
-}
-
-.grid__item--medium {
-   width: 170px;
-   padding: 0.2em;
-   text-align: center;
-}
-
-.grid__item--selectable {
-    cursor: pointer;
-}
-
-.grid__item--selectable:hover {
-    background-color: var(--select-bg-color);
-}
-
-/*** tables ***/
-
-.table--main {
-    margin: 1em auto;
-	border-collapse: collapse;
-    text-align: center;
-}
-
-.table--main th {
-    font-variant: small-caps;
-    border: 1px solid;
-    padding: 0.5em;
-}
-
-.table--main td {
-    border: 1px solid;
-    padding: 0 0.5em;
-}
-
-.table__total {
-    font-variant: small-caps;
-}
-
-.table__total_value {
-    font-weight: bold;
-}
-
-/*** avatars ***/
-
-.avatar {
-    height: 2rem;
-    width: 2rem;
-    align-content: center;
-    justify-content: center;
-    background: #ccc;
-    border-radius: 0.2rem;
-}
-
-.avatar--generated{
-    display: inline-flex;
-    flex-direction: column;
-}
-
-.avatar--float-left {
-    float: left;
-    margin-top: 0.3em;
-    margin-right: 0.5em;
-}
-
-.avatar__content {
-
-}
-
-.avatar--medium {
-    height: var(--size-medium);
-    width: var(--size-medium);
-    border-radius: 0.5rem;
-}
-
-.avatar--generated {
-    text-align: center;
-    background:  #43d2f6;
-}
-
-/*** images ***/
-.img--small {
-    height: 100px;
-}
-
-
-/*** icons ***/
-
-.icon--medium {
-    height: var(--size-medium);
-    display: block;
-    margin: 0 auto;
-}
-
-.icon--small {
-    height: 1em;
-}
-
-.icon--soft {
-    fill: #777;
-}
-
-.icon__name {
-
-}
-
-/*** Messages ***/
-
-.message--info {
-    max-width: 500px;
-    margin: 0 auto;
-    padding: 1em;
-    text-align: justify;
-}
-
-.message--info pre {
-    background: #ddd;
-    padding: 1em;
-}
-
-.message--note {
-    max-width: 500px;
-    margin: 0 auto;
-    padding: 1em;
-    text-align: center;
-}
-
-/*** Menus ***/
-
-.menu ul {
-    display: flex;
-    margin-top: 8px;
-    list-style: none;
-}
-
-.menu a {
-    display: block;
-    color: inherit;
-    text-decoration: none;
-    font-variant: small-caps;
-}
-
-.main_menu {
-    min-width: 200px;
-    /* background-color: #eaeaea; */
-    background-color: #333;
-    color: white;
-    overflow: auto;
-}
-
-.main_menu ul {
-    flex-direction: row;
-    flex-wrap: wrap;
-}
-
-.main_menu li {
-    flex: 1;
-    padding: 0;
-    margin: 0 0.5em;
-}
-
-.main_menu a {
-    display: inline;
-    white-space: nowrap;
-}
-
-.main_menu a:hover {
-    background-color: initial;
-    text-shadow: 1px 1px 2px;
-    font-weight: bold;
-}
-
-.category_menu ul {
-    justify-content: center;
-}
-
-.category_menu li {
-    margin: 0.5em;
-    text-align: center;
-}
-
-.category_menu a {
-    border: solid 1px;
-    padding: 0.5em;
-    border-radius: 0.2em;
-    background: #eee;
-}
-
-/*** containers ***/
-
-/* tabs */
-
-.tab_container {
-    max-width: 1000px;
-    margin: 0 auto;
-}
-
-.tab_header {
-    background-color: white;
-    border-bottom: 1px solid lightgrey;
-}
-
-.tab_header ul {
-    display: flex;
-    margin: 0;
-    padding: 0;
-    list-style: none;
-    background-color: white;
-}
-
-.tab_page {
-    box-sizing: border-box;
-    padding-top: 2em;
-    border: 1px solid lightgrey;
-    border-top: none;
-    display: None;
-}
-
-.tab_page.clicked {
-    display: block;
-}
-
-.tab_button {
-    display: inline;
-    color: grey;
-    background-color: white;
-    border-top: 1px solid lightgrey;
-    border-left: 1px solid lightgrey;
-    border-bottom: 1px solid lightgrey;
-    padding: 0 1em;
-    cursor: pointer;
-    /* we go down by 1px to remove bottom border from .tab_header */
-    margin-bottom: -1px;
-}
-
-.tab_button.clicked {
-    /* background: lightgrey; */
-    color: inherit;
-    border-bottom: none;
-}
-
-li.tab_button:last-child {
-    border-right: 1px solid lightgrey;
-}
-
-.tab_button input {
-    display: None;
-}
-
-.tab_button label {
-    margin: 1em;
-}
-
-.tab_button input:checked + label {
-    font-weight: bold;
-}
-
-/*** Forms ***/
-
-/* a form with only one field */
-
-.form--paper label {
-    font-variant: small-caps;
-}
-
-.form--paper label.required:after {
-    content: " *";
-    font-weight: bold;
-}
-
-.form--paper textarea {
-    resize: vertical;
-}
-
-.form--single {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    flex-direction: column;
-}
-
-.form--single input:not([type="submit"]) {
-    margin: 1em 1em;
-    width: 15em;
-    border-radius: 0.7em;
-    outline: none;
-    border: 1px solid black;
-    padding: 0.4em;
-    box-shadow: none;
-}
-
-.form--single .form_input {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    flex-direction: column;
-}
-
-
-.form_submit {
-    margin: 1em auto 0;
-    display: block;
-}
-
-.form--single .form_submit {
-    margin: 0;
-}
-
-.form_jid {
-    text-align: center;
-}
-
-.form__panel--vertical {
-    display: flex;
-    flex-direction: column;
-    padding: 2em 0;
-}
-
-.form__panel--vertical label {
-    display: block;
-}
-
-.form__panel--vertical .form_input {
-    margin: 0.5em 0;
-}
-
-.form__panel--center textarea,input:not([type="radio"]) {
-    display: block;
-    margin-left: auto;
-    margin-right: auto;
-}
-
-.form__panel--center label {
-    text-align: center;
-}
-
-.form__field--tiny>input {
-    box-sizing: border-box;
-    width: 3em;
-}
-
-.form__field--small>input {
-    box-sizing: border-box;
-    width: 20em;
-    max-width: 95%;
-}
-
-.form__field--medium>input {
-    box-sizing: border-box;
-    width: 50em;
-    max-width: 95%;
-}
-
-.form__field--big>input,textarea {
-    box-sizing: border-box;
-    width: 100%;
-}
-
-/* Textboxes */
-
-.textbox {
-    margin-left: auto;
-    margin-right: auto;
-}
-
-form.textbox>* {
-    display: block;
-    margin: 1em auto;
-    text-align: center;
-    max-width: 100%;
-    box-sizing: border-box;
-}
-
-form.textbox>textarea {
-    text-align: left;
-}
-
-.log_request {
-    text-align: center;
-}
-
-/*** Navigation ***/
-
-.prev_next_links ul {
-    list-style: none;
-    display: flex;
-    padding: 0 2em;
-    margin: 0;
-}
-
-.prev_next_links li {
-    flex: 1;
-}
-
-.prev_next_links li.older_items {
-    text-align: right;
-}
-
-.prev_next_links img {
-    display: block;
-}
-
-.prev_next_links .older_items img {
-    display: block;
-    margin-left: auto;
-    margin-right: 0;
-}
-
-.prev_next_links a {
-    display: inline-block;
-    margin-top: 1em;
-    padding: 0.2em;
-    text-decoration: None;
-    color: inherit;
-    font-variant: small-caps;
-    background: rgba(200,200,200,0.6);
-    border-radius: 0.5em;
-}
-
-.prev_next_links a:hover {
-    background-color: #ddd;
-}
-
-/*** XMLUI ***/
-
-.xmlui_cont_vertical>* {
-    display: block;
-    box-sizing: border-box;
-}
-
-.xmlui_cont_vertical>.xmlui_widget {
-    width: 100%;
-    min-height: 1em;
-    min-width: 1px;
-}
-
-label.xmlui_label {
-    font-weight: bold;
-}
-
-td a {
-  /* we use <a> for non JS links in table
-   * so we don't want specific color/text-decoration by default
-   */
-  color: inherit;
-  text-decoration: inherit;
-}
-
-
-/*** Notifications ***/
-
-.notification.retry {
-    position: fixed;
-    top: 1rem;
-    margin: auto;
-    width: 80%;
-    background: #DB1616;
-    border: 3px solid silver;
-    left: 10%;
-    text-align: center;
-}
-
-#retry_counter {
-    font-weight: bold;
-}
-
-#retry_now {
-    color: blue;
-    text-decoration: underline;
-    cursor: pointer;
-}
-
-@media (min-width: 800px) {
-    html {
-        background-size: auto;
-    }
-
-    body {
-        flex-direction: row;
-    }
-
-    #main_area {
-        overflow: auto;
-    }
-
-    /*** boxes ***/
-
-    .box {
-        border-radius: 1em;
-        box-shadow: 10px 10px 16px -5px rgba(0,0,0,0.5);
-        width: 94%;
-        margin: 1em auto;
-        border: solid 1px;
-        border-color: #9ca0a8;
-    }
-
-    .box--medium {
-        width: 33rem;
-        max-width: 100%;
-    }
-
-    .box--hollow {
-        border-radius: 0.2em;
-        border-width: 1px;
-        margin: 0.5em;
-    }
-
-    /*** Forms ***/
-
-    .form__panel--vertical {
-        display: flex;
-        flex-direction: column;
-        padding: 2em;
-    }
-
-    .form__field--big>input,textarea {
-        box-sizing: border-box;
-        width: 95%;
-    }
-
-    .main_menu a {
-        display: block;
-        padding: 2em 0;
-    }
-
-    .main_menu ul {
-        flex-direction: column;
-        padding-left: 2em;
-    }
-
-    .prev_next_links ul {
-        padding: 0 6em;
-    }
-
-    .instructions--alt {
-        padding-top: 3rem;
-    }
-
-    /*** forms ***/
-
-    .form--single input:not([type="submit"]) {
-        margin: 0 1em;
-    }
-
-    .form--single {
-        display: flex;
-        justify-content: center;
-        flex-direction: row;
-    }
-
-    .form--single .form_input {
-        flex-direction: row;
-    }
-}
--- a/sat_templates/default/static/ticket.css	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,180 +0,0 @@
-@import 'blog.css'; /* needed as blog/articles.html is included */
-
-.instructions {
-    font-style: italic;
-    text-align: center;
-}
-
-.instructions span {
-    padding: 0.3em;
-}
-
-ul.xmlui_list {
-    list-style: none;
-    display: flex;
-    flex-direction: column;
-    padding: 0;
-}
-
-.xmlui_list li {
-    display: inline-flex;
-    background: #eee;
-    padding: 0.5em;
-    margin: 0.5em 0;
-    border: 1px solid silver;
-}
-
-.xmlui_list li:hover {
-    background: yellow;
-}
-
-.xmlui_list a {
-    display: flex;
-    width: 100%;
-    text-decoration: none;
-    color: inherit;
-}
-
-.xmlui_list a:visited {
-    color: inherit;
-}
-
-.tickets a.status_closed {
-    text-decoration: line-through;
-    color: grey;
-}
-
-.xmlui_field__id {
-    font-style: italic;
-    padding-right: 1em;
-}
-
-.xmlui_field__title {
-    padding-right: 1em;
-}
-
-.tickets a.severity_major .xmlui_field__title {
-    font-weight: bold;
-    color: red;
-}
-
-.tickets tbody tr.severity_major .td_title a::before {
-    content: '⚠ ';
-    color: red;
-}
-
-/* single ticket */
-
-.ticket {
-    padding: 20px;
-    max-width: 500px;
-    margin: 0 auto;
-}
-
-.view .xmlui_widget {
-    width: auto;
-}
-
-.view div.xmlui_cont div.xmlui_cont {
-    display: grid;
-    grid-template-columns: min-content 1fr;
-}
-
-.view #label_wid_publisher,
-.view #wid_publisher,
-.view #label_wid_title,
-.view #label_wid_body,
-.view #label_wid_id,
-.view #label_wid_comments_uri,
-.view #wid_comments_uri {
-    display: none
-}
-
-.view .xmlui_label {
-    padding-right: 2em;
-}
-
-.view #wid_id {
-    margin: 0;
-    font-style: italic;
-    grid-column-start: 1;
-    grid-column-end: 3;
-    text-align: right;
-}
-
-.view .xmlui_label {
-    font-weight: bold;
-    float: left;
-    color: #808080cc;
-}
-
-.view #wid_title {
-    font-weight: bold;
-    display: block;
-    text-align: center;
-    grid-column-start: 1;
-    grid-column-end: 3;
-}
-.view #wid_title::first-letter {
-    text-transform: uppercase;
-}
-
-.view #wid_labels span, .xmlui_field__labels span {
-    font-size: 0.8em;
-    background: #eae3e3;
-    font-variant: small-caps;
-    border: 1px solid black;
-    border-radius: 0.5em;
-    padding: 0 2px;
-    white-space: nowrap;
-}
-
-.view #wid_labels span.value_work_in_progress {
-    background: yellow;
-}
-
-.view #wid_type {
-    font-weight: bold;
-}
-
-.view #wid_type span.value_bug::after {
-    content: ' 🐛';
-    color: red;
-}
-
-.view #wid_severity span.value_major {
-    font-weight: bold;
-    color: red;
-}
-
-.view #wid_severity span.value_major::after {
-    content: '⚠ ';
-}
-
-.view #wid_body {
-    white-space: pre-wrap;
-    max-height: 500px;
-    overflow: auto;
-    resize: both;
-    background-color: white;
-    padding: 5px;
-    text-align: justify;
-    border: 1px solid black;
-    border-radius: 5px;
-    grid-column-start: 1;
-    grid-column-end: 3;
-    display: block;
-}
-
-.comment_post {
-    margin-top: 3em;
-}
-
-@media (min-width: 800px) {
-    ul.xmlui_list {
-        padding: 0 2em;
-    }
-    .xmlui_list li {
-        border-radius: 0.3em;
-    }
-}
--- a/sat_templates/default/static/websocket.js	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-/*
-SàT templates: suit of templates for Salut à Toi
-Copyright (C) 2017 Jérôme Poisson (goffi@goffi.org)
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Affero General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-
-/* websocket handler */
-
-
-//TODO: retry websocket instead of reload
-function WSHandler(url, token, debug=false) {
-    var socket = new WebSocket(url, 'libervia_page_' + token );
-    var retried = 0;
-
-    var errorHandler = function(error) {
-        if (retried > 20) {
-            console.error("Too many tries, can't start websocket");
-            alert("Dynamic connection with server can't be established, please try to reload this page in a while or contact your service administrator");
-            return;
-        }
-        var delay = Math.floor((Math.random() * 10) + 1) + 30 * Math.min(retried, 6);
-        notifyRetry(delay, function() {
-            retried++;
-            socket = new WebSocket(url, 'libervia_page_' + token );
-            socket.addEventListener('error', errorHandler);
-        });
-    };
-
-    socket.addEventListener('error', errorHandler);
-
-    if (debug) {
-        socket.addEventListener('message', function(event) {
-            console.log('WS in <== ', JSON.parse(event.data));
-        });
-    }
-
-    socket.addEventListener('message', function(event) {
-        try {data = JSON.parse(event.data);}
-        catch (e) {
-            console.warn('invalid websocket message received: %s', e);
-            return;
-        }
-        switch (data.type) {
-            case 'reload':
-                location.reload(true);
-                break;
-            case 'dom':
-                selected_element = document.body.querySelector(data.selectors);
-                switch (data.update_type) {
-                    case 'append':
-                        var template = document.createElement('template');
-                        template.innerHTML = data.html.trim();
-                        new_element = template.content.firstChild;
-                        selected_element.appendChild(new_element);
-                        break;
-                    default:
-                        console.warn('Unknown DOM update type: %s', data.update_type);
-                }
-                break;
-            default:
-                console.warn('Unknown data type: %s', data.type);
-        }
-    });
-
-    socket.addEventListener('open', function (event) {
-        console.log('Websocket opened');
-        retried = 0;
-    }.bind(this));
-
-    this.send = function(data) {
-        if (debug) {
-            console.log('WS out ==> ', data);
-        }
-        socket.send(JSON.stringify(data));
-    };
-
-    function notifyRetry(timeout, retryCb) {
-        /* Show a notification dialog informing the user that server can't be reach
-         * and call retryCb after timeout seconds.
-         * A "retry now" link allows to retry immediately"
-         *
-         * @param timeout(int): delay before retrying, in seconds
-         * @param retryCb(function): function to call when retrying
-         */
-        var startTime = Date.now() / 1000;
-        var retryIntervalID;
-        var notif = document.createElement("div");
-        notif.setAttribute('class', 'notification retry');
-        //FIXME: we use English without translation for now, must be changed when we can use gettext in Libervia pages
-        notif.innerHTML = "<p>Can't reach the server, retrying in <span id='retry_counter'></span> seconds</p><p><a id='retry_now'>retry now</a></p>";
-        document.body.appendChild(notif);
-        var retryCounter = document.getElementById('retry_counter');
-        retryCounter.textContent = timeout;
-
-        var retry = function () {
-            clearInterval(retryIntervalID);
-            notif.parentNode.removeChild(notif);
-            retryCb();
-        };
-
-        var updateTimer = function () {
-            var elapsed = Math.floor(Date.now() / 1000 - startTime);
-            var remaining = timeout - elapsed;
-            if (remaining < 0) {
-                retry();
-            }
-            else {
-                retryCounter.textContent = remaining;
-            }
-        };
-
-        var retryNow = document.getElementById('retry_now');
-        retryNow.addEventListener('click', function(){
-            retry();
-        });
-
-        retryIntervalID = setInterval(updateTimer, 1000);
-    }
-}
--- a/sat_templates/default/ticket/create.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-{# create a new ticket #}
-
-{% set category_menu = [('tickets_list', url_tickets_list)] %}
-{% extends 'base/base.html' %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-{% import 'input/xmlui.html' as xmlui with context %}
-
-{% block body %}
-<div class='instructions'>
-    <p><span class="box">{% trans app_name=C.APP_NAME%}This page allows you to report an issue or ask/suggest a new feature for {{app_name}}{% endtrans %}</span></p>
-</div>
-<div class="create single ticket box">
-{% call form.form() %}
-    {{ xmlui.generate(new_ticket_xmlui,
-                      attributes = {'title': {'required': 'required',
-                                              'placeholder': _("Short description of your issue/request")},
-                                    'body': {'required': 'required',
-                                             'placeholder': _("Please describe your issue/request with as much details as possible")},
-                                    'labels': {'placeholder': _("You can enter one or several labels separated by commas")},
-                                    })}}
-    {{ field.submit(_("Create ticket")) }}
-{% endcall %}
-</div>
-{% endblock body %}
--- a/sat_templates/default/ticket/discover.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-{% extends 'base/base.html' %}
-{% import 'components/block.html' as block with context %}
-{% import 'components/images.html' as images with context %}
-{% import 'components/avatar.html' as avatar with context %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-
-{% block body %}
-{{ icon_defs('clipboard') }}
-<p class="instructions--head">
-    {% trans %}
-    Please select a tickets tracker
-    {% endtrans %}
-</p>
-{% if tickets_trackers is defined %}
-    <div class="disco_tickets">
-        {{block.disco_icon_grid(tickets_trackers, 'clipboard')}}
-    </div>
-{% endif %}
-
-{% call form.form(class="form--single") %}
-    {{ field.text("jid", _("tickets tracker jid"), required=true)}}
-    {{ field.submit(_("Access")) }}
-{% endcall %}
-{% endblock body %}
--- a/sat_templates/default/ticket/edit.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-{# edit an existing ticket #}
-
-{% set category_menu = [('tickets_list', url_tickets_list)] %}
-{% extends 'base/base.html' %}
-{% import 'input/form.html' as form with context %}
-{% import 'input/field.html' as field with context %}
-{% import 'input/xmlui.html' as xmlui with context %}
-
-{% block body %}
-<div class="create single ticket box">
-{% call form.form() %}
-    {{ xmlui.generate(new_ticket_xmlui,
-                      attributes = {'title': {'required': 'required',
-                                              'placeholder': _("Short description of your issue/request")},
-                                    'body': {'required': 'required',
-                                             'placeholder': _("Please describe your issue/request with as much details as possible")},
-                                    'labels': {'placeholder': _("You can enter one or several labels separated by commas")},
-                                    })}}
-    {{ field.submit(_("Modify ticket")) }}
-{% endcall %}
-</div>
-{% endblock body %}
--- a/sat_templates/default/ticket/item.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-{# display a single ticket
-
-    @variable item(xmlui_item): ticket to display
-    @variable comments(data_object.BlogItems): comments of the ticket
-    @variable comments_service(unicode): service for adding comments
-    @variable comments_node(unicode): node for adding comments
-#}
-
-{% set category_menu = [('tickets', url_tickets_list),
-                        ('ticket_new', url_tickets_new),
-                        ] %}
-{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
-{% import 'input/xmlui.html' as xmlui with context %}
-{% import 'blog/macros.html' as blog with context %}
-{% import 'input/textbox.html' as textbox with context %}
-
-{% block title %}{{item|adv_format('[{value.widget_value.id}] {value.widget_value.title}') }}{% endblock %}
-
-{% block confirm_message %}
-    {% trans %}Your comment has been sent{% endtrans %}
-{% endblock confirm_message %}
-
-{% block body %}
-{{ icon_defs('pencil') }}
-<div id="{{ item.widget_value['id'] }}" class="view single ticket box">
-    {% if url_ticket_edit is defined %}
-        <p class="box__tools">
-            <a href="{{url_ticket_edit}}">
-            {{ icon('pencil', cls='icon--small') }}
-            edit
-            </a>
-        </p>
-    {% endif %}
-    {{ xmlui.generate(item,
-        form=false,
-        filters={'created': {'filters': ['date_fmt'], 'filters_args':[{'fmt': 'short'}]},
-                 'updated': {'filters': ['date_fmt'], 'filters_args':[{'fmt': 'short'}]},
-                 'body': {'filters': ['urlize'], 'filters_args':[{'nofollow': True, 'rel': 'noopener noreferrer'}]}},
-        )}}
-</div>
-{% if comments is defined %}
-<div id="blog_items">
-    {{ blog.show_items(comments|reverse, expanded=true) }}
-</div>
-{% endif %}
-{% if comments_node is defined %}
-    <div class="comment_post">
-        {{- textbox.comment_or_login(service=comments_service, node=comments_node) -}}
-    </div>
-{% endif %}
-{% endblock body %}
--- a/sat_templates/default/ticket/overview.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-{# display the list of tickets #}
-
-{% set category_menu = [('ticket_new', url_tickets_new)] %}
-{% extends 'base/base.html' %}
-{% import 'input/xmlui.html' as xmlui with context %}
-
-{% block body %}
-<div id="tickets" class="view tickets overview">
-    {{ xmlui.generate_list(tickets, (('id', _('Id')),
-                                     ('title', _('Title')),
-                                     ('labels', _('Labels'))),
-                          {'id': '[{value}]'},
-                           item_class_fields=['status', 'priority', 'severity'],
-                           on_click=on_ticket_click) }}
-</div>
-{% endblock body %}
--- a/sat_templates/default/ticket/tickets.html	Sun Jul 15 08:57:56 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-{% extends 'base/base.html' %}
-{% import 'input/xmlui.html' as xmlui with context %}
-
-{% block body %}
-<div id="tickets">
-    {% for ticket in tickets %}
-        <div class="ticket_full">
-            {{ xmlui.generate(ticket) }}
-        </div>
-    {% endfor %}
-</div>
-{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/app/app.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,23 @@
+{% extends 'base/base.html' %}
+{% block body %}
+<article id="web_app_box" class="box">
+    <p>
+        {% trans app_name=C.APP_NAME %}
+            The following link allows you to access {{app_name}} web application, which is a more feature rich way to use this software (but it is also a bit more heavy and complex to use).
+        {% endtrans %}
+    </p>
+    <p class="warning_text">
+        {% trans %}
+            Please note that current version of web application use legacy technologies and will be rewritten for next version of Salut à Toi (0.8). It does contain some bugs and it is under minimal maintenance.
+        {% endtrans %}
+    </p>
+    <p id="link_section">
+        <a href="/libervia.html">{% trans %}Click here to access the web application{% endtrans %}</a>.
+    </p>
+    <p>
+        {% trans %}
+            Next time you can go directly to the above URL.
+        {% endtrans %}
+    </p>
+</article>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/base/base.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,98 @@
+{% set embedded = True %} {# embedded is set to avoid including base.html several times if a generic page is included (e.g. blog/articles.html) #}
+{% import 'components/common.html' as component with context %}
+{{ script.include('common', '') }} {# common.js is, as its name state, a common script, so it's useful to import it here #}
+<!DOCTYPE html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    {% if norobots %}
+        <meta name="robots" content="noindex, nofollow">
+    {% endif %}
+
+    <title>{% block title %}{{C.APP_NAME}}{% endblock %}</title>
+
+    {% if css_content is defined %}
+        <style type="text/css">
+            {{css_content}}
+        </style>
+        {% if css_content_noscript is defined %}
+        <noscript>
+            <style type="text/css">
+                {{css_content_noscript}}
+            </style>
+        </noscript>
+        {% endif %}
+    {% else %}
+        {% for css_file in css_files %}
+            <link rel='stylesheet' type="text/css" href='{{css_file}}'>
+        {% endfor %}
+        {% if css_files_noscript %}
+            <noscript>
+                {% for css_file in css_files_noscript %}
+                    <link rel='stylesheet' type="text/css" href='{{css_file}}'>
+                {% endfor %}
+            </noscript>
+        {% endif %}
+    {% endif %}
+
+    {% if xmpp_uri is defined %}
+        <link rel="alternate" type="application/atom+xml" href="{{xmpp_uri}}" >
+    {% endif %}
+
+    {% if dynamic_style is defined %}
+    {# be extra careful about dynamic style, insure escaping if you use untrusted values ! #}
+        <style type="text/css">
+        {{dynamic_style}}
+        </style>
+    {% endif %}
+
+    {# JS handling #}
+    {% if websocket is defined %}
+        {{ script.include('websocket', '') }}
+    {% endif %}
+    {{ script.generate_scripts() }}
+    {% if websocket is defined %}
+        <script>var socket=new WSHandler("{{websocket.url}}", "{{websocket.token}}", {{websocket.debug}});</script>
+    {% endif %}
+
+    {% block favicon %}
+        <link rel="icon" href="{{media_path}}icons/apps/64/sat.png">
+    {% endblock favicon %}
+</head>
+<body>
+    {% if main_menu is defined %}
+        {% block main_menu %}
+            {{ component.menu(main_menu, class="main_menu") }}
+        {% endblock main_menu %}
+    {% endif %}
+
+    <main id='main_area'>
+        <header>
+            {% if confirm %}
+            {# confirmation message used when post data has been handled correctly #}
+                {% block confirm %}
+                    <div class="box post_confirm">
+                        {% block confirm_message %}
+                            {% trans %}Your data has been sent correctly.{% endtrans %}
+                        {% endblock confirm_message %}
+                    </div>
+                {% endblock confirm %}
+            {% endif %}
+
+        </header>
+
+        <div id="body">
+        {% block category_menu scoped %}
+            {% if category_menu is defined %}
+                {{ component.menu(category_menu, class="category_menu") }}
+            {% endif %}
+        {% endblock category_menu %}
+        {% block body %}
+        {% endblock body %}
+        </div>
+        <footer>{% block footer %}<span>{% trans app_name=C.APP_NAME %}Powered by {{app_name}}{% endtrans %}</span>{% endblock %}</footer>
+    </main>
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/blog/articles.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,30 @@
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% set single = items|length == 1 %}
+{% set dates_format='relative' if single else 'short' %}
+{% import 'blog/macros.html' as blog with context %}
+{% import 'input/navigation.html' as navigation with context %}
+
+{%- block title scoped -%}
+    {%- if not embedded -%}
+        {%- if single -%}
+            {{- items[0].title|default(items[0].content, true)|truncate(60, True, '…') + ' - ' + C.APP_NAME -}}
+        {%- else -%}
+            {{C.APP_NAME}}
+            {# {{- super() -}}
+               FIXME: super() is failing if blog is embedded (i.e. base/base.html is not its direct parent)
+                      not sure what's the best way to avoid that, so just using C.APP_NAME for now #}
+        {%- endif -%}
+    {%- endif -%}
+{%- endblock title -%}
+
+{% block body %}
+{% if items %}
+    <div id="blog_items">
+        {{ blog.show_items(items, expanded=single) }}
+    </div>
+{% else %}
+    <p class="message--info">{% trans %}No articles found in this blog!{% endtrans %}</p>
+{% endif %}
+
+{{ navigation.prev_next(_("newer articles"), _("older articles")) }}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/blog/atom.xml	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns='http://www.w3.org/2005/Atom'>
+    {% if title is defined %}
+        <title>{{title}}</title>
+    {% elif target_profile is defined %}
+        <title>{% trans name=target_profile%}{{name}}'s blog{% endtrans %}</title>
+    {% else %}
+        <title>{% trans app_name=C.APP_NAME%}{{app_name}} blog{% endtrans %}</title>
+    {% endif %}
+    <link href='{{request_uri}}' type='application/atom+xml' rel='self'/>
+    <link href='{{http_uri}}' type='text/html' rel='alternate'/>
+    <link href='{{xmpp_uri}}' type='application/atom+xml' rel='alternate'/>
+    <id>{{xmpp_uri}}</id>
+    <updated>{{updated|date_fmt('iso')}}</updated>
+    {% for item in items %}
+        <entry>
+            {% if item.title_xhtml %}
+                <title type='xhtml'>{{item.title_xhtml}}</title>
+            {% else %}
+                <title>{{item.title|default(item.content|truncate(80, True, '…'), True)}}</title>
+            {% endif %}
+            <link href='{{items_http_uri[item.id]}}' type='text/html' rel='alternate'/>
+            <link href='{{item.uri}}' type='application/atom+xml' rel='alternate'/>
+            <id>{{item.uri}}</id>
+            <updated>{{item.updated|date_fmt('iso')}}</updated>
+            <published>{{item.published|date_fmt('iso')}}</published>
+            <author>
+                <name>{{item.author}}</name>
+                <uri>xmpp:{{item.author_jid}}</uri>
+            </author>
+            {% for tag in item.tags %}
+                <category term="{{tag}}"/>
+            {% endfor %}
+            {% if item.content_xhtml %}
+                <content type='xhtml'>
+                    <div xmlns='http://www.w3.org/1999/xhtml'>
+                    {{item.content_xhtml}}
+                    </div>
+                </content>
+            {% else %}
+                <content type='text'>
+                    {{item.content_txt}}
+                </content>
+            {% endif %}
+        </entry>
+    {% endfor %}
+</feed>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/blog/discover.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,35 @@
+{% extends 'base/base.html' %}
+{% import 'components/block.html' as block %}
+{% import 'components/images.html' as images with context %}
+{% import 'components/avatar.html' as avatar with context %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% block body %}
+{{ icon_defs('blog') }}
+<p class="instructions--head">
+    {% trans %}
+    Please select the blog you want to consult
+    {% endtrans %}
+</p>
+<div class="disco_blogs">
+    <ul class="grid grid--center">
+        {% for entity in disco_entities %}
+            <li class='grid__item grid__item--medium grid__item--selectable'>
+                <a href="{{entities_url[entity]}}" class="items_vert--centered">
+                    {{ avatar.avatar(entity, class="avatar--medium") }}
+                    <span>{{ identities[entity].nick|default(entity, true) }}</span>
+                </a>
+            </li>
+        {% endfor %}
+    </ul>
+</div>
+
+{% if disco_entities %}
+    <p class="instructions--alt">{% trans %}Or enter the jid of a blog writer{% endtrans %}</p>
+{% endif %}
+{% call form.form(class="form--single") %}
+    {{ field.text("jid", _("blog writer jid"), required=true)}}
+    {{ field.submit(_("Consult")) }}
+{% endcall %}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/blog/item.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,98 @@
+{# display a blog item which can be expanded/retracted by clicking on it
+
+    if the locale differs from item language, it will be totally reduced, and will need a click to be displayed
+
+    @variable item(data_object.BlogItem): item to display
+    @variable identities(data_object.Identities): identities which can be used to display info on item author
+    @variable dates_format(unicode): format of the date to use (see date_fmt filter)
+#}
+
+{% block item %}
+
+{% if item.language and locale and locale.language != item.language %}
+    {# we may display items in different language in a specific way #}
+    {% set other_lang = " other_lang" %}
+{% endif %}
+
+{% if expanded %}
+    {# FIXME: the style attribute is not nice, but due to the use of clicked_mh_fix. A cleaner way would be welcomed #}
+    <article id="{{item.id}}" class="init box{{other_lang}} clicked" style="max-height: none">
+{% else %}
+    <article id="{{item.id}}" class="init box{{other_lang}}" >
+{% endif %}
+
+    {# following message is displayed if item lang is different from page locale #}
+    {% if other_lang is defined %}
+        <div class="info"><p>{% trans language=locale.language_name %}This message is not in {{language}}, click to display anyway{% endtrans %}</p></div>
+    {% endif %}
+
+    {# we put a reduce button at the top #}
+    <div class="expand_box box_top" onclick="clicked_mh_fix('{{item.id}}')">
+        <p>
+            <span class='hide'>{% trans %}Click to reduce…{% endtrans %}</span>
+        </p>
+    </div>
+
+    <header>
+        {% block header %}
+        {# title and publication date link to a HTTP page if items_http_uri is set #}
+        {% set item_http_uri = items_http_uri.get(item.id) if items_http_uri is defined else none %}
+
+        <div class="title">
+            {% block blog_title scoped %}
+                {% set title = item.title_xhtml or item.title or '' %}
+                {% if item_http_uri %}
+                    <a href="{{item_http_uri}}">{{title}}</a>
+                {% else %}
+                    {{title}}
+                {% endif %}
+            {% endblock %}
+        </div>
+            {% block metadata scoped %}
+            <div class="metadata">
+            {% if identities is defined %}
+                <span class="author">{{identities[item.author_jid].nick | default(item.author)}}</span>
+            {% else %}
+                <span class="author">{{item.author}}</span>
+            {% endif %}
+            {% set published = item.published|date_fmt(fmt=dates_format) %}
+            {% if item_http_uri %}
+                <span class="blog_data"><a href="{{item_http_uri}}">{{published}}</a></span>
+            {% else %}
+                {{- published -}}
+            {% endif %}
+            </div>
+            {% if item.tags %}
+                <div class="labels">
+                    {% if tags_http_uri is defined %}
+                        {% for tag in item.tags %}
+                            <a href="{{tags_http_uri[tag]}}"><span>{{tag}}</span></a>
+                        {% endfor %}
+                    {% else %}
+                        {% for tag in item.tags %}
+                            <span>{{tag}}</span>
+                        {% endfor %}
+                    {% endif %}
+                </div>
+            {% endif %}
+            {% endblock metadata %}
+        {% endblock header %}
+    </header>
+
+    <div class="content{{' text' if not item.content_xhtml}}">
+        {% block content %}
+        {{- item.content_xhtml or item.content|urlize or '' -}}
+        {% endblock content %}
+    </div>
+
+    {# and the bottom button to expand/reduce the article #}
+    <div class="expand_box box_bottom" onclick="clicked_mh_fix('{{item.id}}')">
+        <p>
+            <span class='show'>{% trans %}Click to expand…{% endtrans %}</span>
+            <span class='hide'>{% trans %}Click to reduce…{% endtrans %}</span>
+        </p>
+    </div>
+
+</article>
+
+{% endblock item %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/blog/macros.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,41 @@
+{% import 'input/textbox.html' as textbox with context %}
+
+{% macro show_items(items, comments=False, expanded=false, dates_fmt=none) %}
+    {# show items and comments items if present after each item,
+        then post form if allow_commenting is set
+        @param items(BlogItems): items to show
+        @param comments(bool): True items are comments
+            if False, a div with "main_article" class will be added
+        @param expanded(bool): initial state of items
+    #}
+    {% if dates_format is undefined %}
+        {% set dates_format = dates_fmt or 'short' %}
+    {% endif %}
+    {% for item in items %}
+        {% if not comments %}<div class="main_article">{% endif %}
+            {% include 'blog/item.html' %}
+        {% if not comments %}</div>{% endif %}
+
+        {# we recursively display comments for all comments nodes (usually there's only one) #}
+        {% for comments_items in item.comments_items_list %}
+            <button class="comments_btn" onclick="clicked_mh_fix('{{'comments_panel'|next_gidx}}');clicked_cls(this)">
+                <span class='show'>{% trans %}show comments{% endtrans %}</span>
+                <span class='hide'>{% trans %}hide comments{% endtrans %}</span>
+                ({{comments_items|count}})
+            </button>
+            <div id="{{'comments_panel'|cur_gidx}}" class="comments_panel">
+                {% if allow_commenting %}
+                    <div class="comment_post">
+                        {{- textbox.comment(service=comments_items.service, node=comments_items.node) -}}
+                    </div>
+                {% endif %}
+
+                <div class="comments">
+                    {{show_items(comments_items, comments=True)}}
+                </div>
+            </div>
+
+        {% endfor %}
+
+    {% endfor %}
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/chat/chat.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,22 @@
+{{ script.include('chat') }}
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% block title %}{{ target_jid }} - {{ super() }}{% endblock %}
+{% block body %}
+<div class="chat_widget">
+    <div id="messages">
+    {% if subject is defined %}
+        <div id="subject">
+            {{- subject|urlize(nofollow=true,target='_blank') -}}
+        </div>
+    {% endif %}
+    {% for msg in messages %}
+        {% include 'chat/message.html' %}
+    {% endfor %}
+    </div>
+    <div class="message_box">
+        <textarea id="message_input" name="message" type="text" placeholder="{{_("enter your message")}}"></textarea>
+    </div>
+</div>
+{% endblock body %}
+
+{% block footer %}{% endblock footer %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/chat/message.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,15 @@
+{% import 'components/avatar.html' as avatar with context %}
+
+<p id="{{msg.id}}" class="msg_{{msg.type}} {{'own_msg' if msg.from_ == own_jid.full()}}">
+    {%- if msg.type != C.MESS_TYPE_INFO %}
+        {%- set author = identities[msg.from_].nick | default(msg.from_) -%}
+        {{ avatar.avatar(msg.from_, "avatar--float-left") }}
+        <span class="msg_header">
+            <span class="author">{{author}}</span>
+            <span class="date">{{msg.timestamp|date_fmt('auto_day')}}</span>
+        </span>
+    {% endif -%}
+    <span class="msg_body">
+        {{- msg.html or (msg.text|urlize(nofollow=true, target="_blank")) -}}
+    </span>
+</p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/chat/select.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,17 @@
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% block body %}
+<p class="instructions--head">{% trans %}Please select the chat room you want to enter{% endtrans %}</p>
+<ul class="rooms_list">
+{% for room in rooms %}
+    <li><a href="{{room.url}}">{{room.name}}</a></li>
+{% endfor %}
+</ul>
+<p class="instructions--alt">{% trans %}Or enter a room address{% endtrans %}</p>
+{% call form.form(class="form--single") %}
+    {{ field.text("jid", _("Room address (JID)"), required=true)}}
+    {{ field.submit(_("Join")) }}
+{% endcall %}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/components/avatar.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,9 @@
+{% macro avatar(jid, class) %}
+    {%- if identities is defined -%}
+        {%- if identities[jid].avatar_basename is defined %}
+            <img class="avatar {{class}}" src="{{cache_path}}{{identities[jid].avatar_basename}}">
+        {% else %}
+            <span class="avatar avatar--generated {{class}}"><span class="avatar__content">{{identities[jid].nick|first|upper}}</span></span>
+        {%- endif -%}
+    {%- endif -%}
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/components/block.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,34 @@
+{% macro separator(label, align='center') %}
+{# display a bloc separator
+    @param label(unicode): label to show
+    @param align(unicode): one of "left", "center", "right"
+#}
+    <div class="block_separator">
+        {% if align in ('center', 'right') %}
+            <div class="block_separator__line"></div>
+        {% endif %}
+        <div class="block_separator__label">
+            {{label}}
+        </div>
+        {% if align in ('center', 'left') %}
+            <div class="block_separator__line"></div>
+        {% endif %}
+    </div>
+{% endmacro %}
+
+{% macro disco_icon_grid(disco_entities, icon_name) %}
+{# display discovered entities in a grid
+    @param disco_entities: entities which mush have a name and url key or attribute
+    @param icon_name: name of a defined icon
+#}
+    <ul class="grid grid--center">
+        {% for disco_entity in disco_entities %}
+            <li class='grid__item grid__item--medium grid__item--selectable'>
+                <a href="{{disco_entity.url}}" class="items_vert--centered">
+                    {{ icon(icon_name, cls='icon--medium') }}
+                    <span>{{ disco_entity.name }}</span>
+                </a>
+            </li>
+        {% endfor %}
+    </ul>
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/components/common.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,27 @@
+{# menu labels, map from menu names to labels #}
+{% set ml = {
+    'login': _('Session') if profile else _('Log in'),
+    'blog': _('Blog'),
+    'forums': _('Forums'),
+    'merge-requests': _('Merge requests'),
+    'merge-request_new': _('Create new merge request'),
+    'tickets': _('Tickets'),
+    'tickets_list': _('List tickets'),
+    'ticket_new': _('Create new ticket'),
+    'chat': _('Chat'),
+    'files': _('Files sharing'),
+    'events': _('Events'),
+    'event_new': _('Create an event'),
+    'photos': _('Photos albums'),
+    'app': _('Application'),
+} %}
+
+{% macro menu(menus, class='') %}
+    <nav class="menu {{class}}">
+        <ul>
+        {% for name,url in menus %}
+            <li><a class="menu_item menu_item--{{name}}" {{ {'href': url}|xmlattr }}>{{ml[name]}}</a></li>
+        {% endfor %}
+        </ul>
+    </nav>
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/components/images.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,15 @@
+{% macro get_icon_client(ident) %}
+    {% if ident.client %}
+        {% if ident.client.pc %}
+            {{ icon('desktop', cls='file__icon') }}
+        {% elif ident.client.phone %}
+            {{ icon('mobile', cls='file__icon') }}
+        {% elif ident.client.web %}
+            {{ icon('globe', cls='file__icon') }}
+        {% elif ident.client.console %}
+            {{ icon('terminal', cls='file__icon') }}
+        {% else %}
+            {{ icon('desktop', cls='file__icon') }}
+        {% endif %}
+    {% endif %}
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/error/401.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,6 @@
+{% extends 'error/base.html' %}
+
+{% block body %}
+<h1>{% trans %}Unauthorized{% endtrans %}</h1>
+<p>{% trans %}Sorry, you are not allowed to access this page.{% endtrans %}</p>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/error/404.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,6 @@
+{% extends 'error/base.html' %}
+
+{% block body %}
+<h1>{% trans %}Not Found{% endtrans %}</h1>
+<p>{% trans %}Sorry, we can't find the resource you are trying to access.{% endtrans %}</p>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/error/base.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,7 @@
+{% extends 'base/base.html' %}
+
+{% block title %}{% trans %}Error {{error_code}}{% endtrans %}{% endblock %}
+{% block body %}
+{% trans %}An error occured while trying to access the resource.{% endtrans %}
+{% endblock body %}
+{% block footer %}{% endblock %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/event/admin.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,85 @@
+{% extends 'base/base.html' %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+{% import 'input/textbox.html' as textbox with context %}
+
+{% block body %}
+<div class='invitation_header box'>
+    <h1>{% trans name=event.name %}{{name}} administration{% endtrans %}</h1>
+    {% if event.image is defined %}
+        <p><img class='event__picture' src="{{event.image}}"></p>
+    {% endif %}
+    {% if event.description is defined %}
+        <p>{{event.description}}</p>
+    {% endif %}
+</div>
+
+{% include 'event/counter.html' %}
+
+{% if invitees %}
+    <div class="box">
+    <h3 class="title">{% trans %}invitees{% endtrans %}</h3>
+    <table class="table--main">
+    <tr>
+        <th>{% trans %}name{% endtrans %}</th>
+        <th>{% trans %}coming?{% endtrans %}</th>
+        <th>{% trans %}guests{% endtrans %}</th>
+    {% for name, data in invitees.iteritems() %}
+        <tr>
+            <td>{{name}}</td>
+            <td>{{data.attend|default('')}}</td>
+            {% if data.attend == 'no' %}
+                <td>&nbsp;</td>
+            {% else %}
+                <td>{{data.guests|default(0)}}</td>
+            {% endif %}
+        </tr>
+    {% endfor %}
+    <tr>
+        <td colspan=2 class="table__total">{% trans %}total expected{% endtrans %}</td>
+        <td class="table__total_value">{{invitees_guests|default('0')}}</td>
+    </tr>
+    </table>
+    </div>
+{% endif %}
+
+<div class="box">
+<h3 class="title">{% trans %}invite people{% endtrans %}</h3>
+{% call form.form(class="form--paper form__panel--vertical form__panel--center") %}
+    {{ textbox.head(event_service, event_node, 'event') }}
+    {{ field.meta('event_id', event_id) }}
+    {{ field.textarea("jids",
+                      _("enter here a list of jid (one per line) to invite"),
+                      class="form__field--medium") }}
+    {{ field.textarea("emails",
+                      _("enter here a list of emails addresses (one per line) to invite"),
+                      class="form__field--medium") }}
+    {{ field.submit(_("Invite people")) }}
+{% endcall %}
+</div>
+
+<div class="box">
+<h3 class="title">{% trans %}write a blog post{% endtrans %}</h3>
+{% call form.form(class="form--paper form__panel--vertical form__panel--center") %}
+    {{ textbox.head(service, node, 'blog') }}
+    {{ field.text("title",
+                  _("title"),
+                  class="form__field--big") }}
+    {{ field.textarea("body",
+                      _("body"),
+                      class="form__field--big") }}
+    {{ field.text("language",
+                  _("language"),
+                  class="form__field--tiny") }}
+    {{ field.checkbox("comments",
+                      _("allow comments"),
+                      checked=true) }}
+    {{ field.submit(_("send")) }}
+{% endcall %}
+</div>
+
+{% if items is defined %}
+    {% include 'blog/articles.html' %}
+{% endif %}
+
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/event/attendance.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,20 @@
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+<div class="attendance box">
+    <p class="poll_instructions">{% trans %}Please indicate if you plan to attend the event:{% endtrans %}</p>
+    {% call form.form() %}
+        {{ field.meta("type", "attendance") }}
+        {{ field.meta("service", event.invitees_service) }}
+        {{ field.meta("node", event.invitees_node) }}
+        <div class="attending">
+            {{ field.choices("attend", (("yes", _("yes")), ("no", _("no")), ("maybe", _("maybe"))), checked=invitee.attend) }}
+        </div>
+        <div class="guests">
+            {{ field.int("guests", label=_("How many people will come (including you)?"), init=invitee.get("guests", 1)) }}
+        </div>
+        <div class="submit">
+            {{ field.submit() }}
+        </div>
+    {% endcall %}
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/event/counter.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,14 @@
+{% if days_left is defined %}
+    {% if days_left > 0 %}
+        <div class="event__counter box">
+            {% trans %}
+                {{days_left}} day left
+            {% pluralize %}
+                {{days_left}} days left
+            {% endtrans %}
+        </div>
+    {% else %}
+        <div class="event__counter box">{% trans %}the event is finished{% endtrans %}</div>
+    {% endif %}
+
+{% endif %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/event/create.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,31 @@
+{# create a new event #}
+
+{% extends 'base/base.html' %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% block body %}
+<div class='instructions--head'>
+{% trans %}Create an event{% endtrans %}
+</div>
+<div class="box--hollow">
+{% call form.form(class="form--paper form__panel--vertical") %}
+    {{ field.text("name", _("name"), required=true) }}
+    {{ field.text("location", _("location"), required=true) }}
+    {{ field.textarea("body",
+                      _("description of the event"),
+                      required=true,
+                      class="form__field--medium") }}
+    {{ field.date("date", _("date of the event"), required=true) }}
+    {{ field.url("main_image", _("event image URL (https)"),
+                 title=_("you can enter here the URL to a JPEG or PNG image to use as representation of your event"),
+                 placeholder=_("JPEG or PNG image URL"),
+                 pattern='http.*(jpg|jpeg|png)') }}
+    {{ field.url("bg_image", _("background image URL (https)"),
+                 title=_("you can enter here the URL to a JPEG or PNG image to use repeating background"),
+                 placeholder=_("JPEG or PNG image URL"),
+                 pattern='http.*(jpg|jpeg|png)') }}
+    {{ field.submit(_("Create event")) }}
+{% endcall %}
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/event/invitation.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,20 @@
+{% extends 'base/base.html' %}
+
+{% block body %}
+<div class='box box--paper'>
+    <h1>{% trans %}Welcome {{name}}{% endtrans %}</h1>
+    <p class='instructions'>{% trans %}You have been invited to participate to an event{% endtrans %}</p>
+    {% if event.image is defined %}
+        <p><img id='event_picture' src="{{event.image}}"></p>
+    {% endif %}
+</div>
+
+{% include 'event/counter.html' %}
+
+{% include 'event/attendance.html' %}
+
+{% if items is defined %}
+    {% include 'blog/articles.html' %}
+{% endif %}
+
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/event/overview.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,36 @@
+{# overview of current events
+
+    @variable item(xmlui_item): ticket to display
+    @variable comments(data_object.BlogItems): comments of the ticket
+    @variable comments_service(unicode): service for adding comments
+    @variable comments_node(unicode): node for adding comments
+#}
+
+{% set category_menu = [('event_new', url_event_new)] %}
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% block body %}
+<div class="box message--info">
+    <p>{% trans %}There is not events discovery yet, this will come in the future.{% endtrans %}</p>
+</div>
+{% if events is defined %}
+    <p class="message--note">
+        {% trans nb_events=events|length%}
+            You have currently {{nb_events}} event in your personal list
+        {% pluralize %}
+            You have currently {{nb_events}} events in your personal list
+        {% endtrans %}
+    </p>
+    <ul class="grid grid--center">
+        {% for event in events %}
+            <li class='grid__item grid__item--medium grid__item--selectable'>
+                <a href="{{event.url}}">
+                    {% if event.image %}
+                        <img class="img--small" src="{{event.image}}">
+                    {% endif %}
+                    <span><em>{{event.name}}</em></span>
+                </a>
+            </li>
+        {% endfor %}
+    </ul>
+{% endif %}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/file/discover.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,73 @@
+{% extends 'base/base.html' %}
+{% import 'components/block.html' as block %}
+{% import 'components/images.html' as images with context %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% block body %}
+{{ icon_defs('server', 'desktop', 'mobile', 'globe', 'terminal') }}
+<p class="instructions--head">
+    {% trans %}
+    Please select the device you want to access
+    {% endtrans %}
+</p>
+<div class="disco_files">
+    {% if disco_service_entities %}
+        <div class="files__services">
+            {{ block.separator(_("services")) }}
+            <ul class="grid grid--center">
+                {% for entity,ident in disco_service_entities.iteritems() %}
+                    <li class='grid__item grid__item--medium grid__item--selectable'>
+                        <a href="{{entities_url[entity]}}">
+                            {{ icon('server', cls='file__icon') }}
+                            <span>
+                                {% if disco_service_entities|count == 1 %}
+                                    {% trans %}your server{% endtrans %}
+                                {% else %}
+                                    {{ ident.values()[0].values()[0][0] }}
+                                {% endif %}
+                            </span>
+                        </a>
+                    </li>
+                {% endfor %}
+            </ul>
+        </div>
+    {% endif %}
+    {% if disco_own_entities %}
+        <div class="files__own">
+            {{ block.separator(_("your devices")) }}
+            <ul class="grid grid--center">
+                {% for entity,ident in disco_own_entities.iteritems() %}
+                    <li class='grid__item grid__item--medium grid__item--selectable'>
+                        <a href="{{entities_url[entity]}}">
+                            {{images.get_icon_client(ident)}}
+                            <span>{{ ident.values()[0].values()[0][0] }}</span>
+                        </a>
+                    </li>
+                {% endfor %}
+            </ul>
+        </div>
+    {% endif %}
+    {% if disco_roster_entities %}
+        <div class="files__roster">
+            {{ block.separator(_("your contacts devices")) }}
+            <ul class="grid grid--center">
+                {% for entity,ident in disco_roster_entities.iteritems() %}
+                    <li class='grid__item grid__item--medium grid__item--selectable'>
+                        <a href="{{entities_url[entity]}}">
+                            {{images.get_icon_client(ident)}}
+                            <span>{{entity.userhost()}}</span>
+                        </a>
+                    </li>
+                {% endfor %}
+            </ul>
+        </div>
+    {% endif %}
+</div>
+
+<p class="instructions--alt">{% trans %}Or enter a full jid of a device{% endtrans %}</p>
+{% call form.form(class="form--single") %}
+    {{ field.text("jid", _("device full jid"), required=true)}}
+    {{ field.submit(_("Access")) }}
+{% endcall %}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/file/overview.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,40 @@
+{% extends 'base/base.html' %}
+
+{% block body %}
+{{ icon_defs('level-up', 'doc','folder-open-empty', 'comment-empty') }}
+<ul id="files">
+    {% if parent_url is defined  %}
+        <li class="file">
+            <a href="{{ parent_url }}">
+                {{ icon('level-up', cls='file__icon') }}
+                {% trans %}parent dir{% endtrans %}
+            </a>
+        </li>
+    {% endif %}
+
+    {% for file in files_data %}
+        {% if file.type == C.FILE_TYPE_DIRECTORY %}
+            <li class="file file_{{file.type}}">
+                <a href="{{file.url}}">
+                    {{ icon('folder-open-empty', cls='file__icon') }}
+                    {{ file.name }}
+                </a>
+            </li>
+        {% else %}
+            <li class="file file_{{file.type}}">
+                <a href="{{file.url}}">
+                    {% if file.thumb_url is defined %}
+                        <img src="{{file.thumb_url}}" class="file__thumbnail" alt="{{file.name}}">
+                    {% else %}
+                        {{ icon('doc', cls='file__icon icon--soft') }}
+                    {% endif %}
+                    {{ file.name }}
+                </a>
+            </li>
+        {% endif %}
+    {% endfor %}
+</ul>
+{% if not files_data %}
+    <p class="message--info">{% trans %}No files are shared in this directory!{% endtrans %}</p>
+{% endif%}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/forum/overview.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,35 @@
+{% extends 'base/base.html' %}
+
+{% macro generate_forums(forums_data, level=0) %}
+    {% set panel_type = "main" if level==0 else "sub" %}
+    <ul class="forum forum__panel_{{panel_type}}">
+    {% for forum in forums_data %}
+        <li class="forum forum__cat_{{panel_type}} forum__level_{{level}}">
+            {% if 'http_url' in forum %}
+                <a href="{{forum['http_url']}}" class="forum_active">
+            {% else %}
+                <a>
+            {% endif %}
+                <span class="forum_title">{{ forum.title }}</span>
+                {% if 'short-desc' in forum %}
+                    <p class="forum_short-desc">{{ forum['short-desc'] }}</p>
+                {% endif %}
+            </a>
+
+            {% if 'sub-forums' in forum %}
+                {{ generate_forums(forum['sub-forums'], level=level+1) }}
+            {% endif %}
+        </li>
+    {% endfor %}
+    </ul>
+{% endmacro %}
+
+{% block body %}
+{% if not forums %}
+    <p class="message--info">{% trans %}No forums found on this server!{% endtrans %}</p>
+{% else %}
+    <div class="forums">
+        {{ generate_forums(forums) }}
+    </div>
+{% endif %}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/forum/view.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,34 @@
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% set dates_format='relative' if single else 'short' %}
+{% import 'blog/macros.html' as blog with context %}
+{% import 'input/textbox.html' as textbox with context %}
+
+{% block body %}
+
+<div id="blog_items">
+    {{ blog.show_items(items, expanded=true) }}
+</div>
+<div class="forum_topic_answer">
+    {{- textbox.comment_or_login(service=service, node=node, placeholder=_("Enter your message here")) -}}
+</div>
+<nav class="prev_next_links">
+    <ul>
+        {% if newer_url is defined %}
+            <li class="newer_items">
+                <a href="{{newer_url}}">
+                    <img src="{{media_path}}icons/tango/actions/32/go-previous.png">
+                    {% trans %}newer messages{% endtrans %}
+                </a>
+            </li>
+        {% endif %}
+        {% if older_url is defined %}
+            <li class="older_items">
+                <a href="{{older_url}}">
+                    <img src="{{media_path}}icons/tango/actions/32/go-next.png">
+                    {% trans %}older messages{% endtrans %}
+                </a>
+            </li>
+        {% endif %}
+    </ul>
+</nav>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/forum/view_topics.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,39 @@
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% import 'input/field.html' as field with context%}
+{% import 'input/textbox.html' as textbox with context %}
+{% import 'input/navigation.html' as navigation with context %}
+{% import 'components/avatar.html' as avatar with context %}
+
+{% block body %}
+
+    {% if not topics %}
+        <div class="message--info">
+            {% trans %}There is not message yet in this forum.{% endtrans %}
+            {% if profile %}
+                {% trans %}You can start a topic of interest by filling this form.{% endtrans %}
+            {% else %}
+                {% trans %}You can login to create a new topic.{% endtrans %}
+            {% endif %}
+        </div>
+    {% endif %}
+    {% if profile %}
+        <div class="forum__topic_create">
+            {% call textbox.textbox(service, node, placeholder=_("Your message"), submit_label=_("Create topic"), type="new_topic") %}
+                {{ field.text("title", placeholder=_("Your topic (try to be short and explicit)"), required=True) }}
+            {% endcall %}
+        </div>
+    {% endif %}
+
+    <div class="forum__topics">
+        {% for topic in topics %}
+            <div>
+                <a href="{{topic.http_uri}}">
+                    {{ avatar.avatar(topic.author) }}
+                    {{topic.title}}
+                </a>
+            </div>
+        {% endfor %}
+    </div>
+
+    {{ navigation.prev_next(_("older topics"), _("newer topics")) }}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/input/field.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,76 @@
+{# macros to create form fields #}
+
+{% macro field(type, name, label="", required=false) %}
+    {# generic field
+       "class" keyword can be used to add classes
+       additional kwargs will be passed as attributes #}
+    <span class="form_input {{kwargs.pop('class', '')}}">
+        {% set cur_id = name|next_gidx %}
+        {% if label %}
+            <label for="{{cur_id}}" {{'class="required"'|safe if required}}>{{label}}</label>
+        {% endif %}
+        <input id="{{cur_id}}" type="{{type}}" name="{{name}}" {{"required" if required}} {{kwargs|xmlattr}}>
+    </span>
+{% endmacro %}
+
+{% macro choices(name, choices_list, checked=none) %}
+    {% for choice, label in choices_list %}
+        <div class="form_input {{kwargs.pop('class', '')}}">
+            <input id="{{name|next_gidx}}" type="radio" name="{{name}}" value="{{choice}}"{{" checked" if checked==choice}}><label for="{{name|cur_gidx}}">{{label}}</label>
+        </div>
+    {% endfor %}
+{% endmacro %}
+
+{% macro int(name, label="", init=0) %}
+    {{ field("number", name=name, label=label, value=init, step=1, min=0, **kwargs) }}
+{% endmacro %}
+
+{% macro checkbox(name, label="", checked=false) %}
+    {% if checked %}
+        {{ field("checkbox", name=name, label=label, checked="checked", **kwargs) }}
+    {% else %}
+        {{ field("checkbox", name=name, label=label, **kwargs) }}
+    {% endif %}
+{% endmacro %}
+
+{% macro text(name, label="", placeholder="", required=false) %}
+    {{ field("text", name=name, label=label, required=required, placeholder=placeholder, **kwargs) }}
+{% endmacro %}
+
+{% macro password(name, label="", required=false) %}
+    {{ field("password", name=name, label=label, required=required, **kwargs) }}
+{% endmacro %}
+
+{% macro email(name, label="", required=false) %}
+    {{ field("email", name=name, label=label, required=required, **kwargs) }}
+{% endmacro %}
+
+{% macro date(name, label="", required=false) %}
+    {{ field("date", name=name, label=label, required=required, **kwargs) }}
+{% endmacro %}
+
+{% macro url(name, label="", required=false) %}
+    {{ field("url", name=name, label=label, required=required, **kwargs) }}
+{% endmacro %}
+
+{% macro file(name, label="", required=false) %}
+    {{ field("file", name=name, label=label, required=required, **kwargs) }}
+{% endmacro %}
+
+{% macro textarea(name, label="", rows=10, cols=50, placeholder='', required=false) %}
+    <div class="form_input {{kwargs.pop('class', '')}}">
+        {% set cur_id = name|next_gidx %}
+        {% if label %}
+            <label for="{{cur_id}}" {{'class="required"'|safe if required}}>{{label}}</label>
+        {% endif %}
+        <textarea id="{{cur_id}}" name="{{name}}" rows="{{rows}}" cols="{{cols}}" placeholder="{{placeholder}}" {{"required" if required}} class="{{kwargs.pop('class', '')}}"></textarea>
+    </div>
+{% endmacro %}
+
+{% macro meta(name, value) %}
+    <input type="hidden" name="{{name}}" value="{{value}}">
+{% endmacro %}
+
+{% macro submit(text=_("Send")) %}
+    <input class="form_submit button" type="submit" value="{{text}}" class="{{kwargs.pop('class', '')}}">
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/input/form.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,8 @@
+{% macro form(action='', class='') %}
+<form method="post" action="{{action}}" {{ {'class': class}|xmlattr }} {{kwargs|xmlattr}} >
+    {% if csrf_token is defined %}
+        <input type="hidden" name="csrf_token" value="{{csrf_token}}">
+    {% endif %}
+    {{ caller() }}
+</form>
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/input/navigation.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,22 @@
+{% macro prev_next(prev_label=_("newer"), next_label=_("older")) %}
+    <nav class="prev_next_links">
+        <ul>
+            {% if newer_url is defined %}
+                <li class="newer_items">
+                    <a href="{{newer_url}}">
+                        <img src="{{media_path}}icons/tango/actions/32/go-previous.png">
+                        {{prev_label}}
+                    </a>
+                </li>
+            {% endif %}
+            {% if older_url is defined %}
+                <li class="older_items">
+                    <a href="{{older_url}}">
+                        <img src="{{media_path}}icons/tango/actions/32/go-next.png">
+                        {{next_label}}
+                    </a>
+                </li>
+            {% endif %}
+        </ul>
+    </nav>
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/input/textbox.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,60 @@
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% macro head(service, node, type="textbox") %}
+    {# include data needed to identify the node to use for commenting #}
+    <input type="hidden" name="type" value="{{type}}">
+    <input type="hidden" name="service" value="{{service}}">
+    <input type="hidden" name="node" value="{{node}}">
+{% endmacro %}
+
+{% macro submit(label=_("Send")) %}
+    <input type="submit" value="{{label}}">
+{% endmacro %}
+
+{% macro textbox(service, node, action='', placeholder='',
+                 submit_label=_("Send"), type="textbox",
+                 class='', ta_class='') %}
+    {# generic content area for comments/blog posts/etc.
+       Only a body by default, but new elements can be
+       added by using this macro with call #}
+    {% set extra_content = caller() if caller is defined else '' %}
+    {% call form.form(action=action, class="textbox " + class) %}
+        {{ head(service, node, type) }}
+        {{ extra_content }}
+        {{ field.textarea("body", placeholder=placeholder, required=True,
+                          class=ta_class) }}
+        {{ submit(label=submit_label) }}
+    {% endcall %}
+{% endmacro %}
+
+{% macro blog_text(service, node, action='', placeholder=_("Your comment")) %}
+    {{ textbox(service, node, action=action, placeholder=placeholder, type="comment") }}
+{% endmacro %}
+
+{% macro comment(service, node, action='', placeholder=_("Your comment"), class='box--medium') %}
+    {{ textbox(service, node, action=action, placeholder=placeholder, type="comment", class=class) }}
+{% endmacro %}
+
+{% macro comment_or_login(service, node, action='', placeholder=none) %}
+    {# show comment form a a message asking to log in
+       login is checked using profile #}
+    {% if profile %}
+        {% if placeholder is none %}
+            {{ comment(service, node, action) }}
+        {% else %}
+            {{ comment(service, node, action, placeholder=placeholder) }}
+        {% endif %}
+    {% else %}
+        <div class="log_request">
+        <p class="not_logged">{% trans %}You are not logged. You need to log in to comment.{% endtrans %}</p>
+        {% if login_url is defined %}
+            <p class="log_in_url">
+                {% trans link_start=('<a href="',login_url,'">')|join|safe, link_end='</a>'|safe %}
+                    To log in {{link_start}}follow this link{{link_end}}
+                {% endtrans %}
+            </p>
+        {% endif %}
+        </div>
+    {% endif %}
+{% endmacro %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/input/xmlui.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,237 @@
+{% import 'input/field.html' as field %}
+
+{# generate methods #}
+
+{% macro generate_container(cont, config) %}
+    {% if cont.type == 'vertical' %}
+        {{ vertical_container(cont, config) }}
+    {% elif cont.type == 'pairs' %}
+        {{ pairs_container(cont, config) }}
+    {% elif cont.type == 'label' %}
+        {{ label_container(cont, config) }}
+    {% endif %}
+{% endmacro %}
+
+{% macro generate_widget(wid, config, id=none) %}
+    {% if wid.type == 'text' %}
+        {{ text_widget(wid, config, id=id) }}
+    {% elif wid.type == 'label' %}
+        {{ label_widget(wid, config) }}
+    {% elif wid.type == 'string' %}
+        {{ string_widget(wid, config, id=id) }}
+    {% elif wid.type == 'jid' %}
+        {# TODO: proper JID widget #}
+        {{ string_widget(wid, config, id=id) }}
+    {% elif wid.type == 'textbox' %}
+        {{ textbox_widget(wid, config, id=id) }}
+    {% elif wid.type == 'list' %}
+        {{ list_widget(wid, config, id=id) }}
+    {% endif %}
+{% endmacro %}
+
+{% macro generate_children(cont, config) %}
+    {% for child in cont.children %}
+        {% if child.category == 'container' %}
+            {{ generate_container(child, config) }}
+        {% else %}
+            {{ generate_widget(child, config) }}
+        {% endif %}
+    {% endfor %}
+
+{% endmacro %}
+
+{% macro generate(xmlui, form=true, filters=none, attributes=none) %}
+{# generate HTML from XMLUI
+    @param xmlui(template_xmlui.XMLUIPanel): xmlui to use
+    @param form(bool): if true will generate form elements
+    @param filters(dict,none): filters as expected by item_filter
+    @param attributes(dict,none): extra attributes to put on named widgets
+#}
+    {% set config = {'form':form, 'filters':filters or {}, 'attrs': attributes or {}} %}
+    {{ generate_container(xmlui.main_cont, config) }}
+{% endmacro %}
+
+{% macro generate_table(xmlui_items, fields, formatters, tr_class_fields, on_click) %}
+{# generate a HTML table from requested widgets names
+    @param xmlui_items(iterable[unicode]): list of xmlui to show (one per row)
+    @param fields(tuple[unicode,unicode]): fields to show (name, label)
+    @param formatters(dict): dictionary of templates to format values:
+        field_name => template
+        if no formatter is set (or None is used) for a field, it will be used unmodified.
+        current xmlui items will be set as "item" key
+    @param tr_class_fields(iterable[unicode]): name of fields to use as class
+        class will be "{name}_{value}" where name is field name, and value field value
+        all lowercase/stripped
+    @param on_click(data_objects.OnClick): thing to do when clicking on a row
+#}
+    {% if formatters is undefined %}
+        {% set formatters = {} %}
+    {% endif %}
+    {% if on_click is undefined %}
+        {% set on_click = {} %}
+    {% endif %}
+    <table>
+        <thead>
+            <tr>
+                {% for name,label in fields %}
+                    <th>{{ label }}</th>
+                {% endfor %}
+            </tr>
+        </thead>
+        <tbody>
+            {% for xmlui in xmlui_items %}
+                {% set link=on_click.formatUrl(item=xmlui.widget_value) if on_click.url else none %}
+                <tr {{ {'class': xmlui|xmlui_class(tr_class_fields)}|xmlattr }}>
+
+                    {% for name,label in fields %}
+                        <td {{ {'class': 'td_'+name}|xmlattr }}>
+                            {% for value in xmlui.widgets[name].values %}
+                                <a {{ {'href':link}|xmlattr }}>{{ value|adv_format(formatters.get(name),item=xmlui.widget_value) }}</a>
+                            {% endfor %}
+                        </td>
+                    {% endfor %}
+                </tr>
+            {% endfor %}
+        </tbody>
+    </table>
+{% endmacro %}
+
+
+
+
+{% macro generate_list(xmlui_items, fields, formatters, item_class_fields, on_click) %}
+{# generate a list of rendered XMLUI from requested widgets names
+    very similar to generate_table but generate a list instead of a tabme
+    @param xmlui_items(iterable[unicode]): list of xmlui to show
+    @param fields(tuple[unicode,unicode]): fields to show (name, label)
+    @param formatters(dict): dictionary of templates to format values:
+        field_name => template
+        if no formatter is set (or None is used) for a field, it will be used unmodified.
+        current xmlui items will be set as "item" key for the template
+    @param item_class_fields(iterable[unicode]): name of fields to use as class
+        class will be "{name}_{value}" where name is field name, and value field value
+        all lowercase/stripped
+    @param on_click(data_objects.OnClick): thing to do when clicking on a row
+#}
+    {% if formatters is undefined %}
+        {% set formatters = {} %}
+    {% endif %}
+    {% if on_click is undefined %}
+        {% set on_click = {} %}
+    {% endif %}
+    <ul class="xmlui_list">
+        {% for xmlui in xmlui_items %}
+            <li>
+            {% set link=on_click.formatUrl(item=xmlui.widget_value) if on_click.url else none %}
+                <a {{ {'class': xmlui|xmlui_class(item_class_fields),
+                        'href':link}|xmlattr }}>
+                    {% for name,label in fields %}
+                        <span {{ {'class': 'xmlui_field__'+name}|xmlattr }}>
+                            {% for label in xmlui.widgets.get(name, {}).labels %}
+                                <span>{{ label|adv_format(formatters.get(name),item=xmlui.widget_value) }}</span>
+                            {% endfor %}
+                        </span>
+                    {% endfor %}
+                </a>
+            </li>
+        {% endfor %}
+    </ul>
+{% endmacro %}
+
+
+
+
+
+{# containers #}
+
+{% macro vertical_container(cont, config) %}
+    <div class="xmlui_cont xmlui_cont_vertical">
+        {{ generate_children(cont, config) }}
+    </div>
+{% endmacro %}
+
+{% macro pairs_container(cont, config) %}
+    {# TODO: proper impelmentation (do the same as vertical container for now #}
+    <div class="xmlui_cont xmlui_cont_vertical">
+        {{ generate_children(cont, config) }}
+    </div>
+{% endmacro %}
+
+{% macro label_container(cont, config) %}
+    <div class="xmlui_cont xmlui_cont_vertical">
+        {% for child in cont.children %}
+            {% if loop.index is odd %}
+                {# label #}
+                {% if child.type == 'label' %}
+                    {% set for_ = ('wid_' + (child.for_name or child.name or '_noname'))|next_gidx %}
+                    {{ label_widget(child, config, for=for_) }}
+                {% endif %}
+            {% else %}
+                {# widget #}
+                {% set id = ('wid_' + (child.name or '_noname'))|cur_gidx %}
+                {{ generate_widget(child, config, id=id) }}
+            {% endif %}
+        {% endfor %}
+    </div>
+{% endmacro %}
+
+
+{# widgets #}
+
+{% macro text_widget(wid, config, id=none) %}
+    <p class="xmlui_widget xmlui_text" {{ {'id':id}|xmlattr }}>
+        {{- wid|item_filter(config.filters)|default('\u00A0',true) -}}
+    </p>
+{% endmacro%}
+
+{% macro label_widget(wid, config, for=none) %}
+    {% if config.form %}
+        <label class="xmlui_widget xmlui_label" {{ {'for':for}|xmlattr }}>
+            {{wid|item_filter(config.filters)}}
+        </label>
+    {% else %}
+        <span class="xmlui_widget xmlui_label" {{ {'id':none if not for else 'label_%s'|format(for)}|xmlattr }}>{{wid|item_filter(config.filters)}}</span>
+    {% endif %}
+{% endmacro%}
+
+{% macro string_widget(wid, config, id=none) %}
+    {% if config.form %}
+        <input class="xmlui_widget xmlui_string" type="text" {{ {'name':wid.name, 'id':id, 'value':wid|item_filter(config.filters)}|dict_ext(config.attrs, wid.name)|xmlattr }}>
+    {% else %}
+        <div class="xmlui_widget xmlui_string"  {{ {'id':id}|xmlattr }}>
+            {{- wid|item_filter(config.filters)|default('\u00A0',true) -}}
+        </div>
+    {% endif %}
+{% endmacro%}
+
+{% macro textbox_widget(wid, config, id=none) %}
+    {% if config.form %}
+        <textarea class="xmlui_widget xmlui_textbox" rows="10" cols="50" {{ {'name':wid.name, 'id':id}|dict_ext(config.attrs, wid.name)|xmlattr }}>
+            {{- wid|item_filter(config.filters) -}}
+        </textarea>
+    {% else %}
+        <p class="xmlui_widget xmlui_textbox" {{ {'id':id}|xmlattr }}>
+            {{- wid|item_filter(config.filters) -}}
+        </p>
+    {% endif %}
+{% endmacro%}
+
+{% macro list_widget(wid, config, id=none) %}
+    {% if config.form %}
+        <select class="xmlui_widget xmlui_list" {{ {'name':wid.name, 'id':id}|dict_ext(config.attrs, wid.name)|xmlattr }}>
+            {% for value,label in wid.options %}
+                <option {{ {'value':value}|xmlattr }} {{ 'selected' if value in wid.selected }}>
+                    {{- label -}}
+                </option>
+            {% endfor %}
+        </select>
+    {% else %}
+        <div class="xmlui_widget xmlui_list" {{ {'id':id}|xmlattr }}>
+            {% for value,label in wid.items %}
+                <span class="xmlui_list_item value_{{value|attr_escape}}">
+                    {{- label -}}
+                </span>
+            {% endfor %}
+        </div>
+    {% endif %}
+{% endmacro%}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/invitation/welcome.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,13 @@
+{% extends 'base/base.html' %}
+
+{% block body %}
+<div class='invitation_header'>
+    <h1>{% trans %}Welcome {{name}}{% endtrans %}</h1>
+    <p class='instructions'>{% trans %}You have been invited to participate with the community, please choose an action below{% endtrans %}</p>
+</div>
+
+{% if include_url is defined %}
+<iframe id='include_main' src='{{include_url}}'></iframe>
+{% endif %}
+
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/login/logged.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,27 @@
+{% set post_confirm_message=_("You have been logged correctly") %}
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% block title %}{{C.APP_NAME}}{% endblock %}
+
+{% block confirm_message %}
+    {% trans %}You have been logged correctly{% endtrans %}
+{% endblock confirm_message %}
+
+{% block body %}
+<div id='logged'>
+    <div class='logged_box box'>
+        {% if guest_session %}
+            <p>{% trans %}You are logged as a guest{% endtrans %}</p>
+        {% else %}
+            <p>{% trans name='<span class="logged_profile">'|safe + profile + '</span>'|safe %}You are logged under the account {{name}} {% endtrans %}</p>
+        {% endif %}
+        <p>{% trans session_started='<span class="logged_time">'|safe + session_started|date_fmt('relative') + '</span>'|safe %}You logged {{session_started}}{% endtrans %}</p>
+    </div>
+    {% call form.form() %}
+        {{ field.meta('type', 'disconnect') }}
+        {{ field.submit(_("Disconnect")) }}
+    {% endcall %}
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/login/login.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,59 @@
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% block title %}{{C.APP_NAME}} login{% endblock %}
+
+{% block body %}
+<div id="login_container">
+<div id="login_box">
+    <div id="login_left">
+        <img src="{{media_path}}libervia/register_left.png">
+    </div>
+    <div id="login_right">
+        {% block login_right_top %}{% endblock %}
+        {% if login_error is defined %}
+            {# error messages displayed in case of failing attempt to login #}
+            <div id="login_error">
+                <p>
+                {% block login_error_message %}
+                {% if login_error == S_C.PROFILE_AUTH_ERROR %}
+                    {%- trans %}Your login and/or password is incorrect. Please try again.{% endtrans -%}
+                {% elif login_error == S_C.XMPP_AUTH_ERROR %}
+                    {%- trans %}Your XMPP account failed to connect. Did you enter the good password? If you have changed your XMPP password since your last connection on Libervia, please use another SàT frontend to update your profile.{% endtrans -%}
+                {% elif login_error == S_C.NO_REPLY %}
+                    {%- trans %}Did not received a reply (the timeout expired or the connection is broken).{% endtrans -%}
+                {% else %}
+                    {%- trans %}An unknown error occurred, please contact your service administrator.{% endtrans -%}
+                {% endif %}
+                {% endblock login_error_message %}
+                </p>
+            </div>
+        {% endif %}
+
+        <div id="login_form">
+            {% block login_form %}
+            {% call form.form() %}
+                {{ field.meta('type', 'login') }}
+                {{ field.text("login", _("Login"),
+                              required=true,
+                              value=login,
+                              )}}
+                {{ field.password("password", _("Password"), required=not empty_password_allowed) }}
+                {{ field.submit(_("Log in")) }}
+            {% endcall %}
+            {% endblock login_form %}
+        </div>
+        {% block login_right_bottom %}
+        {% if register_url is defined %}
+            <div id="create_account_link">
+                <p>
+                    <a href="{{register_url}}">{% trans %}No account yet? Create a new one!{% endtrans %}</a>
+                </p>
+            </div>
+        {% endif %}
+        {% endblock login_right_bottom %}
+    </div>
+</div>
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/login/register.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,49 @@
+{% extends 'login/login.html' %}
+
+{% block title %}{{C.APP_NAME}} register new account{% endblock %}
+
+{% block login_error_message %}
+{% if login_error == S_C.ALREADY_EXISTS %}
+    {%- trans %}This login already exists, please choose another one.{% endtrans -%}
+{% elif login_error == S_C.INVALID_INPUT %}
+    {%- trans %}The data you entered are nod valid.{% endtrans -%}
+{% elif login_error == S_C.BAD_REQUEST %}
+    {%- trans %}Bad request, please contact your service administrator{% endtrans -%}
+{% else %}
+    {%- trans %}An unknown error occurred, please contact your service administrator.{% endtrans -%}
+{% endif %}
+{% endblock login_error_message %}
+
+{% block login_right_top %}
+{% if login_url is defined %}
+    <div id="login_link">
+        <a href="{{login_url}}">
+            {%- trans %}Go to login page{% endtrans -%}
+        </a>
+    </div>
+{% endif %}
+{% endblock login_right_top %}
+
+{% block login_form %}
+{% call form.form(class='register') %}
+    {{ field.meta('type', 'register') }}
+    {{ field.text("login", _("Login"),
+                  required=true,
+                  pattern=S_C.REG_LOGIN_RE,
+                  title=_("Login must be lower case, with only plain letters (a-z), numbers (0-9) or underscore(_)"),
+                  value=login,
+                  )}}
+    {{ field.email("email", _("Email"),
+                   required=true,
+                   value=email,
+                   )}}
+    {{ field.password("password", _("Password"),
+                      required=true,
+                      minlength=S_C.PASSWORD_MIN_LENGTH,
+                      value=password,
+                      )}}
+    {{ field.submit(_("Register new account")) }}
+{% endcall %}
+{% endblock login_form %}
+
+{% block login_right_bottom %}{% endblock %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/merge-request/create.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,9 @@
+{# creata a new ticket #}
+
+{% set category_menu = [('merge-requests', url_tickets_list)] %}
+{% extends 'base/base.html' %}
+{% block body %}
+<div class="box message--info">
+    <p>{% trans %}It is not yet possible to create a merge request from inside Libervia, please use <pre>jp merge-request set</pre> for now. Merge requests welcome ;){% endtrans %}</p>
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/merge-request/discover.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,25 @@
+{% extends 'base/base.html' %}
+{% import 'components/block.html' as block with context %}
+{% import 'components/images.html' as images with context %}
+{% import 'components/avatar.html' as avatar with context %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% block body %}
+{{ icon_defs('merge') }}
+<p class="instructions--head">
+    {% trans %}
+    Please select a merge-requests handler
+    {% endtrans %}
+</p>
+{% if mr_handlers is defined %}
+    <div class="disco_tickets">
+        {{block.disco_icon_grid(mr_handlers, 'merge')}}
+    </div>
+{% endif %}
+
+{% call form.form(class="form--single") %}
+    {{ field.text("jid", _("handler jid"), required=true)}}
+    {{ field.submit(_("Access")) }}
+{% endcall %}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/merge-request/edit.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,26 @@
+{# edit an existing ticket #}
+
+{% set category_menu = [('merge-requests', url_tickets_list),
+                        ('merge-request_new', url_tickets_new)] %}
+{% extends 'base/base.html' %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+{% import 'input/xmlui.html' as xmlui with context %}
+
+{% block body %}
+<div class='instructions'>
+    <p><span class="box">{% trans app_name=C.APP_NAME%}Note: to modify content of the merge request, you'll have to use command line (with jp){% endtrans %}</span></p>
+</div>
+<div class="create single ticket box">
+{% call form.form() %}
+    {{ xmlui.generate(new_ticket_xmlui,
+                      attributes = {'title': {'required': 'required',
+                                              'placeholder': _("Short description of your issue/request")},
+                                    'body': {'required': 'required',
+                                             'placeholder': _("Please describe your issue/request with as much details as possible")},
+                                    'labels': {'placeholder': _("You can enter one or several labels separated by commas")},
+                                    })}}
+    {{ field.submit(_("Modify ticket")) }}
+{% endcall %}
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/merge-request/item.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,73 @@
+{# display a single ticket
+
+    @variable item(xmlui_item): ticket to display
+    @variable comments(data_object.BlogItems): comments of the ticket
+    @variable comments_service(unicode): service for adding comments
+    @variable comments_node(unicode): node for adding comments
+#}
+
+{% set category_menu = [('merge-requests', url_tickets_list),
+                        ('merge-request_new', url_tickets_new)] %}
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% import 'input/xmlui.html' as xmlui with context %}
+{% import 'blog/macros.html' as blog with context %}
+{% import 'input/textbox.html' as textbox with context %}
+
+{% block title %}{{item|adv_format('[{value.widget_value.id}] {value.widget_value.title}') }}{% endblock %}
+
+{% block confirm_message %}
+    {% trans %}Your comment has been sent{% endtrans %}
+{% endblock confirm_message %}
+
+{% block body %}
+{{ icon_defs('pencil') }}
+<div class="tab_container">
+    <div class="tab_header">
+        <ul>
+            <li class="tab_button clicked" onclick='toggle_clicked_class_sel(".tab_button,.tab_page")'>{% trans %}Description{% endtrans %}</li>
+            <li class="tab_button" onclick='toggle_clicked_class_sel(".tab_button,.tab_page")'>{% trans %}Patches{% endtrans %}</li>
+        </ul>
+    </div>
+    <div class="tab_page clicked" id="tab_description">
+        <div id="{{ item.widget_value['id'] }}" class="view single ticket box">
+            {% if url_ticket_edit is defined %}
+                <p class="box__tools">
+                    <a href="{{url_ticket_edit}}">
+                    {{ icon('pencil', cls='icon--small') }}
+                    edit
+                    </a>
+                </p>
+            {% endif %}
+            {{ xmlui.generate(item,
+                form=false,
+                filters={'created': {'filters': ['date_fmt'], 'filters_args':[{'fmt': 'short'}]},
+                         'updated': {'filters': ['date_fmt'], 'filters_args':[{'fmt': 'short'}]},
+                         'body': {'filters': ['urlize'], 'filters_args':[{'nofollow': True, 'rel': 'noopener noreferrer'}]}},
+                )}}
+        </div>
+        {% if comments is defined %}
+        <div id="blog_items">
+            {{ blog.show_items(comments|reverse, expanded=true) }}
+        </div>
+        {% endif %}
+        {% if comments_node is defined %}
+            <div class="comment_post">
+                {{- textbox.comment_or_login(service=comments_service, node=comments_node) -}}
+            </div>
+        {% endif %}
+    </div>
+    <div class="tab_page" id="tab_patches">
+        {% for patch in patches %}
+            <div class="patch">
+                <header class="box">
+                    <div class="author"><label>{% trans %}author:{% endtrans %} </label>{{patch.author}}</div>
+                    <p class="commit_msg">{{patch.commit_msg}}</p>
+                </header>
+                <div class="diff">
+                    {{- patch.diff|highlight('diff') -}}
+                </div>
+            </div>
+        {% endfor %}
+    </div>
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/photo/album.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,33 @@
+{% extends 'base/base.html' %}
+{% import 'input/textbox.html' as textbox with context %}
+{% import 'blog/macros.html' as blog with context %}
+
+{% block body %}
+{{ icon_defs('comment-empty') }}
+<div class="album">
+    {% for file in files_data %}
+        {% if file.type == C.FILE_TYPE_FILE %}
+            <div class="album__item">
+                <div class="album__vignette">
+                    <img src="{{file.thumb_url}}" class="album__thumbnail" alt="{{file.name}}">
+                </div>
+                {% if file.comments_url is defined %}
+                    <span class='album__comments-bar' onclick="clicked_mh_fix('{{'comments_panel'|next_gidx}}')">
+                        {% trans %}comments{% endtrans %}
+                        {% if file.comments_count %}
+                            <span class='comments__count'>({{file.comments_count}})</span>
+                        {% endif %}
+                        {{ icon('comment-empty', cls='icon--small') }}
+                    </span>
+                    <div id='{{'comments_panel'|cur_gidx}}' class="panel-drawer">
+                        {{ blog.show_items(file.comments, expanded=true, dates_fmt='relative') }}
+                        <div class="comment_post">
+                            {{- textbox.comment_or_login(service=file.comments_service, node=file.comments_node) -}}
+                        </div>
+                    </div>
+                {% endif %}
+            </div>
+        {% endif %}
+    {% endfor %}
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/photo/discover.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,11 @@
+{% extends 'base/base.html' %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% block body %}
+<p class="instructions--alt">{% trans %}Photo discovery is not implemented yet, however you can enter a jid below to find its albums{% endtrans %}</p>
+{% call form.form(class="form--single") %}
+    {{ field.text("jid", _("device full jid"), required=true)}}
+    {{ field.submit(_("Access")) }}
+{% endcall %}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/session/disconnect.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,5 @@
+{% extends 'base/base.html' %}
+
+{% block body %}
+<p>{% trans %}You have been disconnected, have a nice day!{% endtrans %}</p>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/app.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,21 @@
+#body {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+#web_app_box {
+    width: 80%;
+    padding: 2em;
+    text-align: justify;
+}
+
+#link_section {
+    font-weight: bold;
+    text-align: center;
+    font-size: 1.5rem;
+}
+
+article p:last-child {
+    text-align: center;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/blog.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,313 @@
+/*** articles ***/
+
+article.box {
+    position: relative;
+    margin: 2% auto;
+    border-style: solid none none;
+    border-width: 1px;
+    padding: 2%;
+    min-height: 9em;
+    max-height: 20em;
+    overflow: hidden;
+    transition: max-height 0.5s;
+}
+
+article video {
+    max-width: 100%;
+    height: auto;
+}
+
+.main_article article.box:not(.clicked) {
+    border-bottom-right-radius: 0;
+    border-bottom-left-radius: 0;
+}
+
+/** header **/
+
+header a {
+    color: inherit;
+    text-decoration: inherit;
+}
+
+header .metadata {
+    text-align: right;
+}
+
+article .author {
+    font-weight: bold;
+}
+
+article .author::after {
+    content: ", ";
+}
+
+/*** labels ***/
+
+.labels {
+    text-align: right;
+    white-space: nowrap;
+}
+
+.labels a {
+    text-decoration: none;
+    color: inherit;
+}
+
+.labels span {
+    font-variant: small-caps;
+    font-size: 0.8rem;
+    background-color: #ddd;
+    border-radius: 0.4em;
+    padding: 0 0.5em;
+    transition: all 0.5s;
+}
+
+.labels a>span {
+    cursor: pointer;
+}
+
+.labels a>span:hover {
+    box-shadow: 0px 0px 6px 1px #000;
+}
+
+
+/** content **/
+
+article div.content {
+    text-align: justify;
+    font-size: 0.9em;
+}
+
+article div.content.text {
+    white-space: pre-wrap;
+}
+
+
+article img {
+    max-width: 100%;
+    margin: 0;
+}
+
+/** reduce/expand buttons **/
+
+.expand_box {
+    cursor: pointer;
+}
+
+.box_top {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+}
+
+.box_bottom {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+}
+
+.expand_box.box_bottom::before {
+    /* we do a gradient to show that text can be expanded */
+    background-image: linear-gradient(to bottom,rgba(0,0,0,0),#ffffff);
+    display: block;
+    content: "";
+    width: 100%;
+    height: 4em;
+    border: none;
+}
+
+.expand_box p {
+    background-color: white;
+    margin: 0;
+    text-align: center;
+    font-weight: bold;
+    font-size: 0.8em;
+    border-style: solid none dotted none;
+    border-width: 1px 0 1px;
+    border-bottom-color: gray;
+}
+
+article .expand_box .hide {
+    /* when not clicked, we only display .show */
+    display: none;
+}
+
+article .expand_box.box_top {
+    /* top expand box only show a reduce button
+     * so it should be displayed only when article is .clicked */
+    display: none;
+}
+
+/** other language **/
+
+/* we hide everything just to display a message informing that
+ * the item is in an other language, and asking to click
+ * to display it */
+
+article.other_lang>div.info {
+    display: none;
+}
+
+article.other_lang.init>* {
+    display: none;
+}
+
+article.other_lang.init>div.info {
+    display: initial;
+}
+
+article.other_lang.init>div.expand_box.box_top {
+    /* as we need to have the message clickable, we cheat and use
+     * expand box on the whole surface but fully transparent */
+    display: initial;
+    height: 100%;
+    opacity: 0;
+}
+
+article.other_lang.init>div.info>p {
+    margin: 0;
+    padding: 0.2em;
+    text-align: center;
+    font-style: italic;
+}
+
+article.other_lang.init {
+    border: none;
+    border-radius: 0;
+    padding: 0;
+    min-height: 0;
+}
+
+/*** comments ***/
+
+button.comments_btn {
+    border: none;
+    font-weight: bold;
+    display: block;
+    margin: 0 10% 0 auto;
+    border-radius: 1em;
+    background:  #b8bcc4;
+    color: #4d4d4d;
+}
+
+button.comments_btn:active {
+    background: #4d4d4d;
+    color: #b8bcc4;
+}
+
+button.comments_btn.clicked span.show {
+    display: none;
+}
+
+button.comments_btn:not(.clicked) span.hide {
+    display: none;
+}
+
+.comments_panel {
+    max-height: 0;
+    opacity: 0;
+    transition: max-height 1s, opacity 2s;
+    overflow: hidden;
+}
+
+.comments_panel.clicked {
+    opacity: 1;
+}
+
+.comments article {
+    background-color: #9ca0a8;
+    border: none;
+    max-height: none;
+}
+
+.comment_post {
+    text-align: center;
+}
+
+.comment_post textarea {
+    border-style: solid;
+    border-width: 1px  0;
+    border-color: black;
+    max-width: 100%;
+}
+
+.comments_panel article .expand_box {
+    /* no expand box in comments */
+    display: none;
+}
+
+/*** media queries ***/
+
+@media (min-width: 500px) {
+    /*** general ***/
+
+    #main_area {
+        background-image: var(--bg-img);
+        background-repeat: no-repeat;
+        background-size: cover;
+    }
+
+    article.box {
+        width: 80%;
+        border-style: solid solid none solid;
+    }
+    .comments article.box {
+        width: 30rem;
+        margin: 2% auto;
+        border: none;
+    }
+    .comment_post textarea {
+        border-width: 1px;
+        border-radius: 1em;
+        border: solid 1px;
+        padding: 0.5em;
+    }
+
+    footer span {
+        background: rgba(200,200,200,0.6);
+        border-radius: 0.5em 0.5em 0 0;
+        padding: 0 0.5em;
+        margin-top: 1em;
+    }
+
+}
+
+/*** clicked ***/
+
+.main_article article.clicked {
+    border-bottom-style: solid;
+}
+
+.main_article article.clicked .expand_box.box_top {
+    display: initial;
+}
+
+.main_article article.clicked .expand_box {
+    opacity: 0;
+    transition: opacity 0.5s;
+}
+
+.main_article article.clicked .expand_box p {
+    background-color: transparent;
+    border: none;
+}
+
+.main_article article.clicked .expand_box:hover {
+    opacity: 1;
+    color: grey;
+}
+
+.main_article article.clicked .expand_box::before {
+    background-image: none;
+    display: none;
+}
+
+.main_article article.clicked .expand_box .hide {
+    display: inline;
+}
+
+.main_article article.clicked .expand_box .show {
+    display: none;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/chat.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,83 @@
+:root {
+  --message_input-height: 2rem;
+}
+
+#main_area {
+    overflow: hidden;
+}
+
+.chat_widget {
+	position: absolute;
+    height: 100%;
+    width: 100%;
+    box-sizing: border-box;
+    display: flex;
+    flex-direction: column;
+}
+
+#messages {
+    height: 100%;
+    min-height: 150px;
+    overflow: auto;
+    box-sizing: border-box;
+    resize: vertical;
+    transition: height 0.6s;
+}
+
+#subject {
+	padding: 1em;
+	text-align: center;
+	background: #eee;
+	font-style: italic;
+}
+
+#messages > p {
+    margin: 0;
+    padding: 0.5em 0 0 0.5em;
+}
+
+#messages .msg_body {
+    white-space: pre-wrap;
+}
+
+#message_input {
+    width: 100%;
+    height: 100%;
+    padding-top: 0.5rem;
+    margin: 0;
+    box-sizing: border-box;
+    resize: none;
+}
+
+.message_box {
+    flex: 1 1 calc(var(--message_input-height));
+    position: relative;
+    min-height: 1rem;
+    box-sizing: border-box;
+}
+
+
+#messages > p.msg_info {
+    white-space: pre-wrap;
+    font-family: monospace;
+    color: #049282;
+}
+
+.msg_header {
+	display: block;
+	font-size: 0.9em;
+}
+
+.author {
+    font-weight: bold;
+}
+
+.date {
+	color: #777;
+}
+
+@media (min-width: 800px) {
+    #messages > p {
+        padding-left: 1.5em;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/chat.js	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,60 @@
+/* SàT Template: Chat page handling
+ *
+ * Copyright (C) 2017 Jérôme Poisson (goffi@goffi.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+var msgInput = document.getElementById('message_input');
+var messages = document.getElementById('messages');
+const messagesTransitionOri = messages.style.transition;
+
+msgInput.addEventListener('keypress', function(event) {
+    if (event.which == 13 && !event.shiftKey) {
+        if (messages.style.height !== '100%') {
+            messages.style.transition = messagesTransitionOri;
+            setTimeout(function() {
+                messages.style.transition = 'initial';
+                messages.scrollTop = messages.scrollHeight;
+            }, 1000);
+            messages.style.height = "100%";
+        }
+        if (!this.value.trim()) {
+            return;
+        }
+        socket.send({'type': 'msg',
+                     'body': this.value});
+        this.value = '';
+        event.preventDefault();
+    }}
+);
+
+var mutationCb = function(mutationsList) {
+    scrollPos = messages.scrollTop + messages.clientHeight;
+    if (messages.lastChild.offsetTop - scrollPos - 10 <= 0) {
+        // we auto scroll only if we are at the bottom of the page
+        // else the use is probably checking history
+        // Note thas this doesn't take margin into account,
+        // we suppose margin to be 0 for messages children
+        messages.scrollTop = messages.scrollHeight;
+    }
+};
+
+var observer = new MutationObserver(mutationCb);
+
+observer.observe(messages, { childList: true });
+// we want to start with scrolling at bottom
+messages.scrollTop = messages.scrollHeight;
+messages.style.transition = 'initial';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/chat_select.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,39 @@
+#main_area {
+    overflow: auto;
+}
+
+.rooms_list {
+	list-style: none;
+    display: grid;
+    text-align: center;
+    padding: 0;
+}
+
+.rooms_list a {
+	text-decoration: none;
+	color: inherit;
+	font-variant: small-caps;
+	font-weight: bold;
+}
+
+.rooms_list li {
+    margin-top: 1em;
+}
+
+.rooms_list li:first-child {
+    margin-top: 0;
+}
+
+.rooms_list li:hover {
+    background-color: #efefef;
+}
+
+@media (min-width: 600px) {
+    .rooms_list {
+        grid-template-columns: 1fr 1fr 1fr;
+    }
+
+    .rooms_list li {
+        margin-top: 0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/common.js	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,134 @@
+var __session_storage_available;
+var __local_storage_available;
+
+function storageAvailable(type) {
+    /* check if session or local storage is available
+     *
+     * @param type(string): "session" or "storage"
+     * @return (boolean): true if requested storage is available
+     */
+    console.assert(type == 'session' || type == 'storage', "bad storage type (%s)", type);
+    const var_name = '__' + type + '_storage_available';
+    var available = window[var_name];
+    if (available === undefined) {
+        // test method from https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
+        var storage = window[type + 'Storage'];
+        try {
+            x = '__storage_test__';
+            storage.setItem(x, x);
+            storage.removeItem(x);
+            available = true;
+        }
+        catch(e) {
+            available = e instanceof DOMException && (
+                    // everything except Firefox
+                    e.code === 22 ||
+                    // Firefox
+                    e.code === 1014 ||
+                    // test name field too, because code might not be present
+                    // everything except Firefox
+                    e.name === 'QuotaExceededError' ||
+                    // Firefox
+                    e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
+                // acknowledge QuotaExceededError only if there's something already stored
+                storage.length !== 0;
+        }
+
+        if (!available) {
+            console.warn("%s storage not available", type);
+        }
+        window[var_name] = available;
+    }
+
+    return available;
+}
+
+function toggle_clicked_class_tag(tag_name, class_name='clicked') {
+    for (let elt of document.getElementsByTagName(tag_name)) {
+        elt.classList.toggle(class_name);
+    }
+}
+
+function toggle_clicked_class_sel(selectors, class_name='clicked') {
+    for (let elt of document.querySelectorAll(selectors)) {
+        elt.classList.toggle(class_name);
+    }
+}
+
+function set_clicked_class_id(trigger_elem_id, target_elem_id=null, class_name='clicked') {
+    if (target_elem_id === null) { target_elem_id = trigger_elem_id; }
+    document.getElementById(trigger_elem_id).addEventListener(
+        "click",
+        function() {
+            document.getElementById(target_elem_id).classList.toggle(class_name);
+        }
+    );
+}
+
+function get_elt(arg) {
+    if (typeof arg === 'string') {
+        // we should have an id
+        return document.getElementById(arg);
+    }
+    else {
+        // we should have an element
+        return arg;
+    }
+}
+
+function clicked_cls(elt) {
+    /* toggle "clicked" class on each click, and remove "init" class if present */
+    // init
+    if (elt.classList.contains("init")) {
+        elt.classList.remove("init");
+    }
+
+    // clicked
+    elt.classList.toggle("clicked");
+}
+
+function clicked_mh_fix(arg) {
+    /* toggle clicked, and fix max-height on transitionend
+     *
+     * needed to workaround transition issue with max-height:none
+     * inspired from https://css-tricks.com/using-css-transitions-auto-dimensions,
+     * thanks to Brandon Smith
+     *
+     * @param arg: element to toggle (id as string, or element itself)
+     * */
+    elt = get_elt(arg);
+
+    if (!elt.classList.contains("clicked")) {
+        /* expand */
+        var fix_expand = function(event) {
+            elt.removeEventListener("transitionend", fix_expand, false);
+            if (elt.classList.contains("clicked")) {
+                /* if event is clicked quicker than transition time,
+                 * this callback can be called on reduce */
+                elt.style.maxHeight = "none";
+            }
+        };
+
+        elt.setAttribute('max_height_init', elt.clientHeight);
+        elt.addEventListener("transitionend", fix_expand, false);
+        clicked_cls(elt);
+        elt.style.maxHeight = elt.scrollHeight + 'px';
+    }
+    else {
+        /* reduce */
+        var transition_save = elt.style.transition;
+        elt.style.transition = '';
+        requestAnimationFrame(function() {
+            elt.style.maxHeight = elt.scrollHeight + 'px';
+            elt.style.transition = transition_save;
+
+            requestAnimationFrame(function() {
+                elt.style.maxHeight = elt.getAttribute('max_height_init') + 'px';
+                elt.removeAttribute('max_height_init');
+                elt.style.maxHeight = null;
+            });
+        });
+
+        clicked_cls(elt);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/event.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,92 @@
+@import 'blog.css'; /* needed as blog/articles.html is included */
+
+.invitation_header {
+    text-align: center;
+    font-variant: small-caps;
+    border: none;
+}
+
+.instructions {
+    font-style: italic;
+    margin: 0;
+}
+
+.event__picture {
+    max-width: 100%;
+    border-radius: 2em;
+}
+
+.event__counter {
+    font-weight: bold;
+    font-size: 1.3em;
+    text-align: center;
+    width: 15em;
+    margin: 1em auto;
+    border: 2px solid #aab6c4;
+    background-color: #f3e7e7;
+    color: #2f3943;
+}
+
+.attendance {
+    background-color: #9ca0a8;
+    padding: 0 0.3em;
+    max-width: 580px;
+    margin: 0 auto;
+    color: #3A3A3A;
+}
+
+.attending {
+    width: 6em;
+    margin: 0 auto;
+}
+
+.attending label {
+    /* display: inline; */
+    margin: 0.8em 0;
+}
+
+.guests label {
+    display: block;
+    margin: 1em 0;
+}
+
+.guests input {
+    width: 2.5em;
+    margin: 0 1em;
+}
+
+.poll_instructions {
+    font-weight: bold;
+    font-size: 0.9em;
+    font-size: 1.1em;
+    text-align: center;
+}
+
+.guests label{
+    text-align: center;
+    /* font-style: italic */
+}
+
+.guests input {
+    display: block;
+    margin: 0 auto;
+}
+
+.submit {
+    width: 15em;
+    margin: 0 auto;
+    padding: 1em 0;
+}
+
+.submit input {
+    width: 100%;
+}
+
+@media (min-width: 500px) {
+    .invitation_header {
+        width: 94%;
+        margin: 0 auto;
+        border: solid 1px;
+        border-color: #9ca0a8;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/file.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,49 @@
+#files {
+    list-style: none;
+    display: flex;
+    flex-wrap: wrap;
+}
+
+.file {
+    padding: 0 0 0.5em;
+    width: 100px;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    text-align: center;
+    overflow-wrap: break-word;
+}
+
+.file:hover {
+    background: #ddd;
+    overflow: visible;
+}
+
+.file a {
+    text-decoration: none;
+    outline: none;
+}
+
+.file a:focus img {
+    outline: 3px solid #bbb;
+}
+
+.file__icon {
+    height: 3em;
+    display: block;
+    margin: 0 auto;
+}
+
+.file__thumbnail {
+    max-width: 300px;
+    height: 125px;
+    display: block;
+    margin: 0 auto;
+}
+
+
+@media (min-width: 500px) {
+    .file {
+        padding: 1em;
+        width: 170px;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/fonts.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,63 @@
+/* generated from https://google-webfonts-helper.herokuapp.com */
+
+/* *** sat_base_font *** */
+
+/* sat_base_font-regular - latin-ext_latin */
+@font-face {
+  font-family: 'sat-base-font';
+  font-style: normal;
+  font-weight: 400;
+  src: local('sat-base-font'), local('sat-base-font-Regular'),
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* sat_base_font-italic - latin-ext_latin */
+@font-face {
+  font-family: 'sat-base-font';
+  font-style: italic;
+  font-weight: 400;
+  src: local('sat-base-font Italic'), local('sat-base-font-Italic'),
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* sat_base_font-700 - latin-ext_latin */
+@font-face {
+  font-family: 'sat-base-font';
+  font-style: normal;
+  font-weight: 700;
+  src: local('sat-base-font Bold'), local('sat-base-font-Bold'),
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* sat_base_font-900 - latin-ext_latin */
+@font-face {
+  font-family: 'sat-base-font';
+  font-style: normal;
+  font-weight: 900;
+  src: local('sat-base-font Black'), local('sat-base-font-Black'),
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* sat_base_font-700italic - latin-ext_latin */
+@font-face {
+  font-family: 'sat-base-font';
+  font-style: italic;
+  font-weight: 700;
+  src: local('sat-base-font Bold Italic'), local('sat-base-font-BoldItalic'),
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
+
+/* sat_base_font-900italic - latin-ext_latin */
+@font-face {
+  font-family: 'sat-base-font';
+  font-style: italic;
+  font-weight: 900;
+  src: local('sat-base-font Black Italic'), local('sat-base-font-BlackItalic'),
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
+       url('fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/fonts/sat_base_font/README.txt	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,7 @@
+This font is based on the Alegreya font by Juan Pablo del Peral (juan@huertatipografica.com.ar), it has been modified to be compressed using https://google-webfonts-helper.herokuapp.com, and put here for being embedded in Salut à Toi templates, to avoid privacy issues with third party website download.
+
+As the name is a reserved name and the compression make the font a derivative, this font has been renamed to "sat_base_font", according to the recommandation read at http://scripts.sil.org/cms/scripts/page.php?item_id=OFL-FAQ_web#1db14da7
+
+Thanks to Juan Pable del Peral for his work!
+
+The license "SIL Open Font License, Version 1.1" only apply to this directory.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/fonts/sat_base_font/SIL Open Font License.txt	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,44 @@
+Copyright (c) 2011, Juan Pablo del Peral (juan@huertatipografica.com.ar), 
+with Reserved Font Names "Alegreya" "Alegreya SC"
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
+
+"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
+
+5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
\ No newline at end of file
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700.woff2 has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-700italic.woff2 has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900.woff2 has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-900italic.woff2 has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-italic.woff2 has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff has changed
Binary file sat_templates/templates/default/static/fonts/sat_base_font/sat_base_font-v7-latin-ext_latin-regular.woff2 has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/forum.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,82 @@
+@import 'blog.css'; /* needed as blog/articles.html is included */
+
+.forums {
+    margin: 2em auto 0 auto;
+    width: 90%;
+}
+
+ul.forum {
+    list-style: none;
+}
+
+ul.forum__panel_sub {
+    box-sizing: border-box;
+    display: flex;
+    flex-flow: row wrap;
+    margin: 0 auto;
+}
+
+.forum__cat_sub {
+    margin: 0.5em 1em;
+    width: 25em;
+}
+
+.forum__cat_sub>a {
+    border: 0.7rem solid #ddd;
+    border-radius: 0.5em;
+    display: block;
+    padding: 1rem;
+    margin-bottom: 1rem;
+    text-decoration: none;
+    color: inherit;
+}
+
+a.forum_active:hover {
+    background-color: #43d2f6;
+}
+
+p.forum_short-desc {
+    color: #666;
+    margin: 0;
+    font-size: 0.8em;
+}
+
+.forum__topics {
+    margin-top: 3em;
+}
+
+.forum__topics>div {
+    box-sizing: border-box;
+    width: 80%;
+    margin: 0.5em auto;
+    padding: 0.2em 2em;
+    background: #eee;
+
+}
+
+.forum__topics>:hover {
+    background-color: #43d2f6;
+}
+
+.forum__topics img.avatar {
+    vertical-align: middle;
+    margin-right: 1em;
+}
+
+.forum__topics a {
+    display: block;
+    text-decoration: none;
+    color: inherit;
+}
+
+.textbox input {
+    width: 100%;
+    box-sizing: border-box;
+}
+
+@media (min-width: 500px) {
+    .textbox input {
+        min-width: 26em;
+        width: auto;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/highlight.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,77 @@
+/* This file as been generated from Pygments using
+ * f.write(HtmlFormatter().get_style_defs('.highlight'))
+ * where f was an open file.
+ * It is used in Libervia for highlighting code or markup
+ * If changes are needed, they should be done in a separate CSS file
+ * so this one keep Pygments' defaults
+ */
+.highlight .hll { background-color: #ffffcc }
+.highlight  { background: #f8f8f8; }
+.highlight .c { color: #408080; font-style: italic } /* Comment */
+.highlight .err { border: 1px solid #FF0000 } /* Error */
+.highlight .k { color: #008000; font-weight: bold } /* Keyword */
+.highlight .o { color: #666666 } /* Operator */
+.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
+.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
+.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
+.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #A00000 } /* Generic.Deleted */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #FF0000 } /* Generic.Error */
+.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+.highlight .gi { color: #00A000 } /* Generic.Inserted */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+.highlight .gt { color: #0044DD } /* Generic.Traceback */
+.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
+.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
+.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
+.highlight .kp { color: #008000 } /* Keyword.Pseudo */
+.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #B00040 } /* Keyword.Type */
+.highlight .m { color: #666666 } /* Literal.Number */
+.highlight .s { color: #BA2121 } /* Literal.String */
+.highlight .na { color: #7D9029 } /* Name.Attribute */
+.highlight .nb { color: #008000 } /* Name.Builtin */
+.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+.highlight .no { color: #880000 } /* Name.Constant */
+.highlight .nd { color: #AA22FF } /* Name.Decorator */
+.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
+.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #0000FF } /* Name.Function */
+.highlight .nl { color: #A0A000 } /* Name.Label */
+.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
+.highlight .nv { color: #19177C } /* Name.Variable */
+.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mb { color: #666666 } /* Literal.Number.Bin */
+.highlight .mf { color: #666666 } /* Literal.Number.Float */
+.highlight .mh { color: #666666 } /* Literal.Number.Hex */
+.highlight .mi { color: #666666 } /* Literal.Number.Integer */
+.highlight .mo { color: #666666 } /* Literal.Number.Oct */
+.highlight .sa { color: #BA2121 } /* Literal.String.Affix */
+.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
+.highlight .sc { color: #BA2121 } /* Literal.String.Char */
+.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
+.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
+.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
+.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
+.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+.highlight .sx { color: #008000 } /* Literal.String.Other */
+.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
+.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
+.highlight .ss { color: #19177C } /* Literal.String.Symbol */
+.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
+.highlight .fm { color: #0000FF } /* Name.Function.Magic */
+.highlight .vc { color: #19177C } /* Name.Variable.Class */
+.highlight .vg { color: #19177C } /* Name.Variable.Global */
+.highlight .vi { color: #19177C } /* Name.Variable.Instance */
+.highlight .vm { color: #19177C } /* Name.Variable.Magic */
+.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/invitation.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,27 @@
+#body {
+    display: flex;
+    flex-direction: column;
+}
+
+.invitation_header {
+    flex: 1
+}
+
+.invitation_header h1,p {
+    text-align: center;
+}
+
+#include_main {
+    flex: 9
+}
+
+#include_main {
+    width: 100%;
+    margin: 0;
+    border: none;
+}
+
+footer {
+    /* footer should already be displayed in included page */
+    display: none;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/login.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,197 @@
+body {
+    background: #111;
+}
+
+footer {
+    color: #999;
+}
+
+#login_container {
+    display: flex;
+    height: 100%;
+    align-items: center;
+    justify-content: center;
+}
+
+#login_box {
+    display: flex;
+    background: #111;
+    color: #aaa;
+    width: 600px;
+    margin: auto;
+}
+
+#login_left {
+    display: none;
+}
+
+#login_right {
+    width: 100%;
+    position: relative;
+}
+
+#login_form {
+    margin-top: 60px;
+}
+
+#login_form label {
+    font-weight: bold;
+    display: block;
+    text-align: center;
+}
+
+#login_form input:not(.form_submit) {
+    display: block;
+    margin: 0 auto;
+    height: 25px;
+    line-height: 25px;
+    width: 200px;
+    text-indent: 11px;
+    background: #000;
+    color: #ccc;
+    border: 1px solid #555;
+    border-radius: 15px 15px 15px 15px;
+}
+
+#login_form input:not(.form_submit):focus {
+	box-shadow: 0 0 2px 2px #43d2f6;
+}
+
+#login_form input:hover {
+    background-color: #222;
+}
+
+#login_form input:focus {
+	border: 1px solid #999;
+	outline: none;
+}
+
+#login_box .form_input {
+    display: block;
+    margin-bottom: 1em;
+}
+
+#login_form .form_submit,
+#logged .form_submit {
+    /* FIXME: as above /media is not good.
+     * url should be replaced by real gradient */
+    color: #fff;
+    background: #222 url('/media/libervia/gradient.png') repeat-x;
+    font-weight: bold;
+    line-height: 1;
+    text-shadow: 0 -1px 1px rgba(0,0,0,0.25);
+    padding: 7px 10px 8px;
+    border: 0;
+    border-radius: 6px 6px 6px 6px;
+    cursor: pointer;
+    margin-top: 30px;
+}
+
+#login_error {
+    position: absolute;
+    margin: -90px 0 0;
+    width: 100%;
+    height: 150px;
+    overflow: auto;
+    font-size: 0.9em;
+	font-weight: bold;
+	color: lightcoral;
+	text-align: center;
+}
+
+#login_error p {
+    position: absolute;
+    bottom: 0;
+    margin-left: 46px;
+    margin-right: 46px;
+}
+
+#create_account_link {
+    width: 100%;
+    margin-top: 3em;
+}
+
+#login_link {
+    margin-top: 1em;
+}
+
+#create_account_link a,
+#login_link a {
+    text-decoration: none;
+    text-align: center;
+    font-size: 0.8em;
+    cursor: pointer;
+    color: #fff;
+    display: block;
+    text-shadow: 1px 1px 0px rgba(255, 255, 255, 0.2);
+}
+
+.logged_box {
+    margin: 3em;
+	padding: 1em;
+	text-align: center;
+	font-style: italic;
+}
+
+.logged_profile {
+    font-style: normal;
+    font-weight: bold;
+}
+
+#login_form form.register input[type=submit] {
+    margin-top: 0.5em;
+}
+
+@media (min-width: 600px) {
+    body {
+        background: transparent;
+    }
+
+    footer {
+        color: black;
+    }
+
+    #login_left {
+        display: inline;
+    }
+
+    #login_right {
+        /* FIXME: there is not way to correctly select images from
+         * media path at the moment */
+        background: url('/media/libervia/register_right.png');
+    }
+
+    #login_error {
+        width: auto;
+        max-height: 50px;
+        margin: 10px 46px 0;
+    }
+     
+    #login_error p {
+        position: static;
+        margin: 0;
+    }
+
+    #login_form label {
+        text-align: initial;
+        position: relative;
+        left: 50px;
+    }
+
+    #login_form label::after {
+        content: ':'
+    }
+
+    #login_form input:not(.form_submit) {
+        display: inline;
+        margin: 0;
+        position: relative;
+        left: 50px;
+    }
+
+    #create_account_link {
+        margin-top: 0;
+        bottom: 0;
+        position: absolute;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/merge-request.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,1 @@
+ticket.css
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/merge-request_item.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,44 @@
+@import 'highlight.css';
+
+.highlight {
+    overflow: auto;
+}
+
+.box {
+    border-radius: 0;
+    box-shadow: none;
+}
+
+.ticket {
+    max-width: none;
+}
+
+.xmlui_cont.xmlui_cont_vertical {
+    max-width: 780px;
+    margin: 0 auto;
+}
+
+.view #wid_body {
+    border: 1px solid silver;
+}
+
+#tab_patches {
+    overflow: auto;
+}
+
+#tab_patches header {
+    border-top: 1px solid silver;
+}
+
+#tab_patches header label {
+    font-weight: bold;
+}
+
+.commit_msg {
+    font-style: italic;
+    white-space: pre-wrap;
+}
+
+.diff {
+    white-space: pre;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/photo.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,51 @@
+@import 'blog.css'; /* needed for comments */
+
+.album {
+    display: flex;
+    flex-wrap: wrap;
+}
+
+.album__item {
+    width: 400px;
+	margin: 0 0.1em 2em 0.1em;
+}
+
+.album__vignette {
+    background-color: #444;
+    height: 300px;
+    position: relative;
+}
+
+.album__thumbnail {
+    height: 100%;
+    display: block;
+    margin: 0 auto;
+}
+
+.album__comments-bar {
+    display: block;
+    font-size: 0.8em;
+    color: black;
+    text-align: right;
+    cursor: pointer;
+}
+
+.album__comments-bar:hover {
+    background-color: #ddd;
+    font-weight: bold;
+}
+
+.comments__count {
+    font-weight: bold;
+}
+
+.panel-drawer {
+    max-height: 0;
+    opacity: 0;
+    transition: max-height 1s, opacity 2s;
+    overflow: hidden;
+}
+
+.panel-drawer.clicked {
+    opacity: 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/styles.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,747 @@
+:root {
+  --select-bg-color: #ddd;
+  --size-medium: 3em;
+}
+
+
+html {
+    font-family: "sat-base-font";
+}
+
+body {
+    margin: 0;
+    padding: 0;
+    display: flex;
+    height: 100vh;
+    flex-direction: column;
+    box-sizing: border-box;
+}
+
+ul {
+    padding: 0;
+}
+
+#main_side_bar {
+
+}
+
+#main_area {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    box-sizing: border-box;
+}
+
+#body {
+    flex: 1;
+    position: relative;
+}
+
+footer {
+    text-align: center;
+    font-size: 0.7em;
+    font-weight: bold;
+}
+.title {
+    font-weight: bold;
+    text-align: center;
+}
+
+.post_confirm {
+    text-align: center;
+    background-color: lightgreen;
+    padding: 1em;
+    font-size: 1.2em;
+    font-weight: bold;
+    width: 60%;
+    margin: 1.5em auto;
+}
+
+/*** Generic ***/
+
+.button {
+    padding: 0.5em 1em;
+    background: #333;
+    color: #ccc;
+    border: 1px solid #555;
+    border-radius: 0.8em;
+    font-weight: bold;
+}
+
+
+.button:hover {
+    background-color: #bc0000;
+}
+
+.instructions--head {
+    font-size: 1.5em;
+    text-align: center;
+}
+
+.instructions--alt {
+    text-align: center;
+    font-style: italic;
+}
+
+.items_vert--centered {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+/*** boxes ***/
+
+.box {
+    background-color: #edf2ff;
+    border-radius: 0;
+    border-color: silver;
+    margin: 0 auto;
+}
+
+.box--medium {
+    max-width: 50em;
+}
+
+.box--small {
+    max-width: 20em;
+}
+
+.box--hollow {
+    border-radius: 0;
+    border-style: solid;
+    border-color: silver;
+    border-width: 1px 0;
+    margin: 0;
+}
+
+.box--paper {
+    text-align: center;
+    font-variant: small-caps;
+    border: none;
+}
+
+.box--center {
+}
+
+.box__tools {
+    /* toolbar in a box */
+    margin: 0;
+    padding: 0;
+}
+
+.box__tools a {
+    text-decoration: none;
+    color: inherit;
+    padding: 0.2em;
+    border-radius: 0.4em;
+}
+
+.box__tools a:hover {
+    background-color: var(--select-bg-color);
+}
+
+
+/*** blocks ***/
+
+.block_separator {
+    font-size: 1.4em;
+    display: flex;
+}
+
+.block_separator__label {
+    display: inline-block;
+    margin: 0 0.2em;
+}
+
+.block_separator__line {
+    height: 1px;
+    background: #ccc;
+    flex: 1;
+    margin-top: 0.7em;
+}
+
+/*** lists ***/
+
+.list {
+    list-style: none;
+    display: flex;
+    flex-direction: column;
+}
+
+.list__item>a {
+    text-decoration: none;
+    color: inherit;
+}
+
+/*** grids ***/
+
+.grid {
+    display: flex;
+    flex-wrap: wrap;
+}
+
+ul.grid {
+    list-style: none;
+}
+
+.grid--center {
+    justify-content: center;
+}
+
+li.grid__item>a {
+    text-decoration: none;
+    color: inherit;
+}
+
+.grid__item--medium {
+   width: 170px;
+   padding: 0.2em;
+   text-align: center;
+}
+
+.grid__item--selectable {
+    cursor: pointer;
+}
+
+.grid__item--selectable:hover {
+    background-color: var(--select-bg-color);
+}
+
+/*** tables ***/
+
+.table--main {
+    margin: 1em auto;
+	border-collapse: collapse;
+    text-align: center;
+}
+
+.table--main th {
+    font-variant: small-caps;
+    border: 1px solid;
+    padding: 0.5em;
+}
+
+.table--main td {
+    border: 1px solid;
+    padding: 0 0.5em;
+}
+
+.table__total {
+    font-variant: small-caps;
+}
+
+.table__total_value {
+    font-weight: bold;
+}
+
+/*** avatars ***/
+
+.avatar {
+    height: 2rem;
+    width: 2rem;
+    align-content: center;
+    justify-content: center;
+    background: #ccc;
+    border-radius: 0.2rem;
+}
+
+.avatar--generated{
+    display: inline-flex;
+    flex-direction: column;
+}
+
+.avatar--float-left {
+    float: left;
+    margin-top: 0.3em;
+    margin-right: 0.5em;
+}
+
+.avatar__content {
+
+}
+
+.avatar--medium {
+    height: var(--size-medium);
+    width: var(--size-medium);
+    border-radius: 0.5rem;
+}
+
+.avatar--generated {
+    text-align: center;
+    background:  #43d2f6;
+}
+
+/*** images ***/
+.img--small {
+    height: 100px;
+}
+
+
+/*** icons ***/
+
+.icon--medium {
+    height: var(--size-medium);
+    display: block;
+    margin: 0 auto;
+}
+
+.icon--small {
+    height: 1em;
+}
+
+.icon--soft {
+    fill: #777;
+}
+
+.icon__name {
+
+}
+
+/*** Messages ***/
+
+.message--info {
+    max-width: 500px;
+    margin: 0 auto;
+    padding: 1em;
+    text-align: justify;
+}
+
+.message--info pre {
+    background: #ddd;
+    padding: 1em;
+}
+
+.message--note {
+    max-width: 500px;
+    margin: 0 auto;
+    padding: 1em;
+    text-align: center;
+}
+
+/*** Menus ***/
+
+.menu ul {
+    display: flex;
+    margin-top: 8px;
+    list-style: none;
+}
+
+.menu a {
+    display: block;
+    color: inherit;
+    text-decoration: none;
+    font-variant: small-caps;
+}
+
+.main_menu {
+    min-width: 200px;
+    /* background-color: #eaeaea; */
+    background-color: #333;
+    color: white;
+    overflow: auto;
+}
+
+.main_menu ul {
+    flex-direction: row;
+    flex-wrap: wrap;
+}
+
+.main_menu li {
+    flex: 1;
+    padding: 0;
+    margin: 0 0.5em;
+}
+
+.main_menu a {
+    display: inline;
+    white-space: nowrap;
+}
+
+.main_menu a:hover {
+    background-color: initial;
+    text-shadow: 1px 1px 2px;
+    font-weight: bold;
+}
+
+.category_menu ul {
+    justify-content: center;
+}
+
+.category_menu li {
+    margin: 0.5em;
+    text-align: center;
+}
+
+.category_menu a {
+    border: solid 1px;
+    padding: 0.5em;
+    border-radius: 0.2em;
+    background: #eee;
+}
+
+/*** containers ***/
+
+/* tabs */
+
+.tab_container {
+    max-width: 1000px;
+    margin: 0 auto;
+}
+
+.tab_header {
+    background-color: white;
+    border-bottom: 1px solid lightgrey;
+}
+
+.tab_header ul {
+    display: flex;
+    margin: 0;
+    padding: 0;
+    list-style: none;
+    background-color: white;
+}
+
+.tab_page {
+    box-sizing: border-box;
+    padding-top: 2em;
+    border: 1px solid lightgrey;
+    border-top: none;
+    display: None;
+}
+
+.tab_page.clicked {
+    display: block;
+}
+
+.tab_button {
+    display: inline;
+    color: grey;
+    background-color: white;
+    border-top: 1px solid lightgrey;
+    border-left: 1px solid lightgrey;
+    border-bottom: 1px solid lightgrey;
+    padding: 0 1em;
+    cursor: pointer;
+    /* we go down by 1px to remove bottom border from .tab_header */
+    margin-bottom: -1px;
+}
+
+.tab_button.clicked {
+    /* background: lightgrey; */
+    color: inherit;
+    border-bottom: none;
+}
+
+li.tab_button:last-child {
+    border-right: 1px solid lightgrey;
+}
+
+.tab_button input {
+    display: None;
+}
+
+.tab_button label {
+    margin: 1em;
+}
+
+.tab_button input:checked + label {
+    font-weight: bold;
+}
+
+/*** Forms ***/
+
+/* a form with only one field */
+
+.form--paper label {
+    font-variant: small-caps;
+}
+
+.form--paper label.required:after {
+    content: " *";
+    font-weight: bold;
+}
+
+.form--paper textarea {
+    resize: vertical;
+}
+
+.form--single {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+}
+
+.form--single input:not([type="submit"]) {
+    margin: 1em 1em;
+    width: 15em;
+    border-radius: 0.7em;
+    outline: none;
+    border: 1px solid black;
+    padding: 0.4em;
+    box-shadow: none;
+}
+
+.form--single .form_input {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+}
+
+
+.form_submit {
+    margin: 1em auto 0;
+    display: block;
+}
+
+.form--single .form_submit {
+    margin: 0;
+}
+
+.form_jid {
+    text-align: center;
+}
+
+.form__panel--vertical {
+    display: flex;
+    flex-direction: column;
+    padding: 2em 0;
+}
+
+.form__panel--vertical label {
+    display: block;
+}
+
+.form__panel--vertical .form_input {
+    margin: 0.5em 0;
+}
+
+.form__panel--center textarea,input:not([type="radio"]) {
+    display: block;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+.form__panel--center label {
+    text-align: center;
+}
+
+.form__field--tiny>input {
+    box-sizing: border-box;
+    width: 3em;
+}
+
+.form__field--small>input {
+    box-sizing: border-box;
+    width: 20em;
+    max-width: 95%;
+}
+
+.form__field--medium>input {
+    box-sizing: border-box;
+    width: 50em;
+    max-width: 95%;
+}
+
+.form__field--big>input,textarea {
+    box-sizing: border-box;
+    width: 100%;
+}
+
+/* Textboxes */
+
+.textbox {
+    margin-left: auto;
+    margin-right: auto;
+}
+
+form.textbox>* {
+    display: block;
+    margin: 1em auto;
+    text-align: center;
+    max-width: 100%;
+    box-sizing: border-box;
+}
+
+form.textbox>textarea {
+    text-align: left;
+}
+
+.log_request {
+    text-align: center;
+}
+
+/*** Navigation ***/
+
+.prev_next_links ul {
+    list-style: none;
+    display: flex;
+    padding: 0 2em;
+    margin: 0;
+}
+
+.prev_next_links li {
+    flex: 1;
+}
+
+.prev_next_links li.older_items {
+    text-align: right;
+}
+
+.prev_next_links img {
+    display: block;
+}
+
+.prev_next_links .older_items img {
+    display: block;
+    margin-left: auto;
+    margin-right: 0;
+}
+
+.prev_next_links a {
+    display: inline-block;
+    margin-top: 1em;
+    padding: 0.2em;
+    text-decoration: None;
+    color: inherit;
+    font-variant: small-caps;
+    background: rgba(200,200,200,0.6);
+    border-radius: 0.5em;
+}
+
+.prev_next_links a:hover {
+    background-color: #ddd;
+}
+
+/*** XMLUI ***/
+
+.xmlui_cont_vertical>* {
+    display: block;
+    box-sizing: border-box;
+}
+
+.xmlui_cont_vertical>.xmlui_widget {
+    width: 100%;
+    min-height: 1em;
+    min-width: 1px;
+}
+
+label.xmlui_label {
+    font-weight: bold;
+}
+
+td a {
+  /* we use <a> for non JS links in table
+   * so we don't want specific color/text-decoration by default
+   */
+  color: inherit;
+  text-decoration: inherit;
+}
+
+
+/*** Notifications ***/
+
+.notification.retry {
+    position: fixed;
+    top: 1rem;
+    margin: auto;
+    width: 80%;
+    background: #DB1616;
+    border: 3px solid silver;
+    left: 10%;
+    text-align: center;
+}
+
+#retry_counter {
+    font-weight: bold;
+}
+
+#retry_now {
+    color: blue;
+    text-decoration: underline;
+    cursor: pointer;
+}
+
+@media (min-width: 800px) {
+    html {
+        background-size: auto;
+    }
+
+    body {
+        flex-direction: row;
+    }
+
+    #main_area {
+        overflow: auto;
+    }
+
+    /*** boxes ***/
+
+    .box {
+        border-radius: 1em;
+        box-shadow: 10px 10px 16px -5px rgba(0,0,0,0.5);
+        width: 94%;
+        margin: 1em auto;
+        border: solid 1px;
+        border-color: #9ca0a8;
+    }
+
+    .box--medium {
+        width: 33rem;
+        max-width: 100%;
+    }
+
+    .box--hollow {
+        border-radius: 0.2em;
+        border-width: 1px;
+        margin: 0.5em;
+    }
+
+    /*** Forms ***/
+
+    .form__panel--vertical {
+        display: flex;
+        flex-direction: column;
+        padding: 2em;
+    }
+
+    .form__field--big>input,textarea {
+        box-sizing: border-box;
+        width: 95%;
+    }
+
+    .main_menu a {
+        display: block;
+        padding: 2em 0;
+    }
+
+    .main_menu ul {
+        flex-direction: column;
+        padding-left: 2em;
+    }
+
+    .prev_next_links ul {
+        padding: 0 6em;
+    }
+
+    .instructions--alt {
+        padding-top: 3rem;
+    }
+
+    /*** forms ***/
+
+    .form--single input:not([type="submit"]) {
+        margin: 0 1em;
+    }
+
+    .form--single {
+        display: flex;
+        justify-content: center;
+        flex-direction: row;
+    }
+
+    .form--single .form_input {
+        flex-direction: row;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/ticket.css	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,180 @@
+@import 'blog.css'; /* needed as blog/articles.html is included */
+
+.instructions {
+    font-style: italic;
+    text-align: center;
+}
+
+.instructions span {
+    padding: 0.3em;
+}
+
+ul.xmlui_list {
+    list-style: none;
+    display: flex;
+    flex-direction: column;
+    padding: 0;
+}
+
+.xmlui_list li {
+    display: inline-flex;
+    background: #eee;
+    padding: 0.5em;
+    margin: 0.5em 0;
+    border: 1px solid silver;
+}
+
+.xmlui_list li:hover {
+    background: yellow;
+}
+
+.xmlui_list a {
+    display: flex;
+    width: 100%;
+    text-decoration: none;
+    color: inherit;
+}
+
+.xmlui_list a:visited {
+    color: inherit;
+}
+
+.tickets a.status_closed {
+    text-decoration: line-through;
+    color: grey;
+}
+
+.xmlui_field__id {
+    font-style: italic;
+    padding-right: 1em;
+}
+
+.xmlui_field__title {
+    padding-right: 1em;
+}
+
+.tickets a.severity_major .xmlui_field__title {
+    font-weight: bold;
+    color: red;
+}
+
+.tickets tbody tr.severity_major .td_title a::before {
+    content: '⚠ ';
+    color: red;
+}
+
+/* single ticket */
+
+.ticket {
+    padding: 20px;
+    max-width: 500px;
+    margin: 0 auto;
+}
+
+.view .xmlui_widget {
+    width: auto;
+}
+
+.view div.xmlui_cont div.xmlui_cont {
+    display: grid;
+    grid-template-columns: min-content 1fr;
+}
+
+.view #label_wid_publisher,
+.view #wid_publisher,
+.view #label_wid_title,
+.view #label_wid_body,
+.view #label_wid_id,
+.view #label_wid_comments_uri,
+.view #wid_comments_uri {
+    display: none
+}
+
+.view .xmlui_label {
+    padding-right: 2em;
+}
+
+.view #wid_id {
+    margin: 0;
+    font-style: italic;
+    grid-column-start: 1;
+    grid-column-end: 3;
+    text-align: right;
+}
+
+.view .xmlui_label {
+    font-weight: bold;
+    float: left;
+    color: #808080cc;
+}
+
+.view #wid_title {
+    font-weight: bold;
+    display: block;
+    text-align: center;
+    grid-column-start: 1;
+    grid-column-end: 3;
+}
+.view #wid_title::first-letter {
+    text-transform: uppercase;
+}
+
+.view #wid_labels span, .xmlui_field__labels span {
+    font-size: 0.8em;
+    background: #eae3e3;
+    font-variant: small-caps;
+    border: 1px solid black;
+    border-radius: 0.5em;
+    padding: 0 2px;
+    white-space: nowrap;
+}
+
+.view #wid_labels span.value_work_in_progress {
+    background: yellow;
+}
+
+.view #wid_type {
+    font-weight: bold;
+}
+
+.view #wid_type span.value_bug::after {
+    content: ' 🐛';
+    color: red;
+}
+
+.view #wid_severity span.value_major {
+    font-weight: bold;
+    color: red;
+}
+
+.view #wid_severity span.value_major::after {
+    content: '⚠ ';
+}
+
+.view #wid_body {
+    white-space: pre-wrap;
+    max-height: 500px;
+    overflow: auto;
+    resize: both;
+    background-color: white;
+    padding: 5px;
+    text-align: justify;
+    border: 1px solid black;
+    border-radius: 5px;
+    grid-column-start: 1;
+    grid-column-end: 3;
+    display: block;
+}
+
+.comment_post {
+    margin-top: 3em;
+}
+
+@media (min-width: 800px) {
+    ul.xmlui_list {
+        padding: 0 2em;
+    }
+    .xmlui_list li {
+        border-radius: 0.3em;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/static/websocket.js	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,131 @@
+/*
+SàT templates: suit of templates for Salut à Toi
+Copyright (C) 2017 Jérôme Poisson (goffi@goffi.org)
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* websocket handler */
+
+
+//TODO: retry websocket instead of reload
+function WSHandler(url, token, debug=false) {
+    var socket = new WebSocket(url, 'libervia_page_' + token );
+    var retried = 0;
+
+    var errorHandler = function(error) {
+        if (retried > 20) {
+            console.error("Too many tries, can't start websocket");
+            alert("Dynamic connection with server can't be established, please try to reload this page in a while or contact your service administrator");
+            return;
+        }
+        var delay = Math.floor((Math.random() * 10) + 1) + 30 * Math.min(retried, 6);
+        notifyRetry(delay, function() {
+            retried++;
+            socket = new WebSocket(url, 'libervia_page_' + token );
+            socket.addEventListener('error', errorHandler);
+        });
+    };
+
+    socket.addEventListener('error', errorHandler);
+
+    if (debug) {
+        socket.addEventListener('message', function(event) {
+            console.log('WS in <== ', JSON.parse(event.data));
+        });
+    }
+
+    socket.addEventListener('message', function(event) {
+        try {data = JSON.parse(event.data);}
+        catch (e) {
+            console.warn('invalid websocket message received: %s', e);
+            return;
+        }
+        switch (data.type) {
+            case 'reload':
+                location.reload(true);
+                break;
+            case 'dom':
+                selected_element = document.body.querySelector(data.selectors);
+                switch (data.update_type) {
+                    case 'append':
+                        var template = document.createElement('template');
+                        template.innerHTML = data.html.trim();
+                        new_element = template.content.firstChild;
+                        selected_element.appendChild(new_element);
+                        break;
+                    default:
+                        console.warn('Unknown DOM update type: %s', data.update_type);
+                }
+                break;
+            default:
+                console.warn('Unknown data type: %s', data.type);
+        }
+    });
+
+    socket.addEventListener('open', function (event) {
+        console.log('Websocket opened');
+        retried = 0;
+    }.bind(this));
+
+    this.send = function(data) {
+        if (debug) {
+            console.log('WS out ==> ', data);
+        }
+        socket.send(JSON.stringify(data));
+    };
+
+    function notifyRetry(timeout, retryCb) {
+        /* Show a notification dialog informing the user that server can't be reach
+         * and call retryCb after timeout seconds.
+         * A "retry now" link allows to retry immediately"
+         *
+         * @param timeout(int): delay before retrying, in seconds
+         * @param retryCb(function): function to call when retrying
+         */
+        var startTime = Date.now() / 1000;
+        var retryIntervalID;
+        var notif = document.createElement("div");
+        notif.setAttribute('class', 'notification retry');
+        //FIXME: we use English without translation for now, must be changed when we can use gettext in Libervia pages
+        notif.innerHTML = "<p>Can't reach the server, retrying in <span id='retry_counter'></span> seconds</p><p><a id='retry_now'>retry now</a></p>";
+        document.body.appendChild(notif);
+        var retryCounter = document.getElementById('retry_counter');
+        retryCounter.textContent = timeout;
+
+        var retry = function () {
+            clearInterval(retryIntervalID);
+            notif.parentNode.removeChild(notif);
+            retryCb();
+        };
+
+        var updateTimer = function () {
+            var elapsed = Math.floor(Date.now() / 1000 - startTime);
+            var remaining = timeout - elapsed;
+            if (remaining < 0) {
+                retry();
+            }
+            else {
+                retryCounter.textContent = remaining;
+            }
+        };
+
+        var retryNow = document.getElementById('retry_now');
+        retryNow.addEventListener('click', function(){
+            retry();
+        });
+
+        retryIntervalID = setInterval(updateTimer, 1000);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/ticket/create.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,25 @@
+{# create a new ticket #}
+
+{% set category_menu = [('tickets_list', url_tickets_list)] %}
+{% extends 'base/base.html' %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+{% import 'input/xmlui.html' as xmlui with context %}
+
+{% block body %}
+<div class='instructions'>
+    <p><span class="box">{% trans app_name=C.APP_NAME%}This page allows you to report an issue or ask/suggest a new feature for {{app_name}}{% endtrans %}</span></p>
+</div>
+<div class="create single ticket box">
+{% call form.form() %}
+    {{ xmlui.generate(new_ticket_xmlui,
+                      attributes = {'title': {'required': 'required',
+                                              'placeholder': _("Short description of your issue/request")},
+                                    'body': {'required': 'required',
+                                             'placeholder': _("Please describe your issue/request with as much details as possible")},
+                                    'labels': {'placeholder': _("You can enter one or several labels separated by commas")},
+                                    })}}
+    {{ field.submit(_("Create ticket")) }}
+{% endcall %}
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/ticket/discover.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,25 @@
+{% extends 'base/base.html' %}
+{% import 'components/block.html' as block with context %}
+{% import 'components/images.html' as images with context %}
+{% import 'components/avatar.html' as avatar with context %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+
+{% block body %}
+{{ icon_defs('clipboard') }}
+<p class="instructions--head">
+    {% trans %}
+    Please select a tickets tracker
+    {% endtrans %}
+</p>
+{% if tickets_trackers is defined %}
+    <div class="disco_tickets">
+        {{block.disco_icon_grid(tickets_trackers, 'clipboard')}}
+    </div>
+{% endif %}
+
+{% call form.form(class="form--single") %}
+    {{ field.text("jid", _("tickets tracker jid"), required=true)}}
+    {{ field.submit(_("Access")) }}
+{% endcall %}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/ticket/edit.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,22 @@
+{# edit an existing ticket #}
+
+{% set category_menu = [('tickets_list', url_tickets_list)] %}
+{% extends 'base/base.html' %}
+{% import 'input/form.html' as form with context %}
+{% import 'input/field.html' as field with context %}
+{% import 'input/xmlui.html' as xmlui with context %}
+
+{% block body %}
+<div class="create single ticket box">
+{% call form.form() %}
+    {{ xmlui.generate(new_ticket_xmlui,
+                      attributes = {'title': {'required': 'required',
+                                              'placeholder': _("Short description of your issue/request")},
+                                    'body': {'required': 'required',
+                                             'placeholder': _("Please describe your issue/request with as much details as possible")},
+                                    'labels': {'placeholder': _("You can enter one or several labels separated by commas")},
+                                    })}}
+    {{ field.submit(_("Modify ticket")) }}
+{% endcall %}
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/ticket/item.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,51 @@
+{# display a single ticket
+
+    @variable item(xmlui_item): ticket to display
+    @variable comments(data_object.BlogItems): comments of the ticket
+    @variable comments_service(unicode): service for adding comments
+    @variable comments_node(unicode): node for adding comments
+#}
+
+{% set category_menu = [('tickets', url_tickets_list),
+                        ('ticket_new', url_tickets_new),
+                        ] %}
+{% if not embedded %}{% extends 'base/base.html' %}{% endif %}
+{% import 'input/xmlui.html' as xmlui with context %}
+{% import 'blog/macros.html' as blog with context %}
+{% import 'input/textbox.html' as textbox with context %}
+
+{% block title %}{{item|adv_format('[{value.widget_value.id}] {value.widget_value.title}') }}{% endblock %}
+
+{% block confirm_message %}
+    {% trans %}Your comment has been sent{% endtrans %}
+{% endblock confirm_message %}
+
+{% block body %}
+{{ icon_defs('pencil') }}
+<div id="{{ item.widget_value['id'] }}" class="view single ticket box">
+    {% if url_ticket_edit is defined %}
+        <p class="box__tools">
+            <a href="{{url_ticket_edit}}">
+            {{ icon('pencil', cls='icon--small') }}
+            edit
+            </a>
+        </p>
+    {% endif %}
+    {{ xmlui.generate(item,
+        form=false,
+        filters={'created': {'filters': ['date_fmt'], 'filters_args':[{'fmt': 'short'}]},
+                 'updated': {'filters': ['date_fmt'], 'filters_args':[{'fmt': 'short'}]},
+                 'body': {'filters': ['urlize'], 'filters_args':[{'nofollow': True, 'rel': 'noopener noreferrer'}]}},
+        )}}
+</div>
+{% if comments is defined %}
+<div id="blog_items">
+    {{ blog.show_items(comments|reverse, expanded=true) }}
+</div>
+{% endif %}
+{% if comments_node is defined %}
+    <div class="comment_post">
+        {{- textbox.comment_or_login(service=comments_service, node=comments_node) -}}
+    </div>
+{% endif %}
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/ticket/overview.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,16 @@
+{# display the list of tickets #}
+
+{% set category_menu = [('ticket_new', url_tickets_new)] %}
+{% extends 'base/base.html' %}
+{% import 'input/xmlui.html' as xmlui with context %}
+
+{% block body %}
+<div id="tickets" class="view tickets overview">
+    {{ xmlui.generate_list(tickets, (('id', _('Id')),
+                                     ('title', _('Title')),
+                                     ('labels', _('Labels'))),
+                          {'id': '[{value}]'},
+                           item_class_fields=['status', 'priority', 'severity'],
+                           on_click=on_ticket_click) }}
+</div>
+{% endblock body %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sat_templates/templates/default/ticket/tickets.html	Mon Sep 10 08:53:33 2018 +0200
@@ -0,0 +1,12 @@
+{% extends 'base/base.html' %}
+{% import 'input/xmlui.html' as xmlui with context %}
+
+{% block body %}
+<div id="tickets">
+    {% for ticket in tickets %}
+        <div class="ticket_full">
+            {{ xmlui.generate(ticket) }}
+        </div>
+    {% endfor %}
+</div>
+{% endblock body %}